From 6ee55c23b042a1559e8cabfccf3b9d3320c4c5cc Mon Sep 17 00:00:00 2001 From: spicyjpeg Date: Thu, 6 Oct 2022 12:15:24 +0200 Subject: Replace psxgpu debug font, add CdGetSector2() --- libpsn00b/include/psxcd.h | 1 + libpsn00b/psxcd/cdgetsector.s | 56 ------------------------------------------ libpsn00b/psxcd/getsector.c | 35 ++++++++++++++++++++++++++ libpsn00b/psxcd/isofs.c | 8 +++--- libpsn00b/psxcd/psxcd_asm.s | 8 +----- libpsn00b/psxgpu/dbugfont.png | Bin 0 -> 1090 bytes libpsn00b/psxgpu/dbugfont.tim | Bin 2112 -> 2112 bytes libpsn00b/psxgpu/font.c | 36 ++++++++++++++------------- 8 files changed, 60 insertions(+), 84 deletions(-) delete mode 100644 libpsn00b/psxcd/cdgetsector.s create mode 100644 libpsn00b/psxcd/getsector.c create mode 100644 libpsn00b/psxgpu/dbugfont.png diff --git a/libpsn00b/include/psxcd.h b/libpsn00b/include/psxcd.h index 03ee792..cf9ecad 100644 --- a/libpsn00b/include/psxcd.h +++ b/libpsn00b/include/psxcd.h @@ -145,6 +145,7 @@ uint32_t CdSyncCallback(CdlCB func); long CdReadyCallback(CdlCB func); int CdGetSector(void *madr, int size); +int CdGetSector2(void *madr, int size); CdlFILE* CdSearchFile(CdlFILE *loc, const char *filename); diff --git a/libpsn00b/psxcd/cdgetsector.s b/libpsn00b/psxcd/cdgetsector.s deleted file mode 100644 index 6a29069..0000000 --- a/libpsn00b/psxcd/cdgetsector.s +++ /dev/null @@ -1,56 +0,0 @@ -.set noreorder - -.include "hwregs_a.inc" - -.section .text - -.global CdGetSector -.type CdGetSector, @function -CdGetSector: - - lui $a2, IOBASE - -#.Lwait_fifo: # Probably redundant as the BIOS CD-ROM -# lbu $v0, CD_REG0($a2) # routines do not not wait for this -# nop -# andi $v0, 0x40 -# beqz $v0, .Lwait_fifo -# nop - - lui $v0, 0x1 -# srl $a1, 2 # (the official implementation expects $a1/size - # to be in 32-bit words rather than bytes) - or $v0, $a1 - sw $a0, DMA3_MADR($a2) # Set DMA base address and transfer length - sw $v0, DMA3_BCR($a2) - - lui $v0, 0x1100 # Start DMA transfer - sw $v0, DMA3_CHCR($a2) - nop - nop - -.Ldma_wait: # Ensure DMA transfer has completed - lw $v0, DMA3_CHCR($a2) - nop - srl $v0, 24 - andi $v0, 0x1 - - bnez $v0, .Ldma_wait - nop - -# Not stable -# sb $0 , CD_REG0($a2) -#.Lflush_fifo: # Read out any remaining bytes in the buffer -# lbu $v1, CD_REG0($a2) -# li $v0, 0x40 -# and $v1, $v0 -# beqz $v1, .Lend_flush -# nop -# lbu $v0, CD_REG2($a2) -# b .Lflush_fifo -# nop -#.Lend_flush: - - jr $ra - li $v0, 1 - diff --git a/libpsn00b/psxcd/getsector.c b/libpsn00b/psxcd/getsector.c new file mode 100644 index 0000000..bc1c8ae --- /dev/null +++ b/libpsn00b/psxcd/getsector.c @@ -0,0 +1,35 @@ +/* + * PSn00bSDK CD drive library (sector DMA API) + * (C) 2022 spicyjpeg - MPL licensed + */ + +#include +#include +#include + +/* DMA transfer functions */ + +int CdGetSector(void *madr, int size) { + //while (!(CD_STAT & (1 << 6))) + //__asm__ volatile(""); + + DMA_MADR(3) = (uint32_t) madr; + DMA_BCR(3) = size | (1 << 16); + DMA_CHCR(3) = 0x11000000; + + while (DMA_CHCR(3) & (1 << 24)) + __asm__ volatile(""); + + return 1; +} + +int CdGetSector2(void *madr, int size) { + //while (!(CD_STAT & (1 << 6))) + //__asm__ volatile(""); + + DMA_MADR(3) = (uint32_t) madr; + DMA_BCR(3) = size | (1 << 16); + DMA_CHCR(3) = 0x11400100; // Transfer 1 word every 16 CPU cycles + + return 1; +} diff --git a/libpsn00b/psxcd/isofs.c b/libpsn00b/psxcd/isofs.c index 582b8d9..d620377 100644 --- a/libpsn00b/psxcd/isofs.c +++ b/libpsn00b/psxcd/isofs.c @@ -434,8 +434,8 @@ static int find_dir_entry(const char *name, ISO_DIR_ENTRY *dirent) static char* get_pathname(char *path, const char *filename) { - char *c = 0; - for (char *i = filename; *i; i++) { + const char *c = 0; + for (const char *i = filename; *i; i++) { if (IS_PATH_SEP(*i)) c = i; } @@ -453,8 +453,8 @@ static char* get_pathname(char *path, const char *filename) static char* get_filename(char *name, const char *filename) { - char *c = 0; - for (char *i = filename; *i; i++) { + const char *c = 0; + for (const char *i = filename; *i; i++) { if (IS_PATH_SEP(*i)) c = i; } diff --git a/libpsn00b/psxcd/psxcd_asm.s b/libpsn00b/psxcd/psxcd_asm.s index 906ab32..16e17d8 100644 --- a/libpsn00b/psxcd/psxcd_asm.s +++ b/libpsn00b/psxcd/psxcd_asm.s @@ -490,13 +490,7 @@ CdSyncCallback: .section .data - -.global psxcd_credits -.type psxcd_credits, @object -psxgpu_credits: - .ascii "psxcd library programs by Lameguy64\n" - .asciiz "2020 PSn00bSDK Project / Meido-Tek Productions\n" - + .comm _cd_last_cmd, 1, 1 .comm _cd_last_mode, 1, 1 .comm _cd_ack_wait, 1, 1 diff --git a/libpsn00b/psxgpu/dbugfont.png b/libpsn00b/psxgpu/dbugfont.png new file mode 100644 index 0000000..ed84268 Binary files /dev/null and b/libpsn00b/psxgpu/dbugfont.png differ diff --git a/libpsn00b/psxgpu/dbugfont.tim b/libpsn00b/psxgpu/dbugfont.tim index 4e6cce2..1edd4af 100644 Binary files a/libpsn00b/psxgpu/dbugfont.tim and b/libpsn00b/psxgpu/dbugfont.tim differ diff --git a/libpsn00b/psxgpu/font.c b/libpsn00b/psxgpu/font.c index 2d4105f..b1c3c7a 100644 --- a/libpsn00b/psxgpu/font.c +++ b/libpsn00b/psxgpu/font.c @@ -27,16 +27,16 @@ void FntLoad(int x, int y) { RECT pos; TIM_IMAGE tim; - GetTimInfo( (const uint32_t *) _gpu_debug_font, &tim ); + GetTimInfo((const uint32_t *) _gpu_debug_font, &tim); // Load font image pos = *tim.prect; pos.x = x; pos.y = y; - _font_tpage = getTPage( 0, 0, pos.x, pos.y ); + _font_tpage = getTPage(0, 0, pos.x, pos.y); - LoadImage( &pos, tim.paddr ); + LoadImage(&pos, tim.paddr); DrawSync(0); // Load font clut @@ -44,9 +44,9 @@ void FntLoad(int x, int y) { pos.x = x; pos.y = y+tim.prect->h; - _font_clut = getClut( pos.x, pos.y ); + _font_clut = getClut(pos.x, pos.y); - LoadImage( &pos, tim.caddr ); + LoadImage(&pos, tim.caddr); DrawSync(0); // Clear previously opened text streams @@ -193,10 +193,11 @@ char *FntFlush(int id) { if( i > 0 ) { i--; - setSprt8( sprt ); - setRGB0( sprt, 128, 128, 128 ); - setXY0( sprt, sx, sy ); - setUV0( sprt, (i%16)<<3, (i>>4)<<3 ); + setSprt8(sprt); + setShadeTex(sprt, 1); + setSemiTrans(sprt, 1); + setXY0(sprt, sx, sy); + setUV0(sprt, (i % 16) * 8, (i / 16) * 8); sprt->clut = _font_clut; setaddr(opri, sprt); opri = (char*)sprt; @@ -237,12 +238,13 @@ char *FntSort(uint32_t *ot, char *pri, int x, int y, const char *text) { if( i > 0 ) { i--; - setSprt8( sprt ); - setRGB0( sprt, 128, 128, 128 ); - setXY0( sprt, x, y ); - setUV0( sprt, (i%16)<<3, (i>>4)<<3 ); + setSprt8(sprt); + setShadeTex(sprt, 1); + setSemiTrans(sprt, 1); + setXY0(sprt, x, y); + setUV0(sprt, (i % 16) * 8, (i / 16) * 8); sprt->clut = _font_clut; - addPrim( ot, sprt ); + addPrim(ot, sprt); sprt++; } @@ -256,9 +258,9 @@ char *FntSort(uint32_t *ot, char *pri, int x, int y, const char *text) { tpage = (DR_TPAGE*)pri; tpage->code[0] = _font_tpage; - setlen( tpage, 1 ); - setcode( tpage, 0xe1 ); - addPrim( ot, pri ); + setlen(tpage, 1); + setcode(tpage, 0xe1); + addPrim(ot, pri); pri += sizeof(DR_TPAGE); return pri; -- cgit v1.2.3 From 3acc4f93f3b6a96da484aab1f08d61f900085e43 Mon Sep 17 00:00:00 2001 From: spicyjpeg Date: Sat, 8 Oct 2022 10:12:31 +0200 Subject: Fix DMACallback bug, disable logging in release builds --- libpsn00b/libc/abort.c | 12 +- libpsn00b/psxapi/drivers.s | 24 ++-- libpsn00b/psxapi/stubs.json | 6 +- libpsn00b/psxcd/isofs.c | 251 ++++++++++++++++-------------------------- libpsn00b/psxcd/psxcd.c | 22 ++-- libpsn00b/psxetc/interrupts.c | 12 +- libpsn00b/psxgpu/common.c | 14 ++- libpsn00b/psxgpu/image.c | 14 ++- libpsn00b/psxpress/mdec.c | 16 ++- libpsn00b/psxspu/common.c | 22 ++-- 10 files changed, 181 insertions(+), 212 deletions(-) diff --git a/libpsn00b/libc/abort.c b/libpsn00b/libc/abort.c index de4323d..562b619 100644 --- a/libpsn00b/libc/abort.c +++ b/libpsn00b/libc/abort.c @@ -1,10 +1,16 @@ #include +#ifdef DEBUG +#define _LOG(...) printf(__VA_ARGS__) +#else +#define _LOG(...) +#endif + /* Standard abort */ void abort() { - printf("abort()\n"); + _LOG("abort()\n"); for (;;) __asm__ volatile(""); @@ -13,7 +19,7 @@ void abort() { /* Internal function used by assert() macro */ void _assert_abort(const char *file, int line, const char *expr) { - printf("%s:%d: assert(%s)\n", file, line, expr); + _LOG("%s:%d: assert(%s)\n", file, line, expr); for (;;) __asm__ volatile(""); @@ -22,7 +28,7 @@ void _assert_abort(const char *file, int line, const char *expr) { /* Pure virtual function call (C++) */ void __cxa_pure_virtual(void) { - printf("__cxa_pure_virtual()\n"); + _LOG("__cxa_pure_virtual()\n"); for (;;) __asm__ volatile(""); diff --git a/libpsn00b/psxapi/drivers.s b/libpsn00b/psxapi/drivers.s index 1cf5050..d991f90 100644 --- a/libpsn00b/psxapi/drivers.s +++ b/libpsn00b/psxapi/drivers.s @@ -90,26 +90,26 @@ ListDev: jr $t2 li $t1, 0x49 -.section .text.InitCard -.global InitCard -.type InitCard, @function -InitCard: +.section .text.InitCARD +.global InitCARD +.type InitCARD, @function +InitCARD: li $t2, 0xb0 jr $t2 li $t1, 0x4a -.section .text.StartCard -.global StartCard -.type StartCard, @function -StartCard: +.section .text.StartCARD +.global StartCARD +.type StartCARD, @function +StartCARD: li $t2, 0xb0 jr $t2 li $t1, 0x4b -.section .text.StopCard -.global StopCard -.type StopCard, @function -StopCard: +.section .text.StopCARD +.global StopCARD +.type StopCARD, @function +StopCARD: li $t2, 0xb0 jr $t2 li $t1, 0x4c diff --git a/libpsn00b/psxapi/stubs.json b/libpsn00b/psxapi/stubs.json index 200cbc7..50ffb55 100644 --- a/libpsn00b/psxapi/stubs.json +++ b/libpsn00b/psxapi/stubs.json @@ -362,19 +362,19 @@ { "type": "b", "id": 74, - "name": "InitCard", + "name": "InitCARD", "file": "drivers.s" }, { "type": "b", "id": 75, - "name": "StartCard", + "name": "StartCARD", "file": "drivers.s" }, { "type": "b", "id": 76, - "name": "StopCard", + "name": "StopCARD", "file": "drivers.s" }, { diff --git a/libpsn00b/psxcd/isofs.c b/libpsn00b/psxcd/isofs.c index d620377..6755d3f 100644 --- a/libpsn00b/psxcd/isofs.c +++ b/libpsn00b/psxcd/isofs.c @@ -10,6 +10,12 @@ // Uncommend to enable debug output //#define DEBUG +#ifdef DEBUG +#define _LOG(...) printf(__VA_ARGS__) +#else +#define _LOG(...) +#endif + #define DEFAULT_PATH_SEP '\\' #define IS_PATH_SEP(ch) (((ch) == '/') || ((ch) == '\\')) @@ -46,9 +52,8 @@ static int _CdReadIsoDescriptor(int session_offs) CdControl(CdlNop, 0, 0); if( (CdStatus()&0x10) ) { -#ifdef DEBUG - printf("psxcd: Lid is still open.\n"); -#endif + _LOG("psxcd: Lid is still open.\n"); + _cd_iso_error = CdlIsoLidOpen; return -1; } @@ -61,61 +66,47 @@ static int _CdReadIsoDescriptor(int session_offs) { return 0; } - -#ifdef DEBUG - printf("psxcd: Parsing ISO file system.\n"); -#endif + + _LOG("psxcd: Parsing ISO file system.\n"); // Seek to volume descriptor CdIntToPos(16+session_offs, &loc); if( !CdControl(CdlSetloc, (uint8_t*)&loc, 0) ) { -#ifdef DEBUG - printf("psxcd: Could not set seek destination.\n"); -#endif + _LOG("psxcd: Could not set seek destination.\n"); + _cd_iso_error = CdlIsoSeekError; return -1; } -#ifdef DEBUG - printf("psxcd: Set seek target.\n"); -#endif - -#ifdef DEBUG - printf("psxcd: Read sectors.\n"); -#endif + _LOG("psxcd: Read sectors.\n"); + // Read volume descriptor CdRead(1, (uint32_t*)_cd_iso_descriptor_buff, CdlModeSpeed); if( CdReadSync(0, 0) ) { -#ifdef DEBUG - printf("psxcd: Error reading ISO volume descriptor.\n"); -#endif + _LOG("psxcd: Error reading ISO volume descriptor.\n"); + _cd_iso_error = CdlIsoReadError; return -1; } - -#ifdef DEBUG - printf("psxcd: Read complete.\n"); -#endif - + + _LOG("psxcd: Read complete.\n"); + // Verify if volume descriptor is present descriptor = (ISO_DESCRIPTOR*)_cd_iso_descriptor_buff; if( strncmp("CD001", descriptor->header.id, 5) ) { -#ifdef DEBUG - printf("psxcd: Disc does not contain a ISO9660 file system.\n"); -#endif + _LOG("psxcd: Disc does not contain a ISO9660 file system.\n"); + _cd_iso_error = CdlIsoInvalidFs; return -1; } - -#ifdef DEBUG - printf("psxcd_dbg: Path table LBA = %d\n", descriptor->pathTable1Offs); - printf("psxcd_dbg: Path table len = %d\n", descriptor->pathTableSize.lsb); -#endif - + + _LOG("psxcd: Path table LBA = %d\n", descriptor->pathTable1Offs); + _LOG("psxcd: Path table len = %d\n", descriptor->pathTableSize.lsb); + // Allocate path table buffer i = ((2047+descriptor->pathTableSize.lsb)>>11)<<11; if( _cd_iso_pathtable_buff ) @@ -123,20 +114,17 @@ static int _CdReadIsoDescriptor(int session_offs) free(_cd_iso_pathtable_buff); } _cd_iso_pathtable_buff = (uint8_t*)malloc(i); - -#ifdef DEBUG - printf("psxcd_dbg: Allocated %d bytes for path table.\n", i); -#endif - + + _LOG("psxcd: Allocated %d bytes for path table.\n", i); + // Read path table CdIntToPos(descriptor->pathTable1Offs, &loc); CdControl(CdlSetloc, (uint8_t*)&loc, 0); CdRead(i>>11, (uint32_t*)_cd_iso_pathtable_buff, CdlModeSpeed); if( CdReadSync(0, 0) ) { -#ifdef DEBUG - printf("psxcd: Error reading ISO path table.\n"); -#endif + _LOG("psxcd: Error reading ISO path table.\n"); + _cd_iso_error = CdlIsoReadError; return -1; } @@ -162,14 +150,13 @@ static int _CdReadIsoDirectory(int lba) CdIntToPos(lba, &loc); i = CdPosToInt(&loc); -#ifdef DEBUG - printf("psxcd_dbg: Seek to sector %d\n", i); -#endif + + _LOG("psxcd_dbg: Seek to sector %d\n", i); + if( !CdControl(CdlSetloc, (uint8_t*)&loc, 0) ) { -#ifdef DEBUG - printf("psxcd: Could not set seek destination.\n"); -#endif + _LOG("psxcd: Could not set seek destination.\n"); + _cd_iso_error = CdlIsoSeekError; return -1; } @@ -184,28 +171,24 @@ static int _CdReadIsoDirectory(int lba) CdRead(1, (uint32_t*)_cd_iso_directory_buff, CdlModeSpeed); if( CdReadSync(0, 0) ) { -#ifdef DEBUG - printf("psxcd: Error reading initial directory record.\n"); -#endif + _LOG("psxcd: Error reading initial directory record.\n"); + _cd_iso_error = CdlIsoReadError; return -1; } direntry = (ISO_DIR_ENTRY*)_cd_iso_directory_buff; _cd_iso_directory_len = direntry->entrySize.lsb; - -#ifdef DEBUG - printf("psxcd_dbg: Location of directory record = %d\n", direntry->entryOffs.lsb); - printf("psxcd_dbg: Size of directory record = %d\n", _cd_iso_directory_len); -#endif + + _LOG("psxcd: Location of directory record = %d\n", direntry->entryOffs.lsb); + _LOG("psxcd: Size of directory record = %d\n", _cd_iso_directory_len); if( _cd_iso_directory_len > 2048 ) { if( !CdControl(CdlSetloc, (uint8_t*)&loc, 0) ) { -#ifdef DEBUG - printf("psxcd: Could not set seek destination.\n"); -#endif + _LOG("psxcd: Could not set seek destination.\n"); + _cd_iso_error = CdlIsoSeekError; return -1; } @@ -213,16 +196,14 @@ static int _CdReadIsoDirectory(int lba) free(_cd_iso_directory_buff); i = ((2047+_cd_iso_directory_len)>>11)<<11; _cd_iso_directory_buff = (uint8_t*)malloc(i); -#ifdef DEBUG - printf("psxcd_dbg: Allocated %d bytes for directory record.\n", i); -#endif + + _LOG("psxcd: Allocated %d bytes for directory record.\n", i); CdRead(i>>11, (uint32_t*)_cd_iso_directory_buff, CdlModeSpeed); if( CdReadSync(0, 0) ) { -#ifdef DEBUG - printf("psxcd: Error reading remaining directory record.\n"); -#endif + _LOG("psxcd: Error reading remaining directory record.\n"); + _cd_iso_error = CdlIsoReadError; return -1; } @@ -243,7 +224,7 @@ static void dump_directory(void) ISO_DIR_ENTRY *dir_entry; char namebuff[16]; - printf("psxcd_dbg: Cached directory record contents:\n"); + _LOG("psxcd: Cached directory record contents:\n"); i = 0; dir_pos = 0; @@ -254,7 +235,7 @@ static void dump_directory(void) strncpy(namebuff, _cd_iso_directory_buff+dir_pos+sizeof(ISO_DIR_ENTRY), dir_entry->identifierLen); - printf("P:%d L:%d %s\n", dir_pos, dir_entry->identifierLen, namebuff); + _LOG("P:%d L:%d %s\n", dir_pos, dir_entry->identifierLen, namebuff); dir_pos += dir_entry->entryLength; i++; @@ -273,7 +254,7 @@ static void dump_directory(void) } } - printf("--\n"); + _LOG("--\n"); } @@ -284,7 +265,7 @@ static void dump_pathtable(void) ISO_DESCRIPTOR *descriptor; char namebuff[16]; - printf("psxcd_dbg: Path table entries:\n"); + _LOG("psxcd: Path table entries:\n"); descriptor = (ISO_DESCRIPTOR*)_cd_iso_descriptor_buff; @@ -298,7 +279,7 @@ static void dump_pathtable(void) tbl_pos+sizeof(ISO_PATHTABLE_ENTRY), tbl_entry->nameLength); - printf("psxcd_dbg: %s\n", namebuff); + _LOG("psxcd: %s\n", namebuff); // Advance to next entry tbl_pos += sizeof(ISO_PATHTABLE_ENTRY) @@ -393,10 +374,8 @@ static int find_dir_entry(const char *name, ISO_DIR_ENTRY *dirent) int dir_pos; ISO_DIR_ENTRY *dir_entry; char namebuff[16]; - -#ifdef DEBUG - printf( "psxcd_dbg: Locating file %s.\n", name ); -#endif + + _LOG("psxcd: Locating file %s.\n", name); i = 0; dir_pos = 0; @@ -489,14 +468,11 @@ CdlFILE *CdSearchFile(CdlFILE *fp, const char *filename) // Read ISO descriptor and path table if( _CdReadIsoDescriptor(0) ) { -#ifdef DEBUG - printf("psxcd: Could not read ISO file system.\n"); -#endif + _LOG("psxcd: Could not read ISO file system.\n"); return NULL; } -#ifdef DEBUG - // printf("psxcd: ISO file system cache updated.\n"); -#endif + + // _LOG("psxcd: ISO file system cache updated.\n"); // _cd_media_changed = 0; //} @@ -504,25 +480,23 @@ CdlFILE *CdSearchFile(CdlFILE *fp, const char *filename) num_dirs = get_pathtable_entry(0, NULL, NULL); #ifdef DEBUG - printf("psxcd_dbg: Directories in path table: %d\n", num_dirs); + _LOG("psxcd: Directories in path table: %d\n", num_dirs); rbuff = resolve_pathtable_path(num_dirs-1, tpath_rbuff+127); if( !rbuff ) { - printf("psxcd_dbg: Could not resolve path.\n"); + _LOG("psxcd: Could not resolve path.\n"); } else { - printf("psxcd_dbg: Longest path: %s|\n", rbuff); + _LOG("psxcd: Longest path: %s|\n", rbuff); } #endif if( get_pathname(search_path, filename) ) { -#ifdef DEBUG - printf("psxcd_dbg: Search path = %s|\n", search_path); -#endif + _LOG("psxcd: Search path = %s|\n", search_path); } // Search the pathtable for a matching path @@ -530,9 +504,8 @@ CdlFILE *CdSearchFile(CdlFILE *fp, const char *filename) for(i=1; iname, filename); // Add version number if not specified @@ -577,15 +542,12 @@ CdlFILE *CdSearchFile(CdlFILE *fp, const char *filename) if( find_dir_entry(fp->name, &dir_entry) ) { -#ifdef DEBUG - printf("psxcd: Could not find file.\n"); -#endif + _LOG("psxcd: Could not find file.\n"); + return NULL; } - -#ifdef DEBUG - printf("psxcd_dbg: Located file at LBA %d.\n", dir_entry.entryOffs.lsb); -#endif + + _LOG("psxcd: Located file at LBA %d.\n", dir_entry.entryOffs.lsb); CdIntToPos(dir_entry.entryOffs.lsb, &fp->pos); fp->size = dir_entry.entrySize.lsb; @@ -609,14 +571,11 @@ CdlDIR *CdOpenDir(const char* path) // Read ISO descriptor and path table if( _CdReadIsoDescriptor( 0 ) ) { -#ifdef DEBUG - printf( "psxcd: Could not read ISO file system.\n" ); -#endif + _LOG( "psxcd: Could not read ISO file system.\n" ); return NULL; } -#ifdef DEBUG -// printf( "psxcd: ISO file system cache updated.\n" ); -#endif + +// _LOG( "psxcd: ISO file system cache updated.\n" ); // _cd_media_changed = 0; // } @@ -626,9 +585,8 @@ CdlDIR *CdOpenDir(const char* path) for( i=1; isize = dir_entry->entrySize.lsb; -#ifdef DEBUG - printf("dir_entry->entryLength = %d, ", dir_entry->entryLength); -#endif - + _LOG("dir_entry->entryLength = %d, ", dir_entry->entryLength); + d_dir->_pos += dir_entry->entryLength; - -#ifdef DEBUG - printf("d_dir->_pos = %d\n", d_dir->_pos); -#endif + + _LOG("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 ) @@ -832,19 +779,15 @@ int CdLoadSession(int session) int i; // Seek to specified session -#ifdef DEBUG - printf("psxcd: CdLoadSession(): Seeking to session %d...\n", session); -#endif + _LOG("psxcd: CdLoadSession(): Seeking to session %d...\n", session); CdControl(CdlSetsession, (unsigned char*)&session, (unsigned char*)&resultbuff); if( CdSync(0, 0) == CdlDiskError ) { -#ifdef DEBUG - printf("psxcd: CdLoadSession(): Session seek failed, " + _LOG("psxcd: CdLoadSession(): Session seek failed, " "session does not exist.\n"); - printf("psxcd: CdLoadSession(): Restarting CD-ROM...\n"); -#endif + _LOG("psxcd: CdLoadSession(): Restarting CD-ROM...\n"); // Restart CD-ROM on session seek failure CdControl(CdlNop, 0, 0); @@ -863,9 +806,8 @@ int CdLoadSession(int session) _ses_scanbuff = scanbuff; // Begin scan for an ISO volume descriptor -#ifdef DEBUG - printf("psxcd: CdLoadSession(): Scanning for ISO9660 volume descriptor.\n"); -#endif + _LOG("psxcd: CdLoadSession(): Scanning for ISO9660 volume descriptor.\n"); + i = CdlModeSpeed; CdControl(CdlSetmode, (unsigned char*)&i, 0); CdControl(CdlReadN, 0, (unsigned char*)resultbuff); @@ -877,9 +819,8 @@ int CdLoadSession(int session) if( !_ses_scanfound ) { -#ifdef DEBUG - printf("psxcd: CdLoadSession(): Did not find volume descriptor.\n"); -#endif + _LOG("psxcd: CdLoadSession(): Did not find volume descriptor.\n"); + _cd_iso_error = CdlIsoInvalidFs; CdReadyCallback((CdlCB)ready_oldcb); return -1; @@ -901,16 +842,12 @@ int CdLoadSession(int session) CdSync(0, 0); loc = (CdlLOC*)resultbuff; - -#ifdef DEBUG - printf("psxcd: CdLoadSession(): Session found in %02d:%02d:%02d (LBA=%d)\n", + + _LOG("psxcd: CdLoadSession(): Session found in %02d:%02d:%02d (LBA=%d)\n", btoi(loc->minute), btoi(loc->second), btoi(loc->sector), CdPosToInt(loc)); -#endif - + i = CdPosToInt(loc)-17; -#ifdef DEBUG - printf("psxcd: CdLoadSession(): Session starting at LBA=%d\n", i); -#endif + _LOG("psxcd: CdLoadSession(): Session starting at LBA=%d\n", i); _cd_media_changed = 1; diff --git a/libpsn00b/psxcd/psxcd.c b/libpsn00b/psxcd/psxcd.c index 6340638..ac93376 100644 --- a/libpsn00b/psxcd/psxcd.c +++ b/libpsn00b/psxcd/psxcd.c @@ -20,13 +20,18 @@ volatile int _cd_last_sector_count; int _cd_media_changed; +#ifdef DEBUG +#define _LOG(...) printf(__VA_ARGS__) +#else +#define _LOG(...) +#endif + void _cd_init(void); void _cd_control(unsigned char com, const void *param, int plen); void _cd_wait_ack(void); void _cd_wait(void); -int CdInit(void) -{ +int CdInit(void) { // Sets up CD-ROM hardware and low-level subsystem _cd_init(); @@ -37,14 +42,11 @@ int CdInit(void) CdControl(CdlNop, 0, 0); CdControl(CdlInit, 0, 0); - if( CdSync(0, 0) != CdlDiskError ) - { + if(CdSync(0, 0) != CdlDiskError) { CdControl(CdlDemute, 0, 0); - printf("psxcd: Init Ok!\n"); - } - else - { - printf("psxcd: Error initializing. Bad disc/drive or no disc inserted.\n"); + _LOG("psxcd: setup done\n"); + } else { + _LOG("psxcd: initialization error, bad disc/drive or no disc inserted\n"); } return 1; @@ -319,7 +321,7 @@ static void CdDoRetry() { int cb; - printf( "CdRead: Retrying...\n" ); + _LOG("psxcd: retrying read...\n"); // Stop reading CdControl(CdlPause, 0, 0); diff --git a/libpsn00b/psxetc/interrupts.c b/libpsn00b/psxetc/interrupts.c index 859209a..1b5ac32 100644 --- a/libpsn00b/psxetc/interrupts.c +++ b/libpsn00b/psxetc/interrupts.c @@ -90,7 +90,7 @@ static void _global_dma_handler(void) { } } -/* Callback registration API */ +/* IRQ and DMA handler API */ void *InterruptCallback(int irq, void (*func)(void)) { if ((irq < 0) || (irq >= NUM_IRQ_CHANNELS)) @@ -127,12 +127,12 @@ void *DMACallback(int dma, void (*func)(void)) { // the callback is being registered or removed. The main DMA IRQ dispatcher // is also registered if this is the first DMA callback being configured, // or disabled if it's the last one being removed. - if (func) { + if (!old_callback && func) { DMA_DICR |= (0x10000 << dma) | (1 << 23); if (!(_num_dma_handlers++)) InterruptCallback(3, &_global_dma_handler); - } else { + } else if (old_callback && !func) { if (--_num_dma_handlers) { DMA_DICR &= ~(0x10000 << dma); } else { @@ -158,7 +158,7 @@ int ResetCallback(void) { return -1; EnterCriticalSection(); - _saved_irq_mask = 1 << 3; // Enable DMA IRQ by default + _saved_irq_mask = 0; _saved_dma_dpcr = 0x03333333; _saved_dma_dicr = 0; @@ -167,10 +167,6 @@ int ResetCallback(void) { for (int i = 0; i < NUM_DMA_CHANNELS; i++) _dma_handlers[i] = (void *) 0; - // Set up the DMA IRQ handler. This handler shall *not* be overridden using - // InterruptCallback(). - _irq_handlers[3] = &_global_dma_handler; - _96_remove(); RestartCallback(); return 0; diff --git a/libpsn00b/psxgpu/common.c b/libpsn00b/psxgpu/common.c index cef1508..e06c63a 100644 --- a/libpsn00b/psxgpu/common.c +++ b/libpsn00b/psxgpu/common.c @@ -29,7 +29,13 @@ static volatile uint8_t _queue_head, _queue_tail, _queue_length; static volatile uint32_t _vblank_counter; static volatile uint16_t _last_hblank; -/* Interrupt handlers */ +/* Private utilities and interrupt handlers */ + +#ifdef DEBUG +#define _LOG(...) printf(__VA_ARGS__) +#else +#define _LOG(...) +#endif static void _vblank_handler(void) { _vblank_counter++; @@ -69,7 +75,7 @@ void ResetGraph(int mode) { _gpu_video_mode = (GPU_GP1 >> 20) & 1; ExitCriticalSection(); - printf("psxgpu: setup done, default mode is %s\n", _gpu_video_mode ? "PAL" : "NTSC"); + _LOG("psxgpu: setup done, default mode is %s\n", _gpu_video_mode ? "PAL" : "NTSC"); } if (mode == 3) { @@ -108,7 +114,7 @@ static void _default_vsync_halt(void) { return; } - printf("psxgpu: VSync() timeout\n"); + _LOG("psxgpu: VSync() timeout\n"); ChangeClearPAD(0); ChangeClearRCnt(3, 0); } @@ -230,7 +236,7 @@ void DrawOTag(const uint32_t *ot) { } IRQ_MASK = mask; - printf("psxgpu: DrawOTag() failed, draw queue full\n"); + _LOG("psxgpu: DrawOTag() failed, draw queue full\n"); return; } diff --git a/libpsn00b/psxgpu/image.c b/libpsn00b/psxgpu/image.c index da51e7d..6190c7a 100644 --- a/libpsn00b/psxgpu/image.c +++ b/libpsn00b/psxgpu/image.c @@ -10,7 +10,13 @@ #define DMA_CHUNK_LENGTH 8 -/* VRAM transfer API */ +/* Private utilities */ + +#ifdef DEBUG +#define _LOG(...) printf(__VA_ARGS__) +#else +#define _LOG(...) +#endif static void _load_store_image( uint32_t command, @@ -20,11 +26,11 @@ static void _load_store_image( ) { size_t length = rect->w * rect->h; if (length % 2) - printf("psxgpu: can't transfer an odd number of pixels\n"); + _LOG("psxgpu: can't transfer an odd number of pixels\n"); length /= 2; if ((length >= DMA_CHUNK_LENGTH) && (length % DMA_CHUNK_LENGTH)) { - printf("psxgpu: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); + _LOG("psxgpu: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); length += DMA_CHUNK_LENGTH - 1; } @@ -50,6 +56,8 @@ static void _load_store_image( DMA_CHCR(2) = 0x01000200 | ((mode & 1) ^ 1); } +/* VRAM transfer API */ + void LoadImage(const RECT *rect, const uint32_t *data) { _load_store_image(0xa0000000, 2, rect, (uint32_t *) data); } diff --git a/libpsn00b/psxpress/mdec.c b/libpsn00b/psxpress/mdec.c index 9c82d6b..53c596e 100644 --- a/libpsn00b/psxpress/mdec.c +++ b/libpsn00b/psxpress/mdec.c @@ -10,7 +10,7 @@ #include #define DMA_CHUNK_LENGTH 32 -#define MDEC_SYNC_TIMEOUT 0x1000000 +#define MDEC_SYNC_TIMEOUT 0x100000 /* Default IDCT matrix and quantization tables */ @@ -81,6 +81,14 @@ static const DECDCTENV _default_mdec_env = { } }; +/* Private utilities */ + +#ifdef DEBUG +#define _LOG(...) printf(__VA_ARGS__) +#else +#define _LOG(...) +#endif + /* Public API */ void DecDCTReset(int mode) { @@ -127,7 +135,7 @@ void DecDCTin(const uint32_t *data, int mode) { // the stream. void DecDCTinRaw(const uint32_t *data, size_t length) { if ((length >= DMA_CHUNK_LENGTH) && (length % DMA_CHUNK_LENGTH)) { - printf("psxmdec: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); + _LOG("psxpress: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); length += DMA_CHUNK_LENGTH - 1; } @@ -149,7 +157,7 @@ int DecDCTinSync(int mode) { return 0; } - printf("psxpress: DecDCTinSync() timeout\n"); + _LOG("psxpress: DecDCTinSync() timeout\n"); return -1; } @@ -174,6 +182,6 @@ int DecDCToutSync(int mode) { return 0; } - printf("psxpress: DecDCToutSync() timeout\n"); + _LOG("psxpress: DecDCToutSync() timeout\n"); return -1; } diff --git a/libpsn00b/psxspu/common.c b/libpsn00b/psxspu/common.c index 55a3dba..4809684 100644 --- a/libpsn00b/psxspu/common.c +++ b/libpsn00b/psxspu/common.c @@ -17,7 +17,13 @@ static SPU_TransferMode _transfer_mode = SPU_TRANSFER_BY_DMA; static uint16_t _transfer_addr = WRITABLE_AREA_ADDR; -/* SPU initialization */ +/* Private utilities */ + +#ifdef DEBUG +#define _LOG(...) printf(__VA_ARGS__) +#else +#define _LOG(...) +#endif static void _wait_status(uint16_t mask, uint16_t value) { for (int i = STATUS_TIMEOUT; i; i--) { @@ -25,9 +31,11 @@ static void _wait_status(uint16_t mask, uint16_t value) { return; } - printf("psxspu: status register timeout (0x%04x)\n", SPU_STAT); + _LOG("psxspu: status register timeout (0x%04x)\n", SPU_STAT); } +/* Public API */ + void SpuInit(void) { SPU_CTRL = 0x0000; // SPU disabled _wait_status(0x001f, 0x0000); @@ -75,19 +83,17 @@ void SpuInit(void) { SPU_KEY_ON = 0x00ffffff; SPU_MASTER_VOL_L = 0x3fff; SPU_MASTER_VOL_R = 0x3fff; - SPU_CD_VOL_L = 0x3fff; - SPU_CD_VOL_R = 0x3fff; + SPU_CD_VOL_L = 0x7fff; + SPU_CD_VOL_R = 0x7fff; } -/* SPU RAM transfer API */ - static void _load_store_data(uint32_t *data, size_t length, int mode) { if (length % 4) - printf("psxspu: can't transfer a number of bytes that isn't multiple of 4\n"); + _LOG("psxspu: can't transfer a number of bytes that isn't multiple of 4\n"); length /= 4; if ((length >= DMA_CHUNK_LENGTH) && (length % DMA_CHUNK_LENGTH)) { - printf("psxspu: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); + _LOG("psxspu: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); length += DMA_CHUNK_LENGTH - 1; } -- cgit v1.2.3 From 82a259240d9c63d4656b9dae0b46a3689840473b Mon Sep 17 00:00:00 2001 From: spicyjpeg Date: Sat, 8 Oct 2022 12:44:34 +0200 Subject: Optimize memset(), add heap usage API, remove _mem_init() --- libpsn00b/include/stdlib.h | 15 +++++- libpsn00b/libc/malloc.c | 62 ++++++++++++++++++--- libpsn00b/libc/memset.s | 132 ++++++++++++++++++++++++++++++++++++++------- libpsn00b/libc/start.c | 25 ++------- 4 files changed, 184 insertions(+), 50 deletions(-) diff --git a/libpsn00b/include/stdlib.h b/libpsn00b/include/stdlib.h index 1888c69..f0753c1 100644 --- a/libpsn00b/include/stdlib.h +++ b/libpsn00b/include/stdlib.h @@ -12,6 +12,16 @@ #define RAND_MAX 0x7fff +/* Structure definitions */ + +typedef struct _HeapUsage { + size_t total; // Total size of heap + stack + size_t heap; // Amount of memory currently reserved for heap + size_t stack; // Amount of memory currently reserved for stack + size_t alloc; // Amount of memory currently allocated + size_t alloc_max; // Maximum amount of memory ever allocated +} HeapUsage; + /* API */ #ifdef __cplusplus @@ -33,11 +43,12 @@ long double strtold(const char *nptr, char **endptr); double strtod(const char *nptr, char **endptr); float strtof(const char *nptr, char **endptr); -void _mem_init(size_t ram_size, size_t stack_max_size); void InitHeap(void *addr, size_t size); -//int SetHeapSize(size_t size); void *sbrk(ptrdiff_t incr); +void TrackHeapUsage(ptrdiff_t alloc_incr); +void GetHeapUsage(HeapUsage *usage); + void *malloc(size_t size); void *calloc(size_t num, size_t size); void *realloc(void *ptr, size_t size); diff --git a/libpsn00b/libc/malloc.c b/libpsn00b/libc/malloc.c index 9d538cd..acac753 100644 --- a/libpsn00b/libc/malloc.c +++ b/libpsn00b/libc/malloc.c @@ -9,6 +9,8 @@ * latter being built on top of the former. This makes it possible to override * only InitHeap() and sbrk() while still using the default allocator, or * override malloc()/realloc()/free() while using the default heap manager. + * Custom allocators should call TrackHeapUsage() to let the heap manager know + * how much memory is allocated at a given time. */ #include @@ -25,11 +27,13 @@ typedef struct _BlockHeader { size_t size; } BlockHeader; -/* Data */ +/* Internal globals */ static void *_heap_start, *_heap_end, *_heap_limit; -static void *_alloc_start = 0; -static BlockHeader *_alloc_head = 0, *_alloc_tail = 0; +static size_t _heap_alloc, _heap_alloc_max; + +static void *_alloc_start; +static BlockHeader *_alloc_head, *_alloc_tail; /* Heap management API */ @@ -37,6 +41,13 @@ __attribute__((weak)) void InitHeap(void *addr, size_t size) { _heap_start = addr; _heap_end = addr; _heap_limit = (void *) ((uintptr_t) addr + size); + + _heap_alloc = 0; + _heap_alloc_max = 0; + + _alloc_start = addr; + _alloc_head = 0; + _alloc_tail = 0; } __attribute__((weak)) void *sbrk(ptrdiff_t incr) { @@ -50,6 +61,22 @@ __attribute__((weak)) void *sbrk(ptrdiff_t incr) { return old_end; } +__attribute__((weak)) void TrackHeapUsage(ptrdiff_t alloc_incr) { + _heap_alloc += alloc_incr; + + if (_heap_alloc > _heap_alloc_max) + _heap_alloc_max = _heap_alloc; +} + +__attribute__((weak)) void GetHeapUsage(HeapUsage *usage) { + usage->total = _heap_limit - _heap_start; + usage->heap = _heap_end - _heap_start; + usage->stack = _heap_limit - _heap_end; + + usage->alloc = _heap_alloc; + usage->alloc_max = _heap_alloc_max; +} + /* Memory allocator */ static BlockHeader *_find_fit(BlockHeader *head, size_t size) { @@ -69,13 +96,16 @@ static BlockHeader *_find_fit(BlockHeader *head, size_t size) { } __attribute__((weak)) void *malloc(size_t size) { + if (!size) + return 0; + size_t _size = _align(size + sizeof(BlockHeader), 8); // Nothing's initialized yet? Let's just initialize the bottom of our heap, // flag it as allocated. if (!_alloc_head) { - if (!_alloc_start) - _alloc_start = sbrk(0); + //if (!_alloc_start) + //_alloc_start = sbrk(0); BlockHeader *new = (BlockHeader *) sbrk(_size); if (!new) @@ -89,6 +119,8 @@ __attribute__((weak)) void *malloc(size_t size) { _alloc_head = new; _alloc_tail = new; + + TrackHeapUsage(_size); return ptr; } @@ -106,6 +138,8 @@ __attribute__((weak)) void *malloc(size_t size) { _alloc_head->prev = new; _alloc_head = new; + + TrackHeapUsage(_size); return ptr; } @@ -122,6 +156,8 @@ __attribute__((weak)) void *malloc(size_t size) { (new->next)->prev = new; prev->next = new; + + TrackHeapUsage(_size); return ptr; } @@ -138,6 +174,8 @@ __attribute__((weak)) void *malloc(size_t size) { _alloc_tail->next = new; _alloc_tail = new; + + TrackHeapUsage(_size); return ptr; } @@ -153,13 +191,14 @@ __attribute__((weak)) void *realloc(void *ptr, size_t size) { if (!ptr) return malloc(size); - size_t _size = _align(size + sizeof(BlockHeader), 8); - + size_t _size = _align(size + sizeof(BlockHeader), 8); BlockHeader *prev = (BlockHeader *) ((uintptr_t) ptr - sizeof(BlockHeader)); // New memory block shorter? if (prev->size >= _size) { + TrackHeapUsage(_size - prev->size); prev->size = _size; + if (!prev->next) sbrk((ptr - sbrk(0)) + _size); @@ -172,12 +211,14 @@ __attribute__((weak)) void *realloc(void *ptr, size_t size) { if (!new) return 0; + TrackHeapUsage(_size - prev->size); prev->size = _size; return ptr; } // Do we have free memory after it? if (((prev->next)->ptr - ptr) > _size) { + TrackHeapUsage(_size - prev->size); prev->size = _size; return ptr; } @@ -209,11 +250,13 @@ __attribute__((weak)) void free(void *ptr) { sbrk(-size); } + TrackHeapUsage(-size); return; } // Finding the proper block BlockHeader *cur = _alloc_head; + for (cur = _alloc_head; ptr != cur->ptr; cur = cur->next) { if (!cur->next) return; @@ -221,14 +264,17 @@ __attribute__((weak)) void free(void *ptr) { if (cur->next) { // In the middle, just unlink it - cur->next->prev = cur->prev; + (cur->next)->prev = cur->prev; + TrackHeapUsage(-(cur->size + sizeof(BlockHeader))); } else { // At the end, shrink heap _alloc_tail = cur->prev; void *top = sbrk(0); size_t size = (top - (cur->prev)->ptr) - (cur->prev)->size; + sbrk(-size); + TrackHeapUsage(-size); } (cur->prev)->next = cur->next; diff --git a/libpsn00b/libc/memset.s b/libpsn00b/libc/memset.s index b3a3af3..5a1589d 100644 --- a/libpsn00b/libc/memset.s +++ b/libpsn00b/libc/memset.s @@ -1,25 +1,117 @@ -# High speed ASM memset implementation by Lameguy64 -# -# Part of PSn00bSDK +# PSn00bSDK optimized memset +# (C) 2022 spicyjpeg - MPL licensed .set noreorder -.section .text - -# Arguments: -# a0 - address to buffer -# a1 - value to set -# a2 - bytes to set +.section .text.memset .global memset -.type memset,@function +.type memset, @function memset: - move $v0, $a0 - blez $a2, .Lexit - addi $a2, -1 - sb $a1, 0($a0) - b memset - addiu $a0, 1 -.Lexit: - jr $ra - nop - \ No newline at end of file + # If more than 16 bytes have to be written then take the "large" path, + # otherwise use the code below. + addiu $t0, $a2, -16 + bgtz $t0, .Llarge_fill + move $v0, $a0 # return_value = dest + + # Jump to one of the sb opcodes below. This is basically a cut-down Duff's + # device implementation with no looping. + la $t0, .Lsmall_duff + 0x40 # jump_addr = &small_duff[(16 - count) * 4] + sll $t1, $a2, 2 + subu $t0, $t1 + addu $a0, $a2 # dest -= 16 - count + jr $t0 + addiu $a0, -16 + +.Lsmall_duff: + sb $a1, 0x0($a0) + sb $a1, 0x1($a0) + sb $a1, 0x2($a0) + sb $a1, 0x3($a0) + sb $a1, 0x4($a0) + sb $a1, 0x5($a0) + sb $a1, 0x6($a0) + sb $a1, 0x7($a0) + sb $a1, 0x8($a0) + sb $a1, 0x9($a0) + sb $a1, 0xa($a0) + sb $a1, 0xb($a0) + sb $a1, 0xc($a0) + sb $a1, 0xd($a0) + sb $a1, 0xe($a0) + jr $ra + sb $a1, 0xf($a0) + +.Llarge_fill: + # Initialize fast filling by repeating the fill byte 4 times, so it can be + # written 32 bits at a time. + andi $a1, 0xff # ch &= 0xff + sll $t0, $a1, 8 # ch |= (ch << 8) | (ch << 16) | (ch << 24) + or $a1, $t0 + sll $t0, $a1, 16 + or $a1, $t0 + + # Fill the first 1-4 bytes (here the swr instruction does all the magic) + # and update dest and count accordingly. + swr $a1, 0($a0) + andi $t0, $a0, 3 # align = 4 - (dest % 4) + addiu $t0, -4 + addu $a2, $t0 # count -= align + subu $a0, $t0 # dest += align + + la $t1, .Llarge_duff + andi $t2, $a2, 3 # remainder = count % 4 + subu $a2, $t2 # count -= remainder + +.Llarge_fill_loop: + # If 128 bytes or more still have to be written, skip calculating the jump + # offset and execute the whole block of sw opcodes. + addiu $a2, -0x80 # count -= 0x80 + bgez $a2, .Llarge_duff + #nop + + # Jump to one of the sw opcodes below. This is the "full" Duff's device. + subu $t0, $t1, $a2 # jump_addr = &large_duff[0x80 - (count + 0x80)] + jr $t0 + addu $a0, $a2 # dest -= 0x80 - (count + 0x80) + +.Llarge_duff: + sw $a1, 0x00($a0) + sw $a1, 0x04($a0) + sw $a1, 0x08($a0) + sw $a1, 0x0c($a0) + sw $a1, 0x10($a0) + sw $a1, 0x14($a0) + sw $a1, 0x18($a0) + sw $a1, 0x1c($a0) + sw $a1, 0x20($a0) + sw $a1, 0x24($a0) + sw $a1, 0x28($a0) + sw $a1, 0x2c($a0) + sw $a1, 0x30($a0) + sw $a1, 0x34($a0) + sw $a1, 0x38($a0) + sw $a1, 0x3c($a0) + sw $a1, 0x40($a0) + sw $a1, 0x44($a0) + sw $a1, 0x48($a0) + sw $a1, 0x4c($a0) + sw $a1, 0x50($a0) + sw $a1, 0x54($a0) + sw $a1, 0x58($a0) + sw $a1, 0x5c($a0) + sw $a1, 0x60($a0) + sw $a1, 0x64($a0) + sw $a1, 0x68($a0) + sw $a1, 0x6c($a0) + sw $a1, 0x70($a0) + sw $a1, 0x74($a0) + sw $a1, 0x78($a0) + sw $a1, 0x7c($a0) + + bgtz $a2, .Llarge_fill_loop + addiu $a0, 0x80 # dest += 0x80 + + # Fill the remaining 1-4 bytes, using (again) an unaligned store. + addu $a0, $t2 # last_byte = dest + remainder - 1 + jr $ra + swl $a1, -1($a0) diff --git a/libpsn00b/libc/start.c b/libpsn00b/libc/start.c index 87ac951..9ff09c8 100644 --- a/libpsn00b/libc/start.c +++ b/libpsn00b/libc/start.c @@ -21,7 +21,7 @@ const char **__argv; static const char *_argv_buffer[ARGC_MAX]; static char _arg_string_buffer[132]; -static void _parse_kernel_args() { +static void _parse_kernel_args(void) { // Copy the argument string from kernel memory into a private buffer (which // won't be cleared or deallocated) and trim it at the first newline. memset(_arg_string_buffer, 0, 132); @@ -48,7 +48,7 @@ static void _parse_kernel_args() { } } -/* Heap initialization */ +/* Main */ // These are defined by the linker script. Note that these are *NOT* pointers, // they are virtual symbols whose location matches their value. The simplest @@ -58,20 +58,6 @@ extern uint8_t __bss_start[]; extern uint8_t _end[]; //extern uint8_t _gp[]; -// This function should not be called manually in most cases. It might be -// useful though to change the stack size and/or reinitialize the heap on -// systems that have more than 2 MB of RAM (e.g. emulators, devkits, PS1-based -// arcade boards). -void _mem_init(size_t ram_size, size_t stack_max_size) { - void *exe_end = _end + 4; - size_t exe_size = (size_t) exe_end - (size_t) __text_start; - size_t ram_used = (0x10000 + exe_size + stack_max_size) & 0xfffffffc; - - InitHeap(exe_end, ram_size - ram_used); -} - -/* Main */ - extern void (*__CTOR_LIST__[])(void); extern void (*__DTOR_LIST__[])(void); @@ -88,10 +74,9 @@ void _start_inner(int32_t override_argc, const char **override_argv) { for (uint32_t *i = (uint32_t *) __bss_start; i < (uint32_t *) _end; i++) *i = 0; - // Initialize the heap, assuming 2 MB of RAM and reserving 128 KB for the - // stack. Note that _mem_init() can be called again in main() to change - // these values. - _mem_init(0x200000, 0x20000); + // Initialize the heap and place it after the executable, assuming 2 MB of + // RAM. Note that InitHeap() can be called again in main(). + InitHeap((void *) _end + 4, (void *) 0x801ffff8 - (void *) _end); if (override_argv) { __argc = override_argc; -- cgit v1.2.3 From 1b1e9b85a51444751dddc0e94a09d19bd4f0885e Mon Sep 17 00:00:00 2001 From: spicyjpeg Date: Sun, 9 Oct 2022 20:26:25 +0200 Subject: Refactor CMake scripts, add separate debug/release builds --- CMakeLists.txt | 40 ++++-- examples/lowlevel/cartrom/CMakeLists.txt | 2 +- indev/psxpad/makefile | 39 ------ libpsn00b/CMakeLists.txt | 57 ++++---- libpsn00b/cmake/flags.cmake | 96 +++++-------- libpsn00b/cmake/internal_setup.cmake | 230 ++++++++++++++++--------------- libpsn00b/cmake/sdk.cmake | 9 +- 7 files changed, 216 insertions(+), 257 deletions(-) delete mode 100644 indev/psxpad/makefile diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f255a2..bb6c5ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ include(ExternalProject) project( PSn00bSDK LANGUAGES NONE - VERSION 0.20 + VERSION 0.21 DESCRIPTION "Open source PlayStation 1 SDK" HOMEPAGE_URL "http://lameguy64.net/?page=psn00bsdk" ) @@ -89,11 +89,17 @@ set( -DPSN00BSDK_BUILD_DATE:STRING=${PSN00BSDK_BUILD_DATE} -DPSN00BSDK_GIT_TAG:STRING=${PSN00BSDK_GIT_TAG} -DPSN00BSDK_GIT_COMMIT:STRING=${PSN00BSDK_GIT_COMMIT} - -DMKPSXISO_NO_LIBFLAC:BOOL=${MKPSXISO_NO_LIBFLAC} +) +set( + _tools_args + ${_common_args} + -DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_TOOLCHAIN_FILE} + -DCMAKE_INSTALL_PREFIX:PATH=${PROJECT_BINARY_DIR}/tree -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} + -DMKPSXISO_NO_LIBFLAC:BOOL=${MKPSXISO_NO_LIBFLAC} ) set( - _sdk_args + _libpsn00b_args ${_common_args} -DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_TOOLCHAIN_FILE} -DCMAKE_INSTALL_PREFIX:PATH=${PROJECT_BINARY_DIR}/tree @@ -103,6 +109,7 @@ set( ${_common_args} -DCMAKE_TOOLCHAIN_FILE:FILEPATH=${PROJECT_BINARY_DIR}/tree/${CMAKE_INSTALL_LIBDIR}/libpsn00b/cmake/sdk.cmake -DCMAKE_INSTALL_PREFIX:PATH=${PROJECT_BINARY_DIR}/examples + -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} ) # Ensure PSn00bSDK isn't being built using the toolchain file from PSn00bSDK @@ -120,35 +127,42 @@ endif() ExternalProject_Add( tools + PREFIX subprojects SOURCE_DIR ${PROJECT_SOURCE_DIR}/tools - BINARY_DIR tools-build - CMAKE_CACHE_ARGS ${_sdk_args} + CMAKE_CACHE_ARGS ${_tools_args} INSTALL_DIR tree ) ExternalProject_Add( mkpsxiso + PREFIX subprojects SOURCE_DIR ${PROJECT_SOURCE_DIR}/tools/mkpsxiso - BINARY_DIR mkpsxiso-build - CMAKE_CACHE_ARGS ${_sdk_args} + CMAKE_CACHE_ARGS ${_tools_args} + INSTALL_DIR tree +) +ExternalProject_Add( + libpsn00b-debug + PREFIX subprojects + SOURCE_DIR ${PROJECT_SOURCE_DIR}/libpsn00b + CMAKE_GENERATOR ${LIBPSN00B_GENERATOR} + CMAKE_CACHE_ARGS ${_libpsn00b_args} -DCMAKE_BUILD_TYPE:STRING=Debug INSTALL_DIR tree ) ExternalProject_Add( - libpsn00b + libpsn00b-release + PREFIX subprojects SOURCE_DIR ${PROJECT_SOURCE_DIR}/libpsn00b - BINARY_DIR libpsn00b-build CMAKE_GENERATOR ${LIBPSN00B_GENERATOR} - CMAKE_CACHE_ARGS ${_sdk_args} + CMAKE_CACHE_ARGS ${_libpsn00b_args} -DCMAKE_BUILD_TYPE:STRING=Release INSTALL_DIR tree - #DEPENDS tools ) ExternalProject_Add( examples + PREFIX subprojects SOURCE_DIR ${PROJECT_SOURCE_DIR}/examples - BINARY_DIR examples-build CMAKE_GENERATOR ${LIBPSN00B_GENERATOR} CMAKE_CACHE_ARGS ${_examples_args} INSTALL_DIR examples - DEPENDS libpsn00b tools mkpsxiso + DEPENDS libpsn00b-debug libpsn00b-release tools mkpsxiso EXCLUDE_FROM_ALL ${SKIP_EXAMPLES} ) diff --git a/examples/lowlevel/cartrom/CMakeLists.txt b/examples/lowlevel/cartrom/CMakeLists.txt index 7d5e86e..2efe6cf 100644 --- a/examples/lowlevel/cartrom/CMakeLists.txt +++ b/examples/lowlevel/cartrom/CMakeLists.txt @@ -17,7 +17,7 @@ file(GLOB _sources *.c *.s) # executable has to be created manually and converted into raw binary format # (for testing on emulators or flashing to a cheat cartridge). add_executable (cartrom ${_sources}) -target_link_libraries(cartrom psn00bsdk_static_exe) +target_link_libraries(cartrom psn00bsdk_exe_nogprel) set_target_properties(cartrom PROPERTIES PREFIX "" SUFFIX ".elf") target_link_options (cartrom PRIVATE -T${PROJECT_SOURCE_DIR}/rom.ld) diff --git a/indev/psxpad/makefile b/indev/psxpad/makefile deleted file mode 100644 index ab6a733..0000000 --- a/indev/psxpad/makefile +++ /dev/null @@ -1,39 +0,0 @@ -include ../../examples/sdk-common.mk - -TARGET = libpad.elf - -CFILES = $(notdir $(wildcard *.c)) -CPPFILES = $(notdir $(wildcard *.cpp)) -AFILES = $(notdir $(wildcard *.s)) - -OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o)) - -INCLUDE += -LIBDIRS += - -LIBS = -lsiofs -lpsxsio -lpsxetc -lpsxgpu -lpsxgte -lpsxspu -lpsxapi -lc - -CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections -CPPFLAGS = $(CFLAGS) -fno-exceptions -AFLAGS = -g -msoft-float -LDFLAGS = -g -Ttext=0x80010000 -gc-sections -T $(GCC_BASE)/mipsel-unknown-elf/lib/ldscripts/elf32elmip.x - -CC = $(PREFIX)gcc -CXX = $(PREFIX)g++ -AS = $(PREFIX)as -LD = $(PREFIX)ld - -all: $(OFILES) - $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET) - elf2x -q $(TARGET) - -build/%.o: %.c - @mkdir -p $(dir $@) - $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ - -build/%.o: %.s - @mkdir -p $(dir $@) - $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@ - -clean: - rm -rf build $(TARGET) $(TARGET:.elf=.exe) diff --git a/libpsn00b/CMakeLists.txt b/libpsn00b/CMakeLists.txt index a662448..71cc659 100644 --- a/libpsn00b/CMakeLists.txt +++ b/libpsn00b/CMakeLists.txt @@ -13,11 +13,7 @@ project( HOMEPAGE_URL "http://lameguy64.net/?page=psn00bsdk" ) -if(NOT DEFINED PSN00BSDK_LIBGCC) - message(FATAL_ERROR "Failed to obtain information about the GCC toolchain. Check your toolchain settings.") -elseif(PSN00BSDK_LIBGCC STREQUAL "PSN00BSDK_LIBGCC-NOTFOUND") - message(FATAL_ERROR "Failed to find libgcc in the GCC toolchain's files. Check your toolchain settings, or set the path to libgcc using -DPSN00BSDK_LIBGCC.") -endif() +include(${PROJECT_SOURCE_DIR}/cmake/flags.cmake) ## Libraries @@ -31,37 +27,36 @@ foreach(_library IN LISTS PSN00BSDK_LIBRARIES) file( GLOB_RECURSE _sources - ${_path}/*.s - ${_path}/*.c - ${_path}/*.cpp - ${_path}/*.cxx + ${_path}/*.s ${_path}/*.c ${_path}/*.cpp ) - psn00bsdk_add_library(${_library} STATIC ${_sources}) -endforeach() + foreach(_suffix IN ITEMS _exe_nogprel _exe_gprel _dll) + set(_name ${_library}${_suffix}) + list(APPEND _libraries ${_name}) -psn00bsdk_target_incbin(psxgpu PRIVATE _gpu_debug_font psxgpu/dbugfont.tim) + psn00bsdk_add_library(${_name} STATIC ${_sources}) + target_link_libraries(${_name} PUBLIC psn00bsdk${_suffix}) + endforeach() +endforeach() -# Extract libgcc's contents and merge them into libc after building. -# Unfortunately glob expressions won't work on Windows, so we have to manually -# enumerate the contents of libgcc and save the list to a temporary file (as it -# is too long to be passed directly on the command line). This is actually the -# most reliable way I found to do this (I tried $ to no avail). -add_custom_command( - TARGET c POST_BUILD - COMMAND ${CMAKE_AR} t ${PSN00BSDK_LIBGCC} $_libgcc.txt - COMMAND ${CMAKE_AR} x ${PSN00BSDK_LIBGCC} - COMMAND ${CMAKE_AR} q $ \@_libgcc.txt - COMMAND ${CMAKE_AR} s $ - #COMMAND ${CMAKE_AR} rsuU $ *.o - COMMENT "Merging libgcc contents into SDK libc" -) +# Add binary assets to each version of the libraries. +foreach(_suffix IN ITEMS _exe_nogprel _exe_gprel _dll) + psn00bsdk_target_incbin( + psxgpu${_suffix} PRIVATE _gpu_debug_font + psxgpu/dbugfont.tim + ) +endforeach() ## Installation install( - TARGETS ${PSN00BSDK_LIBRARIES} - DESTINATION ${CMAKE_INSTALL_LIBDIR}/libpsn00b + TARGETS + psn00bsdk_common + psn00bsdk_exe_gprel + psn00bsdk_exe_nogprel + psn00bsdk_dll + ${_libraries} + DESTINATION ${CMAKE_INSTALL_LIBDIR}/libpsn00b/$> EXPORT libpsn00b ) install( @@ -95,9 +90,11 @@ install( ) # Generate an import script, which will be used by the setup script to find the -# libraries. +# libraries. Note that CMake actually generates two separate import scripts +# (one setting configuration-specific options), so this won't create conflicts +# once the debug and release builds are merged into the same installation tree. install( EXPORT libpsn00b - DESTINATION ${CMAKE_INSTALL_LIBDIR}/libpsn00b/cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/libpsn00b #EXPORT_LINK_INTERFACE_LIBRARIES ) diff --git a/libpsn00b/cmake/flags.cmake b/libpsn00b/cmake/flags.cmake index 5d9c751..fea26cd 100644 --- a/libpsn00b/cmake/flags.cmake +++ b/libpsn00b/cmake/flags.cmake @@ -1,40 +1,23 @@ -# libpsn00b interface targets -# (C) 2021 spicyjpeg - MPL licensed +# PSn00bSDK interface targets +# (C) 2021-2022 spicyjpeg - MPL licensed # This script creates several "virtual" targets (psn00bsdk_*) that set include -# directories and compiler flags when a target is linked against them. The -# following targets are currently defined: -# - psn00bsdk_common -# - psn00bsdk_static_exe -# - psn00bsdk_dynamic_exe -# - psn00bsdk_static_lib -# - psn00bsdk_object_lib (same as psn00bsdk_static_lib) -# - psn00bsdk_shared_lib -# - psn00bsdk_module_lib (same as psn00bsdk_shared_lib) -# -# NOTE: building a static library and linking it as part of a DLL is currently -# *not* supported. +# directories and compiler flags when a target is linked against them. It is +# only used when building libpsn00b, as CMake automatically saves these targets +# into the export script once libpsn00b is installed. -if(NOT TARGET psn00bsdk_common) # Include guard +## Options common to all target types -add_library(psn00bsdk_common INTERFACE) - -foreach( - _target IN ITEMS - static_exe dynamic_exe static_lib object_lib shared_lib module_lib -) - add_library (psn00bsdk_${_target} INTERFACE) - target_link_libraries(psn00bsdk_${_target} INTERFACE psn00bsdk_common) -endforeach() - -# Options common to all target types: -# - Define PLAYSTATION=1 +# - Define PSN00BSDK=1 +# - Always generate debug symbols (stripped by elf2x) # - Optimize for MIPS R3000 # - Inject zero checks into division operations (will throw breaks) # - All standard libraries (including libgcc) disabled # - Put all symbols into separate sections when building # - C++ features that require runtime support disabled # - Unused section stripping enabled + +add_library(psn00bsdk_common INTERFACE) target_compile_options( psn00bsdk_common INTERFACE # CPU options @@ -52,6 +35,7 @@ target_compile_options( -nostdlib # Other options -g + -Wa,--strip-local-absolute -fdata-sections -ffunction-sections -fsigned-char @@ -73,16 +57,20 @@ target_link_options( ) target_compile_definitions( psn00bsdk_common INTERFACE - PLAYSTATION=1 + PSN00BSDK=1 $<$:DEBUG=1> ) -# Options for executables without support for dynamic linking: +## Options for executables without support for dynamic linking + # - Position-independent code disabled -# - GP-relative addressing enabled only for local symbols -# - ABI-compatible calls disabled (incompatible with GP-relative addr) +# - $gp-relative addressing enabled only for local symbols +# - ABI-compatible calls disabled (incompatible with $gp-relative addressing) + +add_library(psn00bsdk_exe_gprel INTERFACE) +target_link_libraries(psn00bsdk_exe_gprel INTERFACE psn00bsdk_common) target_compile_options( - psn00bsdk_static_exe INTERFACE + psn00bsdk_exe_gprel INTERFACE -G8 -fno-pic -mno-abicalls @@ -90,50 +78,42 @@ target_compile_options( -mno-extern-sdata ) target_link_options( - psn00bsdk_static_exe INTERFACE + psn00bsdk_exe_gprel INTERFACE -G8 -static ) -# Options for executables with support for dynamic linking: +## Options for executables with support for dynamic linking + # - Position-independent code disabled -# - GP-relative addressing disabled +# - $gp-relative addressing disabled # - ABI-compatible calls disabled (must be performed manually) + +add_library(psn00bsdk_exe_nogprel INTERFACE) +target_link_libraries(psn00bsdk_exe_nogprel INTERFACE psn00bsdk_common) target_compile_options( - psn00bsdk_dynamic_exe INTERFACE + psn00bsdk_exe_nogprel INTERFACE -G0 -fno-pic -mno-abicalls -mno-gpopt ) target_link_options( - psn00bsdk_dynamic_exe INTERFACE + psn00bsdk_exe_nogprel INTERFACE -G0 -static ) -# Options for static libraries: -# - Position-independent code disabled -# - GP-relative addressing disabled -# - ABI-compatible calls disabled -# - Local stripping enabled -target_compile_options( - psn00bsdk_static_lib INTERFACE - -G0 - -fno-pic - -mno-abicalls - -mno-gpopt - -Wa,--strip-local-absolute -) - -target_link_libraries(psn00bsdk_object_lib INTERFACE psn00bsdk_static_lib) +## Options for dynamically-linked libraries -# Options for dynamically-loaded libraries: # - Position-independent code enabled -# - GP-relative addressing disabled (incompatible with ABI calls) +# - $gp-relative addressing disabled (incompatible with ABI calls) # - ABI-compatible calls enabled + +add_library(psn00bsdk_dll INTERFACE) +target_link_libraries(psn00bsdk_dll INTERFACE psn00bsdk_common) target_compile_options( - psn00bsdk_shared_lib INTERFACE + psn00bsdk_dll INTERFACE -G0 -fPIC -mabicalls @@ -141,11 +121,7 @@ target_compile_options( -mshared ) target_link_options( - psn00bsdk_shared_lib INTERFACE + psn00bsdk_dll INTERFACE -G0 -shared ) - -target_link_libraries(psn00bsdk_module_lib INTERFACE psn00bsdk_shared_lib) - -endif() diff --git a/libpsn00b/cmake/internal_setup.cmake b/libpsn00b/cmake/internal_setup.cmake index d293127..e9f0db5 100644 --- a/libpsn00b/cmake/internal_setup.cmake +++ b/libpsn00b/cmake/internal_setup.cmake @@ -1,5 +1,5 @@ # PSn00bSDK internal setup script for CMake -# (C) 2021 spicyjpeg - MPL licensed +# (C) 2021-2022 spicyjpeg - MPL licensed # This script is included automatically when using the toolchain file and # defines helper functions. @@ -7,6 +7,10 @@ cmake_minimum_required(VERSION 3.20) include(GNUInstallDirs) +# Re-enable support for dynamic linking as CMake's "Generic" system type +# disables it. +set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS ON) + # Fetch SDK version information from build.json. if(NOT DEFINED PSN00BSDK_VERSION) file(READ ${CMAKE_CURRENT_LIST_DIR}/../build.json _json) @@ -17,13 +21,9 @@ if(NOT DEFINED PSN00BSDK_VERSION) string(JSON PSN00BSDK_GIT_COMMIT GET ${_json} git_commit) endif() -## Settings (can be overridden by projects) - -set(PSN00BSDK_EXECUTABLE_SUFFIX ".exe") -set(PSN00BSDK_SHARED_LIBRARY_SUFFIX ".dll") -set(PSN00BSDK_SYMBOL_MAP_SUFFIX ".map") +include(${CMAKE_CURRENT_LIST_DIR}/../libpsn00b.cmake OPTIONAL) -## SDK libraries +## Settings (can be overridden by projects) # DON'T CHANGE THE ORDER or you'll break the libraries' internal dependencies. set( @@ -40,33 +40,23 @@ set( c ) -include(${CMAKE_CURRENT_LIST_DIR}/libpsn00b.cmake OPTIONAL) -include(${CMAKE_CURRENT_LIST_DIR}/flags.cmake) +set(PSN00BSDK_EXECUTABLE_LINK_LIBRARIES ${PSN00BSDK_LIBRARIES}) +set(PSN00BSDK_SHARED_LIBRARY_LINK_LIBRARIES "") -# Use the toolchain path to find libgcc (used to build libpsn00b). Of course -# different installers, packages and distros have different opinions when it -# comes to deciding where to install toolchains, so we have to bruteforce -# multiple combinations of paths. -if(CMAKE_C_COMPILER_VERSION) - string(REGEX MATCH "^([0-9]+)\." _dummy ${CMAKE_C_COMPILER_VERSION}) +set(PSN00BSDK_EXECUTABLE_SUFFIX ".exe") +set(PSN00BSDK_SHARED_LIBRARY_SUFFIX ".dll") +set(PSN00BSDK_SYMBOL_MAP_SUFFIX ".map") - find_library( - PSN00BSDK_LIBGCC gcc - HINTS - ${PSN00BSDK_TC}/lib/gcc-cross/${PSN00BSDK_TARGET}/${CMAKE_C_COMPILER_VERSION} - ${PSN00BSDK_TC}/lib/gcc-cross/${PSN00BSDK_TARGET}/${CMAKE_MATCH_1} - ${PSN00BSDK_TC}/lib/gcc/${PSN00BSDK_TARGET}/${CMAKE_C_COMPILER_VERSION} - ${PSN00BSDK_TC}/lib/gcc/${PSN00BSDK_TARGET}/${CMAKE_MATCH_1} - ${PSN00BSDK_TC}/../lib/gcc-cross/${PSN00BSDK_TARGET}/${CMAKE_C_COMPILER_VERSION} - ${PSN00BSDK_TC}/../lib/gcc-cross/${PSN00BSDK_TARGET}/${CMAKE_MATCH_1} - ${PSN00BSDK_TC}/../lib/gcc/${PSN00BSDK_TARGET}/${CMAKE_C_COMPILER_VERSION} - ${PSN00BSDK_TC}/../lib/gcc/${PSN00BSDK_TARGET}/${CMAKE_MATCH_1} - NO_DEFAULT_PATH - DOC "Path to libgcc (bundled with the GCC toolchain)" - ) +## Include paths + +set(PSN00BSDK_LDSCRIPTS ${CMAKE_CURRENT_LIST_DIR}/../ldscripts) +if(IS_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../include) + set(PSN00BSDK_INCLUDE ${CMAKE_CURRENT_LIST_DIR}/../include) +else() + set(PSN00BSDK_INCLUDE ${CMAKE_CURRENT_LIST_DIR}/../../../include/libpsn00b) endif() -## Tools +## Tool paths set( PSN00BSDK_TOOLS @@ -80,26 +70,41 @@ find_program(SMXLINK smxlink HINTS ${PSN00BSDK_TOOLS}) find_program(LZPACK lzpack HINTS ${PSN00BSDK_TOOLS}) find_program(MKPSXISO mkpsxiso HINTS ${PSN00BSDK_TOOLS}) -## Helper functions for executables +## libgcc -set(PSN00BSDK_LDSCRIPTS ${CMAKE_CURRENT_LIST_DIR}/../ldscripts) -if(IS_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../include) - set(PSN00BSDK_INCLUDE ${CMAKE_CURRENT_LIST_DIR}/../include) -else() - set(PSN00BSDK_INCLUDE ${CMAKE_CURRENT_LIST_DIR}/../../../include/libpsn00b) -endif() +# Use the toolchain path to find libgcc. Of course different installers, +# packages and distros have different opinions when it comes to deciding where +# to install toolchains, so we have to bruteforce multiple combinations of +# paths. +if(CMAKE_C_COMPILER_VERSION) + string(REGEX MATCH "^([0-9]+)\." _dummy ${CMAKE_C_COMPILER_VERSION}) -# psn00bsdk_add_executable( -# -# [EXCLUDE_FROM_ALL] -# ... -# ) -function(psn00bsdk_add_executable name type) - string(TOLOWER ${type} _type) - if(NOT ${_type} MATCHES "^(static|dynamic)$") - message(FATAL_ERROR "Invalid executable type: ${type} (must be STATIC or DYNAMIC)") + find_library( + PSN00BSDK_LIBGCC gcc #REQUIRED + HINTS + ${PSN00BSDK_TC}/lib/gcc-cross/${PSN00BSDK_TARGET}/${CMAKE_C_COMPILER_VERSION} + ${PSN00BSDK_TC}/lib/gcc-cross/${PSN00BSDK_TARGET}/${CMAKE_MATCH_1} + ${PSN00BSDK_TC}/lib/gcc/${PSN00BSDK_TARGET}/${CMAKE_C_COMPILER_VERSION} + ${PSN00BSDK_TC}/lib/gcc/${PSN00BSDK_TARGET}/${CMAKE_MATCH_1} + ${PSN00BSDK_TC}/../lib/gcc-cross/${PSN00BSDK_TARGET}/${CMAKE_C_COMPILER_VERSION} + ${PSN00BSDK_TC}/../lib/gcc-cross/${PSN00BSDK_TARGET}/${CMAKE_MATCH_1} + ${PSN00BSDK_TC}/../lib/gcc/${PSN00BSDK_TARGET}/${CMAKE_C_COMPILER_VERSION} + ${PSN00BSDK_TC}/../lib/gcc/${PSN00BSDK_TARGET}/${CMAKE_MATCH_1} + NO_DEFAULT_PATH + DOC "Path to libgcc (bundled with the GCC toolchain)" + ) + if(PSN00BSDK_LIBGCC STREQUAL "PSN00BSDK_LIBGCC-NOTFOUND") + message(FATAL_ERROR "Failed to find libgcc in the GCC toolchain's files. Check your toolchain settings, or set the path to libgcc using -DPSN00BSDK_LIBGCC.") endif() + add_library(gcc STATIC IMPORTED) + set_property(TARGET gcc PROPERTY IMPORTED_LOCATION ${PSN00BSDK_LIBGCC}) + link_libraries(gcc) +endif() + +## Target helpers + +function(psn00bsdk_add_executable name type) # Throw an error if elf2x was not found (which should never happen if the # SDK is installed properly). if(ELF2X STREQUAL "ELF2X-NOTFOUND") @@ -107,10 +112,10 @@ function(psn00bsdk_add_executable name type) endif() add_executable (${name} ${ARGN}) - target_link_libraries(${name} psn00bsdk_${_type}_exe ${PSN00BSDK_LIBRARIES}) set_target_properties(${name} PROPERTIES PREFIX "" SUFFIX ".elf") target_link_options (${name} PRIVATE -T${PSN00BSDK_LDSCRIPTS}/exe.ld) + psn00bsdk_target_link_sdk (${name} PRIVATE EXECUTABLE ${type} ${PSN00BSDK_EXECUTABLE_LINK_LIBRARIES}) target_include_directories(${name} PRIVATE ${PSN00BSDK_INCLUDE}) # Add post-build steps to generate the .exe and symbol map once the @@ -123,30 +128,26 @@ function(psn00bsdk_add_executable name type) ) endfunction() -# psn00bsdk_add_library( -# -# [EXCLUDE_FROM_ALL] -# ... -# ) -# Note that SHARED and MODULE have the same meaning (both will create a DLL). -# SDK libraries are NOT statically linked in by default; if you need to link -# something, use target_link_libraries() manually. function(psn00bsdk_add_library name type) - string(TOUPPER ${type} _type_upper) - string(TOLOWER ${type} _type) - if(NOT ${_type} MATCHES "^(static|object|shared|module)$") - message(FATAL_ERROR "Invalid library type: ${type} (must be STATIC, OBJECT, SHARED or MODULE)") - endif() + string(TOUPPER ${type} _type) - add_library (${name} ${_type_upper} ${ARGN}) - target_link_libraries(${name} psn00bsdk_${_type}_lib) - - target_include_directories(${name} PRIVATE ${PSN00BSDK_INCLUDE}) + if(_type MATCHES "^(STATIC|OBJECT)$") + # Remove virtual target dependencies to make sure linking against the + # library does not also propagate static library flags. + add_library (${name} ${_type} ${ARGN}) + set_target_properties(${name} PROPERTIES PREFIX "lib" SUFFIX ".a") + set_target_properties(${name} PROPERTIES INTERFACE_LINK_LIBRARIES "") + target_link_libraries(${name} PRIVATE psn00bsdk_common) - if(${_type} MATCHES "^(shared|module)$") + target_include_directories(${name} PRIVATE ${PSN00BSDK_INCLUDE}) + elseif(_type MATCHES "^(SHARED|MODULE)$") + add_library (${name} ${_type} ${ARGN}) set_target_properties(${name} PROPERTIES PREFIX "" SUFFIX ".so") target_link_options (${name} PRIVATE -T${PSN00BSDK_LDSCRIPTS}/dll.ld) + psn00bsdk_target_link_sdk (${name} PRIVATE SHARED_LIBRARY ${PSN00BSDK_SHARED_LIBRARY_LINK_LIBRARIES}) + target_include_directories(${name} PRIVATE ${PSN00BSDK_INCLUDE}) + # Add a post-build step to dump the DLL's raw contents into a new file # separate from the built ELF. add_custom_command( @@ -155,63 +156,48 @@ function(psn00bsdk_add_library name type) BYPRODUCTS ${name}${PSN00BSDK_SHARED_LIBRARY_SUFFIX} ) else() - set_target_properties(${name} PROPERTIES PREFIX "lib" SUFFIX ".a") - - # Remove virtual target dependencies to make sure linking against the - # library does not also propagate static library flags. - set_target_properties(${name} PROPERTIES INTERFACE_LINK_LIBRARIES "") + message(FATAL_ERROR "Invalid library type: ${type} (must be STATIC, OBJECT, SHARED or MODULE)") endif() endfunction() -# psn00bsdk_add_cd_image( -# -# -# -# [DEPENDS ...] -# [additional options passed to add_custom_target()] -# ) -function(psn00bsdk_add_cd_image name image_name config_file) - # Throw an error if mkpsxiso was not found. Performing this check manually - # (instead of just marking mkpsxiso as required) allows simple projects to - # be built even if mkpsxiso is not installed. - if(MKPSXISO STREQUAL "MKPSXISO-NOTFOUND") - message(FATAL_ERROR "Failed to locate mkpsxiso. If mkpsxiso wasn't installed alongside the SDK, check your PATH environment variable.") +## Linking helpers + +function(psn00bsdk_target_link_sdk name type target_type) + set(_libraries ${ARGN}) + string(TOUPPER ${target_type} _target_type) + + if(_target_type STREQUAL "EXECUTABLE") + list(POP_FRONT _libraries) + string(TOUPPER ${ARGV3} _exe_type) + + if(_exe_type MATCHES "^(STATIC|GPREL)$") + set(_suffix _exe_gprel) + elseif(_exe_type MATCHES "^(DYNAMIC|NOGPREL)$") + set(_suffix _exe_nogprel) + else() + message(FATAL_ERROR "Invalid executable type: ${ARGV3} (must be STATIC, GPREL, DYNAMIC or NOGPREL)") + endif() + elseif(_target_type STREQUAL "SHARED_LIBRARY") + set(_suffix _dll) + else() + message(FATAL_ERROR "Invalid target type: ${target_type} (must be EXECUTABLE or SHARED_LIBRARY)") endif() - cmake_path(HASH config_file _hash) - - set(CD_IMAGE_NAME ${image_name}) - set(CD_CONFIG_FILE cd_image_${_hash}.xml) - configure_file(${config_file} ${CD_CONFIG_FILE}) - - add_custom_target( - ${name} ALL - COMMAND ${MKPSXISO} -y ${CD_CONFIG_FILE} - BYPRODUCTS ${image_name}.bin ${image_name}.cue - COMMENT "Building CD image ${image_name}" - ${ARGN} - ) + list(TRANSFORM _libraries APPEND ${_suffix}) + target_link_libraries(${name} ${type} psn00bsdk${_suffix} ${_libraries}) endfunction() -## Helper functions for assets - -# psn00bsdk_target_incbin_a( -# -# -# -# -# -# -# ) function(psn00bsdk_target_incbin_a name type symbol_name size_name path section align) string(MAKE_C_IDENTIFIER ${symbol_name} _id) string(MAKE_C_IDENTIFIER ${size_name} _size) cmake_path(ABSOLUTE_PATH path OUTPUT_VARIABLE _path) + string(SHA1 _hash "${name} ${_id}") + set(_asm_file ${CMAKE_CURRENT_BINARY_DIR}/incbin_${_hash}.s) + # Generate an assembly source file that includes the binary file and add it # to the target's sources. The file is also added as a depedency to ensure # CMake builds it before the target (if it's not a static file). - set(_asm_file ${PROJECT_BINARY_DIR}/incbin_${name}_${_id}.s) file( CONFIGURE OUTPUT ${_asm_file} @@ -246,11 +232,6 @@ ${_size}: set_source_files_properties(${_asm_file} PROPERTIES OBJECT_DEPENDS ${_path}) endfunction() -# psn00bsdk_target_incbin( -# -# -# -# ) function(psn00bsdk_target_incbin name type symbol_name path) string(MAKE_C_IDENTIFIER ${symbol_name} _id) @@ -264,3 +245,28 @@ function(psn00bsdk_target_incbin name type symbol_name path) 4 ) endfunction() + +## CD image and asset helpers + +function(psn00bsdk_add_cd_image name image_name config_file) + # Throw an error if mkpsxiso was not found. Performing this check manually + # (instead of just marking mkpsxiso as required) allows simple projects to + # be built even if mkpsxiso is not installed. + if(MKPSXISO STREQUAL "MKPSXISO-NOTFOUND") + message(FATAL_ERROR "Failed to locate mkpsxiso. If mkpsxiso wasn't installed alongside the SDK, check your PATH environment variable.") + endif() + + cmake_path(HASH config_file _hash) + + set(CD_IMAGE_NAME ${image_name}) + set(CD_CONFIG_FILE cd_image_${_hash}.xml) + configure_file(${config_file} ${CD_CONFIG_FILE}) + + add_custom_target( + ${name} ALL + COMMAND ${MKPSXISO} -y ${CD_CONFIG_FILE} + BYPRODUCTS ${image_name}.bin ${image_name}.cue + COMMENT "Building CD image ${image_name}" + ${ARGN} + ) +endfunction() diff --git a/libpsn00b/cmake/sdk.cmake b/libpsn00b/cmake/sdk.cmake index 8965e79..37b9fd0 100644 --- a/libpsn00b/cmake/sdk.cmake +++ b/libpsn00b/cmake/sdk.cmake @@ -1,5 +1,5 @@ # PSn00bSDK toolchain setup file for CMake -# (C) 2021 spicyjpeg - MPL licensed +# (C) 2021-2022 spicyjpeg - MPL licensed cmake_minimum_required(VERSION 3.20) @@ -14,7 +14,7 @@ set( ## CMake configuration -set(CMAKE_SYSTEM_NAME PlayStation) +set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_SYSTEM_PROCESSOR mipsel) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) @@ -28,6 +28,11 @@ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES PSN00BSDK_TC PSN00BSDK_TARGET PSN00BSDK_VERSION) +# Always generate compile_commands.json alongside build scripts. This allows +# some IDEs and tools (such as clangd) to automatically configure include +# directories and other options. +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + ## Toolchain path setup # Attempt to find GCC using a list of common installation locations. -- cgit v1.2.3 From 1a468c901a7b473a556c6a572c03c68186f03f89 Mon Sep 17 00:00:00 2001 From: spicyjpeg Date: Tue, 11 Oct 2022 11:17:28 +0200 Subject: Update CMake scripts to use generator expressions --- examples/lowlevel/cartrom/CMakeLists.txt | 10 ++- libpsn00b/CMakeLists.txt | 29 ++++--- libpsn00b/cmake/flags.cmake | 127 ++++++++++------------------ libpsn00b/cmake/internal_setup.cmake | 137 ++++++++++++++++++------------- libpsn00b/cmake/sdk.cmake | 14 ++-- 5 files changed, 156 insertions(+), 161 deletions(-) diff --git a/examples/lowlevel/cartrom/CMakeLists.txt b/examples/lowlevel/cartrom/CMakeLists.txt index 2efe6cf..6a94d9f 100644 --- a/examples/lowlevel/cartrom/CMakeLists.txt +++ b/examples/lowlevel/cartrom/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( cartrom @@ -17,9 +17,13 @@ file(GLOB _sources *.c *.s) # executable has to be created manually and converted into raw binary format # (for testing on emulators or flashing to a cheat cartridge). add_executable (cartrom ${_sources}) -target_link_libraries(cartrom psn00bsdk_exe_nogprel) -set_target_properties(cartrom PROPERTIES PREFIX "" SUFFIX ".elf") target_link_options (cartrom PRIVATE -T${PROJECT_SOURCE_DIR}/rom.ld) +set_target_properties( + cartrom PROPERTIES + PREFIX "" + SUFFIX ".elf" + PSN00BSDK_TARGET_TYPE EXECUTABLE_NOGPREL +) target_include_directories(cartrom PRIVATE ${PROJECT_SOURCE_DIR}) diff --git a/libpsn00b/CMakeLists.txt b/libpsn00b/CMakeLists.txt index 71cc659..602b3c8 100644 --- a/libpsn00b/CMakeLists.txt +++ b/libpsn00b/CMakeLists.txt @@ -1,7 +1,7 @@ # libpsn00b build script -# (C) 2021 spicyjpeg - MPL licensed +# (C) 2021-2022 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) # ${PROJECT_SOURCE_DIR} is not available until project() is called. set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/cmake/sdk.cmake) @@ -17,6 +17,9 @@ include(${PROJECT_SOURCE_DIR}/cmake/flags.cmake) ## Libraries +set(_types EXECUTABLE_GPREL EXECUTABLE_NOGPREL SHARED_LIBRARY) +set(_suffixes _exe_gprel _exe_nogprel _dll) + foreach(_library IN LISTS PSN00BSDK_LIBRARIES) # libc needs special handling due to the different directory name. if(${_library} STREQUAL "c") @@ -30,17 +33,26 @@ foreach(_library IN LISTS PSN00BSDK_LIBRARIES) ${_path}/*.s ${_path}/*.c ${_path}/*.cpp ) - foreach(_suffix IN ITEMS _exe_nogprel _exe_gprel _dll) + # Build a separate version of the library for each supported target type + # and create a virtual target that links the appropriate version of the + # library. + add_library(${_library} INTERFACE) + + foreach(_type _suffix IN ZIP_LISTS _types _suffixes) set(_name ${_library}${_suffix}) list(APPEND _libraries ${_name}) psn00bsdk_add_library(${_name} STATIC ${_sources}) - target_link_libraries(${_name} PUBLIC psn00bsdk${_suffix}) + set_target_properties(${_name} PROPERTIES PSN00BSDK_TARGET_TYPE ${_type}) + target_link_libraries( + ${_library} INTERFACE + $<$>,${_type}>:${_name}> + ) endforeach() endforeach() # Add binary assets to each version of the libraries. -foreach(_suffix IN ITEMS _exe_nogprel _exe_gprel _dll) +foreach(_suffix IN LISTS _suffixes) psn00bsdk_target_incbin( psxgpu${_suffix} PRIVATE _gpu_debug_font psxgpu/dbugfont.tim @@ -50,12 +62,7 @@ endforeach() ## Installation install( - TARGETS - psn00bsdk_common - psn00bsdk_exe_gprel - psn00bsdk_exe_nogprel - psn00bsdk_dll - ${_libraries} + TARGETS psn00bsdk ${PSN00BSDK_LIBRARIES} ${_libraries} DESTINATION ${CMAKE_INSTALL_LIBDIR}/libpsn00b/$> EXPORT libpsn00b ) diff --git a/libpsn00b/cmake/flags.cmake b/libpsn00b/cmake/flags.cmake index fea26cd..e56d3fc 100644 --- a/libpsn00b/cmake/flags.cmake +++ b/libpsn00b/cmake/flags.cmake @@ -6,122 +6,85 @@ # only used when building libpsn00b, as CMake automatically saves these targets # into the export script once libpsn00b is installed. -## Options common to all target types +add_library (psn00bsdk INTERFACE) +link_libraries(psn00bsdk) -# - Define PSN00BSDK=1 -# - Always generate debug symbols (stripped by elf2x) -# - Optimize for MIPS R3000 -# - Inject zero checks into division operations (will throw breaks) -# - All standard libraries (including libgcc) disabled -# - Put all symbols into separate sections when building -# - C++ features that require runtime support disabled -# - Unused section stripping enabled - -add_library(psn00bsdk_common INTERFACE) target_compile_options( - psn00bsdk_common INTERFACE - # CPU options - -msoft-float - -march=r3000 - -mtune=r3000 - -mabi=32 - -mno-mt - -mno-llsc - -mdivide-breaks + psn00bsdk INTERFACE + # Options common to all target types + -g + -Wa,--strip-local-absolute -O2 - # Standard library options -ffreestanding -fno-builtin -nostdlib - # Other options - -g - -Wa,--strip-local-absolute -fdata-sections -ffunction-sections -fsigned-char -fno-strict-overflow -fdiagnostics-color=always + -msoft-float + -march=r3000 + -mtune=r3000 + -mabi=32 + -mno-mt + -mno-llsc + -mdivide-breaks $<$: - # C++ options + # Options common to all target types (C++) -fno-exceptions -fno-rtti -fno-unwind-tables -fno-threadsafe-statics -fno-use-cxa-atexit > -) -target_link_options( - psn00bsdk_common INTERFACE - -nostdlib - -Wl,-gc-sections -) -target_compile_definitions( - psn00bsdk_common INTERFACE - PSN00BSDK=1 - $<$:DEBUG=1> -) - -## Options for executables without support for dynamic linking - -# - Position-independent code disabled -# - $gp-relative addressing enabled only for local symbols -# - ABI-compatible calls disabled (incompatible with $gp-relative addressing) - -add_library(psn00bsdk_exe_gprel INTERFACE) -target_link_libraries(psn00bsdk_exe_gprel INTERFACE psn00bsdk_common) -target_compile_options( - psn00bsdk_exe_gprel INTERFACE + $<$>,EXECUTABLE_GPREL>: + # Options for executables with $gp-relative addressing -G8 -fno-pic -mno-abicalls -mgpopt -mno-extern-sdata -) -target_link_options( - psn00bsdk_exe_gprel INTERFACE - -G8 - -static -) - -## Options for executables with support for dynamic linking - -# - Position-independent code disabled -# - $gp-relative addressing disabled -# - ABI-compatible calls disabled (must be performed manually) - -add_library(psn00bsdk_exe_nogprel INTERFACE) -target_link_libraries(psn00bsdk_exe_nogprel INTERFACE psn00bsdk_common) -target_compile_options( - psn00bsdk_exe_nogprel INTERFACE + > + $<$>,EXECUTABLE_NOGPREL>: + # Options for executables without $gp-relative addressing -G0 -fno-pic -mno-abicalls -mno-gpopt -) -target_link_options( - psn00bsdk_exe_nogprel INTERFACE - -G0 - -static -) - -## Options for dynamically-linked libraries - -# - Position-independent code enabled -# - $gp-relative addressing disabled (incompatible with ABI calls) -# - ABI-compatible calls enabled - -add_library(psn00bsdk_dll INTERFACE) -target_link_libraries(psn00bsdk_dll INTERFACE psn00bsdk_common) -target_compile_options( - psn00bsdk_dll INTERFACE + > + $<$>,SHARED_LIBRARY>: + # Options for DLLs -G0 -fPIC -mabicalls -mno-gpopt -mshared + > ) target_link_options( - psn00bsdk_dll INTERFACE + psn00bsdk INTERFACE + # Options common to all target types + -nostdlib + -Wl,-gc-sections + $<$>,EXECUTABLE_GPREL>: + # Options for executables with $gp-relative addressing + -G8 + -static + > + $<$>,EXECUTABLE_NOGPREL>: + # Options for executables without $gp-relative addressing + -G0 + -static + > + $<$>,SHARED_LIBRARY>: + # Options for DLLs -G0 -shared + > +) +target_compile_definitions( + psn00bsdk INTERFACE + PSN00BSDK=1 + $<$:DEBUG=1> ) diff --git a/libpsn00b/cmake/internal_setup.cmake b/libpsn00b/cmake/internal_setup.cmake index e9f0db5..6fecb9f 100644 --- a/libpsn00b/cmake/internal_setup.cmake +++ b/libpsn00b/cmake/internal_setup.cmake @@ -4,13 +4,26 @@ # This script is included automatically when using the toolchain file and # defines helper functions. -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) include(GNUInstallDirs) -# Re-enable support for dynamic linking as CMake's "Generic" system type -# disables it. +## CMake configuration + +# Setting these variables and properties would technically be the toolchain +# script's responsibility, however they are overridden by project() so their +# setting is deferred to this script. +set(CMAKE_EXECUTABLE_SUFFIX ".elf") +set(CMAKE_STATIC_LIBRARY_PREFIX "lib") +set(CMAKE_STATIC_LIBRARY_SUFFIX ".a") +set(CMAKE_SHARED_LIBRARY_PREFIX "") +set(CMAKE_SHARED_LIBRARY_SUFFIX ".so") +set(CMAKE_SHARED_MODULE_PREFIX "") +set(CMAKE_SHARED_MODULE_SUFFIX ".so") + set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS ON) +## PSn00bSDK initialization + # Fetch SDK version information from build.json. if(NOT DEFINED PSN00BSDK_VERSION) file(READ ${CMAKE_CURRENT_LIST_DIR}/../build.json _json) @@ -22,8 +35,9 @@ if(NOT DEFINED PSN00BSDK_VERSION) endif() include(${CMAKE_CURRENT_LIST_DIR}/../libpsn00b.cmake OPTIONAL) - -## Settings (can be overridden by projects) +if(TARGET psn00bsdk) + link_libraries(psn00bsdk) +endif() # DON'T CHANGE THE ORDER or you'll break the libraries' internal dependencies. set( @@ -40,6 +54,8 @@ set( c ) +## Settings (can be overridden by projects) + set(PSN00BSDK_EXECUTABLE_LINK_LIBRARIES ${PSN00BSDK_LIBRARIES}) set(PSN00BSDK_SHARED_LIBRARY_LINK_LIBRARIES "") @@ -47,6 +63,12 @@ set(PSN00BSDK_EXECUTABLE_SUFFIX ".exe") set(PSN00BSDK_SHARED_LIBRARY_SUFFIX ".dll") set(PSN00BSDK_SYMBOL_MAP_SUFFIX ".map") +define_property( + TARGET PROPERTY PSN00BSDK_TARGET_TYPE + BRIEF_DOCS "Type of this target (EXECUTABLE_GPREL, EXECUTABLE_NOGPREL or SHARED_LIBRARY)" + FULL_DOCS "Type of this target (if executable or DLL) or of the executable/DLL this target is going to be linked to (if static library)" +) + ## Include paths set(PSN00BSDK_LDSCRIPTS ${CMAKE_CURRENT_LIST_DIR}/../ldscripts) @@ -56,6 +78,8 @@ else() set(PSN00BSDK_INCLUDE ${CMAKE_CURRENT_LIST_DIR}/../../../include/libpsn00b) endif() +include_directories(AFTER ${PSN00BSDK_INCLUDE}) + ## Tool paths set( @@ -97,14 +121,24 @@ if(CMAKE_C_COMPILER_VERSION) message(FATAL_ERROR "Failed to find libgcc in the GCC toolchain's files. Check your toolchain settings, or set the path to libgcc using -DPSN00BSDK_LIBGCC.") endif() - add_library(gcc STATIC IMPORTED) - set_property(TARGET gcc PROPERTY IMPORTED_LOCATION ${PSN00BSDK_LIBGCC}) - link_libraries(gcc) + add_library (gcc STATIC IMPORTED) + set_target_properties(gcc PROPERTIES IMPORTED_LOCATION ${PSN00BSDK_LIBGCC}) + link_libraries (gcc) endif() ## Target helpers function(psn00bsdk_add_executable name type) + string(TOUPPER ${type} _type) + + if(_type MATCHES "^(STATIC|GPREL)$") + set(_type EXECUTABLE_GPREL) + elseif(_type MATCHES "^(DYNAMIC|NOGPREL)$") + set(_type EXECUTABLE_NOGPREL) + else() + message(FATAL_ERROR "Invalid executable type: ${type} (must be STATIC, GPREL, DYNAMIC or NOGPREL)") + endif() + # Throw an error if elf2x was not found (which should never happen if the # SDK is installed properly). if(ELF2X STREQUAL "ELF2X-NOTFOUND") @@ -112,19 +146,34 @@ function(psn00bsdk_add_executable name type) endif() add_executable (${name} ${ARGN}) - set_target_properties(${name} PROPERTIES PREFIX "" SUFFIX ".elf") - target_link_options (${name} PRIVATE -T${PSN00BSDK_LDSCRIPTS}/exe.ld) - - psn00bsdk_target_link_sdk (${name} PRIVATE EXECUTABLE ${type} ${PSN00BSDK_EXECUTABLE_LINK_LIBRARIES}) - target_include_directories(${name} PRIVATE ${PSN00BSDK_INCLUDE}) + set_target_properties(${name} PROPERTIES PSN00BSDK_TARGET_TYPE ${_type}) + target_link_libraries(${name} PRIVATE ${PSN00BSDK_EXECUTABLE_LINK_LIBRARIES}) + target_link_options (${name} PRIVATE -T$) # Add post-build steps to generate the .exe and symbol map once the # executable is built. + # FIXME: CMake does not (yet) allow target-dependent generator expressions + # to specify the byproducts, so we have to make sure the generated files + # have no prefix/suffix and are in the current build directory. + #set(_repl PATH:REPLACE_EXTENSION,LAST_ONLY,$) add_custom_command( - TARGET ${name} POST_BUILD - COMMAND ${ELF2X} -q ${name}.elf ${name}${PSN00BSDK_EXECUTABLE_SUFFIX} - COMMAND ${TOOLCHAIN_NM} -f posix -l -n ${name}.elf $${name}${PSN00BSDK_SYMBOL_MAP_SUFFIX} - BYPRODUCTS ${name}${PSN00BSDK_EXECUTABLE_SUFFIX} ${name}${PSN00BSDK_SYMBOL_MAP_SUFFIX} + TARGET ${name} POST_BUILD + COMMAND + ${ELF2X} -q + $> + #$> + $ + COMMAND + ${TOOLCHAIN_NM} -f posix -l -n + $> + #$$> + $$ + BYPRODUCTS + #$<${_repl},${PSN00BSDK_EXECUTABLE_SUFFIX}> + #$<${_repl},${PSN00BSDK_SYMBOL_MAP_SUFFIX}> + ${CMAKE_CURRENT_BINARY_DIR}/${name}${PSN00BSDK_EXECUTABLE_SUFFIX} + ${CMAKE_CURRENT_BINARY_DIR}/${name}${PSN00BSDK_SYMBOL_MAP_SUFFIX} + VERBATIM ) endfunction() @@ -132,28 +181,27 @@ function(psn00bsdk_add_library name type) string(TOUPPER ${type} _type) if(_type MATCHES "^(STATIC|OBJECT)$") - # Remove virtual target dependencies to make sure linking against the - # library does not also propagate static library flags. add_library (${name} ${_type} ${ARGN}) - set_target_properties(${name} PROPERTIES PREFIX "lib" SUFFIX ".a") - set_target_properties(${name} PROPERTIES INTERFACE_LINK_LIBRARIES "") - target_link_libraries(${name} PRIVATE psn00bsdk_common) - - target_include_directories(${name} PRIVATE ${PSN00BSDK_INCLUDE}) + #target_link_libraries(${name} PRIVATE psn00bsdk) elseif(_type MATCHES "^(SHARED|MODULE)$") add_library (${name} ${_type} ${ARGN}) - set_target_properties(${name} PROPERTIES PREFIX "" SUFFIX ".so") - target_link_options (${name} PRIVATE -T${PSN00BSDK_LDSCRIPTS}/dll.ld) - - psn00bsdk_target_link_sdk (${name} PRIVATE SHARED_LIBRARY ${PSN00BSDK_SHARED_LIBRARY_LINK_LIBRARIES}) - target_include_directories(${name} PRIVATE ${PSN00BSDK_INCLUDE}) + set_target_properties(${name} PROPERTIES PSN00BSDK_TARGET_TYPE SHARED_LIBRARY) + target_link_libraries(${name} PRIVATE ${PSN00BSDK_SHARED_LIBRARY_LINK_LIBRARIES}) + target_link_options (${name} PRIVATE -T$) # Add a post-build step to dump the DLL's raw contents into a new file # separate from the built ELF. + #set(_repl PATH:REPLACE_EXTENSION,LAST_ONLY,$) add_custom_command( - TARGET ${name} POST_BUILD - COMMAND ${CMAKE_OBJCOPY} -O binary ${name}.so ${name}${PSN00BSDK_SHARED_LIBRARY_SUFFIX} - BYPRODUCTS ${name}${PSN00BSDK_SHARED_LIBRARY_SUFFIX} + TARGET ${name} POST_BUILD + COMMAND + ${CMAKE_OBJCOPY} -O binary + $> + #$> + $ + #BYPRODUCTS $<${_repl},${PSN00BSDK_SHARED_LIBRARY_SUFFIX}> + BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/${name}${PSN00BSDK_SHARED_LIBRARY_SUFFIX} + VERBATIM ) else() message(FATAL_ERROR "Invalid library type: ${type} (must be STATIC, OBJECT, SHARED or MODULE)") @@ -162,31 +210,6 @@ endfunction() ## Linking helpers -function(psn00bsdk_target_link_sdk name type target_type) - set(_libraries ${ARGN}) - string(TOUPPER ${target_type} _target_type) - - if(_target_type STREQUAL "EXECUTABLE") - list(POP_FRONT _libraries) - string(TOUPPER ${ARGV3} _exe_type) - - if(_exe_type MATCHES "^(STATIC|GPREL)$") - set(_suffix _exe_gprel) - elseif(_exe_type MATCHES "^(DYNAMIC|NOGPREL)$") - set(_suffix _exe_nogprel) - else() - message(FATAL_ERROR "Invalid executable type: ${ARGV3} (must be STATIC, GPREL, DYNAMIC or NOGPREL)") - endif() - elseif(_target_type STREQUAL "SHARED_LIBRARY") - set(_suffix _dll) - else() - message(FATAL_ERROR "Invalid target type: ${target_type} (must be EXECUTABLE or SHARED_LIBRARY)") - endif() - - list(TRANSFORM _libraries APPEND ${_suffix}) - target_link_libraries(${name} ${type} psn00bsdk${_suffix} ${_libraries}) -endfunction() - function(psn00bsdk_target_incbin_a name type symbol_name size_name path section align) string(MAKE_C_IDENTIFIER ${symbol_name} _id) string(MAKE_C_IDENTIFIER ${size_name} _size) diff --git a/libpsn00b/cmake/sdk.cmake b/libpsn00b/cmake/sdk.cmake index 37b9fd0..facee26 100644 --- a/libpsn00b/cmake/sdk.cmake +++ b/libpsn00b/cmake/sdk.cmake @@ -1,7 +1,7 @@ # PSn00bSDK toolchain setup file for CMake # (C) 2021-2022 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) set( PSN00BSDK_TC "" @@ -70,10 +70,9 @@ endif() ## Toolchain executables -# ${CMAKE_EXECUTABLE_SUFFIX} seems not to work in toolchain scripts, so we -# can't rely on it to determine the host OS extension for executables. The best -# workaround I found is to extract the extension from the path returned by -# find_program() using a regex. +# As we have overridden ${CMAKE_EXECUTABLE_SUFFIX} we can't rely on it to +# determine the host OS extension for executables. A workaround is to extract +# the extension from the path returned by find_program() using a regex. set(_prefix ${_bin}/${PSN00BSDK_TARGET}) string(REGEX MATCH ".+-gcc(.*)$" _dummy ${_gcc}) @@ -90,7 +89,6 @@ set(TOOLCHAIN_NM ${_prefix}-nm${CMAKE_MATCH_1}) ## SDK setup -# We can't set up the SDK here as the find_*() functions may fail if they are -# called before project(). We can however set a script to be executed right -# after project() is invoked. +# Continue initialization by running internal_setup.cmake after project() is +# invoked. set(CMAKE_PROJECT_INCLUDE ${CMAKE_CURRENT_LIST_DIR}/internal_setup.cmake) -- cgit v1.2.3 From 3f859332c8e345ef3a35e24ab8ee3617cb477df7 Mon Sep 17 00:00:00 2001 From: spicyjpeg Date: Tue, 11 Oct 2022 11:22:30 +0200 Subject: Bump required CMake version to 3.21 --- CMakeLists.txt | 2 +- cpack/fakeroot_fix.cmake | 2 +- cpack/setup.cmake | 2 -- examples/CMakeLists.txt | 2 +- examples/beginner/cppdemo/CMakeLists.txt | 4 ++-- examples/beginner/hello/CMakeLists.txt | 4 ++-- examples/cdrom/cdbrowse/CMakeLists.txt | 4 ++-- examples/cdrom/cdxa/CMakeLists.txt | 4 ++-- examples/demos/n00bdemo/CMakeLists.txt | 4 ++-- examples/graphics/balls/CMakeLists.txt | 4 ++-- examples/graphics/billboard/CMakeLists.txt | 4 ++-- examples/graphics/fpscam/CMakeLists.txt | 4 ++-- examples/graphics/gte/CMakeLists.txt | 4 ++-- examples/graphics/hdtv/CMakeLists.txt | 4 ++-- examples/graphics/render2tex/CMakeLists.txt | 4 ++-- examples/graphics/rgb24/CMakeLists.txt | 4 ++-- examples/graphics/tilesasm/CMakeLists.txt | 4 ++-- examples/io/pads/CMakeLists.txt | 4 ++-- examples/io/system573/CMakeLists.txt | 4 ++-- examples/mdec/mdecimage/CMakeLists.txt | 4 ++-- examples/sound/spustream/CMakeLists.txt | 4 ++-- examples/sound/vagsample/CMakeLists.txt | 4 ++-- examples/system/childexec/CMakeLists.txt | 6 +++--- examples/system/console/CMakeLists.txt | 4 ++-- examples/system/dynlink/CMakeLists.txt | 4 ++-- examples/system/timer/CMakeLists.txt | 4 ++-- examples/system/tty/CMakeLists.txt | 4 ++-- template/CMakeLists.txt | 4 ++-- tools/CMakeLists.txt | 2 +- 29 files changed, 53 insertions(+), 55 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bb6c5ff..3ce6573 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ # workaround is to use ExternalProject_Add() to launch multiple independent # CMake instances, creating what's known as a "superbuild". -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) include(ExternalProject) project( diff --git a/cpack/fakeroot_fix.cmake b/cpack/fakeroot_fix.cmake index 1c1430d..e34baa0 100644 --- a/cpack/fakeroot_fix.cmake +++ b/cpack/fakeroot_fix.cmake @@ -7,7 +7,7 @@ # script does is simply finding and deleting all directories that do not match # the installation prefix before CPack generates the package. -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) set(_prefix ${CPACK_TEMPORARY_INSTALL_DIRECTORY}${CPACK_PACKAGING_INSTALL_PREFIX}) diff --git a/cpack/setup.cmake b/cpack/setup.cmake index 13da515..eaf16f2 100644 --- a/cpack/setup.cmake +++ b/cpack/setup.cmake @@ -2,8 +2,6 @@ # rules to bundle the GCC toolchain and CMake in packages. It is included by # the main CMakeLists.txt script. -cmake_minimum_required(VERSION 3.20) - ## Settings # These can be set from the command line to completely disable bundling CMake diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 15212c8..2fbc4d9 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK examples build script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( PSn00bSDK-examples diff --git a/examples/beginner/cppdemo/CMakeLists.txt b/examples/beginner/cppdemo/CMakeLists.txt index c43d4a1..11a35ed 100644 --- a/examples/beginner/cppdemo/CMakeLists.txt +++ b/examples/beginner/cppdemo/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( cppdemo @@ -12,7 +12,7 @@ project( ) file(GLOB _sources *.cpp) -psn00bsdk_add_executable(cppdemo STATIC ${_sources}) +psn00bsdk_add_executable(cppdemo GPREL ${_sources}) #psn00bsdk_add_cd_image(cppdemo_iso cppdemo iso.xml DEPENDS cppdemo) install(FILES ${PROJECT_BINARY_DIR}/cppdemo.exe TYPE BIN) diff --git a/examples/beginner/hello/CMakeLists.txt b/examples/beginner/hello/CMakeLists.txt index d8297c5..98ab43b 100644 --- a/examples/beginner/hello/CMakeLists.txt +++ b/examples/beginner/hello/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( hello @@ -12,7 +12,7 @@ project( ) file(GLOB _sources *.c) -psn00bsdk_add_executable(hello STATIC ${_sources}) +psn00bsdk_add_executable(hello GPREL ${_sources}) #psn00bsdk_add_cd_image(hello_iso hello iso.xml DEPENDS hello) install(FILES ${PROJECT_BINARY_DIR}/hello.exe TYPE BIN) diff --git a/examples/cdrom/cdbrowse/CMakeLists.txt b/examples/cdrom/cdbrowse/CMakeLists.txt index c2e93fc..0cc091f 100644 --- a/examples/cdrom/cdbrowse/CMakeLists.txt +++ b/examples/cdrom/cdbrowse/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( cdbrowse @@ -12,7 +12,7 @@ project( ) file(GLOB _sources *.c) -psn00bsdk_add_executable(cdbrowse STATIC ${_sources}) +psn00bsdk_add_executable(cdbrowse GPREL ${_sources}) psn00bsdk_add_cd_image(cdbrowse_iso cdbrowse iso.xml DEPENDS cdbrowse) psn00bsdk_target_incbin(cdbrowse PRIVATE ball16c ball16c.tim) diff --git a/examples/cdrom/cdxa/CMakeLists.txt b/examples/cdrom/cdxa/CMakeLists.txt index 70ef77c..fd2f653 100644 --- a/examples/cdrom/cdxa/CMakeLists.txt +++ b/examples/cdrom/cdxa/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( cdxa @@ -13,7 +13,7 @@ project( # TODO: add rules to actually generate a valid .XA file file(GLOB _sources *.c) -psn00bsdk_add_executable(cdxa STATIC ${_sources}) +psn00bsdk_add_executable(cdxa GPREL ${_sources}) #psn00bsdk_add_cd_image(cdxa_iso cdxa iso.xml DEPENDS cdxa) psn00bsdk_target_incbin(cdxa PRIVATE ball16c ball16c.tim) diff --git a/examples/demos/n00bdemo/CMakeLists.txt b/examples/demos/n00bdemo/CMakeLists.txt index a54c198..f7811b0 100644 --- a/examples/demos/n00bdemo/CMakeLists.txt +++ b/examples/demos/n00bdemo/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( n00bdemo @@ -28,7 +28,7 @@ add_custom_command( ) file(GLOB _sources *.s *.c) -psn00bsdk_add_executable(n00bdemo STATIC ${_sources}) +psn00bsdk_add_executable(n00bdemo GPREL ${_sources}) #psn00bsdk_add_cd_image(n00bdemo_iso n00bdemo iso.xml DEPENDS n00bdemo) target_include_directories(n00bdemo PRIVATE ${PROJECT_SOURCE_DIR}) diff --git a/examples/graphics/balls/CMakeLists.txt b/examples/graphics/balls/CMakeLists.txt index deee473..03c2720 100644 --- a/examples/graphics/balls/CMakeLists.txt +++ b/examples/graphics/balls/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( balls @@ -12,7 +12,7 @@ project( ) file(GLOB _sources *.c) -psn00bsdk_add_executable(balls STATIC ${_sources}) +psn00bsdk_add_executable(balls GPREL ${_sources}) #psn00bsdk_add_cd_image(balls_iso balls iso.xml DEPENDS balls) psn00bsdk_target_incbin(balls PRIVATE ball16c ball16c.tim) diff --git a/examples/graphics/billboard/CMakeLists.txt b/examples/graphics/billboard/CMakeLists.txt index 4fc668d..5288896 100644 --- a/examples/graphics/billboard/CMakeLists.txt +++ b/examples/graphics/billboard/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( billboard @@ -12,7 +12,7 @@ project( ) file(GLOB _sources *.c) -psn00bsdk_add_executable(billboard STATIC ${_sources}) +psn00bsdk_add_executable(billboard GPREL ${_sources}) #psn00bsdk_add_cd_image(billboard_iso billboard iso.xml DEPENDS billboard) psn00bsdk_target_incbin(billboard PRIVATE tim_image texture64.tim) diff --git a/examples/graphics/fpscam/CMakeLists.txt b/examples/graphics/fpscam/CMakeLists.txt index cb0c086..2c21296 100644 --- a/examples/graphics/fpscam/CMakeLists.txt +++ b/examples/graphics/fpscam/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( fpscam @@ -12,7 +12,7 @@ project( ) file(GLOB _sources *.c) -psn00bsdk_add_executable(fpscam STATIC ${_sources}) +psn00bsdk_add_executable(fpscam GPREL ${_sources}) #psn00bsdk_add_cd_image(fpscam_iso fpscam iso.xml DEPENDS fpscam) install(FILES ${PROJECT_BINARY_DIR}/fpscam.exe TYPE BIN) diff --git a/examples/graphics/gte/CMakeLists.txt b/examples/graphics/gte/CMakeLists.txt index 90d897b..e9ab4f3 100644 --- a/examples/graphics/gte/CMakeLists.txt +++ b/examples/graphics/gte/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( gte @@ -12,7 +12,7 @@ project( ) file(GLOB _sources *.c) -psn00bsdk_add_executable(gte STATIC ${_sources}) +psn00bsdk_add_executable(gte GPREL ${_sources}) #psn00bsdk_add_cd_image(gte_iso gte iso.xml DEPENDS gte) psn00bsdk_target_incbin(gte PRIVATE tim_texture texture.tim) diff --git a/examples/graphics/hdtv/CMakeLists.txt b/examples/graphics/hdtv/CMakeLists.txt index 804b096..78411f5 100644 --- a/examples/graphics/hdtv/CMakeLists.txt +++ b/examples/graphics/hdtv/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( hdtv @@ -12,7 +12,7 @@ project( ) file(GLOB _sources *.c) -psn00bsdk_add_executable(hdtv STATIC ${_sources}) +psn00bsdk_add_executable(hdtv GPREL ${_sources}) #psn00bsdk_add_cd_image(hdtv_iso hdtv iso.xml DEPENDS hdtv) install(FILES ${PROJECT_BINARY_DIR}/hdtv.exe TYPE BIN) diff --git a/examples/graphics/render2tex/CMakeLists.txt b/examples/graphics/render2tex/CMakeLists.txt index a97cf02..1ef36e0 100644 --- a/examples/graphics/render2tex/CMakeLists.txt +++ b/examples/graphics/render2tex/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( render2tex @@ -12,7 +12,7 @@ project( ) file(GLOB _sources *.c) -psn00bsdk_add_executable(render2tex STATIC ${_sources}) +psn00bsdk_add_executable(render2tex GPREL ${_sources}) #psn00bsdk_add_cd_image(render2tex_iso render2tex iso.xml DEPENDS render2tex) psn00bsdk_target_incbin(render2tex PRIVATE tim_blendpattern blendpattern-16c.tim) diff --git a/examples/graphics/rgb24/CMakeLists.txt b/examples/graphics/rgb24/CMakeLists.txt index 9565b8b..de81db0 100644 --- a/examples/graphics/rgb24/CMakeLists.txt +++ b/examples/graphics/rgb24/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( rgb24 @@ -12,7 +12,7 @@ project( ) file(GLOB _sources *.c) -psn00bsdk_add_executable(rgb24 STATIC ${_sources}) +psn00bsdk_add_executable(rgb24 GPREL ${_sources}) #psn00bsdk_add_cd_image(rgb24_iso rgb24 iso.xml DEPENDS rgb24) psn00bsdk_target_incbin(rgb24 PRIVATE tim_image bunpattern.tim) diff --git a/examples/graphics/tilesasm/CMakeLists.txt b/examples/graphics/tilesasm/CMakeLists.txt index 5b8de96..21ceafc 100644 --- a/examples/graphics/tilesasm/CMakeLists.txt +++ b/examples/graphics/tilesasm/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( tilesasm @@ -12,7 +12,7 @@ project( ) file(GLOB _sources *.s *.c) -psn00bsdk_add_executable(tilesasm STATIC ${_sources}) +psn00bsdk_add_executable(tilesasm GPREL ${_sources}) #psn00bsdk_add_cd_image(tilesasm_iso tilesasm iso.xml DEPENDS tilesasm) psn00bsdk_target_incbin(tilesasm PRIVATE tim_tileset tiles_256.tim) diff --git a/examples/io/pads/CMakeLists.txt b/examples/io/pads/CMakeLists.txt index cf5f817..618b696 100644 --- a/examples/io/pads/CMakeLists.txt +++ b/examples/io/pads/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( pads @@ -12,7 +12,7 @@ project( ) file(GLOB _sources *.c *.s) -psn00bsdk_add_executable(pads STATIC ${_sources}) +psn00bsdk_add_executable(pads GPREL ${_sources}) #psn00bsdk_add_cd_image(pads_iso pads iso.xml DEPENDS pads) install(FILES ${PROJECT_BINARY_DIR}/pads.exe TYPE BIN) diff --git a/examples/io/system573/CMakeLists.txt b/examples/io/system573/CMakeLists.txt index 2a362e8..34b0d69 100644 --- a/examples/io/system573/CMakeLists.txt +++ b/examples/io/system573/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( system573 @@ -12,7 +12,7 @@ project( ) file(GLOB _sources *.c *.s) -psn00bsdk_add_executable(system573 STATIC ${_sources}) +psn00bsdk_add_executable(system573 GPREL ${_sources}) psn00bsdk_add_cd_image(system573_iso system573 iso.xml DEPENDS system573) install( diff --git a/examples/mdec/mdecimage/CMakeLists.txt b/examples/mdec/mdecimage/CMakeLists.txt index b76adb4..b3d8ae1 100644 --- a/examples/mdec/mdecimage/CMakeLists.txt +++ b/examples/mdec/mdecimage/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( mdecimage @@ -12,7 +12,7 @@ project( ) file(GLOB _sources *.c) -psn00bsdk_add_executable(mdecimage STATIC ${_sources}) +psn00bsdk_add_executable(mdecimage GPREL ${_sources}) #psn00bsdk_add_cd_image(mdecimage_iso mdecimage iso.xml DEPENDS mdecimage) psn00bsdk_target_incbin(mdecimage PRIVATE mdec_image image.bin) diff --git a/examples/sound/spustream/CMakeLists.txt b/examples/sound/spustream/CMakeLists.txt index 397796a..63d113b 100644 --- a/examples/sound/spustream/CMakeLists.txt +++ b/examples/sound/spustream/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( spustream @@ -13,7 +13,7 @@ project( # TODO: add rules to actually generate a valid STREAM.BIN file file(GLOB _sources *.c) -psn00bsdk_add_executable(spustream STATIC ${_sources}) +psn00bsdk_add_executable(spustream GPREL ${_sources}) psn00bsdk_add_cd_image(spustream_iso spustream iso.xml DEPENDS spustream) install( diff --git a/examples/sound/vagsample/CMakeLists.txt b/examples/sound/vagsample/CMakeLists.txt index c9849ae..7d06afd 100644 --- a/examples/sound/vagsample/CMakeLists.txt +++ b/examples/sound/vagsample/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( vagsample @@ -12,7 +12,7 @@ project( ) file(GLOB _sources *.c) -psn00bsdk_add_executable(vagsample STATIC ${_sources}) +psn00bsdk_add_executable(vagsample GPREL ${_sources}) #psn00bsdk_add_cd_image(vagsample_iso vagsample iso.xml DEPENDS vagsample) psn00bsdk_target_incbin(vagsample PRIVATE proyt proyt.vag) diff --git a/examples/system/childexec/CMakeLists.txt b/examples/system/childexec/CMakeLists.txt index 7e91589..0c25ca4 100644 --- a/examples/system/childexec/CMakeLists.txt +++ b/examples/system/childexec/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( childexec @@ -13,8 +13,8 @@ project( file(GLOB _sources *.c) file(GLOB _child_sources child/*.c) -psn00bsdk_add_executable(parent STATIC ${_sources}) -psn00bsdk_add_executable(child STATIC ${_child_sources}) +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_target_incbin(parent PRIVATE ball16c ball16c.tim) diff --git a/examples/system/console/CMakeLists.txt b/examples/system/console/CMakeLists.txt index eeb8e62..c6fa573 100644 --- a/examples/system/console/CMakeLists.txt +++ b/examples/system/console/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( console @@ -12,7 +12,7 @@ project( ) file(GLOB _sources *.c) -psn00bsdk_add_executable(console STATIC ${_sources}) +psn00bsdk_add_executable(console GPREL ${_sources}) #psn00bsdk_add_cd_image(console_iso console iso.xml DEPENDS console) psn00bsdk_target_incbin(console PRIVATE ball16c ball16c.tim) diff --git a/examples/system/dynlink/CMakeLists.txt b/examples/system/dynlink/CMakeLists.txt index f5f4ea8..e750fd1 100644 --- a/examples/system/dynlink/CMakeLists.txt +++ b/examples/system/dynlink/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( dynlink @@ -12,7 +12,7 @@ project( ) file(GLOB _sources *.c) -psn00bsdk_add_executable(dynlink_main DYNAMIC ${_sources}) +psn00bsdk_add_executable(dynlink_main NOGPREL ${_sources}) psn00bsdk_add_library (dynlink_cube SHARED library/cube.c) psn00bsdk_add_library (dynlink_balls SHARED library/balls.c) psn00bsdk_add_cd_image( diff --git a/examples/system/timer/CMakeLists.txt b/examples/system/timer/CMakeLists.txt index 328e07e..30efbf3 100644 --- a/examples/system/timer/CMakeLists.txt +++ b/examples/system/timer/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( timer @@ -12,7 +12,7 @@ project( ) file(GLOB _sources *.c) -psn00bsdk_add_executable(timer STATIC ${_sources}) +psn00bsdk_add_executable(timer GPREL ${_sources}) #psn00bsdk_add_cd_image(timer_iso timer iso.xml DEPENDS timer) install(FILES ${PROJECT_BINARY_DIR}/timer.exe TYPE BIN) diff --git a/examples/system/tty/CMakeLists.txt b/examples/system/tty/CMakeLists.txt index 0664502..75ce689 100644 --- a/examples/system/tty/CMakeLists.txt +++ b/examples/system/tty/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( tty @@ -12,7 +12,7 @@ project( ) file(GLOB _sources *.c) -psn00bsdk_add_executable(tty STATIC ${_sources}) +psn00bsdk_add_executable(tty GPREL ${_sources}) #psn00bsdk_add_cd_image(tty_iso tty iso.xml DEPENDS tty) install(FILES ${PROJECT_BINARY_DIR}/tty.exe TYPE BIN) diff --git a/template/CMakeLists.txt b/template/CMakeLists.txt index 4aa648f..a3399db 100644 --- a/template/CMakeLists.txt +++ b/template/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( PSn00bSDK-template @@ -11,7 +11,7 @@ project( HOMEPAGE_URL "http://lameguy64.net/?page=psn00bsdk" ) -psn00bsdk_add_executable(template STATIC main.c) +psn00bsdk_add_executable(template GPREL main.c) psn00bsdk_add_cd_image( iso # Target name diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 6f604d5..c48bc10 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK tools build script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) project( PSn00bSDK-tools -- cgit v1.2.3 From e0e608855b9b2e83a92047294e1f5a242ff51e88 Mon Sep 17 00:00:00 2001 From: spicyjpeg Date: Tue, 11 Oct 2022 11:46:24 +0200 Subject: Replace DEBUG macro with standard NDEBUG macro --- libpsn00b/cmake/flags.cmake | 2 +- libpsn00b/include/assert.h | 6 +++--- libpsn00b/libc/abort.c | 6 +++--- libpsn00b/psxcd/isofs.c | 15 ++++++--------- libpsn00b/psxcd/psxcd.c | 32 ++++++++++++++++---------------- libpsn00b/psxetc/dl.c | 6 +++--- libpsn00b/psxgpu/common.c | 6 +++--- libpsn00b/psxgpu/image.c | 6 +++--- libpsn00b/psxpress/mdec.c | 6 +++--- libpsn00b/psxspu/common.c | 6 +++--- 10 files changed, 44 insertions(+), 47 deletions(-) diff --git a/libpsn00b/cmake/flags.cmake b/libpsn00b/cmake/flags.cmake index e56d3fc..1ca25c2 100644 --- a/libpsn00b/cmake/flags.cmake +++ b/libpsn00b/cmake/flags.cmake @@ -86,5 +86,5 @@ target_link_options( target_compile_definitions( psn00bsdk INTERFACE PSN00BSDK=1 - $<$:DEBUG=1> + $<$:NDEBUG=1> ) diff --git a/libpsn00b/include/assert.h b/libpsn00b/include/assert.h index e27f2ed..32301e2 100644 --- a/libpsn00b/include/assert.h +++ b/libpsn00b/include/assert.h @@ -8,13 +8,13 @@ void _assert_abort(const char *file, int line, const char *expr); -#ifdef DEBUG +#ifdef NDEBUG +#define assert(x) +#else #define assert(expr) { \ if (!(expr)) \ _assert_abort(__FILE__, __LINE__, #expr); \ } -#else -#define assert(x) #endif #endif diff --git a/libpsn00b/libc/abort.c b/libpsn00b/libc/abort.c index 562b619..1108160 100644 --- a/libpsn00b/libc/abort.c +++ b/libpsn00b/libc/abort.c @@ -1,10 +1,10 @@ #include -#ifdef DEBUG -#define _LOG(...) printf(__VA_ARGS__) -#else +#ifdef NDEBUG #define _LOG(...) +#else +#define _LOG(...) printf(__VA_ARGS__) #endif /* Standard abort */ diff --git a/libpsn00b/psxcd/isofs.c b/libpsn00b/psxcd/isofs.c index 6755d3f..fb1f6c9 100644 --- a/libpsn00b/psxcd/isofs.c +++ b/libpsn00b/psxcd/isofs.c @@ -7,13 +7,10 @@ #include "psxcd.h" #include "isofs.h" -// Uncommend to enable debug output -//#define DEBUG - -#ifdef DEBUG -#define _LOG(...) printf(__VA_ARGS__) -#else +#ifdef NDEBUG #define _LOG(...) +#else +#define _LOG(...) printf(__VA_ARGS__) #endif #define DEFAULT_PATH_SEP '\\' @@ -215,7 +212,7 @@ static int _CdReadIsoDirectory(int lba) return 0; } -#ifdef DEBUG +#ifndef NDEBUG static void dump_directory(void) { @@ -479,7 +476,7 @@ CdlFILE *CdSearchFile(CdlFILE *fp, const char *filename) // Get number of directories in path table num_dirs = get_pathtable_entry(0, NULL, NULL); -#ifdef DEBUG +#ifndef NDEBUG _LOG("psxcd: Directories in path table: %d\n", num_dirs); rbuff = resolve_pathtable_path(num_dirs-1, tpath_rbuff+127); @@ -536,7 +533,7 @@ CdlFILE *CdSearchFile(CdlFILE *fp, const char *filename) strcat(fp->name, ";1"); } -#ifdef DEBUG +#ifndef NDEBUG dump_directory(); #endif diff --git a/libpsn00b/psxcd/psxcd.c b/libpsn00b/psxcd/psxcd.c index ac93376..65dea48 100644 --- a/libpsn00b/psxcd/psxcd.c +++ b/libpsn00b/psxcd/psxcd.c @@ -20,10 +20,10 @@ volatile int _cd_last_sector_count; int _cd_media_changed; -#ifdef DEBUG -#define _LOG(...) printf(__VA_ARGS__) -#else +#ifdef NDEBUG #define _LOG(...) +#else +#define _LOG(...) printf(__VA_ARGS__) #endif void _cd_init(void); @@ -88,7 +88,7 @@ int CdControlB(unsigned char com, const void *param, unsigned char *result) int CdControlF(unsigned char com, const void *param) { int param_len=0; - + // Command specific parameters switch(com) { @@ -116,21 +116,21 @@ int CdControlF(unsigned char com, const void *param) break; case CdlGetTD: param_len = 1; + break; + case CdlReadN: + case CdlReadS: + case CdlSeekL: + case CdlSeekP: + if( param ) + { + _cd_control(CdlSetloc, param, 3); + _cd_last_setloc = *((CdlLOC*)param); + } } - - // Issue Setloc if parameters are specified on CdlReadN and CdlReadS - if( ( com == CdlReadN ) || ( com == CdlReadS ) ) - { - if( param ) - { - _cd_control(CdlSetloc, param, 3); - _cd_last_setloc = *((CdlLOC*)param); - } - } - + // Issue CD command _cd_control(com, param, param_len); - + return 1; } diff --git a/libpsn00b/psxetc/dl.c b/libpsn00b/psxetc/dl.c index 6d37605..3d8f3ab 100644 --- a/libpsn00b/psxetc/dl.c +++ b/libpsn00b/psxetc/dl.c @@ -69,10 +69,10 @@ void *(*_dl_resolve_callback)(DLL *, const char *) = 0; /* Private utilities */ -#ifdef DEBUG -#define _LOG(...) printf(__VA_ARGS__) -#else +#ifdef NDEBUG #define _LOG(...) +#else +#define _LOG(...) printf(__VA_ARGS__) #endif #define _ERROR(code, ret) { \ diff --git a/libpsn00b/psxgpu/common.c b/libpsn00b/psxgpu/common.c index e06c63a..1e3d9e5 100644 --- a/libpsn00b/psxgpu/common.c +++ b/libpsn00b/psxgpu/common.c @@ -31,10 +31,10 @@ static volatile uint16_t _last_hblank; /* Private utilities and interrupt handlers */ -#ifdef DEBUG -#define _LOG(...) printf(__VA_ARGS__) -#else +#ifdef NDEBUG #define _LOG(...) +#else +#define _LOG(...) printf(__VA_ARGS__) #endif static void _vblank_handler(void) { diff --git a/libpsn00b/psxgpu/image.c b/libpsn00b/psxgpu/image.c index 6190c7a..a0d7065 100644 --- a/libpsn00b/psxgpu/image.c +++ b/libpsn00b/psxgpu/image.c @@ -12,10 +12,10 @@ /* Private utilities */ -#ifdef DEBUG -#define _LOG(...) printf(__VA_ARGS__) -#else +#ifdef NDEBUG #define _LOG(...) +#else +#define _LOG(...) printf(__VA_ARGS__) #endif static void _load_store_image( diff --git a/libpsn00b/psxpress/mdec.c b/libpsn00b/psxpress/mdec.c index 53c596e..d308994 100644 --- a/libpsn00b/psxpress/mdec.c +++ b/libpsn00b/psxpress/mdec.c @@ -83,10 +83,10 @@ static const DECDCTENV _default_mdec_env = { /* Private utilities */ -#ifdef DEBUG -#define _LOG(...) printf(__VA_ARGS__) -#else +#ifdef NDEBUG #define _LOG(...) +#else +#define _LOG(...) printf(__VA_ARGS__) #endif /* Public API */ diff --git a/libpsn00b/psxspu/common.c b/libpsn00b/psxspu/common.c index 4809684..d6508c7 100644 --- a/libpsn00b/psxspu/common.c +++ b/libpsn00b/psxspu/common.c @@ -19,10 +19,10 @@ static uint16_t _transfer_addr = WRITABLE_AREA_ADDR; /* Private utilities */ -#ifdef DEBUG -#define _LOG(...) printf(__VA_ARGS__) -#else +#ifdef NDEBUG #define _LOG(...) +#else +#define _LOG(...) printf(__VA_ARGS__) #endif static void _wait_status(uint16_t mask, uint16_t value) { -- cgit v1.2.3 From 8e92156bc6a977651771d2cf91ac5800a0e9a913 Mon Sep 17 00:00:00 2001 From: spicyjpeg Date: Tue, 11 Oct 2022 15:39:36 +0200 Subject: Update preset files, README, docs and changelog --- CHANGELOG.md | 32 +++ CMakePresets.json | 4 +- README.md | 66 +++-- cpack/setup.cmake | 4 +- doc/cmake_reference.md | 465 ++++++++++++++++++++++------------- doc/installation.md | 6 +- doc/known_bugs.md | 26 +- examples/README.md | 4 +- libpsn00b/cmake/internal_setup.cmake | 2 - template/CMakePresets.json | 25 +- 10 files changed, 399 insertions(+), 235 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7f4f93..3f04108 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,38 @@ to ensure the changelog can be parsed correctly. ------------------------------------------------------------------------------- +## 2022-10-11: 0.21 + +spicyjpeg: + +- libpsn00b: Completely rewritten CMake scripts. Six copies of each library are + now built and installed, one for each combination of configuration (debug and + release) and target type (executable with/without $gp-relative addressing and + DLL). Library debug logging is now completely disabled when a project is + built in release mode (using `-DCMAKE_BUILD_TYPE=Release`). + +- libc: Replaced `memset()` with a much faster optimized implementation that + makes use of Duff's device. Added `GetHeapUsage()` and `TrackHeapUsage()`. + Removed `_mem_init()`. + +- psxetc: Fixed a critical bug in `DMACallback()` that would lead to the DMA + interrupt handler being disabled entirely in some edge cases. + +- psxgpu: Replaced the debug font with an improved one. No changes have been + made to the API. + +- psxcd: Added `CdGetSector2()` (asynchronous variant of `CdGetSector()`). + `CdControl()` can now take a `CdlLOC` as second argument when issuing a seek + command (previously the argument was ignored if the command was not `ReadN` + or `ReadS`). + +- Replaced the `DEBUG` macro with the standard C `NDEBUG` macro, which is only + defined if the project is being built in release mode. + +- Added `PSN00BSDK_*_LINK_LIBRARIES` CMake variables to control which SDK + libraries are linked to newly created executables and DLLs. Updated + `cmake_reference.md` to reflect the changes. + ## 2022-09-22 spicyjpeg: diff --git a/CMakePresets.json b/CMakePresets.json index 89002a3..eca1478 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -1,8 +1,8 @@ { - "version": 2, + "version": 3, "cmakeMinimumRequired": { "major": 3, - "minor": 20, + "minor": 21, "patch": 0 }, "configurePresets": [ diff --git a/README.md b/README.md index e4a2d15..07ad738 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ and performance reasons. ## Notable features -As of March 28, 2022 +As of October 11, 2022: * Extensive GPU support with lines, flat shaded or textured polygon and sprite primitives, high-speed DMA for VRAM transfers and ordering tables. All video @@ -54,26 +54,24 @@ As of March 28, 2022 HLE BIOS implementations and loader/menu type homebrew programs. * BIOS controller functions for polling controller input work as intended - thanks to proper handling of hardware interrupts. No crude direct I/O polling - of controllers in the main loop. - -* Complete Serial I/O support with SIOCONS driver for tty stdin/stdout - console access. Hardware flow control supported. - -* Full CD-ROM support using libpsxcd featuring data read, CD audio and XA audio - playback, built-in ISO9660 file system parser with no file count limit - (classic ISO9660 only, no Rock Ridge or Joliet extensions) and multi-session. - -* Preliminary MDEC support implemented with libpsxpress (no VLC decoding yet). - Sample encoder included. - -* Can target Konami System 573 arcade hardware with limited support - (see examples/io/system573/main.c for details) - -* Experimental support for compiling separate sections of an executable into - shared library files (DLLs) and linking them dynamically at runtime, plus - support for function and variable introspection by loading a map file - generated at build time. + thanks to proper handling of hardware interrupts. Optional limited support + for manual polling. + +* Complete Serial I/O support and console driver to redirect standard input and + output to the serial port. Hardware flow control supported. + +* Full CD-ROM support using `libpsxcd` featuring data reading, CD-DA and XA + audio playback, a built-in ISO9660 file system parser with no file count + limit and support for multi-session discs. + +* MDEC support, lossy image decompression and video playback using + `libpsxpress` (currently only bitstream versions 1 and 2 are supported). + +* Preliminary limited support for Konami System 573 arcade hardware. + +* Experimental support for dynamic linking at runtime, with support for + function and variable introspection by loading a map file generated at build + time. * Uses Sony SDK library syntax for familiarity to experienced programmers and makes porting existing homebrew projects to PSn00bSDK easier. @@ -113,21 +111,21 @@ apply to PSn00bSDK. ## To-do List -* psxspu: Plenty of work to be done. Hardware timer driven sound/music - system may need to be implemented (an equivalent to the Ss* series of - functions in libspu basically). Functions that make use of the SPU RAM - interrupt feature to play or capture streamed audio should also be added. +* `libpsxspu`: Plenty of work to be done. Some kind of MIDI sequencer (similar + to the one present in the official SDK) should be added at some point, along + with a proper API for audio streaming. -* psxcd: Implement a command queue mechanism for the CD-ROM? +* `libpsxcd`: Implement a command queue mechanism for the CD-ROM. -* libc: Improve the memory allocation framework with multiple allocators, GC - and maybe helpers to manage swapping between main RAM and VRAM/SPU RAM. +* `libpsxpress`: Add support for version 3 and IKI frame bitstreams. -* Further support for MDEC, and tooling to transcode videos to .STR files - (either reimplementing the container and compression format used by the Sony - SDK, or a custom format with better compression). +* `libc`: Improve the memory allocation framework with multiple allocators, + replace the string functions with optimized implementations and maybe add + helpers to manage swapping between main RAM and VRAM/SPU RAM. -* Pad and memory card libraries that don't use the BIOS routines. +* Add a full controller and memory card API that does not depend on the BIOS + controller driver, and possibly a library for interfacing to IDE/ATAPI drives + to make development for arcade systems easier. ## Credits @@ -138,8 +136,8 @@ Main developer/author/whatever: Contributors: -* **spicyjpeg**: dynamic linker, CMake scripts, some docs and examples - (`system/dynlink`, `sound/spustream`, `io/pads`, `io/system573`). +* **spicyjpeg**: dynamic linker, `libpsxpress`, CMake scripts, some docs and + examples. * **Silent**, **G4Vi**, **Chromaryu**: `mkpsxiso` and `dumpsxiso` (maintained as a [separate repo](https://github.com/Lameguy64/mkpsxiso)). diff --git a/cpack/setup.cmake b/cpack/setup.cmake index eaf16f2..d585641 100644 --- a/cpack/setup.cmake +++ b/cpack/setup.cmake @@ -128,11 +128,11 @@ set(CPACK_PACKAGE_INSTALL_DIRECTORY PSn00bSDK) ## DEB/RPM variables -set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.28), cmake (>= 3.20)") +set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.28), cmake (>= 3.21)") set(CPACK_DEBIAN_PACKAGE_RECOMMENDS "ninja-build (>= 1.10)") set(CPACK_DEBIAN_PACKAGE_SUGGESTS "git (>= 2.25)") set(CPACK_DEBIAN_PACKAGE_SECTION devel) -set(CPACK_RPM_PACKAGE_REQUIRES "cmake >= 3.20") +set(CPACK_RPM_PACKAGE_REQUIRES "cmake >= 3.21") set(CPACK_RPM_PACKAGE_SUGGESTS "ninja-build >= 1.10, git >= 2.25") #set(CPACK_RPM_PACKAGE_RELOCATABLE ON) diff --git a/doc/cmake_reference.md b/doc/cmake_reference.md index 25a89ec..bceaac9 100644 --- a/doc/cmake_reference.md +++ b/doc/cmake_reference.md @@ -1,6 +1,15 @@ # PSn00bSDK CMake reference +- [Setup](#setup) +- [Targets](#targets) +- [Commands](#commands) +- [Target properties](#target-properties) +- [Preprocessor definitions](#preprocessor-definitions) +- [Cached settings](#cached-settings) +- [Internal settings](#internal-settings) +- [Read-only variables](#read-only-variables) + ## Setup The only requirement to use the SDK in CMake is to set the @@ -10,32 +19,35 @@ This can be done on the command line (`-DCMAKE_TOOLCHAIN_FILE=...`), in `CMakeLists.txt` (`set(CMAKE_TOOLCHAIN_FILE ...)` before `project()`) or using [presets](https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html). -It's suggested to have a default preset that sets `CMAKE_TOOLCHAIN_FILE` to +It's suggested to have a default preset that sets the toolchain file to `$env{PSN00BSDK_LIBS}/cmake/sdk.cmake`, taking advantage of the `PSN00BSDK_LIBS` environment variable (used by former PSn00bSDK versions) to -automatically find the SDK. Such a preset can be created by placing a +automatically find the SDK if set. Such a preset can be created by placing a `CMakePresets.json` file in the project's root with the following contents: ```json { - "version": 2, + "version": 3, "cmakeMinimumRequired": { "major": 3, - "minor": 20, + "minor": 21, "patch": 0 }, "configurePresets": [ { - "name": "default", - "displayName": "Default configuration", - "description": "Use this preset to build the project using PSn00bSDK.", - "generator": "Ninja", - "binaryDir": "${sourceDir}/build", + "name": "default", + "displayName": "Default configuration", + "description": "Use this preset to build the project using PSn00bSDK.", + "generator": "Ninja", + "toolchainFile": "$env{PSN00BSDK_LIBS}/cmake/sdk.cmake", + "binaryDir": "${sourceDir}/build", "cacheVariables": { - "CMAKE_BUILD_TYPE": "Debug", - "CMAKE_TOOLCHAIN_FILE": "$env{PSN00BSDK_LIBS}/cmake/sdk.cmake", - "PSN00BSDK_TC": "", - "PSN00BSDK_TARGET": "mipsel-none-elf" + "CMAKE_BUILD_TYPE": "Debug", + "PSN00BSDK_TC": "", + "PSN00BSDK_TARGET": "mipsel-none-elf" + }, + "warnings": { + "dev": false } } ] @@ -43,230 +55,345 @@ automatically find the SDK. Such a preset can be created by placing a ``` To avoid having to pass variables to CMake each time the project is built, a -second presets file named `CMakeUserPresets.json` can be created and populated -with hardcoded values in the `cacheVariables` section. This file can be kept -private (e.g. by adding it to `.gitignore`); CMake will automatically load -presets from it instead of `CMakePresets.json` if it exists. +second file named `CMakeUserPresets.json` can be created and populated with +hardcoded values in the `cacheVariables` section. This file can be kept private +(e.g. by adding it to `.gitignore`), and CMake will automatically load presets +from it instead of `CMakePresets.json` if it exists. See the [template](../template/CMakeLists.txt) for an example CMake script showing how to build a simple project. ## Targets -These targets are defined when using PSn00bSDK. There is no need to explicitly -link against any of these, as the helper commands (see below) handle linking -behind the scenes. To avoid conflicts, however, no target should be given any -of these names. - -- `c`, `psxgpu`, `psxgte`, `psxspu`, `psxcd`, `psxsio`, `psxetc`, `psxapi`, `lzp` -- `psn00bsdk_common`, `psn00bsdk_object_lib` -- `psn00bsdk_static_exe` -- `psn00bsdk_dynamic_exe` -- `psn00bsdk_static_lib` -- `psn00bsdk_shared_lib`, `psn00bsdk_module_lib` +The toolchain script creates a target for each PSn00bSDK library. Currently +the following targets are defined: + +- `psxgpu` +- `psxgte` +- `psxspu` +- `psxcd` +- `psxpress` +- `psxsio` +- `psxetc` +- `psxapi` +- `lzp` +- `c` + +Note that these are not actual libraries but virtual targets that link to the +appropriate version of the respective library, depending on the value of the +`PSN00BSDK_TARGET_TYPE` property; refer to the target properties section for +more information. Linking manually using the `target_link_libraries()` command +is usually not necessary for executables as they are linked to all libraries +by default (see `PSN00BSDK_EXECUTABLE_LINK_LIBRARIES`). + +Additionally, two "hidden" libraries named `gcc` and `psn00bsdk` are linked by +default to all targets. The former is the GCC toolchain's `libgcc` (see +`PSN00BSDK_LIBGCC`) while the latter is a virtual target used to set compiler +flags and paths. ## Commands -- `psn00bsdk_add_executable( [EXCLUDE_FROM_ALL] [sources...])` +### `psn00bsdk_add_executable` - A wrapper around `add_executable()` to create PS1 executables. Three files - will be generated for each call to this function: +```cmake +psn00bsdk_add_executable( + + [EXCLUDE_FROM_ALL] + [sources...] +) +``` - - `.elf` (regular ELF executable) - - `.exe` (executable converted to the format expected by the PS1) - - `.map` (symbol map file for dynamic linking/introspection) +A wrapper around `add_executable()` to create PS1 executables. Three files will +be generated for each call to this function: - The `.exe` and `.map` extensions can be customized by overriding - `PSN00BSDK_EXECUTABLE_SUFFIX` and `PSN00BSDK_SYMBOL_MAP_SUFFIX` prior to - creating the executable. +- `.elf` (regular ELF executable) +- `.exe` (executable converted to the format expected by the PS1) +- `.map` (symbol map file for dynamic linking/introspection) - The second argument (mandatory) specifies whether the executable is going to - load DLLs at runtime. If set to `STATIC`, $gp-relative addressing (i.e. - reusing the $gp register normally used for DLL addressing) will be enabled, - slightly reducing executable size and RAM usage but breaking compatibility - with the dynamic linker. +The `.exe` and `.map` extensions can be customized by overriding +`PSN00BSDK_EXECUTABLE_SUFFIX` and `PSN00BSDK_SYMBOL_MAP_SUFFIX` prior to +creating the executable. -- `psn00bsdk_add_library( [EXCLUDE_FROM_ALL] [sources...])` +The second argument (mandatory) specifies whether the executable is going to +load DLLs at runtime. If set to `GPREL` or `STATIC`, $gp-relative addressing +(i.e. reusing the $gp register normally used for DLL addressing to reference +global variables) will be enabled, slightly reducing executable size and RAM +usage but breaking compatibility with the dynamic linker. - Wraps `add_library()` to create static libraries or dynamically-linked - libraries (DLLs). +All executables are automatically linked to the libraries listed in +`PSN00BSDK_EXECUTABLE_LINK_LIBRARIES` (all SDK libraries by default). This +variable can be modified prior to creating the executable to select which +libraries to link. - The second argument (mandatory, unlike `add_library()`) specifies the type of - library to create. `STATIC` will create a static library named `lib.a`. - `SHARED` and `MODULE` will compile a DLL, producing the following files (note - that there is no `lib` prefix for DLLs): +### `psn00bsdk_add_library` - - `.so` (regular ELF shared library) - - `.dll` (raw binary with some ELF headers prepended) +```cmake +psn00bsdk_add_library( + + [EXCLUDE_FROM_ALL] + [sources...] +) +``` - As with executables, the `.dll` extension can be customized by setting - `PSN00BSDK_SHARED_LIBRARY_SUFFIX`. +Wraps `add_library()` to create static libraries or dynamically-linked +libraries (DLLs). -- `psn00bsdk_add_cd_image( [DEPENDS ...] [...])` +The second argument (mandatory, unlike CMake's regular `add_library()`) +specifies the type of library to create. `STATIC` will create a static library +named `lib.a`. `SHARED` and `MODULE` will compile a DLL, producing +the following files (there is no `lib` prefix for DLLs): - Creates a new target that will build a CD image using `mkpsxiso`. +- `.so` (regular ELF shared library) +- `.dll` (raw binary with some ELF headers prepended) - The first argument is the name of the target to create; next up is the name - of the generated image file (`.bin` + `.cue`). The - third argument is the path to the XML file (relative to the source directory) - passed to `mkpsxiso`. +The `.dll` extension can be customized by setting +`PSN00BSDK_SHARED_LIBRARY_SUFFIX` prior to creating the DLL. - The XML file is "configured" by CMake, i.e. any `${var}` or `@var@` - expressions are replaced with the values of the respective variables. In - particular `${CD_IMAGE_NAME}` is replaced with the second argument passed to - `psn00bsdk_add_cd_image()`; the file must properly set the output file names - like this: +All DLLs are automatically linked to the libraries listed in +`PSN00BSDK_SHARED_LIBRARY_LINK_LIBRARIES` (none by default). This variable can +be modified prior to creating the DLL to select which libraries to link. - ```xml - - - ``` +**IMPORTANT**: when adding a static library using this command (or CMake's +`add_library()`), the `PSN00BSDK_TARGET_TYPE` property **must** be set on it +afterwards in order to let CMake know whether the static library is going to be +linked to an executable or a DLL. See `PSN00BSDK_TARGET_TYPE` for more +information. - Any additional argument is passed through to the underlying call to - `add_custom_target()`, so most of the options supported by - `add_custom_target()` (including `DEPENDS`) are also supported here. +### `psn00bsdk_add_cd_image` -- `psn00bsdk_target_incbin( )` +```cmake +psn00bsdk_add_cd_image( + + + + [DEPENDS ] + [other options...] +) +``` - Embeds the contents of a binary file into an executable or a library. +Creates a new virtual target that will build a CD image using `mkpsxiso`. The +CD image will always be considered out-of-date and built, even if none of its +dependencies or any other files have been modified. + +The first argument is the name of the target to create; next up is the name of +the generated image file (`.bin` + `.cue`). The third +argument is the path to the XML file (relative to the source directory) passed +to `mkpsxiso`. + +The XML file is "configured" by CMake, i.e. any `${var}` or `@var@` expressions +are replaced with the values of the respective variables. In particular +`${CD_IMAGE_NAME}` is replaced with the second argument passed to +`psn00bsdk_add_cd_image()`; the file must properly set the output file names +like this: + +```xml + + + + +``` - A new symbol/object will be created with the given name, escaped by replacing - non-alphanumeric characters with underscores. The contents of the file will - be aligned to 4 bytes and placed in the `.data` section. An unsigned 32-bit - integer named `_size` will also be defined and set to the length - of the file in bytes (without taking alignment/padding into account). +Any additional argument is passed through to the underlying call to +`add_custom_target()`, so most of the options supported by +`add_custom_target()` (including `DEPENDS`) are also supported here. - Once added the file and its size can be accessed by C/C++ code by declaring - the respective symbols as an extern array and as an integer, like this: +### `psn00bsdk_target_incbin` - ```c - extern const uint8_t my_file[]; - extern const size_t my_file_size; - ``` +```cmake +psn00bsdk_target_incbin( + + + +) +``` - The fourth argument specifies the path to the binary file relative to the - source directory. This path can be prepended with `${PROJECT_BINARY_DIR}/` to - reference a file generated by the build script (such as an LZP archive): in - that case a file-level dependency will also be created, ensuring CMake does - not attempt to compile the executable or library before the file is built. +Embeds the contents of a binary file into an executable or a library. - **IMPORTANT**: in order for this command to work, assembly language support - must be enabled by specifying `LANGUAGES C ASM` (or `LANGUAGES C CXX ASM` if - C++ is also used) when invoking `project()`. +A new symbol/object will be created with the given name, escaped by replacing +non-alphanumeric characters with underscores. The contents of the file will be +aligned to 4 bytes and placed in the `.data` section. An unsigned 32-bit +integer named `_size` will also be defined and set to the length +of the file in bytes (without taking alignment/padding into account). -- `psn00bsdk_target_incbin_a( )` +Once added the file and its size can be accessed by C/C++ code by declaring the +respective symbols as an extern array and as an integer, like this: - Advanced variant of `psn00bsdk_target_incbin()` that allows specifying a - custom name for the size symbol and changing the default alignment setting. - Note that the size integer is always aligned to a multiple of 4 bytes as the - MIPS architecture doesn't support unaligned reads. +```c +extern const uint8_t my_file[]; +extern const size_t my_file_size; +``` -## Definitions +The fourth argument specifies the path to the binary file relative to the +source directory. This path can be prepended with `${PROJECT_BINARY_DIR}/` to +reference a file generated by the build script (such as an LZP archive): in +that case a file-level dependency will also be created, ensuring CMake does not +attempt to compile the executable or library before the file is built. + +**IMPORTANT**: in order for this command to work, assembly language support +must be enabled by specifying `LANGUAGES C ASM` (or `LANGUAGES C CXX ASM` to +enable C++ support as well) when invoking `project()`. + +### `psn00bsdk_target_incbin_a` + +```cmake +psn00bsdk_target_incbin_a( + + + + +
+ +) +``` -When compiling executables and libraries using the above commands the following -preprocessor macros are automatically `#define`'d: +Advanced variant of `psn00bsdk_target_incbin()` that allows specifying a custom +name for the size symbol and changing the default alignment setting. The value +of the size integer is always rounded up to a multiple of 4 bytes. -- `PLAYSTATION` +See `psn00bsdk_target_incbin()` above for more details. - Always set to 1. Can be used to implement different options or code paths for - libraries, so they can target both the host and PS1 (as it won't be defined - when compiling outside of the SDK). +## Target properties -- `DEBUG` +Each of the following properties can be set individually for each executable or +library using CMake's `set_property()` and `set_target_properties()` commands. - Defined and set to 1 in a debug configuration, i.e. when the - `CMAKE_BUILD_TYPE` variable is set to `Debug`. This value is used by the - PSn00bSDK libraries, and should be used in executables, to enable additional - debug logging. +### `PSN00BSDK_TARGET_TYPE` - Note that the default CMake configuration is usually debug, so it's - recommended to specify `-DCMAKE_BUILD_TYPE=Release` to get rid of the logging - overhead in release builds and reduce executable size. +Determines which SDK libraries are linked to and which compiler flags are added +to the target. Must be set to `EXECUTABLE_GPREL`, `EXECUTABLE_NOGPREL` or +`SHARED_LIBRARY`. -## Cached settings +This property is initialized automatically on executables and DLLs created via +`psn00bsdk_add_executable()` or `psn00bsdk_add_library()`, but *not* on static +libraries as CMake has no way to know about their intended usage (i.e. whether +they are going to be linked to an executable with or without $gp-relative +addressing, or to a DLL). Thus, `PSN00BSDK_TARGET_TYPE` must be set manually on +all static libraries and must match the value set on any executable or DLL the +static library is going to be linked to. + +There is no way to build a "hybrid" static library that can be linked to +multiple target types, short of building multiple copies of it. A workaround +(used internally by PSn00bSDK) is to create a virtual target and use CMake +generator expressions to link to one of the copies depending on the value of +`PSN00BSDK_TARGET_TYPE`. -These variables are stored in CMake's cache and can be edited by the project's -build script, from the CMake command line when configuring the project -(`-Dname=value`) or using an editor such as the CMake GUI. +## Preprocessor definitions -- `PSN00BSDK_TARGET` (`STRING`) +When compiling executables and libraries using the commands listed above the +following C/C++ preprocessor macros are automatically `#define`d: - The GCC toolchain's target triplet. PSn00bSDK assumes the toolchain targets - `mipsel-none-elf` by default, however this can be changed to e.g. use a MIPS - toolchain that was compiled for a slightly-different-but-equivalent target. +### `PSN00BSDK` - The following GCC target triplets have been confirmed to work with PSn00bSDK: +Always set to 1. Can be used to implement different options or code paths for +projects that target both PSn00bSDK and other platforms. - - `mipsel-none-elf` - - `mipsel-unknown-elf` - - ~~`mipsel-linux-gnu`~~ (has issues with linking) +### `NDEBUG` -- `PSN00BSDK_TC` (`PATH`) +Defined and set to 1 in a release configuration, i.e. when `CMAKE_BUILD_TYPE` +is set to `Release` or when a multi-configuration generator is building the +project in release mode; not defined if the project is being built in debug +mode. This value is used by the PSn00bSDK libraries, and should be used in +projects, to enable assertions and additional debug logging (the `assert()` +macro already resolves to a no-op in release mode). - Path to the GCC toolchain's installation prefix/directory. If not set, CMake - will attempt to find the toolchain in the `PATH` environment variable and - store its path in the project's variable cache (so the search does not have - to be repeated). It is recommended to add the toolchain's `bin` subfolder to - `PATH` rather than setting this variable. +Note that the default CMake configuration is usually debug. It is recommended +to build a project in release mode whenever appropriate (by specifying +`-DCMAKE_BUILD_TYPE=Release` or using the Ninja multi-configuration generator) +to get rid of logging overhead. - **IMPORTANT**: if the toolchain's target is not `mipsel-none-elf`, - `PSN00BSDK_TARGET` must be set regardless of whether or not `PSN00BSDK_TC` is - also set. +## Cached settings + +These variables are stored in CMake's cache and are meant to be set by the end +user when building the project (rather than by the project itself). They can be +modified by the build script after invoking `project()`, from the CMake command +line when configuring (`-Dname=value`) or using an IDE or other editor such as +the CMake GUI. + +### `PSN00BSDK_TARGET` (`STRING`) + +The GCC toolchain's target triplet. PSn00bSDK assumes the toolchain targets +`mipsel-none-elf` by default, however this can be changed to e.g. use a MIPS +toolchain that was compiled for `mipsel-unknown-elf` (as used by previous +versions of PSn00bSDK). + +Toolchains that target `mipsel-linux-gnu` are not supported by PSn00bSDK. + +### `PSN00BSDK_TC` (`PATH`) -- `PSN00BSDK_LIBGCC` (`FILEPATH`) +Path to the GCC toolchain's installation prefix/directory. If not set, CMake +will attempt to find the toolchain in the `PATH` environment variable and store +its path in the project's variable cache (so the search does not have to be +repeated). It is recommended to add the toolchain's `bin` subfolder to `PATH` +rather than setting this variable. - Path to the `libgcc.a` library bundled with the GCC toolchain. The contents - of this library are merged into `libc` when building the SDK, so this - variable is only actually needed when compiling `libpsn00b`. Setting this - variable manually usually isn't necessary as CMake will locate `libgcc.a` - automatically after finding the toolchain. +**IMPORTANT**: if the toolchain's target triplet is not `mipsel-none-elf`, +`PSN00BSDK_TARGET` must be set regardless of whether or not `PSN00BSDK_TC` is +also set. + +### `PSN00BSDK_LIBGCC` (`FILEPATH`) + +Path to the `libgcc` library bundled with the GCC toolchain. As required by GCC +this library is always linked to all targets, regardless of whether any SDK +libraries are linked or not. CMake will attempt to locate `libgcc` +automatically after finding the toolchain, so setting this variable manually is +not required in most cases. ## Internal settings These settings are not stored in CMake's cache and can only be set from within -the build script. +the build script after invoking `project()`. + +### `PSN00BSDK_EXECUTABLE_LINK_LIBRARIES`, `PSN00BSDK_SHARED_LIBRARY_LINK_LIBRARIES` (list of `STRING`) -- `PSN00BSDK_LIBRARIES` +Lists of SDK libraries to be linked automatically to all new executables and +DLLs, respectively. By default `PSN00BSDK_EXECUTABLE_LINK_LIBRARIES` includes +all libraries that ship with PSn00bSDK while +`PSN00BSDK_SHARED_LIBRARY_LINK_LIBRARIES` is empty. - List of libraries to link all created targets against. By default this - includes all PSn00bSDK libraries. +These variables can be modified before invoking `psn00bsdk_add_executable()` or +`psn00bsdk_add_library()` to only link a subset of the SDK. Static libraries +are *not* automatically linked to any SDK libraries. -- `PSN00BSDK_EXECUTABLE_SUFFIX`, `PSN00BSDK_SHARED_LIBRARY_SUFFIX`, - `PSN00BSDK_SYMBOL_MAP_SUFFIX` +### `PSN00BSDK_EXECUTABLE_SUFFIX`, `PSN00BSDK_SHARED_LIBRARY_SUFFIX`, `PSN00BSDK_SYMBOL_MAP_SUFFIX` (`STRING`) - File extensions to use for generated PS1 files. The default values are - `.exe`, `.dll` and `.map` respectively. Note that file names and extensions - can be changed anyway when building a CD image. +File extensions to use for generated PS1 files. The default values are `.exe`, +`.dll` and `.map` respectively. These extensions do not have to match the ones +used in the CD image (if any). ## Read-only variables -- `PSN00BSDK_VERSION`, `PSN00BSDK_BUILD_DATE`, `PSN00BSDK_GIT_TAG`, - `PSN00BSDK_GIT_COMMIT` +### `PSN00BSDK_VERSION`, `PSN00BSDK_BUILD_DATE`, `PSN00BSDK_GIT_TAG`, `PSN00BSDK_GIT_COMMIT` (`STRING`) + +These variables are loaded from `lib/libpsn00b/build.json` and contain +information about the SDK's version. `PSN00BSDK_GIT_TAG` and +`PSN00BSDK_GIT_COMMIT` might be empty strings as they are only populated in CI +builds of PSn00bSDK. + +### `PSN00BSDK_LIBRARIES` (list of `STRING`) - These variables are loaded from `lib/libpsn00b/build.json` and contain - information about the SDK's version. Note that `PSN00BSDK_GIT_TAG` and - `PSN00BSDK_GIT_COMMIT` are not populated by default when building PSn00bSDK - manually from source, so they might be empty strings. +List of all libraries that ship with PSn00bSDK, excluding `libgcc`. Each +library in this list is also defined as a target. See the targets section for +more details. -- `PSN00BSDK_TOOLS`, `PSN00BSDK_INCLUDE`, `PSN00BSDK_LDSCRIPTS` +### `PSN00BSDK_TOOLS`, `PSN00BSDK_INCLUDE`, `PSN00BSDK_LDSCRIPTS` (list of `PATH`) - Lists of paths used internally. Should not be set, manipulated or overridden - by scripts. +Lists of paths used internally. Should not be set, manipulated or overridden by +scripts. -- `TOOLCHAIN_NM` +### `TOOLCHAIN_NM` (`FILEPATH`) - Path to the `nm` executable used to generate symbol maps. Although not used - internally by CMake, this program is part of the GCC toolchain. +Path to the `nm` executable used to generate symbol maps. Although not used +internally by CMake, this program is part of the GCC toolchain. -- `ELF2X`, `ELF2CPE`, `MKPSXISO`, `LZPACK`, `SMXLINK` +### `ELF2X`, `ELF2CPE`, `MKPSXISO`, `LZPACK`, `SMXLINK` (`FILEPATH`) - Paths to the PSn00bSDK tools' executables. As no functions are currently - provided for building assets, `LZPACK` and `SMXLINK` can be used with - `add_custom_command()`/`add_custom_target()` to convert models and generate - LZP archives as part of the build pipeline. +Paths to the PSn00bSDK tools' executables. As no functions are currently +provided for building assets, `LZPACK` and `SMXLINK` can be used manually with +CMake's `add_custom_command()` and `add_custom_target()` to convert models and +generate LZP archives as part of the build pipeline. ----------------------------------------- -_Last updated on 2022-02-26 by spicyjpeg_ +_Last updated on 2022-10-11 by spicyjpeg_ diff --git a/doc/installation.md b/doc/installation.md index 382c721..70b7f3e 100644 --- a/doc/installation.md +++ b/doc/installation.md @@ -5,7 +5,7 @@ 1. Install prerequisites. Currently CMake is the only external dependency; you can install it from [here](https://cmake.org/download) or using MSys2 or - your distro's package manager. Make sure you have at least CMake 3.20. + your distro's package manager. Make sure you have at least CMake 3.21. 2. Head over to the releases page, download the latest release's ZIP for your operating system and extract its contents to a directory of your choice, @@ -44,7 +44,7 @@ being built without support for ripping CD audio tracks to FLAC, however the - `git` - `build-essential`, `base-devel` or similar - `make` or `ninja-build` - - `cmake` (3.20+ is required, download it from + - `cmake` (3.21 or later is required, download it from [here](https://cmake.org/download) if your package manager only provides older versions) @@ -185,4 +185,4 @@ The toolchain script defines a few CMake macros to create PS1 executables, DLLs and CD images. See the [reference](cmake_reference.md) for details. ----------------------------------------- -_Last updated on 2022-09-21 by spicyjpeg_ +_Last updated on 2022-10-11 by spicyjpeg_ diff --git a/doc/known_bugs.md b/doc/known_bugs.md index 3fbfdc2..9e4785c 100644 --- a/doc/known_bugs.md +++ b/doc/known_bugs.md @@ -7,14 +7,15 @@ fixed. ## Toolchain -- It is currently not possible to link static libraries (including the SDK - libraries themselves) with DLLs, since the build scripts currently assume that - static library object files are always going to be linked into executables. - This can be worked around by linking all static libraries as part of the main - executable rather than the DLLs: the dynamic linker will automatically search - the executable for undefined symbols used by a DLL and patch the code to use - them. It might be necessary to list such symbols in a dummy array to prevent - the compiler from stripping them away from the executable. +- ~~It is currently not possible to link static libraries (including the SDK~~ + ~~libraries themselves) with DLLs, since the build scripts currently assume~~ + ~~that static library object files are always going to be linked into~~ + ~~executables. This can be worked around by linking all static libraries as~~ + ~~part of the main executable rather than the DLLs: the dynamic linker will~~ + ~~automatically search the executable for undefined symbols used by a DLL~~ + ~~and patch the code to use them.~~ Static libraries are now fully supported, + and SDK libraries can be linked to both executables and DLLs. See the CMake + reference for more details. - Link-time optimization is broken due to GCC not supporting it when linking weak functions written in assembly. @@ -28,7 +29,7 @@ fixed. the length of the data *must* be a multiple of 32 bytes. Attempting to transfer any data whose length isn't a multiple of 32 bytes will result in `DrawSync()` hanging and never returning, however a warning will be printed - on the debug console. + on the debug console if the executable is built in debug mode. `psxspu`: @@ -36,6 +37,11 @@ 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 @@ -48,4 +54,4 @@ fixed. See [README.md in the examples directory](../examples/README.md#examples-summary). ----------------------------------------- -_Last updated on 2022-08-21 by spicyjpeg_ +_Last updated on 2022-10-11 by spicyjpeg_ diff --git a/examples/README.md b/examples/README.md index 82d7698..b63b2a9 100644 --- a/examples/README.md +++ b/examples/README.md @@ -48,7 +48,7 @@ Notes: ## Building the examples -The instructions below assume that PSn00bSDK, CMake 3.20+ and a GCC toolchain +The instructions below assume that PSn00bSDK, CMake 3.21+ and a GCC toolchain are already installed. Refer to the [installation guide](../doc/installation.md) for details. @@ -84,4 +84,4 @@ are for rebuilding the examples *after* the SDK has been installed. CD images for each example. ----------------------------------------- -_Last updated on 2022-08-11 by spicyjpeg_ +_Last updated on 2022-10-11 by spicyjpeg_ diff --git a/libpsn00b/cmake/internal_setup.cmake b/libpsn00b/cmake/internal_setup.cmake index 6fecb9f..e78355f 100644 --- a/libpsn00b/cmake/internal_setup.cmake +++ b/libpsn00b/cmake/internal_setup.cmake @@ -173,7 +173,6 @@ function(psn00bsdk_add_executable name type) #$<${_repl},${PSN00BSDK_SYMBOL_MAP_SUFFIX}> ${CMAKE_CURRENT_BINARY_DIR}/${name}${PSN00BSDK_EXECUTABLE_SUFFIX} ${CMAKE_CURRENT_BINARY_DIR}/${name}${PSN00BSDK_SYMBOL_MAP_SUFFIX} - VERBATIM ) endfunction() @@ -201,7 +200,6 @@ function(psn00bsdk_add_library name type) $ #BYPRODUCTS $<${_repl},${PSN00BSDK_SHARED_LIBRARY_SUFFIX}> BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/${name}${PSN00BSDK_SHARED_LIBRARY_SUFFIX} - VERBATIM ) else() message(FATAL_ERROR "Invalid library type: ${type} (must be STATIC, OBJECT, SHARED or MODULE)") diff --git a/template/CMakePresets.json b/template/CMakePresets.json index d08b334..97d8428 100644 --- a/template/CMakePresets.json +++ b/template/CMakePresets.json @@ -1,22 +1,25 @@ { - "version": 2, + "version": 3, "cmakeMinimumRequired": { "major": 3, - "minor": 20, + "minor": 21, "patch": 0 }, "configurePresets": [ { - "name": "default", - "displayName": "Default configuration", - "description": "Use this preset to build the project using PSn00bSDK.", - "generator": "Ninja", - "binaryDir": "${sourceDir}/build", + "name": "default", + "displayName": "Default configuration", + "description": "Use this preset to build the project using PSn00bSDK.", + "generator": "Ninja", + "toolchainFile": "$env{PSN00BSDK_LIBS}/cmake/sdk.cmake", + "binaryDir": "${sourceDir}/build", "cacheVariables": { - "CMAKE_BUILD_TYPE": "Debug", - "CMAKE_TOOLCHAIN_FILE": "$env{PSN00BSDK_LIBS}/cmake/sdk.cmake", - "PSN00BSDK_TC": "", - "PSN00BSDK_TARGET": "mipsel-none-elf" + "CMAKE_BUILD_TYPE": "Debug", + "PSN00BSDK_TC": "", + "PSN00BSDK_TARGET": "mipsel-none-elf" + }, + "warnings": { + "dev": false } } ] -- cgit v1.2.3 From b458ea70700739bf8a64217af369c7ace08fc954 Mon Sep 17 00:00:00 2001 From: spicyjpeg Date: Thu, 13 Oct 2022 23:21:32 +0200 Subject: Fix dropped IRQs, clean up psxcd and psxetc logging --- doc/known_bugs.md | 7 +-- examples/system/childexec/CMakeLists.txt | 18 +++--- examples/system/childexec/child/child.c | 8 +-- examples/system/childexec/parent.c | 27 +++------ libpsn00b/psxcd/isofs.c | 20 +++---- libpsn00b/psxcd/psxcd.c | 9 +-- libpsn00b/psxetc/dl.c | 98 ++++++++++++++------------------ libpsn00b/psxetc/interrupts.c | 50 +++++++++------- 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; isize = 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](); + } } } -- cgit v1.2.3 From 6eabb5aa549254c2272cedee26d4245f31f2dc7a Mon Sep 17 00:00:00 2001 From: spicyjpeg Date: Sat, 15 Oct 2022 10:02:35 +0200 Subject: Update sound/spustream, clean up other examples --- examples/cdrom/cdbrowse/iso.xml | 1 - examples/cdrom/cdxa/iso.xml | 1 - examples/graphics/tilesasm/iso.xml | 34 ----------- examples/graphics/tilesasm/system.cnf | 4 -- examples/io/pads/main.c | 22 +++---- examples/io/system573/iso.xml | 2 - examples/io/system573/main.c | 22 +++---- examples/sound/spustream/iso.xml | 1 - examples/sound/spustream/main.c | 91 +++++++++++++++++----------- examples/system/dynlink/library/balls.c | 27 +++++---- examples/system/dynlink/library/cube.c | 14 +++-- examples/system/dynlink/library/dll_common.h | 11 ++-- examples/system/dynlink/main.c | 17 +++--- template/iso.xml | 2 +- 14 files changed, 114 insertions(+), 135 deletions(-) delete mode 100644 examples/graphics/tilesasm/iso.xml delete mode 100644 examples/graphics/tilesasm/system.cnf diff --git a/examples/cdrom/cdbrowse/iso.xml b/examples/cdrom/cdbrowse/iso.xml index 5ffca18..771b0e9 100644 --- a/examples/cdrom/cdbrowse/iso.xml +++ b/examples/cdrom/cdbrowse/iso.xml @@ -17,7 +17,6 @@ - diff --git a/examples/cdrom/cdxa/iso.xml b/examples/cdrom/cdxa/iso.xml index b98a16f..6715f94 100644 --- a/examples/cdrom/cdxa/iso.xml +++ b/examples/cdrom/cdxa/iso.xml @@ -17,7 +17,6 @@ - diff --git a/examples/graphics/tilesasm/iso.xml b/examples/graphics/tilesasm/iso.xml deleted file mode 100644 index 477c636..0000000 --- a/examples/graphics/tilesasm/iso.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/examples/graphics/tilesasm/system.cnf b/examples/graphics/tilesasm/system.cnf deleted file mode 100644 index e221726..0000000 --- a/examples/graphics/tilesasm/system.cnf +++ /dev/null @@ -1,4 +0,0 @@ -BOOT=cdrom:\template.exe;1 -TCB=4 -EVENT=10 -STACK=801FFFF0 diff --git a/examples/io/pads/main.c b/examples/io/pads/main.c index 17bf331..29bb527 100644 --- a/examples/io/pads/main.c +++ b/examples/io/pads/main.c @@ -62,17 +62,17 @@ static const char *const PAD_TYPEIDS[] = { #define BGCOLOR_B 0 typedef struct { - DISPENV disp; - DRAWENV draw; -} DB; + DISPENV disp; + DRAWENV draw; +} Framebuffer; typedef struct { - DB db[2]; - uint32_t db_active; -} CONTEXT; + Framebuffer db[2]; + int db_active; +} RenderContext; -void init_context(CONTEXT *ctx) { - DB *db; +void init_context(RenderContext *ctx) { + Framebuffer *db; ResetGraph(0); ctx->db_active = 0; @@ -99,8 +99,8 @@ void init_context(CONTEXT *ctx) { FntOpen(8, 16, 304, 208, 2, 512); } -void display(CONTEXT *ctx) { - DB *db; +void display(RenderContext *ctx) { + Framebuffer *db; DrawSync(0); VSync(0); @@ -227,7 +227,7 @@ void poll_cb(uint32_t port, const volatile uint8_t *buff, size_t rx_len) { /* Main */ -static CONTEXT ctx; +static RenderContext ctx; int main(int argc, const char* argv[]) { init_context(&ctx); diff --git a/examples/io/system573/iso.xml b/examples/io/system573/iso.xml index 0bb84d5..2226089 100644 --- a/examples/io/system573/iso.xml +++ b/examples/io/system573/iso.xml @@ -30,8 +30,6 @@ --> - - diff --git a/examples/io/system573/main.c b/examples/io/system573/main.c index 3404ee4..39ddb64 100644 --- a/examples/io/system573/main.c +++ b/examples/io/system573/main.c @@ -83,17 +83,17 @@ const char *const IO_BOARD_TYPES[] = { #define BGCOLOR_B 0 typedef struct { - DISPENV disp; - DRAWENV draw; -} DB; + DISPENV disp; + DRAWENV draw; +} Framebuffer; typedef struct { - DB db[2]; - uint32_t db_active; -} CONTEXT; + Framebuffer db[2]; + int db_active; +} RenderContext; -void init_context(CONTEXT *ctx) { - DB *db; +void init_context(RenderContext *ctx) { + Framebuffer *db; ResetGraph(0); ctx->db_active = 0; @@ -120,8 +120,8 @@ void init_context(CONTEXT *ctx) { FntOpen(8, 16, 304, 208, 2, 512); } -void display(CONTEXT *ctx) { - DB *db; +void display(RenderContext *ctx) { + Framebuffer *db; DrawSync(0); VSync(0); @@ -135,7 +135,7 @@ void display(CONTEXT *ctx) { /* Main */ -static CONTEXT ctx; +static RenderContext ctx; #define SHOW_STATUS(...) { FntPrint(-1, __VA_ARGS__); FntFlush(-1); display(&ctx); } #define SHOW_ERROR(...) { SHOW_STATUS(__VA_ARGS__); while (1) __asm__("nop"); } diff --git a/examples/sound/spustream/iso.xml b/examples/sound/spustream/iso.xml index 3807046..050d673 100644 --- a/examples/sound/spustream/iso.xml +++ b/examples/sound/spustream/iso.xml @@ -17,7 +17,6 @@ - diff --git a/examples/sound/spustream/main.c b/examples/sound/spustream/main.c index 6179179..acd4f60 100644 --- a/examples/sound/spustream/main.c +++ b/examples/sound/spustream/main.c @@ -117,17 +117,17 @@ #define BGCOLOR_B 0 typedef struct { - DISPENV disp; - DRAWENV draw; -} DB; + DISPENV disp; + DRAWENV draw; +} Framebuffer; typedef struct { - DB db[2]; - int db_active; -} CONTEXT; + Framebuffer db[2]; + int db_active; +} RenderContext; -void init_context(CONTEXT *ctx) { - DB *db; +void init_context(RenderContext *ctx) { + Framebuffer *db; ResetGraph(0); ctx->db_active = 0; @@ -154,8 +154,8 @@ void init_context(CONTEXT *ctx) { FntOpen(8, 16, 304, 208, 2, 512); } -void display(CONTEXT *ctx) { - DB *db; +void display(RenderContext *ctx) { + Framebuffer *db; DrawSync(0); VSync(0); @@ -181,13 +181,9 @@ void display(CONTEXT *ctx) { #define CHUNK_SIZE (BUFFER_SIZE * NUM_CHANNELS) typedef struct { - uint32_t lba; - uint32_t length; - uint32_t pos; - - uint32_t spu_addr; - uint32_t spu_pos; - uint32_t db_active; + int lba, length, pos; + int spu_addr, spu_pos; + int db_active; } StreamContext; static volatile StreamContext str_ctx; @@ -316,10 +312,10 @@ void init_stream(CdlFILE *file) { } void start_stream(void) { - SPU_KEY_OFF = CHANNEL_MASK; + uint32_t addr = BUFFER_START_ADDR + CHUNK_SIZE * str_ctx.db_active; for (int i = 0; i < NUM_CHANNELS; i++) { - SPU_CH_ADDR(i) = SPU_RAM_ADDR(BUFFER_START_ADDR + BUFFER_SIZE * i); + SPU_CH_ADDR(i) = SPU_RAM_ADDR(addr + BUFFER_SIZE * i); SPU_CH_FREQ(i) = SAMPLE_RATE; SPU_CH_ADSR(i) = 0x1fee80ff; } @@ -332,13 +328,25 @@ void start_stream(void) { SPU_CH_VOL_L(1) = 0x0000; SPU_CH_VOL_R(1) = 0x3fff; - SPU_KEY_ON = CHANNEL_MASK; spu_irq_handler(); + SPU_KEY_ON = CHANNEL_MASK; +} + +// This is basically a variant of reset_spu_channels() that only resets the +// channels used to play the stream, to (again) prevent them from triggering +// the SPU IRQ while the stream is paused. +void stop_stream(void) { + SPU_KEY_OFF = CHANNEL_MASK; + + for (int i = 0; i < NUM_CHANNELS; i++) + SPU_CH_ADDR(i) = SPU_RAM_ADDR(DUMMY_BLOCK_ADDR); + + SPU_KEY_ON = CHANNEL_MASK; } /* Main */ -static CONTEXT ctx; +static RenderContext ctx; #define SHOW_STATUS(...) { FntPrint(-1, __VA_ARGS__); FntFlush(-1); display(&ctx); } #define SHOW_ERROR(...) { SHOW_STATUS(__VA_ARGS__); while (1) __asm__("nop"); } @@ -351,7 +359,13 @@ int main(int argc, const char* argv[]) { CdInit(); reset_spu_channels(); - SHOW_STATUS("LOCATING STREAM FILE\n"); + // Set up controller polling. + uint8_t pad_buff[2][34]; + InitPAD(pad_buff[0], 34, pad_buff[1], 34); + StartPAD(); + ChangeClearPAD(0); + + SHOW_STATUS("OPENING STREAM FILE\n"); CdlFILE file; if (!CdSearchFile(&file, "\\STREAM.BIN")) @@ -361,28 +375,27 @@ int main(int argc, const char* argv[]) { init_stream(&file); start_stream(); - // Set up controller polling. - uint8_t pad_buff[2][34]; - InitPAD(pad_buff[0], 34, pad_buff[1], 34); - StartPAD(); - ChangeClearPAD(0); + int paused = 0; uint16_t sample_rate = SAMPLE_RATE; uint16_t last_buttons = 0xffff; while (1) { - FntPrint(-1, "PLAYING SPU STREAM\n"); + FntPrint(-1, "PLAYING SPU STREAM\n\n"); + + FntPrint(-1, "BUFFER: %d\nSTATUS: ", str_ctx.db_active); if (str_ctx.spu_pos >= CHUNK_SIZE) - FntPrint(-1, "STATUS: IDLE\n\n"); - else if (!str_ctx.spu_pos) - FntPrint(-1, "STATUS: SEEKING\n\n"); + FntPrint(-1, "IDLE\n\n"); + else if (str_ctx.spu_pos) + FntPrint(-1, "BUFFERING\n\n"); else - FntPrint(-1, "STATUS: BUFFERING\n\n"); + FntPrint(-1, "SEEKING\n\n"); - FntPrint(-1, "POSITION=%5d/%5d\n", str_ctx.pos, str_ctx.length); - FntPrint(-1, "BUFFERED=%5d/%5d\n", str_ctx.spu_pos, CHUNK_SIZE); - FntPrint(-1, "SMP RATE=%5d HZ\n\n", (sample_rate * 44100) >> 12); + FntPrint(-1, "POSITION: %5d/%5d\n", str_ctx.pos, str_ctx.length); + FntPrint(-1, "BUFFERED: %5d/%5d\n", str_ctx.spu_pos, CHUNK_SIZE); + FntPrint(-1, "SMP RATE: %5d HZ\n\n", (sample_rate * 44100) >> 12); + FntPrint(-1, "[START] %s\n", paused ? "RESUME" : "PAUSE"); FntPrint(-1, "[LEFT/RIGHT] SEEK\n"); FntPrint(-1, "[O] RESET POSITION\n"); FntPrint(-1, "[UP/DOWN] CHANGE SAMPLE RATE\n"); @@ -399,6 +412,14 @@ int main(int argc, const char* argv[]) { if ((pad->type != 4) && (pad->type != 5) && (pad->type != 7)) continue; + if ((last_buttons & PAD_START) && !(pad->btn & PAD_START)) { + paused ^= 1; + if (paused) + stop_stream(); + else + start_stream(); + } + // Seeking by an arbitrary number of sectors isn't a problem as // spu_irq_handler() always realigns the counter. if (!(pad->btn & PAD_LEFT)) diff --git a/examples/system/dynlink/library/balls.c b/examples/system/dynlink/library/balls.c index c537167..457ec4e 100644 --- a/examples/system/dynlink/library/balls.c +++ b/examples/system/dynlink/library/balls.c @@ -21,7 +21,7 @@ typedef struct { int16_t x, y; int16_t xdir, ydir; uint8_t r, g, b, p; -} BALL_TYPE; +} Ball; #define MAX_BALLS 512 @@ -35,12 +35,13 @@ typedef struct { // initialize variables or hardware. static uint32_t frame = 0; -static BALL_TYPE balls[MAX_BALLS]; +static Ball balls[MAX_BALLS]; static TIM_IMAGE ball_tim; -void init(CONTEXT *ctx) { - GetTimInfo(ball16c, &ball_tim); +void init(RenderContext *ctx) { + Framebuffer *db = &(ctx->db[ctx->db_active]); + GetTimInfo(ball16c, &ball_tim); LoadImage(ball_tim.prect, ball_tim.paddr); if (ball_tim.mode & 8) LoadImage(ball_tim.crect, ball_tim.caddr); @@ -48,10 +49,10 @@ void init(CONTEXT *ctx) { // Initialize the balls by giving them a random initial position, velocity // and color. for (uint32_t i = 0; i < MAX_BALLS; i++) { - BALL_TYPE *b = &(balls[i]); + Ball *b = &(balls[i]); - b->x = rand() % (ctx->xres - 16); - b->y = rand() % (ctx->yres - 16); + b->x = rand() % (db->draw.clip.w - 16); + b->y = rand() % (db->draw.clip.h - 16); b->xdir = ((rand() & 1) ? 1 : -1) * ((rand() % 3) + 1); b->ydir = ((rand() & 1) ? 1 : -1) * ((rand() % 3) + 1); b->r = rand() & 0xff; @@ -60,12 +61,12 @@ void init(CONTEXT *ctx) { } } -void render(CONTEXT *ctx, uint16_t buttons) { - DB *db = &(ctx->db[ctx->db_active]); - SPRT_16 *sprt = (SPRT_16 *) ctx->db_nextpri; +void render(RenderContext *ctx, uint16_t buttons) { + Framebuffer *db = &(ctx->db[ctx->db_active]); + SPRT_16 *sprt = (SPRT_16 *) ctx->db_nextpri; for (uint32_t i = 0; i < MAX_BALLS; i++) { - BALL_TYPE *b = &(balls[i]); + Ball *b = &(balls[i]); setSprt16(sprt); @@ -85,12 +86,12 @@ void render(CONTEXT *ctx, uint16_t buttons) { if ( (b->x < 0) || - ((b->x + 16) > ctx->xres) + ((b->x + 16) > db->draw.clip.w) ) b->xdir *= -1; if ( (b->y < 0) || - ((b->y + 16) > ctx->yres) + ((b->y + 16) > db->draw.clip.h) ) b->ydir *= -1; } diff --git a/examples/system/dynlink/library/cube.c b/examples/system/dynlink/library/cube.c index 84fe552..22a805f 100644 --- a/examples/system/dynlink/library/cube.c +++ b/examples/system/dynlink/library/cube.c @@ -81,16 +81,18 @@ static SVECTOR rot = { 0 }; static VECTOR pos = { 0, 0, 400 }; static MATRIX mtx, lmtx; -void init(CONTEXT *ctx) { +void init(RenderContext *ctx) { + Framebuffer *db = &(ctx->db[ctx->db_active]); + InitGeom(); - gte_SetGeomOffset(ctx->xres / 2, ctx->yres / 2); - gte_SetGeomScreen(ctx->xres / 2); + gte_SetGeomOffset(db->draw.clip.w / 2, db->draw.clip.h / 2); + gte_SetGeomScreen(db->draw.clip.w / 2); gte_SetBackColor(63, 63, 63); gte_SetColorMatrix(&color_mtx); } -void render(CONTEXT *ctx, uint16_t buttons) { +void render(RenderContext *ctx, uint16_t buttons) { RotMatrix(&rot, &mtx); TransMatrix(&mtx, &pos); MulMatrix0(&light_mtx, &mtx, &lmtx); @@ -104,8 +106,8 @@ void render(CONTEXT *ctx, uint16_t buttons) { rot.vx += step; rot.vz += step; - DB *db = &(ctx->db[ctx->db_active]); - POLY_F4 *pol4 = (POLY_F4 *) ctx->db_nextpri; + Framebuffer *db = &(ctx->db[ctx->db_active]); + POLY_F4 *pol4 = (POLY_F4 *) ctx->db_nextpri; for (uint32_t i = 0; i < CUBE_FACES; i++) { int32_t p; diff --git a/examples/system/dynlink/library/dll_common.h b/examples/system/dynlink/library/dll_common.h index 315a993..6606bda 100644 --- a/examples/system/dynlink/library/dll_common.h +++ b/examples/system/dynlink/library/dll_common.h @@ -19,13 +19,12 @@ typedef struct { DRAWENV draw; uint32_t ot[OT_LEN]; uint8_t p[PACKET_LEN]; -} DB; +} Framebuffer; typedef struct { - uint16_t xres, yres; - DB db[2]; - uint32_t db_active; - uint8_t *db_nextpri; -} CONTEXT; + Framebuffer db[2]; + int db_active; + uint8_t *db_nextpri; +} RenderContext; #endif diff --git a/examples/system/dynlink/main.c b/examples/system/dynlink/main.c index fff7aa5..fcce5b1 100644 --- a/examples/system/dynlink/main.c +++ b/examples/system/dynlink/main.c @@ -83,12 +83,10 @@ static const char *const DLL_FILENAMES[] = { #define BGCOLOR_G 24 #define BGCOLOR_B 0 -void init_context(CONTEXT *ctx) { - DB *db; +void init_context(RenderContext *ctx) { + Framebuffer *db; ResetGraph(0); - ctx->xres = SCREEN_XRES; - ctx->yres = SCREEN_YRES; ctx->db_active = 0; db = &(ctx->db[0]); @@ -121,8 +119,8 @@ void init_context(CONTEXT *ctx) { FntOpen(4, 12, 312, 32, 2, 256); } -void display(CONTEXT *ctx) { - DB *db; +void display(RenderContext *ctx) { + Framebuffer *db; DrawSync(0); VSync(0); @@ -185,13 +183,14 @@ void *custom_resolver(DLL *dll, const char *name) { // and the pointers returned by DL_GetDLLSymbol() should be saved and reused as // much as possible. typedef struct { - void (*init)(CONTEXT *); - void (*render)(CONTEXT *, uint16_t buttons); + void (*init)(RenderContext *); + void (*render)(RenderContext *, uint16_t buttons); } DLL_API; static DLL *dll = 0; static DLL_API dll_api; -static CONTEXT ctx; + +static RenderContext ctx; /* Main */ diff --git a/template/iso.xml b/template/iso.xml index 477c636..87162b2 100644 --- a/template/iso.xml +++ b/template/iso.xml @@ -24,7 +24,7 @@ - + -- cgit v1.2.3 From 03434a230d8c3ed2e32a3885128e05e42ee11769 Mon Sep 17 00:00:00 2001 From: spicyjpeg Date: Sun, 16 Oct 2022 23:52:19 +0200 Subject: Add mdec/strvideo example, fix psxpress bug --- examples/mdec/strvideo/CMakeLists.txt | 24 ++ examples/mdec/strvideo/iso.xml | 28 +++ examples/mdec/strvideo/main.c | 439 ++++++++++++++++++++++++++++++++++ examples/mdec/strvideo/system.cnf | 4 + libpsn00b/include/psxcd.h | 7 +- libpsn00b/psxcd/getsector.c | 23 ++ libpsn00b/psxcd/psxcd.c | 10 +- libpsn00b/psxpress/mdec.c | 5 + libpsn00b/psxpress/vlc.s | 10 +- libpsn00b/psxpress/vlc2.c | 5 +- 10 files changed, 539 insertions(+), 16 deletions(-) create mode 100644 examples/mdec/strvideo/CMakeLists.txt create mode 100644 examples/mdec/strvideo/iso.xml create mode 100644 examples/mdec/strvideo/main.c create mode 100644 examples/mdec/strvideo/system.cnf diff --git a/examples/mdec/strvideo/CMakeLists.txt b/examples/mdec/strvideo/CMakeLists.txt new file mode 100644 index 0000000..d41556b --- /dev/null +++ b/examples/mdec/strvideo/CMakeLists.txt @@ -0,0 +1,24 @@ +# PSn00bSDK example CMake script +# (C) 2021 spicyjpeg - MPL licensed + +cmake_minimum_required(VERSION 3.21) + +project( + strvideo + LANGUAGES C + VERSION 1.0.0 + DESCRIPTION "PSn00bSDK .STR video playback example" + HOMEPAGE_URL "http://lameguy64.net/?page=psn00bsdk" +) + +file(GLOB _sources *.c) +psn00bsdk_add_executable(strvideo GPREL ${_sources}) +#psn00bsdk_add_cd_image(strvideo_iso strvideo iso.xml DEPENDS strvideo) + +install( + FILES + #${PROJECT_BINARY_DIR}/strvideo.bin + #${PROJECT_BINARY_DIR}/strvideo.cue + ${PROJECT_BINARY_DIR}/strvideo.exe + TYPE BIN +) diff --git a/examples/mdec/strvideo/iso.xml b/examples/mdec/strvideo/iso.xml new file mode 100644 index 0000000..65e0ff5 --- /dev/null +++ b/examples/mdec/strvideo/iso.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + diff --git a/examples/mdec/strvideo/main.c b/examples/mdec/strvideo/main.c new file mode 100644 index 0000000..842bbb8 --- /dev/null +++ b/examples/mdec/strvideo/main.c @@ -0,0 +1,439 @@ +/* + * PSn00bSDK .STR FMV playback example + * (C) 2022 spicyjpeg - MPL licensed + * + * This example demonstrates playback of full-motion video in the standard .STR + * format, using the MDEC for frame decoding and XA for audio. Decoded frames + * are transferred directly to the main framebuffer in this example, but could + * also be output to another VRAM location and used as a background or texture + * for a 2D or 3D scene. + * + * Playing video files requires setting up a fairly complex pipeline, involving + * several buffers and components working in parallel: + * + * - .STR sectors are read continuously from the CD and each frame, usually + * spanning multiple sectors, is reassembled (demuxed) into a buffer in + * memory. In this example the task is performed by cd_sector_handler(). The + * CD drive handles XA-ADPCM sectors automatically, so no CPU intervention is + * necessary to play the audio track interleaved with the video. + * - Once a full frame has been demuxed, the bitstream data is parsed and + * decompressed by the CPU (using DecDCTvlc()) to an array of run-length + * codes to be fed to the MDEC. This is done in the main loop. + * - At the same time the last frame decompressed is read from RAM by the MDEC, + * which decodes it and outputs one 16-pixel-wide vertical slice at a time. + * - When a slice is ready, it is uploaded by mdec_dma_handler() to the current + * framebuffer in VRAM while the MDEC is decoding the next slice. + * A text overlay is drawn on top of the framebuffer using the GPU after the + * entire frame has been decoded. + * + * Since pretty much all buffers used are going to be read and written at the + * same time, double buffering is required for all of them. Every part of the + * pipeline must also run in lockstep with each other to prevent frame + * corruption, hence several functions and flag variables are used to stall the + * main loop until a frame is available for decoding and the MDEC is ready. + * Playback is stopped when a sector with the end-of-file flag set in the XA + * subheader (added at the end of the file by most .STR encoders) is + * encountered; in order to access the subheader, this example requests 2340 + * bytes of data for each sector (rather than the usual 2048) from the drive. + * + * Note that PSn00bSDK's bitstream decoding API only supports version 1 and 2 + * bitstreams currently, so make sure your .STR files are encoded as v2 and not + * v3. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Uncomment to display the video in 24bpp mode. Note that the GPU does not +// support 24bpp rendering, so the text overlay is only enabled in 16bpp mode. +//#define DISP_24BPP + +/* Display/GPU context utilities */ + +#define SCREEN_XRES 320 +#define SCREEN_YRES 240 + +#define BGCOLOR_R 0 +#define BGCOLOR_G 0 +#define BGCOLOR_B 0 + +typedef struct { + DISPENV disp; + DRAWENV draw; +} Framebuffer; + +typedef struct { + Framebuffer db[2]; + int db_active; +} RenderContext; + +void init_context(RenderContext *ctx) { + Framebuffer *db; + + ResetGraph(0); + ctx->db_active = 0; + + db = &(ctx->db[0]); + SetDefDispEnv(&(db->disp), 0, 0, SCREEN_XRES, SCREEN_YRES); + SetDefDrawEnv(&(db->draw), 0, SCREEN_YRES, SCREEN_XRES, SCREEN_YRES); + setRGB0(&(db->draw), BGCOLOR_R, BGCOLOR_G, BGCOLOR_B); + db->draw.isbg = 1; + db->draw.dtd = 1; + + db = &(ctx->db[1]); + SetDefDispEnv(&(db->disp), 0, SCREEN_YRES, SCREEN_XRES, SCREEN_YRES); + SetDefDrawEnv(&(db->draw), 0, 0, SCREEN_XRES, SCREEN_YRES); + setRGB0(&(db->draw), BGCOLOR_R, BGCOLOR_G, BGCOLOR_B); + db->draw.isbg = 1; + db->draw.dtd = 1; + + PutDrawEnv(&(db->draw)); + //PutDispEnv(&(db->disp)); + + // Create a text stream at the top of the screen. + FntLoad(960, 0); + FntOpen(4, 12, 312, 16, 2, 256); +} + +void display(RenderContext *ctx, int sync) { + Framebuffer *db; + ctx->db_active ^= 1; + + DrawSync(0); + if (sync) + VSync(0); + + db = &(ctx->db[ctx->db_active]); + PutDrawEnv(&(db->draw)); + PutDispEnv(&(db->disp)); + SetDispMask(1); +} + +/* CD and MDEC interrupt handlers */ + +#ifdef DISP_24BPP +#define BLOCK_SIZE 24 +#else +#define BLOCK_SIZE 16 +#define DRAW_OVERLAY +#endif + +#define VRAM_X_COORD(x) ((x) * BLOCK_SIZE / 16) + +// All non-audio sectors in .STR files begin with this 32-byte header, which +// contains metadata about the sector and is followed by a chunk of frame +// bitstream data. +// https://problemkaputt.de/psx-spx.htm#cdromfilevideostrstreamingandbspicturecompressionsony +typedef struct { + uint16_t magic; // Always 0x0160 + uint16_t type; // 0x8001 for MDEC + uint16_t sector_id; // Chunk number (0 = first chunk of this frame) + uint16_t sector_count; // Total number of chunks for this frame + uint32_t frame_id; // Frame number + uint32_t bs_length; // Total length of this frame in bytes + + uint16_t width, height; + uint8_t bs_header[8]; + uint32_t _reserved; +} STR_Header; + +// https://problemkaputt.de/psx-spx.htm#cdromxasubheaderfilechannelinterleave +typedef struct { + uint8_t file, channel; + uint8_t submode, coding_info; +} XA_Header; + +// https://problemkaputt.de/psx-spx.htm#cdromsectorencoding +typedef struct { + CdlLOC pos; + XA_Header xa_header[2]; + STR_Header str_header; + uint8_t data[2016]; + uint32_t edc; + uint8_t ecc[276]; +} STR_Sector; + +typedef struct { + uint16_t width, height; + uint32_t bs_data[0x2000]; // Bitstream data read from the disc + uint32_t mdec_data[0x8000]; // Decompressed data to be fed to the MDEC +} StreamBuffer; + +typedef struct { + StreamBuffer frames[2]; + uint32_t slices[2][BLOCK_SIZE * SCREEN_YRES / 2]; + + int frame_id, sector_count; + int dropped_frames; + RECT slice_pos; + int frame_width; + + volatile int8_t sector_pending, frame_ready; + volatile int8_t cur_frame, cur_slice; +} StreamContext; + +StreamContext str_ctx; + +// This buffer is used by cd_sector_handler() as a temporary area for sectors +// read from the CD. Due to DMA limitations it can't be allocated on the stack +// (especially not in the interrupt callbacks' stack, whose size is very +// limited). +STR_Sector sector_buffer; + +void cd_sector_handler(void) { + // Fetch the .STR header of the sector that has been read and check if the + // end-of-file bit is set in the XA header. + CdGetSector(§or_buffer, sizeof(STR_Sector) / 4); + + if ( + (sector_buffer.xa_header[0].submode & (1 << 7)) || + (sector_buffer.xa_header[1].submode & (1 << 7)) + ) { + CdControlF(CdlPause, 0); + str_ctx.frame_ready = -1; + return; + } + + STR_Header *header = §or_buffer.str_header; + StreamBuffer *frame = &str_ctx.frames[str_ctx.cur_frame]; + + // Ignore any non-MDEC sectors that might be present in the stream. + if (header->type != 0x8001) + return; + + // If this sector is actually part of a new frame, validate the sectors + // that have been read so far and flip the bitstream data buffers. + if (header->frame_id != str_ctx.frame_id) { + // Do not set the ready flag if any sector has been missed. + if (str_ctx.sector_count) + str_ctx.dropped_frames++; + else + str_ctx.frame_ready = 1; + + str_ctx.frame_id = header->frame_id; + str_ctx.sector_count = header->sector_count; + str_ctx.cur_frame ^= 1; + + frame = &str_ctx.frames[str_ctx.cur_frame]; + + // Initialize the next frame. Dimensions must be rounded up to the + // nearest multiple of 16 as the MDEC operates on 16x16 pixel blocks. + frame->width = (header->width + 15) & 0xfff0; + frame->height = (header->height + 15) & 0xfff0; + } + + // Append the payload contained in this sector to the current buffer. + memcpy( + &(frame->bs_data[2016 / 4 * header->sector_id]), + sector_buffer.data, + 2016 + ); + str_ctx.sector_count--; +} + +void mdec_dma_handler(void) { + // Handle any sectors that were not processed by cd_event_handler() (see + // below) while a DMA transfer from the MDEC was in progress. As the MDEC + // has just finished decoding a slice, they can be safely handled now. + if (str_ctx.sector_pending) { + cd_sector_handler(); + str_ctx.sector_pending = 0; + } + + // Upload the decoded slice to VRAM and start decoding the next slice (into + // another buffer) if any. + LoadImage(&str_ctx.slice_pos, str_ctx.slices[str_ctx.cur_slice]); + + str_ctx.cur_slice ^= 1; + str_ctx.slice_pos.x += BLOCK_SIZE; + + if (str_ctx.slice_pos.x < str_ctx.frame_width) + DecDCTout( + str_ctx.slices[str_ctx.cur_slice], + BLOCK_SIZE * str_ctx.slice_pos.h / 2 + ); +} + +void cd_event_handler(int event, uint8_t *payload) { + // Ignore all events other than a sector being ready. + if (event != CdlDataReady) + return; + + // Only handle sectors immediately if the MDEC is not decoding a frame, + // otherwise defer handling to mdec_dma_handler(). This is a workaround for + // a hardware conflict between the DMA channels used for the CD drive and + // MDEC output, which shall not run simultaneously. + if (DecDCTinSync(1)) + str_ctx.sector_pending = 1; + else + cd_sector_handler(); +} + +/* Stream helpers */ + +void init_stream(void) { + EnterCriticalSection(); + DMACallback(1, &mdec_dma_handler); + CdReadyCallback(&cd_event_handler); + ExitCriticalSection(); + + // Set the maximum amount of data DecDCTvlc() can output and copy the + // lookup table used for decompression to the scratchpad area. This is + // optional but makes the decompressor slightly faster. See the libpsxpress + // documentation for more details. + DecDCTvlcSize(0x8000); + DecDCTvlcCopyTable((DECDCTTAB *) 0x1f800000); + + str_ctx.dropped_frames = 0; + str_ctx.cur_frame = 0; + str_ctx.cur_slice = 0; +} + +StreamBuffer *get_next_frame(void) { + while (!str_ctx.frame_ready) + __asm__ volatile(""); + + if (str_ctx.frame_ready < 0) + return 0; + + str_ctx.frame_ready = 0; + return &str_ctx.frames[str_ctx.cur_frame ^ 1]; +} + +void start_stream(CdlFILE *file) { + str_ctx.frame_id = -1; + str_ctx.sector_pending = 0; + str_ctx.frame_ready = 0; + + CdSync(0, 0); + + // Configure the CD drive to read 2340-byte sectors at 2x speed and to + // play any XA-ADPCM sectors that might be interleaved with the video data. + uint8_t mode = CdlModeSize | CdlModeRT | CdlModeSpeed; + CdControl(CdlSetmode, (const uint8_t *) &mode, 0); + + // Start reading in real-time mode (i.e. without retrying in case of read + // errors) and wait for the first frame to be buffered. + CdControl(CdlReadS, &(file->pos), 0); + + get_next_frame(); +} + +/* Main */ + +static RenderContext ctx; + +#define SHOW_STATUS(...) { FntPrint(-1, __VA_ARGS__); FntFlush(-1); display(&ctx, 1); } +#define SHOW_ERROR(...) { SHOW_STATUS(__VA_ARGS__); while (1) __asm__("nop"); } + +int main(int argc, const char* argv[]) { + init_context(&ctx); + + SHOW_STATUS("INITIALIZING\n"); + SpuInit(); + CdInit(); + InitGeom(); // Required for PSn00bSDK's DecDCTvlc() + DecDCTReset(0); + + SHOW_STATUS("OPENING VIDEO FILE\n"); + + CdlFILE file; + if (!CdSearchFile(&file, "\\VIDEO.STR")) + SHOW_ERROR("FAILED TO FIND VIDEO.STR\n"); + + init_stream(); + start_stream(&file); + + // Disable framebuffer clearing to get rid of flickering during playback. + display(&ctx, 1); + ctx.db[0].draw.isbg = 0; + ctx.db[1].draw.isbg = 0; +#ifdef DISP_24BPP + ctx.db[0].disp.isrgb24 = 1; + ctx.db[1].disp.isrgb24 = 1; +#endif + + int decode_errors = 0; + + while (1) { + // Wait for a full frame to be read from the disc and decompress the + // bitstream into the format expected by the MDEC. If the video has + // ended, restart playback from the beginning. + StreamBuffer *frame = get_next_frame(); + if (!frame) { + start_stream(&file); + continue; + } + +#ifdef DRAW_OVERLAY + // Measure CPU usage of the decompressor using the hblank counter. + int total_time = TIMER_VALUE(1) + 1; + TIMER_VALUE(1) = 0; +#endif + + if (DecDCTvlc(frame->bs_data, frame->mdec_data)) { + decode_errors++; + continue; + } + +#ifdef DRAW_OVERLAY + int cpu_usage = TIMER_VALUE(1) * 100 / total_time; +#endif + + // Wait for the MDEC to finish decoding the previous frame, then flip + // the framebuffers to display it and prepare the buffer for the next + // frame. + // NOTE: you should *not* call VSync(0) during playback, as the refresh + // rate of the GPU is not synced to the video's frame rate. If you want + // to minimize screen tearing, consider triple buffering instead (i.e. + // always keep 2 fully decoded frames in VRAM and use VSyncCallback() + // to register a function that displays the next decoded frame whenever + // vblank occurs). + DecDCTinSync(0); + DecDCToutSync(0); + +#ifdef DRAW_OVERLAY + FntPrint(-1, "FRAME:%5d READ ERRORS: %5d\n", str_ctx.frame_id, str_ctx.dropped_frames); + FntPrint(-1, "CPU: %5d%% DECODE ERRORS:%5d\n", cpu_usage, decode_errors); + FntFlush(-1); +#endif + display(&ctx, 0); + + // Feed the newly decompressed frame to the MDEC. The MDEC will not + // actually start decoding it until an output buffer is also configured + // by calling DecDCTout() (see below). +#ifdef DISP_24BPP + DecDCTin(frame->mdec_data, DECDCT_MODE_24BPP); +#else + DecDCTin(frame->mdec_data, DECDCT_MODE_16BPP); +#endif + + // Place the frame at the center of the currently active framebuffer + // and start decoding the first slice. Decoded slices will be uploaded + // to VRAM in the background by mdec_dma_handler(). + RECT *fb_clip = &(ctx.db[ctx.db_active].draw.clip); + int x_offset = (fb_clip->w - frame->width) / 2; + int y_offset = (fb_clip->h - frame->height) / 2; + + str_ctx.slice_pos.x = VRAM_X_COORD(fb_clip->x + x_offset); + str_ctx.slice_pos.y = fb_clip->y + y_offset; + str_ctx.slice_pos.w = BLOCK_SIZE; + str_ctx.slice_pos.h = frame->height; + str_ctx.frame_width = VRAM_X_COORD(frame->width); + + DecDCTout( + str_ctx.slices[str_ctx.cur_slice], + BLOCK_SIZE * str_ctx.slice_pos.h / 2 + ); + } + + return 0; +} diff --git a/examples/mdec/strvideo/system.cnf b/examples/mdec/strvideo/system.cnf new file mode 100644 index 0000000..d199117 --- /dev/null +++ b/examples/mdec/strvideo/system.cnf @@ -0,0 +1,4 @@ +BOOT=cdrom:\strvideo.exe;1 +TCB=4 +EVENT=10 +STACK=801FFFF0 diff --git a/libpsn00b/include/psxcd.h b/libpsn00b/include/psxcd.h index cf9ecad..429a439 100644 --- a/libpsn00b/include/psxcd.h +++ b/libpsn00b/include/psxcd.h @@ -55,8 +55,10 @@ #define CdlModeAP 0x02 #define CdlModeRept 0x04 #define CdlModeSF 0x08 -#define CdlModeSize0 0x10 -#define CdlModeSize1 0x20 +//#define CdlModeSize0 0x10 +//#define CdlModeSize1 0x20 +#define CdlModeIgnore 0x10 +#define CdlModeSize 0x20 #define CdlModeRT 0x40 #define CdlModeSpeed 0x80 @@ -146,6 +148,7 @@ uint32_t CdSyncCallback(CdlCB func); long CdReadyCallback(CdlCB func); int CdGetSector(void *madr, int size); int CdGetSector2(void *madr, int size); +int CdDataSync(int mode); CdlFILE* CdSearchFile(CdlFILE *loc, const char *filename); diff --git a/libpsn00b/psxcd/getsector.c b/libpsn00b/psxcd/getsector.c index bc1c8ae..ee5315a 100644 --- a/libpsn00b/psxcd/getsector.c +++ b/libpsn00b/psxcd/getsector.c @@ -7,6 +7,16 @@ #include #include +#define DATA_SYNC_TIMEOUT 0x100000 + +/* Private utilities */ + +#ifdef NDEBUG +#define _LOG(...) +#else +#define _LOG(...) printf(__VA_ARGS__) +#endif + /* DMA transfer functions */ int CdGetSector(void *madr, int size) { @@ -33,3 +43,16 @@ int CdGetSector2(void *madr, int size) { return 1; } + +int CdDataSync(int mode) { + if (mode) + return (DMA_CHCR(3) >> 24) & 1; + + for (int i = DATA_SYNC_TIMEOUT; i; i--) { + if (!(DMA_CHCR(3) & (1 << 24))) + return 0; + } + + _LOG("psxcd: CdDataSync() timeout\n"); + return -1; +} diff --git a/libpsn00b/psxcd/psxcd.c b/libpsn00b/psxcd/psxcd.c index 160a1ed..f48542d 100644 --- a/libpsn00b/psxcd/psxcd.c +++ b/libpsn00b/psxcd/psxcd.c @@ -285,18 +285,10 @@ int CdRead(int sectors, uint32_t *buf, int mode) _cd_read_addr = buf; // Determine sector based on mode flags - if( mode & CdlModeSize0 ) - { - _cd_read_sector_sz = 2328 / 4; - } - else if( mode & CdlModeSize1 ) - { + if( mode & CdlModeSize ) _cd_read_sector_sz = 2340 / 4; - } else - { _cd_read_sector_sz = 2048 / 4; - } _cd_read_counter = VSync(-1); diff --git a/libpsn00b/psxpress/mdec.c b/libpsn00b/psxpress/mdec.c index d308994..06510cb 100644 --- a/libpsn00b/psxpress/mdec.c +++ b/libpsn00b/psxpress/mdec.c @@ -164,6 +164,11 @@ int DecDCTinSync(int mode) { void DecDCTout(uint32_t *data, size_t length) { DecDCToutSync(0); + if ((length >= DMA_CHUNK_LENGTH) && (length % DMA_CHUNK_LENGTH)) { + _LOG("psxpress: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); + length += DMA_CHUNK_LENGTH - 1; + } + DMA_MADR(1) = (uint32_t) data; if (length < DMA_CHUNK_LENGTH) DMA_BCR(1) = 0x00010000 | length; diff --git a/libpsn00b/psxpress/vlc.s b/libpsn00b/psxpress/vlc.s index fe51642..885a3f7 100644 --- a/libpsn00b/psxpress/vlc.s +++ b/libpsn00b/psxpress/vlc.s @@ -131,10 +131,12 @@ _vlc_skip_context_load: #nop .Lprocess_dc_v2_coefficient: # if (!coeff_index && !is_v3) - # The DC coefficient in version 2 frames is not compressed. - srl $v0, $t0, 22 # *output = (window >> (32 - 10)) | quant_scale - or $v0, $t3 - addiu $t7, 1 # coeff_index++ + # The DC coefficient in version 2 frames is not compressed. Value 0x1ff is + # used to signal the end of the bitstream. + srl $v0, $t0, 22 # prefix = (window >> (32 - 10)) + li $v1, 0x01ff + beq $v0, $v1, .Lstop_processing # if (prefix == 0x1ff) break + or $v0, $t3 # *output = prefix | quant_scale sll $t0, 10 # window <<= 10 addiu $t5, -10 # bit_offset -= 10 b .Lwrite_value diff --git a/libpsn00b/psxpress/vlc2.c b/libpsn00b/psxpress/vlc2.c index 73b54b2..9eb99bf 100644 --- a/libpsn00b/psxpress/vlc2.c +++ b/libpsn00b/psxpress/vlc2.c @@ -141,7 +141,10 @@ int __attribute__((optimize(3))) DecDCTvlcContinue2( // TODO: version 3 is currently not supported. return -1; } else { - value = _get_bits_unsigned(10); + value = _get_bits_unsigned(10); + if (value == 0x1ff) + break; + *output = value | quant_scale; _advance_window(10); } -- cgit v1.2.3 From 8770122c970eeedb145ee903e2243b7d4a18605b Mon Sep 17 00:00:00 2001 From: spicyjpeg Date: Sun, 16 Oct 2022 23:58:05 +0200 Subject: Fix sound/spustream, update README and changelog --- CHANGELOG.md | 23 +++++++++++++++++- examples/README.md | 11 +++++---- examples/io/pads/spi.c | 6 ++--- examples/sound/spustream/main.c | 12 +++++---- template/iso.xml | 54 ++++++++++++++++++++++++++++++++++++++++- 5 files changed, 91 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f04108..461d2b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,28 @@ to ensure the changelog can be parsed correctly. ------------------------------------------------------------------------------- -## 2022-10-11: 0.21 +## 2022-10-16: 0.21 + +spicyjpeg: + +- psxetc: Fixed (another) critical bug in the IRQ callback dispatcher. This + also fixed some examples that were broken ever since the library was + rewritten in C. Made the dynamic linker less verbose, improving DLL loading + speed in debug mode. + +- psxcd: Added `CdDataSync()`. Renamed `CdlModeSize0` and `CdlModeSize1` to + `CdlModeIgnore` and `CdlModeSize` respectively. + +- psxpress: Fixed a bug in the Huffman decompression API that would make it + crash if the bitstream header didn't contain a valid decompressed length, + even if the bitstream was properly encoded. This fix makes the API fully + usable for video playback (as demonstrated by the new example). + +- examples: Added `mdec/strvideo` FMV playback example. Fixed + `system/childexec` not properly uninstalling BIOS callbacks before launching + the child executable. Added pause/resume code to `sound/spustream`. + +## 2022-10-11 spicyjpeg: diff --git a/examples/README.md b/examples/README.md index b63b2a9..ade94b0 100644 --- a/examples/README.md +++ b/examples/README.md @@ -24,7 +24,8 @@ Additional information may be found in the source code of each example. | [`io/pads`](./io/pads) | Demonstrates reading controllers via low-level access | EXE | 3 | | [`io/system573`](./io/system573) | Konami System 573 (PS1-based arcade board) example | CD | | | [`lowlevel/cartrom`](./lowlevel/cartrom) | ROM firmware for cheat devices written using GNU GAS | ROM | 4 | -| [`mdec/mdecimage`](./mdec/mdecimage) | Displays a (raw) MDEC format image using libpsxpress | EXE | | +| [`mdec/mdecimage`](./mdec/mdecimage) | Displays a (raw) MDEC format image | EXE | | +| [`mdec/strvideo`](./mdec/strvideo) | Plays a .STR video file using the MDEC | CD | 1 | | [`sound/spustream`](./sound/spustream) | Custom (non XA) CD-ROM audio streaming using the SPU | CD | | | [`sound/vagsample`](./sound/vagsample) | Demonstrates playing VAG sound files using the SPU | EXE | | | [`system/childexec`](./system/childexec) | Loading a child program and returning to parent | EXE | | @@ -35,9 +36,9 @@ Additional information may be found in the source code of each example. Notes: -1. `cdrom/cdxa` does not come with an example XA audio file. In order to run - this example you'll have to provide your own file and build the CD image - manually. +1. `cdrom/cdxa` and `mdec/strvideo` do not come with example files. In order + to run these examples you'll have to provide your own files and build the CD + image manually. 2. `demos/n00bdemo` suffers from flickering on real hardware, especially when masking/stencil buffering is used. 3. `io/pads` seems to work on real hardware, but fails to automatically enable @@ -84,4 +85,4 @@ are for rebuilding the examples *after* the SDK has been installed. CD images for each example. ----------------------------------------- -_Last updated on 2022-10-11 by spicyjpeg_ +_Last updated on 2022-10-16 by spicyjpeg_ diff --git a/examples/io/pads/spi.c b/examples/io/pads/spi.c index 133782c..292e682 100644 --- a/examples/io/pads/spi.c +++ b/examples/io/pads/spi.c @@ -46,9 +46,9 @@ typedef struct _SPI_Context { SPI_Callback callback; } SPI_Context; -static volatile SPI_Context _context; -static volatile SPI_Request volatile *_current_req; -static volatile SPI_Callback _default_cb; +static volatile SPI_Context _context; +static volatile SPI_Request *_current_req; +static volatile SPI_Callback _default_cb; /* Request queue management */ diff --git a/examples/sound/spustream/main.c b/examples/sound/spustream/main.c index acd4f60..1fee883 100644 --- a/examples/sound/spustream/main.c +++ b/examples/sound/spustream/main.c @@ -181,12 +181,14 @@ void display(RenderContext *ctx) { #define CHUNK_SIZE (BUFFER_SIZE * NUM_CHANNELS) typedef struct { - int lba, length, pos; - int spu_addr, spu_pos; - int db_active; + int lba, length; + + volatile int pos; + volatile int spu_addr, spu_pos; + volatile int db_active; } StreamContext; -static volatile StreamContext str_ctx; +static StreamContext str_ctx; // This buffer is used by cd_event_handler() as a temporary area for sectors // read from the CD and uploaded to SPU RAM. Due to DMA limitations it can't be @@ -328,8 +330,8 @@ void start_stream(void) { SPU_CH_VOL_L(1) = 0x0000; SPU_CH_VOL_R(1) = 0x3fff; - spu_irq_handler(); SPU_KEY_ON = CHANNEL_MASK; + spu_irq_handler(); } // This is basically a variant of reset_spu_channels() that only resets the diff --git a/template/iso.xml b/template/iso.xml index 87162b2..29fbd2d 100644 --- a/template/iso.xml +++ b/template/iso.xml @@ -11,6 +11,21 @@ cue_sheet="${CD_IMAGE_NAME}.cue" > + + + + + + - + + -- cgit v1.2.3 From 2f100c78c0f12b56bcd73c203e6216d415d9f772 Mon Sep 17 00:00:00 2001 From: spicyjpeg Date: Mon, 17 Oct 2022 22:42:00 +0200 Subject: Remove interrupt disabling calls in psxcd callback APIs --- examples/cdrom/cdxa/main.c | 2 ++ libpsn00b/include/psxcd.h | 4 ++-- libpsn00b/psxcd/isofs.c | 19 ++++++++++++++----- libpsn00b/psxcd/psxcd.c | 11 ++++++++--- libpsn00b/psxcd/psxcd_asm.s | 30 ++++++------------------------ 5 files changed, 32 insertions(+), 34 deletions(-) diff --git a/examples/cdrom/cdxa/main.c b/examples/cdrom/cdxa/main.c index 4921658..93cf01a 100644 --- a/examples/cdrom/cdxa/main.c +++ b/examples/cdrom/cdxa/main.c @@ -349,7 +349,9 @@ int main(int argc, const char* argv[]) xa_loc = file.pos; /* Hook XA callback function to CdReadyCallback (for auto stop/loop */ + EnterCriticalSection(); CdReadyCallback(xa_callback); + ExitCriticalSection(); /* Set CD mode for XA streaming (2x speed, send XA to SPU, enable filter */ i = CdlModeSpeed|CdlModeRT|CdlModeSF; diff --git a/libpsn00b/include/psxcd.h b/libpsn00b/include/psxcd.h index 429a439..0460f20 100644 --- a/libpsn00b/include/psxcd.h +++ b/libpsn00b/include/psxcd.h @@ -145,7 +145,7 @@ int CdControlF(uint8_t com, const void *param); int CdSync(int mode, uint8_t *result); uint32_t CdSyncCallback(CdlCB func); -long CdReadyCallback(CdlCB func); +int CdReadyCallback(CdlCB func); int CdGetSector(void *madr, int size); int CdGetSector2(void *madr, int size); int CdDataSync(int mode); @@ -168,7 +168,7 @@ void CdCloseDir(CdlDIR* dir); int CdGetVolumeLabel(char* label); -long* CdAutoPauseCallback(void(*func)()); +int* CdAutoPauseCallback(void(*func)()); int CdIsoError(); int CdLoadSession(int session); diff --git a/libpsn00b/psxcd/isofs.c b/libpsn00b/psxcd/isofs.c index 16e64ef..4ec701c 100644 --- a/libpsn00b/psxcd/isofs.c +++ b/libpsn00b/psxcd/isofs.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include "psxcd.h" #include "isofs.h" @@ -795,8 +795,10 @@ int CdLoadSession(int session) } // Set search routine callback + EnterCriticalSection(); ready_oldcb = CdReadyCallback(_scan_callback); - + ExitCriticalSection(); + _ses_scanfound = 0; _ses_scancount = 0; _ses_scancomplete = 0; @@ -811,21 +813,28 @@ int CdLoadSession(int session) // Wait until scan complete while(!_ses_scancomplete); - + + EnterCriticalSection(); CdReadyCallback((void*)_ready_oldcb); - + ExitCriticalSection(); + if( !_ses_scanfound ) { _LOG("psxcd: CdLoadSession(): Did not find volume descriptor.\n"); _cd_iso_error = CdlIsoInvalidFs; + EnterCriticalSection(); CdReadyCallback((CdlCB)ready_oldcb); + ExitCriticalSection(); + return -1; } // Restore old callback if any + EnterCriticalSection(); CdReadyCallback((CdlCB)ready_oldcb); - + ExitCriticalSection(); + // Wait until CD-ROM has completely stopped reading, to get a consistent // fix of the CD-ROM pickup's current location do diff --git a/libpsn00b/psxcd/psxcd.c b/libpsn00b/psxcd/psxcd.c index f48542d..6730531 100644 --- a/libpsn00b/psxcd/psxcd.c +++ b/libpsn00b/psxcd/psxcd.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "psxcd.h" #define READ_TIMEOUT 600 // 10 seconds for NTSC @@ -293,8 +294,10 @@ int CdRead(int sectors, uint32_t *buf, int mode) _cd_read_counter = VSync(-1); // Set read callback + EnterCriticalSection(); _cd_read_oldcb = CdReadyCallback(_CdReadReadyCallback); - + ExitCriticalSection(); + // Set specified mode CdControl(CdlSetmode, (uint8_t*)&mode, 0); @@ -320,9 +323,11 @@ static void CdDoRetry() // Reset timeout _cd_read_counter = VSync(-1); - + + EnterCriticalSection(); CdReadyCallback(_CdReadReadyCallback); - + ExitCriticalSection(); + // Retry read CdControl(CdlSetloc, (void*)&_cd_last_setloc, 0); CdControl(CdlReadN, 0, (uint8_t*)_cd_read_result); diff --git a/libpsn00b/psxcd/psxcd_asm.s b/libpsn00b/psxcd/psxcd_asm.s index 16e17d8..c0a5312 100644 --- a/libpsn00b/psxcd/psxcd_asm.s +++ b/libpsn00b/psxcd/psxcd_asm.s @@ -413,17 +413,11 @@ CdAutoPauseCallback: lw $v0, 0($v1) la $v1, _cd_callback_int4 - - jal EnterCriticalSection - nop - + lw $a0, 4($sp) nop sw $a0, 0($v1) - - jal ExitCriticalSection - nop - + lw $ra, 0($sp) addiu $sp, 8 jr $ra @@ -443,17 +437,11 @@ CdReadyCallback: la $v1, _cd_callback_int1_data sw $v0, 8($sp) - - jal EnterCriticalSection - nop - + lw $a0, 4($sp) nop sw $a0, 0($v1) - - jal ExitCriticalSection - nop - + lw $ra, 0($sp) lw $v0, 8($sp) jr $ra @@ -472,17 +460,11 @@ CdSyncCallback: la $v1, _cd_sync_cb sw $v0, 8($sp) - - jal EnterCriticalSection - nop - + lw $a0, 4($sp) nop sw $a0, 0($v1) - - jal ExitCriticalSection - nop - + lw $ra, 0($sp) lw $v0, 8($sp) jr $ra -- cgit v1.2.3 From b71a55bc489db6bc9beca5cee9cd584e82846ac8 Mon Sep 17 00:00:00 2001 From: spicyjpeg Date: Tue, 18 Oct 2022 15:51:52 +0200 Subject: Add MoveImage(), use draw queue for psxgpu VRAM APIs --- libpsn00b/include/psxgpu.h | 22 ++++-- libpsn00b/psxgpu/common.c | 176 +++++++++++++++++++++++++++------------------ libpsn00b/psxgpu/env.c | 4 +- libpsn00b/psxgpu/image.c | 43 +++++++---- libpsn00b/psxspu/common.c | 58 +++++++-------- 5 files changed, 181 insertions(+), 122 deletions(-) diff --git a/libpsn00b/include/psxgpu.h b/libpsn00b/include/psxgpu.h index 0e7ec00..f2568b0 100644 --- a/libpsn00b/include/psxgpu.h +++ b/libpsn00b/include/psxgpu.h @@ -488,20 +488,30 @@ void PutDrawEnvFast(DRAWENV *env); int GetODE(void); int VSync(int mode); -int DrawSync(int mode); - void *VSyncHaltFunction(void (*func)(void)); void *VSyncCallback(void (*func)(void)); + +int EnqueueDrawOp( + void (*func)(uint32_t, uint32_t, uint32_t), + uint32_t arg1, + uint32_t arg2, + uint32_t arg3 +); +int DrawSync(int mode); void *DrawSyncCallback(void (*func)(void)); -void LoadImage(const RECT *rect, const uint32_t *data); -void StoreImage(const RECT *rect, uint32_t *data); +int LoadImage(const RECT *rect, const uint32_t *data); +int StoreImage(const RECT *rect, uint32_t *data); +int MoveImage(const RECT *rect, int x, int y); +void LoadImage2(const RECT *rect, const uint32_t *data); +void StoreImage2(const RECT *rect, uint32_t *data); +void MoveImage2(const RECT *rect, int x, int y); void ClearOTagR(uint32_t *ot, size_t length); void ClearOTag(uint32_t *ot, size_t length); -void DrawOTag(const uint32_t *ot); +int DrawOTag(const uint32_t *ot); +int DrawOTagEnv(const uint32_t *ot, DRAWENV *env); void DrawOTag2(const uint32_t *ot); -void DrawOTagEnv(const uint32_t *ot, DRAWENV *env); void DrawPrim(const uint32_t *pri); void AddPrim(uint32_t *ot, const void *pri); diff --git a/libpsn00b/psxgpu/common.c b/libpsn00b/psxgpu/common.c index 1e3d9e5..bf70b72 100644 --- a/libpsn00b/psxgpu/common.c +++ b/libpsn00b/psxgpu/common.c @@ -16,6 +16,13 @@ static void _default_vsync_halt(void); +/* Private types */ + +typedef struct { + void (*func)(uint32_t, uint32_t, uint32_t); + uint32_t arg1, arg2, arg3; +} QueueEntry; + /* Internal globals */ GPU_VideoMode _gpu_video_mode; @@ -24,10 +31,10 @@ static void (*_vsync_halt_func)(void) = &_default_vsync_halt; static void (*_vsync_callback)(void) = (void *) 0; static void (*_drawsync_callback)(void) = (void *) 0; -static const uint32_t *volatile _draw_queue[QUEUE_LENGTH]; -static volatile uint8_t _queue_head, _queue_tail, _queue_length; -static volatile uint32_t _vblank_counter; -static volatile uint16_t _last_hblank; +static volatile QueueEntry _draw_queue[QUEUE_LENGTH]; +static volatile uint8_t _queue_head, _queue_tail, _queue_length; +static volatile uint32_t _vblank_counter; +static volatile uint16_t _last_hblank; /* Private utilities and interrupt handlers */ @@ -49,11 +56,11 @@ static void _gpu_dma_handler(void) { while (!(GPU_GP1 & (1 << 26))) __asm__ volatile(""); - if (_queue_length) { - DrawOTag2(_draw_queue[_queue_head++]); + if (--_queue_length) { + QueueEntry *entry = &_draw_queue[_queue_head++]; + _queue_head %= QUEUE_LENGTH; - _queue_length--; - _queue_head %= QUEUE_LENGTH; + entry->func(entry->arg1, entry->arg2, entry->arg3); } else { GPU_GP1 = 0x04000000; // Disable DMA request @@ -103,7 +110,7 @@ void ResetGraph(int mode) { _last_hblank = 0; } -/* Syncing API */ +/* VSync() API */ // TODO: add support for no$psx's "halt" register static void _default_vsync_halt(void) { @@ -144,27 +151,6 @@ int VSync(int mode) { return delta; } -int DrawSync(int mode) { - if (mode) - return (DMA_BCR(2) >> 16); - - // Wait for the queue to become empty. - // TODO: add a timeout - while (_queue_length) - __asm__ volatile(""); - - // Wait for any DMA transfer to finish if DMA is enabled. - if (GPU_GP1 & (3 << 29)) { - while (!(GPU_GP1 & (1 << 28)) || (DMA_CHCR(2) & (1 << 24))) - __asm__ volatile(""); - } - - while (!(GPU_GP1 & (1 << 26))) - __asm__ volatile(""); - - return 0; -} - void *VSyncHaltFunction(void (*func)(void)) { void *old_callback = _vsync_halt_func; _vsync_halt_func = func; @@ -182,6 +168,80 @@ void *VSyncCallback(void (*func)(void)) { return old_callback; } +/* Command queue API */ + +// This function is normally only used internally, but it is exposed for +// advanced use cases. +int EnqueueDrawOp( + void (*func)(uint32_t, uint32_t, uint32_t), + uint32_t arg1, + uint32_t arg2, + uint32_t arg3 +) { + // If GPU DMA is currently busy, append the command to the queue instead of + // executing it immediately. Note that interrupts must be disabled *prior* + // to checking if DMA is busy; disabling them afterwards would create a + // race condition where the DMA transfer could end while interrupts are + // being disabled. Interrupts are disabled through the IRQ_MASK register + // rather than by calling EnterCriticalSection() for performance reasons. + uint16_t mask = IRQ_MASK; + IRQ_MASK = 0; + + if (_queue_length) { + if (_queue_length >= QUEUE_LENGTH) { + IRQ_MASK = mask; + _LOG("psxgpu: draw queue overflow, dropping commands\n"); + return -1; + } + + int length = _queue_length; + _queue_length = length + 1; + + QueueEntry *entry = &_draw_queue[_queue_tail++]; + _queue_tail %= QUEUE_LENGTH; + + entry->func = func; + entry->arg1 = arg1; + entry->arg2 = arg2; + entry->arg3 = arg3; + + IRQ_MASK = mask; + return length; + } + + _queue_length = 1; + + IRQ_MASK = mask; + func(arg1, arg2, arg3); + return 0; +} + +int DrawSync(int mode) { + if (mode) + return _queue_length; + + // Wait for the queue to become empty. + for (int i = VSYNC_TIMEOUT; i; i--) { + if (!_queue_length) + break; + } + + if (!_queue_length) { + // Wait for any DMA transfer to finish if DMA is enabled. + if (GPU_GP1 & (3 << 29)) { + while (!(GPU_GP1 & (1 << 28)) || (DMA_CHCR(2) & (1 << 24))) + __asm__ volatile(""); + } + + while (!(GPU_GP1 & (1 << 26))) + __asm__ volatile(""); + } else { + printf("psxgpu: DrawSync() timeout\n"); + } + + return _queue_length; +} + void *DrawSyncCallback(void (*func)(void)) { EnterCriticalSection(); @@ -214,45 +274,8 @@ void ClearOTag(uint32_t *ot, size_t length) { ot[length - 1] = 0x00ffffff; } -void DrawOTag(const uint32_t *ot) { - // If GPU DMA is currently busy, append the OT to the queue instead of - // drawing it immediately. Note that interrupts must be disabled *prior* to - // checking if DMA is busy; disabling them afterwards would create a race - // condition where the DMA transfer could end while interrupts are being - // disabled. Interrupts are disabled through the IRQ_MASK register rather - // than by calling EnterCriticalSection() for performance reasons. - uint16_t mask = IRQ_MASK; - IRQ_MASK = 0; - - if (DMA_CHCR(2) & (1 << 24)) { - if (_queue_length < QUEUE_LENGTH) { - _draw_queue[_queue_tail++] = ot; - - _queue_length++; - _queue_tail %= QUEUE_LENGTH; - - IRQ_MASK = mask; - return; - } - - IRQ_MASK = mask; - _LOG("psxgpu: DrawOTag() failed, draw queue full\n"); - return; - } - - IRQ_MASK = mask; - DrawOTag2(ot); -} - -void DrawOTag2(const uint32_t *ot) { - GPU_GP1 = 0x04000002; - - while (!(GPU_GP1 & (1 << 26)) || (DMA_CHCR(2) & (1 << 24))) - __asm__ volatile(""); - - DMA_MADR(2) = (uint32_t) ot; - DMA_BCR(2) = 0; - DMA_CHCR(2) = 0x01000401; +void AddPrim(uint32_t *ot, const void *pri) { + addPrim(ot, pri); } void DrawPrim(const uint32_t *pri) { @@ -273,8 +296,19 @@ void DrawPrim(const uint32_t *pri) { DMA_CHCR(2) = 0x01000201; } -void AddPrim(uint32_t *ot, const void *pri) { - addPrim(ot, pri); +int DrawOTag(const uint32_t *ot) { + return EnqueueDrawOp(&DrawOTag2, (uint32_t) ot, 0, 0); +} + +void DrawOTag2(const uint32_t *ot) { + GPU_GP1 = 0x04000002; + + while (!(GPU_GP1 & (1 << 26)) || (DMA_CHCR(2) & (1 << 24))) + __asm__ volatile(""); + + DMA_MADR(2) = (uint32_t) ot; + DMA_BCR(2) = 0; + DMA_CHCR(2) = 0x01000401; } /* Misc. functions */ diff --git a/libpsn00b/psxgpu/env.c b/libpsn00b/psxgpu/env.c index 5642ad4..1b97026 100644 --- a/libpsn00b/psxgpu/env.c +++ b/libpsn00b/psxgpu/env.c @@ -37,7 +37,7 @@ DRAWENV *SetDefDrawEnv(DRAWENV *env, int x, int y, int w, int h) { return env; } -void DrawOTagEnv(const uint32_t *ot, DRAWENV *env) { +int DrawOTagEnv(const uint32_t *ot, DRAWENV *env) { DR_ENV *prim = &(env->dr_env); // All commands are grouped into a single display list packet for @@ -85,7 +85,7 @@ void DrawOTagEnv(const uint32_t *ot, DRAWENV *env) { //while (!(GPU_GP1 & (1 << 26))) //__asm__ volatile(""); - DrawOTag((const uint32_t *) prim); + return EnqueueDrawOp(&DrawOTag2, (uint32_t) prim, 0, 0); } void PutDrawEnv(DRAWENV *env) { diff --git a/libpsn00b/psxgpu/image.c b/libpsn00b/psxgpu/image.c index a0d7065..c09a59d 100644 --- a/libpsn00b/psxgpu/image.c +++ b/libpsn00b/psxgpu/image.c @@ -18,12 +18,7 @@ #define _LOG(...) printf(__VA_ARGS__) #endif -static void _load_store_image( - uint32_t command, - int mode, - const RECT *rect, - uint32_t *data -) { +static void _dma_transfer(const RECT *rect, uint32_t *data, int write) { size_t length = rect->w * rect->h; if (length % 2) _LOG("psxgpu: can't transfer an odd number of pixels\n"); @@ -34,18 +29,17 @@ static void _load_store_image( length += DMA_CHUNK_LENGTH - 1; } - DrawSync(0); GPU_GP1 = 0x04000000; // Disable DMA request GPU_GP0 = 0x01000000; // Flush cache - GPU_GP0 = command; + GPU_GP0 = write ? 0xa0000000 : 0xc0000000; //GPU_GP0 = rect->x | (rect->y << 16); GPU_GP0 = *((const uint32_t *) &(rect->x)); //GPU_GP0 = rect->w | (rect->h << 16); GPU_GP0 = *((const uint32_t *) &(rect->w)); // Enable DMA request, route to GP0 (2) or from GPU_READ (3) - GPU_GP1 = 0x04000000 | mode; + GPU_GP1 = 0x04000002 | (write ^ 1); DMA_MADR(2) = (uint32_t) data; if (length < DMA_CHUNK_LENGTH) @@ -53,17 +47,38 @@ static void _load_store_image( else DMA_BCR(2) = DMA_CHUNK_LENGTH | ((length / DMA_CHUNK_LENGTH) << 16); - DMA_CHCR(2) = 0x01000200 | ((mode & 1) ^ 1); + DMA_CHCR(2) = 0x01000200 | write; } /* VRAM transfer API */ -void LoadImage(const RECT *rect, const uint32_t *data) { - _load_store_image(0xa0000000, 2, rect, (uint32_t *) data); +int LoadImage(const RECT *rect, const uint32_t *data) { + return EnqueueDrawOp(&_dma_transfer, (uint32_t) rect, (uint32_t) data, 1); } -void StoreImage(const RECT *rect, uint32_t *data) { - _load_store_image(0xc0000000, 3, rect, data); +int StoreImage(const RECT *rect, uint32_t *data) { + return EnqueueDrawOp(&_dma_transfer, (uint32_t) rect, (uint32_t) data, 0); +} + +int MoveImage(const RECT *rect, int x, int y) { + return EnqueueDrawOp(&MoveImage2, (uint32_t) rect, x, y); +} + +void LoadImage2(const RECT *rect, const uint32_t *data) { + _dma_transfer(rect, (uint32_t *) data, 1); +} + +void StoreImage2(const RECT *rect, uint32_t *data) { + _dma_transfer(rect, data, 0); +} + +void MoveImage2(const RECT *rect, int x, int y) { + GPU_GP0 = 0x80000000; + //GPU_GP0 = rect->x | (rect->y << 16); + GPU_GP0 = *((const uint32_t *) &(rect->x)); + GPU_GP0 = (x & 0xffff) | (y << 16); + //GPU_GP0 = rect->w | (rect->h << 16); + GPU_GP0 = *((const uint32_t *) &(rect->w)); } /* .TIM image parsers */ diff --git a/libpsn00b/psxspu/common.c b/libpsn00b/psxspu/common.c index d6508c7..380bd3d 100644 --- a/libpsn00b/psxspu/common.c +++ b/libpsn00b/psxspu/common.c @@ -34,6 +34,33 @@ static void _wait_status(uint16_t mask, uint16_t value) { _LOG("psxspu: status register timeout (0x%04x)\n", SPU_STAT); } +static void _dma_transfer(uint32_t *data, size_t length, int write) { + if (length % 4) + _LOG("psxspu: can't transfer a number of bytes that isn't multiple of 4\n"); + + length /= 4; + if ((length >= DMA_CHUNK_LENGTH) && (length % DMA_CHUNK_LENGTH)) { + _LOG("psxspu: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); + length += DMA_CHUNK_LENGTH - 1; + } + + SPU_CTRL &= 0xffcf; // Disable DMA request + _wait_status(0x0030, 0x0000); + + // Enable DMA request for writing (2) or reading (3) + SPU_ADDR = _transfer_addr; + SPU_CTRL |= write ? 0x0020 : 0x0030; + _wait_status(0x0400, 0x0000); + + DMA_MADR(4) = (uint32_t) data; + if (length < DMA_CHUNK_LENGTH) + DMA_BCR(4) = 0x00010000 | length; + else + DMA_BCR(4) = DMA_CHUNK_LENGTH | ((length / DMA_CHUNK_LENGTH) << 16); + + DMA_CHCR(4) = 0x01000200 | write; +} + /* Public API */ void SpuInit(void) { @@ -87,35 +114,8 @@ void SpuInit(void) { SPU_CD_VOL_R = 0x7fff; } -static void _load_store_data(uint32_t *data, size_t length, int mode) { - if (length % 4) - _LOG("psxspu: can't transfer a number of bytes that isn't multiple of 4\n"); - - length /= 4; - if ((length >= DMA_CHUNK_LENGTH) && (length % DMA_CHUNK_LENGTH)) { - _LOG("psxspu: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); - length += DMA_CHUNK_LENGTH - 1; - } - - SPU_CTRL &= 0xffcf; // Disable DMA request - _wait_status(0x0030, 0x0000); - - // Enable DMA request for writing (2) or reading (3) - SPU_ADDR = _transfer_addr; - SPU_CTRL |= mode << 4; - _wait_status(0x0400, 0x0000); - - DMA_MADR(4) = (uint32_t) data; - if (length < DMA_CHUNK_LENGTH) - DMA_BCR(4) = 0x00010000 | length; - else - DMA_BCR(4) = DMA_CHUNK_LENGTH | ((length / DMA_CHUNK_LENGTH) << 16); - - DMA_CHCR(4) = 0x01000200 | ((mode & 1) ^ 1); -} - void SpuRead(uint32_t *data, size_t size) { - _load_store_data(data, size, 3); + _dma_transfer(data, size, 0); } void SpuWrite(const uint32_t *data, size_t size) { @@ -138,7 +138,7 @@ void SpuWrite(const uint32_t *data, size_t size) { return; } - _load_store_data((uint32_t *) data, size, 2); + _dma_transfer((uint32_t *) data, size, 1); } SPU_TransferMode SpuSetTransferMode(SPU_TransferMode mode) { -- cgit v1.2.3 From 9b2ffc6078a850b7d354855cca7622090b41f30c Mon Sep 17 00:00:00 2001 From: spicyjpeg Date: Tue, 18 Oct 2022 17:29:42 +0200 Subject: Add debug log buffering, fix GetHeapUsage() --- libpsn00b/include/psxetc.h | 15 ++++++ libpsn00b/libc/abort.c | 16 ++----- libpsn00b/libc/malloc.c | 22 ++++----- libpsn00b/psxcd/getsector.c | 11 +---- libpsn00b/psxcd/isofs.c | 112 ++++++++++++++++++++------------------------ libpsn00b/psxcd/psxcd.c | 14 ++---- libpsn00b/psxetc/dl.c | 91 +++++++++++++++++------------------ libpsn00b/psxetc/logging.c | 50 ++++++++++++++++++++ libpsn00b/psxgpu/common.c | 31 +++++------- libpsn00b/psxgpu/env.c | 2 +- libpsn00b/psxgpu/image.c | 22 ++++----- libpsn00b/psxpress/mdec.c | 20 +++----- libpsn00b/psxspu/common.c | 14 ++---- 13 files changed, 216 insertions(+), 204 deletions(-) create mode 100644 libpsn00b/psxetc/logging.c diff --git a/libpsn00b/include/psxetc.h b/libpsn00b/include/psxetc.h index 24485d9..fcfec06 100644 --- a/libpsn00b/include/psxetc.h +++ b/libpsn00b/include/psxetc.h @@ -6,12 +6,27 @@ #ifndef __PSXETC_H #define __PSXETC_H +/* Macros */ + +// This macro is used internally by PSn00bSDK to log debug messages to a buffer +// which is then printed to stdout when calling VSync(). +#ifdef NDEBUG +#define _sdk_log(...) +#define _sdk_dump_log() +#else +#define _sdk_log(...) _sdk_log_inner(__VA_ARGS__) +#define _sdk_dump_log() _sdk_dump_log_inner() +#endif + /* Public API */ #ifdef __cplusplus extern "C" { #endif +void _sdk_log_inner(const char *fmt, ...); +void _sdk_dump_log_inner(void); + void *InterruptCallback(int irq, void (*func)(void)); void *GetInterruptCallback(int irq); void *DMACallback(int dma, void (*func)(void)); diff --git a/libpsn00b/libc/abort.c b/libpsn00b/libc/abort.c index 1108160..2db5016 100644 --- a/libpsn00b/libc/abort.c +++ b/libpsn00b/libc/abort.c @@ -1,16 +1,10 @@ -#include - -#ifdef NDEBUG -#define _LOG(...) -#else -#define _LOG(...) printf(__VA_ARGS__) -#endif +#include /* Standard abort */ -void abort() { - _LOG("abort()\n"); +void abort(void) { + _sdk_log("abort()\n"); for (;;) __asm__ volatile(""); @@ -19,7 +13,7 @@ void abort() { /* Internal function used by assert() macro */ void _assert_abort(const char *file, int line, const char *expr) { - _LOG("%s:%d: assert(%s)\n", file, line, expr); + _sdk_log("%s:%d: assert(%s)\n", file, line, expr); for (;;) __asm__ volatile(""); @@ -28,7 +22,7 @@ void _assert_abort(const char *file, int line, const char *expr) { /* Pure virtual function call (C++) */ void __cxa_pure_virtual(void) { - _LOG("__cxa_pure_virtual()\n"); + _sdk_log("__cxa_pure_virtual()\n"); for (;;) __asm__ volatile(""); diff --git a/libpsn00b/libc/malloc.c b/libpsn00b/libc/malloc.c index acac753..e9fd6f4 100644 --- a/libpsn00b/libc/malloc.c +++ b/libpsn00b/libc/malloc.c @@ -120,7 +120,7 @@ __attribute__((weak)) void *malloc(size_t size) { _alloc_head = new; _alloc_tail = new; - TrackHeapUsage(_size); + TrackHeapUsage(size); return ptr; } @@ -139,7 +139,7 @@ __attribute__((weak)) void *malloc(size_t size) { _alloc_head->prev = new; _alloc_head = new; - TrackHeapUsage(_size); + TrackHeapUsage(size); return ptr; } @@ -157,7 +157,7 @@ __attribute__((weak)) void *malloc(size_t size) { (new->next)->prev = new; prev->next = new; - TrackHeapUsage(_size); + TrackHeapUsage(size); return ptr; } @@ -175,7 +175,7 @@ __attribute__((weak)) void *malloc(size_t size) { _alloc_tail->next = new; _alloc_tail = new; - TrackHeapUsage(_size); + TrackHeapUsage(size); return ptr; } @@ -196,7 +196,7 @@ __attribute__((weak)) void *realloc(void *ptr, size_t size) { // New memory block shorter? if (prev->size >= _size) { - TrackHeapUsage(_size - prev->size); + TrackHeapUsage(size - prev->size); prev->size = _size; if (!prev->next) @@ -211,14 +211,14 @@ __attribute__((weak)) void *realloc(void *ptr, size_t size) { if (!new) return 0; - TrackHeapUsage(_size - prev->size); + TrackHeapUsage(size - prev->size); prev->size = _size; return ptr; } // Do we have free memory after it? if (((prev->next)->ptr - ptr) > _size) { - TrackHeapUsage(_size - prev->size); + TrackHeapUsage(size - prev->size); prev->size = _size; return ptr; } @@ -250,7 +250,7 @@ __attribute__((weak)) void free(void *ptr) { sbrk(-size); } - TrackHeapUsage(-size); + TrackHeapUsage(-(_alloc_head->size)); return; } @@ -265,17 +265,15 @@ __attribute__((weak)) void free(void *ptr) { if (cur->next) { // In the middle, just unlink it (cur->next)->prev = cur->prev; - TrackHeapUsage(-(cur->size + sizeof(BlockHeader))); } else { // At the end, shrink heap - _alloc_tail = cur->prev; - void *top = sbrk(0); size_t size = (top - (cur->prev)->ptr) - (cur->prev)->size; + _alloc_tail = cur->prev; sbrk(-size); - TrackHeapUsage(-size); } + TrackHeapUsage(-(cur->size)); (cur->prev)->next = cur->next; } diff --git a/libpsn00b/psxcd/getsector.c b/libpsn00b/psxcd/getsector.c index ee5315a..31d0ac7 100644 --- a/libpsn00b/psxcd/getsector.c +++ b/libpsn00b/psxcd/getsector.c @@ -4,19 +4,12 @@ */ #include +#include #include #include #define DATA_SYNC_TIMEOUT 0x100000 -/* Private utilities */ - -#ifdef NDEBUG -#define _LOG(...) -#else -#define _LOG(...) printf(__VA_ARGS__) -#endif - /* DMA transfer functions */ int CdGetSector(void *madr, int size) { @@ -53,6 +46,6 @@ int CdDataSync(int mode) { return 0; } - _LOG("psxcd: CdDataSync() timeout\n"); + _sdk_log("psxcd: CdDataSync() timeout\n"); return -1; } diff --git a/libpsn00b/psxcd/isofs.c b/libpsn00b/psxcd/isofs.c index 4ec701c..0425c0d 100644 --- a/libpsn00b/psxcd/isofs.c +++ b/libpsn00b/psxcd/isofs.c @@ -1,18 +1,12 @@ #include -#include #include #include #include #include +#include #include "psxcd.h" #include "isofs.h" -#ifdef NDEBUG -#define _LOG(...) -#else -#define _LOG(...) printf(__VA_ARGS__) -#endif - #define DEFAULT_PATH_SEP '\\' #define IS_PATH_SEP(ch) (((ch) == '/') || ((ch) == '\\')) @@ -49,7 +43,7 @@ static int _CdReadIsoDescriptor(int session_offs) CdControl(CdlNop, 0, 0); if( (CdStatus()&0x10) ) { - _LOG("psxcd: Lid is still open.\n"); + _sdk_log("psxcd: Lid is still open.\n"); _cd_iso_error = CdlIsoLidOpen; return -1; @@ -64,45 +58,45 @@ static int _CdReadIsoDescriptor(int session_offs) return 0; } - _LOG("psxcd: Parsing ISO file system.\n"); + _sdk_log("psxcd: Parsing ISO file system.\n"); // Seek to volume descriptor CdIntToPos(16+session_offs, &loc); if( !CdControl(CdlSetloc, (uint8_t*)&loc, 0) ) { - _LOG("psxcd: Could not set seek destination.\n"); + _sdk_log("psxcd: Could not set seek destination.\n"); _cd_iso_error = CdlIsoSeekError; return -1; } - _LOG("psxcd: Read sectors.\n"); + _sdk_log("psxcd: Read sectors.\n"); // Read volume descriptor CdRead(1, (uint32_t*)_cd_iso_descriptor_buff, CdlModeSpeed); if( CdReadSync(0, 0) ) { - _LOG("psxcd: Error reading ISO volume descriptor.\n"); + _sdk_log("psxcd: Error reading ISO volume descriptor.\n"); _cd_iso_error = CdlIsoReadError; return -1; } - _LOG("psxcd: Read complete.\n"); + _sdk_log("psxcd: Read complete.\n"); // Verify if volume descriptor is present descriptor = (ISO_DESCRIPTOR*)_cd_iso_descriptor_buff; if( strncmp("CD001", descriptor->header.id, 5) ) { - _LOG("psxcd: Disc does not contain a ISO9660 file system.\n"); + _sdk_log("psxcd: Disc does not contain a ISO9660 file system.\n"); _cd_iso_error = CdlIsoInvalidFs; return -1; } - _LOG("psxcd: Path table LBA = %d\n", descriptor->pathTable1Offs); - _LOG("psxcd: Path table len = %d\n", descriptor->pathTableSize.lsb); + _sdk_log("psxcd: Path table LBA = %d\n", descriptor->pathTable1Offs); + _sdk_log("psxcd: Path table len = %d\n", descriptor->pathTableSize.lsb); // Allocate path table buffer i = ((2047+descriptor->pathTableSize.lsb)>>11)<<11; @@ -112,7 +106,7 @@ static int _CdReadIsoDescriptor(int session_offs) } _cd_iso_pathtable_buff = (uint8_t*)malloc(i); - _LOG("psxcd: Allocated %d bytes for path table.\n", i); + _sdk_log("psxcd: Allocated %d bytes for path table.\n", i); // Read path table CdIntToPos(descriptor->pathTable1Offs, &loc); @@ -120,7 +114,7 @@ static int _CdReadIsoDescriptor(int session_offs) CdRead(i>>11, (uint32_t*)_cd_iso_pathtable_buff, CdlModeSpeed); if( CdReadSync(0, 0) ) { - _LOG("psxcd: Error reading ISO path table.\n"); + _sdk_log("psxcd: Error reading ISO path table.\n"); _cd_iso_error = CdlIsoReadError; return -1; @@ -148,11 +142,11 @@ static int _CdReadIsoDirectory(int lba) CdIntToPos(lba, &loc); i = CdPosToInt(&loc); - _LOG("psxcd: Seek to sector %d\n", i); + _sdk_log("psxcd: Seek to sector %d\n", i); if( !CdControl(CdlSetloc, (uint8_t*)&loc, 0) ) { - _LOG("psxcd: Could not set seek destination.\n"); + _sdk_log("psxcd: Could not set seek destination.\n"); _cd_iso_error = CdlIsoSeekError; return -1; @@ -168,7 +162,7 @@ static int _CdReadIsoDirectory(int lba) CdRead(1, (uint32_t*)_cd_iso_directory_buff, CdlModeSpeed); if( CdReadSync(0, 0) ) { - _LOG("psxcd: Error reading initial directory record.\n"); + _sdk_log("psxcd: Error reading initial directory record.\n"); _cd_iso_error = CdlIsoReadError; return -1; @@ -177,14 +171,14 @@ static int _CdReadIsoDirectory(int lba) direntry = (ISO_DIR_ENTRY*)_cd_iso_directory_buff; _cd_iso_directory_len = direntry->entrySize.lsb; - _LOG("psxcd: Location of directory record = %d\n", direntry->entryOffs.lsb); - _LOG("psxcd: Size of directory record = %d\n", _cd_iso_directory_len); + _sdk_log("psxcd: Location of directory record = %d\n", direntry->entryOffs.lsb); + _sdk_log("psxcd: Size of directory record = %d\n", _cd_iso_directory_len); if( _cd_iso_directory_len > 2048 ) { if( !CdControl(CdlSetloc, (uint8_t*)&loc, 0) ) { - _LOG("psxcd: Could not set seek destination.\n"); + _sdk_log("psxcd: Could not set seek destination.\n"); _cd_iso_error = CdlIsoSeekError; return -1; @@ -194,12 +188,12 @@ static int _CdReadIsoDirectory(int lba) i = ((2047+_cd_iso_directory_len)>>11)<<11; _cd_iso_directory_buff = (uint8_t*)malloc(i); - _LOG("psxcd: Allocated %d bytes for directory record.\n", i); + _sdk_log("psxcd: Allocated %d bytes for directory record.\n", i); CdRead(i>>11, (uint32_t*)_cd_iso_directory_buff, CdlModeSpeed); if( CdReadSync(0, 0) ) { - _LOG("psxcd: Error reading remaining directory record.\n"); + _sdk_log("psxcd: Error reading remaining directory record.\n"); _cd_iso_error = CdlIsoReadError; return -1; @@ -221,7 +215,7 @@ static void dump_directory(void) ISO_DIR_ENTRY *dir_entry; char namebuff[16]; - _LOG("psxcd: Cached directory record contents:\n"); + _sdk_log("psxcd: Cached directory record contents:\n"); i = 0; dir_pos = 0; @@ -232,7 +226,7 @@ static void dump_directory(void) strncpy(namebuff, _cd_iso_directory_buff+dir_pos+sizeof(ISO_DIR_ENTRY), dir_entry->identifierLen); - _LOG("psxcd: P:%d L:%d %s\n", dir_pos, dir_entry->identifierLen, namebuff); + _sdk_log("psxcd: P:%d L:%d %s\n", dir_pos, dir_entry->identifierLen, namebuff); dir_pos += dir_entry->entryLength; i++; @@ -251,7 +245,7 @@ static void dump_directory(void) } } - _LOG("psxcd: --\n"); + _sdk_log("psxcd: --\n"); } @@ -262,7 +256,7 @@ static void dump_pathtable(void) ISO_DESCRIPTOR *descriptor; char namebuff[16]; - _LOG("psxcd: Path table entries:\n"); + _sdk_log("psxcd: Path table entries:\n"); descriptor = (ISO_DESCRIPTOR*)_cd_iso_descriptor_buff; @@ -276,7 +270,7 @@ static void dump_pathtable(void) tbl_pos+sizeof(ISO_PATHTABLE_ENTRY), tbl_entry->nameLength); - _LOG("psxcd: %s\n", namebuff); + _sdk_log("psxcd: %s\n", namebuff); // Advance to next entry tbl_pos += sizeof(ISO_PATHTABLE_ENTRY) @@ -372,7 +366,7 @@ static int find_dir_entry(const char *name, ISO_DIR_ENTRY *dirent) ISO_DIR_ENTRY *dir_entry; char namebuff[16]; - _LOG("psxcd: Locating file %s.\n", name); + _sdk_log("psxcd: Locating file %s.\n", name); i = 0; dir_pos = 0; @@ -465,11 +459,11 @@ CdlFILE *CdSearchFile(CdlFILE *fp, const char *filename) // Read ISO descriptor and path table if( _CdReadIsoDescriptor(0) ) { - _LOG("psxcd: Could not read ISO file system.\n"); + _sdk_log("psxcd: Could not read ISO file system.\n"); return NULL; } - // _LOG("psxcd: ISO file system cache updated.\n"); + // _sdk_log("psxcd: ISO file system cache updated.\n"); // _cd_media_changed = 0; //} @@ -477,23 +471,23 @@ CdlFILE *CdSearchFile(CdlFILE *fp, const char *filename) num_dirs = get_pathtable_entry(0, NULL, NULL); #ifndef NDEBUG - _LOG("psxcd: Directories in path table: %d\n", num_dirs); + _sdk_log("psxcd: Directories in path table: %d\n", num_dirs); rbuff = resolve_pathtable_path(num_dirs-1, tpath_rbuff+127); if( !rbuff ) { - _LOG("psxcd: Could not resolve path.\n"); + _sdk_log("psxcd: Could not resolve path.\n"); } else { - _LOG("psxcd: Longest path: %s|\n", rbuff); + _sdk_log("psxcd: Longest path: %s|\n", rbuff); } #endif if( get_pathname(search_path, filename) ) { - _LOG("psxcd: Search path = %s|\n", search_path); + _sdk_log("psxcd: Search path = %s|\n", search_path); } // Search the pathtable for a matching path @@ -501,7 +495,7 @@ CdlFILE *CdSearchFile(CdlFILE *fp, const char *filename) for(i=1; iname, filename); @@ -539,12 +533,12 @@ CdlFILE *CdSearchFile(CdlFILE *fp, const char *filename) if( find_dir_entry(fp->name, &dir_entry) ) { - _LOG("psxcd: Could not find file.\n"); + _sdk_log("psxcd: Could not find file.\n"); return NULL; } - _LOG("psxcd: Located file at LBA %d.\n", dir_entry.entryOffs.lsb); + _sdk_log("psxcd: Located file at LBA %d.\n", dir_entry.entryOffs.lsb); CdIntToPos(dir_entry.entryOffs.lsb, &fp->pos); fp->size = dir_entry.entrySize.lsb; @@ -568,11 +562,11 @@ CdlDIR *CdOpenDir(const char* path) // Read ISO descriptor and path table if( _CdReadIsoDescriptor( 0 ) ) { - _LOG( "psxcd: Could not read ISO file system.\n" ); + _sdk_log( "psxcd: Could not read ISO file system.\n" ); return NULL; } -// _LOG( "psxcd: ISO file system cache updated.\n" ); +// _sdk_log( "psxcd: ISO file system cache updated.\n" ); // _cd_media_changed = 0; // } @@ -582,7 +576,7 @@ CdlDIR *CdOpenDir(const char* path) for( i=1; isize = dir_entry->entrySize.lsb; - _LOG("psxcd: dir_entry->entryLength = %d, ", dir_entry->entryLength); + _sdk_log("psxcd: dir_entry->entryLength = %d, ", dir_entry->entryLength); d_dir->_pos += dir_entry->entryLength; - _LOG("psxcd: d_dir->_pos = %d\n", d_dir->_pos); + _sdk_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 ) @@ -776,15 +770,13 @@ int CdLoadSession(int session) int i; // Seek to specified session - _LOG("psxcd: CdLoadSession(): Seeking to session %d...\n", session); + _sdk_log("psxcd: CdLoadSession(): Seeking to session %d...\n", session); CdControl(CdlSetsession, (unsigned char*)&session, (unsigned char*)&resultbuff); if( CdSync(0, 0) == CdlDiskError ) { - _LOG("psxcd: CdLoadSession(): Session seek failed, " - "session does not exist.\n"); - _LOG("psxcd: CdLoadSession(): Restarting CD-ROM...\n"); + _sdk_log("psxcd: CdLoadSession(): Session seek failed, session does not exist. Restarting CD-ROM...\n"); // Restart CD-ROM on session seek failure CdControl(CdlNop, 0, 0); @@ -805,7 +797,7 @@ int CdLoadSession(int session) _ses_scanbuff = scanbuff; // Begin scan for an ISO volume descriptor - _LOG("psxcd: CdLoadSession(): Scanning for ISO9660 volume descriptor.\n"); + _sdk_log("psxcd: CdLoadSession(): Scanning for ISO9660 volume descriptor.\n"); i = CdlModeSpeed; CdControl(CdlSetmode, (unsigned char*)&i, 0); @@ -820,7 +812,7 @@ int CdLoadSession(int session) if( !_ses_scanfound ) { - _LOG("psxcd: CdLoadSession(): Did not find volume descriptor.\n"); + _sdk_log("psxcd: CdLoadSession(): Did not find volume descriptor.\n"); _cd_iso_error = CdlIsoInvalidFs; EnterCriticalSection(); @@ -849,11 +841,11 @@ int CdLoadSession(int session) loc = (CdlLOC*)resultbuff; - _LOG("psxcd: CdLoadSession(): Session found in %02d:%02d:%02d (LBA=%d)\n", + _sdk_log("psxcd: CdLoadSession(): Session found in %02d:%02d:%02d (LBA=%d)\n", btoi(loc->minute), btoi(loc->second), btoi(loc->sector), CdPosToInt(loc)); i = CdPosToInt(loc)-17; - _LOG("psxcd: CdLoadSession(): Session starting at LBA=%d\n", i); + _sdk_log("psxcd: CdLoadSession(): Session starting at LBA=%d\n", i); _cd_media_changed = 1; diff --git a/libpsn00b/psxcd/psxcd.c b/libpsn00b/psxcd/psxcd.c index 6730531..b914b5e 100644 --- a/libpsn00b/psxcd/psxcd.c +++ b/libpsn00b/psxcd/psxcd.c @@ -1,6 +1,6 @@ #include -#include #include +#include #include #include "psxcd.h" @@ -21,12 +21,6 @@ volatile int _cd_last_sector_count; int _cd_media_changed; -#ifdef NDEBUG -#define _LOG(...) -#else -#define _LOG(...) printf(__VA_ARGS__) -#endif - void _cd_init(void); void _cd_control(unsigned char com, const void *param, int plen); void _cd_wait_ack(void); @@ -45,9 +39,9 @@ int CdInit(void) { if(CdSync(0, 0) != CdlDiskError) { CdControl(CdlDemute, 0, 0); - _LOG("psxcd: setup done\n"); + _sdk_log("psxcd: setup done\n"); } else { - _LOG("psxcd: setup error, bad disc/drive or no disc inserted\n"); + _sdk_log("psxcd: setup error, bad disc/drive or no disc inserted\n"); } return 1; @@ -311,7 +305,7 @@ static void CdDoRetry() { int cb; - _LOG("psxcd: retrying read...\n"); + _sdk_log("psxcd: retrying read...\n"); // Stop reading CdControl(CdlPause, 0, 0); diff --git a/libpsn00b/psxetc/dl.c b/libpsn00b/psxetc/dl.c index cf4e466..b85a7df 100644 --- a/libpsn00b/psxetc/dl.c +++ b/libpsn00b/psxetc/dl.c @@ -30,6 +30,7 @@ #include #include #include +#include #include /* Compile options */ @@ -66,12 +67,6 @@ void *(*_dl_resolve_callback)(DLL *, const char *) = 0; /* Private utilities */ -#ifdef NDEBUG -#define _LOG(...) -#else -#define _LOG(...) printf(__VA_ARGS__) -#endif - #define _ERROR(code, ret) { \ _error_code = code; \ return ret; \ @@ -92,7 +87,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); + _sdk_log("psxetc: FATAL! can't resolve %s, locking up\n", _name); while (1) __asm__ volatile("nop"); } @@ -133,7 +128,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); + _sdk_log("psxetc: can't open %s, error = %d\n", filename, fd); _ERROR(RTLD_E_FILE_OPEN, 0); } @@ -144,11 +139,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); + _sdk_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); + //_sdk_log("psxetc: loading %s (%d bytes)..", filename, size); for (uint32_t offset = 0; offset < size; ) { int32_t length = read(fd, &(buffer[offset]), 0x800); @@ -157,16 +152,16 @@ static uint8_t *_dl_load_file(const char *filename, size_t *size_output) { close(fd); free(buffer); - _LOG("failed, error = %d\n", length); + _sdk_log("failed, error = %d\n", length); _ERROR(RTLD_E_FILE_READ, 0); } - //_LOG("."); + //_sdk_log("."); offset += length; } close(fd); - _LOG(" done\n"); + _sdk_log(" done\n"); if (size_output) *size_output = size; @@ -192,7 +187,7 @@ int32_t DL_ParseSymbolMap(const char *ptr, size_t size) { // in order to minimize hash table size _symbol_map.nbucket = entries; _symbol_map.nchain = entries; - _LOG( + _sdk_log( "psxetc: allocating nbucket = %d, nchain = %d\n", _symbol_map.nbucket, entries @@ -205,7 +200,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"); + _sdk_log("psxetc: unable to allocate symbol map table\n"); _ERROR(RTLD_E_MAP_ALLOC, -1); } @@ -248,7 +243,7 @@ int32_t DL_ParseSymbolMap(const char *ptr, size_t size) { (_type == 'D') || // .data (_type == 'B') // .bss )) { - //_LOG( + //_sdk_log( //"psxetc: map sym: %08x,%08x [%c %s]\n", //address, _size, _type, name //); @@ -274,7 +269,7 @@ int32_t DL_ParseSymbolMap(const char *ptr, size_t size) { pos++; } - _LOG("psxetc: parsed %d symbols\n", entries); + _sdk_log("psxetc: parsed %d symbols\n", entries); if (!entries) _ERROR(RTLD_E_NO_SYMBOLS, -1); @@ -307,7 +302,7 @@ void DL_UnloadSymbolMap(void) { void *DL_GetSymbolByName(const char *name) { if (!_symbol_map.entries) { - _LOG("psxetc: attempted lookup with no map loaded\n"); + _sdk_log("psxetc: attempted lookup with no map loaded\n"); _ERROR(RTLD_E_NO_MAP, 0); } @@ -319,7 +314,7 @@ void *DL_GetSymbolByName(const char *name) { // calculated. for (uint32_t i = _symbol_map.bucket[hash_mod]; i != 0xffffffff;) { if (i >= _symbol_map.nchain) { - _LOG( + _sdk_log( "psxetc: GetSymbolByName() index out of bounds (%d >= %d)\n", i, _symbol_map.nchain ); @@ -329,14 +324,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); + //_sdk_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); + _sdk_log("psxetc: map lookup [%s not found]\n", name); _ERROR(RTLD_E_MAP_SYMBOL, 0); } @@ -352,14 +347,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"); + _sdk_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); + _sdk_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 @@ -368,128 +363,128 @@ 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); + //_sdk_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"); + //_sdk_log("[PLTGOT]\n"); dll->got = (void *) (ptr + dyn->d_un.d_val); break; // Offset of .hash section case DT_HASH: - //_LOG("[HASH]\n"); + //_sdk_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"); + //_sdk_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"); + //_sdk_log("[SYMTAB]\n"); dll->symtab = (void *) (ptr + dyn->d_un.d_val); break; // Length of .dynstr section //case DT_STRSZ: - //_LOG("[STRSZ]\n"); + //_sdk_log("[STRSZ]\n"); //break; // Length of each .dynsym entry case DT_SYMENT: - //_LOG("[SYMENT]\n"); + //_sdk_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 DLL symtab entry size %d\n", dyn->d_un.d_val); + _sdk_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"); + //_sdk_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); + _sdk_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"); + //_sdk_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 DLL flags\n"); + _sdk_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"); + //_sdk_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"); + //_sdk_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 DLL base address %08x\n", dyn->d_un.d_val); + _sdk_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"); + //_sdk_log("[MIPS_SYMTABNO]\n"); dll->symbol_count = dyn->d_un.d_val; break; // Index of first unresolved symbol table entry //case DT_MIPS_UNREFEXTNO: - //_LOG("[MIPS_UNREFEXTNO]\n"); + //_sdk_log("[MIPS_UNREFEXTNO]\n"); //break; // Index of first symbol table entry which has a matching GOT entry case DT_MIPS_GOTSYM: - //_LOG("[MIPS_GOTSYM]\n"); + //_sdk_log("[MIPS_GOTSYM]\n"); first_got_sym = dyn->d_un.d_val; break; // Number of pages the GOT is split into (does not apply to PS1) //case DT_MIPS_HIPAGENO: - //_LOG("[MIPS_HIPAGENO]\n"); + //_sdk_log("[MIPS_HIPAGENO]\n"); //break; //default: - //_LOG("[ignored]\n"); + //_sdk_log("[ignored]\n"); } } @@ -501,7 +496,7 @@ DLL *DL_CreateDLL(void *ptr, size_t size, DL_ResolveMode mode) { ((uint32_t) ptr + size - (uint32_t) dll->got) / sizeof(uint32_t) - 2; dll->got_length = local_got_len + (dll->symbol_count - first_got_sym) - 2; - _LOG( + _sdk_log( "psxetc: %d symbols, %d GOT entries\n", dll->symbol_count, dll->got_length ); @@ -530,7 +525,7 @@ DLL *DL_CreateDLL(void *ptr, size_t size, DL_ResolveMode mode) { continue; sym->st_value += (uint32_t) ptr; - //_LOG( + //_sdk_log( //"psxetc: DLL sym: %08x,%08x [%s]\n", //sym->st_value, sym->st_size, _name //); @@ -641,7 +636,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 (%d >= %d)\n", i, nchain); + _sdk_log("psxetc: DL_GetDLLSymbol() index out of bounds (%d >= %d)\n", i, nchain); _ERROR(RTLD_E_HASH_LOOKUP, 0); } @@ -649,14 +644,14 @@ 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); + //_sdk_log("psxetc: DLL lookup [%s = %08x]\n", name, sym->st_value); return sym->st_value; } i = chain[i]; } - _LOG("psxetc: DLL lookup [%s not found]\n", name); + _sdk_log("psxetc: DLL lookup [%s not found]\n", name); _ERROR(RTLD_E_DLL_SYMBOL, 0); } diff --git a/libpsn00b/psxetc/logging.c b/libpsn00b/psxetc/logging.c new file mode 100644 index 0000000..5199190 --- /dev/null +++ b/libpsn00b/psxetc/logging.c @@ -0,0 +1,50 @@ +/* + * PSn00bSDK internal debug logger + * (C) 2022 spicyjpeg - MPL licensed + * + * This file provides the (admittedly minimal) logging system used by all + * PSn00bSDK libraries. Log messages and warnings are issued using the + * _sdk_log() macro and collected into a buffer, whose contents can be flushed + * by calling _sdk_dump_log() (by default this is done by VSync()). Logging is + * only enabled in debug builds of libpsn00b. + */ + +#include +#include +#include +#include +#include + +#define LOG_BUFFER_SIZE 256 + +#ifndef NDEBUG + +/* Internal globals */ + +static char _log_buffer[LOG_BUFFER_SIZE]; +static size_t _log_buffer_length = 0; + +/* Internal logging API */ + +void _sdk_log_inner(const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + _log_buffer_length += vsnprintf( + &_log_buffer[_log_buffer_length], + LOG_BUFFER_SIZE - _log_buffer_length, + fmt, + ap + ); + va_end(ap); +} + +void _sdk_dump_log_inner(void) { + if (!_log_buffer_length) + return; + + write(1, _log_buffer, _log_buffer_length); + _log_buffer_length = 0; +} + +#endif diff --git a/libpsn00b/psxgpu/common.c b/libpsn00b/psxgpu/common.c index bf70b72..a262472 100644 --- a/libpsn00b/psxgpu/common.c +++ b/libpsn00b/psxgpu/common.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include @@ -36,13 +35,7 @@ static volatile uint8_t _queue_head, _queue_tail, _queue_length; static volatile uint32_t _vblank_counter; static volatile uint16_t _last_hblank; -/* Private utilities and interrupt handlers */ - -#ifdef NDEBUG -#define _LOG(...) -#else -#define _LOG(...) printf(__VA_ARGS__) -#endif +/* Private interrupt handlers */ static void _vblank_handler(void) { _vblank_counter++; @@ -57,8 +50,8 @@ static void _gpu_dma_handler(void) { __asm__ volatile(""); if (--_queue_length) { - QueueEntry *entry = &_draw_queue[_queue_head++]; - _queue_head %= QUEUE_LENGTH; + volatile QueueEntry *entry = &_draw_queue[_queue_head++]; + _queue_head %= QUEUE_LENGTH; entry->func(entry->arg1, entry->arg2, entry->arg3); } else { @@ -82,7 +75,7 @@ void ResetGraph(int mode) { _gpu_video_mode = (GPU_GP1 >> 20) & 1; ExitCriticalSection(); - _LOG("psxgpu: setup done, default mode is %s\n", _gpu_video_mode ? "PAL" : "NTSC"); + _sdk_log("psxgpu: setup done, default mode is %s\n", _gpu_video_mode ? "PAL" : "NTSC"); } if (mode == 3) { @@ -115,13 +108,13 @@ void ResetGraph(int mode) { // TODO: add support for no$psx's "halt" register static void _default_vsync_halt(void) { int counter = _vblank_counter; - for (int i = VSYNC_TIMEOUT; i; i--) { if (counter != _vblank_counter) return; } - _LOG("psxgpu: VSync() timeout\n"); + _sdk_log("psxgpu: VSync() timeout\n"); + _sdk_dump_log(); ChangeClearPAD(0); ChangeClearRCnt(3, 0); } @@ -137,6 +130,7 @@ int VSync(int mode) { // Wait for at least one vertical blank event to occur. do { + _sdk_dump_log(); _vsync_halt_func(); // If interlaced mode is enabled, wait until the GPU starts displaying @@ -190,15 +184,15 @@ int EnqueueDrawOp( if (_queue_length) { if (_queue_length >= QUEUE_LENGTH) { IRQ_MASK = mask; - _LOG("psxgpu: draw queue overflow, dropping commands\n"); + _sdk_log("psxgpu: draw queue overflow, dropping commands\n"); return -1; } int length = _queue_length; _queue_length = length + 1; - QueueEntry *entry = &_draw_queue[_queue_tail++]; - _queue_tail %= QUEUE_LENGTH; + volatile QueueEntry *entry = &_draw_queue[_queue_tail++]; + _queue_tail %= QUEUE_LENGTH; entry->func = func; entry->arg1 = arg1; @@ -236,7 +230,8 @@ int DrawSync(int mode) { while (!(GPU_GP1 & (1 << 26))) __asm__ volatile(""); } else { - printf("psxgpu: DrawSync() timeout\n"); + _sdk_log("psxgpu: DrawSync() timeout\n"); + _sdk_dump_log(); } return _queue_length; @@ -297,7 +292,7 @@ void DrawPrim(const uint32_t *pri) { } int DrawOTag(const uint32_t *ot) { - return EnqueueDrawOp(&DrawOTag2, (uint32_t) ot, 0, 0); + return EnqueueDrawOp((void *) &DrawOTag2, (uint32_t) ot, 0, 0); } void DrawOTag2(const uint32_t *ot) { diff --git a/libpsn00b/psxgpu/env.c b/libpsn00b/psxgpu/env.c index 1b97026..f513727 100644 --- a/libpsn00b/psxgpu/env.c +++ b/libpsn00b/psxgpu/env.c @@ -85,7 +85,7 @@ int DrawOTagEnv(const uint32_t *ot, DRAWENV *env) { //while (!(GPU_GP1 & (1 << 26))) //__asm__ volatile(""); - return EnqueueDrawOp(&DrawOTag2, (uint32_t) prim, 0, 0); + return EnqueueDrawOp((void *) &DrawOTag2, (uint32_t) prim, 0, 0); } void PutDrawEnv(DRAWENV *env) { diff --git a/libpsn00b/psxgpu/image.c b/libpsn00b/psxgpu/image.c index c09a59d..968dde5 100644 --- a/libpsn00b/psxgpu/image.c +++ b/libpsn00b/psxgpu/image.c @@ -4,7 +4,7 @@ */ #include -#include +#include #include #include @@ -12,20 +12,14 @@ /* Private utilities */ -#ifdef NDEBUG -#define _LOG(...) -#else -#define _LOG(...) printf(__VA_ARGS__) -#endif - static void _dma_transfer(const RECT *rect, uint32_t *data, int write) { size_t length = rect->w * rect->h; if (length % 2) - _LOG("psxgpu: can't transfer an odd number of pixels\n"); + _sdk_log("psxgpu: can't transfer an odd number of pixels\n"); length /= 2; if ((length >= DMA_CHUNK_LENGTH) && (length % DMA_CHUNK_LENGTH)) { - _LOG("psxgpu: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); + _sdk_log("psxgpu: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); length += DMA_CHUNK_LENGTH - 1; } @@ -53,15 +47,19 @@ static void _dma_transfer(const RECT *rect, uint32_t *data, int write) { /* VRAM transfer API */ int LoadImage(const RECT *rect, const uint32_t *data) { - return EnqueueDrawOp(&_dma_transfer, (uint32_t) rect, (uint32_t) data, 1); + return EnqueueDrawOp( + (void *) &_dma_transfer, (uint32_t) rect, (uint32_t) data, 1 + ); } int StoreImage(const RECT *rect, uint32_t *data) { - return EnqueueDrawOp(&_dma_transfer, (uint32_t) rect, (uint32_t) data, 0); + return EnqueueDrawOp( + (void *) &_dma_transfer, (uint32_t) rect, (uint32_t) data, 0 + ); } int MoveImage(const RECT *rect, int x, int y) { - return EnqueueDrawOp(&MoveImage2, (uint32_t) rect, x, y); + return EnqueueDrawOp((void *) &MoveImage2, (uint32_t) rect, x, y); } void LoadImage2(const RECT *rect, const uint32_t *data) { diff --git a/libpsn00b/psxpress/mdec.c b/libpsn00b/psxpress/mdec.c index 06510cb..d43436f 100644 --- a/libpsn00b/psxpress/mdec.c +++ b/libpsn00b/psxpress/mdec.c @@ -4,7 +4,7 @@ */ #include -#include +#include #include #include #include @@ -81,14 +81,6 @@ static const DECDCTENV _default_mdec_env = { } }; -/* Private utilities */ - -#ifdef NDEBUG -#define _LOG(...) -#else -#define _LOG(...) printf(__VA_ARGS__) -#endif - /* Public API */ void DecDCTReset(int mode) { @@ -135,7 +127,7 @@ void DecDCTin(const uint32_t *data, int mode) { // the stream. void DecDCTinRaw(const uint32_t *data, size_t length) { if ((length >= DMA_CHUNK_LENGTH) && (length % DMA_CHUNK_LENGTH)) { - _LOG("psxpress: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); + _sdk_log("psxpress: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); length += DMA_CHUNK_LENGTH - 1; } @@ -157,7 +149,8 @@ int DecDCTinSync(int mode) { return 0; } - _LOG("psxpress: DecDCTinSync() timeout\n"); + _sdk_log("psxpress: DecDCTinSync() timeout\n"); + _sdk_dump_log(); return -1; } @@ -165,7 +158,7 @@ void DecDCTout(uint32_t *data, size_t length) { DecDCToutSync(0); if ((length >= DMA_CHUNK_LENGTH) && (length % DMA_CHUNK_LENGTH)) { - _LOG("psxpress: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); + _sdk_log("psxpress: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); length += DMA_CHUNK_LENGTH - 1; } @@ -187,6 +180,7 @@ int DecDCToutSync(int mode) { return 0; } - _LOG("psxpress: DecDCToutSync() timeout\n"); + _sdk_log("psxpress: DecDCToutSync() timeout\n"); + _sdk_dump_log(); return -1; } diff --git a/libpsn00b/psxspu/common.c b/libpsn00b/psxspu/common.c index 380bd3d..7d90858 100644 --- a/libpsn00b/psxspu/common.c +++ b/libpsn00b/psxspu/common.c @@ -4,7 +4,7 @@ */ #include -#include +#include #include #include @@ -19,28 +19,22 @@ static uint16_t _transfer_addr = WRITABLE_AREA_ADDR; /* Private utilities */ -#ifdef NDEBUG -#define _LOG(...) -#else -#define _LOG(...) printf(__VA_ARGS__) -#endif - static void _wait_status(uint16_t mask, uint16_t value) { for (int i = STATUS_TIMEOUT; i; i--) { if ((SPU_STAT & mask) == value) return; } - _LOG("psxspu: status register timeout (0x%04x)\n", SPU_STAT); + _sdk_log("psxspu: status register timeout (0x%04x)\n", SPU_STAT); } static void _dma_transfer(uint32_t *data, size_t length, int write) { if (length % 4) - _LOG("psxspu: can't transfer a number of bytes that isn't multiple of 4\n"); + _sdk_log("psxspu: can't transfer a number of bytes that isn't multiple of 4\n"); length /= 4; if ((length >= DMA_CHUNK_LENGTH) && (length % DMA_CHUNK_LENGTH)) { - _LOG("psxspu: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); + _sdk_log("psxspu: transfer data length (%d) is not a multiple of %d, rounding\n", length, DMA_CHUNK_LENGTH); length += DMA_CHUNK_LENGTH - 1; } -- cgit v1.2.3