diff options
| author | Xavi Del Campo <xavi.dcr@tutanota.com> | 2020-01-31 10:32:23 +0100 |
|---|---|---|
| committer | Xavi Del Campo <xavi.dcr@tutanota.com> | 2020-01-31 10:32:23 +0100 |
| commit | 7c24e9a9b02b04dcaf9507acb94091ea70a2c02d (patch) | |
| tree | c28d0748652ad4b4222309e46e6cfc82c0906220 /libpsx | |
| parent | a2b7b6bb1cc2f4a3258b7b2dbc92399d151f864d (diff) | |
| download | psxsdk-7c24e9a9b02b04dcaf9507acb94091ea70a2c02d.tar.gz | |
Imported pristine psxsdk-20190410 from official repo
Diffstat (limited to 'libpsx')
60 files changed, 11366 insertions, 0 deletions
diff --git a/libpsx/Makefile b/libpsx/Makefile new file mode 100644 index 0000000..d905cb8 --- /dev/null +++ b/libpsx/Makefile @@ -0,0 +1,49 @@ +# Makefile for PSX SDK library + +include ../Makefile.cfg + +CFLAGS += -O0 + +# Never remove the line below! +CFLAGS += -D__IN_LIBPSX + +OBJS = $(patsubst src/%.c, out/%.o, $(wildcard src/*.c)) \ + $(patsubst src/libc/%.c, out/libc/%.o, $(wildcard src/libc/*.c)) \ + $(patsubst src/runexe/%.c, out/runexe/%.o, $(wildcard src/runexe/*.c)) \ + $(patsubst src/%.s, out/%.o, $(wildcard src/*.s)) \ + $(patsubst src/runexe/%.s, out/runexe/%.o, $(wildcard src/runexe/*.s)) + +all: libpsx.a start.o + +libpsx.a: $(OBJS) + $(AR) r libpsx.a $(OBJS) + +out/%.o: src/%.c + $(CC) $(CFLAGS) -c -o $@ $< + +out/libc/%.o: src/libc/%.c + $(CC) $(CFLAGS) -c -o $@ $< + +out/runexe/%.o: src/runexe/%.c + $(CC) $(CFLAGS) -c -o $@ $< + +out/%.o: src/%.s + $(CC) $(CFLAGS) -c -o $@ $< + +out/runexe/%.o: src/runexe/%.s + $(CC) $(CFLAGS) -c -o $@ $< + +start.o: src/start/start.s + $(CC) $(CFLAGS) -c -o $@ $< + +install: libpsx.a start.o + cp libpsx.a $(TOOLCHAIN_PREFIX)/lib + cp start.o $(TOOLCHAIN_PREFIX)/lib + cp -r include/* $(TOOLCHAIN_PREFIX)/include + +clean: + rm -f $(OBJS) + rm -f libpsx.a + rm -f start.o + +distclean: clean diff --git a/libpsx/include/bitstring.h b/libpsx/include/bitstring.h new file mode 100644 index 0000000..a9b4c32 --- /dev/null +++ b/libpsx/include/bitstring.h @@ -0,0 +1,78 @@ +/** + * PSXSDK + * + * bitstring.h + * + * Implementation of bitstring.h, a family of macros found in *BSD + * to manipulate bit strings + */ + +#ifndef _BITSTRING_H +#define _BITSTRING_H + +#include <stdlib.h> + +typedef unsigned char bitstr_t; + +#define bitstr_size(nbits) \ + ( (nbits + 7) >> 3 ) + +#define bit_alloc(nbits) \ + calloc( bitstr_size(nbits) , 1) + +#define bit_decl(name, nbits) \ + name[ bitstr_size(nbits) ] + +#define bit_clear(name, bit) \ + name[ bit >> 3 ] &= ~(1 << (bit & 7) ) + +#define bit_set(name, bit) \ + name[ bit >> 3] |= 1 << (bit & 7) + +#define bit_nclear(name, start, stop) \ + do{ \ + int _b__;\ + for(_b__ = start; _b__ <= stop; _b__++) \ + bit_clear(name, _b__);\ + }while(0) + +#define bit_nset(name, start, stop) \ + do{ \ + int _b__;\ + for(_b__ = start; _b__ <= stop; _b__++) \ + bit_set(name, _b__); \ + }while(0) + +#define bit_test(name, bit) \ + ( name[bit >> 3] & (1 << (bit & 7) ) ) + +#define bit_ffs(name, nbits, value) \ + do{\ + int _b__;\ + for(_b__ = 0; _b__ < nbits; _b__++) \ + {\ + printf("bb = %d\n", _b__);\ + if( bit_test(name, _b__) ) \ + {\ + *(value) = _b__; \ + break; \ + }\ + }\ + if( _b__ == nbits ) *(value) = -1;\ + }while(0) + +#define bit_ffc(name, nbits, value) \ + do{\ + int _b__;\ + for(_b__ = 0; _b__ < nbits; _b__++) \ + {\ + if( !bit_test(name, _b__) ) \ + {\ + *(value) = _b__; \ + break; \ + }\ + }\ + if( _b__ == nbits ) *(value) = -1;\ + }while(0) + +#endif diff --git a/libpsx/include/ctype.h b/libpsx/include/ctype.h new file mode 100644 index 0000000..209e175 --- /dev/null +++ b/libpsx/include/ctype.h @@ -0,0 +1,25 @@ +/* + * ctype.h + * + * PSXSDK + */ + +#ifndef _CTYPE_H +#define _CTYPE_H + +int isupper(int c); +int islower(int c); +int isdigit(int c); +int isxdigit(int c); +int isalpha(int c); +int isalnum(int c); +int isspace(int c); +int isprint(int c); +int isgraph(int c); +int iscntrl(int c); +int isblank(int c); +int toupper(int c); +int tolower(int c); + +#endif + diff --git a/libpsx/include/errno.h b/libpsx/include/errno.h new file mode 100644 index 0000000..cfaa8fd --- /dev/null +++ b/libpsx/include/errno.h @@ -0,0 +1,167 @@ +/* + * errno.h + * + * PSXSDK + */ + +#ifndef _ERRNO_H +#define _ERRNO_H + +// There is no real support for errno, this include exists +// mostly to make things compile + +/* + * Declarations from NetBSD's /usr/include/sys/errno.h + * BSD license + */ + +#ifndef __IN_LIBPSX +extern int errno; +#endif + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* Input/output error */ +#define ENXIO 6 /* Device not configured */ +#define E2BIG 7 /* Argument list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file descriptor */ +#define ECHILD 10 /* No child processes */ +#define EDEADLK 11 /* Resource deadlock avoided */ + /* 11 was EAGAIN */ +#define ENOMEM 12 /* Cannot allocate memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* Operation not supported by device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* Too many open files in system */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Inappropriate ioctl for device */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ + +/* math software */ +#define EDOM 33 /* Numerical argument out of domain */ +#define ERANGE 34 /* Result too large or too small */ + +/* non-blocking and interrupt i/o */ +#define EAGAIN 35 /* Resource temporarily unavailable */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define EINPROGRESS 36 /* Operation now in progress */ +#define EALREADY 37 /* Operation already in progress */ + +/* ipc/network software -- argument errors */ +#define ENOTSOCK 38 /* Socket operation on non-socket */ +#define EDESTADDRREQ 39 /* Destination address required */ +#define EMSGSIZE 40 /* Message too long */ +#define EPROTOTYPE 41 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 42 /* Protocol option not available */ +#define EPROTONOSUPPORT 43 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 44 /* Socket type not supported */ +#define EOPNOTSUPP 45 /* Operation not supported */ +#define EPFNOSUPPORT 46 /* Protocol family not supported */ +#define EAFNOSUPPORT 47 /* Address family not supported by protocol family */ +#define EADDRINUSE 48 /* Address already in use */ +#define EADDRNOTAVAIL 49 /* Can't assign requested address */ + +/* ipc/network software -- operational errors */ +#define ENETDOWN 50 /* Network is down */ +#define ENETUNREACH 51 /* Network is unreachable */ +#define ENETRESET 52 /* Network dropped connection on reset */ +#define ECONNABORTED 53 /* Software caused connection abort */ +#define ECONNRESET 54 /* Connection reset by peer */ +#define ENOBUFS 55 /* No buffer space available */ +#define EISCONN 56 /* Socket is already connected */ +#define ENOTCONN 57 /* Socket is not connected */ +#define ESHUTDOWN 58 /* Can't send after socket shutdown */ +#define ETOOMANYREFS 59 /* Too many references: can't splice */ +#define ETIMEDOUT 60 /* Operation timed out */ +#define ECONNREFUSED 61 /* Connection refused */ + +#define ELOOP 62 /* Too many levels of symbolic links */ +#define ENAMETOOLONG 63 /* File name too long */ + +/* should be rearranged */ +#define EHOSTDOWN 64 /* Host is down */ +#define EHOSTUNREACH 65 /* No route to host */ +#define ENOTEMPTY 66 /* Directory not empty */ + +/* quotas & mush */ +#define EPROCLIM 67 /* Too many processes */ +#define EUSERS 68 /* Too many users */ +#define EDQUOT 69 /* Disc quota exceeded */ + +/* Network File System */ +#define ESTALE 70 /* Stale NFS file handle */ +#define EREMOTE 71 /* Too many levels of remote in path */ +#define EBADRPC 72 /* RPC struct is bad */ +#define ERPCMISMATCH 73 /* RPC version wrong */ +#define EPROGUNAVAIL 74 /* RPC prog. not avail */ +#define EPROGMISMATCH 75 /* Program version wrong */ +#define EPROCUNAVAIL 76 /* Bad procedure for program */ + +#define ENOLCK 77 /* No locks available */ +#define ENOSYS 78 /* Function not implemented */ + +#define EFTYPE 79 /* Inappropriate file type or format */ +#define EAUTH 80 /* Authentication error */ +#define ENEEDAUTH 81 /* Need authenticator */ + +/* SystemV IPC */ +#define EIDRM 82 /* Identifier removed */ +#define ENOMSG 83 /* No message of desired type */ +#define EOVERFLOW 84 /* Value too large to be stored in data type */ + +/* Wide/multibyte-character handling, ISO/IEC 9899/AMD1:1995 */ +#define EILSEQ 85 /* Illegal byte sequence */ + +/* From IEEE Std 1003.1-2001 */ +/* Base, Realtime, Threads or Thread Priority Scheduling option errors */ +#define ENOTSUP 86 /* Not supported */ + +/* Realtime option errors */ +#define ECANCELED 87 /* Operation canceled */ + +/* Realtime, XSI STREAMS option errors */ +#define EBADMSG 88 /* Bad or Corrupt message */ + +/* XSI STREAMS option errors */ +#define ENODATA 89 /* No message available */ +#define ENOSR 90 /* No STREAM resources */ +#define ENOSTR 91 /* Not a STREAM */ +#define ETIME 92 /* STREAM ioctl timeout */ + +/* File system extended attribute errors */ +#define ENOATTR 93 /* Attribute not found */ + +/* Realtime, XSI STREAMS option errors */ +#define EMULTIHOP 94 /* Multihop attempted */ +#define ENOLINK 95 /* Link has been severed */ +#define EPROTO 96 /* Protocol error */ + +#define ELAST 96 /* Must equal largest errno */ + +#ifdef _KERNEL +/* pseudo-errors returned inside kernel to modify return to process */ +#define EJUSTRETURN -2 /* don't modify regs, just return */ +#define ERESTART -3 /* restart syscall */ +#define EPASSTHROUGH -4 /* ioctl not handled by this layer */ +#define EDUPFD -5 /* Dup given fd */ +#define EMOVEFD -6 /* Move given fd */ +#endif + +#endif + diff --git a/libpsx/include/fcntl.h b/libpsx/include/fcntl.h new file mode 100644 index 0000000..d51faa1 --- /dev/null +++ b/libpsx/include/fcntl.h @@ -0,0 +1,72 @@ +/* + * fcntl.h + * + * File control + * + * PSXSDK + */ + +#ifndef _FCNTL_H +#define _FCNTL_H + +#define O_RDONLY 1 +#define O_WRONLY 2 +#define O_NONBLOCK 4 +/** Read locked, not shared. */ +#define O_RDLOCK 16 +/** Write locked, not shared. */ +#define O_WRLOCK 32 +#define O_RDWR (O_RDONLY | O_WRONLY) +#define O_APPEND 256 +#define O_CREAT 512 +#define O_TRUNC 1024 +/** Obviously, O_EXCL has no effect in the PSXSDK. */ +#define O_EXCL 0 + +/** The following are PlayStation BIOS extensions. */ + +/** Set to scanning type. Real purpose unknown. */ +#define O_SCAN 4096 +/** Setup for remote command entry. Real purpose unknown. */ +#define O_RCOM 8192 +/** No buffering and console interrupt */ +#define O_NOBUF 16384 +/** Asynchronous I/O mode */ +#define O_NOWAIT 32768 +/** Asynchronous I/O mode, alias */ +#define O_ASYNC O_NOWAIT + +/** + * These are standard C library file I/O functions provided by the PSX BIOS. + * Filenames have to be specified in this way: + * [device]:[filename] + * + * Where device specifies the device the file is on: + * "tty:" Console + * "cdrom:" CD-ROM + * "buXX:" Memory cards + * + * When using cdrom: as device, append file version (;1) to filename + * Example: cdrom:README.TXT;1 + * + * Subdirectory paths have to be specified with backslashes (\), + * like MS-DOS. Read and write operations can be carried only in blocks. + * Blocks are 2048 bytes for the CD-ROM device, and 128 bytes for memory cards. + */ + +// The third argument (file mode) makes no sense in PSXSDK, +// and will be ignored. + +#define open(filename, flags, ...) \ + open(filename, flags) + +/** In previous versions, the second argument for open() + was named `mode'. That was incorrect; now it is correctly named `flags'. +*/ + +int open(const char *filename, int flags); +int read(int d, void *buf, int nbytes); +int close(int d); +int lseek(int fildes, int offset, int whence); + +#endif diff --git a/libpsx/include/inttypes.h b/libpsx/include/inttypes.h new file mode 100644 index 0000000..831c6ed --- /dev/null +++ b/libpsx/include/inttypes.h @@ -0,0 +1,68 @@ +/* inttypes.h */ + +#ifndef _INTTYPES_H +#define _INTTYPES_H + +#include <stdint.h> + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +typedef unsigned char uint_least8_t; +typedef unsigned short uint_least16_t; +typedef unsigned int uint_least32_t; +typedef unsigned long long uint_least64_t; + +typedef unsigned char uint_fast8_t; +typedef unsigned short uint_fast16_t; +typedef unsigned int uint_fast32_t; +typedef unsigned long long uint_fast64_t; + +typedef unsigned long long uintmax_t; +typedef unsigned int uintptr_t; + +typedef signed char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int64_t; + +typedef signed char int_least8_t; +typedef short int_least16_t; +typedef int int_least32_t; +typedef long long int_least64_t; + +typedef char int_fast8_t; +typedef short int_fast16_t; +typedef int int_fast32_t; +typedef long long int_fast64_t; + +typedef long long intmax_t; + +typedef long intptr_t; + +#define PRIu8 "hhu" +#define PRIu16 "hu" +#define PRIu32 "u" +#define PRIu64 "llu" + +#define PRIs8 "hhd" +#define PRIs16 "hd" +#define PRIs32 "d" +#define PRIs64 "lld" + +#define PRIuLEAST8 "hhu" +#define PRIuLEAST16 "hu" +#define PRIuLEAST32 "u" +#define PRIuLEAST64 "llu" + +#define PRIuFAST8 "hhu" +#define PRIuFAST16 "hu" +#define PRIuFAST32 "u" +#define PRIuFAST64 "llu" + +#define PRIuMAX "llu" +#define PRIuPTR "lu" + +#endif diff --git a/libpsx/include/memcard.h b/libpsx/include/memcard.h new file mode 100644 index 0000000..11b443f --- /dev/null +++ b/libpsx/include/memcard.h @@ -0,0 +1,74 @@ +#ifndef _PSXSDK_MEMCARD_H
+#define _PSXSDK_MEMCARD_H
+
+/*Card connection related*/
+enum memcard_status
+{
+ /** Memory card is connected */
+ MEMCARD_CONNECTED = 1,
+ /** Memory card is formatted */
+ MEMCARD_FORMATTED = 2
+};
+
+/**
+ * Results of memory card operations
+ */
+
+enum memcard_operation_result
+{
+ /** Operation was successful - good result */
+ MEMCARD_RW_GOOD = 0x47,
+ /** Bad checksum - bad result */
+ MEMCARD_RW_BADCHECK = 0x4E,
+ /** Bad sector - bad result */
+ MEMCARD_RW_BADSECTOR = 0xFF
+};
+
+/*Card block type*/
+/*#define BLOCK_FORMATTED 0x000000A0
+#define BLOCK_INITIAL 0x00000051
+#define BLOCK_MIDLINK 0x00000052
+#define BLOCK_ENDLINK 0x00000053
+#define BLOCK_DEL_INITIAL 0x000000A1
+#define BLOCK_DEL_MIDLINK 0x000000A2
+#define BLOCK_DEL_ENDLINK 0x000000A3*/
+
+/*128 byte card directory*/
+/*typedef struct{
+ long BlockType;
+ long FileSize;
+ short NextBlock;
+ char FileName[20];
+ char Reserved[97];
+ char XorChecksum;
+}CARDDIR;*/
+
+/**
+ * Reads a 128-byte sector from a memory card.
+ * @param card_slot Memory card slot (0 = first slot, 1 = second slot)
+ * @param sector Sector number (0-511)
+ * @param buffer Pointer to data buffer in which data will be stored
+ * @return Result of operation (possible values in memcard_operation_result enum)
+ */
+
+unsigned char McReadSector(int card_slot, int sector, unsigned char *buffer);
+
+/**
+ * Writes a 128-byte sector to a memory card.
+ * @param card_slot Memory card slot (0 = first slot, 1 = second slot)
+ * @param sector Sector number (0-511)
+ * @param buffer Pointer to data buffer containing data to write
+ * @return Result of operation (possible values in memcard_operation_result enum)
+ */
+
+unsigned char McWriteSector(int card_slot, int sector, unsigned char *buffer);
+
+/**
+ * Get memory card status
+ * @param card_slot Memory card slot (0 = first slot, 1 = second slot)
+ * @return Bitmask for current memory card status (flags in memcard_status enum)
+ */
+
+unsigned int McGetStatus(int card_slot);
+
+#endif
diff --git a/libpsx/include/psx.h b/libpsx/include/psx.h new file mode 100644 index 0000000..881291b --- /dev/null +++ b/libpsx/include/psx.h @@ -0,0 +1,406 @@ +/* + * PSXSDK Library include + */ + +#ifndef _PSX_H +#define _PSX_H + +#include <stdarg.h> + +#ifndef true +#define true 1 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef false +#define false 0 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define IPENDING *((volatile unsigned int*)0x1f801070) +#define IMASK *((volatile unsigned int*)0x1f801074) +#define RCNT_COUNT(x) *((volatile unsigned int*)(0x1f801100 + (x<<4))) +#define RCNT_MODE(x) *((volatile unsigned int*)(0x1f801104 + (x<<4))) +#define RCNT_TARGET(x) *((volatile unsigned int*)(0x1f801108 + (x<<4))) + +/** + * PSXSDK version information in hexadecimal format. + * + * An explanation of version numbers and how they relate to + * releases: + * + PSXSDK_VERSION undefined + * - PSXSDK 0.1 + * + 0.1.99 (0x0199) + * - From PSXSDK releases 2012-03-03 up to 2013-01-14. + * + 0.2.99 (0x0299) + * - PSXSDK 2013-05-14 + * + 0.3.99 (0x0399) + * - PSXSDK 2013-11-09 + * + 0.4.99 (0x0499) + * - PSXSDK 2014-04-22 + * + 0.5.99 (0x0599) + * - PSXSDK 2015-07-29 + * + 0.6.00 (0x0600) + * - PSXSDK 2016-06-03 + * + 0.6.1 (0x0601) + * - PSXSDK 2018-01-10 + * + 0.6.2 (0x0602) + * - PSXSDK 2019-04-10 + */ + +#define PSXSDK_VERSION 0x0602 + +/** + * PSXSDK version information in string format + */ + +#define PSXSDK_VERSION_STRING "0.6.2" + +/** + * PSXSDK version date (BCD YYYY-MM-DD) + */ + +#define PSXSDK_VERSION_DATE 0x20190410 + + +/* + * Include some GCC builtin includes + */ + +#ifndef _PSXSDK_WRAPPER + +#include <psxbios.h> + +#endif + +#include <psxgpu.h> +#include <memcard.h> + +#include <psxpad.h> +#include <psxspu.h> +#include <psxcdrom.h> +#include <psxsio.h> +//#include <adpcm.h> +#include <psxgte.h> + +/** + * Scratch pad - unused data cache, that can be used as "fast RAM" + */ + +extern unsigned char __scratchpad[1024]; + +/** + * Coprocessor 0 register numbers + */ + +enum cop0_register_numbers +{ + /** Contains the last invalid program address which caused a trap. + + It is set by address errors of all kinds. */ + COP0_BADVADDR = 8, + /** CPU mode flags (status register) */ + COP0_SR = 12, + /** Describes the most recently recognized exception. */ + COP0_CAUSE = 13, + /** Return address from trap */ + COP0_EPC = 14, + /** COP0 type and revision level */ + COP0_PRID = 15, +}; + +/** + * Root counter specifications + */ + +enum psx_rcnt_specs +{ + /** Pixel clock*/ + RCntCNT0 = 0xf2000000, + /** Horizontal sync*/ + RCntCNT1 = 0xf2000001, + /** System clock / 8 */ + RCntCNT2 = 0xf2000002, + /** VSync (VBlank) */ + RCntCNT3 = 0xf2000003, +}; + +/** + * Root counter modes + */ + +enum psx_rcnt_modes +{ + /** Interrupt mode */ + RCntIntr = 0x1000, + /** Ignore target and count to 65535 (hex: 0xFFFF) */ + RCntNotar = 0x0100, + /** Timer stop mode */ + RCntStop = 0x0010, + /** System Clock mode */ + RCntSC = 0x0001, +}; + +struct psx_info +{ + struct kernel + { + const char *version; // Kernel version + int year; // Kernel year + int month; // Kernel month + int day; // Kernel day + }kernel; + + struct system + { + int memory; // RAM memory size + }system; +}; + +/** + * Initialize library + */ + +void PSX_Init(void); + +/** + * Flags for PSX_Init. + */ + +enum psx_init_flags +{ + /** PSX_INIT_CD - Initialize CDROM filesystem */ + PSX_INIT_CD = 1, + /** PSX_INIT_SAVESTATE - Save BIOS state before initializing the library */ + PSX_INIT_SAVESTATE = 2, + /** PSX_INIT_NOBIOS - Remove control from the BIOS and let PSXSDK be in complete control */ + PSX_INIT_NOBIOS = 4, +}; + +/** + * Deinitialize library + */ + +void PSX_DeInit(void); + +/** + * Initialize library (extended version) + * + * flags contains a bitmask specifying which flags are enabled + * + * PSX_Init() is the same as PSX_InitEx(PSX_INIT_CD) + * @param flags Flag bitmask (flags are to be OR'd) + */ + +void PSX_InitEx(unsigned int flags); + +/** + * Reads the status of the buttons of the two joypads. + * + * Takes two pointers for 16-bit bitmasks, one for the first player's joypad, + * and one for the second one. Their bits are updated to show which buttons were pressed. + * + * This function only supplies basic functionality, adequate for a normal digital pad. + * + * If more advanced functionality is desired, use PSX_PollPad() instead of this function. + * @attention Note that some joypads, like the official ones from Sony, do not like to be polled more than + * once every 1/60th of a second and if this limitation is not considered the data + * they return is undefined. Other joypads do not have this limitation but in any case err on the safe side. + * @param padbuf Pointer to 16-bit variable where bitmask for pad #1 will be stored. + * If NULL is passed, this argument is ignored. + * @param padbuf2 Pointer to 16-bit variable where bitmask for pad #2 will be stored + * If NULL is passed, this argument is ignored. + */ +void PSX_ReadPad(unsigned short *padbuf, unsigned short *padbuf2); + +/** + * Polls a joypad for information. + * @attention Note that some joypads, like the official ones from Sony, do not like to be polled more than + * once every 1/60th of a second and if this limitation is not considered the data + * they return is undefined. Other joypads do not have this limitation but in any case err on the safe side. + * @param pad_num Number of the pad to poll (0 = pad #1, 1 = pad #2, etc.) + * @param pad_state Pointer to a psx_pad_state structure in which to store information for the pad. + */ + +void PSX_PollPad(int pad_num, psx_pad_state *pad_state); + +/** + * Takes a pointer to a struct psx_info structure, and fills it + * with information about the PlayStation on which the program is running. + * PS-OS kernel build date and version are reported among other things. + * @param info Pointer to struct psx_info structure which will be filled. + */ +void PSX_GetSysInfo(struct psx_info *info); + +/** + * Gets Coprocessor 0 status register + * @return Value of Coprocessor 0 status register + */ + +unsigned int get_cop0_status(void); + +/** + * Sets Coprocessor 0 status register + * @param sreg New value of Coprocessor 0 status register + * @return [[ check: maybe this is a void function ]] + */ + +unsigned int set_cop0_status(unsigned int sreg); + +/** + * Gets the contents of the program counter when the + * last exception happened. + * @return Value of the program counter at the time of the last exception + */ + +unsigned int get_cop0_epc(void); + +/** + * Get value of specified Coprocessor 0 register + * @param register_num Number of Coprocessor 0 register whose value must be retrieved + * @return Value of specified Coprocessor 0 register + */ + +unsigned int get_cop0_register(unsigned char register_num); + +/** + * Set value of specified Coprocessor 0 register + * @param register_num Number of Coprocessor 0 register whose value must be set + * @param value New value of specified Coprocessor 0 register + */ + +void set_cop0_register(unsigned char register_num, unsigned int value); + +/** + * Get value of the specified (data) register of a specified coprocessor + * @param cop_num Coprocessor number + * @param register_num Number of coprocessor register whose value must be retrieved + * @return Value of specified coprocessor register + */ + +unsigned int get_cop_register(unsigned char cop_num, + unsigned char register_num); + + +/** + * Get value of the specified control register of a specified coprocessor + * @param cop_num Coprocessor number + * @param register_num Number of coprocessor register whose value must be retrieved + * @return Value of specified coprocessor register + */ + +unsigned int get_cop_ctrl_register(unsigned char cop_num, + unsigned char register_num); + +/** + * Set value of the specified (data) register of a specified coprocessor + * @param cop_num Coprocessor number + * @param register_num Number of Coprocessor 0 register whose value must be set + * @param value New value of specified Coprocessor 0 register + */ + + void set_cop_register(unsigned char cop_num, + unsigned char register_num, unsigned int value); + +/** + * Set value of the specified control register of a specified coprocessor + * @param cop_num Coprocessor number + * @param register_num Number of Coprocessor 0 register whose value must be set + * @param value New value of specified Coprocessor 0 register + */ + + void set_cop_ctrl_register(unsigned char cop_num, + unsigned char register_num, unsigned int value); + +/** + * Make the specified coprocessor run the specified instruction + * @param operation Operation number for the instruction + */ + +void run_cop_instruction(unsigned char cop_num, + unsigned int operation); + +// Root counter functions + +/** + * Set root counter (documentation TO DO) + * @param spec Spec + * @param target Target + * @param mode mode + */ + +int SetRCnt(int spec, unsigned short target, unsigned int mode); + +/** + * Get root counter (documentation TO DO) + * @param spec Spec + * @return TO DO + */ + +int GetRCnt(int spec); + +/** + * Start root counter (documentation TO DO) + * @param spec Spec + * @return TO DO + */ + +int StartRCnt(int spec); + +/** + * Stop root counter (documentation TO DO) + * @param spec Spec + * @return TO DO + */ + +int StopRCnt(int spec); + +/** + * Restores BIOS state to the one prior the initialization of the library. + * This function can only be used if PSX_InitEx() was called with the + * PSX_INIT_SAVESTATE flag. + * It is usually called by PSX_DeInit() automatically, so unless + * you know what you are doing, you do not need to call it yourself. + * @return 1 on success, 0 on failure, such as the fact that PSX_InitEx() wasn't called + * with the PSX_INIT_SAVESTATE flag. + */ + +int PSX_RestoreBiosState(void); + +/** + * Gets the bitmask for the flags passed to PSX_InitEx() + * @return Flag bitmask + */ + +unsigned int PSX_GetInitFlags(void); + +/** + * Sets an handler function for the VBlank interrupt. + * Used for simple, inaccurate timing - the handler function gets called 60 times a second + * in NTSC video mode and 50 times a second in PAL video mode. + * + * While most games use the VBlank interrupt for timing as they don't require high precision and + * have mechanisms to keep up with the different speed in PAL or NTSC video mode, for precise + * timing VBlank is inadequate. It is better to look at root counters if you desire precision. + * + * If there is already a VBlank handler set, this function replaces the current handler with the specified one. + * @param h Pointer to (new) VBlank handler function + */ + +void SetVBlankHandler(void (*h)()); + +/** + * Removes a previously set VBlank handler. + * + * If SetVBlankHandler() was not called before, calling this function has no effect. + */ + +void RemoveVBlankHandler(void); + +#endif diff --git a/libpsx/include/psxbios.h b/libpsx/include/psxbios.h new file mode 100644 index 0000000..9275393 --- /dev/null +++ b/libpsx/include/psxbios.h @@ -0,0 +1,215 @@ +/* + * PSXSDK: Bios functions + */ + +#ifndef _PSXBIOS_H +#define _PSXBIOS_H + +/* Joypad functions */ + +extern void PAD_init(unsigned long mode, unsigned long *pad_buf); +extern int PAD_dr(void); + +/* ROM information functions */ + +/** + * Returns PSX kernel date. + * @return Kernel date n 0xYYYYMMDD BCD format. + */ + +unsigned long GetKernelDate(void); + +/** + * Returns a pointer to a zero-terminated + * string which contains the kernel ROM version. + * @return Pointer to a zero-terminated string which contains the kernel ROM version. + */ + +const char *GetKernelRomVersion(void); + +/** + * Returns a pointer to a zero-terminated + * string which contains the system ROM version. + * @return Zero-terminated string which contains the system ROM version. + */ + +const char *GetSystemRomVersion(void); + +/** + * GetRamSize() should return size of RAM in bytes. + * It doesn't seem to work most times. On SCPH1001, it returns 0. + * On SCPH1000, it returns 2 (which is the number of megabytes of RAM + * the PSX has.) + * @return Size of RAM in bytes. + */ + +unsigned int GetRamSize(void); + +/* Interrupt/Exception functions */ + +/*void Exception();*/ + +/** + * Enters a critical section. + */ + +void EnterCriticalSection(void); + +/** + * Exits a critical section. + */ + +void ExitCriticalSection(void); + +void SysEnqIntRP(int index, unsigned int *buf); +void SysDeqIntRP(int index, unsigned int *buf); + +void ResetEntryInt(void); + + +/** + * Directory entry + */ +struct DIRENTRY +{ + /** Filename */ + char name[20]; + /** Attributes */ + unsigned int attr; + /** File size in bytes */ + int size; + /** Pointer to next file entry */ + struct DIRENTRY *next; + /** System reserved */ + unsigned char system[8]; +}; + +/** + * Gets information about the first file which + * matches the pattern. ? and * wildcards can be used. + * Characters after * are ignored. + * @param name File name string + * @param dirent Pointer to a struct DIRENTRY object. + * @return dirent on success, NULL on failure. + */ + +struct DIRENTRY *firstfile(const char *name, struct DIRENTRY *dirent); + +/** + * Finds a file with the same conditions as the previous call to firstfile(). + * If a corresponding file is found, file information is stored + * to the structure pointed to by dir. + * + * @param dir Pointer to a struct DIRENTRY object. + * @return dir on success, NULL on failure. + */ + +struct DIRENTRY *nextfile(struct DIRENTRY *dir); + +/** + * Gets the file size of the file named "name". + * It is actually just a wrapper around firstfile. + * It rounds the file size to the block size (2048). + * @param name FIle name string + * @return File size in bytes, rounded. + */ + +int get_file_size(const char *name); + +/** + * This function is like get_file_size() but doesn't round + * the file size to the block size. + * @param name File name string + * @return File size in bytes, unrounded. + */ + +int get_real_file_size(const char *name); + +void InitHeap(void *block , int size); +void FlushCache(void); + +void SetRCntHandler(void (*callback)(), int spec, unsigned short target); +void RemoveRCntHandler(int spec); + +/** + * Opens an event, and returns its identifier + * Must be executed in a critical section + * @param desc Numerical cause descriptor + * @param spec Numerical event type + * @param mode Numerical mode + * @param func Function pointer to callback function + * @return Numerical identifier for the event opened + */ + +int OpenEvent( + int desc, // Cause descriptor + int spec, // Event type + int mode, // Mode + int *(*func)(void) // Pointer to callback function +); + +/** + * Enables an event by its identifier returned by OpenEvent() + * @param event Numerical event identifier + * @return ??? + */ + +int EnableEvent(unsigned int event); + +/** + * Closes an event by its identifier + * @param event Numerical event identifier + * @return ??? + */ + +int CloseEvent(unsigned int event); + +/** + * Disables an event by its identifier + * @param event Numerical event identifier + * @return ??? + */ + +int DisableEvent(unsigned int event); + +/** + * Generates an event. This must be executed in a critical section. + * If the event to deliver is set to generate an interrupt, the handler function is called. + * @param ev1 Numerical cause descriptor + * @param ev2 Numerical event class + * @return ??? + */ + +int DeliverEvent(unsigned int ev1, // Cause descriptor + int ev2); // Event class + +/** + * Checks if the event specified by its identifier has occured + * @param event Numerical event identifier + * @return 1 if the event has occured, 0 if it has not + */ + +int TestEvent(unsigned int event); + +/** + * Waits until the event specified by identifier occurs. + * @param event Numerical event identifier + * @return 1 on success, 0 on failure. + */ + +int WaitEvent(unsigned int event); + +/** + * Replaces the executable image in memory with the one + * contained in another executable file in PSX-EXE format. + * WARNING: Does not work right now. + * + * Most likely you want PSX_RunExe() + * @param name Path name of PSX-EXE executable + * @param argc Number of arguments + * @param argv Pointer to an array of string pointers for each argument + */ + +void LoadExec(char *name, int argc, char **argv); + +#endif diff --git a/libpsx/include/psxcdrom.h b/libpsx/include/psxcdrom.h new file mode 100644 index 0000000..2f18e68 --- /dev/null +++ b/libpsx/include/psxcdrom.h @@ -0,0 +1,82 @@ +#ifndef _PSXCDROM_H +#define _PSXCDROM_H + +#define CDSTATUS_PLAY 0x80 +#define CDSTATUS_SEEK 0x40 +#define CDSTATUS_SHELLOPEN 0x10 + +// Command names + +enum +{ + CdlSync = 0, + CdlNop = 1, CdlGetstat = 1, + CdlSetloc = 2, + CdlPlay = 3, + CdlForward = 4, + CdlBackward = 5, + CdlReadN = 6, + CdlStandby = 7, + CdlStop = 8, + CdlPause = 9, + CdlInit = 10, + CdlMute = 11, + CdlDemute = 12, + CdlSetfilter = 13, + CdlSetmode = 14, + CdlSetparam = 15, + CdlGetlocL = 16, + CdlGetlocP = 17, + CdlCmd18 = 18, + CdlGetTN = 19, + CdlGetTD = 20, + CdlSeekL = 21, + CdlSeekP = 22, + CdlCmd23 = 23, + CdlCmd24 = 24, + CdlTest = 25, + CdlID = 26, + CdlReadS = 27, + CdlReset = 28, + CdlCmd29 = 29, + CdlReadTOC = 30 +}; + +/* + * Send a low-level CDROM command + * cmd = command number + * num = number of arguments + * ... = arguments + */ + +void CdSendCommand(int cmd, int num, ...); + +/** + * Reads the results of a low-level CDROM command + * + * @param out Pointer to array of chars where the output will be stored + * @param max Maximum number of bytes to store + * + * Return value: number of results. + */ + +int CdReadResults(unsigned char *out, int max); + +/** + * Gets CDROM drive status + * @return CDROM drive status bitmask + */ + +int CdGetStatus(void); + +/** + * Play an Audio CD track + * @return 1 on success, 0 on failure + */ + +int CdPlayTrack(unsigned int track); + +unsigned char CdRamRead(unsigned short addr); + + +#endif diff --git a/libpsx/include/psxgpu.h b/libpsx/include/psxgpu.h new file mode 100644 index 0000000..373b2d6 --- /dev/null +++ b/libpsx/include/psxgpu.h @@ -0,0 +1,1142 @@ +#ifndef _PSXGPU_H +#define _PSXGPU_H + +#define GPU_DATA_PORT_ADDR 0x1f801810 +#define GPU_CONTROL_PORT_ADDR 0x1f801814 +#define GPU_DATA_PORT *((volatile unsigned int*)GPU_DATA_PORT_ADDR) +#define GPU_CONTROL_PORT *((volatile unsigned int*)GPU_CONTROL_PORT_ADDR) + +#define DPCR *((volatile unsigned int*)0x1f8010f0) +#define D2_MADR *((volatile unsigned int*)0x1f8010a0) +#define D2_BCR *((volatile unsigned int*)0x1f8010a4) +#define D2_CHCR *((volatile unsigned int*)0x1f8010a8) + +#define get_clutid(cx, cy) (((cx&0x3ff)>>4)|((cy&0x1ff)<<6)) + +/** + * Initializes the GPU. Same as GsInitEx(0) + * + * The display is left disabled. + * You can enable it with GsEnableDisplay() or more preferably with GsSetVideoMode() + */ + +void GsInit(void); + +/** + * Initializes the GPU. + * + * The display is left disabled. + * You can enable it with GsEnableDisplay() or more preferably with GsSetVideoMode() + * @param flags Flag bitmask + */ + +void GsInitEx(unsigned int flags); + +/** + * Resets the GPU + */ + +void GsReset(void); + +/** + * Enables the display (i.e. generation of video output). + * + * Unless you are doing low-level GPU programming, you don't need to call this function; + * the display is enabled automatically by GsSetVideoMode(). + * @param enable If TRUE (>=1) the display will be enabled, if FALSE (== 0) it will be disabled + */ + +void GsEnableDisplay(int enable); + +/** + * Sets a video mode and enables the display. It does so in a quicker way + * than GsSetVideoModeEx(), which wants more arguments but offers greater control + * @param width Width + + 640, 384, 320 and 256 are supported by the PlayStation hardware. + * @param height Height + + 480 and 240 are supported by the PlayStation hardware. + * You probably want to use GsSetVideoModeEx() if you set + * 480 here, because this function doesn't enable interlacing. + * @param video_mode Video mode + + VMODE_NTSC for NTSC, VMODE_PAL for PAL + * @return 1 on success, 0 on failure (such as unavailable video mode) + */ + +int GsSetVideoMode(int width, int height, int video_mode); + +/** + * Works like GsSetVideoMode() but offers more control. + * Interlaced, 24-bit RGB, and "reverse" flags can be specified. + * @param width Width + + 640, 384, 320 and 256 are supported by the PlayStation hardware. + * @param height Height + + 480 and 240 are supported by the PlayStation hardware. + * @param video_mode Video mode + + VMODE_NTSC for NTSC, VMODE_PAL for PAL + * @param rgb24 24-bit RGB mode + + If TRUE (!=0) enables the very rarely used 24-bit color mode. Unless you're very creative, don't enable this. + * @param inter Interlacing + + If TRUE (!=0) enables interlacing. If you set the height paramater to 480, and you want to display your program on + a real television screen, you must enable this. + * @param reverse Reverse?? + + The function of this is not really known. Stay safe and set this to FALSE (0). + * @return 1 on success, 0 on failure (such as unavailable video mode) + */ + +int GsSetVideoModeEx(int width, int height, int video_mode, int rgb24, int inter, int reverse); + +/** + * Assigns the internal pointer to the primitive list to the desired one, + * and resets the linked list position counter. + * The memory address specified by your pointer has to have enough space free to contain all + * the packets which you want to send. + * @param listptr Pointer to primitive list + */ + +void GsSetList(unsigned int *listptr); + +/** + * Assigns the internal pointer to the primitive list to the desired one, + * an sets the linked list position counter to the specified value. + * The memory address specified by your pointer has to have enough space free to contain all + * the packets which you want to send, and you must ensure that the specified position + * is not out of bounds. + * @param listptr Pointer to primitive list + * @param listpos List position + */ + +void GsSetListEx(unsigned int *listptr, unsigned int listpos); + +/** + * Draws the primitive list. + * + * This also has the effect of resetting the current drawing list position. + */ + +void GsDrawList(void); + +/** + * Draws the primitive list using port I/O access. + * + * GsDrawList() uses DMA to transfer the primitive data in the linked list to the GPU. + * + * This function which is of main interest to low-level programmers, uses GPU port I/O access instead, + * and it is slower (as reads and writes must be done by the main CPU), but works in all situations, + * even when you can't get DMA working. + * + * This function due to its nature is blocking, and always waits for completion. + */ + +void GsDrawListPIO(void); + +/** + * Makes non-blocking gpu functions like GsDrawList() + * wait for completion. Removes the need to use GsIsDrawing()/GsIsWorking() + */ + +void GsSetAutoWait(void); + +/** Monochrome 3 point polygon */ + +typedef struct +{ + /** Red color component (0-255) */ + unsigned char r; + /** Green color component (0-255) */ + unsigned char g; + /** Blue color component (0-255) */ + unsigned char b; + /** X Coordinates for vertexes */ + short x[3]; + /** Y Coordinates for vertexes */ + short y[3]; + /** Attribute bitmask */ + unsigned int attribute; +}GsPoly3; + +/** Monochrome 4 point polygon */ + +typedef struct +{ + /** Red color component (0-255) */ + unsigned char r; + /** Green color component (0-255) */ + unsigned char g; + /** Blue color component (0-255) */ + unsigned char b; + /** X Coordinates for vertexes */ + short x[4]; + /** Y Coordinates for vertexes */ + short y[4]; + /** Attribute */ + unsigned int attribute; +}GsPoly4; + +/** Textured 3 point polygon */ + +typedef struct +{ + /** Red color component (0-255) */ + unsigned char r; + /** Green color component (0-255) */ + unsigned char g; + /** Blue color component (0-255) */ + unsigned char b; + /** X Coordinates for vertexes */ + short x[3]; + /** Y Coordinates for vertexes */ + short y[3]; + /** X Texture offsets for vertexes */ + unsigned char u[3]; + /** Y Texture offset for vertexes */ + unsigned char v[3]; + /** CLUT X coordinate */ + short cx; + /** CLUT Y coordinate */ + short cy; + /** Attribute */ + unsigned int attribute; + /** Texture page */ + unsigned char tpage; +}GsTPoly3; + +/** Textured 4 point polygon */ + +typedef struct +{ + /** X Coordinates for vertexes */ + short x[4]; + /** Y Coordinates for vertexes */ + short y[4]; + /** Red color component (0-255) */ + unsigned char r; + /** Green color component (0-255) */ + unsigned char g; + /** Blue color component (0-255) */ + unsigned char b; + /** CLUT X coordinate */ + short cx; + /** CLUT Y coordinate */ + short cy; + /** Texture page */ + unsigned char tpage; + /** Horizontal texture offset */ + unsigned char u[4]; + /** Vertical texture offset */ + unsigned char v[4]; + /** Attribute */ + unsigned int attribute; +}GsTPoly4; + +/** Graduated 3 point polygon */ + +typedef struct +{ + /** Red color components (0-255) */ + unsigned char r[3]; + /** Green color components (0-255) */ + unsigned char g[3]; + /** Blue color components (0-255) */ + unsigned char b[3]; + /** X Coordinates for vertexes */ + short x[3]; + /** Y Coordinates for vertexes */ + short y[3]; + /** Attribute */ + unsigned int attribute; +}GsGPoly3; + +/** Graduated 4 point polygon */ + +typedef struct +{ + /** Red color components (0-255) */ + unsigned char r[4]; + /** Green color components (0-255) */ + unsigned char g[4]; + /** Blue color components (0-255) */ + unsigned char b[4]; + /** X Coordinates for vertexes */ + short x[4]; + /** Y Coordinates for vertexes */ + short y[4]; + /** Attribute */ + unsigned int attribute; +}GsGPoly4; + +/** Graduated textured 3 point polygon */ + +typedef struct +{ + /** Red color components (0-255) */ + unsigned char r[3]; + /** Green color components (0-255) */ + unsigned char g[3]; + /** Blue color components (0-255) */ + unsigned char b[3]; + /** X Coordinates for vertexes */ + short x[3]; + /** Y Coordinates for vertexes */ + short y[3]; + /** CLUT X coordinate */ + short cx; + /** CLUT Y coordinate */ + short cy; + /** Texture page */ + unsigned char tpage; + /** Horizontal texture offset */ + unsigned char u[3]; + /** Vertical texture offset */ + unsigned char v[3]; + /** Attribute */ + unsigned int attribute; +}GsGTPoly3; + +/** Graduated textured 4 point polygon */ + +typedef struct +{ + /** Red color components (0-255) */ + unsigned char r[4]; + /** Green color components (0-255) */ + unsigned char g[4]; + /** Blue color components (0-255) */ + unsigned char b[4]; + /** X Coordinates for vertexes */ + short x[4]; + /** Y Coordinates for vertexes */ + short y[4]; + /** CLUT X coordinate */ + short cx; + /** CLUT Y coordinate */ + short cy; + /** Texture page */ + unsigned char tpage; + /** Horizontal texture offset */ + unsigned char u[4]; + /** Vertical texture offset */ + unsigned char v[4]; + /** Attribute */ + unsigned int attribute; +}GsGTPoly4; + +/** Monochrome line */ + +typedef struct +{ + /** Red color component (0-255) */ + unsigned char r; + /** Green color component (0-255) */ + unsigned char g; + /** Blue color component (0-255) */ + unsigned char b; + /** X Coordinates for points */ + short x[2]; + /** Y Coordinates for points */ + short y[2]; + /** Attribute */ + unsigned int attribute; +}GsLine; + +/** Dot (pixel) */ + +typedef struct +{ + /** Red color component (0-255) */ + unsigned char r; + /** Green color component (0-255) */ + unsigned char g; + /** Blue color component (0-255) */ + unsigned char b; + /** X coordinate */ + short x; + /** Y coordinate */ + short y; + /** Attribute */ + unsigned int attribute; +}GsDot; + +/** Graduated line */ + +typedef struct +{ + /** Red color components (0-255) */ + unsigned char r[2]; + /** Green color components (0-255) */ + unsigned char g[2]; + /** Blue color components (0-255) */ + unsigned char b[2]; + /** X coordinates for points */ + short x[2]; + /** Y coordinates for points */ + short y[2]; + /** Attribute */ + unsigned int attribute; +}GsGLine; + +/** Sprite */ + +typedef struct +{ + short x, y; /* X, Y positions */ + unsigned char u, v; /* Offset into texture page of sprite image data */ + short w, h; /* Width and height of sprite */ + short cx, cy; /* Color look up table (palette) X, Y positions */ + unsigned char r, g, b; /* Luminosity of color components - 128 is normal luminosity */ + unsigned char tpage; /* Texture page */ + unsigned int attribute; /* Attribute */ + + /* Scaling? These are only candidates... + + scalex: + Denotes horizontal scaling + + 0 = true size (unmodified) + 1 = true size (*1) + 2 = double size (*2) + 3 = triple size (*3) + ... + + -1 = true size (/1) + -2 = half size (/2) + -3 = one-third size (/3) + ... + + scaley: + Denotes vertical scaling + + *** The behaviour below was introduced in PSXSDK 0.5 + + If scalex > 8, + resulting width will be (original_width * scalex) / 4096 + scalex = 4096 (SCALE_ONE) (original width), scalex = 2048 (half width), etc. + If scaley > 8, + resulting height will be (original_height * scaley) / 4096 + works like scalex but affects height + */ + int scalex, scaley; + + int rotate; // Rotation angle - Fixed point notation, 4096 = 1 degree + int mx, my; // Coordinates of rotation center - relative to coordinates of sprite +}GsSprite; + +/** Rectangle */ + +typedef struct +{ + + short x, y; + short w, h; + unsigned char r, g, b; + unsigned int attribute; /* Attribute */ +}GsRectangle; + +typedef struct +{ + /** Number of points */ + unsigned int npoints; + /** Red color component (0-255) */ + unsigned char r; + /** Green color component (0-255) */ + unsigned char g; + /** Blue color component (0-255) */ + unsigned char b; + /** X Coordinates for points */ + short *x; + /** Y Coordinates for points */ + short *y; + /** Attribute */ + unsigned int attribute; +}GsPolyLine; + +typedef struct +{ + /** Number of points */ + unsigned int npoints; + /** Red color components (0-255) */ + unsigned char *r; + /** Green color components (0-255) */ + unsigned char *g; + /** Blue color components (0-255) */ + unsigned char *b; + /** X Coordinates for points */ + short *x; + /** Y Coordinates for points */ + short *y; + /** Attribute */ + unsigned int attribute; +}GsGPolyLine; + +/** Map */ + +//typedef struct +//{ +// short x, y; /* X, Y positions */ +// unsigned char u, v; /* Offset into texture page of sprite image data */ +// short w, h; /* Width and height of tilemap */ +// short l; /* Length of tilemap line */ +// short cx, cy; /* Color look up table (palette) X, Y positions */ +// unsigned char r, g, b; /* Luminosity of color components - 128 is normal luminosity */ +// unsigned char tpage; /* Texture page */ +// unsigned int attribute; /* Attribute */ +// +// unsigned short tmw, tmh; /* Map texture width and height */ +// unsigned char tw, th; /* Map tile width and height */ +// +// unsigned char tsize; /* Size of tile in map (1 = 8-bit, 2 = 16-bit, 4 = 32-bit) */ +// +// unsigned int tmask; /* Inverted mask for tile number */ +// +// void *data; /* Pointer to beginning of map data */ +//}GsMap; + +/** Texture color modes. */ + +enum psx_gpu_texmodes +{ + /** 4-bit color mode */ + COLORMODE_4BPP, + /** 8-bit color mode */ + COLORMODE_8BPP, + /** 16-bit color mode */ + COLORMODE_16BPP, + /** 24-bit color mode */ + COLORMODE_24BPP +}; + +/** + * This is the luminance factor with which images + * are drawn as they are stored. (i.e. without applying lighting) + * + * NORMAL_LUMINOSITY (sic) is kept for backward compatibility, + * but "luminosity" is an incorrect term here. + */ + +#define NORMAL_LUMINANCE 128 +#define NORMAL_LUMINOSITY NORMAL_LUMINANCE + +/** + * Macro to specify texture color mode, takes a value from psx_gpu_texmodes + */ +#define COLORMODE(x) x&3 +/** + * Macro to specify translucency/semitransparency mode, where x can be a value from 0 to 3. + * + * If a pixel in image data to be drawn has the STP bit set, semitransparency + * processing is enabled for that pixel. + * + * When the color is black (RGB=0,0,0) STP is processed differently from when it is not + * black. + * + * The table below shows the differences: + * + * Color | STP bit | Processing off | Processing on + * ----- | ---- | ----- | ---- + * Black | 0 | Transparent | Transparent + * Black | 1 | Non-transparent |Non-Transparent + * Not black | 0 | Non-Transparent |Non-Transparent + * Not black | 1 | Non-Transparent |Transparent + * + * If the image pixel is semi-transparent (STP bit set) and not black, the formulas for the + * final pixel color are the following: + * + * Mode | From framebuffer pixel| From image pixel + * ---- | --- | ----- + * 0 | +50% | +50% + * 1 | +100% | +100% + * 2 | +100% | -100% + * 3 | +100% | +25% + * + * The final color component values do not underflow or overflow, they simply saturate at 0 or 255. + */ +#define TRANS_MODE(x) ((x&3)<<2) +/** + * Enable semi-transparency processing for the primitive. + */ +#define ENABLE_TRANS (1<<4) +/** + * Enable horizontal flipping for the primitive. + */ +#define H_FLIP (1<<5) +/** + * Enable vertical flipping for the primitive. + */ +#define V_FLIP (1<<6) + +/** + * Drawing environment. + */ + +typedef struct +{ + /** + * Dithering enabled flag. + */ + unsigned char dither; + /** + * Enable drawing on display area flag. + * + * If this flag is enabled, drawing on display area is allowed. + * + * Usually you enable this flag when you do not want to use double buffering. + */ + unsigned char draw_on_display; + + /** + * Drawing area X start coordinate in framebuffer + */ + short x; + /** + * Drawing area Y start coordinate in framebuffer + */ + short y; + /** + * Drawing area width. + */ + short w; + /** + * Drawing area height. + */ + short h; + + /* + * Drawing offset + */ + //short off_x, off_y; + + /** + * Masking settings (can also be set with GsSetMasking()) + */ + + /** + * Do not draw over pixels which have their mask bit set + */ + unsigned char ignore_mask; + /** + * If this is set, every pixel drawn will have the mask bit set + */ + unsigned char set_mask; +}GsDrawEnv; + +/** + * Display environment. + * + * The width and height of the display area are those of the currently set video mode. + */ + +typedef struct +{ + /** Display area X start coordinate in framebuffer. */ + short x; + /** Display area Y start coordinate in framebuffer. */ + short y; +}GsDispEnv; + +/** + * Image + * @brief This structure describes a TIM image + */ + +typedef struct +{ + + + /** Pixel (color) mode. 0 = 4bpp, 1 = 8bpp, 2 = 16bpp, 3 = 24bpp */ + int pmode; + /** Reports whether this image has a Color Look Up Table. 1 if there's a CLUT, 0 otherwise. */ + int has_clut; + /** X coordinate of CLUT in framebuffer */ + int clut_x; + /** Y coordinate of CLUT in framebuffer */ + int clut_y; + /** Width of CLUT in framebuffer */ + int clut_w; + /** Height of CLUT in framebuffer */ + int clut_h; + /** X coordinate of image in framebuffer */ + int x; + /** Y coordinate of image in framebuffer */ + int y; + /** Width of image in framebuffer */ + int w; + /** Height of image in framebuffer */ + int h; + /** Pointer to CLUT data */ + void *clut_data; + /** Pointer to image data */ + void *data; +}GsImage; + +/** + * Adds a monochrome 3 point polygon to the packet list + * @param poly3 Pointer to structure for monochrome 3 point polygon + */ + +void GsSortPoly3(GsPoly3 *poly3); + +/** + * Adds a monochrome 4 point polygon to the packet list + * @param poly4 Pointer to structure for monochrome 4 point polygon + */ + +void GsSortPoly4(GsPoly4 *poly4); + +/** + * Adds a textured 3 point polygon to the packet list + * @param tpoly3 Pointer to structure for textured 3 point polygon + */ + +void GsSortTPoly3(GsTPoly3 *tpoly3); + +/** + * Adds a textured 4 point polygon to the packet list + * @param tpoly4 Pointer to structure for textured 4 point polygon + */ + +void GsSortTPoly4(GsTPoly4 *tpoly4); + +/** + * Adds a gradated 3 point polygon to the packet list + * @param poly3 Pointer to structure for gradated 3 point polygon + */ + +void GsSortGPoly3(GsGPoly3 *poly3); + +/** + * Adds a gradated 4 point polygon to the packet list + * @param poly4 Pointer to structure for gradated 4 point polygon + */ + +void GsSortGPoly4(GsGPoly4 *poly4); + +/** + * Adds a gradated textured 3 point polygon to the packet list + * @param tpoly3 Pointer to structure for textured 3 point polygon + */ + +void GsSortGTPoly3(GsGTPoly3 *tpoly3); + +/** + * Adds a gradated 4 point polygon to the packet list + * @param tpoly4 Pointer to structure for textured 4 point polygon + */ + +void GsSortGTPoly4(GsGTPoly4 *tpoly4); + +/** + * Adds a monochrome line to the packet list + * @param line Pointer to structure for monochrome line + */ + +void GsSortLine(GsLine *line); + +/** + * Adds a gradated line to the packet list + * @param line Pointer to structure for gradated line + */ + +void GsSortGLine(GsGLine *line); + +/** + * Adds a dot (pixel) to the packet list + * @param dot Pointer to structure for dot + */ + +void GsSortDot(GsDot *dot); + +/** + * Adds a sprite to the packet list + * @param sprite Pointer to structure for sprite + */ + +void GsSortSprite(GsSprite *sprite); + +/** + * Always adds a REAL sprite to the packet list + * + * + GsSortSprite() on the other hand checks for scaling and flipping, which + * are not supported by the "sprite" primitive on the PlayStation, but instead + * are done by using a textured 4-point polygon accordingly. + * GsSortSprite() only uses the sprite primitive when all the attributes + * can be done with a "sprite" primitive as well. + * + * @param sprite Pointer to structure for sprite + */ + +void GsSortSimpleSprite(GsSprite *sprite); + +/** + * Adds a rectangle to the packet list + * @param rectangle Pointer to structure for rectangle + */ + +void GsSortRectangle(GsRectangle *rectangle); + +/** + * Moves image data from a part of the framebuffer to another. + * Actually it does a copy. + * @param src_x Top-left X coordinate of source area + * @param src_y Top-left Y coordinate of source area + * @param dst_x Top-left X coordinate of destination area + * @param dst_y Top-left Y coordinate of destination area + * @param w Width of area + * @param h Height of area + */ + +void MoveImage(int src_x, int src_y, int dst_x, int dst_y, int w, int h); + +/** + * Loads image data into framebuffer memory. + * @param img Pointer to raw image data + * @param x Top-left X coordinate of destination area + * @param y Top-left Y coordinate of destination area + * @param w Width of image data + * @param h Height of image data + */ + +void LoadImage(void *img, int x, int y, int w, int h); + +/** + * Draws a rectangle in the framebuffer, without considering drawing + * and display environments (i.e. it does so in an absolute way) + * @param x Top-left X coordinate of area + * @param y Top-left Y coordinate of area + * @param w Area width + * @param h Area height + * @param r Red (0 - 255) + * @param g Green (0 - 255) + * @param b Blue (0 - 255) + */ + +void DrawFBRect(int x, int y, int w, int h, int r, int g, int b); + +/** + * Set drawing environment + * @param drawenv Pointer to drawing environment structure + */ + +void GsSetDrawEnv(GsDrawEnv *drawenv); + +/** + * Set display environment + * @param dispenv Pointer to display environment structure + */ + +void GsSetDispEnv(GsDispEnv *dispenv); + + + +/* If this flag is set, pixels drawn have MSB set */ +#define MASK_SET 1 +/* If this flag is set, pixels aren't drawn over pixels with MSB set */ +#define MASK_IGNORE 2 + + /** + * Sets masking settings + * @param flag Bitwise flags + */ + +void GsSetMasking(unsigned char flag); + +/** + * Return pointer position in linked list + * @return Pointer position in linked list + */ + +unsigned int GsListPos(void); + +/** + * Three functions which send data to the control port and to the data port + */ + +void gpu_ctrl(unsigned int command, unsigned int param); +void gpu_data(unsigned int data); +void gpu_data_ctrl(unsigned int command, unsigned int param); + +/** + * Puts information about a TIM image passed in a buffer in a GsImage structure. + */ + +int GsImageFromTim(GsImage *image, void *timdata); + +/** + * Uploads an image described by a GsImage structure to video memory. + */ + +void GsUploadImage(GsImage *image); + +/** + * Fills a GsSprite structure with information from an image described + * by a GsImage structure, then optionally uploads data to video memory. + * Sprite coordinates are set to 0. + */ + +int GsSpriteFromImage(GsSprite *sprite, GsImage *image, int do_upload); + +/** + * Checks if the GPU is drawing + * @return 1 if GPU is drawing, 0 otherwise + */ + +int GsIsDrawing(void); + +/** + * Checks if the GPU is working. Alias of GsIsDrawing() + * @return 1 if GPU is working, 0 otherwise. + */ + +int GsIsWorking(void); // Alias of GsIsDrawing() + +/** + * Clear Video RAM + */ + +void GsClearMem(void); + +/** + * Loads the built-in 8x8 font in Video RAM at the specified coordinates + * + * + * Specifying cx and cy as -1 will not load the black&white CLUT to + * video memory. Use GsSetFont() to specify clut x and clut y in that case. + * + * The font occupies a space of 16x128 pixels in 16-bit mode, + * and 64x128 in 4-bit mode. +* @param fb_x X coordinate in framebuffer + * @param fb_y Y coordinate in framebuffer + * @param cx X coordinate of black/white CLUT in framebuffer + * @param cy Y coordinate of black/white CLUT in framebuffer + */ + +void GsLoadFont(int fb_x, int fb_y, int cx, int cy); + +/** + * Prints string using 8x8 font at screen coordinates x, y + * @param x X coordinate + * @param y Y coordinate + * @param fmt format (like *printf()) + * @return Position identifier. + */ + +unsigned int GsPrintFont(int x, int y, const char *fmt, ...); + +/** + * Prints string using 8x8 font at screen coordinates x, y + * Apart from using a variable argument list, this function + * is identical to GsPrintFont() + * @param x X coordinate + * @param y Y coordinate + * @param fmt format (like *printf()) + * @param ap Variable argument list + * @return Position identifier. + */ + +unsigned int GsVPrintFont(int x, int y, const char *fmt, va_list ap); + +/** + * Change font coordinates without reloading it + */ + +void GsSetFont(int fb_x, int fb_y, int cx, int cy); + +/** + * This is a function that sets an internal variable + * flags should be specified as an OR mask + * + * to set the wrap and scale attributes, with X scaling factor 2 and Y scaling + * factor 3, for example: + * GsSetFontAttrib(PRFONT_WRAP | PRFONT_SCALE + * | PRFONT_SCALEX(2) | PRFONT_SCALEY(3)); + * + * to remove all attributes (normal printing): + * + * GsSetFontAttrib(0); + * + * PRFONT_WRAP can't coexist with PRFONT_CENTER or PRFONT_RIGHT + * PRFONT_CENTER and PRFONT_RIGHT are justifying attributes and as such + * they are mutually exclusive - they cannot coexist with each other. + * Specifying both will give priority to PRFONT_CENTER. + * + * Attribute list: + * + * PRFONT_WRAP - Wrap to next row when the text would fall off the screen + * Ideal for debug + * PRFONT_SCALE - Enable font scaling + * PRFONT_SCALEX(i) - Specifies the factor "i" as the X scaling factor + * This has the same meaning as a sprite's scaling factor + * PRFONT_SCALEY(i) - Specify the factor "i" as the Y scaling factor + * This has the same meaning as a sprite's scaling factor + * PRFONT_RIGHT - Justifies text to the right + * PRFONT_CENTER - Justifies text at the center + * PRFONT_RL(f) - Luminance factor for the red component + * PRFONT_GL(f) - Luminance factor for the green component + * PRFONT_BL(f) - Luminance factor for the blue component +*/ + +void GsSetFontAttrib(unsigned int flags); + +/** + * Sets drawing environment + * Enables drawing on the display area, disables dithering and disables all masking flags by default + * @param x Top-left X coordinate of framebuffer area to use for drawing + * @param y Top-left Y coordinate of framebuffer area to use for drawing + * @param w Width of area + * @param h Height of area + */ + +void GsSetDrawEnvSimple(int x, int y, int w, int h); + +/** + * Sets display environment + * @param x Top-left X coordinate of framebuffer area to display + * @param y Top-left Y coordinate of framebuffer area to display + */ + +void GsSetDispEnvSimple(int x, int y); + +/** + Television video modes. +*/ +enum psx_gpu_vmodes +{ + /** NTSC video mode, 60Hz */ + VMODE_NTSC, + /** PAL video mode, 50Hz */ + VMODE_PAL +}; + +/** One scaling unit. */ + +#define SCALE_ONE 4096 + +/** One rotation unit. */ + +#define ROTATE_ONE 4096 + +// GsSetFontAttrib() Attribute Flags + +#define PRFONT_WRAP 1 +#define PRFONT_CENTER 2 +#define PRFONT_RIGHT 4 +#define PRFONT_SCALE 8 +#define PRFONT_UNIXLF 16 +#define PRFONT_COLOR 32 + +// These below are not really attributes... but use them as if they were. + +unsigned int PRFONT_SCALEX(int i); +unsigned int PRFONT_SCALEY(int i); +unsigned int PRFONT_RL(unsigned char f); +unsigned int PRFONT_GL(unsigned char f); +unsigned int PRFONT_BL(unsigned char f); + +// Use this to get the final X and Y positions from the return value +// of GsPrintFont(). Especially useful after wrapping. + +#define prfont_get_fx(i) ((short)(i & 0xffff)) +#define prfont_get_fy(i) ((short)((i >> 16) & 0xffff)) + +// Width and height of the screen in the current video mode + +/** This global variable reports the current screen width, as set by GsSetVideoMode(). Do not modify. */ +extern unsigned short GsScreenW; +/** This global variable reports the current screen height, as set by GsSetVideoMode(). Do not modify. */ +extern unsigned short GsScreenH; +/** This global variable reports the current screen color mode (PAL or NTSC), as set by GsSetVideoMode(). + You can use the values in the psx_gpu_vmodes enum to evaluate this. Do not modify. */ +extern unsigned char GsScreenM; // Current video mode + +/** This global variable reports the width of the current drawing environment. */ +extern unsigned short GsCurDrawEnvW; +/** This global variable reports the height of the current drawing environment. */ +extern unsigned short GsCurDrawEnvH; + +/** + * Clear the entire drawing area with specified color + * @param r Red (0 - 255) + * @param g Green (0 - 255) + * @param b Blue (0 - 255) + */ + +void GsSortCls(int r, int g, int b); + +/** + @attention Macros by their definition do not like being passed invalid values. +*/ + +/** + * Macro to get a texture page number from a coordinate in VRAM + * @param x X coordinate (0-1023) + * @param y Y coordinate (0-511) + */ + +#define gs_get_tpage_num(x,y) ((x/64)+((y/256)*16)) + +/** + * Macro to get an horizontal texture offset from a X coordinate in VRAM + * @param x X coordinate (0-1023) + */ + +#define gs_get_tpage_u(x) (x&0x3f) + +/** + * Macro to get a vertical texture offset from a Y coordinate in VRAM + * @param y Y coordinate (0-511) + */ + +#define gs_get_tpage_v(y) (y&0xff) + +/** + * This macro converts a RGB 888 color to PlayStation color format. + * @param r Red component (0-255) + * @param g Green component (0-255) + * @param b Blue component (0-255) + */ + +#define gs_rgb_to_psx(r, g, b) ((r>>3)|((g>>3)<<5)|((b>>3)<<10)) + +/** + * This macro converts a RGB 888 color (a color whose color components have an intensity between 0 and 255) + * to PlayStation color format, considering an alpha bit. If the alpha bit is non-zero, the STP bit in the color + * is set and will be considered for PlayStation translucency effects. + * @param r Red component (0-255) + * @param g Green component (0-255) + * @param b Blue component (0-255) + * @param a Alpha bit (STP/semitransparency bit) + */ + +#define gs_rgba_to_psx(r, g, b, a) ((r>>3)|((g>>3)<<5)|((b>>3)<<10)|(a==0?0:1)) + +/** + * This function can rotate a vector about the X, Y and Z axes + * If you don't want to rotate a vector about an axis, pass 0 as angle to that axis + * + * It is correct to pass the same argument to v and n, as calculations are first done in an internal buffer + * and then stored in the output array + * + * @param x_a Number of degrees (0-359) to which the vector should be rotated about the X axis + * @param y_a Number of degrees (0-359) to which the vector should be rotated about the Y axis + * @param z_a Number of degrees (0-359) to which the vector should be rotated about the Z axis + * @param v Pointer to an array of coordinates for the source vector + * @param n Pointer to destination array for the coordinates of the rotated vector + */ + +void GsRotateVector(int x_a, int y_a, int z_a, double *v, double *n); + +/** + * Adds a monochrome polyline to the packet list + * @param line Pointer to structure for monochrome polyline + */ + +void GsSortPolyLine(GsPolyLine *line); + +/** + * Adds a gradated polyline to the packet list + * @param line Pointer to structure for monochrome line + */ + +void GsSortGPolyLine(GsGPolyLine *line); + +//void GsSortSimpleMap(GsMap *map); + +#endif diff --git a/libpsx/include/psxgte.h b/libpsx/include/psxgte.h new file mode 100644 index 0000000..24574b9 --- /dev/null +++ b/libpsx/include/psxgte.h @@ -0,0 +1,196 @@ +#ifndef _PSXGTE_H +#define _PSXGTE_H + +/** GTE operations */ + +enum gte_operations +{ + /** Perspective transformation */ + GTE_OP_RTPS = 0x0180001, + /** Perspective Transformation on 3 points */ + GTE_OP_RTPT = 0x0280030, + /** Multiply vector by matrix and vector addition */ + GTE_OP_MVMVA = 0x0400012, + /** Depth Cue Color light */ + GTE_OP_DCPL = 0x0680029, + /** Depth Cueing */ + GTE_OP_DPCS = 0x0780010, + /** Interpolation of a vector and far color vector */ + GTE_OP_INTPL = 0x0980011, + /** Square vector */ + GTE_OP_SQR = 0x0A00428, + /** Normal color single vector */ + GTE_OP_NCS = 0x0C8041E, + /** Normal color three vectors */ + GTE_OP_NCT = 0x0D80420, + /** Normal color depth cue single vector */ + GTE_OP_NCDS = 0x0E80413, + /** Normal color depth cue three vectors */ + GTE_OP_NCDT = 0x0F80416, + /** Depth Cueing */ + GTE_OP_DPCT = 0x0F8002A, + /** Normal Color Color single vector */ + GTE_OP_NCCS = 0x108041B, + /** Normal Color Color three vectors */ + GTE_OP_NCCT = 0x118043F, + /** Color Depth Cue */ + GTE_OP_CDP = 0x1280414, + /** Color Color */ + GTE_OP_CC = 0x138041C, + /** Normal clipping */ + GTE_OP_NCLIP = 0x1400006, + /** Average of three Z values */ + GTE_OP_AVSZ3 = 0x158002D, + /** Average of four Z values */ + GTE_OP_AVSZ4 = 0x168002E, + /** Outer product of 2 vectors */ + GTE_OP_OP = 0x170000C, + /** General purpose interpolation */ + GTE_OP_GPF = 0x190003D, + /** General purpose interpolation */ + GTE_OP_GPL = 0x1A0003E +}; + +/** GTE error flags, grab from cop2 register 63 */ + +enum gte_error_flags +{ + GTE_FLAG_MAC1_OVF_POS = 0x40000000, + GTE_FLAG_MAC2_OVF_POS = 0x20000000, + GTE_FLAG_MAC3_OVF_POS = 0x10000000, + + GTE_FLAG_MAC1_OVF_NEG = 0x08000000, + GTE_FLAG_MAC2_OVF_NEG = 0x04000000, + GTE_FLAG_MAC3_OVF_NEG = 0x02000000, + + GTE_FLAG_IR1_SATURATED = 0x01000000, + GTE_FLAG_IR2_SATURATED = 0x00800000, + GTE_FLAG_IR3_SATURATED = 0x00400000, + + GTE_FLAG_COL_FIFO_R_SATURATED = 0x00200000, + GTE_FLAG_COL_FIFO_G_SATURATED = 0x00100000, + GTE_FLAG_COL_FIFO_B_SATURATED = 0x00080000, + + GTE_FLAG_SZ3_OTZ_SATURATED = 0x00040000, + + GTE_FLAG_DIV_OVF_SATURATED = 0x00020000, + + GTE_FLAG_MAC0_OVF_POS = 0x00010000, + GTE_FLAG_MAC0_OVF_NEG = 0x00008000, + + GTE_FLAG_SX2_SATURATED = 0x00004000, + GTE_FLAG_SY2_SATURATED = 0x00002000, + + GTE_FLAG_IR0_SATURATED = 0x00001000 +}; + +/** GTE data registers */ + +enum gte_data_registers +{ + /** Vector 0 X and Y */ + GTE_R_VXY0 = 0, + /** Vector 0 Z */ + GTE_R_VZ0 = 1, + /** Vector 1 X and Y */ + GTE_R_VXY1 = 2, + /** Vector 1 Z */ + GTE_R_VZ1 = 3, + /** Vector 2 X and Y */ + GTE_R_VXY2 = 4, + /** Vector 2 Z */ + GTE_R_VZ2 = 5, + /** RGB value */ + GTE_R_RGB = 6, + /** Z Average value */ + GTE_R_OTZ = 7, + /** Intermediate value 0 */ + GTE_R_IR0 = 8, + /** Intermediate value 1 */ + GTE_R_IR1 = 9, + /** Intermediate value 2 */ + GTE_R_IR2 = 10, + /** Intermediate value 3 */ + GTE_R_IR3 = 11, + /** Screen XY coordinates 0 FIFO */ + GTE_R_SXY0 = 12, + /** Screen XY coordinates 1 FIFO */ + GTE_R_SXY1 = 13, + /** Screen XY coordinates 2 FIFO */ + GTE_R_SXY2 = 14, + /** Screen XY coordinates P FIFO */ + GTE_R_SXYP = 15, + /** Screen Z 0 FIFO */ + GTE_R_SZ0 = 16, + /** Screen Z 1 FIFO */ + GTE_R_SZ1 = 17, + /** Screen Z 2 FIFO */ + GTE_R_SZ2 = 18, + /** Screen Z 3 FIFO */ + GTE_R_SZ3 = 19, + /** Characteristic color 0 FIFO */ + GTE_R_RGB0 = 20, + /** Characteristic color 1 FIFO */ + GTE_R_RGB1 = 21, + /** Characteristic color 2 FIFO */ + GTE_R_RGB2 = 22, + /** Sum of products value 0 */ + GTE_R_MAC0 = 24, + /** Sum of products value 1 */ + GTE_R_MAC1 = 25, + /** Sum of products value 2 */ + GTE_R_MAC2 = 26, + /** Sum of products value 3 */ + GTE_R_MAC3 = 27, + /** IRGB ?? */ + GTE_R_IRGB = 28, + /** ORGB ?? */ + GTE_R_ORGB = 29, + /** Leading zero count source data. */ + GTE_R_LZCS = 30, + /** Leading zero count result */ + GTE_R_LZCR = 31 +}; + +/** GTE control registers */ + +enum gte_control_registers +{ + GTE_R_R11R12 = 0, + GTE_R_R13R21 = 1, + GTE_R_R22R23 = 2, + GTE_R_R31R32 = 3, + GTE_R_R33 = 4, + GTE_R_TRX = 5, + GTE_R_TRY = 6, + GTE_R_TRZ = 7, + + GTE_R_L11L12 = 8, + GTE_R_L13L21 = 9, + GTE_R_L22L23 = 10, + GTE_R_L31L32 = 11, + GTE_R_L33 = 12, + GTE_R_RBK = 13, + GTE_R_GBK = 14, + GTE_R_BBK = 15, + + GTE_R_LR1LR2 = 16, + GTE_R_LR3LG1 = 17, + GTE_R_LG2LG3 = 18, + GTE_R_LB1LB2 = 19, + GTE_R_LB3 = 20, + GTE_R_RFC = 21, + GTE_R_GFC = 22, + GTE_R_BFC = 23, + + GTE_R_OFX = 24, + GTE_R_OFY = 25, + GTE_R_H = 26, + GTE_R_DQA = 27, + GTE_R_DQB = 28, + GTE_R_ZSF3 = 29, + GTE_R_ZSF4 = 30, + GTE_R_FLAG = 31 +}; + +#endif diff --git a/libpsx/include/psxpad.h b/libpsx/include/psxpad.h new file mode 100644 index 0000000..3f96861 --- /dev/null +++ b/libpsx/include/psxpad.h @@ -0,0 +1,178 @@ +#ifndef _PSXPAD_H
+#define _PSXPAD_H
+
+/* Pad bits defines. */
+
+#define PAD_LEFT (1<<15)
+#define PAD_RIGHT (1<<13)
+#define PAD_UP (1<<12)
+#define PAD_DOWN (1<<14)
+#define PAD_L2 1
+#define PAD_R2 (1<<1)
+#define PAD_L1 (1<<2)
+#define PAD_R1 (1<<3)
+#define PAD_TRIANGLE (1<<4)
+#define PAD_CIRCLE (1<<5)
+#define PAD_CROSS (1<<6)
+#define PAD_SQUARE (1<<7)
+#define PAD_SELECT (1<<8)
+#define PAD_LANALOGB (1<<9)
+#define PAD_RANALOGB (1<<10)
+#define PAD_START (1<<11)
+
+#define PAD_READ_RAW_SIZE 21
+
+/**
+ * These values below are to be used for evalauting the type field of the
+ * psx_pad_state structure
+ */
+
+enum psx_pad_types
+{
+ /** No pad connected. */
+ PADTYPE_NONE,
+ /** Normal pad. */
+ PADTYPE_NORMALPAD,
+ /** Analog joystick, the early ones with analog. */
+ PADTYPE_ANALOGJOY,
+ /** Analog pad, the Dual Shock controller. */
+ PADTYPE_ANALOGPAD,
+ /** Namco NeGcon. Many steering wheels implement this protocol as well. */
+ PADTYPE_NEGCON, // Namco NeGcon
+ /** Konami Justifier gun controller. Many third party gun controllers implement this protocol. */
+ PADTYPE_KONAMIGUN,
+ /** Unknown pad type. */
+ PADTYPE_UNKNOWN
+};
+
+/**
+ * This structure contains the state of the pad (game controller) after
+ * polling it with PSX_PollPad()
+ */
+
+typedef struct
+{
+ /** Status. 0 on success, 255 on failure. */
+ unsigned char status;
+ /** Id. Bits 7-4 indicate the type. Bits 3-0 indicate the number of words
+ in the raw packet returned by the controller. */
+ unsigned char id;
+ /** Type of pad. To be evaluated with the types in the psx_pad_types enum */
+ unsigned char type;
+ /** Button bitmask. To be checked by AND'ing with the defines in
+ psxpad.h for buttons. If a bit is set for a button, it is pressed.
+ Checking the pad type to use this bitmask is not necessary at all,
+ and if button emulations are set up, this may not represent the
+ buttons actually pressed. Also reliable when type is PADTYPE_UNKNOWN */
+ unsigned short buttons;
+
+ /** Extra data for non-normal controllers.
+ You should check the value of the type field before accessing any of this data
+ */
+
+ union extra
+ {
+ /** Data for analog joysticks.
+ * @attention Due to the poor calibration of the analog sticks, it is recommended
+ * that you do not assume "left" for X values lower than zero and
+ * "right" for X values higher than zero.
+ *
+ * @attention It is recommended to pick a value, for instance 64, and assume
+ * "left" for values lower than -64, "right" for values higher than 64,
+ * and no movement for values between -64 and 64.
+ *
+ * @attention The same is valid for Y values, "up" and "down".
+ **/
+
+ struct analogJoy
+ {
+ /** X coordinates for the left analog stick and the right analog stick
+ * @par Value
+ * Totally left: -128, totally right: 127
+ */
+ signed char x[2];
+ /** Y coordinates for the left analog stick and the right analog stick
+ * @par Value
+ * Totally up: -128, totally down: 127
+ */
+ signed char y[2];
+ }analogJoy;
+
+ /** Data for analog joypads (controller).
+ * @attention Due to the poor calibration of the analog sticks, it is recommended
+ * that you do not assume "left" for X values lower than zero and
+ * "right" for X values higher than zero.
+ *
+ * @attention It is recommended to pick a value, for instance 64, and assume
+ * "left" for values lower than -64, "right" for values higher than 64,
+ * and no movement for values between -64 and 64.
+ *
+ * @attention The same is valid for Y values, "up" and "down".
+ **/
+
+ struct analogPad
+ {
+ /** X coordinates for the left analog stick and the right analog stick
+ * @par Value
+ * Totally left: -128, totally right: 127
+ */
+ signed char x[2];
+ /** Y coordinates for the left analog stick and the right analog stick
+ * @par Value
+ * Totally up: -128, totally down: 127
+ */
+ signed char y[2];
+ }analogPad;
+
+ /** Data for Namco NeGcon and steering wheels using its protocol.
+ * Many steering wheels use this protocol or can switch to it if desired.
+ */
+
+ struct negCon
+ {
+ /**
+ * Steering wheel position.
+ *
+ * Unlike analog sticks, the steering is accurate and this value is reliable.
+ *
+ * @par Value
+ * When steering left it is lower than zero, when steering right it is higher than zero
+ * and when not steering at all it is zero.
+ */
+
+ signed char steering;
+
+ /**
+ * Pressure for button I (1).
+ * @par Value
+ * 0 = not pressed, 255 = maximum pressure
+ */
+
+ unsigned char one;
+
+ /**
+ * Pressure for button II (2).
+ * @par Value
+ * 0 = not pressed, 255 = maximum pressure
+ */
+
+ unsigned char two;
+
+ /**
+ * Pressure for "L" shoulder button.
+ * @par Value
+ * 0 = not pressed, 255 = maximum pressure
+ */
+
+ unsigned char shoulder;
+ }negCon;
+ }extra;
+}psx_pad_state;
+
+void QueryPAD(int pad_n, unsigned char *in, unsigned char *out, int len);
+void pad_read_raw(int pad_n, unsigned char *arr);
+void pad_escape_mode(int pad_n, int enable);
+void pad_enable_vibration(int pad_n);
+void pad_set_vibration(int pad_n, unsigned char small, unsigned char big);
+
+#endif
diff --git a/libpsx/include/psxsio.h b/libpsx/include/psxsio.h new file mode 100644 index 0000000..9756f1d --- /dev/null +++ b/libpsx/include/psxsio.h @@ -0,0 +1,121 @@ +#ifndef _PSXSIO_H
+#define _PSXSIO_H
+
+/** Bitrate reload factors */
+
+enum sio_reload_factors
+{
+ /** STOP */
+ SIO_REL_STOP = 0,
+ /** MUL1 */
+ SIO_REL_MUL1 = 1,
+ /** MUL16 */
+ SIO_REL_MUL16 = 2,
+ /** MUL64 */
+ SIO_REL_MUL64 = 3
+};
+
+/** Character (data) length settings */
+
+enum sio_data_len
+{
+ /** Data Length = 5 bits */
+ SIO_DATA_LEN_5 = 0,
+ /** Data Length = 6 bits */
+ SIO_DATA_LEN_6 = 1,
+ /** Data Length = 7 bits */
+ SIO_DATA_LEN_7 = 2,
+ /** Data Length = 8 bits */
+ SIO_DATA_LEN_8 = 3
+};
+
+/** Stop bit length settings */
+
+enum sio_stop_bit
+{
+ /** Length = 1 bit */
+ SIO_STOP_BIT_1 = 1,
+ /** Length = 1.5 bits */
+ SIO_STOP_BIT_1_5 = 2,
+ /** Length = 2 bits */
+ SIO_STOP_BIT_2 = 3
+};
+
+/** Parity settings */
+
+enum sio_parity
+{
+ /** No parity */
+ SIO_PARITY_NONE = 0,
+ /** Odd parity */
+ SIO_PARITY_ODD = 1,
+ /** Even parity */
+ SIO_PARITY_EVEN = 3
+};
+
+/** SIO FIFO Buffer (TX/RX) Register [Read/Write] */
+#define SIO_TX_RX *((volatile unsigned char*)0x1F801050)
+/** SIO Status Register [Read Only] */
+#define SIO_STAT *((volatile unsigned short*)0x1F801054)
+/** SIO Mode Register [Read/Write] */
+#define SIO_MODE *((volatile unsigned short*)0x1F801058)
+/** SIO Control Register [Read/Write] */
+#define SIO_CTRL *((volatile unsigned short*)0x1F80105A)
+/** SIO Baud Rate Register [Read/Write] */
+#define SIO_BPSV *((volatile unsigned short*)0x1F80105E)
+
+
+/**
+ * Initialize SIO communication at the specified bitrate (baud rate).
+ * Mode is 8N1. (Data Length = 8 bit, No parity, Stop bit Length = 1 bit)
+ * @param bitrate Bitrate (baud rate)
+ */
+void SIOStart(int bitrate);
+
+/**
+ * Same as SIOStart() but with more control.
+ * IMPORTANT: Must use defined macros.
+ * For example setting datalength to 5 should be done with "SIO_DATA_LEN_5"
+ * and not by simply passing 5 as an argument.
+ *
+ * @param bitrate Bit rate (baud rate)
+ * @param datalength Character (data) length
+ * @param parity Parity
+ * @param stopbit Stop bit length
+ */
+void SIOStartEx(int bitrate, int datalength, int parity, int stopbit);
+
+/**
+ * Shuts down SIO communication.
+ */
+void SIOStop(void);
+
+/**
+ * Read a single byte from the input buffer.
+ * @return Data byte from input buffer
+ */
+unsigned char SIOReadByte(void);
+
+/**
+ * Send a single byte to the output buffer.
+ * @param data Byte to send
+ */
+void SIOSendByte(unsigned char data);
+
+/**
+ * Check if any data is waiting in the input buffer.
+ * Must be used when fetching data otherwise incorrect data could be read (usually 0x00).
+ * @return Non-zero if there is data waiting in the input buffer, zero otherwise.
+ */
+int SIOCheckInBuffer(void);
+
+/**
+ * Check if port is ready to send data (previous operation finished).
+ * Must be used when sending data as the output buffer is only 2 bytes long.
+ * @return Non-zero if port is ready to send data, zero otherwise.
+ */
+int SIOCheckOutBuffer(void);
+
+
+
+#endif
diff --git a/libpsx/include/psxspu.h b/libpsx/include/psxspu.h new file mode 100644 index 0000000..0de3656 --- /dev/null +++ b/libpsx/include/psxspu.h @@ -0,0 +1,225 @@ +#ifndef _SPU_H
+#define _SPU_H
+
+#define SPU_ADDR *((volatile unsigned short*)0x1f801da6)
+#define SPU_DATA *((volatile unsigned short*)0x1f801da8)
+#define SPU_CONTROL *((volatile unsigned short*)0x1f801daa)
+#define SPU_STATUS *((volatile unsigned short*)0x1f801dac)
+#define SPU_STATUS2 *((volatile unsigned short*)0x1f801dae)
+#define SPU_MVOL_L *((volatile unsigned short*)0x1f801d80)
+#define SPU_MVOL_R *((volatile unsigned short*)0x1f801d82)
+#define SPU_REVERB_L *((volatile unsigned short*)0x1f801d84)
+#define SPU_REVERB_R *((volatile unsigned short*)0x1f801d86)
+#define SPU_KEY_ON1 *((volatile unsigned short*)0x1f801d88)
+#define SPU_KEY_ON2 *((volatile unsigned short*)0x1f801d8a)
+#define SPU_KEY_OFF1 *((volatile unsigned short*)0x1f801d8c)
+#define SPU_KEY_OFF2 *((volatile unsigned short*)0x1f801d8e)
+#define SPU_KEY_FM_MODE1 *((volatile unsigned short*)0x1f801d90)
+#define SPU_KEY_FM_MODE2 *((volatile unsigned short*)0x1f801d92)
+#define SPU_KEY_NOISE_MODE1 *((volatile unsigned short*)0x1f801d94)
+#define SPU_KEY_NOISE_MODE2 *((volatile unsigned short*)0x1f801d96)
+#define SPU_KEY_REVERB_MODE1 *((volatile unsigned short*)0x1f801d98)
+#define SPU_KEY_REVERB_MODE2 *((volatile unsigned short*)0x1f801d9a)
+#define SPU_CD_MVOL_L *((volatile unsigned short*)0x1f801db0)
+#define SPU_CD_MVOL_R *((volatile unsigned short*)0x1f801db2)
+#define SPU_EXT_VOL_L *((volatile unsigned short*)0x1f801db4)
+#define SPU_EXT_VOL_R *((volatile unsigned short*)0x1f801db6)
+#define SPU_REVERB_WORK_ADDR *((volatile unsigned short*)0x1f801da2)
+#define SPU_VOICE_BASE_ADDR(x) (0x1f801c00 + (x<<4))
+
+/** Start address of sound data in Sound RAM */
+#define SPU_DATA_BASE_ADDR 0x1010
+/** Maximum volume. */
+#define SPU_MAXVOL 0x3FFF +
+/** VAG file */
+
+typedef struct
+{
+ /** Version. */
+ unsigned int version;
+ /** Data size. */
+ unsigned int data_size;
+ /** Sample rate. */
+ unsigned int sample_rate;
+ /** Name */
+ unsigned char name[16];
+ /** Pointer to sound data */
+ void *data;
+ /** Address in Sound RAM where the sound data was uploaded */
+ unsigned int spu_addr;
+ /** [Runtime] Voice this VAG is currently being played on */
+ char cur_voice;
+}SsVag;
+
+/**
+ * Set voice volume.
+ * @param voice Voice number (0-23)
+ * @param left Left channel volume
+ * @param right Right channel volume
+ */
+
+void SsVoiceVol(int voice, unsigned short left, unsigned short right);
+
+/**
+ * Set voice pitch.
+ * @param voice Voice
+ * @param pitch Pitch.
+ */
+
+void SsVoicePitch(int voice, unsigned short pitch);
+
+
+/**
+ * Set start Sound RAM address for voice.
+ * @param voice Voice
+ * @param addr Start address in Sound RAM (multiplier of 8)
+ */
+
+void SsVoiceStartAddr(int voice, unsigned int addr);
+
+/**
+ * Set ADSR level for voice
+ * @param voice Voice
+ * @param level ADSR level
+ * @param rate ADSR rate
+ */
+
+void SsVoiceADSRRaw(int voice, unsigned short level, unsigned short rate);
+
+/**
+ * Set repeat address for voice
+ * @param voice Voice
+ * @param addr Address in Sound RAM (multiplier of 8)
+ */
+
+void SsVoiceRepeatAddr(int voice, unsigned int addr);
+
+/**
+ * Set a voice to 'on'. This has the effect of playing the sound specified for the voice.
+ * @param voice Voice
+ */
+
+void SsKeyOn(int voice);
+
+/**
+ * Set a voice to 'off'. This stops the sound specified for the voice.
+ * @param voice Voice
+ */
+
+void SsKeyOff(int voice);
+
+/**
+ * Set the voices specified by the bitmask to 'on'. Like SsKeyOn()
+ * @param mask Bitmask
+ */
+
+void SsKeyOnMask(int mask);
+
+/**
+ * Set the voices specified by the bitmask to 'off'. Like SsKeyOff()
+ * @param mask Bitmask
+ */
+
+void SsKeyOffMask(int mask);
+
+/**
+ * Wait for the SPU to be ready.
+ */
+
+void SsWait(void);
+
+/**
+ * Intialize the SPU.
+ */
+
+void SsInit(void);
+
+/**
+ * Uploads sound data in PSX ADPCM format to Sound RAM.
+ * @param addr Pointer to PSX ADPCM sound data in main RAM
+ * @param size Sound data size
+ * @param spu_addr Destination address in Sound RAM (multiplier of 8).
+ */
+
+void SsUpload(void *addr, int size, int spu_addr);
+
+/**
+ * Converts a sampling rate in hertz to PlayStation pitch rate used by the SPU.
+ * @param hz Sampling rate in hertz.
+ * @return PlayStation pitch rate
+ */
+
+unsigned short SsFreqToPitch(int hz);
+
+/**
+ * Reads information from a buffer containg a VAG file and stores it inside a SsVag structure.
+ * @param vag Pointer to structure in which to store information.
+ * @param data Pointer to VAG file data
+ */
+
+int SsReadVag(SsVag *vag, void *data);
+
+/**
+ * Uploads the sound data specified by a SsVag structure to the specified address in Sound RAM.
+ * The SsVag structure can then be used for playing with SsPlayVag()
+ * @param vag Pointer to SsVag structure
+ * @param spu_addr Destination address in Sound RAM (multiplier of 8)
+ */
+
+void SsUploadVagEx(SsVag *vag, int spu_addr);
+
+
+/**
+ * Uploads the sound data specified by a SsVag structure to Sound RAM, beginning from the
+ * base of usable Sound RAM and continuing from there, in an automatic fashion.
+ * @param vag Pointer to SsVag structure
+ */
+
+void SsUploadVag(SsVag *vag);
+
+/**
+ * Plays the sound specified by the SsVag structure at specified voice and volume.
+ * @param vag Pointer to SsVag structure
+ * @param voice Voice
+ * @param vl Left channel volume
+ * @param vr Right channel volume
+ */
+
+void SsPlayVag(SsVag *vag, unsigned char voice, unsigned short vl,
+ unsigned short vr);
+
+/**
+ * Stops the sound specified by the SsVag structure
+ * @param vag Pointer to SsVag structure
+ */
+
+void SsStopVag(SsVag *vag);
+
+/**
+ * Tell SsUploadVag() to start uploading from the base of usable Sound RAM again.
+ */
+
+void SsResetVagAddr(void);
+
+/**
+ * Enable CD Audio.
+ */
+ +void SsEnableCd(void);
+
+/**
+ * Enable External audio. (???)
+ */
+ +void SsEnableExt(void);
+
+/**
+ * Set CD Audio volume.
+ * @param left Left channel volume
+ * @param right Right channel volume
+ */
+
+void SsCdVol(unsigned short left, unsigned short right); +
+#endif
diff --git a/libpsx/include/psxutil.h b/libpsx/include/psxutil.h new file mode 100644 index 0000000..0dba29e --- /dev/null +++ b/libpsx/include/psxutil.h @@ -0,0 +1,20 @@ +// psxutil.h
+
+#ifndef _PSXUTIL_H
+#define _PSXUTIL_H
+
+/**
+ * Given a button bitmask, returns the name for the buttons
+ * that the bitmask reports activated.
+ * If more than one button is found in the bitmask, it is specified by the symbol &
+ * followed by the other button name and so on...
+ *
+ * @param button Button bitmask as returned by PSX_ReadPad()
+ * @param out Pointer to a string, to which the button names will be output
+ * @param out_len The maximum length of the string
+ * @return The pointer to passed as the "out" parameter
+ */
+
+char *PSX_GetButtonName(unsigned short button, char *out, unsigned int out_len);
+
+#endif
diff --git a/libpsx/include/runexe.h b/libpsx/include/runexe.h new file mode 100644 index 0000000..c42c9ee --- /dev/null +++ b/libpsx/include/runexe.h @@ -0,0 +1,17 @@ +#ifndef _PSXSDK_RUNEXE_H +#define _PSXSDK_RUNEXE_H + +/** + * Replaces running executable code with code from another executable + * stored in a memory buffer and starts executing at the starting point for the new code. + * The executable must be in PSX-EXE format (such as generated by elf2exe). + * Moreover, PSX_InitEx() must have been initialized by specifying the PSX_INIT_SAVESTATE flag. + * @param exeBuffer Pointer to memory buffer where executable is stored + * @return On success this function has the effect of making the PlayStation + * run another executable, so obviously this function will never return in that case. + * This function will only return on failure, where it will return 0. + */ + +int PSX_RunExe(void *exeBuffer); + +#endif diff --git a/libpsx/include/search.h b/libpsx/include/search.h new file mode 100644 index 0000000..7f8574e --- /dev/null +++ b/libpsx/include/search.h @@ -0,0 +1,14 @@ +/* + * search.h + * + * PSXSDK + */ + +#ifndef _SEARCH_H +#define _SEARCH_H + +void *lsearch(void *key , void *base , int belp , int width , int (*cmp)(void * , void *)); +void *bsearch(void *key , void *base , int nel , int size , int (*cmp)(void * , void *)); + +#endif + diff --git a/libpsx/include/stdint.h b/libpsx/include/stdint.h new file mode 100644 index 0000000..e6bb9d2 --- /dev/null +++ b/libpsx/include/stdint.h @@ -0,0 +1,14 @@ +/* stdint.h */ + +#ifndef _STDINT_H +#define _STDINT_H + +#include <inttypes.h> + +// Added ifndef or otherwise GCC 4.8 would complain + +#ifndef __PTRDIFF_TYPE__ +typedef unsigned int ptrdiff_t; +#endif + +#endif diff --git a/libpsx/include/stdio.h b/libpsx/include/stdio.h new file mode 100644 index 0000000..1bf7a99 --- /dev/null +++ b/libpsx/include/stdio.h @@ -0,0 +1,170 @@ +/* + * stdio.h implementation for PSXSDK + */ + +#ifndef _STDIO_H +#define _STDIO_H + +#ifdef _PSXSDK_WRAPPER + +/* + * Dirty hack... + */ + +#include "/usr/include/stdio.h" + +#else + +#include <types.h> + +#include <stdarg.h> +#include <stdbool.h> + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#define EOF -1 + +/* NULL */ +#ifndef NULL +#define NULL (void*)0 +#endif + +enum stdio_directions +{ + STDIO_DIRECTION_BIOS, + STDIO_DIRECTION_SIO +}; + +enum file_devices +{ + FDEV_UNKNOWN, + FDEV_CDROM, + FDEV_MEMCARD, + FDEV_CONSOLE +}; + +extern int __stdio_direction; + +/** + * File stream + */ + +typedef struct +{ + /** File descriptor, as returned by open() */ + int fildes; + /** Current file position */ + unsigned int pos; + /** File access mode */ + unsigned int mode; + /** Device ID */ + unsigned int dev; + /** Size in bytes */ + unsigned int size; + /** Used internally by fopen(), 0 if free, 1 if occupied */ + unsigned int used; + /** End-of-File marker */ + unsigned int eof; + /** Error marker */ + unsigned int error; +}FILE; + +/* Console functions */ + +int putchar(int c); +int puts(const char *str); + +/** + * BIOS printf() implementation. Does not support floating point. + * NOTE: when redirect_stdio_to_sio() is used, PSXSDK's internal implementation is used instead. + */ + +extern int printf(const char *format, ...); + + +#ifdef __IN_LIBPSX + +// Only for code in libpsx + +// If PSXSDK_DEBUG is defined, dprintf() calls are turned into printf() calls +// otherwise they are left out + +#ifdef PSXSDK_DEBUG + #define dprintf printf +#else + #define dprintf(fmt, ...) +#endif + +#endif + +int vsnprintf(char *string, size_t size, const char *fmt, va_list ap); +int vsprintf(char *string, const char *fmt, va_list ap); +int sprintf(char *string, const char *fmt, ...); +int snprintf(char *string, size_t size, const char *fmt, ...); +int vprintf(char *fmt, va_list ap); + +FILE *fdopen(int fildes, const char *mode); +FILE *fopen(const char *path, const char *mode); +int fclose(FILE *stream); +int fread(void *ptr, int size, int nmemb, FILE *f); +int fwrite(void *ptr, int size, int nmemb, FILE *f); + +int fgetc(FILE *f); +int ftell(FILE *f); +int fseek(FILE *f, int offset, int whence); + +int fputs(const char *str, FILE *stream); +void clearerr(FILE *stream); +int feof(FILE *stream); +int ferror(FILE *stream); +int fileno(FILE *stream); + +#define getc(f) fgetc(f) + +int rename(const char *oldname, const char *newname); +int remove(const char *filename); + +#ifndef __cplusplus +// Define delete(x) to be remove(x) only when compiling plain C. +#define delete(x) remove(x) +#endif + +/** + * Redirects STDIO to SIO (serial port) + */ + +void redirect_stdio_to_sio(void); + +/** + * Sets whether a carriage return must be written before a line feed. + * In simpler words, whether '\n' must be translated to a '\r\n' sequence. + * If you come from the Unix world, you most likely want to set this. + * + * @param setting New status of the setting (0 = disabled, 1 = enabled) + */ + +void sio_stdio_mapcr(unsigned int setting); + +/** + * scanf and friends + */ + +int vsscanf(const char *str, const char *fmt, va_list ap); +int sscanf(const char *str, const char *fmt, ...); + + +/** + * STDIO for SIO + */ + +int sio_putchar(int c); +int sio_puts(const char *str); +int sio_printf(const char *fmt, ...); +int sio_vprintf(const char *fmt, va_list ap); + +#endif + +#endif + diff --git a/libpsx/include/stdlib.h b/libpsx/include/stdlib.h new file mode 100644 index 0000000..0242213 --- /dev/null +++ b/libpsx/include/stdlib.h @@ -0,0 +1,66 @@ +/* + * stdlib.h + * + * Standard library functions + * + * PSXSDK + */ + +#ifndef _STDLIB_H +#define _STDLIB_H + +typedef unsigned int size_t; +typedef signed int ssize_t; + +/* Conversion functions */ + +int atoi(const char *s); +long atol(const char *s); +char *itoa(int value, char *str, int base); +char *ltoa(long value, char *str, int base); +char *lltoa(long long value, char *str, int base); +char *utoa(unsigned int value, char *str, int base); +char *ultoa(unsigned long value, char *str, int base); +char *ulltoa(unsigned long long value, char *str, int base); +//extern char atob(char *s); // Is this right? + + +// Random number functions + +#define RAND_MAX 0x7fffffff + +int rand(void); +void srand(unsigned int seed); + +// Quick sort + +void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); + +// Memory allocation functions + +//#warning "malloc() family of functions NEEDS MORE TESTING" + +void *malloc(size_t size); +void free(void *buf); +void *calloc(size_t number, size_t size); +void *realloc(void *buf , size_t n); + +int abs(int x); +long long strtoll(const char *nptr, char **endptr, int base); +long strtol(const char *nptr, char **endptr, int base); +double strtod(const char *nptr, char **endptr); +long double strtold(const char *nptr, char **endptr); +float strtof(const char *nptr, char **endptr); + +// Misc +void abort(void); +void exit(int status); +void call_atexit_callbacks(void); + +// Program return codes + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +#endif + diff --git a/libpsx/include/string.h b/libpsx/include/string.h new file mode 100644 index 0000000..5956b0d --- /dev/null +++ b/libpsx/include/string.h @@ -0,0 +1,64 @@ +/* + * string.h + * + * Prototypes for string functions of the C library + * + * PSXSDK + */ + +// NOTE: The BIOS was found to be unreliable for many functions, +// so it is not used anymore for the libc. + +#ifndef _STRING_H +#define _STRING_H + +#include <strings.h> // for backwards compatibility +#include <types.h> + +char *strcat(char *s , const char *append); +char *strncat(char *s , const char *append, size_t n); +int strcmp(const char *dst , const char *src); +int strncmp(const char *dst , const char *src , size_t len); +int stricmp(const char *s1, const char *s2); // alias of strcasecmp +int strnicmp(const char *s1, const char *s2, size_t len); // alias of strncasecmp +char *strcpy(char *dst , const char *src); +char *strncpy(char *dst , const char *src , size_t n); +int strlen(const char *s); +int strnlen(const char *s, size_t maxlen); +char *strchr(const char *s , int c); +char *strrchr(const char *s , int c); +char *strpbrk(const char *dst , const char *src); +int strspn(const char *s , const char *charset); +int strcspn(const char *s , const char *charset); +char *strsep(char **stringp, const char *delim); +char *strtok(char *str, const char *sep); +char *strstr(const char *big , const char *little); +char *strcasestr(const char *big, const char *little); +char *strlwr(char *string); +char *strupr(char *string); +char *strdup(const char *str); +char *strndup(const char *str, size_t len); +int strlcpy(char *dst, const char *src, size_t size); +int strlcat(char *dst, const char *src, size_t size); +int strcoll(const char *dst , const char *src); + +char *strerror(int errnum); +int strerror_r(int errnum, char *strerrbuf, size_t buflen); + +void *memset(void *dst , char c , size_t n); +void *memmove(void *dst , const void *src , size_t n); +int memcmp(const void *b1 , const void *b2 , size_t n); +void *memchr(void *s , int c , size_t n); +void *memrchr(void *b, int c, size_t len); +void *memcpy(void *dst , const void *src , size_t len); +void *memccpy(void *dst, const void *src, int c, size_t len); +void *memmem(const void *big, size_t big_len, const void *little, size_t little_len); + +// ffsl() and ffsll() are glibc extensions, and are in string.h +// instead of strings.h (like ffs()) for some reason.. + +int ffsl(long value); +int ffsll(long long value); + +#endif + diff --git a/libpsx/include/strings.h b/libpsx/include/strings.h new file mode 100644 index 0000000..7e9082f --- /dev/null +++ b/libpsx/include/strings.h @@ -0,0 +1,37 @@ +/* + * strings.h + * + * PSXSDK + */ + +#ifndef _STRINGS_H +#define _STRINGS_H + +#include <string.h> +#include <types.h> + +#define bcopy(src,dst,len) memmove(dst,src,len) +#define bzero(ptr, len) memset(ptr, 0, len) +#define bcmp(b1,b2,len) memcmp(b1,b2,len) +#define index(s, c) strchr(s, c) +#define rindex(s, c) strrchr(s, c) + +int ffs(int value); +char *index(const char *s, int c); +char *rindex(const char *s, int c); + +/** + * Returns the number of bits set in the value + * @param value Value + * @return Number of bits set in value + */ + +unsigned int popcount(unsigned int value); +unsigned int popcountl(unsigned long value); +unsigned int popcountll(unsigned long long value); +unsigned int popcount32(uint32_t value); +unsigned int popcount64(uint64_t value); +int strcasecmp(const char *s1, const char *s2); +int strncasecmp(const char *s1, const char *s2, size_t len); + +#endif diff --git a/libpsx/include/sys/stat.h b/libpsx/include/sys/stat.h new file mode 100644 index 0000000..5b0d7ca --- /dev/null +++ b/libpsx/include/sys/stat.h @@ -0,0 +1,19 @@ +/** + * PSXSDK + * + * sys/stat.h + */ + +#ifndef _SYS_STAT_H +#define _SYS_STAT_H + +struct stat +{ + unsigned int st_size; + unsigned int st_blksize; + unsigned int st_blocks; +}; + +int stat(const char *path, struct stat *sb); + +#endif diff --git a/libpsx/include/sys/types.h b/libpsx/include/sys/types.h new file mode 100644 index 0000000..2d6df2a --- /dev/null +++ b/libpsx/include/sys/types.h @@ -0,0 +1,11 @@ +#ifndef _SYS_TYPES_H
+#define _SYS_TYPES_H
+
+#include <types.h>
+
+typedef unsigned char u_char;
+typedef unsigned short u_short;
+typedef unsigned int u_int;
+typedef unsigned long u_long;
+
+#endif
diff --git a/libpsx/include/types.h b/libpsx/include/types.h new file mode 100644 index 0000000..395dac4 --- /dev/null +++ b/libpsx/include/types.h @@ -0,0 +1,10 @@ +#ifndef _TYPES_H +#define _TYPES_H + +typedef unsigned int size_t; +typedef signed int ssize_t; + +#include <inttypes.h> +#include <sys/types.h> + +#endif diff --git a/libpsx/include/unistd.h b/libpsx/include/unistd.h new file mode 100644 index 0000000..3ae6aa3 --- /dev/null +++ b/libpsx/include/unistd.h @@ -0,0 +1,22 @@ +/* + * unistd.h + * + * PSXSDK + */ + +#ifndef _UNISTD_H +#define _UNISTD_H + +#include <types.h> + +int lseek(int fd, int off, int whence); +int read(int fd, void *buf, int nbytes); +int write(int fd, void *buf, int nbytes); +int close(int fd); +int cd(char *dirname); + +void swab(const void *src, void *dst, ssize_t len); + +#define chdir(dirname) cd(dirname) + +#endif diff --git a/libpsx/src/atexit.c b/libpsx/src/atexit.c new file mode 100644 index 0000000..835aae3 --- /dev/null +++ b/libpsx/src/atexit.c @@ -0,0 +1,23 @@ +#include <stdlib.h> + +static void *f_ptr[32]; +static int f_ptr_pos = 0; + +int atexit(void (*function)(void)) +{ + if(f_ptr_pos >= 32) + return -1; + + f_ptr[f_ptr_pos++] = function; + + return 0; +} + +void call_atexit_callbacks(void) +{ + int i; + void (*f)(void); + + for(i = (f_ptr_pos - 1); i >= 0; i--) + (f = f_ptr[i])(); +} diff --git a/libpsx/src/cdrom.c b/libpsx/src/cdrom.c new file mode 100644 index 0000000..ca14fd4 --- /dev/null +++ b/libpsx/src/cdrom.c @@ -0,0 +1,240 @@ +/* + * Low-level CDROM library + */ + +#include <stdio.h> +#include <stdarg.h> +#include <psx.h> + +#define CDREG(x) *((unsigned char*)(0x1f801800+x)) + +void _internal_cdrom_handler(); +void (*cdrom_handler_callback)(); +volatile int cdrom_command_direct = 0; +volatile int cdrom_command_done = 0; +volatile int cdrom_direct_cmd; +volatile int cdrom_command_dpos = 0; +volatile unsigned char cdrom_last_command; +volatile unsigned char cdrom_command_stat[2]; + +unsigned int cdrom_queue_buf[4] = {0x0, /* Will contain next interrupt handler in queue */ + 0x0, /* func1 */ + (unsigned int)_internal_cdrom_handler, /* func2 */ + 0x0, /* pad */ + }; + +static const unsigned char cdrom_command_type[0x1F] = // 0 = single int, 1 = double int, 2,3,... = others +{ + 0, // Sync 0 + 0, // GetStat/Nop 1 + 0, // Setloc 2 + 0, // Play 3 + 0, // Forward 4 + 0, // Backward 5 + 0, // ReadN 6 + 0, // Standby 7 + 0, // Stop 8 + 1, // Pause 9 + 1, // Init A + 0, // Mute B + 0, // Demute C + 0, // Setfilter D + 0, // Setmode E + 0, // Getmode F + 0, // GetlocL 10 + 0, // GetlocP 11 + 0xFF, // ??? 12 + 0, // GetTN 13 + 0, // GetTD 14 + 1, // SeekL 15 + 1, // SeekP 16 + 0xFF, // ??? 17 + 0xFF, // ??? 18 + 0, // Test 19 + 1, // ID 1A + 0, // ReadS 1B + 0, // Reset 1C + 0xFF, // ??? 1D + 1, // ReadToc 1E +}; + +void CdSendCommand(int cmd, int num, ...) +{ + int x; + va_list ap; + va_start(ap, num); + +// Wait for command execution to end +// while(CDREG(0) & 128); + +// Flush old interrupts +// If this is not done, some events (like the opening of the shell) will hang the CD controller. + + CDREG(0) = 1; + CDREG(3) = 7; + +// Send parameters + + CDREG(0) = 0; + + while(num) + { + CDREG(2) = (unsigned char)va_arg(ap, unsigned int); + num--; + } + +// Send command + + CDREG(0) = 0; + CDREG(1) = cmd; + +// Depending on the number of INTs we expect for a command, +// we wait for an INT to occur, we store the response data returned, +// and we flush the INT. + for(x = 0; x < (cdrom_command_type[cmd] + 1); x++) + { + CDREG(0) = 1; + while((CDREG(3) & 7) == 0); + + cdrom_command_stat[x] = CDREG(1); + + CDREG(0) = 1; + CDREG(3) = 7; + } + +// Store ID number of last executed command (this) + cdrom_last_command = cmd; + + va_end(ap); +} + +int CdReadResults(unsigned char *out, int max) +{ + int x; + unsigned char *outo = out; + unsigned char b; + + for(x = 0; x < (cdrom_command_type[cdrom_last_command] + 1); x++) + { + if(max > 0) + { + *(out++) = cdrom_command_stat[x]; + max--; + } + } + + CDREG(0) = 1; + + while(CDREG(0) & 0x20) + { + b = CDREG(1); + if(max>0) + { + *(out++) = b; + max--; + } + } + + return (out-outo); +} + +void _internal_cdromlib_callback() +{ + // 0 = ACKNOWLEDGE (0x*2) + // 1 = ACKNOWLEDGE (0x*2), COMPLETE (0x*3) + +/* int x; + + + + unsigned char i; + + + if(cdrom_command_done) + return; + + for(x = 0; x < 100; x++); // Waste time + + CDREG(0) = 1; + i=CDREG(3); + + if((i&0xf)==5) // Error + cdrom_command_done = 1; + + //printf("i&0xf = %x\n", i&0xf); +// printf("cdrom_direct_cmd = %x\n", cdrom_direct_cmd); + + switch(kind[cdrom_direct_cmd]) + { + case 0: + if(((i&0xf)==3) || ((i&0xf) == 2)) + cdrom_command_done = 1; + break; + + case 1: + if((i&0xf)==2) + cdrom_command_done = 1; + break; + + case 0xFF: // Unknown command! + cdrom_command_done = 1; + return; + break; + } + + cdrom_command_stat[0] = i; + + for(x = 0; x < 100; x++); // Waste time + + CDREG(0) = 1; + CDREG(3) = 7; + i = CDREG(1); + cdrom_command_stat[1] = i; + + //printf("cdrom_command_done = %d\n", cdrom_command_done);*/ +} + +void _internal_cdromlib_init() +{ + printf("Starting CDROMlib...\n"); + + EnterCriticalSection(); // Disable IRQs + + SysEnqIntRP(0, cdrom_queue_buf); + + IMASK|=4; + + cdrom_handler_callback = _internal_cdromlib_callback; + + ExitCriticalSection(); // Enable IRQs +} + +int CdGetStatus() +{ + unsigned char out; + + CdSendCommand(CdlGetstat, 0); + CdReadResults(&out, 1); + + return out; +} + +int CdPlayTrack(unsigned int track) +{ + while(CdGetStatus() & CDSTATUS_SEEK); + CdSendCommand(CdlSetmode, 1, 0x20); + CdSendCommand(CdlPlay, 1, ((track/10)<<4)|(track%10)); + + return 1; +} + +unsigned char CdRamRead(unsigned short addr) +{ + unsigned char b; + addr &= 0x3ff; + + CdSendCommand(0x19, 0x60, addr&0xff, addr >> 8); + CdReadResults(&b, 1); + + return b; +} diff --git a/libpsx/src/cdromh.s b/libpsx/src/cdromh.s new file mode 100644 index 0000000..b2968c1 --- /dev/null +++ b/libpsx/src/cdromh.s @@ -0,0 +1,109 @@ +.global _internal_cdrom_handler +.set noat + + +_internal_cdrom_handler: + addi $sp, -112 + sw $at, 0($sp) + sw $v0, 4($sp) + sw $v1, 8($sp) + sw $a0, 12($sp) + sw $a1, 16($sp) + sw $a2, 20($sp) + sw $a3, 24($sp) + sw $t0, 28($sp) + sw $t1, 32($sp) + sw $t2, 36($sp) + sw $t3, 40($sp) + sw $t4, 44($sp) + sw $t5, 48($sp) + sw $t6, 52($sp) + sw $t7, 56($sp) + sw $s0, 60($sp) + sw $s1, 64($sp) + sw $s2, 68($sp) + sw $s3, 72($sp) + sw $s4, 76($sp) + sw $s5, 80($sp) + sw $s6, 84($sp) + sw $s7, 88($sp) + sw $t8, 92($sp) + sw $t9, 96($sp) + sw $gp, 100($sp) + sw $s8, 104($sp) + sw $ra, 108($sp) + +# Do not run code if cdrom interrupt is not enabled + + li $t0, 0x1f801074 + lw $t1, 0($t0) + andi $t1, $t1, 4 + beq $t1, $zero, cdrom_handler_end + nop + +# Do not run code if cdrom interrupt is not pending + + li $t0, 0x1f801070 + lw $t1, 0($t0) + andi $t1, $t1, 4 + beq $t1, $zero, cdrom_handler_end + nop + +# If the CDROM command isn't direct +# (direct = sent by us and not by the BIOS' ISO9660 routines) +# exit and let the BIOS do its work. + +cdrom_check_direct_cmd: + la $t0, cdrom_command_direct + lw $t1, 0($t0) + beq $t1, $zero, cdrom_handler_end + nop + +cdrom_fire_user_handler: + la $t0, cdrom_handler_callback + lw $t1, 0($t0) + + jalr $t1 + nop + +# Remove bit for CDROM interrupt (bit 2) from pending interrupts mask. + +cdrom_handler_remove_pending: + li $t0, 0x1f801070 + lw $t1, 0($t0) + xori $t1, $t1, 4 + sw $t1, 0($t0) + +cdrom_handler_end: + + lw $at, 0($sp) + lw $v0, 4($sp) + lw $v1, 8($sp) + lw $a0, 12($sp) + lw $a1, 16($sp) + lw $a2, 20($sp) + lw $a3, 24($sp) + lw $t0, 28($sp) + lw $t1, 32($sp) + lw $t2, 36($sp) + lw $t3, 40($sp) + lw $t4, 44($sp) + lw $t5, 48($sp) + lw $t6, 52($sp) + lw $t7, 56($sp) + lw $s0, 60($sp) + lw $s1, 64($sp) + lw $s2, 68($sp) + lw $s3, 72($sp) + lw $s4, 76($sp) + lw $s5, 80($sp) + lw $s6, 84($sp) + lw $s7, 88($sp) + lw $t8, 92($sp) + lw $t9, 96($sp) + lw $gp, 100($sp) + lw $s8, 104($sp) + lw $ra, 108($sp) + addi $sp, 112 + jr $ra + nop diff --git a/libpsx/src/cop.c b/libpsx/src/cop.c new file mode 100644 index 0000000..04b49f5 --- /dev/null +++ b/libpsx/src/cop.c @@ -0,0 +1,111 @@ +#include <psx.h> + +unsigned int get_cop_register(unsigned char cop_num, + unsigned char register_num) +{ +// Workaround for MIPS' simplicistic instruction set... + + unsigned int instr[] = + {0x40020000, // cfc $v0, 0 + 0x03E00008, // jr $ra + 0x00000000, // nop + 0x00000000}; // nop + + int (*rawFunc)() = (void*)instr; + +// Write coprocessor register number inside instruction + instr[0] |= ( (cop_num & 3) << 26 ) | ( (register_num & 31) << 11 ); + +// Execute modified instruction + return rawFunc(); +} + +unsigned int get_cop_ctrl_register(unsigned char cop_num, + unsigned char register_num) +{ +// Workaround for MIPS' simplicistic instruction set... + unsigned int instr[] = + {0x40420000, // mfc $v0, 0 + 0x03E00008, // jr $ra + 0x00000000, // nop + 0x00000000}; // nop + + int (*rawFunc)() = (void*)instr; + +// Write coprocessor register number inside instruction + instr[0] |= ( (cop_num & 3) << 26 ) | ( (register_num & 31) << 11 ); + +// Execute modified instruction + return rawFunc(); +} + +unsigned int get_cop0_register(unsigned char register_num) +{ + return get_cop_register(0, register_num); +} + +void set_cop_register(unsigned char cop_num, + unsigned char register_num, + unsigned int value) +{ +// Workaround for MIPS' simplicistic instruction set... + unsigned int instr[] = + {0x40840000, // mtc $a0, 0 + 0x03E00008, // jr $ra + 0x00000000, // nop + 0x00000000}; // nop + + void (*rawFunc)(int value) = (void*)instr; + +// Write coprocessor register number inside instruction + instr[0] |= ( (cop_num & 3) << 26 ) | ( (register_num & 31) << 11 ); + +// Execute modified instruction + rawFunc(value); +} + +void set_cop_ctrl_register(unsigned char cop_num, + unsigned char register_num, + unsigned int value) +{ +// Workaround for MIPS' simplicistic instruction set... + unsigned int instr[] = + {0x40C40000, // ctc $a0, 0 + 0x03E00008, // jr $ra + 0x00000000, // nop + 0x00000000}; // nop + + void (*rawFunc)(int value) = (void*)instr; + +// Write coprocessor register number inside instruction + instr[0] |= ( (cop_num & 3) << 26 ) | ( (register_num & 31) << 11 ); + +// Execute modified instruction + rawFunc(value); +} + +void set_cop0_register(unsigned char register_num, + unsigned int value) +{ + set_cop_register(0, register_num, value); +} + +void run_cop_instruction(unsigned char cop_num, + unsigned int operation) +{ +// Workaround for MIPS' simplicistic instruction set... + unsigned int instr[] = + {0x42000000, // cop 0 + 0x03E00008, // jr $ra + 0x00000000, // nop + 0x00000000}; // nop + + void (*rawFunc)(void) = (void*)instr; + +// Write coprocessor register number inside instruction + instr[0] |= ( (cop_num & 3) << 26 ) | (operation & 0x1ffffff); + +// Execute modified instruction + rawFunc(); +} + diff --git a/libpsx/src/costbl.h b/libpsx/src/costbl.h new file mode 100644 index 0000000..2af73a6 --- /dev/null +++ b/libpsx/src/costbl.h @@ -0,0 +1,26 @@ +// Cosine / sine table used for rotations, 1 degree precision +// While not as good, much faster than using libm cos() and sin() and does not require +// to link libm with libpsx.. + +const double gs_rot_cos_tbl[]= +{ + 1.000000,0.999848,0.999391,0.998630,0.997564, + 0.996195,0.994522,0.992546,0.990268,0.987688, + 0.984808,0.981627,0.978148,0.974370,0.970296, + 0.965926,0.961262,0.956305,0.951057,0.945519, + 0.939693,0.933580,0.927184,0.920505,0.913545, + 0.906308,0.898794,0.891007,0.882948,0.874620, + 0.866025,0.857167,0.848048,0.838671,0.829038, + 0.819152,0.809017,0.798636,0.788011,0.777146, + 0.766044,0.754710,0.743145,0.731354,0.719340, + 0.707107,0.694658,0.681998,0.669131,0.656059, + 0.642788,0.629320,0.615661,0.601815,0.587785, + 0.573576,0.559193,0.544639,0.529919,0.515038, + 0.500000,0.484810,0.469472,0.453990,0.438371, + 0.422618,0.406737,0.390731,0.374607,0.358368, + 0.342020,0.325568,0.309017,0.292372,0.275637, + 0.258819,0.241922,0.224951,0.207912,0.190809, + 0.173648,0.156434,0.139173,0.121869,0.104528, + 0.087156,0.069756,0.052336,0.034899,0.017452, + 0.000000, +}; diff --git a/libpsx/src/exc1.s b/libpsx/src/exc1.s new file mode 100644 index 0000000..379ed6d --- /dev/null +++ b/libpsx/src/exc1.s @@ -0,0 +1,96 @@ + +.text +.global __psxsdk_exception_manager + +__psxsdk_exception_manager: + +# Save registers on stack + +.set noat + addi $sp, -120 +.set noat + sw $at, 0($sp) + mfhi $at + sw $at, 112($sp) + mflo $at + sw $at, 116($sp) +.set at + sw $v0, 4($sp) + sw $v1, 8($sp) + sw $a0, 12($sp) + sw $a1, 16($sp) + sw $a2, 20($sp) + sw $a3, 24($sp) + sw $t0, 28($sp) + sw $t1, 32($sp) + sw $t2, 36($sp) + sw $t3, 40($sp) + sw $t4, 44($sp) + sw $t5, 48($sp) + sw $t6, 52($sp) + sw $t7, 56($sp) + sw $s0, 60($sp) + sw $s1, 64($sp) + sw $s2, 68($sp) + sw $s3, 72($sp) + sw $s4, 76($sp) + sw $s5, 80($sp) + sw $s6, 84($sp) + sw $s7, 88($sp) + sw $t8, 92($sp) + sw $t9, 96($sp) + sw $gp, 100($sp) + sw $fp, 104($sp) + sw $ra, 108($sp) + +# Execute real exception handler + jal __psxsdk_real_exception_handler + nop + +# Load registers from stack + +.set noat + lw $at, 112($sp) + nop + mthi $at + lw $at, 116($sp) + nop + mtlo $at + lw $at, 0($sp) +.set at + lw $v0, 4($sp) + lw $v1, 8($sp) + lw $a0, 12($sp) + lw $a1, 16($sp) + lw $a2, 20($sp) + lw $a3, 24($sp) + lw $t0, 28($sp) + lw $t1, 32($sp) + lw $t2, 36($sp) + lw $t3, 40($sp) + lw $t4, 44($sp) + lw $t5, 48($sp) + lw $t6, 52($sp) + lw $t7, 56($sp) + lw $s0, 60($sp) + lw $s1, 64($sp) + lw $s2, 68($sp) + lw $s3, 72($sp) + lw $s4, 76($sp) + lw $s5, 80($sp) + lw $s6, 84($sp) + lw $s7, 88($sp) + lw $t8, 92($sp) + lw $t9, 96($sp) + lw $gp, 100($sp) + lw $fp, 104($sp) + lw $ra, 108($sp) + addiu $sp, 120 + +# Get exception return address.. + mfc0 $k0, $14 +# Exit from exception handler +.set noreorder # Do not let the assembler fill the delay slot! + jr $k0 + rfe +.set reorder # The assembler can fill the delay slot again. diff --git a/libpsx/src/exception.c b/libpsx/src/exception.c new file mode 100644 index 0000000..6ecabb2 --- /dev/null +++ b/libpsx/src/exception.c @@ -0,0 +1,178 @@ +/** + * exception.c + * + * Exception handling code (part 2) + */ + + #include <stdio.h> + #include <stdlib.h> + #include <psx.h> + +#define DICR *((unsigned int*)0x1f8010f4) +#define IPENDING *((volatile unsigned int*)0x1f801070) +#define IMASK *((volatile unsigned int*)0x1f801074) + +void __psxsdk_exception_manager(); + +void (*_EXC_vblank_handler)(); +void (*_EXC_cdrom_handler)(); +void (*_EXC_sio_handler)(unsigned char *data); +void (*_EXC_dma_handler)(); +unsigned int _EXC_vblank_handler_set; +unsigned int _EXC_cdrom_handler_set; +unsigned int _EXC_sio_handler_set; +unsigned int _EXC_dma_handler_set; + +volatile int __psxsdk_gpu_dma_finished; + +void __psxsdk_real_exception_handler() +{ + unsigned int Cause = get_cop0_register(COP0_CAUSE); + unsigned int Cause_excCode = (Cause >> 2) & 31; + unsigned int Cause_IP = (Cause >> 8) & 255; + unsigned int SR = get_cop0_register(COP0_SR); + unsigned int SR_IM = (SR >> 8) & 255; + int i; +/* unsigned int oldSR = SR; + unsigned int psxIP = IPENDING; + unsigned int psxIM = IMASK; + unsigned int sio_data;*/ + + if(Cause_excCode == 0) // interrupt generated the exception + { + /*for(i = 0; i < 8; i++) + { + if((Cause_IP & (1<<i)) && (SR_IM & (1<<i))) + { + SR ^= 1<<(i+8); + set_cop0_register(COP0_SR, SR); + + switch(i) + { + case 2: // PSX Interrupt controller + // program_vblank_handler(); + break; + } + } + }*/ + + if((Cause_IP & (1<<2)) && (SR_IM & (1<<2))) + { + Cause ^= 1<<10; + set_cop0_register(COP0_CAUSE, Cause); + //SR ^= 1<<10; + //set_cop0_register(COP0_SR, SR); + + //while(IPENDING != 0) + { + for(i = 0; i < 11; i++) + { + if(IPENDING & (1<<i)) + { + // printf("IP = %x\n", IPENDING); +// Very interesting, when reading joypad status the PCSXR emulator sets in IPENDING that IRQ7 is pending even +// if it is not enabled in IMASK! That is insane, but it can be easily worked around. +// So we are going to disable pending bits for IRQs in IPENDING in any case, even if the in IRQ at hand was +// not enabled in IMASK. + + IPENDING ^= 1 << i; + + if(IMASK & (1<<i)) + { + // printf("IM = %x\n", IMASK); + + switch(i) + { + case 0: // VBLANK + // if(!(GPU_CONTROL_PORT & (1<<0x1c))) + // GPU_CONTROL_PORT = 0x02000000; + + // Execute the user-supplied VBlank handler. + if(_EXC_vblank_handler_set) + _EXC_vblank_handler(); + break; + case 2: + /* if(_EXC_cdrom_handler_set) + _EXC_cdrom_handler();*/ + break; + case 3: // DMA + // Execute the user-supplied DMA handler. + if(_EXC_dma_handler_set) + _EXC_dma_handler(); + break; + case 8: + //while(!(SIO_STAT & 2)) + //sio_data = SIO_RX_DATA; + + //_EXC_sio_handler((unsigned char*)&sio_data); + + // SIO_CTRL |= SIOCTRL_ACK; + break; + } + } + } + } + } + } + } +} + +static void __psxsdk_dma_handler() +{ + unsigned int s_dicr = DICR; + unsigned char irq = (s_dicr >> 24) & 127; + + if(irq & (1<<2)) // GPU + __psxsdk_gpu_dma_finished = 1; + + // Acknowledge + DICR = s_dicr; + + // Waste some cycles, so that the acknowledgement is reported +// int x; + +// for(x = 0; x < 1000; x++); +} + +extern void _internal_cdromlib_callback(); + + void __PSX_Init_NoBios() + { + _EXC_vblank_handler = NULL; + _EXC_cdrom_handler = _internal_cdromlib_callback; + _EXC_dma_handler = __psxsdk_dma_handler; + _EXC_sio_handler = NULL; + + _EXC_vblank_handler_set = 0; + _EXC_cdrom_handler_set = 0; + _EXC_dma_handler_set = 1; + _EXC_sio_handler_set = 0; + + IMASK = 0; // Clear Mask + IPENDING = 0; // Clear pending interrupts + +// Disable interrupts + + set_cop0_register(COP0_SR, 0); + +// Change exception vector to point to our exception manager + + *((unsigned int*)0x80000080) = 0x08000000 | ((((unsigned int)__psxsdk_exception_manager)>>2) & 0x3FFFFFF); + *((unsigned int*)0x80000084) = 0; + + +// Enable interrupt generation, and interrupt 2 (PlayStation Interrupt Controller) + set_cop0_register(COP0_SR, (1<<10) | 1); + +// Enable VBlank, CDROM and DMA IRQs (on PlayStation Interrupt Controller) + IMASK = 1 | /* CDROM */ /*4 |*/ 8; + +// Set DMA channel priority + DPCR = 0x07654321; + +// Enable DMA IRQ master, and IRQ generation for DMA channel 2 (GPU) + DICR = (1<<23) | (1<<(16+2)); + +// Setup variables + __psxsdk_gpu_dma_finished = 1; +} diff --git a/libpsx/src/exception.h b/libpsx/src/exception.h new file mode 100644 index 0000000..1c72798 --- /dev/null +++ b/libpsx/src/exception.h @@ -0,0 +1,14 @@ +#ifndef _PSXSDK_EXCEPTION_H +#define _PSXSDK_EXCEPTION_H + +extern void (*_EXC_vblank_handler)(); +extern void (*_EXC_sio_handler)(unsigned char *data); +extern void (*_EXC_dma_handler)(); +extern unsigned int _EXC_vblank_handler_set; +extern unsigned int _EXC_sio_handler_set; +extern unsigned int _EXC_dma_handler_set; + + +void __PSX_Init_NoBios(); + +#endif diff --git a/libpsx/src/font.h b/libpsx/src/font.h new file mode 100644 index 0000000..b1c71cb --- /dev/null +++ b/libpsx/src/font.h @@ -0,0 +1,266 @@ +// 8x8 ASCII font +// 64x128 +// 4-bit format + +// The font was created by John Reeves Hall + +unsigned char psxsdk_font_data[] = +{ +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 1, 0, 0, 16, 16, 0, 0, 16, 16, 0, +0, 0, 1, 0, 0, 0, 0, 0, 0, 16, 1, 0, 0, 0, 1, 0, +0, 0, 0, 0, 0, 0, 1, 0, 0, 16, 16, 0, 0, 16, 16, 0, +0, 16, 17, 1, 0, 17, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 16, 17, 17, 17, +0, 1, 1, 0, 0, 17, 16, 0, 0, 16, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 16, 16, 0, +0, 16, 17, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 16, 17, 17, 17, +0, 0, 1, 1, 0, 16, 16, 1, 16, 0, 16, 1, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 0, +0, 17, 17, 0, 0, 1, 16, 1, 16, 0, 16, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 16, 16, 0, +0, 0, 1, 0, 0, 0, 0, 0, 0, 17, 1, 1, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, +0, 0, 1, 0, 0, 0, 1, 0, 16, 0, 1, 16, 0, 0, 1, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, +0, 16, 0, 0, 0, 0, 16, 0, 0, 1, 1, 1, 0, 0, 1, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, +0, 16, 0, 0, 0, 0, 16, 0, 0, 16, 17, 0, 16, 17, 17, 17, +0, 0, 0, 0, 16, 17, 17, 17, 0, 0, 0, 0, 0, 0, 1, 0, +0, 16, 0, 0, 0, 0, 16, 0, 0, 1, 1, 1, 0, 0, 1, 0, +0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, +0, 0, 1, 0, 0, 0, 1, 0, 16, 0, 1, 16, 0, 0, 1, 0, +0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 1, 0, 0, +0, 0, 16, 0, 0, 16, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, +0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 16, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 16, 17, 0, 0, 0, 1, 0, 0, 16, 17, 0, 0, 16, 17, 0, +0, 0, 17, 0, 0, 17, 17, 1, 0, 16, 17, 0, 0, 17, 17, 1, +0, 1, 0, 1, 0, 16, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, +0, 16, 16, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, +0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, +0, 1, 16, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 16, 0, +0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 16, 0, 0, 0, 17, 0, +0, 17, 17, 1, 0, 17, 17, 0, 0, 17, 17, 0, 0, 0, 1, 0, +0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, +0, 0, 16, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 16, 0, 0, +0, 1, 0, 1, 0, 0, 1, 0, 0, 16, 0, 0, 0, 1, 0, 1, +0, 0, 16, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 16, 0, 0, +0, 16, 17, 0, 0, 16, 17, 0, 0, 17, 17, 1, 0, 16, 17, 0, +0, 0, 17, 1, 0, 16, 17, 0, 0, 16, 17, 0, 0, 16, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 16, 17, 0, 0, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 16, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 16, 17, 0, +0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 17, 0, 0, 0, 17, 0, +0, 0, 1, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 1, 0, 1, +0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 17, 0, 0, 0, 17, 0, +0, 16, 0, 0, 16, 17, 17, 17, 0, 0, 1, 0, 0, 0, 0, 1, +0, 16, 17, 0, 0, 16, 17, 1, 0, 0, 0, 0, 0, 0, 0, 0, +0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 16, 0, +0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 17, 0, 0, 0, 17, 0, +0, 16, 0, 0, 16, 17, 17, 17, 0, 0, 1, 0, 0, 0, 1, 0, +0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 17, 0, 0, 0, 17, 0, +0, 0, 1, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, +0, 16, 17, 0, 0, 16, 17, 0, 0, 0, 0, 0, 0, 0, 16, 0, +0, 0, 16, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 16, 17, 0, 0, 16, 17, 0, 0, 17, 17, 0, 0, 16, 17, 0, +0, 17, 17, 0, 0, 17, 17, 1, 0, 17, 17, 1, 0, 16, 17, 0, +0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, +0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, +0, 1, 17, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, +0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, +0, 1, 1, 1, 0, 17, 17, 1, 0, 17, 17, 0, 0, 1, 0, 0, +0, 1, 0, 1, 0, 17, 17, 0, 0, 17, 17, 1, 0, 1, 17, 1, +0, 1, 17, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, +0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, +0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, +0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, +0, 16, 17, 0, 0, 1, 0, 1, 0, 17, 17, 0, 0, 16, 17, 0, +0, 17, 17, 0, 0, 17, 17, 1, 0, 1, 0, 0, 0, 16, 17, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 1, 0, 1, 0, 16, 17, 0, 0, 0, 17, 1, 0, 1, 0, 1, +0, 16, 0, 0, 16, 0, 0, 16, 0, 1, 0, 1, 0, 16, 17, 0, +0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 16, 0, 0, 1, 0, 1, +0, 16, 0, 0, 16, 1, 0, 17, 0, 17, 0, 1, 0, 1, 0, 1, +0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 16, 0, 0, 1, 16, 0, +0, 16, 0, 0, 16, 16, 16, 16, 0, 1, 1, 1, 0, 1, 0, 1, +0, 17, 17, 1, 0, 0, 1, 0, 0, 0, 16, 0, 0, 17, 1, 0, +0, 16, 0, 0, 16, 0, 1, 16, 0, 1, 1, 1, 0, 1, 0, 1, +0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 16, 0, 0, 1, 16, 0, +0, 16, 0, 0, 16, 0, 0, 16, 0, 1, 16, 1, 0, 1, 0, 1, +0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 16, 0, 0, 1, 0, 1, +0, 16, 0, 0, 16, 0, 0, 16, 0, 1, 0, 1, 0, 1, 0, 1, +0, 1, 0, 1, 0, 16, 17, 0, 0, 16, 1, 0, 0, 1, 0, 1, +0, 16, 17, 1, 16, 0, 0, 16, 0, 1, 0, 1, 0, 16, 17, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 16, 17, 0, 0, 16, 17, 0, 0, 17, 17, 0, 0, 16, 17, 0, +0, 17, 17, 1, 0, 1, 0, 1, 0, 1, 0, 1, 16, 0, 0, 16, +0, 16, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, +0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 16, 0, 0, 16, +0, 16, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, +0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 16, 0, 0, 16, +0, 16, 17, 0, 0, 1, 0, 1, 0, 17, 17, 0, 0, 16, 17, 0, +0, 0, 1, 0, 0, 1, 0, 1, 0, 16, 16, 0, 0, 1, 1, 1, +0, 16, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, +0, 0, 1, 0, 0, 1, 0, 1, 0, 16, 16, 0, 0, 1, 1, 1, +0, 16, 0, 0, 0, 1, 0, 1, 0, 1, 16, 0, 0, 1, 0, 1, +0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 16, 16, 0, +0, 16, 0, 0, 0, 16, 17, 0, 0, 1, 0, 1, 0, 16, 17, 0, +0, 0, 1, 0, 0, 16, 17, 0, 0, 0, 1, 0, 0, 16, 16, 0, +0, 0, 0, 0, 0, 0, 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 1, 0, 1, 0, 1, 0, 1, 0, 17, 17, 1, 0, 16, 17, 0, +16, 0, 0, 0, 0, 16, 17, 0, 0, 0, 1, 0, 0, 0, 0, 0, +0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 16, 0, 0, +0, 1, 0, 0, 0, 0, 16, 0, 0, 16, 16, 0, 0, 0, 0, 0, +0, 16, 16, 0, 0, 16, 16, 0, 0, 0, 16, 0, 0, 16, 0, 0, +0, 16, 0, 0, 0, 0, 16, 0, 0, 1, 0, 1, 0, 0, 0, 0, +0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 16, 0, 0, +0, 0, 1, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 16, 16, 0, 0, 0, 1, 0, 0, 16, 0, 0, 0, 16, 0, 0, +0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 16, 0, 0, +0, 0, 0, 1, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 1, 0, 1, 0, 0, 1, 0, 0, 17, 17, 1, 0, 16, 17, 0, +0, 0, 0, 16, 0, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 17, 17, 17, +0, 16, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, +0, 0, 1, 0, 0, 16, 17, 0, 0, 16, 0, 0, 0, 0, 0, 0, +0, 0, 0, 1, 0, 0, 0, 0, 0, 16, 0, 1, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 1, 0, 16, 17, 0, 0, 16, 17, 0, +0, 0, 17, 1, 0, 16, 17, 0, 0, 16, 0, 0, 0, 16, 17, 16, +0, 0, 0, 0, 0, 16, 17, 1, 0, 16, 0, 1, 0, 1, 0, 0, +0, 16, 0, 1, 0, 1, 0, 1, 0, 17, 1, 0, 0, 1, 0, 1, +0, 0, 0, 0, 0, 1, 0, 1, 0, 16, 0, 1, 0, 1, 0, 0, +0, 16, 0, 1, 0, 17, 17, 1, 0, 16, 0, 0, 0, 1, 0, 1, +0, 0, 0, 0, 0, 1, 0, 1, 0, 16, 0, 1, 0, 1, 0, 0, +0, 16, 0, 1, 0, 1, 0, 0, 0, 16, 0, 0, 0, 16, 17, 1, +0, 0, 0, 0, 0, 16, 17, 16, 0, 1, 17, 0, 0, 16, 17, 0, +0, 0, 17, 16, 0, 16, 17, 0, 0, 16, 0, 0, 0, 0, 0, 1, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 17, 0, +0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, +0, 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, +0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 1, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 16, 0, +0, 0, 1, 0, 1, 17, 16, 1, 0, 1, 17, 0, 0, 16, 17, 0, +0, 17, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, +0, 0, 1, 0, 16, 0, 1, 16, 0, 16, 0, 1, 0, 1, 0, 1, +0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 17, 0, 0, +0, 0, 1, 0, 16, 0, 1, 16, 0, 16, 0, 1, 0, 1, 0, 1, +0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, +0, 0, 1, 0, 16, 0, 0, 16, 0, 16, 0, 1, 0, 1, 0, 1, +0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 16, 0, +0, 0, 1, 0, 16, 0, 0, 16, 0, 16, 0, 1, 0, 16, 17, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 1, 17, 0, 0, 16, 1, 1, 0, 1, 17, 0, 0, 16, 17, 0, +0, 16, 17, 0, 0, 1, 16, 0, 0, 1, 0, 1, 16, 0, 0, 16, +0, 16, 0, 1, 0, 1, 16, 0, 0, 17, 0, 0, 0, 1, 0, 0, +0, 0, 1, 0, 0, 1, 16, 0, 0, 1, 0, 1, 16, 0, 0, 16, +0, 16, 0, 1, 0, 1, 16, 0, 0, 1, 0, 0, 0, 16, 1, 0, +0, 0, 1, 0, 0, 1, 16, 0, 0, 1, 0, 1, 16, 0, 1, 16, +0, 16, 17, 0, 0, 16, 17, 0, 0, 1, 0, 0, 0, 0, 16, 0, +0, 0, 1, 0, 0, 1, 16, 0, 0, 16, 16, 0, 16, 16, 16, 16, +0, 16, 0, 0, 0, 0, 16, 0, 0, 1, 0, 0, 0, 17, 1, 0, +0, 0, 1, 0, 0, 16, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, +0, 16, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, +0, 0, 1, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, +0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 1, 0, 1, 0, 16, 0, 1, 0, 17, 17, 0, 0, 16, 0, 0, +0, 0, 1, 0, 0, 0, 1, 0, 0, 17, 0, 0, 0, 0, 0, 0, +0, 16, 16, 0, 0, 16, 0, 1, 0, 0, 16, 0, 0, 1, 0, 0, +0, 0, 1, 0, 0, 0, 16, 0, 16, 0, 1, 16, 0, 0, 0, 0, +0, 0, 1, 0, 0, 16, 0, 1, 0, 0, 1, 0, 0, 16, 0, 0, +0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 16, 1, 0, 0, 0, 0, +0, 16, 16, 0, 0, 0, 17, 1, 0, 16, 0, 0, 0, 16, 0, 0, +0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 1, 0, 1, 0, 0, 0, 1, 0, 17, 17, 0, 0, 0, 17, 0, +0, 0, 1, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; diff --git a/libpsx/src/gpu.c b/libpsx/src/gpu.c new file mode 100644 index 0000000..7e097c6 --- /dev/null +++ b/libpsx/src/gpu.c @@ -0,0 +1,1507 @@ +// PSXSDK Graphics Processing Unit (GPU) / Graphics Synthesizer (GS) +// Routines + +#include <psx.h> +#include <stdio.h> +#include <strings.h> +#include "font.h" +#include "costbl.h" + +extern volatile int __psxsdk_gpu_dma_finished; + +static unsigned int *linked_list; +static unsigned int linked_list_pos; + +int fb_font_x, fb_font_y, fb_font_cx, fb_font_cy; + +static unsigned int prfont_flags = 0; +static int prfont_scale_x = 0; +static int prfont_scale_y = 0; +static unsigned char prfont_rl = NORMAL_LUMINANCE; +static unsigned char prfont_gl = NORMAL_LUMINANCE; +static unsigned char prfont_bl = NORMAL_LUMINANCE; + +unsigned short GsScreenW; +unsigned short GsScreenH; +unsigned char GsScreenM; + +unsigned short GsCurDrawEnvW; +unsigned short GsCurDrawEnvH; + +double gs_vbuf[4][3]; + +static int __gs_autowait = 0; + +unsigned int PRFONT_SCALEX(int i) +{ + prfont_scale_x = i; + return PRFONT_SCALE; +} + +unsigned int PRFONT_SCALEY(int i) +{ + prfont_scale_y = i; + return PRFONT_SCALE; +} + +unsigned int PRFONT_RL(unsigned char f) +{ + prfont_rl = f; + return PRFONT_COLOR; +} + +unsigned int PRFONT_GL(unsigned char f) +{ + prfont_gl = f; + return PRFONT_COLOR; +} + +unsigned int PRFONT_BL(unsigned char f) +{ + prfont_bl = f; + return PRFONT_COLOR; +} + +unsigned int draw_mode_packet; + +unsigned int setup_attribs(unsigned char tpage, unsigned int attribute, unsigned char *packet); +static void gs_internal_vector_rotate(int x_a, int y_a, int z_a, double *v, double *n); + +static char gpu_stringbuf[512]; + +int gs_calculate_scaled_size(int size, int scale) +{ + if(scale > 8) + return (size * scale) / SCALE_ONE; + else if(scale == 0) + return size; + else if(scale > 0) + return size * scale; + else if(scale > -8) + return size / (scale * -1); + + return (size * SCALE_ONE) / -scale; +} + +void GsSetList(unsigned int *listptr) +{ + linked_list = listptr; + linked_list_pos = 0; +} + +void GsDrawList() +{ + if(PSX_GetInitFlags() & PSX_INIT_NOBIOS) + { +// DMA is unreliable right now, use PIO. + GsDrawListPIO(); + return; + } + + //int x = 0; + + /* Put a terminator, so the link listed ends. */ + linked_list[linked_list_pos] = 0x00ffffff; + +// do{printf("linked_list[%d] = %08x\n", x, linked_list[x]);}while(linked_list[x++]!=0xffffff); + + //#warning "Let's hope this works well." + + while(!(GPU_CONTROL_PORT & (1<<0x1a))); /* Wait for the GPU to finish + * drawing primitives. */ + while(!(GPU_CONTROL_PORT & (1<<0x1c))); /* Wait for the GPU to be free */ + + gpu_ctrl(4, 2); // DMA CPU->GPU mode + D2_MADR = (unsigned int)linked_list; + D2_BCR = 0; + D2_CHCR = (1<<0xa)|1|(1<<0x18); + + linked_list_pos = 0; + + //if(PSX_GetInitFlags() & PSX_INIT_NOBIOS) + // __psxsdk_gpu_dma_finished = 0; + + if(__gs_autowait) + while(GsIsDrawing()); +} + +void GsDrawListPIO() +{ + //linked_list[linked_list_pos] = 0x00ffffff; + int pos = 0; + int sz = 0; + int x; + + while(!(GPU_CONTROL_PORT & (1<<0x1c))); + // Disable DMA + GPU_CONTROL_PORT = 0x04000000; + + + while(pos < linked_list_pos) + { + while(!(GPU_CONTROL_PORT & (1<<0x1c))); + + GPU_DATA_PORT = 0x01000000; // Reset data port + + sz = linked_list[pos++] >> 24; + + for(x = 0; x < sz; x++) + GPU_DATA_PORT = linked_list[pos++]; + } + + linked_list_pos = 0; +// GPU_DATA_PORT = 0xE6000000; // Disable masking stuff +// gpu_data_ctrl(2, ((b&0xff)<<16)|((g&0xff)<<8)|r); +// GPU_DATA_PORT = (y<<16)|x; +// GPU_DATA_PORT = (h<<16)|w; + if(__gs_autowait) + while(GsIsDrawing()); +} + +void GsSortPoly3(GsPoly3 *poly3) +{ + int orig_pos = linked_list_pos; + int x; + unsigned char pkt = 0x20; + unsigned int md; + + md = setup_attribs(0, poly3->attribute, &pkt); + + linked_list[linked_list_pos++] = 0x05000000; + linked_list[linked_list_pos++] = md; + linked_list[linked_list_pos++] = (pkt<<24)|(poly3->b<<16)|(poly3->g<<8)|(poly3->r); + + for(x = 0; x < 3; x++) + linked_list[linked_list_pos++] = ((poly3->y[x]&0x7ff)<<16)|(poly3->x[x]&0x7ff); + + linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff; +} + +void GsSortPoly4(GsPoly4 *poly4) +{ + int orig_pos = linked_list_pos; + int x; + unsigned char pkt = 0x28; + unsigned int md; + + md = setup_attribs(0, poly4->attribute, &pkt); + + linked_list[linked_list_pos++] = 0x06000000; + linked_list[linked_list_pos++] = md; + linked_list[linked_list_pos++] = (pkt<<24)|(poly4->b<<16)|(poly4->g<<8)|(poly4->r); + + for(x = 0; x < 4; x++) + linked_list[linked_list_pos++] = ((poly4->y[x]&0x7ff)<<16)|(poly4->x[x]&0x7ff); + + linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff; +} + +void GsSortGPoly3(GsGPoly3 *poly3) +{ + // PKT 0x30 + + int orig_pos = linked_list_pos; + int x; + unsigned char pkt = 0x30; + unsigned int md; + + md = setup_attribs(0, poly3->attribute, &pkt); + + linked_list[linked_list_pos++] = 0x07000000; + linked_list[linked_list_pos++] = md; + + for(x = 0; x < 3; x++) + { + linked_list[linked_list_pos++] = (poly3->b[x]<<16)|(poly3->g[x]<<8)|(poly3->r[x]) | ((x == 0)?(pkt<<24):0); + linked_list[linked_list_pos++] = ((poly3->y[x]&0x7ff)<<16)|(poly3->x[x]&0x7ff); + } + + linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff; +} + +void GsSortGPoly4(GsGPoly4 *poly4) +{ + // PKT 0x38 + + int orig_pos = linked_list_pos; + int x; + unsigned char pkt = 0x38; + unsigned int md; + + md = setup_attribs(0, poly4->attribute, &pkt); + + linked_list[linked_list_pos++] = 0x09000000; + linked_list[linked_list_pos++] = md; + + for(x = 0; x < 4; x++) + { + linked_list[linked_list_pos++] = (poly4->b[x]<<16)|(poly4->g[x]<<8)|(poly4->r[x]) | ((x == 0)?(pkt<<24):0); + linked_list[linked_list_pos++] = ((poly4->y[x]&0x7ff)<<16)|(poly4->x[x]&0x7ff); + } + + linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff; +} + +void GsSortLine(GsLine *line) +{ + // PKT 0x40 + + int orig_pos = linked_list_pos; + int x; + unsigned char pkt = 0x40; + unsigned int md; + + md = setup_attribs(0, line->attribute, &pkt); + + linked_list[linked_list_pos++] = 0x04000000; + linked_list[linked_list_pos++] = md; + linked_list[linked_list_pos++] = (pkt<<24)|(line->b<<16)|(line->g<<8)|(line->r); + + for(x = 0; x < 2; x++) + linked_list[linked_list_pos++] = ((line->y[x]&0x7ff)<<16)|(line->x[x]&0x7ff); + + linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff; +} + +void GsSortGLine(GsGLine *line) +{ + // PKT 0x50 + + int orig_pos = linked_list_pos; + int x; + unsigned char pkt = 0x50; + unsigned int md; + + md = setup_attribs(0, line->attribute, &pkt); + + linked_list[linked_list_pos++] = 0x05000000; + linked_list[linked_list_pos++] = md; + + for(x=0;x<2;x++) + { + linked_list[linked_list_pos++] = (line->b[x]<<16)|(line->g[x]<<8)|(line->r[x])|((x == 0)?(pkt<<24):0); + linked_list[linked_list_pos++] = ((line->y[x]&0x7ff)<<16)|(line->x[x] & 0x7ff); + } + + linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff; +} + +void GsSortDot(GsDot *dot) +{ + // PKT 0x68 + + int orig_pos = linked_list_pos; + unsigned char pkt = 0x68; + unsigned int md; + + md = setup_attribs(0, dot->attribute, &pkt); + + linked_list[linked_list_pos++] = 0x03000000; + linked_list[linked_list_pos++] = md; + linked_list[linked_list_pos++] = (pkt<<24)|(dot->b<<16)|(dot->g<<8)|(dot->r); + linked_list[linked_list_pos++] = ((dot->y&0x7ff)<<16)|(dot->x&0x7ff); + + linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff; +} + +void GsSortSprite(GsSprite *sprite) +{ + GsTPoly4 tpoly4; + int x, y; + int sx = sprite->x & 0x7ff; + int sy = sprite->y & 0x7ff; + int mcx, mcy; + + /*if(sprite->w > 256) + sprite->w = 256; + + if(sprite->h > 256) + sprite->h = 256;*/ + + // If "sprite" has no flipping and no scaling use sprite primitive + // otherwise manipulate a 4 point textured polygon primitive + + if(sprite->rotate != 0) + { + tpoly4.u[0] = sprite->u; + tpoly4.v[0] = sprite->v; + + tpoly4.u[1] = sprite->u; + tpoly4.v[1] = sprite->v + sprite->h; + + tpoly4.u[2] = sprite->u + sprite->w; + tpoly4.v[2] = sprite->v; + + tpoly4.u[3] = sprite->u + sprite->w; + tpoly4.v[3] = sprite->v + sprite->h; + + gs_vbuf[0][2] = gs_vbuf[1][2] = gs_vbuf[2][2] = gs_vbuf[3][2] = 0; + + mcx = sprite->mx + sprite->x; + mcy = sprite->my + sprite->y; + + gs_vbuf[0][0] = -(mcx - sprite->x); + gs_vbuf[0][1] = (mcy - sprite->y); + + gs_vbuf[1][0] = -(mcx - sprite->x); + gs_vbuf[1][1] = (mcy - (sprite->y + gs_calculate_scaled_size(sprite->h, sprite->scaley))); + + gs_vbuf[2][0] = -(mcx - (sprite->x + gs_calculate_scaled_size(sprite->w, sprite->scalex))); + gs_vbuf[2][1] = (mcy - sprite->y); + + gs_vbuf[3][0] = -(mcx - (sprite->x + gs_calculate_scaled_size(sprite->w, sprite->scalex))); + gs_vbuf[3][1] = (mcy - (sprite->y + gs_calculate_scaled_size(sprite->h, sprite->scaley))); + + for(x = 0; x < 4; x++) + { + gs_internal_vector_rotate(0, 0, sprite->rotate, gs_vbuf[x], gs_vbuf[x]); + tpoly4.x[x] = mcx + gs_vbuf[x][0]; + tpoly4.y[x] = mcy + gs_vbuf[x][1]; + } + + tpoly4.r = sprite->r; + tpoly4.g = sprite->g; + tpoly4.b = sprite->b; + tpoly4.attribute = sprite->attribute; + tpoly4.tpage = sprite->tpage; + tpoly4.cx = sprite->cx; + tpoly4.cy = sprite->cy; + + GsSortTPoly4(&tpoly4); + } + else if((sprite->attribute & (H_FLIP|V_FLIP)) || + sprite->scalex != 0 || sprite->scaley != 0) + { + x = sprite->w; + if(x>256)x=256; + + y = sprite->h; + if(y>256)y=256; + + if(sprite->scalex > 8) + { + x *= sprite->scalex; + x /= 4096; + } + else + { + if(sprite->scalex >= 2) + x*=sprite->scalex; + else if(sprite->scalex <= -2) + x/=-sprite->scalex; + } + + if(sprite->scaley > 8) + { + y *= sprite->scaley; + y /= 4096; + } + else + { + if(sprite->scaley >= 2) + y*=sprite->scaley; + else if(sprite->scaley <= -2) + y/=-sprite->scaley; + } + + tpoly4.x[0] = tpoly4.x[1] = sx; + tpoly4.x[2] = tpoly4.x[3] = (sx + x); + tpoly4.y[0] = tpoly4.y[2] = sy; + tpoly4.y[1] = tpoly4.y[3] = (sy + y); + + if(sprite->attribute & H_FLIP) + { + tpoly4.u[0] = tpoly4.u[1] = (sprite->u + sprite->w) - 1; + tpoly4.u[2] = tpoly4.u[3] = sprite->u; + } + else + { + tpoly4.u[0] = tpoly4.u[1] = sprite->u; + tpoly4.u[2] = tpoly4.u[3] = (sprite->u + sprite->w); + } + + if(sprite->attribute & V_FLIP) + { + tpoly4.v[0] = tpoly4.v[2] = (sprite->v + sprite->h) - 1; + tpoly4.v[1] = tpoly4.v[3] = sprite->v; + } + else + { + tpoly4.v[0] = tpoly4.v[2] = sprite->v; + tpoly4.v[1] = tpoly4.v[3] = (sprite->v + sprite->h); + } + + tpoly4.r = sprite->r; + tpoly4.g = sprite->g; + tpoly4.b = sprite->b; + tpoly4.attribute = sprite->attribute; + tpoly4.tpage = sprite->tpage; + tpoly4.cx = sprite->cx; + tpoly4.cy = sprite->cy; + + GsSortTPoly4(&tpoly4); + } + else + { + GsSortSimpleSprite(sprite); + } +} + +void GsSortSimpleSprite(GsSprite *sprite) +{ + unsigned int orig_pos = linked_list_pos; + unsigned char pkt = 0x64; + unsigned int md; + + md = setup_attribs(sprite->tpage, sprite->attribute, &pkt); + + linked_list[linked_list_pos++] = 0x05000000; + linked_list[linked_list_pos++] = md; + linked_list[linked_list_pos++] = (pkt<<24)|(sprite->b<<16)|(sprite->g<<8)|sprite->r; + linked_list[linked_list_pos++] = ((sprite->y&0x7ff)<<16)|(sprite->x&0x7ff); + linked_list[linked_list_pos++] = (get_clutid(sprite->cx,sprite->cy)<<16)|(sprite->v<<8)|sprite->u; + linked_list[linked_list_pos++] = (sprite->h<<16)|sprite->w; + + linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff; +} + +void GsSortRectangle(GsRectangle *rectangle) +{ + unsigned int orig_pos = linked_list_pos; + unsigned char pkt = 0x60; + unsigned int md; + + md = setup_attribs(0, rectangle->attribute, &pkt); + + linked_list[linked_list_pos++] = 0x04000000; + linked_list[linked_list_pos++] = md; + linked_list[linked_list_pos++] = (pkt<<24)|(rectangle->b<<16)|(rectangle->g<<8)|(rectangle->r); + linked_list[linked_list_pos++] = ((rectangle->y&0x7ff)<<16)|(rectangle->x&0x7ff); + linked_list[linked_list_pos++] = (rectangle->h<<16)|rectangle->w; + + linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff; +} + +void GsSortTPoly4(GsTPoly4 *tpoly4) +{ + unsigned int orig_pos = linked_list_pos; + unsigned char pkt = 0x2c; + unsigned int md; + + /*md = setup_attribs(tpoly4->tpage, tpoly4->attribute, &pkt);*/ + + //printf("tpoly4->tpage = %d\n", tpoly4->tpage); + + md = setup_attribs(tpoly4->tpage, tpoly4->attribute, &pkt); + + //printf("pkt = %x\n", pkt); + + linked_list[linked_list_pos++] = 0x09000000; + //linked_list[linked_list_pos++] = md; + //linked_list[linked_list_pos++] = 0xe0000000; + //linked_list[linked_list_pos++] = 0xe1000105; + + //printf("tpoly4 md: %08x\n", md); + linked_list[linked_list_pos++] = (pkt<<24)|(tpoly4->b<<16)|(tpoly4->g<<8)|(tpoly4->r); + linked_list[linked_list_pos++] = ((tpoly4->y[0]&0x7ff)<<16)|(tpoly4->x[0]&0x7ff); + linked_list[linked_list_pos++] = (get_clutid(tpoly4->cx, tpoly4->cy)<<16)|(tpoly4->v[0]<<8)|tpoly4->u[0]; + linked_list[linked_list_pos++] = ((tpoly4->y[1]&0x7ff)<<16)|(tpoly4->x[1]&0x7ff); + linked_list[linked_list_pos++] = (md << 16)|(tpoly4->v[1]<<8)|tpoly4->u[1]; + linked_list[linked_list_pos++] = ((tpoly4->y[2]&0x7ff)<<16)|(tpoly4->x[2]&0x7ff); + linked_list[linked_list_pos++] = (tpoly4->v[2]<<8)|tpoly4->u[2]; + linked_list[linked_list_pos++] = ((tpoly4->y[3]&0x7ff)<<16)|(tpoly4->x[3]&0x7ff); + linked_list[linked_list_pos++] = (tpoly4->v[3]<<8)|tpoly4->u[3]; + + linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff; +} + +void GsSortTPoly3(GsTPoly3 *tpoly3) +{ + int orig_pos = linked_list_pos; + int x; + unsigned char pkt = 0x24; + unsigned int md; + + md = setup_attribs(tpoly3->tpage, tpoly3->attribute, &pkt); + + linked_list[linked_list_pos++] = 0x07000000; + linked_list[linked_list_pos++] = + (pkt<<24)|(tpoly3->b<<16)|(tpoly3->g<<8)|(tpoly3->r); + + for(x = 0; x < 3; x++) + { + linked_list[linked_list_pos++] = ((tpoly3->y[x]&0x7ff)<<16)|(tpoly3->x[x]&0x7ff); + linked_list[linked_list_pos] = (tpoly3->u[x]<<8)|tpoly3->v[x]; + + switch(x) + { + case 0: + linked_list[linked_list_pos++] |= + get_clutid(tpoly3->cx, tpoly3->cy) << 16; + break; + case 1: + linked_list[linked_list_pos++] |= + md << 16; + break; + default: + linked_list_pos++; + break; + } + } + + linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff; +} + +void MoveImage(int src_x, int src_y, int dst_x, int dst_y, int w, int h) +{ + /* + * This seems more like "CopyImage"... + */ + + while(!(GPU_CONTROL_PORT & (1<<0x1c))); + + GPU_CONTROL_PORT = 0x04000000; + GPU_DATA_PORT = 0x01000000; // Reset command buffer + GPU_DATA_PORT = 0xE6000000; + GPU_DATA_PORT = 0x80000000; + GPU_DATA_PORT = (src_y<<16)|src_x; + GPU_DATA_PORT = (dst_y<<16)|dst_x; + GPU_DATA_PORT = (h<<16)|w; +} + +/* + * Add a method to add arbitrary data to the packet list + */ + +void LoadImage(void *img, int x, int y, int w, int h) +{ + unsigned short *image = (unsigned short*)img; + int a, l; + + //printf("LoadImage: %d, %d, %d, %d\n", x, y, w, h); + + while(!(GPU_CONTROL_PORT & (1<<0x1c))); + + GPU_CONTROL_PORT = 0x04000000; // Disable DMA + +// Reset should be on data port ! otherwise we won't be able +// to write CLUTs for some time after they've been used! +// (why??) + + GPU_DATA_PORT = 0x01000000; + GPU_DATA_PORT = 0xE6000000; // disable masking stuff !! + GPU_DATA_PORT = 0xA0000000; + GPU_DATA_PORT = (y<<16)|x; + GPU_DATA_PORT = (h<<16)|w; + + l = w*h; + if(l&1)l++; + + for(a = 0; a < l; a+=2) + GPU_DATA_PORT = image[a]|(image[a+1]<<16); + + GPU_CONTROL_PORT = 0x01000000; +// while(!(GPU_CONTROL_PORT & (1<<0x1c))); +} + +/*void LoadImage(void *img, int x, int y, int w, int h) +{ + GPU_dw(x, y, w, h, img); + + int l; + + printf("LoadImage: %d, %d, %d, %d\n", x, y, w, h); + + l = w*h; + if(l&1)l++; + l/=2; + + while(!(GPU_CONTROL_PORT & (1<<0x1c))); // Wait for the GPU to be free + + gpu_ctrl(4, 2); // DMA CPU->GPU mode + D2_MADR = (unsigned int)img; + D2_BCR = (l << 16) | 1; + D2_CHCR = 0x01000201; + + // Wait for DMA to finish + + while(D2_CHCR & (1<<0x18)); +//}*/ + +void GsSetDrawEnv(GsDrawEnv *drawenv) +{ + int end_y, end_x; + int mf; + + /* + * Store the 0xe1 packet - we need it because we have to + * modify drawing environment for sprites + */ + + draw_mode_packet = (0xe1<<24)|(drawenv->draw_on_display>=1)<<10| + (drawenv->dither>=1)<<9; + + gpu_data_ctrl(0xe1, draw_mode_packet); + gpu_data_ctrl(0xe2, 0); + gpu_data_ctrl(0xe3, (drawenv->y<<10)|drawenv->x); + + end_x = (drawenv->x + drawenv->w)-1; + end_y = (drawenv->y + drawenv->h)-1; + + gpu_data_ctrl(0xe4, (end_y<<10)|end_x); + + //#warning "Check drawing offset better." + gpu_data_ctrl(0xe5, (drawenv->y<<11)|drawenv->x); + //gpu_data_ctrl(0xe5, 0); + + + mf = 0; + if(drawenv->set_mask) mf|=MASK_SET; + if(drawenv->ignore_mask) mf|=MASK_IGNORE; + + GsSetMasking(mf); + + GsCurDrawEnvW = drawenv->w; + GsCurDrawEnvH = drawenv->h; +} + +void GsSetDispEnv(GsDispEnv *dispenv) +{ + gpu_ctrl(5, (dispenv->y<<10)|dispenv->x); // Display offset +} + +void gpu_ctrl(unsigned int command, unsigned int param) +{ + unsigned int doubleword = (command << 0x18) | param; + + GPU_CONTROL_PORT = 0x01000000; + GPU_CONTROL_PORT = doubleword; +} + +void gpu_data(unsigned int data) +{ + GPU_DATA_PORT = data; +} + +void gpu_data_ctrl(unsigned int command, unsigned int param) +{ + unsigned int doubleword = (command << 0x18) | param; + + GPU_CONTROL_PORT = 0x01000000; + GPU_DATA_PORT = doubleword; +} + +unsigned int setup_attribs(unsigned char tpage, unsigned int attribute, unsigned char *packet) +{ + unsigned int sprite_mode_packet; + + //printf("tpage = %d, attribute = %x, packet = %x\n", tpage, attribute, packet); + //while(1);*/ + +/* + * First, setup draw mode setting. + */ + + sprite_mode_packet = draw_mode_packet; + sprite_mode_packet|= tpage & 0x1f; /* Texture page */ + sprite_mode_packet|= (attribute & 3) << 7; /* Color mode */ + sprite_mode_packet|= ((attribute>>2)&3) << 5; /* Translucency mode */ + +/* + * Check for STP bit flag in attribute, and modify packet byte accordingly + */ + if(attribute & 16) + *packet|=2; + + //printf("sprite_mode_packet = %08x\n", sprite_mode_packet); + + return sprite_mode_packet; +} + +unsigned int GsListPos() +{ + return linked_list_pos; +} + +void GsEnableDisplay(int enable) +{ + gpu_ctrl(3, enable ? 0 : 1); +} + +void GsReset() +{ + gpu_ctrl(0, 0); // Reset GPU +} + +void GsInitEx(unsigned int flags) +{ + //gpu_ctrl(0, 0); // Reset GPU + GsReset(); // Reset GPU + + DPCR |= (1<<0xb); // Enable dma channel 2 + gpu_ctrl(4, 2); // DMA CPU->GPU mode + + //gpu_ctrl(3, 1); // Disable display + GsEnableDisplay(0); // Disable display + + GPU_DATA_PORT = 0x01000000; // Reset data port + + /*gpu_ctrl(6, 0xc40240); // Horizontal start end + gpu_ctrl(7, 0x049025); // Vertical start end*/ + //DrawFBRect(0, 0, 1023, 511, 0, 0, 0); +} + +void GsInit() +{ + GsInitEx(0); +} + +/*void SetVBlankHandler2(void *(callback)()) +{ + unsigned int eventid; + + EnterCriticalSection(); + + IMASK|=8; // Enable VBLANK interrupt + eventid = openevent(0xf0000001, 2, 0x1000, vblank_handler); + + if(eventid == -1) + { + printf("SetVBlankHandler: Failed to open event!\n"); + return; + } + else + printf("SetVBlankHandler: Event opened successfully!\n"); + + if(enableevent(eventid) == 0) + { + printf("SetVBlankHandler: Failed to enable event!\n"); + // Shouldn't we close the event as well? + return; + } + else + printf("SetVBlankHandler: Event enabled successfully!\n"); + + ExitCriticalSection(); +}*/ + +int GsSetVideoMode(int width, int height, int video_mode) +{ + // Just a quick wrapper for GsSetVideoModeEx + return GsSetVideoModeEx(width, height, video_mode, 0, 0, 0); +} + +int GsSetVideoModeEx(int width, int height, int video_mode, int rgb24, + int inter, int reverse) +{ + unsigned char mode = 0; + + GsEnableDisplay(0); + + if(video_mode == VMODE_NTSC) + { + gpu_ctrl(6, 0xC4E24E); // Horizontal screen range + gpu_ctrl(7, 0x040010); // Vertical screen range + } + else + { + gpu_ctrl(6, 0xC62262); // Horizontal screen range + gpu_ctrl(7, 0x04B42D); // Vertical screen range + } + + switch(height) + { + case 240: + break; + case 480: + mode|=4; + break; + default: + printf("%s: error, unknown width %d!\n", __FUNCTION__, width); + return 0; + } + + switch(width) + { + case 256: + break; + case 320: + mode|=1; + break; + case 512: + mode|=2; + break; + case 640: + mode|=3; + break; + case 384: + mode|=64; + break; + default: + printf("%s: error, unknown height %d!\n", __FUNCTION__, height); + return 0; + } + + if(video_mode)mode|=8; // Set PAL + if(rgb24)mode|=16; // Set unaccellerated 24-bit mode + if(inter)mode|=32; // Set interlaced video mode + if(reverse)mode|=128; // Set reverse flag (?) + + gpu_ctrl(8, mode); + GsEnableDisplay(1); + + GsScreenW = width; + GsScreenH = height; + GsScreenM = video_mode; + + return 1; +} + +void DrawFBRect(int x, int y, int w, int h, int r, int g, int b) +{ + while(!(GPU_CONTROL_PORT & (1<<0x1c))); + + // Disable DMA + GPU_CONTROL_PORT = 0x04000000; + + GPU_DATA_PORT = 0x01000000; // Reset data port + GPU_DATA_PORT = 0xE6000000; // Disable masking stuff + gpu_data_ctrl(2, ((b&0xff)<<16)|((g&0xff)<<8)|r); + GPU_DATA_PORT = (y<<16)|x; + GPU_DATA_PORT = (h<<16)|w; +} + +void GsClearMem() +{ + // "Clears" the entire video memory by using DrawFBRect + // and waits that it has finished drawing... + + DrawFBRect(0,0,1023,511,0,0,0); + while(GsIsDrawing()); + DrawFBRect(0,511,1023,1,0,0,0); + while(GsIsDrawing()); + DrawFBRect(1023,511,1,1,0,0,0); + while(GsIsDrawing()); +} + +int GsImageFromTim(GsImage *image, void *timdata) +{ + unsigned int *timdata_i = (unsigned int*)timdata; + unsigned short *timdata_s = (unsigned short*)timdata; + unsigned int pdata_pos; + unsigned int pdata_pos_s; + + //printf("timdata_i[0] = %08x\n", timdata_i[0]); + + if(timdata_i[0] != 0x10) + { + //printf("timdata_i[0] = %08x\n", timdata_i[0]); + return 0; // Unknown version or ID + } + + image->pmode = timdata_i[1] & 7; + + //printf("image->pmode = %d\n", image->pmode); + + image->has_clut = (timdata_i[1] & 8) ? 1 : 0; + + if(!image->has_clut) + pdata_pos = 8; + else + { + pdata_pos = 8 + timdata_i[2]; + image->clut_x = timdata_s[6]; + image->clut_y = timdata_s[7]; + image->clut_w = timdata_s[8]; + image->clut_h = timdata_s[9]; + image->clut_data = &timdata_s[10]; + + /*printf("image->clut_y = %d\n", image->clut_y); + printf("image->clut_x = %d\n", image->clut_x); + printf("image->clut_h = %d\n", image->clut_h); + printf("image->clut_w = %d\n", image->clut_w);*/ + } + + pdata_pos_s = pdata_pos / 2; + + image->x = timdata_s[pdata_pos_s + 2]; + image->y = timdata_s[pdata_pos_s + 3]; + image->w = timdata_s[pdata_pos_s + 4]; + image->h = timdata_s[pdata_pos_s + 5]; + image->data = &timdata_s[pdata_pos_s + 6]; + + /*printf("image->y = %d\n", image->y); + printf("image->x = %d\n", image->x); + printf("image->h = %d\n", image->h); + printf("image->w = %d\n", image->w);*/ + + return 1; +} + +void GsUploadImage(GsImage *image) +{ + if(image->has_clut) + LoadImage(image->clut_data, image->clut_x, image->clut_y, + image->clut_w, image->clut_h); + + LoadImage(image->data, image->x, image->y, image->w, image->h); +} + +int GsSpriteFromImage(GsSprite *sprite, GsImage *image, int do_upload) +{ + if(do_upload) + GsUploadImage(image); + + bzero(sprite, sizeof(GsSprite)); + + sprite->tpage = (image->x / 64) + ((image->y/256)*16); + sprite->u = image->x & 0x3f; + sprite->v = image->y & 0xff; + + sprite->cx = image->clut_x; + sprite->cy = image->clut_y; + + if(image->pmode == 0) // 4-bit pixel mode + sprite->u*=4; + else if(image->pmode == 1) // 8-bit pixel mode + sprite->u*=2; + + switch(image->pmode) + { + case 0: + sprite->w = image->w * 4; + break; + case 1: + sprite->w = image->w * 2; + break; + case 2: + sprite->w = image->w; + break; + case 3: + sprite->w = image->w + (image->w / 2); + break; + } + + sprite->h = image->h; + sprite->attribute = COLORMODE(image->pmode); + sprite->r = sprite->g = sprite->b = NORMAL_LUMINANCE; + + return 1; +} + +void GsSetMasking(unsigned char flag) +{ + gpu_data_ctrl(0xe6, flag); +} + +int GsIsDrawing() +{ + /*int x; + + if(PSX_GetInitFlags() & PSX_INIT_NOBIOS) + { + int r = (!(GPU_CONTROL_PORT & (1<<0x1a))) || (!__psxsdk_gpu_dma_finished); + + for(x = 0; x < 1000; x++); + + return r; + }*/ + + return !(GPU_CONTROL_PORT & (1<<0x1a)) ; +} + + + +// Functions which use default values to use when you do not +// really need to fiddle with all the fields of the structure + +void GsSetDrawEnvSimple(int x, int y, int w, int h) +{ + GsDrawEnv env; + + env.dither = 0; + env.draw_on_display = 1; + env.x = x; + env.y = y; + env.w = w; + env.h = h; + env.ignore_mask = 0; + env.set_mask = 0; + + GsSetDrawEnv(&env); +} + +void GsSetDispEnvSimple(int x, int y) +{ + GsDispEnv env; + + env.x = x; + env.y = y; + + GsSetDispEnv(&env); +} + +// Built-in font functions. + +void GsLoadFont(int fb_x, int fb_y, int cx, int cy) +{ + unsigned short pal[2] = {0x0, 0x7fff}; + + LoadImage(psxsdk_font_data, fb_x, fb_y, 16, 128); + while(GsIsDrawing()); + + if(cx != -1 && cy != -1) + { + LoadImage(pal, cx, cy, 16, 1); + + fb_font_cx = cx; + fb_font_cy = cy; + + while(GsIsDrawing()); + } + + fb_font_x = fb_x; + fb_font_y = fb_y; +} + +unsigned int GsPrintFont_Draw(int x, int y, int scalex, int scaley) +{ + //int r; + GsSprite spr; + char *string; + int fw, fh; + + /*va_list ap; + + va_start(ap, fmt);*/ + +// r = vsnprintf(gpu_stringbuf, 512, fmt, ap); + +// va_end(ap); + fw = gs_calculate_scaled_size(8, scalex);//(8*scalex)/4096; + fh = gs_calculate_scaled_size(8, scaley);//(8*scaley)/4096; + + spr.x = x; + spr.y = y; + spr.r = prfont_rl; + spr.g = prfont_gl; + spr.b = prfont_bl; + spr.attribute = 0; + spr.cx = fb_font_cx; + spr.cy = fb_font_cy; + spr.tpage = (fb_font_x / 64) + ((fb_font_y / 256)*16); + spr.w = 8; + spr.h = 8; + spr.scalex = scalex; + spr.scaley = scaley; + + string = gpu_stringbuf; + + while(*string) + { + if(prfont_flags & PRFONT_WRAP) + { + if(spr.x >= GsScreenW) + { + spr.x = spr.x - GsScreenW; + spr.y += fh; + } + } + + if(*string >= ' ' && *string <= '~') + { + spr.u = ((fb_font_x & 0x3f)*4)+((*string & 7) << 3); + spr.v = (fb_font_y & 0xff)+(*string & 0xf8); + + if((spr.x < GsCurDrawEnvW && (spr.x+fw)>=0) && + (spr.y < GsCurDrawEnvH && (spr.y+fh)>=0)) + { + + if((scalex == 0 || scalex == 1) && (scaley == 0 || scaley == 1)) + GsSortSimpleSprite(&spr); + else + GsSortSprite(&spr); + } + + spr.x += fw; + } + + if(*string == '\r') + spr.x = 0; + + if(*string == '\n') + { + spr.x = (prfont_flags & PRFONT_UNIXLF)? 0 : x; + spr.y += fh; + } + + if(*string == '\t') + spr.x += fw * 8; + + string++; + } + + return (spr.y << 16) | spr.x; +} + +unsigned int GsVPrintFont(int x, int y, const char *fmt, va_list ap) +{ + int r; + //GsSprite spr; + //char *string; + int fw = gs_calculate_scaled_size(8, prfont_scale_x); + + r = vsnprintf(gpu_stringbuf, 512, fmt, ap); + + if(prfont_flags & PRFONT_WRAP) + r = GsPrintFont_Draw(x, y, prfont_scale_x, prfont_scale_y); + else if(prfont_flags & PRFONT_CENTER) + r = GsPrintFont_Draw(x - ((r * fw)/2), y, prfont_scale_x, prfont_scale_y); + else if(prfont_flags & PRFONT_RIGHT) + r = GsPrintFont_Draw(x - (r * fw), y, prfont_scale_x, prfont_scale_y); + else + r = GsPrintFont_Draw(x, y, prfont_scale_x, prfont_scale_y); + + return r; +} + +unsigned int GsPrintFont(int x, int y, const char *fmt, ...) +{ + int r; + + va_list ap; + + va_start(ap, fmt); + + r = GsVPrintFont(x, y, fmt, ap); + + va_end(ap); + + return r; +} + +void GsSetFont(int fb_x, int fb_y, int cx, int cy) +{ + if(fb_x != -1) + fb_font_x = fb_x; + + if(fb_y != -1) + fb_font_y = fb_y; + + if(fb_font_cx != -1) + fb_font_cx = cx; + + if(fb_font_cy != -1) + fb_font_cy = cy; +} + +void GsSetFontAttrib(unsigned int flags) +{ + prfont_flags = flags; + + if(prfont_flags == 0) + { + PRFONT_SCALEX(0); + PRFONT_SCALEY(0); + + PRFONT_RL(NORMAL_LUMINANCE); + PRFONT_GL(NORMAL_LUMINANCE); + PRFONT_BL(NORMAL_LUMINANCE); + } +} + +static double gs_internal_cos(int a) +{ + int a_a = (a>>12)-(((a>>12)/360)*360); + + if(a_a>=0 && a_a<=90) + return gs_rot_cos_tbl[a_a]; + else if(a_a>90 && a_a<=180) + return -gs_rot_cos_tbl[180 - a_a]; + else if(a_a>180 && a_a<=270) + return -gs_rot_cos_tbl[a_a - 180]; + else if(a_a>270 && a_a<=359) + return gs_rot_cos_tbl[360 - a_a]; + + return 0; +} + +static double gs_internal_sin(int a) +{ + int a_a = (a>>12)-(((a>>12)/360)*360); + + if(a_a>=0 && a_a<=90) + return gs_rot_cos_tbl[90-a_a]; + else if(a_a>90 && a_a<=180) + return gs_rot_cos_tbl[a_a-90]; + else if(a_a>180 && a_a<=270) + return -gs_rot_cos_tbl[270-a_a]; + else if(a_a>270 && a_a<=359) + return -gs_rot_cos_tbl[a_a-270]; + + return 0; +} + +static void gs_internal_vector_rotate(int x_a, int y_a, int z_a, double *v, double *n) +{ + double axis_m[3][3]; + double b[3]; + double k[3], s[3]; + int x; + + k[0] = gs_internal_cos(x_a); + k[1] = gs_internal_cos(y_a); + k[2] = gs_internal_cos(z_a); + + s[0] = gs_internal_sin(x_a); + s[1] = gs_internal_sin(y_a); + s[2] = gs_internal_sin(z_a); + + axis_m[0][0] = k[1] * k[2]; + axis_m[0][1] = (k[0] * s[2]) + (s[0]*s[1]*k[2]); + axis_m[0][2] = (s[0]*s[2]) - (k[0]*s[1]*k[2]); + axis_m[1][0] = -(k[1] * s[2]); + axis_m[1][1] = (k[0]*k[2]) - (s[0]*s[1]*s[2]); + axis_m[1][2] = (s[0]*k[2]) + (k[0]*s[1]*s[2]); + axis_m[2][0] = s[1]; + axis_m[2][1] = -(s[0]*k[1]); + axis_m[2][2] = k[0]*k[1]; + + for(x=0;x<3;x++) + b[x] = (axis_m[x][0] * v[0]) + (axis_m[x][1] * v[1]) + (axis_m[x][2] * v[2]); + + b[1]=-b[1]; + + for(x=0;x<3;x++) + n[x]=b[x]; +} + +int GsIsWorking() +{ + return GsIsDrawing(); +} + +void GsSortCls(int r, int g, int b) +{ + GsRectangle rect; + + rect.r = r; + rect.g = g; + rect.b = b; + rect.x = 0; + rect.y = 0; + rect.attribute = 0; + rect.w = GsCurDrawEnvW; + rect.h = GsCurDrawEnvH; + + GsSortRectangle(&rect); +} + +void GsSetAutoWait() +{ + __gs_autowait = 1; +} + +void GsRotateVector(int x_a, int y_a, int z_a, double *v, double *n) +{ + gs_internal_vector_rotate(x_a, y_a, z_a, v, n); +} + +/*void GsSortSimpleMap(GsMap *map) +{ + unsigned int orig_pos = linked_list_pos; + //unsigned int + unsigned char pkt = 0x64; + unsigned int md; + unsigned char curCount = 0; + unsigned int remaining; + unsigned int tn; + unsigned short tu; + unsigned short tv; + int x, y; + + md = setup_attribs(map->tpage, map->attribute, &pkt); + + linked_list[linked_list_pos++] = 0x01000000; + linked_list[linked_list_pos++] = md; + linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff; + + orig_pos = linked_list_pos; + linked_list[linked_list_pos++] = 0x00000000; + + remaining = map->w * map->h; + + for(y = 0; y < map->h; y++) + { + for(x = 0; x < map->w; x++) + { + switch(map->tsize) + { + case 1: + tn = ((unsigned char*)map->data)[(y * map->l) + x]; + break; + case 2: + tn = ((unsigned short*)map->data)[(y * map->l) + x]; + break; + case 4: + tn = ((unsigned int*)map->data)[(y * map->l) + x]; + break; + } + + tn &= ~map->tmask; + + tu = (tn * map->tw) % map->tmw; + tv = ((tn * map->tw) / map->tmw) * map->th; + + linked_list[linked_list_pos++] = (pkt<<24)|(map->b<<16)|(map->g<<8)|map->r; + linked_list[linked_list_pos++] = (((map->y+(y*map->th))&0x7ff)<<16)|((map->x+(x*map->tw))&0x7ff); + linked_list[linked_list_pos++] = (get_clutid(map->cx,map->cy)<<16)|((tv+map->v)<<8)| + (tu+map->u); + linked_list[linked_list_pos++] = (map->th<<16)|map->tw; + + curCount++; + + if(curCount == 252) + { + linked_list[orig_pos] = (252 << 24) | (((unsigned int)&linked_list[linked_list_pos]) & 0xffffff); + orig_pos = linked_list_pos; + + remaining -= curCount; + + if(remaining > 0) + linked_list_pos++; + + curCount = 0; + } + } + } + + if(curCount > 0) + linked_list[orig_pos] = (curCount << 24) | (((unsigned int)&linked_list[linked_list_pos]) & 0xffffff); +}*/ + +void GsSetListEx(unsigned int *listptr, unsigned int listpos) +{ + linked_list = listptr; + linked_list_pos = listpos; +} + +void GsSortPolyLine(GsPolyLine *line) +{ + // PKT 0x48 + + int orig_pos = linked_list_pos; + int x; + unsigned char pkt = 0x48; + unsigned int md; + + md = setup_attribs(0, line->attribute, &pkt); + + linked_list_pos++; // skip this word, we will replace it later + linked_list[linked_list_pos++] = md; + linked_list[linked_list_pos++] = (pkt<<24)|(line->b<<16)|(line->g<<8)|(line->r); + + for(x = 0; x < line->npoints; x++) + linked_list[linked_list_pos++] = ((line->y[x]&0x7ff)<<16)|(line->x[x]&0x7ff); + + linked_list[linked_list_pos++] = 0x55555555; // termination code + + linked_list[orig_pos] = ((line->npoints+3) << 24) | (((unsigned int)&linked_list[linked_list_pos]) & 0xffffff); +} + +void GsSortGPolyLine(GsGPolyLine *line) +{ + // PKT 0x58 + + int orig_pos = linked_list_pos; + int x; + unsigned char pkt = 0x58; + unsigned int md; + + md = setup_attribs(0, line->attribute, &pkt); + + linked_list_pos++; // skip this word, we will replace it later + linked_list[linked_list_pos++] = md; + + for(x=0; x < line->npoints;x++) + { + linked_list[linked_list_pos++] = (line->b[x]<<16)|(line->g[x]<<8)|(line->r[x])|((x == 0)?(pkt<<24):0); + linked_list[linked_list_pos++] = ((line->y[x]&0x7ff)<<16)|(line->x[x] & 0x7ff); + } + + linked_list[linked_list_pos++] = 0x55555555; // termination code + + linked_list[orig_pos] = (((line->npoints*2)+2) << 24) | (((unsigned int)&linked_list[linked_list_pos]) & 0xffffff); +} + +void GsSortGTPoly4(GsGTPoly4 *tpoly4) +{ + unsigned int orig_pos = linked_list_pos; + unsigned char pkt = 0x3c; + unsigned int md; + + /*md = setup_attribs(tpoly4->tpage, tpoly4->attribute, &pkt);*/ + + //printf("tpoly4->tpage = %d\n", tpoly4->tpage); + + md = setup_attribs(tpoly4->tpage, tpoly4->attribute, &pkt); + + //printf("pkt = %x\n", pkt); + + linked_list[linked_list_pos++] = 0x0C000000; + //linked_list[linked_list_pos++] = md; + //linked_list[linked_list_pos++] = 0xe0000000; + //linked_list[linked_list_pos++] = 0xe1000105; + + //printf("tpoly4 md: %08x\n", md); + linked_list[linked_list_pos++] = (pkt<<24)|(tpoly4->b[0]<<16)|(tpoly4->g[0]<<8)|(tpoly4->r[0]); + linked_list[linked_list_pos++] = ((tpoly4->y[0]&0x7ff)<<16)|(tpoly4->x[0]&0x7ff); + linked_list[linked_list_pos++] = (get_clutid(tpoly4->cx, tpoly4->cy)<<16)|(tpoly4->v[0]<<8)|tpoly4->u[0]; + linked_list[linked_list_pos++] = (tpoly4->b[1]<<16)|(tpoly4->g[1]<<8)|tpoly4->r[1]; + linked_list[linked_list_pos++] = ((tpoly4->y[1]&0x7ff)<<16)|(tpoly4->x[1]&0x7ff); + linked_list[linked_list_pos++] = (md << 16)|(tpoly4->v[1]<<8)|tpoly4->u[1]; + linked_list[linked_list_pos++] = (tpoly4->b[1]<<16)|(tpoly4->g[1]<<8)|tpoly4->r[1]; + linked_list[linked_list_pos++] = ((tpoly4->y[2]&0x7ff)<<16)|(tpoly4->x[2]&0x7ff); + linked_list[linked_list_pos++] = (tpoly4->v[2]<<8)|tpoly4->u[2]; + linked_list[linked_list_pos++] = (tpoly4->b[2]<<16)|(tpoly4->g[2]<<8)|tpoly4->r[2]; + linked_list[linked_list_pos++] = ((tpoly4->y[3]&0x7ff)<<16)|(tpoly4->x[3]&0x7ff); + linked_list[linked_list_pos++] = (tpoly4->v[3]<<8)|tpoly4->u[3]; + + linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff; +} + +void GsSortGTPoly3(GsGTPoly3 *tpoly3) +{ + int orig_pos = linked_list_pos; + int x; + unsigned char pkt = 0x34; + unsigned int md; + + md = setup_attribs(tpoly3->tpage, tpoly3->attribute, &pkt); + + linked_list[linked_list_pos++] = 0x09000000; + + for(x = 0; x < 3; x++) + { + linked_list[linked_list_pos++] = + ((x==0)?(pkt<<24):0)|(tpoly3->b[x]<<16)|(tpoly3->g[x]<<8)|(tpoly3->r[x]); + linked_list[linked_list_pos++] = ((tpoly3->y[x]&0x7ff)<<16)|(tpoly3->x[x]&0x7ff); + linked_list[linked_list_pos] = (tpoly3->u[x]<<8)|tpoly3->v[x]; + + switch(x) + { + case 0: + linked_list[linked_list_pos++] |= + get_clutid(tpoly3->cx, tpoly3->cy) << 16; + break; + case 1: + linked_list[linked_list_pos++] |= + md << 16; + break; + default: + linked_list_pos++; + } + } + + linked_list[orig_pos] |= ((unsigned int)&linked_list[linked_list_pos]) & 0xffffff; +} diff --git a/libpsx/src/libc.c b/libpsx/src/libc.c new file mode 100644 index 0000000..8ad519b --- /dev/null +++ b/libpsx/src/libc.c @@ -0,0 +1,705 @@ +/* + * small libc functions for the PSXSDK + * + * In this file, C functions either not implemented by the BIOS + * or very broken in the BIOS are implemented independently + * + * Some functions, such as printf, have both a BIOS implementation + * and an implementation here. The implementation here is prefixed + * with libc_ to not make confusion. + */ + +#include <psx.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <strings.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> + +char onesec_buf[2048]; +int errno; +int __stdio_direction = STDIO_DIRECTION_BIOS; +static unsigned int __sio_cr_mapped = 0; + +#define NUM_OF_FILE_STRUCTS 259 + +FILE file_structs[NUM_OF_FILE_STRUCTS] = +{ + [0] = // stdin + { + .fildes = 0, + .pos = 0, + .mode = O_RDONLY, + .dev = FDEV_CONSOLE, + .size = 0, + .used = 1, + .eof = 0, + .error = 0 + }, + [1] = // stdout + { + .fildes = 1, + .pos = 0, + .mode = O_WRONLY, + .dev = FDEV_CONSOLE, + .size = 0, + .used = 1, + .eof = 0, + .error = 0 + }, + [2] = // stderr + { + .fildes = 2, + .pos = 0, + .mode = O_WRONLY, + .dev = FDEV_CONSOLE, + .size = 0, + .used = 1, + .eof = 0, + .error = 0 + }, +}; + +FILE *stdin = &file_structs[0]; +FILE *stdout = &file_structs[1]; +FILE *stderr = &file_structs[2]; + +#define IS_CONS_IN(f) (f->fildes == 0) +#define IS_CONS_OUT(f) (f->fildes == 1 || f->fildes == 2) + +//unsigned char file_state[NUM_OF_FILE_STRUCTS]; + +int libc_get_transtbl_fname(const char *tofind, char *outstr, int outl); + +unsigned int fmode_to_desmode(const char *fmode) +{ + char rmode[16]; + int x, y; + + y = 0; + + for(x=0;x<15;x++) + { + if(fmode[x] == 0) + break; + else + { + if(fmode[x] != 'b' && fmode[x] != 'f') + rmode[y++] = fmode[x]; + } + } + + rmode[y] = 0; + + if(strcmp(rmode, "r") == 0) + { + dprintf("Open for reading.\n"); + return O_RDONLY; + } + else if(strcmp(rmode, "r+") == 0) + { + dprintf("Open for reading and writing.\n"); + return O_RDWR; + } + else if(strcmp(rmode, "w") == 0) + { + dprintf("Open for writing.\n"); + return O_WRONLY | O_CREAT | O_TRUNC; + } + else if(strcmp(rmode, "w+") == 0) + { + dprintf("Open for writing. Truncate to zero or create file.\n"); + return O_RDWR | O_CREAT | O_TRUNC; + } + else if(strcmp(rmode, "a") == 0) + { + dprintf("Append; open for writing. Create file if it doesn't exist.\n"); + return O_WRONLY | O_APPEND; + } + else if(strcmp(rmode, "a+") == 0) + { + dprintf("Append; open for reading and writing. Create file if it doesn't exist.\n"); + return O_RDWR | O_APPEND | O_CREAT; + } + else + { + return 0; + } +} + +FILE *fdopen(int fildes, const char *mode) +{ +// Adjust for malloc + int x; + +// Find a free file structure + for(x = 0; x < NUM_OF_FILE_STRUCTS; x++) + { + if(file_structs[x].used == 0) + { + bzero(&file_structs[x], sizeof(FILE)); + file_structs[x].used = 1; + break; + } + } + +// If we found no free file structure, return NULL pointer + + if(x == NUM_OF_FILE_STRUCTS) + return NULL; + + file_structs[x].fildes = fildes; + file_structs[x].pos = lseek(fildes, 0, SEEK_CUR); + file_structs[x].mode = fmode_to_desmode(mode); + + return &file_structs[x]; +} + +static FILE *fopen_internal(const char *path, const char *mode, FILE *f) +{ + int fd; + char *s = NULL; + + if(strncmp(path, "cdromL:", 7) == 0) + { + s = malloc(1024); + + if(libc_get_transtbl_fname(path+7, s, 1024) == 0) + return NULL; + + fd = open(s, fmode_to_desmode(mode)); + } + else + fd = open(path, fmode_to_desmode(mode)); + + if(fd == -1) + { + if(s!=NULL)free(s); + return NULL; + } + + if(f == NULL) + f = fdopen(fd, mode); + else + { + f->fildes = fd; + f->pos = lseek(fd, 0, SEEK_CUR); + f->mode = fmode_to_desmode(mode); + } + + if(f == NULL) + { + if(s!=NULL)free(s); + return NULL; + } + + f->dev = FDEV_UNKNOWN; + + if(strncmp(path, "cdrom", 5) == 0 || strncmp(path, "cdromL", 6) == 0) + f->dev = FDEV_CDROM; + else if(strncmp(path, "bu", 2) == 0) + f->dev = FDEV_MEMCARD; + +// nocash bios freezes at get_real_file_size(), due +// to problems with firstfile() + + if(s!=NULL) + { + f->size = get_real_file_size(s); + free(s); + } + else + f->size = get_real_file_size(path); + + return f; +} + +FILE *fopen(const char *path, const char *mode) +{ + return fopen_internal(path, mode, NULL); +} + +int fclose(FILE *stream) +{ + stream->used = 0; + close(stream->fildes); + return 0; +} + +/* + * fread doesn't require reads to be carried in block unit + * Notice that however seeks on the CD drive will be very slow - so avoid using non block units + * + * This is done to make programming and porting easier + */ + +int fread(void *ptr, int size, int nmemb, FILE *f) +{ + int rsize = size * nmemb; + int csize = rsize; + int max; + int nsect = (f->pos + rsize) >> 11; + nsect -= f->pos >> 11; + nsect++; + + //printf("f->dev = %d, f->pos = %d, rsize = %d\n", f->dev, f->pos, rsize); + + if(f->dev == FDEV_CDROM) + { + // First sector + lseek(f->fildes, f->pos & (~0x7ff), SEEK_SET); + read(f->fildes, onesec_buf, 2048); + + max = 2048 - (f->pos & 2047); + + //printf("ptr(FIRST) = %d, %x\n", ptr, ptr); + printf("rsize = %d\n", rsize); + + memcpy(ptr, onesec_buf + (f->pos & 2047), (rsize > max) ? max : rsize); + + // Middle sector + ptr += max; + + //printf("ptr(MIDDLEsex) = %d, %x\n", ptr, ptr); + nsect--; + csize -= max; + + if(nsect > 1) + { + //lseek(f->fildes, (f->pos & (~0x7ff)) + 2048, SEEK_SET); + +//#warning "Check correctness of this calculation." + + /*if(rsize & 2047) + sect_num = (rsize|2047)+1; + else + sect_num = rsize; + + sect_num -= 4096;*/ + + //printf("read_middle=%d, sect_num = %d\n", read(f->fildes, ptr, sect_num), sect_num); + + read(f->fildes, ptr, (nsect - 1) * 2048); + + ptr += (nsect - 1) * 2048; + csize -= (nsect - 1) * 2048; + nsect = 1; + } + + //printf("ptr(LAST) = %d, %x\n", ptr, ptr); + + if(nsect == 1) + { + // Last sector + read(f->fildes, onesec_buf, 2048); + + memcpy(ptr, onesec_buf, csize); + } + } + else if(f->dev == FDEV_CONSOLE) + return 0; + + + if(f->dev != FDEV_CONSOLE) + { + f->pos+= rsize; + f->eof = (f->pos > f->size); + + if(f->eof) + f->pos = f->size; + } + + return rsize; +} + +int fgetc(FILE *f) +{ + unsigned char c; + + if(f->pos >= f->size) + return EOF; + + fread(&c, sizeof(char), 1, f); + + return (int)c; +} + +int ftell(FILE *f) +{ + return f->pos; +} + +int fseek(FILE *f, int offset, int whence) +{ + switch(whence) + { + case SEEK_SET: + f->pos = offset; + break; + case SEEK_CUR: + f->pos+= offset; + break; + case SEEK_END: + f->pos = f->size + offset; + break; + default: + f->pos = whence + offset; + break; + } + + return 0; +} + +int toupper(int c) +{ + if(c >= 'a' && c <= 'z') + return (c-'a')+'A'; + + return c; +} + +int tolower(int c) +{ + if(c >= 'A' && c <= 'Z') + return (c-'A')+'a'; + + return c; +} + +int libc_get_transtbl_fname(const char *tofind, char *outstr, int outl) +{ + FILE *f; + int s; + int x; + int type; + int y; + int l = strlen(tofind); + int filename_found = 0; + int exit_loop = 0; + int otfp = 0; + int tfp = 0; + char transtbl[0x4000]; + char orgname[16]; + char newname[256]; + char rootpath[256]; + + bzero(transtbl, 0x4000); + strcpy(rootpath, "cdrom:\\"); + + f = fopen("cdrom:\\TRANS.TBL;1", "rb"); + + if(f == NULL) + return 0; + + fseek(f, 0, SEEK_END); + s = ftell(f); + fseek(f, 0, SEEK_SET); + fread(transtbl, 1, s, f); + fclose(f); + + outstr[0] = 0; + + x = 0; + + exit_loop = 0; + filename_found = 0; + + for(tfp = 0; tofind[tfp] == '\\' || tofind[tfp] == '/'; tfp++); + + otfp = tfp; + + for(y = otfp; y < l; y++) + { + if(tofind[y] == '\0' || tofind[y] == '\\' || tofind[y] == '/') + break; + } + + tfp = y; + + while((x < s) && !exit_loop) + { + while(transtbl[x] == ' ' || transtbl[x] == '\t' || transtbl[x] == '\n' || transtbl[x] == '\r') + x++; + + if(transtbl[x] == 'F') + type = 0; + else if(transtbl[x] == 'D') + type = 1; + + x++; + + while(transtbl[x] == ' ' || transtbl[x] == '\t' || transtbl[x] == '\n' || transtbl[x] == '\r') + x++; + + y = 0; + + while(!(transtbl[x] == ' ' || transtbl[x] == '\t' || transtbl[x] == '\n' || transtbl[x] == '\r' + || transtbl[x] == 0)) + orgname[y++] = transtbl[x++]; + + orgname[y] = 0; + //printf("orgname = %s\n", orgname); + + while(transtbl[x] == ' ' || transtbl[x] == '\t' || transtbl[x] == '\n' || transtbl[x] == '\r') + x++; + + y = 0; + + while(!(transtbl[x] == '\n' || transtbl[x] == '\r' || transtbl[x] == 0)) + newname[y++] = transtbl[x++]; + + newname[y] = 0; + + while(transtbl[x] == ' ' || transtbl[x] == '\t' || transtbl[x] == '\n' || transtbl[x] == '\r') + x++; + + //printf("newname = %s\n", newname); + + if(strncasecmp(&tofind[otfp], newname, tfp-otfp) == 0) + { + if(type == 0) + { + dprintf("Filename found: %s -> %s%s\n", tofind, rootpath, orgname); + filename_found = 1; + exit_loop = 1; + + strncpy(outstr, rootpath, outl); + strncat(outstr, orgname, outl-strlen(rootpath)); + } + else + { + //printf("Found directory! %s\n", newname); + + //printf("tfp = %d\n", tfp); + + if(tfp == l || tofind[l-1] == '/' + || tofind[l-1] == '\\') + { + dprintf("File not found. A directory was specified.\n"); + exit_loop = 1; + continue; + } + + //tfp++; + for(; tofind[tfp] == '\\' || tofind[tfp] == '/'; tfp++); + + otfp = tfp; + + for(y = otfp; y < l; y++) + { + if(tofind[y] == '\0' || tofind[y] == '\\' || tofind[y] == '/') + break; + } + + tfp = y; + + strcat(rootpath, orgname); + strcat(rootpath, "\\"); + + y = strlen(rootpath); + strcat(rootpath, "TRANS.TBL;1"); + + bzero(transtbl, 0x4000); + + f = fopen(rootpath, "rb"); + + if(f == NULL) + { + dprintf("Couldn't find %s\n", rootpath); + exit_loop = 1; + continue; + } + + rootpath[y] = 0; + + fseek(f, 0, SEEK_END); + s = ftell(f); + fseek(f, 0, SEEK_SET); + fread(transtbl, 1, s, f); + fclose(f); + + x = 0; + } + } + } + + return filename_found; +} + +int isupper(int c) +{ + return (c >= 'A' && c <= 'Z'); +} + +int islower(int c) +{ + return (c >= 'a' && c <= 'z'); +} + +int isdigit(int c) +{ + return (c >= '0' && c <= '9'); +} + +int isxdigit(int c) +{ + return ((c >= '0' && c <= '9') || (c >= 'A' && c<='F') || (c >= 'a' && c<='f')); +} + +int isalpha(int c) +{ + return ((c>='a' && c<='z') || (c>='A' && c<='Z')); +} + +int isalnum(int c) +{ + return ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9')); +} + +int isspace(int c) +{ + return ((c == ' ') || (c == '\f') || (c == '\n') || (c == '\r') || (c == '\t') || (c == '\v')); +} + +int isprint(int c) +{ + return (c >= 0x20) && (c <= 0x7E); +} + +int isgraph(int c) +{ + return (c > 0x20) && (c <= 0x7E); +} + +int iscntrl(int c) +{ + return (c < 0x20); +} + +int isblank(int c) +{ + return ((c == ' ') || (c == '\t')); +} + +void redirect_stdio_to_sio(void) +{ + __stdio_direction = STDIO_DIRECTION_SIO; +} + +void sio_stdio_mapcr(unsigned int setting) +{ + __sio_cr_mapped = setting; +} + +int sio_putchar(int c) +{ + if(c == '\n' && __sio_cr_mapped) + sio_putchar('\r'); + + while(!SIOCheckOutBuffer()); + + SIOSendByte(c); + + return c; +} + +int sio_puts(const char *str) +{ + while(*str) + sio_putchar(*(str++)); + + sio_putchar('\n'); + + return 1; +} + +extern int bios_putchar(int c); +extern int bios_puts(const char *str); + +int putchar(int c) +{ + switch(__stdio_direction) + { + case STDIO_DIRECTION_BIOS: + return bios_putchar(c); + break; + case STDIO_DIRECTION_SIO: + return sio_putchar(c); + break; + } + + return EOF; +} + +int puts(const char *str) +{ + switch(__stdio_direction) + { + case STDIO_DIRECTION_BIOS: + return bios_puts(str); + break; + case STDIO_DIRECTION_SIO: + return sio_puts(str); + break; + } + + return EOF; +} + +int fwrite(void *ptr, int size, int nmemb, FILE *f) +{ + if(IS_CONS_OUT(f)) // stdout or stderr + { + char *c = ptr; + int i; + + for(i = 0; i < size; i++) + putchar(c[i]); + + return size; + } + + return 0; +} + +int fputs(const char *str, FILE *stream) +{ + if(IS_CONS_OUT(stream)) + return puts(str); + + return EOF; +} + +FILE *freopen(const char *path, const char *mode, FILE *stream) +{ + if(stream == NULL) + return NULL; + + if(stream->used) + fclose(stream); + + return fopen_internal(path, mode, stream); +} + +void clearerr(FILE *stream) +{ + stream->eof = 0; + stream->error = 0; +} + +int feof(FILE *stream) +{ + return stream->eof; +} + +int ferror(FILE *stream) +{ + return stream->error; +} + +int fileno(FILE *stream) +{ + return stream->fildes; +} diff --git a/libpsx/src/libc/error.c b/libpsx/src/libc/error.c new file mode 100644 index 0000000..6863b2f --- /dev/null +++ b/libpsx/src/libc/error.c @@ -0,0 +1,19 @@ +#include <stdio.h> +#include <string.h> + +static char strerror_not_implemented[64]; + +char *strerror(int errnum) +{ + strerror_r(errnum, strerror_not_implemented, 64); + + return strerror_not_implemented; +} + +int strerror_r(int errnum, char *strerrbuf, size_t buflen) +{ + snprintf(strerrbuf, buflen, + "strerror(%d)", errnum); + + return 0; +} diff --git a/libpsx/src/libc/misc.c b/libpsx/src/libc/misc.c new file mode 100644 index 0000000..f3a1326 --- /dev/null +++ b/libpsx/src/libc/misc.c @@ -0,0 +1,106 @@ +#include <stdio.h> +#include <stdlib.h> + +static unsigned int rand_seed = 0; +static unsigned int rand_next = 0; + +int abs(int x) +{ + if(x<0)return -x; + + return x; +} + +void srand(unsigned int seed) +{ + rand_seed = seed; +} + +int rand() +{ + rand_next = (rand_next ^ 0x98765432)*0x1357; + + return rand_next % RAND_MAX; +} + +static char *__ulltoa_internal__(unsigned long long value, char *str, int base, int minus_sign, + unsigned long long maxp ) +{ + unsigned long long p; + unsigned long long p3; + int c; + int a; + + p = 1; + + do + { + p3 = p; + p *= base; + + if(maxp && p > maxp) + break; + }while((p >= p3) && !(p % p3)); + + if(minus_sign) + *(str++) = '-'; + + for(a = 0;p3 > 0;p3/=base) + { + c = value / p3; + value %= p3; + + if(c) + a = 1; + + if(a) + { + if(c <= 9) + c += '0'; + else + c = (c - 10) + 'A'; + + *(str++) = c; + } + } + + *str = '\0'; + + return str; +} + +char *ulltoa(unsigned long long value, char *str, int base) +{ + return __ulltoa_internal__(value, str, base, 0, 0); +} + +char *ultoa(unsigned long value, char *str, int base) +{ + return __ulltoa_internal__(value, str, base, 0, (sizeof(long)==8)?0:0xFFFFFFFF); +} + +char *utoa(unsigned int value, char *str, int base) +{ + return __ulltoa_internal__(value, str, base, 0, 0xFFFFFFFF); +} + +char *lltoa(long long value, char *str, int base) +{ + return __ulltoa_internal__((value<0)?-value:value, str, base, value<0, 0); +} + +char *ltoa(long value, char *str, int base) +{ + return __ulltoa_internal__((value<0)?-value:value, str, base, value<0, (sizeof(long)==8)?0:0xFFFFFFFF); +} + +char *itoa(int value, char *str, int base) +{ + return __ulltoa_internal__((value<0)?-value:value, str, base, value<0, 0xFFFFFFFF); +} + +void abort(void) +{ + printf("abort(): Abnormal program termination\n"); + exit(1); +} diff --git a/libpsx/src/libc/printf.c b/libpsx/src/libc/printf.c new file mode 100644 index 0000000..ce8ffcd --- /dev/null +++ b/libpsx/src/libc/printf.c @@ -0,0 +1,899 @@ +/* + * printf.c + * + * Part of the PSXSDK C library + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define SPRINTF_ALT_FLAG (1<<0) +#define SPRINTF_ZERO_FLAG (1<<1) +#define SPRINTF_NEGFIELD_FLAG (1<<2) +#define SPRINTF_SPACE_FLAG (1<<3) +#define SPRINTF_SIGN_FLAG (1<<4) + +// sprintf() macros to calculate the real padding and to write it +// these were made to not repeat the code in the function +// they can only be used in sprintf() + +// sprintf macros START + +#define calculate_real_padding() \ + y = 1; \ + \ + for(x=0;x<=19;x++) \ + { \ + if(x == 0) \ + pad_quantity--; \ + else \ + { \ + if(arg / y) \ + pad_quantity--; \ + } \ + \ + y *= 10; \ + } \ + \ + if(pad_quantity < 0) pad_quantity = 0; + +/*#define calculate_real_padding_hex() \ + for (x = 0; x < 8; x++) \ + { \ + if(x == 0) \ + pad_quantity--; \ + else \ + { \ + if((arg >> (x * 4)) & 0xf) \ + pad_quantity--; \ + } \ + }*/ + +#define calculate_real_padding_hex() \ + last = 0; \ + for (x = 0; x < 16; x++) \ + if((arg >> (x * 4)) & 0xf) \ + last = x; \ + \ + pad_quantity = (pad_quantity - 1) - last; \ + if(pad_quantity < 0) pad_quantity = 0; + +#define write_padding() \ + if(!(flags & SPRINTF_NEGFIELD_FLAG)) \ + for(x = 0; x < pad_quantity; x++) \ + { \ + if(flags & SPRINTF_ZERO_FLAG) \ + put_in_string(string, ssz, '0', string_pos++); \ + else \ + put_in_string(string, ssz, ' ', string_pos++); \ + } + +#define write_neg_padding() \ + if(flags & SPRINTF_NEGFIELD_FLAG) \ + { \ + for(x = 0; x < pad_quantity; x++) \ + put_in_string(string, ssz, ' ', string_pos++);\ + } + +// sprintf macros END + +enum +{ + SPRINTF_SIZE_CHAR, + SPRINTF_SIZE_SHORT, + SPRINTF_SIZE_INT, + SPRINTF_SIZE_LONG, + SPRINTF_SIZE_LONG_LONG, +}; + +static unsigned int get_arg_in_size(int size, unsigned long long *arg, unsigned int check_sign) +{ + int s = 0; + + switch(size) + { + case SPRINTF_SIZE_CHAR: + *arg &= 0xff; + + if(check_sign) + { + if(*arg & (1<<7)) + { + *arg |= 0xffffff00; + *arg = ~(*arg - 1); + s = 1; + } + } + break; + case SPRINTF_SIZE_SHORT: + *arg &= 0xffff; + + if(check_sign) + { + if(*arg & (1<<15)) + { + *arg |= 0xffff0000; + *arg = ~(*arg - 1); + s = 1; + } + } + break; + +// sizeof(long) == sizeof(int) on 32bit, so this will suffice for the psx + + case SPRINTF_SIZE_INT: + case SPRINTF_SIZE_LONG: + *arg &= 0xffffffff; + + if(check_sign) + { + if(*arg & (1<<31)) + { + *arg |= (long long)0xffffffff00000000; + *arg = ~(*arg - 1); + s = 1; + } + } + break; + + case SPRINTF_SIZE_LONG_LONG: + if(check_sign) + { + if(*arg & ((long long)1<<63)) + { + *arg = ~(*arg - 1); + s = 1; + } + } + break; + } + + return s; +} + +static int libc_ulltoa(unsigned long long i, char *dst, int n, int nopad) +{ + int x, y; + unsigned long long a, b; + int empty_digit = 1; + int sp=0; + int n2=0; + + if(n<=0) + return 0; + + for(x=18;x>=0;x--) + { + a = 1; + for(y = 0; y<x; y++) + a *= 10; + + b = (i/a); + + if(b>=1) + empty_digit = 0; + + if(empty_digit == 0 || x == 0 || nopad == 1) + { + i -= b*a; + + //put_in_string(string, ssz, b + '0', string_pos++); + if(n2!=(n-1)) + { + //printf("n2=%d\n",n2); + dst[sp++] = b + '0'; + n2++; + } + } + } + + dst[sp] = 0; + + return n2; +} + +/*static void libc_float_to_string(float fl, char *dst, int n) +{ + unsigned int *p = (unsigned int*)&fl; + unsigned long long i = 0; + unsigned long long f = 0; + int e, m, s; + int x, y; + unsigned long long z; + + s = *p >> 31; + + e = (*p >> 23) & 0xff; + + m = *p & 0x7fffff; + + if(e == 255 && m == 0) // Infinity + { + if(s) strncpy(dst, "-inf", n); + else strncpy(dst, "inf", n); + }else if(e == 255 && m != 0) // NaN + { + strncpy(dst, "nan", n); + } + else + { + e -= 127; + m |= 1<<23; + + + + for(x = 23; x >= 0; x--) + { + if(m & (1<<x)) + { + if(e >= 0) + { + z = 1; + for(y=0;y<e;y++) + z*=2; + + i+=z; + } + else + { + z = 5000000000000000000; + for(y = 1; y < -e; y++) + z /= 2; + + f+=z; + } + } + e--; + } + + if(s && (n>0)) + { + *(dst++) = '-'; + n--; + } + + x = libc_ulltoa(i, dst, n, 0); + n-=x+1; + dst+=x; + + if(n>0) + { + *(dst++) = '.'; + n--; + if(n>0) + { + x = libc_ulltoa(f, dst, n<6?n:6, 1); + n-=x; + dst+=x; + + if(n>0) + *dst=0; + } + } + } +}*/ + +static void libc_double_to_string(double fl, char *dst, int n, int prec) +{ + unsigned long long *p = (unsigned long long *)&fl; + unsigned long long i = 0; + unsigned long long f = 0; + unsigned long long m, s; + long long e; + int x; + unsigned long long z; + + s = *p >> 63; + + e = (*p >> 52) & 0x7ff; + //printf("%d\n", e); + + m = *p & 0xfffffffffffff; + + for(x=0;x<52;x++) + if(m&((unsigned long long)1<<(52-x))) putchar('1'); else putchar('0'); + + if(e == 255 && m == 0) // Infinity + { + if(s) strncpy(dst, "-inf", n); + else strncpy(dst, "inf", n); + }else if(e == 255 && m != 0) // NaN + { + strncpy(dst, "nan", n); + } + else + { + e -= 1023; + m |= (unsigned long long)1<<52; + + for(x = 52; x >= 0; x--) + { + if(m & ((unsigned long long)1<<x)) + { + if(e >= 0) + { + z = (long long)1<<e; + + i+=z; + } + else + { + z = 5000000000000000000; + z >>= -(e + 1); + + f+=z; + } + } + e--; + } + + if(s && (n>0)) + { + *(dst++) = '-'; + n--; + } + + x = libc_ulltoa(i, dst, n, 0); + n-=x+1; + dst+=x; + + dprintf("N = %d\n", n); + + if(n>0) + { + *(dst++) = '.'; + + if(n>0) + libc_ulltoa(f, dst, (n<(prec+1))?n:(prec+1), 1); + } + } +} + +static char libc_sprintf_floatbuf[64]; + +static int __vsnprintf_internal(char *string, size_t size, const char *fmt, va_list ap, int (put_in_string(char *string, unsigned int sz, char c, int pos))) +{ + int string_pos,fmt_pos; + int l; + unsigned long long arg; + char *argcp; + char *argcp_tmp; + int directive_coming = 0; + int flags = 0; + int argsize = 2; // int + int x, y; + unsigned long long a, b; + int empty_digit; + int ssz = size - 1; + int zero_flag_imp = 0; + int pad_quantity = 0; + int pad_quantity_f = -1; + int last; + + if(size == 0) + ssz = 0; + + l = strlen(fmt); + + string_pos = 0; + + for(fmt_pos=0;fmt_pos<l;fmt_pos++) + { + if(directive_coming) + { + switch(fmt[fmt_pos]) + { + case '%': + put_in_string(string, ssz, '%', string_pos++); + directive_coming = 0; + break; + case ' ': + flags |= SPRINTF_SPACE_FLAG; + break; + case '#': // Specify alternate form + flags |= SPRINTF_ALT_FLAG; + break; + case '+': // Specify sign in signed conversions + flags |= SPRINTF_SIGN_FLAG; + break; + case '0': // Padding with zeros... + if(zero_flag_imp == 0) + { + flags |= SPRINTF_ZERO_FLAG; + zero_flag_imp = 1; + //printf("Zero padding enabled!\n"); + } + else + { + pad_quantity *= 10; + //printf("pad_quantity = %d\n", pad_quantity); + } + break; + case '1' ... '9': // '...' cases are a GNU extension, + // but they simplify a lot + + pad_quantity *= 10; + pad_quantity += fmt[fmt_pos] - '0'; + zero_flag_imp = 1; + + //printf("pad_quantity = %d\n", pad_quantity); + break; + case '-': // Negative field flag + if(flags & SPRINTF_ZERO_FLAG) + flags &= ~SPRINTF_ZERO_FLAG; + + flags |= SPRINTF_NEGFIELD_FLAG; + break; + case '.': // Floating point precision + pad_quantity_f = pad_quantity; + pad_quantity = 0; + break; + case 'h': // Half argument size + if(argsize) argsize--; + break; + case 'l': // Double argument size + if(argsize < 2) argsize = 2; + else if(argsize < SPRINTF_SIZE_LONG_LONG) argsize++; + break; + +// 'j', 't', 'z', 'q' added 2013-10-26 by nextvolume + + case 'j': // Maximum integer size + argsize = SPRINTF_SIZE_LONG_LONG; + break; + + case 't': // Size of ptrdiff_t (i.e. long on 32-bit, long long on 64-bit) + argsize = (sizeof(void*)==8)? + SPRINTF_SIZE_LONG_LONG:SPRINTF_SIZE_LONG; + break; + + case 'z': // Size of size_t (int) + argsize = SPRINTF_SIZE_INT; + break; + + case 'q': // Size of quad_t + argsize = SPRINTF_SIZE_LONG_LONG; + break; + + case 'd': // signed decimal + case 'i': + empty_digit = 1; + + //printf("argsize = %d\n", argsize); + + if(argsize < SPRINTF_SIZE_LONG_LONG) + arg = (unsigned long long)va_arg(ap, unsigned int); + else + arg = va_arg(ap, unsigned long long); + + if(flags & SPRINTF_SPACE_FLAG) + put_in_string(string, ssz, ' ', string_pos++); + + if(get_arg_in_size(argsize, &arg, 1)) + { + put_in_string(string, ssz, '-', string_pos++); + pad_quantity--; + } + else + { + if(flags & SPRINTF_SIGN_FLAG) + { + put_in_string(string, ssz, '+', string_pos++); + pad_quantity--; + } + } + + /* Calculate how much padding we have to write */ + + /*y = 1; + + for(x=0;x<=9;x++) + { + if(x == 0) + pad_quantity--; + else + { + if(arg / y) + pad_quantity--; + } + + y *= 10; + } + if(pad_quantity < 0) pad_quantity = 0;*/ + + calculate_real_padding(); + + //printf("Actual pad quantity = %d\n", pad_quantity); + + + + /*if(!(flags & SPRINTF_NEGFIELD_FLAG)) + { + for(x = 0; x < pad_quantity; x++) + { + if(flags & SPRINTF_ZERO_FLAG) + put_in_string(string, ssz, '0', string_pos++); + else + put_in_string(string, ssz, ' ', string_pos++); + } + }*/ + + write_padding(); + + for(x=19;x>=0;x--) + { + a = 1; + for(y = 0; y<x; y++) + a *= 10; + + b = (arg/a); + + if(b>=1) + empty_digit = 0; + + if(empty_digit == 0 || x == 0) + { + arg -= b*a; + + put_in_string(string, ssz, b + '0', string_pos++); + } + } + + /*if(flags & SPRINTF_NEGFIELD_FLAG) + { + for(x = 0; x < pad_quantity; x++) + put_in_string(string, ssz, ' ', string_pos++); + }*/ + write_neg_padding(); + + directive_coming = 0; + break; + case 'u': // unsigned decimal + empty_digit = 1; + + if(argsize < SPRINTF_SIZE_LONG_LONG) + arg = (unsigned long long)va_arg(ap, unsigned int); + else + arg = va_arg(ap, unsigned long long); + + get_arg_in_size(argsize, &arg, 0); + + calculate_real_padding(); + write_padding(); + + for(x=19;x>=0;x--) + { + a = 1; + for(y = 0; y<x; y++) + a *= 10; + + + + b = (arg/a); + + if(b>=1) + empty_digit = 0; + + if(empty_digit == 0 || x == 0) + { + arg -= b*a; + + put_in_string(string, ssz, b + '0', string_pos++); + } + } + + write_neg_padding(); + + directive_coming = 0; + break; + case 'x': // Hexadecimal + case 'X': // Hexadecimal with big letters + case 'p': // Hexadecimal with small letters with '0x' prefix + empty_digit = 1; + + if(argsize < SPRINTF_SIZE_LONG_LONG) + arg = (unsigned long long)va_arg(ap, unsigned int); + else + arg = va_arg(ap, unsigned long long int); + + get_arg_in_size(argsize, &arg, 0); + + if(fmt_pos == 'p') + flags |= SPRINTF_ALT_FLAG; + + if(flags & SPRINTF_ALT_FLAG) + { + put_in_string(string, ssz, '0', string_pos++); + + if(fmt[fmt_pos] == 'X') + put_in_string(string, ssz, 'X', string_pos++); + else + put_in_string(string, ssz, 'x', string_pos++); + } + + calculate_real_padding_hex(); + write_padding(); + + for(x=15;x>=0;x--) + { + y = arg >> (x << 2); + y &= 0xf; + + if(y>=1) + empty_digit = 0; + + if(empty_digit == 0 || x == 0) + { + if(y>=0 && y<=9) + put_in_string(string, ssz, y + '0', string_pos++); + else if(y>=0xA && y<=0xF) + { + if(fmt[fmt_pos] == 'X') + put_in_string(string, ssz, (y - 0xa) + 'A', string_pos++); + else + put_in_string(string, ssz, (y - 0xa) + 'a', string_pos++); + } + } + } + + write_neg_padding(); + + directive_coming = 0; + break; + case 'c': // character + arg = va_arg(ap, int); + + put_in_string(string, ssz, arg & 0xff, string_pos++); + + directive_coming = 0; + break; + case 's': // string + argcp = va_arg(ap, char *); + argcp_tmp = argcp; + + if(argcp == NULL) + { + // Non standard extension, but supported by Linux and the BSDs. + + put_in_string(string, ssz, '(', string_pos++); + put_in_string(string, ssz, 'n', string_pos++); + put_in_string(string, ssz, 'u', string_pos++); + put_in_string(string, ssz, 'l', string_pos++); + put_in_string(string, ssz, 'l', string_pos++); + put_in_string(string, ssz, ')', string_pos++); + + directive_coming = 0; + break; + } + + while(*argcp_tmp) + { + if(pad_quantity > 0) pad_quantity--; + argcp_tmp++; + } + + if(!(flags & SPRINTF_NEGFIELD_FLAG)) + { + while(pad_quantity > 0) + { + put_in_string(string,ssz, ' ', string_pos++); + pad_quantity--; + } + } + + while(*argcp) + { + put_in_string(string, ssz, *argcp, string_pos++); + + argcp++; + } + + if(flags & SPRINTF_NEGFIELD_FLAG) + { + while(pad_quantity > 0) + { + put_in_string(string,ssz, ' ', string_pos++); + pad_quantity--; + } + } + + directive_coming = 0; + break; + case 'o': // Octal + empty_digit = 1; + + if(argsize < SPRINTF_SIZE_LONG_LONG) + arg = (unsigned long long)va_arg(ap, unsigned int); + else + arg = va_arg(ap, unsigned long long); + + for(x=21;x>=0;x--) + { + y = arg >> (x * 3); + y &= 0x7; + + if(y>=1) + empty_digit = 0; + + if(empty_digit == 0 || x == 0) + put_in_string(string, ssz, y + '0', string_pos++); + } + + directive_coming = 0; + break; + case '@': // Binary + empty_digit = 1; + + if(argsize < SPRINTF_SIZE_LONG_LONG) + arg = (unsigned long long)va_arg(ap, unsigned int); + else + arg = va_arg(ap, unsigned long long); + + for(x=63;x>=0;x--) + { + y = (arg >> x); + y &= 1; + + if(y>=1) + empty_digit = 0; + + if(empty_digit == 0 || x == 0) + put_in_string(string, ssz, y + '0', string_pos++); + } + + directive_coming = 0; + break; + + case 'f': + if(pad_quantity_f == -1) + pad_quantity_f = 6; + else + { + x = pad_quantity_f; + pad_quantity_f = pad_quantity; + pad_quantity = x; + } + + dprintf("PRECISION = %d\n", pad_quantity_f); + + libc_double_to_string(va_arg(ap, double), libc_sprintf_floatbuf, 64, pad_quantity_f); + + // calculate padding + pad_quantity -= strlen(libc_sprintf_floatbuf); + + write_padding(); + + for(x=0;libc_sprintf_floatbuf[x]!=0;x++) + put_in_string(string, ssz, libc_sprintf_floatbuf[x], string_pos++); + + write_neg_padding(); + + directive_coming = 0; + break; + case 'n': // Number of characters written + *(va_arg(ap,unsigned int*)) = string_pos; + + directive_coming = 0; + break; + + default: + put_in_string(string, ssz, fmt[fmt_pos], string_pos++); + directive_coming = 0; + } + } + else + { + if(fmt[fmt_pos] == '%') + { + directive_coming = 1; + flags = 0; + argsize = 2; + pad_quantity = 0; + pad_quantity_f = -1; + zero_flag_imp = 0; + } + else + { + put_in_string(string, ssz, fmt[fmt_pos], string_pos++); + } + } + } + + /*if(((size-1) < string_pos) && (size>0)) + string[size - 1] = 0; + else + string[string_pos] = 0;*/ + put_in_string(string, ssz, '\0', string_pos); + + return string_pos; +} + +static int vsnprintf_put_in_string(char *string, unsigned int sz, char c, int pos) +{ + if(pos>=sz) + return 0; + else + string[pos] = c; + + return 1; +} + +int vsnprintf(char *string, size_t size, const char *fmt, va_list ap) +{ + return __vsnprintf_internal(string, size, fmt, ap, vsnprintf_put_in_string); +} + +static int sio_put_in_string(char *string, unsigned int sz, char c, int pos) +{ + sio_putchar(c); + + return 1; +} + +int sio_vprintf(const char *fmt, va_list ap) +{ + return __vsnprintf_internal(NULL, -1, fmt, ap, sio_put_in_string); +} + +static int out_put_in_string(char *string, unsigned int sz, char c, int pos) +{ + putchar(c); + + return 1; +} + +int vprintf(char *fmt, va_list ap) +{ + return __vsnprintf_internal(NULL, -1, fmt, ap, out_put_in_string); +} + +int vsprintf(char *string, const char *fmt, va_list ap) +{ + return vsnprintf(string, 0xffffffff, fmt, ap); +} + +int sprintf(char *string, const char *fmt, ...) +{ + int r; + + va_list ap; + + va_start(ap, fmt); + + r = vsprintf(string, fmt, ap); + + va_end(ap); + + return r; +} + +int snprintf(char *string, size_t size, const char *fmt, ...) +{ + int r; + + va_list ap; + + va_start(ap, fmt); + + r = vsnprintf(string, size, fmt, ap); + + va_end(ap); + + return r; +} + +int sio_printf(const char *fmt, ...) +{ + int r; + + va_list ap; + + va_start(ap, fmt); + + r = sio_vprintf(fmt, ap); + + va_end(ap); + + return r; +} diff --git a/libpsx/src/libc/qsort.c b/libpsx/src/libc/qsort.c new file mode 100644 index 0000000..0cb1d24 --- /dev/null +++ b/libpsx/src/libc/qsort.c @@ -0,0 +1,65 @@ +// quickSort +// +// This public-domain C implementation by Darel Rex Finley. +// +// Modified by Giuseppe Gatta + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) +{ + #define QSORT_MAX_LEVELS 300 + + + int beg[QSORT_MAX_LEVELS], end[QSORT_MAX_LEVELS], i=0, L, R, swap ; + char piv[size]; + + beg[0]=0; end[0]=nmemb; + + while (i>=0) + { + L=beg[i]; R=end[i]-1; + + if (L<R) + { + memcpy(piv, base + (size * L), size); + + while (L<R) + { + while(compar(base + (R*size), piv) > 0 && L<R) R--; + + if (L<R) + { + memcpy(base + (size *L), base + (size * R), size); + L++; + } + + while(compar(base + (L*size), piv) <= 0 && L<R) L++; + + if (L<R) + { + memcpy(base + (size *R), base + (size * L), size); + R--; + } + } + + memcpy(base + (size*L), piv, size); + + beg[i+1]=L+1; + end[i+1]=end[i]; + end[i++]=L; + + if (end[i]-beg[i]>end[i-1]-beg[i-1]) + { + swap=beg[i]; beg[i]=beg[i-1]; beg[i-1]=swap; + swap=end[i]; end[i]=end[i-1]; end[i-1]=swap; + } + } + else + { + i--; + } + } +} diff --git a/libpsx/src/libc/scanf.c b/libpsx/src/libc/scanf.c new file mode 100644 index 0000000..d419030 --- /dev/null +++ b/libpsx/src/libc/scanf.c @@ -0,0 +1,425 @@ +// vsscanf +// Programmed by Giuseppe Gatta, 2011 + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> + +char libc_vsscanf_buf[512]; +char libc_vsscanf_allow[256]; + +enum +{ + elem_skip_space = 1, +}; + +int libc_vsscanf_get_element(char *dst, const char *src, int flag, int s) +{ + int i; + const char *osrc = src; + + if(flag & elem_skip_space) + { + while(*src == ' ') + src++; + } + + for(i=0;i<s;i++) + { + if((flag & elem_skip_space) && *src == ' ') + break; + + if(*src != 0) + *(dst++) = *(src++); + else + break; + } + + *dst = 0; + + return src - osrc; +} + +enum +{ + scanf_s_char, scanf_s_short, scanf_s_int, + scanf_s_long, + scanf_s_long_long +}; + +int vsscanf(const char *str, const char *format, va_list ap) +{ + int fp = 0; + int sp = 0; + int conv = 0; + int sz = scanf_s_int; // size for numbers defaults to 32-bit + int i,x,y,z;// h; + int suppress = 0; +// int neg = 0; + int fsz = 512; + int def_fsz = 1; + int exspace = 0; +// int alt = 0; + int r = 0; + int exit_loop=0; + char *ep; + long long buf; + double fbuf; + + + while(format[fp] && str[sp] && !exit_loop) + { + if(conv) + { + switch(format[fp]) + { + case '%': // Percent, assignment does not occur + conv = 0; + break; + + case 'h': // Halve size + sz--; + break; + + case 'l': // Double size + sz++; + break; + + case '*': // Suppress + suppress = 1; + break; + + case ' ': // Explicit space + exspace = 1; + break; + + case '#': // Alternate format + //alt = 1; + break; + + case '0' ... '9': // '0' ... '9' is a GNU C extension! + if(def_fsz) + { + def_fsz = 0; + fsz = 0; + } + + fsz *= 10; + fsz+=format[fp]-'0'; + + if(fsz > 512) + fsz = 512; // 512 is the maximum. + break; + + case '@': // Binary. Non-standard extension + libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz); + buf = strtoll(libc_vsscanf_buf, &ep, 2); + sp += ep - libc_vsscanf_buf; + + if(!suppress) + { + switch(sz) + { + case scanf_s_char: *(va_arg(ap, signed char*)) = (signed char)buf;break; + case scanf_s_short: *(va_arg(ap, short*)) = (short)buf; break; + case scanf_s_int: *(va_arg(ap, int*)) = (int)buf; break; + case scanf_s_long: *(va_arg(ap, long*)) = (long)buf; break; + case scanf_s_long_long: *(va_arg(ap, long long*)) = buf; break; + } + r++; + } + + conv = 0; + break; + + case 'D': + sz++; + case 'd': // Decimal + case 'u': + libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz); + buf = strtoll(libc_vsscanf_buf, &ep, 10); + sp += ep - libc_vsscanf_buf; + + if(!suppress) + { + switch(sz) + { + case scanf_s_char: *(va_arg(ap, signed char*)) = (signed char)buf;break; + case scanf_s_short: *(va_arg(ap, short*)) = (short)buf; break; + case scanf_s_int: *(va_arg(ap, int*)) = (int)buf; break; + case scanf_s_long: *(va_arg(ap, long*)) = (long)buf; break; + case scanf_s_long_long: *(va_arg(ap, long long*)) = buf; break; + } + r++; + } + + conv = 0; + break; + + case 's': // String + sp += libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz); + + if(!suppress) + { + strcpy(va_arg(ap, char*), libc_vsscanf_buf); + r++; + } + + conv = 0; + break; + + case 'c': + if(def_fsz) + fsz = 1; + + sp += (i = libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], (exspace ? elem_skip_space : 0), fsz)); + if(!suppress) + { + memcpy(va_arg(ap, char*), libc_vsscanf_buf, (fsz>i)?i:fsz); + r++; + } + break; + + case 'n': + if(!suppress) + { + *(va_arg(ap, int*)) = sp; + r++; + } + break; + + case 'p': + case 'x': + case 'X': + libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz); + buf = strtoll(libc_vsscanf_buf, &ep, 16); + sp += ep - libc_vsscanf_buf; + + if(!suppress) + { + switch(sz) + { + case scanf_s_char: *(va_arg(ap, unsigned char*)) = (unsigned char)buf; break; + case scanf_s_short: *(va_arg(ap, unsigned short*)) = (unsigned short)buf; break; + case scanf_s_int: *(va_arg(ap, unsigned int*)) = (unsigned int)buf; break; + case scanf_s_long: *(va_arg(ap, unsigned long*)) = (unsigned long)buf; break; + case scanf_s_long_long: *(va_arg(ap, unsigned long long*)) = (unsigned long long)buf; break; + } + r++; + } + + conv = 0; + break; + + case 'O': + sz++; + case 'o': // Octal integer + libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz); + buf = strtoll(libc_vsscanf_buf, &ep, 8); + sp += ep - libc_vsscanf_buf; + + if(!suppress) + { + switch(sz) + { + case scanf_s_char: *(va_arg(ap, unsigned char*)) = (unsigned char)buf;break; + case scanf_s_short: *(va_arg(ap, unsigned short*)) = (unsigned short)buf; break; + case scanf_s_int: *(va_arg(ap, unsigned int*)) = (unsigned int)buf;break; + case scanf_s_long: *(va_arg(ap, unsigned long*)) = (unsigned long)buf; break; + case scanf_s_long_long: *(va_arg(ap, unsigned long long*)) = (unsigned long long)buf;break; + } + r++; + } + + conv = 0; + break; + + case 'i': + libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz); + + if(libc_vsscanf_buf[0] == '0') + { + if(libc_vsscanf_buf[1] == 'x' || libc_vsscanf_buf[1] == 'X') + i = 16; + else + i = 8; + } + else + i = 10; + + buf = strtoll(libc_vsscanf_buf, &ep, i); + sp += ep - libc_vsscanf_buf; + + if(!suppress) + { + switch(sz) + { + case scanf_s_char: *(va_arg(ap, signed char*)) = (signed char)buf; break; + case scanf_s_short: *(va_arg(ap, short*)) = (short)buf; break; + case scanf_s_int: *(va_arg(ap, int*)) = (int)buf; break; + case scanf_s_long: *(va_arg(ap, long*)) = (long)buf; break; + case scanf_s_long_long: *(va_arg(ap, long long*)) = (long long)buf; break; + } + r++; + } + + conv = 0; + break; + + case '[': + i=0; + x=0; // Exclusion? + //h=0; // Hyphen? + + fp++; + i++; + + while(format[fp]) + { + if(format[fp] == '^' && i==1) + { + memset(libc_vsscanf_allow, 1, 256); + x = 1; + fp++; i++; continue; + } + + if(x) + { + if(format[fp] == ']' && i>=3) + break; + } + else + { + if(format[fp] == ']' && i>=2) + break; + } + + if(format[fp] == '-') + { + if(format[fp+1] != ']') + y = 1; + else + libc_vsscanf_allow['-'] = x^1; + } + else + { + if(y == 1) + { + if(format[fp] < format[fp-2]) + libc_vsscanf_allow[(unsigned char)format[fp]] = x^1; + else + for(z = format[fp-2]; z <= format[fp]; z++) + libc_vsscanf_allow[z] = x^1; + + y = 0; + + //printf("%s all chars from %c to %c\n", x?"Excluding":"Including",format[fp-2], format[fp]); + } + else + libc_vsscanf_allow[(unsigned char)format[fp]] = x^1; + } + + fp++; + i++; + } + +// Now as we know what our character set is, let's get data from the string + /* puts("Character set:"); + + for(y=0;y<16;y++) + { + for(x=0;x<16;x++) + if(libc_vsscanf_allow[(y*16) + x]) + putchar((y*16)+x); + else + putchar('*'); + + putchar('\n'); + } + */ + i = 0; + + while(libc_vsscanf_allow[(unsigned char)str[sp]] && i<512) + libc_vsscanf_buf[i++] = str[sp++]; + + libc_vsscanf_buf[i] = 0; + + if(!suppress) + { + strcpy(va_arg(ap, char*), libc_vsscanf_buf); + r++; + } + break; + + case 'f': // Floating point number + libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz); + fbuf = strtod(libc_vsscanf_buf, &ep); + sp += ep - libc_vsscanf_buf; + + if(!suppress) + { + switch(sz) + { + case scanf_s_char: + case scanf_s_short: + case scanf_s_int: + *(va_arg(ap, float*)) = (float)fbuf; + break; + + case scanf_s_long: + case scanf_s_long_long: + *(va_arg(ap, double*)) = fbuf; + break; + } + r++; + } + + conv = 0; + break; + + } + } + else + { + if(format[fp] == '%') + { + // conv = 1; + // neg = 0; + suppress = 0; + sz = scanf_s_int; + fsz = 512; + def_fsz = 1; + exspace = 0; + // alt = 0; + bzero(libc_vsscanf_allow, 256); + //chset = 0; + } + else if(format[fp] != ' ') + { + if(format[fp] != str[sp]) + exit_loop=1; + + sp++; + } + + } + + fp++; + } + + return r; +} + +int sscanf(const char *str, const char *fmt, ...) +{ + int r; + va_list ap; + + va_start(ap, fmt); + r = vsscanf(str, fmt, ap); + + va_end(ap); + return r; +} diff --git a/libpsx/src/libc/stat.c b/libpsx/src/libc/stat.c new file mode 100644 index 0000000..1c43b92 --- /dev/null +++ b/libpsx/src/libc/stat.c @@ -0,0 +1,31 @@ +#include <psx.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> + +int stat(const char *path, struct stat *sb) +{ + struct DIRENTRY dir_e; + + if(firstfile((char*)path, &dir_e) == NULL) + return -1; + + sb->st_size = dir_e.size; + + if(strncmp(path, "cdrom:", 6) == 0) + sb->st_blksize = 2048; + else if(strncmp(path, "bu00:", 5) == 0 || + strncmp(path, "bu10:", 5) == 0) + sb->st_blksize = 128; + else +// not a real blocksize, will be there just as a placeholder + sb->st_blksize = 1024; + + sb->st_blocks = + sb->st_size / sb->st_blksize; + + if(sb->st_size % sb->st_blksize) + sb->st_blocks++; + + return 0; +} diff --git a/libpsx/src/libc/string.c b/libpsx/src/libc/string.c new file mode 100644 index 0000000..ea59b91 --- /dev/null +++ b/libpsx/src/libc/string.c @@ -0,0 +1,706 @@ +/* + * string.c + * + * Part of the PSXSDK C library + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> + +void *memcpy(void *dst, const void *src, size_t len) +{ + void *dst2 = dst; + + while(len--) + *(((unsigned char*)dst++)) = *(((unsigned char*)src++)); + + return dst2; +} + +void *memccpy(void *dst, const void *src, int c, size_t len) +{ + unsigned char c2; + + while(len--) + { + *(((unsigned char*)dst++)) = ( c2 = *(((unsigned char*)src++)) ); + + if(c2 == c) + return (void*)src; + } + + return NULL; +} + +void *memset(void *dst , char c , size_t n) +{ + unsigned char *dstc = (unsigned char*)dst; + int x; + + for(x = 0; x < n; x++) + dstc[x] = c; + + return dst; +} + +int memcmp(const void *b1, const void *b2, size_t n) +{ + int x; + unsigned char *bp1 = (unsigned char*)b1; + unsigned char *bp2 = (unsigned char*)b2; + + for(x = 0; x < n; x++) + if(bp1[x] != bp2[x]) + return (bp1[x] - bp2[x]); + + return 0; +} + +void *memmove(void *dst, const void *src, size_t len) +{ + void *dst2 = dst; + + dst+=len-1; + src+=len-1; + + while(len--) + *(((unsigned char*)dst--)) = *(((unsigned char*)src--)); + + return dst2; +} + +void *memchr(void *s , int c , size_t n) +{ + while(n--) + { + if(*((unsigned char*)s) == (unsigned char)c) + return s; + + s++; + } + + return NULL; +} + +char *strncpy(char *dst, const char *src, size_t len) +{ + char *odst=dst; + + while(*src && len) + { + *(dst++) = *(src++); + len--; + } + + if(len)*dst = 0; + + return odst; +} + +char *strcpy(char *dst, const char *src) +{ + char *odst = dst; + + while((*(dst++) = *(src++))); + return odst; +} + +int strlen(const char *str) +{ + int i = 0; + while(*(str++))i++; + return i; +} + +char *strchr(const char *s, int c) +{ + int x; + int l = strlen(s); + + for(x = 0; x <= l; x++) + if(s[x] == c) return (char*)&s[x]; + + return NULL; +} + +char *strrchr(const char *s, int c) +{ + int x; + int l = strlen(s); + + for(x = l; x>=0; x--) + if(s[x] == c) return (char*)&s[x]; + + return NULL; +} + +char *strpbrk(const char *s, const char *charset) +{ + int x,y; + + for(x = 0; s[x] != 0; x++) + for(y = 0; charset[y] != 0; y++) + if(s[x] == charset[y]) return (char*)&s[x]; + + return NULL; +} + +char *strstr(const char *big, const char *little) +{ + int ls = strlen(little); + int bs = strlen(big); + int x; + + if(ls == 0) + return (char*)big; + + if(ls > bs) + return NULL; + + for(x = 0; x <= bs-ls; x++) + if(memcmp(little, &big[x], ls) == 0) + return (char*)&big[x]; + + return NULL; +} + +int strcmp(const char *s1, const char *s2) +{ + while(*s1 && *s2 && (*s1 == *s2)) + { + s1++; + s2++; + } + + return *s1-*s2; +} + +int strncmp(const char *s1, const char *s2, size_t len) +{ + int p = 0; + + while(*s1 && *s2 && (*s1 == *s2) && p<len) + { + p++; + + if(p<len) + { + s1++; + s2++; + } + } + + return *s1-*s2; +} + +int strcoll(const char *s1, const char *s2) +{ + return strcmp(s1, s2); +} + +char *strdup(const char *str) +{ + char *ns = (void*)malloc(strlen(str) + 1); + + if(ns == NULL) + return NULL; + + strcpy(ns, str); + return ns; +} + +char *strndup(const char *str, size_t len) +{ + int n=strlen(str); + char *ns = (void*)malloc((n+1)>len?len:(n+1)); + + if(ns == NULL) + return NULL; + + strncpy(ns, str, (n+1)>len?len:(n+1)); + return ns; +} + +long long strtoll(const char *nptr, char **endptr, int base) +{ + int r = 0; + int t = 0; + int n = 0; + + while(*nptr && isspace(*nptr)) + nptr++; + + if(*nptr == '-') + { + nptr++; + n = 1; + } + + if(base == 0) + { + if(*nptr == '0') + base = 8; + else + base = 10; + } + + if(!(base >= 2 && base <= 36)) + return 0; + + if(base == 16 && *nptr == '0') + { + if(*(nptr+1) == 'x' || *(nptr+1) == 'X') + nptr+=2; + } + + while(*nptr) + { + switch(*nptr) + { + case '0'...'9': + t = *nptr - '0'; + break; + case 'a' ... 'z': + t = (*nptr - 'a') + 10; + break; + case 'A' ... 'Z': + t = (*nptr - 'A') + 10; + break; + default: + t = 1000; + break; + } + + if(t>=base) + break; + + r*=base; + r+=t; + nptr++; + } + + if(endptr)*endptr = (char*)nptr; + return n?-r:r; +} + +long strtol(const char *nptr, char **endptr, int base) +{ + return (long)strtoll(nptr, endptr, base); +} + +double strtod(const char *nptr, char **endptr) +{ + char strbuf[64]; + int x = 0; + int y; + double i=0, d=0; + int s=1; + + if(*nptr == '-') + { + nptr++; + s=-1; + } + + while(*nptr >= '0' && *nptr <= '9' && x < 18) + strbuf[x++] = *(nptr++); + + strbuf[x] = 0; + + i = (double)strtoll(strbuf, NULL, 10); + + if(*nptr == '.') + { + nptr++; + x = 0; + + while(*nptr >= '0' && *nptr <= '9' && x < 7) + strbuf[x++] = *(nptr++); + + strbuf[x] = 0; + + if(endptr != NULL) *endptr = (char*)nptr; + + y=1; + + for(x=0;strbuf[x]!=0;x++) + y*=10; + + d = (double)strtoll(strbuf, NULL, 10); + d /= y; + } + else + { + if(endptr != NULL) + *endptr = (char*)nptr; + } + + return (i + d)*s; +} + +long double strtold(const char *nptr, char **endptr) +{ + return (long double)strtod(nptr, endptr); +} + +float strtof(const char *nptr, char **endptr) +{ + return (float)strtod(nptr, endptr); +} + +char *strcat(char *s, const char *append) +{ + strcpy(&s[strlen(s)], append); + + return s; +} + +char *strncat(char *s, const char *append, size_t count) +{ + strncpy(&s[strlen(s)], append, count); + + return s; +} + +int strcasecmp(const char *s1, const char *s2) +{ + while(tolower(*s1) && tolower(*s2) && (tolower(*s1) == tolower(*s2))) + { + s1++; + s2++; + } + + return tolower(*s1)-tolower(*s2); +} + +int strncasecmp(const char *s1, const char *s2, size_t len) +{ + int p = 0; + + while(tolower(*s1) && tolower(*s2) && (tolower(*s1) == tolower(*s2)) && p<len) + { + p++; + + if(p<len) + { + s1++; + s2++; + } + } + + return tolower(*s1)-tolower(*s2); +} + +int stricmp(const char *s1, const char *s2) +{ + return strcasecmp(s1,s2); +} + +int strnicmp(const char *s1, const char *s2, size_t len) +{ + return strncasecmp(s1, s2, len); +} + +//static char *strtok_string; + +char *strsep(char **stringp, const char *delim) +{ + //int x,y; + char *old = *stringp; + const char *s; + int ok = 0; + + while(**stringp && !ok) + { + s = delim; + + while(*delim) + { + if(**stringp == *delim) + { + **stringp = 0; + ok = 1; + break; + } + + delim++; + } + + delim = s; + + *stringp+=1; + } + + if(!ok)*stringp = NULL; + + return old; +} + +char *strtok(char *str, const char *sep) +{ + int x, y; + static char *strtok_string; + static int strtok_len; + static int strtok_pos; + //int strtok_oldpos = 0; + + if(str != NULL) + { + strtok_string = str; + strtok_len = strlen(str); + + for(x = 0; x < strtok_len; x++) + { + for(y = 0; sep[y] != 0; y++) + { + if(strtok_string[x] == sep[y]) + { + strtok_string[x] = 0; + break; + } + } + } + + strtok_pos = 0; + + while(strtok_pos < strtok_len) + { + if(strtok_string[strtok_pos]) + return &strtok_string[strtok_pos]; + + strtok_pos++; + } + } + + while(strtok_pos < strtok_len) + { + if(!strtok_string[strtok_pos]) + { + strtok_pos++; + break; + } + + strtok_pos++; + } + + while(strtok_pos < strtok_len) + { + + if(strtok_string[strtok_pos]) + return &strtok_string[strtok_pos]; + + strtok_pos++; + } + + return NULL; +} + +int strspn(const char *s, const char *charset) +{ + int x, y; + int appears; + + for(x = 0; s[x] != 0; x++) + { + appears = 0; + + for(y = 0; charset[y] != 0; y++) + { + if(s[x] == charset[y]) + { + appears = 1; + break; + } + } + + if(!appears)break; + } + + return x; +} + +int strcspn(const char *s, const char *charset) +{ + int x, y; + int appears; + + for(x = 0; s[x] != 0; x++) + { + appears = 0; + + for(y = 0; charset[y] != 0; y++) + { + if(s[x] == charset[y]) + { + appears = 1; + break; + } + } + + if(appears)break; + } + + return x; +} + +char *strlwr(char *string) +{ + char *old = string; + + while(*string) + { + *string = tolower(*string); + string++; + } + + return old; +} + +char *strupr(char *string) +{ + char *old = string; + + while(*string) + { + *string = toupper(*string); + string++; + } + + return old; +} + +int atoi(const char *string) +{ + return (int)strtol(string, NULL, 10); +} + +long atol(const char *string) +{ + return strtol(string, NULL, 10); +} + +int strnlen(const char *s, size_t maxlen) +{ + int l=0; + + while(*(s++) && l<maxlen) + l++; + + return l; +} + +void *memrchr(void *b, int c, size_t len) +{ + int i = len - 1; + unsigned char *p = b; + + for(i = len - 1; p[i] != (unsigned char)c && i >= 0;i--); + + return (i>=0)?&p[i]:NULL; +} + +char *stpcpy(char *dst, const char *src) +{ + do + { + *(dst++) = *src; + }while(*(src++)); + + return dst-1; +} + +char *stpncpy(char *dst, const char *src, int len) +{ + int c = 0; + + do + { + if(c < len) + *(dst++) = *src; + + c++; + }while(*(src++) && c < len); + + return dst-1; +} + +char *strcasestr(const char *big, const char *little) +{ + while(*big) + { + const char *pbig = big; + const char *plittle = little; + int ok = 1; + + while(*pbig) + { + if(tolower(*pbig) != tolower(*plittle)) + { + ok = 0; + break; + } + + pbig++; + plittle++; + } + + if(ok) + return (char*)big; + + big++; + } + + return NULL; +} + +int strlcpy(char *dst, const char *src, size_t size) +{ + char *src_end = memchr((void*)src, '\0', size); + + if(src_end == NULL) + return 0; + + memcpy(dst, src, src_end - src); + + return (src_end - src); +} + +int strlcat(char *dst, const char *src, size_t size) +{ + int dstl = strlen(dst); + char *q = dst + dstl; + int real_size = size; + + if(memchr((void*)src, '\0', size)) + real_size = strlen(src); + + memcpy(q, src, real_size-dstl-1); + if(real_size != size) q[real_size-dstl-1] = '\0'; + + return size-dstl; +} + +void *memmem(const void *big, size_t big_len, const void *little, + size_t little_len) +{ + int i, j, l; + unsigned char *bigp = (unsigned char*)big; + unsigned char *littlep = (unsigned char*)little; + + for(i = 0, l = (int)(big_len - little_len); i <= l; i++, bigp++) + { + for(j = 0; j < little_len; j++) + { + if(littlep[j] != bigp[j]) + break; + } + + if(j == little_len) + return bigp; + } + + return NULL; +} diff --git a/libpsx/src/libc/strings.c b/libpsx/src/libc/strings.c new file mode 100644 index 0000000..76a5f9f --- /dev/null +++ b/libpsx/src/libc/strings.c @@ -0,0 +1,41 @@ +#include <stdlib.h> +#include <strings.h> +#include <stdint.h> + +#define ffs_func(func_name, type) \ +\ +int func_name(type value) \ +{ \ + int i; \ + int nbits = sizeof(type) * 8;\ + \ + for(i = 0; i < nbits && !(value & ((type)1 << i) ); i++);\ + \ + return (i == nbits) ? 0 : (i + 1);\ +} + +ffs_func(ffs, int); +ffs_func(ffsl, long); +ffs_func(ffsll, long long); + +#define popcount_func(func_name, type) \ +\ +unsigned int func_name(type value) \ +{ \ + int i, bitcnt; \ + int nbits = sizeof(type) * 8; \ + \ + for(i = 0, bitcnt = 0; i < nbits; i++) \ + {\ + if( value & ((type)1 << i) )\ + bitcnt++;\ + }\ + \ + return bitcnt;\ +} + +popcount_func(popcount, unsigned int); +popcount_func(popcountl, unsigned long); +popcount_func(popcountll, unsigned long long); +popcount_func(popcount32, uint32_t); +popcount_func(popcount64, uint64_t); diff --git a/libpsx/src/libc/unistd.c b/libpsx/src/libc/unistd.c new file mode 100644 index 0000000..f64096b --- /dev/null +++ b/libpsx/src/libc/unistd.c @@ -0,0 +1,17 @@ +#include <stdlib.h> +#include <unistd.h> + +void swab(const void *src, void *dst, ssize_t len) +{ + ssize_t x; + const unsigned char *srcp = src; + unsigned char *dstp = dst; + + for(x = 0; x < len; x+=2) + { + dstp[x] = srcp[x + 1]; + + if( (x+1) < len ) + dstp[x+1] = srcp[x]; + } +} diff --git a/libpsx/src/memcard.c b/libpsx/src/memcard.c new file mode 100644 index 0000000..16debf9 --- /dev/null +++ b/libpsx/src/memcard.c @@ -0,0 +1,87 @@ +/*
+ * PSXSDK Memory Card Helper Functions
+ *
+ * These functions help to manage memory card loading/saving
+ *
+ * Normal file functions can be used to do this, but it will be very tedious...
+ */
+
+
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <fcntl.h>
+ #include <memcard.h>
+ #include <string.h>
+ #include <psx.h>
+
+static unsigned char card_cmd[140];
+static unsigned char arr[140];
+
+unsigned char McReadSector(int card_slot, int sector, unsigned char *buffer)
+{
+ memset(&card_cmd[0], 0, 140);
+
+ card_cmd[0] = 0x81; /*MC access*/
+ card_cmd[1] = 0x52; /*Read command*/
+
+ /*Copy frame number to command*/
+ card_cmd[4] = sector >> 8; /*Frame MSB*/
+ card_cmd[5] = sector & 0xFF; /*Frame LSB*/
+
+ QueryPAD(card_slot, card_cmd, arr, sizeof(card_cmd));
+
+ /*Copy received frame data*/
+ memcpy(buffer, &arr[10], 128);
+
+ /*Return RW status*/
+ return arr[139];
+}
+
+unsigned char McWriteSector(int card_slot, int sector, unsigned char *buffer)
+{
+ int i;
+
+ memset(&card_cmd[0], 0, 140);
+
+ card_cmd[0] = 0x81; /*MC access*/
+ card_cmd[1] = 0x57; /*Write command*/
+
+ /*Copy frame number to command*/
+ card_cmd[4] = sector >> 8; /*Frame MSB*/
+ card_cmd[5] = sector & 0xFF; /*Frame LSB*/
+
+ memcpy(&card_cmd[6], buffer, 128);
+
+ /* Compute checksum */
+ for(i = 4, card_cmd[134] = 0; i < 134; i++)
+ card_cmd[134] ^= card_cmd[i];
+
+ QueryPAD(card_slot, card_cmd, arr, sizeof(card_cmd));
+
+ /*Return RW status*/
+ return arr[137];
+}
+
+unsigned int McGetStatus(int card_slot)
+{
+ unsigned int status = 0;
+
+ memset(&card_cmd[0], 0, 140);
+
+ card_cmd[0] = 0x81; /*MC access*/
+ card_cmd[1] = 0x52; /*Read command*/
+
+ /*Copy frame number to command*/
+ card_cmd[4] = 0;//sector >> 8; /*Frame MSB*/
+ card_cmd[5] = 0;//sector & 0xFF; /*Frame LSB*/
+
+ QueryPAD(card_slot, card_cmd, arr, sizeof(card_cmd));
+
+ if(arr[2] == 0x5a && arr[3] == 0x5d)
+ status |= MEMCARD_CONNECTED;
+
+ if(arr[6] == 'M' && arr[7] == 'C')
+ status |= MEMCARD_FORMATTED;
+
+ return status;
+}
diff --git a/libpsx/src/memory.c b/libpsx/src/memory.c new file mode 100644 index 0000000..e6bb806 --- /dev/null +++ b/libpsx/src/memory.c @@ -0,0 +1,215 @@ +/* + * memory.c + * + * PSXSDK malloc() family functions + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +extern int __bss_start[]; +extern int __bss_end[]; + +unsigned int first_free_page; + +// 1K granularity and "pages", so more allocations which are small can be done + +unsigned char busy_pages[2048]; +unsigned int alloc_size[2048]; + +// RAM memory map on the PSX +// 0x80000000 - 0x8000FFFF RAM used by the BIOS +// 0x80010000 - 0x801FFFFF Program memory + +void malloc_setup() +{ + int x; + + dprintf("malloc setup.\n"); + + first_free_page = (unsigned int) __bss_end; + first_free_page-= 0x80000000; + + if(first_free_page & 0x3ff) + first_free_page = (first_free_page | 0x3ff) + 1; + + first_free_page>>=10; + + //printf("First free page: %d, bss_end: %x\n", first_free_page, __bss_end); + + for(x = 0; x < first_free_page; x++) + { + busy_pages[x] = 1; // RAM occupied by program, data and BIOS looks always allocated + alloc_size[x] = 1; // Fake that 1K was required + } + + for(x = first_free_page; x < 2048; x++) + { + busy_pages[x] = 0; + alloc_size[x] = 0; + } +} + +void *malloc(size_t size) +{ + dprintf("malloc(%d)\n", size); + + int x, y; + +// Round size + + if(size & 0x3ff) + size = (size | 0x3ff) + 1; + +// Divide it by 1024 + size >>= 10; + //printf("Allocating %dKb\n", size); + +// Find a free page + for(x = 0; x < 2048; x++) + { + if(busy_pages[x] == 0) + { + // If we find a free page, check how many free pages follow it. + // If it's enough for the memory we want to allocate, then return + // the pointer to the free page we found, otherwise keep finding + + // printf("Page found at %dKb\n", x); + + for(y = 0; y < size; y++) + if(busy_pages[x+y] == 1) goto malloc_keep_finding; + + // We found the memory we wanted, now make it busy + + for(y = 0; y < size; y++) + busy_pages[x+y] = 1; + + // Store allocation size, it is essential for free() + + alloc_size[x] = size; + // printf("malloc(): alloc_size[%d] = %d\n", x, size); + + return (void*)((unsigned int)0x80000000 + (x<<10)); + } +malloc_keep_finding: + ; // Useless statement to make GCC not bail out... + } + +// We couldn't find anything, return NULL + return NULL; +} + +void *calloc(size_t number, size_t size) +{ + void *ptr = malloc(number * size); + unsigned char *cptr = (unsigned char*)ptr; + int x; + + if(ptr == NULL) + ptr = NULL; + + for(x = 0; x < (number * size); x++) + cptr[x] = 0; + + return ptr; +} + +void free(void *ptr) +{ + dprintf("free(%x)\n", (unsigned int)ptr); + + unsigned int ptri = (unsigned int)ptr; + ptri -= 0x80000000; + int x; + + if((ptri & 0x3ff) || (busy_pages[ptri>>10] == 0) || (alloc_size[ptri>>10] == 0)) + { + // If the pointer address is not a multiplier of 1K, or the page + // is free, it means that memory not allocated by malloc() was passed to free. + // Print a warning message and return. + + printf("** free() ** : tried to free memory with invalid pointer at %x\n", + ptri + 0x80000000); + + return; + } + +// Divide ptri by 1024, getting initial page + + ptri>>=10; + +// printf("Freeing page at %dKb\n", ptri); + +// Free pages + +// printf("alloc_size[%d] = %d\n", ptri, alloc_size[ptri]); + + for(x = 0; x < alloc_size[ptri]; x++) + { + dprintf("ptri + x = %d\n", ptri + x); + busy_pages[ptri + x] = 0; + } + +// Set allocation size to 0, finally freeing initial page + + alloc_size[ptri] = 0; + + /*for(x=150;x<170;x++) + printf("%d: %d, %d\n", x, busy_pages[x], alloc_size[x]);*/ +} + +void *realloc(void *ptr, size_t size) +{ + unsigned int ptri = (unsigned int)ptr; + int x; + void *newptr; + + if(ptr == NULL) + return malloc(size); + + ptri -= 0x80000000; + + size |= 0x3ff; + size++; + + size>>=10; + + if((ptri & 0x3ff) || (busy_pages[ptri>>10] == 0) || (alloc_size[ptri>>10] == 0)) + { + // If the pointer address is not a multiplier of 1K, or the page + // is free, it means that memory not allocated by malloc() was passed to realloc. + // Print a warning message and return. + + printf("** realloc() ** : tried to reallocate memory with invalid pointer at %x\n", + ptri + 0x80000000); + + return NULL; + } + +// Get page + + ptri>>=10; + + if(size < alloc_size[ptri]) // New size smaller than old size + { + for(x = size; x < alloc_size[ptri]; x++) + busy_pages[ptri + x] = 0; + + alloc_size[ptri] = size; + } + else if(size > alloc_size[ptri]) // New size bigger than old size + { + newptr = malloc(size * 1024); + + if(newptr == NULL) + return NULL; + + memcpy(newptr, ptr, alloc_size[ptri]); + free(ptr); + + ptr = newptr; + } + + return ptr; +} diff --git a/libpsx/src/memory.h b/libpsx/src/memory.h new file mode 100644 index 0000000..39985b2 --- /dev/null +++ b/libpsx/src/memory.h @@ -0,0 +1,6 @@ +#ifndef _PSXSDK_MEMORY_H +#define _PSXSDK_MEMORY_H + +void malloc_setup(); + +#endif
\ No newline at end of file diff --git a/libpsx/src/pad.c b/libpsx/src/pad.c new file mode 100644 index 0000000..ea3e20e --- /dev/null +++ b/libpsx/src/pad.c @@ -0,0 +1,163 @@ +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <psx.h> + +/* + * Flags taken from PCSX + */ + +// Status Flags +#define TX_RDY 0x0001 +#define RX_RDY 0x0002 +#define TX_EMPTY 0x0004 +#define PARITY_ERR 0x0008 +#define RX_OVERRUN 0x0010 +#define FRAMING_ERR 0x0020 +#define SYNC_DETECT 0x0040 +#define DSR 0x0080 +#define CTS 0x0100 +#define IRQ 0x0200 + +// Control Flags +#define TX_PERM 0x0001 +#define DTR 0x0002 +#define RX_PERM 0x0004 +#define BREAK 0x0008 +#define RESET_ERR 0x0010 +#define RTS 0x0020 +#define PADSIO_RESET 0x0040 + +/* + from BlackBag/Nagra PSX + + 0x1f801040 - unsigned char data; + 0x1f801044 - unsigned short status; + 0x1f80104a - unsigned short cntl; + 0x1f80104e - unsigned short baud; +*/ + +#define PADSIO_DATA(x) *((volatile unsigned char*)(0x1f801040 + (x<<4))) +#define PADSIO_STATUS(x) *((volatile unsigned short*)(0x1f801044 + (x<<4))) +#define PADSIO_MODE(x) *((volatile unsigned short*)(0x1f801048 + (x<<4))) +#define PADSIO_CTRL(x) *((volatile unsigned short*)(0x1f80104a + (x<<4))) +#define PADSIO_BAUD(x) *((volatile unsigned short*)(0x1f80104e + (x<<4))) + +unsigned char readpad_vibrations[4][2]; +int querypad_rxrdy = 1; + +void QueryPAD(int pad_n, unsigned char *in, unsigned char *out, int len) +{ + int x; + volatile int y; // specified as volatile to not make busy loops get optimized out + int i; + unsigned char TempData; + int EmuFlag = 0; + + PADSIO_MODE(0) = 0xD; + PADSIO_BAUD(0) = 0x88; + + if(pad_n == 1) PADSIO_CTRL(0) = 0x3003; else PADSIO_CTRL(0) = 0x1003; + + /*Get the initial command (usually 0x01 or 0x81)*/ + TempData = *in; + + for(y=0;y<400;y++); /*Slight delay before first transmission*/ + + for(x = 0; x < len; x++) + { + /*Must use timeouts or else program hangs on emulators*/ + if(!EmuFlag) + { + for(y=0;y<1000;y++) + { + /*Wait for TX ready*/ + if(PADSIO_STATUS(0) & 4)break; + } + } + + PADSIO_DATA(0) = *in; + in++; + + if(!EmuFlag) + { + /*Check ACK only for Memory Cards*/ + if(TempData == 0x81 || x == 0) + { + for(y=0;y<2000;y++) + { + /*Check for ACK signal*/ + if(PADSIO_STATUS(0) & 128)break; + } + } + + for(i=0;i<100;i++) + { + /*Read RX status flag, required for Xebra*/ + if(PADSIO_STATUS(0) & 2)break; + } + } + + *out = PADSIO_DATA(0); + + /*This is emulator, valid data was received without ACK, ePSXe and PCSX*/ + if(x == 0 && y > 1900 && *out != 0xFF)EmuFlag = 1; + + out++; + } + + PADSIO_CTRL(0) = 0; +} + +void pad_read_raw(int pad_n, unsigned char *arr) +{ + // arr must be at least 16 bytes long... + + unsigned char pad_cmd[PAD_READ_RAW_SIZE] = {1,0x42,0,0,0}; + + pad_cmd[3] = readpad_vibrations[pad_n][0]; + pad_cmd[4] = readpad_vibrations[pad_n][1]; + + QueryPAD(pad_n, pad_cmd, arr, sizeof(pad_cmd)); +} + +void pad_escape_mode(int pad_n, int enable) +{ + unsigned char pad_cmd[] = {1,0x43,0,enable?1:0,0}; + + QueryPAD(pad_n, pad_cmd, NULL, sizeof(pad_cmd)); +} + +void pad_enable_vibration(int pad_n) +{ + unsigned char pad_cmd[] = {1, 0x4d, 0, 0, 1, 0xff, 0xff, 0xff, 0xff}; + + pad_escape_mode(pad_n, 1); // Enter escape / configuration mode + QueryPAD(pad_n, pad_cmd, NULL, sizeof(pad_cmd)); + pad_escape_mode(pad_n, 0); // Exit escape / configuration mode +} + +void pad_set_vibration(int pad_n, unsigned char small, unsigned char big) +{ + if(pad_n >= 0 && pad_n <= 3) + { + readpad_vibrations[pad_n][0] = small; + readpad_vibrations[pad_n][1] = big; + } +} + +/* + // Sony pads make this interface unpractical! +void pad_set_analog(int pad_n, int lock) +{ + unsigned char pad_cmd[9] = + {1, 0x44, 0, 1, lock?3:0, 0, 0, 0, 0}; + unsigned char pad_cmd2[9] = + {1, 0x4f, 0, 0xff, 0xff, 3, 0, 0, 0}; + + pad_escape_mode(pad_n, 1); + QueryPAD(pad_n, pad_cmd, NULL, sizeof(pad_cmd)); + QueryPAD(pad_n, pad_cmd2, NULL, sizeof(pad_cmd)); + pad_escape_mode(pad_n, 0); +}*/ + diff --git a/libpsx/src/psxsdk.c b/libpsx/src/psxsdk.c new file mode 100644 index 0000000..a595bdb --- /dev/null +++ b/libpsx/src/psxsdk.c @@ -0,0 +1,542 @@ +/* + * PSXSDK Library + * + * Free and open source library to develop for the Sony PlayStation + */ + +#include <psx.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "exception.h" + +static const char *sysromver_unavail = "System ROM Version Unavailable"; + +void (*vblank_handler_callback)(); + +extern int *vblank_handler(); + +void (*rcnt_handler_callback)(); + +extern int *rcnt_handler(); + +/*static unsigned int vblank_queue_buf[4] = {0x0, // Will contain next interrupt handler in queue + 0x0, // func1 + (unsigned int)vblank_handler, // func2 + 0x0, // pad + };*/ + +static int vblank_handler_set = 0; +static unsigned int vblank_handler_event_id = 0; + +static int rcnt_handler_set = 0; +static unsigned int rcnt_handler_event_id = 0; +unsigned int rcnt_handler_evfield; + +void _internal_cdromlib_init(void); + +static unsigned int psxSdkFlags = 0; + +static unsigned char *psxBiosState; + +extern void _96_remove(void); +extern void _96_init(void); +extern void InitCARD(void); +extern void StartCARD(void); +extern void StopCARD(void); +extern void _bu_init(void); +extern void BIOSWarmReboot(void); + +void PSX_InitEx(unsigned int flags) +{ + if(flags & PSX_INIT_NOBIOS) + { + printf("Entering No BIOS mode...\n"); + + __PSX_Init_NoBios(); + goto _initex_end; + } + + if(flags & PSX_INIT_SAVESTATE) + { +// Save BIOS state +// This simply copies the entire section of RAM used by the BIOS +// in a buffer. + EnterCriticalSection(); + psxBiosState = malloc(0x10000); + memcpy(psxBiosState, (void*)0x80000000, 0x10000); + ExitCriticalSection(); + } + + /* Reinitialize ISO 9660 filesystem driver */ + + if(flags & PSX_INIT_CD) + { + EnterCriticalSection(); + _96_remove(); + ExitCriticalSection(); + + _96_init(); + } + + + /*This is needed, otherwise PSX will crash when VBlank handler is set*/ + /*InitCARD(1); + StartCARD(); + StopCARD();*/ + + if(flags & PSX_INIT_CD) + _internal_cdromlib_init(); + + printf("PSXSDK testing version !!!\n"); + + vblank_handler_set = 0; +_initex_end: + psxSdkFlags = flags; +} + +void PSX_Init(void) +{ + PSX_InitEx(PSX_INIT_CD); +} + +void PSX_DeInit(void) +{ + if(psxSdkFlags & PSX_INIT_CD) + { + EnterCriticalSection(); + _96_remove(); + ExitCriticalSection(); + } + + RemoveVBlankHandler(); + + if(psxSdkFlags & PSX_INIT_SAVESTATE)// This must always be the last to be called! + PSX_RestoreBiosState(); +} + +void PSX_ReadPad(unsigned short *padbuf, unsigned short *padbuf2) +{ + int x; + unsigned char arr[PAD_READ_RAW_SIZE]; + unsigned short *padbuf_a[2]; + +// Now uses low level pad routines... + padbuf_a[0] = padbuf; + padbuf_a[1] = padbuf2; + + for(x = 0; x < 2; x++) + { + pad_read_raw(x, arr); + + if(arr[2] == 0x5a) + { + *padbuf_a[x] = (arr[3]<<8)|arr[4]; + *padbuf_a[x] = ~*padbuf_a[x]; + } + else + *padbuf_a[x] = 0; + } +} + +unsigned char psxsdkPadArr[PAD_READ_RAW_SIZE]; + +void PSX_PollPad(int pad_num, psx_pad_state *pad_state) +{ +// int x; + /*unsigned short *padbuf_a[2]; + +// Now uses low level pad routines... + padbuf_a[0] = padbuf; + padbuf_a[1] = padbuf2; + + for(x = 0; x < 2; x++) + { + pad_read_raw(x, arr); + + if(arr[2] == 0x5a) + { + *padbuf_a[x] = (arr[3]<<8)|arr[4]; + *padbuf_a[x] = ~*padbuf_a[x]; + } + else + *padbuf_a[x] = 0; + }*/ + + unsigned char *arr = psxsdkPadArr; + + pad_read_raw(pad_num, arr); + + pad_state->status = arr[0]; + pad_state->id = arr[1]; + + pad_state->buttons = (arr[3]<<8)|arr[4]; + pad_state->buttons = ~pad_state->buttons; + + switch(pad_state->id) + { + case 0xFF: + pad_state->type = PADTYPE_NONE; + break; + case 0x41: + pad_state->type = PADTYPE_NORMALPAD; + break; + case 0x53: + pad_state->type = PADTYPE_ANALOGJOY; + pad_state->extra.analogJoy.x[0] = arr[5]-128; + pad_state->extra.analogJoy.y[0] = arr[6]-128; + pad_state->extra.analogJoy.x[1] = arr[7]-128; + pad_state->extra.analogJoy.y[1] = arr[8]-128; + break; + case 0x73: + pad_state->type = PADTYPE_ANALOGPAD; + pad_state->extra.analogPad.x[0] = arr[5]-128; + pad_state->extra.analogPad.y[0] = arr[6]-128; + pad_state->extra.analogPad.x[1] = arr[7]-128; + pad_state->extra.analogPad.y[1] = arr[8]-128; + break; + case 0x23: + pad_state->type = PADTYPE_NEGCON; + pad_state->extra.negCon.steering = arr[5]-128; + pad_state->extra.negCon.one = arr[6]; + pad_state->extra.negCon.two = arr[7]; + pad_state->extra.negCon.shoulder = arr[8]; + break; + case 0x31: + pad_state->type = PADTYPE_KONAMIGUN; + break; + default: + pad_state->type = PADTYPE_UNKNOWN; + } +} + +/*int PSX_GetPadType(unsigned int pad_num) +//{ + //#warning "Function does not currently work!" +// unsigned char arr[16]; + + pad_read_raw(pad_num, arr); + + switch(arr[1]) + { + case 0xFF: + return PADTYPE_NONE; + break; + case 0x41: + return PADTYPE_NORMALPAD; + break; + case 0x53: + return PADTYPE_ANALOGJOY; + break; + case 0x73: + return PADTYPE_ANALOGPAD; + break; + } + + return PADTYPE_UNKNOWN; +}*/ + + +void PSX_GetSysInfo(struct psx_info *info) +{ + unsigned long i,i2; + + info->kernel.version = GetKernelRomVersion(); + + i = GetKernelDate(); + +/* + * Convert year from BCD to decimal + */ + + i2 = i >> 16; + + info->kernel.year = i2 & 0xf; + info->kernel.year+= ((i2>>4)&0xf)*10; + info->kernel.year+= ((i2>>8)&0xf)*100; + info->kernel.year+= ((i2>>12)&0xf)*1000; + +/* + * Convert month from BCD to decimal + */ + i2 = (i >> 8) & 0xff; + + info->kernel.month = i2 & 0xf; + info->kernel.month+= (i2>>4) * 10; + +/* + * Convert day from BCD to decimal + */ + i2 = i & 0xff; + + info->kernel.day = i2 & 0xf; + info->kernel.day+= (i2>>4) * 10; + +/* + * Unless we receive something in the range >= 1 && <= 16, + * RAM size will be reported as 2 Megabytes + */ + + i = GetRamSize(); + + if(i == 0 || i > 16) + info->system.memory = 2<<20; /* 2 Megabytes */ + else + info->system.memory <<= 20; +} + + + +int get_real_file_size(const char *name) +{ + struct DIRENTRY dirent_buf; + + if(firstfile(name, &dirent_buf) == &dirent_buf) + return dirent_buf.size; + else + return 0; +} + +int get_file_size(const char *name) +{ + int i = get_real_file_size(name); + + if(strncmp(name, "cdrom:", 6) == 0) + { + if(i & 0x7ff) + { + i += 0x800; + i &= ~0x7ff; + } + }else if(strncmp(name, "bu", 2) == 0) + { + if(i & 0x7f) + { + i += 0x80; + i &= ~0x7f; + } + } + + return i; +} + +int SetRCnt(int spec, unsigned short target, unsigned int mode) +{ + spec &= 0xf; + + if(spec >= 3) + return 0; + + RCNT_MODE(spec)=0; + RCNT_TARGET(spec)=target; + RCNT_MODE(spec)=mode; + + return 1; +} + +int GetRCnt(int spec) +{ + spec &= 0xf; + + if(spec >= 4) + return -1; + + return (RCNT_COUNT(spec) & 0xffff); +} + +int StartRCnt(int spec) +{ + spec &= 0xf; + + if(spec >= 3) + return 0; + + IMASK |= 1 << (spec + 4); + + return 1; +} + +int StopRCnt(int spec) +{ + spec &= 0xf; + + if(spec >= 3) + return 0; + + IMASK ^= 1 << (spec + 4); + + return 1; +} + +void SetVBlankHandler(void (*callback)()) +{ + if(psxSdkFlags & PSX_INIT_NOBIOS) + { + _EXC_vblank_handler_set = 0; + _EXC_vblank_handler = callback; + _EXC_vblank_handler_set = 1; + return; + } + + if(vblank_handler_set == 1) + { + EnterCriticalSection(); + + vblank_handler_callback = callback; + + ExitCriticalSection(); + + return; + } + +// Enter critical section + + EnterCriticalSection(); + + IMASK|=1; + + vblank_handler_event_id = OpenEvent(RCntCNT3, 2, 0x1000, vblank_handler); + EnableEvent(vblank_handler_event_id); + + vblank_handler_callback = callback; + vblank_handler_set = 1; + +// Exit critical section + + ExitCriticalSection(); +} + +void RemoveVBlankHandler(void) +{ + if(psxSdkFlags & PSX_INIT_NOBIOS) + { + _EXC_vblank_handler_set = 0; + _EXC_vblank_handler = NULL; + return; + } + + if(vblank_handler_set) + { + EnterCriticalSection(); + + DisableEvent(vblank_handler_event_id); + CloseEvent(vblank_handler_event_id); + + //IMASK^=1; + // ^ commented because masking out vblank could give problems to other bios functions + + vblank_handler_set = 0; + + ExitCriticalSection(); + } +} + +void SetRCntHandler(void (*callback)(), int spec, unsigned short target) +{ + if(psxSdkFlags & PSX_INIT_NOBIOS) + return; // Not yet supported in No-Bios Mode + + if(rcnt_handler_set) + { + EnterCriticalSection(); + + rcnt_handler_callback = callback; + + ExitCriticalSection(); + + return; + } + +// Enter critical section + + SetRCnt(spec, target, RCntIntr | 0x08 | 0x10 | 0x40); + StartRCnt(spec); + + EnterCriticalSection(); + rcnt_handler_event_id = OpenEvent(spec, 2, 0x1000, rcnt_handler); + EnableEvent(rcnt_handler_event_id); + + rcnt_handler_callback = callback; + rcnt_handler_set = spec; + + switch(spec) + { + case RCntCNT0: rcnt_handler_evfield = 1 << 4; break; + case RCntCNT1: rcnt_handler_evfield = 1 << 5; break; + case RCntCNT2: rcnt_handler_evfield = 1 << 6; break; + case RCntCNT3: rcnt_handler_evfield = 1; break; + } + +// Exit critical section + + ExitCriticalSection(); +} + +void RemoveRCntHandler(int spec) +{ + if(psxSdkFlags & PSX_INIT_NOBIOS) + return; // Not yet supported in No-Bios Mode + + if(rcnt_handler_set) + { + EnterCriticalSection(); + + DisableEvent(rcnt_handler_event_id); + CloseEvent(rcnt_handler_event_id); + + rcnt_handler_set = 0; + + ExitCriticalSection(); + } +} + +const char *GetSystemRomVersion(void) +{ +// Get pointer to zero-terminated string containing System ROM Version which is embedded in +// most PlayStation BIOSes. + +// If getting the pointer is not possible, a pointer to a string saying "System ROM Unavailable" is returned. + + int x; + + for(x = 0x7ffee; x >= 0; x--) + if(memcmp("System ROM Version", (void*)(0xbfc00000 + x), 18) == 0) + return (char*)(0xbfc00000 + x); + + return sysromver_unavail; +} + +int PSX_RestoreBiosState(void) +{ + if(!(psxSdkFlags & PSX_INIT_SAVESTATE)) + return 0; // can't restore BIOS state if it was not saved previously + + EnterCriticalSection(); + memcpy((void*)0x80000000, psxBiosState, 0x10000); + ExitCriticalSection(); + + return 1; +} + +unsigned int PSX_GetInitFlags(void) +{ + return psxSdkFlags; +} + +void PSX_WarmReboot(void) +{ + if(psxSdkFlags & PSX_INIT_NOBIOS) + { +psx_warmreboot_nobios: + PSX_DeInit(); + __asm__("j _start"); + __asm__("nop"); + } + else + { + if(!(psxSdkFlags & PSX_INIT_CD)) + goto psx_warmreboot_nobios; + + BIOSWarmReboot(); + } +} diff --git a/libpsx/src/runexe/runexe.c b/libpsx/src/runexe/runexe.c new file mode 100644 index 0000000..5fe22b0 --- /dev/null +++ b/libpsx/src/runexe/runexe.c @@ -0,0 +1,76 @@ +/** + * PSXSDK + * + * RunEXE functionality + */ + +#include <psx.h> +#include <stdio.h> +#include <string.h> +#include <runexe.h> + +// Include runexe stage2 position independent code + +extern void PSX_RunExeStage2(); +extern void PSX_RunExeStage2_END(); + +static void *runExeBuffer; + +int PSX_RunExe(void *exeBuffer) +{ + //unsigned char *exe = exeBuffer; + unsigned int *exe = exeBuffer; +// Size of position indipendent code + int sz = PSX_RunExeStage2_END - + PSX_RunExeStage2; + + if(!(PSX_GetInitFlags() & PSX_INIT_SAVESTATE)) + { + printf("RunExe error: State was not saved!\n"); + return 0; + } + + if(((unsigned int)exeBuffer & 3)) + { + printf("RunExe: Alignment violation.\n"); + printf("Specified buffer must have an address which is a multiplier of 4.\n"); + return 0; + } + + // Check magic string + if(strcmp(exeBuffer, "PS-X EXE") != 0) + return 0; // Return failure if magic string couldn't be found + + runExeBuffer = exeBuffer; + + printf("PSXSDK RunExe Debug Information\n"); + printf("t_addr = %08x\n", exe[6]); + printf("t_size = %08x\n", exe[7]); + printf("d_addr = %08x\n", exe[8]); + printf("d_size = %08x\n", exe[9]); + printf("b_addr = %08x\n", exe[10]); + printf("b_size = %08x\n", exe[11]); + printf("s_addr = %08x\n", exe[12]); + printf("s_size = %08x\n", exe[13]); + + printf("OK..! Farewell.\n"); + +// Deinitialize the PSXSDK library + PSX_DeInit(); + +// Copy the position independent stage2 code in high memory + memcpy((void*)0x801fef00, PSX_RunExeStage2, sz); + +// Stack is unusable now! Do not do anything else except calling the stage2 code. + +// Jump to the stage2 code without using the stack.. + + __asm__("la $a0, runExeBuffer"); + __asm__("nop"); + __asm__("lw $a0, 0($a0)"); + __asm__("j 0x801fef00"); + __asm__("nop"); + +// This is never reached but keep the compiler happy + return 0; +} diff --git a/libpsx/src/runexe/stage2.s b/libpsx/src/runexe/stage2.s new file mode 100644 index 0000000..e60e109 --- /dev/null +++ b/libpsx/src/runexe/stage2.s @@ -0,0 +1,40 @@ +.global PSX_RunExeStage2 +.global PSX_RunExeStage2_END + +PSX_RunExeStage2: +# a0 = address of PSX-EXE buffer + +# Load initial program counter in t0 + lw $t0, 0x10($a0) +# Load text section address in t1 + lw $t1, 0x18($a0) +# Load text section size in t2 + lw $t2, 0x1c($a0) + +# Load initial sp register value in sp + lw $sp, 0x30($a0) + +# t3 = current source address + addiu $t3, $a0, 0x800 + +# t4 = current destination address + addu $t4, $t1, $zero + +copyExeLoop: + beq $t2, $zero, copyExeLoop_End + nop +copyExeLoop_2: + lb $t5, 0($t3) + nop + sb $t5, 0($t4) + addiu $t3, $t3, 1 + addiu $t4, $t4, 1 + addiu $t2, $t2, -1 + beq $zero, $zero, copyExeLoop + +copyExeLoop_End: +# Jump to the program we loaded + jr $t0 + nop + +PSX_RunExeStage2_END: diff --git a/libpsx/src/setup.c b/libpsx/src/setup.c new file mode 100644 index 0000000..d77f062 --- /dev/null +++ b/libpsx/src/setup.c @@ -0,0 +1,50 @@ +#include <psx.h> +#include <stdio.h> +#include "memory.h" + +extern int __bss_start[]; +extern int __bss_end[]; + +extern void *__ctor_list; +extern void *__ctor_end; + + +// Function to call static constructors (for C++, etc.) +static void call_ctors(void) +{ + dprintf("Calling static constructors...\n"); + + void **p = &__ctor_end - 1; + + for(--p; *p != NULL && (int)*p != -1 && p > &__ctor_list; p--) + { + dprintf("Constructor address = %x\n", (unsigned int)*p); + (*(void (**)())p)(); + } + + dprintf("Finished calling static constructors\n"); +} + +void psxsdk_setup() +{ + unsigned int x; + + printf("Initializing PSXSDK... \n"); + + dprintf("Clearing BSS space...\n"); + +// Clear BSS space + for(x = (unsigned int)__bss_start; x < (unsigned int)__bss_end; x++) + *((unsigned char*)x) = 0; + + dprintf("BSS space cleared.\n"); + +// Setup memory allocation functions + malloc_setup(); + + dprintf("Finished setting up memory allocation functions.\n"); + +// Call static constructors + call_ctors(); + +} diff --git a/libpsx/src/sio.c b/libpsx/src/sio.c new file mode 100644 index 0000000..5d399d3 --- /dev/null +++ b/libpsx/src/sio.c @@ -0,0 +1,64 @@ +/*
+ * SIO communication library for PSXSDK.
+ * Originally written by Shendo.
+ * Thanks to Martin Korth of the NO$PSX for documentation.
+ *
+ * This library is accessing SIO registers directly, no BIOS routines are used.
+ */
+
+#include <psx.h>
+#include <psxsio.h>
+#include <stdio.h>
+
+void SIOStart(int bitrate)
+{
+ /*Set to 8N1 mode with desired bitrate*/
+ SIOStartEx(bitrate, SIO_DATA_LEN_8, SIO_PARITY_NONE, SIO_STOP_BIT_1);
+}
+
+void SIOStartEx(int bitrate, int datalength, int parity, int stopbit)
+{
+ /*Set SIO_MODE register, bitrate reload factor set to MUL16 by default*/
+ SIO_MODE = SIO_REL_MUL16 | (datalength << 2) | (parity << 4) | (stopbit << 6);
+
+ /*Reset SIO_CTRL register.*/
+ SIO_CTRL = 0;
+
+ /*Set TX and RT to enabled, no handshaking signals.*/
+ SIO_CTRL = 1 | (1 << 2);
+
+ /*Calculate bitrate reload value based on the given bitrate
+ * Reload = SystemClock (33 Mhz) / (Factor (MULI16) * bitrate)*/
+ SIO_BPSV = 0x204CC00 / (16 * bitrate);
+}
+
+void SIOStop()
+{
+ /*Set all SIO related registers to zero*/
+ SIO_MODE = 0;
+ SIO_CTRL = 0;
+ SIO_BPSV = 0;
+}
+
+unsigned char SIOReadByte()
+{
+ return (unsigned char)SIO_TX_RX;
+}
+
+void SIOSendByte(unsigned char data)
+{
+ SIO_TX_RX = data;
+}
+
+int SIOCheckInBuffer()
+{
+ /*Return status of RX FIFO*/
+ return (SIO_STAT & 0x2)>0;
+}
+
+int SIOCheckOutBuffer()
+{
+ /*Return status of TX Ready flag*/
+ return (SIO_STAT & 0x4)>0;
+}
+
\ No newline at end of file diff --git a/libpsx/src/spu.c b/libpsx/src/spu.c new file mode 100644 index 0000000..441acb6 --- /dev/null +++ b/libpsx/src/spu.c @@ -0,0 +1,269 @@ +/** + * PSXSDK + * + * Sound Processing Unit Functions + * Based on code from James Higgs's PSX lib and on code by bitmaster + */ + +#include <stdio.h> +#include <string.h> +#include <psx.h> + +static unsigned int ss_vag_addr; + +void SsVoiceVol(int voice, unsigned short left, unsigned short right) +{ + unsigned short *a = (unsigned short*)SPU_VOICE_BASE_ADDR(voice); + + a[0] = left; + a[1] = right; +} + +void SsVoicePitch(int voice, unsigned short pitch) +{ + unsigned short *a = (unsigned short*)SPU_VOICE_BASE_ADDR(voice); + + a[2] = pitch; +} + +void SsVoiceStartAddr(int voice, unsigned int addr) +{ +// address given is real address, then it is divided by eight when written to the register +// example: SSVoiceStartAddr(0, 0x1008) , writes 0x201 on the register which means 0x1008 + + unsigned short *a = (unsigned short*)SPU_VOICE_BASE_ADDR(voice); + + a[3] = (addr >> 3); +} + +void SsVoiceADSRRaw(int voice, unsigned short level, unsigned short rate) +{ + unsigned short *a = (unsigned short*)SPU_VOICE_BASE_ADDR(voice); + + a[4] = level; + a[5] = rate; +} + +void SsVoiceRepeatAddr(int voice, unsigned int addr) +{ +// only valid after KeyOn +// the explanation for SSVoiceStartAddr() is valid for this function as well + + unsigned short *a = (unsigned short*)SPU_VOICE_BASE_ADDR(voice); + + a[7] = (addr >> 3); +} + +void SsKeyOn(int voice) +{ + unsigned int i = 1 << voice; + + SPU_KEY_ON1 = i & 0xffff; + SPU_KEY_ON2 = i >> 16; + +/* while(SPU_KEY_ON1 != (i & 0xffff)); + while(SPU_KEY_ON2 != (i >> 16)); +*/ +} + +void SsKeyOff(int voice) +{ + unsigned int i = 1 << voice; + + SPU_KEY_OFF1 = i & 0xffff; + SPU_KEY_OFF2 = i >> 16; +} + + + +void SsKeyOnMask(int mask) +{ + SPU_KEY_ON1 = mask & 0xffff; + SPU_KEY_ON2 = mask >> 16; +} + +void SsKeyOffMask(int mask) +{ + SPU_KEY_OFF1 = mask & 0xffff; + SPU_KEY_OFF2 = mask >> 16; +} + +void SsWait() +{ + while(SPU_STATUS2 & 0x7ff); +} + +void SsInit() +{ + int x; + + printf("Initializing SPU (Sound Synthesizer)...\n"); + + DPCR |= 0xB0000; + + SPU_MVOL_L = 0x3fff; + SPU_MVOL_R = 0x3fff; + + SPU_CONTROL = 0x0; + SsWait(); + + SPU_STATUS = 0x4; // Must be done, but not totally understood + + while(SPU_STATUS2 & 0x7ff); + + SPU_REVERB_L = 0x0; + SPU_REVERB_R = 0x0; + + // All keys off + + SPU_KEY_OFF1 = 0xFFFF; + SPU_KEY_OFF2 = 0xFFFF; + + // Switch FM, reverb and noise off + SPU_KEY_FM_MODE1 = 0x0; + SPU_KEY_FM_MODE2 = 0x0; + SPU_KEY_NOISE_MODE1 = 0x0; + SPU_KEY_NOISE_MODE2 = 0x0; + SPU_KEY_REVERB_MODE1 = 0x0; + SPU_KEY_REVERB_MODE2 = 0x0; + + // set CD master volume to 0 (mute it) + SPU_CD_MVOL_L = 0x0; + SPU_CD_MVOL_R = 0x0; + + // set external input volume to 0 (mute it) + SPU_EXT_VOL_L = 0x0; + SPU_EXT_VOL_R = 0x0; + + // set volume of all voices to 0 and adsr to 0,0 + + for(x = 0; x < 24; x++) + { + SsVoiceVol(x, 0, 0); + SsVoiceADSRRaw(x, 0, 0); + } + + SsWait(); + + SPU_CONTROL = 0xC000; // SPU is on + SPU_REVERB_WORK_ADDR = 0xFFFE; // Reverb work address in SPU memory, 0x1fff * 8 = 0xFFF8 + + ss_vag_addr = SPU_DATA_BASE_ADDR; + + printf("SPU/SS Initialized.\n"); +} + +// This implementation of SsUpload() was contributed by Shendo +// It waits either for a period of time or for the status flags to be raised, whichever comes first. +// This makes it work also on ePSXe, which never raises the status flags. + +void SsUpload(void *addr, int size, int spu_addr) +{ + unsigned short *ptr = addr; + int i; + + while(size > 0) + { + SPU_STATUS = 4; // Sound RAM Data Transfer Control + SPU_CONTROL = SPU_CONTROL & ~0x30; // SPUCNT.transfer_mode = 0 (STOP) + + + for(i = 0; i < 100; i++) + if(((SPU_STATUS2 >> 4) & 3) == 0)break; // wait until SPUSTAT.transfer is 0 (STOP) + + SPU_ADDR = spu_addr >> 3; + + for(i = 0; i < 32; i++) + SPU_DATA = ptr[i]; + + SPU_CONTROL = (SPU_CONTROL & ~0x30) | 16; // SPUCNT.transfer_mode = 1 (MANUAL) + + for(i = 0; i < 100; i++) + if(((SPU_STATUS2 >> 4) & 3) == 1)break; // wait until SPUSTAT.transfer is 1 (MANUAL) + + while(SPU_STATUS2 & 0x400); // wait for transfer busy bit to be cleared + + spu_addr += 64; + ptr += 32; + size-=64; + } +} + +unsigned short SsFreqToPitch(int hz) +{ +// Converts a normal samples per second frequency value in Hz +// in a pitch value + +// i.e. 44100 -> 0x1000, 22050 -> 0x800 + + return (hz << 12) / 44100; +} + +int SsReadVag(SsVag *vag, void *data) +{ + unsigned char *i = data; + + if(strncmp(data, "VAGp", 4) != 0) + return 0; + + vag->version = (i[4]<<24)|(i[5]<<16)|(i[6]<<8)|i[7]; + vag->data_size = (i[12]<<24)|(i[13]<<16)|(i[14]<<8)|i[15]; + vag->sample_rate = (i[16]<<24)|(i[17]<<16)|(i[18]<<8)|i[19]; + memcpy(vag->name, &i[32], 16); + vag->data = &i[48]; + + return 1; +} + +void SsUploadVagEx(SsVag *vag, int spu_addr) +{ + vag->spu_addr = spu_addr; + SsUpload(vag->data, vag->data_size, vag->spu_addr); + //spu_addr += vag->data_size; +} + +void SsUploadVag(SsVag *vag) +{ + vag->spu_addr = ss_vag_addr; + SsUploadVagEx(vag, ss_vag_addr); + ss_vag_addr += vag->data_size; +} + +void SsPlayVag(SsVag *vag, unsigned char voice, unsigned short vl, + unsigned short vr) +{ + SsVoicePitch(voice, SsFreqToPitch(vag->sample_rate)); + SsVoiceStartAddr(voice, vag->spu_addr); + SsVoiceVol(voice, vl, vr); + SsKeyOn(voice); + + vag->cur_voice = voice; +} + +void SsStopVag(SsVag *vag) +{ + SsKeyOff(vag->cur_voice); + vag->cur_voice = -1; +} + +void SsResetVagAddr() +{ + ss_vag_addr = SPU_DATA_BASE_ADDR; +} + +void SsEnableCd() +{ + SPU_CONTROL |= 1; + CdSendCommand(CdlDemute, 0); +} + +void SsEnableExt() +{ + SPU_CONTROL |= 2; +} + +void SsCdVol(unsigned short left, unsigned short right) +{ + SPU_CD_MVOL_L = left; + SPU_CD_MVOL_R = right; +} diff --git a/libpsx/src/start/start.s b/libpsx/src/start/start.s new file mode 100755 index 0000000..5c72f79 --- /dev/null +++ b/libpsx/src/start/start.s @@ -0,0 +1,322 @@ +# This is the start code for the PSXSDK.
+# It sets needed things up, and calls the setup and the main function.
+
+# This has to be linked in as the first object when using ld, so that it
+# appears at the start of the .text section.
+# If a ldscript is being used, it is sufficient to specify this as the first
+# startup object.
+
+# nextvolume (2014-03-17):
+# fixed possible stack corruption.
+
+ .align 16
+ .text
+.global _start
+#.global exit
+.extern call_atexit_callbacks
+#.global vblank_handler
+.extern vblank_handler
+.extern vblank_handler_callback
+
+.extern rcnt_handler
+.extern rcnt_handler_evfield
+.extern rcnt_handler_callback
+
+.extern run_bios
+.extern is_load_delay_ok
+.extern exit
+
+.extern get_cop0_status
+.extern set_cop0_status
+.extern get_cop0_epc
+#.global run_bios +#.global is_load_delay_ok
+
+_start:
+ li $29, 0x801fff00 # Load stack pointer
+ li $k1, 0x1f800000 # set to hardware base
+
+ addiu $sp, $sp, -24
+ jal ResetEntryInt
+ nop
+
+ jal psxsdk_setup
+ nop
+
+ jal main
+ nop
+
+_real_exit:
+ la $a0, progtermfmt
+ move $a1, $v0
+
+ jal printf
+ nop
+
+ jal call_atexit_callbacks
+ nop
+
+inf_loop:
+ j inf_loop
+ nop
+
+# VBlank handler
+
+vblank_handler:
+ addi $sp, -120 +.set noat
+ sw $at, 0($sp)
+ mfhi $at
+ sw $at, 112($sp)
+ mflo $at
+ sw $at, 116($sp) +.set at
+ sw $v0, 4($sp)
+ sw $v1, 8($sp)
+ sw $a0, 12($sp)
+ sw $a1, 16($sp)
+ sw $a2, 20($sp)
+ sw $a3, 24($sp)
+ sw $t0, 28($sp)
+ sw $t1, 32($sp)
+ sw $t2, 36($sp)
+ sw $t3, 40($sp)
+ sw $t4, 44($sp)
+ sw $t5, 48($sp)
+ sw $t6, 52($sp)
+ sw $t7, 56($sp)
+ sw $s0, 60($sp)
+ sw $s1, 64($sp)
+ sw $s2, 68($sp)
+ sw $s3, 72($sp)
+ sw $s4, 76($sp)
+ sw $s5, 80($sp)
+ sw $s6, 84($sp)
+ sw $s7, 88($sp)
+ sw $t8, 92($sp)
+ sw $t9, 96($sp)
+ sw $gp, 100($sp)
+ sw $s8, 104($sp)
+ sw $ra, 108($sp)
+
+vblank_fire_user_handler:
+
+ la $t0, vblank_handler_callback + lw $t1, 0($t0)
+
+ addiu $sp, $sp, -24
+ jalr $t1
+ nop
+ addiu $sp, $sp, 24
+
+vblank_acknowledge_irq:
+ li $t0, 0x1f801070 # IPENDING
+
+ lw $t1, 0($t0)
+ nop
+ nop
+ xori $t1, $t1, 1 # Acknowledge VBlank IRQ
+ sw $t1, 0($t0)
+
+vblank_handler_end: +.set noat
+ lw $at, 112($sp)
+ nop
+ mthi $at
+ lw $at, 116($sp)
+ nop
+ mtlo $at + lw $at, 0($sp) +.set at + lw $v0, 4($sp)
+ lw $v1, 8($sp)
+ lw $a0, 12($sp)
+ lw $a1, 16($sp)
+ lw $a2, 20($sp)
+ lw $a3, 24($sp)
+ lw $t0, 28($sp)
+ lw $t1, 32($sp)
+ lw $t2, 36($sp)
+ lw $t3, 40($sp)
+ lw $t4, 44($sp)
+ lw $t5, 48($sp)
+ lw $t6, 52($sp)
+ lw $t7, 56($sp)
+ lw $s0, 60($sp)
+ lw $s1, 64($sp)
+ lw $s2, 68($sp)
+ lw $s3, 72($sp)
+ lw $s4, 76($sp)
+ lw $s5, 80($sp)
+ lw $s6, 84($sp)
+ lw $s7, 88($sp)
+ lw $t8, 92($sp)
+ lw $t9, 96($sp)
+ lw $gp, 100($sp)
+ lw $s8, 104($sp)
+ lw $ra, 108($sp)
+ addi $sp, 120
+ jr $ra
+ nop
+
+# Root counter handler
+
+rcnt_handler:
+ addi $sp, -120
+.set noat
+ sw $at, 0($sp)
+ mfhi $at
+ sw $at, 112($sp)
+ mflo $at
+ sw $at, 116($sp)
+.set at
+ sw $v0, 4($sp)
+ sw $v1, 8($sp)
+ sw $a0, 12($sp)
+ sw $a1, 16($sp)
+ sw $a2, 20($sp)
+ sw $a3, 24($sp)
+ sw $t0, 28($sp)
+ sw $t1, 32($sp)
+ sw $t2, 36($sp)
+ sw $t3, 40($sp)
+ sw $t4, 44($sp)
+ sw $t5, 48($sp)
+ sw $t6, 52($sp)
+ sw $t7, 56($sp)
+ sw $s0, 60($sp)
+ sw $s1, 64($sp)
+ sw $s2, 68($sp)
+ sw $s3, 72($sp)
+ sw $s4, 76($sp)
+ sw $s5, 80($sp)
+ sw $s6, 84($sp)
+ sw $s7, 88($sp)
+ sw $t8, 92($sp)
+ sw $t9, 96($sp)
+ sw $gp, 100($sp)
+ sw $s8, 104($sp)
+ sw $ra, 108($sp)
+
+rcnt_fire_user_handler:
+ la $t0, rcnt_handler_callback + lw $t1, 0($t0)
+
+ addiu $sp, $sp, -24
+ jalr $t1
+ nop
+ addiu $sp, $sp, 24
+
+rcnt_acknowledge_irq:
+ li $t0, 0x1f801070 # IPENDING
+ la $t2, rcnt_handler_evfield
+
+ lw $t1, 0($t0)
+ nop
+ nop
+ xor $t1, $t1, $t2 # Acknowledge Root Counter IRQ
+ sw $t1, 0($t0)
+
+rcnt_handler_end: +.set noat
+ lw $at, 112($sp)
+ nop
+ mthi $at
+ lw $at, 116($sp)
+ nop
+ mtlo $at
+ lw $at, 0($sp)
+.set at
+ lw $v0, 4($sp)
+ lw $v1, 8($sp)
+ lw $a0, 12($sp)
+ lw $a1, 16($sp)
+ lw $a2, 20($sp)
+ lw $a3, 24($sp)
+ lw $t0, 28($sp)
+ lw $t1, 32($sp)
+ lw $t2, 36($sp)
+ lw $t3, 40($sp)
+ lw $t4, 44($sp)
+ lw $t5, 48($sp)
+ lw $t6, 52($sp)
+ lw $t7, 56($sp)
+ lw $s0, 60($sp)
+ lw $s1, 64($sp)
+ lw $s2, 68($sp)
+ lw $s3, 72($sp)
+ lw $s4, 76($sp)
+ lw $s5, 80($sp)
+ lw $s6, 84($sp)
+ lw $s7, 88($sp)
+ lw $t8, 92($sp)
+ lw $t9, 96($sp)
+ lw $gp, 100($sp)
+ lw $s8, 104($sp)
+ lw $ra, 108($sp)
+ addi $sp, 120
+ jr $ra
+ nop
+
+get_cop0_status:
+ mfc0 $v0, $12
+ jr $ra
+ nop
+
+set_cop0_status:
+ mtc0 $a0, $12
+ jr $ra
+ nop
+
+get_cop0_epc:
+ mfc0 $2, $14
+ jr $ra
+ nop
+
+run_bios:
+ j 0xbfc00000
+ nop
+
+is_load_delay_ok: + li $t2, 0 + li $t0, 0x0adecade + la $t1, isldo_data + .word 0x8d2a0000 #lw t2,0(t1) + beq $t0, $t2, load_delay_not_ok + nop +load_delay_ok: + li $v0, 1 + jr $ra + nop +load_delay_not_ok: + li $v0, 0 + jr $ra + nop +
+exit:
+ move $s0, $a0
+
+ la $a0, called_exit
+ move $a1, $s0
+
+ addiu $sp, $sp, -24
+ jal printf
+ nop
+ addiu $sp, $sp, 24
+
+ move $v0, $s0
+
+ j _real_exit
+ nop
+
+ .align 16
+ .data
+
+called_exit:
+ .string "Called exit(%d)\n"
+
+progtermfmt:
+ .string "Program terminated with return value %d\n"
+
+isldo_data:
+ .word 0x0adecade
diff --git a/libpsx/src/syscalls.s b/libpsx/src/syscalls.s new file mode 100644 index 0000000..305d03e --- /dev/null +++ b/libpsx/src/syscalls.s @@ -0,0 +1,344 @@ +# PSX SDK System calls file + +.text + +# Console functions + +.global bios_putchar +.global bios_puts +.global printf +.extern __stdio_direction +.extern sio_printf + +bios_putchar: + li $9, 0x3c + j 0xa0 + nop + +bios_puts: + li $9, 0x3e + j 0xa0 + nop + +printf: + la $9, __stdio_direction + lw $10, 0($9) + beq $10, $0, use_bios_printf + nop + j sio_printf + nop +use_bios_printf: + li $9, 0x3f + j 0xa0 + nop + +# Memory functions +# These are not used by PSXSDK, and are here just for completeness. + +.global InitHeap +.global FlushCache + +InitHeap: + li $9, 0x39 + j 0xa0 + nop + +FlushCache: + li $9, 0x44 + j 0xa0 + nop + +# GPU functions +.global GPU_dw +.global mem2vram +.global SendGPU +.global GPU_cw +.global GPU_cwb +.global SendPrimitive +.global GetGPUStatus + +GPU_dw: + li $9, 0x46 + j 0xa0 + nop + +mem2vram: + li $9, 0x47 + j 0xa0 + nop + +.global ResetEntryInt + +ResetEntryInt: + li $9, 0x18 + j 0xb0 + nop + +# ??? +.global GetKernelDate +.global GetKernelRomVersion +.global GetRamSize + +GetKernelDate: + li $9, 0xb4 + li $4, 0 + j 0xa0 + nop + +GetKernelRomVersion: + li $9, 0xb4 + li $4, 2 + j 0xa0 + nop + +GetRamSize: + li $9, 0xb4 + li $4, 5 + j 0xa0 + nop + +# Event functions +.global OpenEvent +.global EnableEvent +.global CloseEvent +.global DisableEvent +.global WaitEvent +.global TestEvent +.global DeliverEvent + +OpenEvent: + li $9, 0x08 + j 0xb0 + nop + +EnableEvent: + li $9, 0x0c + j 0xb0 + nop + +CloseEvent: + li $9, 0x09 + j 0xb0 + nop + +DisableEvent: + li $9, 0x0d + j 0xb0 + nop + +DeliverEvent: + li $9, 0x07 + j 0xb0 + nop + +WaitEvent: + li $9, 0x0a + j 0xb0 + nop + +TestEvent: + li $9, 0x0b + j 0xb0 + nop + +# File I/O functions +.global open +.global lseek +.global read +.global write +.global close +.global cd +.global firstfile +.global nextfile +.global rename +.global remove + +open: + li $9, 0x32 + j 0xb0 + nop + +lseek: + li $9, 0x33 + j 0xb0 + nop + +read: + li $9, 0x34 + j 0xb0 + nop + +write: + li $9, 0x35 + j 0xb0 + nop + +close: + li $9, 0x36 + j 0xb0 + nop + +cd: + li $9, 0x40 + j 0xb0 + nop + +firstfile: + li $9, 0x42 + j 0xb0 + nop + +nextfile: + li $9, 0x43 + j 0xb0 + nop + +rename: + li $9, 0x44 + j 0xb0 + nop + +remove: + li $9, 0x45 + j 0xb0 + nop + +# Exception / Interrupt functions + +.global EnterCriticalSection +.global ExitCriticalSection +.global SysEnqIntRP +.global SysDeqIntRP + +EnterCriticalSection: + li $a0, 1 + syscall + nop + jr $ra + nop + +ExitCriticalSection: + li $a0, 2 + syscall + nop + jr $ra + nop + +SysEnqIntRP: + li $9, 0x02 + j 0xc0 + nop + +SysDeqIntRP: + li $9, 0x03 + j 0xc0 + nop + +# Filesystem functions + +.global _96_init +.global _96_remove +.global _bu_init + +_96_init: + li $9, 0x71 + j 0xa0 + nop + +_96_remove: + li $9, 0x72 + j 0xa0 + nop + +_bu_init: + li $9, 0x70 + j 0xa0 + nop + +# Executable loading functions + +.global LoadExec + +LoadExec: + li $9, 0x51 + j 0xa0 + nop + +# Memory card routines + +.global InitCARD +.global StartCARD +.global StopCARD +.global _card_info +.global _card_load +.global _card_auto +.global _card_write +.global _card_read +.global _card_status +.global _new_card + +InitCARD: + li $9, 0x4a + j 0xb0 + nop + +StartCARD: + li $9, 0x4b + j 0xb0 + nop + +StopCARD: + li $9, 0x4c + j 0xb0 + nop + +_card_info: + li $9, 0xab + j 0xa0 + nop + +_card_load: + li $9, 0xac + j 0xa0 + nop + +_card_auto: + li $9, 0xad + j 0xa0 + nop + +_card_write: + li $9, 0x4e + j 0xb0 + nop + +_card_read: + li $9, 0x4f + j 0xb0 + nop + +_new_card: + li $9, 0x50 + j 0xb0 + nop + +_card_status: + li $9, 0x5c + j 0xb0 + nop + +# Device functions + +.global PrintInstalledDevices + +PrintInstalledDevices: + li $9, 0x49 + j 0xb0 + nop + +.global BIOSWarmReboot + +BIOSWarmReboot: + li $9, 0xa0 + nop + j 0xa0 diff --git a/libpsx/src/util.c b/libpsx/src/util.c new file mode 100644 index 0000000..a9c7921 --- /dev/null +++ b/libpsx/src/util.c @@ -0,0 +1,42 @@ +// util.c
+// PSXSDK utility functions
+
+// This is not a core part of the PSXSDK
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <psxutil.h>
+
+const char *psxsdk_btn_names[] =
+ { "L2", "R2", "L1", "R1", "Triangle", "Circle", "Cross",
+ "Square", "Select", "Res1", "Res2", "Start",
+ "Up", "Right", "Down", "Left"};
+
+char *PSX_GetButtonName(unsigned short button, char *out, unsigned int out_len)
+{
+ int x;
+
+ if(out_len)out[0] = 0;
+
+ for(x = 0; x < 16; x++)
+ {
+ if(button & (1<<x))
+ {
+ strncat(out, psxsdk_btn_names[x], out_len);
+ out_len -= strlen(out);
+ strncat(out, "&", out_len);
+ out_len--;
+ }
+ }
+
+ if(strlen(out))
+ {
+ if(out[strlen(out) - 1] == '&')
+ out[strlen(out) - 1] = 0;
+ }
+ else
+ strncpy(out, "None", out_len);
+
+ return out;
+}
|
