├── libcdvd ├── lib │ └── DUMMY ├── docs │ └── libcdvd_ref.pdf ├── ee │ ├── Makefile │ ├── cdvd_rpc.h │ └── cdvd_rpc.c ├── iop │ ├── Makefile │ ├── ps2lib_ioman.h │ ├── iop_cdvdman.s │ └── cdvd_iop.h ├── Makefile ├── common │ └── cdvd.h └── license.txt ├── cdvd.irx ├── sjpcm.irx ├── .gitattributes ├── browser ├── init.h ├── pad.h ├── cnfsettings.h ├── ps2font.h ├── bdraw.h ├── cd.h ├── browser.h ├── pad.c ├── cd.c ├── bdraw.c ├── init.c └── ps2font.c ├── .gitignore ├── osd_cpu.h ├── sjpcm.h ├── shared.h ├── sn76496.h ├── sms.h ├── mipsregs.h ├── render.h ├── linkfile ├── psms-reloaded.txt ├── vdp.h ├── ym2413.h ├── Makefile.original ├── psms.h ├── source.txt ├── Makefile ├── system.h ├── z80.h ├── cdinfo.txt ├── README.md ├── sjpcm_rpc.c ├── fmopl.h ├── psms.txt ├── sn76496.c ├── system.c ├── sms.c ├── vdp.c ├── ym2413.c ├── psms.c ├── license ├── render.c └── cpuintrf.h /libcdvd/lib/DUMMY: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cdvd.irx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infval/PSMS-Reloaded-New/HEAD/cdvd.irx -------------------------------------------------------------------------------- /sjpcm.irx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infval/PSMS-Reloaded-New/HEAD/sjpcm.irx -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /browser/init.h: -------------------------------------------------------------------------------- 1 | #ifndef INIT_H_ 2 | #define INIT_H_ 3 | 4 | void InitPS2(void); 5 | 6 | #endif /*INIT_H_*/ 7 | -------------------------------------------------------------------------------- /libcdvd/docs/libcdvd_ref.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infval/PSMS-Reloaded-New/HEAD/libcdvd/docs/libcdvd_ref.pdf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Full https://github.com/github/gitignore/blob/master/C.gitignore 2 | 3 | # Object files 4 | *.o 5 | *.elf 6 | 7 | # Libraries 8 | *.a 9 | 10 | # Generated 11 | /irx/*.c 12 | -------------------------------------------------------------------------------- /browser/pad.h: -------------------------------------------------------------------------------- 1 | #ifndef PAD_H_ 2 | #define PAD_H_ 3 | 4 | // Prototypes 5 | void waitPadReady(int port, int slot); 6 | int initializePad(int port, int slot); 7 | void setupPS2Pad(); 8 | 9 | #endif /*PAD_H_*/ 10 | -------------------------------------------------------------------------------- /libcdvd/ee/Makefile: -------------------------------------------------------------------------------- 1 | EE_LIB = ../lib/libcdvdfs.a 2 | EE_OBJS = cdvd_rpc.o 3 | 4 | all: $(EE_LIB) 5 | 6 | clean: 7 | rm -f $(EE_LIB) $(EE_OBJS) 8 | 9 | include $(PS2SDK)/samples/Makefile.pref 10 | include $(PS2SDK)/samples/Makefile.eeglobal 11 | -------------------------------------------------------------------------------- /browser/cnfsettings.h: -------------------------------------------------------------------------------- 1 | #ifndef CNFSETTINGS_H_ 2 | #define CNFSETTINGS_H_ 3 | 4 | void Default_Global_CNF(void); 5 | void Default_Skin_CNF(void); 6 | void Load_Global_CNF(char *CNF_path_p); 7 | void Save_Global_CNF(char *CNF_path_p); 8 | 9 | #endif /*CNFSETTINGS_H_*/ 10 | -------------------------------------------------------------------------------- /browser/ps2font.h: -------------------------------------------------------------------------------- 1 | #ifndef PS2FONT_H_ 2 | #define PS2FONT_H_ 3 | 4 | // Prototypes 5 | int loadFont(char *path_arg); 6 | void drawChar(unsigned int c, int x, int y, int z, u64 colour); 7 | int printXY(const char *s, int x, int y, int z, u64 colour, int draw, int space); 8 | 9 | #endif /*PS2FONT_H_*/ 10 | -------------------------------------------------------------------------------- /libcdvd/iop/Makefile: -------------------------------------------------------------------------------- 1 | #IOP_LDFLAGS += -m mipsirx 2 | 3 | IOP_BIN = ../lib/cdvd.irx 4 | 5 | IOP_OBJS = cdvd_iop.o iop_cdvdman.o 6 | 7 | 8 | all: $(IOP_BIN) 9 | 10 | clean: 11 | rm -f $(IOP_BIN) $(IOP_OBJS) 12 | 13 | include $(PS2SDK)/samples/Makefile.pref 14 | include $(PS2SDK)/samples/Makefile.iopglobal 15 | -------------------------------------------------------------------------------- /libcdvd/Makefile: -------------------------------------------------------------------------------- 1 | # Remove the line below, if you want to disable silent mode 2 | #.SILENT: 3 | 4 | all: build-ee build-iop 5 | 6 | clean: 7 | $(MAKE) -C ee clean 8 | $(MAKE) -C iop clean 9 | 10 | build-iop: 11 | @echo Building IRX 12 | $(MAKE) -C iop 13 | 14 | build-ee: 15 | @echo Building EE client 16 | $(MAKE) -C ee 17 | -------------------------------------------------------------------------------- /browser/bdraw.h: -------------------------------------------------------------------------------- 1 | #ifndef BDRAW_H_ 2 | #define BDRAW_H_ 3 | 4 | // Prototypes 5 | void menu_bgtexture(GSTEXTURE *gsTexture, float x1, float y1, float x2, float y2, int z); 6 | void DrawScreen(GSGLOBAL *gsGlobal); 7 | void menu_background(float x1, float y1, float x2, float y2, int z); 8 | void browser_primitive(char *title1, char *title2, GSTEXTURE *gsTexture, float x1, float y1, float x2, float y2); 9 | void normalize_screen(void); 10 | void init_custom_screen(void); 11 | void SetupGSKit(void); 12 | void SetDisplayOffset(void); 13 | 14 | #endif /*DRAW_H_*/ 15 | -------------------------------------------------------------------------------- /osd_cpu.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef OSD_CPU_H 3 | #define OSD_CPU_H 4 | 5 | typedef unsigned char UINT8; 6 | typedef unsigned short UINT16; 7 | typedef unsigned int UINT32; 8 | 9 | typedef signed char INT8; 10 | typedef signed short INT16; 11 | typedef signed int INT32; 12 | 13 | typedef union { 14 | #ifdef LSB_FIRST 15 | struct { UINT8 l,h,h2,h3; } b; 16 | struct { UINT16 l,h; } w; 17 | #else 18 | struct { UINT8 h3,h2,h,l; } b; 19 | struct { UINT16 h,l; } w; 20 | #endif 21 | UINT32 d; 22 | } PAIR; 23 | 24 | #endif /* defined OSD_CPU_H */ 25 | -------------------------------------------------------------------------------- /sjpcm.h: -------------------------------------------------------------------------------- 1 | #ifndef _SJPCM_H 2 | #define _SJPCM_H 3 | 4 | #define SJPCM_IRX 0xB0110C5 5 | #define SJPCM_PUTS 0x01 6 | #define SJPCM_INIT 0x02 7 | #define SJPCM_PLAY 0x03 8 | #define SJPCM_PAUSE 0x04 9 | #define SJPCM_SETVOL 0x05 10 | #define SJPCM_ENQUEUE 0x06 11 | #define SJPCM_CLEARBUFF 0x07 12 | 13 | void SjPCM_Puts(char *format, ...); 14 | int SjPCM_Init(); 15 | void SjPCM_Enqueue(short *left, short *right, int size, int wait); 16 | void SjPCM_Play(); 17 | void SjPCM_Pause(); 18 | void SjPCM_Setvol(unsigned int volume); 19 | void SjPCM_Clearbuff(); 20 | 21 | #endif // _SJPCM_H 22 | -------------------------------------------------------------------------------- /libcdvd/ee/cdvd_rpc.h: -------------------------------------------------------------------------------- 1 | #ifndef _CDVD_RPC_H 2 | #define _CDVD_RPC_H 3 | 4 | // include the common definitions 5 | #include "../common/cdvd.h" 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | 12 | int CDVD_Init(); 13 | int CDVD_DiskReady(int mode); 14 | int CDVD_FindFile(const char* fname, struct TocEntry* tocEntry); 15 | void CDVD_Stop(); 16 | int CDVD_TrayReq(int mode); 17 | int CDVD_DiskReady(int mode); 18 | int CDVD_GetDir(const char* pathname, const char* extensions, enum CDVD_getMode getMode, struct TocEntry tocEntry[], unsigned int req_entries, char* new_pathname); 19 | void CDVD_FlushCache(); 20 | unsigned int CDVD_GetSize(); 21 | 22 | 23 | #ifdef __cplusplus 24 | } 25 | #endif 26 | 27 | 28 | #endif // _CDVD_H 29 | -------------------------------------------------------------------------------- /shared.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _SHARED_H_ 3 | #define _SHARED_H_ 4 | 5 | #define VERSION "0.9.3" 6 | 7 | #include 8 | 9 | /* Data types */ 10 | typedef u32 dword; 11 | typedef u16 word; 12 | typedef u8 byte; 13 | 14 | enum { 15 | SRAM_SAVE = 0, 16 | SRAM_LOAD = 1 17 | }; 18 | 19 | /* To keep the MAME code happy */ 20 | #define HAS_YM3812 1 21 | typedef signed short int FMSAMPLE; 22 | 23 | #include 24 | //#include 25 | #include 26 | #include 27 | 28 | #include "z80.h" 29 | #include "sms.h" 30 | #include "vdp.h" 31 | #include "render.h" 32 | #include "sn76496.h" 33 | #include "fmopl.h" 34 | #include "ym2413.h" 35 | #include "system.h" 36 | 37 | #endif /* _SHARED_H_ */ 38 | 39 | -------------------------------------------------------------------------------- /sn76496.h: -------------------------------------------------------------------------------- 1 | #ifndef SN76496_H 2 | #define SN76496_H 3 | 4 | #define MAX_76496 4 5 | 6 | typedef struct 7 | { 8 | int Channel; 9 | int SampleRate; 10 | unsigned int UpdateStep; 11 | int VolTable[16]; 12 | int Register[8]; 13 | int LastRegister; 14 | int Volume[4]; 15 | unsigned int RNG; 16 | int NoiseFB; 17 | int Period[4]; 18 | int Count[4]; 19 | int Output[4]; 20 | }t_SN76496; 21 | 22 | extern t_SN76496 sn[MAX_76496]; 23 | 24 | void SN76496Write(int chip,int data); 25 | void SN76496Update(int chip, signed short int *buffer[2],int length,unsigned char mask); 26 | void SN76496_set_clock(int chip,int clock); 27 | void SN76496_set_gain(int chip,int gain); 28 | int SN76496_init(int chip,int clock,int volume,int sample_rate); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /sms.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _SMS_H_ 3 | #define _SMS_H_ 4 | 5 | #define TYPE_OVERSEAS (0) 6 | #define TYPE_DOMESTIC (1) 7 | 8 | /* SMS context */ 9 | typedef struct 10 | { 11 | byte dummy[0x2000]; 12 | byte ram[0x2000]; 13 | byte sram[0x8000]; 14 | byte fcr[4]; 15 | byte paused; 16 | byte save; 17 | byte country; 18 | byte port_3F; 19 | byte port_F2; 20 | byte use_fm; 21 | byte irq; 22 | byte psg_mask; 23 | }t_sms; 24 | 25 | /* Global data */ 26 | extern t_sms sms; 27 | 28 | /* Function prototypes */ 29 | void sms_frame(int skip_render); 30 | void sms_init(void); 31 | void sms_reset(void); 32 | int sms_irq_callback(int param); 33 | void sms_mapper_w(int address, int data); 34 | void cpu_reset(void); 35 | 36 | #endif /* _SMS_H_ */ 37 | -------------------------------------------------------------------------------- /mipsregs.h: -------------------------------------------------------------------------------- 1 | // register defines for the GNU assembler 2 | 3 | #define zero 0 4 | #define at 1 5 | #define v0 2 6 | #define v1 3 7 | #define a0 4 8 | #define a1 5 9 | #define a2 6 10 | #define a3 7 11 | #define t0 8 12 | #define t1 9 13 | #define t2 10 14 | #define t3 11 15 | #define t4 12 16 | #define t5 13 17 | #define t6 14 18 | #define t7 15 19 | #define s0 16 20 | #define s1 17 21 | #define s2 18 22 | #define s3 19 23 | #define s4 20 24 | #define s5 21 25 | #define s6 22 26 | #define s7 23 27 | #define t8 24 28 | #define t9 25 29 | #define k0 26 30 | #define k1 27 31 | #define gp 28 32 | #define sp 29 33 | #define fp 30 34 | #define ra 31 35 | 36 | -------------------------------------------------------------------------------- /render.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _RENDER_H_ 3 | #define _RENDER_H_ 4 | 5 | /* Pack RGB data into a 16-bit RGB 5:6:5 format */ 6 | #define MAKE_PIXEL(r,g,b) (((r << 8) & 0xF800) | ((g << 3) & 0x07E0) | ((b >> 3) & 0x001F)) 7 | 8 | /* Used for blanking a line in whole or in part */ 9 | #define BACKDROP_COLOR (0x10 | (vdp.reg[7] & 0x0F)) 10 | 11 | /* Global data - used by 'vdp.c' */ 12 | extern byte vram_dirty[0x200]; 13 | extern byte is_vram_dirty; 14 | 15 | /* Function prototypes */ 16 | void render_init(void); 17 | void render_reset(void); 18 | void render_bg_gg(int line); 19 | void render_bg_sms(int line); 20 | void render_obj(int line); 21 | void render_line(int line); 22 | void update_cache(void); 23 | void palette_sync(int index); 24 | void remap_8_to_16(int line); 25 | 26 | #endif /* _RENDER_H_ */ 27 | -------------------------------------------------------------------------------- /linkfile: -------------------------------------------------------------------------------- 1 | _heap_size = 0x800000; 2 | 3 | ENTRY(_start); 4 | SECTIONS { 5 | 6 | .text 0x200000 : { 7 | *(.rodata) 8 | *(.text) 9 | } 10 | .reginfo ALIGN(128) : { 11 | *(.reginfo) 12 | } 13 | .data ALIGN(128) : { 14 | *(.data) 15 | } 16 | .rdata ALIGN(128) : { 17 | *(.rdata) 18 | } 19 | _gp = ALIGN(128) + 0x7ff0; 20 | .lit4 ALIGN(128) : { 21 | *(.lit4) 22 | } 23 | .lit8 ALIGN(128) : { 24 | *(.lit8) 25 | } 26 | .sdata ALIGN(128) : { 27 | *(.sdata) 28 | } 29 | 30 | .sbss ALIGN(128) (NOLOAD) : { /* uninitialized data */ 31 | _fbss = . ; 32 | *(.scommon) 33 | *(.sbss) 34 | } 35 | .bss ALIGN(128) (NOLOAD) : { /* uninitialized data */ 36 | *(.bss) 37 | } 38 | .COMMON ALIGN(128) (NOLOAD) : { /* uninitialized data */ 39 | *(COMMON) 40 | } 41 | _end_bss = . - 4; 42 | _end = . ; 43 | __lc_bh = . ; 44 | . += _heap_size ; 45 | __lc_eh = .; 46 | 47 | } 48 | -------------------------------------------------------------------------------- /browser/cd.h: -------------------------------------------------------------------------------- 1 | #ifndef CD_H 2 | #define CD_H 3 | 4 | #define CDVD_INIT_INIT 0x00 5 | #define CDVD_INIT_NOCHECK 0x01 6 | #define CDVD_INIT_EXIT 0x05 7 | 8 | typedef enum { 9 | CDVD_TYPE_NODISK = 0x00, // No Disc inserted 10 | CDVD_TYPE_DETECT, // Detecting disc type 11 | CDVD_TYPE_DETECT_CD, 12 | CDVD_TYPE_DETECT_DVDSINGLE, 13 | CDVD_TYPE_DETECT_DVDDUAL, 14 | CDVD_TYPE_UNKNOWN, // Unknown disc type 15 | 16 | CDVD_TYPE_PS1CD = 0x10, // PS1 CD with no CDDA tracks 17 | CDVD_TYPE_PS1CDDA, // PS1 CD with CDDA tracks 18 | CDVD_TYPE_PS2CD, // PS2 CD with no CDDA tracks 19 | CDVD_TYPE_PS2CDDA, // PS2 CD with CDDA tracks 20 | CDVD_TYPE_PS2DVD, // PS2 DVD 21 | 22 | CDVD_TYPE_CDDA = 0xFD, // CDDA 23 | CDVD_TYPE_DVDVIDEO, // DVD Video 24 | CDVD_TYPE_ILLEGAL, // Illegal disk type 25 | } CdvdDiscType_t; 26 | 27 | s32 cdInit(s32); 28 | CdvdDiscType_t cdGetDiscType(void); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /psms-reloaded.txt: -------------------------------------------------------------------------------- 1 | PSMS - Reloaded 2 | by: bootsector (bootsector@ig.com.br) 3 | http://www.brunofreitas.com/ 4 | ------------------------------------- 5 | 6 | PSMS Reloaded attempts to bring PSMS 1.2 (by Sjeep) back to life! It now 7 | supports following devices, without relying on any special "FILES.TXT" index: 8 | 9 | :. Memory Card 10 | :. USB Devices 11 | :. CD/DVD 12 | :. HDD 13 | 14 | This version was converted from PS2LIB/GFXPIPE to PS2SDK/GsKit by bootsector. 15 | 16 | Thanks to the following people who (in)directly made this happen: 17 | 18 | :. PS2SDK maintainers/developers 19 | :. PS2DEV forum members (Lukasz and others) 20 | :. ragnarok2040 for his menu component (used in FCEUltra for PS2) 21 | :. dlanor and EP for LaunchElf and its source code 22 | :. Sjeep for the quick and dirty, but still good PSMS port. 23 | :. My lovely wife, Miriam, for letting me to spend some of our 24 | valuable time with this ;) 25 | 26 | This is a WIP project. There are still many features to be added! 27 | 28 | Hope you folks enjoy it! 29 | 30 | bootsector -------------------------------------------------------------------------------- /libcdvd/common/cdvd.h: -------------------------------------------------------------------------------- 1 | #ifndef _CDVD_H 2 | #define _CDVD_H 3 | 4 | // This header contains the common definitions for libcdvd 5 | // that are used by both IOP and EE sides 6 | 7 | #define CDVD_IRX 0xB001337 8 | #define CDVD_FINDFILE 0x01 9 | #define CDVD_GETDIR 0x02 10 | #define CDVD_STOP 0x04 11 | #define CDVD_TRAYREQ 0x05 12 | #define CDVD_DISKREADY 0x06 13 | #define CDVD_FLUSHCACHE 0x07 14 | #define CDVD_GETSIZE 0x08 15 | 16 | 17 | struct TocEntry 18 | { 19 | u32 fileLBA; 20 | u32 fileSize; 21 | u8 fileProperties; 22 | u8 padding1[3]; 23 | char filename[128+1]; 24 | u8 padding2[3]; 25 | } __attribute__((packed)); 26 | 27 | 28 | enum CDVD_getMode { 29 | CDVD_GET_FILES_ONLY = 1, 30 | CDVD_GET_DIRS_ONLY = 2, 31 | CDVD_GET_FILES_AND_DIRS = 3 32 | }; 33 | 34 | // Macros for TrayReq 35 | #define CdTrayOpen 0 36 | #define CdTrayClose 1 37 | #define CdTrayCheck 2 38 | 39 | // Macros for DiskReady 40 | #define CdComplete 0x02 41 | #define CdNotReady 0x06 42 | #define CdBlock 0x00 43 | #define CdNonBlock 0x01 44 | 45 | #endif // _CDVD_H 46 | -------------------------------------------------------------------------------- /vdp.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _VDP_H_ 3 | #define _VDP_H_ 4 | 5 | /* Display timing (NTSC) */ 6 | #define MASTER_CLOCK (3579545) 7 | #define LINES_PER_FRAME (262) 8 | #define FRAMES_PER_SECOND (60) 9 | #define CYCLES_PER_LINE ((MASTER_CLOCK / FRAMES_PER_SECOND) / LINES_PER_FRAME) 10 | 11 | /* VDP context */ 12 | typedef struct 13 | { 14 | byte vram[0x4000]; 15 | byte cram[0x40]; 16 | byte reg[0x10]; 17 | byte status; 18 | byte latch; 19 | byte pending; 20 | byte buffer; 21 | byte code; 22 | word addr; 23 | int ntab; 24 | int satb; 25 | int line; 26 | int left; 27 | byte limit; 28 | }t_vdp; 29 | 30 | /* Global data */ 31 | extern t_vdp vdp; 32 | 33 | /* Function prototypes */ 34 | void vdp_init(void); 35 | void vdp_reset(void); 36 | void vdp_ctrl_w(int data); 37 | int vdp_ctrl_r(void); 38 | byte vdp_vcounter_r(void); 39 | byte vdp_hcounter_r(void); 40 | void vdp_data_w(int data); 41 | int vdp_data_r(void); 42 | void vdp_run(void); 43 | 44 | #endif /* _VDP_H_ */ 45 | 46 | -------------------------------------------------------------------------------- /ym2413.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _YM2413_H_ 3 | #define _YM2413_H_ 4 | 5 | /* Total # of YM2413's that can be used at once - change as needed */ 6 | #define MAX_YM2413 (4) 7 | 8 | /* YM2413 context */ 9 | typedef struct 10 | { 11 | unsigned char reg[0x40]; /* 64 registers */ 12 | unsigned char latch; /* Register latch */ 13 | unsigned char rhythm; /* Rhythm instruments loaded flag */ 14 | unsigned char user[0x10]; /* User instrument settings */ 15 | struct 16 | { 17 | unsigned short int frequency; /* Channel frequency */ 18 | unsigned char volume; /* Channel volume */ 19 | unsigned char instrument; /* Channel instrument */ 20 | }channel[9]; 21 | }t_ym2413; 22 | 23 | /* Global data */ 24 | extern t_ym2413 ym2413[MAX_YM2413]; 25 | 26 | /* Function prototypes */ 27 | void ym2413_init(int count); 28 | void ym2413_reset(int chip); 29 | void ym2413_write(int chip, int address, int data); 30 | void load_instrument(int chip, int ch, int inst, int vol); 31 | void rhythm_mode_init(int chip); 32 | 33 | #endif /* _YM2413_H_ */ 34 | -------------------------------------------------------------------------------- /browser/browser.h: -------------------------------------------------------------------------------- 1 | #ifndef BROWSER_H 2 | #define BROWSER_H 3 | 4 | typedef struct { 5 | char displayname[64]; 6 | int dircheck; 7 | char filename[256]; 8 | } entries; 9 | 10 | typedef struct { 11 | int offset_x; 12 | int offset_y; 13 | u8 display; 14 | u8 interlace; 15 | u8 filter; 16 | u8 sprite_limit; 17 | char elfpath[1024]; 18 | char savepath[1024]; 19 | //char skinpath[1024]; 20 | u16 PlayerInput[2][10]; 21 | int autofire_pattern; 22 | } vars; 23 | 24 | typedef struct { 25 | u64 frame; 26 | u64 textcolor; 27 | u64 highlight; 28 | u64 bgColor1; 29 | u64 bgColor2; 30 | u64 bgColor3; 31 | u64 bgColor4; 32 | char bgTexture[1024]; 33 | char bgMenu[1024]; 34 | } skin; 35 | 36 | // Prototypes 37 | char* browseup(char *path); 38 | int RomBrowserInput(int files_too, int inside_menu); 39 | int listdir(char *path, entries *FileEntry, int files_too); 40 | int listcdvd(const char *path, entries *FileEntry); 41 | int listpfs(char *path, entries *FileEntry, int files_too); 42 | int listpartitions(entries *FileEntry); 43 | char *partname(char *d, const char *hdd_path); 44 | void unmountPartition(int pfs_number); 45 | int mountPartition(char *name); 46 | char* Browser(int files_too, int menu_id, int filtered); 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /Makefile.original: -------------------------------------------------------------------------------- 1 | # 2 | # PSMS 3 | # Copyright (C) 2002 Nick Van Veen 4 | # 5 | 6 | LIBDIR = $(PS2LIB)/ee/lib 7 | INCLUDES = -I$(PS2LIB)/common/include -I$(PS2LIB)/ee/include -I. -I./cpu -I./gfxpipe 8 | 9 | OBJS = sjpcm_rpc.o psms.o menu.o pad.o gs.o hw.o fmopl.o render.o sms.o sn76496.o system.o vdp.o ym2413.o z80.o psms_logo.o font/vixar.o gfxpipe/gfxpipe.o 10 | 11 | LCFILE = linkfile 12 | 13 | LIBS = -lm -lkernel -lc 14 | 15 | PREFIX = ee 16 | AS = $(PREFIX)-gcc 17 | CC = $(PREFIX)-gcc 18 | CPP = cpp 19 | LD = $(PREFIX)-gcc 20 | DVPASM = $(PREFIX)-dvp-as 21 | OBJDUMP = $(PREFIX)-objdump 22 | RM = /bin/rm -f 23 | 24 | CFLAGS = -O2 -EL -pipe -Wall -Wa,-al -D_EE -DLSB_FIRST -DALIGN_DWORD -fomit-frame-pointer -fno-common -mips3 -mcpu=r5900 -ffreestanding -fno-builtin -fshort-double -nostartfiles -mlong64 -mhard-float -mno-abicalls -c 25 | CXXFLAGS = -O2 -Wall -Wa,-al -fno-exceptions -fno-common 26 | LDFLAGS = -Wl,-Map,psms.map -L$(LIBDIR) -L. 27 | 28 | .SUFFIXES: .c .s .cc .dsm 29 | 30 | all: psms.elf 31 | 32 | psms.elf: $(OBJS) 33 | $(LD) -o $@ -T $(LCFILE) $(OBJS) $(LDFLAGS) $(LIBS) 34 | ee-strip -F elf32-littlemips psms.elf 35 | 36 | crt0.o: 37 | $(AS) $(CFLAGS) crt0.s -o $@ > $*.lst 38 | 39 | .s.o: 40 | $(AS) $(CFLAGS) $(INCLUDES) $< -o $@ > $*.lst 41 | 42 | .S.o: 43 | $(AS) $(CFLAGS) $(INCLUDES) $< -o $@ > $*.lst 44 | 45 | .c.o: 46 | $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $*.o > $*.lst 47 | 48 | .cc.o: 49 | $(CC) $(CXXFLAGS) $(INCLUDES) -c $< -o $*.o > $*.lst 50 | 51 | clean: 52 | $(RM) *.o *.map *.lst core *.dis *.elf 53 | -------------------------------------------------------------------------------- /libcdvd/iop/ps2lib_ioman.h: -------------------------------------------------------------------------------- 1 | /* 2 | _____ ___ ____ 3 | ____| | ____| PSX2 OpenSource Project 4 | | ___| |____ (C) 2003 Marcus R. Brown (mrbrown@0xd6.org) 5 | ------------------------------------------------------------------------ 6 | ioman.h 7 | */ 8 | 9 | #ifndef PS2LIB_IOP_IOMAN_H 10 | #define PS2LIB_IOP_IOMAN_H 11 | 12 | /* Compatibility with older fileio.h - This stuff is deprecated, it will be 13 | removed in the next major release! */ 14 | 15 | #include 16 | 17 | struct fileio_driver 18 | { 19 | u8 *device; 20 | u32 xx1; /* always 16? */ 21 | u32 version; /* 1 */ 22 | u8 *description; 23 | void **function_list; 24 | }; 25 | 26 | /* function list index */ 27 | enum 28 | { 29 | FIO_INITIALIZE, /* initialize(struct fileio_driver *); */ 30 | FIO_SHUTDOWN, /* shutdown(struct fileio_driver *) */ 31 | FIO_FORMAT, /* format( int kernel_fd, char *name); */ 32 | FIO_OPEN, /* open( int kernel_fd, char *name, int mode); */ 33 | FIO_CLOSE, /* close( int kernel_fd); */ 34 | FIO_READ, /* read( int kernel_fd, void *ptr, int size); */ 35 | FIO_WRITE, /* write( int kernel_fd, void *ptr, int size); */ 36 | FIO_SEEK, /* seek( int kernel_fd, u32 pos, int mode); */ 37 | FIO_IOCTL, /* ioctl( int kernel_fd, u32 type, void *value); */ 38 | FIO_REMOVE, /* remove( int kernel_fd, char *name); */ 39 | FIO_MKDIR, /* mkdir( int kernel_fd, char *name); */ 40 | FIO_RMDIR, /* rmdir( int kernel_fd, char *name); */ 41 | FIO_DOPEN, /* dopen( int kernel_fd, char *name); */ 42 | FIO_DCLOSE, /* dclose( int kernel_fd); */ 43 | FIO_DREAD, /* dread( int kernel_fd, void *ptr); */ 44 | FIO_GETSTAT, /* getstat( int kernel_fd, char *name, void *buf); it is not void*, but a structure */ 45 | FIO_CHSTAT /* chstat( int kernel_fd, char *name, void *buf, unsigned int mask); */ 46 | }; 47 | 48 | int FILEIO_add( struct fileio_driver *driver); 49 | int FILEIO_del( u8 *device); 50 | 51 | #endif /* PS2LIB_IOP_IOMAN_H */ 52 | -------------------------------------------------------------------------------- /psms.h: -------------------------------------------------------------------------------- 1 | #ifndef _PSMS_H_ 2 | #define _PSMS_H_ 3 | 4 | 5 | //#define DEVEL 6 | //#define CD_BUILD 7 | 8 | 9 | #define WIDTH 256 10 | #define HEIGHT 240 11 | 12 | /* VRAM layout: 13 | 14 | 0x000000 - FB 1 15 | 0x040000 - FB 2 (FB 1 + 256*256*4) 16 | 0x080000 - ZBuf (FB 2 * 2) 17 | 0x0A0000 - End of ZBuf. Star of TEX and CLUT area. 18 | 19 | 0x0B0000 - SMS Display Texture (0xC000 bytes long) 20 | 0x0BC000 - SMS Display Clut (0x200 bytes long) 21 | 22 | 0x0C0000 - PSMS logo image (0x8000 bytes long) 23 | 0x0C8000 - PSMS logo clut (0x200 bytes long) 24 | 25 | 0x0D0000 - PSMS font image (0x10000 bytes long) 26 | 0x0E0000 - PSMS font clut (0x200 bytes long) 27 | 28 | */ 29 | 30 | #define SMS_TEX 0x0B0000 31 | #define SMS_CLUT 0x0BC000 32 | 33 | #define LOGO_TEX 0x0C0000 34 | #define LOGO_CLUT 0x0C8000 35 | 36 | #define FONT_TEX 0x0D0000 37 | #define FONT_CLUT 0x0E0000 38 | 39 | #define VRAM_MAX 0x3E8000 40 | 41 | 42 | 43 | //#define WAIT_PAD_READY(p, s) {while(padGetState((p),(s)) != PAD_STATE_STABLE) WaitForNextVRstart(1); } 44 | #define WAIT_PAD_READY(p, s) {while(padGetState((p),(s)) != PAD_STATE_STABLE); } 45 | 46 | // PSMS Logo 47 | extern unsigned char __attribute__((aligned(16))) psms_image[]; 48 | extern unsigned char __attribute__((aligned(16))) psms_clut[]; 49 | 50 | #define psms_width 256 51 | #define psms_height 128 52 | #define psms_mode 1 53 | 54 | // Menu font 55 | extern unsigned char __attribute__((aligned(16))) vixar_image[]; 56 | extern unsigned char __attribute__((aligned(16))) vixar_clut[]; 57 | extern unsigned char vixarmet[]; 58 | 59 | #define vixar_width 256 60 | #define vixar_height 256 61 | #define vixar_mode 1 62 | 63 | int load_rom(char* filename); 64 | void update_video(); 65 | void update_input(); 66 | int init_machine(); 67 | void LoadModules(); 68 | void setupSMSGS(void); 69 | void setupSMSTexture(void); 70 | int InitPad(int port, int slot, char* buffer); 71 | void test(); 72 | void TextOut(int x, int y, char *string, int z); 73 | void TextOutC(int x_start, int x_end, int y, char *string, int z); 74 | void IngameMenu(); 75 | void psms_save_state(); 76 | void psms_load_state(); 77 | void psms_manage_sram(u8 *sram, int mode); 78 | 79 | void display_error(char* errmsg, int fatal); 80 | 81 | 82 | 83 | #endif /* _PSMS_H_ */ 84 | -------------------------------------------------------------------------------- /libcdvd/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2002, A.Lee & Nicholas Van Veen 2 | All rights reserved. 3 | 4 | Redistribution and use of this software, in source and binary forms, with or 5 | without modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. You are granted a license to use this software for academic, research and 16 | non-commercial purposes only. 17 | 18 | 4. The copyright holder imposes no restrictions on any code developed using 19 | this software. However, the copyright holder retains a non-exclusive 20 | royalty-free license to any modifications to the distribution made by the 21 | licensee. 22 | 23 | 5. Any licensee wishing to make commercial use of this software should contact 24 | the copyright holder to execute the appropriate license for such commercial 25 | use. Commercial use includes: 26 | 27 | - Integration of all or part of the source code into a product for sale 28 | or commercial license by or on behalf of Licensee to third parties, or 29 | 30 | - Distribution of the binary code or source code to third parties that 31 | need it to utilize a commercial product sold or licensed by or on 32 | behalf of Licensee. 33 | 34 | 35 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 36 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 37 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 38 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 39 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 40 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 41 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 42 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 43 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 44 | OF SUCH DAMAGE. 45 | 46 | -------------------------------------------------------------------------------- /libcdvd/iop/iop_cdvdman.s: -------------------------------------------------------------------------------- 1 | /* 2 | _____ ___ ____ 3 | ____| | ____| PSX2 OpenSource Project 4 | | ___| |____ (C)2002, Nick Van Veen 5 | ------------------------------------------------------------------------ 6 | iop_Cdman.s CDVD Manager Functions. 7 | taken from .irx files with symbol table. 8 | */ 9 | 10 | .text 11 | .set noreorder 12 | 13 | 14 | /* ############################### CDVDMAN STUB ####### */ 15 | /* # Added by Sjeep, 24th June 2002 # */ 16 | 17 | .local cdvdman_stub 18 | cdvdman_stub: 19 | .word 0x41e00000 20 | .word 0 21 | .word 0x00000101 22 | .ascii "cdvdman\0" 23 | .align 2 24 | 25 | .globl CdInit # 004 26 | CdInit: 27 | j $31 28 | li $0, 4 29 | 30 | .globl CdStandby # 005 31 | CdStandby: 32 | j $31 33 | li $0, 5 34 | 35 | .globl CdRead # 006 36 | CdRead: 37 | j $31 38 | li $0, 6 39 | 40 | .globl CdSeek # 007 41 | CdSeek: 42 | j $31 43 | li $0, 7 44 | 45 | .globl CdGetError # 008 46 | CdGetError: 47 | j $31 48 | li $0, 8 49 | 50 | .globl CdGetToc # 009 51 | CdGetToc: 52 | j $31 53 | li $0, 9 54 | 55 | .globl CdSearchFile # 010 56 | CdSearchFile: 57 | j $31 58 | li $0, 10 59 | 60 | .globl CdSync # 011 61 | CdSync: 62 | j $31 63 | li $0, 11 64 | 65 | .globl CdGetDiskType # 012 66 | CdGetDiskType: 67 | j $31 68 | li $0, 12 69 | 70 | .globl CdDiskReady # 013 71 | CdDiskReady: 72 | j $31 73 | li $0, 13 74 | 75 | .globl CdTrayReq # 014 76 | CdTrayReq: 77 | j $31 78 | li $0, 14 79 | 80 | .globl CdStop # 015 81 | CdStop: 82 | j $31 83 | li $0, 15 84 | 85 | .globl CdPosToInt # 016 86 | CdPosToInt: 87 | j $31 88 | li $0, 16 89 | 90 | .globl CdIntToPos # 017 91 | CdIntToPos: 92 | j $31 93 | li $0, 17 94 | 95 | .globl CdCheckCmd # 021 96 | CdCheckCmd: 97 | j $31 98 | li $0, 21 99 | 100 | .globl CdReadClock # 024 101 | CdReadClock: 102 | j $31 103 | li $0, 24 104 | 105 | .globl CdStatus # 028 106 | CdStatus: 107 | j $31 108 | li $0, 28 109 | 110 | .globl CdCallback # 037 111 | CdCallback: 112 | j $31 113 | li $0, 37 114 | 115 | .globl CdPause # 038 116 | CdPause: 117 | j $31 118 | li $0, 38 119 | 120 | .globl CdBreak # 039 121 | CdBreak: 122 | j $31 123 | li $0, 39 124 | 125 | .globl CdGetReadPos # 044 126 | CdGetReadPos: 127 | j $31 128 | li $0, 44 129 | 130 | .globl CdReadChain # 066 131 | CdReadChain: 132 | j $31 133 | li $0, 66 134 | 135 | -------------------------------------------------------------------------------- /source.txt: -------------------------------------------------------------------------------- 1 | Notes about PSMS source: 2 | ------------------------ 3 | 4 | PSMS is a port of SMSPlus, the excellent SMS emulator by Charles 5 | Mac Donald. SMSPlus source code is distributed under the terms of 6 | the GNU General Public License. Since PSMS is a derivative of SMSPlus, 7 | PSMS source code is also distributed under the terms of the GNU 8 | General Public License. 9 | 10 | NOTE: PSMS uses other general-purpose free software modules which 11 | are NOT distributed under the terms of the GNU General Public 12 | License. These modules include: 13 | 14 | - Gfxpipe, by Vzzrzzn 15 | - ps2lib, by Gustavo Scotti and many others. 16 | 17 | ------------------------------------------------------------------- 18 | 19 | To compile, you will need an up-to-date cvs version of ps2lib and 20 | the ee toolchain (ee-gcc & ee-binutils). 21 | 22 | WARNING: The PS2 specific code is messy and un-optimised. My goal 23 | was not to produce efficent and easy to read code, just to produce 24 | working code. 25 | 26 | I hope people will learn from my code. Its a good example of how to 27 | quickly and easily port an emulator to the ps2, so hopefully people 28 | will learn from this example and start porting other emulators. 29 | 30 | Note that a few minor bugs have been discovered in PSMS, but I havent 31 | had time to fix them so they are still present in this source code. 32 | The *known* bugs are: 33 | 1) Rom filenames are not turned into capitals, which can cause problems 34 | if FILES.TXT has not been created properly. 35 | 2) The pad init code is badly designed, and it will cause the program to 36 | halt until one of the following conditions are met: a) No controller 37 | is inserted in port 1, or b) a dual-shock controller is insterted in 38 | port 1. 39 | 40 | SjPCM is considered to be a seperate program from PSMS. SjPCM ee-side 41 | source code is distributed under the terms of the GNU General Public 42 | License. IOP-side code will be released once I clean the src. 43 | 44 | Please contact me if you have any questions about the source code, or 45 | if you use parts of the source code in a project. 46 | 47 | - Sjeep 48 | 49 | ------------------------------------------------------------------- 50 | 51 | Legal 52 | ----- 53 | 54 | The PSMS source code is distributed under the terms of the GNU General 55 | Public License. 56 | 57 | The Z80 CPU emulator, SN76489 and YM3812 sound chip emulation, and SEAL 58 | interface code are taken from the MAME project, and terms of their use 59 | are covered under the MAME license. (http://www.mame.net) 60 | 61 | The YM2413 instrument parameter table is also taken from MAME. 62 | 63 | -------------------------------------------------------------------------------- /libcdvd/iop/cdvd_iop.h: -------------------------------------------------------------------------------- 1 | #ifndef _CDVD_IOP_H 2 | #define _CDVD_IOP_H 3 | 4 | #include "../common/cdvd.h" 5 | 6 | // Macros for READ Data pattan 7 | #define CdSecS2048 0 // sector size 2048 8 | #define CdSecS2328 1 // sector size 2328 9 | #define CdSecS2340 2 // sector size 2340 10 | 11 | // Macros for Spindle control 12 | #define CdSpinMax 0 13 | #define CdSpinNom 1 // Starts reading data at maximum rotational velocity and if a read error occurs, the rotational velocity is reduced. 14 | #define CdSpinStm 0 // Recommended stream rotation speed. 15 | 16 | typedef struct { 17 | u8 stat; // 0: normal. Any other: error 18 | u8 second; // second (BCD value) 19 | u8 minute; // minute (BCD value) 20 | u8 hour; // hour (BCD value) 21 | u8 week; // week (BCD value) 22 | u8 day; // day (BCD value) 23 | u8 month; // month (BCD value) 24 | u8 year; // year (BCD value) 25 | } CdCLOCK; 26 | 27 | typedef struct { 28 | u32 lsn; // Logical sector number of file 29 | u32 size; // File size (in bytes) 30 | char name[16]; // Filename 31 | u8 date[8]; // 1th: Seconds 32 | // 2th: Minutes 33 | // 3th: Hours 34 | // 4th: Date 35 | // 5th: Month 36 | // 6th 7th: Year (4 digits) 37 | } CdlFILE; 38 | 39 | typedef struct { 40 | u8 minute; // Minutes 41 | u8 second; // Seconds 42 | u8 sector; // Sector 43 | u8 track; // Track number 44 | } CdlLOCCD; 45 | 46 | typedef struct { 47 | u8 trycount; // Read try count (No. of error retries + 1) (0 - 255) 48 | u8 spindlctrl; // SCECdSpinStm: Recommended stream rotation speed. 49 | // SCECdSpinNom: Starts reading data at maximum rotational velocity and if a read error occurs, the rotational velocity is reduced. 50 | u8 datapattern; // SCECdSecS2048: Data size 2048 bytes 51 | // SCECdSecS2328: 2328 bytes 52 | // SCECdSecS2340: 2340 bytes 53 | u8 pad; // Padding data produced by alignment. 54 | } CdRMode; 55 | 56 | 57 | int CdBreak(void); 58 | int CdCallback( void (*func)() ); 59 | int CdDiskReady(int mode); 60 | int CdGetDiskType(void); 61 | int CdGetError(void); 62 | u32 CdGetReadPos(void); 63 | int CdGetToc(u8 *toc); 64 | int CdInit(int init_mode); 65 | CdlLOCCD *CdIntToPos(int i, CdlLOCCD *p); 66 | int CdPause(void); 67 | int CdPosToInt(CdlLOCCD *p); 68 | int CdRead(u32 lsn, u32 sectors, void *buf, CdRMode *mode); 69 | int CdReadClock(CdCLOCK *rtc); 70 | int CdSearchFile (CdlFILE *fp, const char *name); 71 | int CdSeek(u32 lsn); 72 | int CdStandby(void); 73 | int CdStatus(void); 74 | int CdStop(void); 75 | int CdSync(int mode); 76 | int CdTrayReq(int mode, u32 *traycnt); 77 | int CdFlushCache(void); 78 | unsigned int CdGetSize(void); 79 | 80 | #endif // _CDVD_H 81 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # _____ ___ ____ ___ ____ 2 | # ____| | ____| | | |____| 3 | # | ___| |____ ___| ____| | \ PS2DEV Open Source Project. 4 | #----------------------------------------------------------------------- 5 | # Copyright 2001-2004, ps2dev - http://www.ps2dev.org 6 | # Licenced under Academic Free License version 2.0 7 | # Review ps2sdk README & LICENSE files for further details. 8 | # 9 | 10 | EE_BIN = psms.elf 11 | EE_OBJS = sjpcm_rpc.o psms.o fmopl.o render.o sms.o sn76496.o system.o vdp.o ym2413.o z80.o browser/browser.o browser/cd.o browser/bdraw.o browser/font_uLE.o browser/init.o browser/pad.o browser/ps2font.o browser/cnfsettings.o browser/menu.o browser/Reboot_ELF.o irx/iomanX_irx.o irx/fileXio_irx.o irx/ps2dev9_irx.o irx/ps2atad_irx.o irx/ps2hdd_irx.o irx/ps2fs_irx.o irx/poweroff_irx.o irx/usbd_irx.o irx/cdvd_irx.o irx/usbhdfsd_irx.o irx/sjpcm_irx.o 12 | EE_CFLAGS += -DALIGN_DWORD -DLSB_FIRST 13 | EE_LDFLAGS += -L$(PS2DEV)/gskit/lib -L$(PS2DEV)/ps2sdk/ports/lib -s 14 | EE_LIBS += -lgskit -ldmakit -ljpeg -lpng -lz -lm -lfileXio -lhdd -lmc -lpadx -lpoweroff -lpatches -ldebug 15 | EE_INCS += -I./browser # -I. 16 | EE_INCS += -I$(PS2SDK)/sbv/include -I$(PS2SDK)/ports/include -I$(PS2DEV)/gsKit/include 17 | 18 | EE_INCS += -Ilibcdvd/ee 19 | EE_LDFLAGS += -Llibcdvd/lib 20 | EE_LIBS += -lcdvdfs 21 | 22 | IRX_DIR=$(PS2SDK)/iop/irx 23 | 24 | EE_PACKED_BIN = psms-packed.elf 25 | 26 | #.SUFFIXES: .c .s .cc .dsm 27 | 28 | all: create_irx $(EE_BIN) 29 | $(EE_STRIP) $(EE_BIN) 30 | ps2-packer $(EE_BIN) $(EE_PACKED_BIN) 31 | 32 | create_irx: 33 | mkdir -p irx 34 | 35 | ./irx/iomanX_irx.c: 36 | bin2c $(IRX_DIR)/iomanX.irx ./irx/iomanX_irx.c iomanX_irx 37 | 38 | ./irx/fileXio_irx.c: 39 | bin2c $(IRX_DIR)/fileXio.irx ./irx/fileXio_irx.c fileXio_irx 40 | 41 | ./irx/ps2dev9_irx.c: 42 | bin2c $(IRX_DIR)/ps2dev9.irx ./irx/ps2dev9_irx.c ps2dev9_irx 43 | 44 | ./irx/ps2atad_irx.c: 45 | bin2c $(IRX_DIR)/ps2atad.irx ./irx/ps2atad_irx.c ps2atad_irx 46 | 47 | ./irx/ps2hdd_irx.c: 48 | bin2c $(IRX_DIR)/ps2hdd.irx ./irx/ps2hdd_irx.c ps2hdd_irx 49 | 50 | ./irx/ps2fs_irx.c: 51 | bin2c $(IRX_DIR)/ps2fs.irx ./irx/ps2fs_irx.c ps2fs_irx 52 | 53 | ./irx/poweroff_irx.c: 54 | bin2c $(IRX_DIR)/poweroff.irx ./irx/poweroff_irx.c poweroff_irx 55 | 56 | ./irx/usbd_irx.c: 57 | bin2c $(IRX_DIR)/usbd.irx ./irx/usbd_irx.c usbd_irx 58 | 59 | ./irx/usbhdfsd_irx.c: 60 | bin2c $(IRX_DIR)/usbhdfsd.irx ./irx/usbhdfsd_irx.c usbhdfsd_irx 61 | 62 | ./irx/cdvd_irx.c: 63 | bin2c cdvd.irx ./irx/cdvd_irx.c cdvd_irx 64 | 65 | ./irx/sjpcm_irx.c: 66 | bin2c sjpcm.irx ./irx/sjpcm_irx.c sjpcm_irx 67 | 68 | 69 | clean: 70 | rm -f $(EE_BIN) $(EE_PACKED_BIN) $(EE_OBJS) ./irx/*.c 71 | 72 | run: $(EE_BIN) 73 | ps2client execee host:$(EE_BIN) 74 | 75 | reset: 76 | ps2client reset 77 | 78 | include $(PS2SDK)/samples/Makefile.pref 79 | include $(PS2SDK)/samples/Makefile.eeglobal 80 | 81 | -------------------------------------------------------------------------------- /system.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _SYSTEM_H_ 3 | #define _SYSTEM_H_ 4 | 5 | #define PALETTE_SIZE (0x20) 6 | 7 | /* Console / cartridge types */ 8 | #define TYPE_SMS (0) 9 | #define TYPE_GG (1) 10 | 11 | #define IS_GG (cart.type == TYPE_GG) 12 | #define IS_SMS (cart.type == TYPE_SMS) 13 | 14 | /* Macro to get offset to actual display within bitmap */ 15 | #define BMP_X_OFFSET ((cart.type == TYPE_GG) ? 48 : 0) 16 | #define BMP_Y_OFFSET ((cart.type == TYPE_GG) ? 24 : 0) 17 | 18 | #define BMP_WIDTH (IS_GG ? 160 : 256) 19 | #define BMP_HEIGHT (IS_GG ? 144 : 192) 20 | 21 | /* Mask for removing unused pixel data */ 22 | #define PIXEL_MASK (0x1F) 23 | 24 | /* These can be used for 'input.pad[]' */ 25 | #define INPUT_UP (0x00000001) 26 | #define INPUT_DOWN (0x00000002) 27 | #define INPUT_LEFT (0x00000004) 28 | #define INPUT_RIGHT (0x00000008) 29 | #define INPUT_BUTTON1 (0x00000010) 30 | #define INPUT_BUTTON2 (0x00000020) 31 | 32 | /* These can be used for 'input.system' */ 33 | #define INPUT_START (0x00000001) /* Game Gear only */ 34 | #define INPUT_PAUSE (0x00000002) /* Master System only */ 35 | #define INPUT_SOFT_RESET (0x00000004) /* Master System only */ 36 | #define INPUT_HARD_RESET (0x00000008) /* Works for either console type */ 37 | 38 | /* User input structure */ 39 | typedef struct 40 | { 41 | int pad[2]; 42 | int system; 43 | }t_input; 44 | 45 | /* Sound emulation structure */ 46 | typedef struct 47 | { 48 | int enabled; 49 | int bufsize; 50 | signed short *buffer[2]; 51 | signed short *fm_buffer; /* internal use only */ 52 | signed short *psg_buffer[2]; /* internal use only */ 53 | int log; 54 | void (*callback)(int data); 55 | }t_snd; 56 | 57 | /* Game image structure */ 58 | typedef struct 59 | { 60 | byte *rom; 61 | byte pages; 62 | byte type; 63 | }t_cart; 64 | 65 | /* Bitmap structure */ 66 | typedef struct 67 | { 68 | unsigned char *data; 69 | int width; 70 | int height; 71 | int pitch; 72 | int depth; 73 | struct 74 | { 75 | byte color[32][3]; 76 | byte dirty[32]; 77 | byte update; 78 | }pal; 79 | }t_bitmap; 80 | 81 | /* Global variables */ 82 | extern t_bitmap bitmap; /* Display bitmap */ 83 | extern t_snd snd; /* Sound streams */ 84 | extern t_cart cart; /* Game cartridge data */ 85 | extern t_input input; /* Controller input */ 86 | extern FM_OPL *ym3812; /* YM3812 emulator data */ 87 | 88 | /* Function prototypes */ 89 | void system_init(int rate); 90 | void system_shutdown(void); 91 | void system_reset(void); 92 | void system_load_sram(void); 93 | void system_save_state(void *fd); 94 | void system_load_state(void *fd); 95 | void audio_init(int rate); 96 | 97 | #endif /* _SYSTEM_H_ */ 98 | -------------------------------------------------------------------------------- /browser/pad.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static char padBuf[2][256] __attribute__((aligned(64))); 6 | 7 | u32 old_pad[2]; 8 | 9 | void waitPadReady(int port, int slot) { 10 | int state; 11 | int lastState; 12 | char stateString[16]; 13 | 14 | state = padGetState(port, slot); 15 | lastState = -1; 16 | while ((state != PAD_STATE_DISCONN) && (state != PAD_STATE_STABLE) 17 | && (state != PAD_STATE_FINDCTP1)) { 18 | if (state != lastState) { 19 | padStateInt2String(state, stateString); 20 | printf("Please wait, pad(%d,%d) is in state %s\n", port, slot, 21 | stateString); 22 | } 23 | lastState = state; 24 | state=padGetState(port, slot); 25 | if (port == 1) 26 | break; 27 | } 28 | // Were the pad ever 'out of sync'? 29 | if (lastState != -1) { 30 | printf("Pad OK!\n"); 31 | } 32 | } 33 | 34 | int initializePad(int port, int slot) { 35 | 36 | int ret; 37 | int modes; 38 | int i; 39 | 40 | waitPadReady(port, slot); 41 | 42 | // How many different modes can this device operate in? 43 | // i.e. get # entrys in the modetable 44 | modes = padInfoMode(port, slot, PAD_MODETABLE, -1); 45 | printf("The device has %d modes\n", modes); 46 | 47 | if (modes > 0) { 48 | printf("( "); 49 | for (i = 0; i < modes; i++) { 50 | printf("%d ", padInfoMode(port, slot, PAD_MODETABLE, i)); 51 | } 52 | printf(")"); 53 | } 54 | 55 | printf("It is currently using mode %d\n", padInfoMode(port, slot, 56 | PAD_MODECURID, 0)); 57 | 58 | // If modes == 0, this is not a Dual shock controller 59 | // (it has no actuator engines) 60 | if (modes == 0) { 61 | printf("This is a digital controller?\n"); 62 | return 1; 63 | } 64 | 65 | // Verify that the controller has a DUAL SHOCK mode 66 | i = 0; 67 | do { 68 | if (padInfoMode(port, slot, PAD_MODETABLE, i) == PAD_TYPE_DUALSHOCK) 69 | break; 70 | i++; 71 | } while (i < modes); 72 | if (i >= modes) { 73 | printf("This is no Dual Shock controller\n"); 74 | return 1; 75 | } 76 | 77 | // If ExId != 0x0 => This controller has actuator engines 78 | // This check should always pass if the Dual Shock test above passed 79 | ret = padInfoMode(port, slot, PAD_MODECUREXID, 0); 80 | if (ret == 0) { 81 | printf("This is no Dual Shock controller??\n"); 82 | return 1; 83 | } 84 | 85 | waitPadReady(port, slot); 86 | padSetMainMode(port, slot, PAD_MMODE_DUALSHOCK, PAD_MMODE_UNLOCK); 87 | 88 | return 1; 89 | } 90 | 91 | void setupPS2Pad() { 92 | int port; 93 | int slot = 0; 94 | int ret; 95 | 96 | for (port=0; port<2; port++) { 97 | if ((ret = padPortOpen(port, slot, padBuf[port])) == 0) { 98 | printf("padOpenPort failed: %d\n", ret); 99 | } else 100 | printf("padOpenPort success: %d\n", port); 101 | if (!initializePad(port, slot)) { 102 | printf("pad initalization failed!\n"); 103 | } else 104 | printf("pad initialization success!\n"); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /z80.h: -------------------------------------------------------------------------------- 1 | #ifndef Z80_H 2 | #define Z80_H 3 | 4 | //#define CLEAR_LINE 0 /* clear (a fired, held or pulsed) line */ 5 | //#define ASSERT_LINE 1 /* assert an interrupt immediately */ 6 | 7 | 8 | #include "cpuintrf.h" 9 | #include "osd_cpu.h" 10 | 11 | enum { 12 | Z80_PC=1, Z80_SP, Z80_AF, Z80_BC, Z80_DE, Z80_HL, 13 | Z80_IX, Z80_IY, Z80_AF2, Z80_BC2, Z80_DE2, Z80_HL2, 14 | Z80_R, Z80_I, Z80_IM, Z80_IFF1, Z80_IFF2, Z80_HALT, 15 | Z80_NMI_STATE, Z80_IRQ_STATE, Z80_DC0, Z80_DC1, Z80_DC2, Z80_DC3, 16 | Z80_NMI_NESTING 17 | }; 18 | 19 | extern int z80_ICount; /* T-state count */ 20 | 21 | #define Z80_IGNORE_INT -1 /* Ignore interrupt */ 22 | #define Z80_NMI_INT -2 /* Execute NMI */ 23 | #define Z80_IRQ_INT -1000 /* Execute IRQ */ 24 | 25 | /* Port number written to when entering/leaving HALT state */ 26 | #define Z80_HALT_PORT 0x10000 27 | 28 | extern void z80_reset (void *param); 29 | extern void z80_exit (void); 30 | extern int z80_execute(int cycles); 31 | extern void z80_burn(int cycles); 32 | extern unsigned z80_get_context (void *dst); 33 | extern void z80_set_context (void *src); 34 | extern unsigned z80_get_pc (void); 35 | extern void z80_set_pc (unsigned val); 36 | extern unsigned z80_get_sp (void); 37 | extern void z80_set_sp (unsigned val); 38 | extern unsigned z80_get_reg (int regnum); 39 | extern void z80_set_reg (int regnum, unsigned val); 40 | extern void z80_set_nmi_line(int state); 41 | extern void z80_set_irq_line(int irqline, int state); 42 | extern void z80_set_irq_callback(int (*irq_callback)(int)); 43 | extern void z80_state_save(void *file); 44 | extern void z80_state_load(void *file); 45 | extern const char *z80_info(void *context, int regnum); 46 | extern unsigned z80_dasm(char *buffer, unsigned pc); 47 | 48 | #ifdef MAME_DEBUG 49 | extern unsigned DasmZ80(char *buffer, unsigned pc); 50 | #endif 51 | 52 | /****************************************************************************/ 53 | /* The Z80 registers. HALT is set to 1 when the CPU is halted, the refresh */ 54 | /* register is calculated as follows: refresh=(Regs.R&127)|(Regs.R2&128) */ 55 | /****************************************************************************/ 56 | typedef struct { 57 | /* 00 */ PAIR PREPC,PC,SP,AF,BC,DE,HL,IX,IY; 58 | /* 24 */ PAIR AF2,BC2,DE2,HL2; 59 | /* 34 */ UINT8 R,R2,IFF1,IFF2,HALT,IM,I; 60 | /* 3B */ UINT8 irq_max; /* number of daisy chain devices */ 61 | /* 3C */ INT8 request_irq; /* daisy chain next request device */ 62 | /* 3D */ INT8 service_irq; /* daisy chain next reti handling device */ 63 | /* 3E */ UINT8 nmi_state; /* nmi line state */ 64 | /* 3F */ UINT8 irq_state; /* irq line state */ 65 | /* 40 */ UINT8 int_state[Z80_MAXDAISY]; 66 | /* 44 */ Z80_DaisyChain irq[Z80_MAXDAISY]; 67 | /* 84 */ int (*irq_callback)(int irqline); 68 | /* 88 */ int extra_cycles; /* extra cycles for interrupts */ 69 | } Z80_Regs; 70 | 71 | extern Z80_Regs *Z80_Context; 72 | extern int after_EI; 73 | extern unsigned char *cpu_readmap[8]; 74 | extern unsigned char *cpu_writemap[8]; 75 | 76 | #endif 77 | 78 | -------------------------------------------------------------------------------- /libcdvd/ee/cdvd_rpc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "cdvd_rpc.h" 8 | 9 | int k_sceSifDmaStat(unsigned int id); 10 | static unsigned sbuff[0x1300] __attribute__((aligned (64))); 11 | static SifRpcClientData_t cd0; 12 | 13 | int cdvd_inited = 0; 14 | 15 | int CDVD_Init() 16 | { 17 | int i; 18 | 19 | while(1){ 20 | if (SifBindRpc( &cd0, CDVD_IRX, 0) < 0) return -1; // bind error 21 | if (cd0.server != 0) break; 22 | i = 0x10000; 23 | while(i--); 24 | } 25 | 26 | cdvd_inited = 1; 27 | 28 | return 0; 29 | } 30 | 31 | int CDVD_DiskReady(int mode) 32 | { 33 | if(!cdvd_inited) return -1; 34 | 35 | sbuff[0] = mode; 36 | 37 | SifCallRpc(&cd0,CDVD_DISKREADY,0,(void*)(&sbuff[0]),4,(void*)(&sbuff[0]),4,0,0); 38 | 39 | return sbuff[0]; 40 | } 41 | 42 | int CDVD_FindFile(const char* fname, struct TocEntry* tocEntry) 43 | { 44 | if(!cdvd_inited) return -1; 45 | 46 | strncpy((char*)&sbuff,fname,1024); 47 | 48 | SifCallRpc(&cd0,CDVD_FINDFILE,0,(void*)(&sbuff[0]),1024,(void*)(&sbuff[0]),sizeof(struct TocEntry)+1024,0,0); 49 | 50 | memcpy(tocEntry, &sbuff[256], sizeof(struct TocEntry)); 51 | 52 | return sbuff[0]; 53 | } 54 | 55 | void CDVD_Stop() 56 | { 57 | if(!cdvd_inited) return; 58 | 59 | SifCallRpc(&cd0,CDVD_STOP,0,(void*)(&sbuff[0]),0,(void*)(&sbuff[0]),0,0,0); 60 | 61 | return; 62 | } 63 | 64 | int CDVD_TrayReq(int mode) 65 | { 66 | if(!cdvd_inited) return -1; 67 | 68 | SifCallRpc(&cd0,CDVD_TRAYREQ,0,(void*)(&sbuff[0]),4,(void*)(&sbuff[0]),4,0,0); 69 | 70 | return sbuff[0]; 71 | } 72 | 73 | int CDVD_GetDir(const char* pathname, const char* extensions, enum CDVD_getMode getMode, struct TocEntry tocEntry[], unsigned int req_entries, char* new_pathname) 74 | { 75 | unsigned int num_entries; 76 | 77 | if(!cdvd_inited) return -1; 78 | 79 | // copy the requested pathname to the rpc buffer 80 | strncpy((char*)sbuff,pathname,1023); 81 | 82 | // copy in the extension list to the rpc buffer 83 | if (extensions == NULL) 84 | { 85 | // Can't copy in the extension list since there isnt one, so just null the string in the rpc buffer 86 | sbuff[1024/4] = 0; 87 | } 88 | else 89 | { 90 | strncpy((char*)&sbuff[1024/4],extensions,127); 91 | } 92 | 93 | sbuff[1152/4] = getMode; 94 | 95 | sbuff[1156/4] = (int)tocEntry; 96 | 97 | sbuff[1160/4] = req_entries; 98 | 99 | SifWriteBackDCache(tocEntry, req_entries*sizeof(struct TocEntry)); 100 | 101 | // This will get the directory contents, and fill tocEntry via DMA 102 | SifCallRpc(&cd0,CDVD_GETDIR,0,(void*)(&sbuff[0]),1024+128+4+4+4,(void*)(&sbuff[0]),4+1024,0,0); 103 | 104 | num_entries = sbuff[0]; 105 | 106 | if (new_pathname != NULL) 107 | strncpy(new_pathname,(char*)&sbuff[1],1023); 108 | 109 | return (num_entries); 110 | } 111 | 112 | void CDVD_FlushCache() 113 | { 114 | if(!cdvd_inited) return; 115 | 116 | SifCallRpc(&cd0,CDVD_FLUSHCACHE,0,(void*)(&sbuff[0]),0,(void*)(&sbuff[0]),0,0,0); 117 | 118 | return; 119 | } 120 | 121 | unsigned int CDVD_GetSize() 122 | { 123 | if(!cdvd_inited) return -1; 124 | 125 | SifCallRpc(&cd0,CDVD_GETSIZE,0,(void*)(&sbuff[0]),0,(void*)(&sbuff[0]),4,0,0); 126 | 127 | return sbuff[0]; 128 | } 129 | -------------------------------------------------------------------------------- /cdinfo.txt: -------------------------------------------------------------------------------- 1 | CD Creation 2 | ----------- 3 | 4 | When PSMS boots, its looks for a file in the root directory of 5 | the cd called "FILES.TXT". This file contains a list of all the 6 | roms on the cd, and the actual game names for each of the roms. 7 | In order for PSMS to work correctly, FILES.TXT must be made 8 | correctly - dont expect PSMS to work right if you mess something 9 | up. You have two choices when it comes to making your FILES.TXT 10 | file: You can use a nice GUI app coded by Justice, or you can 11 | create it manually. If you want to use the GUI app, download 12 | from http://psms.gamebase.ca and follow the instructions 13 | included in the archive. If you want to create your FILES.TXT 14 | manually, follow the instructions below. 15 | 16 | ---------------------------------------------------------------- 17 | 18 | 1) Organise the intended directory tree of the CD on your hard disk. 19 | The CD must conform to the ISO9660 standard. This imposes several 20 | limitations on how you can create your cd. All filenames and 21 | directory names may consist ONLY of the following characters: 22 | 23 | A-Z (in upper case!!), 0-9, '_' 24 | 25 | Filenames must be in 8.3 format - ########.### (ALEXKIDD.SMS 26 | or SONIC.GG are valid 8.3 filenames). You may not have more 27 | than 30 files per directory, so if you have more than 30 roms 28 | you must span them accross several directories (ie, ROMS1\ 29 | ROMS2\ ROMS3\ - each of these dirs can hold up to 30 roms). 30 | 31 | Once you have the roms in the sorted out, place PSMS.ELF, SJPCM.IRX 32 | and SYSTEM.CNF so they will end up in the root directory of your CD. 33 | 34 | 2) Create the "FILES.TXT" file. This file accociates actual game 35 | names with filenames. You must use the full filenames realative 36 | to the root directory of the CD (ie, ROMS1\ALEXKIDD.SMS). The 37 | text file is set out as follows: 38 | 39 | Alex the Kidd,ROMS1\ALEXKIDD.SMS 40 | Asterix,ROMS2\ASTERIX.SMS 41 | California Games,ROMS3\CALIFGAM.SMS 42 | 43 | ... and so on. 44 | 45 | There must be a comma in-between the game name and filename. 46 | Make sure you press enter after the last entry (there must be a 47 | newline character after the last entry). 48 | 49 | There is currently a "bug" in the file reading code that PSMS 50 | uses - it can only read 16 bytes from a file at a time. If your 51 | file is NOT a multiple of 16 bytes, the last few characters will 52 | not be read. To fix this, pad the end of the file with spaces 53 | until it is a multiple of 16 byes. 54 | 55 | 3) Create a MODE 2 ISO with PSMS.ELF, SJPCM.IRX, FILES.TXT and 56 | SYSTEM.CNF in the root directory. Place the roms where you have 57 | specified in FILES.TXT (ie, if your FILES.TXT is set up like the 58 | example in step 2, place ROMS1\ ROMS2\ ROMS3\ in the root dir of 59 | your ISO). Make sure your CD writing software creates and burns 60 | the ISO with the correct settings. These are: 61 | 62 | - ISO9660 level 1 filesystem 63 | - ISO9660 character set 64 | - Joliet DISABLED 65 | - ISO9660 relaxations DISABLED 66 | 67 | You may also need to patch your image, depending on your booting 68 | method (some versions of AR/GS require SYSTEM.CNF to be at a 69 | certain location on the CD). 70 | 71 | Burn your ISO, and if you have set it up properly, ENJOY! 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PSMS Reloaded New 2 | Fork of PSMS Reloaded - Sega Master System & Game Gear emulator for PS2. 3 | 4 | [Download](https://github.com/infval/PSMS-Reloaded-New/releases) binary release (ELF file). 5 | 6 | Original PSMS Reloaded: http://www.brunofreitas.com/node/25. 7 | 8 | ## Controls 9 | ### In-game 10 | 11 | Action | Button | Action | Button | Action | Button 12 | ------ | :----: | ------ | :----: | ------ | :----: 13 | Button 1 | ![Square](https://user-images.githubusercontent.com/38145742/38648065-120deeb8-3df8-11e8-984b-cccab8dd4622.png) | `---` | ![Select](https://user-images.githubusercontent.com/38145742/38648134-65d593ca-3df8-11e8-9926-44357e5c44cd.png) | Pause/Start | ![Start](https://user-images.githubusercontent.com/38145742/38648145-717997d0-3df8-11e8-99b0-f98a75fc682b.png) 14 | Button 2 | ![Cross](https://user-images.githubusercontent.com/38145742/38648019-e30fd27a-3df7-11e8-8e6b-660cdf65b9f6.png) | Menu | ![L1](https://user-images.githubusercontent.com/38145742/38646430-9b548400-3df0-11e8-9158-e6d77afd2115.png) | `---` | ![R1](https://user-images.githubusercontent.com/38145742/38648091-2a2bbe76-3df8-11e8-9894-c53092ee8557.png) 15 | Turbo 1 | ![Triangle](https://user-images.githubusercontent.com/38145742/38646514-f0d0f2ec-3df0-11e8-9ff6-968a9f43ba9b.png) | `---` | ![L2](https://user-images.githubusercontent.com/38145742/38648101-3684328e-3df8-11e8-83b6-a17a6bb076a9.png) | `---` | ![R2](https://user-images.githubusercontent.com/38145742/38648109-4039008e-3df8-11e8-9171-1b6bacb38091.png) 16 | Turbo 2 | ![Circle](https://user-images.githubusercontent.com/38145742/38646507-eef3b536-3df0-11e8-8057-c4f8dd361eba.png) | `---` | ![L3](https://user-images.githubusercontent.com/38145742/38648117-4e97d3d0-3df8-11e8-9278-bc95530fad35.png) | `---` | ![R3](https://user-images.githubusercontent.com/38145742/38648122-5b92778e-3df8-11e8-82ea-2eadfcd8764a.png) 17 | 18 | D-pad: D-pad or Analog stick 19 | ### Browser 20 | 21 | Action | Button | Action | Button | Action | Button 22 | ------ | :----: | ------ | :----: | ------ | :----: 23 | `---` | ![Square](https://user-images.githubusercontent.com/38145742/38648065-120deeb8-3df8-11e8-984b-cccab8dd4622.png) | Options | ![Select](https://user-images.githubusercontent.com/38145742/38648134-65d593ca-3df8-11e8-9926-44357e5c44cd.png) | Confirm: save path,
center screen | ![Start](https://user-images.githubusercontent.com/38145742/38648145-717997d0-3df8-11e8-99b0-f98a75fc682b.png) 24 | OK | ![Cross](https://user-images.githubusercontent.com/38145742/38648019-e30fd27a-3df7-11e8-8e6b-660cdf65b9f6.png) | Options | ![L1](https://user-images.githubusercontent.com/38145742/38646430-9b548400-3df0-11e8-9158-e6d77afd2115.png) | `---` | ![R1](https://user-images.githubusercontent.com/38145742/38648091-2a2bbe76-3df8-11e8-9894-c53092ee8557.png) 25 | Back | ![Triangle](https://user-images.githubusercontent.com/38145742/38646514-f0d0f2ec-3df0-11e8-9ff6-968a9f43ba9b.png) | `---` | ![L2](https://user-images.githubusercontent.com/38145742/38648101-3684328e-3df8-11e8-83b6-a17a6bb076a9.png) | `---` | ![R2](https://user-images.githubusercontent.com/38145742/38648109-4039008e-3df8-11e8-9171-1b6bacb38091.png) 26 | `---` | ![Circle](https://user-images.githubusercontent.com/38145742/38646507-eef3b536-3df0-11e8-8057-c4f8dd361eba.png) | `---` | ![L3](https://user-images.githubusercontent.com/38145742/38648117-4e97d3d0-3df8-11e8-9278-bc95530fad35.png) | `---` | ![R3](https://user-images.githubusercontent.com/38145742/38648122-5b92778e-3df8-11e8-82ea-2eadfcd8764a.png) 27 | 28 | D-pad: D-pad 29 | ## Dependencies 30 | * https://github.com/ps2dev/ps2sdk (use [ps2toolchain](https://github.com/ps2dev/ps2toolchain)) 31 | * https://github.com/ps2dev/gsKit 32 | * https://github.com/ps2dev/ps2sdk-ports (libjpeg, libpng, libz) 33 | * https://github.com/ps2dev/ps2-packer (optinal) 34 | -------------------------------------------------------------------------------- /browser/cd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "cd.h" 8 | 9 | #define CD_SERVER_INIT 0x80000592 10 | #define CD_SERVER_SCMD 0x80000593 11 | #define CD_SCMD_GETDISCTYPE 0x03 12 | 13 | SifRpcClientData_t clientInit __attribute__ ((aligned(64))); 14 | u32 initMode __attribute__ ((aligned(64))); 15 | s32 cdThreadId = 0; 16 | s32 bindSearchFile = -1; 17 | s32 bindDiskReady = -1; 18 | s32 bindInit = -1; 19 | s32 bindNCmd = -1; 20 | s32 bindSCmd = -1; 21 | s32 nCmdSemaId = -1; // n-cmd semaphore id 22 | s32 sCmdSemaId = -1; // s-cmd semaphore id 23 | s32 callbackSemaId = -1; // callback semaphore id 24 | s32 cdDebug = 0; 25 | s32 sCmdNum = 0; 26 | SifRpcClientData_t clientSCmd __attribute__ ((aligned(64))); 27 | u8 sCmdRecvBuff[48] __attribute__ ((aligned(64))); 28 | volatile s32 cbSema = 0; 29 | ee_thread_status_t cdThreadParam; 30 | s32 callbackThreadId = 0; 31 | volatile s32 cdCallbackNum __attribute__ ((aligned(64))); 32 | 33 | void cdSemaInit(void); 34 | s32 cdCheckSCmd(s32 cur_cmd); 35 | s32 cdSyncS(s32 mode); 36 | void cdSemaExit(void); 37 | 38 | s32 cdInit(s32 mode) 39 | { 40 | s32 i; 41 | 42 | if (cdSyncS(1)) 43 | return 0; 44 | SifInitRpc(0); 45 | cdThreadId = GetThreadId(); 46 | bindSearchFile = -1; 47 | bindNCmd = -1; 48 | bindSCmd = -1; 49 | bindDiskReady = -1; 50 | bindInit = -1; 51 | 52 | while (1) { 53 | if (SifBindRpc(&clientInit, CD_SERVER_INIT, 0) >= 0) 54 | if (clientInit.server != 0) break; 55 | i = 0x10000; 56 | while (i--); 57 | } 58 | 59 | bindInit = 0; 60 | initMode = mode; 61 | SifWriteBackDCache(&initMode, 4); 62 | if (SifCallRpc(&clientInit, 0, 0, &initMode, 4, 0, 0, 0, 0) < 0) 63 | return 0; 64 | if (mode == CDVD_INIT_EXIT) { 65 | cdSemaExit(); 66 | nCmdSemaId = -1; 67 | sCmdSemaId = -1; 68 | callbackSemaId = -1; 69 | } else { 70 | cdSemaInit(); 71 | } 72 | return 1; 73 | } 74 | 75 | void cdSemaExit(void) 76 | { 77 | if (callbackThreadId) { 78 | cdCallbackNum = -1; 79 | SignalSema(callbackSemaId); 80 | } 81 | DeleteSema(nCmdSemaId); 82 | DeleteSema(sCmdSemaId); 83 | DeleteSema(callbackSemaId); 84 | } 85 | 86 | void cdSemaInit(void) 87 | { 88 | struct t_ee_sema semaParam; 89 | 90 | // return if both semaphores are already inited 91 | if (nCmdSemaId != -1 && sCmdSemaId != -1) 92 | return; 93 | 94 | semaParam.init_count = 1; 95 | semaParam.max_count = 1; 96 | semaParam.option = 0; 97 | nCmdSemaId = CreateSema(&semaParam); 98 | sCmdSemaId = CreateSema(&semaParam); 99 | 100 | semaParam.init_count = 0; 101 | callbackSemaId = CreateSema(&semaParam); 102 | 103 | cbSema = 0; 104 | } 105 | 106 | s32 cdCheckSCmd(s32 cur_cmd) 107 | { 108 | s32 i; 109 | cdSemaInit(); 110 | if (PollSema(sCmdSemaId) != sCmdSemaId) { 111 | if (cdDebug > 0) 112 | printf("Scmd fail sema cur_cmd:%d keep_cmd:%d\n", cur_cmd, sCmdNum); 113 | return 0; 114 | } 115 | sCmdNum = cur_cmd; 116 | ReferThreadStatus(cdThreadId, &cdThreadParam); 117 | if (cdSyncS(1)) { 118 | SignalSema(sCmdSemaId); 119 | return 0; 120 | } 121 | 122 | SifInitRpc(0); 123 | if (bindSCmd >= 0) 124 | return 1; 125 | while (1) { 126 | if (SifBindRpc(&clientSCmd, CD_SERVER_SCMD, 0) < 0) { 127 | if (cdDebug > 0) 128 | printf("Libcdvd bind err S cmd\n"); 129 | } 130 | if (clientSCmd.server != 0) 131 | break; 132 | 133 | i = 0x10000; 134 | while (i--) 135 | ; 136 | } 137 | 138 | bindSCmd = 0; 139 | return 1; 140 | } 141 | 142 | s32 cdSyncS(s32 mode) 143 | { 144 | if (mode == 0) { 145 | if (cdDebug > 0) 146 | printf("S cmd wait\n"); 147 | while (SifCheckStatRpc(&clientSCmd)) 148 | ; 149 | return 0; 150 | } 151 | return SifCheckStatRpc(&clientSCmd); 152 | } 153 | 154 | CdvdDiscType_t cdGetDiscType(void) 155 | { 156 | if (cdCheckSCmd(CD_SCMD_GETDISCTYPE) == 0) 157 | return 0; 158 | 159 | if (SifCallRpc(&clientSCmd, CD_SCMD_GETDISCTYPE, 0, 0, 0, sCmdRecvBuff, 4, 0, 0) < 0) { 160 | SignalSema(sCmdSemaId); 161 | return 0; 162 | } 163 | 164 | SignalSema(sCmdSemaId); 165 | return *(s32 *) UNCACHED_SEG(sCmdRecvBuff); 166 | } 167 | -------------------------------------------------------------------------------- /sjpcm_rpc.c: -------------------------------------------------------------------------------- 1 | /* 2 | --------------------------------------------------------------------- 3 | sjpcm_rpc.c - SjPCM EE-side code. (c) Nick Van Veen (aka Sjeep), 2002 4 | --------------------------------------------------------------------- 5 | 6 | This file is part of the SjPCM. 7 | 8 | SjPCM is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | SjPCM is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with Foobar; if not, write to the Free Software 20 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 | 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "sjpcm.h" 32 | 33 | static unsigned sbuff[64] __attribute__((aligned (64))); 34 | static SifRpcClientData_t cd0; 35 | 36 | int sjpcm_inited = 0; 37 | int pcmbufl, pcmbufr; 38 | int bufpos; 39 | 40 | void SjPCM_Puts(char *format, ...) 41 | { 42 | static char buff[4096]; 43 | va_list args; 44 | int rv; 45 | 46 | if(!sjpcm_inited) return; 47 | 48 | va_start(args, format); 49 | rv = vsnprintf(buff, 4096, format, args); 50 | 51 | memcpy((char*)(&sbuff[0]),buff,252); 52 | SifCallRpc(&cd0,SJPCM_PUTS,0,(void*)(&sbuff[0]),252,(void*)(&sbuff[0]),252,0,0); 53 | } 54 | 55 | void SjPCM_Play() 56 | { 57 | if(!sjpcm_inited) return; 58 | 59 | SifCallRpc(&cd0,SJPCM_PLAY,0,(void*)(&sbuff[0]),0,(void*)(&sbuff[0]),0,0,0); 60 | } 61 | 62 | void SjPCM_Pause() 63 | { 64 | if(!sjpcm_inited) return; 65 | 66 | SifCallRpc(&cd0,SJPCM_PAUSE,0,(void*)(&sbuff[0]),0,(void*)(&sbuff[0]),0,0,0); 67 | } 68 | 69 | void SjPCM_Setvol(unsigned int volume) 70 | { 71 | if(!sjpcm_inited) return; 72 | 73 | sbuff[5] = volume&0x3fff; 74 | SifCallRpc(&cd0,SJPCM_SETVOL,0,(void*)(&sbuff[0]),64,(void*)(&sbuff[0]),64,0,0); 75 | } 76 | 77 | void SjPCM_Clearbuff() 78 | { 79 | if(!sjpcm_inited) return; 80 | 81 | SifCallRpc(&cd0,SJPCM_CLEARBUFF,0,(void*)(&sbuff[0]),0,(void*)(&sbuff[0]),0,0,0); 82 | } 83 | 84 | int SjPCM_Init() 85 | { 86 | int i; 87 | /* 88 | do { 89 | if (SifBindRpc(&cd0, SJPCM_IRX, 0) < 0) { 90 | return -1; 91 | } 92 | nopdelay(); 93 | } while(!cd0.server); 94 | */ 95 | while(1){ 96 | if (SifBindRpc( &cd0, SJPCM_IRX, 0) < 0) return -1; // bind error 97 | if (cd0.server != 0) break; 98 | i = 0x10000; 99 | while(i--); 100 | } 101 | 102 | SifCallRpc(&cd0,SJPCM_INIT,0,(void*)(&sbuff[0]),64,(void*)(&sbuff[0]),64,0,0); 103 | 104 | FlushCache(0); 105 | 106 | pcmbufl = sbuff[1]; 107 | pcmbufr = sbuff[2]; 108 | bufpos = sbuff[3]; 109 | 110 | sjpcm_inited = 1; 111 | 112 | return 0; 113 | } 114 | 115 | // size should either be either 800 (NTSC) or 960 (PAL) 116 | void SjPCM_Enqueue(short *left, short *right, int size, int wait) 117 | { 118 | int i; 119 | SifDmaTransfer_t sdt; 120 | 121 | if (!sjpcm_inited) return; 122 | 123 | sdt.src = (void *)left; 124 | sdt.dest = (void *)(pcmbufl + bufpos); 125 | sdt.size = size*2; 126 | sdt.attr = 0; 127 | 128 | FlushCache(0); 129 | 130 | i = SifSetDma(&sdt, 1); // start dma transfer 131 | while ((wait != 0) && (SifDmaStat(i) >= 0)); // wait for completion of dma transfer 132 | 133 | sdt.src = (void *)right; 134 | sdt.dest = (void *)(pcmbufr + bufpos); 135 | sdt.size = size*2; 136 | sdt.attr = 0; 137 | 138 | FlushCache(0); 139 | 140 | i = SifSetDma(&sdt, 1); 141 | while ((wait != 0) && (SifDmaStat(i) >= 0)); 142 | 143 | sbuff[0] = size; 144 | SifCallRpc(&cd0,SJPCM_ENQUEUE,0,(void*)(&sbuff[0]),64,(void*)(&sbuff[0]),64,0,0); 145 | bufpos = sbuff[3]; 146 | 147 | } 148 | -------------------------------------------------------------------------------- /browser/bdraw.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "browser.h" 5 | #include "ps2font.h" 6 | 7 | #include "browser/bdraw.h" 8 | 9 | extern skin FCEUSkin; 10 | extern vars Settings; 11 | extern GSGLOBAL *gsGlobal; 12 | extern u8 menutex; 13 | extern u8 bgtex; 14 | 15 | static int VCK; 16 | 17 | int FONT_HEIGHT = 16; 18 | int FONT_WIDTH = 8; 19 | 20 | void menu_bgtexture(GSTEXTURE *gsTexture, float x1, float y1, float x2, 21 | float y2, int z) { 22 | int thickness = 3; 23 | 24 | //border 25 | gsKit_prim_sprite(gsGlobal, x1, y1, x2, y1+thickness, z, FCEUSkin.frame); //top 26 | gsKit_prim_sprite(gsGlobal, x1, y1, x1+thickness, y2, z, FCEUSkin.frame); //left 27 | gsKit_prim_sprite(gsGlobal, x2-thickness, y1, x2, y2, z, FCEUSkin.frame); //right 28 | gsKit_prim_sprite(gsGlobal, x1, y2-thickness, x2, y2, z, FCEUSkin.frame); //bottom 29 | 30 | gsKit_prim_sprite_texture( gsGlobal, gsTexture, 31 | x1+thickness, /* X1 */ 32 | y1+thickness, /* Y1 */ 33 | 0.0f, /* U1 */ 34 | 0.0f, /* V1 */ 35 | x2-thickness, /* X2 */ 36 | y2-thickness, /* Y2 */ 37 | gsTexture->Width, /* U2 */ 38 | gsTexture->Height, /* V2*/ 39 | z+1, /* Z */ 40 | GS_SETREG_RGBA(0x80,0x80,0x80,0x80) /* RGBA */ 41 | ); 42 | } 43 | 44 | void DrawScreen(GSGLOBAL *gsGlobal) 45 | { 46 | int i; 47 | 48 | i = 0x10000; 49 | while(i--) asm("nop\nnop\nnop\nnop"); 50 | 51 | gsKit_sync_flip(gsGlobal); 52 | 53 | gsKit_queue_exec(gsGlobal); 54 | } 55 | 56 | 57 | void menu_background(float x1, float y1, float x2, float y2, int z) { 58 | int thickness = 3; 59 | 60 | //border 61 | gsKit_prim_sprite(gsGlobal, x1, y1, x2, y1+thickness, z, FCEUSkin.frame); //top 62 | gsKit_prim_sprite(gsGlobal, x1, y1, x1+thickness, y2, z, FCEUSkin.frame); //left 63 | gsKit_prim_sprite(gsGlobal, x2-thickness, y1, x2, y2, z, FCEUSkin.frame); //right 64 | gsKit_prim_sprite(gsGlobal, x1, y2-thickness, x2, y2, z, FCEUSkin.frame); //bottom 65 | 66 | //background 67 | gsKit_prim_quad_gouraud(gsGlobal, x1+thickness, y1+thickness, 68 | x2-thickness, y1+thickness, 69 | x1+thickness, y2-thickness, 70 | x2-thickness, y2-thickness, 71 | z+1, 72 | FCEUSkin.bgColor1, FCEUSkin.bgColor2, 73 | FCEUSkin.bgColor3, FCEUSkin.bgColor4); 74 | 75 | } 76 | 77 | 78 | 79 | void browser_primitive(char *title1, char *title2, GSTEXTURE *gsTexture, 80 | float x1, float y1, float x2, float y2) { 81 | 82 | if (!menutex || !bgtex) { 83 | menu_bgtexture(gsTexture, x1, y1, x2, y2, 1); 84 | } else { 85 | menu_background(x1, y1, x2, y2, 1); 86 | } 87 | menu_background(x1, y1, x1+(strlen(title1)*9), y1+FONT_HEIGHT*2, 2); 88 | menu_background(x2-(strlen(title2)*12), y1, x2, y1+FONT_HEIGHT*2, 2); 89 | 90 | printXY(title1, x1+(strlen(title2)+4), y1+FONT_HEIGHT/2, 3, 91 | FCEUSkin.textcolor, 2, 0); 92 | printXY(title2, x2-(strlen(title2)*10), y1+FONT_HEIGHT/2, 3, 93 | FCEUSkin.textcolor, 2, 0); 94 | } 95 | 96 | 97 | 98 | void init_custom_screen(void) { 99 | 100 | if (Settings.display) { 101 | gsGlobal->Mode = GS_MODE_PAL; 102 | gsGlobal->Height = 512; 103 | VCK = 4; 104 | } else { 105 | gsGlobal->Mode = GS_MODE_NTSC; 106 | gsGlobal->Height = 448; 107 | VCK = 4; 108 | } 109 | 110 | if (!Settings.interlace) { 111 | gsGlobal->Interlace = GS_NONINTERLACED; 112 | gsGlobal->Field = GS_FRAME; 113 | VCK = 2; 114 | } 115 | 116 | gsKit_vram_clear(gsGlobal); 117 | gsKit_init_screen(gsGlobal); 118 | SetDisplayOffset(); 119 | gsKit_mode_switch(gsGlobal, GS_ONESHOT); 120 | } 121 | 122 | 123 | void SetupGSKit(void) { 124 | /* detect and set screentype */ 125 | if (gsGlobal != NULL) gsKit_deinit_global(gsGlobal); 126 | gsGlobal = gsKit_init_global(); 127 | 128 | /* initialize dmaKit */ 129 | //dmaKit_init(D_CTRL_RELE_OFF,D_CTRL_MFD_OFF, D_CTRL_STS_UNSPEC, D_CTRL_STD_OFF, D_CTRL_RCYC_8); 130 | dmaKit_init(D_CTRL_RELE_OFF, D_CTRL_MFD_OFF, D_CTRL_STS_UNSPEC, 131 | D_CTRL_STD_OFF, D_CTRL_RCYC_8, 1 << DMA_CHANNEL_GIF); 132 | 133 | dmaKit_chan_init(DMA_CHANNEL_GIF); 134 | dmaKit_chan_init(DMA_CHANNEL_FROMSPR); 135 | dmaKit_chan_init(DMA_CHANNEL_TOSPR); 136 | 137 | gsGlobal->DoubleBuffering = GS_SETTING_OFF; 138 | gsGlobal->ZBuffering = GS_SETTING_OFF; 139 | 140 | //640x448, ntsc, tv 141 | //640x512, pal, tv 142 | } 143 | 144 | void SetDisplayOffset(void) 145 | { 146 | gsKit_set_display_offset(gsGlobal, Settings.offset_x * VCK, Settings.offset_y); 147 | } 148 | -------------------------------------------------------------------------------- /browser/init.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "cdvd_rpc.h" 12 | #include "cd.h" 13 | #include 14 | 15 | extern void poweroff_irx; 16 | extern int size_poweroff_irx; 17 | extern void iomanX_irx; 18 | extern int size_iomanX_irx; 19 | extern void fileXio_irx; 20 | extern int size_fileXio_irx; 21 | extern void ps2dev9_irx; 22 | extern int size_ps2dev9_irx; 23 | extern void ps2atad_irx; 24 | extern int size_ps2atad_irx; 25 | extern void ps2hdd_irx; 26 | extern int size_ps2hdd_irx; 27 | extern void ps2fs_irx; 28 | extern int size_ps2fs_irx; 29 | extern void usbd_irx; 30 | extern int size_usbd_irx; 31 | extern void usbhdfsd_irx; 32 | extern int size_usbhdfsd_irx; 33 | extern void cdvd_irx; 34 | extern int size_cdvd_irx; 35 | extern void sjpcm_irx; 36 | extern int size_sjpcm_irx; 37 | 38 | void poweroffps2(int i) 39 | { 40 | poweroffShutdown(); 41 | } 42 | 43 | void LoadHDDModules(void) 44 | { 45 | int ret; 46 | smod_mod_info_t mod_t; 47 | 48 | if(!smod_get_mod_by_name("Poweroff_Handler", &mod_t)) 49 | ret = SifExecModuleBuffer(&poweroff_irx, size_poweroff_irx, 0, NULL, &ret); 50 | if (ret < 0) { 51 | printf("Failed to load module: POWEROFF.IRX"); 52 | } 53 | poweroffInit(); 54 | poweroffSetCallback((void *)poweroffps2, NULL); 55 | if(!smod_get_mod_by_name("IOX/File_Manager", &mod_t)) 56 | ret = SifExecModuleBuffer(&iomanX_irx, size_iomanX_irx,0, NULL, &ret); 57 | if (ret < 0) { 58 | printf("Failed to load module: IOMANX.IRX"); 59 | } 60 | if(!smod_get_mod_by_name("IOX/File_Manager_Rpc", &mod_t)) 61 | ret = SifExecModuleBuffer(&fileXio_irx, size_fileXio_irx,0, NULL, &ret); 62 | if (ret < 0) { 63 | printf("Failed to load module: IOMANX.IRX"); 64 | } 65 | if(!smod_get_mod_by_name("dev9_driver", &mod_t)) 66 | ret = SifExecModuleBuffer(&ps2dev9_irx, size_ps2dev9_irx,0, NULL, &ret); 67 | if (ret < 0) { 68 | printf("Failed to load module: PS2DEV9.IRX"); 69 | } 70 | if(!smod_get_mod_by_name("atad", &mod_t)) 71 | ret = SifExecModuleBuffer(&ps2atad_irx, size_ps2atad_irx,0, NULL, &ret); 72 | if (ret < 0) { 73 | printf("Failed to load module: PS2ATAD.IRX"); 74 | } 75 | static char hddarg[] = "-o" "\0" "4" "\0" "-n" "\0" "20"; 76 | if(!smod_get_mod_by_name("hdd_driver", &mod_t)) 77 | ret = SifExecModuleBuffer(&ps2hdd_irx, size_ps2hdd_irx,sizeof(hddarg), hddarg, &ret); 78 | if (ret < 0) { 79 | printf("Failed to load module: PS2HDD.IRX"); 80 | } 81 | static char pfsarg[] = "-m" "\0" "4" "\0" "-o" "\0" "10" "\0" "-n" "\0" "40"; 82 | if(!smod_get_mod_by_name("pfs_driver", &mod_t)) 83 | ret = SifExecModuleBuffer(&ps2fs_irx, size_ps2fs_irx,sizeof(pfsarg), pfsarg, &ret); 84 | if (ret < 0) { 85 | printf("Failed to load module: PS2FS.IRX"); 86 | } 87 | } 88 | 89 | int LoadBasicModules(void) { 90 | int ret = 0, old = 0; 91 | 92 | smod_mod_info_t mod_t; 93 | 94 | if (!smod_get_mod_by_name("sio2man", &mod_t)) { 95 | ret = SifLoadModule("rom0:XSIO2MAN", 0, NULL); 96 | } 97 | if (mod_t.version == 257) 98 | old = 1; 99 | if (ret < 0) { 100 | printf("Failed to load module: SIO2MAN"); 101 | } 102 | if (!smod_get_mod_by_name("mcman", &mod_t)) { 103 | ret = SifLoadModule("rom0:XMCMAN", 0, NULL); 104 | } 105 | if (mod_t.version == 257) 106 | old = 1; 107 | if (ret < 0) { 108 | printf("Failed to load module: MCMAN"); 109 | } 110 | if (!smod_get_mod_by_name("mcserv", &mod_t)) { 111 | ret = SifLoadModule("rom0:XMCSERV", 0, NULL); 112 | } 113 | if (mod_t.version == 257) 114 | old = 1; 115 | else 116 | mcReset(); 117 | if (ret < 0) { 118 | printf("Failed to load module: MCSERV"); 119 | } 120 | if (!smod_get_mod_by_name("padman", &mod_t)) { 121 | ret = SifLoadModule("rom0:XPADMAN", 0, NULL); 122 | } 123 | if (mod_t.version == 276) 124 | old = 1; 125 | else 126 | padReset(); 127 | if (ret < 0) { 128 | printf("Failed to load module: PADMAN"); 129 | } 130 | 131 | return old; 132 | } 133 | void LoadExtraModules(void) { 134 | int i, ret, sometime; 135 | 136 | ret = SifLoadModule("rom0:LIBSD", 0, NULL); 137 | if (ret < 0) { 138 | printf("Failed to load module: LIBSD"); 139 | } 140 | ret = SifExecModuleBuffer(&sjpcm_irx, size_sjpcm_irx,0, NULL, &ret); 141 | if (ret < 0) { 142 | printf("Failed to load module: SJPCM.IRX"); 143 | } 144 | 145 | ret = SifExecModuleBuffer(&usbd_irx, size_usbd_irx, 0, NULL, &ret); 146 | if (ret < 0) { 147 | printf("Failed to load module: USBD.IRX"); 148 | } 149 | 150 | ret = SifExecModuleBuffer(&cdvd_irx, size_cdvd_irx, 0, NULL, &ret); 151 | if (ret < 0) { 152 | printf("Failed to load module: CDVD.IRX"); 153 | } 154 | 155 | ret = SifExecModuleBuffer(&usbhdfsd_irx, size_usbhdfsd_irx, 0, NULL, &ret); 156 | for (i = 0; i < 3; i++) { //taken from ulaunchelf 157 | sometime = 0x01000000; 158 | while (sometime--) 159 | asm("nop\nnop\nnop\nnop"); 160 | } 161 | 162 | if (ret < 0) { 163 | printf("Failed to load module: USBHDFSD.IRX"); 164 | } 165 | } 166 | 167 | void InitPS2(void) { 168 | SifInitRpc(0); 169 | 170 | //Reset IOP borrowed from uLaunchelf 171 | 172 | if (LoadBasicModules()) { 173 | SifIopReset("rom0:UDNL rom0:EELOADCNF", 0); 174 | while (!SifIopSync()); 175 | fioExit(); 176 | SifExitIopHeap(); 177 | SifLoadFileExit(); 178 | SifExitRpc(); 179 | SifExitCmd(); 180 | 181 | SifInitRpc(0); 182 | FlushCache(0); 183 | FlushCache(2); 184 | 185 | LoadBasicModules(); 186 | } 187 | 188 | sbv_patch_enable_lmb(); 189 | sbv_patch_disable_prefix_check(); 190 | 191 | LoadExtraModules(); 192 | LoadHDDModules(); 193 | 194 | mcInit(MC_TYPE_XMC); 195 | cdInit(CDVD_INIT_INIT); 196 | CDVD_Init(); 197 | 198 | padInit(0); 199 | } 200 | -------------------------------------------------------------------------------- /fmopl.h: -------------------------------------------------------------------------------- 1 | #ifndef __FMOPL_H_ 2 | #define __FMOPL_H_ 3 | 4 | typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec); 5 | typedef void (*OPL_IRQHANDLER)(int param,int irq); 6 | typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us); 7 | typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data); 8 | typedef unsigned char (*OPL_PORTHANDLER_R)(int param); 9 | 10 | /* !!!!! here is private section , do not access there member direct !!!!! */ 11 | 12 | #define OPL_TYPE_WAVESEL 0x01 /* waveform select */ 13 | #define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */ 14 | #define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */ 15 | #define OPL_TYPE_IO 0x08 /* I/O port */ 16 | 17 | /* ---------- OPL one of slot ---------- */ 18 | typedef struct fm_opl_slot { 19 | INT32 TL; /* total level :TL << 8 */ 20 | INT32 TLL; /* adjusted now TL */ 21 | UINT8 KSR; /* key scale rate :(shift down bit) */ 22 | INT32 *AR; /* attack rate :&AR_TABLE[AR<<2] */ 23 | INT32 *DR; /* decay rate :&DR_TALBE[DR<<2] */ 24 | INT32 SL; /* sustin level :SL_TALBE[SL] */ 25 | INT32 *RR; /* release rate :&DR_TABLE[RR<<2] */ 26 | UINT8 ksl; /* keyscale level :(shift down bits) */ 27 | UINT8 ksr; /* key scale rate :kcode>>KSR */ 28 | UINT32 mul; /* multiple :ML_TABLE[ML] */ 29 | UINT32 Cnt; /* frequency count : */ 30 | UINT32 Incr; /* frequency step : */ 31 | /* envelope generator state */ 32 | UINT8 eg_typ; /* envelope type flag */ 33 | UINT8 evm; /* envelope phase */ 34 | INT32 evc; /* envelope counter */ 35 | INT32 eve; /* envelope counter end point */ 36 | INT32 evs; /* envelope counter step */ 37 | INT32 evsa; /* envelope step for AR :AR[ksr] */ 38 | INT32 evsd; /* envelope step for DR :DR[ksr] */ 39 | INT32 evsr; /* envelope step for RR :RR[ksr] */ 40 | /* LFO */ 41 | UINT8 ams; /* ams flag */ 42 | UINT8 vib; /* vibrate flag */ 43 | /* wave selector */ 44 | INT32 **wavetable; 45 | }OPL_SLOT; 46 | 47 | /* ---------- OPL one of channel ---------- */ 48 | typedef struct fm_opl_channel { 49 | OPL_SLOT SLOT[2]; 50 | UINT8 CON; /* connection type */ 51 | UINT8 FB; /* feed back :(shift down bit) */ 52 | INT32 *connect1; /* slot1 output pointer */ 53 | INT32 *connect2; /* slot2 output pointer */ 54 | INT32 op1_out[2]; /* slot1 output for selfeedback */ 55 | /* phase generator state */ 56 | UINT32 block_fnum; /* block+fnum : */ 57 | UINT8 kcode; /* key code : KeyScaleCode */ 58 | UINT32 fc; /* Freq. Increment base */ 59 | UINT32 ksl_base; /* KeyScaleLevel Base step */ 60 | UINT8 keyon; /* key on/off flag */ 61 | } OPL_CH; 62 | 63 | /* OPL state */ 64 | typedef struct fm_opl_f { 65 | UINT8 type; /* chip type */ 66 | int clock; /* master clock (Hz) */ 67 | int rate; /* sampling rate (Hz) */ 68 | double freqbase; /* frequency base */ 69 | double TimerBase; /* Timer base time (==sampling time) */ 70 | UINT8 address; /* address register */ 71 | UINT8 status; /* status flag */ 72 | UINT8 statusmask; /* status mask */ 73 | UINT32 mode; /* Reg.08 : CSM , notesel,etc. */ 74 | /* Timer */ 75 | int T[2]; /* timer counter */ 76 | UINT8 st[2]; /* timer enable */ 77 | /* FM channel slots */ 78 | OPL_CH *P_CH; /* pointer of CH */ 79 | int max_ch; /* maximum channel */ 80 | /* Rythm sention */ 81 | UINT8 rythm; /* Rythm mode , key flag */ 82 | #if BUILD_Y8950 83 | /* Delta-T ADPCM unit (Y8950) */ 84 | YM_DELTAT *deltat; /* DELTA-T ADPCM */ 85 | #endif 86 | /* Keyboard / I/O interface unit (Y8950) */ 87 | UINT8 portDirection; 88 | UINT8 portLatch; 89 | OPL_PORTHANDLER_R porthandler_r; 90 | OPL_PORTHANDLER_W porthandler_w; 91 | int port_param; 92 | OPL_PORTHANDLER_R keyboardhandler_r; 93 | OPL_PORTHANDLER_W keyboardhandler_w; 94 | int keyboard_param; 95 | /* time tables */ 96 | INT32 AR_TABLE[75]; /* atttack rate tables */ 97 | INT32 DR_TABLE[75]; /* decay rate tables */ 98 | UINT32 FN_TABLE[1024]; /* fnumber -> increment counter */ 99 | /* LFO */ 100 | INT32 *ams_table; 101 | INT32 *vib_table; 102 | INT32 amsCnt; 103 | INT32 amsIncr; 104 | INT32 vibCnt; 105 | INT32 vibIncr; 106 | /* wave selector enable flag */ 107 | UINT8 wavesel; 108 | /* external event callback handler */ 109 | OPL_TIMERHANDLER TimerHandler; /* TIMER handler */ 110 | int TimerParam; /* TIMER parameter */ 111 | OPL_IRQHANDLER IRQHandler; /* IRQ handler */ 112 | int IRQParam; /* IRQ parameter */ 113 | OPL_UPDATEHANDLER UpdateHandler; /* stream update handler */ 114 | int UpdateParam; /* stream update parameter */ 115 | } FM_OPL; 116 | 117 | /* ---------- Generic interface section ---------- */ 118 | #define OPL_TYPE_YM3526 (0) 119 | #define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL) 120 | #define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO) 121 | 122 | FM_OPL *OPLCreate(int type, int clock, int rate); 123 | void OPLDestroy(FM_OPL *OPL); 124 | void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset); 125 | void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param); 126 | void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param); 127 | /* Y8950 port handlers */ 128 | void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param); 129 | void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param); 130 | 131 | void OPLResetChip(FM_OPL *OPL); 132 | int OPLWrite(FM_OPL *OPL,int a,int v); 133 | void OPLWriteReg(FM_OPL *OPL, int r, int v); 134 | unsigned char OPLRead(FM_OPL *OPL,int a); 135 | int OPLTimerOver(FM_OPL *OPL,int c); 136 | 137 | /* YM3626/YM3812 local section */ 138 | void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length); 139 | 140 | void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length); 141 | 142 | #endif 143 | -------------------------------------------------------------------------------- /psms.txt: -------------------------------------------------------------------------------- 1 | PSMS v1.2 - SMS Emulator for the PS2 2 | ------------------------------------ 3 | 4 | PS2 specific code By Nick Van Veen (aka Sjeep) 5 | SMS emulation core coded by Charles Mac Donald 6 | 7 | 8 | History: 9 | -------- 10 | 11 | 1.2 - Fixed bug in sound driver that prevented PSMS 12 | from booting with AR/GS swap. Improved FILES.TXT 13 | parsing code, changed key mapping. 14 | 1.1 - Fixed bug in rapid fire code. 15 | 1.0 - First release (preview). 16 | 17 | Introduction: 18 | ------------- 19 | 20 | PSMS is a Sega Mastersystem emulator that run's on the 21 | Sony Playstation 2. It is a port of SMSPlus, the excellent 22 | SMS emulator by Charles Mac Donald. Since the emulation core 23 | was taken from an already very complete emulator, PSMS 24 | inherits all the great features of SMSPlus, such as: 25 | 26 | - Accurate emulation. Compatability rate is around 95%. 27 | - Game Gear support. 28 | - Accurate rendering - all graphics features of the SMS 29 | and GG are emulated and rendered properly. 30 | 31 | PSMS is freeware. You may copy and distribute it as much 32 | as you like. Please do not contact me regarding where to 33 | find ROM's - I can not give out that kind of information. 34 | 35 | Current Features: 36 | ----------------- 37 | 38 | - Full frame rate (easily!!) 39 | - Audio output 40 | - PAL/NTSC auto-detection 41 | - Loads games from the cdrom 42 | - GUI for selecting roms and changing emulation options 43 | - Game Gear Support 44 | - Ability to save/load game states (not to memory card) 45 | - Easy to create your own game compilation cd's 46 | - Analog stick support 47 | 48 | If you would like a feature implimented that is not listed above, 49 | please contact me with your idea. See the contact section below. 50 | 51 | 52 | Usage: 53 | ------ 54 | 55 | First you need to create a cd that includes the emulator, your 56 | SMS/GG roms and a rom database file. See cdinfo.txt for details on 57 | how to get this all set up. Once you've created the cd, boot it 58 | with your favourite method (for most people this will involve a 59 | swap with an Action Replay/Gameshark disk). If your cd has been 60 | created properly, you should see the rom selection screen with a 61 | scroll-box listing all your games. From here you can choose the 62 | game you want to play. Once you've started playing a game, you can 63 | press SELECT to enter the in-game menu where you can save/load the 64 | game state or return to the rom selection screen to choose another 65 | game. 66 | 67 | Rom selection screen controls: 68 | 69 | Up/Down - Hold to scroll up/down. 70 | Left/Right - Hold to scroll up/down a page at a time. 71 | X - Press to start emulation of selected game. 72 | 73 | You may also use the left analog stick to scroll. 74 | 75 | In-game controls: 76 | 77 | PS2 - SMS 78 | ------------------------- 79 | Arrows = D-Pad 80 | Left stick = D-Pad 81 | Square = Button 1 82 | Circle = Button 2 83 | Start = PAUSE (START for GameGear) 84 | L1 = Button 1 Rapid fire 85 | R1 = Button 2 Rapid fire 86 | 87 | Pressing select will bring up the ingame menu. 88 | 89 | NOTE: Input is taken from both controller ports, so 2 player gaming 90 | is supported. The in-game controls are the same for both controllers. 91 | Only the 1st controller can be used in the rom selection screen. 92 | 93 | 94 | Ingame menu: 95 | 96 | From the ingame menu you can... 97 | 98 | - Load/Save game state 99 | - Change SMS region 100 | - Toggle sound output on/off 101 | - Reposition the display 102 | - Return to the main menu 103 | 104 | To reposition the display, hold down SELECT and use the arrow 105 | buttons to move the display to the correct position on the screen. 106 | 107 | State saving: 108 | 109 | At any time during gameplay the state of the game may be 110 | saved, and restored when desired (ie, if you loose a life). 111 | Currently the state is stored in PS2 memory, you cannot store it on 112 | a memory card. The state is valid until you leave the current game. 113 | Once you return to the rom selection screen the state is destroyed. 114 | This is to prevent loading an invalid state (ie, loading a state 115 | saved in a different game to the one currently been emulated). 116 | 117 | Contact: 118 | -------- 119 | 120 | PSMS Homepage: http://psms.gamebase.ca 121 | 122 | 123 | Nick Van Veen (aka Sjeep) 124 | - e-mail: sjeep@gamebase.ca 125 | - IRC: Sjeep, on EFNet 126 | 127 | Charles Mac Donald 128 | - e-mail: cgfm2@hooked.net 129 | - WWW: http://cgfm2.emuviews.com 130 | 131 | Thanks go to: 132 | ------------- 133 | 134 | Vzzrzzn - for releasing src to his demo's, which I learnt 135 | a lot from, and for writing the origional sound 136 | driver (which is no longer used). 137 | 138 | Pukko - for releasing padlib and for the many fixes to 139 | the sif code in psx2lib he has released. 140 | 141 | Gustavo - for the origional psx2lib. 142 | 143 | Oobles - for his IOP tutorial and example code. 144 | 145 | Justice7 - for writing the FILES.TXT util. 146 | 147 | Naplink Team - for Naplink. All development has been done 148 | using naplink. 149 | 150 | Charles Mac Donald - for writing SMSPlus, the excellent 151 | SMS emulator on which PSMS is based. 152 | 153 | Contact him: cgfm2@hooked.net 154 | SMSPlus website: http://cgfm2.emuviews.com. 155 | 156 | 157 | Thanks also to the beta testers: Phex_X, Sykopieces, struct2, 158 | justice7 and Sparcky. 159 | 160 | 161 | Greets to: Nagra, Stryder Hiryu, Now3d, Dreamtime, Vzzrzzn, Oobles, 162 | --------- Gustavo, Pukko, Justice7, Jules, Karmix, Phed_X, Duke, 163 | Adk, struct2, Sparcky, dayta, Sykopieces, adresd and 164 | anybody that I've missed out. 165 | LEGAL: 166 | ------ 167 | 168 | The emulator source code (including origional SMSPlus code and PSMS 169 | code) is distributed under the terms of the GNU General Public License. 170 | A copy of the GNU General Public License can be found in the "license" 171 | file included in the PSMS archive. 172 | 173 | Some PS2 specific src code such as pukko's padlib and vzzrzzn's gfxpipe is 174 | NOT distributed under the terms of the GNU General Public License. Details 175 | are included in the src archive. 176 | 177 | The Z80 CPU emulator, SN76489 and YM3812 sound chip emulation are taken from 178 | the MAME project, and terms of their use are covered under the MAME license. 179 | (http://www.mame.net) 180 | 181 | The YM2413 instrument parameter table is also taken from MAME. 182 | 183 | SMSPlus is (c) Charles Mac Donald. 184 | -------------------------------------------------------------------------------- /sn76496.c: -------------------------------------------------------------------------------- 1 | 2 | #include "shared.h" 3 | 4 | #define MAX_OUTPUT 0x7FFF 5 | #define STEP 0x10000 6 | #define FB_WNOISE 0x12000 7 | #define FB_PNOISE 0x08000 8 | #define NG_PRESET 0x0F35 9 | 10 | t_SN76496 sn[MAX_76496]; 11 | 12 | void SN76496Write(int chip,int data) 13 | { 14 | t_SN76496 *R = &sn[chip]; 15 | 16 | 17 | if (data & 0x80) 18 | { 19 | int r = (data & 0x70) >> 4; 20 | int c = r/2; 21 | 22 | R->LastRegister = r; 23 | R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f); 24 | switch (r) 25 | { 26 | case 0: /* tone 0 : frequency */ 27 | case 2: /* tone 1 : frequency */ 28 | case 4: /* tone 2 : frequency */ 29 | R->Period[c] = R->UpdateStep * R->Register[r]; 30 | if (R->Period[c] == 0) R->Period[c] = R->UpdateStep; 31 | if (r == 4) 32 | { 33 | /* update noise shift frequency */ 34 | if ((R->Register[6] & 0x03) == 0x03) 35 | R->Period[3] = 2 * R->Period[2]; 36 | } 37 | break; 38 | case 1: /* tone 0 : volume */ 39 | case 3: /* tone 1 : volume */ 40 | case 5: /* tone 2 : volume */ 41 | case 7: /* noise : volume */ 42 | R->Volume[c] = R->VolTable[data & 0x0f]; 43 | break; 44 | case 6: /* noise : frequency, mode */ 45 | { 46 | int n = R->Register[6]; 47 | R->NoiseFB = (n & 4) ? FB_WNOISE : FB_PNOISE; 48 | n &= 3; 49 | /* N/512,N/1024,N/2048,Tone #3 output */ 50 | R->Period[3] = (n == 3) ? 2 * R->Period[2] : (R->UpdateStep << (5+n)); 51 | 52 | /* reset noise shifter */ 53 | R->RNG = NG_PRESET; 54 | R->Output[3] = R->RNG & 1; 55 | } 56 | break; 57 | } 58 | } 59 | else 60 | { 61 | int r = R->LastRegister; 62 | int c = r/2; 63 | 64 | switch (r) 65 | { 66 | case 0: /* tone 0 : frequency */ 67 | case 2: /* tone 1 : frequency */ 68 | case 4: /* tone 2 : frequency */ 69 | R->Register[r] = (R->Register[r] & 0x0f) | ((data & 0x3f) << 4); 70 | R->Period[c] = R->UpdateStep * R->Register[r]; 71 | if (R->Period[c] == 0) R->Period[c] = R->UpdateStep; 72 | if (r == 4) 73 | { 74 | /* update noise shift frequency */ 75 | if ((R->Register[6] & 0x03) == 0x03) 76 | R->Period[3] = 2 * R->Period[2]; 77 | } 78 | break; 79 | } 80 | } 81 | } 82 | 83 | 84 | void SN76496Update(int chip,INT16 *buffer[2],int length, unsigned char mask) 85 | { 86 | int i, j; 87 | int buffer_index = 0; 88 | t_SN76496 *R = &sn[chip]; 89 | 90 | /* If the volume is 0, increase the counter */ 91 | for (i = 0;i < 4;i++) 92 | { 93 | if (R->Volume[i] == 0) 94 | { 95 | /* note that I do count += length, NOT count = length + 1. You might think */ 96 | /* it's the same since the volume is 0, but doing the latter could cause */ 97 | /* interferencies when the program is rapidly modulating the volume. */ 98 | if (R->Count[i] <= length*STEP) R->Count[i] += length*STEP; 99 | } 100 | } 101 | 102 | while (length > 0) 103 | { 104 | int vol[4]; 105 | unsigned int out[2]; 106 | int left; 107 | 108 | 109 | /* vol[] keeps track of how long each square wave stays */ 110 | /* in the 1 position during the sample period. */ 111 | vol[0] = vol[1] = vol[2] = vol[3] = 0; 112 | 113 | for (i = 0;i < 3;i++) 114 | { 115 | if (R->Output[i]) vol[i] += R->Count[i]; 116 | R->Count[i] -= STEP; 117 | /* Period[i] is the half period of the square wave. Here, in each */ 118 | /* loop I add Period[i] twice, so that at the end of the loop the */ 119 | /* square wave is in the same status (0 or 1) it was at the start. */ 120 | /* vol[i] is also incremented by Period[i], since the wave has been 1 */ 121 | /* exactly half of the time, regardless of the initial position. */ 122 | /* If we exit the loop in the middle, Output[i] has to be inverted */ 123 | /* and vol[i] incremented only if the exit status of the square */ 124 | /* wave is 1. */ 125 | while (R->Count[i] <= 0) 126 | { 127 | R->Count[i] += R->Period[i]; 128 | if (R->Count[i] > 0) 129 | { 130 | R->Output[i] ^= 1; 131 | if (R->Output[i]) vol[i] += R->Period[i]; 132 | break; 133 | } 134 | R->Count[i] += R->Period[i]; 135 | vol[i] += R->Period[i]; 136 | } 137 | if (R->Output[i]) vol[i] -= R->Count[i]; 138 | } 139 | 140 | left = STEP; 141 | do 142 | { 143 | int nextevent; 144 | 145 | 146 | if (R->Count[3] < left) nextevent = R->Count[3]; 147 | else nextevent = left; 148 | 149 | if (R->Output[3]) vol[3] += R->Count[3]; 150 | R->Count[3] -= nextevent; 151 | if (R->Count[3] <= 0) 152 | { 153 | if (R->RNG & 1) R->RNG ^= R->NoiseFB; 154 | R->RNG >>= 1; 155 | R->Output[3] = R->RNG & 1; 156 | R->Count[3] += R->Period[3]; 157 | if (R->Output[3]) vol[3] += R->Period[3]; 158 | } 159 | if (R->Output[3]) vol[3] -= R->Count[3]; 160 | 161 | left -= nextevent; 162 | } while (left > 0); 163 | 164 | out[0] = out[1] = 0; 165 | for(j = 0; j < 4; j += 1) 166 | { 167 | int k = vol[j] * R->Volume[j]; 168 | if(mask & (1 << (4+j))) out[0] += k; 169 | if(mask & (1 << (0+j))) out[1] += k; 170 | } 171 | 172 | if(out[0] > MAX_OUTPUT * STEP) out[0] = MAX_OUTPUT * STEP; 173 | if(out[1] > MAX_OUTPUT * STEP) out[1] = MAX_OUTPUT * STEP; 174 | buffer[0][buffer_index] = out[0] / STEP; 175 | buffer[1][buffer_index] = out[1] / STEP; 176 | 177 | /* Next sample set */ 178 | buffer_index += 1; 179 | 180 | length--; 181 | } 182 | } 183 | 184 | 185 | 186 | void SN76496_set_clock(int chip,int clock) 187 | { 188 | t_SN76496 *R = &sn[chip]; 189 | 190 | R->UpdateStep = ((double)STEP * R->SampleRate * 16) / clock; 191 | } 192 | 193 | 194 | 195 | void SN76496_set_gain(int chip,int gain) 196 | { 197 | t_SN76496 *R = &sn[chip]; 198 | int i; 199 | double out; 200 | 201 | gain &= 0xff; 202 | out = MAX_OUTPUT / 3; 203 | while (gain-- > 0) 204 | out *= 1.023292992; 205 | 206 | for (i = 0;i < 15;i++) 207 | { 208 | if (out > MAX_OUTPUT / 3) R->VolTable[i] = MAX_OUTPUT / 3; 209 | else R->VolTable[i] = out; 210 | out /= 1.258925412; 211 | } 212 | 213 | R->VolTable[15] = 0; 214 | } 215 | 216 | 217 | 218 | int SN76496_init(int chip,int clock,int volume,int sample_rate) 219 | { 220 | int i; 221 | t_SN76496 *R = &sn[chip]; 222 | 223 | memset(R,0,sizeof(t_SN76496)); // Added for PSMS 224 | 225 | R->SampleRate = sample_rate; 226 | SN76496_set_clock(chip,clock); 227 | 228 | for (i = 0;i < 4;i++) R->Volume[i] = 0; 229 | 230 | R->LastRegister = 0; 231 | for (i = 0;i < 8;i+=2) 232 | { 233 | R->Register[i] = 0; 234 | R->Register[i + 1] = 0x0f; /* volume = 0 */ 235 | } 236 | 237 | for (i = 0;i < 4;i++) 238 | { 239 | R->Output[i] = 0; 240 | R->Period[i] = R->Count[i] = R->UpdateStep; 241 | } 242 | R->RNG = NG_PRESET; 243 | R->Output[3] = R->RNG & 1; 244 | 245 | SN76496_set_gain(0, (volume >> 8) & 0xFF); 246 | 247 | return 0; 248 | } 249 | -------------------------------------------------------------------------------- /system.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1998, 1999, 2000 Charles Mac Donald 3 | 4 | This program is free software; you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation; either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | */ 18 | 19 | #include "shared.h" 20 | 21 | void psms_manage_sram(u8 *sram, int mode); 22 | 23 | t_bitmap bitmap; 24 | t_cart cart; 25 | t_snd snd; 26 | t_input input; 27 | FM_OPL *ym3812; 28 | 29 | extern int snd_sample; 30 | 31 | void system_init(int rate) 32 | { 33 | /* Initialize the VDP emulation */ 34 | vdp_init(); 35 | 36 | /* Initialize the SMS emulation */ 37 | sms_init(); 38 | 39 | /* Initialize the look-up tables and related data */ 40 | render_init(); 41 | 42 | /* Enable sound emulation if the sample rate was specified */ 43 | audio_init(rate); 44 | 45 | /* Don't save SRAM by default */ 46 | sms.save = 0; 47 | 48 | /* Clear emulated button state */ 49 | memset(&input, 0, sizeof(t_input)); 50 | } 51 | 52 | void audio_init(int rate) 53 | { 54 | /* Clear sound context */ 55 | memset(&snd, 0, sizeof(t_snd)); 56 | 57 | /* Reset logging data */ 58 | snd.log = 0; 59 | snd.callback = NULL; 60 | 61 | /* Oops.. sound is disabled */ 62 | if(!rate) return; 63 | 64 | /* Calculate buffer size in samples */ 65 | //snd.bufsize = (rate / 60); 66 | snd.bufsize = snd_sample; 67 | 68 | /* Sound output */ 69 | //snd.buffer[0] = (signed short int *)malloc(snd.bufsize * 2); 70 | //snd.buffer[1] = (signed short int *)malloc(snd.bufsize * 2); 71 | snd.buffer[0] = (signed short int *)memalign(16, snd.bufsize * 2); 72 | snd.buffer[1] = (signed short int *)memalign(16, snd.bufsize * 2); 73 | if(!snd.buffer[0] || !snd.buffer[1]) return; 74 | 75 | /* YM3812/YM2413 sound stream */ 76 | snd.fm_buffer = (signed short int *)memalign(16, snd.bufsize * 2); 77 | if(!snd.fm_buffer) return; 78 | 79 | /* SN76489 sound stream */ 80 | snd.psg_buffer[0] = (signed short int *)memalign(16, snd.bufsize * 2); 81 | snd.psg_buffer[1] = (signed short int *)memalign(16, snd.bufsize * 2); 82 | if(!snd.psg_buffer[0] || !snd.psg_buffer[1]) return; 83 | 84 | /* Set up SN76489 emulation */ 85 | SN76496_init(0, MASTER_CLOCK, 255, rate); 86 | 87 | /* Set up YM3812 emulation */ 88 | ym3812 = OPLCreate(OPL_TYPE_YM3812, MASTER_CLOCK, rate); 89 | if(!ym3812) return; 90 | 91 | /* Set up YM2413 emulation */ 92 | ym2413_init(1); 93 | 94 | /* Inform other functions that we can use sound */ 95 | snd.enabled = 1; 96 | 97 | sms.use_fm = 0; // FM aint working for some reason, will investigate. 98 | } 99 | 100 | 101 | void system_shutdown(void) 102 | { 103 | 104 | if(snd.enabled) OPLDestroy(ym3812); 105 | } 106 | 107 | 108 | void system_reset(void) 109 | { 110 | cpu_reset(); 111 | vdp_reset(); 112 | sms_reset(); 113 | render_reset(); 114 | //system_load_sram(); 115 | psms_manage_sram(sms.sram, SRAM_LOAD); 116 | if(snd.enabled) 117 | { 118 | SN76496_init(0, MASTER_CLOCK, 255, 48000); // Added for PSMS 119 | OPLResetChip(ym3812); 120 | ym2413_reset(0); 121 | } 122 | } 123 | 124 | 125 | void system_save_state(void *fd) 126 | { 127 | /* 128 | // Save VDP context 129 | fwrite(&vdp, sizeof(t_vdp), 1, fd); 130 | 131 | // Save SMS context 132 | fwrite(&sms, sizeof(t_sms), 1, fd); 133 | 134 | // Save Z80 context 135 | fwrite(Z80_Context, sizeof(Z80_Regs), 1, fd); 136 | fwrite(&after_EI, sizeof(int), 1, fd); 137 | 138 | // Save YM2413 registers 139 | fwrite(&ym2413[0].reg[0], 0x40, 1, fd); 140 | 141 | // Save SN76489 context 142 | fwrite(&sn[0], sizeof(t_SN76496), 1, fd); 143 | */ 144 | } 145 | 146 | 147 | void system_load_state(void *fd) 148 | { 149 | /* 150 | int i; 151 | byte reg[0x40]; 152 | 153 | // Initialize everything 154 | cpu_reset(); 155 | system_reset(); 156 | 157 | // Load VDP context 158 | fread(&vdp, sizeof(t_vdp), 1, fd); 159 | 160 | // Load SMS context 161 | fread(&sms, sizeof(t_sms), 1, fd); 162 | 163 | // Load Z80 context 164 | fread(Z80_Context, sizeof(Z80_Regs), 1, fd); 165 | fread(&after_EI, sizeof(int), 1, fd); 166 | 167 | // Load YM2413 registers 168 | fread(reg, 0x40, 1, fd); 169 | 170 | // Load SN76489 context 171 | fread(&sn[0], sizeof(t_SN76496), 1, fd); 172 | 173 | // Restore callbacks 174 | z80_set_irq_callback(sms_irq_callback); 175 | 176 | cpu_readmap[0] = cart.rom + 0x0000; // 0000-3FFF 177 | cpu_readmap[1] = cart.rom + 0x2000; 178 | cpu_readmap[2] = cart.rom + 0x4000; // 4000-7FFF 179 | cpu_readmap[3] = cart.rom + 0x6000; 180 | cpu_readmap[4] = cart.rom + 0x0000; // 0000-3FFF 181 | cpu_readmap[5] = cart.rom + 0x2000; 182 | cpu_readmap[6] = sms.ram; 183 | cpu_readmap[7] = sms.ram; 184 | 185 | cpu_writemap[0] = sms.dummy; 186 | cpu_writemap[1] = sms.dummy; 187 | cpu_writemap[2] = sms.dummy; 188 | cpu_writemap[3] = sms.dummy; 189 | cpu_writemap[4] = sms.dummy; 190 | cpu_writemap[5] = sms.dummy; 191 | cpu_writemap[6] = sms.ram; 192 | cpu_writemap[7] = sms.ram; 193 | 194 | sms_mapper_w(3, sms.fcr[3]); 195 | sms_mapper_w(2, sms.fcr[2]); 196 | sms_mapper_w(1, sms.fcr[1]); 197 | sms_mapper_w(0, sms.fcr[0]); 198 | 199 | // Force full pattern cache update 200 | is_vram_dirty = 1; 201 | memset(vram_dirty, 1, 0x200); 202 | 203 | // Restore palette 204 | for(i = 0; i < PALETTE_SIZE; i += 1) 205 | palette_sync(i); 206 | 207 | // Restore sound state 208 | if(snd.enabled) 209 | { 210 | // Restore YM2413 emulation 211 | OPLResetChip(ym3812); 212 | 213 | // Clear YM2413 context 214 | ym2413_reset(0); 215 | 216 | // Restore rhythm enable first 217 | ym2413_write(0, 0, 0x0E); 218 | ym2413_write(0, 1, reg[0x0E]); 219 | 220 | // User instrument settings 221 | for(i = 0x00; i <= 0x07; i += 1) 222 | { 223 | ym2413_write(0, 0, i); 224 | ym2413_write(0, 1, reg[i]); 225 | } 226 | 227 | // Channel frequency 228 | for(i = 0x10; i <= 0x18; i += 1) 229 | { 230 | ym2413_write(0, 0, i); 231 | ym2413_write(0, 1, reg[i]); 232 | } 233 | 234 | // Channel frequency + ctrl. 235 | for(i = 0x20; i <= 0x28; i += 1) 236 | { 237 | ym2413_write(0, 0, i); 238 | ym2413_write(0, 1, reg[i]); 239 | } 240 | 241 | // Instrument and volume settings 242 | for(i = 0x30; i <= 0x38; i += 1) 243 | { 244 | ym2413_write(0, 0, i); 245 | ym2413_write(0, 1, reg[i]); 246 | } 247 | } 248 | */ 249 | } 250 | -------------------------------------------------------------------------------- /sms.c: -------------------------------------------------------------------------------- 1 | 2 | #include "shared.h" 3 | 4 | /* SMS context */ 5 | t_sms sms __attribute__ ((section (".bss"))); 6 | 7 | /* Run the virtual console emulation for one frame */ 8 | void sms_frame(int skip_render) 9 | { 10 | int i; 11 | 12 | /* Take care of hard resets */ 13 | if(input.system & INPUT_HARD_RESET) 14 | { 15 | system_reset(); 16 | } 17 | 18 | /* Debounce pause key */ 19 | if(input.system & INPUT_PAUSE) 20 | { 21 | if(!sms.paused) 22 | { 23 | sms.paused = 1; 24 | 25 | z80_set_nmi_line(ASSERT_LINE); 26 | z80_set_nmi_line(CLEAR_LINE); 27 | } 28 | } 29 | else 30 | { 31 | sms.paused = 0; 32 | } 33 | 34 | if(snd.log) snd.callback(0x00); 35 | 36 | for(vdp.line = 0; vdp.line < LINES_PER_FRAME; vdp.line += 1) 37 | { 38 | /* Handle VDP line events */ 39 | vdp_run(); 40 | 41 | /* Draw the current frame */ 42 | if(!skip_render) render_line(vdp.line); 43 | 44 | /* Run the Z80 for a line */ 45 | z80_execute(227); 46 | } 47 | 48 | /* Update the emulated sound stream */ 49 | if(snd.enabled) 50 | { 51 | int count; 52 | 53 | SN76496Update(0, snd.psg_buffer, snd.bufsize, sms.psg_mask); 54 | if(sms.use_fm) YM3812UpdateOne(ym3812, snd.fm_buffer, snd.bufsize); 55 | 56 | for(count = 0; count < snd.bufsize; count += 1) 57 | { 58 | signed short left = 0; 59 | signed short right = 0; 60 | left = right = snd.fm_buffer[count]; 61 | left += snd.psg_buffer[0][count]; 62 | right += snd.psg_buffer[1][count]; 63 | snd.buffer[0][count] = left; 64 | snd.buffer[1][count] = right; 65 | } 66 | } 67 | 68 | for(i=0;i<0xC000;i++) 69 | bitmap.data[i] &= PIXEL_MASK; 70 | } 71 | 72 | 73 | void sms_init(void) 74 | { 75 | 76 | //z80_set_context((void *)0x70000000); 77 | 78 | cpu_reset(); 79 | sms_reset(); 80 | } 81 | 82 | 83 | void sms_reset(void) 84 | { 85 | /* Clear SMS context */ 86 | memset(sms.dummy, 0, 0x2000); 87 | memset(sms.ram, 0, 0x2000); 88 | memset(sms.sram, 0, 0x8000); 89 | sms.paused = sms.save = sms.port_3F = sms.port_F2 = sms.irq = 0x00; 90 | sms.psg_mask = 0xFF; 91 | 92 | /* Load memory maps with default values */ 93 | cpu_readmap[0] = cart.rom + 0x0000; 94 | cpu_readmap[1] = cart.rom + 0x2000; 95 | cpu_readmap[2] = cart.rom + 0x4000; 96 | cpu_readmap[3] = cart.rom + 0x6000; 97 | cpu_readmap[4] = cart.rom + 0x0000; 98 | cpu_readmap[5] = cart.rom + 0x2000; 99 | cpu_readmap[6] = sms.ram; 100 | cpu_readmap[7] = sms.ram; 101 | 102 | cpu_writemap[0] = sms.dummy; 103 | cpu_writemap[1] = sms.dummy; 104 | cpu_writemap[2] = sms.dummy; 105 | cpu_writemap[3] = sms.dummy; 106 | cpu_writemap[4] = sms.dummy; 107 | cpu_writemap[5] = sms.dummy; 108 | cpu_writemap[6] = sms.ram; 109 | cpu_writemap[7] = sms.ram; 110 | 111 | sms.fcr[0] = 0x00; 112 | sms.fcr[1] = 0x00; 113 | sms.fcr[2] = 0x01; 114 | sms.fcr[3] = 0x00; 115 | } 116 | 117 | 118 | /* Reset Z80 emulator */ 119 | void cpu_reset(void) 120 | { 121 | z80_reset(0); 122 | z80_set_irq_callback(sms_irq_callback); 123 | } 124 | 125 | 126 | /* Write to memory */ 127 | void cpu_writemem16(int address, int data) 128 | { 129 | cpu_writemap[(address >> 13)][(address & 0x1FFF)] = data; 130 | if(address >= 0xFFFC) sms_mapper_w(address & 3, data); 131 | 132 | //printf("writemem\n"); 133 | } 134 | 135 | 136 | /* Write to an I/O port */ 137 | void cpu_writeport(int port, int data) 138 | { 139 | switch(port & 0xFF) 140 | { 141 | case 0x01: /* GG SIO */ 142 | case 0x02: 143 | case 0x03: 144 | case 0x04: 145 | case 0x05: 146 | break; 147 | 148 | case 0x06: /* GG STEREO */ 149 | if(snd.log) { 150 | snd.callback(0x04); 151 | snd.callback(data); 152 | } 153 | sms.psg_mask = (data & 0xFF); 154 | break; 155 | 156 | case 0x7E: /* SN76489 PSG */ 157 | case 0x7F: 158 | if(snd.log) { 159 | snd.callback(0x03); 160 | snd.callback(data); 161 | } 162 | if(snd.enabled) SN76496Write(0, data); 163 | break; 164 | 165 | case 0xBE: /* VDP DATA */ 166 | vdp_data_w(data); 167 | break; 168 | 169 | case 0xBD: /* VDP CTRL */ 170 | case 0xBF: 171 | vdp_ctrl_w(data); 172 | //printf("vdp_ctrl\n"); 173 | break; 174 | 175 | case 0xF0: /* YM2413 */ 176 | case 0xF1: 177 | if(snd.log) { 178 | snd.callback((port & 1) ? 0x06 : 0x05); 179 | snd.callback(data); 180 | } 181 | if(snd.enabled && sms.use_fm) ym2413_write(0, port & 1, data); 182 | break; 183 | 184 | case 0xF2: /* YM2413 DETECT */ 185 | if(sms.use_fm) sms.port_F2 = (data & 1); 186 | break; 187 | 188 | case 0x3F: /* TERRITORY CTRL. */ 189 | sms.port_3F = ((data & 0x80) | (data & 0x20) << 1) & 0xC0; 190 | if(sms.country == TYPE_DOMESTIC) sms.port_3F ^= 0xC0; 191 | break; 192 | } 193 | } 194 | 195 | 196 | /* Read from an I/O port */ 197 | int cpu_readport(int port) 198 | { 199 | byte temp = 0xFF; 200 | 201 | switch(port & 0xFF) 202 | { 203 | case 0x01: /* GG SIO */ 204 | case 0x02: 205 | case 0x03: 206 | case 0x04: 207 | case 0x05: 208 | return (0x00); 209 | 210 | case 0x7E: /* V COUNTER */ 211 | return (vdp_vcounter_r()); 212 | break; 213 | 214 | case 0x7F: /* H COUNTER */ 215 | return (vdp_hcounter_r()); 216 | break; 217 | 218 | case 0x00: /* INPUT #2 */ 219 | temp = 0xFF; 220 | if(input.system & INPUT_START) temp &= ~0x80; 221 | if(sms.country == TYPE_DOMESTIC) temp &= ~0x40; 222 | return (temp); 223 | 224 | case 0xC0: /* INPUT #0 */ 225 | case 0xDC: 226 | temp = 0xFF; 227 | if(input.pad[0] & INPUT_UP) temp &= ~0x01; 228 | if(input.pad[0] & INPUT_DOWN) temp &= ~0x02; 229 | if(input.pad[0] & INPUT_LEFT) temp &= ~0x04; 230 | if(input.pad[0] & INPUT_RIGHT) temp &= ~0x08; 231 | if(input.pad[0] & INPUT_BUTTON1) temp &= ~0x10; 232 | if(input.pad[0] & INPUT_BUTTON2) temp &= ~0x20; 233 | if(input.pad[1] & INPUT_UP) temp &= ~0x40; 234 | if(input.pad[1] & INPUT_DOWN) temp &= ~0x80; 235 | return (temp); 236 | 237 | case 0xC1: /* INPUT #1 */ 238 | case 0xDD: 239 | temp = 0xFF; 240 | if(input.pad[1] & INPUT_LEFT) temp &= ~0x01; 241 | if(input.pad[1] & INPUT_RIGHT) temp &= ~0x02; 242 | if(input.pad[1] & INPUT_BUTTON1) temp &= ~0x04; 243 | if(input.pad[1] & INPUT_BUTTON2) temp &= ~0x08; 244 | if(input.system & INPUT_SOFT_RESET) temp &= ~0x10; 245 | return ((temp & 0x3F) | (sms.port_3F & 0xC0)); 246 | 247 | case 0xBE: /* VDP DATA */ 248 | return (vdp_data_r()); 249 | 250 | case 0xBD: 251 | case 0xBF: /* VDP CTRL */ 252 | return (vdp_ctrl_r()); 253 | 254 | case 0xF2: /* YM2413 DETECT */ 255 | if(sms.use_fm) return (sms.port_F2); 256 | break; 257 | } 258 | return (0xFF); 259 | } 260 | 261 | 262 | void sms_mapper_w(int address, int data) 263 | { 264 | /* Calculate ROM page index */ 265 | byte page = (data % cart.pages); 266 | 267 | /* Save frame control register data */ 268 | sms.fcr[address] = data; 269 | 270 | switch(address) 271 | { 272 | case 0: 273 | if(data & 8) 274 | { 275 | sms.save = 1; 276 | /* Page in ROM */ 277 | cpu_readmap[4] = &sms.sram[(data & 4) ? 0x4000 : 0x0000]; 278 | cpu_readmap[5] = &sms.sram[(data & 4) ? 0x6000 : 0x2000]; 279 | cpu_writemap[4] = &sms.sram[(data & 4) ? 0x4000 : 0x0000]; 280 | cpu_writemap[5] = &sms.sram[(data & 4) ? 0x6000 : 0x2000]; 281 | } 282 | else 283 | { 284 | /* Page in RAM */ 285 | cpu_readmap[4] = &cart.rom[((sms.fcr[3] % cart.pages) << 14) + 0x0000]; 286 | cpu_readmap[5] = &cart.rom[((sms.fcr[3] % cart.pages) << 14) + 0x2000]; 287 | cpu_writemap[4] = sms.dummy; 288 | cpu_writemap[5] = sms.dummy; 289 | } 290 | break; 291 | 292 | case 1: 293 | cpu_readmap[0] = &cart.rom[(page << 14) + 0x0000]; 294 | cpu_readmap[1] = &cart.rom[(page << 14) + 0x2000]; 295 | break; 296 | 297 | case 2: 298 | cpu_readmap[2] = &cart.rom[(page << 14) + 0x0000]; 299 | cpu_readmap[3] = &cart.rom[(page << 14) + 0x2000]; 300 | break; 301 | 302 | case 3: 303 | if(!(sms.fcr[0] & 0x08)) 304 | { 305 | cpu_readmap[4] = &cart.rom[(page << 14) + 0x0000]; 306 | cpu_readmap[5] = &cart.rom[(page << 14) + 0x2000]; 307 | } 308 | break; 309 | } 310 | } 311 | 312 | 313 | int sms_irq_callback(int param) 314 | { 315 | return (0xFF); 316 | } 317 | 318 | -------------------------------------------------------------------------------- /vdp.c: -------------------------------------------------------------------------------- 1 | 2 | #include "shared.h" 3 | 4 | 5 | /* VDP context */ 6 | t_vdp vdp __attribute__ ((section (".bss"))); 7 | 8 | 9 | /* Return values from the V counter */ 10 | byte vcnt[0x200] = 11 | { 12 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 13 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 14 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 15 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 16 | 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 17 | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 18 | 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 19 | 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 20 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 21 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 22 | 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 23 | 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 24 | 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 25 | 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 26 | 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 27 | 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 28 | 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 29 | }; 30 | 31 | /* Return values from the H counter */ 32 | byte hcnt[0x200] = 33 | { 34 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 35 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 36 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 37 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 38 | 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 39 | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 40 | 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 41 | 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 42 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 43 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 44 | 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 45 | 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 46 | 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 47 | 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 48 | 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 49 | 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 50 | 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 51 | 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 52 | 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 53 | 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 54 | 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 55 | 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 56 | }; 57 | 58 | 59 | /*--------------------------------------------------------------------------*/ 60 | 61 | 62 | /* Initialize VDP emulation */ 63 | void vdp_init(void) 64 | { 65 | vdp_reset(); 66 | } 67 | 68 | 69 | /* Reset VDP emulation */ 70 | void vdp_reset(void) 71 | { 72 | memset(&vdp, 0, sizeof(t_vdp)); 73 | vdp.limit = 1; 74 | } 75 | 76 | 77 | /* Write data to the VDP's control port */ 78 | void vdp_ctrl_w(int data) 79 | { 80 | /* Waiting for the reset of the command? */ 81 | if(vdp.pending == 0) 82 | { 83 | /* Save data for later */ 84 | vdp.latch = data; 85 | 86 | /* Set pending flag */ 87 | vdp.pending = 1; 88 | } 89 | else 90 | { 91 | /* Clear pending flag */ 92 | vdp.pending = 0; 93 | 94 | /* VDP register write */ 95 | if((data & 0xF0) == 0x80) 96 | { 97 | int r = (data & 0x0F); 98 | int d = vdp.latch; 99 | 100 | /* Store register data */ 101 | vdp.reg[r] = d; 102 | 103 | /* Update table addresses */ 104 | vdp.ntab = (vdp.reg[2] << 10) & 0x3800; 105 | vdp.satb = (vdp.reg[5] << 7) & 0x3F00; 106 | 107 | vdp.addr = vdp.code = 0; 108 | } 109 | else 110 | { 111 | /* Extract code bits */ 112 | vdp.code = (data >> 6) & 3; 113 | 114 | /* Make address */ 115 | vdp.addr = (data << 8 | vdp.latch); 116 | 117 | /* Read VRAM for code 0x00 */ 118 | if(vdp.code == 0x00) 119 | { 120 | /* Load buffer with current VRAM byte */ 121 | vdp.buffer = vdp.vram[(vdp.addr & 0x3FFF)]; 122 | 123 | /* Bump address */ 124 | vdp.addr += 1; 125 | } 126 | } 127 | } 128 | } 129 | 130 | 131 | /* Read the status flags */ 132 | int vdp_ctrl_r(void) 133 | { 134 | /* Save the status flags */ 135 | byte temp = vdp.status; 136 | 137 | /* Clear pending flag */ 138 | vdp.pending = 0; 139 | 140 | /* Clear pending interrupt and sprite collision flags */ 141 | vdp.status &= ~(0x80 | 0x40 | 0x20); 142 | 143 | /* Lower the IRQ line */ 144 | if(sms.irq == 1) 145 | { 146 | sms.irq = 0; 147 | z80_set_irq_line(0, CLEAR_LINE); 148 | } 149 | 150 | /* Return the old status flags */ 151 | return (temp); 152 | } 153 | 154 | 155 | /* Write data to the VDP's data port */ 156 | void vdp_data_w(int data) 157 | { 158 | int index; 159 | 160 | /* Clear the pending flag */ 161 | vdp.pending = 0; 162 | 163 | switch(vdp.code) 164 | { 165 | case 0: /* VRAM write */ 166 | case 1: /* VRAM write */ 167 | case 2: /* VRAM write */ 168 | 169 | /* Get current address in VRAM */ 170 | index = (vdp.addr & 0x3FFF); 171 | 172 | /* Only update if data is new */ 173 | if(data != vdp.vram[index]) 174 | { 175 | /* Store VRAM byte */ 176 | vdp.vram[index] = data; 177 | 178 | /* Mark patterns as dirty */ 179 | vram_dirty[(index >> 5)] = is_vram_dirty = 1; 180 | } 181 | break; 182 | 183 | case 3: /* CRAM write */ 184 | if(cart.type == TYPE_GG) 185 | { 186 | index = (vdp.addr & 0x3F); 187 | if(data != vdp.cram[index]) 188 | { 189 | vdp.cram[index] = data; 190 | index = (vdp.addr >> 1) & 0x1F; 191 | palette_sync(index); 192 | } 193 | } 194 | else 195 | { 196 | index = (vdp.addr & 0x1F); 197 | if(data != vdp.cram[index]) 198 | { 199 | vdp.cram[index] = data; 200 | palette_sync(index); 201 | } 202 | } 203 | break; 204 | } 205 | 206 | /* Bump the VRAM address */ 207 | vdp.addr += 1; 208 | } 209 | 210 | 211 | /* Read data from the VDP's data port */ 212 | int vdp_data_r(void) 213 | { 214 | byte temp = 0; 215 | 216 | /* Clear the pending flag */ 217 | vdp.pending = 0; 218 | 219 | switch(vdp.code) 220 | { 221 | case 0: /* VRAM read */ 222 | case 1: /* VRAM read */ 223 | case 2: /* VRAM read */ 224 | 225 | /* Return the buffered value */ 226 | temp = vdp.buffer; 227 | 228 | /* Get data from the current VRAM address */ 229 | vdp.buffer = vdp.vram[(vdp.addr & 0x3FFF)]; 230 | break; 231 | 232 | case 3: /* Undefined */ 233 | /* Return 'no value' data */ 234 | temp = 0xFF; 235 | break; 236 | } 237 | 238 | /* Bump address register */ 239 | vdp.addr += 1; 240 | return (temp); 241 | } 242 | 243 | 244 | /* Process frame events */ 245 | void vdp_run(void) 246 | { 247 | if(vdp.line <= 0xC0) 248 | { 249 | if(vdp.line == 0xC0) 250 | { 251 | vdp.status |= 0x80; 252 | } 253 | 254 | if(vdp.line == 0) 255 | { 256 | vdp.left = vdp.reg[10]; 257 | } 258 | 259 | if(vdp.left == 0) 260 | { 261 | vdp.left = vdp.reg[10]; 262 | vdp.status |= 0x40; 263 | } 264 | else 265 | { 266 | vdp.left -= 1; 267 | } 268 | 269 | if((vdp.status & 0x40) && (vdp.reg[0] & 0x10)) 270 | { 271 | sms.irq = 1; 272 | z80_set_irq_line(0, ASSERT_LINE); 273 | } 274 | } 275 | else 276 | { 277 | vdp.left = vdp.reg[10]; 278 | 279 | if((vdp.line < 0xE0) && (vdp.status & 0x80) && (vdp.reg[1] & 0x20)) 280 | { 281 | sms.irq = 1; 282 | z80_set_irq_line(0, ASSERT_LINE); 283 | } 284 | } 285 | } 286 | 287 | 288 | byte vdp_vcounter_r(void) 289 | { 290 | return (vcnt[(vdp.line & 0x1FF)]); 291 | } 292 | 293 | 294 | byte vdp_hcounter_r(void) 295 | { 296 | int pixel = (((z80_ICount % CYCLES_PER_LINE) / 4) * 3) * 2; 297 | return (hcnt[((pixel >> 1) & 0x1FF)]); 298 | } 299 | -------------------------------------------------------------------------------- /browser/ps2font.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "ps2font.h" 6 | 7 | //extern vars Settings; 8 | extern GSGLOBAL *gsGlobal; 9 | u8 *FontBuffer; 10 | 11 | extern unsigned char font_uLE[]; 12 | enum { 13 | // 0x100-0x109 are 5 double width characters for D-Pad buttons, which are accessed as: 14 | // "�0"==Circle "�1"==Cross "�2"==Square "�3"==Triangle "�4"==filled Square 15 | RIGHT_CUR = 0x10A, // Triangle pointing left, for use to the right of an item 16 | LEFT_CUR = 0x10B, // Triangle pointing right, for use to the left of an item 17 | UP_ARROW = 0x10C, // Arrow pointing up 18 | DN_ARROW = 0x10D, // Arrow pointing up 19 | LT_ARROW = 0x10E, // Arrow pointing up 20 | RT_ARROW = 0x10F, // Arrow pointing up 21 | TEXT_CUR = 0x110, // Vertical bar, for use between two text characters 22 | UL_ARROW = 0x111, // Arrow pointing up and to the left, from a vertical start. 23 | BR_SPLIT = 0x112, // Splits rectangle from BL to TR with BR portion filled 24 | BL_SPLIT = 0x113, // Splits rectangle from TL to BR with BL portion filled 25 | // 0x114-0x11B are 4 double width characters for D-Pad buttons, which are accessed as: 26 | // "�:"==Right "�;"==Down "�<"==Left "�="==Up 27 | // 0x11C-0x123 are 4 doubled characters used as normal/marked folder/file icons 28 | ICON_FOLDER = 0x11C, 29 | ICON_M_FOLDER = 0x11E, 30 | ICON_FILE = 0x120, 31 | ICON_M_FILE = 0x122, 32 | FONT_COUNT = 0x124 // Total number of characters in font 33 | }; 34 | 35 | /*GSTEXTURE FONT_TEX; 36 | 37 | struct { 38 | int Rows; 39 | int Columns; 40 | int CharWidth; 41 | int CharHeight; 42 | u8 Additional[256]; 43 | } fontdata; 44 | 45 | int font_init(GSGLOBAL *gsGlobal) 46 | { 47 | int i; 48 | char *fontpath; 49 | char *datpath; 50 | fontpath = calloc(1,strlen(Settings.savepath)+8); 51 | datpath = calloc(1,strlen(Settings.savepath)+8); 52 | 53 | sprintf(fontpath,"%s%s",Settings.savepath,"strt.png"); 54 | sprintf(datpath,"%s%s",Settings.savepath,"strt.dat"); 55 | 56 | if( gsKit_texture_png(gsGlobal, &FONT_TEX, fontpath) == -1 ) { 57 | printf("Error uploading font png!\n"); 58 | return -1; 59 | } 60 | 61 | fontdata.Columns=16; 62 | fontdata.Rows=16; 63 | fontdata.CharWidth = FONT_TEX.Width / 16; 64 | fontdata.CharHeight = FONT_TEX.Height / 16; 65 | 66 | int File = fioOpen(datpath, O_RDONLY); 67 | //fontdata.Additional=malloc( 0x100 ); 68 | u16 temp_buffer[512]; 69 | if (File > 0) { 70 | fioLseek(File, 0, SEEK_SET); 71 | if(fioRead(File, &temp_buffer, 0x200) <= 0) { 72 | printf("Could not load font sizes: %s\n", datpath); 73 | return -1; 74 | } 75 | fioClose(File); 76 | for (i = 0; i < 0x100; i++) { 77 | fontdata.Additional[i] = temp_buffer[i]; 78 | } 79 | } 80 | else { 81 | int i; 82 | for (i = 0; i < 0x100; i++) { 83 | fontdata.Additional[i] = fontdata.CharWidth; 84 | } 85 | } 86 | 87 | return 0; 88 | } 89 | 90 | void font_print(GSGLOBAL *gsGlobal, float X, float Y, int Z, unsigned long color, char *String) 91 | { 92 | u64 oldalpha = gsGlobal->PrimAlpha; 93 | u8 oldpabe = gsGlobal->PABE; 94 | 95 | u8 fixate = 0; 96 | 97 | //u64 oldalpha = gsGlobal->PrimAlpha; 98 | //gsGlobal->PrimAlpha=ALPHA_BLEND_ADD; 99 | gsKit_set_primalpha(gsGlobal, GS_SETREG_ALPHA(0,1,0,1,0), 0); 100 | 101 | if(gsGlobal->Test->ATE) { 102 | gsKit_set_test(gsGlobal, GS_ATEST_OFF); 103 | fixate = 1; 104 | } 105 | 106 | int cx,cy,i,l; 107 | char c; 108 | cx=X; 109 | cy=Y; 110 | l=strlen( String ); 111 | for( i=0;iInterlace == GS_INTERLACED) { 126 | gsKit_prim_sprite_texture(gsGlobal, &FONT_TEX, cx, cy, 127 | px*fontdata.CharWidth+1, py*fontdata.CharHeight+1, 128 | cx+fontdata.CharWidth, cy+fontdata.CharHeight, 129 | (px+1)*fontdata.CharWidth, (py+1)*fontdata.CharHeight, 130 | Z, color); 131 | } 132 | if(gsGlobal->Interlace == GS_NONINTERLACED) { 133 | gsKit_prim_sprite_texture(gsGlobal, &FONT_TEX, cx, cy, 134 | px*fontdata.CharWidth+1, py*fontdata.CharHeight, 135 | cx+fontdata.CharWidth, cy+fontdata.CharHeight, 136 | (px+1)*fontdata.CharWidth, (py+1)*fontdata.CharHeight-1, 137 | Z, color); 138 | } 139 | cx+=charsiz+1; 140 | } 141 | } 142 | if(fixate) 143 | gsKit_set_test(gsGlobal, GS_ATEST_ON); 144 | 145 | gsGlobal->PABE = oldpabe; 146 | gsGlobal->PrimAlpha=oldalpha; 147 | // gsKit_set_primalpha(gsGlobal, gsGlobal->PrimAlpha, gsGlobal->PABE); 148 | //gsKit_set_primalpha(gsGlobal, gsGlobal->PrimAlpha, gsGlobal->PABE); 149 | }*/ 150 | 151 | int loadFont(char *path_arg) 152 | { 153 | /* int fd; 154 | 155 | if(strlen(path_arg) != 0 ){ 156 | char FntPath[1025]; 157 | genFixPath(path_arg, FntPath); 158 | fd = genOpen( FntPath, O_RDONLY ); 159 | if(fd < 0){ 160 | genClose( fd ); 161 | goto use_default; 162 | } // end if failed open file 163 | genLseek( fd, 0, SEEK_SET ); 164 | if(genLseek( fd, 0, SEEK_END ) > 4700){ 165 | genClose( fd ); 166 | goto use_default; 167 | } 168 | genLseek( fd, 0, SEEK_SET ); 169 | u8 FontHeader[100]; 170 | genRead( fd, FontHeader, 100 ); 171 | if((FontHeader[ 0]==0x00) && 172 | (FontHeader[ 1]==0x02) && 173 | (FontHeader[70]==0x60) && 174 | (FontHeader[72]==0x60) && 175 | (FontHeader[83]==0x90)){ 176 | genLseek( fd, 1018, SEEK_SET ); 177 | if(FontBuffer) 178 | free(FontBuffer); 179 | FontBuffer = malloc( 4096 + 1 ); 180 | genRead( fd, FontBuffer+32*16, 3584 ); // First 32 Chars Are Not Present In .fnt Files 181 | genClose( fd ); 182 | free(FontHeader); 183 | return 1; 184 | }else{ // end if good fnt file 185 | genClose( fd ); 186 | free(FontHeader); 187 | goto use_default; 188 | } // end else bad fnt file 189 | }else{ // end if external font file*/ 190 | //use_default: 191 | if (FontBuffer) 192 | free(FontBuffer); 193 | FontBuffer = malloc(4096 + 1); 194 | memcpy(FontBuffer, &font_uLE, 4096); 195 | //} // end else build-in font 196 | return 0; 197 | } 198 | 199 | void drawChar(unsigned int c, int x, int y, int z, u64 colour) 200 | { 201 | int i, j, pixBase, pixMask; 202 | u8 *cm; 203 | 204 | // if (gsGlobal->Interlace == GS_NONINTERLACED) { 205 | y = y & -2; 206 | // } 207 | 208 | if (c >= FONT_COUNT) 209 | c = '_'; 210 | if (c > 0xFF) // If char is beyond normal ascii range 211 | cm = &font_uLE[c * 16]; // cm points to special char def in default font 212 | else // Else char is inside normal ascii range 213 | cm = &FontBuffer[c * 16]; // cm points to normal char def in active font 214 | 215 | pixMask = 0x80; 216 | for (i = 0; i < 8; i++) { // For i == each pixel column 217 | pixBase = -1; 218 | for (j = 0; j < 16; j++) { // For j == each pixel row 219 | if ((pixBase < 0) && (cm[j] & pixMask)) { // If start of sequence 220 | pixBase = j; 221 | } 222 | else if ((pixBase > -1) && !(cm[j] & pixMask)) { // If end of sequence 223 | gsKit_prim_sprite(gsGlobal, x + i, y + pixBase - 1, x + i + 1, y + j - 1, z, colour); 224 | pixBase = -1; 225 | } 226 | } // Ends for j == each pixel row 227 | if (pixBase > -1) // If end of sequence including final row 228 | gsKit_prim_sprite(gsGlobal, x + i, y + pixBase - 1, x + i + 1, y + j - 1, z, colour); 229 | pixMask >>= 1; 230 | } // Ends for i == each pixel column 231 | } 232 | 233 | #define SCREEN_MARGIN 6 234 | #define FONT_WIDTH 8 235 | 236 | int printXY(const char *s, int x, int y, int z, u64 colour, int draw, int space) 237 | { 238 | unsigned int c1, c2; 239 | int i; 240 | int text_spacing = 8; 241 | 242 | if (space > 0) { 243 | while ((strlen(s) * text_spacing) > space) 244 | if (--text_spacing <= 5) 245 | break; 246 | } else { 247 | while ((strlen(s) * text_spacing) > gsGlobal->Width - SCREEN_MARGIN - FONT_WIDTH * 2) 248 | if (--text_spacing <= 5) 249 | break; 250 | } 251 | 252 | i = 0; 253 | while ((c1 = (unsigned char)s[i++]) != 0) { 254 | if (c1 != 0xFF) { // Normal character 255 | if (draw) 256 | drawChar(c1, x, y, z, colour); 257 | x += text_spacing; 258 | if (x > gsGlobal->Width - SCREEN_MARGIN - FONT_WIDTH) 259 | break; 260 | continue; 261 | } // End if for normal character 262 | // Here we got a sequence starting with 0xFF ('�') 263 | if ((c2 = (unsigned char)s[i++]) == 0) 264 | break; 265 | if ((c2 < '0') || (c2 > '=')) 266 | continue; 267 | c1 = (c2 - '0') * 2 + 0x100; 268 | if (draw) { 269 | // Expand sequence �0=Circle �1=Cross �2=Square �3=Triangle �4=FilledBox 270 | // "�:"=Pad_Right "�;"=Pad_Down "�<"=Pad_Left "�="=Pad_Up 271 | drawChar(c1, x, y, z, colour); 272 | x += 8; 273 | if (x > gsGlobal->Width - SCREEN_MARGIN - FONT_WIDTH) 274 | break; 275 | drawChar(c1 + 1, x, y, z, colour); 276 | x += 8; 277 | if (x > gsGlobal->Width - SCREEN_MARGIN - FONT_WIDTH) 278 | break; 279 | } 280 | } // Ends while(1) 281 | return x; 282 | } 283 | -------------------------------------------------------------------------------- /ym2413.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2000 Charles Mac Donald 3 | 4 | This program is free software; you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation; either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | 18 | YM2413 (OPLL) emulator 19 | by Charles Mac Donald 20 | E-mail: cgfm2@hooked.net 21 | WWW: http://cgfm2.emuviews.com 22 | 23 | Change log: 24 | 25 | [061300] 26 | - Fixed bug where channel numbers larger than 9 could be written to 27 | register groups $10-18, $20-28, $30-38. 28 | 29 | [060800] 30 | - Now the YM2413 chip number is passed to the OPL_WRITE macro, 31 | and the user instrument data is stored in the YM2413 context, 32 | both for multiple YM2413 emulation. 33 | 34 | [060100] 35 | - Added alternate instrument table taken from Allegro's 'fm_inst.h'. 36 | - Changed source so it can compile seperately from SMS Plus. 37 | - Added 'ym2413_reset' function and changed ym2413_init. 38 | 39 | Known issues: 40 | 41 | - The sustain on/off flag (bit 5 of register group $20-28) is not 42 | emulated. According to the manual, the release rate is set to 43 | five when this bit is set. 44 | 45 | - The table of fixed instrument values probably need to be compared 46 | against a real YM2413, so they can be hand-tuned. 47 | 48 | - The rhythm instruments sound good, but are too loud. 49 | The same settings are used for channels 7, 8, 9, which can't be right. 50 | 51 | I based the YM2413 emulation on the following documents. If you want 52 | to improve it or make changes, I'd advise reading the following: 53 | 54 | - Yamaha's YMF-272 (OPL-3) programmer's manual. (ymf272.pdf) 55 | (Has useful table of how the operators map to YM3812 registers) 56 | 57 | - Yamaha's YM2413 programmer's manual. (ym2413.lzh) 58 | 59 | - Vladimir Arnost's OPL-3 programmer's guide. (opl3.txt) 60 | (Explains operator allocation in rhythm mode) 61 | 62 | - The YM2413 emulation from MAME. (ym2413.c/2413intf.h) 63 | */ 64 | 65 | #include "shared.h" 66 | 67 | /* You can replace this to output to another YM3812 emulator 68 | or a perhaps a real OPL-2/OPL-3 sound chip */ 69 | #if USE_ADLIB 70 | #define OPL_WRITE(c,r,d) { outp(0x388+c*2, r); outp(0x389+c*2, d); } 71 | #else 72 | #define OPL_WRITE(c,r,d) OPLWriteReg(ym3812, r, d) 73 | #endif 74 | 75 | /* YM2413 chip contexts */ 76 | t_ym2413 ym2413[MAX_YM2413]; 77 | 78 | /* Fixed instrument settings, from MAME's YM2413 emulation */ 79 | /* This might need some tweaking... */ 80 | unsigned char table[16][11] = 81 | { 82 | /* 20 23 40 43 60 63 80 83 E0 E3 C0 */ 83 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 84 | #if 1 /* Instrument settings from MAME */ 85 | { 0x01, 0x22, 0x23, 0x07, 0xF0, 0xF0, 0x07, 0x18, 0x00, 0x00, 0x00 }, 86 | { 0x23, 0x01, 0x68, 0x05, 0xF2, 0x74, 0x6C, 0x89, 0x00, 0x00, 0x00 }, 87 | { 0x13, 0x11, 0x25, 0x00, 0xD2, 0xB2, 0xF4, 0xF4, 0x00, 0x00, 0x00 }, 88 | { 0x22, 0x21, 0x1B, 0x05, 0xC0, 0xA1, 0x18, 0x08, 0x00, 0x00, 0x00 }, 89 | { 0x22, 0x21, 0x2C, 0x03, 0xD2, 0xA1, 0x18, 0x57, 0x00, 0x00, 0x00 }, 90 | { 0x01, 0x22, 0xBA, 0x01, 0xF1, 0xF1, 0x1E, 0x04, 0x00, 0x00, 0x00 }, 91 | { 0x21, 0x21, 0x28, 0x06, 0xF1, 0xF1, 0x6B, 0x3E, 0x00, 0x00, 0x00 }, 92 | { 0x27, 0x21, 0x60, 0x00, 0xF0, 0xF0, 0x0D, 0x0F, 0x00, 0x00, 0x00 }, 93 | { 0x20, 0x21, 0x2B, 0x06, 0x85, 0xF1, 0x6D, 0x89, 0x00, 0x00, 0x00 }, 94 | { 0x01, 0x21, 0xBF, 0x02, 0x53, 0x62, 0x5F, 0xAE, 0x01, 0x00, 0x00 }, 95 | { 0x23, 0x21, 0x70, 0x07, 0xD4, 0xA3, 0x4E, 0x64, 0x01, 0x00, 0x00 }, 96 | { 0x2B, 0x21, 0xA4, 0x07, 0xF6, 0x93, 0x5C, 0x4D, 0x00, 0x00, 0x00 }, 97 | { 0x21, 0x23, 0xAD, 0x07, 0x77, 0xF1, 0x18, 0x37, 0x00, 0x00, 0x00 }, 98 | { 0x21, 0x21, 0x2A, 0x03, 0xF3, 0xE2, 0x29, 0x46, 0x00, 0x00, 0x00 }, 99 | { 0x21, 0x23, 0x37, 0x03, 0xF3, 0xE2, 0x29, 0x46, 0x00, 0x00, 0x00 }, 100 | #else /* Instrument settings from Allegro */ 101 | { 0x31, 0x21, 0x15, 0x09, 0xdd, 0x56, 0x13, 0x26, 0x01, 0x00, 0x08 }, /* Violin */ 102 | { 0x03, 0x11, 0x54, 0x09, 0xf3, 0xf1, 0x9a, 0xe7, 0x01, 0x00, 0x0c }, /* Acoustic Guitar(steel) */ 103 | { 0x21, 0x21, 0x8f, 0x0c, 0xf2, 0xf2, 0x45, 0x76, 0x00, 0x00, 0x08 }, /* Acoustic Grand */ 104 | { 0xe1, 0xe1, 0x46, 0x09, 0x88, 0x65, 0x5f, 0x1a, 0x00, 0x00, 0x00 }, /* Flute */ 105 | { 0x32, 0x21, 0x90, 0x09, 0x9b, 0x72, 0x21, 0x17, 0x00, 0x00, 0x04 }, /* Clarinet */ 106 | { 0x21, 0x21, 0x4b, 0x09, 0xaa, 0x8f, 0x16, 0x0a, 0x01, 0x00, 0x08 }, /* Oboe */ 107 | { 0x21, 0x21, 0x92, 0x0a, 0x85, 0x8f, 0x17, 0x09, 0x00, 0x00, 0x0c }, /* Trumpet */ 108 | { 0x23, 0xb1, 0x93, 0x09, 0x97, 0x55, 0x23, 0x14, 0x01, 0x00, 0x04 }, /* Church Organ */ 109 | { 0x21, 0x21, 0x9b, 0x09, 0x61, 0x7f, 0x6a, 0x0a, 0x00, 0x00, 0x02 }, /* French Horn */ 110 | { 0x71, 0x72, 0x57, 0x09, 0x54, 0x7a, 0x05, 0x05, 0x00, 0x00, 0x0c }, /* Synth Voice */ 111 | { 0x21, 0x36, 0x80, 0x17, 0xa2, 0xf1, 0x01, 0xd5, 0x00, 0x00, 0x08 }, /* Harpsichord */ 112 | { 0x18, 0x81, 0x62, 0x09, 0xf3, 0xf2, 0xe6, 0xf6, 0x00, 0x00, 0x00 }, /* Vibraphone */ 113 | { 0x31, 0x31, 0x8b, 0x09, 0xf4, 0xf1, 0xe8, 0x78, 0x00, 0x00, 0x0a }, /* Synth Bass 1 */ 114 | { 0x21, 0xa2, 0x1e, 0x09, 0x94, 0xc3, 0x06, 0xa6, 0x00, 0x00, 0x02 }, /* Acoustic Bass */ 115 | { 0x03, 0x21, 0x87, 0x89, 0xf6, 0xf3, 0x22, 0xf8, 0x01, 0x00, 0x06 }, /* Electric Guitar(clean) */ 116 | #endif 117 | }; 118 | 119 | 120 | /*--------------------------------------------------------------------------*/ 121 | 122 | 123 | void ym2413_init(int count) 124 | { 125 | int n; 126 | for(n = 0; n < count; n += 1) 127 | { 128 | /* Reset YM2413 data */ 129 | ym2413_reset(n); 130 | } 131 | } 132 | 133 | 134 | void ym2413_reset(int chip) 135 | { 136 | int n; 137 | 138 | /* Point to current YM2413 context */ 139 | t_ym2413 *opll = &ym2413[chip]; 140 | 141 | /* Clear channel data context */ 142 | memset(opll, 0, sizeof(t_ym2413)); 143 | 144 | /* Clear all YM3812 registers */ 145 | for(n = 0; n < 0x100; n += 1) 146 | { 147 | OPL_WRITE(chip, n, 0x00); 148 | } 149 | 150 | /* Turn off rhythm mode and key-on bits */ 151 | opll->rhythm = 0; 152 | OPL_WRITE(chip, 0xBD, 0x00); 153 | 154 | /* Enable waveform select */ 155 | OPL_WRITE(chip, 0x01, 0x20); 156 | } 157 | 158 | 159 | void ym2413_write(int chip, int address, int data) 160 | { 161 | /* Point to current YM2413 context */ 162 | t_ym2413 *opll = &ym2413[chip]; 163 | 164 | if(address & 1) /* Data port */ 165 | { 166 | /* Store register data */ 167 | opll->reg[opll->latch] = data; 168 | 169 | switch(opll->latch & 0x30) 170 | { 171 | case 0x00: /* User instrument registers */ 172 | switch(opll->latch & 0x0F) 173 | { 174 | case 0x00: /* Misc. ctrl. (modulator) */ 175 | case 0x01: /* Misc. ctrl. (carrier) */ 176 | case 0x02: /* Key scale level and total level (modulator) */ 177 | case 0x04: /* Attack / Decay (modulator) */ 178 | case 0x05: /* Attack / Decay (carrier) */ 179 | case 0x06: /* Sustain / Release (modulator) */ 180 | case 0x07: /* Sustain / Release (carrier) */ 181 | opll->user[(opll->latch & 0x07)] = data; 182 | break; 183 | 184 | case 0x03: /* Key scale level, carrier/modulator waveform, feedback */ 185 | 186 | /* Key scale level (carrier) */ 187 | /* Don't touch the total level (channel volume) */ 188 | opll->user[3] = (opll->user[3] & 0x3F) | (data & 0xC0); 189 | 190 | /* Waveform select for the modulator */ 191 | opll->user[8] = (data >> 3) & 1; 192 | 193 | /* Waveform select for the carrier */ 194 | opll->user[9] = (data >> 4) & 1; 195 | 196 | /* Store feedback level in YM3812 format */ 197 | opll->user[10] = ((data & 0x07) << 1) & 0x0E; 198 | break; 199 | 200 | case 0x0E: /* Rhythm enable and key-on bits */ 201 | if((data & 0x20) && (opll->rhythm == 0)) 202 | { 203 | opll->rhythm = 1; 204 | rhythm_mode_init(chip); 205 | } 206 | else 207 | { 208 | opll->rhythm = 0; 209 | } 210 | OPL_WRITE(chip, 0xBD, (data & 0x3F)); 211 | break; 212 | } 213 | 214 | /* If the user instrument registers were accessed, then 215 | go through each channel and update the ones that were 216 | currently using the user instrument. We can skip the 217 | last three channels in rhythm mode since they can 218 | only use percussion sounds anyways. */ 219 | if(opll->latch <= 0x07) 220 | { 221 | int x; 222 | for(x = 0; x < ((opll->reg[0x0E] & 0x20) ? 6 : 9); x += 1) 223 | if(opll->channel[x].instrument == 0x00) 224 | load_instrument(chip, x, 0x00, opll->channel[x].volume); 225 | } 226 | break; 227 | 228 | case 0x10: /* Channel Frequency (LSB) */ 229 | case 0x20: /* Channel Frequency (MSB) + key-on and sustain control */ 230 | { 231 | int block; 232 | int frequency; 233 | int ch = (opll->latch & 0x0F); 234 | 235 | /* Ensure proper channel range */ 236 | if(ch > 0x08) break; 237 | 238 | /* Get YM2413 channel frequency */ 239 | frequency = ((opll->reg[0x10 + ch] & 0xFF) | ((opll->reg[0x20 + ch] & 0x01) << 8)); 240 | 241 | /* Scale 9 bit frequency to 10 bits */ 242 | frequency = (frequency << 1) & 0x1FFF; 243 | 244 | /* Get YM2413 block */ 245 | block = (opll->reg[0x20 + ch] >> 1) & 7; 246 | 247 | /* Add in block */ 248 | frequency |= (block << 10); 249 | 250 | /* Add key-on flag */ 251 | if(opll->reg[0x20 + ch] & 0x10) frequency |= 0x2000; 252 | 253 | /* Save current frequency/block/key-on setting */ 254 | opll->channel[ch].frequency = (frequency & 0x3FFF); 255 | 256 | /* TODO: Handle sustain flag (bit 5) before key-on */ 257 | 258 | /* Write changes to YM3812 */ 259 | OPL_WRITE(chip, 0xA0 + ch, (opll->channel[ch].frequency >> 0) & 0xFF); 260 | OPL_WRITE(chip, 0xB0 + ch, (opll->channel[ch].frequency >> 8) & 0xFF); 261 | } 262 | break; 263 | 264 | case 0x30: /* Channel Volume Level and Instrument Select */ 265 | 266 | /* Ensure proper channel range */ 267 | if(opll->latch > 0x38) break; 268 | 269 | /* If we're accessing registers 36, 37, or 38, and we're 270 | in rhythm mode, then update the individual volume 271 | settings. */ 272 | if((opll->latch >= 0x36) && (opll->reg[0x0E] & 0x20)) 273 | { 274 | switch(opll->latch & 0x0F) 275 | { 276 | case 0x06: /* Bass drum */ 277 | OPL_WRITE(chip, 0x53, ((data >> 0) & 0x0F) << 2); 278 | break; 279 | 280 | case 0x07: /* High hat and snare drum */ 281 | OPL_WRITE(chip, 0x51, ((data >> 4) & 0x0F) << 2); 282 | OPL_WRITE(chip, 0x54, ((data >> 0) & 0x0F) << 2); 283 | break; 284 | 285 | case 0x08: /* Tom-top and top cymbal */ 286 | OPL_WRITE(chip, 0x52, ((data >> 4) & 0x0F) << 2); 287 | OPL_WRITE(chip, 0x55, ((data >> 0) & 0x0F) << 2); 288 | break; 289 | } 290 | } 291 | else /* Set the new instrument and volume for this channel */ 292 | { 293 | int ch = (opll->latch & 0x0F); 294 | int inst = (data >> 4) & 0x0F; 295 | int vol = (data & 0x0F) << 2; 296 | 297 | load_instrument(chip, ch, inst, vol); 298 | } 299 | break; 300 | } 301 | } 302 | else /* Register latch */ 303 | { 304 | opll->latch = (data & 0x3F); 305 | } 306 | } 307 | 308 | 309 | void rhythm_mode_init(int chip) 310 | { 311 | /* Point to current YM2413 context */ 312 | t_ym2413 *opll = &ym2413[chip]; 313 | 314 | /* Load instrument settings for channel seven. (Bass drum) */ 315 | OPL_WRITE(chip, 0x30, 0x13); 316 | OPL_WRITE(chip, 0x33, 0x11); 317 | OPL_WRITE(chip, 0x50, 0x25); 318 | OPL_WRITE(chip, 0x53, ((opll->reg[0x36] >> 0) & 0x0F) << 2); 319 | OPL_WRITE(chip, 0x70, 0xD7); 320 | OPL_WRITE(chip, 0x73, 0xB7); 321 | OPL_WRITE(chip, 0x90, 0xF4); 322 | OPL_WRITE(chip, 0x93, 0xF4); 323 | OPL_WRITE(chip, 0xF0, 0x00); 324 | OPL_WRITE(chip, 0xF3, 0x00); 325 | OPL_WRITE(chip, 0xC6, 0x00); 326 | /* Use old frequency, but strip key-on bit */ 327 | OPL_WRITE(chip, 0xA6, (opll->channel[6].frequency >> 0) & 0xFF); 328 | OPL_WRITE(chip, 0xB6, (opll->channel[6].frequency >> 8) & 0x1F); 329 | 330 | /* Load instrument settings for channel eight. (High hat and snare drum) */ 331 | OPL_WRITE(chip, 0x31, 0x13); 332 | OPL_WRITE(chip, 0x34, 0x11); 333 | OPL_WRITE(chip, 0x51, ((opll->reg[0x37] >> 4) & 0x0f) << 2); 334 | OPL_WRITE(chip, 0x54, ((opll->reg[0x37] >> 0) & 0x0f) << 2); 335 | OPL_WRITE(chip, 0x71, 0xD7); 336 | OPL_WRITE(chip, 0x74, 0xB7); 337 | OPL_WRITE(chip, 0x91, 0xF4); 338 | OPL_WRITE(chip, 0x94, 0xF4); 339 | OPL_WRITE(chip, 0xF1, 0x00); 340 | OPL_WRITE(chip, 0xF4, 0x00); 341 | OPL_WRITE(chip, 0xC7, 0x00); 342 | /* Use old frequency, but strip key-on bit */ 343 | OPL_WRITE(chip, 0xA7, (opll->channel[7].frequency >> 0) & 0xFF); 344 | OPL_WRITE(chip, 0xB7, (opll->channel[7].frequency >> 8) & 0x1F); 345 | 346 | /* Load instrument settings for channel nine. (Tom-tom and top cymbal) */ 347 | OPL_WRITE(chip, 0x32, 0x13); 348 | OPL_WRITE(chip, 0x35, 0x11); 349 | OPL_WRITE(chip, 0x52, ((opll->reg[0x38] >> 4) & 0x0F) << 2); 350 | OPL_WRITE(chip, 0x55, ((opll->reg[0x38] >> 0) & 0x0F) << 2); 351 | OPL_WRITE(chip, 0x72, 0xD7); 352 | OPL_WRITE(chip, 0x75, 0xB7); 353 | OPL_WRITE(chip, 0x92, 0xF4); 354 | OPL_WRITE(chip, 0x95, 0xF4); 355 | OPL_WRITE(chip, 0xF2, 0x00); 356 | OPL_WRITE(chip, 0xF5, 0x00); 357 | OPL_WRITE(chip, 0xC8, 0x00); 358 | /* Use old frequency, but strip key-on bit */ 359 | OPL_WRITE(chip, 0xA8, (opll->channel[8].frequency >> 0) & 0xFF); 360 | OPL_WRITE(chip, 0xB8, (opll->channel[8].frequency >> 8) & 0x1F); 361 | } 362 | 363 | 364 | /* channel (0-9), instrument (0-F), volume (0-3F, YM3812 format) */ 365 | void load_instrument(int chip, int ch, int inst, int vol) 366 | { 367 | /* Point to current YM2413 context */ 368 | t_ym2413 *opll = &ym2413[chip]; 369 | 370 | /* Point to fixed instrument or user table */ 371 | unsigned char *param = (inst == 0) ? &opll->user[0] : &table[inst][0]; 372 | 373 | /* Maps channels to operator registers */ 374 | unsigned char ch2op[] = {0, 1, 2, 8, 9, 10, 16, 17, 18}; 375 | 376 | /* Make operator offset from requested channel */ 377 | int op = ch2op[ch]; 378 | 379 | /* Store volume level */ 380 | opll->channel[ch].volume = (vol & 0x3F); 381 | 382 | /* Store instrument number */ 383 | opll->channel[ch].instrument = (inst & 0x0F); 384 | 385 | /* Update instrument settings, except frequency registers */ 386 | OPL_WRITE(chip, 0x20 + op, param[0]); 387 | OPL_WRITE(chip, 0x23 + op, param[1]); 388 | OPL_WRITE(chip, 0x40 + op, param[2]); 389 | OPL_WRITE(chip, 0x43 + op, (param[3] & 0xC0) | opll->channel[ch].volume); 390 | OPL_WRITE(chip, 0x60 + op, param[4]); 391 | OPL_WRITE(chip, 0x63 + op, param[5]); 392 | OPL_WRITE(chip, 0x80 + op, param[6]); 393 | OPL_WRITE(chip, 0x83 + op, param[7]); 394 | OPL_WRITE(chip, 0xE0 + op, param[8]); 395 | OPL_WRITE(chip, 0xE3 + op, param[9]); 396 | OPL_WRITE(chip, 0xC0 + ch, param[10]); 397 | } 398 | -------------------------------------------------------------------------------- /psms.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | psms.c - PSMS Reloaded main source file. Contains PSMS core. 4 | 5 | (c) Nick Van Veen (aka Sjeep), 2002 6 | (c) Bruno Freitas (bootsector), 2008 7 | 8 | ------------------------------------------------------------------------- 9 | 10 | This file is part of the PSMS. 11 | 12 | PSMS is free software; you can redistribute it and/or modify 13 | it under the terms of the GNU General Public License as published by 14 | the Free Software Foundation; either version 2 of the License, or 15 | (at your option) any later version. 16 | 17 | PSMS is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU General Public License for more details. 21 | 22 | You should have received a copy of the GNU General Public License 23 | along with Foobar; if not, write to the Free Software 24 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25 | 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include "shared.h" 41 | #include 42 | #include "psms.h" 43 | #include "sjpcm.h" 44 | #include "browser.h" 45 | #include "init.h" 46 | #include "ps2font.h" 47 | #include "pad.h" 48 | #include "bdraw.h" 49 | #include "cnfsettings.h" 50 | #include "zlib.h" 51 | 52 | void Ingame_Menu(void); 53 | 54 | #define SND_RATE 48000 55 | 56 | GSGLOBAL *gsGlobal; 57 | extern skin FCEUSkin; 58 | extern vars Settings; 59 | GSTEXTURE SMSTEX; 60 | 61 | u8 bitmap_data[256 * 256] __attribute__((aligned(128))) __attribute__ ((section (".bss"))); // SMS display is only 256x192, extra data is padding 62 | //u16 clut[256] __attribute__((aligned(16))) __attribute__ ((section (".bss"))); 63 | u32 clut[256] __attribute__((aligned(128))) __attribute__ ((section (".bss"))); 64 | 65 | u8 base_rom[1048576] __attribute__((aligned(64))) __attribute__ ((section (".bss"))); 66 | 67 | extern char path[4096]; 68 | extern u32 old_pad[2]; 69 | 70 | u8 *state; 71 | int state_saved = 0; 72 | 73 | int whichdrawbuf = 0; 74 | int endflag = 0; 75 | int sound = 1; 76 | int snd_sample = 0; 77 | 78 | char rom_filename[1024]; 79 | 80 | int main() 81 | { 82 | char *temp; 83 | 84 | init_machine(); 85 | 86 | system_init(SND_RATE); 87 | 88 | setupSMSTexture(); 89 | 90 | while(1) { 91 | 92 | strcpy(rom_filename,Browser(1,0,1)); 93 | 94 | if(load_rom(rom_filename)) { 95 | continue; // if error loading file, start loop again (ie, go back to menu) 96 | } 97 | 98 | system_reset(); 99 | 100 | setupSMSGS(); 101 | 102 | if(sound) { 103 | SjPCM_Clearbuff(); 104 | SjPCM_Play(); 105 | } 106 | 107 | while(1) 108 | { 109 | /* Get current input */ 110 | update_input(); 111 | 112 | if(endflag) break; 113 | 114 | /* Run the SMS emulation for a frame */ 115 | sms_frame(0); 116 | 117 | if(sound) SjPCM_Enqueue(snd.buffer[0], snd.buffer[1], snd_sample, 1); 118 | 119 | /* Update the display if desired */ 120 | update_video(); 121 | } 122 | 123 | if(sound) SjPCM_Pause(); 124 | 125 | psms_manage_sram(sms.sram, SRAM_SAVE); 126 | 127 | system_reset(); 128 | endflag = 0; 129 | state_saved = 0; 130 | 131 | temp = strrchr(path,'/'); 132 | temp++; 133 | *temp = 0; 134 | } 135 | } 136 | 137 | 138 | int init_machine() 139 | { 140 | int i, sometime; 141 | 142 | InitPS2(); 143 | setupPS2Pad(); 144 | 145 | Default_Global_CNF(); 146 | 147 | Load_Global_CNF("mc0:/PSMS/PSMS.CNF"); 148 | 149 | if(Settings.display) // PAL 150 | snd_sample = SND_RATE / 50; 151 | else // NTSC 152 | snd_sample = SND_RATE / 60; 153 | 154 | for (i = 0; i < 3; i++) { 155 | sometime = 0x10000; 156 | while(sometime--) asm("nop\nnop\nnop\nnop"); 157 | } 158 | 159 | SetupGSKit(); 160 | 161 | gsKit_init_screen(gsGlobal); //initialize everything 162 | init_custom_screen(); //init user screen settings 163 | 164 | loadFont(0); 165 | 166 | Default_Skin_CNF(); 167 | 168 | /* Initialize display bitmap */ 169 | memset(&bitmap, 0, sizeof(t_bitmap)); 170 | bitmap.width = 256; 171 | bitmap.height = 192; 172 | bitmap.depth = 8; 173 | bitmap.pitch = (bitmap.width * (bitmap.depth >> 3)); 174 | bitmap.data = (unsigned char *)&bitmap_data[0]; 175 | 176 | memset(&base_rom,0,1048576); 177 | 178 | state = malloc(sizeof(t_vdp) + sizeof(t_sms) + sizeof(Z80_Regs) + sizeof(int) + sizeof(t_SN76496) + 0x40); 179 | if(state == NULL) { 180 | display_error("Failed to allocate memory!", 1); 181 | } 182 | 183 | 184 | if(SjPCM_Init() < 0) display_error("SjPCM Bind failed!!", 1); 185 | 186 | 187 | return 0; 188 | } 189 | 190 | int load_rom(char* fname) 191 | { 192 | char filename[1024]; 193 | FILE *fd; 194 | long fd_size; 195 | 196 | memset(&base_rom,0,1048576); 197 | 198 | strcpy(filename, fname); 199 | 200 | fd = fopen(filename, "rb"); 201 | if(fd == NULL) { 202 | display_error("Error opening file.",0); 203 | return 1; 204 | } 205 | 206 | fseek(fd,0,SEEK_END); 207 | fd_size = ftell(fd); 208 | fseek(fd,0,SEEK_SET); 209 | 210 | if(fd_size%32768) { // skip 512k header if necessary 211 | fseek(fd,512,SEEK_SET); 212 | fd_size -= 512; 213 | } 214 | 215 | if(fread(base_rom, fd_size, 1, fd) != 1) { 216 | display_error("Short file.",0); 217 | return 1; 218 | } 219 | 220 | fclose(fd); 221 | 222 | if(strstr(strupr(filename), ".GG") != NULL) 223 | cart.type = TYPE_GG; 224 | else 225 | cart.type = TYPE_SMS; 226 | 227 | cart.rom = (char *)&base_rom; 228 | cart.pages = (fd_size / 0x4000); 229 | 230 | return 0; 231 | 232 | } 233 | 234 | void setupSMSTexture(void) { 235 | SMSTEX.PSM = GS_PSM_T8; 236 | SMSTEX.ClutPSM = GS_PSM_CT32; 237 | SMSTEX.Clut = (u32 *)clut; 238 | SMSTEX.VramClut = gsKit_vram_alloc(gsGlobal, gsKit_texture_size(16, 16, SMSTEX.ClutPSM), GSKIT_ALLOC_USERBUFFER); 239 | SMSTEX.Width = 256; 240 | SMSTEX.Height = 256; 241 | SMSTEX.TBW = 4; //256; 242 | SMSTEX.Vram = gsKit_vram_alloc(gsGlobal, gsKit_texture_size(SMSTEX.Width, SMSTEX.Height, SMSTEX.PSM), GSKIT_ALLOC_USERBUFFER); 243 | } 244 | 245 | void setupSMSGS(void) 246 | { 247 | gsGlobal->DrawOrder = GS_OS_PER; 248 | gsKit_mode_switch(gsGlobal, GS_PERSISTENT); 249 | gsKit_queue_reset(gsGlobal->Per_Queue); 250 | 251 | gsKit_clear(gsGlobal, GS_SETREG_RGBA(0x00,0x00,0x00,0x80)); 252 | 253 | if(Settings.filter) 254 | SMSTEX.Filter = GS_FILTER_LINEAR; 255 | else 256 | SMSTEX.Filter = GS_FILTER_NEAREST; 257 | 258 | gsKit_prim_sprite_texture(gsGlobal, &SMSTEX, 259 | (cart.type == TYPE_SMS)? 0.0f:15.0f, /* X1 */ 260 | (cart.type == TYPE_SMS)?20.0f:20.0f, /* Y1 */ 261 | (cart.type == TYPE_SMS)? 0.0f:48.0f, /* U1 */ 262 | (cart.type == TYPE_SMS)? 0.0f:24.0f, /* V1 */ 263 | gsGlobal->Width, /* X2 */ //stretch to screen width 264 | gsGlobal->Height, /* Y2 */ //stretch to screen height 265 | (cart.type == TYPE_SMS)?SMSTEX.Width:208, /* U2 */ 266 | (cart.type == TYPE_SMS)?192:173, //SMSTEX.Height, /* V2 */ 267 | 2, /* Z */ 268 | GS_SETREG_RGBA(0x80,0x80,0x80,0x80) /* RGBA */ 269 | ); 270 | // gsKit_prim_sprite_texture(gsGlobal, &SMSTEX, 271 | // 0.0f, /* X1 */ 272 | // 0.0f, /* Y1 */ 273 | // 0.0f, /* U1 */ 274 | // 0.0f, /* V1 */ 275 | // gsGlobal->Width, /* X2 */ //stretch to screen width 276 | // gsGlobal->Height, /* Y2 */ //stretch to screen height 277 | // SMSTEX.Width, /* U2 */ 278 | // SMSTEX.Height, /* V2 */ 279 | // 2, /* Z */ 280 | // GS_SETREG_RGBA(0x80,0x80,0x80,0x80) /* RGBA */ 281 | // ); 282 | vdp.limit = Settings.sprite_limit; 283 | } 284 | 285 | void update_video() 286 | { 287 | SMSTEX.Mem = (u32 *)bitmap_data; 288 | 289 | gsKit_texture_upload(gsGlobal, &SMSTEX); 290 | 291 | /* vsync and flip buffer */ 292 | gsKit_sync_flip(gsGlobal); 293 | 294 | /* execute render queue */ 295 | gsKit_queue_exec(gsGlobal); 296 | } 297 | 298 | 299 | //void system_load_sram() {} 300 | 301 | void update_input() 302 | { 303 | static struct padButtonStatus pad1; // just in case 304 | static struct padButtonStatus pad2; 305 | static int pad1_connected = 0, pad2_connected = 0; 306 | static int p1_1t=0,p1_2t=0,p2_1t=0,p2_2t=0; 307 | int on = (Settings.autofire_pattern>>3) + 1; 308 | int off = (Settings.autofire_pattern &7) + 1; 309 | static u32 new_pad[2]; 310 | int pad1_data = 0; 311 | int pad2_data = 0; 312 | 313 | memset(&input, 0, sizeof(t_input)); 314 | 315 | if(pad1_connected) { 316 | padRead(0, 0, &pad1); // port, slot, buttons 317 | pad1_data = 0xffff ^ pad1.btns; 318 | new_pad[0] = pad1_data & ~old_pad[0]; 319 | old_pad[0] = pad1_data; 320 | //pad1_data = 0xffff ^ ((pad1.btns[0] << 8) | pad1.btns[1]); 321 | 322 | if(pad1_data & Settings.PlayerInput[0][7]) { 323 | if (p1_1t < on) { 324 | input.pad[0] |= INPUT_BUTTON1; 325 | } 326 | p1_1t = (p1_1t + 1) % (on + off); 327 | } 328 | else { 329 | p1_1t = 0; 330 | } 331 | if(pad1_data & Settings.PlayerInput[0][8]) { 332 | if (p1_2t < on) { 333 | input.pad[0] |= INPUT_BUTTON2; 334 | } 335 | p1_2t = (p1_2t + 1) % (on + off); 336 | } 337 | else { 338 | p1_2t = 0; 339 | } 340 | if(pad1_data & Settings.PlayerInput[0][1]) input.pad[0] |= INPUT_UP; 341 | if(pad1_data & Settings.PlayerInput[0][2]) input.pad[0] |= INPUT_DOWN; 342 | if(pad1_data & Settings.PlayerInput[0][3]) input.pad[0] |= INPUT_LEFT; 343 | if(pad1_data & Settings.PlayerInput[0][4]) input.pad[0] |= INPUT_RIGHT; 344 | if(pad1_data & Settings.PlayerInput[0][5]) input.pad[0] |= INPUT_BUTTON1; 345 | if(pad1_data & Settings.PlayerInput[0][6]) input.pad[0] |= INPUT_BUTTON2; 346 | if(pad1_data & Settings.PlayerInput[0][0]) input.system |= (IS_GG) ? INPUT_START : INPUT_PAUSE; 347 | 348 | if((pad1.mode >> 4) == 0x07) { 349 | if(pad1.ljoy_h < 64) input.pad[0] |= INPUT_LEFT; 350 | else if(pad1.ljoy_h > 192) input.pad[0] |= INPUT_RIGHT; 351 | 352 | if(pad1.ljoy_v < 64) input.pad[0] |= INPUT_UP; 353 | else if(pad1.ljoy_v > 192) input.pad[0] |= INPUT_DOWN; 354 | } 355 | } 356 | 357 | if(pad2_connected) { 358 | padRead(1, 0, &pad2); // port, slot, buttons 359 | pad2_data = 0xffff ^ pad2.btns; 360 | new_pad[1] = pad2_data & ~old_pad[1]; 361 | old_pad[1] = pad2_data; 362 | //pad2_data = 0xffff ^ ((pad2.btns[0] << 8) | pad2.btns[1]); 363 | 364 | if(pad2_data & Settings.PlayerInput[1][7]) { 365 | if (p2_1t < on) { 366 | input.pad[1] |= INPUT_BUTTON1; 367 | } 368 | p2_1t = (p2_1t + 1) % (on + off); 369 | } 370 | else { 371 | p2_1t = 0; 372 | } 373 | if(pad2_data & Settings.PlayerInput[1][8]) { 374 | if (p2_2t < on) { 375 | input.pad[1] |= INPUT_BUTTON2; 376 | } 377 | p2_2t = (p2_2t + 1) % (on + off); 378 | } 379 | else { 380 | p2_2t = 0; 381 | } 382 | if(pad2_data & Settings.PlayerInput[1][1]) input.pad[1] |= INPUT_UP; 383 | if(pad2_data & Settings.PlayerInput[1][2]) input.pad[1] |= INPUT_DOWN; 384 | if(pad2_data & Settings.PlayerInput[1][3]) input.pad[1] |= INPUT_LEFT; 385 | if(pad2_data & Settings.PlayerInput[1][4]) input.pad[1] |= INPUT_RIGHT; 386 | if(pad2_data & Settings.PlayerInput[1][5]) input.pad[1] |= INPUT_BUTTON1; 387 | if(pad2_data & Settings.PlayerInput[1][6]) input.pad[1] |= INPUT_BUTTON2; 388 | // if(pad2_data & Settings.PlayerInput[1][0]) input.system |= (IS_GG) ? INPUT_START : INPUT_PAUSE; 389 | 390 | if((pad2.mode >> 4) == 0x07) { 391 | if(pad2.ljoy_h < 64) input.pad[1] |= INPUT_LEFT; 392 | else if(pad2.ljoy_h > 192) input.pad[1] |= INPUT_RIGHT; 393 | 394 | if(pad2.ljoy_v < 64) input.pad[1] |= INPUT_UP; 395 | else if(pad2.ljoy_v > 192) input.pad[1] |= INPUT_DOWN; 396 | } 397 | } 398 | 399 | //check controller status 400 | if((padGetState(0, 0)) == PAD_STATE_STABLE) { 401 | if(pad1_connected == 0) { 402 | //WaitForNextVRstart(1); 403 | } 404 | pad1_connected = 1; 405 | } else pad1_connected = 0; 406 | 407 | if((padGetState(1, 0)) == PAD_STATE_STABLE) { 408 | if(pad2_connected == 0) { 409 | //WaitForNextVRstart(1); 410 | } 411 | pad2_connected = 1; 412 | } else pad2_connected = 0; 413 | 414 | if((new_pad[0] & Settings.PlayerInput[0][9])) { 415 | if(sound) SjPCM_Pause(); 416 | Ingame_Menu(); 417 | if(sound) SjPCM_Play(); 418 | } 419 | } 420 | 421 | 422 | void display_error(char* errmsg, int fatal) { 423 | printf("%s\n", errmsg); 424 | } 425 | 426 | char *FileBase(char *fname){ 427 | static char fb[21]; 428 | char *p; 429 | 430 | memset(fb, 0, sizeof(fb)); 431 | strncpy(fb, strrchr(fname, '/')+1, 20); 432 | 433 | p = strrchr(fb, '.'); 434 | 435 | if(p) *p = 0; 436 | 437 | return fb; 438 | } 439 | 440 | void psms_save_state(int slot) 441 | { 442 | FILE *fd; 443 | char filename[1024]; 444 | 445 | sprintf(filename, "%s%s%08X.sv%d", Settings.savepath, FileBase(rom_filename), (unsigned int)crc32(0, base_rom, 1048576), slot); 446 | 447 | fd = fopen(filename, "wb"); 448 | 449 | if(fd == NULL) 450 | return; 451 | 452 | //int pos = 0; 453 | 454 | /* Save VDP context */ 455 | fwrite(&vdp, sizeof(t_vdp), 1, fd); 456 | //memcpy(&state[pos],&vdp,sizeof(t_vdp)); 457 | //pos += sizeof(t_vdp); 458 | 459 | /* Save SMS context */ 460 | fwrite(&sms, sizeof(t_sms), 1, fd); 461 | //memcpy(&state[pos],&sms,sizeof(t_sms)); 462 | //pos += sizeof(t_sms); 463 | 464 | /* Save Z80 context */ 465 | fwrite(Z80_Context, sizeof(Z80_Regs), 1, fd); 466 | fwrite(&after_EI, sizeof(int), 1, fd); 467 | //memcpy(&state[pos],Z80_Context,sizeof(Z80_Regs)); 468 | //pos += sizeof(Z80_Regs); 469 | //memcpy(&state[pos],&after_EI,sizeof(int)); 470 | //pos += sizeof(int); 471 | 472 | /* Save YM2413 registers */ 473 | fwrite(&ym2413[0].reg[0], 0x40, 1, fd); 474 | //memcpy(&state[pos],&ym2413[0].reg[0],0x40); 475 | //pos += 0x40; 476 | 477 | /* Save SN76489 context */ 478 | fwrite(&sn[0], sizeof(t_SN76496), 1, fd); 479 | //memcpy(&state[pos],&sn[0],sizeof(t_SN76496)); 480 | //pos += sizeof(t_SN76496); 481 | 482 | fclose(fd); 483 | } 484 | 485 | void psms_load_state(int slot) 486 | { 487 | 488 | 489 | FILE *fd; 490 | char filename[1024]; 491 | 492 | sprintf(filename, "%s%s%08X.sv%d", Settings.savepath, FileBase(rom_filename), (unsigned int)crc32(0, base_rom, 1048576), slot); 493 | 494 | fd = fopen(filename, "rb"); 495 | 496 | if(fd == NULL) 497 | return; 498 | 499 | int i; 500 | byte reg[0x40]; 501 | //int pos = 0; 502 | 503 | /* Initialize everything */ 504 | cpu_reset(); 505 | system_reset(); 506 | 507 | /* Load VDP context */ 508 | fread(&vdp, sizeof(t_vdp), 1, fd); 509 | //memcpy(&vdp,&state[pos],sizeof(t_vdp)); 510 | //pos += sizeof(t_vdp); 511 | 512 | /* Load SMS context */ 513 | fread(&sms, sizeof(t_sms), 1, fd); 514 | //memcpy(&sms,&state[pos],sizeof(t_sms)); 515 | //pos += sizeof(t_sms); 516 | 517 | /* Load Z80 context */ 518 | fread(Z80_Context, sizeof(Z80_Regs), 1, fd); 519 | fread(&after_EI, sizeof(int), 1, fd); 520 | //memcpy(Z80_Context,&state[pos],sizeof(Z80_Regs)); 521 | //pos += sizeof(Z80_Regs); 522 | //memcpy(&after_EI,&state[pos],sizeof(int)); 523 | //pos += sizeof(int); 524 | 525 | /* Load YM2413 registers */ 526 | fread(reg, 0x40, 1, fd); 527 | //memcpy(reg,&state[pos],0x40); 528 | //pos += 0x40; 529 | 530 | /* Load SN76489 context */ 531 | fread(&sn[0], sizeof(t_SN76496), 1, fd); 532 | //memcpy(&sn[0],&state[pos],sizeof(t_SN76496)); 533 | //pos += sizeof(t_SN76496); 534 | 535 | fclose(fd); 536 | 537 | /* Restore callbacks */ 538 | z80_set_irq_callback(sms_irq_callback); 539 | 540 | cpu_readmap[0] = cart.rom + 0x0000; /* 0000-3FFF */ 541 | cpu_readmap[1] = cart.rom + 0x2000; 542 | cpu_readmap[2] = cart.rom + 0x4000; /* 4000-7FFF */ 543 | cpu_readmap[3] = cart.rom + 0x6000; 544 | cpu_readmap[4] = cart.rom + 0x0000; /* 0000-3FFF */ 545 | cpu_readmap[5] = cart.rom + 0x2000; 546 | cpu_readmap[6] = sms.ram; 547 | cpu_readmap[7] = sms.ram; 548 | 549 | cpu_writemap[0] = sms.dummy; 550 | cpu_writemap[1] = sms.dummy; 551 | cpu_writemap[2] = sms.dummy; 552 | cpu_writemap[3] = sms.dummy; 553 | cpu_writemap[4] = sms.dummy; 554 | cpu_writemap[5] = sms.dummy; 555 | cpu_writemap[6] = sms.ram; 556 | cpu_writemap[7] = sms.ram; 557 | 558 | sms_mapper_w(3, sms.fcr[3]); 559 | sms_mapper_w(2, sms.fcr[2]); 560 | sms_mapper_w(1, sms.fcr[1]); 561 | sms_mapper_w(0, sms.fcr[0]); 562 | 563 | /* Force full pattern cache update */ 564 | is_vram_dirty = 1; 565 | memset(vram_dirty, 1, 0x200); 566 | 567 | /* Restore palette */ 568 | for(i = 0; i < PALETTE_SIZE; i += 1) 569 | palette_sync(i); 570 | 571 | /* Restore sound state */ 572 | if(snd.enabled) 573 | { 574 | /* Restore YM2413 emulation */ 575 | OPLResetChip(ym3812); 576 | 577 | /* Clear YM2413 context */ 578 | ym2413_reset(0); 579 | 580 | /* Restore rhythm enable first */ 581 | ym2413_write(0, 0, 0x0E); 582 | ym2413_write(0, 1, reg[0x0E]); 583 | 584 | /* User instrument settings */ 585 | for(i = 0x00; i <= 0x07; i += 1) 586 | { 587 | ym2413_write(0, 0, i); 588 | ym2413_write(0, 1, reg[i]); 589 | } 590 | 591 | /* Channel frequency */ 592 | for(i = 0x10; i <= 0x18; i += 1) 593 | { 594 | ym2413_write(0, 0, i); 595 | ym2413_write(0, 1, reg[i]); 596 | } 597 | 598 | /* Channel frequency + ctrl. */ 599 | for(i = 0x20; i <= 0x28; i += 1) 600 | { 601 | ym2413_write(0, 0, i); 602 | ym2413_write(0, 1, reg[i]); 603 | } 604 | 605 | /* Instrument and volume settings */ 606 | for(i = 0x30; i <= 0x38; i += 1) 607 | { 608 | ym2413_write(0, 0, i); 609 | ym2413_write(0, 1, reg[i]); 610 | } 611 | } 612 | } 613 | 614 | void psms_manage_sram(u8 *sram, int mode) 615 | { 616 | char name[1024]; 617 | FILE *fd; 618 | 619 | sprintf(name, "%s%s%08X.srm", Settings.savepath, FileBase(rom_filename), (unsigned int)crc32(0, base_rom, 1048576)); 620 | 621 | // strcpy(name, game_name); 622 | // strcpy(strrchr(name, '.'), ".sav"); 623 | 624 | switch(mode) 625 | { 626 | case SRAM_SAVE: 627 | if(sms.save) 628 | { 629 | fd = fopen(name, "wb"); 630 | if(fd) 631 | { 632 | fwrite(sram, 0x8000, 1, fd); 633 | fclose(fd); 634 | } 635 | } 636 | break; 637 | 638 | case SRAM_LOAD: 639 | fd = fopen(name, "rb"); 640 | if(fd) 641 | { 642 | sms.save = 1; 643 | fread(sram, 0x8000, 1, fd); 644 | fclose(fd); 645 | } 646 | else 647 | { 648 | /* No SRAM file, so initialize memory */ 649 | memset(sram, 0x00, 0x8000); 650 | } 651 | break; 652 | } 653 | } 654 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 19yy 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) 19yy name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /render.c: -------------------------------------------------------------------------------- 1 | #include "shared.h" 2 | 3 | /* Background drawing function */ 4 | void (*render_bg)(int line); 5 | 6 | /* Pointer to output buffer */ 7 | byte *linebuf; 8 | 9 | /* Internal buffer for drawing non 8-bit displays */ 10 | static byte internal_buffer[0x100]; 11 | 12 | /* Precalculated pixel table */ 13 | static word pixel[PALETTE_SIZE]; 14 | 15 | /* Pattern cache */ 16 | static byte cache[0x20000]; 17 | 18 | /* Dirty pattern info */ 19 | byte vram_dirty[0x200]; 20 | byte is_vram_dirty; 21 | 22 | /* Pixel look-up table */ 23 | static byte lut[0x10000]; 24 | 25 | /* Attribute expansion table */ 26 | dword atex[4] = 27 | { 28 | 0x00000000, 29 | 0x10101010, 30 | 0x20202020, 31 | 0x30303030, 32 | }; 33 | 34 | extern u32 clut[256] __attribute__((aligned(128))) __attribute__ ((section (".bss"))); 35 | 36 | /* Display sizes */ 37 | int vp_vstart; 38 | int vp_vend; 39 | int vp_hstart; 40 | int vp_hend; 41 | 42 | 43 | /* Macros to access memory 32-bits at a time (from MAME's drawgfx.c) */ 44 | 45 | #ifdef ALIGN_DWORD 46 | 47 | static __inline__ dword read_dword(void *address) 48 | { 49 | if ((dword)address & 3) 50 | { 51 | #ifdef LSB_FIRST /* little endian version */ 52 | return ( *((byte *)address) + 53 | (*((byte *)address+1) << 8) + 54 | (*((byte *)address+2) << 16) + 55 | (*((byte *)address+3) << 24) ); 56 | #else /* big endian version */ 57 | return ( *((byte *)address+3) + 58 | (*((byte *)address+2) << 8) + 59 | (*((byte *)address+1) << 16) + 60 | (*((byte *)address) << 24) ); 61 | #endif 62 | } 63 | else 64 | return *(dword *)address; 65 | } 66 | 67 | 68 | static __inline__ void write_dword(void *address, dword data) 69 | { 70 | if ((dword)address & 3) 71 | { 72 | #ifdef LSB_FIRST 73 | *((byte *)address) = data; 74 | *((byte *)address+1) = (data >> 8); 75 | *((byte *)address+2) = (data >> 16); 76 | *((byte *)address+3) = (data >> 24); 77 | #else 78 | *((byte *)address+3) = data; 79 | *((byte *)address+2) = (data >> 8); 80 | *((byte *)address+1) = (data >> 16); 81 | *((byte *)address) = (data >> 24); 82 | #endif 83 | return; 84 | } 85 | else 86 | *(dword *)address = data; 87 | } 88 | #else 89 | #define read_dword(address) *(dword *)address 90 | #define write_dword(address,data) *(dword *)address=data 91 | #endif 92 | 93 | 94 | /****************************************************************************/ 95 | 96 | 97 | /* Initialize the rendering data */ 98 | void render_init(void) 99 | { 100 | int bx, sx, b, s, bp, bf, sf, c; 101 | 102 | /* Generate 64k of data for the look up table */ 103 | for(bx = 0; bx < 0x100; bx += 1) 104 | { 105 | for(sx = 0; sx < 0x100; sx += 1) 106 | { 107 | /* Background pixel */ 108 | b = (bx & 0x0F); 109 | 110 | /* Background priority */ 111 | bp = (bx & 0x20) ? 1 : 0; 112 | 113 | /* Full background pixel + priority + sprite marker */ 114 | bf = (bx & 0x7F); 115 | 116 | /* Sprite pixel */ 117 | s = (sx & 0x0F); 118 | 119 | /* Full sprite pixel, w/ palette and marker bits added */ 120 | sf = (sx & 0x0F) | 0x10 | 0x40; 121 | 122 | /* Overwriting a sprite pixel ? */ 123 | if(bx & 0x40) 124 | { 125 | /* Return the input */ 126 | c = bf; 127 | } 128 | else 129 | { 130 | /* Work out priority and transparency for both pixels */ 131 | c = bp ? b ? bf : s ? sf : bf : s ? sf : bf; 132 | } 133 | 134 | /* Store result */ 135 | lut[(bx << 8) | (sx)] = c; 136 | } 137 | } 138 | 139 | render_reset(); 140 | } 141 | 142 | 143 | /* Reset the rendering data */ 144 | void render_reset(void) 145 | { 146 | int i; 147 | 148 | /* Clear display bitmap */ 149 | memset(bitmap.data, 0, bitmap.pitch * bitmap.height); 150 | 151 | /* Clear palette */ 152 | for(i = 0; i < PALETTE_SIZE; i += 1) 153 | { 154 | palette_sync(i); 155 | } 156 | 157 | /* Invalidate pattern cache */ 158 | is_vram_dirty = 1; 159 | memset(vram_dirty, 1, 0x200); 160 | memset(cache, 0, sizeof(cache)); 161 | 162 | /* Set up viewport size */ 163 | if(IS_GG) 164 | { 165 | vp_vstart = 24; 166 | vp_vend = 168; 167 | vp_hstart = 6; 168 | vp_hend = 26; 169 | } 170 | else 171 | { 172 | vp_vstart = 0; 173 | vp_vend = 192; 174 | vp_hstart = 0; 175 | vp_hend = 32; 176 | } 177 | 178 | /* Pick render routine */ 179 | render_bg = IS_GG ? render_bg_gg : render_bg_sms; 180 | } 181 | 182 | 183 | /* Draw a line of the display */ 184 | void render_line(int line) 185 | { 186 | /* Ensure we're within the viewport range */ 187 | if((line < vp_vstart) || (line >= vp_vend)) return; 188 | 189 | /* Point to current line in output buffer */ 190 | linebuf = (bitmap.depth == 8) ? &bitmap.data[(line * bitmap.pitch)] : &internal_buffer[0]; 191 | 192 | /* Update pattern cache */ 193 | update_cache(); 194 | 195 | /* Blank line */ 196 | if( (!(vdp.reg[1] & 0x40)) || (((vdp.reg[2] & 1) == 0) && (IS_SMS))) 197 | { 198 | memset(linebuf + (vp_hstart << 3), BACKDROP_COLOR, BMP_WIDTH); 199 | } 200 | else 201 | { 202 | /* Draw background */ 203 | render_bg(line); 204 | 205 | /* Draw sprites */ 206 | render_obj(line); 207 | 208 | /* Blank leftmost column of display */ 209 | if(vdp.reg[0] & 0x20) 210 | { 211 | memset(linebuf, BACKDROP_COLOR, 8); 212 | } 213 | } 214 | 215 | if(bitmap.depth != 8) remap_8_to_16(line); 216 | } 217 | 218 | 219 | /* Draw the Master System background */ 220 | void render_bg_sms(int line) 221 | { 222 | int locked = 0; 223 | int v_line = (line + vdp.reg[9]) % 224; 224 | int v_row = (v_line & 7) << 3; 225 | int hscroll = ((vdp.reg[0] & 0x40) && (line < 0x10)) ? 0 : (0x100 - vdp.reg[8]); 226 | int column = vp_hstart; 227 | word attr; 228 | word *nt = (word *)&vdp.vram[vdp.ntab + ((v_line >> 3) << 6)]; 229 | int nt_scroll = (hscroll >> 3); 230 | int shift = (hscroll & 7); 231 | dword atex_mask; 232 | dword *cache_ptr; 233 | dword *linebuf_ptr = (dword *)&linebuf[0 - shift]; 234 | 235 | /* Draw first column (clipped) */ 236 | if(shift) 237 | { 238 | int x, c, a; 239 | 240 | attr = nt[(column + nt_scroll) & 0x1F]; 241 | 242 | #ifndef LSB_FIRST 243 | attr = (((attr & 0xFF) << 8) | ((attr & 0xFF00) >> 8)); 244 | #endif 245 | a = (attr >> 7) & 0x30; 246 | 247 | for(x = shift; x < 8; x += 1) 248 | { 249 | c = cache[((attr & 0x7FF) << 6) | (v_row) | (x)]; 250 | linebuf[(0 - shift) + (x) ] = ((c) | (a)); 251 | } 252 | 253 | column += 1; 254 | } 255 | 256 | /* Draw a line of the background */ 257 | for(; column < vp_hend; column += 1) 258 | { 259 | /* Stop vertical scrolling for leftmost eight columns */ 260 | if((vdp.reg[0] & 0x80) && (!locked) && (column >= 24)) 261 | { 262 | locked = 1; 263 | v_row = (line & 7) << 3; 264 | nt = (word *)&vdp.vram[((vdp.reg[2] << 10) & 0x3800) + ((line >> 3) << 6)]; 265 | } 266 | 267 | /* Get name table attribute word */ 268 | attr = nt[(column + nt_scroll) & 0x1F]; 269 | 270 | #ifndef LSB_FIRST 271 | attr = (((attr & 0xFF) << 8) | ((attr & 0xFF00) >> 8)); 272 | #endif 273 | /* Expand priority and palette bits */ 274 | atex_mask = atex[(attr >> 11) & 3]; 275 | 276 | /* Point to a line of pattern data in cache */ 277 | cache_ptr = (dword *)&cache[((attr & 0x7FF) << 6) | (v_row)]; 278 | 279 | /* Copy the left half, adding the attribute bits in */ 280 | write_dword( &linebuf_ptr[(column << 1)] , read_dword( &cache_ptr[0] ) | (atex_mask)); 281 | 282 | /* Copy the right half, adding the attribute bits in */ 283 | write_dword( &linebuf_ptr[(column << 1) | (1)], read_dword( &cache_ptr[1] ) | (atex_mask)); 284 | } 285 | 286 | /* Draw last column (clipped) */ 287 | if(shift) 288 | { 289 | int x, c, a; 290 | 291 | char *p = &linebuf[(0 - shift)+(column << 3)]; 292 | 293 | attr = nt[(column + nt_scroll) & 0x1F]; 294 | 295 | #ifndef LSB_FIRST 296 | attr = (((attr & 0xFF) << 8) | ((attr & 0xFF00) >> 8)); 297 | #endif 298 | a = (attr >> 7) & 0x30; 299 | 300 | for(x = 0; x < shift; x += 1) 301 | { 302 | c = cache[((attr & 0x7FF) << 6) | (v_row) | (x)]; 303 | p[x] = ((c) | (a)); 304 | } 305 | } 306 | } 307 | 308 | 309 | /* Draw the Game Gear background */ 310 | void render_bg_gg(int line) 311 | { 312 | int v_line = (line + vdp.reg[9]) % 224; 313 | int v_row = (v_line & 7) << 3; 314 | int hscroll = (0x100 - vdp.reg[8]); 315 | int column; 316 | word attr; 317 | word *nt = (word *)&vdp.vram[vdp.ntab + ((v_line >> 3) << 6)]; 318 | int nt_scroll = (hscroll >> 3); 319 | dword atex_mask; 320 | dword *cache_ptr; 321 | dword *linebuf_ptr = (dword *)&linebuf[0 - (hscroll & 7)]; 322 | 323 | /* Draw a line of the background */ 324 | for(column = vp_hstart; column <= vp_hend; column += 1) 325 | { 326 | /* Get name table attribute word */ 327 | attr = nt[(column + nt_scroll) & 0x1F]; 328 | 329 | #ifndef LSB_FIRST 330 | attr = (((attr & 0xFF) << 8) | ((attr & 0xFF00) >> 8)); 331 | #endif 332 | /* Expand priority and palette bits */ 333 | atex_mask = atex[(attr >> 11) & 3]; 334 | 335 | /* Point to a line of pattern data in cache */ 336 | cache_ptr = (dword *)&cache[((attr & 0x7FF) << 6) | (v_row)]; 337 | 338 | /* Copy the left half, adding the attribute bits in */ 339 | write_dword( &linebuf_ptr[(column << 1)] , read_dword( &cache_ptr[0] ) | (atex_mask)); 340 | 341 | /* Copy the right half, adding the attribute bits in */ 342 | write_dword( &linebuf_ptr[(column << 1) | (1)], read_dword( &cache_ptr[1] ) | (atex_mask)); 343 | } 344 | } 345 | 346 | 347 | /* Draw sprites */ 348 | void render_obj(int line) 349 | { 350 | int i; 351 | 352 | /* Sprite count for current line (8 max.) */ 353 | int count = 0; 354 | 355 | /* Sprite dimensions */ 356 | int width = 8; 357 | int height = (vdp.reg[1] & 0x02) ? 16 : 8; 358 | 359 | /* Pointer to sprite attribute table */ 360 | byte *st = (byte *)&vdp.vram[vdp.satb]; 361 | 362 | /* Adjust dimensions for double size sprites */ 363 | if(vdp.reg[1] & 0x01) 364 | { 365 | width *= 2; 366 | height *= 2; 367 | } 368 | 369 | /* Draw sprites in front-to-back order */ 370 | for(i = 0; i < 64; i += 1) 371 | { 372 | /* Sprite Y position */ 373 | int yp = st[i]; 374 | 375 | /* End of sprite list marker? */ 376 | if(yp == 208) return; 377 | 378 | /* Actual Y position is +1 */ 379 | yp += 1; 380 | 381 | /* Wrap Y coordinate for sprites > 240 */ 382 | if(yp > 240) yp -= 256; 383 | 384 | /* Check if sprite falls on current line */ 385 | if((line >= yp) && (line < (yp + height))) 386 | { 387 | byte *linebuf_ptr; 388 | 389 | /* Width of sprite */ 390 | int start = 0; 391 | int end = width; 392 | 393 | /* Sprite X position */ 394 | int xp = st[0x80 + (i << 1)]; 395 | 396 | /* Pattern name */ 397 | int n = st[0x81 + (i << 1)]; 398 | 399 | /* Bump sprite count */ 400 | count += 1; 401 | 402 | /* Too many sprites on this line ? */ 403 | if((vdp.limit) && (count == 9)) return; 404 | 405 | /* X position shift */ 406 | if(vdp.reg[0] & 0x08) xp -= 8; 407 | 408 | /* Add MSB of pattern name */ 409 | if(vdp.reg[6] & 0x04) n |= 0x0100; 410 | 411 | /* Mask LSB for 8x16 sprites */ 412 | if(vdp.reg[1] & 0x02) n &= 0x01FE; 413 | 414 | /* Point to offset in line buffer */ 415 | linebuf_ptr = (byte *)&linebuf[xp]; 416 | 417 | /* Clip sprites on left edge */ 418 | if(xp < 0) 419 | { 420 | start = (0 - xp); 421 | } 422 | 423 | /* Clip sprites on right edge */ 424 | if((xp + width) > 256) 425 | { 426 | end = (256 - xp); 427 | } 428 | 429 | /* Draw double size sprite */ 430 | if(vdp.reg[1] & 0x01) 431 | { 432 | int x; 433 | byte *cache_ptr = (byte *)&cache[(n << 6) | (((line - yp) >> 1) << 3)]; 434 | 435 | /* Draw sprite line */ 436 | for(x = start; x < end; x += 1) 437 | { 438 | /* Source pixel from cache */ 439 | byte sp = cache_ptr[(x >> 1)]; 440 | 441 | /* Only draw opaque sprite pixels */ 442 | if(sp) 443 | { 444 | /* Background pixel from line buffer */ 445 | byte bg = linebuf_ptr[x]; 446 | 447 | /* Look up result */ 448 | linebuf_ptr[x] = lut[(bg << 8) | (sp)]; 449 | 450 | /* Set sprite collision flag */ 451 | if(bg & 0x40) vdp.status |= 0x20; 452 | } 453 | } 454 | } 455 | else /* Regular size sprite (8x8 / 8x16) */ 456 | { 457 | int x; 458 | byte *cache_ptr = (byte *)&cache[(n << 6) | ((line - yp) << 3)]; 459 | 460 | /* Draw sprite line */ 461 | for(x = start; x < end; x += 1) 462 | { 463 | /* Source pixel from cache */ 464 | byte sp = cache_ptr[x]; 465 | 466 | /* Only draw opaque sprite pixels */ 467 | if(sp) 468 | { 469 | /* Background pixel from line buffer */ 470 | byte bg = linebuf_ptr[x]; 471 | 472 | /* Look up result */ 473 | linebuf_ptr[x] = lut[(bg << 8) | (sp)]; 474 | 475 | /* Set sprite collision flag */ 476 | if(bg & 0x40) vdp.status |= 0x20; 477 | } 478 | } 479 | } 480 | } 481 | } 482 | } 483 | 484 | 485 | /* Update pattern cache with modified tiles */ 486 | void update_cache(void) 487 | { 488 | int i, x, y, c; 489 | int b0, b1, b2, b3; 490 | int i0, i1, i2, i3; 491 | 492 | if(!is_vram_dirty) return; 493 | is_vram_dirty = 0; 494 | 495 | for(i = 0; i < 0x200; i += 1) 496 | { 497 | if(vram_dirty[i]) 498 | { 499 | vram_dirty[i] = 0; 500 | 501 | for(y = 0; y < 8; y += 1) 502 | { 503 | b0 = vdp.vram[(i << 5) | (y << 2) | (0)]; 504 | b1 = vdp.vram[(i << 5) | (y << 2) | (1)]; 505 | b2 = vdp.vram[(i << 5) | (y << 2) | (2)]; 506 | b3 = vdp.vram[(i << 5) | (y << 2) | (3)]; 507 | 508 | for(x = 0; x < 8; x += 1) 509 | { 510 | i0 = (b0 >> (7 - x)) & 1; 511 | i1 = (b1 >> (7 - x)) & 1; 512 | i2 = (b2 >> (7 - x)) & 1; 513 | i3 = (b3 >> (7 - x)) & 1; 514 | 515 | c = (i3 << 3 | i2 << 2 | i1 << 1 | i0); 516 | 517 | cache[0x00000 | (i << 6) | ((y ) << 3) | (x )] = c; 518 | cache[0x08000 | (i << 6) | ((y ) << 3) | (7-x)] = c; 519 | cache[0x10000 | (i << 6) | ((7-y) << 3) | (x )] = c; 520 | cache[0x18000 | (i << 6) | ((7-y) << 3) | (7-x)] = c; 521 | } 522 | } 523 | } 524 | } 525 | } 526 | 527 | //void makePS2Clut(void) { 528 | // u32 tmp_clut[32]; 529 | // int idxs[] = {0, 16, 8, 24}; // Tried to invert palette positions, as FCEUltra for PS2 530 | // int i, j, k; 531 | // 532 | // // Don't do anything with the PS2 clut (in test) 533 | // //return; 534 | // 535 | // k = 0; 536 | // for(i = 0; i < 4; i++) { 537 | // for(j = 0; j < 8; j++) { 538 | // tmp_clut[k++] = clut[idxs[i] + j]; 539 | // } 540 | // } 541 | // 542 | // for(k = 0; k < 32; k++) { 543 | // clut[k] = tmp_clut[k]; 544 | // clut[k + 32] = tmp_clut[k]; 545 | // clut[k + 64] = tmp_clut[k]; 546 | // clut[k + 96] = tmp_clut[k]; 547 | // clut[k + 128] = tmp_clut[k]; 548 | // clut[k + 160] = tmp_clut[k]; 549 | // clut[k + 192] = tmp_clut[k]; 550 | // clut[k + 224] = tmp_clut[k]; 551 | // } 552 | //} 553 | 554 | 555 | /* Update a palette entry */ 556 | void palette_sync(int index) 557 | { 558 | int r, g, b, ps2clutidx; 559 | 560 | if(IS_GG) 561 | { 562 | r = ((vdp.cram[(index << 1) | 0] >> 1) & 7) << 5; 563 | g = ((vdp.cram[(index << 1) | 0] >> 5) & 7) << 5; 564 | b = ((vdp.cram[(index << 1) | 1] >> 1) & 7) << 5; 565 | } 566 | else 567 | { 568 | r = ((vdp.cram[index] >> 0) & 3) << 6; 569 | g = ((vdp.cram[index] >> 2) & 3) << 6; 570 | b = ((vdp.cram[index] >> 4) & 3) << 6; 571 | } 572 | 573 | bitmap.pal.color[index][0] = r; 574 | bitmap.pal.color[index][1] = g; 575 | bitmap.pal.color[index][2] = b; 576 | 577 | pixel[index] = MAKE_PIXEL(r, g, b); 578 | 579 | bitmap.pal.dirty[index] = bitmap.pal.update = 1; 580 | 581 | if(index > 7 && index < 16) { 582 | //clut[8 + index] = ( ((b>>0)<<16) | ((g>>0)<<8) | (g>>0) ); 583 | ps2clutidx = 8 + index; 584 | } else if(index > 15 && index < 24) { 585 | //clut[index - 8] = ( ((b>>0)<<16) | ((g>>0)<<8) | (g>>0) ); 586 | ps2clutidx = index - 8; 587 | } else { 588 | //clut[index] = ( ((b>>0)<<16) | ((g>>0)<<8) | (g>>0) ); 589 | ps2clutidx = index; 590 | } 591 | 592 | clut[ps2clutidx] = ( ((b>>0)<<16) | ((g>>0)<<8) | (r>>0) ); 593 | clut[ps2clutidx + 32] = ( ((b>>0)<<16) | ((g>>0)<<8) | (r>>0) ); 594 | clut[ps2clutidx + 64] = ( ((b>>0)<<16) | ((g>>0)<<8) | (r>>0) ); 595 | clut[ps2clutidx + 96] = ( ((b>>0)<<16) | ((g>>0)<<8) | (r>>0) ); 596 | clut[ps2clutidx + 128] = ( ((b>>0)<<16) | ((g>>0)<<8) | (r>>0) ); 597 | clut[ps2clutidx + 160] = ( ((b>>0)<<16) | ((g>>0)<<8) | (r>>0) ); 598 | clut[ps2clutidx + 192] = ( ((b>>0)<<16) | ((g>>0)<<8) | (r>>0) ); 599 | clut[ps2clutidx + 224] = ( ((b>>0)<<16) | ((g>>0)<<8) | (r>>0) ); 600 | 601 | //clut[index | 0x20] = ( ((b>>3)<<10) | ((g>>3)<<5) | (r>>3) ); 602 | //clut[index | 0x40] = ( ((b>>3)<<10) | ((g>>3)<<5) | (r>>3) ); 603 | } 604 | 605 | 606 | void remap_8_to_16(int line) 607 | { 608 | int i; 609 | int length = BMP_WIDTH; 610 | int ofs = BMP_X_OFFSET; 611 | word *p = (word *)&bitmap.data[(line * bitmap.pitch) + (ofs << 1)]; 612 | 613 | for(i = 0; i < length; i += 1) 614 | { 615 | p[i] = pixel[(internal_buffer[(ofs + i)] & PIXEL_MASK)]; 616 | } 617 | } 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | -------------------------------------------------------------------------------- /cpuintrf.h: -------------------------------------------------------------------------------- 1 | #ifndef CPUINTRF_H 2 | #define CPUINTRF_H 3 | 4 | #include "osd_cpu.h" 5 | 6 | /* The old system is obsolete and no longer supported by the core */ 7 | #define NEW_INTERRUPT_SYSTEM 1 8 | 9 | #define MAX_IRQ_LINES 8 /* maximum number of IRQ lines per CPU */ 10 | 11 | #define CLEAR_LINE 0 /* clear (a fired, held or pulsed) line */ 12 | #define ASSERT_LINE 1 /* assert an interrupt immediately */ 13 | #define HOLD_LINE 2 /* hold interrupt line until enable is true */ 14 | #define PULSE_LINE 3 /* pulse interrupt line for one instruction */ 15 | 16 | #define MAX_REGS 64 /* maximum number of register of any CPU */ 17 | 18 | /* Values passed to the cpu_info function of a core to retrieve information */ 19 | enum { 20 | CPU_INFO_REG, 21 | CPU_INFO_FLAGS=MAX_REGS, 22 | CPU_INFO_NAME, 23 | CPU_INFO_FAMILY, 24 | CPU_INFO_VERSION, 25 | CPU_INFO_FILE, 26 | CPU_INFO_CREDITS, 27 | CPU_INFO_REG_LAYOUT, 28 | CPU_INFO_WIN_LAYOUT 29 | }; 30 | 31 | #define CPU_IS_LE 0 /* emulated CPU is little endian */ 32 | #define CPU_IS_BE 1 /* emulated CPU is big endian */ 33 | 34 | /* 35 | * This value is passed to cpu_get_reg to retrieve the previous 36 | * program counter value, ie. before a CPU emulation started 37 | * to fetch opcodes and arguments for the current instrution. 38 | */ 39 | #define REG_PREVIOUSPC -1 40 | 41 | /* 42 | * This value is passed to cpu_get_reg/cpu_set_reg, instead of one of 43 | * the names from the enum a CPU core defines for it's registers, 44 | * to get or set the contents of the memory pointed to by a stack pointer. 45 | * You can specify the n'th element on the stack by (REG_SP_CONTENTS-n), 46 | * ie. lower negative values. The actual element size (UINT16 or UINT32) 47 | * depends on the CPU core. 48 | * This is also used to replace the cpu_geturnpc() function. 49 | */ 50 | #define REG_SP_CONTENTS -2 51 | 52 | /* 53 | * These flags can be defined in the makefile (or project) to 54 | * exclude (zero) or include (non zero) specific CPU cores 55 | */ 56 | #ifndef HAS_GENSYNC 57 | #define HAS_GENSYNC 0 58 | #endif 59 | #ifndef HAS_Z80 60 | #define HAS_Z80 0 61 | #endif 62 | #ifndef HAS_Z80_VM 63 | #define HAS_Z80_VM 0 64 | #endif 65 | #ifndef HAS_8080 66 | #define HAS_8080 0 67 | #endif 68 | #ifndef HAS_8085A 69 | #define HAS_8085A 0 70 | #endif 71 | #ifndef HAS_M6502 72 | #define HAS_M6502 0 73 | #endif 74 | #ifndef HAS_M65C02 75 | #define HAS_M65C02 0 76 | #endif 77 | #ifndef HAS_M65SC02 78 | #define HAS_M65SC02 0 79 | #endif 80 | #ifndef HAS_M65CE02 81 | #define HAS_M65CE02 0 82 | #endif 83 | #ifndef HAS_M6509 84 | #define HAS_M6509 0 85 | #endif 86 | #ifndef HAS_M6510 87 | #define HAS_M6510 0 88 | #endif 89 | #ifndef HAS_N2A03 90 | #define HAS_N2A03 0 91 | #endif 92 | #ifndef HAS_H6280 93 | #define HAS_H6280 0 94 | #endif 95 | #ifndef HAS_I86 96 | #define HAS_I86 0 97 | #endif 98 | #ifndef HAS_V20 99 | #define HAS_V20 0 100 | #endif 101 | #ifndef HAS_V30 102 | #define HAS_V30 0 103 | #endif 104 | #ifndef HAS_V33 105 | #define HAS_V33 0 106 | #endif 107 | #ifndef HAS_I8035 108 | #define HAS_I8035 0 109 | #endif 110 | #ifndef HAS_I8039 111 | #define HAS_I8039 0 112 | #endif 113 | #ifndef HAS_I8048 114 | #define HAS_I8048 0 115 | #endif 116 | #ifndef HAS_N7751 117 | #define HAS_N7751 0 118 | #endif 119 | #ifndef HAS_M6800 120 | #define HAS_M6800 0 121 | #endif 122 | #ifndef HAS_M6801 123 | #define HAS_M6801 0 124 | #endif 125 | #ifndef HAS_M6802 126 | #define HAS_M6802 0 127 | #endif 128 | #ifndef HAS_M6803 129 | #define HAS_M6803 0 130 | #endif 131 | #ifndef HAS_M6808 132 | #define HAS_M6808 0 133 | #endif 134 | #ifndef HAS_HD63701 135 | #define HAS_HD63701 0 136 | #endif 137 | #ifndef HAS_M6805 138 | #define HAS_M6805 0 139 | #endif 140 | #ifndef HAS_M68705 141 | #define HAS_M68705 0 142 | #endif 143 | #ifndef HAS_HD63705 144 | #define HAS_HD63705 0 145 | #endif 146 | #ifndef HAS_HD6309 147 | #define HAS_HD6309 0 148 | #endif 149 | #ifndef HAS_M6809 150 | #define HAS_M6809 0 151 | #endif 152 | #ifndef HAS_KONAMI 153 | #define HAS_KONAMI 0 154 | #endif 155 | #ifndef HAS_M68000 156 | #define HAS_M68000 0 157 | #endif 158 | #ifndef HAS_M68010 159 | #define HAS_M68010 0 160 | #endif 161 | #ifndef HAS_M68020 162 | #define HAS_M68020 0 163 | #endif 164 | #ifndef HAS_T11 165 | #define HAS_T11 0 166 | #endif 167 | #ifndef HAS_S2650 168 | #define HAS_S2650 0 169 | #endif 170 | #ifndef HAS_TMS34010 171 | #define HAS_TMS34010 0 172 | #endif 173 | #ifndef HAS_TMS9900 174 | #define HAS_TMS9900 0 175 | #endif 176 | #ifndef HAS_TMS9940 177 | #define HAS_TMS9940 0 178 | #endif 179 | #ifndef HAS_TMS9980 180 | #define HAS_TMS9980 0 181 | #endif 182 | #ifndef HAS_TMS9985 183 | #define HAS_TMS9985 0 184 | #endif 185 | #ifndef HAS_TMS9989 186 | #define HAS_TMS9989 0 187 | #endif 188 | #ifndef HAS_TMS9995 189 | #define HAS_TMS9995 0 190 | #endif 191 | #ifndef HAS_TMS99105A 192 | #define HAS_TMS99105A 0 193 | #endif 194 | #ifndef HAS_TMS99110A 195 | #define HAS_TMS99110A 0 196 | #endif 197 | #ifndef HAS_Z8000 198 | #define HAS_Z8000 0 199 | #endif 200 | #ifndef HAS_TMS320C10 201 | #define HAS_TMS320C10 0 202 | #endif 203 | #ifndef HAS_CCPU 204 | #define HAS_CCPU 0 205 | #endif 206 | #ifndef HAS_PDP1 207 | #define HAS_PDP1 0 208 | #endif 209 | #ifndef HAS_ADSP2100 210 | #define HAS_ADSP2100 0 211 | #endif 212 | 213 | /* ASG 971222 -- added this generic structure */ 214 | struct cpu_interface 215 | { 216 | unsigned cpu_num; 217 | void (*reset)(void *param); 218 | void (*exit)(void); 219 | int (*execute)(int cycles); 220 | void (*burn)(int cycles); 221 | unsigned (*get_context)(void *reg); 222 | void (*set_context)(void *reg); 223 | unsigned (*get_pc)(void); 224 | void (*set_pc)(unsigned val); 225 | unsigned (*get_sp)(void); 226 | void (*set_sp)(unsigned val); 227 | unsigned (*get_reg)(int regnum); 228 | void (*set_reg)(int regnum, unsigned val); 229 | void (*set_nmi_line)(int linestate); 230 | void (*set_irq_line)(int irqline, int linestate); 231 | void (*set_irq_callback)(int(*callback)(int irqline)); 232 | void (*internal_interrupt)(int type); 233 | void (*cpu_state_save)(void *file); 234 | void (*cpu_state_load)(void *file); 235 | const char* (*cpu_info)(void *context,int regnum); 236 | unsigned (*cpu_dasm)(char *buffer,unsigned pc); 237 | unsigned num_irqs; 238 | int default_vector; 239 | int *icount; 240 | double overclock; 241 | int no_int, irq_int, nmi_int; 242 | int (*memory_read)(int offset); 243 | void (*memory_write)(int offset, int data); 244 | void (*set_op_base)(int pc); 245 | int address_shift; 246 | unsigned address_bits, endianess, align_unit, max_inst_len; 247 | unsigned abits1, abits2, abitsmin; 248 | }; 249 | 250 | extern struct cpu_interface cpuintf[]; 251 | 252 | void cpu_init(void); 253 | void cpu_run(void); 254 | 255 | /* optional watchdog */ 256 | void watchdog_reset_w(int offset,int data); 257 | int watchdog_reset_r(int offset); 258 | /* Use this function to reset the machine */ 259 | void machine_reset(void); 260 | /* Use this function to reset a single CPU */ 261 | void cpu_set_reset_line(int cpu,int state); 262 | /* Use this function to halt a single CPU */ 263 | void cpu_set_halt_line(int cpu,int state); 264 | 265 | /* This function returns CPUNUM current status (running or halted) */ 266 | int cpu_getstatus(int cpunum); 267 | int cpu_gettotalcpu(void); 268 | int cpu_getactivecpu(void); 269 | void cpu_setactivecpu(int cpunum); 270 | 271 | /* Returns the current program counter */ 272 | unsigned cpu_get_pc(void); 273 | /* Set the current program counter */ 274 | void cpu_set_pc(unsigned val); 275 | 276 | /* Returns the current stack pointer */ 277 | unsigned cpu_get_sp(void); 278 | /* Set the current stack pointer */ 279 | void cpu_set_sp(unsigned val); 280 | 281 | /* Get the active CPUs context and return it's size */ 282 | unsigned cpu_get_context(void *context); 283 | /* Set the active CPUs context */ 284 | void cpu_set_context(void *context); 285 | 286 | /* Returns a specific register value (mamedbg) */ 287 | unsigned cpu_get_reg(int regnum); 288 | /* Sets a specific register value (mamedbg) */ 289 | void cpu_set_reg(int regnum, unsigned val); 290 | 291 | /* Returns previous pc (start of opcode causing read/write) */ 292 | /* int cpu_getpreviouspc(void); */ 293 | #define cpu_getpreviouspc() cpu_get_reg(REG_PREVIOUSPC) 294 | 295 | /* Returns the return address from the top of the stack (Z80 only) */ 296 | /* int cpu_getreturnpc(void); */ 297 | /* This can now be handled with a generic function */ 298 | #define cpu_geturnpc() cpu_get_reg(REG_SP_CONTENTS) 299 | 300 | int cycles_currently_ran(void); 301 | int cycles_left_to_run(void); 302 | 303 | /* Returns the number of CPU cycles which take place in one video frame */ 304 | int cpu_gettotalcycles(void); 305 | /* Returns the number of CPU cycles before the next interrupt handler call */ 306 | int cpu_geticount(void); 307 | /* Returns the number of CPU cycles before the end of the current video frame */ 308 | int cpu_getfcount(void); 309 | /* Returns the number of CPU cycles in one video frame */ 310 | int cpu_getfperiod(void); 311 | /* Scales a given value by the ratio of fcount / fperiod */ 312 | int cpu_scalebyfcount(int value); 313 | /* Returns the current scanline number */ 314 | int cpu_getscanline(void); 315 | /* Returns the amount of time until a given scanline */ 316 | double cpu_getscanlinetime(int scanline); 317 | /* Returns the duration of a single scanline */ 318 | double cpu_getscanlineperiod(void); 319 | /* Returns the duration of a single scanline in cycles */ 320 | int cpu_getscanlinecycles(void); 321 | /* Returns the number of cycles since the beginning of this frame */ 322 | int cpu_getcurrentcycles(void); 323 | /* Returns the current horizontal beam position in pixels */ 324 | int cpu_gethorzbeampos(void); 325 | /* 326 | Returns the number of times the interrupt handler will be called before 327 | the end of the current video frame. This is can be useful to interrupt 328 | handlers to synchronize their operation. If you call this from outside 329 | an interrupt handler, add 1 to the result, i.e. if it returns 0, it means 330 | that the interrupt handler will be called once. 331 | */ 332 | int cpu_getiloops(void); 333 | 334 | /* Returns the current VBLANK state */ 335 | int cpu_getvblank(void); 336 | 337 | /* Returns the number of the video frame we are currently playing */ 338 | int cpu_getcurrentframe(void); 339 | 340 | 341 | /* generate a trigger after a specific period of time */ 342 | void cpu_triggertime (double duration, int trigger); 343 | /* generate a trigger now */ 344 | void cpu_trigger (int trigger); 345 | 346 | /* burn CPU cycles until a timer trigger */ 347 | void cpu_spinuntil_trigger (int trigger); 348 | /* burn CPU cycles until the next interrupt */ 349 | void cpu_spinuntil_int (void); 350 | /* burn CPU cycles until our timeslice is up */ 351 | void cpu_spin (void); 352 | /* burn CPU cycles for a specific period of time */ 353 | void cpu_spinuntil_time (double duration); 354 | 355 | /* yield our timeslice for a specific period of time */ 356 | void cpu_yielduntil_trigger (int trigger); 357 | /* yield our timeslice until the next interrupt */ 358 | void cpu_yielduntil_int (void); 359 | /* yield our current timeslice */ 360 | void cpu_yield (void); 361 | /* yield our timeslice for a specific period of time */ 362 | void cpu_yielduntil_time (double duration); 363 | 364 | /* set the NMI line state for a CPU, normally use PULSE_LINE */ 365 | void cpu_set_nmi_line(int cpunum, int state); 366 | /* set the IRQ line state for a specific irq line of a CPU */ 367 | /* normally use state HOLD_LINE, irqline 0 for first IRQ type of a cpu */ 368 | void cpu_set_irq_line(int cpunum, int irqline, int state); 369 | /* this is to be called by CPU cores only! */ 370 | void cpu_generate_internal_interrupt(int cpunum, int type); 371 | /* set the vector to be returned during a CPU's interrupt acknowledge cycle */ 372 | void cpu_irq_line_vector_w(int cpunum, int irqline, int vector); 373 | 374 | /* use these in your write memory/port handles to set an IRQ vector */ 375 | /* offset corresponds to the irq line number here */ 376 | void cpu_0_irq_line_vector_w(int offset, int data); 377 | void cpu_1_irq_line_vector_w(int offset, int data); 378 | void cpu_2_irq_line_vector_w(int offset, int data); 379 | void cpu_3_irq_line_vector_w(int offset, int data); 380 | void cpu_4_irq_line_vector_w(int offset, int data); 381 | void cpu_5_irq_line_vector_w(int offset, int data); 382 | void cpu_6_irq_line_vector_w(int offset, int data); 383 | void cpu_7_irq_line_vector_w(int offset, int data); 384 | 385 | /* Obsolete functions: avoid to use them in new drivers if possible. */ 386 | 387 | /* cause an interrupt on a CPU */ 388 | void cpu_cause_interrupt(int cpu,int type); 389 | void cpu_clear_pending_interrupts(int cpu); 390 | void interrupt_enable_w(int offset,int data); 391 | void interrupt_vector_w(int offset,int data); 392 | int interrupt(void); 393 | int nmi_interrupt(void); 394 | int m68_level1_irq(void); 395 | int m68_level2_irq(void); 396 | int m68_level3_irq(void); 397 | int m68_level4_irq(void); 398 | int m68_level5_irq(void); 399 | int m68_level6_irq(void); 400 | int m68_level7_irq(void); 401 | int ignore_interrupt(void); 402 | 403 | /* CPU context access */ 404 | void* cpu_getcontext (int _activecpu); 405 | int cpu_is_saving_context(int _activecpu); 406 | 407 | /*************************************************************************** 408 | * Get information for the currently active CPU 409 | * cputype is a value from the CPU enum in driver.h 410 | ***************************************************************************/ 411 | /* Return number of address bits */ 412 | unsigned cpu_address_bits(void); 413 | /* Return address mask */ 414 | unsigned cpu_address_mask(void); 415 | /* Return address shift factor (TMS34010 bit addressing mode) */ 416 | int cpu_address_shift(void); 417 | /* Return endianess of the emulated CPU (CPU_IS_LE or CPU_IS_BE) */ 418 | unsigned cpu_endianess(void); 419 | /* Return opcode align unit (1 byte, 2 word, 4 dword) */ 420 | unsigned cpu_align_unit(void); 421 | /* Return maximum instruction length */ 422 | unsigned cpu_max_inst_len(void); 423 | 424 | /* Return name of the active CPU */ 425 | const char *cpu_name(void); 426 | /* Return family name of the active CPU */ 427 | const char *cpu_core_family(void); 428 | /* Return core version of the active CPU */ 429 | const char *cpu_core_version(void); 430 | /* Return core filename of the active CPU */ 431 | const char *cpu_core_file(void); 432 | /* Return credits info for of the active CPU */ 433 | const char *cpu_core_credits(void); 434 | /* Return register layout definition for the active CPU */ 435 | const char *cpu_reg_layout(void); 436 | /* Return (debugger) window layout definition for the active CPU */ 437 | const char *cpu_win_layout(void); 438 | 439 | /* Disassemble an instruction at PC into the given buffer */ 440 | unsigned cpu_dasm(char *buffer, unsigned pc); 441 | /* Return a string describing the currently set flag (status) bits of the active CPU */ 442 | const char *cpu_flags(void); 443 | /* Return a string with a register name and hex value for the active CPU */ 444 | /* regnum is a value defined in the CPU cores header files */ 445 | const char *cpu_dump_reg(int regnum); 446 | /* Return a string describing the active CPUs current state */ 447 | const char *cpu_dump_state(void); 448 | 449 | /*************************************************************************** 450 | * Get information for a specific CPU type 451 | * cputype is a value from the CPU enum in driver.h 452 | ***************************************************************************/ 453 | /* Return address shift factor */ 454 | /* TMS320C10 -1: word addressing mode, TMS34010 3: bit addressing mode */ 455 | int cputype_address_shift(int cputype); 456 | /* Return number of address bits */ 457 | unsigned cputype_address_bits(int cputype); 458 | /* Return address mask */ 459 | unsigned cputype_address_mask(int cputype); 460 | /* Return endianess of the emulated CPU (CPU_IS_LE or CPU_IS_BE) */ 461 | unsigned cputype_endianess(int cputype); 462 | /* Return opcode align unit (1 byte, 2 word, 4 dword) */ 463 | unsigned cputype_align_unit(int cputype); 464 | /* Return maximum instruction length */ 465 | unsigned cputype_max_inst_len(int cputype); 466 | 467 | /* Return name of the CPU */ 468 | const char *cputype_name(int cputype); 469 | /* Return family name of the CPU */ 470 | const char *cputype_core_family(int cputype); 471 | /* Return core version number of the CPU */ 472 | const char *cputype_core_version(int cputype); 473 | /* Return core filename of the CPU */ 474 | const char *cputype_core_file(int cputype); 475 | /* Return credits for the CPU core */ 476 | const char *cputype_core_credits(int cputype); 477 | /* Return register layout definition for the CPU core */ 478 | const char *cputype_reg_layout(int cputype); 479 | /* Return (debugger) window layout definition for the CPU core */ 480 | const char *cputype_win_layout(int cputype); 481 | 482 | /*************************************************************************** 483 | * Get (or set) information for a numbered CPU of the running machine 484 | * cpunum is a value between 0 and cpu_gettotalcpu() - 1 485 | ***************************************************************************/ 486 | /* Return number of address bits */ 487 | unsigned cpunum_address_bits(int cputype); 488 | /* Return address mask */ 489 | unsigned cpunum_address_mask(int cputype); 490 | /* Return endianess of the emulated CPU (CPU_LSB_FIRST or CPU_MSB_FIRST) */ 491 | unsigned cpunum_endianess(int cputype); 492 | /* Return opcode align unit (1 byte, 2 word, 4 dword) */ 493 | unsigned cpunum_align_unit(int cputype); 494 | /* Return maximum instruction length */ 495 | unsigned cpunum_max_inst_len(int cputype); 496 | 497 | /* Get a register value for the specified CPU number of the running machine */ 498 | unsigned cpunum_get_reg(int cpunum, int regnum); 499 | /* Set a register value for the specified CPU number of the running machine */ 500 | void cpunum_set_reg(int cpunum, int regnum, unsigned val); 501 | 502 | /* Return (debugger) register layout definition for the CPU core */ 503 | const char *cpunum_reg_layout(int cpunum); 504 | /* Return (debugger) window layout definition for the CPU core */ 505 | const char *cpunum_win_layout(int cpunum); 506 | 507 | unsigned cpunum_dasm(int cpunum,char *buffer,unsigned pc); 508 | /* Return a string describing the currently set flag (status) bits of the CPU */ 509 | const char *cpunum_flags(int cpunum); 510 | /* Return a string with a register name and value */ 511 | /* regnum is a value defined in the CPU cores header files */ 512 | const char *cpunum_dump_reg(int cpunum, int regnum); 513 | /* Return a string describing the CPUs current state */ 514 | const char *cpunum_dump_state(int cpunum); 515 | /* Return a name for the specified cpu number */ 516 | const char *cpunum_name(int cpunum); 517 | /* Return a family name for the specified cpu number */ 518 | const char *cpunum_core_family(int cpunum); 519 | /* Return a version for the specified cpu number */ 520 | const char *cpunum_core_version(int cpunum); 521 | /* Return a the source filename for the specified cpu number */ 522 | const char *cpunum_core_file(int cpunum); 523 | /* Return a the credits for the specified cpu number */ 524 | const char *cpunum_core_credits(int cpunum); 525 | 526 | /* Dump all of the running machines CPUs state to stderr */ 527 | void cpu_dump_states(void); 528 | 529 | /* daisy-chain link */ 530 | typedef struct { 531 | void (*reset)(int); /* reset callback */ 532 | int (*interrupt_entry)(int); /* entry callback */ 533 | void (*interrupt_reti)(int); /* reti callback */ 534 | int irq_param; /* callback paramater */ 535 | } Z80_DaisyChain; 536 | 537 | #define Z80_MAXDAISY 4 /* maximum of daisy chan device */ 538 | 539 | #define Z80_INT_REQ 0x01 /* interrupt request mask */ 540 | #define Z80_INT_IEO 0x02 /* interrupt disable mask(IEO) */ 541 | 542 | #define Z80_VECTOR(device,state) (((device)<<8)|(state)) 543 | 544 | #endif /* CPUINTRF_H */ 545 | --------------------------------------------------------------------------------