diff options
| author | John Wilbert M. Villamor <lameguy64@gmail.com> | 2019-11-22 09:11:12 +0800 |
|---|---|---|
| committer | John Wilbert M. Villamor <lameguy64@gmail.com> | 2019-11-22 09:11:12 +0800 |
| commit | ea46d05aed0343c20d8fdfaa0e67d54d51e8e2a0 (patch) | |
| tree | 43e2a53f4e5f7f55b075cfc9d6dc7a652a7b0837 | |
| parent | d80d92e13330d527ddb94420b19f9e21bf0e74eb (diff) | |
| download | psn00bsdk-ea46d05aed0343c20d8fdfaa0e67d54d51e8e2a0.tar.gz | |
Added long awaited CD-ROM library and loads of fixes, see changelog for details
47 files changed, 3147 insertions, 147 deletions
@@ -28,7 +28,7 @@ performance reasons. ## Notable features -As of libpsn00b run-time library v0.12b +As of LibPSn00b run-time library v0.15b * Extensive GPU support with polygon primitives, high-speed DMA VRAM transfers and DMA ordering table processing. All video modes for both NTSC @@ -43,8 +43,8 @@ As of libpsn00b run-time library v0.12b * Stable interrupt service routine with easy to use 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 should play well with writing loader programs. + or kernel hacks used and should be compatible with HLE BIOS implementations. + Should also play well with writing loader programs. * Complete Serial I/O support with SIOCONS driver for tty console access through serial interface. @@ -53,10 +53,11 @@ As of libpsn00b run-time library v0.12b thanks to proper interrupt handling, no crude manual polling of controllers in your main loop. -* BIOS CD-ROM support with a custom initialization function that doesn't - clear other DMA channel settings (such as GPU and SPU DMA) for easier - initialization. - +* Full CD-ROM support with data reading, CD audio and XA audio playback. + Features built-in ISO9660 file system parser for locating files and + supports directories containing more than 30 files. Data streaming + should also be possible. + * Uses Sony SDK library syntax for familiarity to experienced programmers and to make porting existing homebrew projects to PSn00bSDK easier. diff --git a/changelog.txt b/changelog.txt index 806e4b3..66b847b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -2,6 +2,47 @@ PSn00bSDK changelog Items that are lower in the log are more recently implemented. +11-22-2019 by Lameguy64: + +* psxapi: Added root counter or timer functions and related definitions. + +* examples: Added timer example. + +* psxgpu: Added DR_AREA, DR_OFFSET and DR_TWIN primitives and accompanying + setDrawArea(), setDrawOffset() and setTexWindow() macros. + +* psxgpu: Added parenthesis to argument value in setlen(), setaddr() and + setcode() macros, preventing addPrims() from being used in a more + sensible manner (ie. addPrims(ot, sub_ot+3, sub_ot)). + +* examples: Added render2tex render to texture example. + +* psxspu: Fixed typo in spuinit.s on section specifier specifying a data + section instead of text section, resulting to jump to + non-instruction-aligned linker errors. + +* psxgpu: Increased ISR stack size to 2048 bytes. + +* psxsio: Added kbhit() to poll keyboard input asynchronously and stdin + is now buffered with an IRQ handler. + +* psxapi: Added AddDummyTty() (for psxsio DelSIO() fix). + +* psxsio: DelSIO() now calls AddDummyTty(). + +* libc: Fixed bug in strncpy() not placing a NULL byte at end of string. + +* libc: Fixed strchr() and strrchr() declarations commented out in string.h. + +* libpsn00b: Added the long awaited libpsxcd library with cdxa example. + Documentation will come soon but existing libcd docs should be good + enough for awhile. + +* psxgpu: Fixed non functioning GPU DMA wait in DrawSync(). + +* LibPSn00b run-time library is now officially 0.15b. + + 10-11-2019 by Lameguy64: * psxetc: Added FntOpen(), FntPrint() and FntFlush() functions. diff --git a/doc/LibPSn00b Reference.odt b/doc/LibPSn00b Reference.odt Binary files differindex ab305d3..d12510c 100644 --- a/doc/LibPSn00b Reference.odt +++ b/doc/LibPSn00b Reference.odt diff --git a/examples/cdxa/ball16c.h b/examples/cdxa/ball16c.h new file mode 100644 index 0000000..c79f273 --- /dev/null +++ b/examples/cdxa/ball16c.h @@ -0,0 +1,16 @@ +unsigned int ball16c_size=192; +unsigned char ball16c[] = { +0x10,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0xc0,0x03,0x10, +0x01,0x10,0x00,0x01,0x00,0x00,0x00,0x31,0xc6,0x73,0xce,0x94,0xd2,0x07,0x9d, +0xd6,0xda,0x38,0xe3,0xef,0xbd,0x9b,0xef,0x8c,0xb1,0xc6,0x98,0xde,0xfb,0x4a, +0xa9,0xa4,0x90,0xad,0xb5,0x00,0x00,0x8c,0x00,0x00,0x00,0xc0,0x03,0x00,0x01, +0x04,0x00,0x10,0x00,0x00,0x00,0x10,0x22,0x12,0x02,0x00,0x00,0x00,0x10,0x32, +0x33,0x23,0x11,0x04,0x00,0x00,0x23,0x55,0x66,0x35,0x72,0x47,0x00,0x20,0x52, +0x86,0x68,0x36,0x12,0x97,0x0a,0x20,0x65,0xbb,0x8b,0x36,0x12,0x91,0x04,0x31, +0x85,0xbb,0x68,0x35,0x12,0x97,0xdc,0x32,0x86,0x8b,0x56,0x35,0x73,0x97,0xa4, +0x32,0x66,0x68,0x55,0x23,0x71,0x9e,0xac,0x32,0x65,0x56,0x33,0x13,0x71,0xce, +0xa4,0x21,0x33,0x33,0x23,0x11,0xe7,0xc9,0xd4,0x12,0x22,0x22,0x13,0x71,0xe7, +0xc9,0xda,0x10,0x17,0x11,0x77,0x77,0x9e,0x4c,0x0d,0x40,0x77,0x71,0xe7,0x9e, +0xc9,0xd4,0x0d,0x00,0x94,0x99,0x99,0xcc,0x4c,0xda,0x00,0x00,0xa0,0xc4,0xc4, +0x44,0xda,0x0d,0x00,0x00,0x00,0xd0,0xaa,0xda,0x0d,0x00,0x00 +}; diff --git a/examples/cdxa/iso.xml b/examples/cdxa/iso.xml new file mode 100644 index 0000000..840b414 --- /dev/null +++ b/examples/cdxa/iso.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<iso_project image_name="cdxa.iso"> + + <track type="data"> + + <identifiers + system ="PLAYSTATION" + application ="PLAYSTATION" + volume ="PSN00BSDK" + volume_set ="PSN00BSDK" + publisher ="MEIDOTEK" + /> + + <directory_tree> + + <file name="system.cnf" type="data" source="system.cnf"/> + <file name="cdxa.exe" type="data" source="cdxa.exe"/> + + <!-- CD-XA file, you'll have to provide your own to make this example work --> + <file name="xasample.xa" type="xa" source="D:\str-temp\subcon.xa"/> + + <dummy sectors="1024"/> + + </directory_tree> + + </track> + +</iso_project> diff --git a/examples/cdxa/main.c b/examples/cdxa/main.c new file mode 100644 index 0000000..5d043eb --- /dev/null +++ b/examples/cdxa/main.c @@ -0,0 +1,551 @@ +/* + * LibPSn00b Example Programs + * + * CD-XA Audio Example + * 2019 Meido-Tek Productions / PSn00bSDK Project + * + * Demonstrates playback and looping of CD-XA audio using the + * new libpsxcd library. + * + * + * Since there is not yet an open source XA audio encoder yet, the + * only way to create XA audio data is by using the official tools. + * You will have to provide your own XA file to get this example + * to work. + * + * You will also need MKPSXISO (https://github.com/lameguy64/mkpsxiso) + * to build an ISO image with your XA audio data. + * + * + * Theory of operation: + * + * CD-XA playback is accomplished by first locating the XA file in + * the ISO9660 file system using CdSearchFile(). CD mode is then set + * using the CdlSetmode command with CdlModeSpeed, CdlModeRT and + * CdlModeSF flags to configure the CD controller for XA audio + * streaming. Trying to play XA audio without CdlModeSF, which + * enables filtering, will feed all XA channels to the SPU resulting + * in a stuttery cacophony of sounds. + * + * The XA channel for playback is selected using the CdlSetfilter + * command and CdlFILTER struct. XA audio is usually comprised of + * multiple audio streams interleaved together and this command + * sets which channel to filter in from all the other channels. + * CdlModeSF enables the filtering feature and is required when + * playing back XA audio streams with multiple interleaved sound + * channels. + * + * Playback is initiated by issuing CdlReadS with the XA file's + * location specified as a parameter, which is internally issued + * to the CD controller as the seek target before CdlReadS is + * actually issued. + * + * Playback can be stopped by simply issuing CdlPause during playback. + * It is not recommended to use CdlStop as it will stop the disc spinning + * and result to much slower response once the disc has stopped. + * + * The most effective method of determining the end of an XA stream is + * by hooking a callback routine with CdReadyCallback(), which is + * triggered whenever a data sector has been read and checking the + * header of the received sector if it belongs to the channel currently + * being played. + * + * Additionally, XA audio data must be encoded with video sectors at + * the end of each XA stream to serve as a terminator marker which + * triggers CdReadyCallback() during playback. From within the callback + * a CdlReadS command with the location of the XA data can be issued again + * to repeat the track or CdlPause to stop playback. + * + * + * Tips: + * + * - For best efficiency, it is recommended to have all XA tracks in + * a single XA file have roughly the same length to one another, + * otherwise tracks that end short will be padded with empty sectors + * which wastes potentially usable disc space. + * + * - The CD filter can be changed during playback and the switchover is + * completely seamless. Use this trick to accomplish dynamic music + * effects that change seamlessly based on events during gameplay. + * + * - With custom tools, it is possible to interleave data sectors with + * a single XA audio stream which would permit music playback during + * loading sessions (aside from using sequenced music). Alternatively, + * CdlReadN can be used to begin playback but with more reliable data + * reading. This is also how streaming FMV sequences are accomplished. + * + * + * Pros over CD audio: + * + * - Does not require changing disc speed when switching between data + * access and audio playback. + * + * - Permits switching between streams during playback without restart. + * + * - Near 1:4 audio compression ratio. + * + * - Data sectors can be interleaved alongside XA audio. + * + * + * Cons compared to CD audio: + * + * - Skips more often on a poor condition disc or optical pick-up. + * + * - Cannot be played with any CD player. + * + * - Lower audio sample rate (37.8KHz whereas CD audio is 44.1KHz, not + * good for audiophools). + * + * + * Controls: + * + * Up/Down - Select channel. + * Cross - Play selected channel. + * Circle - Stop selected channel. + * Right - Switch channel (without restarting playback). + * + * + * Example by Lameguy64 + * + * + * Changelog: + * + * November 22, 2019 - Initial version + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <psxetc.h> +#include <psxgte.h> +#include <psxgpu.h> +#include <psxapi.h> +#include <psxpad.h> +#include <psxsio.h> +#include <psxspu.h> +#include <psxcd.h> + +#include <malloc.h> +#include "ball16c.h" + + +#define MAX_BALLS 1536 /* Number of balls to display */ + +#define OT_LEN 8 /* Ordering table length */ + + +/* Screen coordinates */ +#define SCREEN_XRES 320 +#define SCREEN_YRES 240 + +#define CENTER_X SCREEN_XRES/2 +#define CENTER_Y SCREEN_YRES/2 + + +/* Display and drawing environments */ +DISPENV disp[2]; +DRAWENV draw[2]; + +char pribuff[2][65536]; /* Primitive packet buffers */ +unsigned int ot[2][OT_LEN]; /* Ordering tables */ +char *nextpri; /* Pointer to next packet buffer offset */ +int db = 0; /* Double buffer index */ + + +/* Ball struct and array */ +typedef struct BALL_TYPE +{ + short x,y; + short xdir,ydir; + unsigned char r,g,b,p; +} BALL_TYPE; + +BALL_TYPE balls[MAX_BALLS]; + + +/* TIM image parameters for loading the ball texture and drawing sprites */ +TIM_IMAGE tim; + + +/* XA audio handling stuff */ +volatile int num_loops=0; /* Loop counter */ +volatile int xa_play_channel; /* Currently playing channel number */ +CdlLOC xa_loc; /* XA data start location + + +/* Sector header structure for video sector terminator */ +typedef struct SECTOR_HEAD +{ + u_short id; + u_short chan; + u_char pad[28]; +} SECTOR_HEAD; + + +/* Pad input buffer*/ +char padbuff[2][34]; + +char xa_sector_buff[2048]; + +/* Callback for detecting end of channel (hooked by CdReadyCallback) */ +void xa_callback(int intr, unsigned char *result) +{ + SECTOR_HEAD *sec; + + /* Only respond to data ready callbacks */ + if (intr == CdlDataReady) + { + /* Fetch data sector */ + CdGetSector((u_long*)&xa_sector_buff, 2048); + + /* Quirk: This CdGetSector() implementation must fetch 2048 bytes */ + /* or more otherwise the following sectors will be read in an */ + /* incorrect byte order, probably due to stray data in the data */ + /* FIFO. Trying to flush remaining bytes in the FIFO through */ + /* memory reads after DMA transfer yields random deadlocking on */ + /* real hardware for some reason. CdGetSector() probably reads */ + /* the data FIFO in software rather than DMA transfer whereas */ + /* CdGetSector2() uses DMA transfer in the official SDK. */ + + /* Check if sector belongs to the currently playing channel */ + sec = (SECTOR_HEAD*)xa_sector_buff; + + if( sec->id == 352 ) + { + // Debug + //printf("ID=%d CHAN=%d PL=%d\n", sec->id, (sec->chan>>10)&0xF, xa_play_channel); + + /* Check if sector is of the currently playing channel */ + if( ((sec->chan>>10)&0xF) == xa_play_channel ) + { + num_loops++; + + /* Retry playback by seeking to start of XA data and stream */ + CdControlF(CdlReadS, (u_char*)&xa_loc); + + /* Stop playback */ + //CdControlF(CdlPause, 0); + } + } + } +} + +void init() +{ + int i; + + /* Reset GPU (also installs event handler for VSync) */ + printf("Init GPU... "); + ResetGraph( 0 ); + printf("Done.\n"); + + + /* Uncomment to direct tty messages to serial */ + AddSIO(115200); + + + /* Initialize SPU and CD-ROM */ + printf("Initializing CD-ROM... "); + SpuInit(); + CdInit(0); + printf("Done.\n"); + + + /* Set display and draw environment parameters */ + SetDefDispEnv(&disp[0], 0, 0, SCREEN_XRES, SCREEN_YRES); + SetDefDispEnv(&disp[1], 0, SCREEN_YRES, SCREEN_XRES, SCREEN_YRES); + + SetDefDrawEnv(&draw[0], 0, SCREEN_YRES, SCREEN_XRES, SCREEN_YRES); + SetDefDrawEnv(&draw[1], 0, 0, SCREEN_XRES, SCREEN_YRES); + + + /* Set clear color, area clear and dither processing */ + setRGB0(&draw[0], 63, 0, 127); + draw[0].isbg = 1; + draw[0].dtd = 1; + setRGB0(&draw[1], 63, 0, 127); + draw[1].isbg = 1; + draw[1].dtd = 1; + + + /* Load and open font stream */ + FntLoad(960, 0); + FntOpen(32, 32, 256, 176, 2, 200); + + + /* Upload the ball texture */ + GetTimInfo((unsigned int*)ball16c, &tim); /* Get TIM parameters */ + LoadImage(tim.prect, tim.paddr); /* Upload texture to VRAM */ + if( tim.mode & 0x8 ) + { + LoadImage(tim.crect, tim.caddr); /* Upload CLUT if present */ + } + + + /* Calculate ball positions */ + printf("Calculating balls... "); + + for(i=0; i<MAX_BALLS; i++) + { + balls[i].x = (rand()%304); + balls[i].y = (rand()%224); + balls[i].xdir = 1-(rand()%3); + balls[i].ydir = 1-(rand()%3); + if( !balls[i].xdir ) + balls[i].xdir = 1; + if( !balls[i].ydir ) + balls[i].ydir = 1; + balls[i].xdir *= 2; + balls[i].ydir *= 2; + balls[i].r = (rand()%256); + balls[i].g = (rand()%256); + balls[i].b = (rand()%256); + } + + printf("Done.\n"); + + + /* Initialize pad */ + InitPAD(padbuff[0], 34, padbuff[1], 34); + StartPAD(); + ChangeClearPAD(0); + +} + + +int main(int argc, const char* argv[]) +{ + + SPRT *spr; + SPRT_16 *sprt; + DR_TPAGE *tpri; + PADTYPE *pad; + + CdlFILE file; + CdlFILTER filter; + + int i,counter=0; + int sel_channel=0; + int p_up=0,p_down=0,p_right=0,p_cross=0,p_circle=0; + + + /* Init graphics and stuff before doing anything else */ + init(); + + /* Locate the XA file */ + if( !CdSearchFile(&file, "\\XASAMPLE.XA") ) + { + printf("Unable to find file.\n"); + return 0; + } + else + { + int sec; + sec = CdPosToInt(&file.loc); + printf("XA located at sector %d size %d.\n", sec, file.size); + } + + /* Save file location as XA location */ + xa_loc = file.loc; + + /* Hook XA callback function to CdReadyCallback (for auto stop/loop */ + CdReadyCallback(xa_callback); + + /* Set CD mode for XA streaming (2x speed, send XA to SPU, enable filter */ + i = CdlModeSpeed|CdlModeRT|CdlModeSF; + CdControl(CdlSetmode, (u_char*)&i, 0); + + /* Set file 1 on filter for channels 0-7 */ + filter.file = 1; + + /* Main loop */ + printf("Entering loop...\n"); + + while(1) { + + pad = ((PADTYPE*)padbuff[0]); + + if( pad->stat == 0 ) + { + if(( pad->type == 0x4 )||( pad->type == 0x5 )||( pad->type == 0x7 )) + { + /* Menu selection controls */ + if( !(pad->btn&PAD_UP) ) + { + if( !p_up ) + { + if( sel_channel > 0 ) + { + sel_channel--; + } + p_up = 1; + } + } + else + { + p_up = 0; + } + + if( !(pad->btn&PAD_DOWN) ) + { + if( !p_down ) + { + if( sel_channel < 7 ) + { + sel_channel++; + } + p_down = 1; + } + } + else + { + p_down = 0; + } + + /* Play selected XA channel from start */ + if( !(pad->btn&PAD_CROSS) ) + { + if( !p_cross ) + { + filter.chan = sel_channel; + CdControl(CdlSetfilter, (u_char*)&filter, 0); + CdControl(CdlReadS, (u_char*)&xa_loc, 0); + xa_play_channel = sel_channel; + p_cross = 1; + } + } + else + { + p_cross = 0; + } + + /* Stop playback */ + if( !(pad->btn&PAD_CIRCLE) ) + { + if( !p_circle ) + { + CdControl(CdlPause, 0, 0); + p_circle = 1; + } + } + else + { + p_circle = 0; + } + + /* Change XA channel */ + if( !(pad->btn&PAD_RIGHT) ) + { + if( !p_right ) + { + filter.chan = sel_channel; + CdControl(CdlSetfilter, (u_char*)&filter, 0); + xa_play_channel = sel_channel; + p_right = 1; + } + } + else + { + p_right = 0; + } + + } + } + + + /* Display information */ + FntPrint(-1, "\n PSN00BSDK XA AUDIO EXAMPLE\n\n"); + FntPrint(-1, " CHANNEL:\n"); + + for(i=0; i<8; i++) + { + if( i == sel_channel ) + { + FntPrint(-1, " -->%d\n", i); + } + else + { + FntPrint(-1, " %d\n", i); + } + } + + FntPrint(-1, "\n CURRENT=%d STATUS=%x LOOPS=%d\n", + xa_play_channel, CdStatus(), num_loops); + FntPrint(-1, "\n <X>-PLAY (START) <O>-STOP\n <R>-SET CHANNEL\n"); + + + /* Clear ordering table and set start address of primitive buffer */ + ClearOTagR(ot[db], OT_LEN); + nextpri = pribuff[db]; + + + /* Sort the balls */ + sprt = (SPRT_16*)nextpri; + for( i=0; i<MAX_BALLS; i++ ) { + + setSprt16(sprt); + setXY0(sprt, balls[i].x, balls[i].y); + setRGB0(sprt, balls[i].r, balls[i].g, balls[i].b); + setUV0(sprt, 0, 0); + setClut(sprt, tim.crect->x, tim.crect->y); + + addPrim(ot[db]+(OT_LEN-1), sprt); + sprt++; + + balls[i].x += balls[i].xdir; + balls[i].y += balls[i].ydir; + + if( ( balls[i].x+16 ) > SCREEN_XRES ) { + balls[i].xdir = -2; + } else if( balls[i].x < 0 ) { + balls[i].xdir = 2; + } + + if( ( balls[i].y+16 ) > SCREEN_YRES ) { + balls[i].ydir = -2; + } else if( balls[i].y < 0 ) { + balls[i].ydir = 2; + } + + } + nextpri = (char*)sprt; + + + /* Sort a TPage primitive so the sprites will draw pixels from */ + /* the correct texture page in VRAM */ + tpri = (DR_TPAGE*)nextpri; + setDrawTPage(tpri, 0, 0, getTPage(0, 0, tim.prect->x, tim.prect->y)); + addPrim(ot[db]+(OT_LEN-1), tpri); + nextpri += sizeof(DR_TPAGE); + + /* Draw font */ + FntFlush(-1); + + /* Wait for GPU and VSync */ + DrawSync(0); + VSync(0); + + /* Since draw.isbg is non-zero this clears the screen */ + PutDispEnv(&disp[db]); + PutDrawEnv(&draw[db]); + SetDispMask(1); + + /* Begin drawing the new frame */ + DrawOTag( ot[db]+(OT_LEN-1) ); + + /* Alternate to the next buffer */ + db = !db; + + /* Periodically issue CdlNop every second to update CdStatus() */ + counter++; + if( (counter%60) == 59 ) + { + CdControl(CdlNop, 0, 0); + } + + } + + return 0; + +} diff --git a/examples/cdxa/makefile b/examples/cdxa/makefile new file mode 100644 index 0000000..c94f48c --- /dev/null +++ b/examples/cdxa/makefile @@ -0,0 +1,60 @@ +include ../sdk-common.mk + +TARGET = cdxa.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)) + +PREFIX = mipsel-unknown-elf- + +# Include directories +INCLUDE = -I../../libpsn00b/include + +# Library directories, last entry must point toolchain libraries +LIBDIRS = -L../../libpsn00b + +LIBDIRS += -L$(GCC_BASE)/lib/gcc/mipsel-unknown-elf/$(GCC_VERSION) +INCLUDE += -I$(GCC_BASE)/lib/gcc/mipsel-unknown-elf/$(GCC_VERSION)/include + +LIBS = -lpsxcd -lpsxetc -lpsxgpu -lpsxgte -lpsxspu -lpsxsio -lpsxapi -lc + +CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections +CPPFLAGS = $(CFLAGS) \ + -fno-exceptions \ + -fno-rtti \ + -fno-unwind-tables \ + -fno-threadsafe-statics \ + -fno-use-cxa-atexit + +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) + mkpsxiso -y -q iso.xml + +build/%.o: %.c + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +build/%.o: %.cpp + @mkdir -p $(dir $@) + $(CXX) $(CPPFLAGS) $(INCLUDE) -c $< -o $@ + +build/%.o: %.s + @mkdir -p $(dir $@) + $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@ + +clean: + make -C libpsxcd clean + rm -rf build $(TARGET) $(TARGET:.elf=.exe) diff --git a/examples/cdxa/system.cnf b/examples/cdxa/system.cnf new file mode 100644 index 0000000..e61e50e --- /dev/null +++ b/examples/cdxa/system.cnf @@ -0,0 +1,4 @@ +BOOT=cdrom:\cdxa.exe;1 +TCB=4 +EVENT=10 +STACK=801FFFF0 diff --git a/examples/childexec/parent.c b/examples/childexec/parent.c index dbaf696..7f577e4 100644 --- a/examples/childexec/parent.c +++ b/examples/childexec/parent.c @@ -223,7 +223,8 @@ int main(int argc, const char* argv[]) { /* Sort a TPage primitive so the sprites will draw pixels from */ /* the correct texture page in VRAM */ tpri = (DR_TPAGE*)nextpri; - setDrawTPage( tpri, 0, 0, tim.prect->x, tim.prect->y ); + setDrawTPage( tpri, 0, 0, + getTPage( 0, 0, tim.prect->x, tim.prect->y ) ); addPrim( ot[db]+(OT_LEN-1), tpri ); nextpri += sizeof(DR_TPAGE); @@ -301,4 +302,4 @@ void run_child() { // Set this program's display mode PutDispEnv(&disp); -}
\ No newline at end of file +} diff --git a/examples/fpscam/makefile b/examples/fpscam/makefile index 67fe7c2..4f344eb 100644 --- a/examples/fpscam/makefile +++ b/examples/fpscam/makefile @@ -11,13 +11,7 @@ OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o) INCLUDE += LIBDIRS += -<<<<<<< .mine LIBS = -lpsxetc -lpsxgpu -lpsxgte -lpsxspu -lpsxapi -lc -||||||| .r23 -LIBS = -lc -lpsxetc -lpsxgpu -lpsxgte -lpsxspu -lpsxapi -lgcc -======= -LIBS = -lc -lpsxetc -lpsxgpu -lpsxgte -lpsxspu -lpsxapi -lc ->>>>>>> .r27 CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections CPPFLAGS = $(CFLAGS) -fno-exceptions diff --git a/examples/gte/makefile b/examples/gte/makefile index 89b27d3..2be2374 100644 --- a/examples/gte/makefile +++ b/examples/gte/makefile @@ -11,7 +11,7 @@ OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o) INCLUDE += LIBDIRS += -LIBS = -lc -lpsxetc -lpsxgpu -lpsxgte -lpsxspu -lpsxapi -lgcc +LIBS = -lc -lpsxetc -lpsxgpu -lpsxgte -lpsxspu -lpsxapi -lc CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections CPPFLAGS = $(CFLAGS) -fno-exceptions diff --git a/examples/makefile b/examples/makefile index dda76ce..4c4aadf 100644 --- a/examples/makefile +++ b/examples/makefile @@ -4,7 +4,7 @@ TOPTARGETS = all clean -DIRS = balls gte n00bdemo +DIRS = balls gte n00bdemo fpscam childexec render2tex rgb24 timer billboard $(TOPTARGETS): $(DIRS) diff --git a/examples/n00bdemo/makefile b/examples/n00bdemo/makefile index 8159a22..96275fb 100644 --- a/examples/n00bdemo/makefile +++ b/examples/n00bdemo/makefile @@ -10,7 +10,7 @@ OFILES = $(addprefix build/,$(CFILES:.c=.o) $(AFILES:.s=.o)) INCLUDE += -I../../libpsn00b/lzp LIBDIRS += -L../../libpsn00b/lzp -LIBS = -llzp -lc -lpsxetc -lpsxgpu -lpsxgte -lpsxspu -lpsxapi -lgcc +LIBS = -llzp -lc -lpsxetc -lpsxgpu -lpsxgte -lpsxspu -lpsxapi -lc CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections CPPFLAGS = $(CFLAGS) -fno-exceptions diff --git a/examples/rgb24/makefile b/examples/rgb24/makefile index ada9fbb..eea866d 100644 --- a/examples/rgb24/makefile +++ b/examples/rgb24/makefile @@ -11,12 +11,12 @@ OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o) INCLUDE += LIBDIRS += -LIBS = -lc -lpsxgpu -lpsxapi -lgcc +LIBS = -lpsxgpu -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 +LDFLAGS = -g -Ttext=0x80010000 -gc-sections -T $(GCC_BASE)/mipsel-unknown-elf/lib/ldscripts/elf32elmip.x CC = $(PREFIX)gcc CXX = $(PREFIX)g++ diff --git a/examples/timer/main.c b/examples/timer/main.c new file mode 100644 index 0000000..7d9f7b3 --- /dev/null +++ b/examples/timer/main.c @@ -0,0 +1,154 @@ +#include <stdio.h> +#include <psxgpu.h> +#include <psxapi.h> +#include <psxetc.h> + +/* OT and Packet Buffer sizes */ +#define OT_LEN 256 +#define PACKET_LEN 1024 + +/* Screen resolution */ +#define SCREEN_XRES 320 +#define SCREEN_YRES 240 + +/* Screen center position */ +#define CENTERX SCREEN_XRES>>1 +#define CENTERY SCREEN_YRES>>1 + + +/* Double buffer structure */ +typedef struct { + DISPENV disp; /* Display environment */ + DRAWENV draw; /* Drawing environment */ +} DB; + +/* Double buffer variables */ +DB db[2]; +int db_active = 0; + + +/* Function declarations */ +void init(); +void display(); + + +volatile int timer_calls = 0; +volatile short *timer2_ctrl = (short*)0x1F801124; +void timer_func() +{ + timer_calls++; +} + +volatile int vsync_count = 0; +volatile int tick_count = 0; +volatile int tick_value = 0; + +void vsync_func() +{ + vsync_count++; + if( vsync_count > 60 ) + { + tick_value = timer_calls-tick_count; + tick_count = timer_calls; + vsync_count = 0; + } +} + +/* Main function */ +int main() { + + int counter; + + /* Init graphics and GTE */ + init(); + + + EnterCriticalSection(); + //SetRCnt(RCntCNT2, 0xF040, RCntMdINTR); + + // NTSC clock base + counter = 4304000/560; + + // PAL clock base + //counter = 5163000/560; + + SetRCnt(RCntCNT2, counter, RCntMdINTR); + *timer2_ctrl = 0x1E58; + InterruptCallback(6, timer_func); + StartRCnt(RCntCNT2); + ChangeClearRCnt(2, 0); + ExitCriticalSection(); + + VSyncCallback(vsync_func); + + /* Main loop */ + while( 1 ) { + + FntPrint(-1, "TIMER COUNT=%d\n", timer_calls); + FntPrint(-1, "TICKS/SEC=%d\n", tick_value); + + /* Swap buffers and draw text */ + display(); + + } + + return 0; + +} + +void init() { + + /* Reset the GPU, also installs a VSync event handler */ + ResetGraph( 0 ); + //SetVideoMode(MODE_PAL); + + /* Set display and draw environment areas */ + /* (display and draw areas must be separate, otherwise hello flicker) */ + SetDefDispEnv( &db[0].disp, 0, 0, SCREEN_XRES, SCREEN_YRES ); + SetDefDrawEnv( &db[0].draw, SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES ); + + /* Enable draw area clear and dither processing */ + setRGB0( &db[0].draw, 63, 0, 127 ); + db[0].draw.isbg = 1; + db[0].draw.dtd = 1; + + + /* Define the second set of display/draw environments */ + SetDefDispEnv( &db[1].disp, SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES ); + SetDefDrawEnv( &db[1].draw, 0, 0, SCREEN_XRES, SCREEN_YRES ); + + //db[0].disp.screen.y = 24; + //db[1].disp.screen.y = 24; + + setRGB0( &db[1].draw, 63, 0, 127 ); + db[1].draw.isbg = 1; + db[1].draw.dtd = 1; + + + /* Apply the drawing environment of the first double buffer */ + PutDrawEnv( &db[0].draw ); + + FntLoad(960, 0); + FntOpen(0, 8, 320, 216, 0, 100); + +} + +void display() { + + FntFlush(-1); + + /* Wait for GPU to finish drawing and vertical retrace */ + DrawSync( 0 ); + VSync( 0 ); + + /* Swap buffers */ + db_active ^= 1; + + /* Apply display/drawing environments */ + PutDrawEnv( &db[db_active].draw ); + PutDispEnv( &db[db_active].disp ); + + /* Enable display */ + SetDispMask( 1 ); + +}
\ No newline at end of file diff --git a/examples/timer/makefile b/examples/timer/makefile new file mode 100644 index 0000000..0c1340d --- /dev/null +++ b/examples/timer/makefile @@ -0,0 +1,39 @@ +include ../sdk-common.mk + +TARGET = timer.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 = -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/include/hwregs_a.h b/libpsn00b/include/hwregs_a.h index 27cfc88..9d4313b 100644 --- a/libpsn00b/include/hwregs_a.h +++ b/libpsn00b/include/hwregs_a.h @@ -82,6 +82,10 @@ .set D2_BCR, 0x10a4 .set D2_CHCR, 0x10a8 +.set D3_MADR, 0x10b0 +.set D3_BCR, 0x10b4 +.set D3_CHCR, 0x10b8 + .set D4_MADR, 0x10c0 .set D4_BCR, 0x10c4 .set D4_CHCR, 0x10c8 diff --git a/libpsn00b/include/psxapi.h b/libpsn00b/include/psxapi.h index 9abcd0c..0953dc3 100644 --- a/libpsn00b/include/psxapi.h +++ b/libpsn00b/include/psxapi.h @@ -1,23 +1,38 @@ #ifndef __PSXAPI__ #define __PSXAPI__ -#define DescHW 0xf0000000 -#define DescSW 0xf4000000 - -#define HwCARD (DescHW|0x11) -#define HwCARD_1 (DescHW|0x12) -#define HwCARD_0 (DescHW|0x13) -#define SwCARD (DescHW|0x02) - -#define EvSpIOE 0x0004 -#define EvSpERROR 0x8000 -#define EvSpTIMOUT 0x0100 -#define EvSpNEW 0x0200 - -#define EvMdINTR 0x1000 -#define EvMdNOINTR 0x2000 - -typedef struct { // Device control block +#define DescHW 0xf0000000 +#define DescSW 0xf4000000 + +#define HwCARD (DescHW|0x11) +#define HwCARD_1 (DescHW|0x12) +#define HwCARD_0 (DescHW|0x13) +#define SwCARD (DescHW|0x02) + +#define EvSpIOE 0x0004 +#define EvSpERROR 0x8000 +#define EvSpTIMOUT 0x0100 +#define EvSpNEW 0x0200 + +#define EvMdINTR 0x1000 +#define EvMdNOINTR 0x2000 + +// Root counter (timer) definitions +#define DescRC 0xf2000000 + +#define RCntCNT0 (DescRC|0x00) +#define RCntCNT1 (DescRC|0x01) +#define RCntCNT2 (DescRC|0x02) +#define RCntCNT3 (DescRC|0x03) + +#define RCntMdINTR 0x1000 // Turns on IRQ +#define RCntMdNOINTR 0x2000 // Polling mode +#define RCntMdSC 0x0001 // IRQ when counter target +#define RCntMdSP 0x0000 +#define RCntMdFR 0x0000 +#define RCntMdGATE 0x0010 + +typedef struct { // Device control block char *name; int flags; int ssize; @@ -121,6 +136,7 @@ int chdir(const char *path); int AddDev(DCB *dcb); int DelDev(const char *name); void ListDev(void); +void AddDummyTty(void); void EnterCriticalSection(void); void ExitCriticalSection(void); @@ -151,8 +167,14 @@ int _card_read(int chan, int sector, unsigned char *buf); int _card_write(int chan, int sector, unsigned char *buf); void _new_card(void); +// Timers +int SetRCnt(int spec, unsigned short target, int mode); +int GetRCnt(int spec); +int StartRCnt(int spec); +int StopRCnt(int spec); +int ResetRCnt(int spec); -// Interrupt acknowledge control +// BIOS IRQ acknowledge control void ChangeClearPAD(int mode); void ChangeClearRCnt(int t, int m); diff --git a/libpsn00b/include/psxcd.h b/libpsn00b/include/psxcd.h new file mode 100644 index 0000000..5bb1b5f --- /dev/null +++ b/libpsn00b/include/psxcd.h @@ -0,0 +1,149 @@ +#ifndef _LIBPSXCD_H +#define _LIBPSXCD_H + +#include <sys/types.h> + +/* + * CD-ROM control commands + */ +#define CdlNop 0x01 /* a.k.a. Getstat */ +#define CdlSetloc 0x02 +#define CdlPlay 0x03 +#define CdlForward 0x04 +#define CdlBackward 0x05 +#define CdlReadN 0x06 +#define CdlStandby 0x07 /* a.k.a. MotorOn */ +#define CdlStop 0x08 +#define CdlPause 0x09 +#define CdlInit 0x0A +#define CdlMute 0x0B +#define CdlDemute 0x0C +#define CdlSetfilter 0x0D +#define CdlSetmode 0x0E +#define CdlGetparam 0x0F +#define CdlGetlocL 0x10 +#define CdlGetlocP 0x11 +#define CdlSetsession 0x12 /* ORIGINAL CODE */ +#define CdlGetTN 0x13 +#define CdlGetTD 0x14 +#define CdlSeekL 0x15 +#define CdlSeekP 0x16 +#define CdlTest 0x19 /* ORIGINAL CODE */ +#define CdlReadS 0x1B + +/* + * CD-ROM status bits + */ +#define CdlStatError 0x01 +#define CdlStatStandby 0x02 +#define CdlStatSeekError 0x04 +#define CdlStatIdError 0x08 /* ORIGINAL CODE */ +#define CdlStatShellOpen 0x10 +#define CdlStatRead 0x20 +#define CdlStatSeek 0x40 +#define CdlStatPlay 0x80 + +/* + * CD-ROM mode bits + */ +#define CdlModeDA 0x01 +#define CdlModeAP 0x02 +#define CdlModeRept 0x04 +#define CdlModeSF 0x08 +#define CdlModeSize0 0x10 +#define CdlModeSize1 0x20 +#define CdlModeRT 0x40 +#define CdlModeSpeed 0x80 + +/* + * CD-ROM interrupt result values + */ +#define CdlNoIntr 0x00 +#define CdlDataReady 0x01 +#define CdlComplete 0x02 +#define CdlAcknowledge 0x03 +#define CdlDataEnd 0x04 +#define CdlDiskError 0x05 + +#define btoi(b) ((b)/16*10+(b)%16) /* Convert BCD value to integer */ +#define itob(i) ((i)/10*16+(i)%10) /* Convert integer to BCD value */ + +/* + * CD-ROM disc location struct + */ +typedef struct CdlLOC +{ + u_char minute; + u_char second; + u_char sector; + u_char track; +} CdlLOC; + +/* + * CD-ROM audio attenuation struct (volume) + */ +typedef struct CdlATV +{ + u_char val0; /* L -> SPU L */ + u_char val1; /* L -> SPU R */ + u_char val2; /* R -> SPU R */ + u_char val3; /* R -> SPU L */ +} CdlATV; + +/* + * CD-ROM file information struct + */ +typedef struct CdlFILE +{ + CdlLOC loc; + u_int size; + char name[16]; +} CdlFILE; + +typedef struct CdlFILTER +{ + u_char file; + u_char chan; + u_short pad; +} CdlFILTER; + +/* Data callback */ +typedef void (*CdlCB)(int, unsigned char *); + +#ifdef __cplusplus +extern "C" { +#endif + +int CdInit(int mode); + +CdlLOC *CdIntToPos(int i, CdlLOC *p); +int CdPosToInt(CdlLOC *p); +int CdGetToc(CdlLOC *toc); + +int CdControl(unsigned char com, unsigned char *param, unsigned char *result); +int CdControlB(unsigned char com, unsigned char *param, unsigned char *result); +int CdControlF(unsigned char com, unsigned char *param); +int CdSync(int mode, unsigned char *result); +unsigned int CdSyncCallback(CdlCB func); + +long CdReadyCallback(CdlCB func); +int CdGetSector(void *madr, int size); + +CdlFILE *CdSearchFile(CdlFILE *loc, const char *filename); +int CdRead(int sectors, unsigned int *buf, int mode); +int CdReadSync(int mode, unsigned char *result); +unsigned int CdReadCallback(CdlCB func); + +int CdStatus(void); +int CdMode(void); + +int CdMix(CdlATV *vol); + +/* ORIGINAL CODE */ +long *CdAutoPauseCallback(void(*func)()); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBPSXCD_H */ diff --git a/libpsn00b/include/psxgpu.h b/libpsn00b/include/psxgpu.h index 230775f..5f0798a 100644 --- a/libpsn00b/include/psxgpu.h +++ b/libpsn00b/include/psxgpu.h @@ -114,9 +114,9 @@ /* * Primitive handling macros */ -#define setlen( p, _len ) ( ((P_TAG*)(p))->len = (unsigned char)_len ) -#define setaddr( p, _addr ) ( ((P_TAG*)(p))->addr = (unsigned int)_addr ) -#define setcode( p, _code ) ( ((P_TAG*)(p))->code = (unsigned char)_code ) +#define setlen( p, _len ) ( ((P_TAG*)(p))->len = (unsigned char)(_len) ) +#define setaddr( p, _addr ) ( ((P_TAG*)(p))->addr = (unsigned int)(_addr) ) +#define setcode( p, _code ) ( ((P_TAG*)(p))->code = (unsigned char)(_code) ) #define getlen( p ) ( ((P_TAG*)(p))->len ) #define getaddr( p ) ( ((P_TAG*)(p))->addr ) @@ -126,7 +126,7 @@ #define isendprim( p ) ((((P_TAG*)(p))->addr)==0xffffff) #define addPrim( ot, p ) setaddr( p, getaddr( ot ) ), setaddr( ot, p ) -#define addPrims(ot, p0, p1) setaddr( p1, getaddr( ot ) ), setaddr( ot, p0 ) +#define addPrims( ot, p0, p1 ) setaddr( p1, getaddr( ot ) ), setaddr( ot, p0 ) #define catPrim( p0, p1 ) setaddr( p0, p1 ) #define termPrim( p ) setaddr( p, 0xffffff ) @@ -186,6 +186,22 @@ #define setFill( p ) setlen( p, 3 ), setcode( p, 0x02 ) +#define setDrawOffset( p, _x, _y ) \ + setlen( p, 1 ), \ + (p)->code[0] = (_x&0x3FF)|((_y&0x3FF)<<11), \ + ((char*)(p)->code)[3] = 0xE5 + +#define setDrawArea( p, r ) \ + setlen( p, 2 ), \ + (p)->code[0] = ((r)->x&0x3FF)|(((r)->y&0x1FF)<<10), \ + (p)->code[1] = (((r)->x+(r)->w-1)&0x3FF)|((((r)->y+(r)->h-1)&0x1FF)<<10), \ + ((char*)&(p)->code[0])[3] = 0xE3, \ + ((char*)&(p)->code[1])[3] = 0xE4 + +#define setTexWindow( p, r ) \ + setlen( p, 1 ), \ + (p)->code[0] = ((r)->w&0x1F)|(((r)->h&0x1F)<<5)|(((r)->x&0x1F)<<10)|(((r)->y&0x1F)<<15), \ + ((char*)&(p)->code[0])[3] = 0xE2 /* * Primitive definitions @@ -427,34 +443,44 @@ typedef struct { * VRAM fill and transfer primitive definitions */ -typedef struct { +typedef struct DR_ENV { unsigned int tag; unsigned int code[15]; } DR_ENV; -typedef struct { +typedef struct DR_AREA { + unsigned int tag; + unsigned int code[2]; +} DR_AREA; + +typedef struct DR_OFFSET { + unsigned int tag; + unsigned int code[1]; +} DR_OFFSET; + +typedef struct DR_TWIN { unsigned int tag; unsigned int code[2]; } DR_TWIN; -typedef struct { +typedef struct DR_TPAGE { unsigned int tag; unsigned int code[1]; } DR_TPAGE; -typedef struct { /* ORIGINAL */ +typedef struct DR_MASK { /* ORIGINAL */ unsigned int tag; unsigned int code[1]; } DR_MASK; -typedef struct { /* ORIGINAL */ +typedef struct FILL { /* 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 */ +typedef struct VRAM2VRAM { /* ORIGINAL */ unsigned int tag; unsigned char p0,p1,p2,code; unsigned short x0,y0; @@ -465,18 +491,18 @@ typedef struct { /* ORIGINAL */ // General structs -typedef struct { +typedef struct RECT { short x,y; short w,h; } RECT; -typedef struct { +typedef struct DISPENV_RAW { unsigned int vid_mode; // Video mode short vid_xpos,vid_ypos; // Video position (not framebuffer) short fb_x,fb_y; // Framebuffer display position } DISPENV_RAW; -typedef struct { +typedef struct DISPENV { RECT disp; RECT screen; char isinter; @@ -485,7 +511,7 @@ typedef struct { char pad; } DISPENV; -typedef struct { +typedef struct DRAWENV { RECT clip; // Drawing area short ofs[2]; // GPU draw offset (relative to draw area) RECT tw; // Texture window (doesn't do anything atm) @@ -497,7 +523,7 @@ typedef struct { DR_ENV dr_env; // Draw mode packet area (used by PutDrawEnv) } DRAWENV; -typedef struct { +typedef struct TIM_IMAGE { unsigned int mode; RECT *crect; unsigned int *caddr; diff --git a/libpsn00b/include/psxsio.h b/libpsn00b/include/psxsio.h index df218ac..3f571d7 100644 --- a/libpsn00b/include/psxsio.h +++ b/libpsn00b/include/psxsio.h @@ -58,9 +58,10 @@ void *Sio1Callback(void (*func)(void)); // ORIGINAL void WaitSIO(void); +int kbhit(); #ifdef __cplusplus } #endif -#endif
\ No newline at end of file +#endif diff --git a/libpsn00b/include/string.h b/libpsn00b/include/string.h index 9cd1d64..365d238 100644 --- a/libpsn00b/include/string.h +++ b/libpsn00b/include/string.h @@ -29,8 +29,8 @@ char *strncat(char *s , const char *append, int n); char *strcpy(char *dst , const char *src); char *strncpy(char *dst , const char *src , int n); int strlen(const char *s); -//char *strchr(const char *s , int c); -//char *strrchr(const char *s , int c); +char *strchr(const char *s , int c); +char *strrchr(const char *s , int c); void *memmove(void *dst , const void *src , int n); void *memchr(void *s , int c , int n); diff --git a/libpsn00b/libc/readme.txt b/libpsn00b/libc/readme.txt index 064a353..5bef0fd 100644 --- a/libpsn00b/libc/readme.txt +++ b/libpsn00b/libc/readme.txt @@ -32,12 +32,6 @@ Library header(s): Todo list: - - * Current vsprintf/sprintf implementation from PSXSDK needs to be replaced - as it performs quite slow likely due to the unnecessary int64 arithmetic - performed on any integer value which the compiler has to emulate on the - R3000. A more efficient implementation that only uses int32 is much - preferred. * Many of the string manipulation and memory fill functions in string.c are yet to be replaced with more efficient assembly implementations. diff --git a/libpsn00b/libc/string.c b/libpsn00b/libc/string.c index a14d950..0b7307d 100644 --- a/libpsn00b/libc/string.c +++ b/libpsn00b/libc/string.c @@ -43,7 +43,7 @@ char *strncpy(char *dst, const char *src, int len) len--; } - if(len)*dst = 0; + *dst = 0; return odst; } @@ -139,13 +139,13 @@ char *strstr(const char *big, const char *little) int strcmp(const char *s1, const char *s2) { - while(*s1 && *s2 && (*s1 == *s2)) + while((*s1) && (*s2) && (*s1 == *s2)) { s1++; s2++; } - return *s1-*s2; + return(*s1-*s2); } int strncmp(const char *s1, const char *s2, int len) diff --git a/libpsn00b/libpsxcd/_cd_control.s b/libpsn00b/libpsxcd/_cd_control.s new file mode 100644 index 0000000..7f69266 --- /dev/null +++ b/libpsn00b/libpsxcd/_cd_control.s @@ -0,0 +1,109 @@ +.set noreorder + +.include "hwregs_a.h" + +.section .text + +# +# Issues command and parameter bytes to CD controller directly +# +.global _cd_control +.type _cd_control, @function +_cd_control: + + # a0 - command value + # a1 - pointer to parameters + # a2 - length of parameters + + li $v0, 1 # Set acknowledge wait flag + la $v1, _cd_ack_wait + sb $v0, 0($v1) + + # Commands that have a 'completion' interrupt (CDIRQ2) + + beq $a0, 0x07, .Lset_complete # CdlStandby + nop + beq $a0, 0x08, .Lset_complete # CdlStop + nop + beq $a0, 0x09, .Lset_complete # CdlPause + nop + beq $a0, 0x0A, .Lset_complete # CdlInit + nop + beq $a0, 0x12, .Lset_complete # CdlSetsession + nop + beq $a0, 0x15, .Lset_complete # CdlSeekL + nop + beq $a0, 0x16, .Lset_complete # CdlSeekP + nop + beq $a0, 0x1A, .Lset_complete # GetID + nop + beq $a0, 0x1D, .Lset_complete # GetQ + nop + + la $v1, _cd_complt_wait # Set wait complete flag + sb $0 , 0($v1) + + b .Lno_complete + nop + +.Lset_complete: + + la $v1, _cd_complt_wait # Set wait complete flag + sb $v0, 0($v1) + +.Lno_complete: + + bne $a0, 0x0E, .Lnot_mode + lbu $v0, 0($a1) + la $v1, _cd_last_mode + sb $v0, 0($v1) + +.Lnot_mode: + + la $v1, _cd_last_int # Clear last IRQ value + sb $0 , 0($v1) + + la $v1, _cd_last_cmd # Save command as last command + sb $a0, 0($v1) + + lui $v1, IOBASE + +.Lbusy_wait: + lbu $v0, CD_REG0($v1) + nop + andi $v0, 0x80 + bnez $v0, .Lbusy_wait + nop + + li $v0, 1 # Clear parameter FIFO (in case it wasn't cleared) + sb $v0, CD_REG0($v1) + li $v0, 0x40 + sb $v0, CD_REG3($v1) + +.Lcmd_wait: # Wait for CD to become ready for commands + lbu $v0, CD_REG0($v1) + nop + andi $v0, 0x80 + bnez $v0, .Lcmd_wait + nop + + sb $0 , CD_REG0($v1) + + beqz $a2, .Lno_params + nop + +.Lfeed_params: # Feed parameters to parameter FIFO + lbu $v0, 0($a1) + addi $a2, -1 + sb $v0, CD_REG2($v1) + bgtz $a2, .Lfeed_params + addiu $a1, 1 + +.Lno_params: + + sb $0 , CD_REG0($v1) # Feed command value + sb $a0, CD_REG1($v1) + + jr $ra + nop +
\ No newline at end of file diff --git a/libpsn00b/libpsxcd/cdgetsector.s b/libpsn00b/libpsxcd/cdgetsector.s new file mode 100644 index 0000000..70039bf --- /dev/null +++ b/libpsn00b/libpsxcd/cdgetsector.s @@ -0,0 +1,53 @@ +.set noreorder + +.include "hwregs_a.h" + +.section .text + +.global CdGetSector +.type CdGetSector, @function +CdGetSector: + + lui $a2, IOBASE + +.Lwait_fifo: + lbu $v0, CD_REG0($a2) + nop + andi $v0, 0x40 + beqz $v0, .Lwait_fifo + nop + + lui $v0, 0x1 + srl $a1, 2 + or $v0, $a1 + sw $a0, D3_MADR($a2) # Set DMA base address and transfer length + sw $v0, D3_BCR($a2) + + lui $v0, 0x1100 # Start DMA transfer + sw $v0, D3_CHCR($a2) + nop + nop +.Ldma_wait: + lw $v0, D3_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/libpsxcd/cdmix.s b/libpsn00b/libpsxcd/cdmix.s new file mode 100644 index 0000000..745fb65 --- /dev/null +++ b/libpsn00b/libpsxcd/cdmix.s @@ -0,0 +1,34 @@ +.set noreorder + +.include "hwregs_a.h" + +.section .text + + +.global CdMix +.type CdMix, @function +CdMix: + + lui $a3, IOBASE + + lbu $t0, 0($a0) + lbu $t1, 1($a0) + lbu $t2, 2($a0) + lbu $t3, 3($a0) + + li $v0, 2 + sb $v0, CD_REG0($a3) + sb $t0, CD_REG2($a3) + sb $t1, CD_REG3($a3) + + li $v0, 3 + sb $v0, CD_REG0($a3) + sb $t2, CD_REG1($a3) + sb $t3, CD_REG2($a3) + + li $v0, 0x20 + sb $v0, CD_REG3($a3) + + jr $ra + li $v0, 1 +
\ No newline at end of file diff --git a/libpsn00b/libpsxcd/cdsearchfile.c b/libpsn00b/libpsxcd/cdsearchfile.c new file mode 100644 index 0000000..60e4377 --- /dev/null +++ b/libpsn00b/libpsxcd/cdsearchfile.c @@ -0,0 +1,663 @@ +#include <stdio.h> +#include <malloc.h> +#include <string.h> +#include <psxgpu.h> +#include <psxsio.h> +#include "psxcd.h" + +// Uncommend to enable debug output +//#define DEBUG + +#pragma pack(push, 1) + +/// Structure of a double-endian unsigned short word +typedef struct ISO_USHORT_PAIR +{ + unsigned short lsb; /// LSB format 16-bit word + unsigned short msb; /// MSB format 16-bit word +} ISO_USHORT_PAIR; + +/// Structure of a double-endian unsigned int word +typedef struct ISO_UINT_PAIR +{ + unsigned int lsb; /// LSB format 32-bit word + unsigned int msb; /// MSB format 32-bit word +} ISO_UINT_PAIR; + +/// ISO descriptor header structure +typedef struct ISO_DESCRIPTOR_HEADER +{ + unsigned char type; /// Volume descriptor type (1 is descriptor, 255 is descriptor terminator) + char id[5]; /// Volume descriptor ID (always CD001) + unsigned short version; /// Volume descriptor version (always 0x01) +} ISO_DESCRIPTOR_HEADER; + +/// Structure of a date stamp for ISO_DIR_ENTRY structure +typedef struct ISO_DATESTAMP +{ + unsigned char year; /// number of years since 1900 + unsigned char month; /// month, where 1=January, 2=February, etc. + unsigned char day; /// day of month, in the range from 1 to 31 + unsigned char hour; /// hour, in the range from 0 to 23 + unsigned char minute; /// minute, in the range from 0 to 59 + unsigned char second; /// Second, in the range from 0 to 59 + unsigned char GMToffs; /// Greenwich Mean Time offset +} ISO_DATESTAMP; + +/// Structure of an ISO path table entry (specifically for the cd::IsoReader class) +typedef struct ISO_PATHTABLE_ENTRY +{ + unsigned char nameLength; /// Name length (or 1 for the root directory) + unsigned char extLength; /// Number of sectors in extended attribute record + unsigned int dirOffs; /// Number of the first sector in the directory, as a double word + unsigned short dirLevel; /// Index of the directory record's parent directory + /// If nameLength is odd numbered, a padding byte will be present after the identifier text. +} ISO_PATHTABLE_ENTRY; + +typedef struct ISO_DIR_ENTRY +{ + unsigned char entryLength; // Directory entry length (variable, use for parsing through entries) + unsigned char extLength; // Extended entry data length (always 0) + ISO_UINT_PAIR entryOffs; // Points to the LBA of the file/directory entry + ISO_UINT_PAIR entrySize; // Size of the file/directory entry + ISO_DATESTAMP entryDate; // Date & time stamp of entry + unsigned char flags; // File flags (0x02 for directories, 0x00 for files) + unsigned char fileUnitSize; // Unit size (usually 0 even with Form 2 files such as STR/XA) + unsigned char interleaveGapSize; // Interleave gap size (usually 0 even with Form 2 files such as STR/XA) + ISO_USHORT_PAIR volSeqNum; // Volume sequence number (always 1) + unsigned char identifierLen; // Identifier (file/directory name) length in bytes +} ISO_DIR_ENTRY; + +typedef struct ISO_ROOTDIR_HEADER +{ + unsigned char entryLength; // Always 34 bytes + unsigned char extLength; // Always 0 + ISO_UINT_PAIR entryOffs; // Should point to LBA 22 + ISO_UINT_PAIR entrySize; // Size of entry extent + ISO_DATESTAMP entryDate; // Record date and time + unsigned char flags; // File flags + unsigned char fileUnitSize; + unsigned char interleaveGapSize; + ISO_USHORT_PAIR volSeqNum; + unsigned char identifierLen; // 0x01 + unsigned char identifier; // 0x00 +} ISO_ROOTDIR_HEADER; + +// ISO descriptor structure +typedef struct ISO_DESCRIPTOR +{ + + // ISO descriptor header + ISO_DESCRIPTOR_HEADER header; + // System ID (always PLAYSTATION) + char systemID[32]; + // Volume ID (or label, can be blank or anything) + char volumeID[32]; + // Unused null bytes + unsigned char pad2[8]; + // Size of volume in sector units + ISO_UINT_PAIR volumeSize; + // Unused null bytes + unsigned char pad3[32]; + // Number of discs in this volume set (always 1 for single volume) + ISO_USHORT_PAIR volumeSetSize; + // Number of this disc in volume set (always 1 for single volume) + ISO_USHORT_PAIR volumeSeqNumber; + // Size of sector in bytes (always 2048 bytes) + ISO_USHORT_PAIR sectorSize; + // Path table size in bytes (applies to all the path tables) + ISO_UINT_PAIR pathTableSize; + // LBA to Type-L path table + unsigned int pathTable1Offs; + // LBA to optional Type-L path table (usually a copy of the primary path table) + unsigned int pathTable2Offs; + // LBA to Type-L path table but with MSB format values + unsigned int pathTable1MSBoffs; + // LBA to optional Type-L path table but with MSB format values (usually a copy of the main path table) + unsigned int pathTable2MSBoffs; + // Directory entry for the root directory (similar to a directory entry) + ISO_ROOTDIR_HEADER rootDirRecord; + // Volume set identifier (can be blank or anything) + char volumeSetIdentifier[128]; + // Publisher identifier (can be blank or anything) + char publisherIdentifier[128]; + // Data preparer identifier (can be blank or anything) + char dataPreparerIdentifier[128]; + // Application identifier (always PLAYSTATION) + char applicationIdentifier[128]; + // Copyright file in the file system identifier (can be blank or anything) + char copyrightFileIdentifier[37]; + // Abstract file in the file system identifier (can be blank or anything) + char abstractFileIdentifier[37]; + // Bibliographical file identifier in the file system (can be blank or anything) + char bibliographicFilelIdentifier[37]; + // Volume create date (in text format YYYYMMDDHHMMSSMMGG) + char volumeCreateDate[17]; + // Volume modify date (in text format YYYYMMDDHHMMSSMMGG) + char volumeModifyDate[17]; + // Volume expiry date (in text format YYYYMMDDHHMMSSMMGG) + char volumeExpiryDate[17]; + // Volume effective date (in text format YYYYMMDDHHMMSSMMGG) + char volumeEffeciveDate[17]; + // File structure version (always 1) + unsigned char fileStructVersion; + // Padding + unsigned char dummy0; + // Application specific data (says CD-XA001 at [141], the rest are null bytes) + unsigned char appData[512]; + // Padding + unsigned char pad4[653]; + +} ISO_DESCRIPTOR; + +// Leave non-aligned structure packing +#pragma pack(pop) + +extern char _cd_media_changed; +int _cd_iso_last_dir_lba; + +u_char _cd_iso_descriptor_buff[2048]; +u_char *_cd_iso_pathtable_buff=NULL; +u_char *_cd_iso_directory_buff=NULL; +int _cd_iso_directory_len; + +int _CdReadIsoDescriptor(int session_offs) +{ + int i; + CdlLOC loc; + ISO_DESCRIPTOR *descriptor; + + // Seek to volume descriptor location + CdIntToPos(16+session_offs, &loc); + if( !CdControl(CdlSetloc, (u_char*)&loc, 0) ) + { +#ifdef DEBUG + printf("psxcd: Could not set seek destination.\n"); +#endif + return -1; + } + + // Read volume descriptor + CdRead(1, (u_int*)_cd_iso_descriptor_buff, CdlModeSpeed); + if( CdReadSync(0, 0) ) + { +#ifdef DEBUG + printf("psxcd: Error reading ISO volume descriptor.\n"); +#endif + return -1; + } + + + // 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 have a ISO9660 file system.\n"); +#endif + 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 + + // Allocate path table buffer + i = ((2047+descriptor->pathTableSize.lsb)>>11)<<11; + if( _cd_iso_pathtable_buff ) + { + free(_cd_iso_pathtable_buff); + } + _cd_iso_pathtable_buff = (u_char*)malloc(i); + +#ifdef DEBUG + printf("psxcd_dbg: Allocated %d bytes for path table.\n", i); +#endif + + // Read path table + CdIntToPos(descriptor->pathTable1Offs, &loc); + CdControl(CdlSetloc, (u_char*)&loc, 0); + CdRead(i>>11, (u_int*)_cd_iso_pathtable_buff, CdlModeSpeed); + if( CdReadSync(0, 0) ) + { +#ifdef DEBUG + printf("psxcd: Error reading ISO path table.\n"); +#endif + return -1; + } + + _cd_iso_last_dir_lba = 0; + + return 0; +} + +int _CdReadIsoDirectory(int lba) +{ + int i; + CdlLOC loc; + ISO_DIR_ENTRY *direntry; + + if( lba == _cd_iso_last_dir_lba ) + { + return 0; + } + + CdIntToPos(lba, &loc); + i = CdPosToInt(&loc); +#ifdef DEBUG + printf("psxcd_dbg: Seek to sector %d\n", i); +#endif + if( !CdControl(CdlSetloc, (u_char*)&loc, 0) ) + { +#ifdef DEBUG + printf("psxcd: Could not set seek destination.\n"); +#endif + return -1; + } + + if( _cd_iso_directory_buff ) + { + free(_cd_iso_directory_buff); + } + + // Read first sector of directory record + _cd_iso_directory_buff = (u_char*)malloc(2048); + CdRead(1, (u_int*)_cd_iso_directory_buff, CdlModeSpeed); + if( CdReadSync(0, 0) ) + { +#ifdef DEBUG + printf("psxcd: Error reading initial directory record.\n"); +#endif + 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 + + if( _cd_iso_directory_len > 2048 ) + { + if( !CdControl(CdlSetloc, (u_char*)&loc, 0) ) + { +#ifdef DEBUG + printf("psxcd: Could not set seek destination.\n"); +#endif + return -1; + } + + free(_cd_iso_directory_buff); + i = ((2047+_cd_iso_directory_len)>>11)<<11; + _cd_iso_directory_buff = (u_char*)malloc(i); +#ifdef DEBUG + printf("psxcd_dbg: Allocated %d bytes for directory record.\n", i); +#endif + + CdRead(i>>11, (u_int*)_cd_iso_directory_buff, CdlModeSpeed); + if( CdReadSync(0, 0) ) + { +#ifdef DEBUG + printf("psxcd: Error reading initial directory record.\n"); +#endif + return -1; + } + } + + _cd_iso_last_dir_lba = lba; + + return 0; +} + +#ifdef DEBUG + +void dump_directory(void) +{ + int i; + int dir_pos; + ISO_DIR_ENTRY *dir_entry; + char namebuff[16]; + + printf("psxcd_dbg: Cached directory record contents:\n"); + + i = 0; + dir_pos = 0; + while(1) + { + dir_entry = (ISO_DIR_ENTRY*)(_cd_iso_directory_buff+dir_pos); + + 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); + + dir_pos += dir_entry->entryLength; + i++; + + // Check if padding is reached (end of record sector) + if( _cd_iso_directory_buff[dir_pos] == 0 ) + { + // Snap it to next sector + dir_pos = ((dir_pos+2047)>>11)<<11; + + // Break if exceeds length of directory buffer (end) + if( dir_pos >= _cd_iso_directory_len ) + { + break; + } + } + } + + printf("--\n"); + +} + +void dump_pathtable(void) +{ + u_char *tbl_pos; + ISO_PATHTABLE_ENTRY *tbl_entry; + ISO_DESCRIPTOR *descriptor; + char namebuff[16]; + + printf("psxcd_dbg: Path table entries:\n"); + + descriptor = (ISO_DESCRIPTOR*)_cd_iso_descriptor_buff; + + tbl_pos = _cd_iso_pathtable_buff; + tbl_entry = (ISO_PATHTABLE_ENTRY*)tbl_pos; + + while( (int)(tbl_pos-_cd_iso_pathtable_buff) < + descriptor->pathTableSize.lsb ) + { + strncpy(namebuff, + tbl_pos+sizeof(ISO_PATHTABLE_ENTRY), + tbl_entry->nameLength); + + printf("psxcd_dbg: %s\n", namebuff); + + // Advance to next entry + tbl_pos += sizeof(ISO_PATHTABLE_ENTRY) + +(2*((tbl_entry->nameLength+1)/2)); + + tbl_entry = (ISO_PATHTABLE_ENTRY*)tbl_pos; + } + +} + +#endif + +int get_pathtable_entry(int entry, ISO_PATHTABLE_ENTRY *tbl, char *namebuff) +{ + int i; + u_char *tbl_pos; + ISO_PATHTABLE_ENTRY *tbl_entry; + ISO_DESCRIPTOR *descriptor; + + descriptor = (ISO_DESCRIPTOR*)_cd_iso_descriptor_buff; + + tbl_pos = _cd_iso_pathtable_buff; + tbl_entry = (ISO_PATHTABLE_ENTRY*)tbl_pos; + + i = 0; + while( (int)(tbl_pos-_cd_iso_pathtable_buff) < + descriptor->pathTableSize.lsb ) + { + if( i == (entry-1) ) + { + if( namebuff ) + { + strncpy(namebuff, + tbl_pos+sizeof(ISO_PATHTABLE_ENTRY), + tbl_entry->nameLength); + } + + if( tbl ) + { + *tbl = *tbl_entry; + } + + return 0; + } + + // Advance to next entry + tbl_pos += sizeof(ISO_PATHTABLE_ENTRY) + +(2*((tbl_entry->nameLength+1)/2)); + + tbl_entry = (ISO_PATHTABLE_ENTRY*)tbl_pos; + i++; + } + + if( entry <= 0 ) + { + return i+1; + } + + return -1; +} + +char *resolve_pathtable_path(int entry, char *rbuff) +{ + char namebuff[16]; + ISO_PATHTABLE_ENTRY tbl_entry; + + *rbuff = 0; + + do + { + if( get_pathtable_entry(entry, &tbl_entry, namebuff) ) + { + return NULL; + } + + rbuff -= tbl_entry.nameLength; + memcpy(rbuff, namebuff, tbl_entry.nameLength); + rbuff--; + *rbuff = '\\'; + + // Parse to the parent + entry = tbl_entry.dirLevel; + + } while( entry > 1 ); + + return rbuff; +} + +int find_dir_entry(const char *name, ISO_DIR_ENTRY *dirent) +{ + int i; + int dir_pos; + ISO_DIR_ENTRY *dir_entry; + char namebuff[16]; + +#ifdef DEBUG + printf("psxcd_dbg: Locating file %s.\n", name); +#endif + + i = 0; + dir_pos = 0; + while(dir_pos < _cd_iso_directory_len) + { + dir_entry = (ISO_DIR_ENTRY*)(_cd_iso_directory_buff+dir_pos); + + if( !(dir_entry->flags & 0x2) ) + { + strncpy(namebuff, + _cd_iso_directory_buff+dir_pos+sizeof(ISO_DIR_ENTRY), + dir_entry->identifierLen); + + if( strcmp(namebuff, name) == 0 ) + { + *dirent = *dir_entry; + return 0; + } + } + + dir_pos += dir_entry->entryLength; + i++; + + // Check if padding is reached (end of record sector) + if( _cd_iso_directory_buff[dir_pos] == 0 ) + { + // Snap it to next sector + dir_pos = ((dir_pos+2047)>>11)<<11; + + } + } + + return -1; +} + +char *get_pathname(char *path, const char *filename) +{ + char *c; + c = strrchr(filename, '\\'); + + if(( c == filename ) || ( !c )) + { + path[0] = '\\'; + path[1] = 0; + return NULL; + } + + strncpy(path, filename, (int)(c-filename)); + return path; +} + +char *get_filename(char *name, const char *filename) +{ + char *c; + c = strrchr(filename, '\\'); + + if(( c == filename ) || ( !c )) + { + strcpy(name, filename+1); + return name; + } + + c++; + strcpy(name, c); + return name; +} + +CdlFILE *CdSearchFile(CdlFILE *fp, const char *filename) +{ + int i,j,found_dir,num_dirs; + int dir_len; + char tpath_rbuff[128]; + char search_path[128]; + char *rbuff; + ISO_PATHTABLE_ENTRY tbl_entry; + ISO_DIR_ENTRY dir_entry; + + // Read ISO descriptor if changed flag is set + if( _cd_media_changed ) + { + // Read ISO descriptor and path table + if( _CdReadIsoDescriptor(0) ) + { +#ifdef DEBUG + printf("psxcd: Could not read ISO file system.\n"); +#endif + return NULL; + } +#ifdef DEBUG + printf("psxcd: ISO file system cache updated.\n"); +#endif + _cd_media_changed = 0; + } + + // Get number of directories in path table + num_dirs = get_pathtable_entry(0, NULL, NULL); + +#ifdef DEBUG + printf("psxcd_dbg: 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"); + } + else + { + printf("psxcd_dbg: Longest path: %s|\n", rbuff); + } +#endif + + if( get_pathname(search_path, filename) ) + { +#ifdef DEBUG + printf("psxcd_dbg: Search path = %s|\n", search_path); +#endif + } + + // Search the pathtable for a matching path + found_dir = 0; + for(i=1; i<num_dirs; i++) + { + rbuff = resolve_pathtable_path(i, tpath_rbuff+127); +#ifdef DEBUG + printf("psxcd_dbg: Found = %s|\n", rbuff); +#endif + if( rbuff ) + { + if( strcmp(search_path, rbuff) == 0 ) + { + found_dir = i; + break; + } + } + } + + if( !found_dir ) + { +#ifdef DEBUG + printf("psxcd_dbg: Directory path not found.\n"); +#endif + return NULL; + } + +#ifdef DEBUG + printf("psxcd_dbg: Found directory at record %d!\n", found_dir); +#endif + + get_pathtable_entry(found_dir, &tbl_entry, NULL); + +#ifdef DEBUG + printf("psxcd_dbg: Directory LBA = %d\n", tbl_entry.dirOffs); +#endif + + _CdReadIsoDirectory(tbl_entry.dirOffs); + + get_filename(fp->name, filename); + + // Add version number if not specified + if( !strchr(fp->name, ';') ) + { + strcat(fp->name, ";1"); + } + +#ifdef DEBUG + dump_directory(); +#endif + + if( find_dir_entry(fp->name, &dir_entry) ) + { +#ifdef DEBUG + printf("psxcd: Could not find file.\n"); +#endif + return NULL; + } + +#ifdef DEBUG + printf("psxcd_dbg: Located file at LBA %d.\n", dir_entry.entryOffs.lsb); +#endif + + CdIntToPos(dir_entry.entryOffs.lsb, &fp->loc); + fp->size = dir_entry.entrySize.lsb; + + return fp; +} diff --git a/libpsn00b/libpsxcd/makefile b/libpsn00b/libpsxcd/makefile new file mode 100644 index 0000000..87466b3 --- /dev/null +++ b/libpsn00b/libpsxcd/makefile @@ -0,0 +1,38 @@ +# Run using make (Linux) or gmake (BSD) +# Part of the PSn00bSDK Project +# 2019 Lameguy64 / Meido-Tek Productions + +include ../common.mk + +TARGET = ../libpsxcd.a + +CFILES = $(notdir $(wildcard ./*.c)) +AFILES = $(notdir $(wildcard ./*.s)) +OFILES = $(addprefix build/,$(CFILES:.c=.o) $(AFILES:.s=.o)) + +INCLUDE = -I../include + +CFLAGS = -g -msoft-float -fno-builtin -fdata-sections -ffunction-sections -Wa,--strip-local-absolute +AFLAGS = -g -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) -O2 $(CFLAGS) $(INCLUDE) -c $< -o $@ + +build/%.o: %.s + @mkdir -p $(dir $@) + $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@ + +clean: + rm -Rf build $(TARGET) diff --git a/libpsn00b/libpsxcd/psxcd.c b/libpsn00b/libpsxcd/psxcd.c new file mode 100644 index 0000000..5be9eec --- /dev/null +++ b/libpsn00b/libpsxcd/psxcd.c @@ -0,0 +1,319 @@ +#include <stdio.h> +#include "psxcd.h" + +extern volatile char _cd_ack_wait; +extern volatile unsigned char _cd_last_int; +extern volatile unsigned char _cd_last_mode; +extern volatile unsigned char _cd_status; +extern volatile CdlCB _cd_callback_int1_data; +volatile unsigned char *_cd_result_ptr; + +extern volatile char _cd_media_changed; + +void _cd_init(void); +void _cd_control(unsigned char com, unsigned char *param, int plen); +void _cd_wait_ack(void); +void _cd_wait(void); + +int CdInit(int mode) +{ + // Sets up CD-ROM hardware and low-level subsystem + _cd_init(); + + // So CD ISO file system component will update the ISO descriptor + _cd_media_changed = 1; + + // Issue commands to initialize the CD-ROM hardware + CdControl(CdlNop, 0, 0); + CdControl(CdlInit, 0, 0); + + 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"); + } + + return 1; +} + +int CdControl(unsigned char com, unsigned char *param, unsigned char *result) +{ + // Don't issue command if ack is not received yet + if( _cd_ack_wait ) + { + return 0; + } + + _cd_result_ptr = result; + + CdControlF(com, param); + _cd_wait_ack(); + + return 1; +} + +int CdControlB(unsigned char com, unsigned char *param, unsigned char *result) +{ + if( !CdControl(com, param, result) ) + { + return 0; + } + + CdSync(0, 0); + return 1; +} + +int CdControlF(unsigned char com, unsigned char *param) +{ + int param_len=0; + + // Command specific parameters + switch(com) + { + case CdlSetloc: + param_len = 3; + break; + case CdlPlay: + if( param ) + { + param_len = 1; + } + break; + case CdlSetfilter: + 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; + } + + // Issue Setloc if parameters are specified on CdlReadN and CdlReadS + if( ( com == CdlReadN ) || ( com == CdlReadS ) ) + { + if( param ) + { + _cd_control(CdlSetloc, param, 3); + } + } + + // Issue CD command + _cd_control(com, param, param_len); + + return 1; +} + +int CdSync(int mode, unsigned char *result) +{ + int cdirq; + + if( mode ) + { + if( result ) + { + *result = _cd_status; + } + + cdirq = _cd_last_int; + if( cdirq == CdlAcknowledge ) + { + cdirq = CdlComplete; + } + return cdirq; + } + + _cd_wait(); + + if( result ) + { + *result = _cd_status; + } + + cdirq = _cd_last_int; + if( cdirq == CdlAcknowledge ) + { + cdirq = CdlComplete; + } + + return cdirq; +} + +int CdGetToc(CdlLOC *toc) +{ + u_char track_info[8]; + int i,tracks; + + // Get number of tracks + if( !CdControl(CdlGetTN, 0, track_info) ) + { + return 0; + } + + if( CdSync(1, 0) != CdlComplete ) + { + return 0; + } + + tracks = 1+(btoi(track_info[2])-btoi(track_info[1])); + + // Get track positions + for(i=0; i<tracks; i++) + { + int t = itob(1+i); + if( !CdControl(CdlGetTD, (u_char*)&t, (u_char*)&toc[i]) ) + { + return 0; + } + if( CdSync(1, 0) != CdlComplete ) + { + return 0; + } + toc[i].sector = 0; + toc[i].track = 1+i; + } + + return tracks; +} + +CdlLOC *CdIntToPos(int i, CdlLOC *p) { + + i += 150; + + p->minute = itob((i/75)/60); + p->second = itob((i/75)%60); + p->sector = itob(i%75); + + return p; + +} + +int CdPosToInt(CdlLOC *p) +{ + return ((75*(btoi(p->minute)*60))+(75*btoi(p->second))+btoi(p->sector))-150; +} + +int CdStatus(void) +{ + return _cd_status; +} + +int CdMode(void) +{ + return _cd_last_mode; +} + + +// CD data read routines +volatile int _cd_sector_count = 0; +volatile unsigned int *_cd_read_addr; +volatile unsigned char _cd_read_result[8]; +volatile unsigned int _cd_read_oldcb; +volatile unsigned int _cd_read_sector_sz; +volatile CdlCB _cd_read_cb; + +// Sector callback +static void _CdReadReadyCallback(int status, unsigned char *result) +{ + if( status == CdlDataReady ) + { + // Fetch sector from CD controller + CdGetSector((void*)_cd_read_addr, _cd_read_sector_sz); + + // Increment destination address + _cd_read_addr += _cd_read_sector_sz>>2; + + // Subtract sector count + _cd_sector_count--; + } + + // End reading with pause command when sector count reaches zero + // or when an error occurs + if( ( _cd_sector_count <= 0 ) || ( status == CdlDiskError ) ) + { + // Stop reading + _cd_control(CdlPause, 0, 0); + + // Revert previous ready callback + _cd_callback_int1_data = (CdlCB)_cd_read_oldcb; + + // Execute read completion callback + if( _cd_read_cb ) + { + _cd_read_cb(status, result); + } + } +} + +int CdRead(int sectors, unsigned int *buf, int mode) +{ + // Set sectors to read count + _cd_sector_count = sectors; + _cd_read_addr = buf; + + // Determine sector based on mode flags + if( mode & CdlModeSize0 ) + { + _cd_read_sector_sz = 2328; + } + else if( mode & CdlModeSize1 ) + { + _cd_read_sector_sz = 2340; + } + else + { + _cd_read_sector_sz = 2048; + } + + // Set readt callback + _cd_read_oldcb = CdReadyCallback(_CdReadReadyCallback); + + // Set specified mode + CdControl(CdlSetmode, (unsigned char*)&mode, 0); + + // Begin reading sectors + CdControl(CdlReadN, 0, (unsigned char*)_cd_read_result); + + return 0; +} + +int CdReadSync(int mode, unsigned char *result) +{ + if( mode ) + { + if( CdSync(1, 0) == CdlDiskError ) + { + return -1; + } + return _cd_sector_count; + } + + while(_cd_sector_count > 0); + if( CdSync(0, result) != CdlComplete ) + { + return -1; + } + + return 0; +} + +unsigned int CdReadCallback(CdlCB func) +{ + unsigned int old_func; + + old_func = (unsigned int)_cd_read_cb; + + _cd_read_cb = func; + + return old_func; +} diff --git a/libpsn00b/libpsxcd/psxcd_asm.s b/libpsn00b/libpsxcd/psxcd_asm.s new file mode 100644 index 0000000..7fe1c1d --- /dev/null +++ b/libpsn00b/libpsxcd/psxcd_asm.s @@ -0,0 +1,520 @@ +.set noreorder + +.include "hwregs_a.h" + +.section .text + +.global _cd_init +.type _cd_init, @function +_cd_init: + + addiu $sp, -4 + sw $ra, 0($sp) + + jal EnterCriticalSection + nop + + lui $a3, IOBASE # Acknowledge all CD IRQs + li $v0, 1 + sb $v0, CD_REG0($a3) + li $v0, 0x1f + sb $v0, CD_REG3($a3) + sb $v0, CD_REG2($a3) # Enable all IRQs + + sb $0 , CD_REG0($a3) + sb $0 , CD_REG3($a3) + + li $v0, 0x1325 + sw $v0, COM_DELAY($a3) + + la $a1, _cd_handler + jal InterruptCallback + li $a0, 2 + + li $v0, 2 # Set CD left volume + sb $v0, CD_REG0($a3) + li $v0, 0x80 + sb $v0, CD_REG2($a3) + + li $v0, 3 # Set CD right volume + sb $v0, CD_REG0($a3) + li $v0, 0x80 + sb $v0, CD_REG1($a3) + + li $v0, 0x20 # Apply volume + sb $v0, CD_REG3($a3) + + # Clear a bunch of stats + la $v0, _cd_ack_wait + sb $0 , 0($v0) + la $v0, _cd_complt_wait + sb $0 , 0($v0) + la $v0, _cd_last_cmd + sb $0 , 0($v0) + la $v0, _cd_last_mode + sb $0 , 0($v0) + la $v0, _cd_last_int + sb $0 , 0($v0) + + la $v0, _cd_result_ptr + sw $0 , 0($v0) + + # Clear callback hooks + la $v0, _cd_callback_int1_data + sw $0 , 0($v0) + la $v0, _cd_callback_int4 + sw $0 , 0($v0) + + la $v0, _cd_read_cb + sw $0 , 0($v0) + + lw $v0, DPCR($a3) + li $v1, 0xB000 + or $v0, $v1 + sw $v0, DPCR($a3) + + jal ExitCriticalSection + nop + + #li $a0, 0x01 # GetStat + #jal _cd_control + #move $a2, $0 + #jal _cd_wait + #nop + + #li $a0, 0x0a # Init + #jal _cd_control + #move $a2, $0 + #jal _cd_wait + #nop + + #li $a0, 0x0c # Demute + #jal _cd_control + #move $a2, $0 + #jal _cd_wait + #nop + + #la $a0, _cd_init_msg + #jal printf + #addiu $sp, -16 + #addiu $sp, 16 + + lw $ra, 0($sp) + addiu $sp, 4 + jr $ra + nop + + +.global _cd_wait +.type _cd_wait, @function +_cd_wait: + la $v0, _cd_ack_wait + lbu $v0, 0($v0) + nop + bnez $v0, _cd_wait + nop +.Lcomplete: + la $v0, _cd_complt_wait + lbu $v0, 0($v0) + nop + bnez $v0, .Lcomplete + nop + jr $ra + nop + + +.global _cd_wait_ack +.type _cd_wait_ack, @function +_cd_wait_ack: + la $v0, _cd_ack_wait + lbu $v0, 0($v0) + nop + bnez $v0, _cd_wait_ack + nop + jr $ra + nop + + +.global _cd_wait_complt +.type _cd_wait_complt, @function +_cd_wait_complt: + la $v0, _cd_complt_wait + lbu $v0, 0($v0) + nop + bnez $v0, _cd_wait_complt + nop + jr $ra + nop + + +.type _cd_handler, @function +_cd_handler: + + addiu $sp, -4 + sw $ra, 0($sp) + + lui $a3, IOBASE # Print out IRQ number + li $v0, 1 + sb $v0, CD_REG0($a3) + + lbu $v0, CD_REG3($a3) + nop + andi $v0, 0x7 + + la $v1, _cd_last_int # Save last IRQ value + sb $v0, 0($v1) + + bne $v0, 0x1, .Lno_data + nop + + sb $0 , CD_REG0($a3) # Load data FIFO on INT1 + li $v1, 0x80 + sb $v1, CD_REG3($a3) + +.Lno_data: + + li $v1, 1 + sb $v1, CD_REG0($a3) # Clear CD interrupt and parameter FIFO + li $v1, 0x5f + sb $v1, CD_REG3($a3) + li $v1, 0x40 + sb $v1, CD_REG3($a3) + + li $v1, 0 # Delay when clearing parameter FIFO + sw $v1, 0($0) + li $v1, 1 + sw $v1, 0($0) + li $v1, 2 + sw $v1, 0($0) + li $v1, 3 + sw $v1, 0($0) + + beq $v0, 0x1, .Lirq_1 # Data ready + nop + beq $v0, 0x2, .Lirq_2 # Command finish + nop + beq $v0, 0x3, .Lirq_3 # Acknowledge + nop + beq $v0, 0x4, .Lirq_4 # Data/track end + nop + beq $v0, 0x5, .Lirq_5 # Error + nop + + b .Lirq_misc + nop + +.Lirq_1: # Data ready + + jal _cd_fetch_result + nop + + la $v0, _cd_callback_int1_data + lw $v0, 0($v0) + nop + beqz $v0, .Lirq_misc + nop + + la $a0, _cd_last_int + lbu $a0, 0($a0) + la $a1, _cd_result_ptr + lw $a1, 0($a1) + + jalr $v0 + addiu $sp, -16 + addiu $sp, 16 + + b .Lirq_misc + nop + +.Lirq_2: # Command complete + + jal _cd_fetch_result + nop + + la $v0, _cd_complt_wait + sb $0 , 0($v0) + + la $v0, _cd_sync_cb + lw $v0, 0($v0) + nop + beqz $v0, .Lirq_misc + nop + + la $a0, _cd_last_int + lbu $a0, 0($a0) + la $a1, _cd_result_ptr + lw $a1, 0($a1) + jalr $v0 + addiu $sp, -16 + addiu $sp, 16 + + b .Lirq_misc + nop + +.Lirq_3: # Command acknowledge + + jal _cd_fetch_result + nop + + la $v0, _cd_ack_wait + sb $0 , 0($v0) + + b .Lirq_misc + nop + +.Lirq_4: + + jal _cd_fetch_result + nop + + la $v0, _cd_callback_int4 + lw $v0, 0($v0) + nop + beqz $v0, .Lirq_misc + nop + + jalr $v0 + addiu $sp, -16 + addiu $sp, 16 + + b .Lirq_misc + nop + +.Lirq_5: # Error + + jal _cd_fetch_result + nop + + la $v0, _cd_complt_wait + lbu $v0, 0($v0) + nop + beqz $v0, .Lno_complete + nop + + la $v0, _cd_sync_cb + lw $v0, 0($v0) + nop + beqz $v0, .Lno_complete + nop + + li $a0, 0x05 # CdlDiskError + la $a1, _cd_result_ptr + lw $a1, 0($a1) + jalr $v0 + addiu $sp, -16 + addiu $sp, 16 + +.Lno_complete: + + la $v0, _cd_complt_wait + sb $0 , 0($v0) + la $v0, _cd_ack_wait + sb $0 , 0($v0) + + la $v0, _cd_callback_int1_data + lw $v0, 0($v0) + nop + beqz $v0, .Lirq_misc + nop + + li $a0, 0x05 # CdlDiskError + la $a1, _cd_result_ptr + lw $a1, 0($a1) + + jalr $v0 + addiu $sp, -16 + addiu $sp, 16 + +.Lirq_misc: + + lw $ra, 0($sp) + addiu $sp, 4 + jr $ra + nop + + +_cd_fetch_result: + + lui $a3, IOBASE + + la $a0, _cd_status + lbu $v0, CD_REG1($a3) + + la $v1, _cd_last_int + lbu $v1, 0($v1) + nop + beq $v1, 0x2, .Lirq2_checks + nop + + # IRQ3 checks + + la $v1, _cd_last_cmd + lbu $v1, 0($v1) + nop + beq $v1, 0x10, .Lskip_status + nop + beq $v1, 0x11, .Lskip_status + nop + + b .Lwrite_status + nop + + # IRQ2 checks + +.Lirq2_checks: + + la $v1, _cd_last_cmd + lbu $v1, 0($v1) + nop + beq $v1, 0x1D, .Lskip_status + nop + +.Lwrite_status: + + sb $v0, 0($a0) + +.Lskip_status: + + la $a0, _cd_result_ptr + lw $a0, 0($a0) + nop + beqz $a0, .Lno_result + nop + sb $v0, 0($a0) + addiu $a0, 1 + +.Lread_futher_result: + + lbu $v0, CD_REG0($a3) + nop + andi $v0, 0x20 + beqz $v0, .Lno_result + nop + + lbu $v0, CD_REG1($a3) + lbu $v1, CD_REG0($a3) + sb $v0, 0($a0) + andi $v1, 0x20 + bnez $v1, .Lread_futher_result + addiu $a0, 1 + +.Lno_result: + + jr $ra + nop + + +.global CdAutoPauseCallback +.type CdAutoPauseCallback, @function +CdAutoPauseCallback: + + addiu $sp, -8 + sw $ra, 0($sp) + sw $a0, 4($sp) + + la $v1, _cd_callback_int4 + 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 + nop + + +.global CdReadyCallback +.type CdReadyCallback, @function +CdReadyCallback: + + addiu $sp, -12 + sw $ra, 0($sp) + sw $a0, 4($sp) + + la $v1, _cd_callback_int1_data + lw $v0, 0($v1) + + 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 + addiu $sp, 12 + + +.global CdSyncCallback +.type CdSyncCallback, @function +CdSyncCallback: + addiu $sp, -12 + sw $ra, 0($sp) + sw $a0, 4($sp) + + la $v1, _cd_sync_cb + lw $v0, 0($v1) + + 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 + addiu $sp, 12 + + +.section .data + +.global psxcd_credits +.type psxcd_credits, @object +psxgpu_credits: + .ascii "psxcd library programs by Lameguy64\n" + .asciiz "2019 PSn00bSDK Project / Meido-Tek Productions\n" + +_cd_init_msg: +.asciiz "psxcd: Init OK\n" +.align 4 + +.comm _cd_last_cmd, 1, 1 +.comm _cd_last_mode, 1, 1 +.comm _cd_ack_wait, 1, 1 +.comm _cd_complt_wait, 1, 1 + +.comm _cd_status, 1, 1 +.comm _cd_last_int, 1, 1 + +.comm _cd_media_changed, 1, 1 + +# Callback hooks +.comm _cd_callback_int1_data, 4, 4 # Data IRQ callback +.comm _cd_callback_int4, 4, 4 # Autopause callback +.comm _cd_sync_cb, 4, 4 diff --git a/libpsn00b/libpsxcd/readme.txt b/libpsn00b/libpsxcd/readme.txt new file mode 100644 index 0000000..a85fab5 --- /dev/null +++ b/libpsn00b/libpsxcd/readme.txt @@ -0,0 +1,48 @@ +PSX CD-ROM library, part of PSn00bSDK +2019 Lameguy64 / Meido-Tek Productions + +Licensed under Mozilla Public License + + Open source implementation of the long awaited CD-ROM library that +provides greater functionality than the BIOS CD-ROM subsystem. Supports +pretty much all features of the CD-ROM hardware such as CD data read, +CD Audio and XA audio playback. Data streaming should also be possible +with the use of CdlReadN/CdlReadS commands and CdReadyCallback(). + + Library also includes an ISO9660 file system parser for locating +files within the CD-ROM file system. Unlike the file system parser in +the official libraries libpsxcd can parse directories containing any +number of files. Rock-ridge and Joliet extensions are not supported +however. + + Be aware that the CD-ROM library might have some loose ends as it +is still a work in progress, but should work flawlessly in most use +cases. + + +Library developer(s): + + Lameguy64 + + +Library header(s): + + psxcd.h + + +Todo list: + + * Command query mechanism so that more than 2 CD-ROM commands can + easily be issued in callbacks. Official library probably does this. + + * Helper functions for handling disc changes (CdDiskReady and + CdGetDiskType) are not yet implemented. + + * CdReadBreak() not yet implemented. + + * Data streaming functions (prefixed with St*) not yet implemented. + Would require devising a PSn00bSDK equivalent of the STR file + format. + + * Original functions for querying directory contents in the file + system not yet implemented.
\ No newline at end of file diff --git a/libpsn00b/makefile b/libpsn00b/makefile index d4bba32..f095f17 100644 --- a/libpsn00b/makefile +++ b/libpsn00b/makefile @@ -4,7 +4,7 @@ TOPTARGETS = all clean -LIBDIRS = libc lzp psxgpu psxgte psxapi psxetc psxspu psxsio +LIBDIRS = libc lzp psxgpu psxgte psxapi psxetc psxspu psxsio libpsxcd $(TOPTARGETS): $(LIBDIRS) diff --git a/libpsn00b/psxapi/sys/adddummytty.s b/libpsn00b/psxapi/sys/adddummytty.s new file mode 100644 index 0000000..a569d38 --- /dev/null +++ b/libpsn00b/psxapi/sys/adddummytty.s @@ -0,0 +1,10 @@ +.set noreorder + +.section .text + +.global AddDummyTty +.type AddDummyTty, @function +AddDummyTty: + addiu $t2, $0, 0xa0 + jr $t2 + addiu $t1, $0, 0x99 diff --git a/libpsn00b/psxapi/sys/getrcnt.s b/libpsn00b/psxapi/sys/getrcnt.s new file mode 100644 index 0000000..0b035ed --- /dev/null +++ b/libpsn00b/psxapi/sys/getrcnt.s @@ -0,0 +1,10 @@ +.set noreorder + +.section .text + +.global GetRCnt +.type GetRCnt, @function +GetRCnt: + addiu $t2, $0, 0xb0 + jr $t2 + addiu $t1, $0, 0x03
\ No newline at end of file diff --git a/libpsn00b/psxapi/sys/resetrcnt.s b/libpsn00b/psxapi/sys/resetrcnt.s new file mode 100644 index 0000000..5811625 --- /dev/null +++ b/libpsn00b/psxapi/sys/resetrcnt.s @@ -0,0 +1,10 @@ +.set noreorder + +.section .text + +.global ResetRCnt +.type ResetRCnt, @function +ResetRCnt: + addiu $t2, $0, 0xb0 + jr $t2 + addiu $t1, $0, 0x06
\ No newline at end of file diff --git a/libpsn00b/psxapi/sys/setrcnt.s b/libpsn00b/psxapi/sys/setrcnt.s new file mode 100644 index 0000000..ec6180a --- /dev/null +++ b/libpsn00b/psxapi/sys/setrcnt.s @@ -0,0 +1,10 @@ +.set noreorder + +.section .text + +.global SetRCnt +.type SetRCnt, @function +SetRCnt: + addiu $t2, $0, 0xb0 + jr $t2 + addiu $t1, $0, 0x02
\ No newline at end of file diff --git a/libpsn00b/psxapi/sys/startrcnt.s b/libpsn00b/psxapi/sys/startrcnt.s new file mode 100644 index 0000000..0fd5c33 --- /dev/null +++ b/libpsn00b/psxapi/sys/startrcnt.s @@ -0,0 +1,10 @@ +.set noreorder + +.section .text + +.global StartRCnt +.type StartRCnt, @function +StartRCnt: + addiu $t2, $0, 0xb0 + jr $t2 + addiu $t1, $0, 0x04
\ No newline at end of file diff --git a/libpsn00b/psxapi/sys/stoprcnt.s b/libpsn00b/psxapi/sys/stoprcnt.s new file mode 100644 index 0000000..4af94da --- /dev/null +++ b/libpsn00b/psxapi/sys/stoprcnt.s @@ -0,0 +1,10 @@ +.set noreorder + +.section .text + +.global StopRCnt +.type StopRCnt, @function +StopRCnt: + addiu $t2, $0, 0xb0 + jr $t2 + addiu $t1, $0, 0x05
\ No newline at end of file diff --git a/libpsn00b/psxgpu/drawsync.s b/libpsn00b/psxgpu/drawsync.s index 66d37e2..2e29381 100644 --- a/libpsn00b/psxgpu/drawsync.s +++ b/libpsn00b/psxgpu/drawsync.s @@ -24,7 +24,7 @@ DrawSync: nop .Ldma_wait: - lw $v0, D2_CHCR + lw $v0, D2_CHCR($a0) nop srl $v0, 24 andi $v0, 0x1 @@ -64,4 +64,4 @@ DrawSync: jr $ra srl $v0, 16 -
\ No newline at end of file + diff --git a/libpsn00b/psxgpu/readme.txt b/libpsn00b/psxgpu/readme.txt index 8fe439b..b626e1d 100644 --- a/libpsn00b/psxgpu/readme.txt +++ b/libpsn00b/psxgpu/readme.txt @@ -5,9 +5,9 @@ Licensed under Mozilla Public License Open source implementation of the GPU library written mostly in MIPS assembly. Supports DMA transfers for ordering table draw and transferring -image data to VRAM. The syntax is intentionally made to closely resemble -Sony's syntax for familiarity and to make porting homebrew made using the -official SDK to PSn00bSDK a little easier. +image data to and from VRAM. The syntax is intentionally made to closely +resemble Sony's syntax for familiarity and to make porting homebrew made +using the official SDK to PSn00bSDK a little easier. Library developer(s): @@ -25,5 +25,3 @@ Todo list: * ClearOTag() function (non reverse version of ClearOTagR()) yet to be implemented (but should be trivial). - - * StoreImage() equivalent yet to be implemented. diff --git a/libpsn00b/psxgpu/resetgraph.s b/libpsn00b/psxgpu/resetgraph.s index 93ce185..b956873 100644 --- a/libpsn00b/psxgpu/resetgraph.s +++ b/libpsn00b/psxgpu/resetgraph.s @@ -4,7 +4,7 @@ .section .text -.set ISR_STACK_SIZE, 1024 +.set ISR_STACK_SIZE, 2048 .global ResetGraph # Resets the GPU and installs a .type ResetGraph, @function # VSync event handler diff --git a/libpsn00b/psxgte/readme.txt b/libpsn00b/psxgte/readme.txt index 74951c5..13067ee 100644 --- a/libpsn00b/psxgte/readme.txt +++ b/libpsn00b/psxgte/readme.txt @@ -29,7 +29,7 @@ Library header(s): Todo list: - * Alternate RotMatrix() functions with different rotation order are yet to + * Alternate RotMatrix() functions with different rotation orders are yet to be implemented. * Various high level RotTransPersp style functions not yet implemented. diff --git a/libpsn00b/psxsio/siocons.c b/libpsn00b/psxsio/siocons.c index cd99d68..76bf8be 100644 --- a/libpsn00b/psxsio/siocons.c +++ b/libpsn00b/psxsio/siocons.c @@ -1,9 +1,25 @@ #include <stdio.h> +#include <string.h> #include <psxapi.h> #include <psxgpu.h> #include <psxsio.h> +#define SIO_BUFF_LEN 32 + +static volatile int _sio_key_pending; + +static volatile int _sio_buff_rpos; +static volatile int _sio_buff_wpos; +static volatile char _sio_buff[SIO_BUFF_LEN]; + static void _sio_init() { + + _sio_key_pending = 0; + + memset((void*)_sio_buff, 0, SIO_BUFF_LEN); + _sio_buff_rpos = 0; + _sio_buff_wpos = 0; + } static int _sio_open(FCB *fcb, const char* file, int mode) { @@ -29,9 +45,25 @@ static int _sio_inout(FCB *fcb, int cmd) { } else if (cmd == 1) { // Read - for(i=0; i<fcb->trns_len; i++) { + /*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); + }*/ + + + + for(i=0; i<fcb->trns_len; i++) { + + while( _sio_key_pending == 0 ); + + ((char*)fcb->trns_addr)[i] = _sio_buff[_sio_buff_rpos]; + _sio_key_pending--; + _sio_buff_rpos++; + if( _sio_buff_rpos >= SIO_BUFF_LEN ) + { + _sio_buff_rpos = 0; + } + } return fcb->trns_len; @@ -48,6 +80,29 @@ static int _sio_close(int h) { } +static void _sio_tty_cb(void) +{ + _sio_key_pending++; + + // Get received byte + if( _sio_key_pending < SIO_BUFF_LEN ) + { + _sio_buff[_sio_buff_wpos] = _sio_control(0, 4, 0); + _sio_buff_wpos++; + if( _sio_buff_wpos >= SIO_BUFF_LEN ) + { + _sio_buff_wpos = 0; + } + } + else + { + _sio_control(0, 4, 0); + } + + // Acknowledge SIO IRQ + _sio_control(2, 1, 0); +} + static DCB _sio_dcb = { "tty", 0x3, @@ -74,15 +129,12 @@ static DCB _sio_dcb = { 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); + _sio_control(1, 1, CR_RXEN|CR_TXEN|CR_RXIEN); close(0); close(1); @@ -90,6 +142,8 @@ void AddSIO(int baud) { DelDev(_sio_dcb.name); AddDev(&_sio_dcb); + Sio1Callback(_sio_tty_cb); + open(_sio_dcb.name, 2); open(_sio_dcb.name, 1); @@ -97,12 +151,17 @@ void AddSIO(int baud) { void DelSIO(void) { + Sio1Callback(NULL); + // Reset serial interface _sio_control(2, 0, 0); // Remove TTY device DelDev(_sio_dcb.name); + // Add dummy TTY device + AddDummyTty(); + } void WaitSIO(void) { @@ -134,4 +193,9 @@ void *Sio1Callback(void (*func)()) { return old_isr; -}
\ No newline at end of file +} + +int kbhit() +{ + return(_sio_key_pending>0); +} diff --git a/libpsn00b/psxspu/spuinit.s b/libpsn00b/psxspu/spuinit.s index d3a8e8d..42f302a 100644 --- a/libpsn00b/psxspu/spuinit.s +++ b/libpsn00b/psxspu/spuinit.s @@ -3,7 +3,7 @@ .include "hwregs_a.h" -.section .data +.section .text .global SpuInit diff --git a/libpsn00b/readme.txt b/libpsn00b/readme.txt index 43b120a..1e2e6d7 100644 --- a/libpsn00b/readme.txt +++ b/libpsn00b/readme.txt @@ -3,100 +3,108 @@ LibPSn00b, PSn00bSDK software libraries Licensed under Mozilla Public License -LibPSn00b make up the majority of PSn00bSDK as it provides the functions -necessary for developing software for the PSX. Most libraries, mainly the -GPU and GTE libraries are written mostly in assembly language. +LibPSn00b is a collection of libraries which make up the core backbone of +PSn00bSDK as it provides an essential software framework for developing +homebrew software for the PSX platform. Great majority of the libraries +are been written from scratch written in a mix of C and hand optimized +assembly language for best performance. -Brief library overview: +These libraries can only be compiled with a build of GCC that supports mipsel +as one of the supported targets, naturally as these libraries are intended +for the PSX hardware which uses a MIPS R3000 CPU supported by mipsel. +Compiler version shouldn't matter much and should build fine in 9.1.0, +though 7.4.0 is the most recommended version to use as it is the version +currently used for the majority of the development and testing of LibPSn00b. + + +Brief summary of libraries: libc - Standard C library. Contains only a small subset of the full - standard C library, mostly string and memory manipulation - functions. + standard C library such as string and memory manipulation + functions. Should include libgcc for special compiler specific + dependencies and prevents libc related linker hell. - psxgpu - GPU library for video and graphics control. Most of the - important functions are implemented. + psxgpu - GPU library for video and graphics control. Also includes + interrupt handling for various library subsystems. - psxgte - GTE library for GTE accelerated vector transformations. Most - important functions are implemented. + psxgte - GTE library for GTE accelerated vector transformations necessary + for high performance 3D graphics. - psxapi - Provides access to most of the BIOS functions calls of the - PSX BIOS. + psxapi - Provides access to various BIOS functions in the PSX BIOS. - psxetc - Provides some misc functions such as debug font. + psxetc - Provides some miscellaneous features such as debug font. - psxspu - SPU library. Basic functions such as hardware init, uploading - data to SPU RAM via DMA transfer and playing sound playback - are fully working but is currently lacking a number of - important functions, especially reverb. + psxspu - SPU library. Basic capabilities such as hardware init, + sample upload using DMA and playing samples are supported. + Lacks support for reverb and various sequenced music related + features. - Each library has its own readme file that contains its changelog, todo - list, credits and some additional details of the library. + Each library has its own readme file that contains a todo list, credits + and some additional details of the library. Changelog of all libraries are + compiled in the changelog.txt file. Compiling: - Compiling the LibPSn00b libraries requires GCC and binutils targetting + Compiling the LibPSn00b libraries requires GCC and binutils targeting mipsel-unknown-elf built with libgcc. The path to those binaries must be specified in your PATH environment variable and the binaries must be prefixed by the target architecture (ie. mipsel-unknown-elf-gcc). - Simply run the Makefile in this directory using make (or gmake if you're - in a BSD environment). The Makefile should parse though each library - directory and run the makefile in it. + Simply run the Makefile in this directory with make (or gmake if you're + working in a BSD environment). The Makefile should parse though each + library directory and run the makefile in it. Documentation: - Documentation of all the libraries are found in libn00bref.odf and it features - the same formatting as the official library documents. The document can be - exported in PDF format for easier viewing with a web browser or PDF viewer. + Documentation of all the libraries are found in libn00bref.odf and it + features the same formatting as the official library documents. It is + recommended to export it as a PDF document for easier viewing. Contributing: - Contributions are open for this project. Just obey the following rules - when making a contribution: + Contributions are open for this project. But it is recommended to at + least follow the following rules when contributing to prevent headaches. * If you add new functions to libpsn00b make sure you document them in - libn00bref.odf. Documentation using Doxygen is discouraged. - * This project desires functions that interact with hardware registers to - be written in assembly language. If you decide to write your functions - that interact with hardware registers in C make sure you define your - register pointers as volatile and they must work properly when compiled - with -O2 optimization. - * Functions must work flawlessly on both emulators and real hardware. - * Don't forget to put your user name in the readme file of the library - you've made a contribution on, and details of what you've changed in the - changelog. + libn00bref.odf. Documentation using Doxygen is not recommended. + + * Library functions can either be written in C or assembly language + whichever you prefer. Though it is not entirely mandatory but + recommended to write functions that directly interact with hardware + registers in assembly. + + * Functions must work on both emulators and real hardware. + + * Don't forget to put your name in the readme file of the library you've + made a contribution on and details of what you've changed in the + changelog.txt file. Annoyingmous is not tolerated in this project. + * New functions that are not originally in the official SDK must be marked - as original code in both the library headers and the libn00bref document. + as original code in both the library headers and the libn00bref document + to help differentiate from original functions and new additions. -Library to-do list: - - Since the PSn00bSDK project still a work in progress, essential libraries - for CD and controllers support are not yet created but are high priority. +LibPSn00b to-do list: - libc - Yet to include a complete C standard function + Because the PSn00bSDK project still a work in progress, a number of + essential libraries are considered but not yet developed. The following + lists a number of essential libraries not yet developed. - psxcd - CD library. Not much progress as getting the CD controller to - cooperate has been one heck of a force to be reckoned with. - Gave up with my repeated attempts with no success. Absolutely - huge props to anyone who can figure out how to use the CD - controller properly! -Lameguy64 - - psxpad - Pad/tap/gun library. No work has been done on it currently. - Supporting the Konami Justifier can be ignored as the way how - that lightgun works is pretty crude and likely going to be - awful to implement. Namco's Guncon is a lot simpler to - implement. - - psxpress - MDEC library. No work has been done on it currently. libpress - from the official libraries also contains functions for - encoding SPU compatible ADPCM data from raw PCM samples. - - Before implementing CD and controller support a better interrupt handling - scheme must be implemented as it would save a lot of trouble. Details - regarding this interrupt handler implementation can be found in psxgpu's - readme document.
\ No newline at end of file + psxcd - Full CD-ROM support library. + + psxpad - Pad/tap/gun library for better controller support. May support + PS2 controllers natively. Should provide functions for directly + controlling the controller/memory card interfaces to cater to + development of custom peripherals. + + psxmcrd - Better and faster memory card library that works alongside the + psxpad library. + + psxpress - MDEC and data decompression library. May use DEFLATE for + compressing MDEC data instead of Huffman as used in the + official libraries, which may yield better compression and + higher quality FMVs.
\ No newline at end of file diff --git a/tools/smxlink/main.cpp b/tools/smxlink/main.cpp index ec6f707..8072274 100644 --- a/tools/smxlink/main.cpp +++ b/tools/smxlink/main.cpp @@ -314,7 +314,7 @@ int main(int argc, const char* argv[]) { prim = (PRIM_ID*)priptr; - if( smxPrimitive->IntAttribute( "double", 0 ) ) + if( smxPrimitive->IntAttribute( "double" ) ) prim->nocull = true; if( ( strcasecmp( "F3", primType ) == 0 ) || |
