diff options
| author | John Wilbert M. Villamor <lameguy64@gmail.com> | 2019-06-23 07:42:16 +0800 |
|---|---|---|
| committer | John Wilbert M. Villamor <lameguy64@gmail.com> | 2019-06-23 07:42:16 +0800 |
| commit | 7be9178c0f9b0e698a305ecc5c0c41fcc596a4fc (patch) | |
| tree | e98c627e1da5c764563774b89b0c06d7ac5ad0a4 | |
| parent | ae9e545c3ed33d39ce21ae13ceb8337fa34901b8 (diff) | |
| download | psn00bsdk-7be9178c0f9b0e698a305ecc5c0c41fcc596a4fc.tar.gz | |
LibPSn00b officially v0.10b, added psxsio library, better DrawSync() and VSync(), better reference manual.
59 files changed, 1747 insertions, 487 deletions
@@ -1,78 +1,149 @@ # PSn00bSDK -PSn00bSDK is a 100% free and open source SDK for developing homebrew games -and applications for the original Sony PlayStation. The SDK consists mainly -of libraries and some tools for converting and building resources to be -used on the console. - -While PSn00bSDK is currently a work in progress the project aims to develop -an SDK that is as close to the official Sony SDK as possiblein in terms of -supported hardware features which include GPU, GTE, SPU, CD, MDEC and -controller/memory card peripherals and a library API written to follow the -official SDK's API syntax. With extensive low-level technical documentation -of the PSX readily available (such as nocash's PSX specs) there should be no -excuse to not have full support of the aforementioned hardware features. - -The PSn00bSDK libraries are written mostly in MIPS assembly language with -compiler generated code limited to small and moderately sized support -functions for best possible performance and to keep the runtime library -footprint as small as possible. Many of the library functions avoid using -BIOS calls such as C string and memory manipulation functions and use pure -assembly equivalents for improved performance for memory and string -manipulation operations. +PSn00bSDK is a 100% free and open source SDK project for the original Sony +PlayStation for developing homebrew applications and games for the console +whether it be an open source, freeware, or commercial project. +The SDK is composed mainly of libraries (libpsn00b) and some utilities that +provide a basic framework for developing software for the PlayStation +hardware, the compiler is separate (GCC) and should be acquired from GNU. +The library API is intentionally written to resemble the library API of the +official libraries as closely as possible. This design decision is not only +for familiarity reasons and so that existing sample code and tutorials would +still apply, but to also make porting existing homebrew originally made with +official SDKs to PSn00bSDK easier with few modifications. -## Building the SDK +PSn00bSDK is currently a work in progress and cannot really be considered +production ready, but what is currently implemented should be enough to +produce some interesting homebrew with the SDK, especially with extensive +support for the GPU and GTE hardware. There's no reason not to fully support +the hardware features of the target platform when they have been fully +documented for years (nocash's PSX specs document in this case). + +Most of libpsn00b is written mostly in MIPS assembly, more so functions that +interface with hardware. Many of the standard C functions are implemented in +custom MIPS assembly instead of equivalents found in the BIOS ROM for +performance reasons. + + +## Notable features + +* Extensive GPU support with polygon primitives, high-speed DMA VRAM + transfers and DMA ordering table processing. All video modes for both NTSC + and PAL standards also supported with fully adjustable display area and + automatic video standard detection based on last GPU mode, no BIOS ROM + string checks used. + +* Extensive GTE support with rotate, translate, perspective correction and + lighting through assembly macros (for both C and ASM) and high performance + matrix and vector functions, all calculations performed in fixed point + integer math. + +* Stable and easy to use interrupt service routine with callback system for + simplified handling of hardware and DMA interrupts, no crude event handlers + or kernel hacks used and should be compatible with HLE BIOS implementations + and homebrew loaders and menus. + +* Complete Serial I/O support with SIOCONS driver for tty console access + through serial interface. + +* BIOS controller functions for polling controller input function as + intended, no crude manual polling in main loop. -For most users (particularly those who run Windows) it is recommended to -just download a release package containing the GCC toolchain and libraries -in binary form ready to be used. +* BIOS CD-ROM support with custom initialization function that does not + break other DMA channels (such as GPU and SPU DMA) for easier CD-ROM + initialization. -If you wish to build the SDK yourself building PSn00bSDK requires a GNU -GCC toolchain targeting mipsel-unknown-elf. For instructions on how to -build the GCC toolchain please read toolchain.txt. +* Uses Sony SDK library syntax for familiarity to experienced programmers + and to make porting existing homebrew to PSn00bSDK easier. -To build the PSn00bSDK libraries simply enter the libpsn00b directory and -run make. Make sure you have the path of the toolchain binaries in your PATH -environment variable. If things go accordingly it should run through all -library directories and produce library files. +* Works on real hardware and most popular emulators. -To build the PSn00bSDK tools simply enter the tools directory and run make. -You'll need tinyxml2 to satisfy the lzpack and smxlink tools. -To build the PSn00bSDK examples which also tests if your SDK setup works -correctly simply enter the examples directory and run make. You may want -to modify the sdk-common.mk file first and make sure the library paths are -correct and that your PATH environment variable has the tools/bin directory -in it as elf2x and lzpack are required for the examples to build correctly. +## Obtaining PSn00bSDK + +Because PSn00bSDK is updated semi-regularly as this project is mostly a +work-in-progress, it is better to obtain this SDK from source by building +it yourself in the long run. Prepared packages containing precompiled +libpsn00b libraries, the toolchain and additional utilities not included +in this repository for Windows users are planned, but some arrangements +need to be made. Perhaps when PSn00bSDK is halfway production ready. + +A precompiled copy of the GCC 7.2.0 toolchain for Windows is available +in lameguy64's website in the PSn00bSDK page. This should make building +PSn00bSDK under Windows a bit easier as building the toolchain is the +hardest part of building PSn00bSDK and its more difficult to get it to +compile correctly under Windows. + + +## Building the SDK + +### Windows (needs work/testing): +1. Download the following: + * MinGW GCC + * MSys2 + * tinyxml2 (for lzpack and smxlink) + * GCC 7.2.0 for mipsel-unknown-elf (download from Lameguy64's website) +2. Install MSys2 and MinGW GCC. +3. Extract GCC 7.2.0 for mipsel-unknown-elf to the root of your C drive. +4. Update your PATH environment variable to point to the bin directories of + GCC 7.2.0 for mipsel-unknown-elf, MSys2 and MinGW GCC. Make sure you can + access gcc, mipsel-unknown-elf-gcc and make from any directory in the + command prompt. +5. Build tinyxml2 with MinGW GCC through MSys2's shell. +6. Clone/download PSn00bSDK source files. +7. Enter libpsn00b directory and run make (with optional -j parameter for + building across multiple cores/threads). +8. Enter tools directory and run make, then make install to consolidate the + executables to a bin directory. Add this directory to your PATH + environment variable. +9. Compile the example programs to test if the SDK is set up correctly. + Set correct paths in sdk-common.mk when necessary. + +### Linux and Unix-likes: +1. Build and install the GNU GCC toolchain configured for mipsel-unknown-elf + (see toolchain.txt for details). +2. Install the following (development) package: + * tinyxml2 +3. Clone/download PSn00bSDK source files. +4. Enter the libpsn00b directory and run make. Make sure + mipsel-unknown-elf-gcc is accessible in the terminal from within any + directory beforehand. +5. Enter the tools directory and run make, then make install to consolidate + the binaries to a bin directory. Add this directory to your PATH variable. +6. Compile the example programs to test if the SDK is set up correctly. + Set correct paths in sdk-common.mk when necessary. ## Examples -There are a few graphics examples and complete source code of n00bdemo -included in the examples directory. More example programs may be added in -future updates and contributions are welcome. +There are a few examples and complete source code of n00bdemo included in +the examples directory. More example programs may be added in the future +and contributed example programs are welcome. -## To-do +## To-do List -* Support functions to get C++ classes working are yet to be implemented. - glibc won't compile (or its not included with GCC sources) and likely - depends on a Linux kernel that does not exist on the PS1. Newlib might - be undesirable as it appears to be too bloated for PS1. Just getting - classes to work would be enough. +* libc: C++ support (getting classes, new and delete working is enough) + and better sprintf() (one from PSXSDK is slow due to unnecessary usage + of int64 and somewhat a bit buggy) yet to be implemented. More standard + C library stuff also yet to be implemented. -* psxspu needs to be expanded upon. Currently lacks support for reverb - and many voice controls. +* psxgpu: VRAM download and VRAM move functions, some more primitives + and macros yet to be implemented. -* An 'IRQ handler for all' implementation through BIOS function - SetCustomExitFromException() is yet to be implemented for better/more - reliable interrupt handling. UPDATE: SetCustomExitFromException() hook - is now working! See readme of psxgpu for details. +* psxgte: Higher level GTE rotate translate and perspective functions + yet to be implemented. -* CD-ROM library is yet to be made. +* psxspu: Lots of work to do. -* Better (and faster) sprintf() function. +* psxapi: Plenty of BIOS function calls yet to be added. + +* psxetc: Text stream stuff (FntOpen(), FntPrint(), FndFlush()) for + debug purposes yet to be implemented. + +* Libraries yet to be made: psxcd (for better CD-ROM support) and + psxmdec (MDEC support). ## Usage terms @@ -80,9 +151,12 @@ future updates and contributions are welcome. PSn00bSDK falls under the terms and conditions of the Mozilla Public License. A quick summary of this license is that PSn00bSDK can be used freely in both free and open source projects and commercial closed source -projects. But if modifications to the SDK were made as part of the -development of such projects such changes must be contributed back in -return. +projects as projects using PSn00bSDK does not necessarily have to follow +the MPL as well. + +If modifications to the SDK were made as part of the development of such +projects that enhance its functionality, such changes must be contributed +back in return. ## Credits @@ -90,6 +164,6 @@ return. Main developer: * Lameguy64 -Important references used: +References used: * nocash's PlayStation specs document (http://problemkaputt.de/psx-spx.htm) -* Tails92's PSXSDK project (bits and pieces of it). +* Tails92's PSXSDK project. diff --git a/changelog.txt b/changelog.txt index 1c27eaf..65717bd 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,18 +1,103 @@ PSn00bSDK changelog + +06-23-2019 by Lameguy64: + +* LibPSn00b Run-time Library is officially version 0.10b. + +* Reworked readme file with improved build instructions. + +* libpsn00b: Added missing C extern groups for C++ compatibility in + psxapi.h, stdlib.h and string.h. + +* libpsn00b: Removed changelogs in the readmes of each libpsn00b library + as its much easier to keep track of changes in a single changelog than + scattering them across multiple changelogs. + +* psxapi: Added Exec() function and EXEC struct. + +* psxgpu: Added DrawPrim() function (uses direct I/O). + +* psxgpu: VSync() function completely overhauled. Logic is now based on + Sony's code but more efficient and can return total number of vblanks + elapsed, number of hblanks since last call and wait up to n vblanks + specified by an appropriate argument value. It will also generate a + timeout when vblank interrupt stops working and would attempt to + restart it. + +* psxapi: Added gets() and getc() BIOS functions. + +* psxapi: Corrected a putc()/putchar() discrepancy. putc() puts a character + to a file stream, putchar() puts a character to stdout. + +* Completely revised library reference manual with better formatting and + more functions documented. + +* psxgpu: Added DrawSyncCallback(). + +* psxgpu: Implemented DMA interrupt callback system with DMACallback() + allowing to handle DMA interrupts very easily. + +* libpsn00b: Implemented Serial I/O library (psxsio) with serial tty device + (installed using AddSIO) and serial callback support. Serial library + is also fully documented. + +* psxgpu: Implemented IRQ callback system with InterruptCallback() allowing + to set interrupt callbacks very easily. + +* psxgpu: Implemented proper IRQ handler installed using HookEntryInt or + SetCustomExitFromException() for handling VSync and other interrupts. + ChangeClearPAD(0) must now be called after _InitPad() or vsync timeout + will occur. + +* libpsn00b: Started making local labels prefixed with .L instead of . making + them not appear in symbol lists resulting in a cleaner symbol dump. Still + not possible to do function-scope local labels like in ASMPSX because GAS + syntax is ASS (or ASS GAS which is farts, GAS is farts). + +* psxgpu: DrawSync() function now waits for DMA completion and GPU transfer + ready instead of simply waiting for GPU transfer ready which is the likely + cause of subtle GPU related timing issues, it also sets GPU DMA transfer + mode to off afterwards. It can also read number of words remaining in DMA + transfer if a0 is non-zero but it likely only returns the correct value on + VRAM transfers. Exact way how DrawSync() returns the count in the official + SDK is currently unknown. + + + +06-07-2019 by qbradq: + +* lzpack: Swapped a buffer length litteral with sizeof operator, fixing a + stack overflow bug in some instances. + + + 05-23-2019 by Lameguy64: * Added dev notes.txt file in docs that includes notes about the many - quirks discovered about the system throughout the development of this SDK. + quirks about the console discovered during the development of this + SDK project. * Updated libn00bref.odf a little. +* Added turboboot example. + * Added rgb24 example. -* Made stack usage in ResetGraph() less wasteful. +* Got custom exit handler set using SetCustomExitFromException() (BIOS + function B(19h)) working. Currently used to acknowledge VSync IRQ but + actual VSync handling is still done with events and needs to be + transferred to the custom exit handler. At least it lets BIOS + controller functions to work now. See doc/dev notes.txt for details + on how this handler behaves. + +* Made stack usage in ResetGraph() less wasteful. You only need to + allocate N words on stack based on N arguments of the function + being called. -* VSync IRQ handling now done using a custom exit handler. Actual VSync - handling is yet to be moved to the custom exit handler though. +* VSync IRQ handling now done using a custom exit from exception handler. + Actual VSync handling is yet to be moved to the custom exit handler + though. * Made stack usage in start.s of libc a lot less wasteful. diff --git a/doc/LibPSn00b Reference.odt b/doc/LibPSn00b Reference.odt Binary files differnew file mode 100644 index 0000000..ca5346d --- /dev/null +++ b/doc/LibPSn00b Reference.odt diff --git a/doc/dev notes.txt b/doc/dev notes.txt index 336e6d3..2b280c7 100644 --- a/doc/dev notes.txt +++ b/doc/dev notes.txt @@ -10,21 +10,28 @@ I run into more previously undocumented quirks in the future. need to allocate N words on the stack first when calling a function that has N arguments (addiu $sp, -(4*N) where N = number of arguments of the function being called) even if the arguments are on registers a0 to a3 and the C -functions don't always use the space allotted in stack. +functions don't always use the space allotted in stack. When calling a +function with a variable number of arguments (printf) always allocate +16 bytes of stack. -* A custom handler hooked using BIOS function B(19h) -(SetCustomExitFromException) is only triggered when there's an interrupt -that hasn't been acknowledged by previous IRQ handlers that have been -executed prior. This is also the best point to acknowledge any interrupts -without breaking compatibility with built-in BIOS features and is what the -official SDK uses to handle interrupts. +* Hooking a custom handler using BIOS function HookEntryInt (B(19h), known +as SetCustomExitFromException in nocash docs) is only triggered when there's +an IRQ that is not yet acknowledged by previous IRQ handlers built into the +kernel. This is also the best point to acknowledge any IRQs without breaking +compatibility with built-in BIOS IRQ handlers and is what the official SDK +uses to handle IRQs. To make sure this handler is triggered on every interrupt +you must call ChangeClearPad(0) and ChangeClearRCnt(3, 0) (which are functions +(B(5Bh)) and C(0Ah) respectively) otherwise the pad and root counter handlers +in the kernel will acknowledge the interrupt before your handler, preventing +you from handling them yourself. -* It is not advisable to acknowledge interrupts in event handlers like in -PSXSDK as it would break BIOS features that depend on interrupts. Clearing -the VBlank IRQ in a event handler for example prevents the BIOS controller +* It is not advisable to handle interrupts using event handlers like in +PSXSDK as it breaks BIOS features that depend on interrupts. Clearing the +VBlank IRQ in a event handler for example prevents the BIOS controller functions from working as it depends on the VBlank IRQ to determine when to query controllers. Acknowledge interrupts using a custom handler set by BIOS -function B(19h) (SetCustomExitFromException). +function HookEntryInt (B(19h), known as SetCustomExitFromException in nocash +docs). * When running in high resolution mode you must additionally wait for bit 31 in GPUSTAT (1F801814h) to alternate on every frame (frame 0: wait until 0, @@ -34,10 +41,11 @@ to displayed area enabled. Performing this check in a low resolution/non interlaced mode is harmless. * There's a hardware bug in the GPU FillVRAM command GP0(02h) where if you -set the height to 512 pixels the primitive is executed with a height of 0 as -the hardware does not appear to interpret the last bit of the height value. -This is most apparent when putting a DRAWENV with the height of 512 pixels -(for PAL for example) and background clearing is enabled. +set the height to 512 pixels the primitive is processed with a height of 0 +as the hardware does not appear to interpret the last bit of the height +value. This is most apparent when putting a DRAWENV with the height of 512 +pixels (for PAL for example) and background clearing is enabled, hence why +DRAWENV.isbg is not effective in the official SDK. * In the official SDK, DMA IRQs appear to be enabled only when a callback function is set (ie. DrawSyncCallback() enables IRQ for DMA channel 2). DMA diff --git a/examples/balls/main.c b/examples/balls/main.c index 3e23fb5..ba6a391 100644 --- a/examples/balls/main.c +++ b/examples/balls/main.c @@ -203,8 +203,8 @@ int main(int argc, const char* argv[]) { nextpri += sizeof(DR_TPAGE); /* Wait for GPU and VSync */ - DrawSync(); - VSync(); + DrawSync( 0 ); + VSync( 0 ); /* Since draw.isbg is non-zero this clears the screen */ PutDrawEnv( &draw ); diff --git a/examples/gte/main.c b/examples/gte/main.c index aa7042d..3fec9d7 100644 --- a/examples/gte/main.c +++ b/examples/gte/main.c @@ -288,8 +288,8 @@ void init() { void display() { /* Wait for GPU to finish drawing and vertical retrace */ - DrawSync(); - VSync(); + DrawSync( 0 ); + VSync( 0 ); /* Swap buffers */ db_active ^= 1; diff --git a/examples/n00bdemo/disp.c b/examples/n00bdemo/disp.c index 5a9bb22..d798ee9 100644 --- a/examples/n00bdemo/disp.c +++ b/examples/n00bdemo/disp.c @@ -57,8 +57,8 @@ void initDisplay() { void display() { - VSync(); - DrawSync(); + DrawSync(0); + VSync(0); PutDrawEnv( &draw ); DrawOTag( ot[db]+OT_LEN-1 ); diff --git a/examples/n00bdemo/main.c b/examples/n00bdemo/main.c index 2a5874f..a6eb57e 100644 --- a/examples/n00bdemo/main.c +++ b/examples/n00bdemo/main.c @@ -615,7 +615,7 @@ void transition() { } - DrawSync(); + DrawSync(0); draw.isbg = 1; diff --git a/examples/rgb24/main.c b/examples/rgb24/main.c index 178ece2..9f1a647 100644 --- a/examples/rgb24/main.c +++ b/examples/rgb24/main.c @@ -43,7 +43,7 @@ int main() { // Upload image to VRAM GetTimInfo(tim_image, &tim); LoadImage(tim.prect, tim.paddr); - DrawSync(); + DrawSync(0); while(1) { } diff --git a/libpsn00b/include/hwregs_a.h b/libpsn00b/include/hwregs_a.h index a71a657..27cfc88 100644 --- a/libpsn00b/include/hwregs_a.h +++ b/libpsn00b/include/hwregs_a.h @@ -63,6 +63,13 @@ .set JOY_CTRL, 0x104A .set JOY_BAUD, 0x104E +# Serial +.set SIO_TXRX, 0x1050 +.set SIO_STAT, 0x1054 +.set SIO_MODE, 0x1058 +.set SIO_CTRL, 0x105a +.set SIO_BAUD, 0x105e + # IRQ .set ISTAT, 0x1070 .set IMASK, 0x1074 diff --git a/libpsn00b/include/psxapi.h b/libpsn00b/include/psxapi.h index 9cfb6cb..68dac67 100644 --- a/libpsn00b/include/psxapi.h +++ b/libpsn00b/include/psxapi.h @@ -47,6 +47,20 @@ struct DIRENTRY { // Directory entry char system[4]; }; +struct EXEC { + unsigned int pc0; + unsigned int gp0; + unsigned int t_addr; + unsigned int t_size; + unsigned int d_addr; + unsigned int d_size; + unsigned int b_addr; + unsigned int b_size; + unsigned int s_addr; + unsigned int s_size; + unsigned int sp,fp,rp,ret,base; +}; + // Not recommended to use these functions to install IRQ handlers typedef struct { @@ -56,48 +70,60 @@ typedef struct { unsigned int pad; } INT_RP; -extern void SysEnqIntRP(int pri, INT_RP *rp); -extern void SysDeqIntRP(int pri, INT_RP *rp); +#ifdef __cplusplus +extern "C" { +#endif -// Use event handlers instead +void SysEnqIntRP(int pri, INT_RP *rp); +void SysDeqIntRP(int pri, INT_RP *rp); -extern int OpenEvent(unsigned int class, int spec, int mode, void (*func)()); -extern int CloseEvent(int ev_desc); -extern int EnableEvent(int ev_desc); -extern int DisableEvent(int ev_desc); +// Event handler stuff + +int OpenEvent(unsigned int class, int spec, int mode, void (*func)()); +int CloseEvent(int ev_desc); +int EnableEvent(int ev_desc); +int DisableEvent(int ev_desc); // BIOS file functions -extern int open(const char *name, int mode); -extern int close(int fd); -extern int seek(int fd, unsigned int offset, int mode); -extern int read(int fd, char *buff, unsigned int len); -extern int write(int fd, const char *buff, unsigned int len); -extern int ioctl(int fd, int cmd, int arg); -extern struct DIRENTRY *firstfile(const char *wildcard, struct DIRENTRY *entry); -extern struct DIRENTRY *nextfile(struct DIRENTRY *entry); -extern int erase(const char *name); -extern int chdir(const char *path); +int open(const char *name, int mode); +int close(int fd); +int seek(int fd, unsigned int offset, int mode); +int read(int fd, char *buff, unsigned int len); +int write(int fd, const char *buff, unsigned int len); +int ioctl(int fd, int cmd, int arg); +struct DIRENTRY *firstfile(const char *wildcard, struct DIRENTRY *entry); +struct DIRENTRY *nextfile(struct DIRENTRY *entry); +int erase(const char *name); +int chdir(const char *path); #define delete( p ) erase( p ) #define cd( p ) chdir( p ) // For compatibility int AddDev(DCB *dcb); int DelDev(const char *name); -extern void ListDev(void); - -extern void EnterCriticalSection(void); -extern void ExitCriticalSection(void); +void ListDev(void); -extern void _InitCd(void); -extern void _96_init(void); -extern void _96_remove(void); +void EnterCriticalSection(void); +void ExitCriticalSection(void); -extern void ChangeClearPAD(int mode); +void _InitCd(void); +void _96_init(void); +void _96_remove(void); // BIOS pad functions void _InitPad(char *buff1, int len1, char *buff2, int len2); void _StartPad(void); void _StopPad(void); +void ChangeClearPAD(int mode); +void ChangeClearRCnt(int t, int m); + +// Executable functions +int Exec(struct EXEC *exec, int argc, char *argv); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/libpsn00b/include/psxgpu.h b/libpsn00b/include/psxgpu.h index 24d023a..40b9159 100644 --- a/libpsn00b/include/psxgpu.h +++ b/libpsn00b/include/psxgpu.h @@ -38,8 +38,8 @@ #define setDrawTPage( p, tp, abr, x, y ) \ ( (p)->code[0] = getTPage( tp, abr, x, y ), \ setlen( p, 1 ), setcode( p, 0xe1 ) ) - -/** ORIGINAL FUNCTION **/ + +/* ORIGINAL */ #define setDrawTPageVal( p, tp ) \ ( (p)->code[0] = tp, \ setlen( p, 1 ), setcode( p, 0xe1 ) ) @@ -217,25 +217,24 @@ typedef struct { unsigned int tag; unsigned char r0,g0,b0,code; short x0,y0; - unsigned char u0,v0; - unsigned short clut; short x1,y1; - unsigned char u1,v1; - unsigned short tpage; short x2,y2; - unsigned char u2,v2; - unsigned short pad; -} POLY_FT3; + short x3,y3; +} POLY_F4; typedef struct { unsigned int tag; unsigned char r0,g0,b0,code; short x0,y0; - unsigned char r1,g1,b1,pad0; + unsigned char u0,v0; + unsigned short clut; short x1,y1; - unsigned char r2,g2,b2,pad1; + unsigned char u1,v1; + unsigned short tpage; short x2,y2; -} POLY_G3; + unsigned char u2,v2; + unsigned short pad; +} POLY_FT3; typedef struct { unsigned int tag; @@ -243,53 +242,54 @@ typedef struct { short x0,y0; unsigned char u0,v0; unsigned short clut; - unsigned char r1,g1,b1,pad0; short x1,y1; unsigned char u1,v1; unsigned short tpage; - unsigned char r2,g2,b2,pad1; short x2,y2; unsigned char u2,v2; - unsigned short pad2; -} POLY_GT3; + unsigned short pad0; + short x3,y3; + unsigned char u3,v3; + unsigned short pad1; +} POLY_FT4; typedef struct { unsigned int tag; unsigned char r0,g0,b0,code; short x0,y0; + unsigned char r1,g1,b1,pad0; short x1,y1; + unsigned char r2,g2,b2,pad1; short x2,y2; - short x3,y3; -} POLY_F4; +} POLY_G3; typedef struct { unsigned int tag; unsigned char r0,g0,b0,code; short x0,y0; - unsigned char u0,v0; - unsigned short clut; + unsigned char r1,g1,b1,pad0; short x1,y1; - unsigned char u1,v1; - unsigned short tpage; + unsigned char r2,g2,b2,pad1; short x2,y2; - unsigned char u2,v2; - unsigned short pad0; + unsigned char r3,g3,b3,pad2; short x3,y3; - unsigned char u3,v3; - unsigned short pad1; -} POLY_FT4; +} POLY_G4; typedef struct { unsigned int tag; unsigned char r0,g0,b0,code; short x0,y0; + unsigned char u0,v0; + unsigned short clut; unsigned char r1,g1,b1,pad0; short x1,y1; + unsigned char u1,v1; + unsigned short tpage; unsigned char r2,g2,b2,pad1; short x2,y2; - unsigned char r3,g3,b3,pad2; - short x3,y3; -} POLY_G4; + unsigned char u2,v2; + unsigned short pad2; +} POLY_GT3; typedef struct { unsigned int tag; @@ -431,21 +431,6 @@ typedef struct { /* * VRAM fill and transfer primitive definitions */ -typedef struct { - unsigned int tag; - unsigned char r0,g0,b0,code; - unsigned short x0,y0; // Note: coordinates must be in 16 pixel steps - unsigned short w,h; -} FILL; - -typedef struct { - unsigned int tag; - unsigned char p0,p1,p2,code; - unsigned short x0,y0; - unsigned short x1,y1; - unsigned short w,h; - unsigned int nop[4]; -} VRAM2VRAM; typedef struct { unsigned int tag; @@ -462,11 +447,26 @@ typedef struct { unsigned int code[1]; } DR_TPAGE; -typedef struct { /* ORIGINAL CODE */ +typedef struct { /* ORIGINAL */ unsigned int tag; unsigned int code[1]; } DR_MASK; +typedef struct { /* ORIGINAL */ + unsigned int tag; + unsigned char r0,g0,b0,code; + unsigned short x0,y0; // Note: coordinates must be in 16 pixel steps + unsigned short w,h; +} FILL; + +typedef struct { /* ORIGINAL */ + unsigned int tag; + unsigned char p0,p1,p2,code; + unsigned short x0,y0; + unsigned short x1,y1; + unsigned short w,h; + unsigned int nop[4]; +} VRAM2VRAM; // General structs @@ -528,17 +528,23 @@ void PutDrawEnv(DRAWENV *draw); void SetDispMask(int mask); -void VSync(); -void DrawSync(); +int VSync(int m); +int DrawSync(int m); void WaitGPUcmd(); void WaitGPUdma(); -void VSyncCallback(void (*func)()); +void *VSyncCallback(void (*func)()); +void *DrawSyncCallback(void (*func)()); + +void *DMACallback(int dma, void (*func)()); +void *InterruptCallback(int irq, void (*func)()); +void *GetInterruptCallback(int irq); // Original void LoadImage(RECT *rect, unsigned int *data); void ClearOTagR(unsigned int* ot, int n); void DrawOTag(unsigned int* ot); +void DrawPrim(void *pri); void AddPrim(unsigned int* ot, void* pri); diff --git a/libpsn00b/include/psxpad.h b/libpsn00b/include/psxpad.h index 5478596..01aff06 100644 --- a/libpsn00b/include/psxpad.h +++ b/libpsn00b/include/psxpad.h @@ -68,7 +68,7 @@ typedef struct { unsigned char stat; unsigned char len:4; unsigned char type:4; // Device type (0x1) - unsigned char btn; + unsigned short btn; char x_mov; // X movement of mouse char y_mov; // Y movement of mouse } MOUSETYPE; diff --git a/libpsn00b/include/psxsio.h b/libpsn00b/include/psxsio.h new file mode 100644 index 0000000..df218ac --- /dev/null +++ b/libpsn00b/include/psxsio.h @@ -0,0 +1,66 @@ +#ifndef __PSXSIO_H +#define __PSXSIO_H + +#define SR_TXRDY 0x1 +#define SR_RXRDY 0x2 +#define SR_TXU 0x4 +#define SR_PERROR 0x8 +#define SR_OE 0x10 +#define SR_FE 0x20 +#define SR_DSR 0x80 +#define SR_CTS 0x100 +#define SR_IRQ 0x200 + +#define SIO_TXRDY 0x1 +#define SIO_RXRDY 0x2 +#define SIO_TXU 0x4 +#define SIO_PERROR 0x8 +#define SIO_OE 0x10 +#define SIO_FE 0x20 +#define SIO_DSR 0x80 +#define SIO_CTS 0x100 +#define SIO_IRQ 0x200 + +#define MR_CHLEN_5 0x00 +#define MR_CHLEN_6 0x04 +#define MR_CHLEN_7 0x08 +#define MR_CHLEN_8 0x0C +#define MR_PEN 0x10 +#define MR_P_EVEN 0x30 +#define MR_SB_01 0x40 +#define MR_SB_10 0x80 +#define MR_SB_11 0xc0 + +#define CR_TXEN 0x1 +#define CR_DTR 0x2 +#define CR_RXEN 0x4 +#define CR_BRK 0x8 +#define CR_INTRST 0x10 +#define CR_RTS 0x20 +#define CR_ERRRST 0x40 +#define CR_BUFSZ_1 0x00 +#define CR_BUFSZ_2 0x100 +#define CR_BUFSZ_4 0x200 +#define CR_BUFSZ_8 0x300 +#define CR_TXIEN 0x400 +#define CR_RXIEN 0x800 +#define CR_DSRIEN 0x1000 + +#ifdef __cplusplus +extern "C" { +#endif + +int _sio_control(int cmd, int arg, int param); +void AddSIO(int baud); +void DelSIO(void); + +void *Sio1Callback(void (*func)(void)); + +// ORIGINAL +void WaitSIO(void); + +#ifdef __cplusplus +} +#endif + +#endif
\ No newline at end of file diff --git a/libpsn00b/include/stdio.h b/libpsn00b/include/stdio.h index 5ee9e9b..98c69d0 100644 --- a/libpsn00b/include/stdio.h +++ b/libpsn00b/include/stdio.h @@ -4,7 +4,7 @@ #include <stdarg.h> #ifndef NULL -#define NULL (void*)0 +#define NULL 0 #endif // BIOS seek modes @@ -32,6 +32,14 @@ extern void printf (const char *__format, ...); extern int getc(int __fd); extern int putc(int __char, int __fd); + +#define fputc(__char, __fd) putc(__char, __fd) +#define fgetc(__char, __fd) getc(__char, __fd) + +// Console TTY +extern void gets(char *__s); +extern void puts(const char *__s); +extern int getchar(void); extern void putchar(int __c); // The following functions do not use the BIOS diff --git a/libpsn00b/include/stdlib.h b/libpsn00b/include/stdlib.h index 3909796..f9f41db 100644 --- a/libpsn00b/include/stdlib.h +++ b/libpsn00b/include/stdlib.h @@ -41,6 +41,10 @@ void *calloc(int number, int size); void *realloc(void *buf , int n); */ +#ifdef __cplusplus +extern "C" { +#endif + int rand(); void srand(unsigned long seed); @@ -53,5 +57,9 @@ long double strtold(const char *nptr, char **endptr); double strtod(const char *nptr, char **endptr); float strtof(const char *nptr, char **endptr); +#ifdef __cplusplus +} +#endif + #endif diff --git a/libpsn00b/include/string.h b/libpsn00b/include/string.h index 95796d5..9cd1d64 100644 --- a/libpsn00b/include/string.h +++ b/libpsn00b/include/string.h @@ -9,6 +9,10 @@ #ifndef _STRING_H #define _STRING_H +#ifdef __cplusplus +extern "C" { +#endif + int strcmp(const char *dst , const char *src); int strncmp(const char *dst , const char *src , int len); char *strpbrk(const char *dst , const char *src); @@ -37,6 +41,9 @@ void *memcpy(void *dst , const void *src , int n); void *memset(void *dst , char c , int n); int memcmp(const void *b1 , const void *b2 , int n); +#ifdef __cplusplus +} +#endif #endif diff --git a/libpsn00b/libc/malloc.s b/libpsn00b/libc/malloc.s index 20e5371..fdb196d 100644 --- a/libpsn00b/libc/malloc.s +++ b/libpsn00b/libc/malloc.s @@ -52,7 +52,7 @@ malloc: lw $a2, 0($a2) sll $a0, 2 -.find_next: +.Lfind_next: move $a1, $a2 @@ -61,16 +61,16 @@ malloc: subu $v0, $a2, $a1 # Compute space between current and next - beqz $v1, .empty_block # Occupy empty block (if size = 0) + beqz $v1, .Lempty_block # Occupy empty block (if size = 0) nop - beqz $a2, .new_block # Allocate a new block (if no next) + beqz $a2, .Lnew_block # Allocate a new block (if no next) nop addiu $v0, -(ND_HSIZ*2) # Compute remaining space of block subu $v0, $v1 - blt $v0, $a0, .find_next # Search for the next block if space is not big enough + blt $v0, $a0, .Lfind_next # Search for the next block if space is not big enough nop # Perform a block split using remaining space of current block @@ -88,19 +88,19 @@ malloc: jr $ra addiu $v0, ND_HSIZ -.empty_block: # Occupy an empty block +.Lempty_block: # Occupy an empty block - beqz $a2, .no_next # Skip size calculation if there's no next + beqz $a2, .Lno_next # Skip size calculation if there's no next nop addiu $v0, -ND_HSIZ - blt $v0, $a0, .find_next + blt $v0, $a0, .Lfind_next nop - b .skip_space_check + b .Lskip_space_check nop -.no_next: +.Lno_next: la $v1, _malloc_addr # Check if there's enough space for a block lw $v1, 0($v1) @@ -111,16 +111,16 @@ malloc: addu $v1, $a0 addiu $v1, ND_HSIZ - bgt $v1, $v0, .no_space + bgt $v1, $v0, .Lno_space nop -.skip_space_check: +.Lskip_space_check: sw $a0, ND_SIZE($a1) jr $ra # Return address addiu $v0, $a1, ND_HSIZ -.new_block: # Create a new block +.Lnew_block: # Create a new block addu $a2, $a1, $v1 # Compute address for new block addiu $a2, ND_HSIZ @@ -134,7 +134,7 @@ malloc: addu $v1, $a0 addiu $v1, ND_HSIZ - bgt $v1, $v0, .no_space # Reject if it exceeds specified size + bgt $v1, $v0, .Lno_space # Reject if it exceeds specified size nop sw $a1, ND_PREV($a2) @@ -146,7 +146,8 @@ malloc: jr $ra # Return address addiu $v0, $a2, ND_HSIZ -.no_space: # Return a null if no space can be found +.Lno_space: # Return a null if no space can be found + jr $ra move $v0, $0 @@ -168,10 +169,12 @@ calloc: move $a0, $v0 mflo $a1 -.clear_loop: + +.Lclear_loop: + sw $0 , 0($a0) addi $a1, 4 - bgtz $a1, .clear_loop + bgtz $a1, .Lclear_loop addiu $a0, 4 lw $ra, 0($sp) @@ -191,10 +194,10 @@ free: lw $a1, ND_PREV($a0) lw $a2, ND_NEXT($a0) - beqz $a1, .is_start # Check if block is a starting block + beqz $a1, .Lis_start # Check if block is a starting block nop - beqz $a2, .is_end + beqz $a2, .Lis_end nop # Unlink @@ -203,10 +206,13 @@ free: jr $ra sw $a1, ND_PREV($a2) -.is_end: # Unlinks the ending block +.Lis_end: # Unlinks the ending block + jr $ra sw $0 , ND_NEXT($a1) -.is_start: # Simply set size to 0 if starting block + +.Lis_start: # Simply set size to 0 if starting block + jr $ra sw $0 , ND_SIZE($a0) diff --git a/libpsn00b/libc/memcmp.s b/libpsn00b/libc/memcmp.s index b8b495d..ec1e729 100644 --- a/libpsn00b/libc/memcmp.s +++ b/libpsn00b/libc/memcmp.s @@ -13,19 +13,19 @@ .global memcmp .type memcmp, @function memcmp: - blez $a2, .exit + blez $a2, .Lexit addi $a2, -1 lbu $v0, 0($a0) lbu $v1, 0($a1) addiu $a0, 1 - bne $v0, $v1, .mismatch + bne $v0, $v1, .Lmismatch addiu $a1, 1 b memcmp nop -.mismatch: +.Lmismatch: jr $ra sub $v0, $v1 -.exit: +.Lexit: jr $ra move $v0, $0
\ No newline at end of file diff --git a/libpsn00b/libc/memcpy.s b/libpsn00b/libc/memcpy.s index e1a4e30..e3d1dd5 100644 --- a/libpsn00b/libc/memcpy.s +++ b/libpsn00b/libc/memcpy.s @@ -14,15 +14,15 @@ .type memcpy, @function memcpy: move $v0, $a0 -.loop: +.Lloop: blez $a2, .exit addi $a2, -1 lbu $a3, 0($a1) addiu $a1, 1 sb $a3, 0($a0) - b .loop + b .Lloop addiu $a0, 1 -.exit: +.Lexit: jr $ra nop
\ No newline at end of file diff --git a/libpsn00b/libc/memmove.s b/libpsn00b/libc/memmove.s index 961e71f..d32e2ca 100644 --- a/libpsn00b/libc/memmove.s +++ b/libpsn00b/libc/memmove.s @@ -14,16 +14,16 @@ memmove: addu $a1, $a2 addiu $a0, -1 addiu $a1, -1 -.loop: - blez $a2, .exit +.Lloop: + blez $a2, .Lexit addi $a2, -1 lbu $v1, 0($a1) addiu $a1, -1 sb $v1, 0($a0) addiu $a0, -1 - b .loop + b .Lloop nop -.exit: +.Lexit: jr $ra nop
\ No newline at end of file diff --git a/libpsn00b/libc/memset.s b/libpsn00b/libc/memset.s index f7d86b1..b3a3af3 100644 --- a/libpsn00b/libc/memset.s +++ b/libpsn00b/libc/memset.s @@ -14,12 +14,12 @@ .type memset,@function memset: move $v0, $a0 - blez $a2, .exit + blez $a2, .Lexit addi $a2, -1 sb $a1, 0($a0) b memset addiu $a0, 1 -.exit: +.Lexit: jr $ra nop
\ No newline at end of file diff --git a/libpsn00b/libc/start.s b/libpsn00b/libc/start.s index d08a2c7..2cf6ed0 100644 --- a/libpsn00b/libc/start.s +++ b/libpsn00b/libc/start.s @@ -15,9 +15,9 @@ _start: la $a0, .bss # What are the CORRECT symbols for BSS start and end? la $a1, _end -.clear_bss: +.Lclear_bss: sb $0 , 0($a0) - blt $a0, $a1, .clear_bss + blt $a0, $a1, .Lclear_bss addiu $a0, 1 la $a0, _end+4 # Initialize heap for malloc (does not use BIOS maalloc) diff --git a/libpsn00b/lzp/compress.c b/libpsn00b/lzp/compress.c index 33af08d..5f2b78c 100644 --- a/libpsn00b/lzp/compress.c +++ b/libpsn00b/lzp/compress.c @@ -3,6 +3,7 @@ #include <string.h> #if LZP_USE_MALLOC == TRUE #include <stdlib.h> +#include <malloc.h> #endif #include "lzconfig.h" diff --git a/libpsn00b/lzp/makefile b/libpsn00b/lzp/makefile index befdc34..4f9974f 100644 --- a/libpsn00b/lzp/makefile +++ b/libpsn00b/lzp/makefile @@ -1,6 +1,6 @@ PREFIX = mipsel-unknown-elf- -TARGET = liblzp.a +TARGET = ../liblzp.a CFILES = $(notdir $(wildcard ./*.c)) OFILES = $(addprefix build/,$(CFILES:.c=.o)) diff --git a/libpsn00b/makefile b/libpsn00b/makefile index bcfc9a5..d4bba32 100644 --- a/libpsn00b/makefile +++ b/libpsn00b/makefile @@ -4,7 +4,7 @@ TOPTARGETS = all clean -LIBDIRS = libc lzp psxgpu psxgte psxapi psxetc psxspu +LIBDIRS = libc lzp psxgpu psxgte psxapi psxetc psxspu psxsio $(TOPTARGETS): $(LIBDIRS) diff --git a/libpsn00b/psxapi/stdio/getchar.s b/libpsn00b/psxapi/stdio/getchar.s new file mode 100644 index 0000000..ad645c0 --- /dev/null +++ b/libpsn00b/psxapi/stdio/getchar.s @@ -0,0 +1,10 @@ +.set noreorder +.section .text + +.global getchar +.type getchar, @function +getchar: + addiu $t2, $0, 0xa0 + jr $t2 + addiu $t1, $0, 0x3b +
\ No newline at end of file diff --git a/libpsn00b/psxapi/stdio/gets.s b/libpsn00b/psxapi/stdio/gets.s new file mode 100644 index 0000000..ba423ef --- /dev/null +++ b/libpsn00b/psxapi/stdio/gets.s @@ -0,0 +1,10 @@ +.set noreorder +.section .text + +.global gets +.type gets, @function +gets: + addiu $t2, $0, 0xa0 + jr $t2 + addiu $t1, $0, 0x3d +
\ No newline at end of file diff --git a/libpsn00b/psxapi/stdio/putc.s b/libpsn00b/psxapi/stdio/putc.s index 7c73241..1c6d916 100644 --- a/libpsn00b/psxapi/stdio/putc.s +++ b/libpsn00b/psxapi/stdio/putc.s @@ -1,9 +1,9 @@ .set noreorder .section .text -.global putchar +.global putc .type putc, @function -putchar: +putc: addiu $t2, $0, 0xa0 jr $t2 addiu $t1, $0, 0x09 diff --git a/libpsn00b/psxapi/stdio/putchar.s b/libpsn00b/psxapi/stdio/putchar.s new file mode 100644 index 0000000..a3f6c57 --- /dev/null +++ b/libpsn00b/psxapi/stdio/putchar.s @@ -0,0 +1,10 @@ +.set noreorder +.section .text + +.global putchar +.type putchar, @function +putchar: + addiu $t2, $0, 0xa0 + jr $t2 + addiu $t1, $0, 0x3c +
\ No newline at end of file diff --git a/libpsn00b/psxapi/stdio/puts.s b/libpsn00b/psxapi/stdio/puts.s new file mode 100644 index 0000000..96815eb --- /dev/null +++ b/libpsn00b/psxapi/stdio/puts.s @@ -0,0 +1,10 @@ +.set noreorder +.section .text + +.global puts +.type puts, @function +puts: + addiu $t2, $0, 0xa0 + jr $t2 + addiu $t1, $0, 0x3e +
\ No newline at end of file diff --git a/libpsn00b/psxapi/sys/exec.s b/libpsn00b/psxapi/sys/exec.s new file mode 100644 index 0000000..dacce7e --- /dev/null +++ b/libpsn00b/psxapi/sys/exec.s @@ -0,0 +1,10 @@ +.set noreorder + +.section .text + +.global Exec +.type Exec, @function +Exec: + addiu $t2, $0, 0xa0 + jr $t2 + addiu $t1, $0, 0x43
\ No newline at end of file diff --git a/libpsn00b/psxetc/fntsort.c b/libpsn00b/psxetc/fntsort.c index 29e7de5..3890ebb 100644 --- a/libpsn00b/psxetc/fntsort.c +++ b/libpsn00b/psxetc/fntsort.c @@ -36,8 +36,8 @@ char *FntSort(unsigned int *ot, char *pri, int x, int y, const char *text) { pri = (char*)sprt; tpage = (DR_TPAGE*)pri; - setlen( tpage, 1 ); tpage->code[0] = _font_tpage; + setlen( tpage, 1 ); setcode( tpage, 0xe1 ); addPrim( ot, pri ); pri += sizeof(DR_TPAGE); diff --git a/libpsn00b/psxetc/font.c b/libpsn00b/psxetc/font.c index 3b0370b..2f062b7 100644 --- a/libpsn00b/psxetc/font.c +++ b/libpsn00b/psxetc/font.c @@ -22,7 +22,7 @@ void FntLoad(int x, int y) { _font_tpage = getTPage( 0, 0, pos.x, 0 ) | 0x200; LoadImage( &pos, tim.paddr ); - DrawSync(); + DrawSync(0); // Load font clut pos = *tim.crect; @@ -32,6 +32,6 @@ void FntLoad(int x, int y) { _font_clut = getClut( pos.x, pos.y ); LoadImage( &pos, tim.caddr ); - DrawSync(); + DrawSync(0); }
\ No newline at end of file diff --git a/libpsn00b/psxetc/makefile b/libpsn00b/psxetc/makefile index 676fc6e..fe29212 100644 --- a/libpsn00b/psxetc/makefile +++ b/libpsn00b/psxetc/makefile @@ -12,8 +12,8 @@ OFILES = $(addprefix build/,$(CFILES:.c=.o) $(AFILES:.s=.o)) INCLUDE = -I../include -CFLAGS = -O2 -msoft-float -fno-builtin -nostdlib -Wa,--strip-local-absolute -AFLAGS = -msoft-float --strip-local-absolute +CFLAGS = -g -O2 -msoft-float -fno-builtin -nostdlib -Wa,--strip-local-absolute +AFLAGS = -g -msoft-float --strip-local-absolute CC = $(PREFIX)gcc AS = $(PREFIX)as diff --git a/libpsn00b/psxgpu/dmacallback.s b/libpsn00b/psxgpu/dmacallback.s new file mode 100644 index 0000000..b2f86cf --- /dev/null +++ b/libpsn00b/psxgpu/dmacallback.s @@ -0,0 +1,191 @@ +.set noreorder + +.include "hwregs_a.h" + +.section .text + +.global DMACallback +.type DMACallback, @function +DMACallback: + + # a0 - DMA channel + # a1 - Callback function + + addiu $sp, -8 + sw $ra, 0($sp) + + beqz $a1, .Lremove_cb # Remove callback if function is NULL + nop + + addiu $sp, -8 # Install IRQ handler for DMA handler + sw $a0, 0($sp) # if not set installed yet + sw $a1, 4($sp) + + jal GetInterruptCallback + li $a0, 3 + + bnez $v0, .Lskip_install + nop + + la $a1, _dma_handler + jal InterruptCallback + li $a0, 3 + +.Lskip_install: + + lw $a0, 0($sp) + lw $a1, 4($sp) + addiu $sp, 8 + + la $v0, _dma_func_table + sll $v1, $a0, 2 + addu $v0, $v1 + lw $v1, 0($v0) + sw $a1, 0($v0) + sw $v1, 4($sp) + + lui $a2, IOBASE + + lw $v0, DICR($a2) # Enable DMA interrupt + lui $v1, 0x1 + sll $v1, $a0 + or $v0, $v1 + lui $v1, 0x80 + or $v0, $v1 + sw $v0, DICR($a2) + + b .Lskip_remove + nop + +.Lremove_cb: + + la $v0, _dma_func_table # Set callback address + sll $v1, $a0, 2 + addu $v0, $v1 + lw $v1, 0($v0) + sw $a1, 0($v0) + sw $v1, 4($sp) + + lui $a2, IOBASE # Disable DMA interrupt + lw $v0, DICR($a2) + lui $v1, 0x1 + sll $v1, $a0 + .set noat + addiu $at, $0, -1 + xor $v1, $at + and $v0, $v1 + lui $v1, 0x7f00 + xor $v1, $at + and $v0, $v1 + .set at + sw $v0, DICR($a2) + + jal _dma_has_cb # Check if callbacks are present + nop + bnez $v0, .Lskip_remove + nop + sw $0 , DICR($a2) + + jal GetInterruptCallback # Check if callback is the DMA handler + li $a0, 3 + la $v1, _dma_handler + bne $v0, $v1, .Lskip_remove + nop + + li $a0, 3 + jal InterruptCallback + move $a1, $0 + +.Lskip_remove: + + lw $ra, 0($sp) + lw $v0, 4($sp) + jr $ra + addiu $sp, 8 + + +.type _dma_has_cb, @function +_dma_has_cb: + + la $v1, _dma_func_table + li $t0, 6 + +.Lscan_loop: + + lw $v0, 0($v1) + addiu $v1, 4 + bnez $v0, .Lhas_cb + nop + + bgtz $t0, .Lscan_loop + addiu $t0, -1 + + jr $ra + move $v0, $0 + +.Lhas_cb: + + jr $ra + li $v0, 1 + + +.type _dma_handler, @function +_dma_handler: + + addiu $sp, -12 + sw $ra, 0($sp) + sw $s0, 4($sp) + sw $s1, 8($sp) + + move $s0, $0 + la $s1, _dma_func_table + +.Lhandler_loop: + + lui $a0, IOBASE + lw $v0, DICR($a0) + li $v1, 24 + addu $v1, $s0 + srl $v0, $v1 + andi $v0, 0x1 + + lw $v1, 0($s1) + + beqz $v0, .Lno_irq + addiu $s1, 4 + + beqz $v1, .Lno_irq + nop + + jalr $v1 + nop + +.Lno_irq: + + blt $s0, 6, .Lhandler_loop + addi $s0, 1 + + lui $a0, IOBASE + lw $v0, DICR($a0) + nop + sw $v0, DICR($a0) + + lw $ra, 0($sp) + lw $s0, 4($sp) + lw $s1, 8($sp) + + jr $ra + addiu $sp, -12 + + +.section .data + +_dma_func_table: + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 +
\ No newline at end of file diff --git a/libpsn00b/psxgpu/drawotag.s b/libpsn00b/psxgpu/drawotag.s index 8a5ff0c..ba771fc 100644 --- a/libpsn00b/psxgpu/drawotag.s +++ b/libpsn00b/psxgpu/drawotag.s @@ -13,20 +13,20 @@ DrawOTag: lui $a3, 0x1f80 # I/O segment base -.gpu_wait: # Wait for GPU to be ready for commands & DMA + lui $v0, 0x0400 # Set DMA direction to CPUtoGPU + ori $v0, 0x2 + sw $v0, GP1($a3) + +.Lgpu_wait: # Wait for GPU to be ready for commands & DMA jal ReadGPUstat nop srl $v0, 26 andi $v0, 1 - beqz $v0, .gpu_wait + beqz $v0, .Lgpu_wait nop - lui $v0, 0x0400 # Set DMA direction to CPUtoGPU - ori $v0, 0x2 - sw $v0, GP1($a3) - sw $a0, D2_MADR($a3) # Set DMA base address to specified OT - sw $0, D2_BCR($a3) + sw $0 , D2_BCR($a3) lui $v0, 0x0100 # Begin OT transfer! ori $v0, 0x0401 diff --git a/libpsn00b/psxgpu/drawprim.s b/libpsn00b/psxgpu/drawprim.s new file mode 100644 index 0000000..a216720 --- /dev/null +++ b/libpsn00b/psxgpu/drawprim.s @@ -0,0 +1,40 @@ +.set noreorder + +.include "hwregs_a.h" + +.text + +.global DrawPrim +.type DrawPrim, @function +DrawPrim: + + addiu $sp, -8 + sw $ra, 0($sp) + sw $s0, 4($sp) + + move $s0, $a0 # Wait for GPU to complete + jal DrawSync + move $a0, $0 + + lui $a3, IOBASE + lui $v0, 0x0400 # Set transfer direction to off + sw $v0, GP1($a3) + + move $a0, $s0 + lbu $a1, 3($a0) # Get length of primitive packet + addiu $a0, 4 + +.Ltransfer_loop: + lw $v0, 0($a0) + addiu $a0, 4 + sw $v0, GP0($a3) + bgtz $a1, .Ltransfer_loop + addiu $a1, -1 + + jal DrawSync + move $a0, $0 + + lw $ra, 0($sp) + lw $s0, 4($sp) + jr $ra + addiu $sp, 8
\ No newline at end of file diff --git a/libpsn00b/psxgpu/drawsync.s b/libpsn00b/psxgpu/drawsync.s index 149519d..66d37e2 100644 --- a/libpsn00b/psxgpu/drawsync.s +++ b/libpsn00b/psxgpu/drawsync.s @@ -8,19 +8,60 @@ .global DrawSync .type DrawSync, @function DrawSync: + + bnez $a0, .Lgetwords + lui $a0, IOBASE + addiu $sp, -4 sw $ra, 0($sp) -.gpu_wait: # Wait for GPU to be ready for commands and DMA + jal ReadGPUstat # Check if DMA enabled + nop + srl $v0, 29 + andi $v0, 0x3 + + beqz $v0, .Lsimple_wait + nop + +.Ldma_wait: + lw $v0, D2_CHCR + nop + srl $v0, 24 + andi $v0, 0x1 + bnez $v0, .Ldma_wait + nop + +.Lgpu_wait: jal ReadGPUstat nop - srl $v0, 0x1a + srl $v0, 26 andi $v0, 0x5 - li $v1, 5 - bne $v0, $v1, .gpu_wait + bne $v0, 5, .Lgpu_wait + nop + + b .Lexit nop + +.Lsimple_wait: # Wait for GPU to be ready for next DMA + jal ReadGPUstat + nop + srl $v0, 28 + andi $v0, 0x1 + beqz $v0, .Lsimple_wait + nop + +.Lexit: lw $ra, 0($sp) addiu $sp, 4 jr $ra nop + +.Lgetwords: + + lw $v0, D2_BCR($a0) + nop + + jr $ra + srl $v0, 16 +
\ No newline at end of file diff --git a/libpsn00b/psxgpu/drawsynccallback.s b/libpsn00b/psxgpu/drawsynccallback.s new file mode 100644 index 0000000..c1e28fe --- /dev/null +++ b/libpsn00b/psxgpu/drawsynccallback.s @@ -0,0 +1,103 @@ +.set noreorder + +.include "hwregs_a.h" + +.text + +.global DrawSyncCallback +.type DrawSyncCallback, @function +DrawSyncCallback: + + addiu $sp, -8 + sw $ra, 0($sp) + sw $a0, 4($sp) + + jal EnterCriticalSection + nop + + beqz $a0, .Luninstall + nop + la $a1, _drawsync_handler + jal DMACallback + li $a0, 2 + b .Lcontinue + nop + +.Luninstall: + + move $a1, $0 + jal DMACallback + li $a0, 2 + +.Lcontinue: + + lw $a0, 4($sp) + la $v1, _drawsync_func + lw $v0, 0($v1) + sw $a0, 0($v1) + sw $v0, 4($sp) + +.Lexit: + + jal ExitCriticalSection + nop + + lw $ra, 0($sp) + lw $v0, 4($sp) + jr $ra + addiu $sp, 8 + + +.type _drawsync_handler, @function +_drawsync_handler: + +.Ldma_wait: + + la $v0, _drawsync_func + lw $v0, 0($v0) + nop + beqz $v0, .Lskip + nop + + addiu $sp, -4 + sw $ra, 0($sp) + + lw $v0, D2_CHCR($a0) + nop + srl $v0, 24 + andi $v0, 0x1 + + bnez $v0, .Ldma_wait + nop + +.Lgpu_wait: + jal ReadGPUstat + nop + srl $v0, 28 + andi $v0, 0x1 + beqz $v0, .Lgpu_wait + nop + + la $v1, _drawsync_func + lw $v1, 0($v1) + + lui $v0, 0x0400 # Set DMA direction to off + sw $v0, GP1($a0) + + jalr $v1 + nop + + lw $ra, 0($sp) + addiu $sp, 4 + +.Lskip: + + jr $ra + nop + + +.data + +_drawsync_func: + .word 0 +
\ No newline at end of file diff --git a/libpsn00b/psxgpu/getinterruptcallback.s b/libpsn00b/psxgpu/getinterruptcallback.s new file mode 100644 index 0000000..b465567 --- /dev/null +++ b/libpsn00b/psxgpu/getinterruptcallback.s @@ -0,0 +1,17 @@ +.set noreorder + +.section .text + +.global GetInterruptCallback +.type GetInterruptCallback, @function +GetInterruptCallback: + + # a0 - Interrupt number + + la $a1, _irq_func_table + sll $a0, 2 + addu $a1, $a0 + + jr $ra + lw $v0, 0($a1) +
\ No newline at end of file diff --git a/libpsn00b/psxgpu/interruptcallback.s b/libpsn00b/psxgpu/interruptcallback.s new file mode 100644 index 0000000..8e912d8 --- /dev/null +++ b/libpsn00b/psxgpu/interruptcallback.s @@ -0,0 +1,48 @@ +.set noreorder + +.include "hwregs_a.h" + +.section .text + +.global InterruptCallback +.type InterruptCallback, @function +InterruptCallback: + + # a0 - Interrupt number + # a1 - Callback function + + lui $a2, IOBASE + + beqz $a1, .Ldisable_irq + nop + + lw $v0, IMASK($a2) # Enable interrupt mask + li $v1, 1 + sll $v1, $a0 + or $v0, $v1 + + b .Lcont + sw $v0, IMASK($a2) + +.Ldisable_irq: + +.set noat + lw $v0, IMASK($a2) # Disable interrupt mask + li $v1, 1 + sll $v1, $a0 + addiu $at, $0 , -1 + xor $v1, $at +.set at + and $v0, $v1 + sw $v0, IMASK($a2) + +.Lcont: + + la $a2, _irq_func_table # Get address to IRQ function table + + sll $v1, $a0, 2 # Compute the slot + addu $v1, $a2, $v1 + lw $v0, 0($v1) # Get old handler address + + jr $ra # Return and set new IRQ handler + sw $a1, 0($v1) diff --git a/libpsn00b/psxgpu/loadimage.s b/libpsn00b/psxgpu/loadimage.s index 2376b31..4a3b4e0 100644 --- a/libpsn00b/psxgpu/loadimage.s +++ b/libpsn00b/psxgpu/loadimage.s @@ -19,7 +19,7 @@ LoadImage: lui $s0, 0x1f80 # Set I/O segment base address -.gpu_wait: # Wait for GPU to be ready for commands and DMA +.Lgpu_wait: # Wait for GPU to be ready for commands and DMA jal ReadGPUstat nop srl $v0, 0x1a @@ -27,7 +27,7 @@ LoadImage: li $v1, 5 #srl $v0, 28 #andi $v0, 1 - bne $v0, $v1, .gpu_wait + bne $v0, $v1, .Lgpu_wait nop lui $v0, 0x400 # Set DMA direction to off diff --git a/libpsn00b/psxgpu/putdispenv.s b/libpsn00b/psxgpu/putdispenv.s index 0993e5c..4baa20e 100644 --- a/libpsn00b/psxgpu/putdispenv.s +++ b/libpsn00b/psxgpu/putdispenv.s @@ -32,53 +32,53 @@ PutDispEnv: move $a1, $0 # To use as mode value - bgt $a2, 560, .mode_640 + bgt $a2, 560, .Lmode_640 nop - bgt $a2, 400, .mode_512 + bgt $a2, 400, .Lmode_512 nop - bgt $a2, 352, .mode_384 + bgt $a2, 352, .Lmode_384 nop - bgt $a2, 280, .mode_320 + bgt $a2, 280, .Lmode_320 nop .set noat -.mode_256: +.Lmode_256: li $at, 10 mult $at, $v1 li $a2, 0x24e sll $v0, 2 add $a2, $v0 - b .mode_end + b .Lmode_end li $v1, 0xa00 -.mode_320: +.Lmode_320: li $at, 8 mult $at, $v1 li $a2, 0x258 ori $a1, 0x01 sll $v0, 2 add $a2, $v0 - b .mode_end + b .Lmode_end li $v1, 0xa00 -.mode_384: +.Lmode_384: li $at, 7 mult $at, $v1 li $a2, 0x21b ori $a1, 0x64 sll $v0, 2 add $a2, $v0 - b .mode_end + b .Lmode_end li $v1, 0xa80 -.mode_512: +.Lmode_512: li $at, 5 mult $at, $v1 li $a2, 0x267 ori $a1, 0x02 sll $v0, 2 add $a2, $v0 - b .mode_end + b .Lmode_end li $v1, 0xa00 -.mode_640: +.Lmode_640: li $at, 4 mult $at, $v1 li $a2, 0x26c @@ -86,15 +86,15 @@ PutDispEnv: sll $v0, 2 add $a2, $v0 li $v1, 0xa00 -.mode_end: +.Lmode_end: .set at mflo $v0 - bnez $v0, .no_default # Check if screen with is non zero + bnez $v0, .Lno_default # Check if screen with is non zero nop move $v0, $v1 # Use default if screen width is 0 -.no_default: +.Lno_default: addu $v0, $a2 # Apply horizontal display coordinates sll $v0, 12 @@ -108,19 +108,19 @@ PutDispEnv: lh $v0, DISP_dh($a0) li $a2, 0x10 - ble $v0, 256, .mode_low + ble $v0, 256, .Lmode_low nop -.mode_high: +.Lmode_high: ori $a1, 0x04 -.mode_low: +.Lmode_low: lh $v0, DISP_sy($a0) lh $v1, DISP_sh($a0) add $a2, $v0 - bnez $v1, .no_default_vert + bnez $v1, .Lno_default_vert nop li $v1, 0xf0 -.no_default_vert: +.Lno_default_vert: add $v1, $a2 and $a2, 0x3ff sll $v1, 10 @@ -134,28 +134,28 @@ PutDispEnv: la $v0, _gpu_standard lbu $v0, 0($v0) nop - beqz $v0, .config_ntsc + beqz $v0, .Lconfig_ntsc nop -.config_pal: +.Lconfig_pal: ori $a1, 0x08 -.config_ntsc: +.Lconfig_ntsc: lbu $v0, DISP_inter($a0) lbu $v1, DISP_isrgb24($a0) - beqz $v0, .no_inter + beqz $v0, .Lno_inter nop or $a1, 0x20 -.no_inter: - beqz $v1, .no_rgb24 +.Lno_inter: + beqz $v1, .Lno_rgb24 nop or $a1, 0x10 -.no_rgb24: +.Lno_rgb24: lbu $v0, DISP_inter($a0) nop - beqz $v0, .no_reverse + beqz $v0, .Lno_reverse nop or $a1, 0x80 -.no_reverse: +.Lno_reverse: lui $v0, 0x800 # Apply mode or $a1, $v0 diff --git a/libpsn00b/psxgpu/putdrawenv.s b/libpsn00b/psxgpu/putdrawenv.s index 69af437..c0d5676 100644 --- a/libpsn00b/psxgpu/putdrawenv.s +++ b/libpsn00b/psxgpu/putdrawenv.s @@ -97,7 +97,7 @@ PutDrawEnv: lbu $v0, DRAW_isbg($a0) nop - beqz $v0, .no_fillVRAM + beqz $v0, .Lno_fillVRAM nop lw $v0, DRAW_isbg($a0) # FillVRAM @@ -110,7 +110,7 @@ PutDrawEnv: sw $v0, 24($a1) # 6 srl $v0, $v1, 16 # Workaround as rectangle primitives - blt $v0, 511, .no_overflow # don't accept a height of 512 + blt $v0, 511, .Lno_overflow # don't accept a height of 512 nop li $v0, 511 @@ -118,19 +118,19 @@ PutDrawEnv: andi $v1, 0xffff or $v1, $v0 -.no_overflow: +.Lno_overflow: sw $v1, 28($a1) # 7 li $v0, 0x07ffffff # Packet header (length+terminator) sw $v0, 0($a1) -.no_fillVRAM: +.Lno_fillVRAM: -.gpu_wait: # Wait for GPU to become ready for commands and DMA +.Lgpu_wait: # Wait for GPU to become ready for commands and DMA jal ReadGPUstat nop srl $v0, 26 andi $v0, 1 - beqz $v0, .gpu_wait + beqz $v0, .Lgpu_wait nop jal DrawOTag diff --git a/libpsn00b/psxgpu/readme.txt b/libpsn00b/psxgpu/readme.txt index 0d44e72..8fe439b 100644 --- a/libpsn00b/psxgpu/readme.txt +++ b/libpsn00b/psxgpu/readme.txt @@ -23,39 +23,7 @@ Library header(s): Todo list: - * VSync() and DrawSync() functions lack alternate operating modes such as - getting number of vsyncs elapsed and waiting until a specified number of - vsyncs have passed. - - * (old) VSync interrupt handler should be hooked using BIOS function - SetCustomExitFromException() like the official GPU library instead of - hooking an event handler, but said hook never seems to work. Perhaps - something in the kernel area needs to be patched/set or some event/IRQ - handler needs to be removed as such handlers can skip the custom - exception exit entirely. - - It also appears that all interrupt handling in the official libraries - are done through the GPU library. This would also explain why the - official documentation tells you to always call ResetGraph() at the - very beginning of your programs. - * ClearOTag() function (non reverse version of ClearOTagR()) yet to be - implemented. + implemented (but should be trivial). * StoreImage() equivalent yet to be implemented. - - -Changelog: - - 05-23-2019 by Lameguy64: - - * Got custom exit handler set using SetCustomExitFromException() (BIOS - function B(19h)) working. Currently used to acknowledge VSync IRQ but - actual VSync handling is still done with events and needs to be - transferred to the custom exit handler. At least it lets BIOS - controller functions to work now. See doc/dev notes.txt for details - on how this handler behaves. - - * Made stack usage a lot less wasteful in ResetGraph() (you only need - to allocate N words on stack based on N arguments of the function - being called. diff --git a/libpsn00b/psxgpu/resetgraph.s b/libpsn00b/psxgpu/resetgraph.s index 189b1ad..ff0b353 100644 --- a/libpsn00b/psxgpu/resetgraph.s +++ b/libpsn00b/psxgpu/resetgraph.s @@ -1,5 +1,4 @@ .set noreorder -.set noat .include "hwregs_a.h" @@ -16,21 +15,7 @@ ResetGraph: la $v0, _hooks_installed # Skip installing hooks if this function lbu $v0, 0($v0) # has already been called before once nop - bnez $v0, .skip_hook_init - nop - - # Temporary, may help improve compatibility? - #jal SetDefaultExitFromException - #nop - - jal ChangeClearPAD # Remove pad handler left by the BIOS - move $a0, $0 - - li $a0, 1 - jal ChangeClearRCnt # Remove RCnt handler - move $a1, $0 - - jal _96_remove # Remove CD handling left by the BIOS + bnez $v0, .Lskip_hook_init nop lui $a3, 0x1f80 # Base address for I/O @@ -40,48 +25,51 @@ ResetGraph: sw $v0, DPCR($a3) sw $0 , DICR($a3) # Clear DICR (not needed) - li $v0, 0x9 # Enable IRQ0 (vblank) - sw $v0, IMASK($a3) - - # Set an event handler - - li $a0, 0xf2000003 # RCntCNT3 (vsync class) - li $a1, 0x2 - li $a2, 0x1000 - la $a3, _vsync_func # VSync event handler - - jal OpenEvent # Open a VSync event handler - # (PSXSDK style vsync handler) - addiu $sp, -16 - addiu $sp, 16 - - la $v1, _vsync_event_desc # Save event descriptor - sw $v0, 0($v1) - - move $a0, $v0 - jal EnableEvent # Enable the opened event - addiu $sp, -4 - addiu $sp, 4 - + sw $0 , IMASK($a3) # Clear IRQ settings + la $v0, _hooks_installed # Set installed flag li $v1, 0x1 sb $v1, 0($v0) - la $v0, _vsync_counter # Clear VSync counter + la $v0, _vsync_cb_func # Clear VSync callback function sw $0 , 0($v0) - la $v0, _vsync_callback_func # Clear callback function - sw $0 , 0($v0) - - la $a0, _custom_exit + la $a1, _vsync_irq_callback # Install VSync interrupt callback + jal InterruptCallback + li $a0, 0 + + la $a0, _custom_exit # Set custom exit handler jal SetCustomExitFromException addiu $sp, -4 addiu $sp, 4 + move $a0, $0 + jal ChangeClearPAD # Disable VSync IRQ auto ack + addiu $sp, -4 + addiu $sp, 4 + + li $a0, 3 + move $a1, $0 + jal ChangeClearRCnt # Remove RCnt timer IRQ auto ack + addiu $sp, -8 + addiu $sp, 8 + + jal _96_remove # Remove CD handling left by the BIOS + nop + + la $a0, resetgraph_msg + move $a1, $0 + move $a2, $0 + la $a1, _irq_func_table + la $a2, _custom_exit + jal printf + addiu $sp, -16 + addiu $sp, 16 + jal ExitCriticalSection # Re-enable interrupts nop - -.skip_hook_init: + +.Lskip_hook_init: lui $a3, 0x1f80 @@ -89,42 +77,40 @@ ResetGraph: lui $v1, 0x0010 and $v0, $v1 la $v1, _gpu_standard - beqz $v0, .not_pal + beqz $v0, .Lnot_pal sw $0 , 0($v1) li $v0, 1 sw $v0, 0($v1) -.not_pal: +.Lnot_pal: - lw $a0, 4($sp) # Get argument value + lw $a0, 4($sp) # Get argument value lui $a3, 0x1f80 # Set base I/O again (likely destroyed # by previous calls) li $v0, 0x1d00 # Configure timer 1 as Hblank counter sw $v0, T1_MODE($a3) # Set timer 1 value - - li $at, 1 - beq $a0, $at, .gpu_init_1 + + beq $a0, 1, .Lgpu_init_1 nop - li $at, 3 - beq $a0, $at, .gpu_init_3 + beq $a0, 3, .Lgpu_init_3 nop sw $0 , GP1($a3) # Reset the GPU - b .init_done + b .Linit_done nop -.gpu_init_1: +.Lgpu_init_1: sw $0 , D2_CHCR($a3) # Stop any DMA -.gpu_init_3: +.Lgpu_init_3: li $v0, 0x1 # Reset the command buffer sw $v0, GP1($a3) -.init_done: +.Linit_done: lw $ra, 0($sp) lw $a0, 4($sp) # Return @@ -132,147 +118,312 @@ ResetGraph: addiu $sp, 8 -.global _vsync_func # VSync event handler, executed on -.type _vsync_func, @function # every VBlank -_vsync_func: - - la $gp, _gp - - lui $at, 0x1f80 # Check if there's a VSync IRQ - lw $v0, IMASK($at) +.global VSync # VSync function +.type VSync, @function +VSync: + + addiu $sp, -12 + sw $ra, 0($sp) + sw $s0, 4($sp) + + lui $a3, IOBASE # Get GPU status (for interlace sync) + lw $s0, GP1($a3) + +.Lhwait_loop: # Get Hblank time + lw $v0, T1_CNT($a3) + nop + lw $v1, T1_CNT($a3) nop - andi $v0, $v0, 0x1 - beqz $v0, .exit + bne $v0, $v1, .Lhwait_loop nop + + la $a3, _vsync_lasthblank # Calculate Hblank time since last + lw $v1, 0($a3) + nop + subu $v0, $v1 + andi $v0, 0xffff + + beq $a0, 1, .Lhblank_exit # Return Hblank time only, no VSync + sw $v0, 8($sp) # Stored as return value + + bgez $a0, .Lvsync # Vsync if argument is 0 and up + nop + + la $v0, _vsync_rcnt # Return VSync count only + lw $v0, 0($v0) + nop + b .Lvsync_exit + sw $v0, 8($sp) + +.Lvsync: - lw $v1, ISTAT($at) + bnez $a0, .Lnot_zero nop - andi $v0, $v1, 0x1 - beqz $v0, .exit + li $a0, 1 + +.Lnot_zero: + + la $v0, _vsync_rcnt # Call vsync sub function (with timeout) + lw $v0, 0($v0) + addiu $a1, $a0, 1 + jal _vsync_sub + addu $a0, $v0, $a0 + + lui $v0, 0x40 + and $v0, $s0, $v0 + beqz $v0, .Lhblank_exit + nop + + lui $a3, IOBASE # Interlace wait logic + + lw $v0, GP1($a3) + nop + xor $v0, $s0, $v0 + bltz $v0, .Lhblank_exit + lui $a0, 0x8000 + +.Linterlace_wait: + lw $v0, GP1($a3) + nop + xor $v0, $s0, $v0 + and $v0, $a0 + beqz $v0, .Linterlace_wait nop - #xori $v1, $v1, 0x1 # Acknowledge the IRQ - #sw $v1, ISTAT($at) # Commented out as it breaks BIOS pads +.Lhblank_exit: # Set current Hblank as last value - la $v1, _vsync_counter # Increment VSync counter - lw $v0, 0($v1) + la $a2, _vsync_lasthblank + +.Lhwait2_loop: + lw $v0, T1_CNT($a3) + nop + lw $v1, T1_CNT($a3) + sw $v0, 0($a2) + bne $v0, $v1, .Lhwait2_loop nop - addiu $v0, 1 - sw $v0, 0($v1) - la $v0, _vsync_callback_func # Check if a callback function is set +.Lvsync_exit: + + lw $ra, 0($sp) + lw $s0, 4($sp) + lw $v0, 8($sp) + jr $ra + addiu $sp, 12 + + +.type _vsync_sub, @function +_vsync_sub: + + # a0 - VSync destination count + # a1 - Timeout ratio (number of vsyncs to wait relative to vsync count) + + addiu $sp, -4 + sw $ra, 0($sp) + + sll $a1, 15 # Timeout counter + + la $v0, _vsync_rcnt lw $v0, 0($v0) nop - beqz $v0, .exit + bge $v0, $a0, .Lvsync_sub_exit nop + +.Lvsync_wait: - addiu $sp, -0x20 # Save return address - sw $ra, 28($sp) - - jalr $v0 # Execute user function + addiu $a1, -1 + + la $v1, 0xffffffff + bne $a1, $v1, .Lnot_timeout nop - lw $ra, 28($sp) # Restore previous return address - addiu $sp, 0x20 + la $a0, vsynctimeout_msg + jal puts + addiu $sp, -8 + + jal ChangeClearPAD + move $a0, $0 + + li $a0, 3 + jal ChangeClearRCnt + move $a1, $0 + + addiu $sp, 8 + b .Lvsync_sub_exit + li $v0, -1 + +.Lnot_timeout: -.exit: - jr $ra + la $v0, _vsync_rcnt + lw $v0, 0($v0) + nop + blt $v0, $a0, .Lvsync_wait nop + +.Lvsync_sub_exit: + + lw $ra, 0($sp) + addiu $sp, 4 + jr $ra + move $v0, $0 -.global _vsync_func_2 -.type _vsync_func_2, @function -_vsync_func_2: - lui $at, 0x1f80 # Check if there's a VSync IRQ - lw $v0, IMASK($at) - nop - andi $v0, $v0, 0x1 - beqz $v0, .exit_2 +.type _vsync_irq_callback, @function +_vsync_irq_callback: + + lui $a0, IOBASE + + la $v1, _vsync_rcnt # Increment VSync root counter + lw $v0, 0($v1) nop + addiu $v0, 1 + sw $v0, 0($v1) - lw $v1, ISTAT($at) + la $v0, _vsync_cb_func # Check if a callback function is set + lw $v0, 0($v0) nop - andi $v0, $v1, 0x1 - beqz $v0, .exit_2 + beqz $v0, .Lno_callback nop - xori $v1, $v1, 0x1 # Acknowledge the IRQ - sw $v1, ISTAT($at) - -.exit_2: + addiu $sp, -4 # Save return address + sw $ra, 0($sp) + jalr $v0 # Execute user callback function + nop + lw $ra, 0($sp) # Restore previous return address + addiu $sp, 4 - j ReturnFromException + lui $a0, IOBASE + +.Lno_callback: + + jr $ra nop + +# Global ISR handler of PSn00bSDK -.global VSync # VSync function -.type VSync, @function -VSync: - addiu $sp, -4 - sw $ra, 0($sp) +.set at + +.type _global_isr, @function +_global_isr: + + lui $a0, IOBASE # Get IRQ status + +.Lisr_loop: - la $a1, _vsync_counter - lw $v0, 0($a1) + lui $a0, IOBASE # Get IRQ status + lw $v0, IMASK($a0) nop -.loop: - lw $v1, 0($a1) + + srl $v0, $s1 # Check IRQ mask bit if set + andi $v0, 0x1 + + beqz $v0, .Lno_irq # Don't execute callback if IRQ not enabled nop - beq $v0, $v1, .loop + + lw $v0, ISTAT($a0) nop - - la $v0, _gpu_current_field # Get last field value - lbu $v1, 0($v0) -.wait_field: # Wait for field bit to change - jal ReadGPUstat + srl $v0, $s1 # Check IRQ status bit if set + andi $v0, 0x1 + beqz $v0, .Lno_irq # Don't execute callback if no IRQ nop - srl $v0, 31 - beq $v0, $v1, .wait_field + + lw $v1, 0($s0) # Load IRQ callback function + nop + + lw $v0, ISTAT($a0) # Acknowledge the IRQ (by writing a 0 bit) + li $a1, 1 + sll $a1, $s1 + addiu $a2, $0 , -1 + xor $a1, $a2 + sw $a1, ISTAT($a0) + + beqz $v1, .Lno_irq # Don't execute if callback is not set nop - la $v1, _gpu_current_field # Store new field value - sb $v0, 0($v1) - - lw $ra, 0($sp) - addiu $sp, 4 - jr $ra + jalr $v1 # Call interrupt handler nop + +.Lno_irq: + + addiu $s0, 4 + + blt $s1, 11, .Lisr_loop + addiu $s1, 1 + j ReturnFromException + nop + .section .data -.global library_credits -.type library_credits, @object -library_credits: - .string "psxgpu programs by Lameguy64" +# VSync root counter +.type _vsync_rcnt, @object +_vsync_rcnt: + .word 0 + +.type _vsync_lasthblank, @object +_vsync_lasthblank: + .word 0 + +.comm _vsync_cb_func, 4, 4 + +.comm _gpu_standard, 4, 4 +.comm _gpu_current_field, 4, 4 +.comm _hooks_installed, 4, 4 +# Global ISR callback table + +.global _irq_func_table +.type _irq_func_table, @object +_irq_func_table: + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + +# Global ISR hook structure .type _custom_exit, @object _custom_exit: - .word _vsync_func_2 # pc - .word _vsync_stack # sp - .word 0 # fp - .word 0 # s0 - .word 0 # s1 - .word 0 # s2 - .word 0 # s3 - .word 0 # s4 - .word 0 # s5 - .word 0 # s6 - .word 0 # s7 - .word _gp # gp - - .fill 60 -_vsync_stack: + .word _global_isr # pc + .word _custom_exit_stack # sp + .word 0 # fp + .word _irq_func_table # s0 + .word 0 # s1 + .word 0 # s2 + .word 0 # s3 + .word 0 # s4 + .word 0 # s5 + .word 0 # s6 + .word 0 # s7 + .word _gp # gp + +# Global ISR stack + .fill 124 +_custom_exit_stack: .fill 4 -.type _vsync_counter, @object -_vsync_counter: - .word 0 - -.comm _vsync_callback_func, 4, 4 -.comm _vsync_event_desc, 4, 4 + +.type vsynctimeout_msg, @object +vsynctimeout_msg: + .asciiz "VSync: timeout\n" -.comm _gpu_standard, 4, 4 -.comm _gpu_current_field, 4, 4 -.comm _hooks_installed, 4, 4 +.type resetgraph_msg, @object +resetgraph_msg: + .asciiz "ResetGraph:itb=%08x,ehk=%08x\n" + +.global psxgpu_credits +.type psxgpu_credits, @object +psxgpu_credits: + .ascii "psxgpu programs by Lameguy64\n" + .asciiz "2019 PSn00bSDK Project / Meido-Tek Productions\n" +
\ No newline at end of file diff --git a/libpsn00b/psxgpu/setvideomode.s b/libpsn00b/psxgpu/setvideomode.s index 718a4dd..4395f0a 100644 --- a/libpsn00b/psxgpu/setvideomode.s +++ b/libpsn00b/psxgpu/setvideomode.s @@ -30,13 +30,13 @@ SetVideoMode: andi $a1, 0xf7 # Mask off PAL bit la $v0, _gpu_standard - beqz $a0, .set_done + beqz $a0, .Lset_done sw $0 , 0($v0) li $v1, 1 sw $v1, 0($v0) - b .set_done + b .Lset_done or $a1, 0x8 -.set_done: +.Lset_done: lui $v0, 0x800 # Apply new mode or $a1, $v0 diff --git a/libpsn00b/psxgpu/vsynccallback.s b/libpsn00b/psxgpu/vsynccallback.s index 1f96bbc..4be29c8 100644 --- a/libpsn00b/psxgpu/vsynccallback.s +++ b/libpsn00b/psxgpu/vsynccallback.s @@ -12,7 +12,7 @@ VSyncCallback: sw $a0, 4($sp) lw $a0, 4($sp) - la $v0, _vsync_callback_func + la $v0, _vsync_cb_func sw $a0, 0($v0) jal ExitCriticalSection diff --git a/libpsn00b/psxgte/readme.txt b/libpsn00b/psxgte/readme.txt index 13b92b6..74951c5 100644 --- a/libpsn00b/psxgte/readme.txt +++ b/libpsn00b/psxgte/readme.txt @@ -33,7 +33,3 @@ Todo list: be implemented. * Various high level RotTransPersp style functions not yet implemented. - -Changelog: - - None thus far... diff --git a/libpsn00b/psxgte/squareroot.s b/libpsn00b/psxgte/squareroot.s index 71f40a9..a262d94 100644 --- a/libpsn00b/psxgte/squareroot.s +++ b/libpsn00b/psxgte/squareroot.s @@ -5,6 +5,8 @@ .section .text +# Implementation based from Sony libs + .global SquareRoot12 .type SquareRoot12, @function SquareRoot12: @@ -12,7 +14,7 @@ SquareRoot12: nop nop mfc2 $v0, C2_LZCR - beq $v0, 32, $bad_sqr12 + beq $v0, 32, .Lbad_sqr12 nop andi $t0, $v0, 0x1 addiu $v1, $0 , -2 @@ -21,15 +23,15 @@ SquareRoot12: sub $t1, $t2 sra $t1, 1 addi $t3, $t2, -24 - bltz $t3, $value_less12 + bltz $t3, .Lvalue_less12 nop sllv $t4, $a0, $t3 - b $value_greater12 -$value_less12: + b .Lvalue_greater12 +.Lvalue_less12: addiu $t3, $0 , 24 sub $t3, $t2 srav $t4, $a0, $t3 -$value_greater12: +.Lvalue_greater12: addi $t4, -64 sll $t4, 1 la $t5, sqrt_table @@ -37,18 +39,18 @@ $value_greater12: lh $t5, 0($t5) nop - bltz $t1, $1594c + bltz $t1, .L1594c nop jr $ra sllv $v0, $t5, $t1 -$1594c: +.L1594c: sub $t1, $0 , $t1 jr $ra srl $v0, $t5, $t1 -$bad_sqr12: +.Lbad_sqr12: jr $ra move $v0, $0 @@ -60,7 +62,7 @@ SquareRoot0: nop nop mfc2 $v0, C2_LZCR - beq $v0, 32, $bad_sqr + beq $v0, 32, .Lbad_sqr nop andi $t0, $v0, 0x1 addiu $v1, $0 , -2 @@ -69,15 +71,15 @@ SquareRoot0: sub $t1, $t2 sra $t1, 1 addi $t3, $t2, -24 - bltz $t3, $value_less + bltz $t3, .Lvalue_less nop sllv $t4, $a0, $t3 - b $value_greater -$value_less: + b .Lvalue_greater +.Lvalue_less: addiu $t3, $0 , 24 sub $t3, $t2 srav $t4, $a0, $t3 -$value_greater: +.Lvalue_greater: addi $t4, -64 sll $t4, 1 la $t5, sqrt_table @@ -87,7 +89,7 @@ $value_greater: sllv $t5, $t5, $t1 jr $ra srl $v0, $t5, 12 -$bad_sqr: +.Lbad_sqr: jr $ra move $v0, $0 diff --git a/libpsn00b/psxgte/vectornormals.s b/libpsn00b/psxgte/vectornormals.s index 8907d43..49d949d 100644 --- a/libpsn00b/psxgte/vectornormals.s +++ b/libpsn00b/psxgte/vectornormals.s @@ -6,13 +6,12 @@ .section .text +# Implementation based from Sony libs .global VectorNormalS .type VectorNormalS, @function VectorNormalS: - # Implementation ripped from Sony libs - lw $t0, 0($a0) lw $t1, 4($a0) lw $t2, 8($a0) @@ -42,15 +41,15 @@ VectorNormalS: sra $t6, 1 addiu $t3, $v1, -24 - bltz $t3, $value_neg + bltz $t3, .Lvalue_neg nop - b $value_pos + b .Lvalue_pos sllv $t4, $v0, $t3 -$value_neg: +.Lvalue_neg: addiu $t3, $0 , 24 sub $t3, $v1 srav $t4, $v0, $t3 -$value_pos: +.Lvalue_pos: addi $t4, -64 sll $t4, 1 diff --git a/libpsn00b/psxsio/_sio_control.s b/libpsn00b/psxsio/_sio_control.s new file mode 100644 index 0000000..bae7822 --- /dev/null +++ b/libpsn00b/psxsio/_sio_control.s @@ -0,0 +1,182 @@ +.set noreorder + +.include "hwregs_a.h" + +.section .text + +# Currently implemented serial control functions: +# +# cmd(a0) sub(a1) +# 0 0 Get serial status +# 0 1 Get control line status +# 0 2 Get serial mode +# 0 3 Get baud rate +# 0 4 Read 1 byte +# 1 1 Set serial control +# 1 2 Set serial mode +# 1 3 Set baud rate +# 1 4 Write 1 byte +# 2 0 Reset serial +# 2 1 Acknowledge serial + +.global _sio_control +.type _sio_control, @function +_sio_control: + + # a0 - command + # a1 - subcommand + # a2 - argument + + lui $a3, IOBASE + + beq $a0, $0, .Lcmd0 + nop + beq $a0, 1, .Lcmd1 + nop + beq $a0, 2, .Lcmd2 + nop + jr $ra + nop + + +.Lcmd0: + + beq $a1, $0, .Lcmd0arg0 + nop + beq $a1, 1, .Lcmd0arg1 + nop + beq $a1, 2, .Lcmd0arg2 + nop + beq $a1, 3, .Lcmd0arg3 + nop + beq $a1, 4, .Lcmd0arg4 + nop + jr $ra + nop + +.Lcmd0arg0: # Get SIO status + + lhu $v0, SIO_STAT($a3) + nop + + jr $ra + andi $v0, 0x3FF + +.Lcmd0arg1: # Get control line status + + lhu $v1, SIO_CTRL($a3) + nop + srl $v0, $v1, 1 + andi $v0, 0x1 + srl $v1, 4 + andi $v1, 0x2 + + jr $ra + or $v0, $v1 + + +.Lcmd0arg2: # Get serial mode + + lhu $v0, SIO_MODE($a3) + nop + jr $ra + andi $v0, 0xFF + +.Lcmd0arg3: + + lui $v1, 0x1f + lhu $v0, SIO_BAUD($a3) + ori $v1, 0xa400 + div $v1, $v0 + nop + nop + jr $ra + mflo $v0 + +.Lcmd0arg4: # Serial RX read + + lbu $v0, SIO_TXRX($a3) + nop + jr $ra + nop + + +.Lcmd1: + + beq $a1, 1, .Lcmd1arg1 + nop + beq $a1, 2, .Lcmd1arg2 + nop + beq $a1, 3, .Lcmd1arg3 + nop + beq $a1, 4, .Lcmd1arg4 + nop + jr $ra + nop + +.Lcmd1arg1: + + andi $v0, $a2, 0x1CFF + + jr $ra + sh $a2, SIO_CTRL($a3) + +.Lcmd1arg2: + + jr $ra + sh $a2, SIO_MODE($a3) + +.Lcmd1arg3: + + lui $v0, 0x1f + ori $v0, 0xa400 + divu $v0, $a2 + bnez $a2, .Lgood_baud + nop + jr $ra + nop + +.Lgood_baud: + + mflo $v0 + sh $v0, SIO_BAUD($a3) + nop + jr $ra + nop + +.Lcmd1arg4: + + sb $a2, SIO_TXRX($a3) + nop + jr $ra + nop + +.Lcmd2: + + beq $a1, $0 , .Lcmd2arg0 + li $v0, 1 + beq $a1, $v0, .Lcmd2arg1 + nop + jr $ra + nop + +.Lcmd2arg0: + + li $v0, 0x40 + sh $v0, SIO_CTRL($a3) + sh $0 , SIO_MODE($a3) + sh $0 , SIO_BAUD($a3) + nop + jr $ra + nop + +.Lcmd2arg1: + + lhu $v0, SIO_CTRL($a3) + nop + ori $v0, 0x10 + sh $v0, SIO_CTRL($a3) + jr $ra + nop + +
\ No newline at end of file diff --git a/libpsn00b/psxsio/makefile b/libpsn00b/psxsio/makefile new file mode 100644 index 0000000..ecd6c65 --- /dev/null +++ b/libpsn00b/psxsio/makefile @@ -0,0 +1,38 @@ +# Run using make (Linux) or gmake (BSD) +# Part of the PSn00bSDK Project +# 2019 Lameguy64 / Meido-Tek Productions + +PREFIX = mipsel-unknown-elf- + +TARGET = ../libpsxsio.a + +CFILES = $(notdir $(wildcard ./*.c)) +AFILES = $(notdir $(wildcard ./*.s)) +OFILES = $(addprefix build/,$(CFILES:.c=.o) $(AFILES:.s=.o)) + +INCLUDE = -I../include + +CFLAGS = -O2 -msoft-float -fno-builtin -Wa,--strip-local-absolute +AFLAGS = -msoft-float -Wa,--strip-local-absolute + +CC = $(PREFIX)gcc +AS = $(PREFIX)as +AR = $(PREFIX)ar +RANLIB = $(PREFIX)ranlib + +all: $(TARGET) + +$(TARGET): $(OFILES) + $(AR) cr $(TARGET) $(OFILES) + $(RANLIB) $(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) diff --git a/libpsn00b/psxsio/siocons.c b/libpsn00b/psxsio/siocons.c new file mode 100644 index 0000000..cd99d68 --- /dev/null +++ b/libpsn00b/psxsio/siocons.c @@ -0,0 +1,137 @@ +#include <stdio.h> +#include <psxapi.h> +#include <psxgpu.h> +#include <psxsio.h> + +static void _sio_init() { +} + +static int _sio_open(FCB *fcb, const char* file, int mode) { + + fcb->diskid = 1; + + return 0; + +} + +static int _sio_inout(FCB *fcb, int cmd) { + + int i; + + if(cmd == 2) { // Write + + for(i=0; i<fcb->trns_len; i++) { + while(!(_sio_control(0, 0, 0) & SR_TXU)); + _sio_control(1, 4, ((char*)fcb->trns_addr)[i]); + } + + return fcb->trns_len; + + } else if (cmd == 1) { // Read + + for(i=0; i<fcb->trns_len; i++) { + while(!(_sio_control(0, 0, 0) & SR_RXRDY)); + ((char*)fcb->trns_addr)[i] = _sio_control(0, 4, 0); + } + + return fcb->trns_len; + + } + + return 0; + +} + +static int _sio_close(int h) { + + return h; + +} + +static DCB _sio_dcb = { + "tty", + 0x3, + 0x1, + 0x0, + (void*)_sio_init, // init + (void*)_sio_open, // open + (void*)_sio_inout, // inout + _sio_close, // close + NULL, // ioctl + NULL, // read + NULL, // write + NULL, // erase + NULL, // undelete + NULL, // firstfile + NULL, // nextfile + NULL, // format + NULL, // chdir + NULL, // rename + NULL, // remove + NULL // testdevice +}; + + +volatile void (*_sio_callback)(void) = NULL; + +extern void _sio_irq_handler(void); + + +void AddSIO(int baud) { + + _sio_control(2, 0, 0); + _sio_control(1, 2, MR_SB_01|MR_CHLEN_8|0x02); + _sio_control(1, 3, baud); + _sio_control(1, 1, CR_RXEN|CR_TXEN); + + close(0); + close(1); + + DelDev(_sio_dcb.name); + AddDev(&_sio_dcb); + + open(_sio_dcb.name, 2); + open(_sio_dcb.name, 1); + +} + +void DelSIO(void) { + + // Reset serial interface + _sio_control(2, 0, 0); + + // Remove TTY device + DelDev(_sio_dcb.name); + +} + +void WaitSIO(void) { + + while((_sio_control(0, 0, 0)&(SR_RXRDY)) != (SR_RXRDY)); + _sio_control(0, 4, NULL); + +} + +void *Sio1Callback(void (*func)()) { + + void *old_isr; //= *((int*)&_sio_callback); + + EnterCriticalSection(); + + if( func ) { + + old_isr = InterruptCallback(8, func); + //_sio_callback = func; + + } else { + + old_isr = InterruptCallback(8, NULL); + //_sio_callback = NULL; + + } + + ExitCriticalSection(); + + return old_isr; + +}
\ No newline at end of file diff --git a/libpsn00b/psxspu/readme.txt b/libpsn00b/psxspu/readme.txt index 4cac976..3ed90d0 100644 --- a/libpsn00b/psxspu/readme.txt +++ b/libpsn00b/psxspu/readme.txt @@ -29,8 +29,3 @@ Todo list: * SpuKeyOn() is actually not part of the official library. * SPU reverb configuration functions yet to be implemented. - - -Changelog: - - None so far... diff --git a/libpsn00b/psxspu/spuinit.s b/libpsn00b/psxspu/spuinit.s index fa5ec32..51a54ea 100644 --- a/libpsn00b/psxspu/spuinit.s +++ b/libpsn00b/psxspu/spuinit.s @@ -58,11 +58,11 @@ SpuInit: li $a2, 23 -.clear_voices: +.Lclear_voices: jal SpuSetVoiceRaw move $a0, $a2 addiu $a2, -1 - bgez $a2, .clear_voices + bgez $a2, .Lclear_voices nop li $v0, 0xffff # Set all keys to off @@ -104,11 +104,11 @@ SpuInit: SpuCtrlSync: lui $v1, IOBASE andi $a0, 0x3f -.ctrl_wait: +.Lctrl_wait: lhu $v0, SPUSTAT($v1) # Get SPUSTAT value nop andi $v0, 0x3f - bne $v0, $a0, .ctrl_wait # Wait until SPUCNT and SPUSTAT are equal + bne $v0, $a0, .Lctrl_wait # Wait until SPUCNT and SPUSTAT are equal nop jr $ra nop diff --git a/libpsn00b/psxspu/spusetkey.s b/libpsn00b/psxspu/spusetkey.s index 1270b2a..25a6107 100644 --- a/libpsn00b/psxspu/spusetkey.s +++ b/libpsn00b/psxspu/spusetkey.s @@ -13,13 +13,13 @@ SpuSetKey: lui $a2, IOBASE - beqz $a0, .key_off + beqz $a0, .Lkey_off nop jr $ra sh $a1, SPU_KEY_ON($v1) -.key_off: +.Lkey_off: jr $ra sh $a1, SPU_KEY_OFF($v1) diff --git a/libpsn00b/psxspu/transfer.s b/libpsn00b/psxspu/transfer.s index aed69dc..086bb3b 100644 --- a/libpsn00b/psxspu/transfer.s +++ b/libpsn00b/psxspu/transfer.s @@ -18,10 +18,10 @@ SpuSetTransferMode: .type SpuSetTransferStartAddr, @function SpuSetTransferStartAddr: li $v0, 0x1000 # Check if value is valid - blt $a0, $v0, .bad_value + blt $a0, $v0, .Lbad_value nop li $v0, 0xffff - bgt $a0, $v0, .bad_value + bgt $a0, $v0, .Lbad_value nop la $v1, _spu_transfer_addr @@ -31,7 +31,7 @@ SpuSetTransferStartAddr: jr $ra move $v0, $a0 -.bad_value: +.Lbad_value: jr $ra move $v0, $0 @@ -67,11 +67,11 @@ SpuWrite: lw $a0, 4($sp) -.dma_wait: # Wait for SPU to be ready for DMA +.Ldma_wait: # Wait for SPU to be ready for DMA lhu $v0, SPUSTAT($a3) nop andi $v0, 0x400 # Bit 8 in SPUSTAT never changes to 1 on - bnez $v0, .dma_wait # emulators so use bit 10 instead + bnez $v0, .Ldma_wait # emulators so use bit 10 instead nop sw $a0, D4_MADR($a3) # Set DMA source address |
