From 0240f785506be5ca0379d5c95929cf6db01703d9 Mon Sep 17 00:00:00 2001 From: Ed Mandy Date: Fri, 14 Oct 2016 11:01:29 -0600 Subject: [PATCH] Initial Commit --- DrZ80.h | 76 + DrZ80.s | 7842 +++++++++++++++++++++++++ DrZ80_gpl.txt | 340 ++ DrZ80_support.cpp | 323 ++ DrZ80_support.h | 67 + Makefile.psp | 45 + PARAM.SFO | Bin 0 -> 408 bytes StdAfx.h | 104 + crypt.h | 132 + cz80.cpp | 376 ++ cz80.h | 262 + cz80.inc | 219 + cz80_op.inc | 1332 +++++ cz80_opCB.inc | 548 ++ cz80_opED.inc | 823 +++ cz80_opXY.inc | 714 +++ cz80_opXYCB.inc | 515 ++ cz80_support.cpp | 94 + cz80_support.h | 48 + cz80exec.inc | 124 + cz80jmp.inc | 418 ++ do.cmd | 3 + flash.cpp | 816 +++ flash.h | 37 + graphics.cpp | 1722 ++++++ graphics.h | 81 + homehook Makefile.psp | 48 + homehook.S | 8 + homehook.h | 13 + input.cpp | 261 + input.h | 33 + ioapi.c | 177 + ioapi.h | 75 + koyote.bin | Bin 0 -> 12288 bytes koyote_bin.h | 772 +++ main.cpp | 577 ++ main.h | 89 + memory.cpp | 526 ++ memory.h | 463 ++ neopopsound.cpp | 699 +++ neopopsound.h | 88 + ngpBios.cpp | 214 + ngpBios.h | 22 + psp/-menu.cpp | 1369 +++++ psp/emulate.cpp | 465 ++ psp/emulate.h | 55 + psp/homehookprx/Makefile | 27 + psp/homehookprx/homehook.exp | 16 + psp/homehookprx/homehook.h | 21 + psp/homehookprx/main.c | 106 + psp/homehookprx/sceCtrl_driver.S | 7 + psp/main.cpp | 51 + psp/menu.cpp | 1527 +++++ psp/menu.h | 8 + psp/psplib/COPYING | 674 +++ psp/psplib/Makefile | 102 + psp/psplib/adhoc.c | 499 ++ psp/psplib/adhoc.h | 63 + psp/psplib/ctrl.c | 201 + psp/psplib/ctrl.h | 49 + psp/psplib/font.c | 63 + psp/psplib/font.h | 90 + psp/psplib/genfont.c | 76 + psp/psplib/genfont.exe | Bin 0 -> 10223 bytes psp/psplib/image.c | 587 ++ psp/psplib/image.h | 81 + psp/psplib/libpsplib.a | Bin 0 -> 141546 bytes psp/psplib/pl_file.c | 332 ++ psp/psplib/pl_file.h | 76 + psp/psplib/pl_gfx.c | 221 + psp/psplib/pl_gfx.h | 41 + psp/psplib/pl_image.c | 735 +++ psp/psplib/pl_image.h | 139 + psp/psplib/pl_ini.c | 373 ++ psp/psplib/pl_ini.h | 65 + psp/psplib/pl_menu.c | 351 ++ psp/psplib/pl_menu.h | 132 + psp/psplib/pl_perf.c | 52 + psp/psplib/pl_perf.h | 46 + psp/psplib/pl_psp.c | 127 + psp/psplib/pl_psp.h | 50 + psp/psplib/pl_rewind.c | 195 + psp/psplib/pl_rewind.h | 57 + psp/psplib/pl_snd.c | 328 ++ psp/psplib/pl_snd.h | 67 + psp/psplib/pl_util.c | 193 + psp/psplib/pl_util.h | 52 + psp/psplib/pl_vk.c | 541 ++ psp/psplib/pl_vk.h | 66 + psp/psplib/stockfont.fd | 4099 +++++++++++++ psp/psplib/stockfont.h | 328 ++ psp/psplib/ui.c | 2846 +++++++++ psp/psplib/ui.h | 146 + psp/psplib/video.c | 762 +++ psp/psplib/video.h | 118 + psp/race-icon.png | Bin 0 -> 4209 bytes readme.txt | 90 + sound.cpp | 112 + sound.h | 68 + state.cpp | 421 ++ state.h | 31 + tlcs900h.cpp | 9363 ++++++++++++++++++++++++++++++ tlcs900h.h | 77 + unzip.c | 1562 +++++ unzip.h | 342 ++ 105 files changed, 51867 insertions(+) create mode 100644 DrZ80.h create mode 100644 DrZ80.s create mode 100644 DrZ80_gpl.txt create mode 100644 DrZ80_support.cpp create mode 100644 DrZ80_support.h create mode 100644 Makefile.psp create mode 100644 PARAM.SFO create mode 100644 StdAfx.h create mode 100644 crypt.h create mode 100644 cz80.cpp create mode 100644 cz80.h create mode 100644 cz80.inc create mode 100644 cz80_op.inc create mode 100644 cz80_opCB.inc create mode 100644 cz80_opED.inc create mode 100644 cz80_opXY.inc create mode 100644 cz80_opXYCB.inc create mode 100644 cz80_support.cpp create mode 100644 cz80_support.h create mode 100644 cz80exec.inc create mode 100644 cz80jmp.inc create mode 100644 do.cmd create mode 100644 flash.cpp create mode 100644 flash.h create mode 100644 graphics.cpp create mode 100644 graphics.h create mode 100644 homehook Makefile.psp create mode 100644 homehook.S create mode 100644 homehook.h create mode 100644 input.cpp create mode 100644 input.h create mode 100644 ioapi.c create mode 100644 ioapi.h create mode 100644 koyote.bin create mode 100644 koyote_bin.h create mode 100644 main.cpp create mode 100644 main.h create mode 100644 memory.cpp create mode 100644 memory.h create mode 100644 neopopsound.cpp create mode 100644 neopopsound.h create mode 100644 ngpBios.cpp create mode 100644 ngpBios.h create mode 100644 psp/-menu.cpp create mode 100644 psp/emulate.cpp create mode 100644 psp/emulate.h create mode 100644 psp/homehookprx/Makefile create mode 100644 psp/homehookprx/homehook.exp create mode 100644 psp/homehookprx/homehook.h create mode 100644 psp/homehookprx/main.c create mode 100644 psp/homehookprx/sceCtrl_driver.S create mode 100644 psp/main.cpp create mode 100644 psp/menu.cpp create mode 100644 psp/menu.h create mode 100644 psp/psplib/COPYING create mode 100644 psp/psplib/Makefile create mode 100644 psp/psplib/adhoc.c create mode 100644 psp/psplib/adhoc.h create mode 100644 psp/psplib/ctrl.c create mode 100644 psp/psplib/ctrl.h create mode 100644 psp/psplib/font.c create mode 100644 psp/psplib/font.h create mode 100644 psp/psplib/genfont.c create mode 100644 psp/psplib/genfont.exe create mode 100644 psp/psplib/image.c create mode 100644 psp/psplib/image.h create mode 100644 psp/psplib/libpsplib.a create mode 100644 psp/psplib/pl_file.c create mode 100644 psp/psplib/pl_file.h create mode 100644 psp/psplib/pl_gfx.c create mode 100644 psp/psplib/pl_gfx.h create mode 100644 psp/psplib/pl_image.c create mode 100644 psp/psplib/pl_image.h create mode 100644 psp/psplib/pl_ini.c create mode 100644 psp/psplib/pl_ini.h create mode 100644 psp/psplib/pl_menu.c create mode 100644 psp/psplib/pl_menu.h create mode 100644 psp/psplib/pl_perf.c create mode 100644 psp/psplib/pl_perf.h create mode 100644 psp/psplib/pl_psp.c create mode 100644 psp/psplib/pl_psp.h create mode 100644 psp/psplib/pl_rewind.c create mode 100644 psp/psplib/pl_rewind.h create mode 100644 psp/psplib/pl_snd.c create mode 100644 psp/psplib/pl_snd.h create mode 100644 psp/psplib/pl_util.c create mode 100644 psp/psplib/pl_util.h create mode 100644 psp/psplib/pl_vk.c create mode 100644 psp/psplib/pl_vk.h create mode 100644 psp/psplib/stockfont.fd create mode 100644 psp/psplib/stockfont.h create mode 100644 psp/psplib/ui.c create mode 100644 psp/psplib/ui.h create mode 100644 psp/psplib/video.c create mode 100644 psp/psplib/video.h create mode 100644 psp/race-icon.png create mode 100644 readme.txt create mode 100644 sound.cpp create mode 100644 sound.h create mode 100644 state.cpp create mode 100644 state.h create mode 100644 tlcs900h.cpp create mode 100644 tlcs900h.h create mode 100644 unzip.c create mode 100644 unzip.h diff --git a/DrZ80.h b/DrZ80.h new file mode 100644 index 0000000..0f552b0 --- /dev/null +++ b/DrZ80.h @@ -0,0 +1,76 @@ +/* + * DrZ80 Version 1.0 + * Z80 Emulator by Reesy + * Copyright 2005 Reesy + * + * This file is part of DrZ80. + * + * DrZ80 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * DrZ80 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with DrZ80; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DRZ80_H +#define DRZ80_H + +extern int DrZ80Ver; /* Version number of library */ + +struct DrZ80 +{ + unsigned int Z80PC; /*0x00 - PC Program Counter (Memory Base + PC) */ + unsigned int Z80A; /*0x04 - A Register: 0xAA------ */ + unsigned int Z80F; /*0x08 - F Register: 0xFF------ */ + unsigned int Z80BC; /*0x0C - BC Registers: 0xBBCC---- */ + unsigned int Z80DE; /*0x10 - DE Registers: 0xDDEE---- */ + unsigned int Z80HL; /*0x14 - HL Registers: 0xHHLL---- */ + unsigned int Z80SP; /*0x18 - SP Stack Pointer (Memory Base + PC) */ + unsigned int Z80PC_BASE; /*0x1C - PC Program Counter (Memory Base) */ + unsigned int Z80SP_BASE; /*0x20 - SP Stack Pointer (Memory Base) */ + unsigned int Z80IX; /*0x24 - IX Index Register */ + unsigned int Z80IY; /*0x28 - IY Index Register */ + unsigned int Z80I; /*0x2C - I Interrupt Register */ + unsigned int Z80A2; /*0x30 - A' Register: 0xAA------ */ + unsigned int Z80F2; /*0x34 - F' Register: 0xFF------ */ + unsigned int Z80BC2; /*0x38 - B'C' Registers: 0xBBCC---- */ + unsigned int Z80DE2; /*0x3C - D'E' Registers: 0xDDEE---- */ + unsigned int Z80HL2; /*0x40 - H'L' Registers: 0xHHLL---- */ + int cycles; /* Cycles pending to be executed yet */ + int previouspc; /* Previous PC */ + unsigned char Z80_IRQ; /*0x44 - Set IRQ Number */ + unsigned char Z80IF; /*0x48 - Interrupt Flags: bit1=_IFF1, bit2=_IFF2, bit3=_HALT */ + unsigned char Z80IM; /*0x4C - Set IRQ Mode */ + unsigned char spare; /*0x4C - N/A */ + unsigned int z80irqvector; /*0x38 - Set IRQ Vector i.e. 0xFF=RST */ + void (*z80_irq_callback )(void); + void (*z80_write8 )(unsigned char d,unsigned short a); + void (*z80_write16 )(unsigned short d,unsigned short a); + unsigned char (*z80_in)(unsigned short p); + void (*z80_out )(unsigned short p,unsigned char d); + unsigned char (*z80_read8)(unsigned short a); + unsigned short (*z80_read16)(unsigned short a); + unsigned int (*z80_rebaseSP)(unsigned short new_sp); + unsigned int (*z80_rebasePC)(unsigned short new_pc); +}; + +extern void DrZ80Run(struct DrZ80 *pcy,unsigned int cyc); + +#endif + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif diff --git a/DrZ80.s b/DrZ80.s new file mode 100644 index 0000000..b3adbcd --- /dev/null +++ b/DrZ80.s @@ -0,0 +1,7842 @@ + .DATA +;@ Reesy's Z80 Emulator Version 0.001 + +;@ (c) Copyright 2004 Reesy, All rights reserved +;@ DrZ80 is free for non-commercial use. + +;@ For commercial use, separate licencing terms must be obtained. + + .global DrZ80Run + .global DrZ80Ver + + .equiv INTERRUPT_MODE, 1 ;@0 = Use internal int handler, 1 = Use Mames int handler + .equiv FAST_Z80SP, 1 ;@0 = Use mem functions for stack pointer, 1 = Use direct mem pointer + .equiv UPDATE_CONTEXT, 0 + .equiv FAST_REBASE_PC, 1 ;@1=try not to call the rebase functions + .equiv FAST_REBASE_SP, 1 ;@1=try not to call the rebase functions + .equiv FAKE_PORTIO, 1 ;@1=don't really do any port IO + +.if INTERRUPT_MODE + .extern Interrupt +.endif + +DrZ80Ver: .long 0x0001 + +;@--------------------------------------- + +.macro fetch cycs + subs z80_icount,z80_icount,#\cycs +.if UPDATE_CONTEXT + str z80pc,[cpucontext,#z80pc_pointer] + str z80_icount,[cpucontext,#cycles_pointer] + ldr r1,[cpucontext,#z80pc_base] + sub r2,z80pc,r1 + str r2,[cpucontext,#previouspc] +.endif + ldrplb r0,[z80pc],#1 + ldrpl pc,[opcodes,r0, lsl #2] + bmi z80_execute_end +.endm + +.macro eatcycles cycs + sub z80_icount,z80_icount,#\cycs +.if UPDATE_CONTEXT + str z80_icount,[cpucontext,#cycles_pointer] +.endif +.endm + +.macro readmem8 +.if UPDATE_CONTEXT + str z80pc,[cpucontext,#z80pc_pointer] +.endif + stmfd sp!,{r3,r12} + mov lr,pc + ldr pc,[cpucontext,#z80_read8] ;@ r0 = addr - data returned in r0 + ldmfd sp!,{r3,r12} +.endm + +.macro readmem8HL + mov r0,z80hl, lsr #16 + readmem8 +.endm + +.macro readmem16 +.if UPDATE_CONTEXT + str z80pc,[cpucontext,#z80pc_pointer] +.endif + stmfd sp!,{r3,r12} + mov lr,pc + ldr pc,[cpucontext,#z80_read16] + ldmfd sp!,{r3,r12} +.endm + +.macro writemem8 +.if UPDATE_CONTEXT + str z80pc,[cpucontext,#z80pc_pointer] +.endif + stmfd sp!,{r3,r12} + mov lr,pc + ldr pc,[cpucontext,#z80_write8] ;@ r0=data r1=addr + ldmfd sp!,{r3,r12} +.endm + +.macro writemem8DE + mov r1,z80de, lsr #16 + writemem8 +.endm + +.macro writemem8HL + mov r1,z80hl, lsr #16 + writemem8 +.endm + +.macro writemem16 +.if UPDATE_CONTEXT + str z80pc,[cpucontext,#z80pc_pointer] +.endif + stmfd sp!,{r3,r12} + mov lr,pc + ldr pc,[cpucontext,#z80_write16] ;@ r0=data r1=addr + ldmfd sp!,{r3,r12} +.endm + +.macro copymem8HL_DE +.if UPDATE_CONTEXT + str z80pc,[cpucontext,#z80pc_pointer] +.endif + mov r0,z80hl, lsr #16 + stmfd sp!,{r3,r12} + mov lr,pc + ldr pc,[cpucontext,#z80_read8] ;@ r0 = addr - data returned in r0 +.if UPDATE_CONTEXT + str z80pc,[cpucontext,#z80pc_pointer] +.endif + mov r1,z80de, lsr #16 + mov lr,pc + ldr pc,[cpucontext,#z80_write8] ;@ r0=data r1=addr + ldmfd sp!,{r3,r12} +.endm +;@--------------------------------------- + +.macro rebasepc +.if UPDATE_CONTEXT + str z80pc,[cpucontext,#z80pc_pointer] +.endif +.if FAST_REBASE_PC + ldr r1,[cpucontext,#z80pc_base] + add z80pc,r0,r1 +.else + stmfd sp!,{r3,r12} + mov lr,pc + ldr pc,[cpucontext,#z80_rebasePC] ;@ r0=new pc - external function sets z80pc_base and returns new z80pc in r0 + ldmfd sp!,{r3,r12} + mov z80pc,r0 +.endif +.endm + +.macro rebasesp +.if UPDATE_CONTEXT + str z80pc,[cpucontext,#z80pc_pointer] +.endif +.if FAST_REBASE_SP + ldr r1,[cpucontext,#z80sp_base] + add r0,r0,r1 +.else + stmfd sp!,{r3,r12} + mov lr,pc + ldr pc,[cpucontext,#z80_rebaseSP] ;@ external function must rebase sp + ldmfd sp!,{r3,r12} +.endif +.endm +;@---------------------------------------------------------------------------- + +.macro opADC + movs z80f,z80f,lsr#2 ;@ get C + subcs r0,r0,#0x100 + eor z80f,r0,z80a,lsr#24 ;@ prepare for check of half carry + adcs z80a,z80a,r0,ror#8 + mrs r0,cpsr ;@ S,Z,V&C + eor z80f,z80f,z80a,lsr#24 + and z80f,z80f,#1< 0xFF + writemem8HL + add z80hl,z80hl,#1<<16 + sub z80bc,z80bc,#1<<24 + tst z80bc,#0xFF<<24 + orrmi z80f,z80f,#1< 0xFF + sub z80bc,z80bc,#1<<24 + tst z80bc,#0xFF<<24 + orrmi z80f,z80f,#1< 0xFF + writemem8HL + sub z80hl,z80hl,#1<<16 + sub z80bc,z80bc,#1<<24 + tst z80bc,#0xFF<<24 + orrmi z80f,z80f,#1< 0xFF + sub z80bc,z80bc,#1<<24 + tst z80bc,#0xFF<<24 + orrmi z80f,z80f,#1< 0xFF + writemem8HL + add z80hl,z80hl,#1<<16 + sub z80bc,z80bc,#1<<24 + tst z80bc,#0xFF<<24 + orrmi z80f,z80f,#1< 0xFF + sub z80bc,z80bc,#1<<24 + tst z80bc,#0xFF<<24 + orrmi z80f,z80f,#1< 0xFF + writemem8HL + sub z80hl,z80hl,#1<<16 + sub z80bc,z80bc,#1<<24 + tst z80bc,#0xFF<<24 + orrmi z80f,z80f,#1< 0xFF + sub z80bc,z80bc,#1<<24 + tst z80bc,#0xFF<<24 + orrmi z80f,z80f,#1< + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/DrZ80_support.cpp b/DrZ80_support.cpp new file mode 100644 index 0000000..67c6e6e --- /dev/null +++ b/DrZ80_support.cpp @@ -0,0 +1,323 @@ +//--------------------------------------------------------------------------- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. See also the license.txt file for +// additional informations. +//--------------------------------------------------------------------------- + +// +// Support functions for interfacing with DrZ80 +// + +#ifndef __GP32__ +#include "stdafx.h" +#endif +#include "main.h" +#include "memory.h" +//#include "mainemu.h" + +#include "DrZ80_support.h" + +#define INT_IRQ 0x01 +#define NMI_IRQ 0x02 + +#define PUSH_PC() { Z80.regs.Z80SP=z80_rebaseSP(Z80.regs.Z80SP-Z80.regs.Z80SP_BASE-2); Z80.regs.z80_write16(Z80.regs.Z80PC - Z80.regs.Z80PC_BASE,Z80.regs.Z80SP - Z80.regs.Z80SP_BASE); } +/*#define PUSH_PC() { Z80.regs.Z80SP-=2; Z80.regs.z80_write16(Z80.regs.Z80PC - Z80.regs.Z80PC_BASE,Z80.regs.Z80SP); }*/ + +/*int Z80_ICount;*/ + +Z80_Regs Z80; + +static unsigned int z80_rebaseSP(unsigned short address) +{ + //Z80.regs.Z80SP_BASE = (unsigned int)&mainram[0x3000]; + Z80.regs.Z80SP = Z80.regs.Z80SP_BASE + address; + return (Z80.regs.Z80SP); +} + +static unsigned int z80_rebasePC(unsigned short address) +{ + //Z80.regs.Z80PC_BASE = (unsigned int)&mainram[0x3000]; + Z80.regs.Z80PC = Z80.regs.Z80PC_BASE + address; + return (Z80.regs.Z80PC); +} + +static void z80_irq_callback(void) +{ + Z80.regs.Z80_IRQ = 0x00; +} + + +/**************************************************************************** + * Reset registers to their initial values + ****************************************************************************/ +void Z80_Reset(void) +{ + memset (&Z80, 0, sizeof(Z80_Regs)); +#ifdef DRZ80 + Z80.regs.z80_rebasePC=z80_rebasePC; + Z80.regs.z80_rebaseSP=z80_rebaseSP /* 0 */; + Z80.regs.z80_read8 =z80MemReadB; /* z80_read8 */ + Z80.regs.z80_read16 =z80MemReadW; + Z80.regs.z80_write8 =DrZ80ngpMemWriteB; + Z80.regs.z80_write16 =DrZ80ngpMemWriteW; + Z80.regs.z80_in =DrZ80ngpPortReadB; + Z80.regs.z80_out =DrZ80ngpPortWriteB; + //Z80.regs.z80_irq_callback=z80_irq_callback; + Z80.regs.z80_irq_callback=z80_irq_callback; + Z80.regs.Z80BC = 0013; + Z80.regs.Z80DE = 0x00D8; + Z80.regs.Z80HL = 0x014D; + + + /* + Z80.regs.Z80A = 0x00 <<24; + Z80.regs.Z80F = (1<<2); // set ZFlag + Z80.regs.Z80A2 = 0x00 <<24; + Z80.regs.Z80F2 = 1<<2; // set ZFlag + Z80.regs.Z80BC2 = 0x0000 <<16; + Z80.regs.Z80DE2 = 0x0000 <<16; + Z80.regs.Z80HL2 = 0x0000 <<16; + Z80.regs.Z80IX = 0xFFFF <<16; + Z80.regs.Z80IY = 0xFFFF <<16; + Z80.regs.Z80I = 0x00; + Z80.regs.Z80IM = 0x00; + Z80.regs.Z80_IRQ = 0x00; + Z80.regs.Z80IF = 0x00; + */ + + //Z80.regs.Z80PC=Z80.regs.z80_rebasePC(0x0000); + //Z80.regs.Z80SP=Z80.regs.z80_rebaseSP(0xFFFE); /* 0xf000 */ + + Z80.regs.Z80SP_BASE = (unsigned int)&mainram[0x3000]; + Z80.regs.Z80SP = Z80.regs.Z80SP_BASE + 0xFFFE; + Z80.regs.Z80PC_BASE = (unsigned int)&mainram[0x3000]; + Z80.regs.Z80PC = Z80.regs.Z80PC_BASE + 0x0000; + + Z80.request_irq = Z80.service_irq = -1; + + Z80_Clear_Pending_Interrupts(); +#endif +} + +void Z80_Cause_Interrupt(int type) +{ + /* type value : */ + /* Z80_NMI_INT -> NMI request */ + /* Z80_IGNORE_INT -> no request */ + /* vector(0x00-0xff) -> SINGLE interrupt request */ + /* Z80_VECTOR(device,status) -> DaisyChain change interrupt status */ + /* device : device number of daisy-chain link */ + /* status : Z80_INT_REQ -> interrupt request */ + /* Z80_INT_IEO -> interrupt disable output */ + + if (type == Z80_NMI_INT) + { + Z80.pending_irq |= NMI_IRQ; + } + else if (type != Z80_IGNORE_INT) + { + if( Z80.irq_max ) + { /* daisy chain mode */ + int device = type >> 8; + int state = type & 0xff; + if( Z80.int_state[device] != state ) + { + + /* set new interrupt status */ + Z80.int_state[device] = state; + + /* check interrupt status */ + /* search highest interrupt request device (next interrupt device) */ + /* and highest interrupt service device (next reti device) */ + { + int device; + Z80.request_irq = Z80.service_irq = -1; + + /* search higher IRQ or IEO */ + for( device = 0 ; device < Z80.irq_max ; device ++ ) + { + /* IEO = disable ? */ + if( Z80.int_state[device] & Z80_INT_IEO ) + { + /* if IEO is disable , masking lower IRQ */ + Z80.request_irq = -1; + /* set highest interrupt service device */ + Z80.service_irq = device; + } + /* IRQ = ON ? */ + if( Z80.int_state[device] & Z80_INT_REQ ) + Z80.request_irq = device; + } + /* set interrupt pending flag */ + if( Z80.request_irq >= 0 ) + Z80.pending_irq |= INT_IRQ; + else + Z80.pending_irq &= ~INT_IRQ; + } + } + } + else + { + /* single int mode */ + Z80.regs.z80irqvector = type & 0xff; + Z80.pending_irq |= INT_IRQ; + } + } +} + +void Z80_Clear_Pending_Interrupts(void) +{ + int i; + /* clear irq for all devices */ + for( i = 0 ; i < Z80_MAXDAISY ; i++ ) + Z80.int_state[i] = 0; + Z80.pending_irq = 0; + Z80.service_irq = -1; +} + +// Set all registers to given values +/*void Z80_SetRegs (Z80_Regs *Regs) +{ + memcpy(&Z80,Regs,sizeof(Z80)); + //change_pc(Z80.regs.Z80PC - Z80.regs.Z80PC_BASE); +} + +// Get all registers in given buffer +void Z80_GetRegs (Z80_Regs *Regs) +{ + memcpy(Regs,&Z80,sizeof(Z80)); +} + +// Return program counter +unsigned Z80_GetPC (void) +{ + return (Z80.regs.Z80PC - Z80.regs.Z80PC_BASE); +} + +int Z80_GetPreviousPC (void) +{ + return (Z80.regs.previouspc); +}*/ + + + +void Interrupt(void) +{ + /* This extra check is because DrZ80 calls this function directly but does + not have access to the Z80.pending_irq variable. So we check here instead. */ + if(!Z80.pending_irq) + { + return; + } /* If no pending ints exit */ + + /* Check if ints enabled */ + if ( (Z80.pending_irq & NMI_IRQ) || (Z80.regs.Z80IF&1) ) + { + + int irq_vector = Z80_IGNORE_INT; + + /* there isn't a valid previouspc */ + //{ + //extern int previouspc; + //previouspc = -1; + // Z80.regs.previouspc=-1; + //} + + /* DrZ80 Z80IF */ + /* bit1 = _IFF1 */ + /* bit2 = _IFF2 */ + /* bit3 = _HALT */ + + /* Check if processor was halted */ + if (Z80.regs.Z80IF&4) + { + Z80.regs.Z80PC=Z80.regs.z80_rebasePC(Z80.regs.Z80PC - Z80.regs.Z80PC_BASE + 1); /* Inc PC */ + Z80.regs.Z80IF&= ~4; /* and clear halt */ + } + + if (Z80.pending_irq & NMI_IRQ) + { + Z80.regs.Z80IF = (Z80.regs.Z80IF&1)<<1; /* Save interrupt flip-flop 1 to 2 and Clear interrupt flip-flop 1 */ + PUSH_PC(); + Z80.regs.Z80PC=Z80.regs.z80_rebasePC(0x0066); + /* reset NMI interrupt request */ + Z80.pending_irq &= ~NMI_IRQ; + } + else + { + /* Clear interrupt flip-flop 1 */ + Z80.regs.Z80IF&= ~1; + /* reset INT interrupt request */ + Z80.pending_irq &= ~INT_IRQ; + if ( Z80.irq_max ) + { + if( Z80.request_irq >= 0 ) + { + irq_vector = Z80.irq[Z80.request_irq].interrupt_entry(Z80.irq[Z80.request_irq].irq_param); + Z80.request_irq = -1; + } + } + else + { + irq_vector = Z80.regs.z80irqvector; + } + + /* Interrupt mode 2. Call [Z80.I:databyte] */ + if( Z80.regs.Z80IM == 2 ) + { + /*irq_vector = (irq_vector & 0xff) | (Z80.regs.Z80I << 8); + PUSH_PC(); + Z80.regs.Z80PC=Z80.regs.z80_rebasePC(Z80.regs.z80_read16(irq_vector));*/ + } + else + { + /* Interrupt mode 1. RST 38h */ + if( Z80.regs.Z80IM == 1 ) + { + PUSH_PC(); + Z80.regs.Z80PC=Z80.regs.z80_rebasePC(0x0038); + } + else + { + /* Interrupt mode 0. We check for CALL and JP instructions, */ + /* if neither of these were found we assume a 1 byte opcode */ + /* was placed on the databus */ + /*switch (irq_vector & 0xff0000) + { + case 0xcd0000: /// call + PUSH_PC(); + case 0xc30000: // jump + Z80.regs.Z80PC=Z80.regs.z80_rebasePC(irq_vector & 0xffff); + break; + default: + irq_vector &= 0xff; + PUSH_PC(); + Z80.regs.Z80PC=Z80.regs.z80_rebasePC(0x0038); + break; + }*/ + } + } + } + } + else + { + } +} + +/**************************************************************************** + * Execute IPeriod T-states. Return number of T-states really executed + ****************************************************************************/ +extern "C" int Z80_Execute(int cycles) +{ + Z80.regs.cycles = cycles; + //Z80.regs.previouspc=(Z80.regs.Z80PC - Z80.regs.Z80PC_BASE); + + if (Z80.pending_irq) + Interrupt(); + + DrZ80Run(&Z80.regs, cycles); + //change_pc(Z80.regs.Z80PC - Z80.regs.Z80PC_BASE); + return cycles;// (cycles-Z80.regs.cycles); +} diff --git a/DrZ80_support.h b/DrZ80_support.h new file mode 100644 index 0000000..d1ea7a5 --- /dev/null +++ b/DrZ80_support.h @@ -0,0 +1,67 @@ +#ifndef Z80_H +#define Z80_H + +#ifdef __cplusplus +extern "C" { +#endif + + +//#include "osd_cpu.h" +//#include "cpuintrf.h" +#include "DrZ80.h" + +/* daisy-chain link */ +typedef struct { + void (*reset)(int); /* reset callback */ + int (*interrupt_entry)(int); /* entry callback */ + void (*interrupt_reti)(int); /* reti callback */ + int irq_param; /* callback paramater */ +} Z80_DaisyChain; + +#define Z80_MAXDAISY 4 /* maximum of daisy chan device */ + +#define Z80_INT_REQ 0x01 /* interrupt request mask */ +#define Z80_INT_IEO 0x02 /* interrupt disable mask(IEO) */ + +#define Z80_VECTOR(device,state) (((device)<<8)|(state)) + +/****************************************************************************/ +/* The Z80 registers. HALT is set to 1 when the CPU is halted, the refresh */ +/* register is calculated as follows: refresh=(Regs.R&127)|(Regs.R2&128) */ +/****************************************************************************/ +typedef struct { + struct DrZ80 regs; + int pending_irq; + int irq_max; /* number of daisy chain devices */ + int request_irq; /* daisy chain next request device */ + int service_irq; /* daisy chain next reti handling device */ + int int_state[Z80_MAXDAISY]; + Z80_DaisyChain irq[Z80_MAXDAISY]; +} Z80_Regs; + +/*extern int Z80_ICount; // T-state count */ +extern Z80_Regs Z80; +//#define Z80_ICount (Z80.regs.cycles) + +#define Z80_IGNORE_INT -1 /* Ignore interrupt */ +#define Z80_NMI_INT -2 /* Execute NMI */ +#define Z80_IRQ_INT -1000 /* Execute IRQ */ + +extern unsigned Z80_GetPC (void); /* Get program counter */ +extern int Z80_GetPreviousPC (void); +extern void Z80_GetRegs (Z80_Regs *Regs); /* Get registers */ +extern void Z80_SetRegs (Z80_Regs *Regs); /* Set registers */ +//extern void Z80_Reset (Z80_DaisyChain *daisy_chain); +extern void Z80_Reset(void); +extern int Z80_Execute(int cycles); /* Execute cycles T-States - returns number of cycles actually run */ +extern int Z80_Interrupt(void); +extern void Z80_Cause_Interrupt(int type); +extern void Z80_Clear_Pending_Interrupts(void); +extern void Interrupt(void); /* required for DrZ80 int hack */ + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif + +#endif + diff --git a/Makefile.psp b/Makefile.psp new file mode 100644 index 0000000..c5c7b50 --- /dev/null +++ b/Makefile.psp @@ -0,0 +1,45 @@ +PSPSDK=$(shell psp-config --pspsdk-path) + +PSPAPP=psp +PSPLIB=$(PSPAPP)/psplib + +PSP_FW_VERSION=200 +export PSP_FW_VERSION + +PSP_APP_NAME=RACE! PSP +PSP_APP_VER=2.20 + +TARGET=racepsp +EXTRA_TARGETS=EBOOT.PBP +PSP_EBOOT_TITLE=$(PSP_APP_NAME) $(PSP_APP_VER) +PSP_EBOOT_ICON=$(PSPAPP)/race-icon.png + +BUILD_EMUL=cz80.o cz80_support.o input.o neopopsound.o \ + ngpBios.o tlcs900h.o memory.o flash.o graphics.o \ + main.o state.o sound.o +BUILD_MZ=ioapi.o unzip.o +BUILD_PORT=$(PSPAPP)/main.o $(PSPAPP)/emulate.o $(PSPAPP)/menu.o + +OBJS=$(BUILD_EMUL) $(BUILD_MZ) $(BUILD_PORT) + +DEFINES=-DCZ80 -DTARGET_PSP -D_MAX_PATH=2048 -DHOST_FPS=60 +BASE_DEFS=-DPSP -DPSP_APP_VER=\"$(PSP_APP_VER)\" -DPSP_APP_NAME="\"$(PSP_APP_NAME)\"" +CFLAGS=-O2 -G0 -Wall $(BASE_DEFS) $(DEFINES) +CXXFLAGS=$(CFLAGS) -fno-exceptions -fno-rtti +ASFLAGS=$(CFLAGS) +INCDIR=$(PSPLIB) +LIBDIR=$(PSPLIB) +LIBS=-lpsplib -lpng -lpspgu -lpsppower \ + -lz -lm -lc -lpspaudio -lpsprtc -lpspwlan -lpspnet_adhoc \ + -lpspnet_adhocctl -lpspnet_adhocmatching + +all: build_libs +clean: clean_libs + +include $(PSPSDK)/lib/build.mak + +build_libs: + cd $(PSPLIB) ; $(MAKE) +clean_libs: + cd $(PSPLIB) ; $(MAKE) clean + diff --git a/PARAM.SFO b/PARAM.SFO new file mode 100644 index 0000000000000000000000000000000000000000..2298a034f0a37fda8d6b7fc84c4653bce6b7ec4a GIT binary patch literal 408 zcmcgnK?=e!5S(fS^&sL&JXH|9h_pq#$GVnEYD*FYPyLFI@R2^lNmb|zT$s#GX0l08 z+fxt#PXI4sNC06N`nBzW5yD>otNq@LdQ6@YKEI$IeET_h-8mmo?>qjAS~~uQTGOA9 zA4E(Xs>-Q@7G%mvUYR?Nh0U7c_~DxvTT~a+%E-kj-DtUqMs4fH-mR0eVFE^SA997` rAb?*)nFH7CY?CZS1dX{a^1NVpJx}h%=*fo3;s``d_^P + +#define DWORD unsigned int +#define byte unsigned char + +#define _u8 unsigned char +#define Uint8 unsigned char +#define _u16 unsigned short +#define _u32 unsigned int + +#define BOOL int +#define FALSE 0 +#define TRUE (!0) +#define HWND void* + +#else /* ifdef TARGET_PSP */ + +#ifdef TARGET_GP2X + +//extern "C" void gp2x_memcpy(unsigned char *, unsigned char *, unsigned int); +#define memcpy gp2x_memcpy +#define memcmp gp2x_memcmp +//#define memset gp2x_memset + +#define GENREGSPC_AS_REG //comment out to do it as a regular mem loc +#define GENREGSSR_AS_REG //comment out to do it as a regular mem loc + +register unsigned char *my_pc asm ("r9"); +register unsigned long opcode asm ("r6"); +#ifdef GENREGSPC_AS_REG +register unsigned long gen_regsPC asm("r8"); +#endif +#ifdef GENREGSSR_AS_REG +register unsigned long gen_regsSR asm("r7"); +#endif +#endif + + +#include "StdAfx.h" +#include +#include +#include +#include +#include + + +typedef unsigned int UINT32; +typedef unsigned int DWORD; +typedef void * HRESULT; +typedef unsigned char byte; + +typedef unsigned char _u8; +typedef unsigned short _u16; +typedef unsigned int _u32; + + + + + + +#define MB_OK 1 + +typedef bool BOOL; +#define FALSE false +#define TRUE true + +#ifndef _MAX_PATH +#define _MAX_PATH 150 +#endif + +#ifdef TARGET_WIN +#define DEBUG +#endif + +#ifdef DEBUG +#define dbg_printf printf +#else +#define dbg_printf if(0) printf +#endif +#define dbg_print dbg_printf + +void AfxMessageBox(char *a, int b, int c); +void AfxMessageBox(char *a, int b); +void AfxMessageBox(char *a); + +#define HWND void* +#define BITMAP + +#endif /* ifdef TARGET_PSP */ + +#endif //STDAFX_H diff --git a/crypt.h b/crypt.h new file mode 100644 index 0000000..9c7a89c --- /dev/null +++ b/crypt.h @@ -0,0 +1,132 @@ +/* crypt.h -- base code for crypt/uncrypt ZIPfile + + + Version 1.00, September 10th, 2003 + + Copyright (C) 1998-2003 Gilles Vollant + + This code is a modified version of crypting code in Infozip distribution + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + If you don't need crypting in your application, just define symbols + NOCRYPT and NOUNCRYPT. + + This code support the "Traditional PKWARE Encryption". + + The new AES encryption added on Zip format by Winzip (see the page + http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong + Encryption is not supported. +*/ + +#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) + +/*********************************************************************** + * Return the next byte in the pseudo-random sequence + */ +static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) +{ + unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an + * unpredictable manner on 16-bit systems; not a problem + * with any known compiler so far, though */ + + temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; + return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); +} + +/*********************************************************************** + * Update the encryption keys with the next byte of plain text + */ +static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) +{ + (*(pkeys+0)) = CRC32((*(pkeys+0)), c); + (*(pkeys+1)) += (*(pkeys+0)) & 0xff; + (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; + { + register int keyshift = (int)((*(pkeys+1)) >> 24); + (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); + } + return c; +} + + +/*********************************************************************** + * Initialize the encryption keys and the random header according to + * the given password. + */ +static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) +{ + *(pkeys+0) = 305419896L; + *(pkeys+1) = 591751049L; + *(pkeys+2) = 878082192L; + while (*passwd != '\0') { + update_keys(pkeys,pcrc_32_tab,(int)*passwd); + passwd++; + } +} + +#define zdecode(pkeys,pcrc_32_tab,c) \ + (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) + +#define zencode(pkeys,pcrc_32_tab,c,t) \ + (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) + +#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED + +#define RAND_HEAD_LEN 12 + /* "last resort" source for second part of crypt seed pattern */ +# ifndef ZCR_SEED2 +# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ +# endif + +static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting) + const char *passwd; /* password string */ + unsigned char *buf; /* where to write header */ + int bufSize; + unsigned long* pkeys; + const unsigned long* pcrc_32_tab; + unsigned long crcForCrypting; +{ + int n; /* index in random header */ + int t; /* temporary */ + int c; /* random byte */ + unsigned char header[RAND_HEAD_LEN-2]; /* random header */ + static unsigned calls = 0; /* ensure different random header each time */ + + if (bufSize> 7) & 0xff; + header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); + } + /* Encrypt random header (last two bytes is high word of crc) */ + init_keys(passwd, pkeys, pcrc_32_tab); + for (n = 0; n < RAND_HEAD_LEN-2; n++) + { + buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); + } + buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); + buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); + return n; +} + +#endif diff --git a/cz80.cpp b/cz80.cpp new file mode 100644 index 0000000..591711b --- /dev/null +++ b/cz80.cpp @@ -0,0 +1,376 @@ +/********************************************************************************/ +/* */ +/* CZ80 (Z80 CPU emulator) version 0.92 */ +/* Compiled with Dev-C++ */ +/* Copyright 2004-2005 Stéphane Dallongeville */ +/* */ +/********************************************************************************/ + +#include +#include +#include +/*#ifdef GP2X +#include "gp2x/minimal.h" +#else +#include "sdl/minimal.h" +#endif*/ + +#include "StdAfx.h" +#include "main.h" +#include "memory.h" + +#include "cz80.h" + + +// include macro file +////////////////////// + +#include "cz80.inc" + +// lookup tables +///////////////// + +static u8 SZXY[256]; // zero and sign flags +static u8 SZXYP[256]; // zero, sign and parity flags +static u8 SZXY_BIT[256]; // zero, sign and parity/overflow (=zero) flags for BIT opcode +static u8 SZXYHV_inc[256]; // zero, sign, half carry and overflow flags INC R8 +static u8 SZXYHV_dec[256]; // zero, sign, half carry and overflow flags DEC R8 + +#define fast_memset memset + +// core main functions +/////////////////////// + +void Cz80_Init(cz80_struc *cpu) +{ + u32 i, j, p; + + fast_memset(cpu, 0, sizeof(cz80_struc)); + + // flags tables initialisation + for (i = 0; i < 256; i++) + { + SZXY[i] = i & (CZ80_SF | CZ80_YF | CZ80_XF); + if (!i) SZXY[i] |= CZ80_ZF; + + SZXY_BIT[i] = i & (CZ80_SF | CZ80_YF | CZ80_XF); + if (!i) SZXY_BIT[i] |= CZ80_ZF | CZ80_PF; + + for (j = 0, p = 0; j < 8; j++) if (i & (1 << j)) p++; + SZXYP[i] = SZXY[i]; + if (!(p & 1)) SZXYP[i] |= CZ80_PF; + + SZXYHV_inc[i] = SZXY[i]; + if(i == 0x80) SZXYHV_inc[i] |= CZ80_VF; + if((i & 0x0F) == 0x00) SZXYHV_inc[i] |= CZ80_HF; + + SZXYHV_dec[i] = SZXY[i] | CZ80_NF; + if (i == 0x7F) SZXYHV_dec[i] |= CZ80_VF; + if ((i & 0x0F) == 0x0F) SZXYHV_dec[i] |= CZ80_HF; + } +} + +u32 Cz80_Reset(cz80_struc *cpu) +{ + cz80_struc *CPU = cpu; + + fast_memset(CPU, 0, (u32)(&(CPU->CycleSup)) - (u32)(&(CPU->BC))); + + Cz80_Set_PC(CPU, 0); + zIX = 0xFFFF; + zIY = 0xFFFF; +#if CZ80_DEBUG + zF = CZ80_ZF; +#else + zSP = 0xFFFE; + zFA = 0xFFFF; +#endif + + return CPU->Status; +} + +///////////////////////////////// + +void CZ80_FASTCALL Cz80_Enable(cz80_struc *cpu) +{ + cpu->Status &= ~CZ80_DISABLE; +} + +void CZ80_FASTCALL Cz80_Disable(cz80_struc *cpu) +{ + cpu->Status |= CZ80_DISABLE; +} + +///////////////////////////////// + +#include "cz80exec.inc" + +///////////////////////////////// + +void CZ80_FASTCALL Cz80_Set_IRQ(cz80_struc *cpu, s32 vector) +{ + cpu->IntVect = vector; + cpu->Status |= CZ80_HAS_INT; + cpu->CycleSup = cpu->CycleIO; + cpu->CycleIO = 0; +} + +void CZ80_FASTCALL Cz80_Set_NMI(cz80_struc *cpu) +{ + cpu->Status |= CZ80_HAS_NMI; + cpu->CycleSup = cpu->CycleIO; + cpu->CycleIO = 0; +} + +void CZ80_FASTCALL Cz80_Clear_IRQ(cz80_struc *cpu) +{ + cpu->Status &= ~CZ80_HAS_INT; +} + +void CZ80_FASTCALL Cz80_Clear_NMI(cz80_struc *cpu) +{ + cpu->Status &= ~CZ80_HAS_NMI; +} + +///////////////////////////////// + +s32 CZ80_FASTCALL Cz80_Get_CycleToDo(cz80_struc *cpu) +{ + if (!(cpu->Status & CZ80_RUNNING)) return 0; + + return cpu->CycleToDo; +} + +s32 CZ80_FASTCALL Cz80_Get_CycleRemaining(cz80_struc *cpu) +{ + if (!(cpu->Status & CZ80_RUNNING)) return 0; + + return (cpu->CycleIO + cpu->CycleSup); +} + +s32 CZ80_FASTCALL Cz80_Get_CycleDone(cz80_struc *cpu) +{ + if (!(cpu->Status & CZ80_RUNNING)) return 0; + + return (cpu->CycleToDo - (cpu->CycleIO + cpu->CycleSup)); +} + +void CZ80_FASTCALL Cz80_End_Execute(cz80_struc *cpu) +{ + cpu->CycleToDo -= cpu->CycleIO + cpu->CycleSup; + cpu->CycleIO = cpu->CycleSup = 0; +} + +void CZ80_FASTCALL Cz80_Waste_Cycle(cz80_struc *cpu, s32 cycle) +{ + cpu->CycleIO -= cycle; +} + +// externals main functions +//////////////////////////// + +u32 CZ80_FASTCALL Cz80_Get_BC(cz80_struc *cpu) +{ + cz80_struc *CPU = cpu; + return zBC; +} + +u32 CZ80_FASTCALL Cz80_Get_DE(cz80_struc *cpu) +{ + cz80_struc *CPU = cpu; + return zDE; +} + +u32 CZ80_FASTCALL Cz80_Get_HL(cz80_struc *cpu) +{ + cz80_struc *CPU = cpu; + return zHL; +} + +u32 CZ80_FASTCALL Cz80_Get_AF(cz80_struc *cpu) +{ + cz80_struc *CPU = cpu; + return (zF | (zA << 8)); +} + +u32 CZ80_FASTCALL Cz80_Get_BC2(cz80_struc *cpu) +{ + cz80_struc *CPU = cpu; + return zBC2; +} + +u32 CZ80_FASTCALL Cz80_Get_DE2(cz80_struc *cpu) +{ + cz80_struc *CPU = cpu; + return zDE2; +} + +u32 CZ80_FASTCALL Cz80_Get_HL2(cz80_struc *cpu) +{ + cz80_struc *CPU = cpu; + return zHL2; +} + +u32 CZ80_FASTCALL Cz80_Get_AF2(cz80_struc *cpu) +{ + cz80_struc *CPU = cpu; + return (zF2 | (zA2 << 8)); +} + +u32 CZ80_FASTCALL Cz80_Get_IX(cz80_struc *cpu) +{ + cz80_struc *CPU = cpu; + return zIX; +} + +u32 CZ80_FASTCALL Cz80_Get_IY(cz80_struc *cpu) +{ + cz80_struc *CPU = cpu; + return zIY; +} + +u32 CZ80_FASTCALL Cz80_Get_SP(cz80_struc *cpu) +{ + cz80_struc *CPU = cpu; + return zSP; +} + +u32 CZ80_FASTCALL Cz80_Get_PC(cz80_struc *cpu) +{ + cz80_struc *CPU = cpu; + u8* PC = cpu->PC; + return zRealPC; +} + +u32 CZ80_FASTCALL Cz80_Get_R(cz80_struc *cpu) +{ + cz80_struc *CPU = cpu; + return zR; +} + +u32 CZ80_FASTCALL Cz80_Get_IFF(cz80_struc *cpu) +{ + cz80_struc *CPU = cpu; + u32 value = 0; + + if (zIFF1 & CZ80_IFF) value |= 1; + if (zIFF2 & CZ80_IFF) value |= 2; + return value; +} + +u32 CZ80_FASTCALL Cz80_Get_IM(cz80_struc *cpu) +{ + cz80_struc *CPU = cpu; + return zIM; +} + +u32 CZ80_FASTCALL Cz80_Get_I(cz80_struc *cpu) +{ + cz80_struc *CPU = cpu; + return zI; +} + + +void CZ80_FASTCALL Cz80_Set_BC(cz80_struc *cpu, u32 value) +{ + cz80_struc *CPU = cpu; + zBC = value; +} + +void CZ80_FASTCALL Cz80_Set_DE(cz80_struc *cpu, u32 value) +{ + cz80_struc *CPU = cpu; + zDE = value; +} + +void CZ80_FASTCALL Cz80_Set_HL(cz80_struc *cpu, u32 value) +{ + cz80_struc *CPU = cpu; + zHL = value; +} + +void CZ80_FASTCALL Cz80_Set_AF(cz80_struc *cpu, u32 val) +{ + cz80_struc *CPU = cpu; + zF = val; + zA = val >> 8; +} + +void CZ80_FASTCALL Cz80_Set_BC2(cz80_struc *cpu, u32 value) +{ + cz80_struc *CPU = cpu; + zBC2 = value; +} + +void CZ80_FASTCALL Cz80_Set_DE2(cz80_struc *cpu, u32 value) +{ + cz80_struc *CPU = cpu; + zDE2 = value; +} + +void CZ80_FASTCALL Cz80_Set_HL2(cz80_struc *cpu, u32 value) +{ + cz80_struc *CPU = cpu; + zHL2 = value; +} + +void CZ80_FASTCALL Cz80_Set_AF2(cz80_struc *cpu, u32 val) +{ + cz80_struc *CPU = cpu; + zF2 = val; + zA2 = val >> 8; +} + +void CZ80_FASTCALL Cz80_Set_IX(cz80_struc *cpu, u32 value) +{ + cz80_struc *CPU = cpu; + zIX = value; +} + +void CZ80_FASTCALL Cz80_Set_IY(cz80_struc *cpu, u32 value) +{ + cz80_struc *CPU = cpu; + zIY = value; +} + +void CZ80_FASTCALL Cz80_Set_SP(cz80_struc *cpu, u32 value) +{ + cz80_struc *CPU = cpu; + zSP = value; +} + +void CZ80_FASTCALL Cz80_Set_PC(cz80_struc *cpu, u32 val) +{ +#ifdef CZ80_USE_MAME_CHANGE_PC + change_pc16(val); +#endif + cpu->PC = (u8*)&mame4all_cz80_rom[val]; +} + + +void CZ80_FASTCALL Cz80_Set_R(cz80_struc *cpu, u32 value) +{ + cz80_struc *CPU = cpu; + zR = value & 0xFF; + zR2 = value & 0x80; +} + +void CZ80_FASTCALL Cz80_Set_IFF(cz80_struc *cpu, u32 value) +{ + cz80_struc *CPU = cpu; + zIFF = 0; + if (value & 1) zIFF1 = CZ80_IFF; + if (value & 2) zIFF2 = CZ80_IFF; +} + +void CZ80_FASTCALL Cz80_Set_IM(cz80_struc *cpu, u32 value) +{ + cz80_struc *CPU = cpu; + zIM = value & 3; +} + +void CZ80_FASTCALL Cz80_Set_I(cz80_struc *cpu, u32 value) +{ + cz80_struc *CPU = cpu; + zI = value & 0xFF; +} diff --git a/cz80.h b/cz80.h new file mode 100644 index 0000000..3e34fc8 --- /dev/null +++ b/cz80.h @@ -0,0 +1,262 @@ +/********************************************************************************/ +/* */ +/* CZ80 include file */ +/* C Z80 emulator version 0.92 */ +/* Copyright 2004-2005 St�phane Dallongeville */ +/* */ +/********************************************************************************/ + +#ifndef _CZ80_H_ +#define _CZ80_H_ + +#if defined(__cplusplus) && !defined(USE_CPLUS) +extern "C" { +#endif + + +/******************************/ +/* Compiler dependant defines */ +/******************************/ + +#ifndef u8 +#define u8 unsigned char +#endif + +#ifndef s8 +#define s8 char +#endif + +#ifndef u16 +#define u16 unsigned short +#endif + +#ifndef s16 +#define s16 short +#endif + +#ifndef u32 +#define u32 unsigned int +#endif + +#ifndef s32 +#define s32 int +#endif + +//#define CZ80_FASTCALL __fastcall +#define CZ80_FASTCALL + + +/*************************************/ +/* Z80 core Structures & definitions */ +/*************************************/ + +#define CZ80_FETCH_BITS 4 // [4-12] default = 8 + +#define CZ80_FETCH_SFT (16 - CZ80_FETCH_BITS) +#define CZ80_FETCH_BANK (1 << CZ80_FETCH_BITS) + +#define CZ80_LITTLE_ENDIAN 1 +#define CZ80_USE_JUMPTABLE 1 +#define CZ80_IRQ_CYCLES 1 +#define CZ80_SIZE_OPT 1 +#define CZ80_USE_WORD_HANDLER 0 +#define CZ80_EXACT 0 +#define CZ80_DEBUG 0 + +//use MAME's change_pc function or internal? +//#define CZ80_USE_MAME_CHANGE_PC + + +#define CZ80_SF_SFT 7 +#define CZ80_ZF_SFT 6 +#define CZ80_YF_SFT 5 +#define CZ80_HF_SFT 4 +#define CZ80_XF_SFT 3 +#define CZ80_PF_SFT 2 +#define CZ80_VF_SFT 2 +#define CZ80_NF_SFT 1 +#define CZ80_CF_SFT 0 + +#define CZ80_SF (1 << CZ80_SF_SFT) +#define CZ80_ZF (1 << CZ80_ZF_SFT) +#define CZ80_YF (1 << CZ80_YF_SFT) +#define CZ80_HF (1 << CZ80_HF_SFT) +#define CZ80_XF (1 << CZ80_XF_SFT) +#define CZ80_PF (1 << CZ80_PF_SFT) +#define CZ80_VF (1 << CZ80_VF_SFT) +#define CZ80_NF (1 << CZ80_NF_SFT) +#define CZ80_CF (1 << CZ80_CF_SFT) + +#define CZ80_IFF_SFT CZ80_PF_SFT +#define CZ80_IFF CZ80_PF + +#define CZ80_HAS_INT CZ80_IFF +#define CZ80_HAS_NMI 0x08 + +#define CZ80_RUNNING 0x10 +#define CZ80_HALTED 0x20 +#define CZ80_FAULTED 0x80 +#define CZ80_DISABLE 0x40 + + +typedef u32 CZ80_FASTCALL CZ80_READ(u32 adr); +typedef void CZ80_FASTCALL CZ80_WRITE(u32 adr, u32 data); + +typedef void CZ80_FASTCALL CZ80_RETI_CALLBACK(); +typedef s32 CZ80_FASTCALL CZ80_INT_CALLBACK(s32 param); + +typedef union +{ + u8 B; + s8 SB; +} union8; + +typedef union +{ + struct + { +#if CZ80_LITTLE_ENDIAN + u8 L; + u8 H; +#else + u8 H; + u8 L; +#endif + } B; + struct + { +#if CZ80_LITTLE_ENDIAN + s8 L; + s8 H; +#else + s8 H; + s8 L; +#endif + } SB; + u16 W; + s16 SW; +} union16; + +typedef struct +{ + union + { + u8 r8[8]; + union16 r16[4]; + struct + { + union16 BC; // 32 bytes aligned + union16 DE; + union16 HL; + union16 FA; + }; + }; + + union16 IX; + union16 IY; + union16 SP; + u8 *PC; + + union16 BC2; + union16 DE2; + union16 HL2; + union16 FA2; + + union16 R; + union16 IFF; + + u8 I; + u8 IM; + u8 IntVect; + u8 Status; + + u32 BasePC; + u32 CycleIO; + + u32 CycleToDo; // 32 bytes aligned + u32 CycleSup; +} cz80_struc; + + + +/*************************/ +/* Publics Z80 variables */ +/*************************/ + +//extern cz80_struc CZ80; + + +/*************************/ +/* Publics Z80 functions */ +/*************************/ + +void Cz80_Init(cz80_struc *cpu); +u32 Cz80_Reset(cz80_struc *cpu); + +u32 Cz80_Read_Byte(cz80_struc *cpu, u32 adr); +u32 Cz80_Read_Word(cz80_struc *cpu, u32 adr); +void Cz80_Write_Byte(cz80_struc *cpu, u32 adr, u32 data); +void Cz80_Write_Word(cz80_struc *cpu, u32 adr, u32 data); + +void CZ80_FASTCALL Cz80_Enable(cz80_struc *cpu); +void CZ80_FASTCALL Cz80_Disable(cz80_struc *cpu); + +s32 CZ80_FASTCALL Cz80_Exec(cz80_struc *cpu, s32 cycles); + +void CZ80_FASTCALL Cz80_Set_IRQ(cz80_struc *cpu, s32 vector); +void CZ80_FASTCALL Cz80_Set_NMI(cz80_struc *cpu); +void CZ80_FASTCALL Cz80_Clear_IRQ(cz80_struc *cpu); +void CZ80_FASTCALL Cz80_Clear_NMI(cz80_struc *cpu); + +s32 CZ80_FASTCALL Cz80_Get_CycleToDo(cz80_struc *cpu); +s32 CZ80_FASTCALL Cz80_Get_CycleRemaining(cz80_struc *cpu); +s32 CZ80_FASTCALL Cz80_Get_CycleDone(cz80_struc *cpu); +void CZ80_FASTCALL Cz80_End_Execute(cz80_struc *cpu); +void CZ80_FASTCALL Cz80_Waste_Cycle(cz80_struc *cpu, s32 cycle); + +u32 CZ80_FASTCALL Cz80_Get_BC(cz80_struc *cpu); +u32 CZ80_FASTCALL Cz80_Get_DE(cz80_struc *cpu); +u32 CZ80_FASTCALL Cz80_Get_HL(cz80_struc *cpu); +u32 CZ80_FASTCALL Cz80_Get_AF(cz80_struc *cpu); + +u32 CZ80_FASTCALL Cz80_Get_BC2(cz80_struc *cpu); +u32 CZ80_FASTCALL Cz80_Get_DE2(cz80_struc *cpu); +u32 CZ80_FASTCALL Cz80_Get_HL2(cz80_struc *cpu); +u32 CZ80_FASTCALL Cz80_Get_AF2(cz80_struc *cpu); + +u32 CZ80_FASTCALL Cz80_Get_IX(cz80_struc *cpu); +u32 CZ80_FASTCALL Cz80_Get_IY(cz80_struc *cpu); +u32 CZ80_FASTCALL Cz80_Get_SP(cz80_struc *cpu); +u32 CZ80_FASTCALL Cz80_Get_PC(cz80_struc *cpu); + +u32 CZ80_FASTCALL Cz80_Get_R(cz80_struc *cpu); +u32 CZ80_FASTCALL Cz80_Get_IFF(cz80_struc *cpu); +u32 CZ80_FASTCALL Cz80_Get_IM(cz80_struc *cpu); +u32 CZ80_FASTCALL Cz80_Get_I(cz80_struc *cpu); + +void CZ80_FASTCALL Cz80_Set_BC(cz80_struc *cpu, u32 value); +void CZ80_FASTCALL Cz80_Set_DE(cz80_struc *cpu, u32 value); +void CZ80_FASTCALL Cz80_Set_HL(cz80_struc *cpu, u32 value); +void CZ80_FASTCALL Cz80_Set_AF(cz80_struc *cpu, u32 value); + +void CZ80_FASTCALL Cz80_Set_BC2(cz80_struc *cpu, u32 value); +void CZ80_FASTCALL Cz80_Set_DE2(cz80_struc *cpu, u32 value); +void CZ80_FASTCALL Cz80_Set_HL2(cz80_struc *cpu, u32 value); +void CZ80_FASTCALL Cz80_Set_AF2(cz80_struc *cpu, u32 value); + +void CZ80_FASTCALL Cz80_Set_IX(cz80_struc *cpu, u32 value); +void CZ80_FASTCALL Cz80_Set_IY(cz80_struc *cpu, u32 value); +void CZ80_FASTCALL Cz80_Set_SP(cz80_struc *cpu, u32 value); +void CZ80_FASTCALL Cz80_Set_PC(cz80_struc *cpu, u32 value); + +void CZ80_FASTCALL Cz80_Set_R(cz80_struc *cpu, u32 value); +void CZ80_FASTCALL Cz80_Set_IFF(cz80_struc *cpu, u32 value); +void CZ80_FASTCALL Cz80_Set_IM(cz80_struc *cpu, u32 value); +void CZ80_FASTCALL Cz80_Set_I(cz80_struc *cpu, u32 value); + +#if defined(__cplusplus) && !defined(USE_CPLUS) +}; +#endif + +#endif // _CZ80_H_ + diff --git a/cz80.inc b/cz80.inc new file mode 100644 index 0000000..f3a35d4 --- /dev/null +++ b/cz80.inc @@ -0,0 +1,219 @@ +/********************************************************************************/ +/* */ +/* CZ80 macro file */ +/* C Z80 emulator version 0.92 */ +/* Copyright 2004-2005 Stéphane Dallongeville */ +/* */ +/********************************************************************************/ + +// use zR8 for B/C/D/E/H/L registers only +// use zR16 for BC/DE/HL registers only + +#ifdef CZ80_USE_MAME_CHANGE_PC +#include "memory.h" +#undef READ_WORD +#undef WRITE_WORD +#endif + +//#define mame4all_cz80_rom OP_ROM +//#define mame4all_cz80_ram OP_RAM +extern unsigned char *mame4all_cz80_rom; +extern unsigned char *mame4all_cz80_ram; + +int cpu_readmem16(int address); +void cpu_writemem16(int address,int data); +int cpu_readport(int Port); +void cpu_writeport(int Port,int Value); + +#define zR8(A) CPU->r8[(A) ^ 1] +#define zR16(A) CPU->r16[A].W +#define pzR16(A) &(CPU->r16[A]) + +#define pzFA &(CPU->FA) +#define zFA CPU->FA.W +#define zlFA CPU->FA.B.L +#define zhFA CPU->FA.B.H +#define zA zlFA +#define zF zhFA + +#define pzBC &(CPU->BC) +#define zBC CPU->BC.W +#define zlBC CPU->BC.B.L +#define zhBC CPU->BC.B.H +#define zB zhBC +#define zC zlBC + +#define pzDE &(CPU->DE) +#define zDE CPU->DE.W +#define zlDE CPU->DE.B.L +#define zhDE CPU->DE.B.H +#define zD zhDE +#define zE zlDE + +#define pzHL &(CPU->HL) +#define zHL CPU->HL.W +#define zlHL CPU->HL.B.L +#define zhHL CPU->HL.B.H +#define zH zhHL +#define zL zlHL + +#define zFA2 CPU->FA2.W +#define zlFA2 CPU->FA2.B.L +#define zhFA2 CPU->FA2.B.H +#define zA2 zlFA2 +#define zF2 zhFA2 + +#define zBC2 CPU->BC2.W +#define zDE2 CPU->DE2.W +#define zHL2 CPU->HL2.W + +#define pzIX &(CPU->IX) +#define zIX CPU->IX.W +#define zlIX CPU->IX.B.L +#define zhIX CPU->IX.B.H + +#define pzIY &(CPU->IY) +#define zIY CPU->IY.W +#define zlIY CPU->IY.B.L +#define zhIY CPU->IY.B.H + +#define pzSP &(CPU->SP) +#define zSP CPU->SP.W +#define zlSP CPU->SP.B.L +#define zhSP CPU->SP.B.H + +#define zPC PC +#define zRealPC ((u32)(PC) - ((u32)mame4all_cz80_rom)) + +#define zI CPU->I +#define zIM CPU->IM + +#define zwR CPU->R.W +#define zR1 CPU->R.B.L +#define zR2 CPU->R.B.H +#define zR zR1 + +#define zIFF CPU->IFF.W +#define zIFF1 CPU->IFF.B.L +#define zIFF2 CPU->IFF.B.H + + +#if CZ80_USE_JUMPTABLE +#define _SSOP(A,B) A##B +#define OP(A) _SSOP(OP,A) +#define OPCB(A) _SSOP(OPCB,A) +#define OPED(A) _SSOP(OPED,A) +#define OPXY(A) _SSOP(OPXY,A) +#define OPXYCB(A) _SSOP(OPXYCB,A) +#else +#define OP(A) case A +#define OPCB(A) case A +#define OPED(A) case A +#define OPXY(A) case A +#define OPXYCB(A) case A +#endif + +#define REAL_FETCH_BYTE \ + (*zPC++) + +#define REAL_FETCH_BYTE_S \ + ((s8)(*zPC++)) + +#define FETCH_BYTE(A) \ + A = (mame4all_cz80_ram[((unsigned)zPC)-((unsigned)mame4all_cz80_rom)]); \ + zPC++ + +#define FETCH_BYTE_S(A) \ + A = ((s8)(mame4all_cz80_ram[((unsigned)zPC)-((unsigned)mame4all_cz80_rom)])); \ + zPC++ + +#if CZ80_LITTLE_ENDIAN +#define FETCH_WORD(A) \ + A= ((unsigned short)(mame4all_cz80_ram[((unsigned)zPC)-((unsigned)mame4all_cz80_rom)])) | (((unsigned short)(mame4all_cz80_ram[1+((unsigned)zPC)-((unsigned)mame4all_cz80_rom)])) << 8); \ + zPC += 2 +#else +#define FETCH_WORD(A) \ + A= ((unsigned short)(mame4all_cz80_ram[1+((unsigned)zPC)-((unsigned)mame4all_cz80_rom)])) | (((unsigned short)(mame4all_cz80_ram[((unsigned)zPC)-((unsigned)mame4all_cz80_rom)])) << 8); \ + zPC += 2 +#endif + +#if CZ80_SIZE_OPT + #define RET(A) \ + Z80_ICount -= A; \ + goto Cz80_Exec_Check; +#else + #define RET(A) \ + if ((Z80_ICount -= A) <= 0) goto Cz80_Check_Int; \ + goto Cz80_Exec; +#endif + +#ifdef CZ80_USE_MAME_CHANGE_PC +#define SET_PC(A) \ + change_pc16(A) \ + zPC = (u8*)&mame4all_cz80_rom[A] +#else +#define SET_PC(A) zPC = (u8*)&mame4all_cz80_rom[A] +#endif + +#define PRE_IO \ + CPU->CycleIO = Z80_ICount; + +#define POST_IO \ + Z80_ICount = CPU->CycleIO; + +#define READ_BYTE(A, D) \ + D = cpu_readmem16(A); + +#if CZ80_USE_WORD_HANDLER +#define READ_WORD(A, D) \ + D = CPU->Read_Word(A); +#elif CZ80_LITTLE_ENDIAN +#define READ_WORD(A, D) \ + D = cpu_readmem16(A) | (cpu_readmem16((A) + 1) << 8); +#else +#define READ_WORD(A, D) \ + D = (cpu_readmem16(A) << 8) | cpu_readmem16((A) + 1); +#endif + +#define READSX_BYTE(A, D) \ + D = (s8)cpu_readmem16(A); + +#define WRITE_BYTE(A, D) \ + cpu_writemem16(A, D); + +#if CZ80_USE_WORD_HANDLER +#define WRITE_WORD(A, D) \ + cpu_writemem16(A, D); +#elif CZ80_LITTLE_ENDIAN +#define WRITE_WORD(A, D) \ + cpu_writemem16(A, D); \ + cpu_writemem16((A) + 1, (D) >> 8); +#else +#define WRITE_WORD(A, D) \ + cpu_writemem16(A, D); \ + cpu_writemem16((A) + 1, (D) >> 8); +#endif + +#define PUSH_16(A) \ + { \ + u32 sp; \ + \ + zSP -= 2; \ + sp = zSP; \ + WRITE_WORD(sp, A); \ + } + +#define POP_16(A) \ + { \ + u32 sp; \ + \ + sp = zSP; \ + READ_WORD(sp, A) \ + zSP = sp + 2; \ + } + +#define IN(A, D) \ + D = cpu_readport(A); + +#define OUT(A, D) \ + cpu_writeport(A, D); diff --git a/cz80_op.inc b/cz80_op.inc new file mode 100644 index 0000000..781703c --- /dev/null +++ b/cz80_op.inc @@ -0,0 +1,1332 @@ +/********************************************************************************/ +/* */ +/* CZ80 opcode include source file */ +/* C Z80 emulator version 0.92 */ +/* Copyright 2004-2005 Stéphane Dallongeville */ +/* */ +/********************************************************************************/ + +#if CZ80_USE_JUMPTABLE + goto *JumpTable[Opcode]; +#else +switch (Opcode) +{ +#endif + + // 8 BITS LOAD + + OP(0x00): // NOP + + OP(0x40): // LD B,B + OP(0x49): // LD C,C + OP(0x52): // LD D,D + OP(0x5b): // LD E,E + OP(0x64): // LD H,H + OP(0x6d): // LD L,L + OP(0x7f): // LD A,A +OP_NOP: + RET(4) + + OP(0x41): // LD B,C + OP(0x42): // LD B,D + OP(0x43): // LD B,E + OP(0x44): // LD B,H + OP(0x45): // LD B,L + OP(0x47): // LD B,A + + OP(0x48): // LD C,B + OP(0x4a): // LD C,D + OP(0x4b): // LD C,E + OP(0x4c): // LD C,H + OP(0x4d): // LD C,L + OP(0x4f): // LD C,A + + OP(0x50): // LD D,B + OP(0x51): // LD D,C + OP(0x53): // LD D,E + OP(0x54): // LD D,H + OP(0x55): // LD D,L + OP(0x57): // LD D,A + + OP(0x58): // LD E,B + OP(0x59): // LD E,C + OP(0x5a): // LD E,D + OP(0x5c): // LD E,H + OP(0x5d): // LD E,L + OP(0x5f): // LD E,A + + OP(0x60): // LD H,B + OP(0x61): // LD H,C + OP(0x62): // LD H,D + OP(0x63): // LD H,E + OP(0x65): // LD H,L + OP(0x67): // LD H,A + + OP(0x68): // LD L,B + OP(0x69): // LD L,C + OP(0x6a): // LD L,D + OP(0x6b): // LD L,E + OP(0x6c): // LD L,H + OP(0x6f): // LD L,A + + OP(0x78): // LD A,B + OP(0x79): // LD A,C + OP(0x7a): // LD A,D + OP(0x7b): // LD A,E + OP(0x7c): // LD A,H + OP(0x7d): // LD A,L +OP_LD_R_R: + zR8((Opcode >> 3) & 7) = zR8(Opcode & 7); + RET(4) + + OP(0x06): // LD B,#imm + OP(0x0e): // LD C,#imm + OP(0x16): // LD D,#imm + OP(0x1e): // LD E,#imm + OP(0x26): // LD H,#imm + OP(0x2e): // LD L,#imm + OP(0x3e): // LD A,#imm +OP_LD_R_imm: + FETCH_BYTE(zR8(Opcode >> 3)); + RET(7) + + OP(0x46): // LD B,(HL) + OP(0x4e): // LD C,(HL) + OP(0x56): // LD D,(HL) + OP(0x5e): // LD E,(HL) + OP(0x66): // LD H,(HL) + OP(0x6e): // LD L,(HL) + OP(0x7e): // LD A,(HL) +OP_LD_R_mHL: + PRE_IO + READ_BYTE(zHL, zR8((Opcode >> 3) & 7)) + POST_IO + RET(7) + + OP(0x70): // LD (HL),B + OP(0x71): // LD (HL),C + OP(0x72): // LD (HL),D + OP(0x73): // LD (HL),E + OP(0x74): // LD (HL),H + OP(0x75): // LD (HL),L + OP(0x77): // LD (HL),A +OP_LD_mHL_R: + PRE_IO + WRITE_BYTE(zHL, zR8(Opcode & 7)) + POST_IO + RET(7) + + OP(0x36): // LD (HL), #imm +OP_LD_mHL_imm: + PRE_IO + { u8 t; FETCH_BYTE(t); WRITE_BYTE(zHL,t); } + POST_IO + RET(10) + + { + u32 adr; + + OP(0x0a): // LD A,(BC) +OP_LOAD_A_mBC: + adr = zBC; + goto OP_LOAD_A_mxx; + + OP(0x1a): // LD A,(DE) +OP_LOAD_A_mDE: + adr = zDE; + +OP_LOAD_A_mxx: + PRE_IO + READ_BYTE(adr, zA) + POST_IO + RET(7) + + OP(0x3a): // LD A,(nn) +OP_LOAD_A_mNN: + PRE_IO + FETCH_WORD(adr); + READ_BYTE(adr, zA) + POST_IO + RET(13) + + OP(0x02): // LD (BC),A +OP_LOAD_mBC_A: + adr = zBC; + goto OP_LOAD_mxx_A; + + OP(0x12): // LD (DE),A +OP_LOAD_mDE_A: + adr = zDE; + +OP_LOAD_mxx_A: + PRE_IO + WRITE_BYTE(adr, zA) + POST_IO + RET(7) + + OP(0x32): // LD (nn),A +OP_LOAD_mNN_A: + PRE_IO + FETCH_WORD(adr); + WRITE_BYTE(adr, zA) + POST_IO + RET(13) + } + + // 16 BITS LOAD + + OP(0x01): // LD BC,nn + OP(0x11): // LD DE,nn + OP(0x21): // LD HL,nn +OP_LOAD_RR_imm16: + FETCH_WORD(zR16(Opcode >> 4)); + RET(10) + + OP(0x31): // LD SP,nn +OP_LOAD_SP_imm16: + FETCH_WORD(zSP); + RET(10) + + OP(0xf9): // LD SP,HL +OP_LD_SP_xx: + zSP = data->W; + RET(6) + + { + u32 adr; + + OP(0x2a): // LD HL,(nn) +OP_LD_xx_mNN: + PRE_IO + FETCH_WORD(adr); + READ_WORD(adr, data->W) + POST_IO + RET(16) + + OP(0x22): // LD (nn),HL +OP_LD_mNN_xx: + PRE_IO + FETCH_WORD(adr); + WRITE_WORD(adr, data->W) + POST_IO + RET(16) + } + + // PUSH / POP + + OP(0xf1): // POP AF +OP_POP_AF: + { + u32 res; + + PRE_IO + POP_16(res) + zA = res >> 8; + zF = res & 0xFF; + POST_IO + RET(10) + } + + OP(0xc1): // POP BC + OP(0xd1): // POP DE +OP_POP_RR: + data = pzR16((Opcode >> 4) & 3); + + OP(0xe1): // POP HL +OP_POP: + PRE_IO + POP_16(data->W) + POST_IO + RET(10) + + OP(0xf5): // PUSH AF +OP_PUSH_AF: + PRE_IO + PUSH_16((zA << 8) | zF); + POST_IO + RET(11) + + OP(0xc5): // PUSH BC + OP(0xd5): // PUSH DE +OP_PUSH_RR: + data = pzR16((Opcode >> 4) & 3); + + OP(0xe5): // PUSH HL +OP_PUSH: + PRE_IO + PUSH_16(data->W); + POST_IO + RET(11) + + // EXCHANGE & BLOCK TRANSFERT / SEARCH + + { + u32 tmp; + + OP(0x08): // EX AF,AF' +OP_EX_AF_AF2: + tmp = zFA; + zFA = zFA2; + zFA2 = tmp; + RET(4) + + OP(0xeb): // EX DE,HL +OP_EX_DE_HL: + tmp = zDE; + zDE = zHL; + zHL = tmp; + RET(4) + + OP(0xd9): // EXX +OP_EXX: + tmp = zBC; + zBC = zBC2; + zBC2 = tmp; + tmp = zDE; + zDE = zDE2; + zDE2 = tmp; + tmp = zHL; + zHL = zHL2; + zHL2 = tmp; + RET(4) + } + + OP(0xe3): // EX HL,(SP) + { + u32 adr; + u32 tmp; + +OP_EX_xx_mSP: + PRE_IO + adr = zSP; + tmp = data->W; + READ_WORD(adr, data->W) + WRITE_WORD(adr, tmp) + POST_IO + RET(19) + } + + // 8 BITS ARITHMETIC + + OP(0x04): // INC B + OP(0x0c): // INC C + OP(0x14): // INC D + OP(0x1c): // INC E + OP(0x24): // INC H + OP(0x2c): // INC L + OP(0x3c): // INC A +OP_INC_R: + zR8(Opcode >> 3)++; + zF = (zF & CZ80_CF) | SZXYHV_inc[zR8(Opcode >> 3)]; + RET(4) + + { + u32 adr; + u32 res; + +OP_INC_mIx: + { s8 t; FETCH_BYTE_S(t); adr = data->W + t; } + Z80_ICount -= 11; + goto OP_INC_m; + + OP(0x34): // INC (HL) + adr = zHL; + +OP_INC_m: + PRE_IO + READ_BYTE(adr, res) + res = (res + 1) & 0xFF; + WRITE_BYTE(adr, res) + zF = (zF & CZ80_CF) | SZXYHV_inc[res]; + POST_IO + RET(11) + } + + OP(0x05): // DEC B + OP(0x0d): // DEC C + OP(0x15): // DEC D + OP(0x1d): // DEC E + OP(0x25): // DEC H + OP(0x2d): // DEC L + OP(0x3d): // DEC A +OP_DEC_R: + zR8(Opcode >> 3)--; + zF = (zF & CZ80_CF) | SZXYHV_dec[zR8(Opcode >> 3)]; + RET(4) + + { + u32 adr; + u32 res; + +OP_DEC_mIx: + { s8 t; FETCH_BYTE_S(t); adr = data->W + t; } + Z80_ICount -= 11; + goto OP_DEC_m; + + OP(0x35): // DEC (HL) + adr = zHL; + +OP_DEC_m: + PRE_IO + READ_BYTE(adr, res) + res = (res - 1) & 0xFF; + WRITE_BYTE(adr, res) + zF = (zF & CZ80_CF) | SZXYHV_dec[res]; + POST_IO + RET(11) + } + + { + u32 val; + u32 res; + + // ADD + +OP_ADD_mIx: + PRE_IO + { s8 t; FETCH_BYTE_S(t); READ_BYTE(data->W + t, val); } + POST_IO + Z80_ICount -= 11; + goto OP_ADD; + + OP(0xc6): // ADD A,n +OP_ADD_imm: + FETCH_BYTE(val); + Z80_ICount -= 3; + goto OP_ADD; + + OP(0x86): // ADD A,(HL) +OP_ADD_mHL: + PRE_IO + READ_BYTE(zHL, val) + POST_IO + Z80_ICount -= 3; + goto OP_ADD; + +OP_ADD_IxH: + val = data->B.H; + goto OP_ADD; + +OP_ADD_IxL: + val = data->B.L; + goto OP_ADD; + + OP(0x80): // ADD A,B + OP(0x81): // ADD A,C + OP(0x82): // ADD A,D + OP(0x83): // ADD A,E + OP(0x84): // ADD A,H + OP(0x85): // ADD A,L + OP(0x87): // ADD A,A +OP_ADD_R: + val = zR8(Opcode & 7); + +OP_ADD: +// bench : maybe use src instead of zA in zF calculation + res = zA + val; + zF = SZXY[res & 0xFF] | // S/Z/X/Y flag + ((zA ^ res ^ val) & CZ80_HF) | // H flag + (((val ^ zA ^ 0x80) & (val ^ res) & 0x80) >> 5) | // V flag + ((res >> 8) & CZ80_CF); // C flag + zA = res; + RET(4) + + // ADC + +OP_ADC_mIx: + PRE_IO + { s8 t; FETCH_BYTE_S(t); READ_BYTE(data->W + t, val); } + POST_IO + Z80_ICount -= 11; + goto OP_ADC; + + OP(0xce): // ADC A,n +OP_ADC_imm: + FETCH_BYTE(val); + Z80_ICount -= 3; + goto OP_ADC; + + OP(0x8e): // ADC A,(HL) +OP_ADC_mHL: + PRE_IO + READ_BYTE(zHL, val) + POST_IO + Z80_ICount -= 3; + goto OP_ADC; + +OP_ADC_IxH: + val = data->B.H; + goto OP_ADC; + +OP_ADC_IxL: + val = data->B.L; + goto OP_ADC; + + OP(0x88): // ADC A,B + OP(0x89): // ADC A,C + OP(0x8a): // ADC A,D + OP(0x8b): // ADC A,E + OP(0x8c): // ADC A,H + OP(0x8d): // ADC A,L + OP(0x8f): // ADC A,A +OP_ADC_R: + val = zR8(Opcode & 7); + +OP_ADC: +// bench : maybe use src instead of zA in zF calculation + res = (zA + val) + (zF & CZ80_CF); + zF = SZXY[res & 0xFF] | // S/Z/X/Y flag + ((zA ^ res ^ val) & CZ80_HF) | // H flag + (((val ^ zA ^ 0x80) & (val ^ res) & 0x80) >> 5) | // V flag + ((res >> 8) & CZ80_CF); // C flag + zA = res; + RET(4) + + // SUB + +OP_SUB_mIx: + PRE_IO + { s8 t; FETCH_BYTE_S(t); READ_BYTE(data->W + t, val); } + POST_IO + Z80_ICount -= 11; + goto OP_SUB; + + OP(0xd6): // SUB A,n +OP_SUB_imm: + FETCH_BYTE(val); + Z80_ICount -= 3; + goto OP_SUB; + + OP(0x96): // SUB (HL) +OP_SUB_mHL: + PRE_IO + READ_BYTE(zHL, val) + POST_IO + Z80_ICount -= 3; + goto OP_SUB; + +OP_SUB_IxH: + val = data->B.H; + goto OP_SUB; + +OP_SUB_IxL: + val = data->B.L; + goto OP_SUB; + + OP(0x90): // SUB B + OP(0x91): // SUB C + OP(0x92): // SUB D + OP(0x93): // SUB E + OP(0x94): // SUB H + OP(0x95): // SUB L + OP(0x97): // SUB A +OP_SUB_R: + val = zR8(Opcode & 7); + +OP_SUB: +// bench : maybe use src instead of zA in zF calculation + res = zA - val; + zF = SZXY[res & 0xFF] | // S/Z/X/Y flag + ((zA ^ res ^ val) & CZ80_HF) | // H flag + (((val ^ zA) & (zA ^ res) & 0x80) >> 5) | // V flag + ((res >> 8) & CZ80_CF) | CZ80_NF; // C/N flag + zA = res; + RET(4) + + // SBC + +OP_SBC_mIx: + PRE_IO + { s8 t; FETCH_BYTE_S(t); READ_BYTE(data->W + t, val); } + POST_IO + Z80_ICount -= 11; + goto OP_SBC; + + OP(0xde): // SBC A,n +OP_SBC_imm: + FETCH_BYTE(val); + Z80_ICount -= 3; + goto OP_SBC; + + OP(0x9e): // SBC A,(HL) +OP_SBC_mHL: + PRE_IO + READ_BYTE(zHL, val) + POST_IO + Z80_ICount -= 3; + goto OP_SBC; + +OP_SBC_IxH: + val = data->B.H; + goto OP_SBC; + +OP_SBC_IxL: + val = data->B.L; + goto OP_SBC; + + OP(0x98): // SBC A,B + OP(0x99): // SBC A,C + OP(0x9a): // SBC A,D + OP(0x9b): // SBC A,E + OP(0x9c): // SBC A,H + OP(0x9d): // SBC A,L + OP(0x9f): // SBC A,A +OP_SBC_R: + val = zR8(Opcode & 7); + +OP_SBC: +// bench : maybe use src instead of zA in zF calculation + res = zA - (val + (zF & CZ80_CF)); + zF = SZXY[res & 0xFF] | // S/Z/X/Y flag + ((zA ^ res ^ val) & CZ80_HF) | // H flag + (((val ^ zA) & (zA ^ res) & 0x80) >> 5) | // V flag + ((res >> 8) & CZ80_CF) | CZ80_NF; // C/N flag + zA = res; + RET(4) + + // CP + +OP_CP_mIx: + PRE_IO + { s8 t; FETCH_BYTE_S(t); READ_BYTE(data->W + t, val); } + POST_IO + Z80_ICount -= 11; + goto OP_CP; + + OP(0xfe): // CP n +OP_CP_imm: + FETCH_BYTE(val); + Z80_ICount -= 3; + goto OP_CP; + + OP(0xbe): // CP (HL) +OP_CP_mHL: + PRE_IO + READ_BYTE(zHL, val) + POST_IO + Z80_ICount -= 3; + goto OP_CP; + +OP_CP_IxH: + val = data->B.H; + goto OP_CP; + +OP_CP_IxL: + val = data->B.L; + goto OP_CP; + + OP(0xb8): // CP B + OP(0xb9): // CP C + OP(0xba): // CP D + OP(0xbb): // CP E + OP(0xbc): // CP H + OP(0xbd): // CP L + OP(0xbf): // CP A +OP_CP_R: + val = zR8(Opcode & 7); + +OP_CP: +// bench : maybe use src instead of zA in zF calculation + res = zA - val; +#if CZ80_DEBUG + zF = SZXY[res & 0xFF] | // S/Z/X/Y flag + ((zA ^ res ^ val) & CZ80_HF) | // H flag + (((val ^ zA) & (zA ^ res) & 0x80) >> 5) | // V flag + ((res >> 8) & CZ80_CF) | CZ80_NF; // C/N flag +#else + zF = (SZXY[res & 0xFF] & ~(CZ80_XF | CZ80_YF)) | // S/Z flag + (val & (CZ80_XF | CZ80_YF)) | // X/Y flag + ((zA ^ res ^ val) & CZ80_HF) | // H flag + (((val ^ zA) & (zA ^ res) & 0x80) >> 5) | // V flag + ((res >> 8) & CZ80_CF) | CZ80_NF; // C/N flag +#endif + RET(4) + } + + // AND + + { + u32 val; + + OP(0xa6): // AND (HL) +OP_AND_mHL: + PRE_IO + READ_BYTE(zHL, val) + POST_IO + goto OP_AND_; + + OP(0xe6): // AND A,n +OP_AND_imm: + FETCH_BYTE(val); + +OP_AND_: + zA = zA & val; + zF = SZXYP[zA] | CZ80_HF; + RET(7) + +OP_AND_IxL: + val = data->B.L; + goto OP_AND; + +OP_AND_IxH: + val = data->B.H; + goto OP_AND; + + OP(0xa0): // AND B + OP(0xa1): // AND C + OP(0xa2): // AND D + OP(0xa3): // AND E + OP(0xa4): // AND H + OP(0xa5): // AND L +OP_AND_R: + val = zR8(Opcode & 7); + +OP_AND: + zA = zA & val; + + OP(0xa7): // AND A +OP_AND_A: + zF = SZXYP[zA] | CZ80_HF; + RET(4) + + // XOR + + OP(0xae): // XOR (HL) +OP_XOR_mHL: + PRE_IO + READ_BYTE(zHL, val) + POST_IO + goto OP_XOR_; + + OP(0xee): // XOR A,n +OP_XOR_imm: + FETCH_BYTE(val); + +OP_XOR_: + zA = zA ^ val; + zF = SZXYP[zA]; + RET(7) + +OP_XOR_IxL: + val = data->B.L; + goto OP_XOR; + +OP_XOR_IxH: + val = data->B.H; + goto OP_XOR; + + OP(0xa8): // XOR B + OP(0xa9): // XOR C + OP(0xaa): // XOR D + OP(0xab): // XOR E + OP(0xac): // XOR H + OP(0xad): // XOR L +OP_XOR_R: + val = zR8(Opcode & 7); + +OP_XOR: + zA = zA ^ val; + zF = SZXYP[zA]; + RET(4) + + OP(0xaf): // XOR A +OP_XOR_A: + zA = 0; + zF = SZXYP[zA]; + RET(4) + + // OR + + OP(0xb6): // OR (HL) +OP_OR_mHL: + PRE_IO + READ_BYTE(zHL, val) + POST_IO + goto OP_OR_; + + OP(0xf6): // OR A,n +OP_OR_imm: + FETCH_BYTE(val); + +OP_OR_: + zA = zA | val; + zF = SZXYP[zA]; + RET(7) + +OP_OR_IxL: + val = data->B.L; + goto OP_OR; + +OP_OR_IxH: + val = data->B.H; + goto OP_OR; + + OP(0xb0): // OR B + OP(0xb1): // OR C + OP(0xb2): // OR D + OP(0xb3): // OR E + OP(0xb4): // OR H + OP(0xb5): // OR L +OP_OR_R: + val = zR8(Opcode & 7); + +OP_OR: + zA = zA | val; + + OP(0xb7): // OR A +OP_OR_A: + zF = SZXYP[zA]; + RET(4) + } + + + // MISC ARITHMETIC & CPU CONTROL + + OP(0x27): // DAA +OP_DAA: + { + u8 _F; + u8 cf, nf, hf, lo, hi, diff; + + _F = zF; + cf = _F & CZ80_CF; + nf = _F & CZ80_NF; + hf = _F & CZ80_HF; + lo = zA & 0x0F; + hi = zA >> 4; + + if (cf) + { + diff = (lo <= 9 && !hf) ? 0x60 : 0x66; + } + else + { + if (lo >= 10) + { + diff = hi <= 8 ? 0x06 : 0x66; + } + else + { + if (hi >= 10) + { + diff = hf ? 0x66 : 0x60; + } + else + { + diff = hf ? 0x06 : 0x00; + } + } + } + if (nf) zA -= diff; + else zA += diff; + + _F = SZXYP[zA] | (_F & CZ80_NF); + if (cf || (lo <= 9 ? hi >= 10 : hi >= 9)) _F |= CZ80_CF; + if (nf ? hf && lo <= 5 : lo >= 10) _F |= CZ80_HF; + zF = _F; + RET(4) + } + + OP(0x2f): // CPL +OP_CPL: + zA ^= 0xFF; + zF = (zF & (CZ80_SF | CZ80_ZF | CZ80_PF | CZ80_CF)) | + CZ80_HF | CZ80_NF | + (zA & (CZ80_XF | CZ80_YF)); + RET(4) + + OP(0x37): // SCF +OP_SCF: + zF = (zF & (CZ80_SF | CZ80_ZF | CZ80_PF)) | + (zA & (CZ80_XF | CZ80_YF)) | + CZ80_CF; + RET(4) + + OP(0x3f): // CCF +OP_CCF: + zF = ((zF & (CZ80_SF | CZ80_ZF | CZ80_PF | CZ80_CF)) | + ((zF & CZ80_CF) << 4) | + (zA & (CZ80_XF | CZ80_YF))) ^ + CZ80_CF; + RET(4) + + OP(0x76): // HALT +OP_HALT: + // HALTED state + CPU->Status |= CZ80_HALTED; + // release remaining cycles... + Z80_ICount = 0; + goto Cz80_Exec_Really_End; + + OP(0xf3): // DI +OP_DI: + zIFF = 0; +#if CZ80_DEBUG + RET(4) +#else + Z80_ICount -= 4; + // can't take interrupt after DI so we force next instruction execution + goto Cz80_Exec; +#endif + + OP(0xfb): // EI + OP_EI: + zIFF = CZ80_IFF | (CZ80_IFF << 8); +#if CZ80_DEBUG + RET(4) +#else + // release remaining cycles... + CPU->CycleSup += Z80_ICount - 4; + Z80_ICount = 0; + // can't take interrupt after EI so we force next instruction execution + goto Cz80_Exec; +#endif + + // 16 BITS ARITHMETIC + + OP(0x03): // INC BC +OP_INC_BC: + zBC++; + RET(6) + + OP(0x13): // INC DE +OP_INC_DE: + zDE++; + RET(6) + + OP(0x23): // INC HL +OP_INC_xx: + data->W++; + RET(6) + + OP(0x33): // INC SP +OP_INC_SP: + zSP++; + RET(6) + + OP(0x0b): // DEC BC +OP_DEC_BC: + zBC--; + RET(6) + + OP(0x1b): // DEC DE +OP_DEC_DE: + zDE--; + RET(6) + + OP(0x2b): // DEC HL +OP_DEC_xx: + data->W--; + RET(6) + + OP(0x3b): // DEC SP +OP_DEC_SP: + zSP--; + RET(6) + + // ADD16 + + { + u32 src; + u32 res; + + OP(0x39): // ADD xx,SP +OP_ADD16_xx_SP: + src = zSP; + goto OP_ADD16; + + OP(0x29): // ADD xx,xx +OP_ADD16_xx_xx: + src = data->W; + goto OP_ADD16; + + OP(0x09): // ADD xx,BC +OP_ADD16_xx_BC: + src = zBC; + goto OP_ADD16; + + OP(0x19): // ADD xx,DE +OP_ADD16_xx_DE: + src = zDE; + +OP_ADD16: + res = src + data->W; +#if CZ80_DEBUG + zF = (zF & (CZ80_SF | CZ80_ZF | CZ80_VF)) | // S/Z/V flag + (((src ^ data->W ^ res) >> 8) & CZ80_HF) | // H flag + ((res >> 16) & CZ80_CF); // C flag +#else + zF = (zF & (CZ80_SF | CZ80_ZF | CZ80_VF)) | // S/Z/V flag + (((src ^ data->W ^ res) >> 8) & CZ80_HF) | // H flag + ((res >> 8) & (CZ80_XF | CZ80_YF)) | // X/Y flag + ((res >> 16) & CZ80_CF); // C flag +#endif + data->W = res; + RET(11) + } + + // ROTATE + + { + u8 A; + u8 F; + + OP(0x07): // RLCA +OP_RLCA: + A = zA; + zA = (A << 1) | (A >> 7); + zF = (zF & (CZ80_SF | CZ80_ZF | CZ80_PF)) | // S/Z/P flag + (zA & (CZ80_XF | CZ80_YF | CZ80_CF)); // X/Y/C + RET(4) + + OP(0x0f): // RRCA +OP_RRCA: + A = zA; + zA = (A >> 1) | (A << 7); + zF = (zF & (CZ80_SF | CZ80_ZF | CZ80_PF)) | // S/Z/P flag + (zA & (CZ80_XF | CZ80_YF)) | // X/Y flag + (A & CZ80_CF); // C flag + RET(4) + + OP(0x17): // RLA +OP_RLA: + A = zA; + F = zF; + zA = (A << 1) | (F & CZ80_CF); + zF = (F & (CZ80_SF | CZ80_ZF | CZ80_PF)) | // S/Z/P flag + (zA & (CZ80_XF | CZ80_YF)) | // X/Y flag + (A >> 7); // C flag + RET(4) + + OP(0x1f): // RRA +OP_RRA: + A = zA; + F = zF; + zA = (A >> 1) | (F << 7); + zF = (F & (CZ80_SF | CZ80_ZF | CZ80_PF)) | // S/Z/P flag + (zA & (CZ80_XF | CZ80_YF)) | // X/Y flag + (A & CZ80_CF); // C flag + RET(4) + } + + // JUMP + { + u32 newPC; + + OP(0xd2): // JP NC,nn +OP_JP_NC: + if (!(zF & CZ80_CF)) goto OP_JP; + newPC=(((unsigned)zPC)-((unsigned)mame4all_cz80_rom))+2; + SET_PC(newPC); + RET(10); + + OP(0xda): // JP C,nn +OP_JP_C: + if (zF & CZ80_CF) goto OP_JP; + newPC=(((unsigned)zPC)-((unsigned)mame4all_cz80_rom))+2; + SET_PC(newPC); + RET(10); + + OP(0xe2): // JP PO,nn +OP_JP_PO: + if (!(zF & CZ80_VF)) goto OP_JP; + newPC=(((unsigned)zPC)-((unsigned)mame4all_cz80_rom))+2; + SET_PC(newPC); + RET(10); + + OP(0xea): // JP PE,nn +OP_JP_PE: + if (zF & CZ80_VF) goto OP_JP; + newPC=(((unsigned)zPC)-((unsigned)mame4all_cz80_rom))+2; + SET_PC(newPC); + RET(10); + + OP(0xf2): // JP P,nn +OP_JP_P: + if (!(zF & CZ80_SF)) goto OP_JP; + newPC=(((unsigned)zPC)-((unsigned)mame4all_cz80_rom))+2; + SET_PC(newPC); + RET(10); + + OP(0xfa): // JP M,nn +OP_JP_M: + if (zF & CZ80_SF) goto OP_JP; + newPC=(((unsigned)zPC)-((unsigned)mame4all_cz80_rom))+2; + SET_PC(newPC); + RET(10); + + OP(0xca): // JP Z,nn +OP_JP_Z: + if (zF & CZ80_ZF) goto OP_JP; + newPC=(((unsigned)zPC)-((unsigned)mame4all_cz80_rom))+2; + SET_PC(newPC); + RET(10); + + OP(0xc2): // JP NZ,nn +OP_JP_NZ: + if (!(zF & CZ80_ZF)) goto OP_JP; + newPC=(((unsigned)zPC)-((unsigned)mame4all_cz80_rom))+2; + SET_PC(newPC); + RET(10); + + + OP(0xc3): // JP nn +OP_JP: + FETCH_WORD(newPC); + SET_PC(newPC); + RET(10) + + OP(0xe9): // JP (xx) +OP_JP_xx: + newPC = data->W; + SET_PC(newPC); + RET(4) + + + OP(0x38): // JR C,n +OP_JR_C: + if (zF & CZ80_CF) goto OP_JR; + newPC=(((unsigned)zPC)-((unsigned)mame4all_cz80_rom))+1; + SET_PC(newPC); + RET(7) + + OP(0x30): // JR NC,n +OP_JR_NC: + if (!(zF & CZ80_CF)) goto OP_JR; + newPC=(((unsigned)zPC)-((unsigned)mame4all_cz80_rom))+1; + SET_PC(newPC); + RET(7) + + OP(0x28): // JR Z,n +OP_JR_Z: + if (zF & CZ80_ZF) goto OP_JR; + newPC=(((unsigned)zPC)-((unsigned)mame4all_cz80_rom))+1; + SET_PC(newPC); + RET(7) + + OP(0x20): // JR NZ,n +OP_JR_NZ: + if (!(zF & CZ80_ZF)) goto OP_JR; + newPC=(((unsigned)zPC)-((unsigned)mame4all_cz80_rom))+1; + SET_PC(newPC); + RET(7) + + OP(0x10): // DJNZ n +OP_DJNZ: + Z80_ICount--; + if (--zB) goto OP_JR; + newPC=(((unsigned)zPC)-((unsigned)mame4all_cz80_rom))+1; + SET_PC(newPC); + RET(9) + + OP(0x18): // JR n +OP_JR: + { + u32 adr; + + FETCH_BYTE_S(adr); + // no rebase needed here... + newPC=(((unsigned)zPC)-((unsigned)mame4all_cz80_rom))+adr; + SET_PC(newPC); + RET(12) + } + + // CALL & RETURN + + OP(0xd4): // CALL NC,nn +OP_CALL_NC: + if (!(zF & CZ80_CF)) goto OP_CALL; + newPC=(((unsigned)zPC)-((unsigned)mame4all_cz80_rom))+2; + SET_PC(newPC); + RET(10) + + OP(0xdc): // CALL C,nn +OP_CALL_C: + if (zF & CZ80_CF) goto OP_CALL; + newPC=(((unsigned)zPC)-((unsigned)mame4all_cz80_rom))+2; + SET_PC(newPC); + RET(10) + + OP(0xe4): // CALL PO,nn +OP_CALL_PO: + if (!(zF & CZ80_VF)) goto OP_CALL; + newPC=(((unsigned)zPC)-((unsigned)mame4all_cz80_rom))+2; + SET_PC(newPC); + RET(10) + + OP(0xec): // CALL PE,nn +OP_CALL_PE: + if (zF & CZ80_VF) goto OP_CALL; + newPC=(((unsigned)zPC)-((unsigned)mame4all_cz80_rom))+2; + SET_PC(newPC); + RET(10) + + OP(0xf4): // CALL P,nn +OP_CALL_P: + if (!(zF & CZ80_SF)) goto OP_CALL; + newPC=(((unsigned)zPC)-((unsigned)mame4all_cz80_rom))+2; + SET_PC(newPC); + RET(10) + + OP(0xfc): // CALL M,nn +OP_CALL_M: + if (zF & CZ80_SF) goto OP_CALL; + newPC=(((unsigned)zPC)-((unsigned)mame4all_cz80_rom))+2; + SET_PC(newPC); + RET(10) + + OP(0xcc): // CALL Z,nn +OP_CALL_Z: + if (zF & CZ80_ZF) goto OP_CALL; + newPC=(((unsigned)zPC)-((unsigned)mame4all_cz80_rom))+2; + SET_PC(newPC); + RET(10) + + OP(0xc4): // CALL NZ,nn +OP_CALL_NZ: + if (!(zF & CZ80_ZF)) goto OP_CALL; + newPC=(((unsigned)zPC)-((unsigned)mame4all_cz80_rom))+2; + SET_PC(newPC); + RET(10) + } + + OP(0xcd): // CALL nn +OP_CALL: + { + u32 oldRPC; + u32 newPC; + + PRE_IO + FETCH_WORD(newPC); + oldRPC = zRealPC; + PUSH_16(oldRPC); + SET_PC(newPC); + POST_IO + RET(17) + } + + OP(0xd0): // RET NC +OP_RET_NC: + if (!(zF & CZ80_CF)) goto OP_RET_COND; + RET(5) + + OP(0xd8): // RET C +OP_RET_C: + if (zF & CZ80_CF) goto OP_RET_COND; + RET(5) + + OP(0xe0): // RET PO +OP_RET_PO: + if (!(zF & CZ80_VF)) goto OP_RET_COND; + RET(5) + + OP(0xe8): // RET PE +OP_RET_PE: + if (zF & CZ80_VF) goto OP_RET_COND; + RET(5) + + OP(0xf0): // RET P +OP_RET_P: + if (!(zF & CZ80_SF)) goto OP_RET_COND; + RET(5) + + OP(0xf8): // RET M +OP_RET_M: + if (zF & CZ80_SF) goto OP_RET_COND; + RET(5) + + OP(0xc0): // RET NZ +OP_RET_NZ: + if (!(zF & CZ80_ZF)) goto OP_RET_COND; + RET(5) + + OP(0xc8): // RET Z +OP_RET_Z: + if (zF & CZ80_ZF) goto OP_RET_COND; + RET(5) + +OP_RET_COND: + Z80_ICount -= 7; + + OP(0xc9): // RET +OP_RET: + { + u32 newPC; + + PRE_IO + POP_16(newPC); + SET_PC(newPC); + POST_IO + RET(10) + } + + + OP(0xc7): // RST 0 + OP(0xcf): // RST 1 + OP(0xd7): // RST 2 + OP(0xdf): // RST 3 + OP(0xe7): // RST 4 + OP(0xef): // RST 5 + OP(0xf7): // RST 6 + OP(0xff): // RST 7 +OP_RST: + { + u32 src; + u32 newPC; + + src = zRealPC; + PUSH_16(src); + newPC = Opcode & 0x38; + SET_PC(newPC); + RET(11) + } + + // INPUT & OUTPUT + + { + u32 adr; + + OP(0xd3): // OUT (n),A +OP_OUT_mN_A: + { u8 t; FETCH_BYTE(t); adr = (zA << 8) | t; } + OUT(adr, zA) + RET(11) + + OP(0xdb): // IN A,(n) +OP_IN_A_mN: + { u8 t; FETCH_BYTE(t); adr = (zA << 8) | t; } + IN(adr, zA) + RET(11) + } + + // PREFIXE + + OP(0xcb): // CB PREFIXE (BIT & SHIFT INSTRUCTIONS) +CB_PREFIXE: + Opcode = REAL_FETCH_BYTE; + #include "cz80_opCB.inc" + + OP(0xed): // ED PREFIXE +ED_PREFIXE: + Z80_ICount -= 4; + Opcode = REAL_FETCH_BYTE; + #include "cz80_opED.inc" + + OP(0xdd): // DD PREFIXE (IX) +DD_PREFIXE: + data = pzIX; + goto XY_PREFIXE; + + OP(0xfd): // FD PREFIXE (IY) +FD_PREFIXE: + data = pzIY; + +XY_PREFIXE: + Z80_ICount -= 4; + Opcode = REAL_FETCH_BYTE; + #include "cz80_opXY.inc" + +#if CZ80_USE_JUMPTABLE +#else +} +#endif diff --git a/cz80_opCB.inc b/cz80_opCB.inc new file mode 100644 index 0000000..aa108e4 --- /dev/null +++ b/cz80_opCB.inc @@ -0,0 +1,548 @@ +/********************************************************************************/ +/* */ +/* CZ80 CB opcode include source file */ +/* C Z80 emulator version 0.92 */ +/* Copyright 2004-2005 Stéphane Dallongeville */ +/* */ +/********************************************************************************/ + +#if CZ80_USE_JUMPTABLE + goto *JumpTableCB[Opcode]; +#else +switch (Opcode) +{ +#endif + + OPCB(0x00): // RLC B + OPCB(0x01): // RLC C + OPCB(0x02): // RLC D + OPCB(0x03): // RLC E + OPCB(0x04): // RLC H + OPCB(0x05): // RLC L + OPCB(0x07): // RLC A + { + u8 src = zR8(Opcode); + + zR8(Opcode) = (src << 1) | (src >> 7); + zF = SZXYP[zR8(Opcode)] | (src >> 7); + RET(4 + 4) + } + + OPCB(0x06): // RLC (HL) + { + u32 adr; + u32 src; + u32 res; + + PRE_IO + adr = zHL; + READ_BYTE(adr, src) + res = ((src << 1) | (src >> 7)) & 0xFF; + zF = SZXYP[res] | (src >> 7); + WRITE_BYTE(adr, res) + POST_IO + RET(11 + 4) + } + + + OPCB(0x08): // RRC B + OPCB(0x09): // RRC C + OPCB(0x0a): // RRC D + OPCB(0x0b): // RRC E + OPCB(0x0c): // RRC H + OPCB(0x0d): // RRC L + OPCB(0x0f): // RRC A + { + u8 src = zR8(Opcode & 7); + + zR8(Opcode & 7) = (src >> 1) | (src << 7); + zF = SZXYP[zR8(Opcode & 7)] | (src & CZ80_CF); + RET(4 + 4) + } + + OPCB(0x0e): // RRC (HL) + { + u32 adr; + u32 src; + u32 res; + + PRE_IO + adr = zHL; + READ_BYTE(adr, src) + res = ((src >> 1) | (src << 7)) & 0xFF; + zF = SZXYP[res] | (src & CZ80_CF); + WRITE_BYTE(adr, res) + POST_IO + RET(11 + 4) + } + + + OPCB(0x10): // RL B + OPCB(0x11): // RL C + OPCB(0x12): // RL D + OPCB(0x13): // RL E + OPCB(0x14): // RL H + OPCB(0x15): // RL L + OPCB(0x17): // RL A + { + u8 src = zR8(Opcode & 7); + + zR8(Opcode & 7) = (src << 1) | (zF & CZ80_CF); + zF = SZXYP[zR8(Opcode & 7)] | (src >> 7); + } + RET(4 + 4) + + OPCB(0x16): // RL (HL) + { + u32 adr; + u32 src; + u32 res; + + PRE_IO + adr = zHL; + READ_BYTE(adr, src) + res = ((src << 1) | (zF & CZ80_CF)) & 0xFF; + zF = SZXYP[res] | (src >> 7); + WRITE_BYTE(adr, res) + POST_IO + RET(11 + 4) + } + + + OPCB(0x18): // RR B + OPCB(0x19): // RR C + OPCB(0x1a): // RR D + OPCB(0x1b): // RR E + OPCB(0x1c): // RR H + OPCB(0x1d): // RR L + OPCB(0x1f): // RR A + { + u8 src = zR8(Opcode & 7); + + zR8(Opcode & 7) = (src >> 1) | (zF << 7); + zF = SZXYP[zR8(Opcode & 7)] | (src & CZ80_CF); + } + RET(4 + 4) + + OPCB(0x1e): // RR (HL) + { + u32 adr; + u32 src; + u32 res; + + PRE_IO + adr = zHL; + READ_BYTE(adr, src) + res = ((src >> 1) | (zF << 7)) & 0xFF; + zF = SZXYP[res] | (src & CZ80_CF); + WRITE_BYTE(adr, res) + POST_IO + RET(11 + 4) + } + + + OPCB(0x20): // SLA B + OPCB(0x21): // SLA C + OPCB(0x22): // SLA D + OPCB(0x23): // SLA E + OPCB(0x24): // SLA H + OPCB(0x25): // SLA L + OPCB(0x27): // SLA A + { + u8 src = zR8(Opcode & 7); + + zR8(Opcode & 7) = src << 1; + zF = SZXYP[zR8(Opcode & 7)] | (src >> 7); + } + RET(4 + 4) + + OPCB(0x26): // SLA (HL) + { + u32 adr; + u32 src; + u32 res; + + PRE_IO + adr = zHL; + READ_BYTE(adr, src) + res = (src << 1) & 0xFF; + zF = SZXYP[res] | (src >> 7); + WRITE_BYTE(adr, res) + POST_IO + RET(11 + 4) + } + + + OPCB(0x28): // SRA B + OPCB(0x29): // SRA C + OPCB(0x2a): // SRA D + OPCB(0x2b): // SRA E + OPCB(0x2c): // SRA H + OPCB(0x2d): // SRA L + OPCB(0x2f): // SRA A + { + s8 src = zR8(Opcode & 7); + + zR8(Opcode & 7) = src >> 1; + zF = SZXYP[zR8(Opcode & 7)] | (src & CZ80_CF); + } + RET(4 + 4) + + OPCB(0x2e): // SRA (HL) + { + u32 adr; + u32 src; + u32 res; + + PRE_IO + adr = zHL; + READ_BYTE(adr, src) + res = (u8)(((s8)(src)) >> 1); + zF = SZXYP[res] | (src & CZ80_CF); + WRITE_BYTE(adr, res) + POST_IO + RET(11 + 4) + } + + + OPCB(0x30): // SLL B + OPCB(0x31): // SLL C + OPCB(0x32): // SLL D + OPCB(0x33): // SLL E + OPCB(0x34): // SLL H + OPCB(0x35): // SLL L + OPCB(0x37): // SLL A + { + u8 src = zR8(Opcode & 7); + + zR8(Opcode & 7) = (src << 1) | 1; + zF = SZXYP[zR8(Opcode & 7)] | (src >> 7); + } + RET(4 + 4) + + OPCB(0x36): // SLL (HL) + { + u32 adr; + u32 src; + u32 res; + + PRE_IO + adr = zHL; + READ_BYTE(adr, src) + res = ((src << 1) | 1) & 0xFF; + zF = SZXYP[res] | (src >> 7); + WRITE_BYTE(adr, res) + POST_IO + RET(11 + 4) + } + + + OPCB(0x38): // SRL B + OPCB(0x39): // SRL C + OPCB(0x3a): // SRL D + OPCB(0x3b): // SRL E + OPCB(0x3c): // SRL H + OPCB(0x3d): // SRL L + OPCB(0x3f): // SRL A + { + u8 src = zR8(Opcode & 7); + + zR8(Opcode & 7) = src >> 1; + zF = SZXYP[zR8(Opcode & 7)] | (src & CZ80_CF); + } + RET(4 + 4) + + OPCB(0x3e): // SRL (HL) + { + u32 adr; + u32 src; + u32 res; + + PRE_IO + adr = zHL; + READ_BYTE(adr, src) + res = src >> 1; + zF = SZXYP[res] | (src & CZ80_CF); + WRITE_BYTE(adr, res) + POST_IO + RET(11 + 4) + } + + + OPCB(0x40): // BIT 0,B + OPCB(0x41): // BIT 0,C + OPCB(0x42): // BIT 0,D + OPCB(0x43): // BIT 0,E + OPCB(0x44): // BIT 0,H + OPCB(0x45): // BIT 0,L + OPCB(0x47): // BIT 0,A + + OPCB(0x48): // BIT 1,B + OPCB(0x49): // BIT 1,C + OPCB(0x4a): // BIT 1,D + OPCB(0x4b): // BIT 1,E + OPCB(0x4c): // BIT 1,H + OPCB(0x4d): // BIT 1,L + OPCB(0x4f): // BIT 1,A + + OPCB(0x50): // BIT 2,B + OPCB(0x51): // BIT 2,C + OPCB(0x52): // BIT 2,D + OPCB(0x53): // BIT 2,E + OPCB(0x54): // BIT 2,H + OPCB(0x55): // BIT 2,L + OPCB(0x57): // BIT 2,A + + OPCB(0x58): // BIT 3,B + OPCB(0x59): // BIT 3,C + OPCB(0x5a): // BIT 3,D + OPCB(0x5b): // BIT 3,E + OPCB(0x5c): // BIT 3,H + OPCB(0x5d): // BIT 3,L + OPCB(0x5f): // BIT 3,A + + OPCB(0x60): // BIT 4,B + OPCB(0x61): // BIT 4,C + OPCB(0x62): // BIT 4,D + OPCB(0x63): // BIT 4,E + OPCB(0x64): // BIT 4,H + OPCB(0x65): // BIT 4,L + OPCB(0x67): // BIT 4,A + + OPCB(0x68): // BIT 5,B + OPCB(0x69): // BIT 5,C + OPCB(0x6a): // BIT 5,D + OPCB(0x6b): // BIT 5,E + OPCB(0x6c): // BIT 5,H + OPCB(0x6d): // BIT 5,L + OPCB(0x6f): // BIT 5,A + + OPCB(0x70): // BIT 6,B + OPCB(0x71): // BIT 6,C + OPCB(0x72): // BIT 6,D + OPCB(0x73): // BIT 6,E + OPCB(0x74): // BIT 6,H + OPCB(0x75): // BIT 6,L + OPCB(0x77): // BIT 6,A + + OPCB(0x78): // BIT 7,B + OPCB(0x79): // BIT 7,C + OPCB(0x7a): // BIT 7,D + OPCB(0x7b): // BIT 7,E + OPCB(0x7c): // BIT 7,H + OPCB(0x7d): // BIT 7,L + OPCB(0x7f): // BIT 7,A + { + zF = (zF & CZ80_CF) | CZ80_HF | + SZXY_BIT[zR8(Opcode & 7) & (1 << ((Opcode >> 3) & 7))]; + } + RET(4 + 4) + + OPCB(0x46): // BIT 0,(HL) + OPCB(0x4e): // BIT 1,(HL) + OPCB(0x56): // BIT 2,(HL) + OPCB(0x5e): // BIT 3,(HL) + OPCB(0x66): // BIT 4,(HL) + OPCB(0x6e): // BIT 5,(HL) + OPCB(0x76): // BIT 6,(HL) + OPCB(0x7e): // BIT 7,(HL) + { + u32 src; + u32 bitm; + + PRE_IO + bitm = 1 << ((Opcode >> 3) & 7); + READ_BYTE(zHL, src) + zF = (zF & CZ80_CF) | CZ80_HF | SZXY_BIT[src & bitm]; + POST_IO + RET(8 + 4) + } + + + OPCB(0x80): // RES 0,B + OPCB(0x81): // RES 0,C + OPCB(0x82): // RES 0,D + OPCB(0x83): // RES 0,E + OPCB(0x84): // RES 0,H + OPCB(0x85): // RES 0,L + OPCB(0x87): // RES 0,A + + OPCB(0x88): // RES 1,B + OPCB(0x89): // RES 1,C + OPCB(0x8a): // RES 1,D + OPCB(0x8b): // RES 1,E + OPCB(0x8c): // RES 1,H + OPCB(0x8d): // RES 1,L + OPCB(0x8f): // RES 1,A + + OPCB(0x90): // RES 2,B + OPCB(0x91): // RES 2,C + OPCB(0x92): // RES 2,D + OPCB(0x93): // RES 2,E + OPCB(0x94): // RES 2,H + OPCB(0x95): // RES 2,L + OPCB(0x97): // RES 2,A + + OPCB(0x98): // RES 3,B + OPCB(0x99): // RES 3,C + OPCB(0x9a): // RES 3,D + OPCB(0x9b): // RES 3,E + OPCB(0x9c): // RES 3,H + OPCB(0x9d): // RES 3,L + OPCB(0x9f): // RES 3,A + + OPCB(0xa0): // RES 4,B + OPCB(0xa1): // RES 4,C + OPCB(0xa2): // RES 4,D + OPCB(0xa3): // RES 4,E + OPCB(0xa4): // RES 4,H + OPCB(0xa5): // RES 4,L + OPCB(0xa7): // RES 4,A + + OPCB(0xa8): // RES 5,B + OPCB(0xa9): // RES 5,C + OPCB(0xaa): // RES 5,D + OPCB(0xab): // RES 5,E + OPCB(0xac): // RES 5,H + OPCB(0xad): // RES 5,L + OPCB(0xaf): // RES 5,A + + OPCB(0xb0): // RES 6,B + OPCB(0xb1): // RES 6,C + OPCB(0xb2): // RES 6,D + OPCB(0xb3): // RES 6,E + OPCB(0xb4): // RES 6,H + OPCB(0xb5): // RES 6,L + OPCB(0xb7): // RES 6,A + + OPCB(0xb8): // RES 7,B + OPCB(0xb9): // RES 7,C + OPCB(0xba): // RES 7,D + OPCB(0xbb): // RES 7,E + OPCB(0xbc): // RES 7,H + OPCB(0xbd): // RES 7,L + OPCB(0xbf): // RES 7,A + { + zR8(Opcode & 7) &= ~(1 << ((Opcode >> 3) & 7)); + } + RET(4 + 4) + + OPCB(0x86): // RES 0,(HL) + OPCB(0x8e): // RES 1,(HL) + OPCB(0x96): // RES 2,(HL) + OPCB(0x9e): // RES 3,(HL) + OPCB(0xa6): // RES 4,(HL) + OPCB(0xae): // RES 5,(HL) + OPCB(0xb6): // RES 6,(HL) + OPCB(0xbe): // RES 7,(HL) + { + u32 adr; + u32 res; + u32 bitm; + + PRE_IO + adr = zHL; + bitm = ~(1 << ((Opcode >> 3) & 7)); + READ_BYTE(adr, res) + res &= bitm; + WRITE_BYTE(adr, res) + POST_IO + RET(11 + 4) + } + + + OPCB(0xc0): // SET 0,B + OPCB(0xc1): // SET 0,C + OPCB(0xc2): // SET 0,D + OPCB(0xc3): // SET 0,E + OPCB(0xc4): // SET 0,H + OPCB(0xc5): // SET 0,L + OPCB(0xc7): // SET 0,A + + OPCB(0xc8): // SET 1,B + OPCB(0xc9): // SET 1,C + OPCB(0xca): // SET 1,D + OPCB(0xcb): // SET 1,E + OPCB(0xcc): // SET 1,H + OPCB(0xcd): // SET 1,L + OPCB(0xcf): // SET 1,A + + OPCB(0xd0): // SET 2,B + OPCB(0xd1): // SET 2,C + OPCB(0xd2): // SET 2,D + OPCB(0xd3): // SET 2,E + OPCB(0xd4): // SET 2,H + OPCB(0xd5): // SET 2,L + OPCB(0xd7): // SET 2,A + + OPCB(0xd8): // SET 3,B + OPCB(0xd9): // SET 3,C + OPCB(0xda): // SET 3,D + OPCB(0xdb): // SET 3,E + OPCB(0xdc): // SET 3,H + OPCB(0xdd): // SET 3,L + OPCB(0xdf): // SET 3,A + + OPCB(0xe0): // SET 4,B + OPCB(0xe1): // SET 4,C + OPCB(0xe2): // SET 4,D + OPCB(0xe3): // SET 4,E + OPCB(0xe4): // SET 4,H + OPCB(0xe5): // SET 4,L + OPCB(0xe7): // SET 4,A + + OPCB(0xe8): // SET 5,B + OPCB(0xe9): // SET 5,C + OPCB(0xea): // SET 5,D + OPCB(0xeb): // SET 5,E + OPCB(0xec): // SET 5,H + OPCB(0xed): // SET 5,L + OPCB(0xef): // SET 5,A + + OPCB(0xf0): // SET 6,B + OPCB(0xf1): // SET 6,C + OPCB(0xf2): // SET 6,D + OPCB(0xf3): // SET 6,E + OPCB(0xf4): // SET 6,H + OPCB(0xf5): // SET 6,L + OPCB(0xf7): // SET 6,A + + OPCB(0xf8): // SET 7,B + OPCB(0xf9): // SET 7,C + OPCB(0xfa): // SET 7,D + OPCB(0xfb): // SET 7,E + OPCB(0xfc): // SET 7,H + OPCB(0xfd): // SET 7,L + OPCB(0xff): // SET 7,A + { + zR8(Opcode & 7) |= 1 << ((Opcode >> 3) & 7); + } + RET(4 + 4) + + OPCB(0xc6): // SET 0,(HL) + OPCB(0xce): // SET 1,(HL) + OPCB(0xd6): // SET 2,(HL) + OPCB(0xde): // SET 3,(HL) + OPCB(0xe6): // SET 4,(HL) + OPCB(0xee): // SET 5,(HL) + OPCB(0xf6): // SET 6,(HL) + OPCB(0xfe): // SET 7,(HL) + { + u32 adr; + u32 res; + u32 bitm; + + PRE_IO + adr = zHL; + bitm = 1 << ((Opcode >> 3) & 7); + READ_BYTE(adr, res) + res |= bitm; + WRITE_BYTE(adr, res) + POST_IO + RET(11 + 4) + } + +#if CZ80_USE_JUMPTABLE +#else +} +#endif diff --git a/cz80_opED.inc b/cz80_opED.inc new file mode 100644 index 0000000..3fb4cad --- /dev/null +++ b/cz80_opED.inc @@ -0,0 +1,823 @@ +/********************************************************************************/ +/* */ +/* CZ80 ED opcode include source file */ +/* C Z80 emulator version 0.92 */ +/* Copyright 2004-2005 Stéphane Dallongeville */ +/* */ +/********************************************************************************/ + +#if CZ80_USE_JUMPTABLE + goto *JumpTableED[Opcode]; +#else +switch (Opcode) +{ +#endif + + // ILLEGAL + + OPED(0x00): + OPED(0x01): + OPED(0x02): + OPED(0x03): + OPED(0x04): + OPED(0x05): + OPED(0x06): + OPED(0x07): + OPED(0x08): + OPED(0x09): + OPED(0x0a): + OPED(0x0b): + OPED(0x0c): + OPED(0x0d): + OPED(0x0e): + OPED(0x0f): + OPED(0x10): + OPED(0x11): + OPED(0x12): + OPED(0x13): + OPED(0x14): + OPED(0x15): + OPED(0x16): + OPED(0x17): + OPED(0x18): + OPED(0x19): + OPED(0x1a): + OPED(0x1b): + OPED(0x1c): + OPED(0x1d): + OPED(0x1e): + OPED(0x1f): + OPED(0x20): + OPED(0x21): + OPED(0x22): + OPED(0x23): + OPED(0x24): + OPED(0x25): + OPED(0x26): + OPED(0x27): + OPED(0x28): + OPED(0x29): + OPED(0x2a): + OPED(0x2b): + OPED(0x2c): + OPED(0x2d): + OPED(0x2e): + OPED(0x2f): + OPED(0x30): + OPED(0x31): + OPED(0x32): + OPED(0x33): + OPED(0x34): + OPED(0x35): + OPED(0x36): + OPED(0x37): + OPED(0x38): + OPED(0x39): + OPED(0x3a): + OPED(0x3b): + OPED(0x3c): + OPED(0x3d): + OPED(0x3e): + OPED(0x3f): + OPED(0xbc): + OPED(0xbd): + OPED(0xbe): + OPED(0xbf): + OPED(0xc0): + OPED(0xc1): + OPED(0xc2): + OPED(0xc3): + OPED(0xc4): + OPED(0xc5): + OPED(0xc6): + OPED(0xc7): + OPED(0xc8): + OPED(0xc9): + OPED(0xca): + OPED(0xcb): + OPED(0xcc): + OPED(0xcd): + OPED(0xce): + OPED(0xcf): + OPED(0xd0): + OPED(0xd1): + OPED(0xd2): + OPED(0xd3): + OPED(0xd4): + OPED(0xd5): + OPED(0xd6): + OPED(0xd7): + OPED(0xd8): + OPED(0xd9): + OPED(0xda): + OPED(0xdb): + OPED(0xdc): + OPED(0xdd): + OPED(0xde): + OPED(0xdf): + OPED(0xe0): + OPED(0xe1): + OPED(0xe2): + OPED(0xe3): + OPED(0xe4): + OPED(0xe5): + OPED(0xe6): + OPED(0xe7): + OPED(0xe8): + OPED(0xe9): + OPED(0xea): + OPED(0xeb): + OPED(0xec): + OPED(0xed): + OPED(0xee): + OPED(0xef): + OPED(0xf0): + OPED(0xf1): + OPED(0xf2): + OPED(0xf3): + OPED(0xf4): + OPED(0xf5): + OPED(0xf6): + OPED(0xf7): + OPED(0xf8): + OPED(0xf9): + OPED(0xfa): + OPED(0xfb): + OPED(0xfc): + OPED(0xfd): + OPED(0xfe): + OPED(0xff): + OPED(0x77): + OPED(0x7f): + OPED(0x80): + OPED(0x81): + OPED(0x82): + OPED(0x83): + OPED(0x84): + OPED(0x85): + OPED(0x86): + OPED(0x87): + OPED(0x88): + OPED(0x89): + OPED(0x8a): + OPED(0x8b): + OPED(0x8c): + OPED(0x8d): + OPED(0x8e): + OPED(0x8f): + OPED(0x90): + OPED(0x91): + OPED(0x92): + OPED(0x93): + OPED(0x94): + OPED(0x95): + OPED(0x96): + OPED(0x97): + OPED(0x98): + OPED(0x99): + OPED(0x9a): + OPED(0x9b): + OPED(0x9c): + OPED(0x9d): + OPED(0x9e): + OPED(0x9f): + OPED(0xa4): + OPED(0xa5): + OPED(0xa6): + OPED(0xa7): + OPED(0xac): + OPED(0xad): + OPED(0xae): + OPED(0xaf): + OPED(0xb4): + OPED(0xb5): + OPED(0xb6): + OPED(0xb7): + goto OP_NOP; + + OPED(0x43): // LD (w),BC + data = pzBC; + goto OP_LD_mNN_xx; + + OPED(0x53): // LD (w),DE + data = pzDE; + goto OP_LD_mNN_xx; + + OPED(0x63): // LD (w),HL + data = pzHL; + goto OP_LD_mNN_xx; + + OPED(0x73): // LD (w),SP + data = pzSP; + goto OP_LD_mNN_xx; + + OPED(0x4b): // LD BC,(w) + data = pzBC; + goto OP_LD_xx_mNN; + + OPED(0x5b): // LD DE,(w) + data = pzDE; + goto OP_LD_xx_mNN; + + OPED(0x6b): // LD HL,(w) + data = pzHL; + goto OP_LD_xx_mNN; + + OPED(0x7b): // LD SP,(w) + data = pzSP; + goto OP_LD_xx_mNN; + + + OPED(0x47): // LD I,A + zI = zA; + RET(5) + + OPED(0x4f): // LD R,A + zR = zA - ((CPU->CycleToDo - Z80_ICount) / 4); + zR2 = zA & 0x80; + RET(5) + + OPED(0x57): // LD A,I + { + u8 F; + + zA = zI; + F = zF & CZ80_CF; + F |= zA & (CZ80_SF | CZ80_YF | CZ80_XF); + F |= zIFF2; + if (!zA) F |= CZ80_ZF; + zF = F; + RET(5) + } + + OPED(0x5f): // LD A,R + { + u8 F; + + zA = zR2 + ((zR + ((CPU->CycleToDo - Z80_ICount) / 4)) & 0x7F); + F = zF & CZ80_CF; + F |= zA & (CZ80_SF | CZ80_YF | CZ80_XF); + F |= zIFF2; + if (!zA) F |= CZ80_ZF; + zF = F; + RET(5) + } + + OPED(0x5c): // NEG + OPED(0x54): // NEG + OPED(0x4c): // NEG + OPED(0x44): // NEG + OPED(0x64): // NEG + OPED(0x6c): // NEG + OPED(0x74): // NEG + OPED(0x7c): // NEG + { + u32 val; + u32 res; + + val = zA; + res = 0 - val; + zF = SZXY[res & 0xFF] | // S/Z/X/Y flag + ((res ^ val) & CZ80_HF) | // H flag + (((val & res) & 0x80) >> 5) | // V flag + ((res >> 8) & CZ80_CF) | CZ80_NF; // C/N flag + zA = res; + RET(4) + } + + + OPED(0x67): // RRD (HL) + { + u32 adr; + u8 src; + + PRE_IO + adr = zHL; + READ_BYTE(adr, src) + WRITE_BYTE(adr, (src >> 4) | (zA << 4)) + zA = (zA & 0xF0) | (src & 0x0F); + zF = SZXYP[zA] | (zF & CZ80_CF); + POST_IO + RET(14) + } + + OPED(0x6f): // RLD (HL) + { + u32 adr; + u8 src; + + PRE_IO + adr = zHL; + READ_BYTE(adr, src) + WRITE_BYTE(adr, (src << 4) | (zA & 0x0F)) + zA = (zA & 0xF0) | (src >> 4); + zF = SZXYP[zA] | (zF & CZ80_CF); + POST_IO + RET(14) + } + + + { + u32 src; + u32 res; + + OPED(0x7a): // ADC HL,SP + src = zSP; + goto OP_ADC_HL; + + OPED(0x4a): // ADC HL,BC + OPED(0x5a): // ADC HL,DE + OPED(0x6a): // ADC HL,HL + src = zR16((Opcode >> 4) & 3); + +OP_ADC_HL: + res = zHL + src + (zF & CZ80_CF); + zF = (((src ^ zHL ^ res) >> 8) & CZ80_HF) | // H flag + (((src ^ zHL ^ 0x8000) & (src ^ res) & 0x8000) >> 13) | // V flag + ((res >> 8) & (CZ80_SF | CZ80_XF | CZ80_YF)) | // S/X/Y flag + ((res >> 16) & CZ80_CF) | // C flag + ((res & 0xFFFF) ? 0 : CZ80_ZF); // Z flag + zHL = res; + RET(11) + + + OPED(0x72): // SBC HL,SP + src = zSP; + goto OP_SBC_HL; + + OPED(0x42): // SBC HL,BC + OPED(0x52): // SBC HL,DE + OPED(0x62): // SBC HL,HL + src = zR16((Opcode >> 4) & 3); + +OP_SBC_HL: + res = zHL - src + (zF & CZ80_CF); +#if CZ80_DEBUG + zF = (((src ^ zHL ^ res) >> 8) & CZ80_HF) | CZ80_NF | // H/N flag + (((src ^ zHL) & (zHL ^ res) & 0x8000) >> 13) | // V flag + ((res >> 8) & CZ80_SF) | // S flag + ((res >> 16) & CZ80_CF) | // C flag + ((res & 0xFFFF) ? 0 : CZ80_ZF); // Z flag +#else + zF = (((src ^ zHL ^ res) >> 8) & CZ80_HF) | CZ80_NF | // H/N flag + (((src ^ zHL) & (zHL ^ res) & 0x8000) >> 13) | // V flag + ((res >> 8) & (CZ80_SF | CZ80_XF | CZ80_YF)) | // S/X/Y flag + ((res >> 16) & CZ80_CF) | // C flag + ((res & 0xFFFF) ? 0 : CZ80_ZF); // Z flag +#endif + zHL = res; + RET(11) + } + + + { + u32 res; + + OPED(0x40): // IN B,(C) + OPED(0x48): // IN C,(C) + OPED(0x50): // IN D,(C) + OPED(0x58): // IN E,(C) + OPED(0x60): // IN H,(C) + OPED(0x68): // IN L,(C) + OPED(0x78): // IN E,(C) + + IN(zBC, res); + zR8((Opcode >> 3) & 7) = res; + zF = (zF & CZ80_CF) | SZXYP[res]; + RET(8) + + OPED(0x70): // IN 0,(C) + + IN(zBC, res); + zF = (zF & CZ80_CF) | SZXYP[res]; + RET(8) + } + + + { + u32 src; + + OPED(0x71): // OUT (C),0 + src = 0; + goto OP_OUT_mBC; + + OPED(0x51): // OUT (C),D + OPED(0x41): // OUT (C),B + OPED(0x49): // OUT (C),C + OPED(0x59): // OUT (C),E + OPED(0x61): // OUT (C),H + OPED(0x69): // OUT (C),L + OPED(0x79): // OUT (C),E + src = zR8((Opcode >> 3) & 7); + +OP_OUT_mBC: + OUT(zBC, src); + RET(8) + } + + { + u32 newPC; + + OPED(0x4d): // RETI + OPED(0x5d): // RETI + OPED(0x6d): // RETI + OPED(0x7d): // RETI +// if (CPU->RetI) CPU->RetI(); + + OPED(0x45): // RETN; + OPED(0x55): // RETN; + OPED(0x65): // RETN; + OPED(0x75): // RETN; + PRE_IO + POP_16(newPC); + SET_PC(newPC); + POST_IO + zIFF1 = zIFF2; + Z80_ICount -= 10; + // we need to test for interrupt + goto Cz80_Check_Int; + } + + OPED(0x46): // IM 0 + OPED(0x4e): // IM 0 + OPED(0x66): // IM 0 + OPED(0x6e): // IM 0 + zIM = 0; + RET(4) + + OPED(0x76): // IM 1 + OPED(0x56): // IM 1 + zIM = 1; + RET(4) + + OPED(0x5e): // IM 2 + OPED(0x7e): // IM 2 + zIM = 2; + RET(4) + + + { + u8 val; + u8 F; + + OPED(0xa8): // LDD + PRE_IO + READ_BYTE(zHL--, val) + WRITE_BYTE(zDE--, val) + goto OP_LDX; + + OPED(0xa0): // LDI + PRE_IO + READ_BYTE(zHL++, val) + WRITE_BYTE(zDE++, val) + +OP_LDX: +#if CZ80_EXACT + val += zA; + F = (zF & (CZ80_SF | CZ80_ZF | CZ80_CF)) | + (val & CZ80_XF) | ((val << 4) & CZ80_YF); +#else + F = zF & (CZ80_SF | CZ80_ZF | CZ80_YF | CZ80_XF | CZ80_CF); +#endif + if (--zBC) F |= CZ80_PF; + zF = F; + POST_IO + RET(12) + } + + { + u8 val; + u8 F; + + OPED(0xb8): // LDDR + do + { + PRE_IO + READ_BYTE(zHL--, val) + WRITE_BYTE(zDE--, val) + POST_IO + zBC--; + Z80_ICount -= 21; + } while ((zBC) && (Z80_ICount > -4)); + goto OP_LDXR; + + OPED(0xb0): // LDIR + do + { + PRE_IO + READ_BYTE(zHL++, val) + WRITE_BYTE(zDE++, val) + POST_IO + zBC--; + Z80_ICount -= 21; + } while ((zBC) && (Z80_ICount > -4)); + +OP_LDXR: +#if CZ80_EXACT + val += zA; + F = (zF & (CZ80_SF | CZ80_ZF | CZ80_CF)) | + (val & CZ80_XF) | ((val << 4) & CZ80_YF); +#else + F = zF & (CZ80_SF | CZ80_ZF | CZ80_YF | CZ80_XF | CZ80_CF); +#endif + + if (zBC) + { + // instruction not yet completed... + // we will continu it at next CZ80_Exec + zF = F | CZ80_PF; + zPC -= 2; + Z80_ICount += 4; + goto Cz80_Check_Int; + } + + // instruction completed... + zF = F; + RET(-(5 + 4)) + } + + + { + u8 val; + u8 res; + u8 F; + + OPED(0xa9): // CPD + PRE_IO + READ_BYTE(zHL--, val) + goto OP_CPX; + + OPED(0xa1): // CPI + PRE_IO + READ_BYTE(zHL++, val) + +OP_CPX: + res = zA - val; +#if CZ80_EXACT + F = (zF & CZ80_CF) | (SZXY[res] & ~(CZ80_YF | CZ80_XF)) | + ((zA ^ val ^ res) & CZ80_HF) | CZ80_NF; + if (F & CZ80_HF) res--; + F |= (res & CZ80_XF) | ((res >> 4) & CZ80_YF); +#else + F = (zF & CZ80_CF) | SZXY[res] | + ((zA ^ val ^ res) & CZ80_HF) | CZ80_NF; +#endif + if (--zBC) F |= CZ80_PF; + zF = F; + POST_IO + RET(12) + } + + { + u32 val; + u32 res; + u8 F; + + OPED(0xb9): // CPDR + do + { + PRE_IO + READ_BYTE(zHL--, val) + res = zA - val; + POST_IO + zBC--; + Z80_ICount -= 21; + } while ((zBC) && (res) && (Z80_ICount > -4)); + goto OP_CPXR; + + OPED(0xb1): // CPIR + do + { + PRE_IO + READ_BYTE(zHL++, val) + res = zA - val; + POST_IO + zBC--; + Z80_ICount -= 21; + } while ((zBC) && (res) && (Z80_ICount > -4)); + +OP_CPXR: +#if CZ80_EXACT + F = (zF & CZ80_CF) | (SZXY[res] & ~(CZ80_YF | CZ80_XF)) | + ((zA ^ val ^ res) & CZ80_HF) | CZ80_NF; + if (F & CZ80_HF) res--; + F |= (res & CZ80_XF) | ((res >> 4) & CZ80_YF); +#else + F = (zF & CZ80_CF) | SZXY[res] | + ((zA ^ val ^ res) & CZ80_HF) | CZ80_NF; +#endif + + if (zBC) + { + // instruction not yet completed... + // we will continu it at next CZ80_Exec + zF = F | CZ80_PF; + zPC -= 2; + Z80_ICount += 4; + goto Cz80_Check_Int; + } + + // instruction completed... + zF = F; + RET(-(3 + 4)) + } + + + { + u8 val; +#if CZ80_EXACT + u8 F; +#endif + + OPED(0xaa): // IND + PRE_IO + IN(zBC, val) + WRITE_BYTE(zHL--, val) +#if CZ80_EXACT + if ((((zC - 1) & 0xFF) + val) & 0x100) + { + F = CZ80_HF | CZ80_CF; + goto OP_INX; + } + F = 0; +#endif + goto OP_INX; + + OPED(0xa2): // INI + PRE_IO + IN(zBC, val) + WRITE_BYTE(zHL++, val) +#if CZ80_EXACT + if ((((zC + 1) & 0xFF) + val) & 0x100) + { + F = CZ80_HF | CZ80_CF; + goto OP_INX; + } + F = 0; +#endif + +OP_INX: +#if CZ80_EXACT + // P FLAG isn't correct here ! + zF = F | (SZXY[--zB] + ((val >> 6) & CZ80_NF) + (val & CZ80_PF)); +#else + zF = SZXY[--zB] + ((val >> 6) & CZ80_NF); +#endif + POST_IO + RET(12) + } + + { + u8 val; +#if CZ80_EXACT + u8 F; +#endif + + OPED(0xba): // INDR + do + { + PRE_IO + IN(zBC, val) + WRITE_BYTE(zHL--, val) + POST_IO + zB--; + Z80_ICount -= 21; + } while ((zB) && (Z80_ICount > -4)); +#if CZ80_EXACT + if ((((zC - 1) & 0xFF) + val) & 0x100) + { + F = CZ80_HF | CZ80_CF; + goto OP_INXR; + } + F = 0; +#endif + goto OP_INXR; + + OPED(0xb2): // INIR + do + { + PRE_IO + IN(zBC, val) + WRITE_BYTE(zHL++, val) + POST_IO + zB--; + Z80_ICount -= 21; + } while ((zB) && (Z80_ICount > -4)); +#if CZ80_EXACT + if ((((zC + 1) & 0xFF) + val) & 0x100) + { + F = CZ80_HF | CZ80_CF; + goto OP_INXR; + } + F = 0; +#endif + +OP_INXR: +#if CZ80_EXACT + // P FLAG isn't correct here ! + zF = F | (SZXY[zB] + ((val >> 6) & CZ80_NF) + (val & CZ80_PF)); +#else + zF = SZXY[zB] + ((val >> 6) & CZ80_NF); +#endif + + if (zB) + { + // instruction not yet completed... + // we will continu it at next CZ80_Exec + zPC -= 2; + Z80_ICount += 4; + goto Cz80_Check_Int; + } + + // instruction completed... + RET(-(5 + 4)) + } + + + { + u8 val; +#if CZ80_EXACT + u8 F; +#endif + + OPED(0xab): // OUTD + PRE_IO + READ_BYTE(zHL--, val) + OUT(zBC, val) + goto OP_OUTX; + + OPED(0xa3): // OUTI + PRE_IO + READ_BYTE(zHL++, val) + OUT(zBC, val) + +OP_OUTX: +#if CZ80_EXACT + // P FLAG isn't correct here ! + F = SZXY[--zB] + ((val >> 6) & CZ80_NF) + (val & CZ80_PF); + if ((val + zL) & 0x100) F |= CZ80_HF | CZ80_CF; + zF = F; +#else + zF = SZXY[--zB] + ((val >> 6) & CZ80_NF); +#endif + POST_IO + RET(12) + } + + + { + u8 val; +#if CZ80_EXACT + u8 F; +#endif + + OPED(0xbb): // OUTDR + do + { + PRE_IO + READ_BYTE(zHL--, val) + OUT(zBC, val) + POST_IO + zB--; + Z80_ICount -= 21; + } while ((zB) && (Z80_ICount > -4)); + goto OP_OUTXR; + + OPED(0xb3): // OUTIR + do + { + PRE_IO + READ_BYTE(zHL++, val) + OUT(zBC, val) + POST_IO + zB--; + Z80_ICount -= 21; + } while ((zB) && (Z80_ICount > -4)); + +OP_OUTXR: +#if CZ80_EXACT + // P FLAG isn't correct here ! + F = SZXY[zB] + ((val >> 6) & CZ80_NF) + (val & CZ80_PF); + if ((val + zL) & 0x100) F |= CZ80_HF | CZ80_CF; + zF = F; +#else + zF = SZXY[zB] + ((val >> 6) & CZ80_NF); +#endif + + if (zB) + { + // instruction not yet completed... + // we will continu it at next CZ80_Exec + zPC -= 2; + Z80_ICount += 4; + goto Cz80_Check_Int; + } + + // instruction not yet completed... + RET(-(5 + 4)) + } + +#if CZ80_USE_JUMPTABLE +#else +} +#endif diff --git a/cz80_opXY.inc b/cz80_opXY.inc new file mode 100644 index 0000000..4595264 --- /dev/null +++ b/cz80_opXY.inc @@ -0,0 +1,714 @@ +/********************************************************************************/ +/* */ +/* CZ80 XY opcode include source file */ +/* C Z80 emulator version 0.92 */ +/* Copyright 2004-2005 Stéphane Dallongeville */ +/* */ +/********************************************************************************/ + +#if CZ80_USE_JUMPTABLE + goto *JumpTableXY[Opcode]; +#else +switch (Opcode) +{ +#endif + + OPXY(0x00): // NOP + + // 8 BITS LOAD + + OPXY(0x40): // LD B,B + OPXY(0x49): // LD C,C + OPXY(0x52): // LD D,D + OPXY(0x5b): // LD E,E + OPXY(0x64): // LD H,H + OPXY(0x6d): // LD L,L + OPXY(0x7f): // LD A,A + goto OP_NOP; + + OPXY(0x41): // LD B,C + OPXY(0x42): // LD B,D + OPXY(0x43): // LD B,E + OPXY(0x47): // LD B,A + + OPXY(0x48): // LD C,B + OPXY(0x4a): // LD C,D + OPXY(0x4b): // LD C,E + OPXY(0x4f): // LD C,A + + OPXY(0x50): // LD D,B + OPXY(0x51): // LD D,C + OPXY(0x53): // LD D,E + OPXY(0x57): // LD D,A + + OPXY(0x58): // LD E,B + OPXY(0x59): // LD E,C + OPXY(0x5a): // LD E,D + OPXY(0x5f): // LD E,A + + OPXY(0x78): // LD A,B + OPXY(0x79): // LD A,C + OPXY(0x7a): // LD A,D + OPXY(0x7b): // LD A,E + goto OP_LD_R_R; + + OPXY(0x44): // LD B,HX + OPXY(0x4c): // LD C,HX + OPXY(0x54): // LD D,HX + OPXY(0x5c): // LD E,HX + OPXY(0x7c): // LD A,HX + zR8((Opcode >> 3) & 7) = data->B.H; + RET(4) + + OPXY(0x45): // LD B,LX + OPXY(0x4d): // LD C,LX + OPXY(0x55): // LD D,LX + OPXY(0x5d): // LD E,LX + OPXY(0x7d): // LD A,LX + zR8((Opcode >> 3) & 7) = data->B.L; + RET(4) + + OPXY(0x60): // LD HX,B + OPXY(0x61): // LD HX,C + OPXY(0x62): // LD HX,D + OPXY(0x63): // LD HX,E + OPXY(0x67): // LD HX,A + data->B.H = zR8(Opcode & 7); + RET(4) + + OPXY(0x68): // LD LX,B + OPXY(0x69): // LD LX,C + OPXY(0x6a): // LD LX,D + OPXY(0x6b): // LD LX,E + OPXY(0x6f): // LD LX,A + data->B.L = zR8(Opcode & 7); + RET(4) + + OPXY(0x65): // LD HX,LX + data->B.H = data->B.L; + RET(4) + + OPXY(0x6c): // LD LX,HX + data->B.L = data->B.H; + RET(4) + + OPXY(0x06): // LD B,#imm + OPXY(0x0e): // LD C,#imm + OPXY(0x16): // LD D,#imm + OPXY(0x1e): // LD E,#imm + OPXY(0x3e): // LD A,#imm + goto OP_LD_R_imm; + + OPXY(0x26): // LD HX,#imm + FETCH_BYTE(data->B.H); + RET(7) + + OPXY(0x2e): // LD LX,#imm + FETCH_BYTE(data->B.L); + RET(7) + + OPXY(0x0a): // LD A,(BC) + goto OP_LOAD_A_mBC; + + OPXY(0x1a): // LD A,(DE) + goto OP_LOAD_A_mDE; + + OPXY(0x3a): // LD A,(nn) + goto OP_LOAD_A_mNN; + + OPXY(0x02): // LD (BC),A + goto OP_LOAD_mBC_A; + + OPXY(0x12): // LD (DE),A + goto OP_LOAD_mDE_A; + + OPXY(0x32): // LD (nn),A + goto OP_LOAD_mNN_A; + + { + u32 adr; + + OPXY(0x46): // LD B,(IX+o) + OPXY(0x56): // LD D,(IX+o) + OPXY(0x5e): // LD E,(IX+o) + OPXY(0x66): // LD H,(IX+o) + OPXY(0x6e): // LD L,(IX+o) + OPXY(0x4e): // LD C,(IX+o) + OPXY(0x7e): // LD A,(IX+o) + PRE_IO + { s8 t; FETCH_BYTE_S(t); adr = data->W + t; } + READ_BYTE(adr, zR8((Opcode >> 3) & 7)) + POST_IO + RET(15) + + OPXY(0x70): // LD (IX+o),B + OPXY(0x71): // LD (IX+o),C + OPXY(0x72): // LD (IX+o),D + OPXY(0x73): // LD (IX+o),E + OPXY(0x74): // LD (IX+o),H + OPXY(0x75): // LD (IX+o),L + OPXY(0x77): // LD (IX+o),A + PRE_IO + { s8 t; FETCH_BYTE_S(t); adr = data->W + t; } + WRITE_BYTE(adr, zR8(Opcode & 7)) + POST_IO + RET(15) + + OPXY(0x36): // LD (IX+o),#imm + PRE_IO + { s8 t; FETCH_BYTE_S(t); adr = data->W + t; } + { u8 t; FETCH_BYTE(t); WRITE_BYTE(adr, t); } + POST_IO + RET(15) + } + + // 16 BITS LOAD + + OPXY(0x01): // LD BC,nn + OPXY(0x11): // LD DE,nn + goto OP_LOAD_RR_imm16; + + OPXY(0x21): // LD IX,nn + FETCH_WORD(data->W); + RET(10) + + OPXY(0x31): // LD SP,nn + goto OP_LOAD_SP_imm16; + + OPXY(0x2a): // LD IX,(w) + goto OP_LD_xx_mNN; + + OPXY(0x22): // LD (w),IX + goto OP_LD_mNN_xx; + + OPXY(0xf9): // LD SP,IX + goto OP_LD_SP_xx; + + + // PUSH / POP + + OPXY(0xf1): // POP AF + goto OP_POP_AF; + + OPXY(0xc1): // POP BC + OPXY(0xd1): // POP DE + goto OP_POP_RR; + + OPXY(0xe1): // POP IX + goto OP_POP; + + OPXY(0xf5): // PUSH AF + goto OP_PUSH_AF; + + OPXY(0xc5): // PUSH BC + OPXY(0xd5): // PUSH DE + goto OP_PUSH_RR; + + OPXY(0xe5): // PUSH IX + goto OP_PUSH; + + + // EXCHANGE + + OPXY(0x08): // EX AF,AF' + goto OP_EX_AF_AF2; + + OPXY(0xeb): // EX DE,HL + goto OP_EX_DE_HL; + + OPXY(0xd9): // EXX + goto OP_EXX; + + OPXY(0xe3): // EX (SP),IX + goto OP_EX_xx_mSP; + + + // 8 BITS ARITHMETIC + // INC + + OPXY(0x04): // INC B + OPXY(0x0c): // INC C + OPXY(0x14): // INC D + OPXY(0x1c): // INC E + OPXY(0x3c): // INC A + goto OP_INC_R; + + OPXY(0x24): // INC HX + data->B.H++; + zF = (zF & CZ80_CF) | SZXYHV_inc[data->B.H]; + RET(4) + + OPXY(0x2c): // INC LX + data->B.L++; + zF = (zF & CZ80_CF) | SZXYHV_inc[data->B.L]; + RET(4) + + OPXY(0x34): // INC (IX+o) + goto OP_INC_mIx; + + // DEC + + OPXY(0x05): // DEC B + OPXY(0x0d): // DEC C + OPXY(0x15): // DEC D + OPXY(0x1d): // DEC E + OPXY(0x3d): // DEC A + goto OP_DEC_R; + + OPXY(0x25): // DEC HX + data->B.H--; + zF = (zF & CZ80_CF) | SZXYHV_dec[data->B.H]; + RET(4) + + OPXY(0x2d): // DEC LX + data->B.L--; + zF = (zF & CZ80_CF) | SZXYHV_dec[data->B.L]; + RET(4) + + OPXY(0x35): // DEC (IX+o) + goto OP_DEC_mIx; + + + // ADD + + OPXY(0x80): // ADD A,B + OPXY(0x81): // ADD A,C + OPXY(0x82): // ADD A,D + OPXY(0x83): // ADD A,E + OPXY(0x87): // ADD A,A + goto OP_ADD_R; + + OPXY(0x84): // ADD A,HX + goto OP_ADD_IxH; + + OPXY(0x85): // ADD A,LX + goto OP_ADD_IxL; + + OPXY(0xc6): // ADD A,n + goto OP_ADD_imm; + + OPXY(0x86): // ADD A,(IX+o) + goto OP_ADD_mIx; + + // ADC + + OPXY(0x88): // ADC A,B + OPXY(0x89): // ADC A,C + OPXY(0x8a): // ADC A,D + OPXY(0x8b): // ADC A,E + OPXY(0x8f): // ADC A,A + goto OP_ADC_R; + + OPXY(0xce): // ADC A,n + goto OP_ADC_imm; + + OPXY(0x8c): // ADC A,HX + goto OP_ADC_IxH; + + OPXY(0x8d): // ADC A,LX + goto OP_ADC_IxL; + + OPXY(0x8e): // ADC A,(IX+o) + goto OP_ADC_mIx; + + // SUB + + OPXY(0x90): // SUB B + OPXY(0x91): // SUB C + OPXY(0x92): // SUB D + OPXY(0x93): // SUB E + OPXY(0x97): // SUB A + goto OP_SUB_R; + + OPXY(0x94): // SUB HX + goto OP_SUB_IxH; + + OPXY(0x95): // SUB LX + goto OP_SUB_IxL; + + OPXY(0xd6): // SUB A,n + goto OP_SUB_imm; + + OPXY(0x96): // SUB (IX+o) + goto OP_SUB_mIx; + + // SBC + + OPXY(0x98): // SBC A,B + OPXY(0x99): // SBC A,C + OPXY(0x9a): // SBC A,D + OPXY(0x9b): // SBC A,E + OPXY(0x9f): // SBC A,A + goto OP_SBC_R; + + OPXY(0x9c): // SBC A,HX + goto OP_SBC_IxH; + + OPXY(0x9d): // SBC A,LX + goto OP_SBC_IxL; + + OPXY(0xde): // SBC A,n + goto OP_SBC_imm; + + OPXY(0x9e): // SBC A,(IX+o) + goto OP_SBC_mIx; + + // CP + + OPXY(0xb8): // CP B + OPXY(0xb9): // CP C + OPXY(0xba): // CP D + OPXY(0xbb): // CP E + OPXY(0xbf): // CP A + goto OP_CP_R; + + OPXY(0xbc): // CP HX + goto OP_CP_IxH; + + OPXY(0xbd): // CP LX + goto OP_CP_IxL; + + OPXY(0xfe): // CP n + goto OP_CP_imm; + + OPXY(0xbe): // CP (IX+o) + goto OP_CP_mIx; + + // AND + + OPXY(0xa0): // AND B + OPXY(0xa1): // AND C + OPXY(0xa2): // AND D + OPXY(0xa3): // AND E + goto OP_AND_R; + + OPXY(0xa7): // AND A + goto OP_AND_A; + + OPXY(0xa4): // AND HX + goto OP_AND_IxH; + + OPXY(0xa5): // AND LX + goto OP_AND_IxL; + + OPXY(0xe6): // AND A,n + goto OP_AND_imm; + + OPXY(0xa6): // AND (IX+o) + { + u32 val; + + PRE_IO + { s8 t; FETCH_BYTE_S(t); READ_BYTE(data->W + t, val); } + POST_IO + zA = zA & val; + zF = SZXYP[zA] | CZ80_HF; + RET(15) + } + + // XOR + + OPXY(0xa8): // XOR B + OPXY(0xa9): // XOR C + OPXY(0xaa): // XOR D + OPXY(0xab): // XOR E + goto OP_XOR_R; + + OPXY(0xaf): // XOR A + goto OP_XOR_A; + + OPXY(0xac): // XOR HX + goto OP_XOR_IxH; + + OPXY(0xad): // XOR LX + goto OP_XOR_IxL; + + OPXY(0xee): // XOR A,n + goto OP_XOR_imm; + + OPXY(0xae): // XOR (IX+o) + { + u32 val; + + PRE_IO + { s8 t; FETCH_BYTE_S(t); READ_BYTE(data->W + t, val); } + POST_IO + zA = zA ^ val; + zF = SZXYP[zA]; + RET(15) + } + + // OR + + OPXY(0xb0): // OR B + OPXY(0xb1): // OR C + OPXY(0xb2): // OR D + OPXY(0xb3): // OR E + goto OP_OR_R; + + OPXY(0xb7): // OR A + goto OP_OR_A; + + OPXY(0xb4): // OR HX + goto OP_OR_IxH; + + OPXY(0xb5): // OR LX + goto OP_OR_IxL; + + OPXY(0xf6): // OR A,n + goto OP_OR_imm; + + OPXY(0xb6): // OR (IX+o) + { + u32 val; + + PRE_IO + { s8 t; FETCH_BYTE_S(t); READ_BYTE(data->W + t, val); } + POST_IO + zA = zA | val; + zF = SZXYP[zA]; + RET(15) + } + + + // MISC ARITHMETIC & CPU CONTROL + + OPXY(0x27): // DAA + goto OP_DAA; + + OPXY(0x2f): // CPL + goto OP_CPL; + + OPXY(0x37): // SCF + goto OP_SCF; + + OPXY(0x3f): // CCF + goto OP_CCF; + + OPXY(0x76): // HALT + goto OP_HALT; + + OPXY(0xf3): // DI + goto OP_DI; + + OPXY(0xfb): // EI + goto OP_EI; + + + // 16 BITS ARITHMETIC + + OPXY(0x03): // INC BC + goto OP_INC_BC; + + OPXY(0x13): // INC DE + goto OP_INC_DE; + + OPXY(0x23): // INC IX + goto OP_INC_xx; + + OPXY(0x33): // INC SP + goto OP_INC_SP; + + OPXY(0x0b): // DEC BC + goto OP_DEC_BC; + + OPXY(0x1b): // DEC DE + goto OP_DEC_DE; + + OPXY(0x2b): // DEC IX + goto OP_DEC_xx; + + OPXY(0x3b): // DEC SP + goto OP_DEC_SP; + + // ADD16 + + OPXY(0x09): // ADD IX,BC + goto OP_ADD16_xx_BC; + + OPXY(0x19): // ADD IX,DE + goto OP_ADD16_xx_DE; + + OPXY(0x29): // ADD IX,IX + goto OP_ADD16_xx_xx; + + OPXY(0x39): // ADD IX,SP + goto OP_ADD16_xx_SP; + + + // ROTATE + + OPXY(0x07): // RLCA + goto OP_RLCA; + + OPXY(0x0f): // RRCA + goto OP_RRCA; + + OPXY(0x17): // RLA + goto OP_RLA; + + OPXY(0x1f): // RRA + goto OP_RRA; + + + // JUMP + + OPXY(0xc3): // JP nn + goto OP_JP; + + OPXY(0xe9): // JP (IX) + goto OP_JP_xx; + + + OPXY(0xd2): // JP NC,nn + goto OP_JP_NC; + + OPXY(0xda): // JP C,nn + goto OP_JP_C; + + OPXY(0xe2): // JP PO,nn + goto OP_JP_PO; + + OPXY(0xea): // JP PE,nn + goto OP_JP_PE; + + OPXY(0xf2): // JP P,nn + goto OP_JP_P; + + OPXY(0xfa): // JP M,nn + goto OP_JP_M; + + OPXY(0xca): // JP Z,nn + goto OP_JP_Z; + + OPXY(0xc2): // JP NZ,nn + goto OP_JP_NZ; + + + OPXY(0x18): // JR n + goto OP_JR; + + + OPXY(0x38): // JR C,n + goto OP_JR_C; + + OPXY(0x30): // JR NC,n + goto OP_JR_NC; + + OPXY(0x28): // JR Z,n + goto OP_JR_Z; + + OPXY(0x20): // JR NZ,n + goto OP_JR_NZ; + + + OPXY(0x10): // DJNZ n + goto OP_DJNZ; + + + // CALL & RETURN + + OPXY(0xcd): // CALL nn + goto OP_CALL; + + + OPXY(0xd4): // CALL NC,nn + goto OP_CALL_NC; + + OPXY(0xdc): // CALL C,nn + goto OP_CALL_C; + + OPXY(0xe4): // CALL PO,nn + goto OP_CALL_PO; + + OPXY(0xec): // CALL PE,nn + goto OP_CALL_PE; + + OPXY(0xf4): // CALL P,nn + goto OP_CALL_P; + + OPXY(0xfc): // CALL M,nn + goto OP_CALL_M; + + OPXY(0xcc): // CALL Z,nn + goto OP_CALL_Z; + + OPXY(0xc4): // CALL NZ,nn + goto OP_CALL_NZ; + + + OPXY(0xc9): // RET + goto OP_RET; + + + OPXY(0xd0): // RET NC + goto OP_RET_NC; + + OPXY(0xd8): // RET C + goto OP_RET_C; + + OPXY(0xe0): // RET PO + goto OP_RET_PO; + + OPXY(0xe8): // RET PE + goto OP_RET_PE; + + OPXY(0xf0): // RET P + goto OP_RET_P; + + OPXY(0xf8): // RET M + goto OP_RET_M; + + OPXY(0xc0): // RET NZ + goto OP_RET_NZ; + + OPXY(0xc8): // RET Z + goto OP_RET_Z; + + + OPXY(0xc7): // RST 0 + OPXY(0xcf): // RST 1 + OPXY(0xd7): // RST 2 + OPXY(0xdf): // RST 3 + OPXY(0xe7): // RST 4 + OPXY(0xef): // RST 5 + OPXY(0xf7): // RST 6 + OPXY(0xff): // RST 7 + goto OP_RST; + + + // INPUT & OUTPUT + + OPXY(0xd3): // OUT (n),A + goto OP_OUT_mN_A; + + OPXY(0xdb): // IN A,(n) + goto OP_IN_A_mN; + + + // PREFIXE + + OPXY(0xcb): // XYCB PREFIXE + { + u32 adr; + u32 src; + u32 res; + + { s8 t; FETCH_BYTE_S(t); adr = data->W + t; } + FETCH_BYTE(Opcode); + #include "cz80_opXYCB.inc" + } + + OPXY(0xed): // ED PREFIXE + goto ED_PREFIXE; + + OPXY(0xdd): // DD PREFIXE (IX) + goto DD_PREFIXE; + + OPXY(0xfd): // FD PREFIXE (IY) + goto FD_PREFIXE; + +#if CZ80_USE_JUMPTABLE +#else +} +#endif diff --git a/cz80_opXYCB.inc b/cz80_opXYCB.inc new file mode 100644 index 0000000..44d375c --- /dev/null +++ b/cz80_opXYCB.inc @@ -0,0 +1,515 @@ +/********************************************************************************/ +/* */ +/* CZ80 XYCB opcode include source file */ +/* C Z80 emulator version 0.92 */ +/* Copyright 2004-2005 Stéphane Dallongeville */ +/* */ +/********************************************************************************/ + +#if CZ80_USE_JUMPTABLE + goto *JumpTableXYCB[Opcode]; +#else +switch (Opcode) +{ +#endif + + OPXYCB(0x00): // RLC (Ix+d), B + OPXYCB(0x01): // RLC (Ix+d), C + OPXYCB(0x02): // RLC (Ix+d), D + OPXYCB(0x03): // RLC (Ix+d), E + OPXYCB(0x04): // RLC (Ix+d), H + OPXYCB(0x05): // RLC (Ix+d), L + OPXYCB(0x07): // RLC (Ix+d), A +#if CZ80_EXACT + PRE_IO + READ_BYTE(adr, src) + res = ((src << 1) | (src >> 7)) & 0xFF; + zR8(Opcode) = res; + zF = SZXYP[res] | (src >> 7); + WRITE_BYTE(adr, res) + POST_IO + RET(15 + 4) +#endif + + OPXYCB(0x06): // RLC (Ix+d) + PRE_IO + READ_BYTE(adr, src) + res = ((src << 1) | (src >> 7)) & 0xFF; + zF = SZXYP[res] | (src >> 7); + WRITE_BYTE(adr, res) + POST_IO + RET(15 + 4) + + + OPXYCB(0x08): // RRC (Ix+d), B + OPXYCB(0x09): // RRC (Ix+d), C + OPXYCB(0x0a): // RRC (Ix+d), D + OPXYCB(0x0b): // RRC (Ix+d), E + OPXYCB(0x0c): // RRC (Ix+d), H + OPXYCB(0x0d): // RRC (Ix+d), L + OPXYCB(0x0f): // RRC (Ix+d), A +#if CZ80_EXACT + PRE_IO + READ_BYTE(adr, src) + res = ((src >> 1) | (src << 7)) & 0xFF; + zR8(Opcode & 7) = res; + zF = SZXYP[res] | (src & CZ80_CF); + WRITE_BYTE(adr, res) + POST_IO + RET(15 + 4) +#endif + + OPXYCB(0x0e): // RRC (Ix+d) + PRE_IO + READ_BYTE(adr, src) + res = ((src >> 1) | (src << 7)) & 0xFF; + zF = SZXYP[res] | (src & CZ80_CF); + WRITE_BYTE(adr, res) + POST_IO + RET(15 + 4) + + + OPXYCB(0x10): // RL (Ix+d), B + OPXYCB(0x11): // RL (Ix+d), C + OPXYCB(0x12): // RL (Ix+d), D + OPXYCB(0x13): // RL (Ix+d), E + OPXYCB(0x14): // RL (Ix+d), H + OPXYCB(0x15): // RL (Ix+d), L + OPXYCB(0x17): // RL (Ix+d), A +#if CZ80_EXACT + PRE_IO + READ_BYTE(adr, src) + res = ((src << 1) | (zF & CZ80_CF)) & 0xFF; + zR8(Opcode & 7) = res; + zF = SZXYP[res] | (src >> 7); + WRITE_BYTE(adr, res) + POST_IO + RET(15 + 4) +#endif + + OPXYCB(0x16): // RL (Ix+d) + PRE_IO + READ_BYTE(adr, src) + res = ((src << 1) | (zF & CZ80_CF)) & 0xFF; + zF = SZXYP[res] | (src >> 7); + WRITE_BYTE(adr, res) + POST_IO + RET(15 + 4) + + + OPXYCB(0x18): // RR (Ix+d), B + OPXYCB(0x19): // RR (Ix+d), C + OPXYCB(0x1a): // RR (Ix+d), D + OPXYCB(0x1b): // RR (Ix+d), E + OPXYCB(0x1c): // RR (Ix+d), H + OPXYCB(0x1d): // RR (Ix+d), L + OPXYCB(0x1f): // RR (Ix+d), A +#if CZ80_EXACT + PRE_IO + READ_BYTE(adr, src) + res = ((src >> 1) | (zF << 7)) & 0xFF; + zR8(Opcode & 7) = res; + zF = SZXYP[res] | (src & CZ80_CF); + WRITE_BYTE(adr, res) + POST_IO + RET(15 + 4) +#endif + + OPXYCB(0x1e): // RR (Ix+d) + PRE_IO + READ_BYTE(adr, src) + res = ((src >> 1) | (zF << 7)) & 0xFF; + zF = SZXYP[res] | (src & CZ80_CF); + WRITE_BYTE(adr, res) + POST_IO + RET(15 + 4) + + + OPXYCB(0x20): // SLA (Ix+d), B + OPXYCB(0x21): // SLA (Ix+d), C + OPXYCB(0x22): // SLA (Ix+d), D + OPXYCB(0x23): // SLA (Ix+d), E + OPXYCB(0x24): // SLA (Ix+d), H + OPXYCB(0x25): // SLA (Ix+d), L + OPXYCB(0x27): // SLA (Ix+d), A +#if CZ80_EXACT + PRE_IO + READ_BYTE(adr, src) + res = (src << 1) & 0xFF; + zR8(Opcode & 7) = res; + zF = SZXYP[res] | (src >> 7); + WRITE_BYTE(adr, res) + POST_IO + RET(15 + 4) +#endif + + OPXYCB(0x26): // SLA (Ix+d) + PRE_IO + READ_BYTE(adr, src) + res = (src << 1) & 0xFF; + zF = SZXYP[res] | (src >> 7); + WRITE_BYTE(adr, res) + POST_IO + RET(15 + 4) + + + OPXYCB(0x28): // SRA (Ix+d), B + OPXYCB(0x29): // SRA (Ix+d), C + OPXYCB(0x2a): // SRA (Ix+d), D + OPXYCB(0x2b): // SRA (Ix+d), E + OPXYCB(0x2c): // SRA (Ix+d), H + OPXYCB(0x2d): // SRA (Ix+d), L + OPXYCB(0x2f): // SRA (Ix+d), A +#if CZ80_EXACT + PRE_IO + READ_BYTE(adr, src) + res = (u8)(((s8)(src)) >> 1); + zR8(Opcode & 7) = res; + zF = SZXYP[res] | (src & CZ80_CF); + WRITE_BYTE(adr, res) + POST_IO + RET(15 + 4) +#endif + + OPXYCB(0x2e): // SRA (Ix+d) + PRE_IO + READ_BYTE(adr, src) + res = (u8)(((s8)(src)) >> 1); + zF = SZXYP[res] | (src & CZ80_CF); + WRITE_BYTE(adr, res) + POST_IO + RET(15 + 4) + + + OPXYCB(0x30): // SLL (Ix+d), B + OPXYCB(0x31): // SLL (Ix+d), C + OPXYCB(0x32): // SLL (Ix+d), D + OPXYCB(0x33): // SLL (Ix+d), E + OPXYCB(0x34): // SLL (Ix+d), H + OPXYCB(0x35): // SLL (Ix+d), L + OPXYCB(0x37): // SLL (Ix+d), A +#if CZ80_EXACT + PRE_IO + READ_BYTE(adr, src) + res = ((src << 1) | 1) & 0xFF; + zR8(Opcode & 7) = res; + zF = SZXYP[res] | (src >> 7); + WRITE_BYTE(adr, res) + POST_IO + RET(15 + 4) +#endif + + OPXYCB(0x36): // SLL (Ix+d) + PRE_IO + READ_BYTE(adr, src) + res = ((src << 1) | 1) & 0xFF; + zF = SZXYP[res] | (src >> 7); + WRITE_BYTE(adr, res) + POST_IO + RET(15 + 4) + + + OPXYCB(0x38): // SRL (Ix+d), B + OPXYCB(0x39): // SRL (Ix+d), C + OPXYCB(0x3a): // SRL (Ix+d), D + OPXYCB(0x3b): // SRL (Ix+d), E + OPXYCB(0x3c): // SRL (Ix+d), H + OPXYCB(0x3d): // SRL (Ix+d), L + OPXYCB(0x3f): // SRL (Ix+d), A +#if CZ80_EXACT + PRE_IO + READ_BYTE(adr, src) + res = src >> 1; + zR8(Opcode & 7) = res; + zF = SZXYP[res] | (src & CZ80_CF); + WRITE_BYTE(adr, res) + POST_IO + RET(15 + 4) +#endif + + OPXYCB(0x3e): // SRL (Ix+d) + PRE_IO + READ_BYTE(adr, src) + res = src >> 1; + zF = SZXYP[res] | (src & CZ80_CF); + WRITE_BYTE(adr, res) + POST_IO + RET(15 + 4) + + + OPXYCB(0x40): // BIT 0,(Ix+d) + OPXYCB(0x41): // BIT 0,(Ix+d) + OPXYCB(0x42): // BIT 0,(Ix+d) + OPXYCB(0x43): // BIT 0,(Ix+d) + OPXYCB(0x44): // BIT 0,(Ix+d) + OPXYCB(0x45): // BIT 0,(Ix+d) + OPXYCB(0x47): // BIT 0,(Ix+d) + + OPXYCB(0x48): // BIT 1,(Ix+d) + OPXYCB(0x49): // BIT 1,(Ix+d) + OPXYCB(0x4a): // BIT 1,(Ix+d) + OPXYCB(0x4b): // BIT 1,(Ix+d) + OPXYCB(0x4c): // BIT 1,(Ix+d) + OPXYCB(0x4d): // BIT 1,(Ix+d) + OPXYCB(0x4f): // BIT 1,(Ix+d) + + OPXYCB(0x50): // BIT 2,(Ix+d) + OPXYCB(0x51): // BIT 2,(Ix+d) + OPXYCB(0x52): // BIT 2,(Ix+d) + OPXYCB(0x53): // BIT 2,(Ix+d) + OPXYCB(0x54): // BIT 2,(Ix+d) + OPXYCB(0x55): // BIT 2,(Ix+d) + OPXYCB(0x57): // BIT 2,(Ix+d) + + OPXYCB(0x58): // BIT 3,(Ix+d) + OPXYCB(0x59): // BIT 3,(Ix+d) + OPXYCB(0x5a): // BIT 3,(Ix+d) + OPXYCB(0x5b): // BIT 3,(Ix+d) + OPXYCB(0x5c): // BIT 3,(Ix+d) + OPXYCB(0x5d): // BIT 3,(Ix+d) + OPXYCB(0x5f): // BIT 3,(Ix+d) + + OPXYCB(0x60): // BIT 4,(Ix+d) + OPXYCB(0x61): // BIT 4,(Ix+d) + OPXYCB(0x62): // BIT 4,(Ix+d) + OPXYCB(0x63): // BIT 4,(Ix+d) + OPXYCB(0x64): // BIT 4,(Ix+d) + OPXYCB(0x65): // BIT 4,(Ix+d) + OPXYCB(0x67): // BIT 4,(Ix+d) + + OPXYCB(0x68): // BIT 5,(Ix+d) + OPXYCB(0x69): // BIT 5,(Ix+d) + OPXYCB(0x6a): // BIT 5,(Ix+d) + OPXYCB(0x6b): // BIT 5,(Ix+d) + OPXYCB(0x6c): // BIT 5,(Ix+d) + OPXYCB(0x6d): // BIT 5,(Ix+d) + OPXYCB(0x6f): // BIT 5,(Ix+d) + + OPXYCB(0x70): // BIT 6,(Ix+d) + OPXYCB(0x71): // BIT 6,(Ix+d) + OPXYCB(0x72): // BIT 6,(Ix+d) + OPXYCB(0x73): // BIT 6,(Ix+d) + OPXYCB(0x74): // BIT 6,(Ix+d) + OPXYCB(0x75): // BIT 6,(Ix+d) + OPXYCB(0x77): // BIT 6,(Ix+d) + + OPXYCB(0x78): // BIT 7,(Ix+d) + OPXYCB(0x79): // BIT 7,(Ix+d) + OPXYCB(0x7a): // BIT 7,(Ix+d) + OPXYCB(0x7b): // BIT 7,(Ix+d) + OPXYCB(0x7c): // BIT 7,(Ix+d) + OPXYCB(0x7d): // BIT 7,(Ix+d) + OPXYCB(0x7f): // BIT 7,(Ix+d) + + OPXYCB(0x46): // BIT 0,(Ix+d) + OPXYCB(0x4e): // BIT 1,(Ix+d) + OPXYCB(0x56): // BIT 2,(Ix+d) + OPXYCB(0x5e): // BIT 3,(Ix+d) + OPXYCB(0x66): // BIT 4,(Ix+d) + OPXYCB(0x6e): // BIT 5,(Ix+d) + OPXYCB(0x76): // BIT 6,(Ix+d) + OPXYCB(0x7e): // BIT 7,(Ix+d) + { + u32 bitm; + + PRE_IO + bitm = 1 << ((Opcode >> 3) & 7); + READ_BYTE(adr, src) + zF = (zF & CZ80_CF) | CZ80_HF | // C/H flag + (SZXY_BIT[src & bitm] & ~(CZ80_XF | CZ80_YF)) | // Z/V/N flag + ((adr >> 8) & (CZ80_XF | CZ80_YF)); // X/Y flag + POST_IO + RET(12 + 4) + } + + OPXYCB(0x80): // RES 0,(Ix+d),B + OPXYCB(0x81): // RES 0,(Ix+d),C + OPXYCB(0x82): // RES 0,(Ix+d),D + OPXYCB(0x83): // RES 0,(Ix+d),E + OPXYCB(0x84): // RES 0,(Ix+d),H + OPXYCB(0x85): // RES 0,(Ix+d),L + OPXYCB(0x87): // RES 0,(Ix+d),A + + OPXYCB(0x88): // RES 1,(Ix+d),B + OPXYCB(0x89): // RES 1,(Ix+d),C + OPXYCB(0x8a): // RES 1,(Ix+d),D + OPXYCB(0x8b): // RES 1,(Ix+d),E + OPXYCB(0x8c): // RES 1,(Ix+d),H + OPXYCB(0x8d): // RES 1,(Ix+d),L + OPXYCB(0x8f): // RES 1,(Ix+d),A + + OPXYCB(0x90): // RES 2,(Ix+d),B + OPXYCB(0x91): // RES 2,(Ix+d),C + OPXYCB(0x92): // RES 2,(Ix+d),D + OPXYCB(0x93): // RES 2,(Ix+d),E + OPXYCB(0x94): // RES 2,(Ix+d),H + OPXYCB(0x95): // RES 2,(Ix+d),L + OPXYCB(0x97): // RES 2,(Ix+d),A + + OPXYCB(0x98): // RES 3,(Ix+d),B + OPXYCB(0x99): // RES 3,(Ix+d),C + OPXYCB(0x9a): // RES 3,(Ix+d),D + OPXYCB(0x9b): // RES 3,(Ix+d),E + OPXYCB(0x9c): // RES 3,(Ix+d),H + OPXYCB(0x9d): // RES 3,(Ix+d),L + OPXYCB(0x9f): // RES 3,(Ix+d),A + + OPXYCB(0xa0): // RES 4,(Ix+d),B + OPXYCB(0xa1): // RES 4,(Ix+d),C + OPXYCB(0xa2): // RES 4,(Ix+d),D + OPXYCB(0xa3): // RES 4,(Ix+d),E + OPXYCB(0xa4): // RES 4,(Ix+d),H + OPXYCB(0xa5): // RES 4,(Ix+d),L + OPXYCB(0xa7): // RES 4,(Ix+d),A + + OPXYCB(0xa8): // RES 5,(Ix+d),B + OPXYCB(0xa9): // RES 5,(Ix+d),C + OPXYCB(0xaa): // RES 5,(Ix+d),D + OPXYCB(0xab): // RES 5,(Ix+d),E + OPXYCB(0xac): // RES 5,(Ix+d),H + OPXYCB(0xad): // RES 5,(Ix+d),L + OPXYCB(0xaf): // RES 5,(Ix+d),A + + OPXYCB(0xb0): // RES 6,(Ix+d),B + OPXYCB(0xb1): // RES 6,(Ix+d),C + OPXYCB(0xb2): // RES 6,(Ix+d),D + OPXYCB(0xb3): // RES 6,(Ix+d),E + OPXYCB(0xb4): // RES 6,(Ix+d),H + OPXYCB(0xb5): // RES 6,(Ix+d),L + OPXYCB(0xb7): // RES 6,(Ix+d),A + + OPXYCB(0xb8): // RES 7,(Ix+d),B + OPXYCB(0xb9): // RES 7,(Ix+d),C + OPXYCB(0xba): // RES 7,(Ix+d),D + OPXYCB(0xbb): // RES 7,(Ix+d),E + OPXYCB(0xbc): // RES 7,(Ix+d),H + OPXYCB(0xbd): // RES 7,(Ix+d),L + OPXYCB(0xbf): // RES 7,(Ix+d),A +#if CZ80_EXACT + PRE_IO + READ_BYTE(adr, res) + res &= ~(1 << ((Opcode >> 3) & 7)); + zR8(Opcode & 7) = res; + WRITE_BYTE(adr, res) + POST_IO + RET(15 + 4) +#endif + + OPXYCB(0x86): // RES 0,(Ix+d) + OPXYCB(0x8e): // RES 1,(Ix+d) + OPXYCB(0x96): // RES 2,(Ix+d) + OPXYCB(0x9e): // RES 3,(Ix+d) + OPXYCB(0xa6): // RES 4,(Ix+d) + OPXYCB(0xae): // RES 5,(Ix+d) + OPXYCB(0xb6): // RES 6,(Ix+d) + OPXYCB(0xbe): // RES 7,(Ix+d) + { + u32 bitm; + + PRE_IO + bitm = ~(1 << ((Opcode >> 3) & 7)); + READ_BYTE(adr, res) + res &= bitm; + WRITE_BYTE(adr, res) + POST_IO + RET(15 + 4) + } + + + OPXYCB(0xc0): // SET 0,(Ix+d),B + OPXYCB(0xc1): // SET 0,(Ix+d),C + OPXYCB(0xc2): // SET 0,(Ix+d),D + OPXYCB(0xc3): // SET 0,(Ix+d),E + OPXYCB(0xc4): // SET 0,(Ix+d),H + OPXYCB(0xc5): // SET 0,(Ix+d),L + OPXYCB(0xc7): // SET 0,(Ix+d),A + + OPXYCB(0xc8): // SET 1,(Ix+d),B + OPXYCB(0xc9): // SET 1,(Ix+d),C + OPXYCB(0xca): // SET 1,(Ix+d),D + OPXYCB(0xcb): // SET 1,(Ix+d),E + OPXYCB(0xcc): // SET 1,(Ix+d),H + OPXYCB(0xcd): // SET 1,(Ix+d),L + OPXYCB(0xcf): // SET 1,(Ix+d),A + + OPXYCB(0xd0): // SET 2,(Ix+d),B + OPXYCB(0xd1): // SET 2,(Ix+d),C + OPXYCB(0xd2): // SET 2,(Ix+d),D + OPXYCB(0xd3): // SET 2,(Ix+d),E + OPXYCB(0xd4): // SET 2,(Ix+d),H + OPXYCB(0xd5): // SET 2,(Ix+d),L + OPXYCB(0xd7): // SET 2,(Ix+d),A + + OPXYCB(0xd8): // SET 3,(Ix+d),B + OPXYCB(0xd9): // SET 3,(Ix+d),C + OPXYCB(0xda): // SET 3,(Ix+d),D + OPXYCB(0xdb): // SET 3,(Ix+d),E + OPXYCB(0xdc): // SET 3,(Ix+d),H + OPXYCB(0xdd): // SET 3,(Ix+d),L + OPXYCB(0xdf): // SET 3,(Ix+d),A + + OPXYCB(0xe0): // SET 4,(Ix+d),B + OPXYCB(0xe1): // SET 4,(Ix+d),C + OPXYCB(0xe2): // SET 4,(Ix+d),D + OPXYCB(0xe3): // SET 4,(Ix+d),E + OPXYCB(0xe4): // SET 4,(Ix+d),H + OPXYCB(0xe5): // SET 4,(Ix+d),L + OPXYCB(0xe7): // SET 4,(Ix+d),A + + OPXYCB(0xe8): // SET 5,(Ix+d),B + OPXYCB(0xe9): // SET 5,(Ix+d),C + OPXYCB(0xea): // SET 5,(Ix+d),D + OPXYCB(0xeb): // SET 5,(Ix+d),E + OPXYCB(0xec): // SET 5,(Ix+d),H + OPXYCB(0xed): // SET 5,(Ix+d),L + OPXYCB(0xef): // SET 5,(Ix+d),A + + OPXYCB(0xf0): // SET 6,(Ix+d),B + OPXYCB(0xf1): // SET 6,(Ix+d),C + OPXYCB(0xf2): // SET 6,(Ix+d),D + OPXYCB(0xf3): // SET 6,(Ix+d),E + OPXYCB(0xf4): // SET 6,(Ix+d),H + OPXYCB(0xf5): // SET 6,(Ix+d),L + OPXYCB(0xf7): // SET 6,(Ix+d),A + + OPXYCB(0xf8): // SET 7,(Ix+d),B + OPXYCB(0xf9): // SET 7,(Ix+d),C + OPXYCB(0xfa): // SET 7,(Ix+d),D + OPXYCB(0xfb): // SET 7,(Ix+d),E + OPXYCB(0xfc): // SET 7,(Ix+d),H + OPXYCB(0xfd): // SET 7,(Ix+d),L + OPXYCB(0xff): // SET 7,(Ix+d),A +#if CZ80_EXACT + PRE_IO + READ_BYTE(adr, res) + res |= 1 << ((Opcode >> 3) & 7); + zR8(Opcode & 7) = res; + WRITE_BYTE(adr, res) + POST_IO + RET(15 + 4) +#endif + + OPXYCB(0xc6): // SET 0,(Ix+d) + OPXYCB(0xce): // SET 1,(Ix+d) + OPXYCB(0xd6): // SET 2,(Ix+d) + OPXYCB(0xde): // SET 3,(Ix+d) + OPXYCB(0xe6): // SET 4,(Ix+d) + OPXYCB(0xee): // SET 5,(Ix+d) + OPXYCB(0xf6): // SET 6,(Ix+d) + OPXYCB(0xfe): // SET 7,(Ix+d) + { + u32 bitm; + + PRE_IO + bitm = 1 << ((Opcode >> 3) & 7); + READ_BYTE(adr, res) + res |= bitm; + WRITE_BYTE(adr, res) + POST_IO + RET(15 + 4) + } + +#if CZ80_USE_JUMPTABLE +#else +} +#endif diff --git a/cz80_support.cpp b/cz80_support.cpp new file mode 100644 index 0000000..32bbb0a --- /dev/null +++ b/cz80_support.cpp @@ -0,0 +1,94 @@ +#include +#include +#include + +//#include "driver.h" +//#include "cpuintrf.h" +#include "memory.h" +//#include "z80/z80.h" +#include "cz80.h" + +// #include "hack.h" + +unsigned char *mame4all_cz80_rom = &mainram[0x3000]; +unsigned char *mame4all_cz80_ram = &mainram[0x3000]; + +cz80_struc RACE_cz80_struc_alloc; +cz80_struc *RACE_cz80_struc=&RACE_cz80_struc_alloc; + +#include "memory.h" + +void Z80_Init() +{ + Cz80_Init(RACE_cz80_struc); +} + +void Z80_Reset() +{ + //unsigned *ctx=(unsigned *)(((unsigned)cpu_getcontext(cpu_getactivecpu()))); + + //RACE_cz80_struc=(cz80_struc *)&ctx[4]; + + //Cz80_Init(RACE_cz80_struc); + Cz80_Reset(RACE_cz80_struc); + + //ctx[0]=(unsigned)Cz80_Get_PC(RACE_cz80_struc); +} + +/*void Z80_GetRegs(Z80_Regs *Regs) +{ + unsigned *ctx=(unsigned *)Regs; + ctx[0] = (unsigned)Cz80_Get_PC(RACE_cz80_struc); +}*/ + +/*void Z80_SetRegs (Z80_Regs *Regs) +{ + unsigned *ctx=(unsigned *)Regs; + RACE_cz80_struc=(cz80_struc *)&ctx[4]; + Cz80_Set_PC(RACE_cz80_struc,ctx[0]); +}*/ + +unsigned Z80_GetPC (void) +{ + return Cz80_Get_PC(RACE_cz80_struc); +} + +void Z80_Cause_Interrupt(int type) +{ + if (type == Z80_NMI_INT) + Cz80_Set_NMI(RACE_cz80_struc); + else if (type >= 0) + Cz80_Set_IRQ(RACE_cz80_struc, type & 0xff); +} + +void Z80_Clear_Pending_Interrupts(void) +{ + Cz80_Clear_IRQ(RACE_cz80_struc); + Cz80_Clear_NMI(RACE_cz80_struc); +} + + +int Z80_Execute(int cycles) +{ + return Cz80_Exec(RACE_cz80_struc,cycles); +} + +int cpu_readmem16(int address) +{ + return z80ngpMemReadB(address); +} + +void cpu_writemem16(int address,int data) +{ + DrZ80ngpMemWriteB(data,address); +} + +int cpu_readport(int Port) +{ + return DrZ80ngpPortReadB(Port); +} + +void cpu_writeport(int Port,int Value) +{ + DrZ80ngpPortWriteB(Port,Value); +} diff --git a/cz80_support.h b/cz80_support.h new file mode 100644 index 0000000..e0f4574 --- /dev/null +++ b/cz80_support.h @@ -0,0 +1,48 @@ +#ifndef Z80_H +#define Z80_H + +#ifdef __cplusplus +extern "C" { +#endif + + +//#include "osd_cpu.h" +//#include "cpuintrf.h" +//#include "DrZ80.h" + +/* daisy-chain link */ +typedef struct { + void (*reset)(int); /* reset callback */ + int (*interrupt_entry)(int); /* entry callback */ + void (*interrupt_reti)(int); /* reti callback */ + int irq_param; /* callback paramater */ +} Z80_DaisyChain; + +#define Z80_MAXDAISY 4 /* maximum of daisy chan device */ + +#define Z80_INT_REQ 0x01 /* interrupt request mask */ +#define Z80_INT_IEO 0x02 /* interrupt disable mask(IEO) */ + +#define Z80_VECTOR(device,state) (((device)<<8)|(state)) + + +#define Z80_IGNORE_INT -1 /* Ignore interrupt */ +#define Z80_NMI_INT -2 /* Execute NMI */ +#define Z80_IRQ_INT -1000 /* Execute IRQ */ + +extern unsigned Z80_GetPC (void); /* Get program counter */ +extern int Z80_GetPreviousPC (void); +extern void Z80_Init(void); +extern void Z80_Reset(void); +extern int Z80_Execute(int cycles); /* Execute cycles T-States - returns number of cycles actually run */ +extern int Z80_Interrupt(void); +extern void Z80_Cause_Interrupt(int type); +extern void Z80_Clear_Pending_Interrupts(void); +extern void Interrupt(void); /* required for DrZ80 int hack */ + +#ifdef __cplusplus +} /* End of extern "C" */ +#endif + +#endif + diff --git a/cz80exec.inc b/cz80exec.inc new file mode 100644 index 0000000..459ca5c --- /dev/null +++ b/cz80exec.inc @@ -0,0 +1,124 @@ +/********************************************************************************/ +/* */ +/* CZ80 exec include source file */ +/* C Z80 emulator version 0.92 */ +/* Copyright 2004-2005 Stéphane Dallongeville */ +/* */ +/********************************************************************************/ + +s32 Z80_ICount; + +s32 CZ80_FASTCALL Cz80_Exec(cz80_struc *cpu, s32 cycles) +{ +#if CZ80_USE_JUMPTABLE + #include "cz80jmp.inc" +#endif + +#if __x86__ + register cz80_struc *CPU asm ("ebx"); + register u8 *PC asm ("esi"); + register u32 Opcode asm ("edx"); +#else + cz80_struc *CPU; + u8 *PC; + u32 Opcode; +#endif + + CPU = cpu; + PC = CPU->PC; + + if (CPU->Status & (CZ80_RUNNING | CZ80_DISABLE | CZ80_FAULTED)) + { + return (CPU->Status | 0x80000000); + } + + CPU->CycleToDo = Z80_ICount = cycles; + CPU->CycleSup = 0; + CPU->Status |= CZ80_RUNNING; + +Cz80_Check_Int: + // check for interrupt + if (CPU->Status & (zIFF1 | CZ80_HAS_NMI)) + { + u32 newPC; + + if (CPU->Status & CZ80_HAS_NMI) + { + // NMI + CPU->Status &= ~(CZ80_HALTED | CZ80_HAS_NMI); + zIFF1 = 0; + newPC = 0x66; + } + else + { + // INT + CPU->Status &= ~(CZ80_HALTED | CZ80_HAS_INT); + zIFF= 0; + + // IM = 1 + if (zIM == 1) newPC = 0x38; + else + { + u32 adr; + + Opcode = CPU->IntVect & 0xFF; + // IM = 0 + if (zIM == 0) + goto Cz80_Exec_direct; + // IM = 2 + adr = Opcode | (zI << 8); + READ_WORD(adr, newPC) +#if CZ80_IRQ_CYCLES + Z80_ICount -= 8; +#endif + } + } + + // set new PC + { + u32 src = zRealPC; + + PUSH_16(src) + SET_PC(newPC); +#if CZ80_IRQ_CYCLES + Z80_ICount -= 11; +#endif + } + } + + // if some cycles left + if ((Z80_ICount += CPU->CycleSup) > 0) + { + CPU->CycleSup = 0; + if (!(CPU->Status & CZ80_HALTED)) goto Cz80_Exec; + + // CPU halted + Z80_ICount = 0; + } + +Cz80_Exec_Really_End: + // no more cycles, end execution + CPU->Status &= ~CZ80_RUNNING; + CPU->PC = PC; + + // number of executed cycles + Z80_ICount = CPU->CycleToDo - Z80_ICount; + + // update R register + zR = (zR + (Z80_ICount >> 2)) & 0x7F; + + return Z80_ICount; + +#if CZ80_SIZE_OPT +Cz80_Exec_Check: + if (Z80_ICount <= 0) goto Cz80_Check_Int; +#endif + +Cz80_Exec: + { + Opcode = REAL_FETCH_BYTE; +Cz80_Exec_direct: + union16 *data = pzHL; + #include "cz80_op.inc" + } +} diff --git a/cz80jmp.inc b/cz80jmp.inc new file mode 100644 index 0000000..9f4801b --- /dev/null +++ b/cz80jmp.inc @@ -0,0 +1,418 @@ +/********************************************************************************/ +/* */ +/* CZ80 JumpTable include source file */ +/* C Z80 emulator version 0.91 */ +/* Copyright 2004-2005 Stéphane Dallongeville */ +/* */ +/********************************************************************************/ + +static const void *JumpTable[0x100] = { + &&OP0x00, &&OP0x01, &&OP0x02, &&OP0x03, + &&OP0x04, &&OP0x05, &&OP0x06, &&OP0x07, + &&OP0x08, &&OP0x09, &&OP0x0a, &&OP0x0b, + &&OP0x0c, &&OP0x0d, &&OP0x0e, &&OP0x0f, + + &&OP0x10, &&OP0x11, &&OP0x12, &&OP0x13, + &&OP0x14, &&OP0x15, &&OP0x16, &&OP0x17, + &&OP0x18, &&OP0x19, &&OP0x1a, &&OP0x1b, + &&OP0x1c, &&OP0x1d, &&OP0x1e, &&OP0x1f, + + &&OP0x20, &&OP0x21, &&OP0x22, &&OP0x23, + &&OP0x24, &&OP0x25, &&OP0x26, &&OP0x27, + &&OP0x28, &&OP0x29, &&OP0x2a, &&OP0x2b, + &&OP0x2c, &&OP0x2d, &&OP0x2e, &&OP0x2f, + + &&OP0x30, &&OP0x31, &&OP0x32, &&OP0x33, + &&OP0x34, &&OP0x35, &&OP0x36, &&OP0x37, + &&OP0x38, &&OP0x39, &&OP0x3a, &&OP0x3b, + &&OP0x3c, &&OP0x3d, &&OP0x3e, &&OP0x3f, + + &&OP0x40, &&OP0x41, &&OP0x42, &&OP0x43, + &&OP0x44, &&OP0x45, &&OP0x46, &&OP0x47, + &&OP0x48, &&OP0x49, &&OP0x4a, &&OP0x4b, + &&OP0x4c, &&OP0x4d, &&OP0x4e, &&OP0x4f, + + &&OP0x50, &&OP0x51, &&OP0x52, &&OP0x53, + &&OP0x54, &&OP0x55, &&OP0x56, &&OP0x57, + &&OP0x58, &&OP0x59, &&OP0x5a, &&OP0x5b, + &&OP0x5c, &&OP0x5d, &&OP0x5e, &&OP0x5f, + + &&OP0x60, &&OP0x61, &&OP0x62, &&OP0x63, + &&OP0x64, &&OP0x65, &&OP0x66, &&OP0x67, + &&OP0x68, &&OP0x69, &&OP0x6a, &&OP0x6b, + &&OP0x6c, &&OP0x6d, &&OP0x6e, &&OP0x6f, + + &&OP0x70, &&OP0x71, &&OP0x72, &&OP0x73, + &&OP0x74, &&OP0x75, &&OP0x76, &&OP0x77, + &&OP0x78, &&OP0x79, &&OP0x7a, &&OP0x7b, + &&OP0x7c, &&OP0x7d, &&OP0x7e, &&OP0x7f, + + &&OP0x80, &&OP0x81, &&OP0x82, &&OP0x83, + &&OP0x84, &&OP0x85, &&OP0x86, &&OP0x87, + &&OP0x88, &&OP0x89, &&OP0x8a, &&OP0x8b, + &&OP0x8c, &&OP0x8d, &&OP0x8e, &&OP0x8f, + + &&OP0x90, &&OP0x91, &&OP0x92, &&OP0x93, + &&OP0x94, &&OP0x95, &&OP0x96, &&OP0x97, + &&OP0x98, &&OP0x99, &&OP0x9a, &&OP0x9b, + &&OP0x9c, &&OP0x9d, &&OP0x9e, &&OP0x9f, + + &&OP0xa0, &&OP0xa1, &&OP0xa2, &&OP0xa3, + &&OP0xa4, &&OP0xa5, &&OP0xa6, &&OP0xa7, + &&OP0xa8, &&OP0xa9, &&OP0xaa, &&OP0xab, + &&OP0xac, &&OP0xad, &&OP0xae, &&OP0xaf, + + &&OP0xb0, &&OP0xb1, &&OP0xb2, &&OP0xb3, + &&OP0xb4, &&OP0xb5, &&OP0xb6, &&OP0xb7, + &&OP0xb8, &&OP0xb9, &&OP0xba, &&OP0xbb, + &&OP0xbc, &&OP0xbd, &&OP0xbe, &&OP0xbf, + + &&OP0xc0, &&OP0xc1, &&OP0xc2, &&OP0xc3, + &&OP0xc4, &&OP0xc5, &&OP0xc6, &&OP0xc7, + &&OP0xc8, &&OP0xc9, &&OP0xca, &&OP0xcb, + &&OP0xcc, &&OP0xcd, &&OP0xce, &&OP0xcf, + + &&OP0xd0, &&OP0xd1, &&OP0xd2, &&OP0xd3, + &&OP0xd4, &&OP0xd5, &&OP0xd6, &&OP0xd7, + &&OP0xd8, &&OP0xd9, &&OP0xda, &&OP0xdb, + &&OP0xdc, &&OP0xdd, &&OP0xde, &&OP0xdf, + + &&OP0xe0, &&OP0xe1, &&OP0xe2, &&OP0xe3, + &&OP0xe4, &&OP0xe5, &&OP0xe6, &&OP0xe7, + &&OP0xe8, &&OP0xe9, &&OP0xea, &&OP0xeb, + &&OP0xec, &&OP0xed, &&OP0xee, &&OP0xef, + + &&OP0xf0, &&OP0xf1, &&OP0xf2, &&OP0xf3, + &&OP0xf4, &&OP0xf5, &&OP0xf6, &&OP0xf7, + &&OP0xf8, &&OP0xf9, &&OP0xfa, &&OP0xfb, + &&OP0xfc, &&OP0xfd, &&OP0xfe, &&OP0xff +}; + +static const void *JumpTableCB[0x100] = { + &&OPCB0x00, &&OPCB0x01, &&OPCB0x02, &&OPCB0x03, + &&OPCB0x04, &&OPCB0x05, &&OPCB0x06, &&OPCB0x07, + &&OPCB0x08, &&OPCB0x09, &&OPCB0x0a, &&OPCB0x0b, + &&OPCB0x0c, &&OPCB0x0d, &&OPCB0x0e, &&OPCB0x0f, + + &&OPCB0x10, &&OPCB0x11, &&OPCB0x12, &&OPCB0x13, + &&OPCB0x14, &&OPCB0x15, &&OPCB0x16, &&OPCB0x17, + &&OPCB0x18, &&OPCB0x19, &&OPCB0x1a, &&OPCB0x1b, + &&OPCB0x1c, &&OPCB0x1d, &&OPCB0x1e, &&OPCB0x1f, + + &&OPCB0x20, &&OPCB0x21, &&OPCB0x22, &&OPCB0x23, + &&OPCB0x24, &&OPCB0x25, &&OPCB0x26, &&OPCB0x27, + &&OPCB0x28, &&OPCB0x29, &&OPCB0x2a, &&OPCB0x2b, + &&OPCB0x2c, &&OPCB0x2d, &&OPCB0x2e, &&OPCB0x2f, + + &&OPCB0x30, &&OPCB0x31, &&OPCB0x32, &&OPCB0x33, + &&OPCB0x34, &&OPCB0x35, &&OPCB0x36, &&OPCB0x37, + &&OPCB0x38, &&OPCB0x39, &&OPCB0x3a, &&OPCB0x3b, + &&OPCB0x3c, &&OPCB0x3d, &&OPCB0x3e, &&OPCB0x3f, + + &&OPCB0x40, &&OPCB0x41, &&OPCB0x42, &&OPCB0x43, + &&OPCB0x44, &&OPCB0x45, &&OPCB0x46, &&OPCB0x47, + &&OPCB0x48, &&OPCB0x49, &&OPCB0x4a, &&OPCB0x4b, + &&OPCB0x4c, &&OPCB0x4d, &&OPCB0x4e, &&OPCB0x4f, + + &&OPCB0x50, &&OPCB0x51, &&OPCB0x52, &&OPCB0x53, + &&OPCB0x54, &&OPCB0x55, &&OPCB0x56, &&OPCB0x57, + &&OPCB0x58, &&OPCB0x59, &&OPCB0x5a, &&OPCB0x5b, + &&OPCB0x5c, &&OPCB0x5d, &&OPCB0x5e, &&OPCB0x5f, + + &&OPCB0x60, &&OPCB0x61, &&OPCB0x62, &&OPCB0x63, + &&OPCB0x64, &&OPCB0x65, &&OPCB0x66, &&OPCB0x67, + &&OPCB0x68, &&OPCB0x69, &&OPCB0x6a, &&OPCB0x6b, + &&OPCB0x6c, &&OPCB0x6d, &&OPCB0x6e, &&OPCB0x6f, + + &&OPCB0x70, &&OPCB0x71, &&OPCB0x72, &&OPCB0x73, + &&OPCB0x74, &&OPCB0x75, &&OPCB0x76, &&OPCB0x77, + &&OPCB0x78, &&OPCB0x79, &&OPCB0x7a, &&OPCB0x7b, + &&OPCB0x7c, &&OPCB0x7d, &&OPCB0x7e, &&OPCB0x7f, + + &&OPCB0x80, &&OPCB0x81, &&OPCB0x82, &&OPCB0x83, + &&OPCB0x84, &&OPCB0x85, &&OPCB0x86, &&OPCB0x87, + &&OPCB0x88, &&OPCB0x89, &&OPCB0x8a, &&OPCB0x8b, + &&OPCB0x8c, &&OPCB0x8d, &&OPCB0x8e, &&OPCB0x8f, + + &&OPCB0x90, &&OPCB0x91, &&OPCB0x92, &&OPCB0x93, + &&OPCB0x94, &&OPCB0x95, &&OPCB0x96, &&OPCB0x97, + &&OPCB0x98, &&OPCB0x99, &&OPCB0x9a, &&OPCB0x9b, + &&OPCB0x9c, &&OPCB0x9d, &&OPCB0x9e, &&OPCB0x9f, + + &&OPCB0xa0, &&OPCB0xa1, &&OPCB0xa2, &&OPCB0xa3, + &&OPCB0xa4, &&OPCB0xa5, &&OPCB0xa6, &&OPCB0xa7, + &&OPCB0xa8, &&OPCB0xa9, &&OPCB0xaa, &&OPCB0xab, + &&OPCB0xac, &&OPCB0xad, &&OPCB0xae, &&OPCB0xaf, + + &&OPCB0xb0, &&OPCB0xb1, &&OPCB0xb2, &&OPCB0xb3, + &&OPCB0xb4, &&OPCB0xb5, &&OPCB0xb6, &&OPCB0xb7, + &&OPCB0xb8, &&OPCB0xb9, &&OPCB0xba, &&OPCB0xbb, + &&OPCB0xbc, &&OPCB0xbd, &&OPCB0xbe, &&OPCB0xbf, + + &&OPCB0xc0, &&OPCB0xc1, &&OPCB0xc2, &&OPCB0xc3, + &&OPCB0xc4, &&OPCB0xc5, &&OPCB0xc6, &&OPCB0xc7, + &&OPCB0xc8, &&OPCB0xc9, &&OPCB0xca, &&OPCB0xcb, + &&OPCB0xcc, &&OPCB0xcd, &&OPCB0xce, &&OPCB0xcf, + + &&OPCB0xd0, &&OPCB0xd1, &&OPCB0xd2, &&OPCB0xd3, + &&OPCB0xd4, &&OPCB0xd5, &&OPCB0xd6, &&OPCB0xd7, + &&OPCB0xd8, &&OPCB0xd9, &&OPCB0xda, &&OPCB0xdb, + &&OPCB0xdc, &&OPCB0xdd, &&OPCB0xde, &&OPCB0xdf, + + &&OPCB0xe0, &&OPCB0xe1, &&OPCB0xe2, &&OPCB0xe3, + &&OPCB0xe4, &&OPCB0xe5, &&OPCB0xe6, &&OPCB0xe7, + &&OPCB0xe8, &&OPCB0xe9, &&OPCB0xea, &&OPCB0xeb, + &&OPCB0xec, &&OPCB0xed, &&OPCB0xee, &&OPCB0xef, + + &&OPCB0xf0, &&OPCB0xf1, &&OPCB0xf2, &&OPCB0xf3, + &&OPCB0xf4, &&OPCB0xf5, &&OPCB0xf6, &&OPCB0xf7, + &&OPCB0xf8, &&OPCB0xf9, &&OPCB0xfa, &&OPCB0xfb, + &&OPCB0xfc, &&OPCB0xfd, &&OPCB0xfe, &&OPCB0xff +}; + +static const void *JumpTableED[0x100] = { + &&OPED0x00, &&OPED0x01, &&OPED0x02, &&OPED0x03, + &&OPED0x04, &&OPED0x05, &&OPED0x06, &&OPED0x07, + &&OPED0x08, &&OPED0x09, &&OPED0x0a, &&OPED0x0b, + &&OPED0x0c, &&OPED0x0d, &&OPED0x0e, &&OPED0x0f, + + &&OPED0x10, &&OPED0x11, &&OPED0x12, &&OPED0x13, + &&OPED0x14, &&OPED0x15, &&OPED0x16, &&OPED0x17, + &&OPED0x18, &&OPED0x19, &&OPED0x1a, &&OPED0x1b, + &&OPED0x1c, &&OPED0x1d, &&OPED0x1e, &&OPED0x1f, + + &&OPED0x20, &&OPED0x21, &&OPED0x22, &&OPED0x23, + &&OPED0x24, &&OPED0x25, &&OPED0x26, &&OPED0x27, + &&OPED0x28, &&OPED0x29, &&OPED0x2a, &&OPED0x2b, + &&OPED0x2c, &&OPED0x2d, &&OPED0x2e, &&OPED0x2f, + + &&OPED0x30, &&OPED0x31, &&OPED0x32, &&OPED0x33, + &&OPED0x34, &&OPED0x35, &&OPED0x36, &&OPED0x37, + &&OPED0x38, &&OPED0x39, &&OPED0x3a, &&OPED0x3b, + &&OPED0x3c, &&OPED0x3d, &&OPED0x3e, &&OPED0x3f, + + &&OPED0x40, &&OPED0x41, &&OPED0x42, &&OPED0x43, + &&OPED0x44, &&OPED0x45, &&OPED0x46, &&OPED0x47, + &&OPED0x48, &&OPED0x49, &&OPED0x4a, &&OPED0x4b, + &&OPED0x4c, &&OPED0x4d, &&OPED0x4e, &&OPED0x4f, + + &&OPED0x50, &&OPED0x51, &&OPED0x52, &&OPED0x53, + &&OPED0x54, &&OPED0x55, &&OPED0x56, &&OPED0x57, + &&OPED0x58, &&OPED0x59, &&OPED0x5a, &&OPED0x5b, + &&OPED0x5c, &&OPED0x5d, &&OPED0x5e, &&OPED0x5f, + + &&OPED0x60, &&OPED0x61, &&OPED0x62, &&OPED0x63, + &&OPED0x64, &&OPED0x65, &&OPED0x66, &&OPED0x67, + &&OPED0x68, &&OPED0x69, &&OPED0x6a, &&OPED0x6b, + &&OPED0x6c, &&OPED0x6d, &&OPED0x6e, &&OPED0x6f, + + &&OPED0x70, &&OPED0x71, &&OPED0x72, &&OPED0x73, + &&OPED0x74, &&OPED0x75, &&OPED0x76, &&OPED0x77, + &&OPED0x78, &&OPED0x79, &&OPED0x7a, &&OPED0x7b, + &&OPED0x7c, &&OPED0x7d, &&OPED0x7e, &&OPED0x7f, + + &&OPED0x80, &&OPED0x81, &&OPED0x82, &&OPED0x83, + &&OPED0x84, &&OPED0x85, &&OPED0x86, &&OPED0x87, + &&OPED0x88, &&OPED0x89, &&OPED0x8a, &&OPED0x8b, + &&OPED0x8c, &&OPED0x8d, &&OPED0x8e, &&OPED0x8f, + + &&OPED0x90, &&OPED0x91, &&OPED0x92, &&OPED0x93, + &&OPED0x94, &&OPED0x95, &&OPED0x96, &&OPED0x97, + &&OPED0x98, &&OPED0x99, &&OPED0x9a, &&OPED0x9b, + &&OPED0x9c, &&OPED0x9d, &&OPED0x9e, &&OPED0x9f, + + &&OPED0xa0, &&OPED0xa1, &&OPED0xa2, &&OPED0xa3, + &&OPED0xa4, &&OPED0xa5, &&OPED0xa6, &&OPED0xa7, + &&OPED0xa8, &&OPED0xa9, &&OPED0xaa, &&OPED0xab, + &&OPED0xac, &&OPED0xad, &&OPED0xae, &&OPED0xaf, + + &&OPED0xb0, &&OPED0xb1, &&OPED0xb2, &&OPED0xb3, + &&OPED0xb4, &&OPED0xb5, &&OPED0xb6, &&OPED0xb7, + &&OPED0xb8, &&OPED0xb9, &&OPED0xba, &&OPED0xbb, + &&OPED0xbc, &&OPED0xbd, &&OPED0xbe, &&OPED0xbf, + + &&OPED0xc0, &&OPED0xc1, &&OPED0xc2, &&OPED0xc3, + &&OPED0xc4, &&OPED0xc5, &&OPED0xc6, &&OPED0xc7, + &&OPED0xc8, &&OPED0xc9, &&OPED0xca, &&OPED0xcb, + &&OPED0xcc, &&OPED0xcd, &&OPED0xce, &&OPED0xcf, + + &&OPED0xd0, &&OPED0xd1, &&OPED0xd2, &&OPED0xd3, + &&OPED0xd4, &&OPED0xd5, &&OPED0xd6, &&OPED0xd7, + &&OPED0xd8, &&OPED0xd9, &&OPED0xda, &&OPED0xdb, + &&OPED0xdc, &&OPED0xdd, &&OPED0xde, &&OPED0xdf, + + &&OPED0xe0, &&OPED0xe1, &&OPED0xe2, &&OPED0xe3, + &&OPED0xe4, &&OPED0xe5, &&OPED0xe6, &&OPED0xe7, + &&OPED0xe8, &&OPED0xe9, &&OPED0xea, &&OPED0xeb, + &&OPED0xec, &&OPED0xed, &&OPED0xee, &&OPED0xef, + + &&OPED0xf0, &&OPED0xf1, &&OPED0xf2, &&OPED0xf3, + &&OPED0xf4, &&OPED0xf5, &&OPED0xf6, &&OPED0xf7, + &&OPED0xf8, &&OPED0xf9, &&OPED0xfa, &&OPED0xfb, + &&OPED0xfc, &&OPED0xfd, &&OPED0xfe, &&OPED0xff +}; + +static const void *JumpTableXY[0x100] = { + &&OPXY0x00, &&OPXY0x01, &&OPXY0x02, &&OPXY0x03, + &&OPXY0x04, &&OPXY0x05, &&OPXY0x06, &&OPXY0x07, + &&OPXY0x08, &&OPXY0x09, &&OPXY0x0a, &&OPXY0x0b, + &&OPXY0x0c, &&OPXY0x0d, &&OPXY0x0e, &&OPXY0x0f, + + &&OPXY0x10, &&OPXY0x11, &&OPXY0x12, &&OPXY0x13, + &&OPXY0x14, &&OPXY0x15, &&OPXY0x16, &&OPXY0x17, + &&OPXY0x18, &&OPXY0x19, &&OPXY0x1a, &&OPXY0x1b, + &&OPXY0x1c, &&OPXY0x1d, &&OPXY0x1e, &&OPXY0x1f, + + &&OPXY0x20, &&OPXY0x21, &&OPXY0x22, &&OPXY0x23, + &&OPXY0x24, &&OPXY0x25, &&OPXY0x26, &&OPXY0x27, + &&OPXY0x28, &&OPXY0x29, &&OPXY0x2a, &&OPXY0x2b, + &&OPXY0x2c, &&OPXY0x2d, &&OPXY0x2e, &&OPXY0x2f, + + &&OPXY0x30, &&OPXY0x31, &&OPXY0x32, &&OPXY0x33, + &&OPXY0x34, &&OPXY0x35, &&OPXY0x36, &&OPXY0x37, + &&OPXY0x38, &&OPXY0x39, &&OPXY0x3a, &&OPXY0x3b, + &&OPXY0x3c, &&OPXY0x3d, &&OPXY0x3e, &&OPXY0x3f, + + &&OPXY0x40, &&OPXY0x41, &&OPXY0x42, &&OPXY0x43, + &&OPXY0x44, &&OPXY0x45, &&OPXY0x46, &&OPXY0x47, + &&OPXY0x48, &&OPXY0x49, &&OPXY0x4a, &&OPXY0x4b, + &&OPXY0x4c, &&OPXY0x4d, &&OPXY0x4e, &&OPXY0x4f, + + &&OPXY0x50, &&OPXY0x51, &&OPXY0x52, &&OPXY0x53, + &&OPXY0x54, &&OPXY0x55, &&OPXY0x56, &&OPXY0x57, + &&OPXY0x58, &&OPXY0x59, &&OPXY0x5a, &&OPXY0x5b, + &&OPXY0x5c, &&OPXY0x5d, &&OPXY0x5e, &&OPXY0x5f, + + &&OPXY0x60, &&OPXY0x61, &&OPXY0x62, &&OPXY0x63, + &&OPXY0x64, &&OPXY0x65, &&OPXY0x66, &&OPXY0x67, + &&OPXY0x68, &&OPXY0x69, &&OPXY0x6a, &&OPXY0x6b, + &&OPXY0x6c, &&OPXY0x6d, &&OPXY0x6e, &&OPXY0x6f, + + &&OPXY0x70, &&OPXY0x71, &&OPXY0x72, &&OPXY0x73, + &&OPXY0x74, &&OPXY0x75, &&OPXY0x76, &&OPXY0x77, + &&OPXY0x78, &&OPXY0x79, &&OPXY0x7a, &&OPXY0x7b, + &&OPXY0x7c, &&OPXY0x7d, &&OPXY0x7e, &&OPXY0x7f, + + &&OPXY0x80, &&OPXY0x81, &&OPXY0x82, &&OPXY0x83, + &&OPXY0x84, &&OPXY0x85, &&OPXY0x86, &&OPXY0x87, + &&OPXY0x88, &&OPXY0x89, &&OPXY0x8a, &&OPXY0x8b, + &&OPXY0x8c, &&OPXY0x8d, &&OPXY0x8e, &&OPXY0x8f, + + &&OPXY0x90, &&OPXY0x91, &&OPXY0x92, &&OPXY0x93, + &&OPXY0x94, &&OPXY0x95, &&OPXY0x96, &&OPXY0x97, + &&OPXY0x98, &&OPXY0x99, &&OPXY0x9a, &&OPXY0x9b, + &&OPXY0x9c, &&OPXY0x9d, &&OPXY0x9e, &&OPXY0x9f, + + &&OPXY0xa0, &&OPXY0xa1, &&OPXY0xa2, &&OPXY0xa3, + &&OPXY0xa4, &&OPXY0xa5, &&OPXY0xa6, &&OPXY0xa7, + &&OPXY0xa8, &&OPXY0xa9, &&OPXY0xaa, &&OPXY0xab, + &&OPXY0xac, &&OPXY0xad, &&OPXY0xae, &&OPXY0xaf, + + &&OPXY0xb0, &&OPXY0xb1, &&OPXY0xb2, &&OPXY0xb3, + &&OPXY0xb4, &&OPXY0xb5, &&OPXY0xb6, &&OPXY0xb7, + &&OPXY0xb8, &&OPXY0xb9, &&OPXY0xba, &&OPXY0xbb, + &&OPXY0xbc, &&OPXY0xbd, &&OPXY0xbe, &&OPXY0xbf, + + &&OPXY0xc0, &&OPXY0xc1, &&OPXY0xc2, &&OPXY0xc3, + &&OPXY0xc4, &&OPXY0xc5, &&OPXY0xc6, &&OPXY0xc7, + &&OPXY0xc8, &&OPXY0xc9, &&OPXY0xca, &&OPXY0xcb, + &&OPXY0xcc, &&OPXY0xcd, &&OPXY0xce, &&OPXY0xcf, + + &&OPXY0xd0, &&OPXY0xd1, &&OPXY0xd2, &&OPXY0xd3, + &&OPXY0xd4, &&OPXY0xd5, &&OPXY0xd6, &&OPXY0xd7, + &&OPXY0xd8, &&OPXY0xd9, &&OPXY0xda, &&OPXY0xdb, + &&OPXY0xdc, &&OPXY0xdd, &&OPXY0xde, &&OPXY0xdf, + + &&OPXY0xe0, &&OPXY0xe1, &&OPXY0xe2, &&OPXY0xe3, + &&OPXY0xe4, &&OPXY0xe5, &&OPXY0xe6, &&OPXY0xe7, + &&OPXY0xe8, &&OPXY0xe9, &&OPXY0xea, &&OPXY0xeb, + &&OPXY0xec, &&OPXY0xed, &&OPXY0xee, &&OPXY0xef, + + &&OPXY0xf0, &&OPXY0xf1, &&OPXY0xf2, &&OPXY0xf3, + &&OPXY0xf4, &&OPXY0xf5, &&OPXY0xf6, &&OPXY0xf7, + &&OPXY0xf8, &&OPXY0xf9, &&OPXY0xfa, &&OPXY0xfb, + &&OPXY0xfc, &&OPXY0xfd, &&OPXY0xfe, &&OPXY0xff +}; + +static const void *JumpTableXYCB[0x100] = { + &&OPXYCB0x00, &&OPXYCB0x01, &&OPXYCB0x02, &&OPXYCB0x03, + &&OPXYCB0x04, &&OPXYCB0x05, &&OPXYCB0x06, &&OPXYCB0x07, + &&OPXYCB0x08, &&OPXYCB0x09, &&OPXYCB0x0a, &&OPXYCB0x0b, + &&OPXYCB0x0c, &&OPXYCB0x0d, &&OPXYCB0x0e, &&OPXYCB0x0f, + + &&OPXYCB0x10, &&OPXYCB0x11, &&OPXYCB0x12, &&OPXYCB0x13, + &&OPXYCB0x14, &&OPXYCB0x15, &&OPXYCB0x16, &&OPXYCB0x17, + &&OPXYCB0x18, &&OPXYCB0x19, &&OPXYCB0x1a, &&OPXYCB0x1b, + &&OPXYCB0x1c, &&OPXYCB0x1d, &&OPXYCB0x1e, &&OPXYCB0x1f, + + &&OPXYCB0x20, &&OPXYCB0x21, &&OPXYCB0x22, &&OPXYCB0x23, + &&OPXYCB0x24, &&OPXYCB0x25, &&OPXYCB0x26, &&OPXYCB0x27, + &&OPXYCB0x28, &&OPXYCB0x29, &&OPXYCB0x2a, &&OPXYCB0x2b, + &&OPXYCB0x2c, &&OPXYCB0x2d, &&OPXYCB0x2e, &&OPXYCB0x2f, + + &&OPXYCB0x30, &&OPXYCB0x31, &&OPXYCB0x32, &&OPXYCB0x33, + &&OPXYCB0x34, &&OPXYCB0x35, &&OPXYCB0x36, &&OPXYCB0x37, + &&OPXYCB0x38, &&OPXYCB0x39, &&OPXYCB0x3a, &&OPXYCB0x3b, + &&OPXYCB0x3c, &&OPXYCB0x3d, &&OPXYCB0x3e, &&OPXYCB0x3f, + + &&OPXYCB0x40, &&OPXYCB0x41, &&OPXYCB0x42, &&OPXYCB0x43, + &&OPXYCB0x44, &&OPXYCB0x45, &&OPXYCB0x46, &&OPXYCB0x47, + &&OPXYCB0x48, &&OPXYCB0x49, &&OPXYCB0x4a, &&OPXYCB0x4b, + &&OPXYCB0x4c, &&OPXYCB0x4d, &&OPXYCB0x4e, &&OPXYCB0x4f, + + &&OPXYCB0x50, &&OPXYCB0x51, &&OPXYCB0x52, &&OPXYCB0x53, + &&OPXYCB0x54, &&OPXYCB0x55, &&OPXYCB0x56, &&OPXYCB0x57, + &&OPXYCB0x58, &&OPXYCB0x59, &&OPXYCB0x5a, &&OPXYCB0x5b, + &&OPXYCB0x5c, &&OPXYCB0x5d, &&OPXYCB0x5e, &&OPXYCB0x5f, + + &&OPXYCB0x60, &&OPXYCB0x61, &&OPXYCB0x62, &&OPXYCB0x63, + &&OPXYCB0x64, &&OPXYCB0x65, &&OPXYCB0x66, &&OPXYCB0x67, + &&OPXYCB0x68, &&OPXYCB0x69, &&OPXYCB0x6a, &&OPXYCB0x6b, + &&OPXYCB0x6c, &&OPXYCB0x6d, &&OPXYCB0x6e, &&OPXYCB0x6f, + + &&OPXYCB0x70, &&OPXYCB0x71, &&OPXYCB0x72, &&OPXYCB0x73, + &&OPXYCB0x74, &&OPXYCB0x75, &&OPXYCB0x76, &&OPXYCB0x77, + &&OPXYCB0x78, &&OPXYCB0x79, &&OPXYCB0x7a, &&OPXYCB0x7b, + &&OPXYCB0x7c, &&OPXYCB0x7d, &&OPXYCB0x7e, &&OPXYCB0x7f, + + &&OPXYCB0x80, &&OPXYCB0x81, &&OPXYCB0x82, &&OPXYCB0x83, + &&OPXYCB0x84, &&OPXYCB0x85, &&OPXYCB0x86, &&OPXYCB0x87, + &&OPXYCB0x88, &&OPXYCB0x89, &&OPXYCB0x8a, &&OPXYCB0x8b, + &&OPXYCB0x8c, &&OPXYCB0x8d, &&OPXYCB0x8e, &&OPXYCB0x8f, + + &&OPXYCB0x90, &&OPXYCB0x91, &&OPXYCB0x92, &&OPXYCB0x93, + &&OPXYCB0x94, &&OPXYCB0x95, &&OPXYCB0x96, &&OPXYCB0x97, + &&OPXYCB0x98, &&OPXYCB0x99, &&OPXYCB0x9a, &&OPXYCB0x9b, + &&OPXYCB0x9c, &&OPXYCB0x9d, &&OPXYCB0x9e, &&OPXYCB0x9f, + + &&OPXYCB0xa0, &&OPXYCB0xa1, &&OPXYCB0xa2, &&OPXYCB0xa3, + &&OPXYCB0xa4, &&OPXYCB0xa5, &&OPXYCB0xa6, &&OPXYCB0xa7, + &&OPXYCB0xa8, &&OPXYCB0xa9, &&OPXYCB0xaa, &&OPXYCB0xab, + &&OPXYCB0xac, &&OPXYCB0xad, &&OPXYCB0xae, &&OPXYCB0xaf, + + &&OPXYCB0xb0, &&OPXYCB0xb1, &&OPXYCB0xb2, &&OPXYCB0xb3, + &&OPXYCB0xb4, &&OPXYCB0xb5, &&OPXYCB0xb6, &&OPXYCB0xb7, + &&OPXYCB0xb8, &&OPXYCB0xb9, &&OPXYCB0xba, &&OPXYCB0xbb, + &&OPXYCB0xbc, &&OPXYCB0xbd, &&OPXYCB0xbe, &&OPXYCB0xbf, + + &&OPXYCB0xc0, &&OPXYCB0xc1, &&OPXYCB0xc2, &&OPXYCB0xc3, + &&OPXYCB0xc4, &&OPXYCB0xc5, &&OPXYCB0xc6, &&OPXYCB0xc7, + &&OPXYCB0xc8, &&OPXYCB0xc9, &&OPXYCB0xca, &&OPXYCB0xcb, + &&OPXYCB0xcc, &&OPXYCB0xcd, &&OPXYCB0xce, &&OPXYCB0xcf, + + &&OPXYCB0xd0, &&OPXYCB0xd1, &&OPXYCB0xd2, &&OPXYCB0xd3, + &&OPXYCB0xd4, &&OPXYCB0xd5, &&OPXYCB0xd6, &&OPXYCB0xd7, + &&OPXYCB0xd8, &&OPXYCB0xd9, &&OPXYCB0xda, &&OPXYCB0xdb, + &&OPXYCB0xdc, &&OPXYCB0xdd, &&OPXYCB0xde, &&OPXYCB0xdf, + + &&OPXYCB0xe0, &&OPXYCB0xe1, &&OPXYCB0xe2, &&OPXYCB0xe3, + &&OPXYCB0xe4, &&OPXYCB0xe5, &&OPXYCB0xe6, &&OPXYCB0xe7, + &&OPXYCB0xe8, &&OPXYCB0xe9, &&OPXYCB0xea, &&OPXYCB0xeb, + &&OPXYCB0xec, &&OPXYCB0xed, &&OPXYCB0xee, &&OPXYCB0xef, + + &&OPXYCB0xf0, &&OPXYCB0xf1, &&OPXYCB0xf2, &&OPXYCB0xf3, + &&OPXYCB0xf4, &&OPXYCB0xf5, &&OPXYCB0xf6, &&OPXYCB0xf7, + &&OPXYCB0xf8, &&OPXYCB0xf9, &&OPXYCB0xfa, &&OPXYCB0xfb, + &&OPXYCB0xfc, &&OPXYCB0xfd, &&OPXYCB0xfe, &&OPXYCB0xff +}; + diff --git a/do.cmd b/do.cmd new file mode 100644 index 0000000..6ab095a --- /dev/null +++ b/do.cmd @@ -0,0 +1,3 @@ +copy /Y eboot.pbp h:\PSP\GAME\race +del racepsp.elf +del eboot.pbp diff --git a/flash.cpp b/flash.cpp new file mode 100644 index 0000000..7384651 --- /dev/null +++ b/flash.cpp @@ -0,0 +1,816 @@ +//--------------------------------------------------------------------------- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. See also the license.txt file for +// additional informations. +//--------------------------------------------------------------------------- + +// +// Flash chip emulation by Flavor +// with ideas from Koyote (who originally got ideas from Flavor :) +// for emulation of NGPC carts +// + +#ifndef __GP32__ +#include "StdAfx.h" +#endif +#include "memory.h" +#include "flash.h" +#include +#include + +//#define DEBUG_FLASH +#ifdef DEBUG_FLASH +FILE *debugFile = NULL; +#define stderr debugFile +#define stdout debugFile +#endif + + +/* Manuf ID's +Supported +0x98 Toshiba +0xEC Samsung +0xB0 Sharp + +Other +0x89 Intel +0x01 AMD +0xBF SST +*/ +unsigned char manufID = 0x98; //we're always Toshiba! +unsigned char deviceID = 0x2F; +unsigned char cartSize = 32; +unsigned long bootBlockStartAddr = 0x1F0000; +unsigned char bootBlockStartNum = 31; +//unsigned long cartAddrMask = 0x3FFFFF; + +//with selector, I get +//writeSaveGameFile: Couldn't open Battery//mnt/sd/Games/race/ChryMast.ngf file +#ifdef __GP32__ +#define SAVEGAME_DIR "dev0:\\GPMM\\NGPC\\BATTERY\\" +#else +#define SAVEGAME_DIR "states/" +#endif + +unsigned char currentWriteCycle = 1; //can be 1 through 6 +unsigned char currentCommand = NO_COMMAND; + +#define FLASH_VALID_ID 0x0053 + +typedef struct NGFheaderStruct +{ + unsigned short version; //always 0x53? + unsigned short numBlocks; //how many blocks are in the file + unsigned long fileLen; //length of the file +} ; + +typedef struct blockStruct +{ + unsigned long NGPCaddr; //where this block starts (in NGPC memory map) + unsigned long len; // length of following data +} ; + +#define MAX_BLOCKS 35 //a 16m chip has 35 blocks (SA0-SA34) +unsigned char blocksDirty[2][MAX_BLOCKS]; //max of 2 chips +unsigned char needToWriteFile = 0; +char ngfFilename[300] = {0}; + +#define FLASH_WRITE 0 +#define FLASH_ERASE 1 + + + +void setupFlashParams() +{ + switch(cartSize) + { + default: + case 32: + deviceID = 0x2F; //the upper chip will always be 16bit + bootBlockStartAddr = 0x1F0000; + bootBlockStartNum = 31; + //cartAddrMask=0x3FFFFF; + break; + case 16: + deviceID = 0x2F; + bootBlockStartAddr = 0x1F0000; + bootBlockStartNum = 31; + //cartAddrMask=0x1FFFFF; + break; + case 8: + deviceID = 0x2C; + bootBlockStartAddr = 0xF0000; + bootBlockStartNum = 15; + //cartAddrMask=0x0FFFFF; + break; + case 4: + deviceID = 0xAB; + bootBlockStartAddr = 0x70000; + bootBlockStartNum = 7; + //cartAddrMask=0x07FFFF; + break; + case 0: + manufID = 0x00; + deviceID = 0x00; + bootBlockStartAddr = 0x00000; + bootBlockStartNum = 0; + //cartAddrMask=0; + break; + } +} + +unsigned char blockNumFromAddr(unsigned long addr) +{ + addr &= 0x1FFFFF/* & cartAddrMask*/; + + if(addr >= bootBlockStartAddr) + { + unsigned long bootAddr = addr-bootBlockStartAddr; + //boot block is 32k, 8k, 8k, 16k (0x8000,0x2000,0x2000,0x4000) + if(bootAddr < 0x8000) + return (bootBlockStartAddr / 0x10000); + else if(bootAddr < 0xA000) + return (bootBlockStartAddr / 0x10000) + 1; + else if(bootAddr < 0xC000) + return (bootBlockStartAddr / 0x10000) + 2; + else if(bootAddr < 0x10000) + return (bootBlockStartAddr / 0x10000) + 3; + } + +#ifdef DEBUG_FLASH + fprintf(debugFile, "blockNumFromAddr: addr=0x%08X returning=%d\n", addr, addr / 0x10000); +#endif + + return addr / 0x10000; +} + +unsigned long blockNumToAddr(unsigned char chip, unsigned char blockNum) +{ + unsigned long addr; + + if(blockNum >= bootBlockStartNum) + { + addr = bootBlockStartNum * 0x10000; + + unsigned char bootBlock = blockNum - bootBlockStartNum; + if(bootBlock>=1) + addr+= 0x8000; + if(bootBlock>=2) + addr+= 0x2000; + if(bootBlock>=3) + addr+= 0x2000; + } + else + addr = blockNum * 0x10000; + + if(chip) + addr+=0x200000; + +#ifdef DEBUG_FLASH + fprintf(debugFile, "blockNumToAddr: chip=%d blockNum=%d addr=0x%08X\n", chip, blockNum, addr); +#endif + + return addr; +} + +unsigned long blockSize(unsigned char blockNum) +{ + if(blockNum >= bootBlockStartNum) + { + unsigned char bootBlock = blockNum - bootBlockStartNum; + if(bootBlock==3) + return 0x4000; + if(bootBlock==2) + return 0x2000; + if(bootBlock==1) + return 0x2000; + if(bootBlock==0) + return 0x8000; + } + + return 0x10000; +} + +void setupNGFfilename() +{ + int dotSpot = -1, pos = 0; + int slashSpot = -1; + + if(strlen(ngfFilename) != 0) + { +#ifdef DEBUG_FLASH + fprintf(debugFile, "setupNGFfilename: %s file already opened\n", ngfFilename); + return; //already set up +#endif + } + + strcpy(ngfFilename, SAVEGAME_DIR); + + pos = strlen(m_emuInfo.RomFileName); + + while(pos>=0) + { + if(m_emuInfo.RomFileName[pos] == '/') + { + slashSpot = pos; + break; + } + + pos--; + } + + strcat(ngfFilename, &m_emuInfo.RomFileName[slashSpot+1]); + + for(pos=strlen(ngfFilename);pos>=0 && dotSpot == -1; pos--) + { + if(ngfFilename[pos] == '.') + dotSpot = pos; + } + if(dotSpot == -1) + { + fprintf(stderr, "setupNGFfilename: Couldn't find the . in %s file\n", ngfFilename); + return; + } + + strcpy(&ngfFilename[dotSpot+1], "ngf"); + fprintf(stdout, "setupNGFfilename: using %s for save-game info\n", ngfFilename); +} + +//write all the dirty blocks out to a file +void writeSaveGameFile() +{ + //find the dirty blocks and write them to the .NGF file + int totalBlocks = bootBlockStartNum+4; + int i; + FILE *ngfFile; + + int bytes; + NGFheaderStruct NGFheader; + blockStruct block; + +#ifdef DEBUG_FLASH + fprintf(debugFile, "writeSaveGameFile: entry totalBlocks=%d\n", totalBlocks); +#endif + + setupNGFfilename(); + + + ngfFile = fopen(ngfFilename, "wb"); + if(!ngfFile) + { + fprintf(stderr, "writeSaveGameFile: Couldn't open %s file\n", ngfFilename); + return; + } + + + NGFheader.version = 0x53; + NGFheader.numBlocks = 0; + NGFheader.fileLen = sizeof(NGFheaderStruct); + //add them all up, first + for(i=0;i MAX_BLOCKS) + { + fprintf(stderr, "loadSaveGameFile: numBlocks=%d overflow\n", NGFheader.numBlocks); + free(blockMem); + return; + } + + //loop through the blocks and insert them into mainrom + for(i=0; i < NGFheader.numBlocks; i++) + { + blockHeader = (blockStruct*) blocks; + blocks += sizeof(blockStruct); + + if(!((blockHeader->NGPCaddr >= 0x200000 && blockHeader->NGPCaddr < 0x400000) + || + (blockHeader->NGPCaddr >= 0x800000 && blockHeader->NGPCaddr < 0xA00000) )) + { + fprintf(stderr, "loadSaveGameFile: invalid blockHeader->NGPCaddr=0x%08X\n", blockHeader->NGPCaddr); + free(blockMem); + return; + } + if(blockHeader->NGPCaddr >= 0x800000) + { + blockHeader->NGPCaddr -= 0x600000; + blocksDirty[1][blockNumFromAddr(blockHeader->NGPCaddr-0x200000)] = 1; + } + else if(blockHeader->NGPCaddr >= 0x200000) + { + blockHeader->NGPCaddr -= 0x200000; + blocksDirty[0][blockNumFromAddr(blockHeader->NGPCaddr)] = 1; + } + + memcpy(&mainrom[blockHeader->NGPCaddr], blocks, blockHeader->len); + + blocks += blockHeader->len; + } + + free(blockMem); + +#ifdef DEBUG_FLASH + fprintf(debugFile, "loadSaveGameFile: exit\n"); +#endif +} + +void flashWriteByte(unsigned long addr, unsigned char data, unsigned char operation) +{ + //addr &= cartAddrMask; //the stuff gets mirrored to the higher slots. + + if(blockNumFromAddr(addr) == 0) //hack because DWARP writes to bank 0 + return; + +#ifdef DEBUG_FLASH + if(debugFile != NULL && operation == FLASH_WRITE) + { + fprintf(debugFile, "fWB: addr=0x%08X data=0x%02X\n", addr, data); + } +#endif + + //set a dirty flag for the block that we are writing to + if(addr < 0x200000) + { + blocksDirty[0][blockNumFromAddr(addr)] = 1; + needToWriteFile = 1; + } + else if(addr < 0x400000) + { + blocksDirty[1][blockNumFromAddr(addr)] = 1; + needToWriteFile = 1; + } + else + return; //panic + + //changed to &= because it's actually how flash works + //flash memory can be erased (changed to 0xFF) + //and when written, 1s can become 0s, but you can't turn 0s into 1s (except by erasing) + if(operation == FLASH_ERASE) + mainrom[addr] = 0xFF; //we're just erasing, so set to 0xFF + else + mainrom[addr] &= data; //actually writing data +} + +unsigned char flashReadInfo(unsigned long addr) +{ + currentWriteCycle = 1; + currentCommand = COMMAND_INFO_READ; + + switch(addr&0x03) + { + case 0: + return manufID; + case 1: + return deviceID; + case 2: + return 0; //block not protected + case 3: //thanks Koyote + default: + return 0x80; + } +} + +void flashChipWrite(unsigned long addr, unsigned char data) +{ +#ifdef DEBUG_FLASH + if(debugFile != NULL) + { + fprintf(debugFile, "fCW: addr=0x%08X data=0x%02X cycle=%02d command=%02d\n", addr, data, currentWriteCycle, currentCommand); + } +#endif + if(addr >= 0x800000 && cartSize != 32) + return; + + switch(currentWriteCycle) + { + case 1: + if((addr & 0xFFFF) == 0x5555 && data == 0xAA) + currentWriteCycle++; + else if(data == 0xF0) + { + currentWriteCycle=1;//this is a reset command + writeSaveGameFile(); + } + else + currentWriteCycle=1; + + currentCommand = NO_COMMAND; + break; + case 2: + if((addr & 0xFFFF) == 0x2AAA && data == 0x55) + currentWriteCycle++; + else + currentWriteCycle=1; + + currentCommand = NO_COMMAND; + break; + case 3: + if((addr & 0xFFFF) == 0x5555 && data == 0x80) + currentWriteCycle++;//continue on + else if((addr & 0xFFFF) == 0x5555 && data == 0xF0) + { + currentWriteCycle=1; + writeSaveGameFile(); + } + else if((addr & 0xFFFF) == 0x5555 && data == 0x90) + { + currentWriteCycle++; + currentCommand = COMMAND_INFO_READ; + //now, the next time we read from flash, we should return a ID value + // or a block protect value + break; + } + else if((addr & 0xFFFF) == 0x5555 && data == 0xA0) + { + currentWriteCycle++; + currentCommand = COMMAND_BYTE_PROGRAM; + break; + } + else + currentWriteCycle=1; + + currentCommand = NO_COMMAND; + break; + + case 4: + if(currentCommand == COMMAND_BYTE_PROGRAM)//time to write to flash memory + { + if(addr >= 0x200000 && addr < 0x400000) + addr -= 0x200000; + else if(addr >= 0x800000 && addr < 0xA00000) + addr -= 0x600000; + + //should be changed to just write to mainrom + flashWriteByte(addr, data, FLASH_WRITE); + + currentWriteCycle=1; + } + else if((addr & 0xFFFF) == 0x5555 && data == 0xAA) + currentWriteCycle++; + else + currentWriteCycle=1; + + currentCommand = NO_COMMAND; + break; + case 5: + if((addr & 0xFFFF) == 0x2AAA && data == 0x55) + currentWriteCycle++; + else + currentWriteCycle=1; + + currentCommand = NO_COMMAND; + break; + case 6: + if((addr & 0xFFFF) == 0x5555 && data == 0x10)//chip erase + { + currentWriteCycle=1; + currentCommand = COMMAND_CHIP_ERASE; + + //erase the entire chip + //memset it to all 0xFF + //I think we won't implement this + + break; + } + if(data == 0x30 || data == 0x50)//block erase + { + unsigned char chip=0; + currentWriteCycle=1; + currentCommand = COMMAND_BLOCK_ERASE; + + //erase the entire block that contains addr + //memset it to all 0xFF + + if(addr >= 0x800000) + chip = 1; + + vectFlashErase(chip, blockNumFromAddr(addr)); + break; + } + else + currentWriteCycle=1; + + currentCommand = NO_COMMAND; + break; + + + default: + currentWriteCycle = 1; + currentCommand = NO_COMMAND; + break; + } +} + +//this should be called when a ROM is unloaded +void flashShutdown() +{ + writeSaveGameFile(); +#ifdef DEBUG_FLASH + fclose(debugFile); +#endif +} + +//this should be called when a ROM is loaded +void flashStartup() +{ +#ifdef DEBUG_FLASH + if(debugFile == NULL) + { + debugFile = fopen("flashDebug.txt", "wt"); + } +#endif + memset(blocksDirty[0], 0, MAX_BLOCKS*sizeof(blocksDirty[0][0])); + memset(blocksDirty[1], 0, MAX_BLOCKS*sizeof(blocksDirty[0][0])); + needToWriteFile = 0; + + loadSaveGameFile(); +} + +void vectFlashWrite(unsigned char chip, unsigned int to, unsigned char *fromAddr, unsigned int numBytes) +{ +#ifdef DEBUG_FLASH + if(debugFile != NULL) + { + fprintf(debugFile, "vFW: chip=%d to=0x%08X *fromAddr=%02x num=%d\n", chip, to, *fromAddr, numBytes); + } +#endif + + if(chip) + to+=0x200000; + + //memcpy(dest,fromAddr,numBytes); + while(numBytes--) + { + flashWriteByte(to, *fromAddr, FLASH_WRITE); + fromAddr++; + to++; + } +} + +void vectFlashErase(unsigned char chip, unsigned char blockNum) +{ + /*unsigned char totalBlocks = bootBlockStartNum+4; + + if(blockNum >= totalBlocks) + blockNum = totalBlocks-1;*/ + + //this needs to be modified to take into account boot block areas (less than 64k) + unsigned long blockAddr = blockNumToAddr(chip, blockNum); + unsigned long numBytes = blockSize(blockNum); + +#ifdef DEBUG_FLASH + if(debugFile != NULL) + { + fprintf(debugFile, "vectFlashErase: chip=%d blockNum=%d\n", chip, blockNum); + } +#endif + + //memset block to 0xFF + //memset(&mainrom[blockAddr], 0xFF, numBytes); + while(numBytes--) + { + flashWriteByte(blockAddr, 0xFF, FLASH_ERASE); + blockAddr++; + } +} + +void vectFlashChipErase(unsigned char chip) +{ +#ifdef DEBUG_FLASH + if(debugFile != NULL) + { + fprintf(debugFile, "vectFlashChipErase: chip=%d\n", chip); + } +#endif +} + +void setFlashSize(unsigned long romSize) +{ + //add individual hacks here. + if(strncmp((const char *)&mainrom[0x24], "DELTA WARP ", 11)==0)//delta warp + { + //1 8mbit chip + cartSize = 8; + } + else if(romSize > 0x200000) + { + //2 16mbit chips + cartSize = 32; + } + else if(romSize > 0x100000) + { + //1 16mbit chip + cartSize = 16; + } + else if(romSize > 0x080000) + { + //1 8mbit chip + cartSize = 8; + } + else if(romSize > 0x040000) + { + //1 4mbit chip + cartSize = 4; + } + else if(romSize == 0) //no cart, just emu BIOS + { + cartSize = 0; + } + else + { + //we don't know. It's probablly a homebrew or something cut down + // so just pretend we're a Bung! cart + //2 16mbit chips + cartSize = 32; + } + + setupFlashParams(); + + + flashStartup(); +} + diff --git a/flash.h b/flash.h new file mode 100644 index 0000000..f429922 --- /dev/null +++ b/flash.h @@ -0,0 +1,37 @@ +//--------------------------------------------------------------------------- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. See also the license.txt file for +// additional informations. +//--------------------------------------------------------------------------- + +// +// Flash chip emulation by Flavor +// with ideas from Koyote (who originally got ideas from Flavor :) +// for emulation of NGPC carts +// + +#define NO_COMMAND 0x00 +#define COMMAND_BYTE_PROGRAM 0xA0 +#define COMMAND_BLOCK_ERASE 0x30 +#define COMMAND_CHIP_ERASE 0x10 +#define COMMAND_INFO_READ 0x90 + + +extern unsigned char currentCommand;//what command are we currently on (if any) + +void flashChipWrite(unsigned long addr, unsigned char data); +void vectFlashWrite(unsigned char chip, unsigned int to, unsigned char *fromAddr, unsigned int numBytes); +void vectFlashErase(unsigned char chip, unsigned char blockNum); +void vectFlashChipErase(unsigned char chip); +void setFlashSize(unsigned long romSize); +void flashShutdown(); +unsigned char flashReadInfo(unsigned long addr); + + +extern unsigned char needToWriteFile; +void writeSaveGameFile(); + +#define WRITE_SAVEGAME_IF_DIRTY if(needToWriteFile) writeSaveGameFile();//we found a dirty one, so write the file + diff --git a/graphics.cpp b/graphics.cpp new file mode 100644 index 0000000..d7a89ec --- /dev/null +++ b/graphics.cpp @@ -0,0 +1,1722 @@ +//--------------------------------------------------------------------------- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. See also the license.txt file for +// additional informations. +//--------------------------------------------------------------------------- + +// graphics.cpp: implementation of the graphics class. +// +////////////////////////////////////////////////////////////////////// + +//Flavor - Convert from DirectDraw to SDL + +//Flavor #define WIN32_LEAN_AND_MEAN + +#include "StdAfx.h" +#include "main.h" +#ifndef TARGET_PSP +#include "menu.h" +#include "GP2X.h" +#endif +#include "graphics.h" +#include "memory.h" + +#ifdef TARGET_PSP +#include "psp/psplib/video.h" +extern PspImage *Screen; +extern int gfx_hacks; +#endif + +#define INITGUID + +#ifdef ZOOM_SUPPORT +int zoom=0; +#endif + + +//SDL_Color SDLpalette[256]; + + +// +// 16 bit graphics buffers +// At the moment there's no system which uses more than 16 bit +// colors. +// A grpaphics buffer holds number referencing to the color from +// the "total palette" for that system. +// +int totalpalette[32*32*32]; + +#ifdef __GP32__ + +#define OFFSETX 80 +#define OFFSETY 44 +unsigned short drawBuffer[NGPC_SIZEX*NGPC_SIZEY]; + +#else + +unsigned short *drawBuffer; + +#endif + +// NGP specific +// precalculated pattern structures +const unsigned char mypatterns[256*4] = + { + 0,0,0,0, 0,0,0,1, 0,0,0,2, 0,0,0,3, 0,0,1,0, 0,0,1,1, 0,0,1,2, 0,0,1,3, + 0,0,2,0, 0,0,2,1, 0,0,2,2, 0,0,2,3, 0,0,3,0, 0,0,3,1, 0,0,3,2, 0,0,3,3, + 0,1,0,0, 0,1,0,1, 0,1,0,2, 0,1,0,3, 0,1,1,0, 0,1,1,1, 0,1,1,2, 0,1,1,3, + 0,1,2,0, 0,1,2,1, 0,1,2,2, 0,1,2,3, 0,1,3,0, 0,1,3,1, 0,1,3,2, 0,1,3,3, + 0,2,0,0, 0,2,0,1, 0,2,0,2, 0,2,0,3, 0,2,1,0, 0,2,1,1, 0,2,1,2, 0,2,1,3, + 0,2,2,0, 0,2,2,1, 0,2,2,2, 0,2,2,3, 0,2,3,0, 0,2,3,1, 0,2,3,2, 0,2,3,3, + 0,3,0,0, 0,3,0,1, 0,3,0,2, 0,3,0,3, 0,3,1,0, 0,3,1,1, 0,3,1,2, 0,3,1,3, + 0,3,2,0, 0,3,2,1, 0,3,2,2, 0,3,2,3, 0,3,3,0, 0,3,3,1, 0,3,3,2, 0,3,3,3, + 1,0,0,0, 1,0,0,1, 1,0,0,2, 1,0,0,3, 1,0,1,0, 1,0,1,1, 1,0,1,2, 1,0,1,3, + 1,0,2,0, 1,0,2,1, 1,0,2,2, 1,0,2,3, 1,0,3,0, 1,0,3,1, 1,0,3,2, 1,0,3,3, + 1,1,0,0, 1,1,0,1, 1,1,0,2, 1,1,0,3, 1,1,1,0, 1,1,1,1, 1,1,1,2, 1,1,1,3, + 1,1,2,0, 1,1,2,1, 1,1,2,2, 1,1,2,3, 1,1,3,0, 1,1,3,1, 1,1,3,2, 1,1,3,3, + 1,2,0,0, 1,2,0,1, 1,2,0,2, 1,2,0,3, 1,2,1,0, 1,2,1,1, 1,2,1,2, 1,2,1,3, + 1,2,2,0, 1,2,2,1, 1,2,2,2, 1,2,2,3, 1,2,3,0, 1,2,3,1, 1,2,3,2, 1,2,3,3, + 1,3,0,0, 1,3,0,1, 1,3,0,2, 1,3,0,3, 1,3,1,0, 1,3,1,1, 1,3,1,2, 1,3,1,3, + 1,3,2,0, 1,3,2,1, 1,3,2,2, 1,3,2,3, 1,3,3,0, 1,3,3,1, 1,3,3,2, 1,3,3,3, + 2,0,0,0, 2,0,0,1, 2,0,0,2, 2,0,0,3, 2,0,1,0, 2,0,1,1, 2,0,1,2, 2,0,1,3, + 2,0,2,0, 2,0,2,1, 2,0,2,2, 2,0,2,3, 2,0,3,0, 2,0,3,1, 2,0,3,2, 2,0,3,3, + 2,1,0,0, 2,1,0,1, 2,1,0,2, 2,1,0,3, 2,1,1,0, 2,1,1,1, 2,1,1,2, 2,1,1,3, + 2,1,2,0, 2,1,2,1, 2,1,2,2, 2,1,2,3, 2,1,3,0, 2,1,3,1, 2,1,3,2, 2,1,3,3, + 2,2,0,0, 2,2,0,1, 2,2,0,2, 2,2,0,3, 2,2,1,0, 2,2,1,1, 2,2,1,2, 2,2,1,3, + 2,2,2,0, 2,2,2,1, 2,2,2,2, 2,2,2,3, 2,2,3,0, 2,2,3,1, 2,2,3,2, 2,2,3,3, + 2,3,0,0, 2,3,0,1, 2,3,0,2, 2,3,0,3, 2,3,1,0, 2,3,1,1, 2,3,1,2, 2,3,1,3, + 2,3,2,0, 2,3,2,1, 2,3,2,2, 2,3,2,3, 2,3,3,0, 2,3,3,1, 2,3,3,2, 2,3,3,3, + 3,0,0,0, 3,0,0,1, 3,0,0,2, 3,0,0,3, 3,0,1,0, 3,0,1,1, 3,0,1,2, 3,0,1,3, + 3,0,2,0, 3,0,2,1, 3,0,2,2, 3,0,2,3, 3,0,3,0, 3,0,3,1, 3,0,3,2, 3,0,3,3, + 3,1,0,0, 3,1,0,1, 3,1,0,2, 3,1,0,3, 3,1,1,0, 3,1,1,1, 3,1,1,2, 3,1,1,3, + 3,1,2,0, 3,1,2,1, 3,1,2,2, 3,1,2,3, 3,1,3,0, 3,1,3,1, 3,1,3,2, 3,1,3,3, + 3,2,0,0, 3,2,0,1, 3,2,0,2, 3,2,0,3, 3,2,1,0, 3,2,1,1, 3,2,1,2, 3,2,1,3, + 3,2,2,0, 3,2,2,1, 3,2,2,2, 3,2,2,3, 3,2,3,0, 3,2,3,1, 3,2,3,2, 3,2,3,3, + 3,3,0,0, 3,3,0,1, 3,3,0,2, 3,3,0,3, 3,3,1,0, 3,3,1,1, 3,3,1,2, 3,3,1,3, + 3,3,2,0, 3,3,2,1, 3,3,2,2, 3,3,2,3, 3,3,3,0, 3,3,3,1, 3,3,3,2, 3,3,3,3, + }; + +// standard VRAM table adresses +unsigned char *sprite_table = get_address(0x00008800); +unsigned char *pattern_table = get_address(0x0000A000); +unsigned short*patterns = (unsigned short*)pattern_table; +unsigned short *tile_table_front = (unsigned short *)get_address(0x00009000); +unsigned short *tile_table_back = (unsigned short *)get_address(0x00009800); +unsigned short *palette_table = (unsigned short *)get_address(0x00008200); +unsigned char *bw_palette_table = get_address(0x00008100); +unsigned char *sprite_palette_numbers = get_address(0x00008C00); +// VDP registers +// +// wher is the vdp rendering now on the lcd display? +//unsigned char *scanlineX = get_address(0x00008008); +unsigned char *scanlineY = get_address(0x00008009); +// frame 0/1 priority registers +unsigned char *frame0Pri = get_address(0x00008000); +unsigned char *frame1Pri = get_address(0x00008030); +// windowing registers +unsigned char *wndTopLeftX = get_address(0x00008002); +unsigned char *wndTopLeftY = get_address(0x00008003); +unsigned char *wndSizeX = get_address(0x00008004); +unsigned char *wndSizeY = get_address(0x00008005); +// scrolling registers +unsigned char *scrollSpriteX = get_address(0x00008020); +unsigned char *scrollSpriteY = get_address(0x00008021); +unsigned char *scrollFrontX = get_address(0x00008032); +unsigned char *scrollFrontY = get_address(0x00008033); +unsigned char *scrollBackX = get_address(0x00008034); +unsigned char *scrollBackY = get_address(0x00008035); +// background color selection register and table +unsigned char *bgSelect = get_address(0x00008118); +unsigned short *bgTable = (unsigned short *)get_address(0x000083E0); +unsigned char *oowSelect = get_address(0x00008012); +unsigned short *oowTable = (unsigned short *)get_address(0x000083F0); +// machine constants +unsigned char *color_switch = get_address(0x00006F91); + + +// Defines +#define ZeroStruct(x) ZeroMemory(&x, sizeof(x)); x.dwSize = sizeof(x); +#define SafeRelease(x) if(x) { x->Release(); x = NULL; } + + +// target window +/* +unsigned short p2[16] = { + 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, + 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000 + }; +*/ + +#define BLIT_X_OFFSET 8 +#define BLIT_Y_OFFSET 8 +#define BLIT_OFFSET (BLIT_X_OFFSET + (BLIT_Y_OFFSET*SIZEX)) +#define BLIT_WIDTH (160) +#define BLIT_HEIGHT (152) +#define SCREEN_X_OFFSET ((screen->w - BLIT_WIDTH)/2) +#define SCREEN_Y_OFFSET ((screen->h - BLIT_HEIGHT)/2) + +#define PSP_FUDGE 0//(32) //32 is good for 480x272 -64 is for 320x240 (squish) +#define SCREEN_OFFET (SCREEN_X_OFFSET + (SCREEN_Y_OFFSET*(screen->w+PSP_FUDGE)))//extra fudge factor for PSP? + +#ifndef TARGET_PSP +#define DO_PERIODIC_FLASH_SAVES +#define DO_FPS_DISPLAY +#endif +#if defined(DO_FPS_DISPLAY) || defined(DO_PERIODIC_FLASH_SAVES) +static unsigned int frameCount = 0; +#ifdef __GP32__ +static char fps[32]; +#endif +#endif + +//Flavor - For speed testing, you can turn off screen updates +//#define NO_SCREEN_OUTPUT //seems to give about 4-6FPS on GP2X + +// flip buffers and indicate that one of the buffers is ready +// for blitting to the screen. +void graphicsBlitEnd() +{ + //displayDirty=1; +} + + +#ifdef TARGET_PSP +void graphics_paint(); +#else + +// blit the display buffer, if necessary, and put it to the screen +inline void graphics_paint() +{ +#ifndef NO_SCREEN_OUTPUT + +#ifndef __GP32__ + //should update only what changed, but test with one that updates entire screen +#ifndef ZOOM_SUPPORT + SDL_UpdateRect(screen, SCREEN_X_OFFSET, SCREEN_Y_OFFSET, BLIT_WIDTH, BLIT_HEIGHT); +#else +/* static int prevZoom=0; + if(prevZoom!=zoom) + SDL_FillRect(actualScreen, NULL, SDL_MapRGB(screen->format,0,0,0));//fill black + + if(zoom<=0) + { + SDL_Rect scrRect = {SCREEN_X_OFFSET, SCREEN_Y_OFFSET, BLIT_WIDTH, BLIT_HEIGHT}; + SDL_BlitSurface(screen, &scrRect, actualScreen, &scrRect); + + if(prevZoom==zoom) + SDL_UpdateRects(actualScreen, 1, &scrRect); + else + SDL_Flip(actualScreen); + } + else //if(zoom>0) + { + SDL_Rect scrRect = {SCREEN_X_OFFSET, SCREEN_Y_OFFSET, BLIT_WIDTH, BLIT_HEIGHT}; + SDL_Rect ascrRect = {scrRect.x-zoom, scrRect.y-zoom, scrRect.w+(zoom*2), scrRect.h+(zoom*2)}; + + SDL_SoftStretch(screen, &scrRect, actualScreen, &ascrRect); + if(prevZoom==zoom) + SDL_UpdateRects(actualScreen, 1, &ascrRect); + else + SDL_Flip(actualScreen); + } + prevZoom=zoom;*/ + +//For now, no variable zooming + SDL_Rect scrRect = {SCREEN_X_OFFSET, SCREEN_Y_OFFSET, BLIT_WIDTH, BLIT_HEIGHT}; + SDL_BlitSurface(screen, &scrRect, actualScreen, &scrRect); + SDL_UpdateRects(actualScreen, 1, &scrRect); +#endif + //SDL_UpdateRect(screen, 0, 0, screen->w, screen->h); +#endif + //SDL_Flip(screen); + //} +#endif + +#if defined(DO_FPS_DISPLAY) || defined(DO_PERIODIC_FLASH_SAVES) + static unsigned int startTime = 0; + unsigned int currTime; + + if(startTime == 0) + startTime = SDL_GetTicks(); + + currTime = SDL_GetTicks(); + + if((currTime - startTime) >= 1000) + { +#ifdef DO_PERIODIC_FLASH_SAVES + //WRITE_SAVEGAME_IF_DIRTY; + if(needToWriteFile && options[PERIODIC_SAVES_OPTION]) + { + if(options[FPS_OPTION]) + printTTF("S", 10, 10, red, 1, actualScreen, 1); + writeSaveGameFile();//we found a dirty one, so write the file + if(options[FPS_OPTION]) + printTTF("S", 10, 10, green, 1, actualScreen, 1); + } + else + { +#endif +#ifdef DO_FPS_DISPLAY + //SDL_Rect numRect = + if(options[FPS_OPTION]) + drawNumber(frameCount, 10, 10); + //SDL_UpdateRect(screen, numRect.x, numRect.y, numRect.w, numRect.h); +#endif +#ifdef DO_PERIODIC_FLASH_SAVES + } +#endif + + startTime = currTime; + frameCount = 0; + } + +#endif +} +#endif + +#if defined(DO_FPS_DISPLAY) || defined(DO_PERIODIC_FLASH_SAVES) +inline void incFrameCount() +{ + frameCount++; +} +#endif + +void write_screenshot(FILE *f) +{ +#if 0 + png_structp png_ptr; + png_infop info_ptr; + png_color_8 sig_bit; + png_byte row[SIZEX*3]; + int x,y; + unsigned short *p, *gb; + png_byte *rowpt; + + if (NULL == (png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) + return; + if (NULL == (info_ptr = png_create_info_struct(png_ptr))) + { + png_destroy_write_struct(&png_ptr, png_infopp_NULL); + return; + } + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_write_struct(&png_ptr, &info_ptr); + return; + } + png_init_io(png_ptr, f); + png_set_IHDR(png_ptr, info_ptr, + paintRect.right - paintRect.left, + paintRect.bottom - paintRect.top, + 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + sig_bit.red = 8; + sig_bit.green = 8; + sig_bit.blue = 8; + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + png_write_info(png_ptr, info_ptr); + gb = &displayBuffer[SIZEX * 8]; + for(y = paintRect.bottom - paintRect.top; y; y--) + { + rowpt = row; + p = gb + 8; + for(x = paintRect.right - paintRect.left; x; x--) + { + *rowpt = (totalpalette32[*p]>>16) & 0xFF; + rowpt++; + *rowpt = (totalpalette32[*p]>>8) & 0xFF; + rowpt++; + *rowpt = totalpalette32[*p] & 0xFF; + rowpt++; + p++; + } + gb+= SIZEX; + rowpt = row; + png_write_row(png_ptr, rowpt); + } + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + return; +#endif //#if 0 +} + +////////////////////////////////////////////////////////////////////////////// +// +// Palette Initialization +// +////////////////////////////////////////////////////////////////////////////// + +void (*palette_init)(DWORD dwRBitMask, DWORD dwGBitMask, DWORD dwBBitMask); + +void palette_init32(DWORD dwRBitMask, DWORD dwGBitMask, DWORD dwBBitMask) +{ +/* dbg_print("in palette_init32(0x%X, 0x%X, 0x%X)\n", dwRBitMask, dwGBitMask, dwBBitMask); + + char RShiftCount = 0, GShiftCount = 0, BShiftCount = 0; + char RBitCount = 0, GBitCount = 0, BBitCount = 0; + int r,g,b; + DWORD i; + + i = dwRBitMask; + while (!(i&1)) + { + i = i >> 1; + RShiftCount++; + } + while (i&1) + { + i = i >> 1; + RBitCount++; + } + i = dwGBitMask; + while (!(i&1)) + { + i = i >> 1; + GShiftCount++; + } + while (i&1) + { + i = i >> 1; + GBitCount++; + } + i = dwBBitMask; + while (!(i&1)) + { + i = i >> 1; + BShiftCount++; + } + while (i&1) + { + i = i >> 1; + BBitCount++; + } + switch(m_emuInfo.machine) + { + case NGP: + case NGPC: + case GAMEGEAR: + case LYNX: + case WONDERSWAN: + case WONDERSWANCOLOR: + case ADVISION: + for (b=0; b<16; b++) + for (g=0; g<16; g++) + for (r=0; r<16; r++) + totalpalette[b*256+g*16+r] = + (((b<<(BBitCount-4))+(b>>(4-(BBitCount-4))))<>(4-(GBitCount-4))))<>(4-(RBitCount-4))))<>(5-(BBitCount-5))))<>(5-(GBitCount-5))))<>(5-(RBitCount-5))))<> 1; + RShiftCount++; + } + while (i&1) + { + i = i >> 1; + RBitCount++; + } + i = dwGBitMask; + while (!(i&1)) + { + i = i >> 1; + GShiftCount++; + } + while (i&1) + { + i = i >> 1; + GBitCount++; + } + i = dwBBitMask; + while (!(i&1)) + { + i = i >> 1; + BShiftCount++; + } + while (i&1) + { + i = i >> 1; + BBitCount++; + } + switch(m_emuInfo.machine) + { + case NGP: + case NGPC: + for (b=0; b<16; b++) + for (g=0; g<16; g++) + for (r=0; r<16; r++) + totalpalette[b*256+g*16+r] = + (((b<<(BBitCount-4))+(b>>(4-(BBitCount-4))))<>(4-(GBitCount-4))))<>(4-(RBitCount-4))))<>(4-(8-4))))<<0) + + (((g<<(8-4))+(g>>(4-(8-4))))<<8) + + (((r<<(8-4))+(r>>(4-(8-4))))<<16); + } + break; + case GAMEBOY: + case GAMEBOYPOCKET: + case GAMEBOYCOLOR: + case SUPERGAMEBOY: + case SUPERVISION: + case NES: + for (b=0; b<32; b++) + for (g=0; g<32; g++) + for (r=0; r<32; r++) + { + totalpalette32[b*32*32+g*32+r] = + (((b<<(8-5))+(b>>(5-(8-5))))<<0) + + (((g<<(8-5))+(g>>(5-(8-5))))<<8) + + (((r<<(8-5))+(r>>(5-(8-5))))<<16); + } + break; + }*/ +} + +////////////////////////////////////////////////////////////////////////////// +// +// Neogeo Pocket & Neogeo Pocket color rendering +// +////////////////////////////////////////////////////////////////////////////// + +//static const bwTable[8] = { 0x0000, 0x0333, 0x0555, 0x0777, 0x0999, 0x0BBB, 0x0DDD, 0x0FFF }; +//NOTA Color para juegos b/n +static const unsigned short bwTable[8] = + { + //NOTA nose,nose,window,nose,nose,nose,nose,nose + // B, G,R + 0x0FFF, 0x0DDD, 0x0BBB, 0x0999, 0x0777, 0x0555, 0x0333, 0x0000 + }; + +#ifndef __GP32__ + +// used for rendering the sprites + +typedef struct +{ + unsigned short offset; // offset in graphics buffer to blit, Flavor hopes 16bits is good enough + unsigned short pattern; // pattern code including palette number + unsigned short *tilept; // pointer into the tile description + unsigned short *palette; // palette used to render this sprite +} +SPRITE; + +typedef struct +{ + unsigned short *gbp; // (0,x) base for drawing + unsigned char count[152]; + SPRITE sprite[152][64]; +} +SPRITEDEFS; + +//unsigned int spritesDirty = true; + +SPRITEDEFS spriteDefs[3]; // 4 priority levels + +// definitions of types and variables that are used internally during +// rendering of a screen + +typedef struct +{ + unsigned short *gbp; // pointer into graphics buffer + unsigned char oldScrollX; // keep an eye on the old and previous values + unsigned char *newScrollX; // of the scroll values + unsigned char oldScrollY; + unsigned char *newScrollY; + unsigned short *tileBase; // start address of the tile table this structure represents + short tile[21]; // the tile code + unsigned short *palettes[21]; // palettes associated with tiles + unsigned short *tilept[21]; // tile lines to render + unsigned short *palette; // palette for the tiles this VSYNC +} +TILECACHE; + +unsigned short palettes[16*4+16*4+16*4]; // placeholder for the converted palette + + +TILECACHE tCBack; // tile pointer cache for the back buffer +TILECACHE tCFront; // tile pointer cache for the front buffer + +//int BGCol; // placeholder for the background color this VSYNC +//int OOWCol; // placeholder for the outside window color this VSYNC +//unsigned char SprPriLo, SprPriHi, SprPri = 0; + + +inline void set_paletteCol(unsigned short *palette_table, + unsigned short *sprite, + unsigned short *front, + unsigned short *back) +{ + int i; + // initialize palette table + // + // initialize back plane palette table + + //these should actually be setting the SDL palette + + for(i=0;i<16*4;i++) + { + //sprite[i] = *palette_table & 0x0FFF; + sprite[i] = NGPC_TO_SDL16(palette_table[i]); + //SDLpalette[i].r=(palette_table[i]&0xF)<<4; + //SDLpalette[i].g=(palette_table[i]&0xF0); + //SDLpalette[i].b=((palette_table[i]>>4)&0xF0); + } + + // initialize front plane palette table + for(i=0;i<16*4;i++) + { + //front[i] = *palette_table & 0x0FFF; + front[i] = NGPC_TO_SDL16(palette_table[i+16*4]); + //SDLpalette[i].r=(palette_table[i+16*4]&0xF)<<4; + //SDLpalette[i].g=(palette_table[i+16*4]&0xF0); + //SDLpalette[i].b=((palette_table[i+16*4]>>4)&0xF0); + } + + // initialize sprite palette table (?) + for(i=0;i<16*4;i++) + { + //back[i] = *palette_table & 0x0FFF; + back[i] = NGPC_TO_SDL16(palette_table[i+16*4*2]); + //SDLpalette[i].r=(palette_table[i+16*4*2]&0xF)<<4; + //SDLpalette[i].g=(palette_table[i+16*4*2]&0xF0); + //SDLpalette[i].b=((palette_table[i+16*4*2]>>4)&0xF0); + } + + //if(!SDL_SetColors(screen, SDLpalette, 16*4*2, 16*4)) + // dbg_print("set_paletteCol: SDL_SetPalette failed\n"); + + //Flavor + //I could take all the colors from sprite, front, back , BGCol, OOWCol, and set the SDL palette + //or, just take palette_table and set it +} + +inline void set_paletteBW(unsigned short *palette_table, + unsigned short *sprite, + unsigned short *front, + unsigned short *back) +{ + int i; + unsigned char *pt = ((unsigned char *)palette_table)-0x0100; // get b/w color table + // initialize palette table + // + for(i=0;i<4;i++) + { + // initialize sprite palette table + sprite[i] = NGPC_TO_SDL16(bwTable[pt[i] & 0x07]); + sprite[4+i] = NGPC_TO_SDL16(bwTable[pt[4+i] & 0x07]); + // initialize front plane palette table + front[i] = NGPC_TO_SDL16(bwTable[pt[8+i] & 0x07]); + front[4+i] = NGPC_TO_SDL16(bwTable[pt[8+4+i] & 0x07]); + // initialize back plane palette table + back[i] = NGPC_TO_SDL16(bwTable[pt[16+i] & 0x07]); + back[4+i] = NGPC_TO_SDL16(bwTable[pt[16+4+i] & 0x07]); + } +} + +//I think there's something wrong with this on the GP2X, because CFC2's intro screen is all red +inline void lineClear(TILECACHE *tC, unsigned short col) +{ + for(int i=0; i<21*8; i++) + { + tC->gbp[i] = col; + } +} + +inline void clipLeftRight(SPRITEDEFS *sprDef, unsigned short OOWCol) +{ + int i,j; + + j = *wndTopLeftX + 8; + if (j > (NGPC_SIZEX+8)) + j = NGPC_SIZEX+8; + for(i=8; igbp[i] = OOWCol; + j = j + *wndSizeX; + if (j > (NGPC_SIZEX+8)) + j = NGPC_SIZEX+8; + for(i=j; i < (NGPC_SIZEX+8); i++) + sprDef->gbp[i] = OOWCol; +} + +inline void lineFront(TILECACHE *tC) +{ + int i; + unsigned char a,b; + const unsigned char *p2; + unsigned short *gb; + + //for 8bit SDL, this would set gb to the index of the proper color + //then, we'd set gb to p2[n]+(i*sizeof(palette)) + + gb = tC->gbp; + for (i=0;i<21;i++) + { + a = *(((unsigned char *)tC->tilept[i])+1); + b = *((unsigned char *)tC->tilept[i]); + if (tC->tile[i]&0x8000) + { + p2 = &mypatterns[b*4]; + if (p2[3]) + gb[0] = tC->palettes[i][p2[3]]; + if (p2[2]) + gb[1] = tC->palettes[i][p2[2]]; + if (p2[1]) + gb[2] = tC->palettes[i][p2[1]]; + if (p2[0]) + gb[3] = tC->palettes[i][p2[0]]; + p2 = &mypatterns[a*4]; + if (p2[3]) + gb[4] = tC->palettes[i][p2[3]]; + if (p2[2]) + gb[5] = tC->palettes[i][p2[2]]; + if (p2[1]) + gb[6] = tC->palettes[i][p2[1]]; + if (p2[0]) + gb[7] = tC->palettes[i][p2[0]]; + } + else + { + p2 = &mypatterns[a*4]; + if (p2[0]) + gb[0] = tC->palettes[i][p2[0]]; + if (p2[1]) + gb[1] = tC->palettes[i][p2[1]]; + if (p2[2]) + gb[2] = tC->palettes[i][p2[2]]; + if (p2[3]) + gb[3] = tC->palettes[i][p2[3]]; + p2 = &mypatterns[b*4]; + if (p2[0]) + gb[4] = tC->palettes[i][p2[0]]; + if (p2[1]) + gb[5] = tC->palettes[i][p2[1]]; + if (p2[2]) + gb[6] = tC->palettes[i][p2[2]]; + if (p2[3]) + gb[7] = tC->palettes[i][p2[3]]; + } + if (tC->tile[i]&0x4000) + tC->tilept[i]-= 1; + else + tC->tilept[i]+= 1; + gb+= 8; + } +} + +inline void lineSprite(SPRITEDEFS *sprDefs) +{ + SPRITE *spr; + unsigned short *gb; + unsigned char a,b; + const unsigned char *p2; + + //for 8bit SDL, this would set gb to the index of the proper color + //then, we'd set gb to p2[n] + + for (int i=sprDefs->count[*scanlineY];i>0;i--) + { + spr = &sprDefs->sprite[*scanlineY][i-1]; + gb = &sprDefs->gbp[spr->offset]; + a = *(((unsigned char *)spr->tilept)+1); + b = *((unsigned char *)spr->tilept); + if (spr->pattern&0x8000) + { + p2 = &mypatterns[b*4]; + if (p2[3]) + gb[0] = spr->palette[p2[3]]; + if (p2[2]) + gb[1] = spr->palette[p2[2]]; + if (p2[1]) + gb[2] = spr->palette[p2[1]]; + if (p2[0]) + gb[3] = spr->palette[p2[0]]; + p2 = &mypatterns[a*4]; + if (p2[3]) + gb[4] = spr->palette[p2[3]]; + if (p2[2]) + gb[5] = spr->palette[p2[2]]; + if (p2[1]) + gb[6] = spr->palette[p2[1]]; + if (p2[0]) + gb[7] = spr->palette[p2[0]]; + } + else + { + p2 = &mypatterns[a*4]; + if (p2[0]) + gb[0] = spr->palette[p2[0]]; + if (p2[1]) + gb[1] = spr->palette[p2[1]]; + if (p2[2]) + gb[2] = spr->palette[p2[2]]; + if (p2[3]) + gb[3] = spr->palette[p2[3]]; + p2 = &mypatterns[b*4]; + if (p2[0]) + gb[4] = spr->palette[p2[0]]; + if (p2[1]) + gb[5] = spr->palette[p2[1]]; + if (p2[2]) + gb[6] = spr->palette[p2[2]]; + if (p2[3]) + gb[7] = spr->palette[p2[3]]; + } + } +} + +// sort all the sprites according to their priorities +/*inline void spriteSort(unsigned int bw) +{ + unsigned short spriteCode; + unsigned short *pt; + unsigned char x, y, prevx=0, prevy=0; + int i, j; + + SPRITEDEFS *SprPri00 = &spriteDefs[0]; + SPRITEDEFS *SprPri40 = &spriteDefs[1]; + SPRITEDEFS *SprPri80 = &spriteDefs[2]; + SPRITEDEFS *SprPriC0 = &spriteDefs[3]; + + + // initialize the number of sprites in each structure + SprPri00->count = 0; + SprPri40->count = 0; + SprPri80->count = 0; + SprPriC0->count = 0; + for (i=0;i<64;i++) + { + spriteCode = *((unsigned short *)(sprite_table+4*i)); + if (spriteCode & 0x0400) + prevx+= *(sprite_table+4*i+2); + else + prevx = *(sprite_table+4*i+2) + 8; + x = prevx + *scrollSpriteX; + if (spriteCode & 0x0200) + prevy+= *(sprite_table+4*i+3); + else + prevy = *(sprite_table+4*i+3) + 8; + y = prevy + *scrollSpriteY; + j = *scanlineY+8 - y; + if ((spriteCode>0xff) && (j >= 0) && (j < 8) && (x<168)) //is this sprite visable on the current scanline? + { + // if ((j >= 0) && (j < 8) && (x<168)) { + SPRITE *spr = NULL; + // *(sprite_palette_numbers+i) + pt = (unsigned short *)(pattern_table + 16*(spriteCode & 0x01ff) + + ((spriteCode&0x4000) ? (7-j)*2 : j*2)); + switch (spriteCode & 0x1800) + { + // case order reversed because priority 3 (and 2) sprites occur most of the time + case 0x1800: + spr = &SprPriC0->sprite[SprPriC0->count]; + SprPriC0->count++; + break; + case 0x1000: + spr = &SprPri80->sprite[SprPri80->count]; + SprPri80->count++; + break; + case 0x0800: + spr = &SprPri40->sprite[SprPri40->count]; + SprPri40->count++; + break; + case 0x0000: + spr = &SprPri00->sprite[SprPri00->count]; + SprPri00->count++; + break; + } + spr->pattern = spriteCode; + spr->offset = x; + spr->tilept = pt; + spr->palette = ((bw) ? &palettes[(spriteCode>>11)&0x04] + : &palettes[(*(sprite_palette_numbers+i)&0x0F)*4]); + } + } +}*/ + +inline void spriteSortAll(unsigned int bw) +{ + unsigned int spriteCode; + unsigned short *pt; + unsigned char x, y, prevx=0, prevy=0; + unsigned int i, j, k, scanline; + SPRITE *spr; + + SPRITEDEFS *SprPri40 = &spriteDefs[0]; + SPRITEDEFS *SprPri80 = &spriteDefs[1]; + SPRITEDEFS *SprPriC0 = &spriteDefs[2]; + + // initialize the number of sprites in each structure + memset(SprPri40->count, 0, 152); + memset(SprPri80->count, 0, 152); + memset(SprPriC0->count, 0, 152); + for (i=0;i<64;i++) + { + spriteCode = *((unsigned short *)(sprite_table+4*i)); + + if ((spriteCode<=0xff) || ((spriteCode & 0x1800)==0)) + continue; + + if (spriteCode & 0x0400) + prevx+= *(sprite_table+4*i+2); + else + prevx = *(sprite_table+4*i+2) + 8; + x = prevx + *scrollSpriteX; + + if (spriteCode & 0x0200) + prevy+= *(sprite_table+4*i+3); + else + prevy = *(sprite_table+4*i+3) + 8; + y = prevy + *scrollSpriteY; + + if (x>167 || y>151) + continue; + + for(k=0; k<8; k++) + { + scanline = y+k-8; + if(scanline < 0 || scanline >= 152) + continue; + +// if ((x<168) && (spriteCode>0xff) && (spriteCode & 0x1800)) +// { + switch (spriteCode & 0x1800) + { + // case order reversed because priority 3 (and 2) sprites occur most of the time + case 0x1800: + spr = &SprPriC0->sprite[scanline][SprPriC0->count[scanline]++]; + break; + case 0x1000: + spr = &SprPri80->sprite[scanline][SprPri80->count[scanline]++]; + break; + case 0x0800: + spr = &SprPri40->sprite[scanline][SprPri40->count[scanline]++]; + break; + } + j = scanline+8 - y; + spr->pattern = spriteCode; + spr->offset = x; + spr->tilept = (unsigned short *)(pattern_table + 16*(spriteCode & 0x01ff) + + ((spriteCode&0x4000) ? (7-j)*2 : j*2)); + spr->palette = ((bw) ? &palettes[(spriteCode>>11)&0x04] + : &palettes[(*(sprite_palette_numbers+i)&0x0F)*4]); +// } + } + } +} + + +// initialize drawing/blitting of a screen +void graphicsBlitInit() +{ + // buffers 0 and 1 + // definitions for the back frame + tCBack.gbp = &drawBuffer[8*SIZEX + (8-((*scrollBackX)&7))]; + tCBack.newScrollX = scrollBackX; + tCBack.newScrollY = scrollBackY; + tCBack.tileBase = tile_table_back; + tCBack.palette = &palettes[16*4+16*4]; + // definitions for the front frame + tCFront.gbp = &drawBuffer[8*SIZEX + (8-((*scrollFrontX)&7))]; + tCFront.newScrollX = scrollFrontX; + tCFront.newScrollY = scrollFrontY; + tCFront.tileBase = tile_table_front; + tCFront.palette = &palettes[16*4]; + // definitions for sprite priorities + //SprPriLo = *frame1Pri>>6; + //SprPriHi = *frame0Pri>>6; // ? + spriteDefs[0].gbp = &drawBuffer[8*SIZEX]; + spriteDefs[1].gbp = &drawBuffer[8*SIZEX]; + spriteDefs[2].gbp = &drawBuffer[8*SIZEX]; + //spriteDefs[3].gbp = &drawBuffer[8*SIZEX]; + // force recalculations for first line + tCBack.oldScrollX = *tCBack.newScrollX; + tCBack.oldScrollY = *tCBack.newScrollY+1; // force calculation of structure data + tCFront.oldScrollX = *tCFront.newScrollX; + tCFront.oldScrollY = *tCFront.newScrollY+1; // force calculation of structure data + // start drawing at line 0 + // *scanlineY = 0; +} + +inline void RenderTileCache(TILECACHE *tC, unsigned int bw) +{ + int i; + unsigned char line; + unsigned short *temp; + + if ((tC->oldScrollX != *tC->newScrollX) || + (tC->oldScrollY != *tC->newScrollY) || + (((*tC->newScrollY + *scanlineY)&7) == 0)) + { + // update the structure to reflect the changed scroll registers + // first update pointer into render buffer + tC->gbp = tC->gbp + (tC->oldScrollX&7) - (*tC->newScrollX&7); + + tC->oldScrollX = *tC->newScrollX; + tC->oldScrollY = *tC->newScrollY; + + temp = tC->tileBase + (((tC->oldScrollY + *scanlineY)&0xf8)<<2); + for (i=0;i<21;i++) + { + tC->tile[i] = *(temp + (((tC->oldScrollX>>3) + i)&31)); + line = (*tC->newScrollY + *scanlineY)&7; + tC->palettes[i] = ((bw) ? tC->palette + ((tC->tile[i] & 0x2000) ? 4 : 0) + : tC->palette + ((tC->tile[i]>>7) & 0x3C)); + tC->tilept[i] = (unsigned short *)(pattern_table + ((tC->tile[i] & 0x01ff)<<4)); + tC->tilept[i]+= ((tC->tile[i]&0x4000) ? 7-line : line); + } + } +} + +void graphicsBlitLine(unsigned char render) +{ + //dbg_print("in graphicsBlitLine *scanlineY = %d\n", *scanlineY); + + + if (*scanlineY < 152) + { + //if(*scanlineY == 0) //Flavor moved set_palette off of every line. Helps speed, hurts hi-color apps + //Flavor now only changes palette when dirty + + //this is currently broken for BW games + //if(*scanlineY == 0) + + + // set the palettes, background color, and outside window color + //Flavor moving to scanline 0 set_palette(palette_table,&palettes[0],&palettes[16*4],&palettes[16*4+16*4]); + // sort sprites by priority + if(render) + { + unsigned int bw = (m_emuInfo.machine == NGP); + unsigned short OOWCol = NGPC_TO_SDL16(oowTable[*oowSelect & 0x07]); + +#ifndef TARGET_PSP + SDL_LockSurface(screen); +#endif + if(*scanlineY == 0) + { + if(bw) + set_paletteBW(palette_table,&palettes[0],&palettes[16*4],&palettes[16*4+16*4]); + else + set_paletteCol(palette_table,&palettes[0],&palettes[16*4],&palettes[16*4+16*4]); + + /*if(spritesDirty) + { + spriteSortAll(bw); + spritesDirty = false; + }*/ + spriteSortAll(bw); + } + + //spriteSort(bw); //this needs to be re-done faster. We shouldn't need to sort them every scanline + + // change the tile caches if needed + RenderTileCache(&tCBack, bw); + RenderTileCache(&tCFront, bw); + + // blit the planes, take priority registers into account + + if(*bgSelect & 0x80) /*== 0x80)*/ + lineClear(&tCBack, NGPC_TO_SDL16(bgTable[*bgSelect & 0x07])); + else if(bw) + lineClear(&tCBack, NGPC_TO_SDL16(bwTable[0])); //in 8-bit mode, this would be the index of BGCol in the SDL palette + else + lineClear(&tCBack, 0); //in 8-bit mode, this would be the index of BGCol in the SDL palette + + + lineSprite(&spriteDefs[0]); + + if (*frame1Pri & 0x80) + { + lineFront(&tCFront); + lineSprite(&spriteDefs[1]); + lineFront(&tCBack); + } + else + { + lineFront(&tCBack); + lineSprite(&spriteDefs[1]); + lineFront(&tCFront); + } + + lineSprite(&spriteDefs[2]); + + + // clip left and right sides of screen if necessary + clipLeftRight(&spriteDefs[2], OOWCol); + + if (*wndTopLeftY > *scanlineY || *scanlineY >= (*wndTopLeftY + *wndSizeY)) + { + //tCBack.gbp -= SIZEX; //Flavor, I don't get why these were here + lineClear(&tCBack, OOWCol); //in 8-bit mode, this would be the index of OOWCol in the SDL palette + //tCBack.gbp += SIZEX; //Flavor, I don't get why these were here + } +#ifndef TARGET_PSP + SDL_UnlockSurface(screen); +#endif + } + + // increase scanline count + tCFront.gbp+= SIZEX; + tCBack.gbp+= SIZEX; + spriteDefs[0].gbp+= SIZEX; + spriteDefs[1].gbp+= SIZEX; + spriteDefs[2].gbp+= SIZEX; + //spriteDefs[3].gbp+= SIZEX; + + if (*scanlineY == 151) + { + // start VBlank period + tlcsMemWriteB(0x00008010,tlcsMemReadB(0x00008010) | 0x40); + if(render) + graphics_paint();//displayDirty = 1; + } + + *scanlineY+= 1; + } + else if (*scanlineY == 198) + { + // stop VBlank period + tlcsMemWriteB(0x00008010,tlcsMemReadB(0x00008010) & ~0x40); + graphicsBlitInit(); + +#if defined(DO_FPS_DISPLAY) || defined(DO_PERIODIC_FLASH_SAVES) + incFrameCount(); +#endif + + *scanlineY = 0; + } + else + *scanlineY+= 1; + +} + +#endif // __GP32__ + +// +// THOR'S GRAPHIC CORE +// + +typedef struct +{ + unsigned char flip; + unsigned char x; + unsigned char pal; +} MYSPRITE; + +typedef struct +{ + unsigned short tile; + unsigned char id; +} MYSPRITEREF; + +typedef struct +{ + unsigned char count[152]; + MYSPRITEREF refs[152][64]; +} MYSPRITEDEF; + +MYSPRITEDEF mySprPri40,mySprPri80,mySprPriC0; +MYSPRITE mySprites[64]; +unsigned short myPalettes[192]; + +void sortSprites(unsigned int bw) +{ + unsigned int spriteCode; + unsigned char x, y, prevx=0, prevy=0; + unsigned int i, j; + unsigned short tile; + MYSPRITEREF *spr; + + // initialize the number of sprites in each structure + memset(mySprPri40.count, 0, 152); + memset(mySprPri80.count, 0, 152); + memset(mySprPriC0.count, 0, 152); + + for (i=0;i<64;i++) + { + spriteCode = *((unsigned short *)(sprite_table+4*i)); + + prevx = (spriteCode & 0x0400 ? prevx : 0) + *(sprite_table+4*i+2); + x = prevx + *scrollSpriteX; + + prevy = (spriteCode & 0x0200 ? prevy : 0) + *(sprite_table+4*i+3); + y = prevy + *scrollSpriteY; + + if ((x>167 && x<249) || (y>151 && y<249) || (spriteCode<=0xff) || ((spriteCode & 0x1800)==0)) + continue; + + mySprites[i].x = x; + mySprites[i].pal = bw ? ((spriteCode>>11)&0x04) : ((sprite_palette_numbers[i]&0xf)<<2); + mySprites[i].flip = spriteCode>>8; + tile = (spriteCode & 0x01ff)<<3; + + for (j = 0; j < 8; ++j,++y) + { + if (y>151) + continue; + switch (spriteCode & 0x1800) + { + case 0x1800: + spr = &mySprPriC0.refs[y][mySprPriC0.count[y]++]; + break; + case 0x1000: + spr = &mySprPri80.refs[y][mySprPri80.count[y]++]; + break; + case 0x0800: + spr = &mySprPri40.refs[y][mySprPri40.count[y]++]; + break; + default: continue; + } + spr->id = i; + spr->tile = tile + (spriteCode&0x4000 ? 7-j : j); + } + } +} + +void drawSprites(unsigned short* draw, + MYSPRITEREF *sprites,int count, + int x0,int x1) +{ + unsigned short*pal; + unsigned int pattern,pix,cnt; + MYSPRITE *spr; + int i,cx; + + for (i=count-1;i>=0;--i) + { + pattern = patterns[sprites[i].tile]; + if (pattern==0) + continue; + + spr = &mySprites[sprites[i].id]; + + if (spr->x>248) + cx = spr->x-256; + else + cx = spr->x; + + if (cx+8<=x0 || cx>=x1) + continue; + + pal = &myPalettes[spr->pal]; + + if (cxflip&0x80) + { + pattern>>=((8-cnt)<<1); + for (cx=x0;pattern;++cx) + { + pix = pattern & 0x3; + if (pix) + draw[cx] = pal[pix]; + pattern>>=2; + } + } + else + { + pattern &= (0xffff>>((8-cnt)<<1)); + for (cx = x0+cnt-1;pattern;--cx) + { + pix = pattern & 0x3; + if (pix) + draw[cx] = pal[pix]; + pattern>>=2; + } + } + } + else if (cx+7flip&0x80) + { + for (;pattern;++cx) + { + pix = pattern & 0x3; + if (pix) + draw[cx] = pal[pix]; + pattern>>=2; + } + } + else + { + for (cx+=7;pattern;--cx) + { + pix = pattern & 0x3; + if (pix) + draw[cx] = pal[pix]; + pattern>>=2; + } + } + } + else + { + cnt = x1-cx; + if (spr->flip&0x80) + { + pattern &= (0xffff>>((8-cnt)<<1)); + for (;pattern;++cx) + { + pix = pattern & 0x3; + if (pix) + draw[cx] = pal[pix]; + pattern>>=2; + } + } + else + { + pattern>>=((8-cnt)<<1); + for (cx+=cnt-1;pattern;--cx) + { + pix = pattern & 0x3; + if (pix) + draw[cx] = pal[pix]; + pattern>>=2; + } + } + } + } +} + +void drawScrollPlane(unsigned short* draw, + unsigned short* tile_table,int scrpal, + unsigned char dx,unsigned char dy, + int x0,int x1,unsigned int bw) +{ + unsigned short*tiles; + unsigned short*pal; + unsigned int pattern; + unsigned int j,count,pix,idy,tile; + int i,x2; + + dx+=x0; + tiles = tile_table+((dy>>3)<<5)+(dx>>3); + + count = 8-(dx&0x7); + dx &= 0xf8; + dy &= 0x7; + idy = 7-dy; + + i = x0; + + if (count<8) + { + tile = *(tiles++); + pattern = patterns[(((tile&0x1ff))<<3) + (tile&0x4000 ? idy:dy)]; + if (pattern) + { + pal = &myPalettes[scrpal + (bw ? (tile&0x2000 ? 4 : 0) : ((tile>>7)&0x3c))]; + if (tile&0x8000) + { + pattern>>=((8-count)<<1); + for (j=i;pattern;++j) + { + pix = pattern & 0x3; + if (pix) + draw[j] = pal[pix]; + pattern>>=2; + } + } + else + { + pattern &= (0xffff>>((8-count)<<1)); + for (j=i+count-1;pattern;--j) + { + pix = pattern & 0x3; + if (pix) + draw[j] = pal[pix]; + pattern>>=2; + } + } + } + i+=count; + dx+=8; + if (dx==0) + tiles-=32; + } + + x2 = i+((x1-i)&0xf8); + + for (;i>7)&0x3c))]; + if (tile&0x8000) + { + for (j=i;pattern;++j) + { + pix = pattern & 0x3; + if (pix) + draw[j] = pal[pix]; + pattern>>=2; + } + } + else + { + for (j=i+7;pattern;--j) + { + pix = pattern & 0x3; + if (pix) + draw[j] = pal[pix]; + pattern>>=2; + } + } + } + dx+=8; + if (dx==0) + tiles-=32; + } + + if (x2!=x1) + { + count = x1-x2; + tile = *(tiles++); + pattern = patterns[(((tile&0x1ff))<<3) + (tile&0x4000 ? idy:dy)]; + if (pattern) + { + pal = &myPalettes[scrpal + (bw ? (tile&0x2000 ? 4 : 0) : ((tile>>7)&0x3c))]; + if (tile&0x8000) + { + pattern &= (0xffff>>((8-count)<<1)); + for (j=i;pattern;++j) + { + pix = pattern & 0x3; + if (pix) + draw[j] = pal[pix]; + pattern>>=2; + } + } + else + { + pattern>>=((8-count)<<1); + for (j=i+count-1;pattern;--j) + { + pix = pattern & 0x3; + if (pix) + draw[j] = pal[pix]; + pattern>>=2; + } + } + } + } +} + +void myGraphicsBlitLine(unsigned char render) //NOTA +{ + int i,x0,x1; + if (*scanlineY < 152) + { + if(render) + { +#ifdef __GP32__ + unsigned short* draw = &drawBuffer[*scanlineY*NGPC_SIZEX]; +#elif TARGET_PSP + unsigned short* draw = &drawBuffer[(*scanlineY)*(Screen->Width)]; +#else + unsigned short* draw = &drawBuffer[(*scanlineY)*(screen->w+PSP_FUDGE)];//extra fudge factor for PSP??? +#endif + unsigned short bgcol; + unsigned int bw = (m_emuInfo.machine == NGP); + unsigned short OOWCol = NGPC_TO_SDL16(oowTable[*oowSelect & 0x07]); + unsigned short* pal; + unsigned short* mempal; + +#if !defined(__GP32__) && !defined(TARGET_PSP) + SDL_LockSurface(screen); +#endif + + if (*scanlineY==0) + sortSprites(bw); + if (*scanlineY<*wndTopLeftY || *scanlineY>*wndTopLeftY+*wndSizeY || *wndSizeX==0 || *wndSizeY==0) + { + + for (i=0;i=zoomy && *scanlineYNGPC_SIZEX) + x1 = NGPC_SIZEX; + + for (i=x0;i 0) + drawScrollPlane(draw,tile_table_back,128,*scrollBackX,*scrollBackY+*scanlineY,x0,x1,bw); + else + drawScrollPlane(draw,tile_table_back,128,1,*scrollBackY+*scanlineY,x0,x1,bw);} + + } + else + { + drawScrollPlane(draw,tile_table_back,128,*scrollBackX,*scrollBackY+*scanlineY,x0,x1,bw); + if (mySprPri80.count[*scanlineY]) + drawSprites(draw,mySprPri80.refs[*scanlineY],mySprPri80.count[*scanlineY],x0,x1); + drawScrollPlane(draw,tile_table_front,64,*scrollFrontX,*scrollFrontY+*scanlineY,x0,x1,bw); + } + + if (mySprPriC0.count[*scanlineY]) + drawSprites(draw,mySprPriC0.refs[*scanlineY],mySprPriC0.count[*scanlineY],x0,x1); + + for (i=0;iPixels; +#elif __GP32__ + palette_init = palette_init16; + palette_init(0xf800,0x07c0,0x003e); +#else + dbg_print("in graphics_init\n"); + + + switch (screen->format->BitsPerPixel) + { + case 8: + palette_init = palette_init8; + break; + case 16: + palette_init = palette_init16; + break; + case 32: + palette_init = palette_init32; + break; + } + + //palettes = palette_table; + drawBuffer = ((unsigned short*) screen->pixels) + SCREEN_OFFET; + + palette_init(screen->format->Rmask, + screen->format->Gmask, screen->format->Bmask); + + pngpalette_init(); +#endif + + switch(m_emuInfo.machine) + { + case NGP: + bgTable = (unsigned short *)bwTable; + oowTable = (unsigned short *)bwTable; + //set_palette = set_paletteBW; +#ifndef __GP32__ + graphicsBlitInit(); +#endif + *scanlineY = 0; + break; + case NGPC: + bgTable = (unsigned short *)get_address(0x000083E0); + oowTable = (unsigned short *)get_address(0x000083F0); + //set_palette = set_paletteCol; +#ifndef __GP32__ + graphicsBlitInit(); +#endif + *scanlineY = 0; + break; + } +#ifndef __GP32__ + /*SDL_Surface *skin = IMG_Load("skin.jpg"); + if(skin) + { + SDL_BlitSurface(skin, NULL, screen, NULL); + SDL_Flip(screen); + }*/ +#endif + return TRUE; +} + +void graphics_cleanup() +{} + diff --git a/graphics.h b/graphics.h new file mode 100644 index 0000000..7ed6146 --- /dev/null +++ b/graphics.h @@ -0,0 +1,81 @@ +//--------------------------------------------------------------------------- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. See also the license.txt file for +// additional informations. +//--------------------------------------------------------------------------- + +// graphics.h: interface for the graphics class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_GRAPHICS_H__EE4B1FE1_8EB2_11D3_8644_00A0241D2A65__INCLUDED_) +#define AFX_GRAPHICS_H__EE4B1FE1_8EB2_11D3_8644_00A0241D2A65__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +//actual NGPC +#define NGPC_SIZEX 160 +#define NGPC_SIZEY 152 + +#define ZOOM_SUPPORT + +//render screen 260x152 is good for NGPC +#define SIZEX 260//480//368//320//480 +#define SIZEY 152//272//207//240//272 + +//extern unsigned char bwPaletteDirty, spritePaletteDirty, frontPaletteDirty, backPaletteDirty; +//extern unsigned char bgoowDirty; +//extern unsigned int spritesDirty; + + +// graphics buffer will hold the screen transformed to full RGB colors used by the emulated system +//extern int *graphics_buffer; +//extern unsigned short *drawBuffer; +//extern unsigned short drawBuffer[SIZEX*SIZEY]; +//extern unsigned char *drawBuffer; +//extern BITMAP myBitmap; + +#ifndef __GP32__ +BOOL graphics_init(HWND phWnd); +#else +BOOL graphics_init(); +#endif +void graphics_blit(void); +void graphics_paint(); +void graphics_cleanup(); +void write_screenshot(FILE *f); +// new renderer (NeoGeo Pocket (Color)) +void incFrameCount(); +void graphicsBlitInit(); +void graphicsBlitLine(unsigned char render); +void myGraphicsBlitLine(unsigned char render); +void graphicsBlitEnd(); +// renderer for Gameboy Color +void gbcGraphicsBlitInit(); +void gbcGraphicsBlitLine(); + +void setColPaletteEntry(unsigned char addr, unsigned short data); +void setBWPaletteEntry(unsigned char addr, unsigned short data); + + +// +// adventure vision stuff +// +void advGraphicsEnd(); + +void graphics_debug(FILE *f); + +extern unsigned short palettes[16*4+16*4+16*4]; // placeholder for the converted palette +extern int totalpalette[32*32*32]; +#define NGPC_TO_SDL16(col) totalpalette[col] + +#define setColPaletteEntry(addr, data) palettes[(addr)] = NGPC_TO_SDL16(data) +#define setBWPaletteEntry(addr, data) palettes[(addr)] = NGPC_TO_SDL16(data) + +extern unsigned char *scanlineY; + +#endif // !defined(AFX_GRAPHICS_H__EE4B1FE1_8EB2_11D3_8644_00A0241D2A65__INCLUDED_) diff --git a/homehook Makefile.psp b/homehook Makefile.psp new file mode 100644 index 0000000..4f6f4bd --- /dev/null +++ b/homehook Makefile.psp @@ -0,0 +1,48 @@ +PSPSDK=$(shell psp-config --pspsdk-path) + +PSPAPP=psp +PSPLIB=$(PSPAPP)/psplib + +PSP_FW_VERSION=200 +export PSP_FW_VERSION + +PSP_APP_NAME=RACE! PSP +PSP_APP_VER=2.17 + +TARGET=racepsp +EXTRA_TARGETS=EBOOT.PBP +PSP_EBOOT_TITLE=$(PSP_APP_NAME) $(PSP_APP_VER) +PSP_EBOOT_ICON=$(PSPAPP)/race-icon.png + + +BUILD_EMUL=cz80.o cz80_support.o input.o neopopsound.o \ + ngpBios.o tlcs900h.o memory.o flash.o graphics.o \ + main.o state.o sound.o +BUILD_MZ=ioapi.o unzip.o +BUILD_PORT=$(PSPAPP)/main.o $(PSPAPP)/emulate.o $(PSPAPP)/menu.o +HOMEHOOKOBJ = $(PSPAPP)/homehook.o + + +OBJS=$(BUILD_EMUL) $(BUILD_MZ) $(BUILD_PORT) $(HOMEHOOKOBJ) + +DEFINES=-DCZ80 -DTARGET_PSP -D_MAX_PATH=2048 -DHOST_FPS=60 +BASE_DEFS=-DPSP -DPSP_APP_VER=\"$(PSP_APP_VER)\" -DPSP_APP_NAME="\"$(PSP_APP_NAME)\"" +CFLAGS=-O2 -G0 -Wall -DHOME_HOOK $(BASE_DEFS) $(DEFINES) +CXXFLAGS=$(CFLAGS) -fno-exceptions -fno-rtti +ASFLAGS=$(CFLAGS) +INCDIR=$(PSPLIB) $(PSPAPP)/homehookprx +LIBDIR=$(PSPLIB) +LIBS=-lpsplib -lpng -lpspgu -lpsppower \ + -lz -lm -lc -lpspaudio -lpsprtc -lpspwlan -lpspnet_adhoc \ + -lpspnet_adhocctl -lpspnet_adhocmatching + +all: build_libs +clean: clean_libs + +include $(PSPSDK)/lib/build.mak + +build_libs: + cd $(PSPLIB) ; $(MAKE) +clean_libs: + cd $(PSPLIB) ; $(MAKE) clean + diff --git a/homehook.S b/homehook.S new file mode 100644 index 0000000..75ea083 --- /dev/null +++ b/homehook.S @@ -0,0 +1,8 @@ + .set noreorder + +#include "pspstub.s" + + STUB_START "homehook",0x40090000,0x00020005 + STUB_FUNC 0xDDC19F6B,initHomeButton + STUB_FUNC 0x40DC34E4,readHomeButton + STUB_END diff --git a/homehook.h b/homehook.h new file mode 100644 index 0000000..47e704c --- /dev/null +++ b/homehook.h @@ -0,0 +1,13 @@ +/****************************************************************************** + + homehook.prx + +******************************************************************************/ + +#ifndef HOMEHOOK_PRX_H +#define HOMEHOOK_PRX_H + +void initHomeButton(int devkit_version); +unsigned int readHomeButton(void); + +#endif /* HOMEHOOK_PRX_H */ diff --git a/input.cpp b/input.cpp new file mode 100644 index 0000000..041957a --- /dev/null +++ b/input.cpp @@ -0,0 +1,261 @@ +// input.cpp: implementation of the input class. +// +////////////////////////////////////////////////////////////////////// + +//Flavor - Convert from DirectInput to SDL/GP2X + +#ifndef __GP32__ +#include "StdAfx.h" +#endif +#include "main.h" +#include "input.h" +#include "memory.h" +///#include "menu.h" + + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +// address where the state of the input device(s) is stored +//unsigned char *InputByte = get_address(0x00006F82); +unsigned char ngpInputState = 0; +unsigned char *InputByte = &ngpInputState; + +#ifndef TARGET_PSP +extern SDL_Joystick *joystick; +#endif +#ifdef ZOOM_SUPPORT +extern int zoom; +#endif + +#ifdef __GP32__ +#define DIK_UP BUTTON_UP +#define DIK_DOWN BUTTON_DOWN +#define DIK_LEFT BUTTON_LEFT +#define DIK_RIGHT BUTTON_RIGHT +#define DIK_SPACE BUTTON_A +#define DIK_N BUTTON_B +#define DIK_S BUTTON_SELECT +#define DIK_O BUTTON_START +#else +#define DIK_UP SDLK_UP +#define DIK_DOWN SDLK_DOWN +#define DIK_LEFT SDLK_LEFT +#define DIK_RIGHT SDLK_RIGHT +#define DIK_SPACE SDLK_a +#define DIK_N SDLK_b +#define DIK_S SDLK_ESCAPE +#define DIK_O SDLK_SPACE +#endif + +#define DOWN(x) keystates[x] +#ifdef __GP32__ +u16 keystates = 0; +#else +Uint8 *keystates = NULL; +#endif + +struct joy_range +{ + int minx, maxx, miny, maxy; +} range; + +#ifdef __GP32__ +void InitInput() +#else +BOOL InitInput(HWND hwnd) +#endif +{ +#ifndef TARGET_PSP +#ifndef __GP32__ + keystates = PSP_GetKeyStateArray(NULL); +#endif + // setup standard values for input + // NGP/NGPC: + m_sysInfo[NGP].InputKeys[KEY_UP] = DIK_UP; + m_sysInfo[NGP].InputKeys[KEY_DOWN] = DIK_DOWN; + m_sysInfo[NGP].InputKeys[KEY_LEFT] = DIK_LEFT; + m_sysInfo[NGP].InputKeys[KEY_RIGHT] = DIK_RIGHT; + m_sysInfo[NGP].InputKeys[KEY_BUTTON_A] = DIK_SPACE; + m_sysInfo[NGP].InputKeys[KEY_BUTTON_B] = DIK_N; + m_sysInfo[NGP].InputKeys[KEY_SELECT] = DIK_O; // Option button + m_sysInfo[NGPC].InputKeys[KEY_UP] = DIK_UP; + m_sysInfo[NGPC].InputKeys[KEY_DOWN] = DIK_DOWN; + m_sysInfo[NGPC].InputKeys[KEY_LEFT] = DIK_LEFT; + m_sysInfo[NGPC].InputKeys[KEY_RIGHT] = DIK_RIGHT; + m_sysInfo[NGPC].InputKeys[KEY_BUTTON_A] = DIK_SPACE; + m_sysInfo[NGPC].InputKeys[KEY_BUTTON_B] = DIK_N; + m_sysInfo[NGPC].InputKeys[KEY_SELECT] = DIK_O; // Option button + + range.minx = -32767;//INT_MIN; + range.maxx = 32767;//INT_MAX; + range.miny = -32767;//INT_MIN; + range.maxy = 32767;//INT_MAX; +#endif /* TARGET_PSP */ + return TRUE; +} + +#ifdef __GP32__ +extern "C" +{ + int gp_getButton(); + void clearScreen(); +} +int zoom=0,zoomy=16; +#endif + +#ifndef TARGET_PSP +void UpdateInputState() +{ +#ifdef __GP32__ + int key = gp_getButton(); + + if ((key & BUTTON_R) && (key & BUTTON_L)) + { + m_bIsActive = FALSE;//Flavor exit emulation + return; + } + + if (key & BUTTON_R) { + zoom ^= 1; + while ((key=gp_getButton())&BUTTON_R); + if (!zoom) + clearScreen(); + } + + if (key & BUTTON_L) { + if (key & BUTTON_DOWN) { + if (zoomy<32) + zoomy+=1; + return; + } + if (key & BUTTON_UP) { + if (zoomy>0) + zoomy-=1; + return; + } + } + if(key & BUTTON_DOWN) + *InputByte = 0x02; + else if(key & BUTTON_UP) + *InputByte = 0x01; + else + *InputByte = 0; + + if(key & BUTTON_RIGHT) + *InputByte |= 0x08; + else if(key & BUTTON_LEFT) + *InputByte |= 0x04; + + if (key & BUTTON_A) + *InputByte|= 0x10; + if (key & BUTTON_B) + *InputByte|= 0x20; + if (key & BUTTON_SELECT) + *InputByte|= 0x40; +#else + SDL_Event event; + +#ifdef TARGET_PSP + while(SDL_PollEvent(&event)) + { + } + + if (SDL_JoystickGetButton(joystick, PSP_BUTTON_R) && SDL_JoystickGetButton(joystick, PSP_BUTTON_L)) + { + m_bIsActive = FALSE;//Flavor exit emulation + return; + } + + int x_axis = SDL_JoystickGetAxis (joystick, 0); + int y_axis = SDL_JoystickGetAxis (joystick, 1); + +/* if (x_axis < range.minx) range.minx = x_axis; + if (y_axis < range.miny) range.miny = y_axis; + if (x_axis > range.maxx) range.maxx = x_axis; + if (y_axis > range.maxy) range.maxy = y_axis; + +*/ + + *InputByte = 0; + if(SDL_JoystickGetButton(joystick, PSP_BUTTON_DOWN) || (y_axis > (range.miny + 2*(range.maxy - range.miny)/3))) + { + *InputByte |= 0x02; + } + if(SDL_JoystickGetButton(joystick, PSP_BUTTON_UP) || (y_axis < (range.miny + (range.maxy - range.miny)/3))) + { + *InputByte |= 0x01; + } + if(SDL_JoystickGetButton(joystick, PSP_BUTTON_RIGHT) || (x_axis > (range.minx + 2*(range.maxx - range.minx)/3))) + { + *InputByte |= 0x08; + } + if(SDL_JoystickGetButton(joystick, PSP_BUTTON_LEFT) || (x_axis < (range.minx + (range.maxx - range.minx)/3))) + { + *InputByte |= 0x04; + } + + if (SDL_JoystickGetButton(joystick, PSP_BUTTON_X)) + *InputByte |= 0x10; + if (SDL_JoystickGetButton(joystick, PSP_BUTTON_O)) + *InputByte |= 0x20; + if (SDL_JoystickGetButton(joystick, PSP_BUTTON_TRI)) + *InputByte |= 0x40; + +/* no variable zoom for now +#ifdef ZOOM_SUPPORT + if(SDL_JoystickGetButton(joystick, PSP_BUTTON_R) && zoom<60)//272-152=120/2=60 + zoom++; + if(SDL_JoystickGetButton(joystick, PSP_BUTTON_L) && zoom>0) + zoom--; +#endif*/ + + /*if (SDL_JoystickGetButton(joystick, PSP_BUTTON_VOLUP)) + increaseVolume(); + else if (SDL_JoystickGetButton(joystick, PSP_BUTTON_VOLDOWN)) + decreaseVolume();*/ +#else + SYSTEMINFO *si; + PSP_SetKeyStates(); //make sure they're updated + + while(SDL_PollEvent(&event)) + { + } + + if (DOWN(SDLK_r) && DOWN(SDLK_l)) + m_bIsActive = FALSE;//Flavor exit emulation + + + si = &m_sysInfo[NGP]; + *InputByte = 0; + if (DOWN(si->InputKeys[KEY_BUTTON_A])) + *InputByte|= 0x10; + if (DOWN(si->InputKeys[KEY_BUTTON_B])) + *InputByte|= 0x20; + if (DOWN(si->InputKeys[KEY_SELECT])) + *InputByte|= 0x40; + if (DOWN(si->InputKeys[KEY_UP])) + *InputByte|= 0x01; + if (DOWN(si->InputKeys[KEY_DOWN])) + *InputByte|= 0x02; + if (DOWN(si->InputKeys[KEY_LEFT])) + *InputByte|= 0x04; + if (DOWN(si->InputKeys[KEY_RIGHT])) + *InputByte|= 0x08; + + if (DOWN(SDLK_KP_PLUS)) + increaseVolume(); + else if (DOWN(SDLK_KP_MINUS)) + decreaseVolume(); +#endif +#endif +} +#endif /* TARGET_PSP */ + +void FreeInput() +{ + +} diff --git a/input.h b/input.h new file mode 100644 index 0000000..fff1100 --- /dev/null +++ b/input.h @@ -0,0 +1,33 @@ +//--------------------------------------------------------------------------- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. See also the license.txt file for +// additional informations. +//--------------------------------------------------------------------------- + +// input.h: interface for the input class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_INPUT_H__59701BE2_A97A_11D3_8645_00A0241D2A65__INCLUDED_) +#define AFX_INPUT_H__59701BE2_A97A_11D3_8645_00A0241D2A65__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +//Flavor#define DIRECTINPUT_VERSION 0x0300 +//Flavor#include + +extern unsigned char ngpInputState; + +#ifndef __GP32__ +BOOL InitInput(HWND hWnd); +#else +void InitInput(); +#endif +void UpdateInputState(); +void FreeInput(); + +#endif // !defined(AFX_INPUT_H__59701BE2_A97A_11D3_8645_00A0241D2A65__INCLUDED_) diff --git a/ioapi.c b/ioapi.c new file mode 100644 index 0000000..80443b7 --- /dev/null +++ b/ioapi.c @@ -0,0 +1,177 @@ +/* ioapi.c -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + Version 1.00, September 10th, 2003 + + Copyright (C) 1998-2003 Gilles Vollant +*/ + +#include +#include +#include + +#include "zlib.h" +#include "ioapi.h" + + + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +voidpf ZCALLBACK fopen_file_func OF(( + voidpf opaque, + const char* filename, + int mode)); + +uLong ZCALLBACK fread_file_func OF(( + voidpf opaque, + voidpf stream, + void* buf, + uLong size)); + +uLong ZCALLBACK fwrite_file_func OF(( + voidpf opaque, + voidpf stream, + const void* buf, + uLong size)); + +long ZCALLBACK ftell_file_func OF(( + voidpf opaque, + voidpf stream)); + +long ZCALLBACK fseek_file_func OF(( + voidpf opaque, + voidpf stream, + uLong offset, + int origin)); + +int ZCALLBACK fclose_file_func OF(( + voidpf opaque, + voidpf stream)); + +int ZCALLBACK ferror_file_func OF(( + voidpf opaque, + voidpf stream)); + + +voidpf ZCALLBACK fopen_file_func (opaque, filename, mode) + voidpf opaque; + const char* filename; + int mode; +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen(filename, mode_fopen); + return file; +} + + +uLong ZCALLBACK fread_file_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + void* buf; + uLong size; +{ + uLong ret; + ret = fread(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + + +uLong ZCALLBACK fwrite_file_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + const void* buf; + uLong size; +{ + uLong ret; + ret = fwrite(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +long ZCALLBACK ftell_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + long ret; + ret = ftell((FILE *)stream); + return ret; +} + +long ZCALLBACK fseek_file_func (opaque, stream, offset, origin) + voidpf opaque; + voidpf stream; + uLong offset; + int origin; +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + fseek((FILE *)stream, offset, fseek_origin); + return ret; +} + +int ZCALLBACK fclose_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + int ret; + ret = fclose((FILE *)stream); + return ret; +} + +int ZCALLBACK ferror_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + int ret; + ret = ferror((FILE *)stream); + return ret; +} + +void fill_fopen_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = fopen_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell_file = ftell_file_func; + pzlib_filefunc_def->zseek_file = fseek_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/ioapi.h b/ioapi.h new file mode 100644 index 0000000..6bc2a2c --- /dev/null +++ b/ioapi.h @@ -0,0 +1,75 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + Version 1.00, September 10th, 2003 + + Copyright (C) 1998-2003 Gilles Vollant +*/ + +#ifndef _ZLIBIOAPI_H +#define _ZLIBIOAPI_H + + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + + +#ifndef ZCALLBACK + +#if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) +#define ZCALLBACK CALLBACK +#else +#define ZCALLBACK +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + + + +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size)) +#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size)) +#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream)) +#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream)) +#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream)) + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/koyote.bin b/koyote.bin new file mode 100644 index 0000000000000000000000000000000000000000..d1445f6fd4ebd1fa3824c448f2a34495e0f9390d GIT binary patch literal 12288 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 am04X}%)6&hO=~Pp6eqL={J;Hg=)VAG(@0JL literal 0 HcmV?d00001 diff --git a/koyote_bin.h b/koyote_bin.h new file mode 100644 index 0000000..4fa0ca6 --- /dev/null +++ b/koyote_bin.h @@ -0,0 +1,772 @@ +#define KOYOTE_BIN_SIZE 12288 +const unsigned char koyote_bin[KOYOTE_BIN_SIZE] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0xA6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, + 0x01, 0x00, 0x03, 0x00, 0x13, 0x00, 0x07, 0x00, 0x24, 0x00, 0x30, 0x00, 0x99, 0x01, 0x03, 0x13, + 0x07, 0x24, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x31, 0x00, + 0x3A, 0x00, 0x30, 0x00, 0x37, 0x00, 0x20, 0x00, 0x50, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xE5, 0xFF, 0x00, 0x72, 0xE5, 0xFF, 0x00, 0x6C, 0xE5, + 0xFF, 0x00, 0x66, 0xE5, 0xFF, 0x00, 0x62, 0xE5, 0xFF, 0x00, 0x5C, 0xE5, 0xFF, 0x00, 0x56, 0xE5, + 0xFF, 0x00, 0x4E, 0xE5, 0xFF, 0x00, 0x44, 0xE5, 0xFF, 0x00, 0x3C, 0xE5, 0xFF, 0x00, 0x32, 0xE5, + 0xFF, 0x00, 0x28, 0xE5, 0xFF, 0x00, 0xC0, 0xE7, 0xFF, 0x00, 0xB4, 0xE7, 0xFF, 0x00, 0xA8, 0xE7, + 0xFF, 0x00, 0x96, 0xE7, 0xFF, 0x00, 0x8A, 0xE7, 0xFF, 0x00, 0x80, 0xE7, 0xFF, 0x00, 0x76, 0xE7, + 0xFF, 0x00, 0x70, 0xE7, 0xFF, 0x00, 0x68, 0xE7, 0xFF, 0x00, 0x5E, 0xE7, 0xFF, 0x00, 0x54, 0xE7, + 0xFF, 0x00, 0x4C, 0xE7, 0xFF, 0x00, 0x40, 0xE7, 0xFF, 0x00, 0x30, 0xE7, 0xFF, 0x00, 0xE4, 0xE7, + 0xFF, 0x00, 0xDA, 0xE7, 0xFF, 0x00, 0xD2, 0xE7, 0xFF, 0x00, 0xFC, 0xE8, 0xFF, 0x00, 0xEE, 0xE8, + 0xFF, 0x00, 0xE0, 0xE8, 0xFF, 0x00, 0xD2, 0xE8, 0xFF, 0x00, 0xC4, 0xE8, 0xFF, 0x00, 0xB6, 0xE8, + 0xFF, 0x00, 0xA6, 0xE8, 0xFF, 0x00, 0x96, 0xE8, 0xFF, 0x00, 0x86, 0xE8, 0xFF, 0x00, 0x76, 0xE8, + 0xFF, 0x00, 0x66, 0xE8, 0xFF, 0x00, 0x56, 0xE8, 0xFF, 0x00, 0x46, 0xE8, 0xFF, 0x00, 0x36, 0xE8, + 0xFF, 0x00, 0x26, 0xE8, 0xFF, 0x00, 0x16, 0xE8, 0xFF, 0x00, 0x06, 0xE8, 0xFF, 0x00, 0xF6, 0xE7, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x86, 0xF2, 0x1A, 0xCA, 0x00, 0x0E, 0xF2, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0E, 0x00, 0x0D, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0B, 0x00, 0x0A, + 0x00, 0x09, 0x00, 0x08, 0x00, 0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, + 0x00, 0x03, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0x10, 0x38, 0x00, 0x78, 0x03, 0x18, 0x10, 0x3E, 0x08, 0x00, 0x03, 0x1E, 0x10, 0x3E, 0x08, 0x00, + 0x03, 0x1E, 0x10, 0x3E, 0x08, 0x00, 0x03, 0x1E, 0x11, 0x3E, 0x08, 0x00, 0x03, 0x1E, 0x12, 0x3E, + 0x00, 0x00, 0x40, 0x01, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x1E, + 0x12, 0x3E, 0x08, 0x00, 0x03, 0x1E, 0x12, 0x3E, 0x08, 0x00, 0x03, 0x1E, 0x12, 0x3E, 0x08, 0x00, + 0x03, 0x1E, 0x12, 0x3E, 0x08, 0x00, 0x03, 0x1E, 0x12, 0x3E, 0x08, 0x00, 0x03, 0x1E, 0x12, 0x3E, + 0x08, 0x00, 0x03, 0x1E, 0x12, 0x3E, 0x08, 0x00, 0x03, 0x1E, 0x12, 0x3E, 0x08, 0x00, 0x03, 0x1E, + 0x12, 0x3E, 0x08, 0x00, 0x03, 0x1E, 0x12, 0x3E, 0x08, 0x00, 0x03, 0x1E, 0x12, 0x3E, 0x08, 0x00, + 0x03, 0x1E, 0x12, 0x3E, 0x08, 0x00, 0x03, 0x1E, 0x13, 0x18, 0x60, 0x88, 0x04, 0x00, 0x14, 0x18, + 0x68, 0x88, 0x04, 0x00, 0x15, 0x18, 0x70, 0x88, 0x04, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0E, 0x00, 0x0D, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0B, 0x00, 0x0A, + 0x00, 0x09, 0x00, 0x08, 0x00, 0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, + 0x00, 0x03, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x07, 0x00, 0x07, 0x00, 0x06, + 0x00, 0x06, 0x00, 0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x46, 0x00, 0x46, 0x00, 0x45, 0x80, 0x46, 0x80, 0x47, 0x00, 0x48, 0x00, 0x47, 0x00, 0x44, + 0x80, 0x44, 0x80, 0x43, 0x00, 0x49, 0x80, 0x49, 0x80, 0x4A, 0x00, 0x4B, 0x00, 0x4A, 0x80, 0x45, + 0xC0, 0x4B, 0x00, 0x4C, 0x80, 0x4B, 0x40, 0x4C, 0x80, 0x4C, 0xC0, 0x4C, 0x00, 0x4D, 0x40, 0x4D, + 0x80, 0x4D, 0xC0, 0x4D, 0x00, 0x4E, 0x40, 0x4E, 0x80, 0x4E, 0xC0, 0x4E, 0x00, 0x4F, 0x40, 0x4F, + 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, 0x06, 0x00, 0x10, 0x01, 0x00, 0xFF, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x11, 0x00, 0x8E, 0x02, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0xA0, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x02, 0x87, 0xFC, 0x00, 0x00, + 0xD6, 0x55, 0xFF, 0x00, 0x30, 0x45, 0x08, 0x08, 0x00, 0x02, 0x01, 0x90, 0xC2, 0x93, 0x01, 0x01, + 0x09, 0x00, 0x01, 0x90, 0xC2, 0x93, 0x01, 0x01, 0x05, 0x00, 0x01, 0x90, 0x42, 0x94, 0x01, 0x01, + 0x09, 0x00, 0x01, 0x90, 0x42, 0x94, 0x01, 0x01, 0x05, 0x00, 0x06, 0x90, 0x80, 0x93, 0x12, 0x03, + 0x06, 0x00, 0x08, 0x81, 0x44, 0x9B, 0x08, 0x01, 0xA1, 0x00, 0x08, 0x81, 0xC2, 0x9B, 0x12, 0x03, + 0x9F, 0x55, 0xFF, 0x00, 0xA2, 0x9C, 0x01, 0x01, 0x3A, 0x5A, 0xFF, 0x00, 0x02, 0x90, 0xC2, 0x93, + 0x12, 0x01, 0x0A, 0x00, 0x02, 0x90, 0x42, 0x94, 0x12, 0x01, 0x1C, 0x00, 0xF0, 0x01, 0x06, 0x90, + 0x80, 0x93, 0x12, 0x03, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x28, 0x56, 0x67, 0x00, 0x18, + 0x00, 0x47, 0x00, 0x18, 0x00, 0x4B, 0x00, 0x18, 0x80, 0x4B, 0x00, 0x18, 0x00, 0x4C, 0x00, 0x00, + 0x00, 0x47, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xFF, 0x47, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xFE, 0x4B, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xFC, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xFB, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xFA, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xF8, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xF6, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xF5, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xF4, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xF3, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xF2, 0xB7, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xF1, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xF0, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xEF, 0x67, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xEE, 0x18, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xED, 0x28, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xEC, 0x28, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xEB, 0x30, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xEA, 0x30, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xE9, 0x38, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xE8, 0x38, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xE7, 0x40, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xE6, 0x40, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xE5, 0x48, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xE4, 0x48, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xE3, 0x48, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xE2, 0x50, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xE1, 0x50, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xE0, 0x58, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xDF, 0x58, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xDE, 0x78, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xDD, 0x80, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xDC, 0x80, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xDB, 0x88, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xDA, 0x88, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xD9, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xD8, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xD7, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xD6, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xD5, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xD4, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xD3, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xD2, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xD1, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xD0, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xCF, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xCE, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xCD, 0x0D, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xCC, 0x1F, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xCB, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xCA, 0x09, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xC9, 0x1F, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xC8, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xC7, 0x01, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xC6, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xC5, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xC4, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xC2, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xBF, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xBE, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xBD, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xBC, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xBB, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xBA, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xB9, 0x01, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xB8, 0x01, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xB7, 0x01, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xB6, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xB5, 0x01, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xB4, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xB3, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xB2, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xB1, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xB0, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xAF, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xAE, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xAD, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xAC, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xAB, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xAA, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xA9, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xA8, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xA7, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xA6, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xA5, 0x01, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xA4, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xA3, 0x01, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xA2, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0xA1, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0xA0, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x9F, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x9E, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x9D, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x9C, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x9B, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x9A, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x99, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x98, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x97, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x96, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x95, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x94, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x93, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x92, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x91, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x90, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x8F, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x8E, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x8D, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x8C, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x8B, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x8A, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x89, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x88, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x87, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x86, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x85, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x84, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x83, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x82, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x81, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x7E, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x7C, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x7B, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x7A, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x79, 0x02, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x77, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x76, 0x01, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x75, 0x65, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x74, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x73, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x72, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x71, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x6E, 0x81, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x6D, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x6C, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x6B, 0x83, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x6A, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x69, 0x81, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x68, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x67, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x66, 0x82, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x65, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x64, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x63, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x62, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x61, 0x80, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x60, 0x82, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x5E, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x5C, 0x80, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x5A, 0x81, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x59, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x58, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x57, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x56, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x55, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x54, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x53, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x52, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x51, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x50, 0x81, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x4F, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x4E, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x4C, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x4B, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x4A, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x49, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x47, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x46, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x45, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x44, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x43, 0x83, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x42, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x41, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x3E, 0x83, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x3C, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x3A, 0x82, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x39, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x38, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x37, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x36, 0x10, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x35, 0x10, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x34, 0x10, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x33, 0x10, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x32, 0x10, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x31, 0x10, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x30, 0x10, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x2F, 0x11, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x2E, 0x11, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x2D, 0x11, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x2C, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x2A, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x29, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x27, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x26, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x25, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x23, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x21, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x1E, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x1C, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x1A, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x19, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x17, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x15, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x13, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x11, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x09, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x07, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x05, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x03, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x01, 0x00, 0x3D, 0x00, 0x3D, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x80, 0x00, 0x00, + 0x85, 0x80, 0x00, 0x00, 0x85, 0x80, 0x00, 0x00, 0x85, 0x80, 0x00, 0x00, 0x05, 0x00, 0x98, 0x00, + 0xE8, 0x00, 0xFA, 0x00, 0x74, 0x01, 0x84, 0x01, 0x85, 0x80, 0x00, 0x00, 0x85, 0x80, 0x00, 0x00, + 0x85, 0x80, 0x00, 0x00, 0x85, 0x80, 0x00, 0x00, 0x85, 0x80, 0x00, 0x00, 0x85, 0x80, 0x00, 0x00, + 0x85, 0x80, 0x00, 0x00, 0x85, 0x80, 0x00, 0x00, 0x85, 0x80, 0x00, 0x00, 0x85, 0x80, 0x00, 0x00, + 0x85, 0x80, 0x00, 0x00, 0x85, 0x80, 0x00, 0x00, 0x85, 0x80, 0x00, 0x00, 0x85, 0x80, 0x00, 0x00, + 0x85, 0x80, 0x00, 0x00, 0x85, 0x80, 0x00, 0x00, 0x85, 0x80, 0x00, 0x00, 0x85, 0x80, 0x00, 0x00, + 0x85, 0x80, 0x00, 0x00, 0x85, 0x80, 0x00, 0x00, 0x85, 0x80, 0x00, 0x00, 0x85, 0x80, 0x00, 0x00, + 0x85, 0x80, 0x00, 0x00, 0x85, 0x80, 0x00, 0x00, 0x85, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x00, 0x00, 0x00, 0x00, 0x64, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xC0, 0x03, 0x00, 0xE7, 0x3F, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x7B, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0xEF, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x00, 0x84, 0x00, + 0x99, 0x01, 0x00, 0x00, 0x18, 0x00, 0x21, 0x01, 0x84, 0x01, 0x00, 0x00, 0x14, 0x00, 0x8D, 0x00, + 0x65, 0x01, 0x00, 0x00, 0xB2, 0x00, 0x54, 0x01, 0x6C, 0x01, 0x00, 0x00, 0x4B, 0x00, 0xA0, 0x00, + 0xEE, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0xFF, 0x05, 0x6C, 0x94, 0x85, 0x7B, 0x0F, 0x00, 0x05, 0x40, 0x0B, 0x00, + 0x0F, 0x00, 0x00, 0x40, 0x05, 0x40, 0x06, 0x40, 0x07, 0x40, 0x08, 0x40, 0x0A, 0x40, 0x09, 0x40, + 0x01, 0x40, 0x02, 0x40, 0x03, 0x40, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x02, 0x04, 0x04, 0x05, 0x06, 0x04, 0x02, 0x0E, 0x04, 0x04, 0x05, + 0x02, 0x04, 0x05, 0x06, 0x07, 0x07, 0x00, 0xFB, 0x0C, 0x00, 0xDE, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x27, 0x7D, 0x00, 0x00, 0x0F, 0x7A, 0x00, 0x00, 0xAC, 0x7F, 0x00, 0x00, 0x27, 0x7D, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xAB, 0x26, 0x00, 0x12, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x18, 0x58, 0x00, 0x00, 0x80, 0x98, 0x00, 0xAC, 0x00, 0x62, 0xFF, 0x00, 0x10, 0x10, + 0x10, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4A, 0x61, 0x6E, 0x2E, 0x20, 0x20, 0x31, 0x20, 0x20, 0x31, 0x39, 0x39, 0x39, 0x20, 0x30, 0x20, + 0x30, 0x30, 0x20, 0x41, 0x4D, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x19, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x99, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5E, 0x68, 0xFF, 0x00, 0x40, 0x64, 0x80, 0x64, 0x00, 0x10, 0xFF, 0x00, 0xD6, 0x35, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC2, 0x39, 0xFF, 0x00, 0x40, 0x60, 0x00, 0x62, 0x00, 0x20, 0x00, 0x00, 0x00, 0x60, 0xFF, 0x00, + 0x00, 0x00, 0x18, 0x58, 0xFC, 0x00, 0x00, 0x04, 0x06, 0x0C, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x12, 0x44, 0xFF, 0x00, 0xC0, 0x63, 0x80, 0x64, 0x00, 0x80, 0xFF, 0x00, 0x80, 0x60, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0xE0, 0x58, 0x00, + 0x44, 0x48, 0x03, 0x01, 0x03, 0x00, 0x80, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x44, 0xFF, 0x00, 0x40, 0x44, 0xFF, 0x00, 0x40, 0x63, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xCF, 0x45, 0xFF, 0x00, 0x00, 0x63, 0x40, 0x61, 0x00, 0x60, 0xFF, 0x00, 0x80, 0x60, 0x00, 0x00, + 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x00, 0x02, 0x04, 0xE0, 0xC8, 0x00, + 0x20, 0x50, 0x05, 0x02, 0x03, 0x01, 0x80, 0x00, 0x00, 0x00, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x71, 0x46, 0xFF, 0x00, 0x61, 0x46, 0xFF, 0x00, 0x00, 0x62, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xCF, 0x45, 0xFF, 0x00, 0x00, 0x63, 0x80, 0x64, 0x00, 0x68, 0xFF, 0x00, 0x80, 0x60, 0x00, 0x00, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x00, 0x02, 0x04, 0xE0, 0xC8, 0x00, + 0x58, 0x50, 0x05, 0x02, 0x03, 0x01, 0x80, 0x00, 0x00, 0x00, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x71, 0x46, 0xFF, 0x00, 0x61, 0x46, 0xFF, 0x00, 0x00, 0x62, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xCF, 0x45, 0xFF, 0x00, 0xC0, 0x62, 0xC0, 0x63, 0x00, 0x68, 0xFF, 0x00, 0x80, 0x60, 0x00, 0x00, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x00, 0x01, 0x06, 0xE0, 0x58, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, 0x0F, + 0x00, 0x00, 0x0A, 0x00, 0xCF, 0x09, 0xFF, 0x0F, 0x00, 0x0F, 0xFF, 0x0F, 0x3F, 0x00, 0xFF, 0x0F, + 0x55, 0x07, 0xF5, 0x08, 0xF5, 0x08, 0xFF, 0x0F, 0x40, 0x0D, 0x40, 0x0D, 0x40, 0x0D, 0xFF, 0x0F, + 0xFF, 0x0F, 0x9F, 0x00, 0x00, 0x06, 0xFF, 0x0F, 0xFF, 0x0F, 0x22, 0x08, 0x00, 0x07, 0xFF, 0x0F, + 0x90, 0x0B, 0x80, 0x0A, 0x70, 0x0A, 0xFF, 0x0F, 0x70, 0x0A, 0x60, 0x09, 0x50, 0x09, 0xFF, 0x0F, + 0x50, 0x09, 0x40, 0x09, 0x31, 0x08, 0xFF, 0x0F, 0x31, 0x08, 0x22, 0x08, 0x00, 0x07, 0xFF, 0x0F, + 0xFF, 0x0F, 0x88, 0x08, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0x88, 0x08, 0x00, 0x00, 0xFF, 0x0F, + 0xE2, 0x0F, 0xFB, 0x0F, 0x5F, 0x0F, 0xFF, 0x0F, 0x3F, 0x00, 0xFF, 0x0F, 0x3F, 0x00, 0xFF, 0x0F, + 0xFF, 0x0F, 0x88, 0x08, 0x00, 0x00, 0xFF, 0x0F, 0x10, 0x0A, 0xFF, 0x0F, 0x50, 0x0F, 0xFF, 0x0F, + 0x00, 0x00, 0x0F, 0x00, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x06, 0x00, 0x00, 0xFF, 0x0F, + 0xFF, 0x0F, 0x9F, 0x00, 0x00, 0x06, 0xFF, 0x0F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, + 0xCC, 0x0F, 0xCC, 0x0F, 0x77, 0x09, 0xFF, 0x0F, 0xCC, 0x0F, 0x68, 0x06, 0x77, 0x09, 0xFF, 0x0F, + 0xCD, 0x0A, 0x68, 0x06, 0x48, 0x02, 0xFF, 0x0F, 0x77, 0x09, 0x68, 0x06, 0x48, 0x02, 0xFF, 0x0F, + 0xCC, 0x0F, 0x77, 0x09, 0xC0, 0x0F, 0xFF, 0x0F, 0x6F, 0x00, 0x4F, 0x00, 0xAF, 0x00, 0xFF, 0x0F, + 0xF3, 0x0F, 0x4B, 0x06, 0x16, 0x01, 0xFF, 0x0F, 0xF3, 0x0F, 0x50, 0x0E, 0x16, 0x01, 0xFF, 0x0F, + 0x4B, 0x06, 0x4B, 0x06, 0x16, 0x01, 0xFF, 0x0F, 0x4B, 0x06, 0x18, 0x03, 0x16, 0x01, 0xFF, 0x0F, + 0x4B, 0x06, 0x50, 0x0E, 0x16, 0x01, 0xFF, 0x0F, 0x4B, 0x06, 0x16, 0x01, 0x07, 0x02, 0xFF, 0x0F, + 0xF9, 0x0D, 0x8D, 0x04, 0xAA, 0x0C, 0xFF, 0x0F, 0xB0, 0x0B, 0x20, 0x02, 0x40, 0x04, 0xFF, 0x0F, + 0xFF, 0x0F, 0x50, 0x05, 0x1F, 0x08, 0xFF, 0x0F, 0x80, 0x08, 0x50, 0x05, 0x81, 0x08, 0xFF, 0x0F, + 0xB0, 0x0B, 0x70, 0x07, 0x50, 0x05, 0xFF, 0x0F, 0xFF, 0x01, 0xEB, 0x0F, 0xC0, 0x0F, 0xFF, 0x0F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xD5, 0x35, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xD6, 0x35, 0xFF, 0x00, 0x40, 0x64, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x40, 0x60, 0x80, 0x60, 0xC0, 0x60, 0x00, 0x61, 0x40, 0x61, 0x80, 0x61, 0xC0, 0x61, + 0x00, 0x62, 0x40, 0x62, 0x80, 0x62, 0xC0, 0x62, 0x00, 0x63, 0x40, 0x63, 0x80, 0x63, 0xC0, 0x63, + 0x02, 0x00, 0x02, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x63, 0xA1, + 0x4D, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x12, 0x17, 0x10, 0x42, 0x43, 0xE1, 0x1A, 0xBD, 0x7E, + 0xFF, 0x06, 0xD8, 0x03, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x88, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x60, 0x30, 0x00, 0x00, 0x06, 0x10, 0x60, 0x36, 0x08, 0x00, + 0x06, 0x16, 0x61, 0x36, 0x08, 0x00, 0x06, 0x16, 0x62, 0x36, 0x08, 0x00, 0x06, 0x16, 0x63, 0x36, + 0x08, 0x00, 0x06, 0x16, 0x64, 0x36, 0x08, 0x00, 0x06, 0x16, 0x61, 0x16, 0x08, 0x00, 0x07, 0x16, + 0x62, 0x16, 0x08, 0x00, 0x07, 0x16, 0x63, 0x16, 0x08, 0x00, 0x07, 0x16, 0x64, 0x16, 0x08, 0x00, + 0x07, 0x16, 0x61, 0x36, 0x08, 0x00, 0x08, 0x16, 0x62, 0x36, 0x08, 0x00, 0x08, 0x16, 0x63, 0x36, + 0x08, 0x00, 0x08, 0x16, 0x64, 0x36, 0x08, 0x00, 0x08, 0x16, 0x61, 0x16, 0x08, 0x00, 0x09, 0x16, + 0x62, 0x16, 0x08, 0x00, 0x09, 0x16, 0x63, 0x16, 0x08, 0x00, 0x09, 0x16, 0x64, 0x16, 0x08, 0x00, + 0x09, 0x16, 0x64, 0x16, 0x08, 0x00, 0x09, 0x16, 0x64, 0x16, 0x08, 0x00, 0x09, 0x16, 0x65, 0x16, + 0x68, 0x08, 0x05, 0x16, 0x65, 0x16, 0x08, 0x00, 0x05, 0x16, 0x65, 0x16, 0x08, 0x00, 0x05, 0x16, + 0x65, 0x16, 0x08, 0x00, 0x05, 0x16, 0x65, 0x16, 0x08, 0x00, 0x05, 0x16, 0x65, 0x16, 0x08, 0x00, + 0x05, 0x16, 0x65, 0x16, 0x08, 0x00, 0x05, 0x16, 0x65, 0x16, 0x08, 0x00, 0x05, 0x16, 0x65, 0x16, + 0x08, 0x00, 0x05, 0x16, 0x65, 0x16, 0x08, 0x00, 0x05, 0x16, 0x65, 0x16, 0x08, 0x00, 0x05, 0x16, + 0x65, 0x16, 0x08, 0x00, 0x05, 0x16, 0x65, 0x16, 0x08, 0x00, 0x05, 0x16, 0x65, 0x16, 0x08, 0x00, + 0x05, 0x16, 0x65, 0x16, 0x08, 0x00, 0x05, 0x16, 0x65, 0x16, 0x08, 0x00, 0x05, 0x16, 0x65, 0x16, + 0x08, 0x00, 0x05, 0x16, 0x65, 0x16, 0x08, 0x00, 0x05, 0x16, 0x65, 0x16, 0x08, 0x00, 0x05, 0x16, + 0x65, 0x16, 0x08, 0x00, 0x05, 0x16, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, + 0xEF, 0x0B, 0x60, 0x0F, 0x00, 0x01, 0x4D, 0x00, 0xFF, 0x0F, 0x97, 0x08, 0x54, 0x02, 0x4D, 0x00, + 0xFF, 0x0F, 0x97, 0x08, 0x54, 0x02, 0x9B, 0x00, 0xD9, 0x0F, 0x64, 0x0B, 0x00, 0x06, 0xA5, 0x00, + 0xFD, 0x0F, 0x94, 0x0B, 0x22, 0x06, 0xA5, 0x00, 0xFD, 0x0F, 0x94, 0x0B, 0x22, 0x06, 0xA5, 0x00, + 0xFD, 0x0F, 0x94, 0x0B, 0x22, 0x06, 0xA5, 0x00, 0xFD, 0x0F, 0x94, 0x0B, 0x22, 0x06, 0xA5, 0x00, + 0xFD, 0x0F, 0x94, 0x0B, 0x22, 0x06, 0xA5, 0x00, 0xFD, 0x0F, 0x94, 0x0B, 0x22, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x07, + 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x08, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x89, 0x00, 0x00, 0x80, 0x00, 0xA0, 0x00, 0x00, 0x05, 0x03, 0xF0, 0x20, 0x10, 0x05, + 0x0A, 0x00, 0x85, 0x0D, 0xC2, 0x75, 0x00, 0x00, 0x91, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x18, 0x28, 0x00, 0x01, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xA8, 0x93, 0x2B, 0x00, 0x9E, 0x78, 0x20, 0x00, 0x0A, 0x01, 0x00, 0x00, 0xFF, 0x03, 0x00, 0x00, + 0x84, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x39, 0x26, 0x00, 0x31, 0x54, 0x45, 0x4D, 0x00, 0xFF, + 0x11, 0x00, 0x05, 0x0B, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x02, 0x3B, 0x48, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A, 0x08, 0x0A, 0x08, 0x12, 0x10, 0x12, 0x1A, 0x18, + 0x1A, 0x18, 0x1A, 0x0A, 0x08, 0x0A, 0x01, 0x01, 0x00, 0xFC, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x49, 0xE6, 0x6B, 0x39, 0x49, 0xE6, 0x6B, + 0x21, 0x00, 0x00, 0x98, 0x09, 0x00, 0x0F, 0x00, 0x03, 0x00, 0x12, 0x2F, 0x23, 0x00, 0x00, 0x98, + 0x09, 0x00, 0x0D, 0x00, 0x03, 0x00, 0xCC, 0x2E, 0x23, 0x00, 0x39, 0x49, 0xE6, 0x6B, 0x21, 0x00, + 0x00, 0x98, 0x09, 0x00, 0x0F, 0x00, 0x03, 0x00, 0x08, 0x2F, 0x23, 0x00, 0x00, 0x98, 0x4C, 0x01, + 0x00, 0x00, 0x3A, 0x6F, 0x20, 0x00, 0x0A, 0xE4, 0xD4, 0xE4, 0x22, 0x00, 0x1C, 0x6F, 0x20, 0x83, + 0x40, 0x83, 0x40, 0x25, 0x00, 0xA1, 0x02, 0x80, 0x00, 0xFF, 0xA7, 0x83, 0x40, 0x25, 0x00, 0xA1, + 0x02, 0x83, 0x40, 0x25, 0x00, 0xA1, 0x02, 0x80, 0x00, 0xFF, 0xAA, 0x22, 0x28, 0x83, 0x40, 0x25, + 0x00, 0xA1, 0x02, 0x80, 0x00, 0xFF, 0x3B, 0xEC, 0x2E, 0x00, 0x80, 0x83, 0x40, 0x25, 0x00, 0x83, + 0xE5, 0x25, 0xFF, 0x00, 0x12, 0x20, 0xFF, 0x00, 0xB3, 0x1F, 0xFF, 0x00, 0x80, 0x64, 0x00, 0x00, + 0x8C, 0x1F, 0xFF, 0x00, 0xC3, 0x23, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, + 0xE5, 0x34, 0xFF, 0x00, 0x40, 0x50, 0x00, 0x60, 0x00, 0x00, 0xE5, 0x25, 0xFF, 0x00, 0x12, 0x20, + 0xFF, 0x00, 0xB3, 0x1F, 0xDA, 0x01, 0xE5, 0x25, 0xFF, 0x00, 0x12, 0x20, 0xFF, 0x00, 0xB3, 0x1F, + 0xFF, 0x00, 0x80, 0x64, 0x00, 0x00, 0xC5, 0x50, 0xFF, 0x00, 0x58, 0x6E, 0x00, 0x00, 0x40, 0x50, + 0x00, 0x00, 0x20, 0x70, 0xFF, 0x00, 0xF9, 0x70, 0xFF, 0x00, 0xDF, 0x23, 0xFF, 0x00, 0x00, 0x00, + 0xC3, 0x23, 0xFF, 0x00, 0x10, 0xFB, 0x9D, 0x27, 0xFF, 0x00, 0x00, 0xF8, 0xE4, 0x00, 0x20, 0x00, + 0x89, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x66, 0x4D, 0x65, 0x6D, 0x6F, 0x72, 0x79, 0x20, 0x20, + 0x44, 0x75, 0x6D, 0x70, 0xDD, 0x00, 0xBD, 0x01, 0xC1, 0x01, 0x58, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0xDE, 0x0A, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBA, 0xAA, 0xBA, + 0xAA, 0xAA, 0xAA, 0x75, 0xA5, 0xDE, 0x77, 0xF5, 0xDF, 0xFD, 0xFF, 0xF7, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x6F, 0xFF, 0x00, 0x40, 0x14, 0xFF, + 0x00, 0xFF, 0x5A, 0x75, 0xD5, 0x01, 0x77, 0x00, 0x03, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0xFD, 0x77, 0x77, + 0xFF, 0xFF, 0x55, 0x99, 0x55, 0x65, 0x55, 0x95, 0x55, 0x65, 0xA5, 0xA5, 0xA5, 0x5A, 0x00, 0x55, + 0x00, 0x04, 0x5A, 0x04, 0xA7, 0x95, 0x55, 0x02, 0x5A, 0x04, 0xA5, 0x95, 0x53, 0x02, 0x5A, 0x04, + 0xA3, 0x95, 0x51, 0x02, 0x5A, 0x04, 0xA1, 0x95, 0x4F, 0x02, 0x5A, 0x04, 0x9F, 0x95, 0x4C, 0x02, + 0x5A, 0x04, 0x9D, 0x95, 0x48, 0x02, 0x5A, 0x04, 0x9C, 0x95, 0x44, 0x02, 0xAF, 0x95, 0x56, 0x02, + 0x5A, 0x04, 0xAD, 0x95, 0x56, 0x02, 0x5A, 0x04, 0xAB, 0x95, 0x56, 0x02, 0x5A, 0x04, 0xA9, 0x95, + 0x02, 0x5A, 0x04, 0x92, 0x97, 0x54, 0x02, 0x5A, 0x04, 0x8F, 0x97, 0x52, 0x02, 0x5A, 0x04, 0x8C, + 0x97, 0x4F, 0x02, 0x5A, 0x04, 0x88, 0x97, 0x4C, 0x02, 0x5A, 0x04, 0x85, 0x97, 0x49, 0x02, 0x5A, + 0x04, 0x81, 0x97, 0x45, 0x02, 0x5A, 0x04, 0x33, 0x41, 0x01, 0x90, 0x9E, 0x97, 0x57, 0x02, 0x5A, + 0x04, 0x9B, 0x97, 0x57, 0x02, 0x5A, 0x04, 0x98, 0x97, 0x56, 0x02, 0x5A, 0x04, 0x95, 0x97, 0x55, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x55, 0x55, 0x66, 0x55, 0x55, 0x66, 0x66, + 0x55, 0x55, 0xA5, 0x66, 0x55, 0x6A, 0xA5, 0x95, 0xA5, 0x6A, 0xA9, 0xAA, 0xA9, 0x6A, 0xA9, 0x6A, + 0xAA, 0x5A, 0xA5, 0x66, 0xA5, 0x55, 0xCB, 0x04, 0xC0, 0xB2, 0x23, 0xC0, 0xB2, 0x3E, 0x01, 0x14, + 0x3A, 0x1E, 0x12, 0x00, 0x5A, 0x15, 0xC1, 0x05, 0x6D, 0x3F, 0xFF, 0x66, 0x06, 0xCB, 0xCE, 0xFE, + 0xC0, 0xB2, 0xCB, 0xCB, 0x05, 0x07, 0xC0, 0x51, 0x21, 0xC9, 0xCC, 0x1C, 0x66, 0x04, 0xF1, 0x06, + 0x6D, 0x41, 0xC1, 0x01, 0x6D, 0x21, 0xC1, 0x01, 0x6D, 0x61, 0xC1, 0x03, 0x6D, 0x81, 0xC9, 0xCC, + 0x3F, 0xF1, 0xC0, 0x6C, 0x32, 0xF3, 0x03, 0xE8, 0xE0, 0x14, 0x50, 0x00, 0xC1, 0x01, 0x6D, 0x3F, + 0x37, 0x6A, 0x06, 0xF1, 0x05, 0x6D, 0x00, 0x00, 0x0E, 0xF1, 0x05, 0x6D, 0x00, 0xFF, 0x0E, 0xAA, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x00, 0x00, 0xFC, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x55, 0x55, + 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xF7, 0xFF, 0xFD, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xDD, 0x0D, 0xBB, 0x0B, 0x99, 0x09, + 0x77, 0x07, 0x44, 0x04, 0x33, 0x03, 0x00, 0x00, 0xFF, 0x0F, 0xDD, 0x0D, 0xBB, 0x0B, 0x99, 0x09, + 0x77, 0x07, 0x44, 0x04, 0x33, 0x03, 0x00, 0x00, 0xFF, 0x0F, 0xDD, 0x0D, 0xBB, 0x0B, 0x99, 0x09, + 0x77, 0x07, 0x44, 0x04, 0x33, 0x03, 0x00, 0x00, 0xFF, 0x0F, 0xDD, 0x0D, 0xBB, 0x0B, 0x99, 0x09, + 0x77, 0x07, 0x44, 0x04, 0x33, 0x03, 0x00, 0x00, 0xFF, 0x0F, 0xDD, 0x0D, 0xBB, 0x0B, 0x99, 0x09, + 0x77, 0x07, 0x44, 0x04, 0x33, 0x03, 0x00, 0x00, 0xFF, 0x0F, 0xDD, 0x0D, 0xBB, 0x0B, 0x99, 0x09, + 0x77, 0x07, 0x44, 0x04, 0x33, 0x03, 0x00, 0x00, 0xFF, 0x0F, 0xDD, 0x0D, 0xBB, 0x0B, 0x99, 0x09, + 0x77, 0x07, 0x44, 0x04, 0x33, 0x03, 0x00, 0x00, 0xFF, 0x0F, 0xDD, 0x0D, 0xBB, 0x0B, 0x99, 0x09, + 0x77, 0x07, 0x44, 0x04, 0x33, 0x03, 0x00, 0x00, 0x2A, 0x00, 0x55, 0xF3, 0xF1, 0x55, 0x55, 0x00, + 0xF0, 0x0E, 0xFF, 0xFF, 0x03, 0x00, 0x66, 0x08, 0xB2, 0xCD, 0x66, 0xEE, 0x82, 0xF0, 0x66, 0x02, + 0x21, 0xFF, 0x0E, 0x69, 0x55, 0x69, 0x55, 0x59, 0x95, 0x5A, 0x95, 0x5A, 0xA5, 0x5A, 0xA5, 0x5A, + 0xFF, 0x5A, 0x00, 0x00, 0x00, 0x01, 0x22, 0x01, 0x01, 0x00, 0x00, 0x00, 0x22, 0xE8, 0x26, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0x50, 0x4E, 0xA9, 0x55, 0x69, 0x56, 0x69, 0x55, 0x69, 0x56, 0x6A, + 0x55, 0x5A, 0xAA, 0x76, 0xAA, 0x57, 0xAA, 0x75, 0xEA, 0x55, 0x6A, 0x77, 0x5A, 0x55, 0x5E, 0x77, + 0x57, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x59, 0x55, + 0xCF, 0x07, 0x01, 0x01, 0x57, 0x55, 0x5F, 0x55, 0x5F, 0x55, 0xAF, 0x99, 0x7F, 0x55, 0x9A, 0x99, + 0x66, 0x56, 0x7F, 0x66, 0xFF, 0x99, 0xFF, 0xA7, 0xFF, 0x9F, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA9, 0xAA, 0xAA, 0xAA, 0xA9, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x56, 0x66, 0x75, 0xDD, 0x5D, 0x57, 0x77, 0xFF, 0x5F, 0x77, 0x77, + 0xDD, 0x5D, 0x69, 0xA5, 0x56, 0x65, 0x55, 0x59, 0xDD, 0x99, 0x77, 0x76, 0xD5, 0x7D, 0x75, 0x75, + 0x55, 0xDD, 0xFF, 0x6B, 0xFF, 0xDD, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x99, 0xD9, 0xAA, 0xDA, 0x99, 0xD9, 0xAA, 0xDA, 0x99, 0xD9, 0xAA, 0xEA, 0x99, 0x69, + 0xAA, 0x6A, 0x65, 0x65, 0x95, 0x55, 0xA5, 0x65, 0x95, 0x55, 0xA5, 0x65, 0x95, 0x55, 0xA5, 0x65, + 0xDC, 0x02, 0x00, 0x40, 0x40, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x03, 0x00, 0x00, 0x00, 0x6A, 0x66, 0x6A, 0x55, 0x5A, 0x66, 0x5A, 0x55, 0x5A, 0x66, + 0x5A, 0x55, 0x69, 0x66, 0x5A, 0x55, 0x6A, 0x56, 0x56, 0x55, 0x66, 0x55, 0x56, 0x55, 0x66, 0x55, + 0x55, 0x55, 0xA9, 0x56, 0xAA, 0x56, 0xAA, 0x55, 0x88, 0x00, 0x20, 0x00, 0x88, 0x00, 0x20, 0x00, + 0x88, 0x00, 0x20, 0x00, 0x88, 0x00, 0x20, 0x00, 0x88, 0x00, 0x20, 0x00, 0x88, 0x00, 0x20, 0x00, + 0x88, 0x00, 0x20, 0x00, 0x88, 0x00, 0x20, 0x00, 0x88, 0x00, 0x20, 0x00, 0x88, 0x00, 0x20, 0x00, + 0x88, 0x00, 0x20, 0x00, 0x88, 0x00, 0x20, 0x00, 0x88, 0x00, 0x20, 0x00, 0x88, 0x00, 0x20, 0x00, + 0x88, 0x00, 0x20, 0x00, 0x88, 0x00, 0x20, 0x00, 0x88, 0x00, 0x20, 0x00, 0x88, 0x00, 0x20, 0x00, +} ; diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..576ac3f --- /dev/null +++ b/main.cpp @@ -0,0 +1,577 @@ +//--------------------------------------------------------------------------- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. See also the license.txt file for +// additional informations. +//--------------------------------------------------------------------------- + +// +// This is the main program entry point +// + +#ifndef TARGET_PSP +#include +#include +#endif + +#include "unzip.h" + +#ifndef __GP32__ +#include "StdAfx.h" +#endif + +#include "main.h" + + +//#include "msounds.h" +#include "memory.h" +//#include "mainemu.h" +#include "tlcs900h.h" +#include "input.h" + +#include "graphics.h" +#include "tlcs900h.h" +#ifndef __GP32__ +//#include "timer.h" +#endif + +#include "neopopsound.h" + +#ifdef DRZ80 +#include "DrZ80_support.h" +#else +#if defined(CZ80) +#include "cz80_support.h" +#else +#include "z80.h" +#endif +#endif + +#ifdef __GP32__ +#include "fileio.h" +#include "gfx.h" +#elif !defined(TARGET_PSP) +SDL_Surface* screen = NULL; // Main program screen +SDL_Surface* actualScreen = NULL; // Main program screen +#endif + +extern int finscan; +extern int idioma; +extern int tipo_consola; + +BOOL m_bIsActive; +int exitNow=0; +EMUINFO m_emuInfo; +SYSTEMINFO m_sysInfo[NR_OF_SYSTEMS]; + +FILE *errorLog = NULL; +FILE *outputRam = NULL; + +#define numberof(a) (sizeof(a)/sizeof(*(a))) + +void mainemuinit() +{ + // initialize cpu memory + mem_init(); +#ifndef __GP32__ + graphics_init(NULL); +#else + graphics_init(); +#endif + + // initialize the TLCS-900H cpu + tlcs_init(); + +#if defined(DRZ80) || defined(CZ80) + Z80_Init(); + Z80_Reset(); +#else + z80Init(); +#endif + + // if neogeo pocket color rom, act if we are a neogeo pocket color + tlcsMemWriteB(0x6F91,tlcsMemReadB(0x00200023)); + if (tipo_consola==1) tlcsMemWriteB(0x6F91,0x00); + + // pretend we're running in English mode + + //NOTA IDIOMA 00 Ingles - 01 Jap + if (idioma == 0){ + tlcsMemWriteB(0x00006F87,0x01);} + if (idioma == 1){ + tlcsMemWriteB(0x00006F87,0x00);} + + // kludges & fixes + switch (tlcsMemReadW(0x00200020)) + { + case 0x0059: // Sonic + case 0x0061: // Metal SLug 2nd + *get_address(0x0020001F) = 0xFF; + break; + } + ngpSoundOff(); + //Flavor sound_start(); +} + +#if !defined(__GP32__) && !defined(TARGET_PSP) + +void AfxMessageBox(char *a, int b, int c) +{ + dbg_print(a); +} +void AfxMessageBox(char *a, int b) +{ + dbg_print(a); +} +void AfxMessageBox(char *a) +{ + dbg_print(a); +} + +#endif + +void SetActive(BOOL bActive) +{ + m_bIsActive = bActive; +} + +void SetEmu(int machine) +{ + m_emuInfo.machine = machine; + m_emuInfo.drv = &m_sysInfo[machine]; +} + +bool initRom() +{ + char *licenseInfo = " BY SNK CORPORATION"; + char *ggLicenseInfo = "TMR SEGA"; + BOOL romFound = TRUE; + int i, m; + + finscan=198; + + if (mainrom[0x000020] == 0x65 || mainrom[0x000020] == 0x93) + { + finscan=199; + } + + + //dbg_print("in openNgp(%s)\n", lpszPathName); + + // first stop the current emulation + //dbg_print("openNgp: SetEmu(NONE)\n"); + SetEmu(NGPC); + //dbg_print("openNgp: SetActive(FALSE)\n"); + SetActive(FALSE); + + // check NEOGEO POCKET + // check license info + for (i=0;i<19;i++) + { + if (mainrom[0x000009 + i] != licenseInfo[i]) + romFound = FALSE; + } + if (romFound) + { + //dbg_print("openNgp: romFound == TRUE\n"); + i = mainrom[0x000023]; + if (i == 0x10 || i == 0x00) + { + // initiazlie emulation + if (i == 0x10) { + m = NGPC; + } else { + // fix for missing Mono/Color setting in Cool Coom Jam SAMPLE rom + if (mainrom[0x000020] == 0x34 && mainrom[0x000021] == 0x12) + m = NGPC; + else m = NGP; + } + if (tipo_consola==1) m = NGP; + + //dbg_print("openNgp: SetEmu(%d)\n", m); + SetEmu(m); + + //dbg_print("openNgp: Calling mainemuinit(%s)\n", lpszPathName); + mainemuinit(); + // start running the emulation loop + //dbg_print("openNgp: SetActive(TRUE)\n"); + SetActive(TRUE); + + // acknowledge opening of the document went fine + //dbg_print("openNgp: returning success\n"); + return TRUE; + } + + fprintf(stderr, "Not a valid or unsupported rom file.\n"); + return FALSE; + } + + fprintf(stderr, "Not a valid or unsupported rom file. romFound==FALSE\n"); + return FALSE; +} + +void initSysInfo() +{ + m_bIsActive = FALSE; + + m_emuInfo.machine = NGPC; + m_emuInfo.drv = &m_sysInfo[m_emuInfo.machine]; + m_emuInfo.romSize = 0; + +/* strcpy(m_emuInfo.ProgramFolder, ""); + strcpy(m_emuInfo.SavePath, ""); + strcpy(m_emuInfo.DebugPath, ""); + strcpy(m_emuInfo.RomPath, ""); + strcpy(m_emuInfo.OpenFileName, ""); + strcpy(m_emuInfo.SaveFileName, ""); + strcpy(m_emuInfo.OpenFileName, ""); + strcpy(m_emuInfo.DebugPath, "");; + strcpy(m_emuInfo.RomFileName, ""); + strcpy(m_emuInfo.SaveFileName, ""); + strcpy(m_emuInfo.ScreenPath, "");*/ + strcpy(m_emuInfo.RomFileName, ""); +#define NO_SOUND_OUTPUT +#ifdef NO_SOUND_OUTPUT + m_emuInfo.sample_rate = 0; +#else + m_emuInfo.sample_rate = 44100; +#endif + m_emuInfo.stereo = 1; + //m_emuInfo.fps = 60;//30;//100; //Flavor, tweak this! + +/* m_sysInfo[NONE].hSize = 160; + m_sysInfo[NONE].vSize = 152; + m_sysInfo[NONE].Ticks = 0; + //m_sysInfo[NONE].sound[0].sound_type = 0;*/ + + m_sysInfo[NGP].hSize = 160; + m_sysInfo[NGP].vSize = 152; + m_sysInfo[NGP].Ticks = 6*1024*1024; +/* m_sysInfo[NGP].sound[0].sound_type = SOUND_SN76496; + m_sysInfo[NGP].sound[0].sound_interface = new_SN76496(1, 3*1024*1024, MIXER(50,MIXER_PAN_CENTER)); + m_sysInfo[NGP].sound[1].sound_type = SOUND_DAC; + m_sysInfo[NGP].sound[1].sound_interface = new_DAC(2,MIXER(50,MIXER_PAN_LEFT),MIXER(50,MIXER_PAN_RIGHT)); + m_sysInfo[NGP].sound[2].sound_type = 0; + m_sysInfo[NGP].Back0 = TRUE; + m_sysInfo[NGP].Back1 = TRUE; + m_sysInfo[NGP].Sprites = TRUE;*/ + + m_sysInfo[NGPC].hSize = 160; + m_sysInfo[NGPC].vSize = 152; + m_sysInfo[NGPC].Ticks = 6*1024*1024; +/* m_sysInfo[NGPC].sound[0].sound_type = SOUND_SN76496; + m_sysInfo[NGPC].sound[0].sound_interface = new_SN76496(1, 3*1024*1024, 50); + m_sysInfo[NGPC].sound[1].sound_type = SOUND_DAC; + m_sysInfo[NGPC].sound[1].sound_interface = new_DAC(2,MIXER(50,MIXER_PAN_LEFT),MIXER(50,MIXER_PAN_RIGHT)); + m_sysInfo[NGPC].sound[2].sound_type = 0; + m_sysInfo[NGPC].Back0 = TRUE; + m_sysInfo[NGPC].Back1 = TRUE; + m_sysInfo[NGPC].Sprites = TRUE;*/ +} + +char *getFileNameExtension(char *nom_fichier) { + char *ptrPoint = nom_fichier; + while(*nom_fichier) { + if (*nom_fichier == '.') + ptrPoint = nom_fichier; + nom_fichier++; + } + return ptrPoint; +} + +int loadFromZipByName(unsigned char *buffer, char *archive, char *filename, int *filesize) +{ + char name[_MAX_PATH]; + //unsigned char *buffer; + int i; + const char *recognizedExtensions[] = { + ".ngp", + ".npc", + ".ngc" + }; + + int zerror = UNZ_OK; + unzFile zhandle; + unz_file_info zinfo; + + zhandle = unzOpen(archive); + if(!zhandle) return (0); + + /* Seek to first file in archive */ + zerror = unzGoToFirstFile(zhandle); + if(zerror != UNZ_OK) + { + unzClose(zhandle); + return (0); + } + + //On scanne tous les fichiers de l'archive et ne prend que ceux qui ont une extension valable, sinon on prend le dernier fichier trouvé... + while (zerror == UNZ_OK) { + if (unzGetCurrentFileInfo(zhandle, &zinfo, name, 0xff, NULL, 0, NULL, 0) != UNZ_OK) { + unzClose(zhandle); + return 0; + } + + //Vérifions que c'est la bonne extension + char *extension = getFileNameExtension(name); + + for (i=0;i (4*1024*1024)) + { + unzClose(zhandle); + return (0); + } + + /* Open current file */ + zerror = unzOpenCurrentFile(zhandle); + if(zerror != UNZ_OK) + { + unzClose(zhandle); + return (0); + } + + /* Allocate buffer and read in file */ + //buffer = malloc(*filesize); + //if(!buffer) return (NULL); + zerror = unzReadCurrentFile(zhandle, buffer, *filesize); + + /* Internal error: free buffer and close file */ + if(zerror < 0 || zerror != *filesize) + { + //free(buffer); + //buffer = NULL; + unzCloseCurrentFile(zhandle); + unzClose(zhandle); + return (0); + } + + /* Close current file and archive file */ + unzCloseCurrentFile(zhandle); + unzClose(zhandle); + + memcpy(filename, name, _MAX_PATH); + return 1; +} + +/* + Verifies if a file is a ZIP archive or not. + Returns: 1= ZIP archive, 0= not a ZIP archive +*/ +int check_zip(char *filename) +{ + unsigned char buf[2]; + FILE *fd = NULL; + fd = fopen(filename, "rb"); + if(!fd) return (0); + fread(buf, 2, 1, fd); + fclose(fd); + if(memcmp(buf, "PK", 2) == 0) return (1); + return (0); +} + +int strrchr2(const char *src, int c) +{ + size_t len; + + len=strlen(src); + while(len>0){ + len--; + if(*(src+len) == c) + return len; + } + + return 0; +} + +int handleInputFile(char *romName) +{ + FILE *romFile; + int iDepth = 0; + int size; + + + initSysInfo(); //initialize it all + + //if it's a ZIP file, we need to handle that here. + iDepth = strrchr2(romName, '.'); + iDepth++; + if( ( strcmp( romName + iDepth, "zip" ) == 0 ) || ( strcmp( romName + iDepth, "ZIP" ) == 0 )) + { + //get ROM from ZIP + if(check_zip(romName)) + { + char name[_MAX_PATH]; + if(!loadFromZipByName(mainrom, romName, name, &size)) + { + fprintf(stderr, "Load failed from %s\n", romName); + return 0; + } + m_emuInfo.romSize = size; + strcpy(m_emuInfo.RomFileName, romName); + } + else + { + fprintf(stderr, "%s not PKZIP file\n", romName); + return 0; + } + } + else + { + //get ROM from binary ROM file + romFile = fopen(romName, "rb"); + if(!romFile) + { + fprintf(stderr, "Couldn't open %s file\n", romName); + return 0; + } + + m_emuInfo.romSize = fread(mainrom, 1, 4*1024*1024, romFile); + strcpy(m_emuInfo.RomFileName, romName); + } + + if(!initRom()) + { + fprintf(stderr, "initRom couldn't handle %s file\n", romName); + return 0; + } + + setFlashSize(m_emuInfo.romSize); + return 1; +} + + +#ifndef TARGET_PSP +int main(int argc, char *argv[]) +{ + char romName[512]; + +#ifdef TARGET_PSP + SetupCallbacks(); + scePowerSetClockFrequency(222, 222, 111); + scePowerSetClockFrequency(266, 266, 133); + scePowerSetClockFrequency(333, 333, 166); +#endif + if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_JOYSTICK) < 0) + { + fprintf(stderr, "SDL_Init failed!\n"); +#ifdef TARGET_PSP + sceKernelExitGame(); +#endif + return -1; + } + // Set up quiting so that it automatically runs on exit. + atexit(SDL_Quit); + + PSP_JoystickOpen(); + + actualScreen = SDL_SetVideoMode (SIZEX, SIZEY, 16, SDL_SWSURFACE); + if (actualScreen == NULL) + { + fprintf(stderr, "SDL_SetVideoMode failed!\n"); +#ifdef TARGET_PSP + sceKernelExitGame(); +#endif + return -1; + } + else + { + dbg_print("screen params: bpp=%d\n", actualScreen->format->BitsPerPixel); + } +#ifdef ZOOM_SUPPORT + screen = SDL_CreateRGBSurface (actualScreen->flags, + actualScreen->w, + actualScreen->h, + actualScreen->format->BitsPerPixel, + actualScreen->format->Rmask, + actualScreen->format->Gmask, + actualScreen->format->Bmask, + actualScreen->format->Amask); + if (screen == NULL) + { + fprintf(stderr, "SDL_CreateRGBSurface failed!\n"); +#ifdef TARGET_PSP + sceKernelExitGame(); +#endif + return -1; + } +#else + screen = actualScreen; +#endif + SDL_ShowCursor(0); //disable the cursor + + /* Set up the SDL_TTF */ + TTF_Init(); + atexit(TTF_Quit); + //printTTF("calling LoadRomFromPSP", 10, TEXT_HEIGHT*1, white, 1, actualScreen, 1); + + sound_system_init(); + while(!exitNow) + { +#ifdef TARGET_WIN + strncpy(romName, argv[1], 500); + dbg_print("Starting emulation on file \"%s\"\n"); +#endif + if(LoadRomFromPSP(romName, actualScreen)<=0) + { + break; + } + SDL_FillRect(actualScreen, NULL, SDL_MapRGB(screen->format,0,0,0));//fill black + SDL_Flip(actualScreen); + +//printTTF(romName, 20, TEXT_HEIGHT*16, white, 1, actualScreen, 1); + + system_sound_chipreset(); //Resets chips + + handleInputFile(romName); + + InitInput(NULL); + + dbg_print("Running NGPC Emulation\n"); + + SDL_PauseAudio(0); //run audio +#ifdef TARGET_PSP + switch(options[PSP_MHZ_OPTION]) + { + case PSP_MHZ_222: + scePowerSetClockFrequency(222, 222, 111); + break; + case PSP_MHZ_266: + scePowerSetClockFrequency(266, 266, 133); + break; + default: + case PSP_MHZ_333: + scePowerSetClockFrequency(333, 333, 166); + break; + } +#endif + ngpc_run(); +#ifdef TARGET_PSP + scePowerSetClockFrequency(333, 333, 166); +#endif + SDL_PauseAudio(1); //pause audio + + flashShutdown(); + } + + //printTTF("EXITING", 10, TEXT_HEIGHT*10, white, 1); +#ifdef TARGET_PSP + sceKernelExitGame(); //Exit the program when it is done. +#endif + return 0; +} +#endif \ No newline at end of file diff --git a/main.h b/main.h new file mode 100644 index 0000000..10aaf7c --- /dev/null +++ b/main.h @@ -0,0 +1,89 @@ +#ifndef MAIN_H +#define MAIN_H + +#include +#include +#include +#include +#include +#include +#include + +#if !defined(__GP32__) && !defined(TARGET_PSP) +#include "GP2X.h" +extern SDL_Surface* screen; +extern SDL_Surface* actualScreen; +#endif + + +struct SYSTEMINFO { + int hSize; + int vSize; + int Ticks; + int InputKeys[12]; + //MachineSound sound[4]; + // Dynamic System Info + BOOL Back0; + BOOL Back1; + BOOL Sprites; +}; + +struct EMUINFO { +/* char ProgramFolder[_MAX_PATH]; // place holders for filenames + char SavePath[_MAX_PATH]; + char DebugPath[_MAX_PATH]; + char RomPath[_MAX_PATH]; + char ScreenPath[_MAX_PATH]; + + char OpenFileName[_MAX_PATH]; // place holders for filenames + char SaveFileName[_MAX_PATH];*/ + char RomFileName[_MAX_PATH]; + + int machine; // what kind of machine should we emulate + int romSize; // what is the size of the currently loaded file + int sample_rate; // what is the current sample rate + int stereo; // play in stereo? + //unsigned int fps; + int samples; + SYSTEMINFO *drv; +}; + +#define KEY_UP 0 +#define KEY_DOWN 1 +#define KEY_LEFT 2 +#define KEY_RIGHT 3 +#define KEY_START 4 +#define KEY_BUTTON_A 5 +#define KEY_BUTTON_B 6 +#define KEY_SELECT 7 +#define KEY_UP_2 8 +#define KEY_DOWN_2 9 +#define KEY_LEFT_2 10 +#define KEY_RIGHT_2 11 + +// Possible Neogeo Pocket versions +#define NGP 0x00 +#define NGPC 0x01 + +#define NR_OF_SYSTEMS 2 + + +extern BOOL m_bIsActive; +extern EMUINFO m_emuInfo; +extern SYSTEMINFO m_sysInfo[NR_OF_SYSTEMS]; +extern int romSize; + +int handleInputFile(char *romName); +void mainemuinit(); + +#ifdef __GP32__ +#define HOST_FPS 60 //100 was what it was, originally +#else +#ifdef TARGET_PSP //to call these FPS is a bit of a misnomer +#define HOST_FPS 60 //the number of frames we want to draw to the host's screen every second +#else +#define HOST_FPS 60 //100 was what it was, originally +#endif +#endif + +#endif diff --git a/memory.cpp b/memory.cpp new file mode 100644 index 0000000..14cdd98 --- /dev/null +++ b/memory.cpp @@ -0,0 +1,526 @@ +//--------------------------------------------------------------------------- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. See also the license.txt file for +// additional informations. +//--------------------------------------------------------------------------- + +// memory.cpp: implementation of the memory class. +// +// Quick & dirty implementation; no rom protection etc. +// +// TODO: +// +////////////////////////////////////////////////////////////////////// + +#ifndef __GP32__ +#include "StdAfx.h" +#endif +#include "main.h" +#include "memory.h" +#include "input.h" // for Gameboy Input +#include "graphics.h" // for i/o ports of the game gear +//#include "mainemu.h" +#include "sound.h" +//#include "z80.h" +#include "tlcs900h.h" +#include "koyote_bin.h" + + +#ifdef DRZ80 +#include "DrZ80_support.h" +/*#else +#if defined(CZ80) +#include "cz80_support.h" +#else +#include "z80.h"*/ +#endif + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + + +// define work memory for neogeo pocket color +// +// internal cpu ram and internal I/O register (2KB + 160 bytes) +//unsigned char cpuram[0x08a0]; +// regular work ram (32 kbytes?) +// on the gameboy maximum of 128kbyte of RAM is possible, plus some internal ram (64KB) +unsigned char __attribute__ ((__aligned__(4))) mainram[(64+32+128)*1024]; +// rom area for roms (4 Megabyte) +unsigned char __attribute__ ((__aligned__(4))) mainrom[4*1024*1024]; +// cpu internal ROM including vector table starting at 0xff0000 +unsigned char __attribute__ ((__aligned__(4))) cpurom[256*1024];//prob only needs 0x10000 +// +unsigned char __attribute__ ((__aligned__(4))) *cpuram; + +// +// preliminary address map: +// +// 0x00000000 - 0x000000ff : cpuram +// 0x00004000 - 0x0000ffff : ram +// 0x00200000 - 0x003fffff : rom (lower 16Mbit) +// 0x00800000 - 0x009fffff : rom (higher 16Mbit) +// 0x00fffe00 - 0x00ffffff : other ram/rom +// + +unsigned char realBIOSloaded = 0; + + +/////////////////////////////////////////////////////////////////// +// +//// z80 memory instructions +// +/////////////////////////////////////////////////////////////////// + +// function place holders +unsigned char (*z80MemReadB)(unsigned short addr); +unsigned short (*z80MemReadW)(unsigned short addr); +void (*z80MemWriteB)(unsigned short addr, unsigned char data); +void (*z80MemWriteW)(unsigned short addr, unsigned short data); +void (*z80PortWriteB)(unsigned char port, unsigned char data); +unsigned char (*z80PortReadB)(unsigned char port); + + + +//////////////////////////////////////////////////////////////////////////////////// +/// +/// Neogeo Pocket z80 functions +/// +//////////////////////////////////////////////////////////////////////////////////// + +unsigned char z80ngpMemReadB(unsigned short addr) { + unsigned char temp; + if (addr < 0x4000) { + return mainram[0x3000 + addr]; + } + switch(addr) { + case 0x4000: // sound chip read + break; + case 0x4001: + break; + case 0x8000: + temp= cpuram[0xBC]; + return temp; + case 0xC000: + break; + } + return 0x00; +} + +unsigned short z80ngpMemReadW(unsigned short addr) +{ + return (z80ngpMemReadB(addr+1) << 8) | z80ngpMemReadB(addr); +} + +void z80ngpMemWriteB(unsigned short addr, unsigned char data) { + if (addr < 0x4000) { + mainram[0x3000 + addr] = data; return; + } + + switch (addr) + { + case 0x4000: + Write_SoundChipNoise(data);//Flavor SN76496Write(0, data); + return; + case 0x4001: + Write_SoundChipTone(data);//Flavor SN76496Write(0, data); + return; + case 0x8000: + cpuram[0xBC] = data; + return; + case 0xC000: + tlcs_interrupt_wrapper(0x03); + return; + } +} + +void z80ngpMemWriteW(unsigned short addr, unsigned short data) { + if (addr < 0x4000) { + mainram[0x3000 + addr] = data&0xFF; + mainram[0x3000 + addr+1] = data>>8; + return; + } + + switch (addr) + { + case 0x4000: + Write_SoundChipNoise(data&0xFF);//Flavor SN76496Write(0, data); + Write_SoundChipNoise(data>>8);//Flavor SN76496Write(0, data); + return; + case 0x4001: + Write_SoundChipTone(data&0xFF);//Flavor SN76496Write(0, data); + Write_SoundChipTone(data>>8);//Flavor SN76496Write(0, data); + return; + case 0x8000: + cpuram[0xBC] = data&0xFF; + cpuram[0xBC] = data>>8; + return; + case 0xC000: + tlcs_interrupt_wrapper(0x03); + tlcs_interrupt_wrapper(0x03); + return; + } +} + +void z80ngpPortWriteB(unsigned char port, unsigned char data) { + // acknowledge interrupt, any port works +} + +unsigned char z80ngpPortReadB(unsigned char port) { + return 0xFF; +} + +#if defined(DRZ80) || defined(CZ80) +void DrZ80ngpMemWriteB(unsigned char data, unsigned short addr) +{ + if (addr < 0x4000) { + mainram[0x3000 + addr] = data; return; + } + switch (addr) { + case 0x4000: + Write_SoundChipNoise(data);//Flavor SN76496Write(0, data); + return; + case 0x4001: + Write_SoundChipTone(data);//Flavor SN76496Write(0, data); + return; + case 0x8000: + cpuram[0xBC] = data; + return; + case 0xC000: + tlcs_interrupt_wrapper(0x03); + return; + } +} + +void DrZ80ngpMemWriteW(unsigned short data, unsigned short addr) +{ + if (addr < 0x4000) { + mainram[0x3000 + addr] = data&0xFF; + mainram[0x3000 + addr+1] = data>>8; + return; + } + + switch (addr) + { + case 0x4000: + Write_SoundChipNoise(data&0xFF);//Flavor SN76496Write(0, data); + Write_SoundChipNoise(data>>8);//Flavor SN76496Write(0, data); + return; + case 0x4001: + Write_SoundChipTone(data&0xFF);//Flavor SN76496Write(0, data); + Write_SoundChipTone(data>>8);//Flavor SN76496Write(0, data); + return; + case 0x8000: + cpuram[0xBC] = data&0xFF; + cpuram[0xBC] = data>>8; + return; + case 0xC000: + tlcs_interrupt_wrapper(0x03); + tlcs_interrupt_wrapper(0x03); + return; + } +} + +void DrZ80ngpPortWriteB(unsigned short port, unsigned char data) +{ + // acknowledge interrupt, any port works +} + +unsigned char DrZ80ngpPortReadB(unsigned short port) +{ + return 0xFF; +} +#endif + + + +///////////////////////////////////////////////////////////////////////////////////// +//// General Functions /// +///////////////////////////////////////////////////////////////////////////////////// + +const unsigned char ngpcpuram[256] = { + // 0x00 + 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0xFF, 0xFF, + // 0x10 + 0x34, 0x3C, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x3F, 0xFF, 0x2D, 0x01, 0xFF, 0xFF, 0x03, 0xB2, + // 0x20 + 0x80, 0x00, 0x01, 0x90, 0x03, 0xB0, 0x90, 0x62, 0x05, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x4C, 0x4C, + // 0x30 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x20, 0xFF, 0x80, 0x7F, + // 0x40 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // 0x50 + 0x00, 0x20, 0x69, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + // 0x60 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x03, 0x03, 0x02, 0x00, 0x00, 0x00, + // 0x70 (0x70-0x7A: interrupt level settings) + 0x02, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + + +const unsigned char ngpInterruptCode[] = { + 0x07, // RETI + 0xD1, 0xBA, 0x6F, 0x04, // PUSHW (6FBA) FFF801 SWI3 + 0xD1, 0xB8, 0x6F, 0x04, // PUSHW (6FB8) + 0x0E, // RET + 0xD1, 0xBE, 0x6F, 0x04, // PUSHW (6FBE) FFF80A SWI4 + 0xD1, 0xBC, 0x6F, 0x04, // PUSHW (6FBC) + 0x0E, // RET + 0xD1, 0xC2, 0x6F, 0x04, // PUSHW (6FC2) FFF813 SWI5 + 0xD1, 0xC0, 0x6F, 0x04, // PUSHW (6FC0) + 0x0E, // RET + 0xD1, 0xC6, 0x6F, 0x04, // PUSHW (6FC6) FFF81C SWI6 + 0xD1, 0xC4, 0x6F, 0x04, // PUSHW (6FC4) + 0x0E, // RET + 0xD1, 0xCA, 0x6F, 0x04, // PUSHW (6FCA) FFF825 RTC Alarm + 0xD1, 0xC8, 0x6F, 0x04, // PUSHW (6FC8) + 0x0E, // RET + 0xD1, 0xCE, 0x6F, 0x04, // PUSHW (6FCE) FFF82E VBlank + 0xD1, 0xCC, 0x6F, 0x04, // PUSHW (6FCC) + 0x0E, // RET + 0xD1, 0xD2, 0x6F, 0x04, // PUSHW (6FD2) FFF837 interrupt from z80 + 0xD1, 0xD0, 0x6F, 0x04, // PUSHW (6FD0) + 0x0E, // RET + 0xD1, 0xD6, 0x6F, 0x04, // PUSHW (6FD6) FFF840 INTT0 + 0xD1, 0xD4, 0x6F, 0x04, // PUSHW (6FD4) + 0x0E, // RET + 0xD1, 0xDA, 0x6F, 0x04, // PUSHW (6FDA) FFF849 INTT1 + 0xD1, 0xD8, 0x6F, 0x04, // PUSHW (6FD8) + 0x0E, // RET + 0xD1, 0xDE, 0x6F, 0x04, // PUSHW (6FDE) FFF852 INTT2 + 0xD1, 0xDC, 0x6F, 0x04, // PUSHW (6FDC) + 0x0E, // RET + 0xD1, 0xE2, 0x6F, 0x04, // PUSHW (6FE2) FFF85B INTT3 (interrupt to z80) + 0xD1, 0xE0, 0x6F, 0x04, // PUSHW (6FE0) + 0x0E, // RET + 0xD1, 0xE6, 0x6F, 0x04, // PUSHW (6FE6) FFF864 Serial Receive + 0xD1, 0xE4, 0x6F, 0x04, // PUSHW (6FE4) + 0x0E, // RET + 0xD1, 0xEA, 0x6F, 0x04, // PUSHW (6FEA) FFF86D Serial Communication + 0xD1, 0xE8, 0x6F, 0x04, // PUSHW (6FE8) + 0x0E, // RET + 0xD1, 0xEE, 0x6F, 0x04, // PUSHW (6FEE) FFF876 Reserved + 0xD1, 0xEC, 0x6F, 0x04, // PUSHW (6FEC) + 0x0E, // RET + 0xD1, 0xF2, 0x6F, 0x04, // PUSHW (6FF2) FFF87F End DMA Channel 0 + 0xD1, 0xF0, 0x6F, 0x04, // PUSHW (6FF0) + 0x0E, // RET + 0xD1, 0xF6, 0x6F, 0x04, // PUSHW (6FF6) FFF888 End DMA Channel 1 + 0xD1, 0xF4, 0x6F, 0x04, // PUSHW (6FF4) + 0x0E, // RET + 0xD1, 0xFA, 0x6F, 0x04, // PUSHW (6FFA) FFF891 End DMA Channel 2 + 0xD1, 0xF8, 0x6F, 0x04, // PUSHW (6FF8) + 0x0E, // RET + 0xD1, 0xFE, 0x6F, 0x04, // PUSHW (6FFE) FFF89A End DMA Channel 3 + 0xD1, 0xFC, 0x6F, 0x04, // PUSHW (6FFC) + 0x0E, // RET +}; + +const unsigned long ngpVectors[0x21] = { + 0x00FFF800, 0x00FFF000, 0x00FFF800, 0x00FFF801, // 00, 04, 08, 0C + 0x00FFF80A, 0x00FFF813, 0x00FFF81C, 0x00FFF800, // 10, 14, 18, 1C + 0x00FFF800, 0x00FFF800, 0x00FFF825, 0x00FFF82E, // 20, 24, 28, 2C + 0x00FFF837, 0x00FFF800, 0x00FFF800, 0x00FFF800, // 30, 34, 38, 3C + 0x00FFF840, 0x00FFF849, 0x00FFF852, 0x00FFF85B, // 40, 44, 48, 4C + 0x00FFF800, 0x00FFF800, 0x00FFF800, 0x00FFF800, // 50, 54, 58, 5C + 0x00FFF864, 0x00FFF86D, 0x00FFF800, 0x00FFF800, // 60, 64, 68, 6C + 0x00FFF800, 0x00FFF87F, 0x00FFF888, 0x00FFF891, // 70, 74, 78, 7C + 0x00FFF89A // 80 +}; + +//return 0 on fail +unsigned char loadBIOS() +{ + FILE *biosFile; + int bytesRead; + + + biosFile = fopen("NPBIOS.BIN", "rb"); + if(!biosFile) + return 0; + + + bytesRead = fread(cpurom, 1, 0x10000, biosFile); + fclose(biosFile); + + if(bytesRead != 0x10000) + { + fprintf(stderr, "loadBIOS: Bad BIOS file %s\n", "NPBIOS.BIN"); + return 0; + } + return 1; +} + +void mem_init() +{ + int x; + unsigned int i; + + cpuram = mainram; + memset(&mainram,0,sizeof(mainram)); + switch(m_emuInfo.machine) { + case NGP: + case NGPC: + cpuram = &mainram[128*1024]; + if(!loadBIOS()) + { + realBIOSloaded = 0; + memset(&cpurom,0,sizeof(cpurom)); + + //in theory, if we've loaded the BIOS, we shouldn't need much of this, but good luck with that. + // setup fake jump table for the additional bios calls + for (i=0; i<0x40; i++) + { + // using the 1A (reg) dummy instruction to emulate the bios + cpurom[0xe000 + 0x40 * i] = 0xc8; + cpurom[0xe001 + 0x40 * i] = 0x1a; + cpurom[0xe002 + 0x40 * i] = i; + cpurom[0xe003 + 0x40 * i] = 0x0e; + *((unsigned long *)(&cpurom[0xfe00 + 4*i])) = (unsigned long)0x00ffe000 + 0x40 * i; + } + + // setup SWI 1 code & vector + x = 0xf000; + cpurom[x] = 0x17; x++; cpurom[x] = 0x03; x++; // ldf 3 + cpurom[x] = 0x3C; x++; // push XIX + cpurom[x] = 0xC8; x++; cpurom[x] = 0xCC; x++; // and w,1F + cpurom[x] = 0x1F; x++; + cpurom[x] = 0xC8; x++; cpurom[x] = 0x80; x++; // add w,w + cpurom[x] = 0xC8; x++; cpurom[x] = 0x80; x++; // add w,w + cpurom[x] = 0x44; x++; cpurom[x] = 0x00; x++; // ld XIX,0x00FFFE00 + cpurom[x] = 0xFE; x++; cpurom[x] = 0xFF; x++; // + cpurom[x] = 0x00; x++; // + cpurom[x] = 0xE3; x++; cpurom[x] = 0x03; x++; // ld XIX,(XIX+W) + cpurom[x] = 0xF0; x++; cpurom[x] = 0xE1; x++; // + cpurom[x] = 0x24; x++; // + cpurom[x] = 0xB4; x++; cpurom[x] = 0xE8; x++; // call XIX + cpurom[x] = 0x5C; x++; // pop XIX + cpurom[x] = 0x07; x++; // reti + *((unsigned long *)(&cpurom[0xff04])) = (unsigned long)0x00fff000; + // setup interrupt code + for(i=0; i> 24) == 0xFF) + // dbg_print("1) addr=0x%X returning=0x%X\n", addr, &cpuram[addr]); + return &cpuram[addr]; + } + if (addr>0x00003fff && addr<0x00018000) + { + //if((unsigned long)&mainram[addr-0x00004000] >> 24 == 0xFF) + // dbg_print("2) addr=0x%X returning=0x%X\n", addr, &mainram[addr-0x00004000]); + + switch (addr) //Thanks Koyote + { + case 0x6F80: + mainram[addr-0x00004000] = 0xFF; + break; + case 0x6F80+1: + mainram[addr-0x00004000] = 0x03; + break; + case 0x6F85: + mainram[addr-0x00004000] = 0x00; + break; + case 0x6F82: + mainram[addr-0x00004000] = ngpInputState; + break; + case 0x6DA2: + mainram[addr-0x00004000] = 0x80; + break; + } + return &mainram[addr-0x00004000]; + } + } + else + { + if (addr<0x00400000) + { + return &mainrom[(addr-0x00200000)/*&cartAddrMask*/]; + } + if(addr<0x00800000) //Flavor added + { + return 0; + } + if (addr<0x00A00000) + { + return &mainrom[(addr-(0x00800000-0x00200000))/*&cartAddrMask*/]; + } + if(addr<0x00FF0000) //Flavor added + { + return 0; + } + + //if((unsigned long)&cpurom[addr-0x00ff0000] >> 24 == 0xFF) + // dbg_print("5) addr=0x%X returning=0x%X\n", addr, &cpurom[addr-0x00ff0000]); + + return &cpurom[addr-0x00ff0000]; + } + + //dbg_print("6) addr=0x%X returning=0\n", addr); + return 0; //Flavor ERROR +} + +/*inline unsigned char *get_addressW(unsigned long addr) +{ + addr&= 0x00FFFFFF; + if (addr<0x00200000) + { + if (addr<0x000008a0) + { + return &cpuram[addr]; + } + if (addr>0x00003fff && addr<0x00018000) + return &mainram[addr-0x00004000]; + + return NULL; + } + else + { + return NULL; + } + return NULL; //Flavor ERROR +}*/ + +// read a byte from a memory address (addr) +inline unsigned char tlcsMemReadB(unsigned long addr) +{ + addr&= 0x00FFFFFF; + + if(currentCommand == COMMAND_INFO_READ) + return flashReadInfo(addr); + + if (addr < 0x00200000) { + if (addr < 0x000008A0) { + if(addr == 0xBC) + { + ngpSoundExecute(); + } + return cpuram[addr]; + } + else if (addr > 0x00003FFF && addr < 0x00018000) + { + + switch (addr) //Thanks Koyote + { + case 0x6DA2: + return 0x80; + break; + case 0x6F80: + return 0xFF; + break; + case 0x6F80+1: + return 0x03; + break; + case 0x6F85: + return 0x00; + break; + case 0x6F82: + return ngpInputState; + break; + + default: + return mainram[addr-0x00004000]; + } + return mainram[addr-0x00004000]; + } + } + else + { + if (addr<0x00400000) + return mainrom[(addr-0x00200000)/*&cartAddrMask*/]; + if (addr<0x00800000) + return 0xFF; + if (addr<0x00a00000) + return mainrom[(addr-(0x00800000-0x00200000))/*&cartAddrMask*/]; + if (addr<0x00ff0000) + return 0xFF; + return cpurom[addr-0x00ff0000]; + } + return 0xFF; +} + +// read a word from a memory address (addr) +inline unsigned short tlcsMemReadW(unsigned long addr) +{ +#ifdef TARGET_GP2X + register unsigned short i asm("r0"); + register byte *gA asm("r1"); + + gA = get_address(addr); + + if(gA == 0) + return 0; + + asm volatile( + "ldrb %0, [%1]\n\t" + "ldrb r2, [%1, #1]\n\t" + "orr %0, %0, r2, asl #8" + : "=r" (i) + : "r" (gA) + : "r2"); + + return i; +#else +/* unsigned short i; + byte *gA = get_address(addr); + + if(gA == 0) + return 0; + + i = *(gA++); + i |= (*gA) << 8; + + return i; + */ + return tlcsMemReadB(addr) | (tlcsMemReadB(addr+1) << 8); +#endif +} + + +// read a long word from a memory address (addr) +inline unsigned long tlcsMemReadL(unsigned long addr) +{ +#ifdef TARGET_GP2X + register unsigned long i asm("r0"); + register byte *gA asm("r4"); + + gA = get_address(addr); + + if(gA == 0) + return 0; + + asm volatile( + "bic r1,%1,#3 \n" + "ldmia r1,{r0,r3} \n" + "ands r1,%1,#3 \n" + "movne r2,r1,lsl #3 \n" + "movne r0,r0,lsr r2 \n" + "rsbne r1,r2,#32 \n" + "orrne r0,r0,r3,lsl r1" + : "=r"(i) + : "r"(gA) + : "r1","r2","r3"); + + return i; +#else + unsigned long i; + byte *gA = get_address(addr); + + if(gA == 0) + return 0; + + i = *(gA++); + i |= (*(gA++)) << 8; + i |= (*(gA++)) << 16; + i |= (*gA) << 24; + + return i; + //return tlcsMemReadB(addr) | (tlcsMemReadB(addr +1) << 8) | (tlcsMemReadB(addr +2) << 16) | (tlcsMemReadB(addr +3) << 24); +#endif +} + +// write a byte (data) to a memory address (addr) +inline void tlcsMemWriteB(unsigned long addr, unsigned char data) +{ + addr&= 0x00FFFFFF; + if (addr<0x000008a0) + { + switch(addr) { + //case 0x80: // CPU speed + // break; + case 0xA0: // L CH Sound Source Control Register + if (cpuram[0xB8] == 0x55 && cpuram[0xB9] == 0xAA) + Write_SoundChipNoise(data);//Flavor SN76496Write(0, data); + break; + case 0xA1: // R CH Sound Source Control Register + if (cpuram[0xB8] == 0x55 && cpuram[0xB9] == 0xAA) + Write_SoundChipTone(data); //Flavor SN76496Write(0, data); + break; + case 0xA2: // L CH DAC Control Register + ngpSoundExecute(); + if (cpuram[0xB8] == 0xAA) + dac_writeL(data); //Flavor DAC_data_w(0,data); + break; + /*case 0xA3: // R CH DAC Control Register //Flavor hack for mono only sound + ngpSoundExecute(); + if (cpuram[0xB8] == 0xAA) + dac_writeR(data);//Flavor DAC_data_w(1,data); + break;*/ + case 0xB8: // Z80 Reset +// if (data == 0x55) DAC_data_w(0,0); + case 0xB9: // Sourd Source Reset Control Register + switch(data) { + case 0x55: + ngpSoundStart(); + break; + case 0xAA: + ngpSoundExecute(); + ngpSoundOff(); + break; + } + break; + case 0xBA: + ngpSoundExecute(); +#if defined(DRZ80) || defined(CZ80) + Z80_Cause_Interrupt(Z80_NMI_INT); +#else + z80Interrupt(Z80NMI); +#endif + break; + } + cpuram[addr] = data; + return; + } + else if (addr>0x00003fff && addr<0x00018000) + { + if (addr == 0x87E2 && mainram[0x47F0] != 0xAA) + return; // disallow writes to GEMODE + + /*if((addr >= 0x8800 && addr <= 0x88FF) + || (addr >= 0x8C00 && addr <= 0x8FFF) + || (addr >= 0xA000 && addr <= 0xBFFF) + || addr == 0x00008020 + || addr == 0x00008021) + { + spritesDirty = true; + }*/ + + mainram[addr-0x00004000] = data; + return; + } + else if (addr>=0x00200000 && addr<0x00400000) + flashChipWrite(addr, data); + else if (addr>=0x00800000 && addr<0x00A00000) + flashChipWrite(addr, data); + +} + + + + + +#endif // _MEMORYH_ diff --git a/neopopsound.cpp b/neopopsound.cpp new file mode 100644 index 0000000..093426e --- /dev/null +++ b/neopopsound.cpp @@ -0,0 +1,699 @@ +// Flavor modified sound.c and sound.h from NEOPOP +// which was originally based on sn76496.c from MAME +// some ideas also taken from NeoPop-SDL code + +//--------------------------------------------------------------------------- +// Originally from +// NEOPOP : Emulator as in Dreamland +// +// Copyright (c) 2001-2002 by neopop_uk +//--------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. See also the license.txt file for +// additional informations. +//--------------------------------------------------------------------------- + + +/************************************************************************ + * * + * Portions, but not all of this source file are based on MAME v0.60 * + * File "sn76496.c". All copyright goes to the original author. * + * The remaining parts, including DAC processing, by neopop_uk * + * * + ************************************************************************/ + +#ifndef __GP32__ +#include "StdAfx.h" +#endif + +#include "neopopsound.h" + + +#include "main.h" +#include "memory.h" +//#include "menu.h" + + +//============================================================================= + +SoundChip toneChip; +SoundChip noiseChip; + +//==== DAC +#ifdef TARGET_WIN +#define DAC_BUFFERSIZE (2560 * 1024) //at (256 * 1024) the PC version will crash on MS2 intro +#else +#define DAC_BUFFERSIZE (256 * 1024) //at (256 * 1024) the PC version will crash on MS2 intro +#endif + +int dacLBufferRead, dacLBufferWrite, dacLBufferCount; +_u16 dacBufferL[DAC_BUFFERSIZE]; +int fixsoundmahjong; + +#if !defined(__GP32__) && !defined(TARGET_PSP) + +int volume = SDL_MIX_MAXVOLUME;//SDL_MIX_MAXVOLUME / 2; + +void increaseVolume() +{ + if(volume < SDL_MIX_MAXVOLUME) + volume++; +} + +void decreaseVolume() +{ + if(volume > 0) + volume--; +} + +#endif + +//============================================================================= + +#define SOUNDCHIPCLOCK (3072000) //Unverified / sounds correct + +#define MAX_OUTPUT 0x7fff +#define STEP 0x10000 //Fixed point adjuster + +#define MAX_OUTPUT_STEP 0x7fff0000 +#define STEP_SHIFT 16 + +static _u32 VolTable[16]; +static _u32 UpdateStep = 0; //Number of steps during one sample. + +/* Formulas for noise generator */ +/* bit0 = output */ + +/* noise feedback for white noise mode (verified on real SN76489 by John Kortink) */ +#define FB_WNOISE 0x14002 /* (16bits) bit16 = bit0(out) ^ bit2 ^ bit15 */ + +/* noise feedback for periodic noise mode */ +#define FB_PNOISE 0x08000 /* 15bit rotate */ + +/* noise generator start preset (for periodic noise) */ +#define NG_PRESET 0x0f35 + +#define max(a,b) (a>b?a:b) +#define min(a,b) (a 0) + { + toneChip.Output[i] ^= 1; + if (toneChip.Output[i]) vol[i] += toneChip.Period[i]; + break; + } + toneChip.Count[i] += toneChip.Period[i]; + vol[i] += toneChip.Period[i]; + } + if (toneChip.Output[i]) vol[i] -= toneChip.Count[i]; + } +/* + left = STEP; + do + { + int nextevent; + + if (toneChip.Count[3] < left) nextevent = toneChip.Count[3]; + else nextevent = left; + + if (toneChip.Output[3]) vol[3] += toneChip.Count[3]; + toneChip.Count[3] -= nextevent; + if (toneChip.Count[3] <= 0) + { + if (toneChip.RNG & 1) toneChip.RNG ^= toneChip.NoiseFB; + toneChip.RNG >>= 1; + toneChip.Output[3] = toneChip.RNG & 1; + toneChip.Count[3] += toneChip.Period[3]; + if (toneChip.Output[3]) vol[3] += toneChip.Period[3]; + } + if (toneChip.Output[3]) vol[3] -= toneChip.Count[3]; + + left -= nextevent; + } while (left > 0); +*/ + + out = vol[0] * toneChip.Volume[0] + vol[1] * toneChip.Volume[1] + + vol[2] * toneChip.Volume[2]; + + //if (out > MAX_OUTPUT * STEP) out = MAX_OUTPUT * STEP; + if (out > MAX_OUTPUT_STEP) out = MAX_OUTPUT_STEP; + + return out>>STEP_SHIFT;//out / STEP; +} + +//============================================================================= + +static _u16 sample_chip_noise(void) +{ + int i; + + //int vol[4]; + int vol3 = 0; + unsigned int out; + int left; + + /* vol[] keeps track of how long each square wave stays */ + /* in the 1 position during the sample period. */ +/* + vol[0] = vol[1] = vol[2] = vol[3] = 0; + for (i = 0; i < 3; i++) + { + if (noiseChip.Output[i]) vol[i] += noiseChip.Count[i]; + noiseChip.Count[i] -= STEP; + + // Period[i] is the half period of the square wave. Here, in each + // loop I add Period[i] twice, so that at the end of the loop the + // square wave is in the same status (0 or 1) it was at the start. + // vol[i] is also incremented by Period[i], since the wave has been 1 + // exactly half of the time, regardless of the initial position. + // If we exit the loop in the middle, Output[i] has to be inverted + // and vol[i] incremented only if the exit status of the square + // wave is 1. + + while (noiseChip.Count[i] <= 0) + { + noiseChip.Count[i] += noiseChip.Period[i]; + if (noiseChip.Count[i] > 0) + { + noiseChip.Output[i] ^= 1; + if (noiseChip.Output[i]) vol[i] += noiseChip.Period[i]; + break; + } + noiseChip.Count[i] += noiseChip.Period[i]; + vol[i] += noiseChip.Period[i]; + } + if (noiseChip.Output[i]) vol[i] -= noiseChip.Count[i]; + } +*/ + if (noiseChip.Volume[3]) + { + left = STEP; + do + { + int nextevent = min(noiseChip.Count[3],left); + + //if (noiseChip.Count[3] < left) nextevent = noiseChip.Count[3]; + //else nextevent = left; + + if (noiseChip.Output[3]) vol3 += noiseChip.Count[3]; + noiseChip.Count[3] -= nextevent; + if (noiseChip.Count[3] <= 0) + { + if (noiseChip.RNG & 1) noiseChip.RNG ^= noiseChip.NoiseFB; + noiseChip.RNG >>= 1; + noiseChip.Output[3] = noiseChip.RNG & 1; + noiseChip.Count[3] += noiseChip.Period[3]; + if (noiseChip.Output[3]) vol3 += noiseChip.Period[3]; + } + if (noiseChip.Output[3]) vol3 -= noiseChip.Count[3]; + + left -= nextevent; + } while (left > 0); + } + out = vol3 * noiseChip.Volume[3]; + + //if (out > MAX_OUTPUT * STEP) out = MAX_OUTPUT * STEP; + if (out > MAX_OUTPUT_STEP) out = MAX_OUTPUT_STEP; + + return out>>STEP_SHIFT;//out / STEP; +} + +//============================================================================= + +void sound_update(_u16* chip_buffer, int length_bytes) +{ + length_bytes >>= 1;//turn it into words + while (length_bytes) + { + //Mix a mono track out of: (Tone + Noise) >> 1 + //Write it to the sound buffer + *(chip_buffer++) = (sample_chip_tone() + sample_chip_noise()) >> 1; + + length_bytes--; + } +} + +//============================================================================= + +void WriteSoundChip(SoundChip* chip, _u8 data) +{ +#if !defined(__GP32__) && !defined(TARGET_PSP) + SDL_LockAudio(); +#endif + //Command + if (data & 0x80) + { + int r = (data & 0x70) >> 4; + int c = r>>1;//r/2; + + chip->LastRegister = r; + chip->Register[r] = (chip->Register[r] & 0x3f0) | (data & 0x0f); + + switch(r) + { + case 0: /* tone 0 : frequency */ + case 2: /* tone 1 : frequency */ + case 4: /* tone 2 : frequency */ + chip->Period[c] = UpdateStep * chip->Register[r]; + if (chip->Period[c] == 0) chip->Period[c] = UpdateStep; + if (r == 4) + { + /* update noise shift frequency */ + if ((chip->Register[6] & 0x03) == 0x03) + chip->Period[3] = chip->Period[2]<<1; + } + break; + + case 1: /* tone 0 : volume */ + case 3: /* tone 1 : volume */ + case 5: /* tone 2 : volume */ + case 7: /* noise : volume */ +#ifdef NEOPOP_DEBUG + if (filter_sound) + { + if (chip == &toneChip) + system_debug_message("sound (T): Set Tone %d Volume to %d (0 = min, 15 = max)", c, 15 - (data & 0xF)); + else + system_debug_message("sound (N): Set Tone %d Volume to %d (0 = min, 15 = max)", c, 15 - (data & 0xF)); + } +#endif + chip->Volume[c] = VolTable[data & 0xF]; + break; + + case 6: /* noise : frequency, mode */ + { + int n = chip->Register[6]; +#ifdef NEOPOP_DEBUG + if (filter_sound) + { + char *pm, *nm = "White"; + if ((n & 4)) nm = "Periodic"; + + switch(n & 3) + { + case 0: pm = "N/512"; break; + case 1: pm = "N/1024"; break; + case 2: pm = "N/2048"; break; + case 3: pm = "Tone#2"; break; + } + + if (chip == &toneChip) + system_debug_message("sound (T): Set Noise Mode to %s, Period = %s", nm, pm); + else + system_debug_message("sound (N): Set Noise Mode to %s, Period = %s", nm, pm); + } +#endif + chip->NoiseFB = (n & 4) ? FB_WNOISE : FB_PNOISE; + n &= 3; + /* N/512,N/1024,N/2048,Tone #2 output */ + chip->Period[3] = (n == 3) ? 2 * chip->Period[2] : (UpdateStep << (5+n)); + + /* reset noise shifter */ + chip->RNG = NG_PRESET; + chip->Output[3] = chip->RNG & 1; + + } + break; + } + } + else + { + int r = chip->LastRegister; + int c = r/2; + + switch (r) + { + case 0: /* tone 0 : frequency */ + case 2: /* tone 1 : frequency */ + case 4: /* tone 2 : frequency */ + chip->Register[r] = (chip->Register[r] & 0x0f) | ((data & 0x3f) << 4); + chip->Period[c] = UpdateStep * chip->Register[r]; + if (chip->Period[c] == 0) chip->Period[c] = UpdateStep; + if (r == 4) + { + /* update noise shift frequency */ + if ((chip->Register[6] & 0x03) == 0x03) + chip->Period[3] = chip->Period[2]<<1; + } +#ifdef NEOPOP_DEBUG + if (filter_sound) + { + if (chip == &toneChip) + system_debug_message("sound (T): Set Tone %d Frequency to %d", c, chip->Register[r]); + else + system_debug_message("sound (N): Set Tone %d Frequency to %d", c, chip->Register[r]); + } +#endif + break; + } + } +#if !defined(__GP32__) && !defined(TARGET_PSP) + SDL_UnlockAudio(); +#endif +} + +//============================================================================= + +//#ifdef TARGET_PSP +void dac_writeL(unsigned char data) +{ + static int conv=5; +#if !defined(__GP32__) && !defined(TARGET_PSP) + SDL_LockAudio(); +#endif + +#ifdef TARGET_PSP + //pretend that conv=5.5 (44100/8000) conversion factor + + if(conv==5) + conv=6; + else + { + conv=5; + + //Arregla el sonido del Super Real Mahjong + if (fixsoundmahjong>500) + conv=3; + } + +#else + conv=1; +#endif + + for(int i=0;i>1; + length_bytes &= 0xFFFFFFFE; //make sure it's 16bit safe + + if(dacLBufferRead+length_words >= DAC_BUFFERSIZE) + { + SDL_MixAudio((Uint8*)stream, (Uint8*)&dacBufferL[dacLBufferRead], (DAC_BUFFERSIZE-dacLBufferRead)*2, volume); //mix it to the buffer + SDL_MixAudio((Uint8*)&stream[DAC_BUFFERSIZE-dacLBufferRead], (Uint8*)dacBufferL, length_bytes-((DAC_BUFFERSIZE-dacLBufferRead)*2), volume); //mix it to the buffer + dacLBufferRead = length_words-(DAC_BUFFERSIZE-dacLBufferRead); + } + else + { + SDL_MixAudio((Uint8*)stream, (Uint8*)&dacBufferL[dacLBufferRead], length_bytes, volume); //mix it to the buffer + dacLBufferRead += length_words; + } + + dacLBufferCount -= length_words; //need it in 16bits +#endif +} + + +void dac_update(_u16* dac_buffer, int length_bytes) +{ + while (length_bytes > 1) + { + //Copy then clear DAC data +#ifdef TARGET_PSP + *(dac_buffer++) |= dacBufferL[dacLBufferRead]; +#else + *(dac_buffer++) = dacBufferL[dacLBufferRead]; +#endif + dacBufferL[dacLBufferRead] = 0; //silence? + + length_bytes -= 2; // 1 byte = 8 bits + + if (dacLBufferCount > 0) + { + dacLBufferCount--; + + //Advance the DAC read +// dacLBufferRead++; + if (++dacLBufferRead == DAC_BUFFERSIZE) + dacLBufferRead = 0; + } + } +} + +//============================================================================= + +#ifdef __GP32__ +volatile int soundON = 0; +#endif + +//Resets the sound chips, also used whenever sound options are changed +void sound_init(int SampleRate) +{ + int i; + double out; + + /* the base clock for the tone generators is the chip clock divided by 16; */ + /* for the noise generator, it is clock / 256. */ + /* Here we calculate the number of steps which happen during one sample */ + /* at the given sample rate. No. of events = sample rate / (clock/16). */ + /* STEP is a multiplier used to turn the fraction into a fixed point */ + /* number. */ + UpdateStep = (_u32)(((double)STEP * SampleRate * 16) / SOUNDCHIPCLOCK); + + //Initialise Left Chip + memset(&toneChip, 0, sizeof(SoundChip)); + + //Initialise Right Chip + memset(&noiseChip, 0, sizeof(SoundChip)); + + //Default register settings + for (i = 0;i < 8;i+=2) + { + toneChip.Register[i] = 0; + toneChip.Register[i + 1] = 0x0f; /* volume = 0 */ + noiseChip.Register[i] = 0; + noiseChip.Register[i + 1] = 0x0f; /* volume = 0 */ + } + + for (i = 0;i < 4;i++) + { + toneChip.Output[i] = 0; + toneChip.Period[i] = toneChip.Count[i] = UpdateStep; + noiseChip.Output[i] = 0; + noiseChip.Period[i] = noiseChip.Count[i] = UpdateStep; + } + + //Build the volume table + out = MAX_OUTPUT / 3; + + /* build volume table (2dB per step) */ + for (i = 0;i < 15;i++) + { + VolTable[i] = (_u32)out; + out /= 1.258925412; /* = 10 ^ (2/20) = 2dB */ + } + VolTable[15] = 0; + + + //Clear the DAC buffer + for (i = 0; i < DAC_BUFFERSIZE; i++) + dacBufferL[i] = 0; + + dacLBufferCount = 0; + dacLBufferRead = 0; + dacLBufferWrite = 0; + +#ifdef __GP32__ + soundON = 1; +#endif +} + +//============================================================================= + + + + +#ifdef TARGET_PSP +#define NGPC_CHIP_FREQUENCY 44100 +#else +#define NGPC_CHIP_FREQUENCY 8000 +#endif +int chip_freq=NGPC_CHIP_FREQUENCY;//what we'd prefer + +#define CHIPBUFFERLENGTH 35280 + +#define UNDEFINED 0xFFFFFF + +// ====== Chip sound ========= +//static LPDIRECTSOUNDBUFFER chipBuffer = NULL; // Chip Buffer +static int lastChipWrite = 0, chipWrite = UNDEFINED; //Write Cursor + +// ====== DAC sound ========= +//static LPDIRECTSOUNDBUFFER dacBuffer = NULL; // DAC Buffer +static int lastDacWrite = 0, dacWrite = UNDEFINED; //Write Cursor + + +_u8 blockSound[CHIPBUFFERLENGTH], blockDAC[CHIPBUFFERLENGTH]; // Gets filled with sound data. +unsigned int blockSoundWritePtr = 0; +unsigned int blockSoundReadPtr = 0; + +void system_sound_chipreset(void) +{ + //Initialises sound chips, matching frequncies + sound_init(chip_freq); +} + +#ifdef __GP32__ + +int audioCallback(unsigned short* sndBuf,int len) { + int i,smp; + if (soundON==0) + return 0; + for (i=0;i> 1; + smp = (smp + dacBufferL[dacLBufferRead]) >> 1; + + *(sndBuf++) = smp; + *(sndBuf++) = smp; // stereo ? + dacBufferL[dacLBufferRead] = 0; //silence? + if (dacLBufferCount > 0) + { + dacLBufferCount--; + if (++dacLBufferRead == DAC_BUFFERSIZE) + dacLBufferRead = 0; + } + } + return 1; +} + +#endif + +#ifndef TARGET_PSP +void mixaudioCallback(void *userdata, Uint8 *stream, int len) +{ +#ifndef __GP32__ + sound_update((_u16*)blockSound, len); //Get sound data +// memcpy(stream, blockSound, len); //put it in the buffer + SDL_MixAudio(stream, blockSound, len, volume); //mix it to the buffer + + if(dacLBufferCount >= len) + { + //dac_update((_u16*)blockDAC, len); //Get DAC data + //SDL_MixAudio(stream, blockDAC, len, volume); //mix it to the buffer + + dac_mixer((_u16*)stream, len); //Get DAC data + } +#endif +} +#endif /* TARGET_PSP */ + +int sound_system_init() +{ +#if !defined(__GP32__) && !defined(TARGET_PSP) + //set up SDL sound here? + SDL_AudioSpec fmt, retFmt; + + fmt.freq = chip_freq; //11025 is good for dac_ sound + fmt.format = AUDIO_S16; + fmt.channels = 1; +#ifdef TARGET_PSP + fmt.samples = 512; +#else + fmt.samples = 512; +#endif + fmt.callback = mixaudioCallback; + fmt.userdata = NULL; + + /* Open the audio device and start playing sound! */ + if ( SDL_OpenAudio(&fmt, &retFmt) < 0 ) { + fprintf(stderr, "Unable to open audio: %s\n", SDL_GetError()); + exit(1); + } + + chip_freq = retFmt.freq; + + system_sound_chipreset(); //Resets chips + + SDL_PauseAudio(0); +#else + system_sound_chipreset(); //Resets chips +#endif + return 1; +} + + +//call this every so often to update the sound output +void system_sound_update(void) +{ +} + + + diff --git a/neopopsound.h b/neopopsound.h new file mode 100644 index 0000000..25ca167 --- /dev/null +++ b/neopopsound.h @@ -0,0 +1,88 @@ +// Flavor modified sound.c and sound.h from NEOPOP +// which was originally based on sn76496.c from MAME +// some ideas also taken from NeoPop-SDL code + +//--------------------------------------------------------------------------- +// Originally from +// NEOPOP : Emulator as in Dreamland +// +// Copyright (c) 2001-2002 by neopop_uk +//--------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. See also the license.txt file for +// additional informations. +//--------------------------------------------------------------------------- + + +#ifndef __NEOPOPSOUND__ +#define __NEOPOPSOUND__ +//============================================================================= + +#ifdef __GP32__ +#include "main.h" +#endif +#include "StdAfx.h" + +typedef struct +{ + int LastRegister; /* last register written */ + int Register[8]; /* registers */ + int Volume[4]; + int Period[4]; + int Count[4]; + int Output[4]; + + unsigned int RNG; /* noise generator */ + int NoiseFB; /* noise feedback mask */ + +} SoundChip; + +//============================================================================= + +extern SoundChip toneChip; +extern SoundChip noiseChip; + +void WriteSoundChip(SoundChip* chip, _u8 data); + +int sound_system_init(); +BOOL system_sound_init(void); +void system_sound_chipreset(void); + + + +//void system_sound_update(void); +void system_sound_update(int nframes); +void system_VBL(void); + +#define Write_SoundChipTone(VALUE) (WriteSoundChip(&toneChip, VALUE)) +#define Write_SoundChipNoise(VALUE) (WriteSoundChip(&noiseChip, VALUE)) + +//============================================================================= + +//void dac_writeL(unsigned char); +//void dac_writeR(unsigned char); + +void sound_init(int SampleRate); + +extern BOOL mute; + +void dac_update(_u16* dac_buffer, int length_bytes); +void sound_update(_u16* chip_buffer, int length_bytes); + +#ifndef __GP32__ +void increaseVolume(); +void decreaseVolume(); +#endif + +//#define dac_writeL dac_write +//#define dac_writeR dac_write +void dac_writeL(unsigned char); +//void dac_writeR(unsigned char); +void dac_write(unsigned char); + +//============================================================================= +#endif diff --git a/ngpBios.cpp b/ngpBios.cpp new file mode 100644 index 0000000..ee5d0d0 --- /dev/null +++ b/ngpBios.cpp @@ -0,0 +1,214 @@ +//--------------------------------------------------------------------------- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. See also the license.txt file for +// additional informations. +//--------------------------------------------------------------------------- + +// ngpBios.cpp: implementation of the ngpBios class. +// +////////////////////////////////////////////////////////////////////// + +#ifndef __GP32__ +#include "StdAfx.h" +#endif +#include "main.h" +#include "ngpBios.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +unsigned char sysfont[8*256] = +{ + // 0x00 - 0x07 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0xf8, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // 0x08 - 0x0F + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, + 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + // 0x10 - 0x17 + 0x20, 0x30, 0x38, 0x3c, 0x38, 0x30, 0x20, 0x00, 0x04, 0x0c, 0x1c, 0x3c, 0x1c, 0x0c, 0x04, 0x00, + 0x00, 0x00, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x00, 0x00, + 0x20, 0x3c, 0x08, 0x3c, 0x28, 0x7e, 0x08, 0x00, 0x3c, 0x24, 0x3c, 0x24, 0x3c, 0x24, 0x24, 0x00, + 0x3c, 0x24, 0x24, 0x3c, 0x24, 0x24, 0x3c, 0x00, 0x10, 0x10, 0x54, 0x54, 0x10, 0x28, 0xc6, 0x00, + // 0x18 - 0x1F + 0x10, 0x12, 0xd4, 0x58, 0x54, 0x92, 0x10, 0x00, 0x10, 0x10, 0x7c, 0x10, 0x38, 0x54, 0x92, 0x00, + 0x10, 0x28, 0x7c, 0x92, 0x38, 0x54, 0xfe, 0x00, 0x10, 0x10, 0x10, 0x7c, 0x10, 0x10, 0xfe, 0x00, + 0x7f, 0xff, 0xe0, 0xff, 0x7f, 0x01, 0xff, 0xff, 0xdc, 0xde, 0x1f, 0x9f, 0xdf, 0xdd, 0xdc, 0x9c, + 0x3b, 0x3b, 0x3b, 0xbb, 0xfb, 0xfb, 0xfb, 0x7b, 0x8f, 0x9e, 0xbc, 0xf8, 0xf8, 0xbc, 0x9e, 0x8f, + // 0x20 - 0x27 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x08, 0x10, 0x00, 0x18, 0x00, + 0x6c, 0x6c, 0x24, 0x48, 0x00, 0x00, 0x00, 0x00, 0x14, 0x14, 0xfe, 0x28, 0xfe, 0x50, 0x50, 0x00, + 0x10, 0x7c, 0x90, 0x7c, 0x12, 0xfc, 0x10, 0x00, 0x42, 0xa4, 0xa8, 0x54, 0x2a, 0x4a, 0x84, 0x00, + 0x30, 0x48, 0x38, 0x62, 0x94, 0x88, 0x76, 0x00, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, + // 0x28 - 0x2F + 0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, 0x20, 0x10, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, + 0x10, 0x92, 0x54, 0x38, 0x38, 0x54, 0x92, 0x00, 0x10, 0x10, 0x10, 0xfe, 0x10, 0x10, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, + // 0x30 - 0x37 + 0x3c, 0x42, 0x46, 0x5a, 0x62, 0x42, 0x3c, 0x00, 0x08, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, + 0x3c, 0x42, 0x42, 0x0c, 0x30, 0x40, 0x7e, 0x00, 0x3c, 0x42, 0x02, 0x1c, 0x02, 0x42, 0x3c, 0x00, + 0x0c, 0x14, 0x24, 0x44, 0x7e, 0x04, 0x04, 0x00, 0x7e, 0x40, 0x7c, 0x02, 0x02, 0x42, 0x3c, 0x00, + 0x3c, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x7e, 0x02, 0x04, 0x08, 0x08, 0x10, 0x10, 0x00, + // 0x38 - 0x3F + 0x3c, 0x42, 0x42, 0x3c, 0x42, 0x42, 0x3c, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x3c, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x08, 0x10, 0x00, + 0x00, 0x08, 0x10, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x08, 0x04, 0x08, 0x10, 0x00, 0x00, 0x3c, 0x62, 0x62, 0x0c, 0x18, 0x00, 0x18, 0x00, + // 0x40 - 0x47 + 0x7c, 0x82, 0xba, 0xa2, 0xba, 0x82, 0x7c, 0x00, 0x10, 0x28, 0x28, 0x44, 0x7c, 0x82, 0x82, 0x00, + 0x7c, 0x42, 0x42, 0x7c, 0x42, 0x42, 0x7c, 0x00, 0x1c, 0x22, 0x40, 0x40, 0x40, 0x22, 0x1c, 0x00, + 0x78, 0x44, 0x42, 0x42, 0x42, 0x44, 0x78, 0x00, 0x7e, 0x40, 0x40, 0x7e, 0x40, 0x40, 0x7e, 0x00, + 0x7e, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x00, 0x3c, 0x42, 0x80, 0x9e, 0x82, 0x46, 0x3a, 0x00, + // + 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, + 0x02, 0x02, 0x02, 0x02, 0x42, 0x42, 0x3c, 0x00, 0x42, 0x44, 0x48, 0x50, 0x68, 0x44, 0x42, 0x00, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x82, 0xc6, 0xaa, 0x92, 0x82, 0x82, 0x82, 0x00, + 0x42, 0x62, 0x52, 0x4a, 0x46, 0x42, 0x42, 0x00, 0x38, 0x44, 0x82, 0x82, 0x82, 0x44, 0x38, 0x00, + // 0x50 + 0x7c, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x40, 0x00, 0x38, 0x44, 0x82, 0x82, 0x8a, 0x44, 0x3a, 0x00, + 0x7c, 0x42, 0x42, 0x7c, 0x48, 0x44, 0x42, 0x00, 0x3c, 0x42, 0x40, 0x3c, 0x02, 0x42, 0x3c, 0x00, + 0xfe, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, + 0x82, 0x82, 0x44, 0x44, 0x28, 0x28, 0x10, 0x00, 0x82, 0x92, 0x92, 0xaa, 0xaa, 0x44, 0x44, 0x00, + // + 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x00, 0x82, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x00, + 0x7e, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7e, 0x00, 0x18, 0x10, 0x10, 0x10, 0x10, 0x10, 0x18, 0x00, + 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x18, 0x00, + 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, + // 0x60 + 0x08, 0x10, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x04, 0x7c, 0x84, 0x84, 0x7e, 0x00, + 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x42, 0x3c, 0x00, + 0x02, 0x02, 0x3e, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x7e, 0x40, 0x3e, 0x00, + 0x0c, 0x10, 0x3e, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x3e, 0x02, 0x7c, 0x00, + // + 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x00, 0x18, 0x18, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, + 0x06, 0x06, 0x00, 0x02, 0x42, 0x42, 0x3c, 0x00, 0x20, 0x20, 0x26, 0x28, 0x30, 0x28, 0x26, 0x00, + 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x80, 0xec, 0x92, 0x92, 0x92, 0x92, 0x00, + 0x00, 0x40, 0x78, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x00, + // 0x70 + 0x00, 0x3c, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x00, 0x00, 0x78, 0x84, 0x84, 0x7c, 0x04, 0x06, 0x00, + 0x00, 0x00, 0x5c, 0x62, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x3c, 0x02, 0x7c, 0x00, + 0x00, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x0e, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x3f, 0x00, + 0x00, 0x00, 0x42, 0x42, 0x24, 0x24, 0x18, 0x00, 0x00, 0x00, 0x92, 0x92, 0x92, 0x92, 0x6c, 0x00, + // + 0x00, 0x00, 0x42, 0x24, 0x18, 0x24, 0x42, 0x00, 0x00, 0x00, 0x42, 0x42, 0x3e, 0x02, 0x7c, 0x00, + 0x00, 0x00, 0x7e, 0x02, 0x3c, 0x40, 0x7e, 0x00, 0x08, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x00, + 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, 0x20, 0x10, 0x10, 0x08, 0x10, 0x10, 0x20, 0x00, + 0x00, 0x00, 0x60, 0x92, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // 0x80 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x90, 0x90, 0x60, 0x00, + 0x1e, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x40, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78, 0x30, 0x00, 0x00, + 0x20, 0xf8, 0x26, 0x78, 0xd0, 0x80, 0x7c, 0x00, 0x00, 0x10, 0x3a, 0x1c, 0x36, 0x5a, 0x36, 0x00, + // + 0x00, 0x00, 0x44, 0x42, 0x42, 0x42, 0x30, 0x00, 0x00, 0x3c, 0x00, 0x3c, 0x42, 0x02, 0x3c, 0x00, + 0x00, 0x3c, 0x00, 0x7c, 0x08, 0x38, 0x66, 0x00, 0x00, 0x14, 0x72, 0x1c, 0x32, 0x52, 0x34, 0x00, + 0x00, 0x28, 0x2c, 0x3a, 0x62, 0x16, 0x10, 0x00, 0x00, 0x08, 0x5c, 0x6a, 0x4a, 0x0c, 0x18, 0x00, + 0x00, 0x08, 0x0c, 0x38, 0x4c, 0x4a, 0x38, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x62, 0x02, 0x1c, 0x00, + // 0x90 + 0x00, 0x00, 0x80, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x28, 0xf2, 0x3c, 0x6a, 0xaa, 0xb6, 0xec, 0x00, + 0x80, 0x88, 0x84, 0x84, 0x82, 0x92, 0x70, 0x00, 0x78, 0x00, 0x3c, 0xc2, 0x02, 0x04, 0x78, 0x00, + 0x78, 0x00, 0xfc, 0x08, 0x30, 0x50, 0x9e, 0x00, 0x2c, 0xf2, 0x20, 0x7c, 0xa2, 0xa2, 0xe4, 0x00, + 0x28, 0xf4, 0x2a, 0x4a, 0x4a, 0x88, 0xb0, 0x00, 0x20, 0xfc, 0x12, 0xfc, 0x08, 0xc2, 0x7c, 0x00, + // + 0x04, 0x18, 0x60, 0x80, 0xc0, 0x30, 0x0e, 0x00, 0x84, 0xbe, 0x84, 0x84, 0x84, 0x84, 0x58, 0x00, + 0x00, 0x7c, 0x02, 0x00, 0x80, 0x82, 0x7e, 0x00, 0x20, 0xfe, 0x10, 0x78, 0x8c, 0xc0, 0x7c, 0x00, + 0x80, 0x80, 0x80, 0x80, 0x82, 0x84, 0x78, 0x00, 0x04, 0xfe, 0x3c, 0x44, 0x7c, 0x04, 0x78, 0x00, + 0x44, 0x5e, 0xf4, 0x44, 0x48, 0x40, 0x3e, 0x00, 0x44, 0x58, 0xe0, 0x3e, 0xc0, 0x40, 0x3c, 0x00, + // 0xA0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x90, 0x90, 0x60, 0x00, + 0x1e, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x40, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78, 0x30, 0x00, 0x00, + 0x1e, 0x62, 0x1e, 0x62, 0x04, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x1e, 0x6a, 0x0e, 0x08, 0x18, 0x00, + // 0xA8 + 0x00, 0x00, 0x06, 0x18, 0x68, 0x08, 0x08, 0x00, 0x00, 0x10, 0x1c, 0x72, 0x42, 0x04, 0x38, 0x00, + 0x00, 0x00, 0x0c, 0x78, 0x10, 0x10, 0x7e, 0x00, 0x00, 0x08, 0x08, 0x7c, 0x18, 0x28, 0x48, 0x00, + 0x00, 0x00, 0x26, 0x1a, 0x72, 0x10, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x34, 0x04, 0x08, 0x7e, 0x00, + 0x00, 0x00, 0x78, 0x04, 0x3c, 0x04, 0x78, 0x00, 0x00, 0x00, 0x52, 0x4a, 0x22, 0x04, 0x38, 0x00, + // 0xB0 + 0x00, 0x00, 0x80, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xc2, 0x14, 0x1c, 0x10, 0x30, 0x60, 0x00, + 0x02, 0x0c, 0x38, 0xc8, 0x08, 0x08, 0x08, 0x00, 0x60, 0x3c, 0xe2, 0x82, 0x82, 0x04, 0x38, 0x00, + 0x00, 0x1c, 0x70, 0x10, 0x10, 0x1c, 0xe2, 0x00, 0x08, 0xfe, 0x18, 0x38, 0x68, 0xc8, 0x18, 0x00, + 0x10, 0x3e, 0xd2, 0x12, 0x22, 0x62, 0xcc, 0x00, 0x20, 0x3c, 0xf0, 0x1e, 0xf0, 0x08, 0x08, 0x00, + // + 0x10, 0x3e, 0x62, 0xc2, 0x04, 0x0c, 0x70, 0x00, 0x40, 0x7e, 0x44, 0x84, 0x84, 0x08, 0x30, 0x00, + 0x3e, 0xc2, 0x02, 0x02, 0x02, 0x02, 0xfc, 0x00, 0x44, 0x5e, 0xe4, 0x44, 0x44, 0x08, 0xf0, 0x00, + 0x60, 0x12, 0xc2, 0x22, 0x04, 0x04, 0xf8, 0x00, 0x3c, 0xc6, 0x0c, 0x08, 0x38, 0x6c, 0xc6, 0x00, + 0x40, 0x4e, 0x72, 0xc4, 0x4c, 0x40, 0x3e, 0x00, 0x82, 0x42, 0x62, 0x04, 0x04, 0x08, 0x70, 0x00, + // 0xC0 + 0x3c, 0x42, 0x72, 0x8a, 0x04, 0x0c, 0x70, 0x00, 0x0c, 0xf8, 0x10, 0xfe, 0x10, 0x10, 0x60, 0x00, + 0x22, 0xa2, 0x92, 0x42, 0x04, 0x08, 0x70, 0x00, 0x3c, 0x40, 0x1e, 0xe8, 0x08, 0x10, 0x60, 0x00, + 0x40, 0x40, 0x70, 0x4c, 0x42, 0x40, 0x40, 0x00, 0x08, 0x3e, 0xc8, 0x08, 0x08, 0x18, 0x70, 0x00, + 0x00, 0x1c, 0x60, 0x00, 0x00, 0x3c, 0xc2, 0x00, 0x3c, 0xc2, 0x26, 0x38, 0x1c, 0x36, 0xe2, 0x00, + // + 0x10, 0x3c, 0xc6, 0x1c, 0x38, 0xd6, 0x12, 0x00, 0x02, 0x02, 0x02, 0x06, 0x04, 0x1c, 0xf0, 0x00, + 0x18, 0x4c, 0x44, 0x46, 0x42, 0x82, 0x82, 0x00, 0x80, 0x86, 0xbc, 0xe0, 0x80, 0x80, 0x7e, 0x00, + 0x3c, 0xc2, 0x02, 0x02, 0x04, 0x08, 0x30, 0x00, 0x30, 0x48, 0x4c, 0x84, 0x86, 0x02, 0x02, 0x00, + 0x10, 0xfe, 0x10, 0x54, 0x52, 0x92, 0x92, 0x00, 0x3c, 0xc2, 0x02, 0x44, 0x28, 0x10, 0x0c, 0x00, + // 0xD0 + 0x70, 0x0c, 0x60, 0x18, 0xc4, 0x30, 0x0e, 0x00, 0x30, 0x40, 0x4c, 0x84, 0x8e, 0xba, 0x62, 0x00, + 0x04, 0x04, 0x64, 0x18, 0x0c, 0x16, 0xe2, 0x00, 0x1c, 0xe0, 0x3e, 0xe0, 0x20, 0x20, 0x1e, 0x00, + 0x4e, 0x52, 0x62, 0xe4, 0x20, 0x10, 0x18, 0x00, 0x1c, 0x64, 0x04, 0x08, 0x08, 0x10, 0xfe, 0x00, + 0x1c, 0x62, 0x02, 0x3e, 0x02, 0x02, 0x7c, 0x00, 0x3c, 0xc0, 0x3e, 0xc2, 0x02, 0x04, 0x78, 0x00, + // + 0x44, 0x42, 0x42, 0x42, 0x22, 0x04, 0x78, 0x00, 0x50, 0x50, 0x52, 0x52, 0x52, 0x54, 0x88, 0x00, + 0x80, 0x80, 0x82, 0x82, 0x84, 0x88, 0xf0, 0x00, 0x1c, 0xe2, 0x82, 0x82, 0x82, 0x4c, 0x74, 0x00, + 0x3c, 0xc2, 0x82, 0x82, 0x02, 0x04, 0x38, 0x00, 0xc0, 0x62, 0x22, 0x02, 0x04, 0x08, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x02, 0x00, + // 0xE0 + 0x20, 0xf8, 0x40, 0x5e, 0x80, 0xa0, 0x9e, 0x00, 0x20, 0xfe, 0x40, 0x7c, 0xc2, 0x86, 0x3c, 0x00, + 0x00, 0x3c, 0xc6, 0x02, 0x02, 0x0c, 0x38, 0x00, 0x0e, 0xf8, 0x10, 0x20, 0x20, 0x10, 0x0e, 0x00, + 0x40, 0x4c, 0x30, 0x40, 0x80, 0x80, 0x7e, 0x00, 0x44, 0xf2, 0x4a, 0x9c, 0xa4, 0xa6, 0x3a, 0x00, + 0x40, 0x5c, 0x82, 0x80, 0xa0, 0xa0, 0x9e, 0x00, 0x48, 0x7c, 0x52, 0xb2, 0xbe, 0xaa, 0x4c, 0x00, + // + 0x20, 0xfc, 0x32, 0x62, 0xee, 0xaa, 0x2c, 0x00, 0x38, 0x54, 0x92, 0x92, 0xb2, 0xa2, 0x4c, 0x00, + 0x44, 0x5e, 0x84, 0x9c, 0xa4, 0xa6, 0x9c, 0x00, 0x28, 0xee, 0x44, 0x84, 0x84, 0x44, 0x38, 0x00, + 0x78, 0x10, 0x64, 0x34, 0x8a, 0x8a, 0x30, 0x00, 0x30, 0x58, 0x48, 0x84, 0x84, 0x02, 0x02, 0x00, + 0xbc, 0x88, 0xbe, 0x84, 0xbc, 0xa6, 0x9c, 0x00, 0x68, 0x1e, 0x68, 0x1e, 0x78, 0x8c, 0x7a, 0x00, + // 0xF0 + 0x70, 0x14, 0x7c, 0x96, 0x94, 0x94, 0x68, 0x00, 0x2c, 0xf2, 0x60, 0xa0, 0xa2, 0xc2, 0x7c, 0x00, + 0x48, 0x7c, 0x6a, 0xaa, 0xb2, 0xb2, 0x6c, 0x00, 0x10, 0xf8, 0x20, 0xf8, 0x22, 0x22, 0x1c, 0x00, + 0x48, 0x5c, 0x6a, 0xc2, 0x64, 0x20, 0x18, 0x00, 0x10, 0xbc, 0xd6, 0xca, 0xaa, 0x1c, 0x70, 0x00, + 0x10, 0x1c, 0x12, 0x70, 0x9c, 0x92, 0x70, 0x00, 0xe0, 0x18, 0x40, 0x7c, 0xc2, 0x82, 0x3c, 0x00, + // + 0x44, 0x42, 0x82, 0xa2, 0x62, 0x04, 0x78, 0x00, 0x7c, 0x38, 0x7c, 0xc2, 0xba, 0x26, 0x3c, 0x00, + 0x48, 0xd4, 0x64, 0x64, 0xc4, 0xc4, 0x46, 0x00, 0x7c, 0x30, 0x7c, 0xc2, 0x82, 0x06, 0x3c, 0x00, + 0x20, 0xfc, 0x32, 0x62, 0xe2, 0xa2, 0x2c, 0x00, 0x10, 0x30, 0x60, 0x72, 0xd2, 0x92, 0x9c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x02, 0x00, +}; + +// set system font +void ngpBiosSYSFONTSET(unsigned char *pt, char trans, char font) +{ + int i,j; + unsigned char data, line; + + for(i = 0; i < 8*256; i++) { + data = 0; + line = sysfont[i]; + for(j = 0; j < 4; j++) { + data = data<<2; + data|= ((line&0x80) ? font : trans); + line = line<<1; + } + pt[1] = data; + data = 0; + for(j = 0; j < 4; j++) { + data = data<<2; + data|= ((line&0x80) ? font : trans); + line = line<<1; + } + pt[0] = data; + pt+= 2; + } +} + diff --git a/ngpBios.h b/ngpBios.h new file mode 100644 index 0000000..d75a97c --- /dev/null +++ b/ngpBios.h @@ -0,0 +1,22 @@ +//--------------------------------------------------------------------------- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. See also the license.txt file for +// additional informations. +//--------------------------------------------------------------------------- + +// ngpBios.h: interface for the ngpBios class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_NGPBIOS_H__96457662_3A01_11D4_8645_0050DA4EEEA0__INCLUDED_) +#define AFX_NGPBIOS_H__96457662_3A01_11D4_8645_0050DA4EEEA0__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +void ngpBiosSYSFONTSET(unsigned char *pt, char i, char j); + +#endif // !defined(AFX_NGPBIOS_H__96457662_3A01_11D4_8645_0050DA4EEEA0__INCLUDED_) diff --git a/psp/-menu.cpp b/psp/-menu.cpp new file mode 100644 index 0000000..ed7d0f5 --- /dev/null +++ b/psp/-menu.cpp @@ -0,0 +1,1369 @@ +#include +#include +#include + +#include +#include +#include + +#include "StdAfx.h" +#include "main.h" +#include "input.h" +#include "neopopsound.h" +#include "flash.h" + +#include "menu.h" +#include "emulate.h" + +#include "pl_psp.h" +#include "pl_snd.h" +#include "image.h" +#include "video.h" +#include "pl_perf.h" +#include "ctrl.h" +#include "pl_util.h" +#include "pl_file.h" +#include "pl_ini.h" +#include "pl_rewind.h" +#include "ui.h" +#include "state.h" + +#undef u32 + +extern PspImage *Screen; +extern pl_rewind Rewinder; + +pl_file_path CurrentGame = "", + GamePath, + SaveStatePath, + ScreenshotPath, + IniPath, + BorderPath; +static PspImage *Background; +static PspImage *NoSaveIcon; +static int TabIndex; +static int ResumeEmulation; +static int dmode; +static int fskip; +static int cclock; +static int rrewind; +static int vvsync; +static int ppos; +static int ccont; +static int bbord; +const char *bordername; +int save_name; +int sinborde; + +psp_ctrl_map_t current_map; +psp_options_t psp_options; + +/* Default configuration */ +static psp_ctrl_map_t default_map = +{ + { + JST|0x01, /* Analog Up */ + JST|0x02, /* Analog Down */ + JST|0x04, /* Analog Left */ + JST|0x08, /* Analog Right */ + JST|0x01, /* D-pad Up */ + JST|0x02, /* D-pad Down */ + JST|0x04, /* D-pad Left */ + JST|0x08, /* D-pad Right */ + 0, /* Square */ + JST|0x10, /* Cross */ + JST|0x20, /* Circle */ + 0, /* Triangle */ + 0, /* L Trigger */ + 0, /* R Trigger */ + JST|0x40, /* Select */ + 0, /* Start */ + SPC|SPC_MENU, /* L+R Triggers */ + 0, /* Start+Select */ + 0, /* Select + L */ + 0, /* Select + R */ + } +}; + +/* Tab labels */ +static const char *TabLabel[] = +{ + "Game", + "Save/Load", + "Controls", + "Options", + "System", + "About" +}; + +static const char + PresentSlotText[] = "\026\244\020 Save\t\026\001\020 Load\t\026\243\020 Delete", + EmptySlotText[] = "\026\244\020 Save", + ControlHelpText[] = "\026\250\020 Change mapping\t\026\001\020 Save to \271"; + +#define TAB_QUICKLOAD 0 +#define TAB_STATE 1 +#define TAB_CONTROLS 2 +#define TAB_OPTIONS 3 +#define TAB_SYSTEM 4 +#define TAB_ABOUT 5 +#define TAB_MAX TAB_ABOUT + +#define OPTION_DISPLAY_MODE 0x01 +#define OPTION_FRAME_SKIP 0x02 +#define OPTION_CLOCK_FREQ 0x03 +#define OPTION_SHOW_FPS 0x04 +#define PERFECT_SYNC 0x05 +#define OPTION_CONTROL_MODE 0x06 +#define OPTION_ANIMATE 0x07 +#define OPTION_AUTOFIRE 0x08 +#define OPTION_POSVX 0x09 +#define SYSTEM_RESET 0x10 +#define SYSTEM_SCRNSHOT 0x11 +#define SYSTEM_EXIT 0x12 +#define OPTION_BORDER 0x13 + + +#define SET_AS_CURRENT_GAME(filename) \ + strncpy(CurrentGame, filename, sizeof(CurrentGame) - 1) +#define CURRENT_GAME (CurrentGame) +#define GAME_LOADED (CurrentGame[0] != '\0') + +static void psp_init_controls(); +static int psp_load_controls(); +static int psp_save_controls(); +static void psp_load_options(); +static int psp_save_options(); +static int psp_save_options_game(); +static void psp_load_options_game(); +static void psp_load_border_name(); + +static void psp_discard_alpha(PspImage *image); + +static void psp_display_control_tab(); +static void psp_display_state_tab(); + +static PspImage* psp_load_state_icon(const char *path); +static int psp_load_state(const char *path); +static PspImage* psp_save_state(const char *path, PspImage *icon); + +static const char *QuickloadFilter[] = { "ZIP", "NGP", "NGC", "NGPC", '\0' }; + +static int OnGenericCancel(const void *uiobject, + const void *param); +static void OnGenericRender(const void *uiobject, + const void *item_obj); +static int OnGenericButtonPress(const PspUiFileBrowser *browser, + const char *path, + u32 button_mask); + +static int OnSplashButtonPress(const struct PspUiSplash *splash, + u32 button_mask); +static void OnSplashRender(const void *uiobject, + const void *null); +static const char* OnSplashGetStatusBarText(const struct PspUiSplash *splash); + +static int OnMenuOk(const void *menu, + const void *item); +static int OnMenuButtonPress(const struct PspUiMenu *uimenu, + pl_menu_item* item, + u32 button_mask); +static int OnMenuItemChanged(const struct PspUiMenu *uimenu, + pl_menu_item* item, + const pl_menu_option* option); + +static int OnSaveStateOk(const void *gallery, const void *item); +static int OnSaveStateButtonPress(const PspUiGallery *gallery, + pl_menu_item *sel, + u32 button_mask); + +static int OnQuickloadOk(const void *browser, const void *path); + +static void OnSystemRender(const void *uiobject, + const void *item_obj); + +PspUiFileBrowser QuickloadBrowser = +{ + OnGenericRender, + OnQuickloadOk, + OnGenericCancel, + OnGenericButtonPress, + QuickloadFilter, + 0 +}; + +PspUiMenu + OptionUiMenu = + { + OnGenericRender, /* OnRender() */ + OnMenuOk, /* OnOk() */ + OnGenericCancel, /* OnCancel() */ + OnMenuButtonPress, /* OnButtonPress() */ + OnMenuItemChanged, /* OnItemChanged() */ + }, + SystemUiMenu = + { + OnSystemRender, /* OnRender() */ + OnMenuOk, /* OnOk() */ + OnGenericCancel, /* OnCancel() */ + OnMenuButtonPress, /* OnButtonPress() */ + OnMenuItemChanged, /* OnItemChanged() */ + }, + ControlUiMenu = + { + OnGenericRender, /* OnRender() */ + OnMenuOk, /* OnOk() */ + OnGenericCancel, /* OnCancel() */ + OnMenuButtonPress, /* OnButtonPress() */ + OnMenuItemChanged, /* OnItemChanged() */ + }; + +PspUiGallery SaveStateGallery = +{ + OnGenericRender, /* OnRender() */ + OnSaveStateOk, /* OnOk() */ + OnGenericCancel, /* OnCancel() */ + OnSaveStateButtonPress, /* OnButtonPress() */ + NULL /* Userdata */ +}; + +/* Menu options */ +PL_MENU_OPTIONS_BEGIN(MappableButtons) + /* Unmapped */ + PL_MENU_OPTION("None", 0) + /* Special */ + PL_MENU_OPTION("Special: Open Menu", (SPC|SPC_MENU)) + PL_MENU_OPTION("Special: Rewind", (SPC|SPC_REWIND)) + /* Directions */ + PL_MENU_OPTION("Up", (JST|0x01)) + PL_MENU_OPTION("Down", (JST|0x02)) + PL_MENU_OPTION("Left", (JST|0x04)) + PL_MENU_OPTION("Right", (JST|0x08)) + /* Buttons */ + PL_MENU_OPTION("A", (JST|0x10)) + PL_MENU_OPTION("B", (JST|0x20)) + PL_MENU_OPTION("A (autofire)", (AFI|0x10)) + PL_MENU_OPTION("B (autofire)", (AFI|0x20)) + PL_MENU_OPTION("Option", (JST|0x40)) + PL_MENU_OPTION("Test switch", (JST|0x80)) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(ToggleOptions) + PL_MENU_OPTION("Disabled", 0) + PL_MENU_OPTION("Enabled", 1) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(AutofireOptions) + PL_MENU_OPTION("Once every 3 frames", 2) + PL_MENU_OPTION("Once every 10 frames", 9) + PL_MENU_OPTION("Once every 30 frames", 29) + PL_MENU_OPTION("Once every 60 frames", 59) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(ScreenSizeOptions) + PL_MENU_OPTION("Actual size", DISPLAY_MODE_UNSCALED) + PL_MENU_OPTION("4:3 scaled (fit height)", DISPLAY_MODE_FIT_HEIGHT) + PL_MENU_OPTION("16:9 scaled (fit screen)", DISPLAY_MODE_FILL_SCREEN) + PL_MENU_OPTION("Simple 2x - SW", SIMPLE_2X) + PL_MENU_OPTION("Simple 2x Wide - SW", SIMPLE_W) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(FrameskipOptions) + PL_MENU_OPTION("30fps", 1) + PL_MENU_OPTION("60fps", 0) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(VsyncOptions) + PL_MENU_OPTION("Normal VSync", 0) + PL_MENU_OPTION("Perfect VSync", 1) + PL_MENU_OPTION("Intelligent VSync", 2) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(BorderOptions) + PL_MENU_OPTION("No border", 0) + PL_MENU_OPTION("Default", 1) + PL_MENU_OPTION("Custom", 2) + PL_MENU_OPTION("Baseball",3) + PL_MENU_OPTION("Casino",4) + PL_MENU_OPTION("Pachinko",5) + PL_MENU_OPTION("Dating sim",6) + PL_MENU_OPTION("Board",7) + PL_MENU_OPTION("Generic RPG",8) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(ScreenPosOptions) + PL_MENU_OPTION("2", 2) + PL_MENU_OPTION("8", 8) + PL_MENU_OPTION("16", 16) + PL_MENU_OPTION("18", 18) + PL_MENU_OPTION("22", 22) + PL_MENU_OPTION("24", 24) + PL_MENU_OPTION("32", 32) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(PspClockFreqOptions) + PL_MENU_OPTION("222 MHz", 222) + PL_MENU_OPTION("266 MHz", 266) + PL_MENU_OPTION("300 MHz", 300) + PL_MENU_OPTION("333 MHz", 333) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(ControlModeOptions) + PL_MENU_OPTION("\026\242\020 cancels, \026\241\020 confirms (US)", 0) + PL_MENU_OPTION("\026\241\020 cancels, \026\242\020 confirms (Japan)", 1) +PL_MENU_OPTIONS_END + +/* Menu items */ +PL_MENU_ITEMS_BEGIN(ControlMenuDef) + PL_MENU_ITEM(PSP_CHAR_ANALUP,0,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_ANALDOWN,1,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_ANALLEFT,2,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_ANALRIGHT,3,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_UP,4,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_DOWN,5,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_LEFT,6,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_RIGHT,7,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_SQUARE,8,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_CROSS,9,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_CIRCLE,10,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_TRIANGLE,11,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_LTRIGGER,12,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_RTRIGGER,13,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_SELECT,14,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_START,15,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_LTRIGGER"+"PSP_CHAR_RTRIGGER,16,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_START"+"PSP_CHAR_SELECT,17,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_SELECT"+"PSP_CHAR_LTRIGGER,18,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_SELECT"+"PSP_CHAR_RTRIGGER,19,MappableButtons,ControlHelpText) +PL_MENU_ITEMS_END +PL_MENU_ITEMS_BEGIN(OptionMenuDef) + PL_MENU_HEADER("Video") + PL_MENU_ITEM("Screen size",OPTION_DISPLAY_MODE,ScreenSizeOptions,"\026\250\020 Change screen size") + PL_MENU_ITEM("Screen position",OPTION_POSVX,ScreenPosOptions,"\026\244\020 Change screen position") + PL_MENU_ITEM("VSYNC",PERFECT_SYNC,VsyncOptions,"\026\250\020 Enable/disable vsync options") + PL_MENU_HEADER("Input") + PL_MENU_ITEM("Rate of autofire", OPTION_AUTOFIRE,AutofireOptions,"\026\250\020 Adjust rate of autofire") + PL_MENU_HEADER("Performance") + PL_MENU_ITEM("Frame skipping", OPTION_FRAME_SKIP,FrameskipOptions,"\026\250\020 Select number of frames to skip per update") + PL_MENU_ITEM("PSP clock frequency",OPTION_CLOCK_FREQ,PspClockFreqOptions,"\026\250\020 Larger values: faster emulation, faster battery depletion (default: 222MHz)") + PL_MENU_ITEM("Show FPS counter",OPTION_SHOW_FPS,ToggleOptions,"\026\250\020 Show/hide the frames-per-second counter") + PL_MENU_HEADER("Menu") + PL_MENU_ITEM("Button mode",OPTION_CONTROL_MODE,ControlModeOptions,"\026\250\020 Change OK and Cancel button mapping") + PL_MENU_ITEM("Border",OPTION_BORDER,BorderOptions,"\026\250\020 Enable/disable PNG borders") + // PL_MENU_ITEM("Animations",OPTION_ANIMATE,ToggleOptions,"\026\250\020 Enable/disable menu animations") +PL_MENU_ITEMS_END +PL_MENU_ITEMS_BEGIN(SystemMenuDef) + PL_MENU_HEADER("Options") + PL_MENU_ITEM("Reset",SYSTEM_RESET,NULL,"\026\001\020 Reset system") + PL_MENU_ITEM("Save screenshot",SYSTEM_SCRNSHOT,NULL,"\026\001\020 Save screenshot") + PL_MENU_ITEM("Exit Emulator",SYSTEM_EXIT,NULL,"\026\001\020 Exit Emulator") +PL_MENU_ITEMS_END + +PspUiSplash SplashScreen = +{ + OnSplashRender, + OnGenericCancel, + OnSplashButtonPress, + OnSplashGetStatusBarText +}; + +int InitMenu() +{ + if (!InitEmulation()) + return 0; + + /* Initialize paths */ + sprintf(SaveStatePath, "%sstates/", pl_psp_get_app_directory()); + sprintf(ScreenshotPath, "%sscreens/", pl_psp_get_app_directory()); + sprintf(GamePath, "%s", pl_psp_get_app_directory()); + + /* Load the background image */ + Background = pspImageLoadPng("background.png"); + + /* Initialize menus */ + pl_menu_create(&SystemUiMenu.Menu, SystemMenuDef); + pl_menu_create(&OptionUiMenu.Menu, OptionMenuDef); + pl_menu_create(&ControlUiMenu.Menu, ControlMenuDef); + + /* Init NoSaveState icon image */ + NoSaveIcon = pspImageCreate(160, 152, PSP_IMAGE_16BPP); + pspImageClear(NoSaveIcon, RGB(0x44,0x00,0x00)); + + /* Initialize state menu */ + int i; + pl_menu_item *item; + for (i = 0; i < 10; i++) + { + item = pl_menu_append_item(&SaveStateGallery.Menu, i, NULL); + pl_menu_set_item_help_text(item, EmptySlotText); + } + + /* Initialize options */ + psp_load_controls(); + psp_load_options(); + + /* Initialize UI components */ + UiMetric.Background = Background; + UiMetric.Font = &PspStockFont; + UiMetric.Left = 8; + UiMetric.Top = 24; + UiMetric.Right = 475; + UiMetric.Bottom = 250; + UiMetric.ScrollbarColor = PSP_COLOR_GRAY; + UiMetric.ScrollbarBgColor = 0x44ffffff; + UiMetric.ScrollbarWidth = 10; + UiMetric.TextColor = PSP_COLOR_GRAY; + UiMetric.SelectedColor = COLOR(0xf7,0xc2,0x50,0xFF); + UiMetric.SelectedBgColor = COLOR(0xd5,0xf1,0x17,0x99); + UiMetric.StatusBarColor = PSP_COLOR_WHITE; + UiMetric.BrowserFileColor = PSP_COLOR_GRAY; + UiMetric.BrowserDirectoryColor = PSP_COLOR_YELLOW; + UiMetric.GalleryIconsPerRow = 5; + UiMetric.GalleryIconMarginWidth = 16; + UiMetric.MenuItemMargin = 5; + UiMetric.MenuSelOptionBg = PSP_COLOR_GRAY; + UiMetric.MenuOptionBoxColor = PSP_COLOR_GRAY; + UiMetric.MenuOptionBoxBg = COLOR(0x44,0x00,0x00,0xbb); + UiMetric.MenuDecorColor = UiMetric.SelectedColor; + UiMetric.DialogFogColor = COLOR(0xd5,0xf1,0x17,0xbb); + UiMetric.TitlePadding = 4; + UiMetric.TitleColor = PSP_COLOR_WHITE; + UiMetric.MenuFps = 30; + UiMetric.TabBgColor = COLOR(0xcc,0x73,0x73,0xff); + UiMetric.BrowserScreenshotPath = ScreenshotPath; + UiMetric.BrowserScreenshotDelay = 2; + + TabIndex = TAB_QUICKLOAD; + + return 1; +} + +void DisplayMenu() +{ + pl_menu_item *item; + + /* Menu loop */ + do + { + ResumeEmulation = 0; + /*NOTA RESUMEN*/ + SetVideoMode(); + + /* Set normal clock frequency */ + pl_psp_set_clock_freq(222); + /* Set buttons to autorepeat */ + pspCtrlSetPollingMode(PSP_CTRL_AUTOREPEAT); + + do + { + /* Display appropriate tab */ + switch (TabIndex) + { + case TAB_QUICKLOAD: + pspUiOpenBrowser(&QuickloadBrowser, + (GAME_LOADED) ? CURRENT_GAME : GamePath); + break; + case TAB_CONTROLS: + psp_display_control_tab(); + break; + case TAB_OPTIONS: + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_DISPLAY_MODE); + pl_menu_select_option_by_value(item, (void*)(int)psp_options.display_mode); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, PERFECT_SYNC); + pl_menu_select_option_by_value(item, (void*)(int)psp_options.pvsync); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_CLOCK_FREQ); + pl_menu_select_option_by_value(item, (void*)(int)psp_options.clock_freq); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_SHOW_FPS); + pl_menu_select_option_by_value(item, (void*)(int)psp_options.show_fps); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_CONTROL_MODE); + pl_menu_select_option_by_value(item, (void*)(UiMetric.OkButton == PSP_CTRL_CIRCLE)); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_POSVX); + pl_menu_select_option_by_value(item, (void*)(int)psp_options.pos_vert); + // item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_ANIMATE); + // pl_menu_select_option_by_value(item, (void*)(int)UiMetric.Animate); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_FRAME_SKIP); + pl_menu_select_option_by_value(item, (void*)(int)psp_options.frame_skip); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_AUTOFIRE); + pl_menu_select_option_by_value(item, (void*)(int)psp_options.autofire); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_BORDER); + pl_menu_select_option_by_value(item, (void*)(int)psp_options.border); + + pspUiOpenMenu(&OptionUiMenu, NULL); + + if (!GAME_LOADED){psp_save_options();} + else{ + psp_save_options_game();} + break; + case TAB_STATE: + psp_display_state_tab(); + break; + case TAB_SYSTEM: + pspUiOpenMenu(&SystemUiMenu, NULL); + break; + case TAB_ABOUT: + pspUiSplashScreen(&SplashScreen); + break; + } + } while (!ExitPSP && !ResumeEmulation); + + if (!ExitPSP) + { + /* Set clock frequency during emulation */ + pl_psp_set_clock_freq(psp_options.clock_freq); + /* Set buttons to normal mode */ + pspCtrlSetPollingMode(PSP_CTRL_NORMAL); + + if (ResumeEmulation) + { + /* Resume emulation */ + if (UiMetric.Animate) pspUiFadeout(); + RunEmulation(); + if (UiMetric.Animate) pspUiFadeout(); + } + } + } while (!ExitPSP); +} + +void TrashMenu() +{ + TrashEmulation(); + + pl_menu_destroy(&SystemUiMenu.Menu); + pl_menu_destroy(&OptionUiMenu.Menu); + pl_menu_destroy(&ControlUiMenu.Menu); + pl_menu_destroy(&SaveStateGallery.Menu); + + pspImageDestroy(NoSaveIcon); + pspImageDestroy(Background); + psp_load_border_name(); + //psp_save_options(); + +} + +/* Handles drawing of generic items */ +static void OnGenericRender(const void *uiobject, + const void *item_obj) +{ + /* Draw tabs */ + int i, x, width, height = pspFontGetLineHeight(UiMetric.Font); + for (i = 0, x = 5; i <= TAB_MAX; i++, x += width + 10) + { + width = -10; + + if (!GAME_LOADED && (i == TAB_STATE || i == TAB_SYSTEM)) + continue; + if (GAME_LOADED && (i == TAB_ABOUT)) + continue; + + /* Determine width of text */ + width = pspFontGetTextWidth(UiMetric.Font, TabLabel[i]); + + /* Draw background of active tab */ + if (i == TabIndex) + pspVideoFillRect(x - 5, 0, x + width + 5, height + 1, UiMetric.TabBgColor); + + /* Draw name of tab */ + pspVideoPrint(UiMetric.Font, x, 0, TabLabel[i], PSP_COLOR_WHITE); + } +} + +static int OnGenericButtonPress(const PspUiFileBrowser *browser, + const char *path, + u32 button_mask) +{ + int tab_index; + + /* If L or R are pressed, switch tabs */ + if (button_mask & PSP_CTRL_LTRIGGER) + { + TabIndex--; + do + { + tab_index = TabIndex; + if (!GAME_LOADED && (TabIndex == TAB_STATE || TabIndex == TAB_SYSTEM)) TabIndex--; + if (GAME_LOADED && (TabIndex == TAB_ABOUT)) TabIndex--; + if (TabIndex < 0) TabIndex = TAB_MAX; + } while (tab_index != TabIndex); + } + else if (button_mask & PSP_CTRL_RTRIGGER) + { + TabIndex++; + do + { + tab_index = TabIndex; + if (!GAME_LOADED && (TabIndex == TAB_STATE || TabIndex == TAB_SYSTEM)) TabIndex++; + if (GAME_LOADED && (TabIndex == TAB_ABOUT)) TabIndex++; + if (TabIndex > TAB_MAX) TabIndex = 0; + } while (tab_index != TabIndex); + } + else if ((button_mask & (PSP_CTRL_START | PSP_CTRL_SELECT)) + == (PSP_CTRL_START | PSP_CTRL_SELECT)) + { + if (pl_util_save_vram_seq(ScreenshotPath, "ui")) + pspUiAlert("Saved successfully"); + else + pspUiAlert("ERROR: Not saved"); + return 0; + } + else return 0; + + return 1; +} + +static int OnGenericCancel(const void *uiobject, + const void* param) +{ + if (!GAME_LOADED) + return 0; + psp_load_border_name(); + ResumeEmulation = 1; + return 1; +} + +static int OnQuickloadOk(const void *browser, + const void *path) +{ + /* Write flash data for current game */ + if (GAME_LOADED) + writeSaveGameFile(); + + pspUiFlashMessage("Loading, please wait..."); + + if (!handleInputFile((char*)path)) + { + pspUiAlert("Error loading cartridge"); + return 0; + } + + /* Reset selected state */ + SaveStateGallery.Menu.selected = NULL; + + SET_AS_CURRENT_GAME((char*)path); + pl_file_get_parent_directory((const char*)path, + GamePath, + sizeof(GamePath)); + ResumeEmulation = 1; + + /*NOTA RESUMEN*/ + + psp_load_options_game(); + psp_load_border_name(); + save_name = 1; + system_sound_chipreset(); /* Reset sound */ + pl_rewind_reset(&Rewinder); + + return 1; +} + +static int OnSaveStateOk(const void *gallery, const void *item) +{ + char *path; + const char *config_name = pl_file_get_filename(CURRENT_GAME); + + path = (char*)malloc(strlen(SaveStatePath) + strlen(config_name) + 8); + sprintf(path, "%s%s_%02i.rcs", SaveStatePath, config_name, + ((const pl_menu_item*)item)->id); + + if (pl_file_exists(path) && pspUiConfirm("Load state?")) + { + if (psp_load_state(path)) + { + ResumeEmulation = 1; + pl_menu_find_item_by_id(&((PspUiGallery*)gallery)->Menu, + ((pl_menu_item*)item)->id); + // pspUiAlert(path); + free(path); + // pspUiAlert("de nuevo"); + // pspUiAlert(path); + pl_rewind_reset(&Rewinder); + + return 1; + } + + pspUiAlert("ERROR: State not loaded"); + } + + free(path); + return 0; +} + +static int OnSaveStateButtonPress(const PspUiGallery *gallery, + pl_menu_item *sel, + u32 button_mask) +{ + if (button_mask & PSP_CTRL_SQUARE + || button_mask & PSP_CTRL_TRIANGLE) + { + char *path; + char caption[32]; + const char *config_name = pl_file_get_filename(CURRENT_GAME); + pl_menu_item *item = pl_menu_find_item_by_id(&gallery->Menu, sel->id); + + path = (char*)malloc(strlen(SaveStatePath) + strlen(config_name) + 8); + sprintf(path, "%s%s_%02i.rcs", SaveStatePath, config_name, item->id); + + do /* not a real loop; flow control construct */ + { + if (button_mask & PSP_CTRL_SQUARE) + { + if (pl_file_exists(path) && !pspUiConfirm("Overwrite existing state?")) + break; + + pspUiFlashMessage("Saving, please wait ..."); + + PspImage *icon; + if (!(icon = psp_save_state(path, Screen))) + { + pspUiAlert("ERROR: State not saved"); + break; + } + + SceIoStat stat; + + /* Trash the old icon (if any) */ + if (item->param && item->param != NoSaveIcon) + pspImageDestroy((PspImage*)item->param); + + /* Update icon, help text */ + item->param = icon; + pl_menu_set_item_help_text(item, PresentSlotText); + + /* Get file modification time/date */ + if (sceIoGetstat(path, &stat) < 0) + sprintf(caption, "ERROR"); + else + sprintf(caption, "%02i/%02i/%02i %02i:%02i", + stat.st_mtime.month, + stat.st_mtime.day, + stat.st_mtime.year - (stat.st_mtime.year / 100) * 100, + stat.st_mtime.hour, + stat.st_mtime.minute); + + pl_menu_set_item_caption(item, caption); + } + else if (button_mask & PSP_CTRL_TRIANGLE) + { + if (!pl_file_exists(path) || !pspUiConfirm("Delete state?")) + break; + + if (!pl_file_rm(path)) + { + pspUiAlert("ERROR: State not deleted"); + break; + } + + /* Trash the old icon (if any) */ + if (item->param && item->param != NoSaveIcon) + pspImageDestroy((PspImage*)item->param); + + /* Update icon, caption */ + item->param = NoSaveIcon; + pl_menu_set_item_help_text(item, EmptySlotText); + pl_menu_set_item_caption(item, "Empty"); + } + } while (0); + + if (path) free(path); + return 0; + } + + return OnGenericButtonPress(NULL, NULL, button_mask); +} + +static void OnSplashRender(const void *splash, + const void *null) +{ + int fh, i, x, y, height; + const char *lines[] = + { + PSP_APP_NAME" version "PSP_APP_VER" ("__DATE__")", + " ", + "2014 TheElf", + "\026http://theelf-megadev.com/psp", + " ", + "2008-2009 Akop Karapetyan", + "\026http://psp.akop.org/race", + "2008 Flavor", + "2006 Judge_", + NULL + }; + + fh = pspFontGetLineHeight(UiMetric.Font); + + for (i = 0; lines[i]; i++); + height = fh * (i - 1); + + /* Render lines */ + for (i = 0, y = SCR_HEIGHT / 2 - height / 2; lines[i]; i++, y += fh) + { + x = SCR_WIDTH / 2 - pspFontGetTextWidth(UiMetric.Font, lines[i]) / 2; + pspVideoPrint(UiMetric.Font, x, y, lines[i], PSP_COLOR_GRAY); + } + + /* Render PSP status */ + OnGenericRender(splash, null); +} + +static int OnSplashButtonPress(const struct PspUiSplash *splash, + u32 button_mask) +{ + return OnGenericButtonPress(NULL, NULL, button_mask); +} + +static const char* OnSplashGetStatusBarText(const struct PspUiSplash *splash) +{ + return "\026\255\020/\026\256\020 Switch tabs"; +} + +static int OnMenuOk(const void *uimenu, const void* sel_item) +{ + if (uimenu == &ControlUiMenu) + { + /* Save to MS */ + if (psp_save_controls()) + pspUiAlert("Changes saved"); + else + pspUiAlert("ERROR: Changes not saved"); + } + else + { + switch (((const pl_menu_item*)sel_item)->id) + { + case SYSTEM_RESET: + if (pspUiConfirm("Reset the system?")) + { + /* Write flash data for current game */ + if (GAME_LOADED) + writeSaveGameFile(); + + mainemuinit(); + pl_rewind_reset(&Rewinder); + + ResumeEmulation = 1; + return 1; + } + break; + case SYSTEM_SCRNSHOT: + /* Save screenshot */ + if (!pl_util_save_image_seq(ScreenshotPath, + pl_file_get_filename(CURRENT_GAME), + Screen)) + pspUiAlert("ERROR: Screenshot not saved"); + else + pspUiAlert("Screenshot saved successfully"); + break; + } + } + return 0; +} + +static int OnMenuButtonPress(const struct PspUiMenu *uimenu, + pl_menu_item* sel_item, + u32 button_mask) +{ + if (uimenu == &ControlUiMenu) + { + if (button_mask & PSP_CTRL_TRIANGLE) + { + pl_menu_item *item; + int i; + + /* Load default mapping */ + memcpy(¤t_map, &default_map, sizeof(psp_ctrl_map_t)); + + /* Modify the menu */ + for (item = ControlUiMenu.Menu.items, i = 0; item; item = item->next, i++) + pl_menu_select_option_by_value(item, (void*)default_map.button_map[i]); + + return 0; + } + } + + return OnGenericButtonPress(NULL, NULL, button_mask); +} + +static int OnMenuItemChanged(const struct PspUiMenu *uimenu, + pl_menu_item* item, + const pl_menu_option* option) +{ + if (uimenu == &ControlUiMenu) + { + current_map.button_map[item->id] = (unsigned int)option->value; + } + else + { + switch((int)item->id) + { + case OPTION_DISPLAY_MODE: + psp_options.display_mode = (int)option->value; + break; + case OPTION_FRAME_SKIP: + psp_options.frame_skip = (int)option->value; + break; + case OPTION_CLOCK_FREQ: + psp_options.clock_freq = (int)option->value; + break; + case OPTION_SHOW_FPS: + psp_options.show_fps = (int)option->value; + break; + case OPTION_CONTROL_MODE: + UiMetric.OkButton = (!(int)option->value) + ? PSP_CTRL_CROSS : PSP_CTRL_CIRCLE; + UiMetric.CancelButton = (!(int)option->value) + ? PSP_CTRL_CIRCLE : PSP_CTRL_CROSS; + break; + case PERFECT_SYNC: + psp_options.pvsync = (int)option->value; + break; + case OPTION_POSVX: + psp_options.pos_vert = (int)option->value; + break; + case OPTION_ANIMATE: + UiMetric.Animate = (int)option->value; + break; + case OPTION_AUTOFIRE: + psp_options.autofire = (int)option->value; + break; + case OPTION_BORDER: + psp_options.border = (int)option->value; + break; + } + } + return 1; +} + +static void OnSystemRender(const void *uiobject, + const void *item_obj) +{ + int w, h, x, y; + w = Screen->Viewport.Width; + h = Screen->Viewport.Height; + x = UiMetric.Right - w - UiMetric.ScrollbarWidth; + y = SCR_HEIGHT - h - 56; + + /* Draw a small representation of the screen */ + pspVideoShadowRect(x, y, x + w - 1, y + h - 1, PSP_COLOR_BLACK, 3); + sceGuDisable(GU_BLEND); + pspVideoPutImage(Screen, x, y, w, h); + sceGuEnable(GU_BLEND); + pspVideoDrawRect(x, y, x + w - 1, y + h - 1, PSP_COLOR_GRAY); + + OnGenericRender(uiobject, item_obj); +} + +static void psp_init_controls() +{ + /* Initialize to default configuration */ + memcpy(¤t_map, &default_map, sizeof(psp_ctrl_map_t)); +} + +static int psp_load_controls() +{ + psp_ctrl_map_t *config = ¤t_map; + pl_file_path path; + snprintf(path, sizeof(path) - 1, "%sbuttons.cnf", + pl_psp_get_app_directory()); + + /* If no configuration, load defaults */ + if (!pl_file_exists(path)) + { + psp_init_controls(); + return 1; + } + + /* Open file for reading */ + FILE *file = fopen(path, "r"); + if (!file) return 0; + + /* Read contents of struct */ + int nread = fread(config, sizeof(psp_ctrl_map_t), 1, file); + fclose(file); + + if (nread != 1) + { + psp_init_controls(); + return 0; + } + + return 1; +} + +static int psp_save_controls() +{ + psp_ctrl_map_t *config = ¤t_map; + pl_file_path path; + snprintf(path, sizeof(path) - 1, "%sbuttons.cnf", + pl_psp_get_app_directory()); + + /* Open file for writing */ + FILE *file = fopen(path, "w"); + if (!file) return 0; + + /* Write contents of struct */ + int nwritten = fwrite(config, sizeof(psp_ctrl_map_t), 1, file); + fclose(file); + + return (nwritten == 1); +} + +static void psp_display_control_tab() +{ + pl_menu_item *item; + int i; + + /* Load current button mappings */ + for (item = ControlUiMenu.Menu.items, i = 0; item; item = item->next, i++) + pl_menu_select_option_by_value(item, (void*)current_map.button_map[i]); + + pspUiOpenMenu(&ControlUiMenu, NULL); +} + +static void psp_display_state_tab() +{ + pl_menu_item *item, *sel = NULL; + SceIoStat stat; + ScePspDateTime latest; + char caption[32]; + const char *config_name = pl_file_get_filename(CURRENT_GAME); + char *path = (char*)malloc(strlen(SaveStatePath) + strlen(config_name) + 8); + char *game_name = strdup(config_name); + char *dot = strrchr(game_name, '.'); + if (dot) *dot='\0'; + + memset(&latest,0,sizeof(latest)); + + /* Initialize icons */ + for (item = SaveStateGallery.Menu.items; item; item = item->next) + { + sprintf(path, "%s%s_%02i.rcs", SaveStatePath, config_name, item->id); + + if (pl_file_exists(path)) + { + if (sceIoGetstat(path, &stat) < 0) + sprintf(caption, "ERROR"); + else + { + /* Determine the latest save state */ + if (pl_util_date_compare(&latest, &stat.st_mtime) < 0) + { + sel = item; + latest = stat.st_mtime; + } + + sprintf(caption, "%02i/%02i/%02i %02i:%02i", + stat.st_mtime.month, + stat.st_mtime.day, + stat.st_mtime.year - (stat.st_mtime.year / 100) * 100, + stat.st_mtime.hour, + stat.st_mtime.minute); + } + + pl_menu_set_item_caption(item, caption); + item->param = psp_load_state_icon(path); + pl_menu_set_item_help_text(item, PresentSlotText); + } + else + { + pl_menu_set_item_caption(item, "Empty"); + item->param = NoSaveIcon; + pl_menu_set_item_help_text(item, EmptySlotText); + } + } + + free(path); + + /* Highlight the latest save state if none are selected */ + if (SaveStateGallery.Menu.selected == NULL) + SaveStateGallery.Menu.selected = sel; + + pspUiOpenGallery(&SaveStateGallery, game_name); + free(game_name); + + /* Destroy any icons */ + for (item = SaveStateGallery.Menu.items; item; item = item->next) + if (item->param != NULL && item->param != NoSaveIcon) + pspImageDestroy((PspImage*)item->param); +} + +/* Load state icon */ +static PspImage* psp_load_state_icon(const char *path) +{ + FILE *f = fopen(path, "r"); + if (!f) return NULL; + + /* Load image */ + PspImage *image = pspImageLoadPngFd(f); + fclose(f); + + return image; +} + +/* Load state */ +static int psp_load_state(const char *path) +{ + /* Open file for reading */ + FILE *f = fopen(path, "r"); + if (!f) return 0; + + /* Load image into temporary object */ + PspImage *image = pspImageLoadPngFd(f); + pspImageDestroy(image); + + /* Load the state data */ + int status = state_restore(f); + fclose(f); + + return status; +} + +static void psp_discard_alpha(PspImage *image) +{ + int i, j; + for (i = image->Viewport.Y; i < image->Viewport.Height; i++) + for (j = image->Viewport.X; j < image->Viewport.Width; j++) + ((u16*)image->Pixels)[(i * image->Width) + j] |= 0x8000; +} + +/* Save state */ +static PspImage* psp_save_state(const char *path, PspImage *icon) +{ + /* Open file for writing */ + FILE *f; + if (!(f = fopen(path, "w"))) + return NULL; + + /* Create thumbnail */ + PspImage *thumb; + thumb = pspImageCreateCopy(icon); + + if (!thumb) { fclose(f); return NULL; } + + psp_discard_alpha(thumb); + + /* Write the thumbnail */ + if (!pspImageSavePngFd(f, thumb)) + { + pspImageDestroy(thumb); + fclose(f); + pl_file_rm(path); + return NULL; + } + + /* Write the state */ + if (!state_store(f)) + { + pspImageDestroy(thumb); + thumb = NULL; + } + + fclose(f); + return thumb; +} + + + + + +static void psp_load_border_name() +{ + + if (psp_options.border == 2){ + sprintf(BorderPath, "%sborders/", pl_psp_get_app_directory()); + + const char *border_name = pl_file_get_filename(CURRENT_GAME); + pl_file_path path; + snprintf(path, sizeof(path) - 1, "%s%sborder.png", BorderPath, border_name); + bordername = path;} + + + if (psp_options.border >= 3){ + sprintf(BorderPath, "%sborders/", pl_psp_get_app_directory()); + + const char *border_name = pl_file_get_filename(CURRENT_GAME); + pl_file_path path; + if (psp_options.border == 3){ + snprintf(path, sizeof(path) - 1, "%simg1.png", BorderPath, border_name);} + if (psp_options.border == 4){ + snprintf(path, sizeof(path) - 1, "%simg2.png", BorderPath, border_name);} + if (psp_options.border == 5){ + snprintf(path, sizeof(path) - 1, "%simg3.png", BorderPath, border_name);} + if (psp_options.border == 6){ + snprintf(path, sizeof(path) - 1, "%simg4.png", BorderPath, border_name);} + if (psp_options.border == 7){ + snprintf(path, sizeof(path) - 1, "%simg5.png", BorderPath, border_name);} + if (psp_options.border == 8){ + snprintf(path, sizeof(path) - 1, "%simg6.png", BorderPath, border_name);} + bordername = path;} + + + + } + + + +static void psp_load_options_game() +{ + sprintf(IniPath, "%sini/", pl_psp_get_app_directory()); + + const char *config_name = pl_file_get_filename(CURRENT_GAME); + pl_file_path path; + snprintf(path, sizeof(path) - 1, "%s%soptions.ini", + IniPath, config_name); + + /* Load INI */ + pl_ini_file file; + pl_ini_load(&file, path); + + + psp_options.display_mode = pl_ini_get_int(&file, "Video", "Display Mode", dmode); + psp_options.frame_skip = pl_ini_get_int(&file, "Video", "Frame Skipping", fskip); + psp_options.clock_freq = pl_ini_get_int(&file, "Video", "PSP Clock Frequency", cclock); + psp_options.show_fps = pl_ini_get_int(&file, "Video", "Show FPS", 0); + psp_options.update_freq = pl_ini_get_int(&file, "Video", "Update Frequency", HOST_FPS); + psp_options.rewind_save_rate = pl_ini_get_int(&file, "Enhancements", "Rewind Save Rate", rrewind); + pl_ini_get_string(&file, "File", "Game Path", NULL, + GamePath, sizeof(GamePath)); + psp_options.pvsync = pl_ini_get_int(&file, "Video", "Vsync", vvsync); + psp_options.pos_vert = pl_ini_get_int(&file, "Video", "PosVert", ppos); + UiMetric.Animate = pl_ini_get_int(&file, "Menu", "Animate", 0); + psp_options.border = pl_ini_get_int(&file, "Enhancements", "Border", bbord); + psp_options.autofire = pl_ini_get_int(&file, "Input", "Autofire", 2); + if (psp_options.autofire < 2) + psp_options.autofire = 2; + + int control_mode = pl_ini_get_int(&file, "Menu", "Control Mode", ccont); + UiMetric.OkButton = (!control_mode) + ? PSP_CTRL_CROSS : PSP_CTRL_CIRCLE; + UiMetric.CancelButton = (!control_mode) + ? PSP_CTRL_CIRCLE : PSP_CTRL_CROSS; + + /* Clean up */ + pl_ini_destroy(&file); +} + + +static void psp_load_options() +{ + pl_file_path path; + snprintf(path, sizeof(path) - 1, "%s%s", + pl_psp_get_app_directory(), "options.ini"); + + /* Load INI */ + pl_ini_file file; + pl_ini_load(&file, path); + + psp_options.display_mode = pl_ini_get_int(&file, "Video", "Display Mode", + SIMPLE_2X); + psp_options.frame_skip = pl_ini_get_int(&file, "Video", "Frame Skipping", 1); + psp_options.clock_freq = pl_ini_get_int(&file, "Video", "PSP Clock Frequency", 333); + psp_options.show_fps = pl_ini_get_int(&file, "Video", "Show FPS", 0); + psp_options.update_freq = pl_ini_get_int(&file, "Video", "Update Frequency", HOST_FPS); + psp_options.rewind_save_rate = pl_ini_get_int(&file, "Enhancements", "Rewind Save Rate", 5); + pl_ini_get_string(&file, "File", "Game Path", NULL, + GamePath, sizeof(GamePath)); + psp_options.pvsync = pl_ini_get_int(&file, "Video", "Vsync", 1); + psp_options.pos_vert = pl_ini_get_int(&file, "Video", "PosVert", 22); + UiMetric.Animate = pl_ini_get_int(&file, "Menu", "Animate", 0); + psp_options.border = pl_ini_get_int(&file, "Enhancements", "Border", 0); + psp_options.autofire = pl_ini_get_int(&file, "Input", "Autofire", 2); + if (psp_options.autofire < 2) + psp_options.autofire = 2; + + int control_mode = pl_ini_get_int(&file, "Menu", "Control Mode", 1); + UiMetric.OkButton = (!control_mode) + ? PSP_CTRL_CROSS : PSP_CTRL_CIRCLE; + UiMetric.CancelButton = (!control_mode) + ? PSP_CTRL_CIRCLE : PSP_CTRL_CROSS; + + dmode = psp_options.display_mode; + fskip = psp_options.frame_skip; + cclock = psp_options.clock_freq; + rrewind = psp_options.rewind_save_rate; + vvsync = psp_options.pvsync; + ppos = psp_options.pos_vert; + ccont = control_mode; + bbord = psp_options.border; + + /* Clean up */ + pl_ini_destroy(&file); +} + +static int psp_save_options() +{ + + pl_file_path path; + snprintf(path, sizeof(path) - 1, "%s%s", + pl_psp_get_app_directory(), "options.ini"); + + + /* Initialize INI structure */ + pl_ini_file file; + pl_ini_create(&file); + pl_ini_set_int(&file, "Video", "Display Mode", + psp_options.display_mode); + pl_ini_set_int(&file, "Video", "Frame Skipping", + psp_options.frame_skip); + pl_ini_set_int(&file, "Video", "PSP Clock Frequency", + psp_options.clock_freq); + pl_ini_set_int(&file, "Video", "Update Frequency", + psp_options.update_freq); + pl_ini_set_int(&file, "Video", "Show FPS", + psp_options.show_fps); + pl_ini_set_int(&file, "Menu", "Control Mode", + (UiMetric.OkButton == PSP_CTRL_CIRCLE)); + pl_ini_set_int(&file, "Video", "Vsync", + psp_options.pvsync); + pl_ini_set_int(&file, "Video", "PosVert", + psp_options.pos_vert); + pl_ini_set_int(&file, "Menu", "Animate", + UiMetric.Animate); + pl_ini_set_int(&file, "Enhancements", "Border", + psp_options.border); + pl_ini_set_int(&file, "Input", "Autofire", + psp_options.autofire); + pl_ini_set_int(&file, "Enhancements", "Rewind Save Rate", + psp_options.rewind_save_rate); + pl_ini_set_string(&file, "File", "Game Path", + GamePath); + + int status = pl_ini_save(&file, path); + pl_ini_destroy(&file); + + return status; +} + +static int psp_save_options_game() +{ + sprintf(IniPath, "%sini/", pl_psp_get_app_directory()); + + const char *config_name = pl_file_get_filename(CURRENT_GAME); + pl_file_path path; + snprintf(path, sizeof(path) - 1, "%s%soptions.ini", + IniPath, config_name); + + /* Initialize INI structure */ + pl_ini_file file; + pl_ini_create(&file); + pl_ini_set_int(&file, "Video", "Display Mode", + psp_options.display_mode); + pl_ini_set_int(&file, "Video", "Frame Skipping", + psp_options.frame_skip); + pl_ini_set_int(&file, "Video", "PSP Clock Frequency", + psp_options.clock_freq); + pl_ini_set_int(&file, "Video", "Update Frequency", + psp_options.update_freq); + pl_ini_set_int(&file, "Video", "Show FPS", + psp_options.show_fps); + pl_ini_set_int(&file, "Menu", "Control Mode", + (UiMetric.OkButton == PSP_CTRL_CIRCLE)); + pl_ini_set_int(&file, "Video", "Vsync", + psp_options.pvsync); + pl_ini_set_int(&file, "Video", "PosVert", + psp_options.pos_vert); + pl_ini_set_int(&file, "Menu", "Animate", + UiMetric.Animate); + pl_ini_set_int(&file, "Enhancements", "Border", + psp_options.border); + pl_ini_set_int(&file, "Input", "Autofire", + psp_options.autofire); + pl_ini_set_int(&file, "Enhancements", "Rewind Save Rate", + psp_options.rewind_save_rate); + pl_ini_set_string(&file, "File", "Game Path", + GamePath); + + int status = pl_ini_save(&file, path); + pl_ini_destroy(&file); + + return status; +} diff --git a/psp/emulate.cpp b/psp/emulate.cpp new file mode 100644 index 0000000..477cc86 --- /dev/null +++ b/psp/emulate.cpp @@ -0,0 +1,465 @@ +#include +#include +#include + +#include +#include +#include +#include +#include "emulate.h" + + +#include "pl_psp.h" +#include "pl_snd.h" +#include "image.h" +#include "video.h" +#include "pl_perf.h" +#include "pl_file.h" +#include "ctrl.h" +#include "pl_util.h" +#include "pl_rewind.h" +#include + +#include "StdAfx.h" +#include "state.h" +#include "neopopsound.h" +#include "input.h" +#include "flash.h" +#include "tlcs900h.h" +#include "memory.h" + +psp_ctrl_mask_to_index_map_t physical_to_emulated_button_map[] = +{ + { PSP_CTRL_LTRIGGER | PSP_CTRL_RTRIGGER, 16 }, + { PSP_CTRL_START | PSP_CTRL_SELECT, 17 }, + { PSP_CTRL_SELECT | PSP_CTRL_LTRIGGER, 18 }, + { PSP_CTRL_SELECT | PSP_CTRL_RTRIGGER, 19 }, + { PSP_CTRL_ANALUP, 0 }, { PSP_CTRL_ANALDOWN, 1 }, + { PSP_CTRL_ANALLEFT, 2 }, { PSP_CTRL_ANALRIGHT, 3 }, + { PSP_CTRL_UP, 4 }, { PSP_CTRL_DOWN, 5 }, + { PSP_CTRL_LEFT, 6 }, { PSP_CTRL_RIGHT, 7 }, + { PSP_CTRL_SQUARE, 8 }, { PSP_CTRL_CROSS, 9 }, + { PSP_CTRL_CIRCLE, 10 }, { PSP_CTRL_TRIANGLE, 11 }, + { PSP_CTRL_LTRIGGER, 12 }, { PSP_CTRL_RTRIGGER, 13 }, + { PSP_CTRL_SELECT, 14 }, { PSP_CTRL_START, 15 }, + { 0, -1 } +}; + +PspImage *Screen; +pl_rewind Rewinder; + +extern int m_bIsActive; +extern psp_ctrl_map_t current_map; +extern pl_file_path ScreenshotPath; +extern int changeborder; +extern int gameonram; +extern int primerjuego; +extern int customborder; +int borderc; + +/*NOTA*/ +extern int res2x; +extern PspImage *borderimg; +extern int vertical; +extern int bilinear; +int diferencia; +extern char *bordername; +extern int sinborde; +const char *border_back; +extern int save_name; +static int fondo; +extern int bordernull; +int tmp1; +int tmp2; +/*NOTA*/ + + +static pl_perf_counter FpsCounter; +static int ScreenX, ScreenY, ScreenW, ScreenH; +static int ClearScreen; +static int Rewinding; +static int frames_until_save; +static u32 TicksPerUpdate; +static u64 LastTick; +static u64 CurrentTick; +static u8 RewindEnabled; + +static void AudioCallback(pl_snd_sample* buf, + unsigned int samples, + void *userdata); + +/* Initialize emulation */ +int InitEmulation() +{ + if (!(Screen = pspImageCreateVram(256, 152, PSP_IMAGE_16BPP))) + return 0; + + Screen->Viewport.Width = 160; + Screen->Viewport.Height = 152; + + sound_system_init(); + + /* Initialize rewinder */ + pl_rewind_init(&Rewinder, + state_store_mem, + state_restore_mem, + state_get_size); + + pl_snd_set_callback(0, AudioCallback, NULL); + + return 1; +} + +void graphics_paint() +{ + + pspVideoBegin(); + + + + + + /* Clear the buffer first, if necessary */ + if (ClearScreen >= 0) + { + ClearScreen--; + pspVideoClearScreen(); + } + + /* Blit screen */ + sceGuDisable(GU_BLEND); + pspVideoPutImage(Screen, ScreenX, ScreenY, ScreenW, ScreenH); + + /*vertical=0; + Screen->Viewport.Height = 24; + pspVideoPutImage(Screen, ScreenX, 0, ScreenW, 24); + vertical=48; + Screen->Viewport.Height = 136; + pspVideoPutImage(Screen, ScreenX, 24, ScreenW,224); + vertical=136; + Screen->Viewport.Height = 152; + pspVideoPutImage(Screen, ScreenX, 256, ScreenW,16);*/ + + + SceCtrlData pad; + sceCtrlReadBufferPositive(&pad, 1); + + + if (psp_options.display_mode==SIMPLE_2X){ + if (pad.Buttons & PSP_CTRL_START) + { + tmp1 = vertical; + tmp2 = Screen->Viewport.Height; + vertical=0; + //bilinear = 1; + Screen->Viewport.Height = 152; + pspVideoPutImage(Screen, ScreenX, ScreenY, 320, 272); + bilinear = 0; + vertical = tmp1 ; + Screen->Viewport.Height = tmp2; + }} + + + sceGuEnable(GU_BLEND); + + if (fondo<10) { + + if (psp_options.border==1) pspVideoPutImage1(borderimg, 0, 0, 480, 272); + else pspVideoPutImage1(borderimg, 0, 0, 0, 0); + + fondo++; + } + + //sceDisplayWaitVblankStart(); + + + /* Wait if needed + + if (psp_options.pvsync == 0) { + + if (psp_options.update_freq) + { + do { sceRtcGetCurrentTick(&CurrentTick); } + while (CurrentTick - LastTick < TicksPerUpdate); + LastTick = CurrentTick; + } + } + */ + + if (psp_options.pvsync == 1) + { + sceDisplayWaitVblankStart(); + } + + else { + do { sceRtcGetCurrentTick(&CurrentTick); } + while (CurrentTick - LastTick < TicksPerUpdate); + LastTick = CurrentTick;} + + + + + /* Show FPS counter */ + if (psp_options.show_fps) + { + static char fps_display[64]; + sprintf(fps_display, " %3.02f ", pl_perf_update_counter(&FpsCounter)); + + int width = pspFontGetTextWidth(&PspStockFont, fps_display); + int height = pspFontGetLineHeight(&PspStockFont); + + pspVideoFillRect(SCR_WIDTH - width, 0, SCR_WIDTH, height, PSP_COLOR_BLACK); + pspVideoPrint(&PspStockFont, SCR_WIDTH - width, 0, fps_display, PSP_COLOR_WHITE); + } + + + pspVideoEnd(); + + pspVideoSwapBuffers(); + +} + +/* Run emulation */ +void RunEmulation() +{ + + //pl_psp_set_clock_freq(psp_options.clock_freq); + + + float ratio; + + res2x = 0; + /* Recompute screen size/position */ + switch (psp_options.display_mode) + { + default: + case DISPLAY_MODE_UNSCALED: + + if (borderc==0){ + borderimg = pspImageLoadPng("border.png"); + borderc=1; + } + + fondo=0; + res2x = 0; + bilinear = 0; + ScreenW = Screen->Viewport.Width; + ScreenH = Screen->Viewport.Height; + break; + case DISPLAY_MODE_FIT_HEIGHT: + + if (borderc==0){ + borderimg = pspImageLoadPng("border.png"); + borderc=1; + } + fondo=0; + bilinear = 1; + res2x = 0; + ratio = (float)SCR_HEIGHT / (float)Screen->Viewport.Height; + ScreenW = (int)((float)Screen->Viewport.Width * ratio); + ScreenH = SCR_HEIGHT; + break; + case DISPLAY_MODE_FILL_SCREEN: + + if (borderc==0){ + borderimg = pspImageLoadPng("border.png"); + borderc=1; + } + + fondo=20; + bilinear = 1; + ScreenW = SCR_WIDTH; + ScreenH = SCR_HEIGHT; + break; + case SIMPLE_2X: + res2x = 1; + bilinear = 0; + + if (borderc==0){ + borderimg = pspImageLoadPng("border.png"); + borderc=1; + } + + fondo=0; + vertical = psp_options.pos_vert; + diferencia = (32 - vertical)/2; + Screen->Viewport.Height = 152-(diferencia); + ScreenW = (SCR_WIDTH/3)*2; + ScreenH = SCR_HEIGHT; + break; + case SIMPLE_W: + + if (borderc==0){ + borderimg = pspImageLoadPng("border.png"); + borderc=1; + } + + fondo=20; + res2x = 1; + bilinear = 0; + vertical = psp_options.pos_vert; + diferencia = (32 - vertical)/2; + Screen->Viewport.Height = 152-(diferencia); + ScreenW = SCR_WIDTH; + ScreenH = SCR_HEIGHT; + break; + } + + ScreenX = (SCR_WIDTH / 2) - (ScreenW / 2); + ScreenY = (SCR_HEIGHT / 2) - (ScreenH / 2); + + /* Initialize performance counter */ + pl_perf_init_counter(&FpsCounter); + ClearScreen = 1; + frames_until_save = 0; + Rewinding = 0; + + /* Determine if at least 1 button is mapped to 'rewind' */ + RewindEnabled = 0; + psp_ctrl_mask_to_index_map_t *current_mapping = physical_to_emulated_button_map; + for (; current_mapping->mask; current_mapping++) + { + u32 code = current_map.button_map[current_mapping->index]; + if ((code & SPC) && (CODE_MASK(code) == SPC_REWIND)) + { + RewindEnabled = 1; /* Rewind button is mapped */ + break; + } + } + + /* Recompute update frequency*/ + u32 TicksPerSecond = sceRtcGetTickResolution(); + if (psp_options.update_freq) + { + TicksPerUpdate = TicksPerSecond + / (psp_options.update_freq / (psp_options.frame_skip + 1)); + sceRtcGetCurrentTick(&LastTick); + } + + /* Resume sound */ + pl_snd_resume(0); + + /* Resume emulation */ + m_bIsActive = 1; + ngpc_run(); + + /* Pause sound */ + pl_snd_pause(0); +} + + +void SetVideoMode() +{ + res2x = 0; + Screen->Viewport.Height = 152; + ScreenW = Screen->Viewport.Width; + ScreenH = Screen->Viewport.Height; + + ScreenX = (SCR_WIDTH / 2) - (ScreenW / 2); + ScreenY = (SCR_HEIGHT / 2) - (ScreenH / 2); + ClearScreen = 1; + } + + +void UpdateInputState() +{ + ngpInputState = 0; + + /* Parse input */ + static int autofire_status = 0; + static SceCtrlData pad; + + if (pspCtrlPollControls(&pad)) + { + if (--autofire_status < 0) + autofire_status = psp_options.autofire; + psp_ctrl_mask_to_index_map_t *current_mapping = physical_to_emulated_button_map; + + for (; current_mapping->mask; current_mapping++) + { + u32 code = current_map.button_map[current_mapping->index]; + u8 on = (pad.Buttons & current_mapping->mask) == current_mapping->mask; + + /* Check to see if a button set is pressed. If so, unset it, so it */ + /* doesn't trigger any other combination presses. */ + if (on) pad.Buttons &= ~current_mapping->mask; + + if (!Rewinding) + { + if (code & AFI) + { + if (on && (autofire_status == 0)) + ngpInputState |= CODE_MASK(code); + continue; + } + else if (code & JST) + { + if (on) ngpInputState |= CODE_MASK(code); + continue; + } + } + + if (code & SPC) + { + switch (CODE_MASK(code)) + { + case SPC_MENU: + if (on) m_bIsActive = 0; + break; + case SPC_REWIND: + Rewinding = on; + break; + } + } + } + } +} + +void HandleStateSaving() +{ + if (!RewindEnabled) + return; + + /* Rewind/save state */ + if (!Rewinding) + { + if (--frames_until_save <= 0) + { + frames_until_save = psp_options.rewind_save_rate; + pl_rewind_save(&Rewinder); + } + } + else + { + frames_until_save = psp_options.rewind_save_rate; + pl_rewind_restore(&Rewinder); + } +} + +static void AudioCallback(pl_snd_sample* buf, + unsigned int samples, + void *userdata) +{ + int length_bytes = samples << 1; /* 2 bytes per sample */ + + if (!Rewinding) + { + sound_update((_u16*)buf, length_bytes); //Get sound data + dac_update((_u16*)buf, length_bytes); + } + else /* Render silence */ + { + memset(buf, 0, length_bytes); + } +} + +/* Release emulation resources */ +void TrashEmulation() +{ + pl_rewind_destroy(&Rewinder); + + flashShutdown(); + + pspImageDestroy(Screen); +} + diff --git a/psp/emulate.h b/psp/emulate.h new file mode 100644 index 0000000..563eed7 --- /dev/null +++ b/psp/emulate.h @@ -0,0 +1,55 @@ +#ifndef PSP_EMULATE_H +#define PSP_EMULATE_H + +int InitEmulation(); +void RunEmulation(); +void TrashEmulation(); +void SetVideoMode(); + +#define DISPLAY_MODE_UNSCALED 0 +#define DISPLAY_MODE_FIT_HEIGHT 1 +#define DISPLAY_MODE_FILL_SCREEN 2 +#define SIMPLE_2X 3 +#define SIMPLE_W 4 + +#define MAP_BUTTONS 20 + +#define JST 0x100 +#define AFI 0x200 +#define SPC 0x400 + +#define SPC_MENU 1 +#define SPC_REWIND 2 + +#define CODE_MASK(x) (x & 0xff) + +typedef struct psp_ctrl_map_t +{ + uint32_t button_map[MAP_BUTTONS]; +} psp_ctrl_map_t; + +typedef struct psp_ctrl_mask_to_index_map_t +{ + uint64_t mask; + uint8_t index; +} psp_ctrl_mask_to_index_map_t; + +typedef struct psp_options_t +{ + uint8_t display_mode; + uint8_t show_fps; + uint8_t frame_skip; + uint16_t clock_freq; + uint8_t autofire; + uint8_t pos_vert; + uint8_t pvsync; + int OF; + uint8_t border; + uint8_t language; + int rewind_save_rate; + uint8_t update_freq; +} psp_options_t; + +extern psp_options_t psp_options; + +#endif diff --git a/psp/homehookprx/Makefile b/psp/homehookprx/Makefile new file mode 100644 index 0000000..fa8924d --- /dev/null +++ b/psp/homehookprx/Makefile @@ -0,0 +1,27 @@ +TARGET = homehook +OBJS = main.o sceCtrl_driver.o + +INCDIR = +CFLAGS = -O2 -G0 -Wall +CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti +ASFLAGS = $(CFLAGS) + +BUILD_PRX = 1 +PRX_EXPORTS = $(TARGET).exp + +USE_KERNEL_LIBC=1 +USE_KERNEL_LIBS=1 + +LIBDIR = +LDFLAGS = -mno-crt0 -nostartfiles +LIBS = -lpspsdk + +PSPSDK=$(shell psp-config --pspsdk-path) +include $(PSPSDK)/lib/build.mak + +all: + psp-build-exports -s $(PRX_EXPORTS) + @cp $(TARGET).prx ../../ + @cp $(TARGET).S ../ + @rm -f $(TARGET).prx + @rm -f $(TARGET).S diff --git a/psp/homehookprx/homehook.exp b/psp/homehookprx/homehook.exp new file mode 100644 index 0000000..a2a52ea --- /dev/null +++ b/psp/homehookprx/homehook.exp @@ -0,0 +1,16 @@ +# Define the exports for the prx +PSP_BEGIN_EXPORTS + +# These four lines are mandatory (although you can add other functions like module_stop) +# syslib is a psynonym for the single mandatory export. +PSP_EXPORT_START(syslib, 0, 0x8000) +PSP_EXPORT_FUNC_HASH(module_start) +PSP_EXPORT_VAR_HASH(module_info) +PSP_EXPORT_END + +PSP_EXPORT_START(homehook, 0, 0x4001) +PSP_EXPORT_FUNC(initHomeButton) +PSP_EXPORT_FUNC(readHomeButton) +PSP_EXPORT_END + +PSP_END_EXPORTS diff --git a/psp/homehookprx/homehook.h b/psp/homehookprx/homehook.h new file mode 100644 index 0000000..2d15509 --- /dev/null +++ b/psp/homehookprx/homehook.h @@ -0,0 +1,21 @@ +/****************************************************************************** + + homehook.prx + +******************************************************************************/ + +#ifndef HOMEHOOK_PRX_H +#define HOMEHOOK_PRX_H + +#ifdef __cplusplus +extern "C" { +#endif + +void initHomeButton(int devkit_version); +u32 readHomeButton(void); + +#ifdef __cplusplus +} +#endif + +#endif /* HOMEHOOK_PRX_H */ diff --git a/psp/homehookprx/main.c b/psp/homehookprx/main.c new file mode 100644 index 0000000..b9e8f76 --- /dev/null +++ b/psp/homehookprx/main.c @@ -0,0 +1,106 @@ +/****************************************************************************** + + homehook371.prx + +******************************************************************************/ + +#include +#include + + +PSP_MODULE_INFO("homehook", PSP_MODULE_KERNEL, 0, 0); +PSP_MAIN_THREAD_ATTR(0); + + +/****************************************************************************** + prototypes +******************************************************************************/ + +int sceCtrl_driver_3A622550(SceCtrlData *pad_data, int count); +int sceCtrl_driver_C4AAD55F(SceCtrlData *pad_data, int count); + +#define sceCtrlPeekBufferPositive sceCtrl_driver_3A622550 +#define sceCtrlPeekBufferPositive371 sceCtrl_driver_C4AAD55F + + +/****************************************************************************** + local variables +******************************************************************************/ + +static volatile int home_active; +static u32 home_button; +static SceUID home_thread; + +static int (*__sceCtrlPeekBufferPositive)(SceCtrlData *pad_data, int count); + + +/****************************************************************************** + functions +******************************************************************************/ + +static int home_button_thread(SceSize args, void *argp) +{ + SceCtrlData paddata; + + home_active = 1; + + while (home_active) + { + if (__sceCtrlPeekBufferPositive) + { + (*__sceCtrlPeekBufferPositive)(&paddata, 1); + home_button = paddata.Buttons & PSP_CTRL_HOME; + } + sceKernelDelayThread(10 * 1000); + } + + sceKernelExitDeleteThread(0); + + return 0; +} + + +void initHomeButton(int devkit_version) +{ + if (devkit_version < 0x03060010) + __sceCtrlPeekBufferPositive = sceCtrlPeekBufferPositive; + else + __sceCtrlPeekBufferPositive = sceCtrlPeekBufferPositive371; +} + + +u32 readHomeButton(void) +{ + return home_button; +} + + +int module_start(SceSize args, void *argp) +{ + __sceCtrlPeekBufferPositive = NULL; + + home_button = 0; + home_active = 0; + home_thread = sceKernelCreateThread("Home Button Thread", + home_button_thread, + 0x11, + 0x200, + 0, + NULL); + + if (home_thread >= 0) + sceKernelStartThread(home_thread, 0, 0); + + return 0; +} + + +int module_stop(void) +{ + if (home_thread >= 0) + { + home_active = 0; + sceKernelDelayThread(20 * 1000); + } + return 0; +} diff --git a/psp/homehookprx/sceCtrl_driver.S b/psp/homehookprx/sceCtrl_driver.S new file mode 100644 index 0000000..d701a60 --- /dev/null +++ b/psp/homehookprx/sceCtrl_driver.S @@ -0,0 +1,7 @@ + .set noreorder + +#include "pspimport.s" + +IMPORT_START "sceCtrl_driver",0x00010000 +IMPORT_FUNC "sceCtrl_driver",0x3A622550,sceCtrl_driver_3A622550 +IMPORT_FUNC "sceCtrl_driver",0xC4AAD55F,sceCtrl_driver_C4AAD55F diff --git a/psp/main.cpp b/psp/main.cpp new file mode 100644 index 0000000..ef49d27 --- /dev/null +++ b/psp/main.cpp @@ -0,0 +1,51 @@ +#include +#include +#include + +#include + +#include "pl_snd.h" +#include "video.h" +#include "pl_psp.h" +#include "ctrl.h" + +#include "./menu.h" + +PSP_MODULE_INFO(PSP_APP_NAME, 0, 1, 1); +PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER | THREAD_ATTR_VFPU); + +extern int m_bIsActive; + +static void ExitCallback(void* arg) +{ + m_bIsActive = 0; + ExitPSP = 1; +} + +int main(int argc, char **argv) +{ + /* Initialize PSP */ + pl_psp_init(argv[0]); + pl_snd_init(512, 0); + pspCtrlInit(); + pspVideoInit(); + + /* Initialize callbacks */ + pl_psp_register_callback(PSP_EXIT_CALLBACK, + ExitCallback, + NULL); + pl_psp_start_callback_thread(); + + if (InitMenu()) + { + DisplayMenu(); + TrashMenu(); + } + + /* Release PSP resources */ + pl_snd_shutdown(); + pspVideoShutdown(); + pl_psp_shutdown(); + + return(0); +} diff --git a/psp/menu.cpp b/psp/menu.cpp new file mode 100644 index 0000000..b13cf34 --- /dev/null +++ b/psp/menu.cpp @@ -0,0 +1,1527 @@ +#include +#include +#include + +#include +#include +#include + +#include "StdAfx.h" +#include "main.h" +#include "input.h" +#include "neopopsound.h" +#include "flash.h" +#include "memory.h" +#include "menu.h" +#include "emulate.h" + +#include "pl_psp.h" +#include "pl_snd.h" +#include "image.h" +#include "video.h" +#include "pl_perf.h" +#include "ctrl.h" +#include "pl_util.h" +#include "pl_file.h" +#include "pl_ini.h" +#include "pl_rewind.h" +#include "ui.h" +#include "state.h" +#include "tlcs900h.h" +#undef u32 + +extern PspImage *Screen; +extern pl_rewind Rewinder; +PspImage *borderimg; +pl_file_path CurrentGame = "", + GamePath, + SaveStatePath, + ScreenshotPath, + IniPath, + BorderPath; +static PspImage *Background; +static PspImage *NoSaveIcon; +static int TabIndex; +static int ResumeEmulation; +static int dmode; +static int fskip; +static int cclock; +static int rrewind; +static int vvsync; +static int ppos; +static int ccont; +static int bbord; +char *bordername; +int save_name; +int sinborde; +int changeborder; +int gameonram; +int idioma; +int primerjuego; + +int nuevarom; +int customborder; +int bordernull; +static int juegon; +extern int tipo_consola; +extern int fixsoundmahjong; +int gfx_hacks; + +psp_ctrl_map_t current_map; +psp_options_t psp_options; + +/* Default configuration */ +static psp_ctrl_map_t default_map = +{ + { + JST|0x01, /* Analog Up */ + JST|0x02, /* Analog Down */ + JST|0x04, /* Analog Left */ + JST|0x08, /* Analog Right */ + JST|0x01, /* D-pad Up */ + JST|0x02, /* D-pad Down */ + JST|0x04, /* D-pad Left */ + JST|0x08, /* D-pad Right */ + 0, /* Square */ + JST|0x10, /* Cross */ + JST|0x20, /* Circle */ + 0, /* Triangle */ + 0, /* L Trigger */ + 0, /* R Trigger */ + JST|0x40, /* Select */ + 0, /* Start */ + SPC|SPC_MENU, /* L+R Triggers */ + 0, /* Start+Select */ + 0, /* Select + L */ + 0, /* Select + R */ + } +}; + +/* Tab labels */ +static const char *TabLabel[] = +{ + "Game", + "Save/Load", + "Controls", + "Options", + "System", + "About" +}; + +static const char + PresentSlotText[] = "\026\244\020 Save\t\026\001\020 Load\t\026\243\020 Delete", + EmptySlotText[] = "\026\244\020 Save", + ControlHelpText[] = "\026\250\020 Change mapping\t\026\001\020 Save to \271"; + +#define TAB_QUICKLOAD 0 +#define TAB_STATE 1 +#define TAB_CONTROLS 2 +#define TAB_OPTIONS 3 +#define TAB_SYSTEM 4 +#define TAB_ABOUT 5 +#define TAB_MAX TAB_ABOUT + +#define OPTION_DISPLAY_MODE 0x01 +#define OPTION_FRAME_SKIP 0x02 +#define OPTION_CLOCK_FREQ 0x03 +#define OPTION_SHOW_FPS 0x04 +#define PERFECT_SYNC 0x05 +#define OPTION_CONTROL_MODE 0x06 +#define OPTION_ANIMATE 0x07 +#define OPTION_AUTOFIRE 0x08 +#define OPTION_POSVX 0x09 +#define SYSTEM_RESET 0x10 +#define SYSTEM_SCRNSHOT 0x11 +#define SYSTEM_EXIT 0x12 +#define OPTION_BORDER 0x13 +#define OPTION_LANG 0x14 + +#define SET_AS_CURRENT_GAME(filename) \ + strncpy(CurrentGame, filename, sizeof(CurrentGame) - 1) +#define CURRENT_GAME (CurrentGame) +#define GAME_LOADED (CurrentGame[0] != '\0') + +static void psp_init_controls(); +static int psp_load_controls(); +static int psp_save_controls(); +static void LoadOptions(); +static int SaveOptions(); +static int CreateOptions(); +static void LoadOptions_game(); +static void loadborder(); + + + + + +static void psp_discard_alpha(PspImage *image); + +static void psp_display_control_tab(); +static void psp_display_state_tab(); + +static PspImage* psp_load_state_icon(const char *path); +static int psp_load_state(const char *path); +static PspImage* psp_save_state(const char *path, PspImage *icon); + +static const char *QuickloadFilter[] = { "ZIP", '\0' }; + +static int OnGenericCancel(const void *uiobject, + const void *param); +static void OnGenericRender(const void *uiobject, + const void *item_obj); +static int OnGenericButtonPress(const PspUiFileBrowser *browser, + const char *path, + u32 button_mask); + +static int OnSplashButtonPress(const struct PspUiSplash *splash, + u32 button_mask); +static void OnSplashRender(const void *uiobject, + const void *null); +static const char* OnSplashGetStatusBarText(const struct PspUiSplash *splash); + +static int OnMenuOk(const void *menu, + const void *item); +static int OnMenuButtonPress(const struct PspUiMenu *uimenu, + pl_menu_item* item, + u32 button_mask); +static int OnMenuItemChanged(const struct PspUiMenu *uimenu, + pl_menu_item* item, + const pl_menu_option* option); + +static int OnSaveStateOk(const void *gallery, const void *item); +static int OnSaveStateButtonPress(const PspUiGallery *gallery, + pl_menu_item *sel, + u32 button_mask); + +static int OnQuickloadOk(const void *browser, const void *path); + +static void OnSystemRender(const void *uiobject, + const void *item_obj); + +PspUiFileBrowser QuickloadBrowser = +{ + OnGenericRender, + OnQuickloadOk, + OnGenericCancel, + OnGenericButtonPress, + QuickloadFilter, + 0 +}; + +PspUiMenu + OptionUiMenu = + { + OnGenericRender, /* OnRender() */ + OnMenuOk, /* OnOk() */ + OnGenericCancel, /* OnCancel() */ + OnMenuButtonPress, /* OnButtonPress() */ + OnMenuItemChanged, /* OnItemChanged() */ + }, + SystemUiMenu = + { + OnSystemRender, /* OnRender() */ + OnMenuOk, /* OnOk() */ + OnGenericCancel, /* OnCancel() */ + OnMenuButtonPress, /* OnButtonPress() */ + OnMenuItemChanged, /* OnItemChanged() */ + }, + ControlUiMenu = + { + OnGenericRender, /* OnRender() */ + OnMenuOk, /* OnOk() */ + OnGenericCancel, /* OnCancel() */ + OnMenuButtonPress, /* OnButtonPress() */ + OnMenuItemChanged, /* OnItemChanged() */ + }; + +PspUiGallery SaveStateGallery = +{ + OnGenericRender, /* OnRender() */ + OnSaveStateOk, /* OnOk() */ + OnGenericCancel, /* OnCancel() */ + OnSaveStateButtonPress, /* OnButtonPress() */ + NULL /* Userdata */ +}; + +/* Menu options */ +PL_MENU_OPTIONS_BEGIN(MappableButtons) + /* Unmapped */ + PL_MENU_OPTION("None", 0) + /* Special */ + PL_MENU_OPTION("Special: Open Menu", (SPC|SPC_MENU)) + PL_MENU_OPTION("Special: Rewind", (SPC|SPC_REWIND)) + /* Directions */ + PL_MENU_OPTION("Up", (JST|0x01)) + PL_MENU_OPTION("Down", (JST|0x02)) + PL_MENU_OPTION("Left", (JST|0x04)) + PL_MENU_OPTION("Right", (JST|0x08)) + /* Buttons */ + PL_MENU_OPTION("A", (JST|0x10)) + PL_MENU_OPTION("B", (JST|0x20)) + PL_MENU_OPTION("A (autofire)", (AFI|0x10)) + PL_MENU_OPTION("B (autofire)", (AFI|0x20)) + PL_MENU_OPTION("Option", (JST|0x40)) + PL_MENU_OPTION("Test switch", (JST|0x80)) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(ToggleOptions) + PL_MENU_OPTION("Disabled", 0) + PL_MENU_OPTION("Enabled", 1) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(AutofireOptions) + PL_MENU_OPTION("Once every 3 frames", 2) + PL_MENU_OPTION("Once every 10 frames", 9) + PL_MENU_OPTION("Once every 30 frames", 29) + PL_MENU_OPTION("Once every 60 frames", 59) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(ScreenSizeOptions) + PL_MENU_OPTION("Actual size", DISPLAY_MODE_UNSCALED) + PL_MENU_OPTION("4:3 scaled (fit height)", DISPLAY_MODE_FIT_HEIGHT) + PL_MENU_OPTION("16:9 scaled (fit screen)", DISPLAY_MODE_FILL_SCREEN) + PL_MENU_OPTION("Simple 2x - SW", SIMPLE_2X) + PL_MENU_OPTION("Simple 2x Wide - SW", SIMPLE_W) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(FrameskipOptions) + PL_MENU_OPTION("Auto", 2) + PL_MENU_OPTION("30 Hz", 1) + PL_MENU_OPTION("60 Hz", 0) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(VsyncOptions) + PL_MENU_OPTION("Normal", 0) + PL_MENU_OPTION("Precise", 1) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(BorderOptions) + PL_MENU_OPTION("No border", 0) + PL_MENU_OPTION("PNG Border", 1) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(ScreenPosOptions) + PL_MENU_OPTION("2", 2) + PL_MENU_OPTION("8", 8) + PL_MENU_OPTION("16", 16) + PL_MENU_OPTION("18", 18) + PL_MENU_OPTION("Auto", 0) + PL_MENU_OPTION("22", 22) + PL_MENU_OPTION("24", 24) + PL_MENU_OPTION("32", 32) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(PspClockFreqOptions) + PL_MENU_OPTION("222 MHz", 222) + PL_MENU_OPTION("266 MHz", 266) + PL_MENU_OPTION("300 MHz", 300) + PL_MENU_OPTION("333 MHz", 333) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(ControlModeOptions) + PL_MENU_OPTION("\026\242\020 cancels, \026\241\020 confirms (US)", 0) + PL_MENU_OPTION("\026\241\020 cancels, \026\242\020 confirms (Japan)", 1) +PL_MENU_OPTIONS_END +PL_MENU_OPTIONS_BEGIN(LangOptions) + PL_MENU_OPTION("English", 0) + PL_MENU_OPTION("Japanese", 1) +PL_MENU_OPTIONS_END + + +/* Menu items */ +PL_MENU_ITEMS_BEGIN(ControlMenuDef) + PL_MENU_ITEM(PSP_CHAR_ANALUP,0,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_ANALDOWN,1,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_ANALLEFT,2,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_ANALRIGHT,3,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_UP,4,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_DOWN,5,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_LEFT,6,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_RIGHT,7,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_SQUARE,8,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_CROSS,9,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_CIRCLE,10,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_TRIANGLE,11,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_LTRIGGER,12,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_RTRIGGER,13,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_SELECT,14,MappableButtons,ControlHelpText) + //PL_MENU_ITEM(PSP_CHAR_START,15,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_LTRIGGER"+"PSP_CHAR_RTRIGGER,16,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_START"+"PSP_CHAR_SELECT,17,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_SELECT"+"PSP_CHAR_LTRIGGER,18,MappableButtons,ControlHelpText) + PL_MENU_ITEM(PSP_CHAR_SELECT"+"PSP_CHAR_RTRIGGER,19,MappableButtons,ControlHelpText) +PL_MENU_ITEMS_END +PL_MENU_ITEMS_BEGIN(OptionMenuDef) + PL_MENU_HEADER("Video") + PL_MENU_ITEM("Screen size",OPTION_DISPLAY_MODE,ScreenSizeOptions,"\026\250\020 Change screen size") + PL_MENU_ITEM("Screen position",OPTION_POSVX,ScreenPosOptions,"\026\244\020 Change screen position") + PL_MENU_ITEM("VSYNC",PERFECT_SYNC,VsyncOptions,"\026\250\020 Enable/disable vsync options") + PL_MENU_HEADER("Input") + PL_MENU_ITEM("Rate of autofire", OPTION_AUTOFIRE,AutofireOptions,"\026\250\020 Adjust rate of autofire") + PL_MENU_HEADER("Performance") + PL_MENU_ITEM("Screen Refresh", OPTION_FRAME_SKIP,FrameskipOptions,"\026\250\020 Select number of frames to skip per update") + PL_MENU_ITEM("PSP clock frequency",OPTION_CLOCK_FREQ,PspClockFreqOptions,"\026\250\020 Larger values: faster emulation, faster battery depletion (default: 222MHz)") + PL_MENU_ITEM("Show FPS counter",OPTION_SHOW_FPS,ToggleOptions,"\026\250\020 Show/hide the frames-per-second counter") + PL_MENU_HEADER("Menu") + PL_MENU_ITEM("Button mode",OPTION_CONTROL_MODE,ControlModeOptions,"\026\250\020 Change OK and Cancel button mapping") + PL_MENU_ITEM("Border",OPTION_BORDER,BorderOptions,"\026\250\020 Enable/disable PNG borders") + PL_MENU_ITEM("Language",OPTION_LANG,LangOptions,"Language") + // PL_MENU_ITEM("Animations",OPTION_ANIMATE,ToggleOptions,"\026\250\020 Enable/disable menu animations") +PL_MENU_ITEMS_END +PL_MENU_ITEMS_BEGIN(SystemMenuDef) + PL_MENU_HEADER("Options") + PL_MENU_ITEM("Reset",SYSTEM_RESET,NULL,"\026\001\020 Reset system") + PL_MENU_ITEM("Save screenshot",SYSTEM_SCRNSHOT,NULL,"\026\001\020 Save screenshot") + PL_MENU_ITEM("Exit Emulator",SYSTEM_EXIT,NULL,"\026\001\020 Exit Emulator") +PL_MENU_ITEMS_END + +PspUiSplash SplashScreen = +{ + OnSplashRender, + OnGenericCancel, + OnSplashButtonPress, + OnSplashGetStatusBarText +}; + +int InitMenu() +{ + if (!InitEmulation()) + return 0; + + /* Initialize paths */ + sprintf(SaveStatePath, "%sstates/", pl_psp_get_app_directory()); + sprintf(ScreenshotPath, "%sscreens/", pl_psp_get_app_directory()); + sprintf(GamePath, "%s", pl_psp_get_app_directory()); + + juegon=0; + primerjuego=1; + LoadOptions(); + + /* Load the background image */ + Background = pspImageLoadPng("background.png"); + + /* Initialize menus */ + pl_menu_create(&SystemUiMenu.Menu, SystemMenuDef); + pl_menu_create(&OptionUiMenu.Menu, OptionMenuDef); + pl_menu_create(&ControlUiMenu.Menu, ControlMenuDef); + + /* Init NoSaveState icon image */ + NoSaveIcon = pspImageCreate(160, 152, PSP_IMAGE_16BPP); + pspImageClear(NoSaveIcon, RGB(0x44,0x00,0x00)); + + /* Initialize state menu */ + int i; + pl_menu_item *item; + for (i = 0; i < 10; i++) + { + item = pl_menu_append_item(&SaveStateGallery.Menu, i, NULL); + pl_menu_set_item_help_text(item, EmptySlotText); + } + + + /* Initialize options */ + psp_load_controls(); + + + /* Initialize UI components */ + UiMetric.Background = Background; + UiMetric.Font = &PspStockFont; + UiMetric.Left = 8; + UiMetric.Top = 24; + UiMetric.Right = 475; + UiMetric.Bottom = 250; + UiMetric.ScrollbarColor = PSP_COLOR_GRAY; + UiMetric.ScrollbarBgColor = 0x44ffffff; + UiMetric.ScrollbarWidth = 10; + UiMetric.TextColor = PSP_COLOR_GRAY; + UiMetric.SelectedColor = COLOR(0xf7,0xc2,0x50,0xFF); + UiMetric.SelectedBgColor = COLOR(0xd5,0xf1,0x17,0x99); + UiMetric.StatusBarColor = PSP_COLOR_WHITE; + UiMetric.BrowserFileColor = PSP_COLOR_GRAY; + UiMetric.BrowserDirectoryColor = PSP_COLOR_YELLOW; + UiMetric.GalleryIconsPerRow = 5; + UiMetric.GalleryIconMarginWidth = 16; + UiMetric.MenuItemMargin = 5; + UiMetric.MenuSelOptionBg = PSP_COLOR_GRAY; + UiMetric.MenuOptionBoxColor = PSP_COLOR_GRAY; + UiMetric.MenuOptionBoxBg = COLOR(0x44,0x00,0x00,0xbb); + UiMetric.MenuDecorColor = UiMetric.SelectedColor; + UiMetric.DialogFogColor = COLOR(0xd5,0xf1,0x17,0xbb); + UiMetric.TitlePadding = 4; + UiMetric.TitleColor = PSP_COLOR_WHITE; + UiMetric.MenuFps = 30; + UiMetric.TabBgColor = COLOR(0xcc,0x73,0x73,0xff); + UiMetric.BrowserScreenshotPath = ScreenshotPath; + UiMetric.BrowserScreenshotDelay = 2; + + TabIndex = TAB_QUICKLOAD; + + return 1; +} + +void DisplayMenu() +{ + pl_menu_item *item; + + /* Menu loop */ + do + { + ResumeEmulation = 0; + /*NOTA RESUMEN*/ + SetVideoMode(); + + /* Set normal clock frequency */ + pl_psp_set_clock_freq(222); + /* Set buttons to autorepeat */ + pspCtrlSetPollingMode(PSP_CTRL_AUTOREPEAT); + + do + { + /* Display appropriate tab */ + switch (TabIndex) + { + case TAB_QUICKLOAD: + pspUiOpenBrowser(&QuickloadBrowser, + (GAME_LOADED) ? CURRENT_GAME : GamePath); + break; + case TAB_CONTROLS: + psp_display_control_tab(); + break; + case TAB_OPTIONS: + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_DISPLAY_MODE); + pl_menu_select_option_by_value(item, (void*)(int)psp_options.display_mode); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, PERFECT_SYNC); + pl_menu_select_option_by_value(item, (void*)(int)psp_options.pvsync); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_CLOCK_FREQ); + pl_menu_select_option_by_value(item, (void*)(int)psp_options.clock_freq); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_SHOW_FPS); + pl_menu_select_option_by_value(item, (void*)(int)psp_options.show_fps); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_CONTROL_MODE); + pl_menu_select_option_by_value(item, (void*)(UiMetric.OkButton == PSP_CTRL_CIRCLE)); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_POSVX); + pl_menu_select_option_by_value(item, (void*)(int)psp_options.pos_vert); + // item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_ANIMATE); + // pl_menu_select_option_by_value(item, (void*)(int)psp_options.language); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_FRAME_SKIP); + pl_menu_select_option_by_value(item, (void*)(int)psp_options.frame_skip); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_AUTOFIRE); + pl_menu_select_option_by_value(item, (void*)(int)psp_options.autofire); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_BORDER); + pl_menu_select_option_by_value(item, (void*)(int)psp_options.border); + item = pl_menu_find_item_by_id(&OptionUiMenu.Menu, OPTION_LANG); + pl_menu_select_option_by_value(item, (void*)(int)psp_options.language); + + + pspUiOpenMenu(&OptionUiMenu, NULL); + + if (pspUiConfirm("Save config?")) + { + if (juegon==1){ + psp_options.OF = 1; + CreateOptions();} + + if (juegon==0){ + SaveOptions();}} + + break; + case TAB_STATE: + psp_display_state_tab(); + break; + case TAB_SYSTEM: + pspUiOpenMenu(&SystemUiMenu, NULL); + break; + case TAB_ABOUT: + pspUiSplashScreen(&SplashScreen); + break; + } + } while (!ExitPSP && !ResumeEmulation); + + if (!ExitPSP) + { + /* Set clock frequency during emulation */ + pl_psp_set_clock_freq(psp_options.clock_freq); + /* Set buttons to normal mode */ + pspCtrlSetPollingMode(PSP_CTRL_NORMAL); + + if (ResumeEmulation) + { + + //NOTA + + /* + 0x05 Cotton - Fantastic Night Dreams - 60fps + 0x83 Bikkuriman 2000 - 60fps + 0x85 Densetsu no Ogre Battle - 60fps + 0x62 Mizuki Shigeru Youkai Shashin Kan - 60fps + 0x96 Nige-ron-pa - 60fps + 0x81 Oekaki - 60fps + 0x55 Pac-Man - 60fps + 0x32 Party Mail - 60fps + 0x06 Picture Puzzle - 60fps + 0x41 Puyo Pop - 60fps + 0x78 Soreike! Hanafuda Doujyou - 60fps + 0x94 Rockman Battle & Fighters - 60fps + 0x65 Gals Fighter - 60fps + 0x93 Gals Fighter EU - 60fps + 0x11 Fatal Fury - 60fps + + 0x94 Rockman Battle & Fighters - 24v + 0x20 Puzzle Bobble Mini - 16v + 0x11 Super Real Mahjong - 16v + 0x31 Bust-A-Move Pocket EU - 16v + 0x90 Faselei! - 18v + 0x01 King of Fighters R-1 - 24v + 0x23 King of Fighters R-2 - 24v + 0x21 Metal Slug - 1st Mission - 16v + 0x63 Mezase! Kanji Ou - 8v + 0x30 Samurai Shodown 2 - 16v + 0x08 Samurai Shodown - 16v + 0x41 Puyo Pop - 16v + 0x69 SVC - The Match of The Millennium MONO - 0v + */ + + // 0x11 Super Real Mahjong sound fix + fixsoundmahjong=0; + + gfx_hacks=0; + + + if (psp_options.pos_vert==0) { + + if (mainrom[0x000020] == 0x94 || mainrom[0x000020] == 0x01 || mainrom[0x000020] == 0x23) + psp_options.pos_vert=24; + + if (mainrom[0x000020] == 0x05) + psp_options.pos_vert=30; + + if (mainrom[0x000020] == 0x90) + psp_options.pos_vert=18; + + if (mainrom[0x000020] == 0x63) + psp_options.pos_vert=8; + + if (mainrom[0x000020] == 0x31 || mainrom[0x000020] == 0x08 || mainrom[0x000020] == 0x21 || mainrom[0x000020] == 0x30 || mainrom[0x000020] == 0x20 || mainrom[0x000020] == 0x41) + psp_options.pos_vert=16; + + if (mainrom[0x000020] == 0x11 && mainrom[0x000021] == 0x01) + psp_options.pos_vert=16; + + if (tipo_consola==1 && mainrom[0x000020] == 0x69) + psp_options.pos_vert=0; + + else + psp_options.pos_vert=22; + + } + + + + + + if (psp_options.frame_skip==2) { + + if ((mainrom[0x000020] == 0x11 && mainrom[0x000021] == 0x00 ) || mainrom[0x000020] == 0x93 || mainrom[0x000020] == 0x65 || mainrom[0x000020] == 0x05 || mainrom[0x000020] == 0x83 || mainrom[0x000020] == 0x85 || mainrom[0x000020] == 0x62 || mainrom[0x000020] == 0x96 || mainrom[0x000020] == 0x81 || mainrom[0x000020] == 0x55 || mainrom[0x000020] == 0x32 || mainrom[0x000020] == 0x06 || mainrom[0x000020] == 0x41 || mainrom[0x000020] == 0x78 || mainrom[0x000020] == 0x94 ) + psp_options.frame_skip=0; + + else + psp_options.frame_skip=1; } + + + //NOTA HAcks + // 0x07 Oelsol + + if (mainrom[0x000020] == 0x07 || mainrom[0x000020] == 0x30 || mainrom[0x000020] == 0x08 || mainrom[0x000020] == 0x10 || mainrom[0x000020] == 0x12 || (mainrom[0x000020] == 0x11 && mainrom[0x000021] == 0x01)) + gfx_hacks=1; + + + // loadborder(); + RunEmulation(); + } + } + } while (!ExitPSP); +} + +void TrashMenu() +{ + TrashEmulation(); + + pl_menu_destroy(&SystemUiMenu.Menu); + pl_menu_destroy(&OptionUiMenu.Menu); + pl_menu_destroy(&ControlUiMenu.Menu); + pl_menu_destroy(&SaveStateGallery.Menu); + + pspImageDestroy(NoSaveIcon); + pspImageDestroy(Background); +} + +/* Handles drawing of generic items */ +static void OnGenericRender(const void *uiobject, + const void *item_obj) +{ + /* Draw tabs */ + int i, x, width, height = pspFontGetLineHeight(UiMetric.Font); + for (i = 0, x = 5; i <= TAB_MAX; i++, x += width + 10) + { + width = -10; + + if (!GAME_LOADED && (i == TAB_STATE || i == TAB_SYSTEM)) + continue; + if (GAME_LOADED && (i == TAB_ABOUT)) + continue; + + /* Determine width of text */ + width = pspFontGetTextWidth(UiMetric.Font, TabLabel[i]); + + /* Draw background of active tab */ + if (i == TabIndex) + pspVideoFillRect(x - 5, 0, x + width + 5, height + 1, UiMetric.TabBgColor); + + /* Draw name of tab */ + pspVideoPrint(UiMetric.Font, x, 0, TabLabel[i], PSP_COLOR_WHITE); + } +} + +static int OnGenericButtonPress(const PspUiFileBrowser *browser, + const char *path, + u32 button_mask) +{ + int tab_index; + + /* If L or R are pressed, switch tabs */ + if (button_mask & PSP_CTRL_LTRIGGER) + { + TabIndex--; + do + { + tab_index = TabIndex; + if (!GAME_LOADED && (TabIndex == TAB_STATE || TabIndex == TAB_SYSTEM)) TabIndex--; + if (GAME_LOADED && (TabIndex == TAB_ABOUT)) TabIndex--; + if (TabIndex < 0) TabIndex = TAB_MAX; + } while (tab_index != TabIndex); + } + else if (button_mask & PSP_CTRL_RTRIGGER) + { + TabIndex++; + do + { + tab_index = TabIndex; + if (!GAME_LOADED && (TabIndex == TAB_STATE || TabIndex == TAB_SYSTEM)) TabIndex++; + if (GAME_LOADED && (TabIndex == TAB_ABOUT)) TabIndex++; + if (TabIndex > TAB_MAX) TabIndex = 0; + } while (tab_index != TabIndex); + } + else if ((button_mask & (PSP_CTRL_START | PSP_CTRL_SELECT)) + == (PSP_CTRL_START | PSP_CTRL_SELECT)) + { + if (pl_util_save_vram_seq(ScreenshotPath, "ui")) + pspUiAlert("Saved successfully"); + else + pspUiAlert("ERROR: Not saved"); + return 0; + } + else return 0; + + return 1; +} + +static int OnGenericCancel(const void *uiobject, + const void* param) +{ + if (GAME_LOADED) ResumeEmulation = 1; + return 1; +} + +static int OnQuickloadOk(const void *browser, + const void *path) +{ + + + /* Write flash data for current game */ + if (GAME_LOADED) + writeSaveGameFile(); + + pspUiFlashMessage("Loading, please wait..."); + + if (!handleInputFile((char*)path)) + { + pspUiAlert("Error loading cartridge"); + return 0; + } + + /* Reset selected state */ + SaveStateGallery.Menu.selected = NULL; + + SET_AS_CURRENT_GAME((char*)path); + pl_file_get_parent_directory((const char*)path, + GamePath, + sizeof(GamePath)); + + LoadOptions(); + SaveOptions(); + + + juegon=1; + + + LoadOptions_game(); + + + if (psp_options.OF == 0) + { + LoadOptions(); + psp_options.OF = 1; + } + + //pl_psp_set_clock_freq(333); + + save_name = 1; + nuevarom = 1; + + + + ResumeEmulation = 1; + + /*NOTA RESUMEN*/ + + //pspUiAlert("Resumen despues de cargar"); + + system_sound_chipreset(); /* Reset sound */ + pl_rewind_reset(&Rewinder); + + + idioma = psp_options.language; + + return 1; +} + + + +static int OnSaveStateOk(const void *gallery, const void *item) +{ + char *path_save; + const char *config_name = pl_file_get_filename(CURRENT_GAME); + + path_save = (char*)malloc(strlen(SaveStatePath) + strlen(config_name) + 8); + sprintf(path_save, "%s%s_%02i.rcs", SaveStatePath, config_name, + ((const pl_menu_item*)item)->id); + + if (pl_file_exists(path_save) && pspUiConfirm("Load state?")) + { + if (psp_load_state(path_save)) + { + /*NOTA*/ + + /*NOTA*/ + + + + ResumeEmulation = 1; + pl_menu_find_item_by_id(&((PspUiGallery*)gallery)->Menu, + ((pl_menu_item*)item)->id); + // pspUiAlert(path); + //free(path); + //pspUiAlert("de nuevo"); + // pspUiAlert(path); + pl_rewind_reset(&Rewinder); + // loadborder(); + return 1; + + } + + pspUiAlert("ERROR: State not loaded"); + } + + free(path_save); + return 0; +} + +static int OnSaveStateButtonPress(const PspUiGallery *gallery, + pl_menu_item *sel, + u32 button_mask) +{ + if (button_mask & PSP_CTRL_SQUARE + || button_mask & PSP_CTRL_TRIANGLE) + { + char *path; + char caption[32]; + const char *config_name = pl_file_get_filename(CURRENT_GAME); + pl_menu_item *item = pl_menu_find_item_by_id(&gallery->Menu, sel->id); + + path = (char*)malloc(strlen(SaveStatePath) + strlen(config_name) + 8); + sprintf(path, "%s%s_%02i.rcs", SaveStatePath, config_name, item->id); + + do /* not a real loop; flow control construct */ + { + if (button_mask & PSP_CTRL_SQUARE) + { + if (pl_file_exists(path) && !pspUiConfirm("Overwrite existing state?")) + break; + + pspUiFlashMessage("Saving, please wait ..."); + + PspImage *icon; + if (!(icon = psp_save_state(path, Screen))) + { + pspUiAlert("ERROR: State not saved"); + break; + } + + SceIoStat stat; + + /* Trash the old icon (if any) */ + if (item->param && item->param != NoSaveIcon) + pspImageDestroy((PspImage*)item->param); + + /* Update icon, help text */ + item->param = icon; + pl_menu_set_item_help_text(item, PresentSlotText); + + /* Get file modification time/date */ + if (sceIoGetstat(path, &stat) < 0) + sprintf(caption, "ERROR"); + else + sprintf(caption, "%02i/%02i/%02i %02i:%02i", + stat.st_mtime.month, + stat.st_mtime.day, + stat.st_mtime.year - (stat.st_mtime.year / 100) * 100, + stat.st_mtime.hour, + stat.st_mtime.minute); + + pl_menu_set_item_caption(item, caption); + } + else if (button_mask & PSP_CTRL_TRIANGLE) + { + if (!pl_file_exists(path) || !pspUiConfirm("Delete state?")) + break; + + if (!pl_file_rm(path)) + { + pspUiAlert("ERROR: State not deleted"); + break; + } + + /* Trash the old icon (if any) */ + if (item->param && item->param != NoSaveIcon) + pspImageDestroy((PspImage*)item->param); + + /* Update icon, caption */ + item->param = NoSaveIcon; + pl_menu_set_item_help_text(item, EmptySlotText); + pl_menu_set_item_caption(item, "Empty"); + } + } while (0); + + if (path) free(path); + return 0; + } + + return OnGenericButtonPress(NULL, NULL, button_mask); +} + +static void OnSplashRender(const void *splash, + const void *null) +{ + int fh, i, x, y, height; + const char *lines[] = + { + PSP_APP_NAME" version "PSP_APP_VER" ("__DATE__")", + " ", + "2014 TheElf", + "\026http://theelf-megadev.com/psp", + " ", + "2008-2009 Akop Karapetyan", + "\026http://psp.akop.org/race", + "2008 Flavor", + "2006 Judge_", + NULL + }; + + fh = pspFontGetLineHeight(UiMetric.Font); + + for (i = 0; lines[i]; i++); + height = fh * (i - 1); + + /* Render lines */ + for (i = 0, y = SCR_HEIGHT / 2 - height / 2; lines[i]; i++, y += fh) + { + x = SCR_WIDTH / 2 - pspFontGetTextWidth(UiMetric.Font, lines[i]) / 2; + pspVideoPrint(UiMetric.Font, x, y, lines[i], PSP_COLOR_GRAY); + } + + /* Render PSP status */ + OnGenericRender(splash, null); +} + +static int OnSplashButtonPress(const struct PspUiSplash *splash, + u32 button_mask) +{ + return OnGenericButtonPress(NULL, NULL, button_mask); +} + +static const char* OnSplashGetStatusBarText(const struct PspUiSplash *splash) +{ + return "\026\255\020/\026\256\020 Switch tabs"; +} + +static int OnMenuOk(const void *uimenu, const void* sel_item) +{ + if (uimenu == &ControlUiMenu) + { + /* Save to MS */ + if (psp_save_controls()) + pspUiAlert("Changes saved"); + else + pspUiAlert("ERROR: Changes not saved"); + } + else + { + switch (((const pl_menu_item*)sel_item)->id) + { + case SYSTEM_RESET: + if (pspUiConfirm("Reset the system?")) + { + /* Write flash data for current game */ + if (GAME_LOADED) + writeSaveGameFile(); + + mainemuinit(); + pl_rewind_reset(&Rewinder); + + ResumeEmulation = 1; + return 1; + } + break; + + case SYSTEM_EXIT: + if (pspUiConfirm("Quit Emulation?")) + { + /* Write flash data for current game */ + if (GAME_LOADED) + writeSaveGameFile(); + ExitPSP = 1; + } + break; + + case SYSTEM_SCRNSHOT: + /* Save screenshot */ + if (!pl_util_save_image_seq(ScreenshotPath, + pl_file_get_filename(CURRENT_GAME), + Screen)) + pspUiAlert("ERROR: Screenshot not saved"); + else + pspUiAlert("Screenshot saved successfully"); + break; + + } + } + return 0; +} + +static int OnMenuButtonPress(const struct PspUiMenu *uimenu, + pl_menu_item* sel_item, + u32 button_mask) +{ + if (uimenu == &ControlUiMenu) + { + if (button_mask & PSP_CTRL_TRIANGLE) + { + pl_menu_item *item; + int i; + + /* Load default mapping */ + memcpy(¤t_map, &default_map, sizeof(psp_ctrl_map_t)); + + /* Modify the menu */ + for (item = ControlUiMenu.Menu.items, i = 0; item; item = item->next, i++) + pl_menu_select_option_by_value(item, (void*)default_map.button_map[i]); + + return 0; + } + } + + return OnGenericButtonPress(NULL, NULL, button_mask); +} + +static int OnMenuItemChanged(const struct PspUiMenu *uimenu, + pl_menu_item* item, + const pl_menu_option* option) +{ + if (uimenu == &ControlUiMenu) + { + current_map.button_map[item->id] = (unsigned int)option->value; + } + else + { + switch((int)item->id) + { + case OPTION_DISPLAY_MODE: + psp_options.display_mode = (int)option->value; + break; + case OPTION_FRAME_SKIP: + psp_options.frame_skip = (int)option->value; + break; + case OPTION_CLOCK_FREQ: + psp_options.clock_freq = (int)option->value; + break; + case OPTION_SHOW_FPS: + psp_options.show_fps = (int)option->value; + break; + case OPTION_CONTROL_MODE: + UiMetric.OkButton = (!(int)option->value) + ? PSP_CTRL_CROSS : PSP_CTRL_CIRCLE; + UiMetric.CancelButton = (!(int)option->value) + ? PSP_CTRL_CIRCLE : PSP_CTRL_CROSS; + break; + case PERFECT_SYNC: + psp_options.pvsync = (int)option->value; + break; + case OPTION_POSVX: + psp_options.pos_vert = (int)option->value; + break; + case OPTION_ANIMATE: + psp_options.language = (int)option->value; + break; + case OPTION_AUTOFIRE: + psp_options.autofire = (int)option->value; + break; + case OPTION_BORDER: + psp_options.border = (int)option->value; + break; + case OPTION_LANG: + psp_options.language = (int)option->value; + break; + } + } + return 1; +} + +static void OnSystemRender(const void *uiobject, + const void *item_obj) +{ + int w, h, x, y; + w = Screen->Viewport.Width; + h = Screen->Viewport.Height; + x = UiMetric.Right - w - UiMetric.ScrollbarWidth; + y = SCR_HEIGHT - h - 56; + + /* Draw a small representation of the screen */ + pspVideoShadowRect(x, y, x + w - 1, y + h - 1, PSP_COLOR_BLACK, 3); + sceGuDisable(GU_BLEND); + pspVideoPutImage(Screen, x, y, w, h); + sceGuEnable(GU_BLEND); + pspVideoDrawRect(x, y, x + w - 1, y + h - 1, PSP_COLOR_GRAY); + + OnGenericRender(uiobject, item_obj); +} + +static void psp_init_controls() +{ + /* Initialize to default configuration */ + memcpy(¤t_map, &default_map, sizeof(psp_ctrl_map_t)); +} + +static int psp_load_controls() +{ + psp_ctrl_map_t *config = ¤t_map; + pl_file_path path; + snprintf(path, sizeof(path) - 1, "%sbuttons.cnf", + pl_psp_get_app_directory()); + + /* If no configuration, load defaults */ + if (!pl_file_exists(path)) + { + psp_init_controls(); + return 1; + } + + /* Open file for reading */ + FILE *file = fopen(path, "r"); + if (!file) return 0; + + /* Read contents of struct */ + int nread = fread(config, sizeof(psp_ctrl_map_t), 1, file); + fclose(file); + + if (nread != 1) + { + psp_init_controls(); + return 0; + } + + return 1; +} + +static int psp_save_controls() +{ + psp_ctrl_map_t *config = ¤t_map; + pl_file_path path; + snprintf(path, sizeof(path) - 1, "%sbuttons.cnf", + pl_psp_get_app_directory()); + + /* Open file for writing */ + FILE *file = fopen(path, "w"); + if (!file) return 0; + + /* Write contents of struct */ + int nwritten = fwrite(config, sizeof(psp_ctrl_map_t), 1, file); + fclose(file); + + return (nwritten == 1); +} + +static void psp_display_control_tab() +{ + pl_menu_item *item; + int i; + + /* Load current button mappings */ + for (item = ControlUiMenu.Menu.items, i = 0; item; item = item->next, i++) + pl_menu_select_option_by_value(item, (void*)current_map.button_map[i]); + + pspUiOpenMenu(&ControlUiMenu, NULL); +} + +static void psp_display_state_tab() +{ + pl_menu_item *item, *sel = NULL; + SceIoStat stat; + ScePspDateTime latest; + char caption[32]; + const char *config_name = pl_file_get_filename(CURRENT_GAME); + char *path = (char*)malloc(strlen(SaveStatePath) + strlen(config_name) + 8); + char *game_name = strdup(config_name); + char *dot = strrchr(game_name, '.'); + if (dot) *dot='\0'; + + memset(&latest,0,sizeof(latest)); + + /* Initialize icons */ + for (item = SaveStateGallery.Menu.items; item; item = item->next) + { + sprintf(path, "%s%s_%02i.rcs", SaveStatePath, config_name, item->id); + + if (pl_file_exists(path)) + { + if (sceIoGetstat(path, &stat) < 0) + sprintf(caption, "ERROR"); + else + { + /* Determine the latest save state */ + if (pl_util_date_compare(&latest, &stat.st_mtime) < 0) + { + sel = item; + latest = stat.st_mtime; + } + + sprintf(caption, "%02i/%02i/%02i %02i:%02i", + stat.st_mtime.month, + stat.st_mtime.day, + stat.st_mtime.year - (stat.st_mtime.year / 100) * 100, + stat.st_mtime.hour, + stat.st_mtime.minute); + } + + pl_menu_set_item_caption(item, caption); + item->param = psp_load_state_icon(path); + pl_menu_set_item_help_text(item, PresentSlotText); + } + else + { + pl_menu_set_item_caption(item, "Empty"); + item->param = NoSaveIcon; + pl_menu_set_item_help_text(item, EmptySlotText); + } + } + + free(path); + + /* Highlight the latest save state if none are selected */ + if (SaveStateGallery.Menu.selected == NULL) + SaveStateGallery.Menu.selected = sel; + + pspUiOpenGallery(&SaveStateGallery, game_name); + free(game_name); + + /* Destroy any icons */ + for (item = SaveStateGallery.Menu.items; item; item = item->next) + if (item->param != NULL && item->param != NoSaveIcon) + pspImageDestroy((PspImage*)item->param); +} + +/* Load state icon */ +static PspImage* psp_load_state_icon(const char *path) +{ + FILE *f = fopen(path, "r"); + if (!f) return NULL; + + /* Load image */ + PspImage *image = pspImageLoadPngFd(f); + fclose(f); + + return image; +} + +/* Load state */ +static int psp_load_state(const char *path) +{ + /* Open file for reading */ + FILE *f = fopen(path, "r"); + if (!f) return 0; + + /* Load image into temporary object */ + PspImage *image = pspImageLoadPngFd(f); + pspImageDestroy(image); + + /* Load the state data */ + int status = state_restore(f); + fclose(f); + + return status; +} + +static void psp_discard_alpha(PspImage *image) +{ + int i, j; + for (i = image->Viewport.Y; i < image->Viewport.Height; i++) + for (j = image->Viewport.X; j < image->Viewport.Width; j++) + ((u16*)image->Pixels)[(i * image->Width) + j] |= 0x8000; +} + +/* Save state */ +static PspImage* psp_save_state(const char *path, PspImage *icon) +{ + /* Open file for writing */ + FILE *f; + if (!(f = fopen(path, "w"))) + return NULL; + + /* Create thumbnail */ + PspImage *thumb; + thumb = pspImageCreateCopy(icon); + + if (!thumb) { fclose(f); return NULL; } + + psp_discard_alpha(thumb); + + /* Write the thumbnail */ + if (!pspImageSavePngFd(f, thumb)) + { + pspImageDestroy(thumb); + fclose(f); + pl_file_rm(path); + return NULL; + } + + /* Write the state */ + if (!state_store(f)) + { + pspImageDestroy(thumb); + thumb = NULL; + } + + fclose(f); + return thumb; +} + + + + static void loadborder() +{ + + + sprintf(BorderPath, "%sborders/", pl_psp_get_app_directory()); + pl_file_path path; + + bordernull=0; + + if (psp_options.border==1){ + const char *border_name = pl_file_get_filename(CURRENT_GAME); + snprintf(path, sizeof(path) - 1, "%s%sborder.png", BorderPath, border_name); + bordername = path; + customborder=1; + + FILE *fp; + fp = fopen(bordername,"r"); + + if (fp == NULL) { + + snprintf(path, sizeof(path) - 1, "%sborder.png", BorderPath); + customborder=0;} + + bordername = path; + } + + else{ + customborder=0; + bordernull=1; + } + + + } + + + +static void LoadOptions_game() +{ + sprintf(IniPath, "%sini/", pl_psp_get_app_directory()); + + const char *config_name = pl_file_get_filename(CURRENT_GAME); + pl_file_path path; + snprintf(path, sizeof(path) - 1, "%s%soptions.ini", IniPath, config_name); + + /* Load INI */ + pl_ini_file file; + pl_ini_load(&file, path); + + + psp_options.display_mode = pl_ini_get_int(&file, "Video", "Display Mode", dmode); + psp_options.frame_skip = pl_ini_get_int(&file, "Video", "Screen Refresh", fskip); + psp_options.clock_freq = pl_ini_get_int(&file, "Video", "PSP Clock Frequency", cclock); + psp_options.show_fps = pl_ini_get_int(&file, "Video", "Show FPS", 0); + psp_options.update_freq = pl_ini_get_int(&file, "Video", "Update Frequency", HOST_FPS); + psp_options.rewind_save_rate = pl_ini_get_int(&file, "Enhancements", "Rewind Save Rate", rrewind); + pl_ini_get_string(&file, "File", "Game Path", NULL, + GamePath, sizeof(GamePath)); + psp_options.pvsync = pl_ini_get_int(&file, "Video", "Vsync", vvsync); + psp_options.pos_vert = pl_ini_get_int(&file, "Video", "PosVert", ppos); + psp_options.language = pl_ini_get_int(&file, "Menu", "Language", 1); + psp_options.OF = pl_ini_get_int(&file, "System", "OFile", 0); + psp_options.border = pl_ini_get_int(&file, "Enhancements", "Border", bbord); + psp_options.autofire = pl_ini_get_int(&file, "Input", "Autofire", 2); + if (psp_options.autofire < 2) + psp_options.autofire = 2; + + int control_mode = pl_ini_get_int(&file, "Menu", "Control Mode", ccont); + UiMetric.OkButton = (!control_mode) + ? PSP_CTRL_CROSS : PSP_CTRL_CIRCLE; + UiMetric.CancelButton = (!control_mode) + ? PSP_CTRL_CIRCLE : PSP_CTRL_CROSS; + + /* Clean up */ + pl_ini_destroy(&file); +} + + +static void LoadOptions() +{ + pl_file_path path; + snprintf(path, sizeof(path) - 1, "%soptions.ini", pl_psp_get_app_directory()); + + /* Load INI */ + pl_ini_file file; + pl_ini_load(&file, path); + + psp_options.display_mode = pl_ini_get_int(&file, "Video", "Display Mode", SIMPLE_2X); + psp_options.frame_skip = pl_ini_get_int(&file, "Video", "Screen Refresh", 2); + psp_options.clock_freq = pl_ini_get_int(&file, "Video", "PSP Clock Frequency", 333); + psp_options.show_fps = pl_ini_get_int(&file, "Video", "Show FPS", 0); + psp_options.update_freq = pl_ini_get_int(&file, "Video", "Update Frequency", HOST_FPS); + psp_options.rewind_save_rate = pl_ini_get_int(&file, "Enhancements", "Rewind Save Rate", 5); + pl_ini_get_string(&file, "File", "Game Path", NULL, + GamePath, sizeof(GamePath)); + psp_options.pvsync = pl_ini_get_int(&file, "Video", "Vsync", 1); + psp_options.pos_vert = pl_ini_get_int(&file, "Video", "PosVert", 0); + psp_options.language = pl_ini_get_int(&file, "Menu", "Language", 0); + psp_options.OF = pl_ini_get_int(&file, "System", "OFile", 0); + psp_options.border = pl_ini_get_int(&file, "Enhancements", "Border", 1); + psp_options.autofire = pl_ini_get_int(&file, "Input", "Autofire", 2); + if (psp_options.autofire < 2) + psp_options.autofire = 2; + + int control_mode = pl_ini_get_int(&file, "Menu", "Control Mode", 1); + UiMetric.OkButton = (!control_mode) + ? PSP_CTRL_CROSS : PSP_CTRL_CIRCLE; + UiMetric.CancelButton = (!control_mode) + ? PSP_CTRL_CIRCLE : PSP_CTRL_CROSS; + + dmode = psp_options.display_mode; + fskip = psp_options.frame_skip; + cclock = psp_options.clock_freq; + rrewind = psp_options.rewind_save_rate; + vvsync = psp_options.pvsync; + ppos = psp_options.pos_vert; + ccont = control_mode; + bbord = psp_options.border; + + /* Clean up */ + pl_ini_destroy(&file); +} + +static int SaveOptions() +{ + + pl_file_path path; + snprintf(path, sizeof(path) - 1, "%soptions.ini", pl_psp_get_app_directory()); + + /* Initialize INI structure */ + pl_ini_file file; + pl_ini_create(&file); + pl_ini_set_int(&file, "Video", "Display Mode", + psp_options.display_mode); + pl_ini_set_int(&file, "Video", "Screen Refresh", + psp_options.frame_skip); + pl_ini_set_int(&file, "Video", "PSP Clock Frequency", + psp_options.clock_freq); + pl_ini_set_int(&file, "Video", "Update Frequency", + psp_options.update_freq); + pl_ini_set_int(&file, "Video", "Show FPS", + psp_options.show_fps); + pl_ini_set_int(&file, "Menu", "Control Mode", + (UiMetric.OkButton == PSP_CTRL_CIRCLE)); + pl_ini_set_int(&file, "Video", "Vsync", + psp_options.pvsync); + pl_ini_set_int(&file, "Video", "PosVert", + psp_options.pos_vert); + pl_ini_set_int(&file, "Menu", "Language", + psp_options.language); + pl_ini_set_int(&file, "Enhancements", "Border", + psp_options.border); + pl_ini_set_int(&file, "Input", "Autofire", + psp_options.autofire); + pl_ini_set_int(&file, "Enhancements", "Rewind Save Rate", + psp_options.rewind_save_rate); + pl_ini_set_string(&file, "File", "Game Path", + GamePath); + + int status = pl_ini_save(&file, path); + pl_ini_destroy(&file); + + return status; +} + +static int CreateOptions() +{ + sprintf(IniPath, "%sini/", pl_psp_get_app_directory()); + + const char *config_name = pl_file_get_filename(CURRENT_GAME); + pl_file_path path; + snprintf(path, sizeof(path) - 1, "%s%soptions.ini", IniPath, config_name); + + /* Initialize INI structure */ + pl_ini_file file; + pl_ini_create(&file); + pl_ini_set_int(&file, "Video", "Display Mode", + psp_options.display_mode); + pl_ini_set_int(&file, "Video", "Screen Refresh", + psp_options.frame_skip); + pl_ini_set_int(&file, "Video", "PSP Clock Frequency", + psp_options.clock_freq); + pl_ini_set_int(&file, "Video", "Update Frequency", + psp_options.update_freq); + pl_ini_set_int(&file, "Video", "Show FPS", + psp_options.show_fps); + pl_ini_set_int(&file, "Menu", "Control Mode", + (UiMetric.OkButton == PSP_CTRL_CIRCLE)); + pl_ini_set_int(&file, "Video", "Vsync", + psp_options.pvsync); + pl_ini_set_int(&file, "Video", "PosVert", + psp_options.pos_vert); + pl_ini_set_int(&file, "System", "OFile", + psp_options.OF); + pl_ini_set_int(&file, "Menu", "Language", + psp_options.language); + pl_ini_set_int(&file, "Enhancements", "Border", + psp_options.border); + pl_ini_set_int(&file, "Input", "Autofire", + psp_options.autofire); + pl_ini_set_int(&file, "Enhancements", "Rewind Save Rate", + psp_options.rewind_save_rate); + pl_ini_set_string(&file, "File", "Game Path", + GamePath); + + int status = pl_ini_save(&file, path); + pl_ini_destroy(&file); + + return status; +} diff --git a/psp/menu.h b/psp/menu.h new file mode 100644 index 0000000..f6d77d3 --- /dev/null +++ b/psp/menu.h @@ -0,0 +1,8 @@ +#ifndef PSP_MENU_H +#define PSP_MENU_H + +int InitMenu(); +void DisplayMenu(); +void TrashMenu(); + +#endif diff --git a/psp/psplib/COPYING b/psp/psplib/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/psp/psplib/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/psp/psplib/Makefile b/psp/psplib/Makefile new file mode 100644 index 0000000..1964c72 --- /dev/null +++ b/psp/psplib/Makefile @@ -0,0 +1,102 @@ +## Makefile for psplib library +## Copyright (C) 2008-2009 Akop Karapetyan + +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. + +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. + +## You should have received a copy of the GNU General Public License +## along with this program. If not, see . + +## Author contact information: dev@psp.akop.org + +ifndef PSP_FW_VERSION +PSP_FW_VERSION=200 +endif + +CC=psp-gcc +AR=psp-ar +RANLIB=psp-ranlib +RM=rm -rf +PSPSDK=$(shell psp-config --pspsdk-path) +CFLAGS=-G0 -Wall -I$(PSPSDK)/include +DEFINES=-DPSP -D_PSP_FW_VERSION=$(PSP_FW_VERSION) + +all: libpsplib.a + +libpsplib.a: \ + adhoc.o font.o image.o ctrl.o video.o ui.o \ + pl_ini.o pl_perf.o pl_vk.o pl_util.o pl_image.o \ + pl_psp.o pl_menu.o pl_file.o pl_snd.o pl_gfx.o \ + pl_rewind.o + + $(AR) cru $@ $? + $(RANLIB) $@ + @echo Compiled for firmware $(PSP_FW_VERSION) + +clean: + $(RM) *.o genfont stockfont.h *.a + +font.o: font.c font.h stockfont.h + $(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $< + +video.o: video.c video.h + $(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $< + +ctrl.o: ctrl.c ctrl.h + $(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $< + +adhoc.o: adhoc.c adhoc.h + $(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $< + +ui.o: ui.c ui.h pl_file.o pl_psp.o \ + ctrl.o font.o pl_menu.o video.o \ + adhoc.o + $(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $< + +pl_snd.o: pl_snd.c pl_snd.h + $(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $< + +pl_psp.o: pl_psp.c pl_psp.h + $(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $< + +pl_ini.o: pl_ini.c pl_ini.h + $(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $< + +pl_vk.o: pl_vk.c pl_vk.h video.o font.o \ + ctrl.o + $(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $< + +pl_util.o: pl_util.c pl_util.h image.o \ + pl_file.o video.o + $(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $< + +pl_perf.o: pl_perf.c pl_perf.h + $(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $< + +pl_menu.o: pl_menu.c pl_menu.h + $(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $< + +pl_file.o: pl_file.c pl_file.h + $(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $< + +pl_image.o: pl_image.c pl_image.h + $(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $< + +pl_gfx.o: pl_gfx.c pl_gfx.h + $(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $< + +pl_rewind.o: pl_rewind.c pl_rewind.h + $(CC) $(DEFINES) $(CFLAGS) -O2 -c -o $@ $< + +stockfont.h: stockfont.fd genfont + ./genfont < $< > $@ + +genfont: genfont.c + cc $< -o $@ diff --git a/psp/psplib/adhoc.c b/psp/psplib/adhoc.c new file mode 100644 index 0000000..fd2affb --- /dev/null +++ b/psp/psplib/adhoc.c @@ -0,0 +1,499 @@ +/* psplib/adhoc.c + Adhoc Wi-fi matching and communication + + Copyright (C) 2007-2008 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: pspdev@akop.org +*/ + +#include "adhoc.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ADHOC_TIMEOUT (10 * 1000000) +#define ADHOC_BLOCKSIZE 0x400 + +int _net_adhoc_ctl_connect = 0; +int _net_adhoc_pdp_create = 0; +int _net_adhoc_matching_start = 0; +int _net_adhoc_matching_create = 0; +int _net_adhoc_matching_init = 0; +int _net_adhoc_ctl_init = 0; +int _net_adhoc_init = 0; +int _net_init = 0; +char _matching_data[128]; +int _pdp_id, _matching_id; +PspMAC _own_mac; + +int pspAdhocRecvBlockingMAC(void *buffer, int length, PspMAC mac); + +int pspAdhocInit(const char *product_name, + PspMatchingCallback callback) +{ + /* Shut down adhoc, if currently enabled */ + pspAdhocShutdown(); + + struct productStruct product; + char mac[20]; + int err, state = 0; + + strncpy(product.product, product_name, 9); + product.unknown = 0; + if (sceUtilityGetSystemParamString(PSP_SYSTEMPARAM_ID_STRING_NICKNAME, + _matching_data, 128) != 0) + return 0; + + if ((err = sceNetInit(0x20000, 0x2A, 0x1000, 0x2A, 0x1000)) == 0) + { + _net_init = 1; + if ((err = sceNetAdhocInit()) == 0) + { + _net_adhoc_init = 1; + if ((err = sceNetAdhocctlInit(0x2000, 0x20, &product)) == 0) + { + _net_adhoc_ctl_init = 1; + if ((err = sceNetAdhocctlConnect((void*)"")) == 0) + { + _net_adhoc_ctl_connect = 1; + do + { + if ((err = sceNetAdhocctlGetState(&state)) != 0) break; + sceKernelDelayThread(1000000/60); + } while (state != 1); + + /* Get WLAN MAC */ + unsigned char own_mac[8]; + sceWlanGetEtherAddr(own_mac); + memcpy(_own_mac, own_mac, sizeof(unsigned char) * 6); + + if (err == 0) + { + sceWlanGetEtherAddr((unsigned char*)mac); + if ((_pdp_id = sceNetAdhocPdpCreate((unsigned char*)mac, 0x309, 0x400, 0)) > 0) + { + _net_adhoc_pdp_create = 1; + if ((err = sceNetAdhocMatchingInit(0x20000)) == 0) + { + _net_adhoc_matching_init = 1; + _matching_id = sceNetAdhocMatchingCreate(3, + 0xa, + 0x22b, + 0x800, + 0x2dc6c0, + 0x5b8d80, + 3, + 0x7a120, + callback); + if (_matching_id >= 0) + { + _net_adhoc_matching_create = 1; + err = sceNetAdhocMatchingStart(_matching_id, + 0x10, + 0x2000, + 0x10, + 0x2000, + strlen(_matching_data) + 1, + _matching_data); + if (err == 0) + { + _net_adhoc_matching_start = 1; + /* Everything checked out */ + return 1; + } + sceNetAdhocMatchingDelete(_matching_id); + _net_adhoc_matching_create = 0; + } + sceNetAdhocMatchingTerm(); + _net_adhoc_matching_init = 0; + } + sceNetAdhocPdpDelete(_pdp_id, 0); + _net_adhoc_pdp_create = 0; + } + } + sceNetAdhocctlDisconnect(); + _net_adhoc_ctl_connect = 0; + } + sceNetAdhocctlTerm(); + _net_adhoc_ctl_init = 0; + } + sceNetAdhocTerm(); + _net_adhoc_init = 0; + } + sceNetTerm(); + _net_init = 0; + } + + return 0; +} + +void pspAdhocCancelTarget(const PspMAC mac) +{ + sceNetAdhocMatchingCancelTarget(_matching_id, (unsigned char*)mac); +} + +void pspAdhocSelectTarget(const PspMAC mac) +{ + sceNetAdhocMatchingSelectTarget(_matching_id, (unsigned char*)mac, 0, 0); +} + +int pspAdhocIsMACEqual(const PspMAC mac1, const PspMAC mac2) +{ + int i; + for (i = 0; i < 6; i++) + if (mac1[i] != mac2[i]) + return 0; + return 1; +} + +int pspAdhocShutdown() +{ + if (_net_init) + { + if (_net_adhoc_init) + { + if (_net_adhoc_ctl_init) + { + if (_net_adhoc_ctl_connect) + { + if (_net_adhoc_pdp_create) + { + if (_net_adhoc_matching_init) + { + if (_net_adhoc_matching_create) + { + if (_net_adhoc_matching_start) + { + sceNetAdhocMatchingStop(_matching_id); + _net_adhoc_matching_start = 0; + } + sceNetAdhocMatchingDelete(_matching_id); + _net_adhoc_matching_create = 0; + } + sceNetAdhocMatchingTerm(); + _net_adhoc_matching_init = 0; + } + sceNetAdhocPdpDelete(_pdp_id, 0); + _net_adhoc_pdp_create = 0; + } + sceNetAdhocctlDisconnect(); + _net_adhoc_ctl_connect = 0; + } + sceNetAdhocctlTerm(); + _net_adhoc_ctl_init = 0; + } + sceNetAdhocTerm(); + _net_adhoc_init = 0; + } + sceNetTerm(); + _net_init = 0; + } + + return 1; +} + +/* Must be called from KERNEL thread */ +int pspAdhocLoadDrivers() +{ + _net_adhoc_matching_start = 0; + _net_adhoc_matching_create = 0; + _net_adhoc_matching_init = 0; + _net_adhoc_pdp_create = 0; + _net_adhoc_ctl_connect = 0; + _net_adhoc_ctl_init = 0; + _net_adhoc_init = 0; + _net_init = 0; + +#if (_PSP_FW_VERSION < 200) + int modID; + + modID = pspSdkLoadStartModule("flash0:/kd/ifhandle.prx", + PSP_MEMORY_PARTITION_KERNEL); + if (modID < 0) return modID; + + modID = pspSdkLoadStartModule("flash0:/kd/memab.prx", + PSP_MEMORY_PARTITION_KERNEL); + if (modID < 0) return modID; + + modID = pspSdkLoadStartModule("flash0:/kd/pspnet_adhoc_auth.prx", + PSP_MEMORY_PARTITION_KERNEL); + if (modID < 0) return modID; + + modID = pspSdkLoadStartModule("flash0:/kd/pspnet.prx", + PSP_MEMORY_PARTITION_USER); + if (modID < 0) return modID; + else pspSdkFixupImports(modID); + + modID = pspSdkLoadStartModule("flash0:/kd/pspnet_adhoc.prx", + PSP_MEMORY_PARTITION_USER); + if (modID < 0) return modID; + else pspSdkFixupImports(modID); + + modID = pspSdkLoadStartModule("flash0:/kd/pspnet_adhocctl.prx", + PSP_MEMORY_PARTITION_USER); + if (modID < 0) return modID; + else pspSdkFixupImports(modID); + + modID = pspSdkLoadStartModule("flash0:/kd/pspnet_adhoc_matching.prx", + PSP_MEMORY_PARTITION_USER); + if (modID < 0) return modID; + else pspSdkFixupImports(modID); + + sceKernelDcacheWritebackAll(); + sceKernelIcacheInvalidateAll(); +#else + sceUtilityLoadNetModule(PSP_NET_MODULE_COMMON); + sceUtilityLoadNetModule(PSP_NET_MODULE_ADHOC); +#endif + + return 1; +} + +int pspAdhocConnect(const PspMAC mac) +{ + int err, state = 0; + char temp[64]; + char ssid[10]; + sceNetEtherNtostr((unsigned char*)mac, temp); + + ssid[0] = temp[9]; + ssid[1] = temp[10]; + ssid[2] = temp[12]; + ssid[3] = temp[13]; + ssid[4] = temp[15]; + ssid[5] = temp[16]; + ssid[6] = '\0'; + + if (_net_adhoc_ctl_connect) + { + if (_net_adhoc_pdp_create) + { + if (_net_adhoc_matching_init) + { + if (_net_adhoc_matching_create) + { + if (_net_adhoc_matching_start) + { + sceNetAdhocMatchingStop(_matching_id); + _net_adhoc_matching_start = 0; + } + sceNetAdhocMatchingDelete(_matching_id); + _net_adhoc_matching_create = 0; + } + sceNetAdhocMatchingTerm(); + _net_adhoc_matching_init = 0; + } + sceNetAdhocPdpDelete(_pdp_id, 0); + _net_adhoc_pdp_create = 0; + } + sceNetAdhocctlDisconnect(); + _net_adhoc_ctl_connect = 0; + } + + do + { + if ((err = sceNetAdhocctlGetState(&state)) != 0) break; + sceKernelDelayThread(1000000/60); + } while (state == 1); + + if ((err = sceNetAdhocctlConnect((void*)ssid)) == 0) + { + do + { + if ((err = sceNetAdhocctlGetState(&state)) != 0) break; + sceKernelDelayThread(1000000/60); + } while (state != 1); + + if (!err) + { + if ((_pdp_id = sceNetAdhocPdpCreate(_own_mac, 0x309, 0x800, 0)) > 0) + { + if (pspAdhocIsMACEqual(mac, _own_mac)) + sceKernelDelayThread(1000000); + return 1; + } + } + + if (_net_adhoc_ctl_connect) + { + sceNetAdhocctlDisconnect(); + _net_adhoc_ctl_connect = 0; + } + + if (state == 1) + { + do + { + if ((err = sceNetAdhocctlGetState(&state)) != 0) + break; + sceKernelDelayThread(1000000/60); + } while (state == 1); + } + } + + if (_net_init) + { + if (_net_adhoc_init) + { + if (_net_adhoc_ctl_init) + { + sceNetAdhocctlTerm(); + _net_adhoc_ctl_init = 0; + } + sceNetAdhocTerm(); + _net_adhoc_init = 0; + } + sceNetTerm(); + _net_init = 0; + } + + return 0; +} + +int pspAdhocGetOwnMAC(PspMAC mac) +{ + memcpy(mac, _own_mac, sizeof(unsigned char) * 6); + return 1; +} + +int pspAdhocIsWLANEnabled() +{ + return sceWlanGetSwitchState(); +} + +int pspAdhocSendBlocking(const PspMAC mac, const void *buffer, int length) +{ + if (sceNetAdhocPdpSend(_pdp_id, (unsigned char*)mac, 0x309, + (void*)buffer, length, ADHOC_TIMEOUT, 0) < 0) + return 0; + return length; +} + +int pspAdhocRecvBlockingMAC(void *buffer, int length, PspMAC mac) +{ + unsigned short port = 0; + if (sceNetAdhocPdpRecv(_pdp_id, mac, &port, buffer, &length, ADHOC_TIMEOUT, 0) < 0) + return 0; + return length; +} + +int pspAdhocRecvBlocking(void *buffer, int length) +{ + PspMAC mac; + return pspAdhocRecvBlockingMAC(buffer, length, mac); +} + +int pspAdhocSendWithAck(const PspMAC mac, const void *buffer, int length) +{ + int ack_data = 0; + int chunk_size = length; + int bytes_sent = 0; + + do + { + if (chunk_size > ADHOC_BLOCKSIZE) + chunk_size = ADHOC_BLOCKSIZE; + + pspAdhocSendBlocking(mac, buffer, chunk_size); + + if (pspAdhocRecvBlocking(&ack_data, sizeof(int)) == 0) + return 0; + + if (ack_data != chunk_size) + return 0; + + buffer += ADHOC_BLOCKSIZE; + bytes_sent += ADHOC_BLOCKSIZE; + chunk_size = length - bytes_sent; + } while (bytes_sent < length); + + return length; +} + +int pspAdhocRecvWithAck(void *buffer, int length) +{ + int chunk_size = length; + int bytes_rcvd = 0; + PspMAC source_mac; + + do + { + if (chunk_size > ADHOC_BLOCKSIZE) + chunk_size = ADHOC_BLOCKSIZE; + + if (pspAdhocRecvBlockingMAC(buffer, chunk_size, source_mac) == 0) + return 0; + + pspAdhocSendBlocking(source_mac, &chunk_size, sizeof(int)); + + buffer += ADHOC_BLOCKSIZE; + bytes_rcvd += ADHOC_BLOCKSIZE; + chunk_size = length - bytes_rcvd; + } while (bytes_rcvd < length); + + return length; +} + +int pspAdhocSendBlob(const PspMAC mac, const void *buffer, int length) +{ + if (!pspAdhocSendWithAck(mac, &length, sizeof(int))) + return 0; + if (!pspAdhocSendWithAck(mac, buffer, length)) + return 0; + return 1; +} + +int pspAdhocRecvBlob(void **buffer, int *length) +{ + if (!pspAdhocRecvWithAck(length, sizeof(int))) + return 0; + if (!(*buffer = malloc(*length))) + return 0; + if (!pspAdhocRecvWithAck(*buffer, *length)) + { + free(*buffer); + return 0; + } + return 1; +} + +int pspAdhocSend(const PspMAC mac, const void *buffer, int length) +{ + if (sceNetAdhocPdpSend(_pdp_id, (unsigned char*)mac, 0x309, (void*)buffer, length, 0, 1) < 0) + return 0; + return length; +} + +int pspAdhocRecv(void *buffer, int length) +{ + unsigned short port = 0; + unsigned char mac[6]; + + if (sceNetAdhocPdpRecv(_pdp_id, mac, &port, buffer, &length, 0, 1) < 0) + return 0; + return length; +} diff --git a/psp/psplib/adhoc.h b/psp/psplib/adhoc.h new file mode 100644 index 0000000..11a9da1 --- /dev/null +++ b/psp/psplib/adhoc.h @@ -0,0 +1,63 @@ +/* psplib/adhoc.h + Adhoc Wi-fi matching and communication + + Copyright (C) 2007-2008 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: pspdev@akop.org +*/ + +#ifndef _PSP_ADHOC_H +#define _PSP_ADHOC_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned char PspMAC[6]; +typedef void(*PspMatchingCallback)(int unk1, + int event, + unsigned char *mac2, + int opt_len, + void *opt_data); + +int pspAdhocLoadDrivers(); +int pspAdhocInit(const char *product_name, + PspMatchingCallback callback); +int pspAdhocConnect(const PspMAC mac); +int pspAdhocShutdown(); + +void pspAdhocSelectTarget(const PspMAC mac); +void pspAdhocCancelTarget(const PspMAC mac); + +int pspAdhocGetOwnMAC(PspMAC mac); +int pspAdhocIsMACEqual(const PspMAC mac1, const PspMAC mac2); +int pspAdhocIsWLANEnabled(); + +int pspAdhocSend(const PspMAC mac, const void *buffer, int length); +int pspAdhocRecv(void *buffer, int length); +int pspAdhocSendBlocking(const PspMAC mac, const void *buffer, int length); +int pspAdhocRecvBlocking(void *buffer, int length); +int pspAdhocSendWithAck(const PspMAC mac, const void *buffer, int length); +int pspAdhocRecvWithAck(void *buffer, int length); +int pspAdhocRecvBlob(void **buffer, int *length); +int pspAdhocSendBlob(const PspMAC mac, const void *buffer, int length); + +#ifdef __cplusplus +} +#endif + + +#endif /* _PSP_ADHOC_H */ diff --git a/psp/psplib/ctrl.c b/psp/psplib/ctrl.c new file mode 100644 index 0000000..2782274 --- /dev/null +++ b/psp/psplib/ctrl.c @@ -0,0 +1,201 @@ +/* psplib/ctrl.c + Controller routines + + Copyright (C) 2007-2008 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: pspdev@akop.org +*/ + +#include +#include +#include + +#include "ctrl.h" + +#define PSP_CTRL_DELAY 400 +#define PSP_CTRL_THRESHOLD 50 +#define PSP_CTRL_BUTTONS 12 + +static int PollingMode; +static u64 PushTime[PSP_CTRL_BUTTONS]; +static const int ButtonMap[PSP_CTRL_BUTTONS] = +{ + PSP_CTRL_UP, + PSP_CTRL_DOWN, + PSP_CTRL_LEFT, + PSP_CTRL_RIGHT, + PSP_CTRL_CROSS, + PSP_CTRL_CIRCLE, + PSP_CTRL_SQUARE, + PSP_CTRL_TRIANGLE, + PSP_CTRL_LTRIGGER, + PSP_CTRL_RTRIGGER, + PSP_CTRL_SELECT, + PSP_CTRL_START, +}; + +void pspCtrlInit() +{ + /* Init PSP controller */ + sceCtrlSetSamplingCycle(0); + //sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG); + + PollingMode = PSP_CTRL_NORMAL; +} + +int pspCtrlGetPollingMode() +{ + return PollingMode; +} + +void pspCtrlSetPollingMode(int mode) +{ + /* If autorepeat is being shut off, wait until it's "safe" */ + if (PollingMode == PSP_CTRL_AUTOREPEAT) + { + int i; + SceCtrlData p; + u64 tick; + int wait; + + do + { + wait = 0; + + if (!sceCtrlPeekBufferPositive(&p, 1)) + break; + + /* Get current tick count */ + sceRtcGetCurrentTick(&tick); + + /* If at least one button is being held, wait until */ + /* next autorepeat interval, or until it's released */ + for (i = 0; i < PSP_CTRL_BUTTONS; i++) + if (tick < PushTime[i] && (p.Buttons & ButtonMap[i])) + { wait = 1; break; } + } + while (wait); + } + + PollingMode = mode; + + /* If autorepeat is being turned on, initialize autorepeat data */ + if (mode == PSP_CTRL_AUTOREPEAT) + { + SceCtrlData p; + int i; + u64 tick; + u32 tick_res; + + /* Poll the controls */ + if (sceCtrlPeekBufferPositive(&p, 1)) + { + /* Get current tick count */ + sceRtcGetCurrentTick(&tick); + tick_res = sceRtcGetTickResolution(); + + /* Check each button */ + for (i = 0; i < PSP_CTRL_BUTTONS; i++) + PushTime[i] = (p.Buttons & ButtonMap[i]) ? tick + PSP_CTRL_DELAY * (tick_res / 1000) : 0; + } + } +} + +int pspCtrlPollControls(SceCtrlData *pad) +{ + int stat; + + /* Simulate button autorepeat */ + if (PollingMode == PSP_CTRL_AUTOREPEAT) + { + SceCtrlData p; + int stat, i; + u64 tick; + u32 tick_res; + + /* Poll the controls */ + if (!(stat = sceCtrlPeekBufferPositive(&p, 1))) + return stat; + + /* Get current tick count */ + sceRtcGetCurrentTick(&tick); + tick_res = sceRtcGetTickResolution(); + + /* Check each button */ + for (i = 0; i < PSP_CTRL_BUTTONS; i++) + { + if (p.Buttons & ButtonMap[i]) + { + if (!PushTime[i] || tick >= PushTime[i]) + { + /* Button was pushed for the first time, or time to repeat */ + pad->Buttons |= ButtonMap[i]; + /* Compute next press time */ + PushTime[i] = tick + ((PushTime[i]) ? PSP_CTRL_THRESHOLD : PSP_CTRL_DELAY) + * (tick_res / 1000); + } + else + { + /* No need to repeat yet */ + pad->Buttons &= ~ButtonMap[i]; + } + } + else + { + /* Button was released */ + pad->Buttons &= ~ButtonMap[i]; + PushTime[i] = 0; + } + } + + /* Copy analog stick status */ + pad->Lx = p.Lx; + pad->Ly = p.Ly; + + /* Unset the analog stick bits */ + pad->Buttons &= ~(PSP_CTRL_ANALUP + | PSP_CTRL_ANALDOWN + | PSP_CTRL_ANALLEFT + | PSP_CTRL_ANALRIGHT); + + /* Set the bits based on analog stick status */ + if (pad->Ly < 32) pad->Buttons |= PSP_CTRL_ANALUP; + else if (pad->Ly >= 224) pad->Buttons |= PSP_CTRL_ANALDOWN; + if (pad->Lx < 32) pad->Buttons |= PSP_CTRL_ANALLEFT; + else if (pad->Lx >= 224) pad->Buttons |= PSP_CTRL_ANALRIGHT; + + return stat; + } + + /* Default is normal behavior */ + if (!(stat = sceCtrlPeekBufferPositive(pad, 1))) + return stat; + + /* Unset the analog stick bits */ + pad->Buttons &= ~(PSP_CTRL_ANALUP + | PSP_CTRL_ANALDOWN + | PSP_CTRL_ANALLEFT + | PSP_CTRL_ANALRIGHT); + + /* Set the bits based on analog stick status */ + if (pad->Ly < 32) pad->Buttons |= PSP_CTRL_ANALUP; + else if (pad->Ly >= 224) pad->Buttons |= PSP_CTRL_ANALDOWN; + if (pad->Lx < 32) pad->Buttons |= PSP_CTRL_ANALLEFT; + else if (pad->Lx >= 224) pad->Buttons |= PSP_CTRL_ANALRIGHT; + + return stat; +} + diff --git a/psp/psplib/ctrl.h b/psp/psplib/ctrl.h new file mode 100644 index 0000000..e05cd8f --- /dev/null +++ b/psp/psplib/ctrl.h @@ -0,0 +1,49 @@ +/* psplib/ctrl.h + Controller routines + + Copyright (C) 2007-2008 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: pspdev@akop.org +*/ + +#ifndef _PSP_CTRL_H +#define _PSP_CTRL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* These bits are currently unused */ +#define PSP_CTRL_ANALUP 0x00000002 +#define PSP_CTRL_ANALDOWN 0x00000004 +#define PSP_CTRL_ANALLEFT 0x00000400 +#define PSP_CTRL_ANALRIGHT 0x00000800 + +#define PSP_CTRL_NORMAL 0 +#define PSP_CTRL_AUTOREPEAT 1 + +void pspCtrlInit(); +int pspCtrlGetPollingMode(); +void pspCtrlSetPollingMode(int mode); +int pspCtrlPollControls(SceCtrlData *pad); + +#ifdef __cplusplus +} +#endif + +#endif // _PSP_FILEIO_H diff --git a/psp/psplib/font.c b/psp/psplib/font.c new file mode 100644 index 0000000..20d3485 --- /dev/null +++ b/psp/psplib/font.c @@ -0,0 +1,63 @@ +/* psplib/font.c + Rudimentary bitmap font implementation + + Copyright (C) 2007-2008 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: pspdev@akop.org +*/ + +#include "font.h" +#include "stockfont.h" + +int pspFontGetLineHeight(const PspFont *font) +{ + return font->Height; +} + +int pspFontGetTextWidth(const PspFont *font, const char *string) +{ + const unsigned char *ch; + int width, max, w; + + for (ch = (unsigned char*)string, width = 0, max = 0; *ch; ch++) + { + /* Tab = 4 spaces (TODO) */ + if (*ch == '\t') w = font->Chars[(unsigned char)' '].Width * 4; + /* Newline */ + else if (*ch == '\n') width = w = 0; + /* Special char */ + else if (*ch < 32) w = 0; + /* Normal char */ + else w = font->Chars[(unsigned char)(*ch)].Width; + + width += w; + if (width > max) max = width; + } + + return max; +} + +int pspFontGetTextHeight(const PspFont *font, const char *string) +{ + const char *ch; + int lines; + + for (ch = string, lines = 1; *ch; ch++) + if (*ch == '\n') lines++; + + return lines * font->Height; +} + diff --git a/psp/psplib/font.h b/psp/psplib/font.h new file mode 100644 index 0000000..a33b969 --- /dev/null +++ b/psp/psplib/font.h @@ -0,0 +1,90 @@ +/* psplib/font.h + Rudimentary bitmap font implementation + + Copyright (C) 2007-2008 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: pspdev@akop.org +*/ + +#ifndef _PSP_FONT_H +#define _PSP_FONT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define PSP_CHAR_ANALUP "\251" +#define PSP_CHAR_ANALDOWN "\252" +#define PSP_CHAR_ANALLEFT "\253" +#define PSP_CHAR_ANALRIGHT "\254" +#define PSP_CHAR_UP "\245" +#define PSP_CHAR_DOWN "\246" +#define PSP_CHAR_LEFT "\247" +#define PSP_CHAR_RIGHT "\250" +#define PSP_CHAR_SQUARE "\244" +#define PSP_CHAR_CROSS "\241" +#define PSP_CHAR_CIRCLE "\242" +#define PSP_CHAR_TRIANGLE "\243" +#define PSP_CHAR_LTRIGGER "\255" +#define PSP_CHAR_RTRIGGER "\256" +#define PSP_CHAR_SELECT "\257\260" +#define PSP_CHAR_START "\261\262" + +#define PSP_CHAR_UP_ARROW "\272" +#define PSP_CHAR_DOWN_ARROW "\273" + +#define PSP_CHAR_POWER "\267" +#define PSP_CHAR_EMPTY_BATT "\266" +#define PSP_CHAR_FULL_BATT "\263" +#define PSP_CHAR_FLOPPY "\274" + +#define PSP_CHAR_MS "\271" + +#define PSP_FONT_RESTORE 020 +#define PSP_FONT_BLACK 021 +#define PSP_FONT_RED 022 +#define PSP_FONT_GREEN 023 +#define PSP_FONT_BLUE 024 +#define PSP_FONT_GRAY 025 +#define PSP_FONT_YELLOW 026 +#define PSP_FONT_MAGENTA 027 +#define PSP_FONT_WHITE 030 + +struct PspFont +{ + unsigned char Height; + unsigned char Ascent; + struct + { + unsigned char Width; + unsigned short *Char; + } Chars[256]; +}; + +typedef struct PspFont PspFont; + +extern const PspFont PspStockFont; + +int pspFontGetLineHeight(const PspFont *font); +int pspFontGetTextWidth(const PspFont *font, const char *string); +int pspFontGetTextHeight(const PspFont *font, const char *string); + + +#ifdef __cplusplus +} +#endif + +#endif // _PSP_FONT_H diff --git a/psp/psplib/genfont.c b/psp/psplib/genfont.c new file mode 100644 index 0000000..a5d0385 --- /dev/null +++ b/psp/psplib/genfont.c @@ -0,0 +1,76 @@ +/* psplib/genfont.c + This file contains a simple font converter. It converts + 'fd' format fonts (by Simon Tatham) into array + used by the font rendering library + + Copyright (C) 2007-2008 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: pspdev@akop.org +*/ + +#include + +int main(int argc, char* argv) +{ + char line[256]; + int widths[256]; + int i,j,c; + + int ascent = 0; + int height = 0; + int ascii = 0; + int chars = 0; + + scanf("height %i\n", &height); + scanf("ascent %i\n", &ascent); + + printf("unsigned short _ch[][%i] = {\n", height); + + while (!feof(stdin)) + { + if (scanf("\nchar %d\n", &ascii) < 1 || chars > 255) + break; + + scanf("width %d\n", &widths[chars]); + + printf(" { "); + + for (i=0;i=0;j--) + if (line[j]=='1') + c|=1<<(widths[chars]-j-1); + + printf("0x%04x%s", c, (ixXX1%_)7w=2E z*THF$%F%kOtTqNqB&w@Y8mdT5E2KthR01W%2~|z2fDqwFC`fgAsJ7y&7NSx_t8BkB zGxxd91Da3?G0NPT`R1H&&Y3wgd+#`#zB|FZj4>Z_sl?cEl$65!dFjU}x^Mi-^Ea|% zH@tG|aZmdzw{{Q4vPwFW8puQvN;Hy8rgWuOQ!>LzC6-iLH+LzCRG(J2Y?(hOsXN*j zYxnrry0zhM7GSK>!`KYF-n-OO(ab6#M21x$qmO44+&XFlr*5e55(Q%&qH%PRalaT- zq#hJV2T2y95r)r1@F}M{T^rFc=HzvFkU@s8Haiqnzr8Ng7tte(y-c`*Omk6%Y)fHQ zAFk`oW(f+@qn;k+X_VDZ)x`uK_c;t1;=9o)3%)5Q@_FmCIs;n@@8{+#bMGxYjUZzA zDcy7W%{>>YpKZHPGqq4E^%vTBW7$18B&hLb;=;5q*bxY`*$ALNy)@xW;M+UDbqQmj z{wI#Zg(C+{(+GTGhbPdqiFH=|8SN&qRDmSC#r>gS_?EUdP4JIi2S=M5hF1xLiU+A* zs;qi#d}E1k^unn#?~Lb(_lCeY*C|z=`;C~SjdyXweo!@?KMR2l*m2G;>Yb<;4-#7F z4ptU9fpoTu%>65$JaVwa=2qejgeqZ7Ccl;m09tP1xQO zf|(}%s5ybT8E<}SxC(RpQ&QOm6*04g{A-{q9;9dC;AuQ_C+Nv`UZ2ZT#araX$@3Lh zHX*m_RN=MUc`xYlZ$RSbU?ktE&VA=KSXd>8Xr);otBgev!FZS~5i2T8o(p3#VB+to z<2l&Qw*qaJ2Md48ovd6(M}8)-caF;34eWL*&&{nmiF#qCaJpEDC@sxkYi((mq8+-T zF#Mn5aAl$AJk3`j6r9b06+0I@b{TC4q|!|X!eO>|ehT&RZNXb|?=DOuju|U#6Dl33 zL#41Xcok~_Ef>X{9DyyZ-8aG#dicn z!_;$6@>buHTj2Ep7H(?AhNwY-+Ord3WZr(TD z5~5RNx}{kZchdP@XK)=zm-ynih4O6*~O8Ps~>$#(a zGsn53>xHB1xuXrQ7oHd;2c96ZLhdpS2j-R{XfU6}O_dK7hXY-h(sNbC2Yp2kBF6K9 zr{c~xGYhcgrSac_kBz@b&n?f>Z+_wZ<1fRN+}USRZI@~$9DJpkW4sMB`6+3X_34AWrYO45fw zsSk~yuI#B*?zj!y%58V};mV%7{QhVvnbnn!YO!^qCz2o6k&>-(qYOZQX_)0d~yRHic#71@xUp zK8rky{2_8Bbb`pW$j!*D$Q{T=+G?x+FZy>dRUOdujE1l!?nbl|kyw)I8$4<(ksi)y zYFf{r{cJ@v5|5{%)c4Pd=+1#hV@WlZ)U`}95(nn>_Qm6BG^5w6>V}SnhP0MZ@gW=4 z@L8pK`!NP%_xlni$4`9e4AlFHk1fe)Mn}z(EWUgD*@K>YHGNa6Z#b@Pj3oQw8u=W) z@+>TDsDo8(IrQ#t>wKWCea&hPfaYo@pCt1zg;jVKXTHTQ!;G(20!hK^A@}&p20=X4 zi4RSq2^q6$R*bJ!0!Z77n*evJ>yO1T`Rp;|3;2x~@C<0lew-e4d@;GWvF!AQ!@V#q z6bLcXyZ^0R+IV~%3j3JoaO($%uZ7>h1)Xnwp*+*AbDrqQIR zFpZsN)r~Zrwh(#K5`c=6IbOy*YH9I%l3*z8Mw(u*5Xr2RG4C&9K4fW0=Iw5z zsoBz!%=Kl=2P_%E(?~Dc5VPhdH0VZ}I!rBeu@G{YGhce$g$$TIq`!hx&GgCEonD}w z$yoP^CGOSHO`ByTH130{)65z%9!_AGLo4-wj4YmT15xaRBLLXi#>{5&zTpG1S1ZG48=Sa z#g#rz%q!5Ps99{?iI!qHdz#buUZS65)BhBr> zSmtljZZpP=Gm0)!9B~+;HxLKX^r3~wm>;#6-EU3Ict=v8#Usib{czdn$1G;Km+8gW zIr>&hOTJk>1sU;X)gKws(6FV!WF$e5#nZ134kw53RRB~nOE2~rUSI@wx>|cj&hzT! z#^@fZxz1;KN*pz1$WCXHJfSpT?!_hEJWoL8V)J9f#;53eXyj5hOW%)QUS{nPBN9Bz zAni>52ftR61&&y4-0em}cUy>zI?|$K?aEQZFJq@P9zef?In?b&n&>Z&P8s?xbRdn- zxRJG!rWU%`?~q?crmq0XjQxc_MT81uULuyvzky81y;H$d@v+GQ9HDm-N`8!U7A4su zkd;8_+So$AP6!g+qzRb~QpQ45E~D6Fb^;*|OXi@|vY3BShCBzv_)ZaHy;LT128eO8 z37Nl>3=-{Ef&2@IHDjvycxK|g*YJG>iNaH1p{gZ!#4@R*vF`;>y_B(RUhhCumA>y) z8rt{g3uY+OpQ6QFIH0rCwgG7a>zJeIfknq_L1JFEk)y4kSx55SOcLT&XyA!4Dy0y!#2}13-w? zTAg14IqYCQ4rJ6sR0L2TMS?kp=wg3{%rQ$wUi2uA(cgoNwNFXw10Y0XjlPtOaWH?0 z5N404+klXwrPT~%KM)cXer-T?!h!Tqr-S(sAjZiiw2D9`9a=vELYvMS>(|8NK&F5k z0zw^v=T%f`e_6=8R7J9QN)7~*y6@Z6rgn6-ZE4-CcDA)| zZc*Fs>*_|lq1$d|FPu{8WlznLk3yiedvm8HpG-ik3uQhgCf~ILatY0w`_!E>A)F ziJ{Oan?X#DaZH<(=7qdO7F~R2oI6(59+ARv-M+N<(Xy?_s=)~>RB3l{m*j7j(Q;k$ z%MIk1^h<3bPRU=#j42RNW8WF^RHP4oE9j3$2C`Pn$kR~HeLU7Xgg-QB@inW}2uu|L dX_;^56Mg05Tz-Q%M#0}U=)=tjCS3;8e*wP+ScU)q literal 0 HcmV?d00001 diff --git a/psp/psplib/image.c b/psp/psplib/image.c new file mode 100644 index 0000000..b41deed --- /dev/null +++ b/psp/psplib/image.c @@ -0,0 +1,587 @@ +/* psplib/image.h + Image manipulation/saving/loading + + Copyright (C) 2007-2008 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: pspdev@akop.org +*/ + +#include +#include +#include +#include + +#include "video.h" +#include "image.h" + +typedef unsigned char byte; + +int FindPowerOfTwoLargerThan(int n); +int FindPowerOfTwoLargerThan2(int n); + +/* Creates an image in memory */ +PspImage* pspImageCreate(int width, int height, int bpp) +{ + if (bpp != PSP_IMAGE_INDEXED && bpp != PSP_IMAGE_16BPP) return NULL; + + int size = width * height * (bpp / 8); + void *pixels = memalign(16, size); + + if (!pixels) return NULL; + + PspImage *image = (PspImage*)malloc(sizeof(PspImage)); + + if (!image) + { + free(pixels); + return NULL; + } + + memset(pixels, 0, size); + + image->Width = width; + image->Height = height; + image->Pixels = pixels; + + image->Viewport.X = 0; + image->Viewport.Y = 0; + image->Viewport.Width = width; + image->Viewport.Height = height; + + int i; + for (i = 1; i < width; i *= 2); + image->PowerOfTwo = (i == width); + image->BytesPerPixel = bpp / 8; + image->FreeBuffer = 1; + image->Depth = bpp; + memset(image->Palette, 0, sizeof(image->Palette)); + image->PalSize = (unsigned short)256; + + switch (image->Depth) + { + case PSP_IMAGE_INDEXED: + image->TextureFormat = GU_PSM_T8; + break; + case PSP_IMAGE_16BPP: + image->TextureFormat = GU_PSM_5551; + break; + } + + return image; +} + +/* Creates an image using portion of VRAM */ +PspImage* pspImageCreateVram(int width, int height, int bpp) +{ + if (bpp != PSP_IMAGE_INDEXED && bpp != PSP_IMAGE_16BPP) return NULL; + + int i, size = width * height * (bpp / 8); + void *pixels = pspVideoAllocateVramChunk(size); + + if (!pixels) return NULL; + + PspImage *image = (PspImage*)malloc(sizeof(PspImage)); + if (!image) return NULL; + + memset(pixels, 0, size); + + image->Width = width; + image->Height = height; + image->Pixels = pixels; + + image->Viewport.X = 0; + image->Viewport.Y = 0; + image->Viewport.Width = width; + image->Viewport.Height = height; + + for (i = 1; i < width; i *= 2); + image->PowerOfTwo = (i == width); + image->BytesPerPixel = bpp >> 3; + image->FreeBuffer = 0; + image->Depth = bpp; + memset(image->Palette, 0, sizeof(image->Palette)); + image->PalSize = (unsigned short)256; + + switch (image->Depth) + { + case PSP_IMAGE_INDEXED: image->TextureFormat = GU_PSM_T8; break; + case PSP_IMAGE_16BPP: image->TextureFormat = GU_PSM_5551; break; + } + + return image; +} + +PspImage* pspImageCreateOptimized(int width, int height, int bpp) +{ + PspImage *image = pspImageCreate(FindPowerOfTwoLargerThan(width), height, bpp); + if (image) image->Viewport.Width = width; + + return image; +} + +/* Destroys image */ +void pspImageDestroy(PspImage *image) +{ + if (image->FreeBuffer) free(image->Pixels); + free(image); +} + +PspImage* pspImageRotate(const PspImage *orig, int angle_cw) +{ + PspImage *final; + + /* Create image of appropriate size */ + switch(angle_cw) + { + case 0: + return pspImageCreateCopy(orig); + case 90: + final = pspImageCreate(orig->Viewport.Height, + orig->Viewport.Width, orig->Depth); + break; + case 180: + final = pspImageCreate(orig->Viewport.Width, + orig->Viewport.Height, orig->Depth); + break; + case 270: + final = pspImageCreate(orig->Viewport.Height, + orig->Viewport.Width, orig->Depth); + break; + default: + return NULL; + } + + int i, j, k, di = 0; + int width = final->Width; + int height = final->Height; + int l_shift = orig->BytesPerPixel >> 1; + + const unsigned char *source = (unsigned char*)orig->Pixels; + unsigned char *dest = (unsigned char*)final->Pixels; + + /* Skip to Y viewport starting point */ + source += (orig->Viewport.Y * orig->Width) << l_shift; + + /* Copy image contents */ + for (i = 0, k = 0; i < orig->Viewport.Height; i++) + { + /* Skip to the start of the X viewport */ + source += orig->Viewport.X << l_shift; + + for (j = 0; j < orig->Viewport.Width; j++, source += 1 << l_shift, k++) + { + switch(angle_cw) + { + case 90: + di = (width - (k / height) - 1) + (k % height) * width; + break; + case 180: + di = (height - i - 1) * width + (width - j - 1); + break; + case 270: + di = (k / height) + (height - (k % height) - 1) * width; + break; + } + + /* Write to destination */ + if (orig->Depth == PSP_IMAGE_INDEXED) dest[di] = *source; + else ((unsigned short*)dest)[di] = *(unsigned short*)source; /* 16 bpp */ + } + + /* Skip to the end of the line */ + source += (orig->Width - (orig->Viewport.X + orig->Viewport.Width)) << l_shift; + } + + if (orig->Depth == PSP_IMAGE_INDEXED) + { + memcpy(final->Palette, orig->Palette, sizeof(orig->Palette)); + final->PalSize = orig->PalSize; + } + + return final; +} + +/* Creates a half-sized thumbnail of an image */ +PspImage* pspImageCreateThumbnail(const PspImage *image) +{ + PspImage *thumb; + int i, j, p; + + if (!(thumb = pspImageCreate(image->Viewport.Width >> 1, + image->Viewport.Height >> 1, image->Depth))) + return NULL; + + int dy = image->Viewport.Y + image->Viewport.Height; + int dx = image->Viewport.X + image->Viewport.Width; + + for (i = image->Viewport.Y, p = 0; i < dy; i += 2) + for (j = image->Viewport.X; j < dx; j += 2) + if (image->Depth == PSP_IMAGE_INDEXED) + ((unsigned char*)thumb->Pixels)[p++] + = ((unsigned char*)image->Pixels)[(image->Width * i) + j]; + else + ((unsigned short*)thumb->Pixels)[p++] + = ((unsigned short*)image->Pixels)[(image->Width * i) + j]; + + if (image->Depth == PSP_IMAGE_INDEXED) + { + memcpy(thumb->Palette, image->Palette, sizeof(image->Palette)); + thumb->PalSize = image->PalSize; + } + + return thumb; +} + +int pspImageDiscardColors(const PspImage *original) +{ + if (original->Depth != PSP_IMAGE_16BPP) return 0; + + int y, x, gray; + unsigned short *p; + + for (y = 0, p = (unsigned short*)original->Pixels; y < original->Height; y++) + for (x = 0; x < original->Width; x++, p++) + { + gray = (RED(*p) * 3 + GREEN(*p) * 4 + BLUE(*p) * 2) / 9; + *p = RGB(gray, gray, gray); + } + + return 1; +} + +int pspImageBlur(const PspImage *original, PspImage *blurred) +{ + if (original->Width != blurred->Width + || original->Height != blurred->Height + || original->Depth != blurred->Depth + || original->Depth != PSP_IMAGE_16BPP) return 0; + + int r, g, b, n, i, y, x, dy, dx; + unsigned short p; + + for (y = 0, i = 0; y < original->Height; y++) + { + for (x = 0; x < original->Width; x++, i++) + { + r = g = b = n = 0; + for (dy = y - 1; dy <= y + 1; dy++) + { + if (dy < 0 || dy >= original->Height) continue; + + for (dx = x - 1; dx <= x + 1; dx++) + { + if (dx < 0 || dx >= original->Width) continue; + + p = ((unsigned short*)original->Pixels)[dx + dy * original->Width]; + r += RED(p); + g += GREEN(p); + b += BLUE(p); + n++; + } + + r /= n; + g /= n; + b /= n; + ((unsigned short*)blurred->Pixels)[i] = RGB(r, g, b); + } + } + } + + return 1; +} + +/* Creates an exact copy of the image */ +PspImage* pspImageCreateCopy(const PspImage *image) +{ + PspImage *copy; + + /* Create image */ + if (!(copy = pspImageCreate(image->Width, image->Height, image->Depth))) + return NULL; + + /* Copy pixels */ + int size = image->Width * image->Height * image->BytesPerPixel; + memcpy(copy->Pixels, image->Pixels, size); + memcpy(©->Viewport, &image->Viewport, sizeof(PspViewport)); + memcpy(copy->Palette, image->Palette, sizeof(image->Palette)); + copy->PalSize = image->PalSize; + + return copy; +} + +/* Clears an image */ +void pspImageClear(PspImage *image, unsigned int color) +{ + if (image->Depth == PSP_IMAGE_INDEXED) + { + memset(image->Pixels, color & 0xff, image->Width * image->Height); + } + else if (image->Depth == PSP_IMAGE_16BPP) + { + int i; + unsigned short *pixel = image->Pixels; + for (i = image->Width * image->Height - 1; i >= 0; i--, pixel++) + *pixel = color & 0xffff; + } +} + +/* Loads an image from a file */ +PspImage* pspImageLoadPng(const char *path) +{ + FILE *fp = fopen(path,"rb"); + if(!fp) return NULL; + + PspImage *image = pspImageLoadPngFd(fp); + fclose(fp); + + return image; +} + +/* Saves an image to a file */ +int pspImageSavePng(const char *path, const PspImage* image) +{ + FILE *fp = fopen( path, "wb" ); + if (!fp) return 0; + + int stat = pspImageSavePngFd(fp, image); + fclose(fp); + + return stat; +} + +#define IRGB(r,g,b,a) (((((b)>>3)&0x1F)<<10)|((((g)>>3)&0x1F)<<5)|\ + (((r)>>3)&0x1F)|(a?0x8000:0)) + +/* Loads an image from an open file descriptor (16-bit PNG)*/ +PspImage* pspImageLoadPngFd(FILE *fp) +{ + const size_t nSigSize = 8; + byte signature[nSigSize]; + if (fread(signature, sizeof(byte), nSigSize, fp) != nSigSize) + return 0; + + if (!png_check_sig(signature, nSigSize)) + return 0; + + png_struct *pPngStruct = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if(!pPngStruct) + return 0; + + png_info *pPngInfo = png_create_info_struct(pPngStruct); + if(!pPngInfo) + { + png_destroy_read_struct(&pPngStruct, NULL, NULL); + return 0; + } + + if (setjmp(pPngStruct->jmpbuf)) + { + png_destroy_read_struct(&pPngStruct, NULL, NULL); + return 0; + } + + png_init_io(pPngStruct, fp); + png_set_sig_bytes(pPngStruct, nSigSize); + png_read_png(pPngStruct, pPngInfo, + PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | + PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_BGR , NULL); + + png_uint_32 width = pPngInfo->width; + png_uint_32 height = pPngInfo->height; + int color_type = pPngInfo->color_type; + + PspImage *image; + + int mod_width = FindPowerOfTwoLargerThan2(width); + if (!(image = pspImageCreate(mod_width, height, PSP_IMAGE_16BPP))) + { + png_destroy_read_struct(&pPngStruct, &pPngInfo, NULL); + return 0; + } + + image->Viewport.Width = width; + + png_byte **pRowTable = pPngInfo->row_pointers; + unsigned int x, y; + byte r, g, b, a; + unsigned short *out = image->Pixels; + + for (y=0; yViewport.Width; + height = image->Viewport.Height; + + if (!(bitmap = (u8*)malloc(sizeof(u8) * width * height * 3))) + return 0; + + if (image->Depth == PSP_IMAGE_INDEXED) + { + const unsigned char *pixel; + pixel = (unsigned char*)image->Pixels + (image->Viewport.Y * image->Width); + + for (i = 0; i < height; i++) + { + /* Skip to the start of the viewport */ + pixel += image->Viewport.X; + for (j = 0; j < width; j++, pixel++) + { + bitmap[i * width * 3 + j * 3 + 0] = RED(image->Palette[*pixel]); + bitmap[i * width * 3 + j * 3 + 1] = GREEN(image->Palette[*pixel]); + bitmap[i * width * 3 + j * 3 + 2] = BLUE(image->Palette[*pixel]); + } + /* Skip to the end of the line */ + pixel += image->Width - (image->Viewport.X + width); + } + } + else + { + const unsigned short *pixel; + pixel = (unsigned short*)image->Pixels + (image->Viewport.Y * image->Width); + + for (i = 0; i < height; i++) + { + /* Skip to the start of the viewport */ + pixel += image->Viewport.X; + for (j = 0; j < width; j++, pixel++) + { + bitmap[i * width * 3 + j * 3 + 0] = RED(*pixel); + bitmap[i * width * 3 + j * 3 + 1] = GREEN(*pixel); + bitmap[i * width * 3 + j * 3 + 2] = BLUE(*pixel); + } + /* Skip to the end of the line */ + pixel += image->Width - (image->Viewport.X + width); + } + } + + png_struct *pPngStruct = png_create_write_struct( PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL ); + + if (!pPngStruct) + { + free(bitmap); + return 0; + } + + png_info *pPngInfo = png_create_info_struct( pPngStruct ); + if (!pPngInfo) + { + png_destroy_write_struct( &pPngStruct, NULL ); + free(bitmap); + return 0; + } + + png_byte **buf = (png_byte**)malloc(height * sizeof(png_byte*)); + if (!buf) + { + png_destroy_write_struct( &pPngStruct, &pPngInfo ); + free(bitmap); + return 0; + } + + unsigned int y; + for (y = 0; y < height; y++) + buf[y] = (byte*)&bitmap[y * width * 3]; + + if (setjmp( pPngStruct->jmpbuf )) + { + free(buf); + free(bitmap); + png_destroy_write_struct( &pPngStruct, &pPngInfo ); + return 0; + } + + png_init_io( pPngStruct, fp ); + png_set_IHDR( pPngStruct, pPngInfo, width, height, 8, + PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + png_write_info( pPngStruct, pPngInfo ); + png_write_image( pPngStruct, buf ); + png_write_end( pPngStruct, pPngInfo ); + + png_destroy_write_struct( &pPngStruct, &pPngInfo ); + free(buf); + free(bitmap); + + return 1; +} + +int FindPowerOfTwoLargerThan(int n) +{ + int i; + for (i = n; i < n; i *= 2); + return i; +} + +int FindPowerOfTwoLargerThan2(int n) +{ + int i; + for (i = 1; i < n; i *= 2); + return i; +} diff --git a/psp/psplib/image.h b/psp/psplib/image.h new file mode 100644 index 0000000..ff1eb7d --- /dev/null +++ b/psp/psplib/image.h @@ -0,0 +1,81 @@ +/* psplib/image.h + Image manipulation/saving/loading + + Copyright (C) 2007-2008 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: pspdev@akop.org +*/ + +#ifndef _PSP_IMAGE_H +#define _PSP_IMAGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define PSP_IMAGE_INDEXED 8 +#define PSP_IMAGE_16BPP 16 + +typedef struct +{ + int X; + int Y; + int Width; + int Height; +} PspViewport; + +typedef struct +{ + int Width; + int Height; + void *Pixels; + PspViewport Viewport; + char FreeBuffer; + char BytesPerPixel; + char Depth; + char PowerOfTwo; + unsigned int TextureFormat; + /* TODO: don't allocate if not necessary */ + unsigned short __attribute__((aligned(16))) Palette[256]; + unsigned short PalSize; +} PspImage; + +/* Create/destroy */ +PspImage* pspImageCreate(int width, int height, int bits_per_pixel); +PspImage* pspImageCreateVram(int width, int height, int bits_per_pixel); +PspImage* pspImageCreateOptimized(int width, int height, int bpp); +void pspImageDestroy(PspImage *image); + +PspImage* pspImageRotate(const PspImage *orig, int angle_cw); +PspImage* pspImageCreateThumbnail(const PspImage *image); +PspImage* pspImageCreateCopy(const PspImage *image); +void pspImageClear(PspImage *image, unsigned int color); + +PspImage* pspImageLoadPng(const char *path); +int pspImageSavePng(const char *path, const PspImage* image); +PspImage* pspImageLoadPngFd(FILE *fp); +int pspImageSavePngFd(FILE *fp, const PspImage* image); + +int pspImageBlur(const PspImage *original, PspImage *blurred); +int pspImageDiscardColors(const PspImage *original); + +#ifdef __cplusplus +} +#endif + +#endif // _PSP_IMAGE_H diff --git a/psp/psplib/libpsplib.a b/psp/psplib/libpsplib.a new file mode 100644 index 0000000000000000000000000000000000000000..9220e6285e3cc98f9f2be419415c781619a3738a GIT binary patch literal 141546 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 literal 0 HcmV?d00001 diff --git a/psp/psplib/pl_file.c b/psp/psplib/pl_file.c new file mode 100644 index 0000000..be94278 --- /dev/null +++ b/psp/psplib/pl_file.c @@ -0,0 +1,332 @@ +/* psplib/pl_file.c + File and directory query routines + + Copyright (C) 2007-2009 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: dev@psp.akop.org +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "pl_file.h" + +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +static void + sort_file_list(pl_file_list *list, + int count); +static int + compare_files_by_name(const void *s1, + const void *s2); +static int + mkdir_recursive(const char *path); + +void pl_file_get_parent_directory(const char *path, + char *parent, + int length) +{ + int pos = strlen(path) - 1, + len; + + for (; pos >= 0 && path[pos] == '/'; pos--); + for (; pos >= 0 && path[pos] != '/'; pos--); + + if (pos < 0) + { + len = MIN(strlen(path), length - 1); + strncpy(parent, path, len); + parent[len] = '\0'; + return; + } + + len = MIN(pos + 1, length - 1); + strncpy(parent, path, len); + parent[len] = '\0'; +} + +const char* pl_file_get_filename(const char *path) +{ + const char *filename; + if (!(filename = strrchr(path, '/'))) + return path; + return filename + 1; +} + +const char* pl_file_get_extension(const char *path) +{ + const char *filename = pl_file_get_filename(path); + const char *ext; + if (!(ext = strrchr(filename, '.'))) + return filename + strlen(filename); + return ext + 1; +} + +int pl_file_rm(const char *path) +{ + return sceIoRemove(path) >= 0; +} + +/* Returns size of file in bytes or <0 if error */ +int pl_file_get_file_size(const char *path) +{ + SceIoStat stat; + memset(&stat, 0, sizeof(stat)); + if (sceIoGetstat(path, &stat) < 0) + return -1; + + return (int)stat.st_size; +} + +int pl_file_is_root_directory(const char *path) +{ + const char *pos = strchr(path, '/'); + return !pos || !(*(pos + 1)); +} + +int pl_file_exists(const char *path) +{ + SceIoStat stat; + return sceIoGetstat(path, &stat) == 0; +} + +int pl_file_is_of_type(const char *path, + const char *extension) +{ + int fn_len, ext_len; + const char *file_ext; + + fn_len = strlen(path); + ext_len = strlen(extension); + + /* Filename must be at least 2 chars longer (period + a char) */ + if (fn_len < ext_len + 2) + return 0; + + file_ext = path + (fn_len - ext_len); + if (*(file_ext - 1) == '.' && strcasecmp(file_ext, extension) == 0) + return 1; + + return 0; +} + +void pl_file_destroy_file_list(pl_file_list *list) +{ + pl_file *file, *next; + + for (file = list->files; file; file = next) + { + next = file->next; + free(file->name); + free(file); + } +} + +static int mkdir_recursive(const char *path) +{ + int exit_status = 1; + SceIoStat stat; + + if (sceIoGetstat(path, &stat) == 0) + /* If not a directory, cannot continue; otherwise success */ + return (stat.st_attr & FIO_SO_IFDIR); + + /* First, try creating its parent directory */ + char *slash_pos = strrchr(path, '/'); + if (!slash_pos); /* Top level */ + else if (slash_pos != path && slash_pos[-1] == ':'); /* Top level */ + else + { + char *parent = strdup(path); + parent[slash_pos - path] = '\0'; + exit_status = mkdir_recursive(parent); + + free(parent); + } + + if (exit_status && slash_pos[1] != '\0') + { + if (sceIoMkdir(path, 0777) != 0) + exit_status = 0; + } + + return exit_status; +} + +int pl_file_mkdir_recursive(const char *path) +{ + return mkdir_recursive(path); +} + +int pl_file_get_file_list_count(const pl_file_list *list) +{ + int count = 0; + pl_file *file; + + for (file = list->files; file; file = file->next) + count++; + return count; +} + +/* Returns number of files successfully read; negative number if error */ +int pl_file_get_file_list(pl_file_list *list, + const char *path, + const char **filter) +{ + SceUID fd = sceIoDopen(path); + if (fd < 0) return -1; + + SceIoDirent dir; + memset(&dir, 0, sizeof(dir)); + + pl_file *file, *last = NULL; + list->files = NULL; + + const char **pext; + int loop; + int count = 0; + + while (sceIoDread(fd, &dir) > 0) + { + if (filter && !(dir.d_stat.st_attr & FIO_SO_IFDIR)) + { + /* Loop through the list of allowed extensions and compare */ + for (pext = filter, loop = 1; *pext; pext++) + { + if (pl_file_is_of_type(dir.d_name, *pext)) + { + loop = 0; + break; + } + } + + if (loop) continue; + } + + /* Create a new file entry */ + if (!(file = (pl_file*)malloc(sizeof(pl_file)))) + { + pl_file_destroy_file_list(list); + return -1; + } + + file->name = strdup(dir.d_name); + file->next = NULL; + file->attrs = (dir.d_stat.st_attr & FIO_SO_IFDIR) + ? PL_FILE_DIRECTORY : 0; + + /* Update preceding element */ + if (last) last->next = file; + else list->files = file; + + last = file; + count++; + } + + sceIoDclose(fd); + + /* Sort the files by name */ + sort_file_list(list, count); + return count; +} + +static void sort_file_list(pl_file_list *list, + int count) +{ + pl_file **files, *file, **fp; + int i; + + if (count < 1) + return; + + /* Copy the file entries to an array */ + files = (pl_file**)malloc(sizeof(pl_file*) * count); + for (file = list->files, fp = files; file; file = file->next, i++, fp++) + *fp = file; + + /* Sort the array */ + qsort((void*)files, count, sizeof(pl_file*), compare_files_by_name); + + /* Rearrange the file entries in the list */ + list->files = files[0]; + list->files->next = NULL; + + for (i = 1; i < count; i++) + files[i - 1]->next = files[i]; + + pl_file *last = files[count - 1]; + last->next = NULL; + free(files); +} + +static int compare_files_by_name(const void *s1, const void *s2) +{ + pl_file *f1 = *(pl_file**)s1, *f2 = *(pl_file**)s2; + if ((f1->attrs & PL_FILE_DIRECTORY) == (f2->attrs & PL_FILE_DIRECTORY)) + return strcasecmp(f1->name, f2->name); + else if (f1->attrs & PL_FILE_DIRECTORY) + return -1; + else return 1; +} + +int pl_file_open_directory(const char *path, + const char *subdir, + char *result, + int result_len) +{ + /* This routine should be made more robust */ + /* to accept subdirs like ../../ etc... */ + int path_len = strlen(path); + int copy_len; + + /* Ascend one level */ + if (strcmp(subdir, "..") == 0) + { + pl_file_get_parent_directory(path, + result, + result_len); + return 1; + } + else + { + copy_len = MIN(result_len - 1, strlen(subdir) + path_len + 2); + snprintf(result, copy_len, "%s%s/", path, subdir); + result[copy_len] = '\0'; + return 1; + } + + /* If we're here, then we couldn't figure out final path */ + /* Just copy the original path */ + copy_len = MIN(result_len - 1, path_len); + strncpy(result, path, copy_len); + result[copy_len] = '\0'; + + return (strcmp(subdir, ".") == 0); +} + +int pl_file_is_directory(const char *path) +{ + int len; + if ((len = strlen(path)) < 1) + return 0; + return (path[len - 1] == '/'); +} diff --git a/psp/psplib/pl_file.h b/psp/psplib/pl_file.h new file mode 100644 index 0000000..c31eb7b --- /dev/null +++ b/psp/psplib/pl_file.h @@ -0,0 +1,76 @@ +/* psplib/file.h + File and directory query routines + + Copyright (C) 2007-2009 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: dev@psp.akop.org +*/ + +#ifndef _PL_FILE_H +#define _PL_FILE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define PL_FILE_DIRECTORY 0x01 +#define PL_FILE_MAX_PATH_LEN 1024 + +typedef char pl_file_path[PL_FILE_MAX_PATH_LEN]; + +typedef struct pl_file_t +{ + char *name; + unsigned char attrs; + struct pl_file_t *next; +} pl_file; + +typedef struct pl_file_list_t +{ + struct pl_file_t *files; +} pl_file_list; + +void pl_file_get_parent_directory(const char *path, + char *parent, + int length); +const char* + pl_file_get_filename(const char *path); +const char* + pl_file_get_extension(const char *path); +int pl_file_get_file_size(const char *path); +int pl_file_exists(const char *path); +int pl_file_rm(const char *path); +int pl_file_open_directory(const char *path, + const char *subdir, + char *result, + int result_len); +int pl_file_is_directory(const char *path); +int pl_file_is_root_directory(const char *path); +int pl_file_is_of_type(const char *path, + const char *extension); +int pl_file_mkdir_recursive(const char *path); +/* Returns number of files successfully read; <0 if error */ +int pl_file_get_file_list(pl_file_list *list, + const char *path, + const char **filter); +void pl_file_destroy_file_list(pl_file_list *list); +int pl_file_get_file_list_count(const pl_file_list *list); + +#ifdef __cplusplus +} +#endif + +#endif // _PL_FILE_H diff --git a/psp/psplib/pl_gfx.c b/psp/psplib/pl_gfx.c new file mode 100644 index 0000000..cd59066 --- /dev/null +++ b/psp/psplib/pl_gfx.c @@ -0,0 +1,221 @@ +/* psplib/pl_gfx.c + Graphics rendering routines + + Copyright (C) 2007-2009 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: dev@psp.akop.org +*/ + +#include +#include +#include +#include + +#include "pl_gfx.h" +#include "pl_image.h" + +#define SLICE_SIZE 16 +#define BUF_WIDTH 512 +#define VRAM_START 0x04000000 +#define VRAM_UNCACHED 0x40000000 + +typedef struct pl_gfx_vertex_t +{ + unsigned short u, v; + unsigned short color; + short x, y, z; +} pl_gfx_vertex; + +static unsigned int get_bytes_per_pixel(unsigned int format); +static unsigned int get_texture_format(pl_image_format format); + +static void *_vram_alloc_ptr = NULL; +static void *_disp_buffer = NULL; +static void *_draw_buffer = NULL; +static void *_depth_buffer = NULL; +static unsigned int _format = 0; + +static unsigned int __attribute__((aligned(16))) _disp_list[262144]; + +static unsigned int get_bytes_per_pixel(unsigned int format) +{ + switch (format) + { + case GU_PSM_5650: + case GU_PSM_5551: + case GU_PSM_4444: + return 2; + case GU_PSM_8888: + return 4; + case GU_PSM_T8: + return 1; + default: + return 0; + } +} + +static unsigned int get_texture_format(pl_image_format format) +{ + switch (format) + { + case pl_image_indexed: + return GU_PSM_T8; + case pl_image_5551: + return GU_PSM_5551; + case pl_image_4444: + return GU_PSM_4444; + default: + return 0; + } +} + +int pl_gfx_init(unsigned int format) +{ + unsigned int bytes_per_pixel = + get_bytes_per_pixel(format); + unsigned int vram_offset = 0; + + if (!bytes_per_pixel) return 0; + + _format = 0; + _vram_alloc_ptr = (void*)(VRAM_START|VRAM_UNCACHED|0x00088000); + + /* Initialize draw buffer */ + int size = bytes_per_pixel * BUF_WIDTH * PL_GFX_SCREEN_HEIGHT; + _draw_buffer = (void*)vram_offset; + vram_offset += size; + /* TODO: bpp was originally 4 instead of 2 here */ + _disp_buffer = (void*)vram_offset; + vram_offset += size; + _depth_buffer = (void*)vram_offset; + vram_offset += size; + + sceGuInit(); + sceGuStart(GU_DIRECT, _disp_list); + sceGuDrawBuffer(format, + _draw_buffer, + BUF_WIDTH); + sceGuDispBuffer(PL_GFX_SCREEN_WIDTH, + PL_GFX_SCREEN_HEIGHT, + _disp_buffer, + BUF_WIDTH); + sceGuDepthBuffer(_depth_buffer, + BUF_WIDTH); + sceGuDisable(GU_TEXTURE_2D); + sceGuOffset(0, 0); + sceGuViewport(PL_GFX_SCREEN_WIDTH/2, + PL_GFX_SCREEN_HEIGHT/2, + PL_GFX_SCREEN_WIDTH, + PL_GFX_SCREEN_HEIGHT); + sceGuDepthRange(0xc350, 0x2710); + sceGuDisable(GU_ALPHA_TEST); + sceGuBlendFunc(GU_ADD, + GU_SRC_ALPHA, + GU_ONE_MINUS_SRC_ALPHA, + 0, 0); + sceGuEnable(GU_BLEND); + sceGuDisable(GU_DEPTH_TEST); + sceGuEnable(GU_CULL_FACE); + sceGuDisable(GU_LIGHTING); + sceGuFrontFace(GU_CW); +/* TODO: sceGuScissor(0, 0, SCR_WIDTH, SCR_HEIGHT); */ +/* sceGuEnable(GU_SCISSOR_TEST); */ + sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT); + sceGuAmbientColor(0xffffffff); + sceGuFinish(); + sceGuSync(0,0); + sceGuDisplay(GU_TRUE); + + return 1; +} + +void pl_gfx_shutdown() +{ + sceGuTerm(); +} + +void* pl_gfx_vram_alloc(unsigned int bytes) +{ + void *ptr = _vram_alloc_ptr; + _vram_alloc_ptr += bytes; + + /* Align pointer to 16 bytes */ + int rem = (unsigned int)_vram_alloc_ptr & 15; + if (rem != 0) + _vram_alloc_ptr += 16 - rem; + + return ptr; +} + +void pl_video_put_image(const pl_image *image, + int dx, + int dy, + int dw, + int dh) +{ + sceKernelDcacheWritebackAll(); + sceGuEnable(GU_TEXTURE_2D); + + /* TODO: Rewrite so that any format is rendered */ + if (image->format == pl_image_indexed) + { + sceGuClutMode(get_texture_format(image->palette.format), + 0, 0xff, 0); + sceGuClutLoad(image->palette.colors >> 3, + image->palette.palette); + } + + sceGuTexMode(get_texture_format(image->format), + 0, 0, GU_FALSE); + sceGuTexImage(0, + image->line_width, + image->line_width, + image->line_width, + image->bitmap); + sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); + sceGuTexFilter(GU_LINEAR, GU_LINEAR); + + pl_gfx_vertex *vertices; + int start, end, sc_end, slsz_scaled; + slsz_scaled = ceil((float)dw * (float)SLICE_SIZE) / (float)image->view.w; + + start = image->view.x; + end = image->view.x + image->view.w; + sc_end = dx + dw; + + for (; start < end; start += SLICE_SIZE, dx += slsz_scaled) + { + vertices = (pl_gfx_vertex*)sceGuGetMemory(2 * sizeof(pl_gfx_vertex)); + + vertices[0].u = start; + vertices[0].v = image->view.y; + vertices[1].u = start + SLICE_SIZE; + vertices[1].v = image->view.h + image->view.y; + + vertices[0].x = dx; vertices[0].y = dy; + vertices[1].x = dx + slsz_scaled; vertices[1].y = dy + dh; + + vertices[0].color + = vertices[1].color + = vertices[0].z + = vertices[1].z = 0; + + sceGuDrawArray(GU_SPRITES, + GU_TEXTURE_16BIT|GU_COLOR_5551|GU_VERTEX_16BIT|GU_TRANSFORM_2D,2,0,vertices); + } + + sceGuDisable(GU_TEXTURE_2D); +} diff --git a/psp/psplib/pl_gfx.h b/psp/psplib/pl_gfx.h new file mode 100644 index 0000000..4331991 --- /dev/null +++ b/psp/psplib/pl_gfx.h @@ -0,0 +1,41 @@ +/* psplib/pl_gfx.h + Graphics routines + + Copyright (C) 2007-2009 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: dev@psp.akop.org +*/ + +#ifndef _PL_GFX_H +#define _PL_GFX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define PL_GFX_SCREEN_WIDTH 480 +#define PL_GFX_SCREEN_HEIGHT 272 + +int pl_gfx_init(); +void pl_gfx_shutdown(); + +void* pl_gfx_vram_alloc(unsigned int bytes); + +#ifdef __cplusplus +} +#endif + +#endif // PL_GFX_H diff --git a/psp/psplib/pl_image.c b/psp/psplib/pl_image.c new file mode 100644 index 0000000..bbf8c86 --- /dev/null +++ b/psp/psplib/pl_image.c @@ -0,0 +1,735 @@ +/* psplib/pl_image.h + Image manipulation/saving/loading + + Copyright (C) 2007-2009 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: dev@psp.akop.org +*/ + +#include +#include +#include + +#include "pl_image.h" +#include "pl_file.h" + +#ifdef PSP +#include "pl_gfx.h" +#endif + +static uint get_next_power_of_two(uint n); +static uint get_bitmap_size(const pl_image *image); +int copy_from_void(pl_image_format format, + const void *from, + uint32_t *to); +int copy_to_void(pl_image_format format, + uint32_t from, + void *to); + +int pl_image_create(pl_image *image, + uint width, + uint height, + pl_image_format format, + uint8_t flags) +{ + uint bytes_per_pixel = pl_image_get_bytes_per_pixel(format); + if (!bytes_per_pixel) + return 0; + + /* Allocate memory */ + uint line_width = get_next_power_of_two(width); + uint pitch = line_width * bytes_per_pixel; + uint buf_len = pitch * height; + void *buffer = NULL; + +#ifdef PSP + if (flags & PL_IMAGE_USE_VRAM) /* use VRAM */ + buffer = pl_gfx_vram_alloc(buf_len); + else /* use heap */ +#endif + buffer = memalign(16, buf_len); + + if (!buffer) return 0; + + memset(buffer, 0, buf_len); + + /* Init. structure */ + image->view.x = image->view.y = 0; + image->view.w = width; + image->view.h = height; + image->height = height; + image->line_width = line_width; + image->pitch = pitch; + image->format = format; + image->flags = flags; + image->bitmap = buffer; + + image->palette.palette = NULL; + image->palette.colors = 0; + image->palette.format = 0; + + return 1; +} + +void pl_image_destroy(pl_image *image) +{ + /* Release bitmap */ + if (!(image->flags & PL_IMAGE_USE_VRAM)) + free(image->bitmap); + + /* Release palette */ + if (image->palette.palette) + free(image->palette.palette); +} + +int pl_image_palettize(pl_image *image, + pl_image_format pal_format, + uint pal_colors) +{ + if ((image->format != pl_image_indexed) || /* palette only valid for indexed images */ + (pal_colors == 0) || /* need at least 1 color */ + (pal_colors & 15) || /* number of colors must be divisible by 16 */ + (pal_format == pl_image_indexed)) /* 'indexed' not valid for palette format */ + return 0; + + /* Allocate pal. space */ + uint bytes_per_pixel = pl_image_get_bytes_per_pixel(pal_format); + void *palette; + if (!(palette = memalign(16, bytes_per_pixel * pal_colors))) + return 0; + + /* Release current pal. */ + if (image->palette.palette) + free(image->palette.palette); + + /* Reset image pal. */ + image->palette.format = pal_format; + image->palette.colors = pal_colors; + image->palette.palette = palette; + + return 1; +} + +int pl_image_set_palette_color(pl_image *image, + uint index, + uint32_t color) +{ + if (image->format != pl_image_indexed || + index > image->palette.colors) + return 0; + + switch (image->palette.format) + { + case pl_image_4444: + case pl_image_5551: + ((uint16_t*)(image->palette.palette))[index] = color & 0xffff; + return 1; + default: + return 0; + } +} + +int pl_image_create_duplicate(const pl_image *original, + pl_image *copy) +{ + /* create image */ + if (!pl_image_create(copy, + original->line_width, + original->height, + original->format, + 0)) /* TODO: all but vram flag */ + return 0; + + /* copy palette */ + if (original->palette.palette) + { + if (!pl_image_palettize(copy, + original->palette.format, + original->palette.colors)) + { + pl_image_destroy(copy); + return 0; + } + + uint pal_size = copy->palette.colors * + pl_image_get_bytes_per_pixel(copy->palette.format); + memcpy(copy->palette.palette, + original->palette.palette, + pal_size); + } + + /* copy image */ + memcpy(copy->bitmap, + original->bitmap, + get_bitmap_size(copy)); + + /* copy misc. attributes */ + copy->view = original->view; + + return 1; +} + +int pl_image_compose_color(pl_image_format dest_format, + uint32_t *color, + uint8_t red, + uint8_t green, + uint8_t blue, + uint8_t alpha) +{ + switch (dest_format) + { + case pl_image_indexed: + /* TODO: indexed color? */ + return 0; + case pl_image_4444: + *color = (((alpha >> 4) & 0x0F) << 12) | + (((blue >> 4) & 0x0F) << 8) | + (((green >> 4) & 0x0F) << 4) | + ((red >> 4) & 0x0F); + return 1; + case pl_image_5551: + *color = (((alpha >> 7) & 0x01) << 15) | + (((blue >> 3) & 0x1F) << 10) | + (((green >> 3) & 0x1F) << 5) | + ((red >> 3) & 0x1F); + return 1; + default: + return 0; + } +} + +int pl_image_split_color(pl_image_format src_format, + const pl_image_palette *src_palette, + uint32_t color, + uint8_t *red, + uint8_t *green, + uint8_t *blue, + uint8_t *alpha) +{ + switch (src_format) + { + case pl_image_indexed: + /* Palette's format may not be indexed */ + if (src_palette->format == pl_image_indexed) + return 0; + + /* Get actual color */ + copy_from_void(src_palette->format, + src_palette->palette + color * + pl_image_get_bytes_per_pixel(src_palette->format), + &color); + + /* Split color */ + return pl_image_split_color(src_palette->format, + NULL, + color, + red, + green, + blue, + alpha); + case pl_image_4444: + *red = (color & 0x0F) * 0xFF/0x0F; + *green = ((color >> 4) & 0x0F) * 0xFF/0x0F; + *blue = ((color >> 8) & 0x0F) * 0xFF/0x0F; + *alpha = ((color >> 12) & 0x0F) * 0xFF/0x0F; + return 1; + case pl_image_5551: + *red = (color & 0x1F) * 0xFF/0x1F; + *green = ((color >> 5) & 0x1F) * 0xFF/0x1F; + *blue = ((color >> 10) & 0x1F) * 0xFF/0x1F; + *alpha = ((color >> 15) & 0x01) * 0xFF/0x01; + return 1; + default: + return 0; + } +} + +int pl_image_load_png_stream(pl_image *image, + FILE *stream) +{ + /* hardcoded for now */ + pl_image_format format = pl_image_5551; + + const size_t nSigSize = 8; + uint8_t signature[nSigSize]; + if (fread(signature, sizeof(uint8_t), nSigSize, stream) != nSigSize) + return 0; + + if (!png_check_sig(signature, nSigSize)) + return 0; + + png_struct *pPngStruct = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if(!pPngStruct) + return 0; + + png_info *pPngInfo = png_create_info_struct(pPngStruct); + if(!pPngInfo) + { + png_destroy_read_struct(&pPngStruct, NULL, NULL); + return 0; + } + + if (setjmp(pPngStruct->jmpbuf)) + { + png_destroy_read_struct(&pPngStruct, NULL, NULL); + return 0; + } + + png_init_io(pPngStruct, stream); + png_set_sig_bytes(pPngStruct, nSigSize); + png_read_png(pPngStruct, pPngInfo, + PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | + PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_BGR , NULL); + + png_uint_32 width = pPngInfo->width; + png_uint_32 height = pPngInfo->height; + int color_type = pPngInfo->color_type; + + if (!pl_image_create(image, + width, + height, + format, + 0)) + { + png_destroy_read_struct(&pPngStruct, &pPngInfo, NULL); + return 0; + } + + png_byte **pRowTable = pPngInfo->row_pointers; + unsigned int x, y; + uint8_t r, g, b, a; + uint32_t color; + int bytes_per_pixel = pl_image_get_bytes_per_pixel(format); + void *line_ptr, *pel_ptr; + + for (y = 0, line_ptr = image->bitmap; + y < height; + y++, line_ptr += image->pitch) + { + png_byte *pRow = pRowTable[y]; + + for (x = 0, pel_ptr = line_ptr; + x < width; + x++, pel_ptr += bytes_per_pixel) + { + switch(color_type) + { + case PNG_COLOR_TYPE_GRAY: + r = g = b = *pRow++; + a = 0xff; + break; + case PNG_COLOR_TYPE_GRAY_ALPHA: + r = g = b = pRow[0]; + a = pRow[1]; + pRow += 2; + break; + case PNG_COLOR_TYPE_RGB: + b = pRow[0]; + g = pRow[1]; + r = pRow[2]; + a = 0xff; + pRow += 3; + break; + case PNG_COLOR_TYPE_RGB_ALPHA: + b = pRow[0]; + g = pRow[1]; + r = pRow[2]; + a = pRow[3]; + pRow += 4; + break; + default: + r = g = b = a = 0; + break; + } + + pl_image_compose_color(format, &color, r, g, b, a); + copy_to_void(format, color, pel_ptr); + } + } + + png_destroy_read_struct(&pPngStruct, &pPngInfo, NULL); + + return 1; +} + +int pl_image_save_png_stream(const pl_image *image, + FILE *stream) +{ + unsigned char *bitmap; + int i, j; + uint8_t r, g, b, a; + int width = image->view.w; + int height = image->view.h; + int bytes_per_pixel = pl_image_get_bytes_per_pixel(image->format); + void *line_ptr, *pel_ptr; + uint32_t color; + + if (!(bitmap = (u8*)malloc(sizeof(u8) * width * height * 3))) + return 0; + + for (i = 0, line_ptr = image->bitmap + (image->view.y * image->pitch); + i < height; + i++, line_ptr += image->pitch) + { + /* Skip to the start of the viewport */ + for (j = 0, pel_ptr = line_ptr + (image->view.x * bytes_per_pixel); + j < width; + j++, pel_ptr += bytes_per_pixel) + { + copy_from_void(image->format, pel_ptr, &color); + pl_image_split_color(image->format, + &image->palette, + color, + &r,&g,&b,&a); + + bitmap[i * width * 3 + j * 3 + 0] = r; + bitmap[i * width * 3 + j * 3 + 1] = g; + bitmap[i * width * 3 + j * 3 + 2] = b; + } + } + + png_struct *pPngStruct = png_create_write_struct( PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL ); + + if (!pPngStruct) + { + free(bitmap); + return 0; + } + + png_info *pPngInfo = png_create_info_struct( pPngStruct ); + if (!pPngInfo) + { + png_destroy_write_struct( &pPngStruct, NULL ); + free(bitmap); + return 0; + } + + png_byte **buf = (png_byte**)malloc(height * sizeof(png_byte*)); + if (!buf) + { + png_destroy_write_struct( &pPngStruct, &pPngInfo ); + free(bitmap); + return 0; + } + + unsigned int y; + for (y = 0; y < height; y++) + buf[y] = (uint8_t*)&bitmap[y * width * 3]; + + if (setjmp( pPngStruct->jmpbuf )) + { + free(buf); + free(bitmap); + png_destroy_write_struct( &pPngStruct, &pPngInfo ); + return 0; + } + + png_init_io( pPngStruct, stream ); + png_set_IHDR( pPngStruct, pPngInfo, width, height, 8, + PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + png_write_info( pPngStruct, pPngInfo ); + png_write_image( pPngStruct, buf ); + png_write_end( pPngStruct, pPngInfo ); + + png_destroy_write_struct( &pPngStruct, &pPngInfo ); + free(buf); + free(bitmap); + + return 1; +} + +int pl_image_load(pl_image *image, + const char *path) +{ + int status = 0; + FILE *stream = NULL; + + if (pl_file_is_of_type(path, "png")) + { + if ((stream = fopen(path, "r"))) + status = pl_image_load_png_stream(image, + stream); + } + else status = 0; + + if (stream) fclose(stream); + return status; +} + +int pl_image_save(const pl_image *image, + const char *path) +{ + int status = 0; + FILE *stream = NULL; + + if (pl_file_is_of_type(path, "png")) + { + if ((stream = fopen(path, "w"))) + status = pl_image_save_png_stream(image, + stream); + } + else status = 0; + + if (stream) fclose(stream); + return status; +} + +int pl_image_clear(pl_image *image, + uint8_t red, + uint8_t green, + uint8_t blue, + uint8_t alpha) +{ + uint32_t color; + int x, y; + void *line_ptr, *pel_ptr; + uint bytes_per_pixel = pl_image_get_bytes_per_pixel(image->format); + + if (!pl_image_compose_color(image->format, + &color, + red, + green, + blue, + alpha)) + return 0; + + for (y = 0, line_ptr = image->bitmap; + y < image->height; + y++, line_ptr += image->pitch) + { + for (x = 0, pel_ptr = line_ptr; + x < image->line_width; + x++, pel_ptr += bytes_per_pixel) + { + copy_to_void(image->format, + color, + pel_ptr); + } + } + + return 1; +} + +int pl_image_create_thumbnail(const pl_image *original, + pl_image *thumb) +{ + /* create image */ + if (!pl_image_create(thumb, + original->view.w / 2, + original->view.h / 2, + original->format, + 0)) /* TODO: all but vram flag */ + return 0; + + /* copy palette */ + if (original->format == pl_image_indexed && + original->palette.palette) + { + if (!pl_image_palettize(thumb, + original->palette.format, + original->palette.colors)) + { + pl_image_destroy(thumb); + return 0; + } + + uint pal_size = thumb->palette.colors * + pl_image_get_bytes_per_pixel(thumb->palette.format); + memcpy(thumb->palette.palette, + original->palette.palette, + pal_size); + } + + int x, y; + uint32_t color; + uint bytes_per_pixel = + pl_image_get_bytes_per_pixel(original->format); + void *slp = original->bitmap + original->view.y * original->pitch; + void *spp; + void *dlp = thumb->bitmap; + void *dpp; + + /* copy bitmap */ + for (y = 0; + y < thumb->view.h; + y++, dlp += thumb->pitch, slp += (original->pitch << 1)) + { + for (x = 0, dpp = dlp, spp = slp + original->view.x * bytes_per_pixel; + x < thumb->view.w; + x++, dpp += bytes_per_pixel, spp += (bytes_per_pixel << 1)) + { + copy_from_void(original->format, spp, &color); + copy_to_void(thumb->format, color, dpp); + } + } + + return 1; +} + +#if 0 +int pl_image_rotate(const pl_image *original, + pl_image *rotated, + int angle_cw) +{ + int status = 0; + + /* Create image */ + switch(angle_cw) + { + case 0: /* just duplicate */ + return pl_image_create_duplicate(original, + rotated); + case 90: + case 270: + status = pl_image_create(rotated, + original->view.h, + original->view.w, + original->format, + 0); + break; + case 180: + status = pl_image_create(rotated, + original->view.w, + original->view.h, + original->format, + 0); + break; + default: + return 0; + } + + if (!status) return 0; + + /* copy palette */ + if (original->format == pl_image_indexed && + original->palette.palette) + { + if (!pl_image_palettize(rotated, + original->palette.format, + original->palette.colors)) + { + pl_image_destroy(rotated); + return 0; + } + + uint pal_size = rotated->palette.colors * + pl_image_get_bytes_per_pixel(rotated->palette.format); + memcpy(rotated->palette.palette, + original->palette.palette, + pal_size); + } + + int x, y; + uint32_t color; + uint bytes_per_pixel = + pl_image_get_bytes_per_pixel(original->format); + void *slp = original->bitmap + original->view.y * original->pitch; + void *spp, *dpp; + + /* copy bitmap */ + for (y = 0; + y < original->view.h; + y++, slp += original->pitch) + { + for (x = 0, spp = slp + original->view.x * bytes_per_pixel; + x < original->view.w; + x++, spp += bytes_per_pixel) + { + copy_from_void(original->format, spp, &color); + switch(angle_cw) + { + case 90: +/* + dpp = rotated->bitmap + (rotated->line_width - (k / rotated->height) - 1) * + rotated->pitch; + dpp += (k % rotated->height) * rotated->pitch; +*/ +// di = (width - (k / height) - 1) + (k % height) * width; + break; + case 180: +/* +(height - i - 1) * width + +(width - j - 1); +*/ + dpp = rotated->bitmap + (rotated->height - y - 1) * rotated->pitch; + dpp += (rotated->line_width - x - 1) * bytes_per_pixel; + break; + case 270: +// di = (k / height) + (height - (k % height) - 1) * width; + break; + } + copy_to_void(rotated->format, color, dpp); + } + } + + return 1; +} +#endif + +static uint get_next_power_of_two(uint n) +{ + uint i; + for (i = 0x10; i < n; i <<= 1); + return i; +} + +static uint get_bitmap_size(const pl_image *image) +{ + return image->pitch * image->height; +} + +int copy_from_void(pl_image_format format, + const void *from, + uint32_t *to) +{ + switch (pl_image_get_bytes_per_pixel(format)) + { + case 1: + *to = *(uint8_t*)from; + return 1; + case 2: + *to = *(uint16_t*)from; + return 1; + case 4: + *to = *(uint32_t*)from; + default: + return 0; + } +} + +int copy_to_void(pl_image_format format, + uint32_t from, + void *to) +{ + switch (pl_image_get_bytes_per_pixel(format)) + { + case 1: + *(uint8_t*)to = (uint8_t)from; + return 1; + case 2: + *(uint16_t*)to = (uint16_t)from; + return 1; + case 4: + *(uint32_t*)to = (uint32_t)from; + return 1; + default: + return 0; + } +} diff --git a/psp/psplib/pl_image.h b/psp/psplib/pl_image.h new file mode 100644 index 0000000..3a97284 --- /dev/null +++ b/psp/psplib/pl_image.h @@ -0,0 +1,139 @@ +/* psplib/pl_image.h + Image manipulation/saving/loading + + Copyright (C) 2007-2009 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: dev@psp.akop.org +*/ + +#ifndef _PL_IMAGE_H +#define _PL_IMAGE_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PL_IMAGE_USE_VRAM 0x01 + +#define uint unsigned int + +typedef enum pl_image_format_t +{ + pl_image_indexed = 0x01, /* & 0x07 gives */ + pl_image_4444 = 0x02, /* bytes per pixel */ + pl_image_5551 = 0x12, +} pl_image_format; + +typedef struct pl_image_palette_t +{ + void *palette; + uint colors; + pl_image_format + format; +} pl_image_palette; + +typedef struct pl_image_view_t +{ + uint x; + uint y; + uint w; + uint h; +} pl_image_view; + +typedef struct pl_image_t +{ + pl_image_view + view; + uint height; + uint line_width; + uint pitch; + pl_image_format + format; + pl_image_palette + palette; + uint8_t flags; + void *bitmap; +} pl_image; + +int pl_image_create(pl_image *image, + uint width, + uint height, + pl_image_format format, + uint8_t flags); +void pl_image_destroy(pl_image *image); + +int pl_image_palettize(pl_image *image, + pl_image_format pal_format, + uint pal_colors); +int pl_image_set_palette_color(pl_image *image, + uint index, + uint32_t color); + +uint pl_image_get_depth(const pl_image *image); + +int pl_image_compose_color(pl_image_format dest_format, + uint32_t *color, + uint8_t red, + uint8_t green, + uint8_t blue, + uint8_t alpha); +int pl_image_split_color(pl_image_format src_format, + const pl_image_palette *src_palette, + uint32_t color, + uint8_t *red, + uint8_t *green, + uint8_t *blue, + uint8_t *alpha); + +int pl_image_load_png_stream(pl_image *image, + FILE *stream); +int pl_image_save_png_stream(const pl_image *image, + FILE *stream); + +int pl_image_load(pl_image *image, + const char *path); +int pl_image_save(const pl_image *image, + const char *path); + +int pl_image_create_duplicate(const pl_image *original, + pl_image *copy); +int pl_image_create_thumbnail(const pl_image *original, + pl_image *thumb); + +#define pl_image_get_bytes_per_pixel(format) \ + ((format) & 0x07) + +int pl_image_clear(pl_image *image, + uint8_t red, + uint8_t green, + uint8_t blue, + uint8_t alpha); +#if 0 +int pl_image_rotate(const pl_image *original, + pl_image *rotated, + int angle_cw); +#endif + +#undef uint + +#ifdef __cplusplus +} +#endif + +#endif // _PL_IMAGE_H diff --git a/psp/psplib/pl_ini.c b/psp/psplib/pl_ini.c new file mode 100644 index 0000000..c8d58e2 --- /dev/null +++ b/psp/psplib/pl_ini.c @@ -0,0 +1,373 @@ +/* psplib/pl_ini.h + INI file reading/writing + + Copyright (C) 2007-2009 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: dev@psp.akop.org +*/ + +#include "pl_ini.h" + +#include +#include +#include +#include + +#define PL_MAX_LINE_LENGTH 512 + +typedef struct pl_ini_pair_t +{ + char *key; + char *value; + struct pl_ini_pair_t *next; +} pl_ini_pair; + +typedef struct pl_ini_section_t +{ + char *name; + struct pl_ini_pair_t *head; + struct pl_ini_section_t *next; +} pl_ini_section; + +static pl_ini_section* create_section(const char *name); +static pl_ini_pair* create_pair(char *string); +static pl_ini_section* find_section(const pl_ini_file *file, + const char *section_name); +static pl_ini_pair* find_pair(const pl_ini_section *section, + const char *key_name); +static pl_ini_pair* locate(const pl_ini_file *file, + const char *section_name, + const char *key_name); +static pl_ini_pair* locate_or_create(pl_ini_file *file, + const char *section_name, + const char *key_name); + +int pl_ini_create(pl_ini_file *file) +{ + file->head = NULL; + return 1; +} + +int pl_ini_load(pl_ini_file *file, + const char *path) +{ + file->head = NULL; + + FILE *stream; + if (!(stream = fopen(path, "r"))) + return 0; + + pl_ini_section *current_section = NULL; + pl_ini_pair *tail; + + char string[PL_MAX_LINE_LENGTH], + name[PL_MAX_LINE_LENGTH]; + char *ptr; + int len; + + /* Create unnamed section */ + current_section = NULL; + tail = NULL; + + while(!feof(stream) && fgets(string, sizeof(string), stream)) + { + /* TODO: Skip whitespace */ + /* New section */ + if (string[0] == '[') + { + if ((ptr = strrchr(string, ']'))) + { + len = ptr - string - 1; + strncpy(name, string + 1, len); + name[len] = '\0'; + + if (!current_section) + current_section = file->head = create_section(name); + else + { + current_section->next = create_section(name); + current_section = current_section->next; + } + + tail = NULL; + } + } + else if (string[0] =='#'); /* Do nothing - comment */ + else + { + /* No section defined - create empty section */ + if (!current_section) + { + current_section = create_section(strdup("")); + file->head = current_section; + tail = NULL; + } + + pl_ini_pair *pair = create_pair(string); + if (pair) + { + if (tail) tail->next = pair; + else current_section->head = pair; + tail = pair; + } + } + } + + fclose(stream); + return 1; +} + +int pl_ini_save(const pl_ini_file *file, + const char *path) +{ + FILE *stream; + if (!(stream = fopen(path, "w"))) + return 0; + + pl_ini_section *section; + pl_ini_pair *pair; + + for (section = file->head; section; section = section->next) + { + fprintf(stream, "[%s]\n", section->name); + for (pair = section->head; pair; pair = pair->next) + fprintf(stream, "%s=%s\n", pair->key, pair->value); + } + + fclose(stream); + return 1; +} + +int pl_ini_get_int(const pl_ini_file *file, + const char *section, + const char *key, + int default_value) +{ + pl_ini_pair *pair = locate(file, section, key); + return (pair) ? atoi(pair->value) : default_value; +} + +int pl_ini_get_string(const pl_ini_file *file, + const char *section, + const char *key, + const char *default_value, + char *copy_to, + int dest_len) +{ + pl_ini_pair *pair = locate(file, section, key); + if (pair) + { + strncpy(copy_to, pair->value, dest_len); + return 1; + } + else if (default_value) + { + strncpy(copy_to, default_value, dest_len); + return 1; + } + + return 0; +} + +void pl_ini_set_int(pl_ini_file *file, + const char *section, + const char *key, + int value) +{ + pl_ini_pair *pair; + if (!(pair = locate_or_create(file, section, key))) + return; + + /* Replace the value */ + if (pair->value) + free(pair->value); + + char temp[64]; + snprintf(temp, 63, "%i", value); + pair->value = strdup(temp); +} + +void pl_ini_set_string(pl_ini_file *file, + const char *section, + const char *key, + const char *string) +{ + pl_ini_pair *pair; + if (!(pair = locate_or_create(file, section, key))) + return; + + /* Replace the value */ + if (pair->value) + free(pair->value); + pair->value = strdup(string); +} + +void pl_ini_destroy(pl_ini_file *file) +{ + pl_ini_section *section, *next_section; + pl_ini_pair *pair, *next_pair; + + for (section = file->head; section; section = next_section) + { + next_section = section->next; + + if (section->name) + free(section->name); + for (pair = section->head; pair; pair = next_pair) + { + next_pair = pair->next; + if (pair->key) + free(pair->key); + if (pair->value) + free(pair->value); + free(pair); + } + + free(section); + } +} + +static pl_ini_section* find_section(const pl_ini_file *file, + const char *section_name) +{ + pl_ini_section *section; + for (section = file->head; section; section = section->next) + if (strcmp(section_name, section->name) == 0) + return section; + + return NULL; +} + +static pl_ini_pair* find_pair(const pl_ini_section *section, + const char *key_name) +{ + pl_ini_pair *pair; + for (pair = section->head; pair; pair = pair->next) + if (strcmp(pair->key, key_name) == 0) + return pair; + + return NULL; +} + +static pl_ini_pair* locate(const pl_ini_file *file, + const char *section_name, + const char *key_name) +{ + pl_ini_section *section; + if (!(section = find_section(file, section_name))) + return NULL; + + return find_pair(section, key_name); +} + +static pl_ini_pair* locate_or_create(pl_ini_file *file, + const char *section_name, + const char *key_name) +{ + pl_ini_section *section = find_section(file, section_name); + pl_ini_pair *pair = NULL; + + if (section) + pair = find_pair(section, key_name); + else + { + /* Create section */ + section = create_section(section_name); + + if (!file->head) + file->head = section; + else + { + pl_ini_section *s; + for (s = file->head; s->next; s = s->next); /* Find the tail */ + s->next = section; + } + } + + if (!pair) + { + /* Create pair */ + pair = (pl_ini_pair*)malloc(sizeof(pl_ini_pair)); + pair->key = strdup(key_name); + pair->value = NULL; + pair->next = NULL; + + if (!section->head) + section->head = pair; + else + { + pl_ini_pair *p; + for (p = section->head; p->next; p = p->next); /* Find the tail */ + p->next = pair; + } + } + + return pair; +} + +static pl_ini_section* create_section(const char *name) +{ + pl_ini_section *section + = (pl_ini_section*)malloc(sizeof(pl_ini_section)); + section->head = NULL; + section->next = NULL; + section->name = strdup(name); + + return section; +} + +static pl_ini_pair* create_pair(char *string) +{ + char *ptr; + if (!(ptr = strchr(string, '='))) + return NULL; + + int len; + char *name, *value; + + /* Copy NAME */ + len = ptr - string; + if (!(name = (char*)malloc(sizeof(char) * (len + 1)))) + return NULL; + strncpy(name, string, len); + name[len] = '\0'; + + /* Copy VALUE */ + if (!(value = strdup(ptr + 1))) + { + free(name); + return NULL; + } + + len = strlen(value); + if (value[len - 1] == '\n') value[len - 1] = '\0'; + + /* Create struct */ + pl_ini_pair *pair = (pl_ini_pair*)malloc(sizeof(pl_ini_pair)); + + if (!pair) + { + free(name); + free(value); + return NULL; + } + + pair->key = name; + pair->value = value; + pair->next = NULL; + + return pair; +} diff --git a/psp/psplib/pl_ini.h b/psp/psplib/pl_ini.h new file mode 100644 index 0000000..00f6c7d --- /dev/null +++ b/psp/psplib/pl_ini.h @@ -0,0 +1,65 @@ +/* psplib/pl_ini.h + INI file reading/writing + + Copyright (C) 2007-2009 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: dev@psp.akop.org +*/ + +#ifndef _PL_INI_H +#define _PL_INI_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct pl_ini_section_t; + +typedef struct pl_ini_file_t +{ + struct pl_ini_section_t *head; +} pl_ini_file; + +int pl_ini_create(pl_ini_file *file); +void pl_ini_destroy(pl_ini_file *file); +int pl_ini_load(pl_ini_file *file, + const char *path); +int pl_ini_save(const pl_ini_file *file, + const char *path); +int pl_ini_get_int(const pl_ini_file *file, + const char *section, + const char *key, + const int default_value); +void pl_ini_set_int(pl_ini_file *file, + const char *section, + const char *key, + int value); +int pl_ini_get_string(const pl_ini_file *file, + const char *section, + const char *key, + const char *default_value, + char *copy_to, + int dest_len); +void pl_ini_set_string(pl_ini_file *file, + const char *section, + const char *key, + const char *string); + +#ifdef __cplusplus +} +#endif + +#endif // _PL_INI_H diff --git a/psp/psplib/pl_menu.c b/psp/psplib/pl_menu.c new file mode 100644 index 0000000..3af4e6b --- /dev/null +++ b/psp/psplib/pl_menu.c @@ -0,0 +1,351 @@ +/* psplib/pl_menu.c + Simple menu implementation + + Copyright (C) 2007-2009 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: dev@psp.akop.org +*/ + +#include +#include + +#include "pl_menu.h" + +static void + destroy_item(pl_menu_item *item); +static pl_menu_item* + find_last_item(const pl_menu *menu); +static pl_menu_option* + find_last_option(const pl_menu_item *item); + +int pl_menu_create(pl_menu *menu, + const pl_menu_def *def) +{ + menu->items = NULL; + menu->selected = NULL; + + /* No definition; nothing more to do */ + if (!def) return 1; + + pl_menu_item *item; + + /* Initialize menu */ + for (; def->id || def->caption; def++) + { + /* Append the item */ + item = pl_menu_append_item(menu, + def->id, + def->caption); + + if (item) + { + /* Add the options */ + if (def->options) + { + const pl_menu_option_def *option_def; + for (option_def = def->options; option_def->text; option_def++) + pl_menu_append_option(item, + option_def->text, + option_def->value, 0); + } + + /* Set help text */ + item->help_text = (def->help_text) + ? strdup(def->help_text) : NULL; + } + } + + return 1; +} + +void pl_menu_destroy(pl_menu *menu) +{ + pl_menu_clear_items(menu); +} + +void pl_menu_clear_items(pl_menu *menu) +{ + pl_menu_item *item, *next; + + for (item = menu->items; item; item = next) + { + next = item->next; + destroy_item(item); + } + + menu->items = NULL; + menu->selected = NULL; +} + +int pl_menu_remove_item(pl_menu *menu, + pl_menu_item *which) +{ + pl_menu_item *item; + int found = 0; + + /* Make sure the item is in the menu */ + for (item = menu->items; item; item = item->next) + if (item == which) + { found = 1; break; } + if (!found) return 0; + + /* Redirect pointers */ + if (item->prev) + item->prev->next = item->next; + else + menu->items = item->next; + + if (item->next) + item->next->prev = item->prev; + + if (menu->selected == item) + menu->selected = item->next; + + /* Destroy the item */ + destroy_item(item); + + return 1; +} + +static void destroy_item(pl_menu_item *item) +{ + if (item->caption) + free(item->caption); + if (item->help_text) + free(item->help_text); + + pl_menu_clear_options(item); + free(item); +} + +void pl_menu_clear_options(pl_menu_item *item) +{ + pl_menu_option *option, *next; + + for (option = item->options; option; option = next) + { + next = option->next; + free(option->text); + free(option); + } + + item->selected = NULL; + item->options = NULL; +} + +static pl_menu_item* find_last_item(const pl_menu *menu) +{ + if (!menu->items) + return NULL; + + pl_menu_item *item; + for (item = menu->items; item->next; item = item->next); + + return item; +} + +static pl_menu_option* find_last_option(const pl_menu_item *item) +{ + if (!item->options) + return NULL; + + pl_menu_option *option; + for (option = item->options; option->next; option = option->next); + + return option; +} + +pl_menu_item* pl_menu_append_item(pl_menu *menu, + unsigned int id, + const char *caption) +{ + pl_menu_item* item = (pl_menu_item*)malloc(sizeof(pl_menu_item)); + if (!item) return NULL; + + if (!caption) + item->caption = NULL; + else + { + if (!(item->caption = strdup(caption))) + { + free(item); + return NULL; + } + } + + pl_menu_item *last = find_last_item(menu); + item->help_text = NULL; + item->id = id; + item->param = NULL; + item->options = NULL; + item->selected = NULL; + item->next = NULL; + item->prev = last; + + if (last) + last->next = item; + else + menu->items = item; + + return item; +} + +pl_menu_item* pl_menu_find_item_by_index(const pl_menu *menu, + int index) +{ + pl_menu_item *item; + int i = 0; + + for (item = menu->items; item; item = item->next, i++) + if (i == index) + return item; + + return NULL; +} + +pl_menu_item* pl_menu_find_item_by_id(const pl_menu *menu, + unsigned int id) +{ + pl_menu_item *item; + for (item = menu->items; item; item = item->next) + if (item->id == id) + return item; + + return NULL; +} + +int pl_menu_get_item_count(const pl_menu *menu) +{ + int i = 0; + pl_menu_item *item = menu->items; + for (; item; item = item->next) i++; + return i; +} + +pl_menu_option* pl_menu_append_option(pl_menu_item *item, + const char *text, + const void *value, + int select) +{ + pl_menu_option *option; + if (!(option = (pl_menu_option*)malloc(sizeof(pl_menu_option)))) + return NULL; + + if (!(option->text = strdup(text))) + { + free(option); + return NULL; + } + + option->value = value; + option->next = NULL; + + if (item->options) + { + pl_menu_option *last = find_last_option(item); + last->next = option; + option->prev = last; + } + else + { + item->options = option; + option->prev = NULL; + } + + if (select) + item->selected = option; + + return option; +} + +pl_menu_option* pl_menu_find_option_by_index(const pl_menu_item *item, + int index) +{ + int i; + pl_menu_option *option; + + for (i = 0, option = item->options; + option && (i <= index); + i++, option = option->next) + if (i == index) + return option; + + return NULL; +} + +pl_menu_option* pl_menu_find_option_by_value(const pl_menu_item *item, + const void *value) +{ + pl_menu_option *option; + for (option = item->options; option; option = option->next) + if (option->value == value) + return option; + + return NULL; +} + +pl_menu_option* pl_menu_select_option_by_index(pl_menu_item *item, + int index) +{ + pl_menu_option *option = pl_menu_find_option_by_index(item, + index); + if (!option) + return NULL; + + return (item->selected = option); +} + +pl_menu_option* pl_menu_select_option_by_value(pl_menu_item *item, + const void *value) +{ + pl_menu_option *option = pl_menu_find_option_by_value(item, + value); + if (!option) + return NULL; + + return (item->selected = option); +} + +int pl_menu_update_option(pl_menu_option *option, + const char *text, + const void *value) +{ + if (option->text) + free(option->text); + + option->text = (text) ? strdup(text) : NULL; + option->value = value; + + return (!text || option->text); +} + +int pl_menu_set_item_caption(pl_menu_item *item, + const char *caption) +{ + if (item->caption) + free(item->caption); + item->caption = (caption) ? strdup(caption) : NULL; + return (!caption || item->caption); +} + +int pl_menu_set_item_help_text(pl_menu_item *item, + const char *help_text) +{ + if (item->help_text) + free(item->help_text); + item->help_text = (help_text) ? strdup(help_text) : NULL; + return (!help_text || item->help_text); +} diff --git a/psp/psplib/pl_menu.h b/psp/psplib/pl_menu.h new file mode 100644 index 0000000..ad90d2a --- /dev/null +++ b/psp/psplib/pl_menu.h @@ -0,0 +1,132 @@ +/* psplib/pl_menu.h + Simple menu implementation + + Copyright (C) 2007-2009 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: dev@psp.akop.org +*/ + +#ifndef _PL_MENU_H +#define _PL_MENU_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct pl_menu_option_t +{ + char *text; + const void *value; + struct pl_menu_option_t *prev; + struct pl_menu_option_t *next; +} pl_menu_option; + +typedef struct pl_menu_item_t +{ + unsigned int id; + char *caption; + char *help_text; + const void *param; + struct pl_menu_option_t *selected; + struct pl_menu_option_t *options; + struct pl_menu_item_t *prev; + struct pl_menu_item_t *next; +} pl_menu_item; + +typedef struct pl_menu_t +{ + struct pl_menu_item_t *selected; + struct pl_menu_item_t *items; +} pl_menu; + +#define PL_MENU_ITEMS_BEGIN(ident) \ + pl_menu_def ident[] = { +#define PL_MENU_HEADER(text) \ + {0,"\t"text,NULL,NULL}, +#define PL_MENU_ITEM(caption,id,option_list,help) \ + {id,caption,help,option_list}, +#define PL_MENU_ITEMS_END \ + {0,NULL,NULL,NULL}}; + +#define PL_MENU_OPTIONS_BEGIN(ident) \ + pl_menu_option_def ident[] = { +#define PL_MENU_OPTION(text,param) \ + {text,(const void*)(param)}, +#define PL_MENU_OPTIONS_END \ + {NULL,NULL}}; + +typedef struct pl_menu_option_def_t +{ + const char *text; + const void *value; +} pl_menu_option_def; + +typedef struct pl_menu_def_t +{ + unsigned int id; + const char *caption; + const char *help_text; + pl_menu_option_def *options; +} pl_menu_def; + +int pl_menu_create(pl_menu *menu, + const pl_menu_def *def); +void pl_menu_destroy(pl_menu *menu); +void pl_menu_clear_items(pl_menu *menu); +pl_menu_item* + pl_menu_append_item(pl_menu *menu, + unsigned int id, + const char *caption); +pl_menu_item* + pl_menu_find_item_by_index(const pl_menu *menu, + int index); +pl_menu_item* + pl_menu_find_item_by_id(const pl_menu *menu, + unsigned int id); +int pl_menu_remove_item(pl_menu *menu, + pl_menu_item *which); +int pl_menu_get_item_count(const pl_menu *menu); +int pl_menu_set_item_caption(pl_menu_item *item, + const char *caption); +int pl_menu_set_item_help_text(pl_menu_item *item, + const char *help_text); +void pl_menu_clear_options(pl_menu_item *item); +pl_menu_option* + pl_menu_append_option(pl_menu_item *item, + const char *text, + const void *value, + int select); +pl_menu_option* + pl_menu_find_option_by_index(const pl_menu_item *item, + int index); +pl_menu_option* + pl_menu_find_option_by_value(const pl_menu_item *item, + const void *value); +pl_menu_option* + pl_menu_select_option_by_index(pl_menu_item *item, + int index); +pl_menu_option* + pl_menu_select_option_by_value(pl_menu_item *item, + const void *value); +int pl_menu_update_option(pl_menu_option *option, + const char *text, + const void *value); + +#ifdef __cplusplus +} +#endif + +#endif // _PL_MENU_H diff --git a/psp/psplib/pl_perf.c b/psp/psplib/pl_perf.c new file mode 100644 index 0000000..086b056 --- /dev/null +++ b/psp/psplib/pl_perf.c @@ -0,0 +1,52 @@ +/* psplib/pl_perf.c + Performance benchmarking + + Copyright (C) 2007-2009 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: dev@psp.akop.org +*/ + +#include +#include + +#include "pl_perf.h" + +void pl_perf_init_counter(pl_perf_counter *counter) +{ + counter->fps = 0; + counter->frame_count = 0; + counter->ticks_per_second = (float)sceRtcGetTickResolution(); + sceRtcGetCurrentTick(&counter->last_tick); +} + +float pl_perf_update_counter(pl_perf_counter *counter) +{ + u64 current_tick; + sceRtcGetCurrentTick(¤t_tick); + + counter->frame_count++; + if (current_tick - counter->last_tick >= + counter->ticks_per_second) + { + /* A second elapsed; recompute FPS */ + counter->fps = (float)counter->frame_count + / (float)((current_tick - counter->last_tick) / counter->ticks_per_second); + counter->last_tick = current_tick; + counter->frame_count = 0; + } + + return counter->fps; +} diff --git a/psp/psplib/pl_perf.h b/psp/psplib/pl_perf.h new file mode 100644 index 0000000..3d59797 --- /dev/null +++ b/psp/psplib/pl_perf.h @@ -0,0 +1,46 @@ +/* psplib/pl_perf.h + Performance benchmarking + + Copyright (C) 2007-2009 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: dev@psp.akop.org +*/ + +#ifndef _PL_PERF_H +#define _PL_PERF_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct pl_perf_counter_t +{ + float ticks_per_second; + int frame_count; + u64 last_tick; + float fps; +} pl_perf_counter; + +void pl_perf_init_counter(pl_perf_counter *counter); +float pl_perf_update_counter(pl_perf_counter *counter); + +#ifdef __cplusplus +} +#endif + +#endif // _PL_PERF_H diff --git a/psp/psplib/pl_psp.c b/psp/psplib/pl_psp.c new file mode 100644 index 0000000..4f3d995 --- /dev/null +++ b/psp/psplib/pl_psp.c @@ -0,0 +1,127 @@ +/* psplib/pl_psp.c + Platform init/shutdown and various system routines + + Copyright (C) 2007-2009 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: dev@psp.akop.org +*/ + +#include +#include +#include +#include + +#include "pl_psp.h" + +typedef struct pl_psp_callback_t +{ + void (*handler)(void *param); + void *param; +} pl_psp_callback; + +static char _app_directory[1024]; +static pl_psp_callback _exit_callback; +int ExitPSP; + +static int _callback_thread(SceSize args, void* argp); +static int _callback(int arg1, int arg2, void* common); + +int pl_psp_init(const char *app_path) +{ + ExitPSP = 0; + + char *pos; + if (!(pos = strrchr(app_path, '/'))) + _app_directory[0] = '\0'; + else + { + strncpy(_app_directory, app_path, pos - app_path + 1); + _app_directory[pos - app_path + 1] = '\0'; + } + + _exit_callback.handler = NULL; + _exit_callback.param = NULL; + + return 1; +} + +const char* pl_psp_get_app_directory() +{ + return _app_directory; +} + +void pl_psp_shutdown() +{ + sceKernelExitGame(); +} + +void pl_psp_set_clock_freq(int freq) +{ + if (freq < 222) freq = 222; + else if (freq > 333) freq = 333; + scePowerSetClockFrequency(freq, freq, freq/2); +} + +static int _callback(int arg1, int arg2, void* common) +{ + pl_psp_callback *callback = (pl_psp_callback*)common; + callback->handler(callback->param); + + return 0; +} + +static int _callback_thread(SceSize args, void* argp) +{ + int cbid; + + if (_exit_callback.handler) + { + cbid = sceKernelCreateCallback("Exit Callback", _callback, &_exit_callback); + sceKernelRegisterExitCallback(cbid); + } + + sceKernelSleepThreadCB(); + return 0; +} + +int pl_psp_register_callback(pl_callback_type type, + void (*func)(void *param), + void *param) +{ + switch (type) + { + case PSP_EXIT_CALLBACK: + _exit_callback.handler = func; + _exit_callback.param = param; + break; + default: + return 0; + } + + return 1; +} + +int pl_psp_start_callback_thread() +{ + int thid; + + if ((thid = sceKernelCreateThread("update_thread", _callback_thread, 0x11, 0xFA0, 0, 0)) < 0) + return 0; + + sceKernelStartThread(thid, 0, NULL); + + return thid; +} diff --git a/psp/psplib/pl_psp.h b/psp/psplib/pl_psp.h new file mode 100644 index 0000000..78b4cbe --- /dev/null +++ b/psp/psplib/pl_psp.h @@ -0,0 +1,50 @@ +/* psplib/pl_psp.h + Platform init/shutdown and various system routines + + Copyright (C) 2007-2009 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: dev@psp.akop.org +*/ + +#ifndef _PL_PSP_H +#define _PL_PSP_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + PSP_EXIT_CALLBACK +} pl_callback_type; + +extern int ExitPSP; + +int pl_psp_init(const char *app_path); +void pl_psp_shutdown(); +void pl_psp_set_clock_freq(int freq); +const char* pl_psp_get_app_directory(); + +int pl_psp_register_callback(pl_callback_type type, + void (*func)(void *param), + void *param); +int pl_psp_start_callback_thread(); + +#ifdef __cplusplus +} +#endif + +#endif // _PL_PSP_H diff --git a/psp/psplib/pl_rewind.c b/psp/psplib/pl_rewind.c new file mode 100644 index 0000000..b3ba803 --- /dev/null +++ b/psp/psplib/pl_rewind.c @@ -0,0 +1,195 @@ +/* psplib/pl_rewind.c + State rewinding routines + + Copyright (C) 2009 Akop Karapetyan + Based on code by DaveX (efengeler@gmail.com) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: dev@psp.akop.org +*/ + +#include +#include + +#include "pl_rewind.h" + +typedef struct rewind_state +{ + void *data; + struct rewind_state *prev; + struct rewind_state *next; +} rewind_state_t; + +static int get_free_memory(); + +int pl_rewind_init(pl_rewind *rewind, + int (*save_state)(void *), + int (*load_state)(void *), + int (*get_state_size)()) +{ + float memory_needed = (float)get_free_memory() * 0.85; + int state_data_size = get_state_size(); + int state_count = (int)(memory_needed + / (float)(state_data_size + sizeof(rewind_state_t))); + + if (state_count < 1) + return 0; + + /* First state */ + rewind_state_t *prev, *curr = NULL; + if (!(rewind->start = (rewind_state_t*)malloc(sizeof(rewind_state_t)))) + return 0; + + if (!(rewind->start->data = malloc(state_data_size))) + { + free(rewind->start); + rewind->start = NULL; + return 0; + } + + prev = rewind->start; + + /* The rest */ + int i; + for (i = 1; i < state_count; i++) + { + /* If allocation fails, compose a shorter state chain */ + if (!(curr = (rewind_state_t*)malloc(sizeof(rewind_state_t)))) + { + state_count = i + 1; + break; + } + + /* If allocation fails, compose a shorter state chain */ + if (!(curr->data = malloc(state_data_size))) + { + state_count = i + 1; + free(curr); + break; + } + + prev->next = curr; + curr->prev = prev; + prev = curr; + } + + /* Make circular */ + rewind->start->prev = prev; + curr->next = rewind->start; + + /* Init structure */ + rewind->current = NULL; + rewind->save_state = save_state; + rewind->load_state = load_state; + rewind->get_state_size = get_state_size; + rewind->state_data_size = state_data_size; + rewind->state_count = state_count; + + return 1; +} + +void pl_rewind_realloc(pl_rewind *rewind) +{ + pl_rewind_destroy(rewind); + pl_rewind_init(rewind, + rewind->save_state, + rewind->load_state, + rewind->get_state_size); +} + +void pl_rewind_destroy(pl_rewind *rewind) +{ + rewind->start->prev->next = NULL; /* Prevent infinite loop */ + rewind_state_t *curr, *next; + + for (curr = rewind->start; curr; curr = next) + { + next = curr->next; + free(curr->data); + free(curr); + } + + rewind->start = NULL; + rewind->current = NULL; +} + +void pl_rewind_reset(pl_rewind *rewind) +{ + rewind->current = NULL; +} + +int pl_rewind_save(pl_rewind *rewind) +{ + rewind_state_t *save_slot = + (rewind->current) ? rewind->current->next + : rewind->start; + + if (!rewind->save_state(save_slot->data)) + return 0; + + rewind->current = save_slot; + + /* Move starting point forward, if we've reached the start node */ + if (save_slot->next == rewind->start) + rewind->start = rewind->start->next; + + return 1; +} + +int pl_rewind_restore(pl_rewind *rewind) +{ + rewind_state_t *load_slot = rewind->current; + if (!(load_slot && rewind->load_state(load_slot->data))) + return 0; + + /* Can't go past the starting point */ + if (load_slot != rewind->start) + rewind->current = rewind->current->prev; + + return 1; +} + +static int get_free_memory() +{ + const int + chunk_size = 65536, // 64 kB + chunks = 1024; // 65536 * 1024 = 64 MB + void *mem_reserv[chunks]; + int total_mem = 0, i; + + /* Initialize */ + for (i = 0; i < chunks; i++) + mem_reserv[i] = NULL; + + /* Allocate */ + for (i = 0; i < chunks; i++) + { + if (!(mem_reserv[i] = malloc(chunk_size))) + break; + + total_mem += chunk_size; + } + + /* Free */ + for (i = 0; i < chunks; i++) + { + if (!mem_reserv[i]) + break; + free(mem_reserv[i]); + } + + return total_mem; +} + diff --git a/psp/psplib/pl_rewind.h b/psp/psplib/pl_rewind.h new file mode 100644 index 0000000..9272e79 --- /dev/null +++ b/psp/psplib/pl_rewind.h @@ -0,0 +1,57 @@ +/* psplib/pl_rewind.h + State rewinding routines + + Copyright (C) 2009 Akop Karapetyan + Based on code by DaveX (efengeler@gmail.com) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: dev@psp.akop.org +*/ + +#ifndef _PL_REWIND_H +#define _PL_REWIND_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct rewind_state; + +typedef struct +{ + int state_data_size; + int state_count; + struct rewind_state *start; + struct rewind_state *current; + int (*save_state)(void *); + int (*load_state)(void *); + int (*get_state_size)(); +} pl_rewind; + +int pl_rewind_init(pl_rewind *rewind, + int (*save_state)(void *), + int (*load_state)(void *), + int (*get_state_size)()); +void pl_rewind_realloc(pl_rewind *rewind); +void pl_rewind_destroy(pl_rewind *rewind); +void pl_rewind_reset(pl_rewind *rewind); +int pl_rewind_save(pl_rewind *rewind); +int pl_rewind_restore(pl_rewind *rewind); + +#ifdef __cplusplus +} +#endif + +#endif // _PL_REWIND_H diff --git a/psp/psplib/pl_snd.c b/psp/psplib/pl_snd.c new file mode 100644 index 0000000..3704efa --- /dev/null +++ b/psp/psplib/pl_snd.c @@ -0,0 +1,328 @@ +/* psplib/pl_snd.c + Simple sound playback library + + Copyright (C) 2007-2009 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: dev@psp.akop.org +*/ + +#include "pl_snd.h" + +#include +#include +#include +#include +#include + +#define AUDIO_CHANNELS 1 +#define DEFAULT_SAMPLES 512 +#define VOLUME_MAX 0x8000 + +static int sound_ready; +static volatile int sound_stop; + +typedef struct { + int thread_handle; + int sound_ch_handle; + int left_vol; + int right_vol; + pl_snd_callback callback; + void *user_data; + short *sample_buffer[2]; + unsigned int samples[2]; + unsigned char paused; + unsigned char stereo; +} pl_snd_channel_info; + +static pl_snd_channel_info sound_stream[AUDIO_CHANNELS]; + +static int channel_thread(int args, void *argp); +static void free_buffers(); +static unsigned int get_bytes_per_sample(int channel); + +int pl_snd_init(int sample_count, + int stereo) +{ + int i, j, failed; + sound_stop = 0; + sound_ready = 0; + + /* Check sample count */ + if (sample_count <= 0) sample_count = DEFAULT_SAMPLES; + sample_count = PSP_AUDIO_SAMPLE_ALIGN(sample_count); + + pl_snd_channel_info *ch_info; + for (i = 0; i < AUDIO_CHANNELS; i++) + { + ch_info = &sound_stream[i]; + ch_info->sound_ch_handle = -1; + ch_info->thread_handle = -1; + ch_info->left_vol = VOLUME_MAX; + ch_info->right_vol = VOLUME_MAX; + ch_info->callback = NULL; + ch_info->user_data = NULL; + ch_info->paused = 1; + ch_info->stereo = stereo; + + for (j = 0; j < 2; j++) + { + ch_info->sample_buffer[j] = NULL; + ch_info->samples[j] = 0; + } + } + + /* Initialize buffers */ + for (i = 0; i < AUDIO_CHANNELS; i++) + { + ch_info = &sound_stream[i]; + for (j = 0; j < 2; j++) + { + if (!(ch_info->sample_buffer[j] = + (short*)malloc(sample_count * get_bytes_per_sample(i)))) + { + free_buffers(); + return 0; + } + + ch_info->samples[j] = sample_count; + } + } + + /* Initialize channels */ + for (i = 0, failed = 0; i < AUDIO_CHANNELS; i++) + { + sound_stream[i].sound_ch_handle = + sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL, + sample_count, + (stereo) + ? PSP_AUDIO_FORMAT_STEREO + : PSP_AUDIO_FORMAT_MONO); + + if (sound_stream[i].sound_ch_handle < 0) + { + failed = 1; + break; + } + } + + if (failed) + { + for (i = 0; i < AUDIO_CHANNELS; i++) + { + if (sound_stream[i].sound_ch_handle != -1) + { + sceAudioChRelease(sound_stream[i].sound_ch_handle); + sound_stream[i].sound_ch_handle = -1; + } + } + + free_buffers(); + return 0; + } + + sound_ready = 1; + + char label[16]; + strcpy(label, "audiotX"); + + for (i = 0; i < AUDIO_CHANNELS; i++) + { + label[6] = '0' + i; + sound_stream[i].thread_handle = + sceKernelCreateThread(label, (void*)&channel_thread, 0x12, 0x10000, + 0, NULL); + + if (sound_stream[i].thread_handle < 0) + { + sound_stream[i].thread_handle = -1; + failed = 1; + break; + } + + if (sceKernelStartThread(sound_stream[i].thread_handle, sizeof(i), &i) != 0) + { + failed = 1; + break; + } + } + + if (failed) + { + sound_stop = 1; + for (i = 0; i < AUDIO_CHANNELS; i++) + { + if (sound_stream[i].thread_handle != -1) + { + //sceKernelWaitThreadEnd(sound_stream[i].threadhandle,NULL); + sceKernelDeleteThread(sound_stream[i].thread_handle); + } + + sound_stream[i].thread_handle = -1; + } + + sound_ready = 0; + free_buffers(); + return 0; + } + + return sample_count; +} + +void pl_snd_shutdown() +{ + int i; + sound_ready = 0; + sound_stop = 1; + + for (i = 0; i < AUDIO_CHANNELS; i++) + { + if (sound_stream[i].thread_handle != -1) + { + //sceKernelWaitThreadEnd(sound_stream[i].threadhandle,NULL); + sceKernelDeleteThread(sound_stream[i].thread_handle); + } + + sound_stream[i].thread_handle = -1; + } + + for (i = 0; i < AUDIO_CHANNELS; i++) + { + if (sound_stream[i].sound_ch_handle != -1) + { + sceAudioChRelease(sound_stream[i].sound_ch_handle); + sound_stream[i].sound_ch_handle = -1; + } + } + + free_buffers(); +} + +static inline int play_blocking(unsigned int channel, + unsigned int vol1, + unsigned int vol2, + void *buf) +{ + if (!sound_ready) return -1; + if (channel >= AUDIO_CHANNELS) return -1; + + return sceAudioOutputPannedBlocking(sound_stream[channel].sound_ch_handle, + vol1, vol2, buf); +} + +static int channel_thread(int args, void *argp) +{ + volatile int bufidx = 0; + int channel = *(int*)argp; + int i, j; + unsigned short *ptr_m; + unsigned int *ptr_s; + void *bufptr; + unsigned int samples; + pl_snd_callback callback; + pl_snd_channel_info *ch_info; + + ch_info = &sound_stream[channel]; + for (j = 0; j < 2; j++) + memset(ch_info->sample_buffer[j], 0, + ch_info->samples[j] * get_bytes_per_sample(channel)); + + while (!sound_stop) + { + callback = ch_info->callback; + bufptr = ch_info->sample_buffer[bufidx]; + samples = ch_info->samples[bufidx]; + + if (callback && !ch_info->paused) + /* Use callback to fill buffer */ + callback(bufptr, samples, ch_info->user_data); + else + { + /* Fill buffer with silence */ + if (ch_info->stereo) + for (i = 0, ptr_s = bufptr; i < samples; i++) *(ptr_s++) = 0; + else + for (i = 0, ptr_m = bufptr; i < samples; i++) *(ptr_m++) = 0; + } + + /* Play sound */ + play_blocking(channel, + ch_info->left_vol, + ch_info->right_vol, + bufptr); + + /* Switch active buffer */ + bufidx = (bufidx ? 0 : 1); + } + + sceKernelExitThread(0); + return 0; +} + +static void free_buffers() +{ + int i, j; + + pl_snd_channel_info *ch_info; + for (i = 0; i < AUDIO_CHANNELS; i++) + { + ch_info = &sound_stream[i]; + for (j = 0; j < 2; j++) + { + if (ch_info->sample_buffer[j]) + { + free(ch_info->sample_buffer[j]); + ch_info->sample_buffer[j] = NULL; + } + } + } +} + +int pl_snd_set_callback(int channel, + pl_snd_callback callback, + void *userdata) +{ + if (channel < 0 || channel > AUDIO_CHANNELS) + return 0; + volatile pl_snd_channel_info *pci = &sound_stream[channel]; + pci->callback = NULL; + pci->user_data = userdata; + pci->callback = callback; + + return 1; +} + +static unsigned int get_bytes_per_sample(int channel) +{ + return (sound_stream[channel].stereo) + ? sizeof(pl_snd_stereo_sample) + : sizeof(pl_snd_mono_sample); +} + +int pl_snd_pause(int channel) +{ + if (channel < 0 || channel > AUDIO_CHANNELS) + return 0; + sound_stream[channel].paused = 1; + return 1; +} + +int pl_snd_resume(int channel) +{ + if (channel < 0 || channel > AUDIO_CHANNELS) + return 0; + sound_stream[channel].paused = 0; + return 1; +} diff --git a/psp/psplib/pl_snd.h b/psp/psplib/pl_snd.h new file mode 100644 index 0000000..cc17cce --- /dev/null +++ b/psp/psplib/pl_snd.h @@ -0,0 +1,67 @@ +/* psplib/pl_snd.h + Simple sound playback library + + Copyright (C) 2007-2009 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: dev@psp.akop.org +*/ + +#ifndef _PL_SND_H +#define _PL_SND_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define PL_SND_ALIGN_SAMPLE(s) (((s) + 63) & ~63) +#define PL_SND_TRUNCATE_SAMPLE(s) ((s) & ~63) + +typedef struct pl_snd_stereo_sample_t +{ + short l; + short r; +} pl_snd_stereo_sample; + +typedef struct pl_snd_mono_sample_t +{ + short ch; +} pl_snd_mono_sample; + +typedef union pl_snd_sample_t +{ + pl_snd_stereo_sample stereo; + pl_snd_mono_sample mono; +} pl_snd_sample; + +typedef void (*pl_snd_callback)(pl_snd_sample *buffer, + unsigned int samples, + void *user_data); + +int pl_snd_init(int samples, + int stereo); +int pl_snd_set_callback(int channel, + pl_snd_callback callback, + void *userdata); +int pl_snd_pause(int channel); +int pl_snd_resume(int channel); +void pl_snd_shutdown(); + +#ifdef __cplusplus +} +#endif + +#endif // _PL_SND_H + diff --git a/psp/psplib/pl_util.c b/psp/psplib/pl_util.c new file mode 100644 index 0000000..3c750be --- /dev/null +++ b/psp/psplib/pl_util.c @@ -0,0 +1,193 @@ +/* psplib/pl_util.c + Various utility functions + + Copyright (C) 2007-2009 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: dev@psp.akop.org +*/ + +#include "pl_util.h" + +#include +#include +#include +#include +#include + +#include "pl_file.h" +#include "video.h" + +#define CRC_BUFFER_SIZE 8192 + +static uint32_t compute_buffer_crc(uint32_t inCrc32, + const void *buf, + size_t bufLen); + +int pl_util_save_image_seq(const char *path, + const char *filename, + const PspImage *image) +{ + /* If screenshot path does not exist, create it */ + if (!pl_file_exists(path)) + if (!pl_file_mkdir_recursive(path)) + return 0; + + /* Loop until first free screenshot slot is found */ + int i = 0; + pl_file_path full_path; + do + { + snprintf(full_path, + sizeof(full_path) - 1, + "%s%s-%02i.png", + path, filename, i); + } while (pl_file_exists(full_path) && ++i < 100); + + /* Save the screenshot */ + return pspImageSavePng(full_path, image); +} + +int pl_util_save_vram_seq(const char *path, + const char *filename) +{ + PspImage* vram = pspVideoGetVramBufferCopy(); + if (!vram) return 0; + + int exit_code = pl_util_save_image_seq(path, + filename, + vram); + pspImageDestroy(vram); + + return exit_code; +} + +int pl_util_date_compare(const ScePspDateTime *date1, + const ScePspDateTime *date2) +{ + if (date1->year != date2->year) + return date1->year - date2->year; + if (date1->month != date2->month) + return date1->month - date2->month; + if (date1->day != date2->day) + return date1->day - date2->day; + if (date1->hour != date2->hour) + return date1->hour - date2->hour; + if (date1->minute != date2->minute) + return date1->minute - date2->minute; + if (date1->second != date2->second) + return date1->second - date2->second; + return 0; +} + +int pl_util_compute_crc32_buffer(const void *buf, + size_t buf_len, + uint32_t *crc_32) +{ + *crc_32 = compute_buffer_crc(0, + buf, + buf_len); + return 1; +} + + +int pl_util_compute_crc32_file(const char *path, + uint32_t *outCrc32) +{ + FILE *file; + if (!(file = fopen(path, "r"))) + return 0; + + int status = pl_util_compute_crc32_fd(file, outCrc32); + fclose(file); + + return status; +} + +int pl_util_compute_crc32_fd(FILE *file, + uint32_t *outCrc32) +{ + unsigned char buf[CRC_BUFFER_SIZE]; + size_t bufLen; + + /** accumulate crc32 from file **/ + *outCrc32 = 0; + while (1) + { + if ((bufLen = fread( buf, 1, CRC_BUFFER_SIZE, file )) == 0) + { + if (ferror(file)) + return -1; + break; + } + *outCrc32 = compute_buffer_crc(*outCrc32, buf, bufLen); + } + + return 0; +} + +static uint32_t compute_buffer_crc(uint32_t inCrc32, + const void *buf, + size_t bufLen) +{ + static const unsigned long crcTable[256] = { + 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535, + 0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD, + 0xE7B82D07,0x90BF1D91,0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D, + 0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC, + 0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,0x3B6E20C8,0x4C69105E,0xD56041E4, + 0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C, + 0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,0x26D930AC, + 0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F, + 0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB, + 0xB6662D3D,0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F, + 0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB, + 0x086D3D2D,0x91646C97,0xE6635C01,0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E, + 0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA, + 0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,0x4DB26158,0x3AB551CE, + 0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A, + 0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9, + 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409, + 0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81, + 0xB7BD5C3B,0xC0BA6CAD,0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739, + 0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8, + 0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,0xF00F9344,0x8708A3D2,0x1E01F268, + 0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0, + 0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,0xD6D6A3E8, + 0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B, + 0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF, + 0x4669BE79,0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703, + 0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7, + 0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A, + 0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE, + 0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,0x86D3D2D4,0xF1D4E242, + 0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6, + 0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45, + 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D, + 0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5, + 0x47B2CF7F,0x30B5FFE9,0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605, + 0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94, + 0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D }; + unsigned long crc32; + unsigned char *byteBuf; + size_t i; + + /** accumulate crc32 for buffer **/ + crc32 = inCrc32 ^ 0xFFFFFFFF; + byteBuf = (unsigned char*) buf; + for (i=0; i < bufLen; i++) + crc32 = (crc32 >> 8) ^ crcTable[ (crc32 ^ byteBuf[i]) & 0xFF ]; + return( crc32 ^ 0xFFFFFFFF ); +} diff --git a/psp/psplib/pl_util.h b/psp/psplib/pl_util.h new file mode 100644 index 0000000..1c54c85 --- /dev/null +++ b/psp/psplib/pl_util.h @@ -0,0 +1,52 @@ +/* psplib/pl_util.h + Various utility functions + + Copyright (C) 2007-2009 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: dev@psp.akop.org +*/ + +#ifndef _PL_UTIL_H +#define _PL_UTIL_H + +#include +#include "image.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Sequential image saves */ +int pl_util_save_image_seq(const char *path, + const char *filename, + const PspImage *image); +int pl_util_save_vram_seq(const char *path, + const char *prefix); +int pl_util_date_compare(const ScePspDateTime *date1, + const ScePspDateTime *date2); +int pl_util_compute_crc32_buffer(const void *buf, + size_t buf_len, + uint32_t *crc_32); +int pl_util_compute_crc32_fd(FILE *file, + uint32_t *outCrc32); +int pl_util_compute_crc32_file(const char *path, + uint32_t *outCrc32); + +#ifdef __cplusplus +} +#endif + +#endif // _PL_UTIL_H diff --git a/psp/psplib/pl_vk.c b/psp/psplib/pl_vk.c new file mode 100644 index 0000000..dc37836 --- /dev/null +++ b/psp/psplib/pl_vk.c @@ -0,0 +1,541 @@ +/* psplib/pl_vk.c + Virtual keyboard implementation + + Copyright (C) 2008-2009 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: dev@psp.akop.org +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "video.h" + +#include "pl_vk.h" + +#define PL_VK_DELAY 400 +#define PL_VK_THRESHOLD 50 + +#define PL_VK_BUTTON_BG COLOR(0x44,0x44,0x44,0x33) +#define PL_VK_LAYOUT_BG COLOR(0,0,0,0x22) +#define PL_VK_STUCK_COLOR COLOR(0xff,0,0,0x33) +#define PL_VK_SELECTED_COLOR COLOR(0xff,0xff,0xff,0x88) + +static const int _button_map[] = +{ + PSP_CTRL_UP, + PSP_CTRL_DOWN, + PSP_CTRL_LEFT, + PSP_CTRL_RIGHT, + PSP_CTRL_CIRCLE, + PSP_CTRL_TRIANGLE, + 0 +}; +static u64 _push_time[6]; + +typedef struct pl_vk_button_t +{ + uint16_t code; + uint16_t x; + uint16_t y; + uint16_t w; + uint16_t h; + uint8_t is_sticky; +} pl_vk_button; + +typedef struct pl_vk_sticky_t +{ + uint16_t code; + uint8_t status; + uint16_t *key_index; + uint8_t index_count; +} pl_vk_sticky; + +static void filter_repeats(SceCtrlData *pad); +static void render_to_display_list(pl_vk_layout *layout); + +int pl_vk_load(pl_vk_layout *layout, + const char *data_path, + const char *image_path, + int(*read_callback)(unsigned int), + void(*write_callback)(unsigned int, int)) +{ + /* Reset physical button status */ + int i; + for (i = 0; _button_map[i]; i++) + _push_time[i] = 0; + + /* Initialize */ + layout->keys = NULL; + layout->stickies = NULL; + layout->keyb_image = NULL; + layout->key_count = layout->sticky_count = + layout->offset_x = layout->offset_y = + layout->selected = layout->held_down = 0; + + /* Load image */ + if (image_path && !(layout->keyb_image = pspImageLoadPng(image_path))) + return 0; + + /* Init callbacks */ + layout->read_callback = read_callback; + layout->write_callback = write_callback; + + /* Try opening file */ + FILE *file; + if (!(file = fopen(data_path, "r"))) + { + pl_vk_destroy(layout); + return 0; + } + + int code; + uint16_t x, y, w, h; + + /* Determine button count */ + while ((fscanf(file, "0x%x\t%hi\t%hi\t%hi\t%hi\n", + &code, &x, &y, &w, &h) == 5) && code) + layout->key_count++; + + /* Rewind to start */ + rewind(file); + + layout->keys = (pl_vk_button*)malloc(layout->key_count * + sizeof(pl_vk_button)); + if (!layout->keys) + { + fclose(file); + pl_vk_destroy(layout); + return 0; + } + + /* Start reading keys */ + pl_vk_button *button; + for (i = 0, button = layout->keys; i < layout->key_count; i++, button++) + { + if (fscanf(file, "0x%x\t%hi\t%hi\t%hi\t%hi\n", + &code, &x, &y, &w, &h) < 5) + { + fclose(file); + pl_vk_destroy(layout); + return 0; + } + + button->code = code & 0xffff; + button->x = x; + button->y = y; + button->w = w; + button->h = h; + button->is_sticky = 0; + } + + /* "Swallow" last record */ + fscanf(file, "0x%x\t%hi\t%hi\t%hi\t%hi\n", + &code, &x, &y, &w, &h); + + /* Determine sticky count */ + long pos = ftell(file); + while ((fscanf(file, "0x%x\t", &code) == 1) && code) + layout->sticky_count++; + + /* Rewind again */ + fseek(file, pos, SEEK_SET); + + if (layout->sticky_count > 0) + { + layout->stickies = (pl_vk_sticky*)malloc(layout->sticky_count * + sizeof(pl_vk_sticky)); + if (!layout->stickies) + { + fclose(file); + pl_vk_destroy(layout); + return 0; + } + + /* Start reading stickies */ + pl_vk_sticky *sticky; + for (i = 0, sticky = layout->stickies; i < layout->sticky_count; i++, sticky++) + { + if (fscanf(file, "0x%x\t", &code) < 1) + { + fclose(file); + pl_vk_destroy(layout); + return 0; + } + + sticky->code = code & 0xffff; + sticky->status = 0; + sticky->index_count = 0; + sticky->key_index = NULL; + + int j; + for (j = 0; j < layout->key_count; j++) + { + /* Mark sticky status */ + if (layout->keys[j].code == sticky->code) + layout->keys[j].is_sticky = 1; + + /* Determine number of matching sticky keys */ + if (layout->keys[j].code == sticky->code) + sticky->index_count++; + } + + /* Allocate space */ + if (sticky->index_count > 0) + { + sticky->key_index = (uint16_t*)malloc(sticky->index_count * + sizeof(uint16_t)); + if (!sticky->index_count) + { + fclose(file); + pl_vk_destroy(layout); + return 0; + } + } + + /* Save indices */ + int count; + for (j = 0, count = 0; j < layout->key_count; j++) + if (layout->keys[j].code == sticky->code) + sticky->key_index[count++] = j; + } + } + + /* "Swallow" last record */ + fscanf(file, "0x%x\t", &code); + + /* Read the offsets */ + if (fscanf(file, "%hi\t%hi\n", + &layout->offset_x, &layout->offset_y) < 2) + { + fclose(file); + pl_vk_destroy(layout); + return 0; + } + + render_to_display_list(layout); + + /* Close the file */ + fclose(file); + return 1; +} + +static void filter_repeats(SceCtrlData *pad) +{ + SceCtrlData p = *pad; + int i; + u64 tick; + u32 tick_res; + + /* Get current tick count */ + sceRtcGetCurrentTick(&tick); + tick_res = sceRtcGetTickResolution(); + + /* Check each button */ + for (i = 0; i < _button_map[i]; i++) + { + if (p.Buttons & _button_map[i]) + { + if (!_push_time[i] || tick >= _push_time[i]) + { + /* Button was pushed for the first time, or time to repeat */ + pad->Buttons |= _button_map[i]; + /* Compute next press time */ + _push_time[i] = tick + ((_push_time[i]) ? PL_VK_THRESHOLD : PL_VK_DELAY) + * (tick_res / 1000); + } + else + { + /* No need to repeat yet */ + pad->Buttons &= ~_button_map[i]; + } + } + else + { + /* Button was released */ + pad->Buttons &= ~_button_map[i]; + _push_time[i] = 0; + } + } +} + +void pl_vk_release_all(pl_vk_layout *layout) +{ + /* Release 'held down' key */ + if (layout->held_down && layout->write_callback) + { + layout->write_callback(layout->held_down, 0); + layout->held_down = 0; + } + + /* Unset all sticky keys */ + int i; + pl_vk_sticky *sticky; + for (i = 0, sticky = layout->stickies; + i < layout->sticky_count; + i++, sticky++) + { + sticky->status = 0; + if (layout->write_callback) + layout->write_callback(sticky->code, 0); + } +} + +void pl_vk_reinit(pl_vk_layout *layout) +{ + int i; + for (i = 0; _button_map[i]; i++) + _push_time[i] = 0; + layout->held_down = 0; + + pl_vk_sticky *sticky; + for (i = 0, sticky = layout->stickies; i < layout->sticky_count; i++, sticky++) + sticky->status = (layout->read_callback) + ? layout->read_callback(sticky->code) : 0; +} + +void pl_vk_navigate(pl_vk_layout *layout, + SceCtrlData *pad) +{ + int i; + filter_repeats(pad); + + if ((pad->Buttons & PSP_CTRL_SQUARE) + && layout->write_callback && !layout->held_down) + { + /* Button pressed */ + layout->held_down = layout->keys[layout->selected].code; + layout->write_callback(layout->held_down, 1); + + /* Unstick if the key is stuck */ + if (layout->keys[layout->selected].is_sticky) + { + pl_vk_sticky *sticky; + for (i = 0, sticky = layout->stickies; i < layout->sticky_count; i++, sticky++) + { + /* Active sticky key; toggle status */ + if (sticky->status && + layout->keys[layout->selected].code == sticky->code) + { + sticky->status = !sticky->status; + break; + } + } + } + } + else if (!(pad->Buttons & PSP_CTRL_SQUARE) + && layout->write_callback && layout->held_down) + { + /* Button released */ + layout->write_callback(layout->held_down, 0); + layout->held_down = 0; + } + + if (pad->Buttons & PSP_CTRL_RIGHT) + { + if (layout->selected + 1 < layout->key_count + && layout->keys[layout->selected].y == layout->keys[layout->selected + 1].y) + layout->selected++; + } + else if (pad->Buttons & PSP_CTRL_LEFT) + { + if (layout->selected > 0 + && layout->keys[layout->selected].y == layout->keys[layout->selected - 1].y) + layout->selected--; + } + else if (pad->Buttons & PSP_CTRL_DOWN) + { + /* Find first button on the next row */ + for (i = layout->selected + 1; + i < layout->key_count && layout->keys[i].y == layout->keys[layout->selected].y; + i++); + + if (i < layout->key_count) + { + /* Find button below the current one */ + int r = i; + for (; i < layout->key_count && layout->keys[i].y == layout->keys[r].y; i++) + if (layout->keys[i].x + layout->keys[i].w / 2 >= layout->keys[layout->selected].x + layout->keys[layout->selected].w / 2) + break; + + layout->selected = (i < layout->key_count && layout->keys[r].y == layout->keys[i].y) + ? i : i - 1; + } + } + else if (pad->Buttons & PSP_CTRL_UP) + { + /* Find first button on the previous row */ + for (i = layout->selected - 1; + i >= 0 && layout->keys[i].y == layout->keys[layout->selected].y; + i--); + + if (i >= 0) + { + /* Find button above the current one */ + int r = i; + for (; i >= 0 && layout->keys[i].y == layout->keys[r].y; i--) + if (layout->keys[i].x + layout->keys[i].w / 2 <= + layout->keys[layout->selected].x + layout->keys[layout->selected].w / 2) + break; + + layout->selected = (i >= 0 && layout->keys[r].y == layout->keys[i].y) + ? i : i + 1; + } + } + + if (layout->write_callback) + { + if (pad->Buttons & PSP_CTRL_CIRCLE && + layout->keys[layout->selected].is_sticky) + { + pl_vk_sticky *sticky; + for (i = 0, sticky = layout->stickies; i < layout->sticky_count; i++, sticky++) + { + /* Sticky key; toggle status */ + if (layout->keys[layout->selected].code == sticky->code) + { + sticky->status = !sticky->status; + layout->write_callback(sticky->code, sticky->status); + break; + } + } + } + else if (pad->Buttons & PSP_CTRL_TRIANGLE) + { + /* Unset all sticky keys */ + pl_vk_sticky *sticky; + for (i = 0, sticky = layout->stickies; i < layout->sticky_count; i++, sticky++) + { + sticky->status = 0; + layout->write_callback(sticky->code, 0); + } + } + } + + /* Unset used buttons */ + for (i = 0; _button_map[i]; i++) + pad->Buttons &= ~_button_map[i]; +} + +void pl_vk_render(const pl_vk_layout *layout) +{ + int off_x, off_y, i, j; + const pl_vk_button *button; + + pspVideoCallList(layout->call_list); + + off_x = (SCR_WIDTH / 2 - layout->keyb_image->Viewport.Width / 2); + off_y = (SCR_HEIGHT / 2 - layout->keyb_image->Viewport.Height / 2); + + if (layout->keyb_image) + pspVideoPutImage(layout->keyb_image, + off_x, off_y, + layout->keyb_image->Viewport.Width, + layout->keyb_image->Viewport.Height); + else + { + /* TODO: render the entire layout */ + } + + off_x += layout->offset_x; + off_y += layout->offset_y; + + /* Highlight sticky buttons */ + pl_vk_sticky *sticky; + for (i = 0, sticky = layout->stickies; + i < layout->sticky_count; + i++, sticky++) + { + if (sticky->status) + { + for (j = 0; j < sticky->index_count; j++) + { + button = &(layout->keys[sticky->key_index[j]]); + pspVideoFillRect(off_x + button->x + 1, + off_y + button->y + 1, + off_x + button->x + button->w, + off_y + button->y + button->h, + PL_VK_STUCK_COLOR); + } + } + } + + /* Highlight selected button */ + button = &(layout->keys[layout->selected]); + pspVideoFillRect(off_x + button->x + 1, + off_y + button->y + 1, + off_x + button->x + button->w, + off_y + button->y + button->h, + PL_VK_SELECTED_COLOR); +} + +void pl_vk_destroy(pl_vk_layout *layout) +{ + /* Destroy sticky keys */ + if (layout->stickies) + { + int i; + pl_vk_sticky *sticky; + for (i = 0, sticky = layout->stickies; i < layout->sticky_count; i++, sticky++) + free(sticky->key_index); + free(layout->stickies); + } + + if (layout->keys) + free(layout->keys); + + if (layout->keyb_image) + pspImageDestroy(layout->keyb_image); +} + +static void render_to_display_list(pl_vk_layout *layout) +{ + /* Render the virtual keyboard to a call list */ + memset(layout->call_list, 0, sizeof(layout->call_list)); + + sceGuStart(GU_CALL, layout->call_list); + + const pl_vk_button *button; + int off_x, off_y; + int i; + + off_x = (SCR_WIDTH / 2 - layout->keyb_image->Viewport.Width / 2); + off_y = (SCR_HEIGHT / 2 - layout->keyb_image->Viewport.Height / 2); + + pspVideoFillRect(off_x, + off_y, + off_x + layout->keyb_image->Viewport.Width + 1, + off_y + layout->keyb_image->Viewport.Height + 1, + PL_VK_LAYOUT_BG); + + off_x += layout->offset_x; + off_y += layout->offset_y; + + for (i = 0, button = layout->keys; i < layout->key_count; i++, button++) + pspVideoFillRect(off_x + button->x, + off_y + button->y, + off_x + button->x + button->w + 1, + off_y + button->y + button->h + 1, + PL_VK_BUTTON_BG); + + sceGuFinish(); +} diff --git a/psp/psplib/pl_vk.h b/psp/psplib/pl_vk.h new file mode 100644 index 0000000..4089abd --- /dev/null +++ b/psp/psplib/pl_vk.h @@ -0,0 +1,66 @@ +/* psplib/pl_vk.h + Virtual keyboard implementation + + Copyright (C) 2008-2009 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: dev@psp.akop.org +*/ + +#ifndef _PL_VK_H +#define _PL_VK_H + +#include "ctrl.h" +#include "image.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct pl_vk_button_t; +struct pl_vk_sticky_t; + +typedef struct pl_vk_layout_t +{ + uint16_t key_count; + struct pl_vk_button_t *keys; + uint16_t sticky_count; + struct pl_vk_sticky_t *stickies; + uint16_t offset_x; + uint16_t offset_y; + uint16_t selected; + uint16_t held_down; + PspImage *keyb_image; + unsigned int __attribute__((aligned(16))) call_list[262144]; + int(*read_callback)(unsigned int code); + void(*write_callback)(unsigned int code, int status); +} pl_vk_layout; + +int pl_vk_load(pl_vk_layout *layout, + const char *data_path, + const char *image_path, + int(*read_callback)(unsigned int), + void(*write_callback)(unsigned int, int)); +void pl_vk_destroy(pl_vk_layout *layout); +void pl_vk_reinit(pl_vk_layout *layout); +void pl_vk_render(const pl_vk_layout *layout); +void pl_vk_navigate(pl_vk_layout *layout, SceCtrlData *pad); +void pl_vk_release_all(pl_vk_layout *layout); + +#ifdef __cplusplus +} +#endif + +#endif // _PL_VK_H diff --git a/psp/psplib/stockfont.fd b/psp/psplib/stockfont.fd new file mode 100644 index 0000000..f22093e --- /dev/null +++ b/psp/psplib/stockfont.fd @@ -0,0 +1,4099 @@ +height 13 +ascent 11 + +char 0 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 1 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 2 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 3 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 4 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 5 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 6 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 7 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 8 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 9 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 10 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 11 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 12 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 13 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 14 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 15 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 16 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 17 +width 6 +000000 +000000 +000000 +111111 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 18 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +111111 +000000 +000000 +000000 +000000 +000000 +000000 + +char 19 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +111111 +000000 +000000 +000000 + +char 20 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +111111 + +char 21 +width 6 +001000 +001000 +001000 +001000 +001000 +001000 +001111 +001000 +001000 +001000 +001000 +001000 +001000 + +char 22 +width 6 +001000 +001000 +001000 +001000 +001000 +001000 +111000 +001000 +001000 +001000 +001000 +001000 +001000 + +char 23 +width 6 +001000 +001000 +001000 +001000 +001000 +001000 +111111 +000000 +000000 +000000 +000000 +000000 +000000 + +char 24 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +111111 +001000 +001000 +001000 +001000 +001000 +001000 + +char 25 +width 6 +001000 +001000 +001000 +001000 +001000 +001000 +001000 +001000 +001000 +001000 +001000 +001000 +001000 + +char 26 +width 6 +000000 +000000 +000000 +000110 +011000 +100000 +011000 +000110 +000000 +111110 +000000 +000000 +000000 + +char 27 +width 6 +000000 +000000 +000000 +110000 +001100 +000010 +001100 +110000 +000000 +111110 +000000 +000000 +000000 + +char 28 +width 6 +000000 +000000 +000000 +000000 +000000 +111110 +010100 +010100 +010100 +010100 +010100 +000000 +000000 + +char 29 +width 6 +000000 +000000 +000000 +000000 +000000 +000010 +111110 +001000 +111110 +100000 +000000 +000000 +000000 + +char 30 +width 6 +000000 +000000 +001100 +010010 +010000 +010000 +111000 +010000 +010000 +010010 +101100 +000000 +000000 + +char 31 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +001100 +000000 +000000 +000000 +000000 +000000 +000000 + +char 32 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 33 +width 6 +000000 +000000 +001000 +001000 +001000 +001000 +001000 +001000 +001000 +000000 +001000 +000000 +000000 + +char 34 +width 6 +000000 +000000 +010100 +010100 +010100 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 35 +width 6 +000000 +000000 +000000 +010100 +010100 +111110 +010100 +111110 +010100 +010100 +000000 +000000 +000000 + +char 36 +width 6 +000000 +000000 +001000 +011110 +101000 +101000 +011100 +001010 +001010 +111100 +001000 +000000 +000000 + +char 37 +width 6 +000000 +000000 +010010 +101010 +010100 +000100 +001000 +010000 +010100 +101010 +100100 +000000 +000000 + +char 38 +width 6 +000000 +000000 +000000 +010000 +101000 +101000 +010000 +101000 +100110 +100100 +011010 +000000 +000000 + +char 39 +width 6 +000000 +000000 +001100 +001000 +010000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 40 +width 6 +000000 +000100 +001000 +001000 +010000 +010000 +010000 +010000 +010000 +001000 +001000 +000100 +000000 + +char 41 +width 6 +000000 +010000 +001000 +001000 +000100 +000100 +000100 +000100 +000100 +001000 +001000 +010000 +000000 + +char 42 +width 6 +000000 +000000 +001000 +101010 +011100 +101010 +001000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 43 +width 6 +000000 +000000 +000000 +000000 +001000 +001000 +111110 +001000 +001000 +000000 +000000 +000000 +000000 + +char 44 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +001100 +001000 +010000 +000000 + +char 45 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +111110 +000000 +000000 +000000 +000000 +000000 +000000 + +char 46 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +001000 +011100 +001000 +000000 + +char 47 +width 6 +000000 +000000 +000010 +000010 +000100 +000100 +001000 +010000 +010000 +100000 +100000 +000000 +000000 + +char 48 +width 6 +000000 +000000 +000000 +011100 +110110 +100010 +100010 +100010 +100010 +110110 +011100 +000000 +000000 + +char 49 +width 6 +000000 +000000 +000000 +111000 +001000 +001000 +001000 +001000 +001000 +001000 +111110 +000000 +000000 + +char 50 +width 6 +000000 +000000 +000000 +011100 +100010 +000010 +000010 +000100 +001000 +010000 +111110 +000000 +000000 + +char 51 +width 6 +000000 +000000 +000000 +011100 +100010 +000010 +011100 +000010 +000010 +100010 +011100 +000000 +000000 + +char 52 +width 7 +0000000 +0000000 +0000000 +0000100 +0001100 +0010100 +0100100 +1000100 +1111110 +0000100 +0000100 +0000000 +0000000 + +char 53 +width 7 +000000 +000000 +000000 +111100 +100000 +100000 +111100 +000010 +000010 +000010 +111100 +000000 +000000 + +char 54 +width 6 +000000 +000000 +000000 +001110 +010000 +100000 +111100 +100010 +100010 +100010 +011100 +000000 +000000 + +char 55 +width 6 +000000 +000000 +000000 +111110 +000010 +000100 +000100 +001000 +001000 +001000 +010000 +000000 +000000 + +char 56 +width 6 +000000 +000000 +000000 +011100 +100010 +100010 +011100 +100010 +100010 +100010 +011100 +000000 +000000 + +char 57 +width 7 +000000 +000000 +000000 +011100 +100010 +100010 +100010 +011110 +000010 +000100 +111000 +000000 +000000 + +char 58 +width 6 +000000 +000000 +000000 +001000 +011100 +001000 +000000 +000000 +001000 +011100 +001000 +000000 +000000 + +char 59 +width 6 +000000 +000000 +000000 +000000 +001000 +011100 +001000 +000000 +000000 +001100 +001000 +010000 +000000 + +char 60 +width 6 +000000 +000000 +000010 +000100 +001000 +010000 +100000 +010000 +001000 +000100 +000010 +000000 +000000 + +char 61 +width 6 +000000 +000000 +000000 +000000 +000000 +111110 +000000 +000000 +111110 +000000 +000000 +000000 +000000 + +char 62 +width 6 +000000 +000000 +100000 +010000 +001000 +000100 +000010 +000100 +001000 +010000 +100000 +000000 +000000 + +char 63 +width 6 +000000 +000000 +011100 +100010 +100010 +000010 +000100 +001000 +001000 +000000 +001000 +000000 +000000 + +char 64 +width 6 +000000 +000000 +011100 +100010 +100010 +100110 +101010 +101010 +101100 +100000 +011110 +000000 +000000 + +char 65 +width 8 +00000000 +00000000 +00000000 +00010000 +00101000 +00101000 +00101000 +01000100 +01111100 +01000100 +10000010 +00000000 +00000000 + +char 66 +width 7 +0000000 +0000000 +0000000 +1111100 +1000010 +1000010 +1111100 +1000010 +1000010 +1000010 +1111100 +0000000 +0000000 + +char 67 +width 7 +0000000 +0000000 +0000000 +0011100 +0100010 +1000000 +1000000 +1000000 +1000000 +0100010 +0011100 +0000000 +0000000 + +char 68 +width 8 +0000000 +0000000 +0000000 +1111000 +1000100 +1000010 +1000010 +1000010 +1000010 +1000100 +1111000 +0000000 +0000000 + +char 69 +width 6 +000000 +000000 +000000 +111110 +100000 +100000 +111110 +100000 +100000 +100000 +111110 +000000 +000000 + +char 70 +width 6 +000000 +000000 +000000 +111110 +100000 +100000 +111110 +100000 +100000 +100000 +100000 +000000 +000000 + +char 71 +width 8 +00000000 +00000000 +00000000 +00111100 +01000010 +10000000 +10000000 +10001110 +10000010 +01000010 +00111100 +00000000 +00000000 + +char 72 +width 7 +0000000 +0000000 +0000000 +1000010 +1000010 +1000010 +1111110 +1000010 +1000010 +1000010 +1000010 +0000000 +0000000 + +char 73 +width 2 +00 +00 +00 +10 +10 +10 +10 +10 +10 +10 +10 +00 +00 + +char 74 +width 4 +0000 +0000 +0000 +0010 +0010 +0010 +0010 +0010 +0010 +0010 +0010 +0010 +1100 + +char 75 +width 7 +0000000 +0000000 +0000000 +1000100 +1001000 +1010000 +1100000 +1010000 +1001000 +1000100 +1000010 +0000000 +0000000 + +char 76 +width 6 +000000 +000000 +000000 +100000 +100000 +100000 +100000 +100000 +100000 +100000 +111110 +000000 +000000 + +char 77 +width 8 +00000000 +00000000 +00000000 +10000010 +11000110 +11000110 +10101010 +10101010 +10010010 +10000010 +10000010 +00000000 +00000000 + +char 78 +width 7 +0000000 +0000000 +0000000 +1100010 +1100010 +1010010 +1010010 +1001010 +1001010 +1000110 +1000110 +0000000 +0000000 + +char 79 +width 8 +00000000 +00000000 +00000000 +00111000 +01000100 +10000010 +10000010 +10000010 +10000010 +01000100 +00111000 +00000000 +00000000 + +char 80 +width 6 +000000 +000000 +000000 +111100 +100010 +100010 +100010 +111100 +100000 +100000 +100000 +000000 +000000 + +char 81 +width 8 +00000000 +00000000 +00000000 +00111000 +01000100 +10000010 +10000010 +10000010 +10000010 +01000100 +00111000 +00001100 +00000000 + +char 82 +width 7 +0000000 +0000000 +0000000 +1111000 +1000100 +1000100 +1000100 +1111000 +1001000 +1000100 +1000010 +0000000 +0000000 + +char 83 +width 7 +0000000 +0000000 +0000000 +0111100 +1000010 +1000000 +1111000 +0000110 +0000010 +1000010 +0111100 +0000000 +0000000 + +char 84 +width 8 +00000000 +00000000 +00000000 +11111110 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00000000 +00000000 + +char 85 +width 7 +0000000 +0000000 +0000000 +1000010 +1000010 +1000010 +1000010 +1000010 +1000010 +1100110 +0111100 +0000000 +0000000 + +char 86 +width 9 +00000000 +00000000 +00000000 +10000010 +10000010 +01000100 +01000100 +00101000 +00101000 +00010000 +00010000 +00000000 +00000000 + +char 87 +width 10 +0000000000 +0000000000 +0000000000 +1000100010 +1000100010 +0100100100 +0101010100 +0101010100 +0101010100 +0010001000 +0010001000 +0000000000 +0000000000 + +char 88 +width 8 +00000000 +00000000 +00000000 +10000010 +01000100 +00101000 +00010000 +00010000 +00101000 +01000100 +10000010 +00000000 +00000000 + +char 89 +width 8 +00000000 +00000000 +00000000 +10000010 +01000100 +00101000 +00010000 +00010000 +00010000 +00010000 +00010000 +00000000 +00000000 + +char 90 +width 8 +00000000 +00000000 +00000000 +11111110 +00000100 +00001000 +00010000 +00010000 +00100000 +01000000 +11111110 +00000000 +00000000 + +char 91 +width 6 +000000 +011100 +010000 +010000 +010000 +010000 +010000 +010000 +010000 +010000 +010000 +011100 +000000 + +char 92 +width 6 +000000 +000000 +100000 +100000 +010000 +010000 +001000 +000100 +000100 +000010 +000010 +000000 +000000 + +char 93 +width 6 +000000 +011100 +000100 +000100 +000100 +000100 +000100 +000100 +000100 +000100 +000100 +011100 +000000 + +char 94 +width 6 +000000 +000000 +001000 +010100 +100010 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 95 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +111110 +000000 + +char 96 +width 6 +000000 +000000 +001100 +000100 +000010 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 97 +width 6 +000000 +000000 +000000 +000000 +000000 +011100 +000010 +011110 +100010 +100010 +011110 +000000 +000000 + +char 98 +width 6 +000000 +000000 +100000 +100000 +100000 +111100 +100010 +100010 +100010 +100010 +111100 +000000 +000000 + +char 99 +width 5 +00000 +00000 +00000 +00000 +00000 +01110 +10000 +10000 +10000 +10000 +01110 +00000 +00000 + +char 100 +width 6 +000000 +000000 +000010 +000010 +000010 +011110 +100010 +100010 +100010 +100010 +011110 +000000 +000000 + +char 101 +width 6 +000000 +000000 +000000 +000000 +000000 +011100 +100010 +111110 +100000 +110010 +011100 +000000 +000000 + +char 102 +width 5 +00000 +00000 +01110 +01000 +01000 +11110 +01000 +01000 +01000 +01000 +01000 +00000 +00000 + +char 103 +width 6 +000000 +000000 +000000 +000000 +000000 +011110 +100010 +100010 +100010 +100010 +011110 +000010 +011100 + +char 104 +width 6 +000000 +000000 +100000 +100000 +100000 +100000 +111100 +100010 +100010 +100010 +100010 +000000 +000000 + +char 105 +width 2 +00 +00 +00 +00 +10 +00 +10 +10 +10 +10 +10 +00 +00 + +char 106 +width 3 +000 +000 +000 +000 +010 +000 +010 +010 +010 +010 +010 +010 +110 + +char 107 +width 7 +000000 +000000 +100000 +100000 +100000 +100100 +101000 +110000 +101000 +100100 +100010 +000000 +000000 + +char 108 +width 2 +00 +00 +10 +10 +10 +10 +10 +10 +10 +10 +10 +00 +00 + +char 109 +width 10 +0000000000 +0000000000 +0000000000 +0000000000 +0000000000 +1111111100 +1000100010 +1000100010 +1000100010 +1000100010 +1000100010 +0000000000 +0000000000 + +char 110 +width 6 +000000 +000000 +000000 +000000 +000000 +111100 +100010 +100010 +100010 +100010 +100010 +000000 +000000 + +char 111 +width 6 +000000 +000000 +000000 +000000 +000000 +011100 +100010 +100010 +100010 +100010 +011100 +000000 +000000 + +char 112 +width 6 +000000 +000000 +000000 +000000 +000000 +111100 +100010 +100010 +100010 +100010 +111100 +100000 +100000 + +char 113 +width 6 +000000 +000000 +000000 +000000 +000000 +011110 +100010 +100010 +100010 +100010 +011110 +000010 +000010 + +char 114 +width 5 +00000 +00000 +00000 +00000 +00000 +10110 +11000 +10000 +10000 +10000 +10000 +00000 +00000 + +char 115 +width 6 +000000 +000000 +000000 +000000 +000000 +011100 +100010 +111000 +000110 +100010 +011100 +000000 +000000 + +char 116 +width 5 +00000 +00000 +00000 +01000 +01000 +11110 +01000 +01000 +01000 +01000 +01110 +00000 +00000 + +char 117 +width 6 +000000 +000000 +000000 +000000 +000000 +100010 +100010 +100010 +100010 +100010 +011110 +000000 +000000 + +char 118 +width 7 +0000000 +0000000 +0000000 +0000000 +0000000 +1000010 +1000010 +0100100 +0100100 +0011000 +0011000 +0000000 +0000000 + +char 119 +width 8 +00000000 +00000000 +00000000 +00000000 +00000000 +10010010 +10010010 +10101010 +10101010 +01000100 +01000100 +00000000 +00000000 + +char 120 +width 7 +0000000 +0000000 +0000000 +0000000 +0000000 +1000010 +0100100 +0011000 +0011000 +0100100 +1000010 +0000000 +0000000 + +char 121 +width 7 +0000000 +0000000 +0000000 +0000000 +0000000 +1000010 +1000010 +0100100 +0100100 +0011000 +0011000 +0010000 +1100000 + +char 122 +width 6 +000000 +000000 +000000 +000000 +000000 +111110 +000010 +000100 +001000 +010000 +111110 +000000 +000000 + +char 123 +width 6 +000000 +000110 +001000 +001000 +001000 +001000 +110000 +001000 +001000 +001000 +001000 +000110 +000000 + +char 124 +width 6 +000000 +000000 +001000 +001000 +001000 +001000 +001000 +001000 +001000 +001000 +001000 +000000 +000000 + +char 125 +width 6 +000000 +110000 +001000 +001000 +001000 +001000 +000110 +001000 +001000 +001000 +001000 +110000 +000000 + +char 126 +width 6 +000000 +000000 +010010 +101010 +100100 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 127 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 128 +width 6 +000000 +000000 +001110 +010000 +010000 +111100 +010000 +111100 +010000 +010000 +001110 +000000 +000000 + +char 129 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 130 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +001100 +000100 +001000 +000000 + +char 131 +width 6 +000000 +000000 +000100 +001010 +001000 +001000 +011100 +001000 +001000 +001000 +001000 +101000 +010000 + +char 132 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +110110 +010010 +100100 +000000 + +char 133 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +101010 +000000 +000000 + +char 134 +width 6 +000000 +000000 +001000 +001000 +111110 +001000 +001000 +001000 +001000 +001000 +001000 +000000 +000000 + +char 135 +width 6 +000000 +000000 +001000 +001000 +111110 +001000 +001000 +111110 +001000 +001000 +001000 +000000 +000000 + +char 136 +width 6 +000000 +001100 +010010 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 137 +width 6 +000000 +000000 +010010 +101010 +010100 +000100 +001000 +010000 +011010 +110101 +101010 +000000 +000000 + +char 138 +width 6 +000000 +010010 +001100 +000000 +011100 +100010 +100000 +011100 +000010 +100010 +011100 +000000 +000000 + +char 139 +width 6 +000000 +000000 +000000 +000000 +000100 +001000 +010000 +010000 +001000 +000100 +000000 +000000 +000000 + +char 140 +width 6 +000000 +000000 +011110 +101000 +101000 +101000 +101100 +101000 +101000 +101000 +011110 +000000 +000000 + +char 141 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 142 +width 6 +000000 +010010 +001100 +000000 +111110 +000010 +000100 +001000 +010000 +100000 +111110 +000000 +000000 + +char 143 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 144 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 145 +width 6 +000000 +000000 +000100 +001000 +001100 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 146 +width 6 +000000 +000000 +001100 +000100 +001000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 147 +width 6 +000000 +000000 +010010 +100100 +110110 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 148 +width 6 +000000 +000000 +110110 +010010 +100100 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 149 +width 6 +000000 +000000 +000000 +000000 +011100 +111110 +111110 +111110 +011100 +000000 +000000 +000000 +000000 + +char 150 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +111110 +000000 +000000 +000000 +000000 +000000 +000000 + +char 151 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +111111 +000000 +000000 +000000 +000000 +000000 +000000 + +char 152 +width 6 +000000 +001010 +010100 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 153 +width 6 +000000 +000000 +111101 +010111 +010101 +010101 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 154 +width 6 +000000 +000000 +100100 +011000 +000000 +011100 +100010 +011000 +000100 +100010 +011100 +000000 +000000 + +char 155 +width 6 +000000 +000000 +000000 +000000 +010000 +001000 +000100 +000100 +001000 +010000 +000000 +000000 +000000 + +char 156 +width 6 +000000 +000000 +000000 +000000 +000000 +010100 +101010 +101110 +101000 +101010 +010100 +000000 +000000 + +char 157 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 158 +width 6 +000000 +000000 +010010 +001100 +000000 +111110 +000100 +001000 +010000 +100000 +111110 +000000 +000000 + +char 159 +width 6 +000000 +010100 +010100 +000000 +100010 +010100 +010100 +001000 +001000 +001000 +001000 +000000 +000000 + +char 160 +width 6 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 + +char 161 +width 9 +000000000 +000000000 +000000000 +010000010 +001000100 +000101000 +000010000 +000101000 +001000100 +010000010 +000000000 +000000000 +000000000 + +char 162 +width 9 +000000000 +000000000 +000000000 +000111000 +001000100 +010000010 +010000010 +010000010 +001000100 +000111000 +000000000 +000000000 +000000000 + +char 163 +width 10 +0000000000 +0000000000 +0000000000 +0000000000 +0000100000 +0001010000 +0010001000 +0100000100 +1111111110 +0000000000 +0000000000 +0000000000 +0000000000 + +char 164 +width 9 +000000000 +000000000 +000000000 +011111110 +010000010 +010000010 +010000010 +010000010 +010000010 +011111110 +000000000 +000000000 +000000000 + +char 165 +width 10 +0000000000 +0000000000 +0111111110 +0100000010 +0100000010 +0100110010 +0101111010 +0100000010 +0010000100 +0001001000 +0000110000 +0000000000 +0000000000 + +char 166 +width 10 +0000000000 +0000000000 +0000110000 +0001001000 +0010000100 +0100000010 +0101111010 +0100110010 +0100000010 +0100000010 +0111111110 +0000000000 +0000000000 + +char 167 +width 11 +00000000000 +00000000000 +00000000000 +01111110000 +01000001000 +01001000100 +01011000010 +01011000010 +01001000100 +01000001000 +01111110000 +00000000000 +00000000000 + +char 168 +width 11 +00000000000 +00000000000 +00000000000 +00001111110 +00010000010 +00100010010 +01000011010 +01000011010 +00100010010 +00010000010 +00001111110 +00000000000 +00000000000 + +char 169 +width 10 +0000000000 +0000000000 +0011111000 +0100000100 +1000100010 +1001110010 +1010101010 +1000100010 +1000100010 +0100000100 +0011111000 +0000000000 +0000000000 + +char 170 +width 10 +0000000000 +0000000000 +0011111000 +0100000100 +1000100010 +1000100010 +1010101010 +1001110010 +1000100010 +0100000100 +0011111000 +0000000000 +0000000000 + +char 171 +width 10 +0000000000 +0000000000 +0011111000 +0100000100 +1000100010 +1001000010 +1011111010 +1001000010 +1000100010 +0100000100 +0011111000 +0000000000 +0000000000 + +char 172 +width 10 +0000000000 +0000000000 +0011111000 +0100000100 +1000100010 +1000010010 +1011111010 +1000010010 +1000100010 +0100000100 +0011111000 +0000000000 +0000000000 + +char 173 +width 16 +0000000000000000 +0000000000000000 +1111111111111110 +1000000000000010 +1000010000000010 +1000010000000010 +1000010000000010 +1000010000000010 +1000011111000010 +1000000000000010 +1111111111111110 +0000000000000000 +0000000000000000 + +char 174 +width 16 +0000000000000000 +0000000000000000 +1111111111111110 +1000000000000010 +1000011110000010 +1000010001000010 +1000011110000010 +1000010001000010 +1000010001000010 +1000000000000010 +1111111111111110 +0000000000000000 +0000000000000000 + +char 175 +width 16 +0000000000000000 +0000000000000000 +0000000000000000 +0110111010001110 +1000100010001000 +1000100010001000 +0100110010001100 +0010100010001000 +0010100010001000 +1100111011101110 +0000000000000000 +0000000000000000 +0000000000000000 + +char 176 +width 8 +00000000 +00000000 +00000000 +01101110 +10000100 +10000100 +10000100 +10000100 +10000100 +01100100 +00000000 +00000000 +00000000 + +char 177 +width 16 +0000000000000000 +0000000000000000 +0000000000000000 +0110111001001100 +1000010010101010 +1000010010101010 +0100010011101100 +0010010010101010 +0010010010101010 +1100010010101010 +0000000000000000 +0000000000000000 +0000000000000000 + +char 178 +width 4 +0000 +0000 +0000 +1110 +0100 +0100 +0100 +0100 +0100 +0100 +0000 +0000 +0000 + +char 179 +width 15 +000000000000000 +000000000000000 +001111111111110 +001000000000010 +001011011011010 +111011011011010 +111011011011010 +111011011011010 +001011011011010 +001000000000010 +001111111111110 +000000000000000 +000000000000000 + +char 180 +width 15 +000000000000000 +000000000000000 +001111111111110 +001000000000010 +001000011011010 +111000011011010 +111000011011010 +111000011011010 +001000011011010 +001000000000010 +001111111111110 +000000000000000 +000000000000000 + +char 181 +width 15 +000000000000000 +000000000000000 +001111111111110 +001000000000010 +001000000011010 +111000000011010 +111000000011010 +111000000011010 +001000000011010 +001000000000010 +001111111111110 +000000000000000 +000000000000000 + +char 182 +width 15 +000000000000000 +000000000000000 +001111111111110 +001000000000010 +001000000000010 +111000000000010 +111000000000010 +111000000000010 +001000000000010 +001000000000010 +001111111111110 +000000000000000 +000000000000000 + +char 183 +width 9 +000000000 +001000100 +001000100 +011111110 +010000010 +010000010 +001000100 +000111000 +000010000 +000001000 +000000110 +000000000 +000000000 + +char 184 +width 10 +0000000000 +0000000000 +0011111000 +0100000100 +1000100010 +1000100010 +1000111010 +1000000010 +1000000010 +0100000100 +0011111000 +0000000000 +0000000000 + +char 185 +width 15 +000000000000000 +000000000000000 +111111111111110 +100000000000010 +100000000000010 +100000000000010 +100100000000010 +101100000000010 +100100000000010 +010000000000010 +001111111111110 +000000000000000 +000000000000000 + +char 186 +width 6 +000000 +000000 +001000 +011100 +101010 +001000 +001000 +001000 +001000 +001000 +001000 +000000 +000000 + +char 187 +width 6 +000000 +000000 +001000 +001000 +001000 +001000 +001000 +001000 +101010 +011100 +001000 +000000 +000000 + +char 188 +width 10 +0000000000 +0000000000 +1111111100 +1011101010 +1011101010 +1011111010 +1000000010 +1011111010 +1011111010 +1011111010 +1111111110 +0000000000 +0000000000 + +char 189 +width 6 +000000 +000000 +000000 +000000 +001000 +001000 +111110 +011100 +110110 +100010 +000000 +000000 +000000 + +char 190 +width 6 +000000 +010000 +101000 +010000 +001000 +101000 +010010 +000110 +001010 +001110 +000010 +000000 +000000 + +char 191 +width 6 +000000 +000000 +001000 +000000 +001000 +001000 +010000 +100000 +100010 +100010 +011100 +000000 +000000 + +char 192 +width 6 +000000 +010000 +001000 +000000 +001000 +010100 +100010 +100010 +111110 +100010 +100010 +000000 +000000 + +char 193 +width 6 +000000 +000100 +001000 +000000 +001000 +010100 +100010 +100010 +111110 +100010 +100010 +000000 +000000 + +char 194 +width 6 +000000 +001100 +010010 +000000 +001000 +010100 +100010 +100010 +111110 +100010 +100010 +000000 +000000 + +char 195 +width 6 +000000 +001010 +010100 +000000 +001000 +010100 +100010 +100010 +111110 +100010 +100010 +000000 +000000 + +char 196 +width 6 +000000 +010100 +010100 +000000 +001000 +010100 +100010 +100010 +111110 +100010 +100010 +000000 +000000 + +char 197 +width 6 +000000 +001000 +010100 +001000 +001000 +010100 +100010 +100010 +111110 +100010 +100010 +000000 +000000 + +char 198 +width 6 +000000 +000000 +010110 +101000 +101000 +101000 +101100 +111000 +101000 +101000 +101110 +000000 +000000 + +char 199 +width 6 +000000 +000000 +011100 +100010 +100000 +100000 +100000 +100000 +100000 +100010 +011100 +001000 +010000 + +char 200 +width 6 +000000 +010000 +001000 +000000 +111110 +100000 +100000 +111100 +100000 +100000 +111110 +000000 +000000 + +char 201 +width 6 +000000 +000100 +001000 +000000 +111110 +100000 +100000 +111100 +100000 +100000 +111110 +000000 +000000 + +char 202 +width 6 +000000 +001100 +010010 +000000 +111110 +100000 +100000 +111100 +100000 +100000 +111110 +000000 +000000 + +char 203 +width 6 +000000 +010100 +010100 +000000 +111110 +100000 +100000 +111100 +100000 +100000 +111110 +000000 +000000 + +char 204 +width 6 +000000 +010000 +001000 +000000 +011100 +001000 +001000 +001000 +001000 +001000 +011100 +000000 +000000 + +char 205 +width 6 +000000 +000100 +001000 +000000 +011100 +001000 +001000 +001000 +001000 +001000 +011100 +000000 +000000 + +char 206 +width 6 +000000 +001100 +010010 +000000 +011100 +001000 +001000 +001000 +001000 +001000 +011100 +000000 +000000 + +char 207 +width 6 +000000 +010100 +010100 +000000 +011100 +001000 +001000 +001000 +001000 +001000 +011100 +000000 +000000 + +char 208 +width 6 +000000 +000000 +111100 +010010 +010010 +010010 +111010 +010010 +010010 +010010 +111100 +000000 +000000 + +char 209 +width 6 +000000 +001010 +010100 +000000 +100010 +100010 +110010 +101010 +100110 +100010 +100010 +000000 +000000 + +char 210 +width 6 +000000 +010000 +001000 +000000 +011100 +100010 +100010 +100010 +100010 +100010 +011100 +000000 +000000 + +char 211 +width 6 +000000 +000100 +001000 +000000 +011100 +100010 +100010 +100010 +100010 +100010 +011100 +000000 +000000 + +char 212 +width 6 +000000 +001100 +010010 +000000 +011100 +100010 +100010 +100010 +100010 +100010 +011100 +000000 +000000 + +char 213 +width 6 +000000 +001010 +010100 +000000 +011100 +100010 +100010 +100010 +100010 +100010 +011100 +000000 +000000 + +char 214 +width 6 +000000 +010100 +010100 +000000 +011100 +100010 +100010 +100010 +100010 +100010 +011100 +000000 +000000 + +char 215 +width 6 +000000 +000000 +000000 +000000 +000000 +100010 +010100 +001000 +010100 +100010 +000000 +000000 +000000 + +char 216 +width 6 +000000 +000010 +011100 +100110 +100110 +101010 +101010 +101010 +110010 +110010 +011100 +100000 +000000 + +char 217 +width 6 +000000 +010000 +001000 +000000 +100010 +100010 +100010 +100010 +100010 +100010 +011100 +000000 +000000 + +char 218 +width 6 +000000 +000100 +001000 +000000 +100010 +100010 +100010 +100010 +100010 +100010 +011100 +000000 +000000 + +char 219 +width 6 +000000 +001100 +010010 +000000 +100010 +100010 +100010 +100010 +100010 +100010 +011100 +000000 +000000 + +char 220 +width 6 +000000 +010100 +010100 +000000 +100010 +100010 +100010 +100010 +100010 +100010 +011100 +000000 +000000 + +char 221 +width 6 +000000 +000100 +001000 +000000 +100010 +100010 +010100 +001000 +001000 +001000 +001000 +000000 +000000 + +char 222 +width 6 +000000 +000000 +100000 +111100 +100010 +100010 +100010 +111100 +100000 +100000 +100000 +000000 +000000 + +char 223 +width 6 +000000 +000000 +011000 +100100 +100100 +101000 +101000 +100100 +100010 +100010 +101100 +000000 +000000 + +char 224 +width 6 +000000 +000000 +010000 +001000 +000000 +011100 +000010 +011110 +100010 +100110 +011010 +000000 +000000 + +char 225 +width 6 +000000 +000000 +000100 +001000 +000000 +011100 +000010 +011110 +100010 +100110 +011010 +000000 +000000 + +char 226 +width 6 +000000 +000000 +001100 +010010 +000000 +011100 +000010 +011110 +100010 +100110 +011010 +000000 +000000 + +char 227 +width 6 +000000 +000000 +001010 +010100 +000000 +011100 +000010 +011110 +100010 +100110 +011010 +000000 +000000 + +char 228 +width 6 +000000 +000000 +010100 +010100 +000000 +011100 +000010 +011110 +100010 +100110 +011010 +000000 +000000 + +char 229 +width 6 +000000 +001100 +010010 +001100 +000000 +011100 +000010 +011110 +100010 +100110 +011010 +000000 +000000 + +char 230 +width 6 +000000 +000000 +000000 +000000 +000000 +011100 +001010 +011100 +101000 +101010 +010100 +000000 +000000 + +char 231 +width 6 +000000 +000000 +000000 +000000 +000000 +011100 +100010 +100000 +100000 +100010 +011100 +001000 +010000 + +char 232 +width 6 +000000 +000000 +010000 +001000 +000000 +011100 +100010 +111110 +100000 +100010 +011100 +000000 +000000 + +char 233 +width 6 +000000 +000000 +000100 +001000 +000000 +011100 +100010 +111110 +100000 +100010 +011100 +000000 +000000 + +char 234 +width 6 +000000 +000000 +001100 +010010 +000000 +011100 +100010 +111110 +100000 +100010 +011100 +000000 +000000 + +char 235 +width 6 +000000 +000000 +010100 +010100 +000000 +011100 +100010 +111110 +100000 +100010 +011100 +000000 +000000 + +char 236 +width 6 +000000 +000000 +010000 +001000 +000000 +011000 +001000 +001000 +001000 +001000 +011100 +000000 +000000 + +char 237 +width 6 +000000 +000000 +000100 +001000 +000000 +011000 +001000 +001000 +001000 +001000 +011100 +000000 +000000 + +char 238 +width 6 +000000 +000000 +001100 +010010 +000000 +011000 +001000 +001000 +001000 +001000 +011100 +000000 +000000 + +char 239 +width 6 +000000 +000000 +010100 +010100 +000000 +011000 +001000 +001000 +001000 +001000 +011100 +000000 +000000 + +char 240 +width 6 +000000 +010100 +001000 +011000 +000100 +011100 +100010 +100010 +100010 +100010 +011100 +000000 +000000 + +char 241 +width 6 +000000 +000000 +001010 +010100 +000000 +101100 +110010 +100010 +100010 +100010 +100010 +000000 +000000 + +char 242 +width 6 +000000 +000000 +010000 +001000 +000000 +011100 +100010 +100010 +100010 +100010 +011100 +000000 +000000 + +char 243 +width 6 +000000 +000000 +000100 +001000 +000000 +011100 +100010 +100010 +100010 +100010 +011100 +000000 +000000 + +char 244 +width 6 +000000 +000000 +001100 +010010 +000000 +011100 +100010 +100010 +100010 +100010 +011100 +000000 +000000 + +char 245 +width 6 +000000 +000000 +001010 +010100 +000000 +011100 +100010 +100010 +100010 +100010 +011100 +000000 +000000 + +char 246 +width 6 +000000 +000000 +010100 +010100 +000000 +011100 +100010 +100010 +100010 +100010 +011100 +000000 +000000 + +char 247 +width 6 +000000 +000000 +000000 +001000 +001000 +000000 +111110 +000000 +001000 +001000 +000000 +000000 +000000 + +char 248 +width 6 +000000 +000000 +000000 +000000 +000010 +011100 +100110 +101010 +101010 +110010 +011100 +100000 +000000 + +char 249 +width 6 +000000 +000000 +010000 +001000 +000000 +100010 +100010 +100010 +100010 +100110 +011010 +000000 +000000 + +char 250 +width 6 +000000 +000000 +000100 +001000 +000000 +100010 +100010 +100010 +100010 +100110 +011010 +000000 +000000 + +char 251 +width 6 +000000 +000000 +001100 +010010 +000000 +100010 +100010 +100010 +100010 +100110 +011010 +000000 +000000 + +char 252 +width 6 +000000 +000000 +010100 +010100 +000000 +100010 +100010 +100010 +100010 +100110 +011010 +000000 +000000 + +char 253 +width 6 +000000 +000000 +000100 +001000 +000000 +100010 +100010 +100010 +100110 +011010 +000010 +100010 +011100 + +char 254 +width 6 +000000 +000000 +000000 +100000 +100000 +101100 +110010 +100010 +100010 +110010 +101100 +100000 +100000 + +char 255 +width 6 +000000 +000000 +010100 +010100 +000000 +100010 +100010 +100010 +100110 +011010 +000010 +100010 +011100 + diff --git a/psp/psplib/stockfont.h b/psp/psplib/stockfont.h new file mode 100644 index 0000000..3f30843 --- /dev/null +++ b/psp/psplib/stockfont.h @@ -0,0 +1,328 @@ +unsigned short _ch[][13] = { + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 0 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 1 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 2 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 3 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 4 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 5 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 6 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 7 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 8 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 9 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 10 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 11 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 12 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 13 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 14 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 15 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 16 */ + { 0x0000,0x0000,0x0000,0x003f,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 17 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x003f,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 18 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x003f,0x0000,0x0000,0x0000 }, /* 19 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x003f }, /* 20 */ + { 0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x000f,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008 }, /* 21 */ + { 0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x0038,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008 }, /* 22 */ + { 0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x003f,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 23 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x003f,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008 }, /* 24 */ + { 0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008 }, /* 25 */ + { 0x0000,0x0000,0x0000,0x0006,0x0018,0x0020,0x0018,0x0006,0x0000,0x003e,0x0000,0x0000,0x0000 }, /* 26 */ + { 0x0000,0x0000,0x0000,0x0030,0x000c,0x0002,0x000c,0x0030,0x0000,0x003e,0x0000,0x0000,0x0000 }, /* 27 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x003e,0x0014,0x0014,0x0014,0x0014,0x0014,0x0000,0x0000 }, /* 28 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0002,0x003e,0x0008,0x003e,0x0020,0x0000,0x0000,0x0000 }, /* 29 */ + { 0x0000,0x0000,0x000c,0x0012,0x0010,0x0010,0x0038,0x0010,0x0010,0x0012,0x002c,0x0000,0x0000 }, /* 30 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x000c,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 31 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 32 */ + { 0x0000,0x0000,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x0000,0x0008,0x0000,0x0000 }, /* 33 */ + { 0x0000,0x0000,0x0014,0x0014,0x0014,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 34 */ + { 0x0000,0x0000,0x0000,0x0014,0x0014,0x003e,0x0014,0x003e,0x0014,0x0014,0x0000,0x0000,0x0000 }, /* 35 */ + { 0x0000,0x0000,0x0008,0x001e,0x0028,0x0028,0x001c,0x000a,0x000a,0x003c,0x0008,0x0000,0x0000 }, /* 36 */ + { 0x0000,0x0000,0x0012,0x002a,0x0014,0x0004,0x0008,0x0010,0x0014,0x002a,0x0024,0x0000,0x0000 }, /* 37 */ + { 0x0000,0x0000,0x0000,0x0010,0x0028,0x0028,0x0010,0x0028,0x0026,0x0024,0x001a,0x0000,0x0000 }, /* 38 */ + { 0x0000,0x0000,0x000c,0x0008,0x0010,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 39 */ + { 0x0000,0x0004,0x0008,0x0008,0x0010,0x0010,0x0010,0x0010,0x0010,0x0008,0x0008,0x0004,0x0000 }, /* 40 */ + { 0x0000,0x0010,0x0008,0x0008,0x0004,0x0004,0x0004,0x0004,0x0004,0x0008,0x0008,0x0010,0x0000 }, /* 41 */ + { 0x0000,0x0000,0x0008,0x002a,0x001c,0x002a,0x0008,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 42 */ + { 0x0000,0x0000,0x0000,0x0000,0x0008,0x0008,0x003e,0x0008,0x0008,0x0000,0x0000,0x0000,0x0000 }, /* 43 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x000c,0x0008,0x0010,0x0000 }, /* 44 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x003e,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 45 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0008,0x001c,0x0008,0x0000 }, /* 46 */ + { 0x0000,0x0000,0x0002,0x0002,0x0004,0x0004,0x0008,0x0010,0x0010,0x0020,0x0020,0x0000,0x0000 }, /* 47 */ + { 0x0000,0x0000,0x0000,0x001c,0x0036,0x0022,0x0022,0x0022,0x0022,0x0036,0x001c,0x0000,0x0000 }, /* 48 */ + { 0x0000,0x0000,0x0000,0x0038,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x003e,0x0000,0x0000 }, /* 49 */ + { 0x0000,0x0000,0x0000,0x001c,0x0022,0x0002,0x0002,0x0004,0x0008,0x0010,0x003e,0x0000,0x0000 }, /* 50 */ + { 0x0000,0x0000,0x0000,0x001c,0x0022,0x0002,0x001c,0x0002,0x0002,0x0022,0x001c,0x0000,0x0000 }, /* 51 */ + { 0x0000,0x0000,0x0000,0x0004,0x000c,0x0014,0x0024,0x0044,0x007e,0x0004,0x0004,0x0000,0x0000 }, /* 52 */ + { 0x0000,0x0000,0x0000,0x0078,0x0040,0x0040,0x0078,0x0004,0x0004,0x0004,0x0078,0x0000,0x0000 }, /* 53 */ + { 0x0000,0x0000,0x0000,0x000e,0x0010,0x0020,0x003c,0x0022,0x0022,0x0022,0x001c,0x0000,0x0000 }, /* 54 */ + { 0x0000,0x0000,0x0000,0x003e,0x0002,0x0004,0x0004,0x0008,0x0008,0x0008,0x0010,0x0000,0x0000 }, /* 55 */ + { 0x0000,0x0000,0x0000,0x001c,0x0022,0x0022,0x001c,0x0022,0x0022,0x0022,0x001c,0x0000,0x0000 }, /* 56 */ + { 0x0000,0x0000,0x0000,0x0038,0x0044,0x0044,0x0044,0x003c,0x0004,0x0008,0x0070,0x0000,0x0000 }, /* 57 */ + { 0x0000,0x0000,0x0000,0x0008,0x001c,0x0008,0x0000,0x0000,0x0008,0x001c,0x0008,0x0000,0x0000 }, /* 58 */ + { 0x0000,0x0000,0x0000,0x0000,0x0008,0x001c,0x0008,0x0000,0x0000,0x000c,0x0008,0x0010,0x0000 }, /* 59 */ + { 0x0000,0x0000,0x0002,0x0004,0x0008,0x0010,0x0020,0x0010,0x0008,0x0004,0x0002,0x0000,0x0000 }, /* 60 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x003e,0x0000,0x0000,0x003e,0x0000,0x0000,0x0000,0x0000 }, /* 61 */ + { 0x0000,0x0000,0x0020,0x0010,0x0008,0x0004,0x0002,0x0004,0x0008,0x0010,0x0020,0x0000,0x0000 }, /* 62 */ + { 0x0000,0x0000,0x001c,0x0022,0x0022,0x0002,0x0004,0x0008,0x0008,0x0000,0x0008,0x0000,0x0000 }, /* 63 */ + { 0x0000,0x0000,0x001c,0x0022,0x0022,0x0026,0x002a,0x002a,0x002c,0x0020,0x001e,0x0000,0x0000 }, /* 64 */ + { 0x0000,0x0000,0x0000,0x0010,0x0028,0x0028,0x0028,0x0044,0x007c,0x0044,0x0082,0x0000,0x0000 }, /* 65 */ + { 0x0000,0x0000,0x0000,0x007c,0x0042,0x0042,0x007c,0x0042,0x0042,0x0042,0x007c,0x0000,0x0000 }, /* 66 */ + { 0x0000,0x0000,0x0000,0x001c,0x0022,0x0040,0x0040,0x0040,0x0040,0x0022,0x001c,0x0000,0x0000 }, /* 67 */ + { 0x0000,0x0000,0x0000,0x00f0,0x0088,0x0084,0x0084,0x0084,0x0084,0x0088,0x00f0,0x0000,0x0000 }, /* 68 */ + { 0x0000,0x0000,0x0000,0x003e,0x0020,0x0020,0x003e,0x0020,0x0020,0x0020,0x003e,0x0000,0x0000 }, /* 69 */ + { 0x0000,0x0000,0x0000,0x003e,0x0020,0x0020,0x003e,0x0020,0x0020,0x0020,0x0020,0x0000,0x0000 }, /* 70 */ + { 0x0000,0x0000,0x0000,0x003c,0x0042,0x0080,0x0080,0x008e,0x0082,0x0042,0x003c,0x0000,0x0000 }, /* 71 */ + { 0x0000,0x0000,0x0000,0x0042,0x0042,0x0042,0x007e,0x0042,0x0042,0x0042,0x0042,0x0000,0x0000 }, /* 72 */ + { 0x0000,0x0000,0x0000,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0000,0x0000 }, /* 73 */ + { 0x0000,0x0000,0x0000,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x000c }, /* 74 */ + { 0x0000,0x0000,0x0000,0x0044,0x0048,0x0050,0x0060,0x0050,0x0048,0x0044,0x0042,0x0000,0x0000 }, /* 75 */ + { 0x0000,0x0000,0x0000,0x0020,0x0020,0x0020,0x0020,0x0020,0x0020,0x0020,0x003e,0x0000,0x0000 }, /* 76 */ + { 0x0000,0x0000,0x0000,0x0082,0x00c6,0x00c6,0x00aa,0x00aa,0x0092,0x0082,0x0082,0x0000,0x0000 }, /* 77 */ + { 0x0000,0x0000,0x0000,0x0062,0x0062,0x0052,0x0052,0x004a,0x004a,0x0046,0x0046,0x0000,0x0000 }, /* 78 */ + { 0x0000,0x0000,0x0000,0x0038,0x0044,0x0082,0x0082,0x0082,0x0082,0x0044,0x0038,0x0000,0x0000 }, /* 79 */ + { 0x0000,0x0000,0x0000,0x003c,0x0022,0x0022,0x0022,0x003c,0x0020,0x0020,0x0020,0x0000,0x0000 }, /* 80 */ + { 0x0000,0x0000,0x0000,0x0038,0x0044,0x0082,0x0082,0x0082,0x0082,0x0044,0x0038,0x000c,0x0000 }, /* 81 */ + { 0x0000,0x0000,0x0000,0x0078,0x0044,0x0044,0x0044,0x0078,0x0048,0x0044,0x0042,0x0000,0x0000 }, /* 82 */ + { 0x0000,0x0000,0x0000,0x003c,0x0042,0x0040,0x0078,0x0006,0x0002,0x0042,0x003c,0x0000,0x0000 }, /* 83 */ + { 0x0000,0x0000,0x0000,0x00fe,0x0010,0x0010,0x0010,0x0010,0x0010,0x0010,0x0010,0x0000,0x0000 }, /* 84 */ + { 0x0000,0x0000,0x0000,0x0042,0x0042,0x0042,0x0042,0x0042,0x0042,0x0066,0x003c,0x0000,0x0000 }, /* 85 */ + { 0x0000,0x0000,0x0000,0x0104,0x0104,0x0088,0x0088,0x0050,0x0050,0x0020,0x0020,0x0000,0x0000 }, /* 86 */ + { 0x0000,0x0000,0x0000,0x0222,0x0222,0x0124,0x0154,0x0154,0x0154,0x0088,0x0088,0x0000,0x0000 }, /* 87 */ + { 0x0000,0x0000,0x0000,0x0082,0x0044,0x0028,0x0010,0x0010,0x0028,0x0044,0x0082,0x0000,0x0000 }, /* 88 */ + { 0x0000,0x0000,0x0000,0x0082,0x0044,0x0028,0x0010,0x0010,0x0010,0x0010,0x0010,0x0000,0x0000 }, /* 89 */ + { 0x0000,0x0000,0x0000,0x00fe,0x0004,0x0008,0x0010,0x0010,0x0020,0x0040,0x00fe,0x0000,0x0000 }, /* 90 */ + { 0x0000,0x001c,0x0010,0x0010,0x0010,0x0010,0x0010,0x0010,0x0010,0x0010,0x0010,0x001c,0x0000 }, /* 91 */ + { 0x0000,0x0000,0x0020,0x0020,0x0010,0x0010,0x0008,0x0004,0x0004,0x0002,0x0002,0x0000,0x0000 }, /* 92 */ + { 0x0000,0x001c,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x001c,0x0000 }, /* 93 */ + { 0x0000,0x0000,0x0008,0x0014,0x0022,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 94 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x003e,0x0000 }, /* 95 */ + { 0x0000,0x0000,0x000c,0x0004,0x0002,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 96 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x001c,0x0002,0x001e,0x0022,0x0022,0x001e,0x0000,0x0000 }, /* 97 */ + { 0x0000,0x0000,0x0020,0x0020,0x0020,0x003c,0x0022,0x0022,0x0022,0x0022,0x003c,0x0000,0x0000 }, /* 98 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x000e,0x0010,0x0010,0x0010,0x0010,0x000e,0x0000,0x0000 }, /* 99 */ + { 0x0000,0x0000,0x0002,0x0002,0x0002,0x001e,0x0022,0x0022,0x0022,0x0022,0x001e,0x0000,0x0000 }, /* 100 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x001c,0x0022,0x003e,0x0020,0x0032,0x001c,0x0000,0x0000 }, /* 101 */ + { 0x0000,0x0000,0x000e,0x0008,0x0008,0x001e,0x0008,0x0008,0x0008,0x0008,0x0008,0x0000,0x0000 }, /* 102 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x001e,0x0022,0x0022,0x0022,0x0022,0x001e,0x0002,0x001c }, /* 103 */ + { 0x0000,0x0000,0x0020,0x0020,0x0020,0x0020,0x003c,0x0022,0x0022,0x0022,0x0022,0x0000,0x0000 }, /* 104 */ + { 0x0000,0x0000,0x0000,0x0000,0x0002,0x0000,0x0002,0x0002,0x0002,0x0002,0x0002,0x0000,0x0000 }, /* 105 */ + { 0x0000,0x0000,0x0000,0x0000,0x0002,0x0000,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0006 }, /* 106 */ + { 0x0000,0x0000,0x0040,0x0040,0x0040,0x0048,0x0050,0x0060,0x0050,0x0048,0x0044,0x0000,0x0000 }, /* 107 */ + { 0x0000,0x0000,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0000,0x0000 }, /* 108 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x03fc,0x0222,0x0222,0x0222,0x0222,0x0222,0x0000,0x0000 }, /* 109 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x003c,0x0022,0x0022,0x0022,0x0022,0x0022,0x0000,0x0000 }, /* 110 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x001c,0x0022,0x0022,0x0022,0x0022,0x001c,0x0000,0x0000 }, /* 111 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x003c,0x0022,0x0022,0x0022,0x0022,0x003c,0x0020,0x0020 }, /* 112 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x001e,0x0022,0x0022,0x0022,0x0022,0x001e,0x0002,0x0002 }, /* 113 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0016,0x0018,0x0010,0x0010,0x0010,0x0010,0x0000,0x0000 }, /* 114 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x001c,0x0022,0x0038,0x0006,0x0022,0x001c,0x0000,0x0000 }, /* 115 */ + { 0x0000,0x0000,0x0000,0x0008,0x0008,0x001e,0x0008,0x0008,0x0008,0x0008,0x000e,0x0000,0x0000 }, /* 116 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0022,0x0022,0x0022,0x0022,0x0022,0x001e,0x0000,0x0000 }, /* 117 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0042,0x0042,0x0024,0x0024,0x0018,0x0018,0x0000,0x0000 }, /* 118 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0092,0x0092,0x00aa,0x00aa,0x0044,0x0044,0x0000,0x0000 }, /* 119 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0042,0x0024,0x0018,0x0018,0x0024,0x0042,0x0000,0x0000 }, /* 120 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0042,0x0042,0x0024,0x0024,0x0018,0x0018,0x0010,0x0060 }, /* 121 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x003e,0x0002,0x0004,0x0008,0x0010,0x003e,0x0000,0x0000 }, /* 122 */ + { 0x0000,0x0006,0x0008,0x0008,0x0008,0x0008,0x0030,0x0008,0x0008,0x0008,0x0008,0x0006,0x0000 }, /* 123 */ + { 0x0000,0x0000,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x0000,0x0000 }, /* 124 */ + { 0x0000,0x0030,0x0008,0x0008,0x0008,0x0008,0x0006,0x0008,0x0008,0x0008,0x0008,0x0030,0x0000 }, /* 125 */ + { 0x0000,0x0000,0x0012,0x002a,0x0024,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 126 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 127 */ + { 0x0000,0x0000,0x000e,0x0010,0x0010,0x003c,0x0010,0x003c,0x0010,0x0010,0x000e,0x0000,0x0000 }, /* 128 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 129 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x000c,0x0004,0x0008,0x0000 }, /* 130 */ + { 0x0000,0x0000,0x0004,0x000a,0x0008,0x0008,0x001c,0x0008,0x0008,0x0008,0x0008,0x0028,0x0010 }, /* 131 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0036,0x0012,0x0024,0x0000 }, /* 132 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x002a,0x0000,0x0000 }, /* 133 */ + { 0x0000,0x0000,0x0008,0x0008,0x003e,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x0000,0x0000 }, /* 134 */ + { 0x0000,0x0000,0x0008,0x0008,0x003e,0x0008,0x0008,0x003e,0x0008,0x0008,0x0008,0x0000,0x0000 }, /* 135 */ + { 0x0000,0x000c,0x0012,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 136 */ + { 0x0000,0x0000,0x0012,0x002a,0x0014,0x0004,0x0008,0x0010,0x001a,0x0035,0x002a,0x0000,0x0000 }, /* 137 */ + { 0x0000,0x0012,0x000c,0x0000,0x001c,0x0022,0x0020,0x001c,0x0002,0x0022,0x001c,0x0000,0x0000 }, /* 138 */ + { 0x0000,0x0000,0x0000,0x0000,0x0004,0x0008,0x0010,0x0010,0x0008,0x0004,0x0000,0x0000,0x0000 }, /* 139 */ + { 0x0000,0x0000,0x001e,0x0028,0x0028,0x0028,0x002c,0x0028,0x0028,0x0028,0x001e,0x0000,0x0000 }, /* 140 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 141 */ + { 0x0000,0x0012,0x000c,0x0000,0x003e,0x0002,0x0004,0x0008,0x0010,0x0020,0x003e,0x0000,0x0000 }, /* 142 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 143 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 144 */ + { 0x0000,0x0000,0x0004,0x0008,0x000c,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 145 */ + { 0x0000,0x0000,0x000c,0x0004,0x0008,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 146 */ + { 0x0000,0x0000,0x0012,0x0024,0x0036,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 147 */ + { 0x0000,0x0000,0x0036,0x0012,0x0024,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 148 */ + { 0x0000,0x0000,0x0000,0x0000,0x001c,0x003e,0x003e,0x003e,0x001c,0x0000,0x0000,0x0000,0x0000 }, /* 149 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x003e,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 150 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x003f,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 151 */ + { 0x0000,0x000a,0x0014,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 152 */ + { 0x0000,0x0000,0x003d,0x0017,0x0015,0x0015,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 153 */ + { 0x0000,0x0000,0x0024,0x0018,0x0000,0x001c,0x0022,0x0018,0x0004,0x0022,0x001c,0x0000,0x0000 }, /* 154 */ + { 0x0000,0x0000,0x0000,0x0000,0x0010,0x0008,0x0004,0x0004,0x0008,0x0010,0x0000,0x0000,0x0000 }, /* 155 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0014,0x002a,0x002e,0x0028,0x002a,0x0014,0x0000,0x0000 }, /* 156 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 157 */ + { 0x0000,0x0000,0x0012,0x000c,0x0000,0x003e,0x0004,0x0008,0x0010,0x0020,0x003e,0x0000,0x0000 }, /* 158 */ + { 0x0000,0x0014,0x0014,0x0000,0x0022,0x0014,0x0014,0x0008,0x0008,0x0008,0x0008,0x0000,0x0000 }, /* 159 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 }, /* 160 */ + { 0x0000,0x0000,0x0000,0x0082,0x0044,0x0028,0x0010,0x0028,0x0044,0x0082,0x0000,0x0000,0x0000 }, /* 161 */ + { 0x0000,0x0000,0x0000,0x0038,0x0044,0x0082,0x0082,0x0082,0x0044,0x0038,0x0000,0x0000,0x0000 }, /* 162 */ + { 0x0000,0x0000,0x0000,0x0000,0x0020,0x0050,0x0088,0x0104,0x03fe,0x0000,0x0000,0x0000,0x0000 }, /* 163 */ + { 0x0000,0x0000,0x0000,0x00fe,0x0082,0x0082,0x0082,0x0082,0x0082,0x00fe,0x0000,0x0000,0x0000 }, /* 164 */ + { 0x0000,0x0000,0x01fe,0x0102,0x0102,0x0132,0x017a,0x0102,0x0084,0x0048,0x0030,0x0000,0x0000 }, /* 165 */ + { 0x0000,0x0000,0x0030,0x0048,0x0084,0x0102,0x017a,0x0132,0x0102,0x0102,0x01fe,0x0000,0x0000 }, /* 166 */ + { 0x0000,0x0000,0x0000,0x03f0,0x0208,0x0244,0x02c2,0x02c2,0x0244,0x0208,0x03f0,0x0000,0x0000 }, /* 167 */ + { 0x0000,0x0000,0x0000,0x007e,0x0082,0x0112,0x021a,0x021a,0x0112,0x0082,0x007e,0x0000,0x0000 }, /* 168 */ + { 0x0000,0x0000,0x00f8,0x0104,0x0222,0x0272,0x02aa,0x0222,0x0222,0x0104,0x00f8,0x0000,0x0000 }, /* 169 */ + { 0x0000,0x0000,0x00f8,0x0104,0x0222,0x0222,0x02aa,0x0272,0x0222,0x0104,0x00f8,0x0000,0x0000 }, /* 170 */ + { 0x0000,0x0000,0x00f8,0x0104,0x0222,0x0242,0x02fa,0x0242,0x0222,0x0104,0x00f8,0x0000,0x0000 }, /* 171 */ + { 0x0000,0x0000,0x00f8,0x0104,0x0222,0x0212,0x02fa,0x0212,0x0222,0x0104,0x00f8,0x0000,0x0000 }, /* 172 */ + { 0x0000,0x0000,0xfffe,0x8002,0x8402,0x8402,0x8402,0x8402,0x87c2,0x8002,0xfffe,0x0000,0x0000 }, /* 173 */ + { 0x0000,0x0000,0xfffe,0x8002,0x8782,0x8442,0x8782,0x8442,0x8442,0x8002,0xfffe,0x0000,0x0000 }, /* 174 */ + { 0x0000,0x0000,0x0000,0x6e8e,0x8888,0x8888,0x4c8c,0x2888,0x2888,0xceee,0x0000,0x0000,0x0000 }, /* 175 */ + { 0x0000,0x0000,0x0000,0x006e,0x0084,0x0084,0x0084,0x0084,0x0084,0x0064,0x0000,0x0000,0x0000 }, /* 176 */ + { 0x0000,0x0000,0x0000,0x6e4c,0x84aa,0x84aa,0x44ec,0x24aa,0x24aa,0xc4aa,0x0000,0x0000,0x0000 }, /* 177 */ + { 0x0000,0x0000,0x0000,0x000e,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0000,0x0000,0x0000 }, /* 178 */ + { 0x0000,0x0000,0x1ffe,0x1002,0x16da,0x76da,0x76da,0x76da,0x16da,0x1002,0x1ffe,0x0000,0x0000 }, /* 179 */ + { 0x0000,0x0000,0x1ffe,0x1002,0x10da,0x70da,0x70da,0x70da,0x10da,0x1002,0x1ffe,0x0000,0x0000 }, /* 180 */ + { 0x0000,0x0000,0x1ffe,0x1002,0x101a,0x701a,0x701a,0x701a,0x101a,0x1002,0x1ffe,0x0000,0x0000 }, /* 181 */ + { 0x0000,0x0000,0x1ffe,0x1002,0x1002,0x7002,0x7002,0x7002,0x1002,0x1002,0x1ffe,0x0000,0x0000 }, /* 182 */ + { 0x0000,0x0044,0x0044,0x00fe,0x0082,0x0082,0x0044,0x0038,0x0010,0x0008,0x0006,0x0000,0x0000 }, /* 183 */ + { 0x0000,0x0000,0x00f8,0x0104,0x0222,0x0222,0x023a,0x0202,0x0202,0x0104,0x00f8,0x0000,0x0000 }, /* 184 */ + { 0x0000,0x0000,0x7ffe,0x4002,0x4002,0x4002,0x4802,0x5802,0x4802,0x2002,0x1ffe,0x0000,0x0000 }, /* 185 */ + { 0x0000,0x0000,0x0008,0x001c,0x002a,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x0000,0x0000 }, /* 186 */ + { 0x0000,0x0000,0x0008,0x0008,0x0008,0x0008,0x0008,0x0008,0x002a,0x001c,0x0008,0x0000,0x0000 }, /* 187 */ + { 0x0000,0x0000,0x03fc,0x02ea,0x02ea,0x02fa,0x0202,0x02fa,0x02fa,0x02fa,0x03fe,0x0000,0x0000 }, /* 188 */ + { 0x0000,0x0000,0x0000,0x0000,0x0008,0x0008,0x003e,0x001c,0x0036,0x0022,0x0000,0x0000,0x0000 }, /* 189 */ + { 0x0000,0x0010,0x0028,0x0010,0x0008,0x0028,0x0012,0x0006,0x000a,0x000e,0x0002,0x0000,0x0000 }, /* 190 */ + { 0x0000,0x0000,0x0008,0x0000,0x0008,0x0008,0x0010,0x0020,0x0022,0x0022,0x001c,0x0000,0x0000 }, /* 191 */ + { 0x0000,0x0010,0x0008,0x0000,0x0008,0x0014,0x0022,0x0022,0x003e,0x0022,0x0022,0x0000,0x0000 }, /* 192 */ + { 0x0000,0x0004,0x0008,0x0000,0x0008,0x0014,0x0022,0x0022,0x003e,0x0022,0x0022,0x0000,0x0000 }, /* 193 */ + { 0x0000,0x000c,0x0012,0x0000,0x0008,0x0014,0x0022,0x0022,0x003e,0x0022,0x0022,0x0000,0x0000 }, /* 194 */ + { 0x0000,0x000a,0x0014,0x0000,0x0008,0x0014,0x0022,0x0022,0x003e,0x0022,0x0022,0x0000,0x0000 }, /* 195 */ + { 0x0000,0x0014,0x0014,0x0000,0x0008,0x0014,0x0022,0x0022,0x003e,0x0022,0x0022,0x0000,0x0000 }, /* 196 */ + { 0x0000,0x0008,0x0014,0x0008,0x0008,0x0014,0x0022,0x0022,0x003e,0x0022,0x0022,0x0000,0x0000 }, /* 197 */ + { 0x0000,0x0000,0x0016,0x0028,0x0028,0x0028,0x002c,0x0038,0x0028,0x0028,0x002e,0x0000,0x0000 }, /* 198 */ + { 0x0000,0x0000,0x001c,0x0022,0x0020,0x0020,0x0020,0x0020,0x0020,0x0022,0x001c,0x0008,0x0010 }, /* 199 */ + { 0x0000,0x0010,0x0008,0x0000,0x003e,0x0020,0x0020,0x003c,0x0020,0x0020,0x003e,0x0000,0x0000 }, /* 200 */ + { 0x0000,0x0004,0x0008,0x0000,0x003e,0x0020,0x0020,0x003c,0x0020,0x0020,0x003e,0x0000,0x0000 }, /* 201 */ + { 0x0000,0x000c,0x0012,0x0000,0x003e,0x0020,0x0020,0x003c,0x0020,0x0020,0x003e,0x0000,0x0000 }, /* 202 */ + { 0x0000,0x0014,0x0014,0x0000,0x003e,0x0020,0x0020,0x003c,0x0020,0x0020,0x003e,0x0000,0x0000 }, /* 203 */ + { 0x0000,0x0010,0x0008,0x0000,0x001c,0x0008,0x0008,0x0008,0x0008,0x0008,0x001c,0x0000,0x0000 }, /* 204 */ + { 0x0000,0x0004,0x0008,0x0000,0x001c,0x0008,0x0008,0x0008,0x0008,0x0008,0x001c,0x0000,0x0000 }, /* 205 */ + { 0x0000,0x000c,0x0012,0x0000,0x001c,0x0008,0x0008,0x0008,0x0008,0x0008,0x001c,0x0000,0x0000 }, /* 206 */ + { 0x0000,0x0014,0x0014,0x0000,0x001c,0x0008,0x0008,0x0008,0x0008,0x0008,0x001c,0x0000,0x0000 }, /* 207 */ + { 0x0000,0x0000,0x003c,0x0012,0x0012,0x0012,0x003a,0x0012,0x0012,0x0012,0x003c,0x0000,0x0000 }, /* 208 */ + { 0x0000,0x000a,0x0014,0x0000,0x0022,0x0022,0x0032,0x002a,0x0026,0x0022,0x0022,0x0000,0x0000 }, /* 209 */ + { 0x0000,0x0010,0x0008,0x0000,0x001c,0x0022,0x0022,0x0022,0x0022,0x0022,0x001c,0x0000,0x0000 }, /* 210 */ + { 0x0000,0x0004,0x0008,0x0000,0x001c,0x0022,0x0022,0x0022,0x0022,0x0022,0x001c,0x0000,0x0000 }, /* 211 */ + { 0x0000,0x000c,0x0012,0x0000,0x001c,0x0022,0x0022,0x0022,0x0022,0x0022,0x001c,0x0000,0x0000 }, /* 212 */ + { 0x0000,0x000a,0x0014,0x0000,0x001c,0x0022,0x0022,0x0022,0x0022,0x0022,0x001c,0x0000,0x0000 }, /* 213 */ + { 0x0000,0x0014,0x0014,0x0000,0x001c,0x0022,0x0022,0x0022,0x0022,0x0022,0x001c,0x0000,0x0000 }, /* 214 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0022,0x0014,0x0008,0x0014,0x0022,0x0000,0x0000,0x0000 }, /* 215 */ + { 0x0000,0x0002,0x001c,0x0026,0x0026,0x002a,0x002a,0x002a,0x0032,0x0032,0x001c,0x0020,0x0000 }, /* 216 */ + { 0x0000,0x0010,0x0008,0x0000,0x0022,0x0022,0x0022,0x0022,0x0022,0x0022,0x001c,0x0000,0x0000 }, /* 217 */ + { 0x0000,0x0004,0x0008,0x0000,0x0022,0x0022,0x0022,0x0022,0x0022,0x0022,0x001c,0x0000,0x0000 }, /* 218 */ + { 0x0000,0x000c,0x0012,0x0000,0x0022,0x0022,0x0022,0x0022,0x0022,0x0022,0x001c,0x0000,0x0000 }, /* 219 */ + { 0x0000,0x0014,0x0014,0x0000,0x0022,0x0022,0x0022,0x0022,0x0022,0x0022,0x001c,0x0000,0x0000 }, /* 220 */ + { 0x0000,0x0004,0x0008,0x0000,0x0022,0x0022,0x0014,0x0008,0x0008,0x0008,0x0008,0x0000,0x0000 }, /* 221 */ + { 0x0000,0x0000,0x0020,0x003c,0x0022,0x0022,0x0022,0x003c,0x0020,0x0020,0x0020,0x0000,0x0000 }, /* 222 */ + { 0x0000,0x0000,0x0018,0x0024,0x0024,0x0028,0x0028,0x0024,0x0022,0x0022,0x002c,0x0000,0x0000 }, /* 223 */ + { 0x0000,0x0000,0x0010,0x0008,0x0000,0x001c,0x0002,0x001e,0x0022,0x0026,0x001a,0x0000,0x0000 }, /* 224 */ + { 0x0000,0x0000,0x0004,0x0008,0x0000,0x001c,0x0002,0x001e,0x0022,0x0026,0x001a,0x0000,0x0000 }, /* 225 */ + { 0x0000,0x0000,0x000c,0x0012,0x0000,0x001c,0x0002,0x001e,0x0022,0x0026,0x001a,0x0000,0x0000 }, /* 226 */ + { 0x0000,0x0000,0x000a,0x0014,0x0000,0x001c,0x0002,0x001e,0x0022,0x0026,0x001a,0x0000,0x0000 }, /* 227 */ + { 0x0000,0x0000,0x0014,0x0014,0x0000,0x001c,0x0002,0x001e,0x0022,0x0026,0x001a,0x0000,0x0000 }, /* 228 */ + { 0x0000,0x000c,0x0012,0x000c,0x0000,0x001c,0x0002,0x001e,0x0022,0x0026,0x001a,0x0000,0x0000 }, /* 229 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x001c,0x000a,0x001c,0x0028,0x002a,0x0014,0x0000,0x0000 }, /* 230 */ + { 0x0000,0x0000,0x0000,0x0000,0x0000,0x001c,0x0022,0x0020,0x0020,0x0022,0x001c,0x0008,0x0010 }, /* 231 */ + { 0x0000,0x0000,0x0010,0x0008,0x0000,0x001c,0x0022,0x003e,0x0020,0x0022,0x001c,0x0000,0x0000 }, /* 232 */ + { 0x0000,0x0000,0x0004,0x0008,0x0000,0x001c,0x0022,0x003e,0x0020,0x0022,0x001c,0x0000,0x0000 }, /* 233 */ + { 0x0000,0x0000,0x000c,0x0012,0x0000,0x001c,0x0022,0x003e,0x0020,0x0022,0x001c,0x0000,0x0000 }, /* 234 */ + { 0x0000,0x0000,0x0014,0x0014,0x0000,0x001c,0x0022,0x003e,0x0020,0x0022,0x001c,0x0000,0x0000 }, /* 235 */ + { 0x0000,0x0000,0x0010,0x0008,0x0000,0x0018,0x0008,0x0008,0x0008,0x0008,0x001c,0x0000,0x0000 }, /* 236 */ + { 0x0000,0x0000,0x0004,0x0008,0x0000,0x0018,0x0008,0x0008,0x0008,0x0008,0x001c,0x0000,0x0000 }, /* 237 */ + { 0x0000,0x0000,0x000c,0x0012,0x0000,0x0018,0x0008,0x0008,0x0008,0x0008,0x001c,0x0000,0x0000 }, /* 238 */ + { 0x0000,0x0000,0x0014,0x0014,0x0000,0x0018,0x0008,0x0008,0x0008,0x0008,0x001c,0x0000,0x0000 }, /* 239 */ + { 0x0000,0x0014,0x0008,0x0018,0x0004,0x001c,0x0022,0x0022,0x0022,0x0022,0x001c,0x0000,0x0000 }, /* 240 */ + { 0x0000,0x0000,0x000a,0x0014,0x0000,0x002c,0x0032,0x0022,0x0022,0x0022,0x0022,0x0000,0x0000 }, /* 241 */ + { 0x0000,0x0000,0x0010,0x0008,0x0000,0x001c,0x0022,0x0022,0x0022,0x0022,0x001c,0x0000,0x0000 }, /* 242 */ + { 0x0000,0x0000,0x0004,0x0008,0x0000,0x001c,0x0022,0x0022,0x0022,0x0022,0x001c,0x0000,0x0000 }, /* 243 */ + { 0x0000,0x0000,0x000c,0x0012,0x0000,0x001c,0x0022,0x0022,0x0022,0x0022,0x001c,0x0000,0x0000 }, /* 244 */ + { 0x0000,0x0000,0x000a,0x0014,0x0000,0x001c,0x0022,0x0022,0x0022,0x0022,0x001c,0x0000,0x0000 }, /* 245 */ + { 0x0000,0x0000,0x0014,0x0014,0x0000,0x001c,0x0022,0x0022,0x0022,0x0022,0x001c,0x0000,0x0000 }, /* 246 */ + { 0x0000,0x0000,0x0000,0x0008,0x0008,0x0000,0x003e,0x0000,0x0008,0x0008,0x0000,0x0000,0x0000 }, /* 247 */ + { 0x0000,0x0000,0x0000,0x0000,0x0002,0x001c,0x0026,0x002a,0x002a,0x0032,0x001c,0x0020,0x0000 }, /* 248 */ + { 0x0000,0x0000,0x0010,0x0008,0x0000,0x0022,0x0022,0x0022,0x0022,0x0026,0x001a,0x0000,0x0000 }, /* 249 */ + { 0x0000,0x0000,0x0004,0x0008,0x0000,0x0022,0x0022,0x0022,0x0022,0x0026,0x001a,0x0000,0x0000 }, /* 250 */ + { 0x0000,0x0000,0x000c,0x0012,0x0000,0x0022,0x0022,0x0022,0x0022,0x0026,0x001a,0x0000,0x0000 }, /* 251 */ + { 0x0000,0x0000,0x0014,0x0014,0x0000,0x0022,0x0022,0x0022,0x0022,0x0026,0x001a,0x0000,0x0000 }, /* 252 */ + { 0x0000,0x0000,0x0004,0x0008,0x0000,0x0022,0x0022,0x0022,0x0026,0x001a,0x0002,0x0022,0x001c }, /* 253 */ + { 0x0000,0x0000,0x0000,0x0020,0x0020,0x002c,0x0032,0x0022,0x0022,0x0032,0x002c,0x0020,0x0020 }, /* 254 */ + { 0x0000,0x0000,0x0014,0x0014,0x0000,0x0022,0x0022,0x0022,0x0026,0x001a,0x0002,0x0022,0x001c }, /* 255 */ +}; + +const PspFont PspStockFont = +{ 13, 11, + { + { 0x06,_ch[0x00] },{ 0x06,_ch[0x01] },{ 0x06,_ch[0x02] },{ 0x06,_ch[0x03] }, + { 0x06,_ch[0x04] },{ 0x06,_ch[0x05] },{ 0x06,_ch[0x06] },{ 0x06,_ch[0x07] }, + { 0x06,_ch[0x08] },{ 0x06,_ch[0x09] },{ 0x06,_ch[0x0a] },{ 0x06,_ch[0x0b] }, + { 0x06,_ch[0x0c] },{ 0x06,_ch[0x0d] },{ 0x06,_ch[0x0e] },{ 0x06,_ch[0x0f] }, + { 0x06,_ch[0x10] },{ 0x06,_ch[0x11] },{ 0x06,_ch[0x12] },{ 0x06,_ch[0x13] }, + { 0x06,_ch[0x14] },{ 0x06,_ch[0x15] },{ 0x06,_ch[0x16] },{ 0x06,_ch[0x17] }, + { 0x06,_ch[0x18] },{ 0x06,_ch[0x19] },{ 0x06,_ch[0x1a] },{ 0x06,_ch[0x1b] }, + { 0x06,_ch[0x1c] },{ 0x06,_ch[0x1d] },{ 0x06,_ch[0x1e] },{ 0x06,_ch[0x1f] }, + { 0x06,_ch[0x20] },{ 0x06,_ch[0x21] },{ 0x06,_ch[0x22] },{ 0x06,_ch[0x23] }, + { 0x06,_ch[0x24] },{ 0x06,_ch[0x25] },{ 0x06,_ch[0x26] },{ 0x06,_ch[0x27] }, + { 0x06,_ch[0x28] },{ 0x06,_ch[0x29] },{ 0x06,_ch[0x2a] },{ 0x06,_ch[0x2b] }, + { 0x06,_ch[0x2c] },{ 0x06,_ch[0x2d] },{ 0x06,_ch[0x2e] },{ 0x06,_ch[0x2f] }, + { 0x06,_ch[0x30] },{ 0x06,_ch[0x31] },{ 0x06,_ch[0x32] },{ 0x06,_ch[0x33] }, + { 0x07,_ch[0x34] },{ 0x07,_ch[0x35] },{ 0x06,_ch[0x36] },{ 0x06,_ch[0x37] }, + { 0x06,_ch[0x38] },{ 0x07,_ch[0x39] },{ 0x06,_ch[0x3a] },{ 0x06,_ch[0x3b] }, + { 0x06,_ch[0x3c] },{ 0x06,_ch[0x3d] },{ 0x06,_ch[0x3e] },{ 0x06,_ch[0x3f] }, + { 0x06,_ch[0x40] },{ 0x08,_ch[0x41] },{ 0x07,_ch[0x42] },{ 0x07,_ch[0x43] }, + { 0x08,_ch[0x44] },{ 0x06,_ch[0x45] },{ 0x06,_ch[0x46] },{ 0x08,_ch[0x47] }, + { 0x07,_ch[0x48] },{ 0x02,_ch[0x49] },{ 0x04,_ch[0x4a] },{ 0x07,_ch[0x4b] }, + { 0x06,_ch[0x4c] },{ 0x08,_ch[0x4d] },{ 0x07,_ch[0x4e] },{ 0x08,_ch[0x4f] }, + { 0x06,_ch[0x50] },{ 0x08,_ch[0x51] },{ 0x07,_ch[0x52] },{ 0x07,_ch[0x53] }, + { 0x08,_ch[0x54] },{ 0x07,_ch[0x55] },{ 0x09,_ch[0x56] },{ 0x0a,_ch[0x57] }, + { 0x08,_ch[0x58] },{ 0x08,_ch[0x59] },{ 0x08,_ch[0x5a] },{ 0x06,_ch[0x5b] }, + { 0x06,_ch[0x5c] },{ 0x06,_ch[0x5d] },{ 0x06,_ch[0x5e] },{ 0x06,_ch[0x5f] }, + { 0x06,_ch[0x60] },{ 0x06,_ch[0x61] },{ 0x06,_ch[0x62] },{ 0x05,_ch[0x63] }, + { 0x06,_ch[0x64] },{ 0x06,_ch[0x65] },{ 0x05,_ch[0x66] },{ 0x06,_ch[0x67] }, + { 0x06,_ch[0x68] },{ 0x02,_ch[0x69] },{ 0x03,_ch[0x6a] },{ 0x07,_ch[0x6b] }, + { 0x02,_ch[0x6c] },{ 0x0a,_ch[0x6d] },{ 0x06,_ch[0x6e] },{ 0x06,_ch[0x6f] }, + { 0x06,_ch[0x70] },{ 0x06,_ch[0x71] },{ 0x05,_ch[0x72] },{ 0x06,_ch[0x73] }, + { 0x05,_ch[0x74] },{ 0x06,_ch[0x75] },{ 0x07,_ch[0x76] },{ 0x08,_ch[0x77] }, + { 0x07,_ch[0x78] },{ 0x07,_ch[0x79] },{ 0x06,_ch[0x7a] },{ 0x06,_ch[0x7b] }, + { 0x06,_ch[0x7c] },{ 0x06,_ch[0x7d] },{ 0x06,_ch[0x7e] },{ 0x06,_ch[0x7f] }, + { 0x06,_ch[0x80] },{ 0x06,_ch[0x81] },{ 0x06,_ch[0x82] },{ 0x06,_ch[0x83] }, + { 0x06,_ch[0x84] },{ 0x06,_ch[0x85] },{ 0x06,_ch[0x86] },{ 0x06,_ch[0x87] }, + { 0x06,_ch[0x88] },{ 0x06,_ch[0x89] },{ 0x06,_ch[0x8a] },{ 0x06,_ch[0x8b] }, + { 0x06,_ch[0x8c] },{ 0x06,_ch[0x8d] },{ 0x06,_ch[0x8e] },{ 0x06,_ch[0x8f] }, + { 0x06,_ch[0x90] },{ 0x06,_ch[0x91] },{ 0x06,_ch[0x92] },{ 0x06,_ch[0x93] }, + { 0x06,_ch[0x94] },{ 0x06,_ch[0x95] },{ 0x06,_ch[0x96] },{ 0x06,_ch[0x97] }, + { 0x06,_ch[0x98] },{ 0x06,_ch[0x99] },{ 0x06,_ch[0x9a] },{ 0x06,_ch[0x9b] }, + { 0x06,_ch[0x9c] },{ 0x06,_ch[0x9d] },{ 0x06,_ch[0x9e] },{ 0x06,_ch[0x9f] }, + { 0x06,_ch[0xa0] },{ 0x09,_ch[0xa1] },{ 0x09,_ch[0xa2] },{ 0x0a,_ch[0xa3] }, + { 0x09,_ch[0xa4] },{ 0x0a,_ch[0xa5] },{ 0x0a,_ch[0xa6] },{ 0x0b,_ch[0xa7] }, + { 0x0b,_ch[0xa8] },{ 0x0a,_ch[0xa9] },{ 0x0a,_ch[0xaa] },{ 0x0a,_ch[0xab] }, + { 0x0a,_ch[0xac] },{ 0x10,_ch[0xad] },{ 0x10,_ch[0xae] },{ 0x10,_ch[0xaf] }, + { 0x08,_ch[0xb0] },{ 0x10,_ch[0xb1] },{ 0x04,_ch[0xb2] },{ 0x0f,_ch[0xb3] }, + { 0x0f,_ch[0xb4] },{ 0x0f,_ch[0xb5] },{ 0x0f,_ch[0xb6] },{ 0x09,_ch[0xb7] }, + { 0x0a,_ch[0xb8] },{ 0x0f,_ch[0xb9] },{ 0x06,_ch[0xba] },{ 0x06,_ch[0xbb] }, + { 0x0a,_ch[0xbc] },{ 0x06,_ch[0xbd] },{ 0x06,_ch[0xbe] },{ 0x06,_ch[0xbf] }, + { 0x06,_ch[0xc0] },{ 0x06,_ch[0xc1] },{ 0x06,_ch[0xc2] },{ 0x06,_ch[0xc3] }, + { 0x06,_ch[0xc4] },{ 0x06,_ch[0xc5] },{ 0x06,_ch[0xc6] },{ 0x06,_ch[0xc7] }, + { 0x06,_ch[0xc8] },{ 0x06,_ch[0xc9] },{ 0x06,_ch[0xca] },{ 0x06,_ch[0xcb] }, + { 0x06,_ch[0xcc] },{ 0x06,_ch[0xcd] },{ 0x06,_ch[0xce] },{ 0x06,_ch[0xcf] }, + { 0x06,_ch[0xd0] },{ 0x06,_ch[0xd1] },{ 0x06,_ch[0xd2] },{ 0x06,_ch[0xd3] }, + { 0x06,_ch[0xd4] },{ 0x06,_ch[0xd5] },{ 0x06,_ch[0xd6] },{ 0x06,_ch[0xd7] }, + { 0x06,_ch[0xd8] },{ 0x06,_ch[0xd9] },{ 0x06,_ch[0xda] },{ 0x06,_ch[0xdb] }, + { 0x06,_ch[0xdc] },{ 0x06,_ch[0xdd] },{ 0x06,_ch[0xde] },{ 0x06,_ch[0xdf] }, + { 0x06,_ch[0xe0] },{ 0x06,_ch[0xe1] },{ 0x06,_ch[0xe2] },{ 0x06,_ch[0xe3] }, + { 0x06,_ch[0xe4] },{ 0x06,_ch[0xe5] },{ 0x06,_ch[0xe6] },{ 0x06,_ch[0xe7] }, + { 0x06,_ch[0xe8] },{ 0x06,_ch[0xe9] },{ 0x06,_ch[0xea] },{ 0x06,_ch[0xeb] }, + { 0x06,_ch[0xec] },{ 0x06,_ch[0xed] },{ 0x06,_ch[0xee] },{ 0x06,_ch[0xef] }, + { 0x06,_ch[0xf0] },{ 0x06,_ch[0xf1] },{ 0x06,_ch[0xf2] },{ 0x06,_ch[0xf3] }, + { 0x06,_ch[0xf4] },{ 0x06,_ch[0xf5] },{ 0x06,_ch[0xf6] },{ 0x06,_ch[0xf7] }, + { 0x06,_ch[0xf8] },{ 0x06,_ch[0xf9] },{ 0x06,_ch[0xfa] },{ 0x06,_ch[0xfb] }, + { 0x06,_ch[0xfc] },{ 0x06,_ch[0xfd] },{ 0x06,_ch[0xfe] },{ 0x06,_ch[0xff] }, + } +}; diff --git a/psp/psplib/ui.c b/psp/psplib/ui.c new file mode 100644 index 0000000..d847658 --- /dev/null +++ b/psp/psplib/ui.c @@ -0,0 +1,2846 @@ +/* psplib/ui.c + Simple user interface implementation + + Copyright (C) 2007-2008 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: pspdev@akop.org +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pl_psp.h" +#include "pl_file.h" +#include "ctrl.h" +#include "ui.h" +#include "font.h" + +int tipo_consola; + +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +#define UI_ANIM_FRAMES 8 +#define UI_ANIM_FOG_STEP 0x0f + +#define ADHOC_INITIALIZING "Initializing Ad-hoc networking. Please wait..." +#define ADHOC_AWAITING_JOIN "Waiting for someone to join..." + +#define CONTROL_BUTTON_MASK \ + (PSP_CTRL_CIRCLE | PSP_CTRL_TRIANGLE | PSP_CTRL_CROSS | PSP_CTRL_SQUARE | \ + PSP_CTRL_LTRIGGER | PSP_CTRL_RTRIGGER | PSP_CTRL_SELECT | PSP_CTRL_START) + +static const char + *AlertDialogButtonTemplate = "\026\001\020/\026\002\020 Close", + *ConfirmDialogButtonTemplate = "\026\001\020 Confirm\t\026\002\020 Cancel", + *YesNoCancelDialogButtonTemplate = + "\026\001\020 Yes\t\026"PSP_CHAR_SQUARE"\020 No\t\026\002\020 Cancel", + + *SelectorTemplate = "\026\001\020 Confirm\t\026\002\020 Cancel", + + *BrowserTemplates[] = { + "\026\002\020 Cancel\t\026\001\020 Open", + "\026\002\020 Cancel\t\026\001\020 Enter directory", + "\026\002\020 Cancel\t\026\001\020 Open\t\026"PSP_CHAR_TRIANGLE"\020 Parent directory", + "\026\002\020 Cancel\t\026\001\020 Enter directory\t\026"PSP_CHAR_TRIANGLE"\020 Parent directory" + }, + + *SplashStatusBarTemplate = "\026\255\020/\026\256\020 Switch tabs", + + *OptionModeTemplate = + "\026\245\020/\026\246\020 Select\t\026\247\020/\026\002\020 Cancel\t\026\250\020/\026\001\020 Confirm"; + +enum +{ + BrowserTemplateOpenTop = 0, + BrowserTemplateEnterTop = 1, + BrowserTemplateOpen = 2, + BrowserTemplateEnter = 3, +}; + +void enter_directory(pl_file_path current_dir, + const char *subdir); + +#define BROWSER_TEMPLATE_COUNT 4 + +struct UiPos +{ + int Index; + int Offset; + const pl_menu_item *Top; +}; + +struct AdhocMatchEvent +{ + int NewEvent; + int EventID; + PspMAC EventMAC; + PspMAC CurrentMAC; + char OptData[512]; +}; + +static struct AdhocMatchEvent _adhoc_match_event; + +static void adhocMatchingCallback(int unk1, + int event, + unsigned char *mac2, + int opt_len, + void *opt_data); + +#define ADHOC_PENDING 0 +#define ADHOC_WAIT_CLI 1 +#define ADHOC_WAIT_HOST 2 +#define ADHOC_WAIT_EST 3 +#define ADHOC_ESTABLISHED 4 +#define ADHOC_EST_AS_CLI 5 + +#ifndef MATCHING_JOINED +#define MATCHING_JOINED PSP_ADHOC_MATCHING_EVENT_JOIN +#define MATCHING_DISCONNECT PSP_ADHOC_MATCHING_EVENT_LEFT +#define MATCHING_CANCELED PSP_ADHOC_MATCHING_EVENT_CANCEL +#define MATCHING_SELECTED PSP_ADHOC_MATCHING_EVENT_ACCEPT +#define MATCHING_REJECTED PSP_ADHOC_MATCHING_EVENT_REJECT +#define MATCHING_ESTABLISHED PSP_ADHOC_MATCHING_EVENT_COMPLETE +#endif + +/* TODO: dynamically allocate ?? */ +static unsigned int __attribute__((aligned(16))) call_list[524288];//262144]; + +/* Gets status string - containing current time and battery information */ +static void GetStatusString(char *status, int length) +{ + static char main_str[128], batt_str[32]; + pspTime time; + + /* Get current time */ + sceRtcGetCurrentClockLocalTime(&time); + + /* Get the battery/power-related information */ + if (!scePowerIsBatteryExist()) sprintf(batt_str, PSP_CHAR_POWER); + else + { + /* If the battery's online, display charging stats */ + int batt_time = scePowerGetBatteryLifeTime(); + int batt_percent = scePowerGetBatteryLifePercent(); + int i, charging = scePowerIsBatteryCharging(); + + static int percentiles[] = { 60, 30, 12, 0 }; + for (i = 0; i < 4; i++) + if (batt_percent >= percentiles[i]) + break; + + /* Fix for when battery switches state from AC to batt */ + batt_time = (batt_time >= 0) ? batt_time : 0; + + sprintf(batt_str, "%c%3i%% (%02i:%02i)", + (charging) ? *PSP_CHAR_POWER : *PSP_CHAR_FULL_BATT + i, + batt_percent, batt_time / 60, batt_time % 60); + } + + /* Write the rest of the string */ + sprintf(main_str, "\270%2i/%2i %02i%c%02i %s ", + time.month, time.day, time.hour, (time.microseconds > 500000) ? ':' : ' ', + time.minutes, batt_str); + + strncpy(status, main_str, length); + status[length - 1] = '\0'; +} + +static inline void RenderStatus() +{ + static char status[128]; + GetStatusString(status, sizeof(status)); + + int width = pspFontGetTextWidth(UiMetric.Font, status); + pspVideoPrint(UiMetric.Font, SCR_WIDTH - width, 0, status, PSP_COLOR_WHITE); +} + +static void ReplaceIcons(char *string) +{ + char *ch; + + for (ch = string; *ch; ch++) + { + switch(*ch) + { + case '\001': *ch = pspUiGetButtonIcon(UiMetric.OkButton); break; + case '\002': *ch = pspUiGetButtonIcon(UiMetric.CancelButton); break; + } + } +} + +char pspUiGetButtonIcon(u32 button_mask) +{ + switch (button_mask) + { + case PSP_CTRL_CROSS: return *PSP_CHAR_CROSS; + case PSP_CTRL_CIRCLE: return *PSP_CHAR_CIRCLE; + case PSP_CTRL_TRIANGLE: return *PSP_CHAR_TRIANGLE; + case PSP_CTRL_SQUARE: return *PSP_CHAR_SQUARE; + default: return '?'; + } +} + +void pspUiAlert(const char *message) +{ + PspImage *screen = NULL; + int sx, sy, dx, dy, th, fh, mw, cw, w, h; + int i, n = UI_ANIM_FRAMES; + char *instr = strdup(AlertDialogButtonTemplate); + ReplaceIcons(instr); + + mw = pspFontGetTextWidth(UiMetric.Font, message); + cw = pspFontGetTextWidth(UiMetric.Font, instr); + fh = pspFontGetLineHeight(UiMetric.Font); + th = pspFontGetTextHeight(UiMetric.Font, message); + + w = ((mw > cw) ? mw : cw) + 50; + h = th + fh * 3; + sx = SCR_WIDTH / 2 - w / 2; + sy = SCR_HEIGHT / 2 - h / 2; + dx = sx + w; + dy = sy + h; + + /* Intro animation */ + if (UiMetric.Animate) + { + /* Get copy of screen */ + screen = pspVideoGetVramBufferCopy(); + + for (i = 0; i < n; i++) + { + pspVideoBegin(); + + /* Clear screen */ + pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height); + + /* Apply fog and draw frame */ + pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT, + COLOR(0,0,0,UI_ANIM_FOG_STEP*i)); + pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2, + SCR_HEIGHT/2-(((dy-sy)/n)*i)/2, + SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2, + COLOR(RED_32(UiMetric.MenuOptionBoxBg), + GREEN_32(UiMetric.MenuOptionBoxBg), + BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i)); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + } + } + + pspVideoBegin(); + + if (UiMetric.Animate) + pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height); + + pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT, + COLOR(0,0,0,UI_ANIM_FOG_STEP*n)); + pspVideoFillRect(sx, sy, dx, dy, UiMetric.MenuOptionBoxBg); + pspVideoPrint(UiMetric.Font, SCR_WIDTH / 2 - mw / 2, sy + fh * 0.5, message, + UiMetric.TextColor); + pspVideoPrint(UiMetric.Font, SCR_WIDTH / 2 - cw / 2, dy - fh * 1.5, instr, + UiMetric.TextColor); + pspVideoGlowRect(sx, sy, dx - 1, dy - 1, + COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP*n), 2); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + + SceCtrlData pad; + + /* Loop until X or O is pressed */ + while (!ExitPSP) + { + if (!pspCtrlPollControls(&pad)) + continue; + + if (pad.Buttons & UiMetric.OkButton || pad.Buttons & UiMetric.CancelButton) + break; + } + + if (!ExitPSP && UiMetric.Animate) + { + /* Exit animation */ + for (i = n - 1; i >= 0; i--) + { + pspVideoBegin(); + + /* Clear screen */ + pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height); + + /* Apply fog and draw frame */ + pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT, + COLOR(0,0,0,UI_ANIM_FOG_STEP*i)); + pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2, + SCR_HEIGHT/2-(((dy-sy)/n)*i)/2, + SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2, + COLOR(RED_32(UiMetric.MenuOptionBoxBg), + GREEN_32(UiMetric.MenuOptionBoxBg), + BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i)); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + } + } + + if (screen) pspImageDestroy(screen); + free(instr); +} + +int pspUiYesNoCancel(const char *message) +{ + PspImage *screen = NULL; + int sx, sy, dx, dy, th, fh, mw, cw, w, h; + int i, n = UI_ANIM_FRAMES; + char *instr = strdup(YesNoCancelDialogButtonTemplate); + ReplaceIcons(instr); + + mw = pspFontGetTextWidth(UiMetric.Font, message); + cw = pspFontGetTextWidth(UiMetric.Font, instr); + fh = pspFontGetLineHeight(UiMetric.Font); + th = pspFontGetTextHeight(UiMetric.Font, message); + + w = ((mw > cw) ? mw : cw) + 50; + h = th + fh * 3; + sx = SCR_WIDTH / 2 - w / 2; + sy = SCR_HEIGHT / 2 - h / 2; + dx = sx + w; + dy = sy + h; + + /* Intro animation */ + if (UiMetric.Animate) + { + /* Get copy of screen */ + screen = pspVideoGetVramBufferCopy(); + + for (i = 0; i < n; i++) + { + pspVideoBegin(); + + /* Clear screen */ + pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height); + + /* Apply fog and draw frame */ + pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT, + COLOR(0,0,0,UI_ANIM_FOG_STEP*i)); + pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2, + SCR_HEIGHT/2-(((dy-sy)/n)*i)/2, + SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2, + COLOR(RED_32(UiMetric.MenuOptionBoxBg), + GREEN_32(UiMetric.MenuOptionBoxBg), + BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i)); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + } + } + + pspVideoBegin(); + + if (UiMetric.Animate) + pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height); + pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT, + COLOR(0,0,0,UI_ANIM_FOG_STEP*n)); + pspVideoFillRect(sx, sy, dx, dy, UiMetric.MenuOptionBoxBg); + pspVideoPrint(UiMetric.Font, SCR_WIDTH / 2 - mw / 2, sy + fh * 0.5, message, + UiMetric.TextColor); + pspVideoPrint(UiMetric.Font, SCR_WIDTH / 2 - cw / 2, dy - fh * 1.5, instr, + UiMetric.TextColor); + pspVideoGlowRect(sx, sy, dx - 1, dy - 1, + COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP*n), 2); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + + SceCtrlData pad; + + /* Loop until X or O is pressed */ + while (!ExitPSP) + { + if (!pspCtrlPollControls(&pad)) + continue; + + if (pad.Buttons & UiMetric.OkButton || pad.Buttons & UiMetric.CancelButton + || pad.Buttons & PSP_CTRL_SQUARE) break; + } + + if (!ExitPSP && UiMetric.Animate) + { + /* Exit animation */ + for (i = n - 1; i >= 0; i--) + { + pspVideoBegin(); + + /* Clear screen */ + pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height); + + /* Apply fog and draw frame */ + pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT, + COLOR(0,0,0,UI_ANIM_FOG_STEP*i)); + pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2, + SCR_HEIGHT/2-(((dy-sy)/n)*i)/2, + SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2, + COLOR(RED_32(UiMetric.MenuOptionBoxBg), + GREEN_32(UiMetric.MenuOptionBoxBg), + BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i)); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + } + } + + if (screen) pspImageDestroy(screen); + free(instr); + + if (pad.Buttons & UiMetric.CancelButton) return PSP_UI_CANCEL; + else if (pad.Buttons & PSP_CTRL_SQUARE) return PSP_UI_NO; + else return PSP_UI_YES; +} + +int pspUiConfirm(const char *message) +{ + PspImage *screen = NULL; + int sx, sy, dx, dy, th, fh, mw, cw, w, h; + int i, n = UI_ANIM_FRAMES; + char *instr = strdup(ConfirmDialogButtonTemplate); + ReplaceIcons(instr); + + mw = pspFontGetTextWidth(UiMetric.Font, message); + cw = pspFontGetTextWidth(UiMetric.Font, instr); + fh = pspFontGetLineHeight(UiMetric.Font); + th = pspFontGetTextHeight(UiMetric.Font, message); + + w = ((mw > cw) ? mw : cw) + 50; + h = th + fh * 3; + sx = SCR_WIDTH / 2 - w / 2; + sy = SCR_HEIGHT / 2 - h / 2; + dx = sx + w; + dy = sy + h; + + if (UiMetric.Animate) + { + /* Get copy of screen */ + screen = pspVideoGetVramBufferCopy(); + + /* Intro animation */ + for (i = 0; i < n; i++) + { + pspVideoBegin(); + + /* Clear screen */ + pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height); + + /* Apply fog and draw frame */ + pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT, + COLOR(0,0,0,UI_ANIM_FOG_STEP*i)); + pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2, + SCR_HEIGHT/2-(((dy-sy)/n)*i)/2, + SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2, + COLOR(RED_32(UiMetric.MenuOptionBoxBg), + GREEN_32(UiMetric.MenuOptionBoxBg), + BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i)); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + } + } + + pspVideoBegin(); + + if (UiMetric.Animate) + pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height); + pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT, + COLOR(0,0,0,UI_ANIM_FOG_STEP*n)); + pspVideoFillRect(sx, sy, dx, dy, UiMetric.MenuOptionBoxBg); + pspVideoPrint(UiMetric.Font, SCR_WIDTH / 2 - mw / 2, sy + fh * 0.5, message, + UiMetric.TextColor); + pspVideoPrint(UiMetric.Font, SCR_WIDTH / 2 - cw / 2, dy - fh * 1.5, instr, + UiMetric.TextColor); + pspVideoGlowRect(sx, sy, dx - 1, dy - 1, + COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP*n), 2); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + + SceCtrlData pad; + + /* Loop until X or O is pressed */ + while (!ExitPSP) + { + if (!pspCtrlPollControls(&pad)) + continue; + + if (pad.Buttons & UiMetric.OkButton || pad.Buttons & UiMetric.CancelButton) + break; + } + + if (!ExitPSP && UiMetric.Animate) + { + /* Exit animation */ + for (i = n - 1; i >= 0; i--) + { + pspVideoBegin(); + + /* Clear screen */ + pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height); + + /* Apply fog and draw frame */ + pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT, + COLOR(0,0,0,UI_ANIM_FOG_STEP*i)); + pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2, + SCR_HEIGHT/2-(((dy-sy)/n)*i)/2, + SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2, + COLOR(RED_32(UiMetric.MenuOptionBoxBg), + GREEN_32(UiMetric.MenuOptionBoxBg), + BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i)); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + } + } + + if (screen) pspImageDestroy(screen); + free(instr); + + return pad.Buttons & UiMetric.OkButton; +} + +void pspUiFlashMessage(const char *message) +{ + PspImage *screen = NULL; + int sx, sy, dx, dy, fh, mw, mh, w, h; + int i, n = UI_ANIM_FRAMES; + + mw = pspFontGetTextWidth(UiMetric.Font, message); + fh = pspFontGetLineHeight(UiMetric.Font); + mh = pspFontGetTextHeight(UiMetric.Font, message); + + w = mw + 50; + h = mh + fh * 2; + sx = SCR_WIDTH / 2 - w / 2; + sy = SCR_HEIGHT / 2 - h / 2; + dx = sx + w; + dy = sy + h; + + if (UiMetric.Animate) + { + /* Get copy of screen */ + screen = pspVideoGetVramBufferCopy(); + + /* Intro animation */ + for (i = 0; i < n; i++) + { + pspVideoBegin(); + + /* Clear screen */ + pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height); + + /* Apply fog and draw frame */ + pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT, + COLOR(0,0,0,UI_ANIM_FOG_STEP*i)); + pspVideoFillRect(SCR_WIDTH/2-(((dx-sx)/n)*i)/2, + SCR_HEIGHT/2-(((dy-sy)/n)*i)/2, + SCR_WIDTH/2+(((dx-sx)/n)*i)/2, SCR_HEIGHT/2+(((dy-sy)/n)*i)/2, + COLOR(RED_32(UiMetric.MenuOptionBoxBg), + GREEN_32(UiMetric.MenuOptionBoxBg), + BLUE_32(UiMetric.MenuOptionBoxBg),(0xff/n)*i)); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + } + } + + pspVideoBegin(); + + if (UiMetric.Animate) + pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height); + pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT, + COLOR(0,0,0,UI_ANIM_FOG_STEP*n)); + pspVideoFillRect(sx, sy, dx, dy, UiMetric.MenuOptionBoxBg); + pspVideoPrintCenter(UiMetric.Font, + sx, sy + fh, dx, message, UiMetric.TextColor); + pspVideoGlowRect(sx, sy, dx - 1, dy - 1, + COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP*n), 2); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + + if (screen) pspImageDestroy(screen); +} + +void pspUiOpenBrowser(PspUiFileBrowser *browser, const char *start_path) +{ + pl_file *file; + pl_file_list list; + const pl_menu_item *sel, *last_sel; + pl_menu_item *item; + SceCtrlData pad; + char *instructions[BROWSER_TEMPLATE_COUNT]; + int delay; + PspImage *screenshot = NULL; + int screenshot_width = 0; + int screenshot_height = 0; + + /* Initialize instruction strings */ + int i; + for (i = 0; i < BROWSER_TEMPLATE_COUNT; i++) + { + instructions[i] = strdup(BrowserTemplates[i]); + ReplaceIcons(instructions[i]); + } + + if (!start_path) + start_path = pl_psp_get_app_directory(); + + pl_file_path cur_path; + if (!pl_file_is_directory(start_path)) + pl_file_get_parent_directory(start_path, cur_path, sizeof(cur_path)); + else + { + int copy_len = MIN(strlen(start_path), sizeof(cur_path) - 1); + strncpy(cur_path, start_path, copy_len); + cur_path[copy_len] = '\0'; + } + + const char *cur_file = pl_file_get_filename(start_path); + struct UiPos pos; + int lnmax, lnhalf; + int sby, sbh, j, h, w, fh = pspFontGetLineHeight(UiMetric.Font); + int sx, sy, dx, dy; + int hasparent, is_dir; + + /*NOTA*/ + sx = UiMetric.Left-13; + sy = UiMetric.Top + fh + UiMetric.TitlePadding; + dx = UiMetric.Right; + dy = UiMetric.Bottom; + w = dx - sx - UiMetric.ScrollbarWidth; + h = dy - sy; + + pl_menu menu; + pl_menu_create(&menu, NULL); + + memset(call_list, 0, sizeof(call_list)); + + int sel_top = 0, last_sel_top = 0, fast_scroll; + + /* Begin browsing (outer) loop */ + while (!ExitPSP) + { + delay = UiMetric.BrowserScreenshotDelay; + sel = last_sel = NULL; + pos.Top = NULL; + pl_menu_clear_items(&menu); + + /* Load list of files for the selected path */ + if (pl_file_get_file_list(&list, cur_path, browser->Filter) >= 0) + { + /* Check for a parent path, prepend .. if necessary */ + if ((hasparent =! pl_file_is_root_directory(cur_path))) + { + item = pl_menu_append_item(&menu, 0, ".."); + item->param = (void*)PL_FILE_DIRECTORY; + } + + /* Add a menu item for each file */ + for (file = list.files; file; file = file->next) + { + /* Skip files that begin with '.' */ + if (file->name && file->name[0] == '.') + continue; + + item = pl_menu_append_item(&menu, 0, file->name); + item->param = (void*)(int)file->attrs; + + if (cur_file && strcmp(file->name, cur_file) == 0) + sel = item; + } + + cur_file = NULL; + + /* Destroy the file list */ + pl_file_destroy_file_list(&list); + } + else + { + /* Check for a parent path, prepend .. if necessary */ + if ((hasparent = !pl_file_is_root_directory(cur_path))) + { + item = pl_menu_append_item(&menu, 0, ".."); + item->param = (void*)PL_FILE_DIRECTORY; + } + } + + /* Initialize variables */ + lnmax = (dy - sy) / fh; + lnhalf = lnmax >> 1; + int item_count = pl_menu_get_item_count(&menu); + sbh = (item_count > lnmax) + ? (int)((float)h * ((float)lnmax / (float)item_count)) : 0; + + pos.Index = pos.Offset = 0; + + if (!sel) + { + /* Select the first file/dir in the directory */ + if (menu.items && menu.items->next) + sel=menu.items->next; + else if (menu.items) + sel=menu.items; + } + + /* Compute index and offset of selected file */ + if (sel) + { + pos.Top = menu.items; + for (item = menu.items; item != sel; item = item->next) + { + if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top=pos.Top->next; } + else pos.Index++; + } + } + + pspVideoWaitVSync(); + + /* Begin navigation (inner) loop */ + while (!ExitPSP) + { + if (!pspCtrlPollControls(&pad)) + continue; + + fast_scroll = 0; + if (delay >= 0) delay--; + if ((delay == 0) + && sel + && !screenshot + && !((unsigned int)sel->param & PL_FILE_DIRECTORY) + && UiMetric.BrowserScreenshotPath) + { + pl_file_path screenshot_path; + sprintf(screenshot_path, "%s%s-00.png", + UiMetric.BrowserScreenshotPath, sel->caption); + screenshot = pspImageLoadPng(screenshot_path); + } + + /* Check the directional buttons */ + if (sel) + { + if ((pad.Buttons & PSP_CTRL_DOWN || pad.Buttons & PSP_CTRL_ANALDOWN) && sel->next) + { + if (pos.Index+1 >= lnmax) { pos.Offset++; pos.Top=pos.Top->next; } + else pos.Index++; + sel=sel->next; + fast_scroll = pad.Buttons & PSP_CTRL_ANALDOWN; + } + else if ((pad.Buttons & PSP_CTRL_UP || pad.Buttons & PSP_CTRL_ANALUP) && sel->prev) + { + if (pos.Index - 1 < 0) { pos.Offset--; pos.Top=pos.Top->prev; } + else pos.Index--; + sel = sel->prev; + fast_scroll = pad.Buttons & PSP_CTRL_ANALUP; + } + else if (pad.Buttons & PSP_CTRL_LEFT) + { + for (i=0; sel->prev && i < lnhalf; i++) + { + if (pos.Index-1 < 0) { pos.Offset--; pos.Top=pos.Top->prev; } + else pos.Index--; + sel=sel->prev; + } + } + else if (pad.Buttons & PSP_CTRL_RIGHT) + { + for (i=0; sel->next && i < lnhalf; i++) + { + if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top=pos.Top->next; } + else pos.Index++; + sel=sel->next; + } + } + + /* File/dir selection */ + if (pad.Buttons & UiMetric.OkButton) + { + tipo_consola=0; + if (((unsigned int)sel->param & PL_FILE_DIRECTORY)) + { + enter_directory(cur_path, sel->caption); + break; + } + else + { + int exit = 1; + + /* Selected a file */ + if (browser->OnOk) + { + char *file = malloc((strlen(cur_path) + strlen(sel->caption) + 1) * sizeof(char)); + sprintf(file, "%s%s", cur_path, sel->caption); + exit = browser->OnOk(browser, file); + free(file); + } + + if (exit) goto exit_browser; + else continue; + } + } + if (pad.Buttons & PSP_CTRL_SQUARE) + { + //NOTA + tipo_consola=1; + int exit = 1; + + /* Selected a file */ + if (browser->OnOk) + { + char *file = malloc((strlen(cur_path) + strlen(sel->caption) + 1) * sizeof(char)); + sprintf(file, "%s%s", cur_path, sel->caption); + exit = browser->OnOk(browser, file); + free(file); + } + + if (exit) goto exit_browser; + else continue; + + } + + + } + + if (pad.Buttons & PSP_CTRL_TRIANGLE) + { + if (!pl_file_is_root_directory(cur_path)) + { + enter_directory(cur_path, ".."); + break; + } + } + else if (pad.Buttons & UiMetric.CancelButton) + { + if (browser->OnCancel) + browser->OnCancel(browser, cur_path); + goto exit_browser; + } + else if ((pad.Buttons & CONTROL_BUTTON_MASK) && browser->OnButtonPress) + { + char *file = NULL; + int exit; + + if (sel) + { + file = malloc((strlen(cur_path) + strlen(sel->caption) + 1) * sizeof(char)); + sprintf(file, "%s%s", cur_path, sel->caption); + } + + exit = browser->OnButtonPress(browser, + file, pad.Buttons & CONTROL_BUTTON_MASK); + + if (file) free(file); + if (exit) goto exit_browser; + } + + is_dir = (unsigned int)sel->param & PL_FILE_DIRECTORY; + + sceGuStart(GU_CALL, call_list); + + /* NOTA Draw current path */ + pspVideoPrint(UiMetric.Font, sx+10, UiMetric.Top, cur_path, + UiMetric.TitleColor); + pspVideoDrawLine(UiMetric.Left, UiMetric.Top + fh - 1, UiMetric.Left + w, + UiMetric.Top + fh - 1, UiMetric.TitleColor); + + const char *instruction; + if (hasparent) + instruction = instructions[(is_dir) + ? BrowserTemplateEnter : BrowserTemplateOpen]; + else + instruction = instructions[(is_dir) + ? BrowserTemplateEnterTop : BrowserTemplateOpenTop]; + + pspVideoPrintCenter(UiMetric.Font, + sx, SCR_HEIGHT - fh, dx, instruction, UiMetric.StatusBarColor); + + /* Draw scrollbar */ + if (sbh > 0) + { + sby = sy + (int)((float)(h - sbh) + * ((float)(pos.Offset + pos.Index) / (float)item_count)); + pspVideoFillRect(dx - UiMetric.ScrollbarWidth, sy, dx, dy, + UiMetric.ScrollbarBgColor); + pspVideoFillRect(dx - UiMetric.ScrollbarWidth, sby, dx, sby + sbh, + UiMetric.ScrollbarColor); + } + + /* Render the files */ + for (item = (pl_menu_item*)pos.Top, i = 0, j = sy; + item && i < lnmax; item = item->next, j += fh, i++) + { + if (item == sel) sel_top = j; + + pspVideoPrintClipped(UiMetric.Font, sx + 10, j, item->caption, w - 10, + "...", (item == sel) ? UiMetric.SelectedColor + : ((unsigned int)item->param & PL_FILE_DIRECTORY) + ? UiMetric.BrowserDirectoryColor : UiMetric.BrowserFileColor); + } + + /* Render status information */ + RenderStatus(); + + /* Perform any custom drawing */ + if (browser->OnRender) + browser->OnRender(browser, "not implemented"); + + sceGuFinish(); + + if (screenshot) + { + screenshot_width = screenshot->Viewport.Width; + screenshot_height = screenshot->Viewport.Height; + } + + if (sel != last_sel && !fast_scroll && sel && last_sel + && UiMetric.Animate) + { + /* Move animation */ + int f, n = 4; + for (f = 1; f <= n; f++) + { + pspVideoBegin(); + + /* Clear screen */ + if (!UiMetric.Background) pspVideoClearScreen(); + else pspVideoPutImage(UiMetric.Background, 0, 0, + UiMetric.Background->Viewport.Width, UiMetric.Background->Height); + + /* Render screenshot */ + if (screenshot) + pspVideoPutImage(screenshot, + (UiMetric.Right-8) - screenshot_width - UiMetric.ScrollbarWidth, + ((UiMetric.Bottom - UiMetric.Top) / 2 - + screenshot_height / 2) + (UiMetric.Top-20), + screenshot_width, + screenshot_height); + + /* Selection box */ + int box_top = last_sel_top-((last_sel_top-sel_top)/n)*f; + pspVideoFillRect(sx, sel_top, sx+(w-178), sel_top+fh, + UiMetric.SelectedBgColor); + + sceGuCallList(call_list); + + pspVideoEnd(); + + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + } + } + + pspVideoBegin(); + + /* Clear screen */ + if (UiMetric.Background) + pspVideoPutImage(UiMetric.Background, 0, 0, + UiMetric.Background->Viewport.Width, UiMetric.Background->Height); + else pspVideoClearScreen(); + + + /* NOTA: Render screenshot */ + if (screenshot) + pspVideoPutImage(screenshot, + (UiMetric.Right-8) - screenshot_width - UiMetric.ScrollbarWidth, + ((UiMetric.Bottom - UiMetric.Top) / 2 - + screenshot_height / 2) + (UiMetric.Top-20), + screenshot_width, + screenshot_height); + + /* NOTA: Barra de seleccion rom Render selection box */ + if (sel) pspVideoFillRect(sx, sel_top, sx+(w-178), sel_top+fh, + UiMetric.SelectedBgColor); + + sceGuCallList(call_list); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + + if (last_sel != sel) + { + if (screenshot != NULL) + { + pspImageDestroy(screenshot); + screenshot = NULL; + } + + delay = UiMetric.BrowserScreenshotDelay; + } + + last_sel = sel; + last_sel_top = sel_top; + } + } + +exit_browser: + + if (screenshot != NULL) + pspImageDestroy(screenshot); + + /* Free instruction strings */ + for (i = 0; i < BROWSER_TEMPLATE_COUNT; i++) + free(instructions[i]); + + pl_menu_destroy(&menu); +} + +void pspUiOpenGallery(PspUiGallery *gallery, const char *title) +{ + pl_menu *menu = &(gallery->Menu); + const pl_menu_item *top, *item; + SceCtrlData pad; + pl_menu_item *sel = menu->selected; + + int sx, sy, dx, dy, + orig_w = 272, orig_h = 228, // defaults + fh, c, i, j, + sbh, sby, + w, h, + icon_w, icon_h, + grid_w, grid_h, + icon_idx, icon_off, + rows, vis_v, vis_s, + icons; + const pl_menu_item *last_sel = NULL; + + /* Find first icon and save its width/height */ + for (item = menu->items; item; item = item->next) + { + if (item->param) + { + orig_w = ((PspImage*)item->param)->Viewport.Width; + orig_h = ((PspImage*)item->param)->Height; + break; + } + } + + fh = pspFontGetLineHeight(UiMetric.Font); + sx = UiMetric.Left; + sy = UiMetric.Top + ((title) ? fh + UiMetric.TitlePadding : 0); + dx = UiMetric.Right; + dy = UiMetric.Bottom; + w = (dx - sx) - UiMetric.ScrollbarWidth; // visible width + h = dy - sy; // visible height + icon_w = (w - UiMetric.GalleryIconMarginWidth + * (UiMetric.GalleryIconsPerRow - 1)) / UiMetric.GalleryIconsPerRow; // icon width + icon_h = (int)((float)icon_w + / ((float)orig_w / (float)orig_h)); // icon height + grid_w = icon_w + UiMetric.GalleryIconMarginWidth; // width of the grid + grid_h = icon_h + (fh * 2); // half-space for margin + 1 line of text + icons = pl_menu_get_item_count(menu); // number of icons total + rows = ceil((float)icons / (float)UiMetric.GalleryIconsPerRow); // number of rows total + vis_v = h / grid_h; // number of rows visible at any time + vis_s = UiMetric.GalleryIconsPerRow * vis_v; // max. number of icons visible on screen at any time + int max_w = ((float)icon_w * 1.5); /* Maximized width */ + int max_h = ((float)icon_h * 1.5); /* Maximized height */ + + icon_idx = 0; + icon_off = 0; + top = menu->items; + + if (!sel) + { + /* Select the first icon */ + sel = menu->items; + } + else + { + /* Find the selected icon */ + for (item = menu->items; item; item = item->next) + { + if (item == sel) + break; + + if (++icon_idx >= vis_s) + { + icon_idx=0; + icon_off += vis_s; + top = item; + } + } + + if (item != sel) + { + /* Icon not found; reset to first icon */ + sel = menu->items; + top = menu->items; + icon_idx = 0; + icon_off = 0; + } + } + + /* Compute height of scrollbar */ + sbh = ((float)vis_v / (float)(rows + (rows % vis_v))) * (float)h; + + /* Compute update frequency */ + u32 ticks_per_sec, ticks_per_upd; + u64 current_tick, last_tick; + + ticks_per_sec = sceRtcGetTickResolution(); + sceRtcGetCurrentTick(&last_tick); + ticks_per_upd = ticks_per_sec / UiMetric.MenuFps; + + memset(call_list, 0, sizeof(call_list)); + int sel_left = 0 /*, max_left = 0 */; + int sel_top = 0 /*, max_top = 0 */; + + pspVideoWaitVSync(); + + /* Begin navigation loop */ + while (!ExitPSP) + { + if (!pspCtrlPollControls(&pad)) + continue; + + /* Check the directional buttons */ + if (sel) + { + if (pad.Buttons & PSP_CTRL_RIGHT && sel->next) + { + sel = sel->next; + if (++icon_idx >= vis_s) + { + icon_idx = 0; + icon_off += vis_s; + top = sel; + } + } + else if (pad.Buttons & PSP_CTRL_LEFT && sel->prev) + { + sel = sel->prev; + if (--icon_idx < 0) + { + icon_idx = vis_s-1; + icon_off -= vis_s; + for (i = 0; i < vis_s && top; i++) top = top->prev; + } + } + else if (pad.Buttons & PSP_CTRL_DOWN) + { + for (i = 0; sel->next && i < UiMetric.GalleryIconsPerRow; i++) + { + sel = sel->next; + if (++icon_idx >= vis_s) + { + icon_idx = 0; + icon_off += vis_s; + top = sel; + } + } + } + else if (pad.Buttons & PSP_CTRL_UP) + { + for (i = 0; sel->prev && i < UiMetric.GalleryIconsPerRow; i++) + { + sel = sel->prev; + if (--icon_idx < 0) + { + icon_idx = vis_s-1; + icon_off -= vis_s; + for (j = 0; j < vis_s && top; j++) top = top->prev; + } + } + } + + if (pad.Buttons & UiMetric.OkButton) + { + pad.Buttons &= ~UiMetric.OkButton; + if (!gallery->OnOk || gallery->OnOk(gallery, sel)) + break; + } + } + + if (pad.Buttons & UiMetric.CancelButton) + { + pad.Buttons &= ~UiMetric.CancelButton; + if (gallery->OnCancel) + gallery->OnCancel(gallery, sel); + break; + } + + if ((pad.Buttons & CONTROL_BUTTON_MASK) && gallery->OnButtonPress) + if (gallery->OnButtonPress(gallery, sel, pad.Buttons & CONTROL_BUTTON_MASK)) + break; + + if (last_sel != sel && last_sel && sel && sel->param && UiMetric.Animate) + { + /* "Implode" animation */ + int f = 1, n = 2; +// for (f = n - 1; f > 0; f--) +// { + pspVideoBegin(); + + /* Clear screen */ + if (!UiMetric.Background) pspVideoClearScreen(); + else pspVideoPutImage(UiMetric.Background, 0, 0, + UiMetric.Background->Viewport.Width, UiMetric.Background->Height); + + sceGuCallList(call_list); + + pspVideoEnd(); + + /* Render the menu items */ + for (i = sy, item = top; item && i + grid_h < dy; i += grid_h) + for (j = sx, c = 0; item && c < UiMetric.GalleryIconsPerRow; j += grid_w, c++, item = item->next) + if (item->param && item != last_sel) + { + pspVideoBegin(); + pspVideoPutImage((PspImage*)item->param, j, i, icon_w, icon_h); + pspVideoEnd(); + } + + pspVideoBegin(); + + pspVideoPutImage((PspImage*)last_sel->param, + sel_left-(icon_w+((max_w-icon_w)/n)*f)/2, + sel_top-(icon_h+((max_h-icon_h)/n)*f)/2, + icon_w+((max_w-icon_w)/n)*f, + icon_h+((max_h-icon_h)/n)*f); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); +// } + } + + sceGuStart(GU_CALL, call_list); + + /* Draw title */ + if (title) + { + pspVideoPrint(UiMetric.Font, UiMetric.Left, UiMetric.Top, + title, UiMetric.TitleColor); + pspVideoDrawLine(UiMetric.Left, UiMetric.Top + fh - 1, UiMetric.Left + w, + UiMetric.Top + fh - 1, UiMetric.TitleColor); + } + + /* Draw scrollbar */ + if (sbh < h) + { + sby = sy + (((float)icon_off / (float)UiMetric.GalleryIconsPerRow) + / (float)(rows + (rows % vis_v))) * (float)h; + pspVideoFillRect(dx - UiMetric.ScrollbarWidth, + sy, dx, dy, UiMetric.ScrollbarBgColor); + pspVideoFillRect(dx - UiMetric.ScrollbarWidth, + sby, dx, sby+sbh, UiMetric.ScrollbarColor); + } + + /* Draw instructions */ + if (sel && sel->help_text) + { + static char help_copy[PL_FILE_MAX_PATH_LEN]; + strncpy(help_copy, sel->help_text, PL_FILE_MAX_PATH_LEN - 1); + help_copy[PL_FILE_MAX_PATH_LEN - 1] = '\0'; + ReplaceIcons(help_copy); + + pspVideoPrintCenter(UiMetric.Font, + 0, SCR_HEIGHT - fh, SCR_WIDTH, help_copy, UiMetric.StatusBarColor); + } + + /* Render non-image components of each item */ + for (i = sy, item = top; item && i + grid_h < dy; i += grid_h) + { + for (j = sx, c = 0; item && c < UiMetric.GalleryIconsPerRow; j += grid_w, c++, item = item->next) + { + if (item != sel) + { + pspVideoShadowRect(j - 1, i - 1, j + icon_w, i + icon_h, PSP_COLOR_BLACK, 3); + pspVideoDrawRect(j - 1, i - 1, j + icon_w, i + icon_h, UiMetric.TextColor); + + if (item->caption) + { + int cap_pos = j + icon_w / 2 + - pspFontGetTextWidth(UiMetric.Font, item->caption) / 2; + pspVideoPrint(UiMetric.Font, cap_pos, + i + icon_h + (fh / 2), item->caption, UiMetric.TextColor); + } + } + else + { + sel_left = j + icon_w / 2; + sel_top = i + icon_h / 2; + + sel_left = (sel_left-max_w/2 < sx) ? sx+max_w/2 : sel_left; + sel_top = (sel_top-max_h/2 < UiMetric.Top) + ? UiMetric.Top+max_h/2 : sel_top; + sel_left = (sel_left+max_w/2 > dx) ? dx-max_w/2 : sel_left; + sel_top = (sel_top+max_h/2 > dy) ? dy-max_h/2 : sel_top; + } + } + } + + /* Render status information */ + RenderStatus(); + + /* Perform any custom drawing */ + if (gallery->OnRender) + gallery->OnRender(gallery, sel); + + sceGuFinish(); + + if (last_sel != sel && last_sel && sel && sel->param && UiMetric.Animate) + { + /* Popup animation */ + int f = 1, n = 2; +// for (f = 1; f < n; f++) +// { + pspVideoBegin(); + + /* Clear screen */ + if (!UiMetric.Background) pspVideoClearScreen(); + else pspVideoPutImage(UiMetric.Background, 0, 0, + UiMetric.Background->Viewport.Width, UiMetric.Background->Height); + + sceGuCallList(call_list); + + pspVideoEnd(); + + /* Render the menu items */ + for (i = sy, item = top; item && i + grid_h < dy; i += grid_h) + for (j = sx, c = 0; item && c < UiMetric.GalleryIconsPerRow; j += grid_w, c++, item = item->next) + if (item->param && item != sel) + { + pspVideoBegin(); + pspVideoPutImage((PspImage*)item->param, j, i, icon_w, icon_h); + pspVideoEnd(); + } + + pspVideoBegin(); + + pspVideoPutImage((PspImage*)sel->param, + sel_left-(icon_w+((max_w-icon_w)/n)*f)/2, + sel_top-(icon_h+((max_h-icon_h)/n)*f)/2, + icon_w+((max_w-icon_w)/n)*f, + icon_h+((max_h-icon_h)/n)*f); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); +// } + } + + pspVideoBegin(); + + /* Clear screen */ + if (!UiMetric.Background) pspVideoClearScreen(); + else pspVideoPutImage(UiMetric.Background, 0, 0, + UiMetric.Background->Viewport.Width, UiMetric.Background->Height); + + sceGuCallList(call_list); + + pspVideoEnd(); + + /* Render the menu items */ + for (i = sy, item = top; item && i + grid_h < dy; i += grid_h) + for (j = sx, c = 0; item && c < UiMetric.GalleryIconsPerRow; j += grid_w, c++, item = item->next) + if (item->param && item != sel) + { + pspVideoBegin(); + pspVideoPutImage((PspImage*)item->param, j, i, icon_w, icon_h); + pspVideoEnd(); + } + + pspVideoBegin(); + + if (sel && sel->param) + { + pspVideoPutImage((PspImage*)sel->param, sel_left-max_w/2, sel_top-max_h/2, + max_w, max_h); + pspVideoGlowRect(sel_left-max_w/2, sel_top-max_h/2, + sel_left+max_w/2 - 1, sel_top+max_h/2 - 1, + COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP * UI_ANIM_FRAMES), 2); + } + + if (sel && sel->caption) + { + int cap_left = sel_left + - pspFontGetTextWidth(UiMetric.Font, sel->caption) / 2; + pspVideoPrint(UiMetric.Font, cap_left, + sel_top + max_h/2 - (fh + (fh - UiMetric.Font->Ascent)), sel->caption, + UiMetric.TextColor); + } + + pspVideoEnd(); + + last_sel = sel; + + /* Wait if needed */ + do { sceRtcGetCurrentTick(¤t_tick); } + while (current_tick - last_tick < ticks_per_upd); + last_tick = current_tick; + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + } + + menu->selected = sel; +} + +void pspUiOpenMenu(PspUiMenu *uimenu, const char *title) +{ + struct UiPos pos; + pl_menu *menu = &(uimenu->Menu); + const pl_menu_item *item; + SceCtrlData pad; + const pl_menu_option *temp_option; + int lnmax; + int sby, sbh, i, j, k, h, w, fh = pspFontGetLineHeight(UiMetric.Font); + int sx, sy, dx, dy, sel_top = 0, last_sel_top = 0; + int max_item_w = 0, item_w; + int option_mode, max_option_w = 0; + int arrow_w = pspFontGetTextWidth(UiMetric.Font, "\272"); + int anim_frame = 0, anim_incr = 1; + pl_menu_item *sel = menu->selected, *last_sel = NULL; + + sx = UiMetric.Left; + sy = UiMetric.Top + ((title) ? (fh + UiMetric.TitlePadding) : 0); + dx = UiMetric.Right; + dy = UiMetric.Bottom; + w = dx - sx - UiMetric.ScrollbarWidth; + h = dy - sy; + + memset(call_list, 0, sizeof(call_list)); + + /* Determine width of the longest caption */ + for (item = menu->items; item; item = item->next) + { + if (item->caption) + { + item_w = pspFontGetTextWidth(UiMetric.Font, item->caption); + if (item_w > max_item_w) + max_item_w = item_w; + } + } + + /* Initialize variables */ + lnmax = (dy - sy) / fh; + int item_count = pl_menu_get_item_count(menu); + sbh = (item_count > lnmax) + ? (int)((float)h * ((float)lnmax / (float)item_count)) : 0; + + pos.Index = 0; + pos.Offset = 0; + pos.Top = NULL; + option_mode = 0; + temp_option = NULL; + + int cur_x=0, min_x=0, max_x=0; + int cur_y=0, min_y=0, max_y=0; + + /* Find first selectable item */ + if (!sel) + { + for (sel = menu->items; sel; sel = sel->next) + if (sel->caption && sel->caption[0] != '\t') + break; + } + + /* Compute index and offset of selected file */ + pos.Top = menu->items; + for (item = menu->items; item != sel; item = item->next) + { + if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top = pos.Top->next; } + else pos.Index++; + } + + pspVideoWaitVSync(); + pl_menu_item *last; + struct UiPos last_valid; + + /* Compute update frequency */ + u32 ticks_per_sec, ticks_per_upd; + u64 current_tick, last_tick; + + ticks_per_sec = sceRtcGetTickResolution(); + sceRtcGetCurrentTick(&last_tick); + ticks_per_upd = ticks_per_sec / UiMetric.MenuFps; + + int fast_scroll; + + /* Begin navigation loop */ + while (!ExitPSP) + { + if (!pspCtrlPollControls(&pad)) + continue; + + fast_scroll = 0; + anim_frame += (UiMetric.Animate) ? anim_incr : 0; + if (anim_frame > 2 || anim_frame < 0) + anim_incr *= -1; + + /* Check the directional buttons */ + if (sel) + { + if (pad.Buttons & PSP_CTRL_DOWN || pad.Buttons & PSP_CTRL_ANALDOWN) + { + fast_scroll = pad.Buttons & PSP_CTRL_ANALDOWN; + + if (option_mode) + { + if (temp_option->next) + temp_option = temp_option->next; + } + else + { + if (sel->next) + { + last = sel; + last_valid = pos; + + for (;;) + { + if (pos.Index + 1 >= lnmax) + { + pos.Offset++; + pos.Top = pos.Top->next; + } + else pos.Index++; + + sel = sel->next; + + if (!sel) + { + sel = last; + pos = last_valid; + break; + } + + if (sel->caption && sel->caption[0] != '\t') + break; + } + } + } + } + else if (pad.Buttons & PSP_CTRL_UP || pad.Buttons & PSP_CTRL_ANALUP) + { + fast_scroll = pad.Buttons & PSP_CTRL_ANALUP; + + if (option_mode) + { + if (temp_option->prev) + temp_option = temp_option->prev; + } + else + { + if (sel->prev) + { + last = sel; + last_valid = pos; + + for (;;) + { + if (pos.Index - 1 < 0) + { + pos.Offset--; + pos.Top = pos.Top->prev; + } + else pos.Index--; + + sel = sel->prev; + + if (!sel) + { + sel = last; + + pos.Index = 0; + pos.Offset = 0; + pos.Top = menu->items; + + for (item = menu->items; item != sel; item = item->next) + { + if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top = pos.Top->next; } + else pos.Index++; + } + + break; + } + + if (sel->caption && sel->caption[0] != '\t') + break; + } + } + } + } + + /* Recompute box bounds if scrolling in option mode */ + if (option_mode && (pad.Buttons & + (PSP_CTRL_UP|PSP_CTRL_ANALUP|PSP_CTRL_DOWN|PSP_CTRL_ANALDOWN))) + { + cur_x = sx + max_item_w + UiMetric.MenuItemMargin + 10; + min_y = sy + pos.Index * fh; + cur_y = min_y + fh / 2; + max_y = sy + (pos.Index + 1) * fh; + min_x = cur_x - UiMetric.MenuItemMargin; + max_x = cur_x + max_option_w + UiMetric.MenuItemMargin; + cur_x += pspFontGetTextWidth(UiMetric.Font, " >"); + if (sel->selected && sel->selected->text) + cur_x += pspFontGetTextWidth(UiMetric.Font, sel->selected->text); + + const pl_menu_option *option; + for (option = temp_option; option && min_y >= sy; option = option->prev, min_y -= fh); + for (option = temp_option->next; option && max_y < dy; option = option->next, max_y += fh); + max_y += fh; + } + + if (option_mode) + { + if (pad.Buttons & PSP_CTRL_RIGHT || pad.Buttons & UiMetric.OkButton) + { + option_mode = 0; + + /* If the callback function refuses the change, restore selection */ + if (!uimenu->OnItemChanged || uimenu->OnItemChanged(uimenu, sel, temp_option)) + sel->selected = (pl_menu_option*)temp_option; + } + else if (pad.Buttons & PSP_CTRL_LEFT || pad.Buttons & UiMetric.CancelButton) + { + option_mode = 0; + + if (pad.Buttons & UiMetric.CancelButton) + pad.Buttons &= ~UiMetric.CancelButton; + } + + if (!option_mode) + { + if (UiMetric.Animate) + { + /* Deflation animation */ + for (i = UI_ANIM_FRAMES - 1; i >= 0; i--) + { + pspVideoBegin(); + if (!UiMetric.Background) pspVideoClearScreen(); + else pspVideoPutImage(UiMetric.Background, 0, 0, + UiMetric.Background->Viewport.Width, UiMetric.Background->Height); + + pspVideoCallList(call_list); + + /* Perform any custom drawing */ + if (uimenu->OnRender) + uimenu->OnRender(uimenu, sel); + + /* Clear screen */ + pspVideoFillRect(cur_x - ((cur_x - min_x) / UI_ANIM_FRAMES) * i, + cur_y - ((cur_y - min_y) / UI_ANIM_FRAMES) * i, + cur_x + ((max_x - cur_x) / UI_ANIM_FRAMES) * i, + cur_y + ((max_y - cur_y) / UI_ANIM_FRAMES) * i, + UiMetric.MenuOptionBoxBg); + + /* Selected option for the item */ + if (sel->selected && sel->selected->text) + pspVideoPrint(UiMetric.Font, + sx + max_item_w + UiMetric.MenuItemMargin + 10, + sy + pos.Index * fh, sel->selected->text, UiMetric.SelectedColor); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + } + } + } + } + else + { + if ((pad.Buttons & PSP_CTRL_RIGHT) + && sel->options && sel->options->next) + { + option_mode = 1; + max_option_w = 0; + int width; + const pl_menu_option *option; + + /* Find the longest option caption */ + for (option = sel->options; option; option = option->next) + if (option->text && (width = pspFontGetTextWidth(UiMetric.Font, option->text)) > max_option_w) + max_option_w = width; + + temp_option = (sel->selected) ? sel->selected : sel->options; + + /* Determine bounds */ + cur_x = sx + max_item_w + UiMetric.MenuItemMargin + 10; + min_y = sy + pos.Index * fh; + cur_y = min_y + fh / 2; + max_y = sy + (pos.Index + 1) * fh; + min_x = cur_x - UiMetric.MenuItemMargin; + max_x = cur_x + max_option_w + UiMetric.MenuItemMargin; + cur_x += pspFontGetTextWidth(UiMetric.Font, " >"); + if (sel->selected && sel->selected->text) + cur_x += pspFontGetTextWidth(UiMetric.Font, sel->selected->text); + + for (option = temp_option; option && min_y >= sy; option = option->prev, min_y -= fh); + for (option = temp_option->next; option && max_y < dy; option = option->next, max_y += fh); + max_y += fh; + + if (!UiMetric.Animate) + { + /* Expansion animation */ + for (i = 0; i <= UI_ANIM_FRAMES; i++) + { + pspVideoBegin(); + + if (!UiMetric.Background) pspVideoClearScreen(); + else pspVideoPutImage(UiMetric.Background, 0, 0, + UiMetric.Background->Viewport.Width, + UiMetric.Background->Height); + + pspVideoCallList(call_list); + + /* Perform any custom drawing */ + if (uimenu->OnRender) + uimenu->OnRender(uimenu, sel); + + pspVideoFillRect(cur_x - ((cur_x - min_x) / UI_ANIM_FRAMES) * i, + cur_y - ((cur_y - min_y) / UI_ANIM_FRAMES) * i, + cur_x + ((max_x - cur_x) / UI_ANIM_FRAMES) * i, + cur_y + ((max_y - cur_y) / UI_ANIM_FRAMES) * i, + UiMetric.MenuOptionBoxBg); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + } + } + } + else if (pad.Buttons & UiMetric.OkButton) + { + if (!uimenu->OnOk || uimenu->OnOk(uimenu, sel)) + break; + } + } + } + + if (!option_mode) + { + if (pad.Buttons & UiMetric.CancelButton) + { + if (uimenu->OnCancel) + uimenu->OnCancel(uimenu, sel); + break; + } + + if ((pad.Buttons & CONTROL_BUTTON_MASK) && uimenu->OnButtonPress) + { + if (uimenu->OnButtonPress(uimenu, sel, pad.Buttons & CONTROL_BUTTON_MASK)) + break; + } + } + + /* Render to a call list */ + sceGuStart(GU_CALL, call_list); + + /* Draw instructions */ + if (sel) + { + const char *dirs = NULL; + + if (!option_mode && sel->help_text) + { + static char help_copy[PL_FILE_MAX_PATH_LEN]; + strncpy(help_copy, sel->help_text, PL_FILE_MAX_PATH_LEN - 1); + help_copy[PL_FILE_MAX_PATH_LEN - 1] = '\0'; + ReplaceIcons(help_copy); + + dirs = help_copy; + } + else if (option_mode) + { + static char help_copy[PL_FILE_MAX_PATH_LEN]; + strncpy(help_copy, OptionModeTemplate, PL_FILE_MAX_PATH_LEN - 1); + help_copy[PL_FILE_MAX_PATH_LEN - 1] = '\0'; + ReplaceIcons(help_copy); + + dirs = help_copy; + } + + if (dirs) + pspVideoPrintCenter(UiMetric.Font, + 0, SCR_HEIGHT - fh, SCR_WIDTH, dirs, UiMetric.StatusBarColor); + } + + /* Draw title */ + if (title) + { + pspVideoPrint(UiMetric.Font, UiMetric.Left, UiMetric.Top, + title, UiMetric.TitleColor); + pspVideoDrawLine(UiMetric.Left, UiMetric.Top + fh - 1, UiMetric.Left + w, + UiMetric.Top + fh - 1, UiMetric.TitleColor); + } + + /* Render the menu items */ + for (item = pos.Top, i = 0, j = sy; item && i < lnmax; item = item->next, j += fh, i++) + { + if (item->caption) + { + /* Section header */ + if (item->caption[0] == '\t') + { + // if (i != 0) j += fh / 2; + pspVideoPrint(UiMetric.Font, sx, j, item->caption + 1, UiMetric.TitleColor); + pspVideoDrawLine(sx, j + fh - 1, sx + w, j + fh - 1, UiMetric.TitleColor); + continue; + } + + if (item == sel) sel_top = j; + + /* Item caption */ + pspVideoPrint(UiMetric.Font, sx + 10, j, item->caption, + (item == sel) ? UiMetric.SelectedColor : UiMetric.TextColor); + + if (!option_mode || item != sel) + { + /* Selected option for the item */ + if (item->selected) + { + k = sx + max_item_w + UiMetric.MenuItemMargin + 10; + k += pspVideoPrint(UiMetric.Font, k, j, item->selected->text, + (item == sel) ? UiMetric.SelectedColor : UiMetric.TextColor); + + if (!option_mode && item == sel) + if (sel->options && sel->options->next) + pspVideoPrint(UiMetric.Font, k + anim_frame, j, " >", UiMetric.MenuDecorColor); + } + } + } + } + + /* Render status information */ + RenderStatus(); + + /* Draw scrollbar */ + if (sbh > 0) + { + sby = sy + (int)((float)(h - sbh) * ((float)(pos.Offset + pos.Index) / (float)item_count)); + pspVideoFillRect(dx - UiMetric.ScrollbarWidth, sy, dx, dy, UiMetric.ScrollbarBgColor); + pspVideoFillRect(dx - UiMetric.ScrollbarWidth, sby, dx, sby + sbh, UiMetric.ScrollbarColor); + } + + /* End writing to call list */ + sceGuFinish(); + + if (!option_mode && !fast_scroll && sel && last_sel + && UiMetric.Animate && last_sel != sel) + { + /* Move animation */ + int f, n = 4; + for (f = 1; f <= n; f++) + { + pspVideoBegin(); + + /* Clear screen */ + if (!UiMetric.Background) pspVideoClearScreen(); + else pspVideoPutImage(UiMetric.Background, 0, 0, + UiMetric.Background->Viewport.Width, UiMetric.Background->Height); + + int box_top = last_sel_top-((last_sel_top-sel_top)/n)*f; + pspVideoFillRect(sx, box_top, sx+w, box_top+fh, + UiMetric.SelectedBgColor); + + sceGuCallList(call_list); + + /* Perform any custom drawing */ + if (uimenu->OnRender) + uimenu->OnRender(uimenu, sel); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + } + } + + /* Begin direct rendering */ + pspVideoBegin(); + + /* Clear screen */ + if (!UiMetric.Background) pspVideoClearScreen(); + else pspVideoPutImage(UiMetric.Background, 0, 0, + UiMetric.Background->Viewport.Width, UiMetric.Background->Height); + + /* NOTA: Tamanio otras barras Draw the highlight for selected item */ + if (!option_mode) + pspVideoFillRect(sx, sel_top, sx+(w-168), sel_top+fh, + UiMetric.SelectedBgColor); + + pspVideoCallList(call_list); + + /* Perform any custom drawing */ + if (uimenu->OnRender) + uimenu->OnRender(uimenu, sel); + + /* Render menu options */ + if (option_mode) + { + k = sx + max_item_w + UiMetric.MenuItemMargin + 10; + int arrow_x = min_x + (UiMetric.MenuItemMargin / 2 - arrow_w / 2); + const pl_menu_option *option; + + /* Background */ + pspVideoFillRect(min_x, min_y, max_x, max_y, UiMetric.MenuOptionBoxBg); + pspVideoFillRect(min_x, sy + pos.Index * fh, max_x, + sy + (pos.Index + 1) * fh, UiMetric.MenuSelOptionBg); + pspVideoGlowRect(min_x, min_y, max_x - 1, max_y - 1, + COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP * UI_ANIM_FRAMES), 2); + + /* Render selected item + previous items */ + i = sy + pos.Index * fh; + for (option = temp_option; option && i >= sy; option = option->prev, i -= fh) + pspVideoPrint(UiMetric.Font, k, i, option->text, (option == temp_option) + ? UiMetric.SelectedColor : UiMetric.MenuOptionBoxColor); + + /* Up arrow */ + if (option) pspVideoPrint(UiMetric.Font, arrow_x, + i + fh + anim_frame, PSP_CHAR_UP_ARROW, UiMetric.MenuDecorColor); + + /* Render following items */ + i = sy + (pos.Index + 1) * fh; + for (option = temp_option->next; option && i < dy; option = option->next, i += fh) + pspVideoPrint(UiMetric.Font, k, i, option->text, + UiMetric.MenuOptionBoxColor); + + /* Down arrow */ + if (option) pspVideoPrint(UiMetric.Font, arrow_x, i - fh - anim_frame, + PSP_CHAR_DOWN_ARROW, UiMetric.MenuDecorColor); + } + + pspVideoEnd(); + + /* Wait if needed */ + do { sceRtcGetCurrentTick(¤t_tick); } + while (current_tick - last_tick < ticks_per_upd); + last_tick = current_tick; + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + + last_sel = sel; + last_sel_top = sel_top; + } + + menu->selected = sel; +} + +void pspUiSplashScreen(PspUiSplash *splash) +{ + SceCtrlData pad; + int fh = pspFontGetLineHeight(UiMetric.Font); + + while (!ExitPSP) + { + if (!pspCtrlPollControls(&pad)) + continue; + + if (pad.Buttons & UiMetric.CancelButton) + { + if (splash->OnCancel) splash->OnCancel(splash, NULL); + break; + } + + if ((pad.Buttons & CONTROL_BUTTON_MASK) && splash->OnButtonPress) + { + if (splash->OnButtonPress(splash, pad.Buttons & CONTROL_BUTTON_MASK)) + break; + } + + pspVideoBegin(); + + /* Clear screen */ + if (UiMetric.Background) + pspVideoPutImage(UiMetric.Background, 0, 0, + UiMetric.Background->Viewport.Width, UiMetric.Background->Height); + else + pspVideoClearScreen(); + + /* Draw instructions */ + const char *dirs = (splash->OnGetStatusBarText) + ? splash->OnGetStatusBarText(splash) + : SplashStatusBarTemplate; + pspVideoPrintCenter(UiMetric.Font, UiMetric.Left, + SCR_HEIGHT - fh, UiMetric.Right, dirs, UiMetric.StatusBarColor); + + /* Render status information */ + RenderStatus(); + + /* Perform any custom drawing */ + if (splash->OnRender) + splash->OnRender(splash, NULL); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + } +} + +const pl_menu_item* pspUiSelect(const char *title, const pl_menu *menu) +{ + const pl_menu_item *sel, *item, *last_sel = NULL; + struct UiPos pos; + int lnmax, lnhalf; + int i, j, h, w, fh = pspFontGetLineHeight(UiMetric.Font); + int sx, sy, dx, dy; + int anim_frame = 0, anim_incr = 1; + int arrow_w = pspFontGetTextWidth(UiMetric.Font, PSP_CHAR_DOWN_ARROW); + int widest = 100; + int sel_top = 0, last_sel_top = 0; + SceCtrlData pad; + + char *help_text = strdup(SelectorTemplate); + ReplaceIcons(help_text); + + memset(call_list, 0, sizeof(call_list)); + + /* Determine width of the longest caption */ + for (item = menu->items; item; item = item->next) + { + if (item->caption) + { + int item_w = pspFontGetTextWidth(UiMetric.Font, item->caption); + if (item_w > widest) + widest = item_w; + } + } + + widest += UiMetric.MenuItemMargin * 2; + + sx = SCR_WIDTH - widest; + sy = UiMetric.Top; + dx = SCR_WIDTH; + dy = UiMetric.Bottom; + w = dx - sx; + h = dy - sy; + + u32 ticks_per_sec, ticks_per_upd; + u64 current_tick, last_tick; + + /* Initialize variables */ + lnmax = (dy - sy) / fh; + lnhalf = lnmax >> 1; + + sel = menu->items; + pos.Top = menu->items; + pos.Index = pos.Offset = 0; + + pspVideoWaitVSync(); + + /* Compute update frequency */ + ticks_per_sec = sceRtcGetTickResolution(); + sceRtcGetCurrentTick(&last_tick); + ticks_per_upd = ticks_per_sec / UiMetric.MenuFps; + + /* Get copy of screen */ + PspImage *screen = pspVideoGetVramBufferCopy(); + + if (UiMetric.Animate) + { + /* Intro animation */ + for (i = 0; i < UI_ANIM_FRAMES; i++) + { + pspVideoBegin(); + + /* Clear screen */ + pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height); + + /* Apply fog and draw right frame */ + pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT, + COLOR(0, 0, 0, UI_ANIM_FOG_STEP * i)); + pspVideoFillRect(SCR_WIDTH - (i * (widest / UI_ANIM_FRAMES)), + 0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + } + } + + int fast_scroll; + + /* Begin navigation loop */ + while (!ExitPSP) + { + if (!pspCtrlPollControls(&pad)) + continue; + + fast_scroll = 0; + + /* Incr/decr animation frame */ + anim_frame += (UiMetric.Animate) ? anim_incr : 0; + if (anim_frame > 2 || anim_frame < 0) + anim_incr *= -1; + + /* Check the directional buttons */ + if (sel) + { + if ((pad.Buttons & PSP_CTRL_DOWN || pad.Buttons & PSP_CTRL_ANALDOWN) + && sel->next) + { + fast_scroll = pad.Buttons & PSP_CTRL_ANALDOWN; + if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top = pos.Top->next; } + else pos.Index++; + sel = sel->next; + } + else if ((pad.Buttons & PSP_CTRL_UP || pad.Buttons & PSP_CTRL_ANALUP) + && sel->prev) + { + fast_scroll = pad.Buttons & PSP_CTRL_ANALUP; + if (pos.Index - 1 < 0) { pos.Offset--; pos.Top = pos.Top->prev; } + else pos.Index--; + sel = sel->prev; + } + else if (pad.Buttons & PSP_CTRL_LEFT) + { + for (i = 0; sel->prev && i < lnhalf; i++) + { + if (pos.Index - 1 < 0) { pos.Offset--; pos.Top = pos.Top->prev; } + else pos.Index--; + sel = sel->prev; + } + } + else if (pad.Buttons & PSP_CTRL_RIGHT) + { + for (i = 0; sel->next && i < lnhalf; i++) + { + if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top = pos.Top->next; } + else pos.Index++; + sel=sel->next; + } + } + + if (pad.Buttons & UiMetric.OkButton) break; + } + + if (pad.Buttons & UiMetric.CancelButton) { sel = NULL; break; } + + /* Render to a call list */ + sceGuStart(GU_CALL, call_list); + + /* Apply fog and draw frame */ + pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT, + COLOR(0, 0, 0, UI_ANIM_FOG_STEP * UI_ANIM_FRAMES)); + pspVideoGlowRect(sx, 0, dx - 1, SCR_HEIGHT - 1, + COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP * UI_ANIM_FRAMES), 2); + + /* Title */ + if (title) + pspVideoPrintCenter(UiMetric.Font, sx, 0, dx, + title, UiMetric.TitleColor); + + /* Render the items */ + for (item = (pl_menu_item*)pos.Top, i = 0, j = sy; + item && i < lnmax; item = item->next, j += fh, i++) + { + if (item == sel) sel_top = j; + pspVideoPrintClipped(UiMetric.Font, sx + 10, j, item->caption, w - 10, + "...", (item == sel) ? UiMetric.SelectedColor : UiMetric.TextColor); + } + + /* Up arrow */ + if (pos.Top && pos.Top->prev) pspVideoPrint(UiMetric.Font, + SCR_WIDTH - arrow_w * 2, sy + anim_frame, + PSP_CHAR_UP_ARROW, UiMetric.MenuDecorColor); + + /* Down arrow */ + if (item) pspVideoPrint(UiMetric.Font, SCR_WIDTH - arrow_w * 2, + dy - fh - anim_frame, PSP_CHAR_DOWN_ARROW, UiMetric.MenuDecorColor); + + /* Shortcuts */ + pspVideoPrintCenter(UiMetric.Font, sx, SCR_HEIGHT - fh, dx, + help_text, UiMetric.StatusBarColor); + + sceGuFinish(); + + if (sel != last_sel && !fast_scroll && sel && last_sel + && UiMetric.Animate) + { + /* Move animation */ + int f, n = 4; + for (f = 1; f <= n; f++) + { + pspVideoBegin(); + + /* Clear screen */ + pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height); + pspVideoFillRect(sx, 0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg); + + /* Selection box */ + int box_top = last_sel_top-((last_sel_top-sel_top)/n)*f; + pspVideoFillRect(sx, box_top, sx + w, box_top + fh, + UiMetric.SelectedBgColor); + + sceGuCallList(call_list); + + pspVideoEnd(); + + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + } + } + + pspVideoBegin(); + + /* Clear screen */ + pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height); + pspVideoFillRect(sx, 0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg); + + if (sel) pspVideoFillRect(sx, sel_top, sx + w, sel_top + fh, + UiMetric.SelectedBgColor); + + sceGuCallList(call_list); + + pspVideoEnd(); + + /* Wait if needed */ + do { sceRtcGetCurrentTick(¤t_tick); } + while (current_tick - last_tick < ticks_per_upd); + last_tick = current_tick; + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + + last_sel = sel; + last_sel_top = sel_top; + } + + if (UiMetric.Animate) + { + /* Exit animation */ + for (i = UI_ANIM_FRAMES - 1; i >= 0; i--) + { + pspVideoBegin(); + + /* Clear screen */ + pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height); + + /* Apply fog and draw right frame */ + pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT, + COLOR(0, 0, 0, UI_ANIM_FOG_STEP * i)); + pspVideoFillRect(SCR_WIDTH - (i * (widest / UI_ANIM_FRAMES)), + 0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + } + } + + free(help_text); + pspImageDestroy(screen); + + return sel; +} + +static void adhocMatchingCallback(int unk1, + int event, + unsigned char *mac2, + int opt_len, + void *opt_data) +{ + _adhoc_match_event.NewEvent = 1; + _adhoc_match_event.EventID = event; + memcpy(_adhoc_match_event.EventMAC, mac2, + sizeof(unsigned char) * 6); + strncpy(_adhoc_match_event.OptData, opt_data, sizeof(char) * opt_len); + _adhoc_match_event.OptData[opt_len] = '\0'; +} + +int pspUiAdhocHost(const char *name, PspMAC mac) +{ + /* Check the wlan switch */ + if (!pspAdhocIsWLANEnabled()) + { + pspUiAlert("Error: WLAN switch is turned off"); + return 0; + } + + pspUiFlashMessage(ADHOC_INITIALIZING); + _adhoc_match_event.NewEvent = 0; + + /* Initialize ad-hoc networking */ + if (!pspAdhocInit("ULUS99999", adhocMatchingCallback)) + { + pspUiAlert("Ad-hoc networking initialization failed"); + return 0; + } + + /* Wait for someone to join */ + pspUiFlashMessage(ADHOC_AWAITING_JOIN); + + int state = ADHOC_WAIT_CLI; + PspMAC selected; + + /* Loop until someone joins or host cancels */ + while (!ExitPSP) + { + SceCtrlData pad; + + if (!pspCtrlPollControls(&pad)) + continue; + + if (pad.Buttons & UiMetric.CancelButton) + break; + + if (_adhoc_match_event.NewEvent) + { + _adhoc_match_event.NewEvent = 0; + + switch(_adhoc_match_event.EventID) + { + case MATCHING_JOINED: + break; + case MATCHING_DISCONNECT: + case MATCHING_CANCELED: + if (pspAdhocIsMACEqual(selected, _adhoc_match_event.EventMAC)) + state = ADHOC_WAIT_CLI; + break; + case MATCHING_SELECTED: + if (state == ADHOC_WAIT_CLI) + { + memcpy(selected, _adhoc_match_event.EventMAC, + sizeof(unsigned char) * 6); + sceKernelDelayThread(1000000/60); + pspAdhocSelectTarget(selected); + state = ADHOC_WAIT_EST; + } + break; + case MATCHING_ESTABLISHED: + if (state == ADHOC_WAIT_EST) + { + if (pspAdhocIsMACEqual(selected, _adhoc_match_event.EventMAC)) + { + state = ADHOC_ESTABLISHED; + goto established; + } + } + break; + } + } + + /* Wait if needed */ + sceKernelDelayThread(1000000/60); + } + +established: + + if (state == ADHOC_ESTABLISHED) + { + sceKernelDelayThread(1000000); + + PspMAC my_mac; + pspAdhocGetOwnMAC(my_mac); + memcpy(mac, selected, sizeof(unsigned char) * 6); + + if (!pspAdhocConnect(my_mac)) + return 0; + + return 1; + } + + /* Shutdown ad-hoc networking */ + pspAdhocShutdown(); + return 0; +} + +int pspUiAdhocJoin(PspMAC mac) +{ + /* Check the wlan switch */ + if (!pspAdhocIsWLANEnabled()) + { + pspUiAlert("Error: WLAN switch is turned off"); + return 0; + } + + char *title = "Select host"; + + /* Get copy of screen */ + PspImage *screen = pspVideoGetVramBufferCopy(); + + pspUiFlashMessage(ADHOC_INITIALIZING); + _adhoc_match_event.NewEvent = 0; + + /* Initialize ad-hoc networking */ + if (!pspAdhocInit("ULUS99999", adhocMatchingCallback)) + { + pspUiAlert("Ad-hoc networking initialization failed"); + pspImageDestroy(screen); + return 0; + } + + /* Initialize menu */ + pl_menu menu; + pl_menu_create(&menu, NULL); + + int state = ADHOC_PENDING; + const pl_menu_item *sel, *item, *last_sel = NULL; + struct UiPos pos; + int lnmax, lnhalf; + int i, j, h, w, fh = pspFontGetLineHeight(UiMetric.Font); + int sx, sy, dx, dy; + int anim_frame = 0, anim_incr = 1; + int arrow_w = pspFontGetTextWidth(UiMetric.Font, PSP_CHAR_DOWN_ARROW); + int widest = 100; + int sel_top = 0, last_sel_top = 0; + SceCtrlData pad; + PspMAC selected; + + char *help_text = strdup(SelectorTemplate); + ReplaceIcons(help_text); + + memset(call_list, 0, sizeof(call_list)); + + /* Determine width of the longest caption */ + for (item = menu.items; item; item = item->next) + { + if (item->caption) + { + int item_w = pspFontGetTextWidth(UiMetric.Font, item->caption); + if (item_w > widest) + widest = item_w; + } + } + + widest += UiMetric.MenuItemMargin * 2; + + sx = SCR_WIDTH - widest; + sy = UiMetric.Top; + dx = SCR_WIDTH; + dy = UiMetric.Bottom; + w = dx - sx; + h = dy - sy; + + u32 ticks_per_sec, ticks_per_upd; + u64 current_tick, last_tick; + + /* Initialize variables */ + lnmax = (dy - sy) / fh; + lnhalf = lnmax >> 1; + + sel = menu.items; + pos.Top = menu.items; + pos.Index = pos.Offset = 0; + + pspVideoWaitVSync(); + + /* Compute update frequency */ + ticks_per_sec = sceRtcGetTickResolution(); + sceRtcGetCurrentTick(&last_tick); + ticks_per_upd = ticks_per_sec / UiMetric.MenuFps; + + if (UiMetric.Animate) + { + /* Intro animation */ + for (i = 0; i < UI_ANIM_FRAMES; i++) + { + pspVideoBegin(); + + /* Clear screen */ + pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height); + + /* Apply fog and draw right frame */ + pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT, + COLOR(0, 0, 0, UI_ANIM_FOG_STEP * i)); + pspVideoFillRect(SCR_WIDTH - (i * (widest / UI_ANIM_FRAMES)), + 0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + } + } + + int fast_scroll, found_psp; + + /* Begin navigation loop */ + while (!ExitPSP) + { + if (_adhoc_match_event.NewEvent) + { + found_psp = 0; + pl_menu_item *adhoc_item; + _adhoc_match_event.NewEvent = 0; + + if (_adhoc_match_event.EventID == MATCHING_JOINED) + { + /* Make sure the machine isn't already on the list */ + for (adhoc_item = menu.items; adhoc_item; adhoc_item = adhoc_item->next) + if (adhoc_item->param && pspAdhocIsMACEqual((unsigned char*)adhoc_item->param, + _adhoc_match_event.EventMAC)) + { + found_psp = 1; + break; + } + + if (!found_psp) + { + /* Create item */ + adhoc_item = pl_menu_append_item(&menu, 0, _adhoc_match_event.OptData); + + /* Add MAC */ + unsigned char *opp_mac = (unsigned char*)malloc(6 * sizeof(unsigned char)); + memcpy(opp_mac, _adhoc_match_event.EventMAC, sizeof(unsigned char) * 6); + adhoc_item->param = opp_mac; + + if (!pos.Top) + sel = pos.Top = menu.items; + } + } + else if (_adhoc_match_event.EventID == MATCHING_DISCONNECT) + { + /* Make sure the machine IS on the list */ + for (adhoc_item = menu.items; adhoc_item; adhoc_item = adhoc_item->next) + if (adhoc_item->param && pspAdhocIsMACEqual((unsigned char*)adhoc_item->param, + _adhoc_match_event.EventMAC)) + { + found_psp = 1; + break; + } + + if (found_psp) + { + /* Free MAC & destroy item */ + free((void*)adhoc_item->param); + pl_menu_remove_item(&menu, adhoc_item); + + /* Reset items */ + sel = pos.Top = menu.items; + pos.Index = pos.Offset = 0; + } + } + else if (_adhoc_match_event.EventID == MATCHING_REJECTED) + { + /* Host rejected connection */ + if (state == ADHOC_WAIT_HOST) + { + state = ADHOC_PENDING; + } + } + else if (_adhoc_match_event.EventID == MATCHING_ESTABLISHED) + { + if (state == ADHOC_WAIT_HOST) + { + state = ADHOC_EST_AS_CLI; + break; + } + } + } + + /* Delay */ + sceKernelDelayThread(1000000/60); + + if (!pspCtrlPollControls(&pad)) + continue; + + fast_scroll = 0; + + /* Incr/decr animation frame */ + anim_frame += (UiMetric.Animate) ? anim_incr : 0; + if (anim_frame > 2 || anim_frame < 0) + anim_incr *= -1; + + /* Check the directional buttons */ + if (sel) + { + if ((pad.Buttons & PSP_CTRL_DOWN || pad.Buttons & PSP_CTRL_ANALDOWN) + && sel->next) + { + fast_scroll = pad.Buttons & PSP_CTRL_ANALDOWN; + if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top = pos.Top->next; } + else pos.Index++; + sel = sel->next; + } + else if ((pad.Buttons & PSP_CTRL_UP || pad.Buttons & PSP_CTRL_ANALUP) + && sel->prev) + { + fast_scroll = pad.Buttons & PSP_CTRL_ANALUP; + if (pos.Index - 1 < 0) { pos.Offset--; pos.Top = pos.Top->prev; } + else pos.Index--; + sel = sel->prev; + } + else if (pad.Buttons & PSP_CTRL_LEFT) + { + for (i = 0; sel->prev && i < lnhalf; i++) + { + if (pos.Index - 1 < 0) { pos.Offset--; pos.Top = pos.Top->prev; } + else pos.Index--; + sel = sel->prev; + } + } + else if (pad.Buttons & PSP_CTRL_RIGHT) + { + for (i = 0; sel->next && i < lnhalf; i++) + { + if (pos.Index + 1 >= lnmax) { pos.Offset++; pos.Top = pos.Top->next; } + else pos.Index++; + sel=sel->next; + } + } + + if (pad.Buttons & UiMetric.OkButton) + { + if (state == ADHOC_PENDING) + { + state = ADHOC_WAIT_HOST; + memcpy(selected, sel->param, sizeof(unsigned char) * 6); + pspAdhocSelectTarget(selected); + } + } + } + + if (pad.Buttons & UiMetric.CancelButton) { sel = NULL; break; } + + /* Render to a call list */ + sceGuStart(GU_CALL, call_list); + + /* Apply fog and draw frame */ + pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT, + COLOR(0, 0, 0, UI_ANIM_FOG_STEP * UI_ANIM_FRAMES)); + pspVideoGlowRect(sx, 0, dx - 1, SCR_HEIGHT - 1, + COLOR(0xff,0xff,0xff,UI_ANIM_FOG_STEP * UI_ANIM_FRAMES), 2); + + /* Title */ + if (title) + pspVideoPrintCenter(UiMetric.Font, sx, 0, dx, + title, UiMetric.TitleColor); + + /* Render the items */ + for (item = (pl_menu_item*)pos.Top, i = 0, j = sy; + item && i < lnmax; item = item->next, j += fh, i++) + { + if (item == sel) sel_top = j; + pspVideoPrintClipped(UiMetric.Font, sx + 10, j, item->caption, w - 10, + "...", (item == sel) ? UiMetric.SelectedColor : UiMetric.TextColor); + } + + /* Up arrow */ + if (pos.Top && pos.Top->prev) pspVideoPrint(UiMetric.Font, + SCR_WIDTH - arrow_w * 2, sy + anim_frame, + PSP_CHAR_UP_ARROW, UiMetric.MenuDecorColor); + + /* Down arrow */ + if (item) pspVideoPrint(UiMetric.Font, SCR_WIDTH - arrow_w * 2, + dy - fh - anim_frame, PSP_CHAR_DOWN_ARROW, UiMetric.MenuDecorColor); + + /* Shortcuts */ + pspVideoPrintCenter(UiMetric.Font, sx, SCR_HEIGHT - fh, dx, + help_text, UiMetric.StatusBarColor); + + sceGuFinish(); + + if (sel != last_sel && !fast_scroll && sel && last_sel + && UiMetric.Animate) + { + /* Move animation */ + int f, n = 4; + for (f = 1; f <= n; f++) + { + pspVideoBegin(); + + /* Clear screen */ + pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height); + pspVideoFillRect(sx, 0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg); + + /* Selection box */ + int box_top = last_sel_top-((last_sel_top-sel_top)/n)*f; + pspVideoFillRect(sx, box_top, sx + w, box_top + fh, + UiMetric.SelectedBgColor); + + sceGuCallList(call_list); + + pspVideoEnd(); + + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + } + } + + pspVideoBegin(); + + /* Clear screen */ + pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height); + pspVideoFillRect(sx, 0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg); + + if (sel) pspVideoFillRect(sx, sel_top, sx + w, sel_top + fh, + UiMetric.SelectedBgColor); + + sceGuCallList(call_list); + + pspVideoEnd(); + + /* Wait if needed */ + do { sceRtcGetCurrentTick(¤t_tick); } + while (current_tick - last_tick < ticks_per_upd); + last_tick = current_tick; + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + + last_sel = sel; + last_sel_top = sel_top; + } + + if (UiMetric.Animate) + { + /* Exit animation */ + for (i = UI_ANIM_FRAMES - 1; i >= 0; i--) + { + pspVideoBegin(); + + /* Clear screen */ + pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height); + + /* Apply fog and draw right frame */ + pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT, + COLOR(0, 0, 0, UI_ANIM_FOG_STEP * i)); + pspVideoFillRect(SCR_WIDTH - (i * (widest / UI_ANIM_FRAMES)), + 0, dx, SCR_HEIGHT, UiMetric.MenuOptionBoxBg); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + } + } + + free(help_text); + pspImageDestroy(screen); + + /* Free memory used for MACs; menu resources */ + for (item = menu.items; item; item=item->next) + if (item->param) free((void*)item->param); + pl_menu_destroy(&menu); + + if (state == ADHOC_EST_AS_CLI) + { + memcpy(mac, selected, sizeof(unsigned char) * 6); + + if (!pspAdhocConnect(selected)) + return 0; + + return 1; + } + + /* Shut down ad-hoc networking */ + pspAdhocShutdown(); + return 0; +} + +void pspUiFadeout() +{ + /* Get copy of screen */ + PspImage *screen = pspVideoGetVramBufferCopy(); + + /* Exit animation */ + int i, alpha; + for (i = 0; i < UI_ANIM_FRAMES; i++) + { + pspVideoBegin(); + + /* Clear screen */ + pspVideoPutImage(screen, 0, 0, screen->Viewport.Width, screen->Height); + + /* Apply fog */ + alpha = (0x100/UI_ANIM_FRAMES)*i-1; + if (alpha > 0) + pspVideoFillRect(0, 0, SCR_WIDTH, SCR_HEIGHT, COLOR(0,0,0,alpha)); + + pspVideoEnd(); + + /* Swap buffers */ + pspVideoWaitVSync(); + pspVideoSwapBuffers(); + } + + pspImageDestroy(screen); +} + +void enter_directory(pl_file_path current_dir, + const char *subdir) +{ + pl_file_path new_path; + pl_file_open_directory(current_dir, + subdir, + new_path, + sizeof(new_path)); + strcpy(current_dir, new_path); +} diff --git a/psp/psplib/ui.h b/psp/psplib/ui.h new file mode 100644 index 0000000..9da4209 --- /dev/null +++ b/psp/psplib/ui.h @@ -0,0 +1,146 @@ +/* psplib/ui.h + Simple user interface implementation + + Copyright (C) 2007-2008 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: pspdev@akop.org +*/ + +#ifndef _PSP_UI_H +#define _PSP_UI_H + +#include "video.h" +#include "pl_menu.h" +#include "adhoc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct PspUiMetric +{ + const PspImage *Background; + const PspFont *Font; + u64 CancelButton; + u64 OkButton; + int Left; + int Top; + int Right; + int Bottom; + u32 ScrollbarColor; + u32 ScrollbarBgColor; + int ScrollbarWidth; + u32 TextColor; + u32 SelectedColor; + u32 SelectedBgColor; + u32 StatusBarColor; + int MenuFps; + + u32 DialogFogColor; + + u32 BrowserFileColor; + u32 BrowserDirectoryColor; + u32 BrowserScreenshotDelay; + const char *BrowserScreenshotPath; + + int GalleryIconsPerRow; + int GalleryIconMarginWidth; + + int MenuItemMargin; + u32 MenuSelOptionBg; + u32 MenuOptionBoxColor; + u32 MenuOptionBoxBg; + u32 MenuDecorColor; + + int TitlePadding; + u32 TitleColor; + u32 TabBgColor; + int Animate; +} PspUiMetric; + +typedef struct PspUiFileBrowser +{ + void (*OnRender)(const void *browser, const void *path); + int (*OnOk)(const void *browser, const void *file); + int (*OnCancel)(const void *gallery, const void *parent_dir); + int (*OnButtonPress)(const struct PspUiFileBrowser* browser, + const char *selected, u32 button_mask); + const char **Filter; + void *Userdata; +} PspUiFileBrowser; + +typedef struct PspUiMenu +{ + void (*OnRender)(const void *uimenu, const void *item); + int (*OnOk)(const void *menu, const void *item); + int (*OnCancel)(const void *menu, const void *item); + int (*OnButtonPress)(const struct PspUiMenu *menu, pl_menu_item *item, + u32 button_mask); + int (*OnItemChanged)(const struct PspUiMenu *menu, pl_menu_item *item, + const pl_menu_option *option); + pl_menu Menu; +} PspUiMenu; + +typedef struct PspUiGallery +{ + void (*OnRender)(const void *gallery, const void *item); + int (*OnOk)(const void *gallery, const void *item); + int (*OnCancel)(const void *gallery, const void *item); + int (*OnButtonPress)(const struct PspUiGallery *gallery, pl_menu_item* item, + u32 button_mask); + void *Userdata; + pl_menu Menu; +} PspUiGallery; + +typedef struct PspUiSplash +{ + void (*OnRender)(const void *splash, const void *null); + int (*OnCancel)(const void *splash, const void *null); + int (*OnButtonPress)(const struct PspUiSplash *splash, u32 button_mask); + const char* (*OnGetStatusBarText)(const struct PspUiSplash *splash); +} PspUiSplash; + +#define PSP_UI_YES 2 +#define PSP_UI_NO 1 +#define PSP_UI_CANCEL 0 + +#define PSP_UI_CONFIRM 1 + +char pspUiGetButtonIcon(u32 button_mask); + +void pspUiOpenBrowser(PspUiFileBrowser *browser, const char *start_path); +void pspUiOpenGallery(PspUiGallery *gallery, const char *title); +void pspUiOpenMenu(PspUiMenu *uimenu, const char *title); +void pspUiSplashScreen(PspUiSplash *splash); + +int pspUiAdhocHost(const char *name, PspMAC mac); +int pspUiAdhocJoin(PspMAC mac); + +int pspUiConfirm(const char *message); +int pspUiYesNoCancel(const char *message); +void pspUiAlert(const char *message); +void pspUiFlashMessage(const char *message); +const pl_menu_item* pspUiSelect(const char *title, const pl_menu *menu); + +void pspUiFadeout(); + +PspUiMetric UiMetric; + +#ifdef __cplusplus +} +#endif + +#endif // _PSP_UI_H diff --git a/psp/psplib/video.c b/psp/psplib/video.c new file mode 100644 index 0000000..5b6ee23 --- /dev/null +++ b/psp/psplib/video.c @@ -0,0 +1,762 @@ +/* psplib/video.c + Graphics rendering routines + + Copyright (C) 2007-2008 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: pspdev@akop.org +*/ + +/* TODO: move ScratchBuffer into VRAM */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "video.h" + +#define SLICE_SIZE 64 + +#define VRAM_START 0x04000000 +#define VRAM_SIZE 0x00200000 + +int res2x; +int vertical; +int bilinear; + + + +const unsigned int PspFontColor[] = +{ + 0, /* Restore */ + PSP_COLOR_BLACK, + PSP_COLOR_RED, + PSP_COLOR_GREEN, + PSP_COLOR_BLUE, + PSP_COLOR_GRAY, + PSP_COLOR_YELLOW, + PSP_COLOR_MAGENTA, + PSP_COLOR_WHITE +}; + +struct TexVertex +{ + unsigned short u, v; + unsigned short color; + short x, y, z; +}; + +static u8 FrameIndex; +static void *DisplayBuffer; +static void *DrawBuffer; +static int PixelFormat; +static int TexColor; +static unsigned int VBlankFreq; +static void *VramOffset; +static void *VramChunkOffset; +static unsigned short __attribute__((aligned(16))) ScratchBuffer[BUF_WIDTH * SCR_HEIGHT]; +//static void *ScratchBuffer; +//static int ScratchBufferSize; +static unsigned int __attribute__((aligned(16))) List[262144]; /* TODO: ? */ + +static void* GetBuffer(const PspImage *image); +static inline int PutChar(const PspFont *font, int sx, int sy, unsigned char sym, int color); + +void pspVideoInit() +{ + PixelFormat = GU_PSM_5551; + TexColor = GU_COLOR_5551; + VramOffset = 0; + FrameIndex = 0; + VramChunkOffset = (void*)0x44088000; +// ScratchBufferSize = sizeof(unsigned short) * BUF_WIDTH * SCR_HEIGHT; +// ScratchBuffer = pspVideoAllocateVramChunk(ScratchBufferSize); //;memalign(16, ScratchBufferSize); + + int size; + unsigned int vram_buffer_offset = 0; + + /* Initialize draw buffer */ + size = 2 * BUF_WIDTH * SCR_HEIGHT; + DrawBuffer = (void*)vram_buffer_offset; + vram_buffer_offset += size; + + /* Initialize display buffer */ + size = 4 * BUF_WIDTH * SCR_HEIGHT; + DisplayBuffer = (void*)vram_buffer_offset; + vram_buffer_offset += size; + + /* Initialize depth buffer */ + size = 2 * BUF_WIDTH * SCR_HEIGHT; + void *depth_buf = (void*)vram_buffer_offset; + vram_buffer_offset += size; + + sceGuInit(); + sceGuStart(GU_DIRECT, List); + sceGuDrawBuffer(PixelFormat, DrawBuffer, BUF_WIDTH); + sceGuDispBuffer(SCR_WIDTH, SCR_HEIGHT, DisplayBuffer, BUF_WIDTH); + sceGuDepthBuffer(depth_buf, BUF_WIDTH); + sceGuDisable(GU_TEXTURE_2D); + sceGuOffset(0, 0); + sceGuViewport(SCR_WIDTH/2, SCR_HEIGHT/2, SCR_WIDTH, SCR_HEIGHT); + sceGuDepthRange(0xc350, 0x2710); + sceGuDisable(GU_ALPHA_TEST); + sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); + sceGuEnable(GU_BLEND); + sceGuDisable(GU_DEPTH_TEST); + sceGuEnable(GU_CULL_FACE); + sceGuDisable(GU_LIGHTING); + sceGuFrontFace(GU_CW); + sceGuScissor(0, 0, SCR_WIDTH, SCR_HEIGHT); + sceGuEnable(GU_SCISSOR_TEST); + sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT); + sceGuAmbientColor(0xffffffff); + sceGuFinish(); + sceGuSync(0,0); + + /* Compute VBlank frequency */ + u64 t[2]; + int i; + for (i = 0; i < 2; i++) + { + sceDisplayWaitVblankStart(); + sceRtcGetCurrentTick(&t[i]); + } + VBlankFreq = round(1.00 / ((double)(t[1] - t[0]) + * (1.00 / (double)sceRtcGetTickResolution()))); + + sceGuDisplay(GU_TRUE); +} + +void* GetBuffer(const PspImage *image) +{ + int i, j, w, h; + static int last_w = -1, last_h = -1; + int x_offset, x_skip, x_buf_skip; + + w = (image->Viewport.Width > BUF_WIDTH) + ? BUF_WIDTH : image->Viewport.Width; + h = (image->Viewport.Height > SCR_HEIGHT) + ? SCR_HEIGHT : image->Viewport.Height; + + if (w != last_w || h != last_h) + memset(ScratchBuffer, 0, sizeof(ScratchBuffer)); + + x_offset = image->Viewport.X; + x_skip = image->Width - (image->Viewport.X + image->Viewport.Width); + x_buf_skip = BUF_WIDTH - w; + + if (image->Depth == PSP_IMAGE_INDEXED) + { + unsigned char *img_ptr = &((unsigned char*)image->Pixels)[image->Viewport.Y * image->Width]; + unsigned char *buf_ptr = (unsigned char*)ScratchBuffer; + + for (i = 0; i < h; i++) + { + img_ptr += x_offset; + for (j = 0; j < w; j++, img_ptr++, buf_ptr++) + *buf_ptr = *img_ptr; + buf_ptr += x_buf_skip; + img_ptr += x_skip; + } + } + else if (image->Depth == PSP_IMAGE_16BPP) + { + unsigned short *img_ptr = &((unsigned short*)image->Pixels)[image->Viewport.Y * image->Width]; + unsigned short *buf_ptr = ScratchBuffer; + + for (i = 0; i < h; i++) + { + img_ptr += x_offset; + for (j = 0; j < w; j++, img_ptr++, buf_ptr++) + *buf_ptr = *img_ptr; + buf_ptr += x_buf_skip; + img_ptr += x_skip; + } + } + + last_w = w; + last_h = h; + + return ScratchBuffer; +} + +void pspVideoBeginList(void *list) +{ + sceGuStart(GU_CALL, list); +} + +void pspVideoBegin() +{ + sceGuStart(GU_DIRECT, List); +} + +void pspVideoEnd() +{ + sceGuFinish(); + sceGuSync(0, 0); +} + +void pspVideoPutImage(const PspImage *image, int dx, int dy, int dw, int dh) +{ + sceGuScissor(dx, dy, dx + dw, dy + dh); + + void *pixels; + int width; + + if (image->PowerOfTwo) + { + pixels = image->Pixels; + width = image->Width; + } + else + { + pixels = GetBuffer(image); + width = BUF_WIDTH; + } + + sceKernelDcacheWritebackAll(); +/* + if (image->Depth != PSP_IMAGE_INDEXED && + dw == image->Viewport.Width && dh == image->Viewport.Height) + { + sceGuCopyImage(PixelFormat, + image->Viewport.X, image->Viewport.Y, + image->Viewport.Width, image->Viewport.Height, + width, pixels, dx, dy, + BUF_WIDTH, (void *)(VRAM_START + (u32)VramOffset)); + } + else +*/ + { + sceGuEnable(GU_TEXTURE_2D); + + if (image->Depth == PSP_IMAGE_INDEXED) + { + sceGuClutMode(PixelFormat, 0, 0xff, 0); + sceGuClutLoad(image->PalSize >> 3, image->Palette); + } + + sceGuTexMode(image->TextureFormat, 0, 0, GU_FALSE); + sceGuTexImage(0, width, width, width, pixels); + sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); + + if (bilinear == 0 ) + { + sceGuTexFilter(GU_NEAREST, GU_NEAREST); + } + else if (bilinear == 1 ) + { + sceGuTexFilter(GU_LINEAR, GU_LINEAR); + } + + + struct TexVertex* vertices; + int start, end, sc_end, slsz_scaled; + slsz_scaled = ceil((float)dw * (float)SLICE_SIZE) / (float)image->Viewport.Width; + + start = image->Viewport.X; + end = image->Viewport.X + image->Viewport.Width; + sc_end = dx + dw; + + /* TODO: Convert to floating-point coords */ + for (; start < end; start += SLICE_SIZE, dx += slsz_scaled) + { + vertices = (struct TexVertex*)sceGuGetMemory(2 * sizeof(struct TexVertex)); + + vertices[0].u = start; + vertices[0].v = image->Viewport.Y; + vertices[1].u = start + SLICE_SIZE; + vertices[1].v = image->Viewport.Height + image->Viewport.Y; + + /* NOTA*/ + + + if (res2x == 0) + {vertices[0].x = dx; vertices[0].y = dy;} + else if (res2x == 1) + {vertices[0].x = dx; vertices[0].y = dy-vertical;} + + + + + vertices[1].x = dx + slsz_scaled; vertices[1].y = dy + dh; + + vertices[0].color + = vertices[1].color + = vertices[0].z + = vertices[1].z = 0; + + sceGuDrawArray(GU_SPRITES, + GU_TEXTURE_16BIT|TexColor|GU_VERTEX_16BIT|GU_TRANSFORM_2D,2,0,vertices); + } + + sceGuDisable(GU_TEXTURE_2D); + } + + sceGuScissor(0, 0, SCR_WIDTH, SCR_HEIGHT); +} + +void pspVideoPutImage1(const PspImage *image, int dx, int dy, int dw, int dh) +{ + sceGuScissor(dx, dy, dx + dw, dy + dh); + + void *pixels; + int width; + + if (image->PowerOfTwo) + { + pixels = image->Pixels; + width = image->Width; + } + else + { + pixels = GetBuffer(image); + width = BUF_WIDTH; + } + + sceKernelDcacheWritebackAll(); +/* + if (image->Depth != PSP_IMAGE_INDEXED && + dw == image->Viewport.Width && dh == image->Viewport.Height) + { + sceGuCopyImage(PixelFormat, + image->Viewport.X, image->Viewport.Y, + image->Viewport.Width, image->Viewport.Height, + width, pixels, dx, dy, + BUF_WIDTH, (void *)(VRAM_START + (u32)VramOffset)); + } + else +*/ + { + sceGuEnable(GU_TEXTURE_2D); + + if (image->Depth == PSP_IMAGE_INDEXED) + { + sceGuClutMode(PixelFormat, 0, 0xff, 0); + sceGuClutLoad(image->PalSize >> 3, image->Palette); + } + + sceGuTexMode(image->TextureFormat, 0, 0, GU_FALSE); + sceGuTexImage(0, width, width, width, pixels); + sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); + sceGuTexFilter(GU_NEAREST, GU_NEAREST); + struct TexVertex* vertices; + int start, end, sc_end, slsz_scaled; + slsz_scaled = ceil((float)dw * (float)SLICE_SIZE) / (float)image->Viewport.Width; + + start = image->Viewport.X; + end = image->Viewport.X + image->Viewport.Width; + sc_end = dx + dw; + + /* TODO: Convert to floating-point coords */ + for (; start < end; start += SLICE_SIZE, dx += slsz_scaled) + { + vertices = (struct TexVertex*)sceGuGetMemory(2 * sizeof(struct TexVertex)); + + vertices[0].u = start; + vertices[0].v = image->Viewport.Y; + vertices[1].u = start + SLICE_SIZE; + vertices[1].v = image->Viewport.Height + image->Viewport.Y; + + /* NOTA*/ + + {vertices[0].x = dx; vertices[0].y = dy;} + + + vertices[1].x = dx + slsz_scaled; vertices[1].y = dy + dh; + + vertices[0].color + = vertices[1].color + = vertices[0].z + = vertices[1].z = 0; + + sceGuDrawArray(GU_SPRITES, + GU_TEXTURE_16BIT|TexColor|GU_VERTEX_16BIT|GU_TRANSFORM_2D,2,0,vertices); + } + + sceGuDisable(GU_TEXTURE_2D); + } + + sceGuScissor(0, 0, SCR_WIDTH, SCR_HEIGHT); +} + + + +void pspVideoPutImageAlpha(const PspImage *image, int dx, int dy, int dw, int dh, + unsigned char alpha) +{ + sceGuScissor(dx, dy, dx + dw, dy + dh); + + void *pixels; + int width; + + if (image->PowerOfTwo) + { + pixels = image->Pixels; + width = image->Width; + } + else + { + pixels = GetBuffer(image); + width = BUF_WIDTH; + } + + sceKernelDcacheWritebackAll(); +/* + if (image->Depth != PSP_IMAGE_INDEXED && + dw == image->Viewport.Width && dh == image->Viewport.Height) + { + sceGuCopyImage(PixelFormat, + image->Viewport.X, image->Viewport.Y, + image->Viewport.Width, image->Viewport.Height, + width, pixels, dx, dy, + BUF_WIDTH, (void *)(VRAM_START + (u32)VramOffset)); + } + else +*/ + { + unsigned int alpha_color = 0xff + | ((unsigned int)alpha << 8) + | ((unsigned int)alpha << 16) + | ((unsigned int)alpha << 24); + sceGuEnable(GU_TEXTURE_2D); + sceGuBlendFunc(GU_ADD, GU_FIX, GU_FIX, alpha_color, alpha_color); + + if (image->Depth == PSP_IMAGE_INDEXED) + { + sceGuClutMode(PixelFormat, 0, 0xff, 0); + sceGuClutLoad(image->PalSize >> 3, image->Palette); + } + + sceGuTexMode(image->TextureFormat, 0, 0, GU_FALSE); + sceGuTexImage(0, width, width, width, pixels); + sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); + sceGuTexFilter(GU_LINEAR, GU_LINEAR); + + struct TexVertex* vertices; + int start, end, sc_end, slsz_scaled; + slsz_scaled = ceil((float)dw * (float)SLICE_SIZE) / (float)image->Viewport.Width; + + start = image->Viewport.X; + end = image->Viewport.X + image->Viewport.Width; + sc_end = dx + dw; + + /* TODO: Convert to floating-point coords */ + for (; start < end; start += SLICE_SIZE, dx += slsz_scaled) + { + vertices = (struct TexVertex*)sceGuGetMemory(2 * sizeof(struct TexVertex)); + + vertices[0].u = start; + vertices[0].v = image->Viewport.Y; + vertices[1].u = start + SLICE_SIZE; + vertices[1].v = image->Viewport.Height + image->Viewport.Y; + + vertices[0].x = dx; vertices[0].y = dy; + vertices[1].x = dx + slsz_scaled; vertices[1].y = dy + dh; + + vertices[0].color + = vertices[1].color + = vertices[0].z + = vertices[1].z = 0; + + sceGuDrawArray(GU_SPRITES, + GU_TEXTURE_16BIT|TexColor|GU_VERTEX_16BIT|GU_TRANSFORM_2D,2,0,vertices); + } + + sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); + sceGuDisable(GU_TEXTURE_2D); + } + + sceGuScissor(0, 0, SCR_WIDTH, SCR_HEIGHT); +} + +void pspVideoSwapBuffers() +{ + VramOffset = sceGuSwapBuffers(); + FrameIndex = !FrameIndex; +} + +void pspVideoShutdown() +{ + sceGuTerm(); +} + +void pspVideoWaitVSync() +{ + sceDisplayWaitVblankStart(); +} + +void pspVideoDrawLine(int sx, int sy, int dx, int dy, u32 color) +{ + PspVertex *vert = (PspVertex*)sceGuGetMemory(sizeof(PspVertex) * 2); + memset(vert, 0, sizeof(PspVertex) * 2); + + vert[0].x = sx; vert[0].y = sy; vert[0].color = color; + vert[1].x = dx; vert[1].y = dy; vert[1].color = color; + + sceGuDrawArray(GU_LINES, GU_COLOR_8888 | GU_VERTEX_16BIT | GU_TRANSFORM_2D, 2, NULL, vert); +} + +void pspVideoDrawRect(int sx, int sy, int dx, int dy, u32 color) +{ + PspVertex *vert = (PspVertex*)sceGuGetMemory(sizeof(PspVertex) * 5); + memset(vert, 0, sizeof(PspVertex) * 5); + + vert[0].x=sx; vert[0].y=sy; vert[0].color = color; + vert[1].x=sx; vert[1].y=dy; vert[1].color = color; + vert[2].x=dx; vert[2].y=dy; vert[2].color = color; + vert[3].x=dx; vert[3].y=sy; vert[3].color = color; + vert[4].x=sx; vert[4].y=sy; vert[4].color = color; + + sceGuDrawArray(GU_LINE_STRIP, GU_COLOR_8888|GU_VERTEX_16BIT|GU_TRANSFORM_2D, 5, NULL, vert); +} + +void pspVideoShadowRect(int sx, int sy, int dx, int dy, u32 color, int depth) +{ + int i; + u32 alpha; + color &= ~0xff000000; + + for (i = depth, alpha = 0x30000000; i > 0; i--, alpha += 0x20000000) + { + pspVideoDrawLine(sx + i, dy + i, dx + i, dy + i, color | alpha); + pspVideoDrawLine(dx + i, sy + i, dx + i, dy + i + 1, color | alpha); + } +} + +void pspVideoGlowRect(int sx, int sy, int dx, int dy, u32 color, int radius) +{ + int i; + u32 alpha; + color &= ~0xff000000; + + for (i = radius, alpha = 0x30000000; i > 0; i--, alpha += 0x20000000) + pspVideoDrawRect(sx - i, sy - i, dx + i, dy + i, color | alpha); +} + +void pspVideoFillRect(int sx, int sy, int dx, int dy, u32 color) +{ + PspVertex *vert = (PspVertex*)sceGuGetMemory(4 * sizeof(PspVertex)); + memset(vert, 0, sizeof(PspVertex) * 4); + + vert[0].x = sx; vert[0].y = sy; vert[0].color = color; + vert[1].x = dx; vert[1].y = sy; vert[1].color = color; + vert[2].x = dx; vert[2].y = dy; vert[2].color = color; + vert[3].x = sx; vert[3].y = dy; vert[3].color = color; + + sceGuDrawArray(GU_TRIANGLE_FAN, GU_COLOR_8888|GU_VERTEX_16BIT|GU_TRANSFORM_2D, 4, NULL, vert); +} + +void pspVideoCallList(const void *list) +{ + sceGuCallList(list); +} + +void pspVideoClearScreen() +{ + sceGuClear(GU_COLOR_BUFFER_BIT); +} + +inline int PutChar(const PspFont *font, int sx, int sy, unsigned char sym, int color) +{ + /* Instead of a tab, skip 4 spaces */ + if (sym == (u8)'\t') + return font->Chars[(int)' '].Width * 4; + + /* This function should be rewritten to write directly to VRAM, probably */ + int h, v, i, j, w, s; + w = font->Chars[(int)sym].Width; + h = font->Height; + + /* Allocate and clear enough memory to write the pixels of the char */ + s = sizeof(PspVertex) * (w + 2) * (h + 2); + PspVertex *vert = (PspVertex*)sceGuGetMemory(s); + memset(vert, 0, s); + + unsigned short row; + int shift; + + v = 0; + for (j = 0; j < w; j++) + if (font->Chars[(int)sym].Char[0] & (1 << (w - j))) + { vert[v].x = sx + j; vert[v].y = sy - 1; vert[v].color = 0xff000000; v++; } + + /* Initialize pixel values */ + for (i = 0; i < h; i++) + { + for (j = 0; j < w; j++) + { + row = font->Chars[(int)sym].Char[i]; + shift = w - j; + + if (row & (1 << shift)) + { + if (j == 0 || !(row & (1 << (shift + 1)))) + { vert[v].x = sx + j - 1; vert[v].y = sy + i; vert[v].color = 0xff000000; v++; } + vert[v].x = sx + j; vert[v].y = sy + i; vert[v].color = color; v++; + vert[v].x = sx + j + 1; vert[v].y = sy + i; vert[v].color = 0xff000000; v++; + } + else if (i > 0 && i < h - 1) + { + if ((i > 0) && (font->Chars[(int)sym].Char[i - 1] & (1 << shift))) + { vert[v].x = sx + j; vert[v].y = sy + i; vert[v].color = 0xff000000; v++; } + else if ((i < h - 1) && (font->Chars[(int)sym].Char[i + 1] & (1 << shift))) + { vert[v].x = sx + j; vert[v].y = sy + i; vert[v].color = 0xff000000; v++; } + } + } + } + + for (j = 0; j < w; j++) + if (font->Chars[(int)sym].Char[h - 1] & (1 << (w - j))) + { vert[v].x = sx + j; vert[v].y = sy + h; vert[v].color = 0xff000000; v++; } + + /* Render the char as a set of pixels */ + sceGuDrawArray(GU_POINTS, GU_COLOR_8888|GU_VERTEX_16BIT|GU_TRANSFORM_2D, v, NULL, vert); + + /* Return total width */ + return w; +} + +int pspVideoPrint(const PspFont *font, int sx, int sy, const char *string, u32 color) +{ + return pspVideoPrintN(font, sx, sy, string, -1, color); +} + +int pspVideoPrintCenter(const PspFont *font, int sx, int sy, int dx, const char *string, u32 color) +{ + const unsigned char *ch; + int width, c = color, max; + + width = pspFontGetTextWidth(font, string); + sx += (dx - sx) / 2 - width / 2; + + for (ch = (unsigned char*)string, width = 0, max = 0; *ch; ch++) + { + if (*ch < 32) + { + if (*ch >= PSP_FONT_RESTORE && *ch <= PSP_FONT_WHITE) + { + c = (*ch == PSP_FONT_RESTORE) ? color : PspFontColor[(int)(*ch) - PSP_FONT_RESTORE]; + continue; + } + else if (*ch == '\n') + { + sy += font->Height; + width = 0; + continue; + } + } + + width += PutChar(font, sx + width, sy, (u8)(*ch), c); + if (width > max) max = width; + } + + return max; +} + +int pspVideoPrintN(const PspFont *font, int sx, int sy, const char *string, int count, u32 color) +{ + const unsigned char *ch; + int width, i, c = color, max; + + for (ch = (unsigned char*)string, width = 0, i = 0, max = 0; *ch && (count < 0 || i < count); ch++, i++) + { + if (*ch < 32) + { + if (*ch >= PSP_FONT_RESTORE && *ch <= PSP_FONT_WHITE) + { + c = (*ch == PSP_FONT_RESTORE) ? color : PspFontColor[(int)(*ch) - PSP_FONT_RESTORE]; + continue; + } + else if (*ch == '\n') + { + sy += font->Height; + width = 0; + continue; + } + } + + width += PutChar(font, sx + width, sy, (u8)(*ch), c); + if (width > max) max = width; + } + + return max; +} + +int pspVideoPrintClipped(const PspFont *font, int sx, int sy, const char* string, int max_w, char* clip, u32 color) +{ + int str_w = pspFontGetTextWidth(font, string); + + if (str_w <= max_w) + return pspVideoPrint(font, sx, sy, string, color); + + int w, len; + const char *ch; + int clip_w = pspFontGetTextWidth(font, clip); + + for (ch=string, w=0, len=0; *ch && (w + clip_w < max_w); ch++, len++) + { + if (*ch == '\t') w += font->Chars[(u8)' '].Width * 4; + else w += font->Chars[(u8)(*ch)].Width; + } + + w = pspVideoPrintN(font, sx, sy, string, len - 1, color); + pspVideoPrint(font, sx + w, sy, clip, color); + + return w + clip_w; +} + +PspImage* pspVideoGetVramBufferCopy() +{ + int i, j; + unsigned short *pixel, + *vram_addr = (u16*)((u8*)VRAM_START + 0x40000000); + PspImage *image; + + if (!(image = pspImageCreate(BUF_WIDTH, SCR_HEIGHT, PSP_IMAGE_16BPP))) + return NULL; + + image->Viewport.Width = SCR_WIDTH; + + for (i = 0; i < image->Height; i++) + { + for (j = 0; j < image->Viewport.Width; j++) + { + pixel = (unsigned short*)image->Pixels + (i * image->Width + j); + *pixel = *(vram_addr + (i * BUF_WIDTH + j)) | 0x8000; + } + } + + return image; +} + +void* pspVideoAllocateVramChunk(unsigned int bytes) +{ + void *ptr = VramChunkOffset; + VramChunkOffset += bytes; + + return ptr; +} + +unsigned int pspVideoGetVSyncFreq() +{ + return VBlankFreq; +} + diff --git a/psp/psplib/video.h b/psp/psplib/video.h new file mode 100644 index 0000000..bf0bd94 --- /dev/null +++ b/psp/psplib/video.h @@ -0,0 +1,118 @@ +/* psplib/video.h + Graphics rendering routines + + Copyright (C) 2007-2008 Akop Karapetyan + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Author contact information: pspdev@akop.org +*/ + +#ifndef _PSP_VIDEO_H +#define _PSP_VIDEO_H + +#include + +#include "font.h" +#include "image.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PSP_COLOR_WHITE (u32)0xffffffff +#define PSP_COLOR_BLACK (u32)0xff000000 +#define PSP_COLOR_GRAY (u32)0xffcccccc +#define PSP_COLOR_DARKGRAY (u32)0xff777777 +#define PSP_COLOR_RED (u32)0xff0000ff +#define PSP_COLOR_GREEN (u32)0xff00ff00 +#define PSP_COLOR_BLUE (u32)0xffff0000 +#define PSP_COLOR_YELLOW (u32)0xff00ffff +#define PSP_COLOR_MAGENTA (u32)0xffff00ff + +#define PSP_VIDEO_UNSCALED 0 +#define PSP_VIDEO_FIT_HEIGHT 1 +#define PSP_VIDEO_FILL_SCREEN 2 + +#define BUF_WIDTH 512 +#define SCR_WIDTH 480 +#define SCR_HEIGHT 272 + +#define COLOR(r,g,b,a) (((int)(r)&0xff)|(((int)(g)&0xff)<<8)|\ + (((int)(b)&0xff)<<16)|(((int)(a)&0xff)<<24)) + +#define RGB(r,g,b) (((((b)>>3)&0x1F)<<10)|((((g)>>3)&0x1F)<<5)|\ + (((r)>>3)&0x1F)|0x8000) +#define RED(pixel) ((((pixel))&0x1f)*0xff/0x1f) +#define GREEN(pixel) ((((pixel)>>5)&0x1f)*0xff/0x1f) +#define BLUE(pixel) ((((pixel)>>10)&0x1f)*0xff/0x1f) + +#define RGB_32(r,g,b) COLOR(r,g,b,0xff) +#define RGBA_32(r,g,b,a) COLOR(r,g,b,a) + +#define RED_32(c) ((c)&0xff) +#define GREEN_32(c) (((c)>>8)&0xff) +#define BLUE_32(c) (((c)>>16)&0xff) +#define ALPHA_32(c) (((c)>>24)&0xff) + +extern const unsigned int PspFontColor[]; + +typedef struct PspVertex +{ + unsigned int color; + short x, y, z; +} PspVertex; + +void pspVideoInit(); +void pspVideoShutdown(); +void pspVideoClearScreen(); +void pspVideoWaitVSync(); +void pspVideoSwapBuffers(); + +void pspVideoBegin(); +void pspVideoEnd(); + +void pspVideoDrawLine(int sx, int sy, int dx, int dy, u32 color); +void pspVideoDrawRect(int sx, int sy, int dx, int dy, u32 color); +void pspVideoFillRect(int sx, int sy, int dx, int dy, u32 color); + +int pspVideoPrint(const PspFont *font, int sx, int sy, const char *string, u32 color); +int pspVideoPrintCenter(const PspFont *font, int sx, int sy, int dx, const char *string, u32 color); +int pspVideoPrintN(const PspFont *font, int sx, int sy, const char *string, int count, u32 color); +int pspVideoPrintClipped(const PspFont *font, int sx, int sy, const char* string, int max_w, char* clip, u32 color); +int pspVideoPrintNRaw(const PspFont *font, int sx, int sy, const char *string, int count, u32 color); +int pspVideoPrintRaw(const PspFont *font, int sx, int sy, const char *string, u32 color); + +void pspVideoPutImage(const PspImage *image, int dx, int dy, int dw, int dh); +void pspVideoPutImage1(const PspImage *image, int dx, int dy, int dw, int dh); +void pspVideoPutImageAlpha(const PspImage *image, int dx, int dy, int dw, int dh, + unsigned char alpha); + +void pspVideoGlowRect(int sx, int sy, int dx, int dy, u32 color, int radius); +void pspVideoShadowRect(int sx, int sy, int dx, int dy, u32 color, int depth); + +PspImage* pspVideoGetVramBufferCopy(); + +void pspVideoBeginList(void *list); +void pspVideoCallList(const void *list); + +void* pspVideoAllocateVramChunk(unsigned int bytes); + +unsigned int pspVideoGetVSyncFreq(); + +#ifdef __cplusplus +} +#endif + +#endif // _PSP_VIDEO_H diff --git a/psp/race-icon.png b/psp/race-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8a5f0aa70056444b671455244ac9e8a83ba655e2 GIT binary patch literal 4209 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 Hu0mjfYJ&)# literal 0 HcmV?d00001 diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..250a8b9 --- /dev/null +++ b/readme.txt @@ -0,0 +1,90 @@ + / __/ / + / _// / . ||//.\/ ./ +/_/ /_/_/|_|_/\_/_/\_\ + +=================================================================================== + +Full Name: RACE! (As In Koyote-Land) +Date: 5-18-06 +Original Author: Judge_ +Website: http://www.personal.triticom.com/~erm/GP2X/ +Contact: http://www.gp32x.com/board/index.php?showuser=300 + http://www.neo-geo.com/forums/member.php?userid=1670 +GPL: Yes + +(R)ather +(A) +(C)ardfighter +(E)mulator +(!) + +RACE! is a Neo Geo Pocket (NGP) and Neo Geo Pocket Color (NGPC) emulator for +multiple platforms. +=================================================================================== + +Known Issues: +------------- +Must exit emulator using L+R to make sure save-game file gets written +Missing file selector +No emulator state saving + + +Portability: +------------ +The GP2X and PC versions use SDL. The code should be very portable to any +Little Endian system. If your system is Big Endian, the TLCS900h core may +be problematic. + +Please contact Flavor if you have any interest in porting RACE! to another system. + + +Credits: +-------- +Judge_ - RACE! is based on Judge_'s MHE (Multiple Handheld Emulator) code. + Judge_ is a guru of the NGPC devel scene. + +Flavor - Flavor has been the head of the project to port Judge_'s emulator + to GP2X. Porting/Optimizing/Testing/Fixing/etc. + +Thor - Thor has been integral to the RACE! project. He was originally + contacted to help fix a sound problem. Since then he was fixed + numerous items, optimized many parts of the emulation, and ported RACE! + to the GP32 among other things. + +Reesy - Thanks to Reesy, we have DrZ80, a hand optimized ARM ASM Z80 core. + +Hooka - TJ Hooka is head of the PR department. + +NeoPop_uk- Author of the NeoPop NGPC emulator. Some of his code is in RACE! + and some ideas have come from his emulator. + +Cal2 - AKA David Raingeard. Koyote has been an inspiration, and some + information and example code has come from Koyote. + +Tom at www.Play-Asia.com + - Without you, I might not own a GP2X or may not have owned a GP32! + +Mr. Spiv - ARM assembly code and more + +Mithris - Code pointers and GP2X hardware help + +RobBrown - Morale support and code help + +Empee - Sometimes just being there is enough. + +Sweater Fish Deluxe + - Help with NGPC flash cart codes from my days of working on my + MultiROM project. + +Craigix at www.gp2x.co.uk and www.gbax.com + - Thanks for pushing the GP32 and GP2X scenes with great competitions, + prizes, games, etc. Also, thanks for dealing with GamePark and GPH for us. + +Other people that have helped me along the way. + Fuz, Ivan, Darkfader, JeffF, and everyone on the NGPCdev Yahoo! Groups List + Comic Kaze and all the people at the Sector: NGP forum. + Miq01, Paeryn, Guyfawkes, DZZ, and the developers from #gp2xdev + Firefly, Don Miguel, Ph0x, and others from #gp32dev + www.gp32x.com and www.neo-geo.com forum people + + diff --git a/sound.cpp b/sound.cpp new file mode 100644 index 0000000..e9fb84c --- /dev/null +++ b/sound.cpp @@ -0,0 +1,112 @@ +//--------------------------------------------------------------------------- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. See also the license.txt file for +// additional informations. +//--------------------------------------------------------------------------- + +// sound.cpp: implementation of the sound class. +// +////////////////////////////////////////////////////////////////////// + +//Flavor - Convert from DirectSound to SDL + +#ifndef __GP32__ +#include "StdAfx.h" +#endif +#include "main.h" +#include "sound.h" +#include "memory.h" + +#ifdef DRZ80 +#include "DrZ80_support.h" +#else +#if defined(CZ80) +#include "cz80_support.h" +#else +#include "z80.h" +#endif +#endif + +#ifndef __GP32__ +#include +#endif + +#define Machine (&m_emuInfo) + + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +int sndCycles = 0; + +void soundStep(int cycles) +{ + sndCycles+= cycles; +} + +///////////////////////////////////////////////////////////////////////////////// +/// +/// Neogeo Pocket Sound system +/// +///////////////////////////////////////////////////////////////////////////////// + +unsigned int ngpRunning; + +void ngpSoundStart() +{ + ngpRunning = 1; // ? +#if defined(DRZ80) || defined(CZ80) + Z80_Reset(); +#else + z80Init(); + z80SetRunning(1); +#endif +} + +/// Execute all gained cycles (divided by 2) +void ngpSoundExecute() +{ +#if defined(DRZ80) || defined(CZ80) + int toRun = sndCycles/2; + if(ngpRunning) + { + Z80_Execute(toRun); + } + //timer_add_cycles(toRun); + sndCycles -= toRun; +#else + int elapsed; + while(sndCycles > 0) + { + elapsed = z80Step(); + sndCycles-= (2*elapsed); + //timer_add_cycles(elapsed); + } +#endif +} + +/// Switch sound system off +void ngpSoundOff() { + ngpRunning = 0; +#if defined(DRZ80) || defined(CZ80) + +#else + z80SetRunning(0); +#endif +} + +// Generate interrupt to ngp sound system +void ngpSoundInterrupt() { + if (ngpRunning) + { +#if defined(DRZ80) || defined(CZ80) + Z80_Cause_Interrupt(0x100);//Z80_IRQ_INT??? +#else + z80Interrupt(0); +#endif + } +} + diff --git a/sound.h b/sound.h new file mode 100644 index 0000000..988994e --- /dev/null +++ b/sound.h @@ -0,0 +1,68 @@ +//--------------------------------------------------------------------------- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. See also the license.txt file for +// additional informations. +//--------------------------------------------------------------------------- + +// sound.h: interface for the sound class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_SOUND_H__15E0A182_A0FD_11D4_8645_0050DA4EEEA0__INCLUDED_) +#define AFX_SOUND_H__15E0A182_A0FD_11D4_8645_0050DA4EEEA0__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#ifndef __GP32__ +#include "StdAfx.h" +#endif +#include "main.h" + +int initSound(); +void soundCleanup(); + +#ifndef __GP32__ +void setHwnd(HWND hWnd); +#endif + +// +// stolen MAME things +// +int osd_start_audio_stream(int stereo); +void osd_stop_audio_stream(void); +int osd_update_audio_stream(short *buffer); +void osd_set_mastervolume(int _attenuation); +int osd_get_mastervolume(void); + +// +// General sound system functions +// +void soundStep(int cycles); +void soundOutput(); + +#define NUM_CHANNELS 32 +#if !defined(__GP32__) && !defined(PSP) +extern Mix_Chunk *chunks[NUM_CHANNELS]; +#endif + +// +// Gameboy sound system +// +void gbSoundInit(); +void gbSoundUpdate(); +void gbSoundWrite(int reg, unsigned char data); + +/// +/// Neogeo pocket sound functions +/// +void sound_update(void); +void ngpSoundStart(); +void ngpSoundExecute(); +void ngpSoundOff(); +void ngpSoundInterrupt(); + +#endif // !defined(AFX_SOUND_H__15E0A182_A0FD_11D4_8645_0050DA4EEEA0__INCLUDED_) diff --git a/state.cpp b/state.cpp new file mode 100644 index 0000000..4905fee --- /dev/null +++ b/state.cpp @@ -0,0 +1,421 @@ +//--------------------------------------------------------------------------- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. See also the license.txt file for +// additional informations. +//--------------------------------------------------------------------------- + +// state.cpp: state saving +// +// 01/20/2009 Cleaned up interface, added loading from memory +// Moved signature-related stuff out of race_state (A.K.) +// 09/11/2008 Initial version (Akop Karapetyan) +// +////////////////////////////////////////////////////////////////////// + +#include "cz80.h" +#include "neopopsound.h" + +#include +#include +#include "state.h" +#include "tlcs900h.h" +#include "memory.h" + +#ifdef PC +#undef PC +#endif + +#define CURRENT_SAVE_STATE_VERSION 0x11 + +struct race_state_header +{ + u8 state_version; /* State version */ + u8 rom_signature[0x40]; /* Rom signature, for verification */ +}; + +struct race_state_0x11 +{ + /* Memory */ + u8 ram[0xc000]; + u8 cpuram[0x08a0]; + + /* TLCS-900h Registers */ + u32 pc, sr; + u8 f_dash; + u32 gpr[23]; + + /* Z80 Registers */ + cz80_struc RACE_cz80_struc; + u32 PC_offset; + s32 Z80_ICount; + + /* Sound */ + int sndCycles; + SoundChip toneChip; + SoundChip noiseChip; + + /* Timers */ + int timer0, timer1, timer2, timer3; + + /* DMA */ + u8 ldcRegs[64]; +}; + +struct race_state_0x10 /* Older state format */ +{ + //Save state version + u8 state_version; // = 0x10 + + //Rom signature + u8 rom_signature[0x40]; + + //Memory + u8 ram[0xc000]; + u8 cpuram[0x08a0];// 0xC000]; 0x38000 + + //TLCS-900h Registers + u32 pc, sr; + u8 f_dash; + u32 gpr[23]; + + //Z80 Registers + cz80_struc RACE_cz80_struc; + u32 PC_offset; + s32 Z80_ICount; + + //Sound Chips + int sndCycles; + SoundChip toneChip; + SoundChip noiseChip; + + //Timers + int timer0, timer1, timer2, timer3; + + //DMA + u8 ldcRegs[64]; +}; + +typedef struct race_state_0x11 race_state_t; + +static int state_store(race_state_t *rs); +static int state_restore(race_state_t *rs); +static int state_restore_0x10(FILE *stream); + +int state_store_mem(void *state) +{ + return state_store((race_state_t*)state); +} + +int state_restore_mem(void *state) +{ + return state_restore((race_state_t*)state); +} + +int state_get_size() +{ + return sizeof(race_state_t); +} + +static int state_store(race_state_t *rs) +{ + int i = 0; + + /* TLCS-900h Registers */ + rs->pc = gen_regsPC; + rs->sr = gen_regsSR; + rs->f_dash = F2; + + rs->gpr[i++] = gen_regsXWA0; + rs->gpr[i++] = gen_regsXBC0; + rs->gpr[i++] = gen_regsXDE0; + rs->gpr[i++] = gen_regsXHL0; + + rs->gpr[i++] = gen_regsXWA1; + rs->gpr[i++] = gen_regsXBC1; + rs->gpr[i++] = gen_regsXDE1; + rs->gpr[i++] = gen_regsXHL1; + + rs->gpr[i++] = gen_regsXWA2; + rs->gpr[i++] = gen_regsXBC2; + rs->gpr[i++] = gen_regsXDE2; + rs->gpr[i++] = gen_regsXHL2; + + rs->gpr[i++] = gen_regsXWA3; + rs->gpr[i++] = gen_regsXBC3; + rs->gpr[i++] = gen_regsXDE3; + rs->gpr[i++] = gen_regsXHL3; + + rs->gpr[i++] = gen_regsXIX; + rs->gpr[i++] = gen_regsXIY; + rs->gpr[i++] = gen_regsXIZ; + rs->gpr[i++] = gen_regsXSP; + + rs->gpr[i++] = gen_regsSP; + rs->gpr[i++] = gen_regsXSSP; + rs->gpr[i++] = gen_regsXNSP; + + /* Z80 Registers */ + extern cz80_struc *RACE_cz80_struc; + extern s32 Z80_ICount; + int size_of_z80 = + (u32)(&(RACE_cz80_struc->CycleSup)) - (u32)(&(RACE_cz80_struc->BC)); + memcpy(&rs->RACE_cz80_struc, RACE_cz80_struc, size_of_z80); + rs->Z80_ICount = Z80_ICount; + rs->PC_offset = Cz80_Get_PC(RACE_cz80_struc); + + /* Sound */ + extern int sndCycles; + rs->sndCycles = sndCycles; + memcpy(&rs->toneChip, &toneChip, sizeof(SoundChip)); + memcpy(&rs->noiseChip, &noiseChip, sizeof(SoundChip)); + + /* Timers */ + rs->timer0 = timer0; + rs->timer1 = timer1; + rs->timer2 = timer2; + rs->timer3 = timer3; + + /* DMA */ + memcpy(&rs->ldcRegs, &ldcRegs, sizeof(ldcRegs)); + + /* Memory */ + memcpy(rs->ram, mainram, sizeof(rs->ram)); + memcpy(rs->cpuram, &mainram[0x20000], sizeof(rs->cpuram)); + + return 1; +} + +static int state_restore(race_state_t *rs) +{ + int i = 0; + + /* TLCS-900h Registers */ + gen_regsPC = rs->pc; + gen_regsSR = rs->sr; + F2 = rs->f_dash; + + gen_regsXWA0 = rs->gpr[i++]; + gen_regsXBC0 = rs->gpr[i++]; + gen_regsXDE0 = rs->gpr[i++]; + gen_regsXHL0 = rs->gpr[i++]; + + gen_regsXWA1 = rs->gpr[i++]; + gen_regsXBC1 = rs->gpr[i++]; + gen_regsXDE1 = rs->gpr[i++]; + gen_regsXHL1 = rs->gpr[i++]; + + gen_regsXWA2 = rs->gpr[i++]; + gen_regsXBC2 = rs->gpr[i++]; + gen_regsXDE2 = rs->gpr[i++]; + gen_regsXHL2 = rs->gpr[i++]; + + gen_regsXWA3 = rs->gpr[i++]; + gen_regsXBC3 = rs->gpr[i++]; + gen_regsXDE3 = rs->gpr[i++]; + gen_regsXHL3 = rs->gpr[i++]; + + gen_regsXIX = rs->gpr[i++]; + gen_regsXIY = rs->gpr[i++]; + gen_regsXIZ = rs->gpr[i++]; + gen_regsXSP = rs->gpr[i++]; + + gen_regsSP = rs->gpr[i++]; + gen_regsXSSP = rs->gpr[i++]; + gen_regsXNSP = rs->gpr[i++]; + + /* Z80 Registers */ + extern cz80_struc *RACE_cz80_struc; + extern s32 Z80_ICount; + int size_of_z80 = + (u32)(&(RACE_cz80_struc->CycleSup)) - (u32)(&(RACE_cz80_struc->BC)); + + memcpy(RACE_cz80_struc, &rs->RACE_cz80_struc, size_of_z80); + Z80_ICount = rs->Z80_ICount; + Cz80_Set_PC(RACE_cz80_struc, rs->PC_offset); + + /* Sound */ + extern int sndCycles; + sndCycles = rs->sndCycles; + memcpy(&toneChip, &rs->toneChip, sizeof(SoundChip)); + memcpy(&noiseChip, &rs->noiseChip, sizeof(SoundChip)); + + /* Timers */ + timer0 = rs->timer0; + timer1 = rs->timer1; + timer2 = rs->timer2; + timer3 = rs->timer3; + + /* DMA */ + memcpy(&ldcRegs, &rs->ldcRegs, sizeof(ldcRegs)); + + /* Memory */ + memcpy(mainram, rs->ram, sizeof(rs->ram)); + memcpy(&mainram[0x20000], rs->cpuram, sizeof(rs->cpuram)); + + /* Reinitialize TLCS (mainly redirect pointers) */ + tlcs_reinit(); + + return 1; +} + +int state_restore(FILE *stream) +{ + /* Note current position (in case of compatibility rewinds */ + long read_pos = ftell(stream); + + /* Read header */ + struct race_state_header rsh; + if (fread(&rsh, sizeof(rsh), 1, stream) < 1) + return 0; + + /* Verify state version */ + if (rsh.state_version == 0x10) + { + fseek(stream, read_pos, SEEK_SET); /* Rewind and load old format */ + return state_restore_0x10(stream); + } + else if (rsh.state_version != CURRENT_SAVE_STATE_VERSION) + return 0; /* Unsupported version */ + + /* Verify ROM signature */ + if (memcmp(mainrom, rsh.rom_signature, sizeof(rsh.rom_signature)) != 0) + return 0; + + /* Read state data */ + race_state_t rs; + if (fread(&rs, sizeof(rs), 1, stream) < 1) + return 0; + + /* Restore state */ + return state_restore(&rs); +} + +int state_store(FILE *stream) +{ + /* Set version & ROM signature information */ + struct race_state_header rsh; + rsh.state_version = CURRENT_SAVE_STATE_VERSION; + memcpy(rsh.rom_signature, mainrom, sizeof(rsh.rom_signature)); + + /* Initialize state data */ + race_state_t rs; + if (!state_store(&rs)) + return 0; + + /* Write to file */ + if (fwrite(&rsh, sizeof(rsh), 1, stream) < 1) + return 0; + if (fwrite(&rs, sizeof(rs), 1, stream) < 1) + return 0; + + return 1; +} + +int state_store(char* filename) +{ + FILE *stream; + if (!(stream = fopen(filename, "w"))) + return 0; + + int status = state_store(stream); + fclose(stream); + + return status; +} + +int state_restore(char* filename) +{ + FILE *stream; + if (!(stream = fopen(filename, "r"))) + return 0; + + int status = state_restore(stream); + fclose(stream); + + return status; +} + +static int state_restore_0x10(FILE *stream) +{ + struct race_state_0x10 rs; + if (fread(&rs, sizeof(rs), 1, stream) < 1) + return 0; + + // Verify state version + if (rs.state_version != 0x10) + return 0; + + // Verify ROM signature + if (memcmp(mainrom, rs.rom_signature, sizeof(rs.rom_signature)) != 0) + return 0; + + //TLCS-900h Registers + gen_regsPC = rs.pc; + gen_regsSR = rs.sr; + F2 = rs.f_dash; + + int i = 0; + gen_regsXWA0 = rs.gpr[i++]; + gen_regsXBC0 = rs.gpr[i++]; + gen_regsXDE0 = rs.gpr[i++]; + gen_regsXHL0 = rs.gpr[i++]; + + gen_regsXWA1 = rs.gpr[i++]; + gen_regsXBC1 = rs.gpr[i++]; + gen_regsXDE1 = rs.gpr[i++]; + gen_regsXHL1 = rs.gpr[i++]; + + gen_regsXWA2 = rs.gpr[i++]; + gen_regsXBC2 = rs.gpr[i++]; + gen_regsXDE2 = rs.gpr[i++]; + gen_regsXHL2 = rs.gpr[i++]; + + gen_regsXWA3 = rs.gpr[i++]; + gen_regsXBC3 = rs.gpr[i++]; + gen_regsXDE3 = rs.gpr[i++]; + gen_regsXHL3 = rs.gpr[i++]; + + gen_regsXIX = rs.gpr[i++]; + gen_regsXIY = rs.gpr[i++]; + gen_regsXIZ = rs.gpr[i++]; + gen_regsXSP = rs.gpr[i++]; + + gen_regsSP = rs.gpr[i++]; + gen_regsXSSP = rs.gpr[i++]; + gen_regsXNSP = rs.gpr[i++]; + + //Z80 Registers + extern cz80_struc *RACE_cz80_struc; + extern s32 Z80_ICount; + int size_of_z80 = + (u32)(&(RACE_cz80_struc->CycleSup)) - (u32)(&(RACE_cz80_struc->BC)); + + memcpy(RACE_cz80_struc, &rs.RACE_cz80_struc, size_of_z80); + Z80_ICount = rs.Z80_ICount; + Cz80_Set_PC(RACE_cz80_struc, rs.PC_offset); + + //Sound Chips + extern int sndCycles; + sndCycles = rs.sndCycles; + memcpy(&toneChip, &rs.toneChip, sizeof(SoundChip)); + memcpy(&noiseChip, &rs.noiseChip, sizeof(SoundChip)); + + //Timers + timer0 = rs.timer0; + timer1 = rs.timer1; + timer2 = rs.timer2; + timer3 = rs.timer3; + + //DMA + memcpy(&ldcRegs, &rs.ldcRegs, sizeof(ldcRegs)); + + //Memory + memcpy(mainram, rs.ram, sizeof(rs.ram)); + memcpy(&mainram[0x20000], rs.cpuram, sizeof(rs.cpuram)); + + tlcs_reinit(); + + return 1; +} diff --git a/state.h b/state.h new file mode 100644 index 0000000..c5dc530 --- /dev/null +++ b/state.h @@ -0,0 +1,31 @@ +//--------------------------------------------------------------------------- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. See also the license.txt file for +// additional informations. +//--------------------------------------------------------------------------- + +// state.h: state saving +// +// 01/20/2009 Cleaned up interface, added loading from memory (A.K.) +// Moved struct definitions to .cpp +// 09/11/2008 Initial version (Akop Karapetyan) +// +////////////////////////////////////////////////////////////////////// + +#ifndef _STATE_H +#define _STATE_H + +int state_get_size(); +int state_store_mem(void *state); +int state_restore_mem(void *state); + +int state_store(char* filename); +int state_restore(char* filename); +int state_store(FILE *stream); +int state_restore(FILE *stream); + +//============================================================================= +#endif // _STATE_H + diff --git a/tlcs900h.cpp b/tlcs900h.cpp new file mode 100644 index 0000000..26394d1 --- /dev/null +++ b/tlcs900h.cpp @@ -0,0 +1,9363 @@ +//--------------------------------------------------------------------------- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. See also the license.txt file for +// additional informations. +//--------------------------------------------------------------------------- + +// tlcs900h.cpp: implementation of the tlcs900h class. +// +// 010906 - Checked and fixed ADD/ADC/SUB/SBC/AND/OR/XOR/MUL/MULS/DAA for 100% correctness +// 010324 - Fixed a stupid flag bug in the rotate & shift instructions +// 001230 - Fixed and cleaned XORCF and ORCF instructions +// 991225 - Added the previous register bank +// 991219 - Finished redoing all the flag handling, time to do some bugfixing again... +// 991215 - Hopefully fixed the V flag in the ADD, ADC, SUB and SBC operations +// 991210 - Fixed some minor bugs after a cdoe read +// 991207 - Fixed a bug in DIVS and a bug in the bit test operations +// 991127 - Redid the signed conditionals, hopefully good this time +// +// TODO: +// - Check state counting for rlc,rrc,rl4, rrc, sla, sra, srl +// - Optimizing repeating instructions, such as LDIR, LDDIR, etc. +// I took out the optimizing instructions to be able to implement +// accurate timers. Might put these back as soon as i have the timers +// up and running in a stable state.... +// - Implementation MULA operation incomplete (V flag) +// +////////////////////////////////////////////////////////////////////// + + +#ifndef __GP32__ +#include "StdAfx.h" +#endif + +#ifdef TARGET_PSP +#include +#include +#include +#include +#include + +#include "psp/emulate.h" +#endif + +#include +#include +#include +#include "main.h" +#include "tlcs900h.h" +#include "memory.h" +//#include "mainemu.h" +#include "input.h" +#include "graphics.h" +#include "ngpBios.h" +#include "neopopsound.h" + +#ifdef _DEBUG +#undef THIS_FILE +static char THIS_FILE[]=__FILE__; +#define new DEBUG_NEW +#endif + +int finscan; +int contador; +extern int gfx_hacks; +extern int fixsoundmahjong; +unsigned char *rasterY = get_address(0x00008035); + +#ifdef PSP +void HandleStateSaving(); +#endif + +// ngpcdis.cpp +// +// Emulator for tlcs-900H based on: +// Disassembler for a neogeo pocket color rom (TLCS-900H cpu) +// +// TODO: +// - Fix Bugs! +// +// +// there don't seem to be any direct calls into the bios. The way bios calls seem to be +// implemented is through SWI 1. SWI 1 is called and some parameters are passed in some +// registers. +// +// +// the TLCS-900H has several registers: +// 8-bit registers: W, A, B, C, D, E, H, L +// 16-bit registers: WA, BC, DE, HL, IX, IY, IZ, SP +// 32-bit registers: XWA, XBC, XDE, XHL, XIZ, XIY, XIZ, XSP +// +// the encoding of general 8/16/32 bit registers is unknown at this point; ie, which +// register number refers to which register (part) name. +// the encoding is a tad different for different size modes (B,W,L) +// +// probable setup of the register numbers: +// 0x0x - register bank 0 +// 0x1x - register bank 1 +// 0x2x - register bank 2 +// 0x3x - register bank 3 +// 0xDx - previous register bank (?) +// 0xEx - current register bank +// 0xFx - special register bank (XIX, XIY, XIZ, XSP) +// RA, RW, QA, QW, etc.. the true LSB MSB order seems to give the best results :) +// +// Roms start at address 0x00200000 +// There seems to be some RAM starting at 0x00004000 +// +// Also some special additional registers from this particular member of the 900H +// seems to be getting used, presumably for communication purposes??? +// +// Register bank #3 is the 'system' bank and set #2 is the regular work bank???? +// +// I think the CPU is a TMP95CS64F, or a special SNK derivation thereof +// +// + +unsigned char Ztable[256]; // zero and sign flags table for faster setting +unsigned char SZtable[256]; // zero and sign flags table for faster setting + +//#define USE_PARITY_TABLE //this is currently broken! +#ifdef USE_PARITY_TABLE +unsigned char parityVtable[256]; // zero and sign flags table for faster setting +#endif + +//#define TCLS900H_PROFILING +#ifdef TCLS900H_PROFILING +struct profStruct +{ + unsigned int ticks, calls; + unsigned int decode[256]; +}; + +struct profStruct profile[256]; + +char *instr_names[256] = + { + "nop", "normal", "pushsr", "popsr", "tmax", "halt", "ei", "reti", + "ld8I", "pushI", "ldw8I", "pushwI", "incf", "decf", "ret", "retd", + "rcf", "scf", "ccf", "zcf", "pushA", "popA", "exFF", "ldf", + "pushF", "popF", "jp16", "jp24", "call16", "call24", "calr", "udef", + "ldRIB", "ldRIB", "ldRIB", "ldRIB", "ldRIB", "ldRIB", "ldRIB", "ldRIB", + "pushRW", "pushRW", "pushRW", "pushRW", "pushRW", "pushRW", "pushRW", "pushRW", + "ldRIW", "ldRIW", "ldRIW", "ldRIW", "ldRIW", "ldRIW", "ldRIW", "ldRIW", + "pushRL", "pushRL", "pushRL", "pushRL", "pushRL", "pushRL", "pushRL", "pushRL", + // + "ldRIL", "ldRIL", "ldRIL", "ldRIL", "ldRIL", "ldRIL", "ldRIL", "ldRIL", + "popRW", "popRW", "popRW", "popRW", "popRW", "popRW", "popRW", "popRW", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "popRL", "popRL", "popRL", "popRL", "popRL", "popRL", "popRL", "popRL", + "jrcc0", "jrcc1", "jrcc2", "jrcc3", "jrcc4", "jrcc5", "jrcc6", "jrcc7", + "jrcc8", "jrcc9", "jrccA", "jrccB", "jrccC", "jrccD", "jrccE", "jrccF", + "jrlcc0", "jrlcc1", "jrlcc2", "jrlcc3", "jrlcc4", "jrlcc5", "jrlcc6", "jrlcc7", + "jrlcc8", "jrlcc9", "jrlccA", "jrlccB", "jrlccC", "jrlccD", "jrlccE", "jrlccF", + // + "decode80", "decode80", "decode80", "decode80", "decode80", "decode80", "decode80", "decode80", + "decode88", "decode88", "decode88", "decode88", "decode88", "decode88", "decode88", "decode88", + "decode90", "decode90", "decode90", "decode90", "decode90", "decode90", "decode90", "decode90", + "decode98", "decode98", "decode98", "decode98", "decode98", "decode98", "decode98", "decode98", + "decodeA0", "decodeA0", "decodeA0", "decodeA0", "decodeA0", "decodeA0", "decodeA0", "decodeA0", + "decodeA8", "decodeA8", "decodeA8", "decodeA8", "decodeA8", "decodeA8", "decodeA8", "decodeA8", + "decodeB0", "decodeB0", "decodeB0", "decodeB0", "decodeB0", "decodeB0", "decodeB0", "decodeB0", + "decodeB8", "decodeB8", "decodeB8", "decodeBB", "decodeB8", "decodeB8", "decodeB8", "decodeB8", + // + "decodeC0", "decodeC1", "decodeC2", "decodeC3", "decodeC4", "decodeC5", "udef", "decodeC7", + "decodeC8", "decodeC8", "decodeC8", "decodeC8", "decodeC8", "decodeC8", "decodeC8", "decodeC8", + "decodeD0", "decodeD1", "decodeD2", "decodeD3", "decodeD4", "decodeD5", "udef", "decodeD7", + "decodeD8", "decodeD8", "decodeD8", "decodeD8", "decodeD8", "decodeD8", "decodeD8", "decodeD8", + "decodeE0", "decodeE1", "decodeE2", "decodeE3", "decodeE4", "decodeE5", "udef", "decodeE7", + "decodeE8", "decodeE8", "decodeE8", "decodeE8", "decodeE8", "decodeE8", "decodeE8", "decodeE8", + "decodeF0", "decodeF1", "decodeF2", "decodeF3", "decodeF4", "decodeF5", "udef", "ldx", + "swi", "swi", "swi", "swi", "swi", "swi", "swi", "swi" + }; + +char *instr_table80[256] = + { + "udef", "udef", "udef", "udef", "pushM00", "udef", "rld00", "rrd00", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "ldi", "ldir", "ldd", "lddr", "cpiB", "cpirB", "cpdB", "cpdrB", + "udef", "ld16M00", "udef", "udef", "udef", "udef", "udef", "udef", + "ldRM00", "ldRM00", "ldRM00", "ldRM00", "ldRM00", "ldRM00", "ldRM00", "ldRM00", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "exMRB00", "exMRB00", "exMRB00", "exMRB00", "exMRB00", "exMRB00", "exMRB00", "exMRB00", + "addMI00", "adcMI00", "subMI00", "sbcMI00", "andMI00", "xorMI00", "orMI00", "cpMI00", + // + "mulRMB00", "mulRMB00", "mulRMB00", "mulRMB00", "mulRMB00", "mulRMB00", "mulRMB00", "mulRMB00", + "mulsRMB00", "mulsRMB00", "mulsRMB00", "mulsRMB00", "mulsRMB00", "mulsRMB00", "mulsRMB00", "mulsRMB00", + "divRMB00", "divRMB00", "divRMB00", "divRMB00", "divRMB00", "divRMB00", "divRMB00", "divRMB00", + "divsRMB00", "divsRMB00", "divsRMB00", "divsRMB00", "divsRMB00", "divsRMB00", "divsRMB00", "divsRMB00", + "inc3M00", "inc3M00", "inc3M00", "inc3M00", "inc3M00", "inc3M00", "inc3M00", "inc3M00", + "dec3M00", "dec3M00", "dec3M00", "dec3M00", "dec3M00", "dec3M00", "dec3M00", "dec3M00", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "rlcM00", "rrcM00", "rlM00", "rrM00", "slaM00", "sraM00", "sllM00", "srlM00", + // + "addRMB00", "addRMB00", "addRMB00", "addRMB00", "addRMB00", "addRMB00", "addRMB00", "addRMB00", + "addMRB00", "addMRB00", "addMRB00", "addMRB00", "addMRB00", "addMRB00", "addMRB00", "addMRB00", + "adcRMB00", "adcRMB00", "adcRMB00", "adcRMB00", "adcRMB00", "adcRMB00", "adcRMB00", "adcRMB00", + "adcMRB00", "adcMRB00", "adcMRB00", "adcMRB00", "adcMRB00", "adcMRB00", "adcMRB00", "adcMRB00", + "subRMB00", "subRMB00", "subRMB00", "subRMB00", "subRMB00", "subRMB00", "subRMB00", "subRMB00", + "subMRB00", "subMRB00", "subMRB00", "subMRB00", "subMRB00", "subMRB00", "subMRB00", "subMRB00", + "sbcRMB00", "sbcRMB00", "sbcRMB00", "sbcRMB00", "sbcRMB00", "sbcRMB00", "sbcRMB00", "sbcRMB00", + "sbcMRB00", "sbcMRB00", "sbcMRB00", "sbcMRB00", "sbcMRB00", "sbcMRB00", "sbcMRB00", "sbcMRB00", + // + "andRMB00", "andRMB00", "andRMB00", "andRMB00", "andRMB00", "andRMB00", "andRMB00", "andRMB00", + "andMRB00", "andMRB00", "andMRB00", "andMRB00", "andMRB00", "andMRB00", "andMRB00", "andMRB00", + "xorRMB00", "xorRMB00", "xorRMB00", "xorRMB00", "xorRMB00", "xorRMB00", "xorRMB00", "xorRMB00", + "xorMRB00", "xorMRB00", "xorMRB00", "xorMRB00", "xorMRB00", "xorMRB00", "xorMRB00", "xorMRB00", + "orRMB00", "orRMB00", "orRMB00", "orRMB00", "orRMB00", "orRMB00", "orRMB00", "orRMB00", + "orMRB00", "orMRB00", "orMRB00", "orMRB00", "orMRB00", "orMRB00", "orMRB00", "orMRB00", + "cpRMB00", "cpRMB00", "cpRMB00", "cpRMB00", "cpRMB00", "cpRMB00", "cpRMB00", "cpRMB00", + "cpMRB00", "cpMRB00", "cpMRB00", "cpMRB00", "cpMRB00", "cpMRB00", "cpMRB00", "cpMRB00" + }; + +char *instr_table90[256] = + { + "udef", "udef", "udef", "udef", "pushwM10", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "ldiw", "ldirw", "lddw", "lddrw", "cpiW", "cpirW", "cpdW", "cpdrW", + "udef", "ldw16M10", "udef", "udef", "udef", "udef", "udef", "udef", + "ldRM10", "ldRM10", "ldRM10", "ldRM10", "ldRM10", "ldRM10", "ldRM10", "ldRM10", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "exMRW10", "exMRW10", "exMRW10", "exMRW10", "exMRW10", "exMRW10", "exMRW10", "exMRW10", + "addwMI10", "adcwMI10", "subwMI10", "sbcwMI10", "andwMI10", "xorwMI10", "orwMI10", "cpwMI10", + // + "mulRMW10", "mulRMW10", "mulRMW10", "mulRMW10", "mulRMW10", "mulRMW10", "mulRMW10", "mulRMW10", + "mulsRMW10", "mulsRMW10", "mulsRMW10", "mulsRMW10", "mulsRMW10", "mulsRMW10", "mulsRMW10", "mulsRMW10", + "divRMW10", "divRMW10", "divRMW10", "divRMW10", "divRMW10", "divRMW10", "divRMW10", "divRMW10", + "divsRMW10", "divsRMW10", "divsRMW10", "divsRMW10", "divsRMW10", "divsRMW10", "divsRMW10", "divsRMW10", + "incw3M10", "incw3M10", "incw3M10", "incw3M10", "incw3M10", "incw3M10", "incw3M10", "incw3M10", + "decw3M10", "decw3M10", "decw3M10", "decw3M10", "decw3M10", "decw3M10", "decw3M10", "decw3M10", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "rlcwM10", "rrcwM10", "rlwM10", "rrwM10", "slawM10", "srawM10", "sllwM10", "srlwM10", + // + "addRMW10", "addRMW10", "addRMW10", "addRMW10", "addRMW10", "addRMW10", "addRMW10", "addRMW10", + "addMRW10", "addMRW10", "addMRW10", "addMRW10", "addMRW10", "addMRW10", "addMRW10", "addMRW10", + "adcRMW10", "adcRMW10", "adcRMW10", "adcRMW10", "adcRMW10", "adcRMW10", "adcRMW10", "adcRMW10", + "adcMRW10", "adcMRW10", "adcMRW10", "adcMRW10", "adcMRW10", "adcMRW10", "adcMRW10", "adcMRW10", + "subRMW10", "subRMW10", "subRMW10", "subRMW10", "subRMW10", "subRMW10", "subRMW10", "subRMW10", + "subMRW10", "subMRW10", "subMRW10", "subMRW10", "subMRW10", "subMRW10", "subMRW10", "subMRW10", + "sbcRMW10", "sbcRMW10", "sbcRMW10", "sbcRMW10", "sbcRMW10", "sbcRMW10", "sbcRMW10", "sbcRMW10", + "sbcMRW10", "sbcMRW10", "sbcMRW10", "sbcMRW10", "sbcMRW10", "sbcMRW10", "sbcMRW10", "sbcMRW10", + // + "andRMW10", "andRMW10", "andRMW10", "andRMW10", "andRMW10", "andRMW10", "andRMW10", "andRMW10", + "andMRW10", "andMRW10", "andMRW10", "andMRW10", "andMRW10", "andMRW10", "andMRW10", "andMRW10", + "xorRMW10", "xorRMW10", "xorRMW10", "xorRMW10", "xorRMW10", "xorRMW10", "xorRMW10", "xorRMW10", + "xorMRW10", "xorMRW10", "xorMRW10", "xorMRW10", "xorMRW10", "xorMRW10", "xorMRW10", "xorMRW10", + "orRMW10", "orRMW10", "orRMW10", "orRMW10", "orRMW10", "orRMW10", "orRMW10", "orRMW10", + "orMRW10", "orMRW10", "orMRW10", "orMRW10", "orMRW10", "orMRW10", "orMRW10", "orMRW10", + "cpRMW10", "cpRMW10", "cpRMW10", "cpRMW10", "cpRMW10", "cpRMW10", "cpRMW10", "cpRMW10", + "cpMRW10", "cpMRW10", "cpMRW10", "cpMRW10", "cpMRW10", "cpMRW10", "cpMRW10", "cpMRW10" + }; + +char *instr_table98[256] = + { + "udef", "udef", "udef", "udef", "pushwM10", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "ldw16M10", "udef", "udef", "udef", "udef", "udef", "udef", + "ldRM10", "ldRM10", "ldRM10", "ldRM10", "ldRM10", "ldRM10", "ldRM10", "ldRM10", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "exMRW10", "exMRW10", "exMRW10", "exMRW10", "exMRW10", "exMRW10", "exMRW10", "exMRW10", + "addwMI10", "adcwMI10", "subwMI10", "sbcwMI10", "andwMI10", "xorwMI10", "orwMI10", "cpwMI10", + // + "mulRMW10", "mulRMW10", "mulRMW10", "mulRMW10", "mulRMW10", "mulRMW10", "mulRMW10", "mulRMW10", + "mulsRMW10", "mulsRMW10", "mulsRMW10", "mulsRMW10", "mulsRMW10", "mulsRMW10", "mulsRMW10", "mulsRMW10", + "divRMW10", "divRMW10", "divRMW10", "divRMW10", "divRMW10", "divRMW10", "divRMW10", "divRMW10", + "divsRMW10", "divsRMW10", "divsRMW10", "divsRMW10", "divsRMW10", "divsRMW10", "divsRMW10", "divsRMW10", + "incw3M10", "incw3M10", "incw3M10", "incw3M10", "incw3M10", "incw3M10", "incw3M10", "incw3M10", + "decw3M10", "decw3M10", "decw3M10", "decw3M10", "decw3M10", "decw3M10", "decw3M10", "decw3M10", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "rlcwM10", "rrcwM10", "rlwM10", "rrwM10", "slawM10", "srawM10", "sllwM10", "srlwM10", + // + "addRMW10", "addRMW10", "addRMW10", "addRMW10", "addRMW10", "addRMW10", "addRMW10", "addRMW10", + "addMRW10", "addMRW10", "addMRW10", "addMRW10", "addMRW10", "addMRW10", "addMRW10", "addMRW10", + "adcRMW10", "adcRMW10", "adcRMW10", "adcRMW10", "adcRMW10", "adcRMW10", "adcRMW10", "adcRMW10", + "adcMRW10", "adcMRW10", "adcMRW10", "adcMRW10", "adcMRW10", "adcMRW10", "adcMRW10", "adcMRW10", + "subRMW10", "subRMW10", "subRMW10", "subRMW10", "subRMW10", "subRMW10", "subRMW10", "subRMW10", + "subMRW10", "subMRW10", "subMRW10", "subMRW10", "subMRW10", "subMRW10", "subMRW10", "subMRW10", + "sbcRMW10", "sbcRMW10", "sbcRMW10", "sbcRMW10", "sbcRMW10", "sbcRMW10", "sbcRMW10", "sbcRMW10", + "sbcMRW10", "sbcMRW10", "sbcMRW10", "sbcMRW10", "sbcMRW10", "sbcMRW10", "sbcMRW10", "sbcMRW10", + // + "andRMW10", "andRMW10", "andRMW10", "andRMW10", "andRMW10", "andRMW10", "andRMW10", "andRMW10", + "andMRW10", "andMRW10", "andMRW10", "andMRW10", "andMRW10", "andMRW10", "andMRW10", "andMRW10", + "xorRMW10", "xorRMW10", "xorRMW10", "xorRMW10", "xorRMW10", "xorRMW10", "xorRMW10", "xorRMW10", + "xorMRW10", "xorMRW10", "xorMRW10", "xorMRW10", "xorMRW10", "xorMRW10", "xorMRW10", "xorMRW10", + "orRMW10", "orRMW10", "orRMW10", "orRMW10", "orRMW10", "orRMW10", "orRMW10", "orRMW10", + "orMRW10", "orMRW10", "orMRW10", "orMRW10", "orMRW10", "orMRW10", "orMRW10", "orMRW10", + "cpRMW10", "cpRMW10", "cpRMW10", "cpRMW10", "cpRMW10", "cpRMW10", "cpRMW10", "cpRMW10", + "cpMRW10", "cpMRW10", "cpMRW10", "cpMRW10", "cpMRW10", "cpMRW10", "cpMRW10", "cpMRW10" + }; + +char *instr_tableA0[256] = + { + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "ldRM20", "ldRM20", "ldRM20", "ldRM20", "ldRM20", "ldRM20", "ldRM20", "ldRM20", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + // + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef ", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + // + "addRML20", "addRML20", "addRML20", "addRML20", "addRML20", "addRML20", "addRML20", "addRML20", + "addMRL20", "addMRL20", "addMRL20", "addMRL20", "addMRL20", "addMRL20", "addMRL20", "addMRL20", + "adcRML20", "adcRML20", "adcRML20", "adcRML20", "adcRML20", "adcRML20", "adcRML20", "adcRML20", + "adcMRL20", "adcMRL20", "adcMRL20", "adcMRL20", "adcMRL20", "adcMRL20", "adcMRL20", "adcMRL20", + "subRML20", "subRML20", "subRML20", "subRML20", "subRML20", "subRML20", "subRML20", "subRML20", + "subMRL20", "subMRL20", "subMRL20", "subMRL20", "subMRL20", "subMRL20", "subMRL20", "subMRL20", + "sbcRML20", "sbcRML20", "sbcRML20", "sbcRML20", "sbcRML20", "sbcRML20", "sbcRML20", "sbcRML20", + "sbcMRL20", "sbcMRL20", "sbcMRL20", "sbcMRL20", "sbcMRL20", "sbcMRL20", "sbcMRL20", "sbcMRL20", + // + "andRML20", "andRML20", "andRML20", "andRML20", "andRML20", "andRML20", "andRML20", "andRML20", + "andMRL20", "andMRL20", "andMRL20", "andMRL20", "andMRL20", "andMRL20", "andMRL20", "andMRL20", + "xorRML20", "xorRML20", "xorRML20", "xorRML20", "xorRML20", "xorRML20", "xorRML20", "xorRML20", + "xorMRL20", "xorMRL20", "xorMRL20", "xorMRL20", "xorMRL20", "xorMRL20", "xorMRL20", "xorMRL20", + "orRML20", "orRML20", "orRML20", "orRML20", "orRML20", "orRML20", "orRML20", "orRML20", + "orMRL20", "orMRL20", "orMRL20", "orMRL20", "orMRL20", "orMRL20", "orMRL20", "orMRL20", + "cpRML20", "cpRML20", "cpRML20", "cpRML20", "cpRML20", "cpRML20", "cpRML20", "cpRML20", + "cpMRL20", "cpMRL20", "cpMRL20", "cpMRL20", "cpMRL20", "cpMRL20", "cpMRL20", "cpMRL20" + }; + +char *instr_tableB0[256] = + { + "ldMI30", "udef", "ldwMI30", "udef", "popM30", "udef", "popwM30", "udef", + "udef", "udef", "udef", "udef", "udef ", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "ldM1630", "udef", "ldwM1630", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "ldaRMW30", "ldaRMW30", "ldaRMW30", "ldaRMW30", "ldaRMW30", "ldaRMW30", "ldaRMW30", "ldaRMW30", + "andcfAM30", "orcfAM30", "xorcfAM30", "ldcfAM30", "stcfAM30", "udef", "udef", "udef", + "ldaRML30", "ldaRML30", "ldaRML30", "ldaRML30", "ldaRML30", "ldaRML30", "ldaRML30", "ldaRML30", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + // + "ldMR30B", "ldMR30B", "ldMR30B", "ldMR30B", "ldMR30B", "ldMR30B", "ldMR30B", "ldMR30B", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "ldMR30W", "ldMR30W", "ldMR30W", "ldMR30W", "ldMR30W", "ldMR30W", "ldMR30W", "ldMR30W", + "udef", "udef", "udef ", "udef", "udef", "udef", "udef", "udef", + "ldMR30L", "ldMR30L", "ldMR30L", "ldMR30L", "ldMR30L", "ldMR30L", "ldMR30L", "ldMR30L", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef ", "udef", "udef", "udef", "udef", "udef", "udef", + // + "andcf3M30", "andcf3M30", "andcf3M30", "andcf3M30", "andcf3M30", "andcf3M30", "andcf3M30", "andcf3M30", + "orcf3M30", "orcf3M30", "orcf3M30", "orcf3M30", "orcf3M30", "orcf3M30", "orcf3M30", "orcf3M30", + "xorcf3M30", "xorcf3M30", "xorcf3M30", "xorcf3M30", "xorcf3M30", "xorcf3M30", "xorcf3M30", "xorcf3M30", + "ldcf3M30", "ldcf3M30", "ldcf3M30", "ldcf3M30", "ldcf3M30", "ldcf3M30", "ldcf3M30", "ldcf3M30", + "stcf3M30", "stcf3M30", "stcf3M30", "stcf3M30", "stcf3M30", "stcf3M30", "stcf3M30", "stcf3M30", + "tset3M30", "tset3M30", "tset3M30", "tset3M30", "tset3M30", "tset3M30", "tset3M30", "tset3M30", + "res3M30", "res3M30", "res3M30", "res3M30", "res3M30", "res3M30", "res3M30", "res3M30", + "set3M30", "set3M30", "set3M30", "set3M30", "set3M30", "set3M30", "set3M30", "set3M30", + // + "chg3M30", "chg3M30", "chg3M30", "chg3M30", "chg3M30", "chg3M30", "chg3M30", "chg3M30", + "bit3M30", "bit3M30", "bit3M30", "bit3M30", "bit3M30", "bit3M30", "bit3M30", "bit3M30", + "jpccM300", "jpccM301", "jpccM302", "jpccM303", "jpccM304", "jpccM305", "jpccM306", "jpccM307", + "jpccM308", "jpccM309", "jpccM30A", "jpccM30B", "jpccM30C", "jpccM30D", "jpccM30E", "jpccM30F", + "callccM300", "callccM301", "callccM302", "callccM303", "callccM304", "callccM305", "callccM306", "callccM307", + "callccM308", "callccM309", "callccM30A", "callccM30B", "callccM30C", "callccM30D", "callccM30E", "callccM30F", + "retcc0", "retcc1", "retcc2", "retcc3", "retcc4", "retcc5", "retcc6", "retcc7", + "retcc8", "retcc9", "retccA", "retccB", "retccC", "retccD", "retccE", "retccF" + }; + +char *instr_tableB8[256] = + { + "ldMI30", "udef", "ldwMI30", "udef", "popM30", "udef", "popwM30", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "ldM1630", "udef", "ldwM1630", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "ldaRMW30", "ldaRMW30", "ldaRMW30", "ldaRMW30", "ldaRMW30", "ldaRMW30", "ldaRMW30", "ldaRMW30", + "andcfAM30", "orcfAM30", "xorcfAM30", "ldcfAM30", "stcfAM30", "udef", "udef", "udef", + "ldaRML30", "ldaRML30", "ldaRML30", "ldaRML30", "ldaRML30", "ldaRML30", "ldaRML30", "ldaRML30", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + // + "ldMR30B", "ldMR30B", "ldMR30B", "ldMR30B", "ldMR30B", "ldMR30B", "ldMR30B", "ldMR30B", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "ldMR30W", "ldMR30W", "ldMR30W", "ldMR30W", "ldMR30W", "ldMR30W", "ldMR30W", "ldMR30W", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "ldMR30L", "ldMR30L", "ldMR30L", "ldMR30L", "ldMR30L", "ldMR30L", "ldMR30L", "ldMR30L", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + // + "andcf3M30", "andcf3M30", "andcf3M30", "andcf3M30", "andcf3M30", "andcf3M30", "andcf3M30", "andcf3M30", + "orcf3M30", "orcf3M30", "orcf3M30", "orcf3M30", "orcf3M30", "orcf3M30", "orcf3M30", "orcf3M30", + "xorcf3M30", "xorcf3M30", "xorcf3M30", "xorcf3M30", "xorcf3M30", "xorcf3M30", "xorcf3M30", "xorcf3M30", + "ldcf3M30", "ldcf3M30", "ldcf3M30", "ldcf3M30", "ldcf3M30", "ldcf3M30", "ldcf3M30", "ldcf3M30", + "stcf3M30", "stcf3M30", "stcf3M30", "stcf3M30", "stcf3M30", "stcf3M30", "stcf3M30", "stcf3M30", + "tset3M30", "tset3M30", "tset3M30", "tset3M30", "tset3M30", "tset3M30", "tset3M30", "tset3M30", + "res3M30", "res3M30", "res3M30", "res3M30", "res3M30", "res3M30", "res3M30", "res3M30", + "set3M30", "set3M30", "set3M30", "set3M30", "set3M30", "set3M30", "set3M30", "set3M30", + // + "chg3M30", "chg3M30", "chg3M30", "chg3M30", "chg3M30", "chg3M30", "chg3M30", "chg3M30", + "bit3M30", "bit3M30", "bit3M30", "bit3M30", "bit3M30", "bit3M30", "bit3M30", "bit3M30", + "jpccM300", "jpccM301", "jpccM302", "jpccM303", "jpccM304", "jpccM305", "jpccM306", "jpccM307", + "jpccM308", "jpccM309", "jpccM30A", "jpccM30B", "jpccM30C", "jpccM30D", "jpccM30E", "jpccM30F", + "callccM300", "callccM301", "callccM302", "callccM303", "callccM304", "callccM305", "callccM306", "callccM307", + "callccM308", "callccM309", "callccM30A", "callccM30B", "callccM30C", "callccM30D", "callccM30E", "callccM30F", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef" + }; + +char *instr_tableC0[256] = + { + "udef", "udef", "udef", "udef", "pushM00", "udef", "rld00", "rrd00", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "ld16M00", "udef", "udef", "udef", "udef", "udef", "udef", + "ldRM00", "ldRM00", "ldRM00", "ldRM00", "ldRM00", "ldRM00", "ldRM00", "ldRM00", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "exMRB00", "exMRB00", "exMRB00", "exMRB00", "exMRB00", "exMRB00", "exMRB00", "exMRB00", + "addMI00", "adcMI00", "subMI00", "sbcMI00", "andMI00", "xorMI00", "orMI00", "cpMI00", + // + "mulRMB00", "mulRMB00", "mulRMB00", "mulRMB00", "mulRMB00", "mulRMB00", "mulRMB00", "mulRMB00", + "mulsRMB00", "mulsRMB00", "mulsRMB00", "mulsRMB00", "mulsRMB00", "mulsRMB00", "mulsRMB00", "mulsRMB00", + "divRMB00", "divRMB00", "divRMB00", "divRMB00", "divRMB00", "divRMB00", "divRMB00", "divRMB00", + "divsRMB00", "divsRMB00", "divsRMB00", "divsRMB00", "divsRMB00", "divsRMB00", "divsRMB00", "divsRMB00", + "inc3M00", "inc3M00", "inc3M00", "inc3M00", "inc3M00", "inc3M00", "inc3M00", "inc3M00", + "dec3M00", "dec3M00", "dec3M00", "dec3M00", "dec3M00", "dec3M00", "dec3M00", "dec3M00", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "rlcM00", "rrcM00", "rlM00", "rrM00", "slaM00", "sraM00", "sllM00", "srlM00", + // + "addRMB00", "addRMB00", "addRMB00", "addRMB00", "addRMB00", "addRMB00", "addRMB00", "addRMB00", + "addMRB00", "addMRB00", "addMRB00", "addMRB00", "addMRB00", "addMRB00", "addMRB00", "addMRB00", + "adcRMB00", "adcRMB00", "adcRMB00", "adcRMB00", "adcRMB00", "adcRMB00", "adcRMB00", "adcRMB00", + "adcMRB00", "adcMRB00", "adcMRB00", "adcMRB00", "adcMRB00", "adcMRB00", "adcMRB00", "adcMRB00", + "subRMB00", "subRMB00", "subRMB00", "subRMB00", "subRMB00", "subRMB00", "subRMB00", "subRMB00", + "subMRB00", "subMRB00", "subMRB00", "subMRB00", "subMRB00", "subMRB00", "subMRB00", "subMRB00", + "sbcRMB00", "sbcRMB00", "sbcRMB00", "sbcRMB00", "sbcRMB00", "sbcRMB00", "sbcRMB00", "sbcRMB00", + "sbcMRB00", "sbcMRB00", "sbcMRB00", "sbcMRB00", "sbcMRB00", "sbcMRB00", "sbcMRB00", "sbcMRB00", + // + "andRMB00", "andRMB00", "andRMB00", "andRMB00", "andRMB00", "andRMB00", "andRMB00", "andRMB00", + "andMRB00", "andMRB00", "andMRB00", "andMRB00", "andMRB00", "andMRB00", "andMRB00", "andMRB00", + "xorRMB00", "xorRMB00", "xorRMB00", "xorRMB00", "xorRMB00", "xorRMB00", "xorRMB00", "xorRMB00", + "xorMRB00", "xorMRB00", "xorMRB00", "xorMRB00", "xorMRB00", "xorMRB00", "xorMRB00", "xorMRB00", + "orRMB00", "orRMB00", "orRMB00", "orRMB00", "orRMB00", "orRMB00", "orRMB00", "orRMB00", + "orMRB00", "orMRB00", "orMRB00", "orMRB00", "orMRB00", "orMRB00", "orMRB00", "orMRB00", + "cpRMB00", "cpRMB00", "cpRMB00", "cpRMB00", "cpRMB00", "cpRMB00", "cpRMB00", "cpRMB00", + "cpMRB00", "cpMRB00", "cpMRB00", "cpMRB00", "cpMRB00", "cpMRB00", "cpMRB00", "cpMRB00" + }; + +char *instr_tableC8[256] = + { + "udef", "udef", "udef", "ldrIB", "pushrB", "poprB", "cplrB", "negrB", + "mulrIB", "mulsrIB", "divrIB", "divsrIB", "udef", "udef", "udef", "udef", + "daar", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "bios", "udef", "djnzB", "udef", "udef", "udef", + "andcf4rB", "orcf4rB", "xorcf4rB", "ldcf4rB", "stcf4rB", "udef", "udef", "udef", + "andcfArB", "orcfArB", "xorcfArB", "ldcfArB", "stcfArB", "udef", "ldccrB", "ldcrcB", + "res4rB", "set4rB", "chg4rB", "bit4rB", "tset4rB", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + // + "mulRrB", "mulRrB", "mulRrB", "mulRrB", "mulRrB", "mulRrB", "mulRrB", "mulRrB", + "mulsRrB", "mulsRrB", "mulsRrB", "mulsRrB", "mulsRrB", "mulsRrB", "mulsRrB", "mulsRrB", + "divRrB", "divRrB", "divRrB", "divRrB", "divRrB", "divRrB", "divRrB", "divRrB", + "divsRrB", "divsRrB", "divsRrB", "divsRrB", "divsRrB", "divsRrB", "divsRrB", "divsRrB", + "inc3rB", "inc3rB", "inc3rB", "inc3rB", "inc3rB", "inc3rB", "inc3rB", "inc3rB", + "dec3rB", "dec3rB", "dec3rB", "dec3rB", "dec3rB", "dec3rB", "dec3rB", "dec3rB", + "sccB0", "sccB1", "sccB2", "sccB3", "sccB4", "sccB5", "sccB6", "sccB7", + "sccB8", "sccB9", "sccBA", "sccBB", "sccBC", "sccBD", "sccBE", "sccBF", + // + "addRrB", "addRrB", "addRrB", "addRrB", "addRrB", "addRrB", "addRrB", "addRrB", + "ldRrB", "ldRrB", "ldRrB", "ldRrB", "ldRrB", "ldRrB", "ldRrB", "ldRrB", + "adcRrB", "adcRrB", "adcRrB", "adcRrB", "adcRrB", "adcRrB", "adcRrB", "adcRrB", + "ldrRB", "ldrRB", "ldrRB", "ldrRB", "ldrRB", "ldrRB", "ldrRB", "ldrRB", + "subRrB", "subRrB", "subRrB", "subRrB", "subRrB", "subRrB", "subRrB", "subRrB", + "ldr3B", "ldr3B", "ldr3B", "ldr3B", "ldr3B", "ldr3B", "ldr3B", "ldr3B", + "sbcRrB", "sbcRrB", "sbcRrB", "sbcRrB", "sbcRrB", "sbcRrB", "sbcRrB", "sbcRrB", + "exRrB", "exRrB", "exRrB", "exRrB", "exRrB", "exRrB", "exRrB", "exRrB", + // + "andRrB", "andRrB", "andRrB", "andRrB", "andRrB", "andRrB", "andRrB", "andRrB", + "addrIB", "adcrIB", "subrIB", "sbcrIB", "andrIB", "xorrIB", "orrIB", "cprIB", + "xorRrB", "xorRrB", "xorRrB", "xorRrB", "xorRrB", "xorRrB", "xorRrB", "xorRrB", + "cpr3B", "cpr3B", "cpr3B", "cpr3B", "cpr3B", "cpr3B", "cpr3B", "cpr3B", + "orRrB", "orRrB", "orRrB", "orRrB", "orRrB", "orRrB", "orRrB", "orRrB", + "rlc4rB", "rrc4rB", "rl4rB", "rr4rB", "sla4rB", "sra4rB", "sll4rB", "srl4rB", + "cpRrB", "cpRrB", "cpRrB", "cpRrB", "cpRrB", "cpRrB", "cpRrB", "cpRrB", + "rlcArB", "rrcArB", "rlArB", "rrArB", "slaArB", "sraArB", "sllArB", "srlArB" + }; + +char *instr_tableD0[256] = + { + "udef", "udef", "udef", "udef", "pushwM10", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "ldw16M10", "udef", "udef", "udef", "udef", "udef", "udef", + "ldRM10", "ldRM10", "ldRM10", "ldRM10", "ldRM10", "ldRM10", "ldRM10", "ldRM10", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "exMRW10", "exMRW10", "exMRW10", "exMRW10", "exMRW10", "exMRW10", "exMRW10", "exMRW10", + "addwMI10", "adcwMI10", "subwMI10", "sbcwMI10", "andwMI10", "xorwMI10", "orwMI10", "cpwMI10", + // + "mulRMW10", "mulRMW10", "mulRMW10", "mulRMW10", "mulRMW10", "mulRMW10", "mulRMW10", "mulRMW10", + "mulsRMW10", "mulsRMW10", "mulsRMW10", "mulsRMW10", "mulsRMW10", "mulsRMW10", "mulsRMW10", "mulsRMW10", + "divRMW10", "divRMW10", "divRMW10", "divRMW10", "divRMW10", "divRMW10", "divRMW10", "divRMW10", + "divsRMW10", "divsRMW10", "divsRMW10", "divsRMW10", "divsRMW10", "divsRMW10", "divsRMW10", "divsRMW10", + "incw3M10", "incw3M10", "incw3M10", "incw3M10", "incw3M10", "incw3M10", "incw3M10", "incw3M10", + "decw3M10", "decw3M10", "decw3M10", "decw3M10", "decw3M10", "decw3M10", "decw3M10", "decw3M10", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "rlcwM10", "rrcwM10", "rlwM10", "rrwM10", "slawM10", "srawM10", "sllwM10", "srlwM10", + // + "addRMW10", "addRMW10", "addRMW10", "addRMW10", "addRMW10", "addRMW10", "addRMW10", "addRMW10", + "addMRW10", "addMRW10", "addMRW10", "addMRW10", "addMRW10", "addMRW10", "addMRW10", "addMRW10", + "adcRMW10", "adcRMW10", "adcRMW10", "adcRMW10", "adcRMW10", "adcRMW10", "adcRMW10", "adcRMW10", + "adcMRW10", "adcMRW10", "adcMRW10", "adcMRW10", "adcMRW10", "adcMRW10", "adcMRW10", "adcMRW10", + "subRMW10", "subRMW10", "subRMW10", "subRMW10", "subRMW10", "subRMW10", "subRMW10", "subRMW10", + "subMRW10", "subMRW10", "subMRW10", "subMRW10", "subMRW10", "subMRW10", "subMRW10", "subMRW10", + "sbcRMW10", "sbcRMW10", "sbcRMW10", "sbcRMW10", "sbcRMW10", "sbcRMW10", "sbcRMW10", "sbcRMW10", + "sbcMRW10", "sbcMRW10", "sbcMRW10", "sbcMRW10", "sbcMRW10", "sbcMRW10", "sbcMRW10", "sbcMRW10", + // + "andRMW10", "andRMW10", "andRMW10", "andRMW10", "andRMW10", "andRMW10", "andRMW10", "andRMW10", + "andMRW10", "andMRW10", "andMRW10", "andMRW10", "andMRW10", "andMRW10", "andMRW10", "andMRW10", + "xorRMW10", "xorRMW10", "xorRMW10", "xorRMW10", "xorRMW10", "xorRMW10", "xorRMW10", "xorRMW10", + "xorMRW10", "xorMRW10", "xorMRW10", "xorMRW10", "xorMRW10", "xorMRW10", "xorMRW10", "xorMRW10", + "orRMW10", "orRMW10", "orRMW10", "orRMW10", "orRMW10", "orRMW10", "orRMW10", "orRMW10", + "orMRW10", "orMRW10", "orMRW10", "orMRW10", "orMRW10", "orMRW10", "orMRW10", "orMRW10", + "cpRMW10", "cpRMW10", "cpRMW10", "cpRMW10", "cpRMW10", "cpRMW10", "cpRMW10", "cpRMW10", + "cpMRW10", "cpMRW10", "cpMRW10", "cpMRW10", "cpMRW10", "cpMRW10", "cpMRW10", "cpMRW10" + }; + +char *instr_tableD8[256] = + { + "udef", "udef", "udef", "ldrIW", "pushrW", "poprW", "cplrW", "negrW", + "mulrIW", "mulsrIW", "divrIW", "divsrIW", "udef", "udef", "bs1f", "bs1b", + "udef", "udef", "extzrW", "extsrW", "paarW", "udef", "mirrr", "udef", + "udef", "mular", "udef", "udef", "djnzW", "udef", "udef", "udef", + "andcf4rW", "orcf4rW", "xorcf4rW", "ldcf4rW", "stcf4rW", "udef", "udef", "udef", + "andcfArW", "orcfArW", "xorcfArW", "ldcfArW", "stcfArW", "udef", "ldccrW", "ldcrcW", + "res4rW", "set4rW", "chg4rW", "bit4rW", "tset4rW", "udef", "udef", "udef", + "minc1", "minc2", "minc4", "udef", "mdec1", "mdec2", "mdec4", "udef", + // + "mulRrW", "mulRrW", "mulRrW", "mulRrW", "mulRrW", "mulRrW", "mulRrW", "mulRrW", + "mulsRrW", "mulsRrW", "mulsRrW", "mulsRrW", "mulsRrW", "mulsRrW", "mulsRrW", "mulsRrW", + "divRrW", "divRrW", "divRrW", "divRrW", "divRrW", "divRrW", "divRrW", "divRrW", + "divsRrW", "divsRrW", "divsRrW", "divsRrW", "divsRrW", "divsRrW", "divsRrW", "divsRrW", + "inc3rW", "inc3rW", "inc3rW", "inc3rW", "inc3rW", "inc3rW", "inc3rW", "inc3rW", + "dec3rW", "dec3rW", "dec3rW", "dec3rW", "dec3rW", "dec3rW", "dec3rW", "dec3rW", + "sccW0", "sccW1", "sccW2", "sccW3", "sccW4", "sccW5", "sccW6", "sccW7", + "sccW8", "sccW9", "sccWA", "sccWB", "sccWC", "sccWD", "sccWE", "sccWF", + // + "addRrW", "addRrW", "addRrW", "addRrW", "addRrW", "addRrW", "addRrW", "addRrW", + "ldRrW", "ldRrW", "ldRrW", "ldRrW", "ldRrW", "ldRrW", "ldRrW", "ldRrW", + "adcRrW", "adcRrW", "adcRrW", "adcRrW", "adcRrW", "adcRrW", "adcRrW", "adcRrW", + "ldrRW", "ldrRW", "ldrRW", "ldrRW", "ldrRW", "ldrRW", "ldrRW", "ldrRW", + "subRrW", "subRrW", "subRrW", "subRrW", "subRrW", "subRrW", "subRrW", "subRrW", + "ldr3W", "ldr3W", "ldr3W", "ldr3W", "ldr3W", "ldr3W", "ldr3W", "ldr3W", + "sbcRrW", "sbcRrW", "sbcRrW", "sbcRrW", "sbcRrW", "sbcRrW", "sbcRrW", "sbcRrW", + "exRrW", "exRrW", "exRrW", "exRrW", "exRrW", "exRrW", "exRrW", "exRrW", + // + "andRrW", "andRrW", "andRrW", "andRrW", "andRrW", "andRrW", "andRrW", "andRrW", + "addrIW", "adcrIW", "subrIW", "sbcrIW", "andrIW", "xorrIW", "orrIW", "cprIW", + "xorRrW", "xorRrW", "xorRrW", "xorRrW", "xorRrW", "xorRrW", "xorRrW", "xorRrW", + "cpr3W", "cpr3W", "cpr3W", "cpr3W", "cpr3W", "cpr3W", "cpr3W", "cpr3W", + "orRrW", "orRrW", "orRrW", "orRrW", "orRrW", "orRrW", "orRrW", "orRrW", + "rlc4rW", "rrc4rW", "rl4rW", "rr4rW", "sla4rW", "sra4rW", "sll4rW", "srl4rW", + "cpRrW", "cpRrW", "cpRrW", "cpRrW", "cpRrW", "cpRrW", "cpRrW", "cpRrW", + "rlcArW", "rrcArW", "rlArW", "rrArW", "slaArW", "sraArW", "sllArW", "srlArW" + }; + +char *instr_tableE0[256] = + { + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "ldRM20", "ldRM20", "ldRM20", "ldRM20", "ldRM20", "ldRM20", "ldRM20", "ldRM20", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + // + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef ", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + // + "addRML20", "addRML20", "addRML20", "addRML20", "addRML20", "addRML20", "addRML20", "addRML20", + "addMRL20", "addMRL20", "addMRL20", "addMRL20", "addMRL20", "addMRL20", "addMRL20", "addMRL20", + "adcRML20", "adcRML20", "adcRML20", "adcRML20", "adcRML20", "adcRML20", "adcRML20", "adcRML20", + "adcMRL20", "adcMRL20", "adcMRL20", "adcMRL20", "adcMRL20", "adcMRL20", "adcMRL20", "adcMRL20", + "subRML20", "subRML20", "subRML20", "subRML20", "subRML20", "subRML20", "subRML20", "subRML20", + "subMRL20", "subMRL20", "subMRL20", "subMRL20", "subMRL20", "subMRL20", "subMRL20", "subMRL20", + "sbcRML20", "sbcRML20", "sbcRML20", "sbcRML20", "sbcRML20", "sbcRML20", "sbcRML20", "sbcRML20", + "sbcMRL20", "sbcMRL20", "sbcMRL20", "sbcMRL20", "sbcMRL20", "sbcMRL20", "sbcMRL20", "sbcMRL20", + // + "andRML20", "andRML20", "andRML20", "andRML20", "andRML20", "andRML20", "andRML20", "andRML20", + "andMRL20", "andMRL20", "andMRL20", "andMRL20", "andMRL20", "andMRL20", "andMRL20", "andMRL20", + "xorRML20", "xorRML20", "xorRML20", "xorRML20", "xorRML20", "xorRML20", "xorRML20", "xorRML20", + "xorMRL20", "xorMRL20", "xorMRL20", "xorMRL20", "xorMRL20", "xorMRL20", "xorMRL20", "xorMRL20", + "orRML20", "orRML20", "orRML20", "orRML20", "orRML20", "orRML20", "orRML20", "orRML20", + "orMRL20", "orMRL20", "orMRL20", "orMRL20", "orMRL20", "orMRL20", "orMRL20", "orMRL20", + "cpRML20", "cpRML20", "cpRML20", "cpRML20", "cpRML20", "cpRML20", "cpRML20", "cpRML20", + "cpMRL20", "cpMRL20", "cpMRL20", "cpMRL20", "cpMRL20", "cpMRL20", "cpMRL20", "cpMRL20" + }; + +char *instr_tableE8[256] = + { + "udef", "udef", "udef", "ldrIL", "pushrL", "poprL", "udef", "udef", + "udef", "udef", "udef", "udef", "link", "unlk", "udef", "udef", + "udef", "udef", "extzrL", "extsrL", "paarL", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "ldccrL", "ldcrcL", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + // + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "inc3rL", "inc3rL", "inc3rL", "inc3rL", "inc3rL", "inc3rL", "inc3rL", "inc3rL", + "dec3rL", "dec3rL", "dec3rL", "dec3rL", "dec3rL", "dec3rL", "dec3rL", "dec3rL", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + // + "addRrL", "addRrL", "addRrL", "addRrL", "addRrL", "addRrL", "addRrL", "addRrL", + "ldRrL", "ldRrL", "ldRrL", "ldRrL", "ldRrL", "ldRrL", "ldRrL", "ldRrL", + "adcRrL", "adcRrL", "adcRrL", "adcRrL", "adcRrL", "adcRrL", "adcRrL", "adcRrL", + "ldrRL", "ldrRL", "ldrRL", "ldrRL", "ldrRL", "ldrRL", "ldrRL", "ldrRL", + "subRrL", "subRrL", "subRrL", "subRrL", "subRrL", "subRrL", "subRrL", "subRrL", + "ldr3L", "ldr3L", "ldr3L", "ldr3L", "ldr3L", "ldr3L", "ldr3L", "ldr3L", + "sbcRrL", "sbcRrL", "sbcRrL", "sbcRrL", "sbcRrL", "sbcRrL", "sbcRrL", "sbcRrL", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + // + "andRrL", "andRrL", "andRrL", "andRrL", "andRrL", "andRrL", "andRrL", "andRrL", + "addrIL", "adcrIL", "subrIL", "sbcrIL", "andrIL", "xorrIL", "orrIL", "cprIL", + "xorRrL", "xorRrL", "xorRrL", "xorRrL", "xorRrL", "xorRrL", "xorRrL", "xorRrL", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "orRrL", "orRrL", "orRrL", "orRrL", "orRrL", "orRrL", "orRrL", "orRrL", + "rlc4rL", "rrc4rL", "rl4rL", "rr4rL", "sla4rL", "sra4rL", "sll4rL", "srl4rL", + "cpRrL", "cpRrL", "cpRrL", "cpRrL", "cpRrL", "cpRrL", "cpRrL", "cpRrL", + "rlcArL", "rrcArL", "rlArL", "rrArL", "slaArL", "sraArL", "sllArL", "srlArL" + }; + +char *instr_tableF0[256] = + { + "ldMI30", "udef", "ldwMI30", "udef", "popM30", "udef", "popwM30", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "ldM1630", "udef", "ldwM1630", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "ldaRMW30", "ldaRMW30", "ldaRMW30", "ldaRMW30", "ldaRMW30", "ldaRMW30", "ldaRMW30", "ldaRMW30", + "andcfAM30", "orcfAM30", "xorcfAM30", "ldcfAM30", "stcfAM30", "udef", "udef", "udef", + "ldaRML30", "ldaRML30", "ldaRML30", "ldaRML30", "ldaRML30", "ldaRML30", "ldaRML30", "ldaRML30", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + // + "ldMR30B", "ldMR30B", "ldMR30B", "ldMR30B", "ldMR30B", "ldMR30B", "ldMR30B", "ldMR30B", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "ldMR30W", "ldMR30W", "ldMR30W", "ldMR30W", "ldMR30W", "ldMR30W", "ldMR30W", "ldMR30W", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "ldMR30L", "ldMR30L", "ldMR30L", "ldMR30L", "ldMR30L", "ldMR30L", "ldMR30L", "ldMR30L", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + // + "andcf3M30", "andcf3M30", "andcf3M30", "andcf3M30", "andcf3M30", "andcf3M30", "andcf3M30", "andcf3M30", + "orcf3M30", "orcf3M30", "orcf3M30", "orcf3M30", "orcf3M30", "orcf3M30", "orcf3M30", "orcf3M30", + "xorcf3M30", "xorcf3M30", "xorcf3M30", "xorcf3M30", "xorcf3M30", "xorcf3M30", "xorcf3M30", "xorcf3M30", + "ldcf3M30", "ldcf3M30", "ldcf3M30", "ldcf3M30", "ldcf3M30", "ldcf3M30", "ldcf3M30", "ldcf3M30", + "stcf3M30", "stcf3M30", "stcf3M30", "stcf3M30", "stcf3M30", "stcf3M30", "stcf3M30", "stcf3M30", + "tset3M30", "tset3M30", "tset3M30", "tset3M30", "tset3M30", "tset3M30", "tset3M30", "tset3M30", + "res3M30", "res3M30", "res3M30", "res3M30", "res3M30", "res3M30", "res3M30", "res3M30", + "set3M30", "set3M30", "set3M30", "set3M30", "set3M30", "set3M30", "set3M30", "set3M30", + // + "chg3M30", "chg3M30", "chg3M30", "chg3M30", "chg3M30", "chg3M30", "chg3M30", "chg3M30", + "bit3M30", "bit3M30", "bit3M30", "bit3M30", "bit3M30", "bit3M30", "bit3M30", "bit3M30", + "jpccM300", "jpccM301", "jpccM302", "jpccM303", "jpccM304", "jpccM305", "jpccM306", "jpccM307", + "jpccM308", "jpccM309", "jpccM30A", "jpccM30B", "jpccM30C", "jpccM30D", "jpccM30E", "jpccM30F", + "callccM300", "callccM301", "callccM302", "callccM303", "callccM304", "callccM305", "callccM306", "callccM307", + "callccM308", "callccM309", "callccM30A", "callccM30B", "callccM30C", "callccM30D", "callccM30E", "callccM30F", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef", + "udef", "udef", "udef", "udef", "udef", "udef", "udef", "udef" + }; + +void initTlcs900hProfile() +{ + memset(profile, 0, 256 * sizeof(profStruct)); +} + +void printTlcs900hProfile() +{ + FILE *profileFile; + profileFile = fopen("profile.csv", "wt"); + if(!profileFile) + { + fprintf(stderr, "Couldn't open %s file\n", "profile.csv"); + return; + } + + fprintf(profileFile, "Opcode, Calls, Ticks, TicksPerCall, Name\n"); + for(int op=0; op < 256; op++) + { + fprintf(profileFile, "0x%02X, %9d, %9d, %f, %s\n", + op, profile[op].calls, profile[op].ticks, profile[op].calls?((double)profile[op].ticks)/((double)profile[op].calls):0, instr_names[op]); + } + + unsigned char decodes[13] = {0x80,0x90,0x98,0xa0,0xb0,0xb8,0xc0,0xc8,0xd0,0xd8,0xe0,0xe8,0xf0}; + char** decodestr[13] = {instr_table80,instr_table90,instr_table98,instr_tableA0, + instr_tableB0,instr_tableB8,instr_tableC0,instr_tableC8, + instr_tableD0,instr_tableD8,instr_tableE0,instr_tableE8, + instr_tableF0}; + fprintf(profileFile, "\nDecodes\n"); + for(int d=0; d < 13; d++) + { + fprintf(profileFile, "\nDecode 0x%02X\n",decodes[d]); + for(int sub=0; sub < 256; sub++) + if (profile[decodes[d]].decode[sub]) + { + fprintf(profileFile, "0x%02X, %s, %9d\n",sub, decodestr[d][sub], profile[decodes[d]].decode[sub]); + } + } + + fclose(profileFile); +} +#endif + +// declare all registers +// XWA0, XBC0, XDE0, XHL0, 0,1,2,3 +// XWA1, XBC1, XDE1, XHL1, 4,5,6,7 +// XWA2, XBC2, XDE2, XHL2, 8,9,10,11 +// XWA3, XBC3, XDE3, XHL3, 12,13,14,15 +// XIX, XIY, XIZ, XSP 16,17,18,19 XNSP = Normal Stack Pointer +// PC, SR, XSSP, XNSP 20,21,22,23 XSSP = System Stack Pointer, XSP = current stack pointer +//unsigned long gen_regs[24]; +unsigned long gen_regsXWA0, gen_regsXBC0, gen_regsXDE0, gen_regsXHL0, gen_regsXWA1, +gen_regsXBC1, gen_regsXDE1, gen_regsXHL1, gen_regsXWA2, gen_regsXBC2, +gen_regsXDE2, gen_regsXHL2, gen_regsXWA3, gen_regsXBC3, gen_regsXDE3, +gen_regsXHL3, gen_regsXIX, gen_regsXIY, gen_regsXIZ, gen_regsXSP, +gen_regsSP, gen_regsXSSP, gen_regsXNSP; + +#ifdef TARGET_GP2X +//it's defined in StdAfx.h +#ifndef GENREGSPC_AS_REG +unsigned long gen_regsPC; +#endif +#ifndef GENREGSSR_AS_REG +unsigned long gen_regsSR; +#endif +#else +unsigned long gen_regsPC, gen_regsSR; +//#define gen_regsSRb ((unsigned char *)&gen_regsSR)[0]//lsbyte of gen_regsSR +#endif + +// declare ldc registers +unsigned char __attribute__ ((__aligned__(4))) ldcRegs[64]; + +// declare struct for easy access to flags of flag register +//struct SR0 { +// unsigned long C0:1; +// unsigned long N0:1; +// unsigned long V0:1; +// unsigned long dummy0:1; +// unsigned long H0:1; +// unsigned long dummy1:1; +// unsigned long Z0:1; +// unsigned long S0:1; +// unsigned long RFP0:3; +// unsigned long MAXM0:1; +// unsigned long IFF0:3; +// unsigned long SYSM0:1; +//}; +// lower byte of SR: F +//#define C ((*(struct SR0 *)(&gen_regsSR)).C0) +//#define N ((*(struct SR0 *)(&gen_regsSR)).N0) +//#define V ((*(struct SR0 *)(&gen_regsSR)).V0) +//#define H ((*(struct SR0 *)(&gen_regsSR)).H0) +//#define Z ((*(struct SR0 *)(&gen_regsSR)).Z0) +//#define S ((*(struct SR0 *)(&gen_regsSR)).S0) +#define CF 0x01 +#define NF 0x02 +#define VF 0x04 +//#define D0 0x08 +#define HF 0x10 +//#define D1 0x20 +#define ZF 0x40 +#define SF 0x80 +// upper byte of SR +//#define RFP ((*(struct SR0 *)(&gen_regsSR)).RFP0) +//#define MAXM ((*(struct SR0 *)(&gen_regsSR)).MAXM0) +//#define IFF ((*(struct SR0 *)(&gen_regsSR)).IFF0) +//#define SYSM ((*(struct SR0 *)(&gen_regsSR)).SYSM0) +// definition for F' +unsigned char F2; + +#ifdef TARGET_GP2X +//it's defined in StdAfx.h +#else +unsigned char *my_pc = NULL; +#endif + +//unsigned char *saved_my_pc; + + +// pointers to all register(parts) that could be accessed in byte mode +unsigned char *allregsB[256]; +unsigned char *cregsB[8]; +// pointers to all register(parts) that could be accessed in word mode +unsigned short *allregsW[256]; +unsigned short *cregsW[8]; +// pointers to all register(parts) that could be accessed in long mode +unsigned long *allregsL[256]; +unsigned long *cregsL[8]; + +// number of states passed and the number of states until a new interrupt should occur +// 1 state = 100ns at 20 MHz +// 1 state = 80ns at 25 MHz +int state; +int checkstate; +int DMAstate; +// Clock multiplier to reflect the CPU speed +// 1 - 6144 kHz +// 2 - 3072 kHz +// 4 - 1536 kHz +// 8 - 768 kHz +//16 - 384 kHz +int tlcsClockMulti; +// +// is there an interrupt we need to honor? +#define INT_QUEUE_MAX 4 +unsigned char interruptPendingLevel; +unsigned char pendingInterrupts[7][INT_QUEUE_MAX]; + +// used during decoding of instructions, will hold the arguments for the operands +unsigned long mem; +unsigned char *regB, memB; +unsigned short *regW, memW; +unsigned long *regL, memL; + +// used during instruction decode +// lastbyte - to keep track of the last read byte; used when extra information is stored in the +// opcode itself. +#ifndef TARGET_GP2X +unsigned char opcode; +#endif +unsigned char lastbyte; +//unsigned char opcode1, opcode2; + + +// for debugging +int debugIndex, debugCount; + +// wrapper +int memoryCycles; + + +inline unsigned char mem_readB(unsigned long addr) +{ + if (addr > 0x200000) + memoryCycles++; + return tlcsMemReadB(addr); +} + +inline unsigned short mem_readW(unsigned long addr) +{ + if (addr > 0x200000) + memoryCycles+=2; + return tlcsMemReadW(addr); +} + +inline unsigned long mem_readL(unsigned long addr) +{ + if (addr > 0x200000) + memoryCycles+=4; + return tlcsMemReadL(addr); +} + +inline void mem_writeB(unsigned long addr, unsigned char data) +{ + // if (addr > 0x200000) memoryCycles++; + tlcsMemWriteB(addr, data); +} + +inline void tlcsFastMemWriteB(unsigned long addr,unsigned char data) +{ + //Flavor: I think we're getting carried away with this addr&0xFFFFFF junk. It's all over, now. :( + mainram[((addr&0xFFFFFF)-0x00004000)] = data; +} + +inline void tlcsFastMemWriteW(unsigned long addr, unsigned short data) +{ + //Flavor: I think we're getting carried away with this addr&0xFFFFFF junk. It's all over, now. :( + unsigned char*ram = mainram+((addr&0xFFFFFF)-0x00004000); + if (((unsigned long)ram)&0x1) + { + *(ram++) = data; + *(ram) = data>>8; + } + else + *((unsigned short*)ram) = data; +} + +inline void tlcsFastMemWriteL(unsigned long addr, unsigned long data) +{ + //Flavor: I think we're getting carried away with this addr&0xFFFFFF junk. It's all over, now. :( + unsigned char*ram = mainram+((addr&0xFFFFFF)-0x00004000); + if (((unsigned long)ram)&0x3) + { + *(ram++) = data; + *(ram++) = data>>8; + *(ram++) = data>>16; + *ram = data>>24; + } + else + *((unsigned long*)ram) = data; +} + + +inline void tlcsMemWriteBaddrB(unsigned char addr, unsigned char data) +{ + //NOTA Super Real Mahjong sound fix + + if (gfx_hacks==1){ + if (mainrom[0x000020] == 0x11 && mainrom[0x000021] == 0x01) + fixsoundmahjong++;} + + switch(addr) { + //case 0x80: // CPU speed + // break; + case 0xA0: // L CH Sound Source Control Register + if (cpuram[0xB8] == 0x55 && cpuram[0xB9] == 0xAA) + Write_SoundChipNoise(data);//Flavor SN76496Write(0, data); + break; + case 0xA1: // R CH Sound Source Control Register + if (cpuram[0xB8] == 0x55 && cpuram[0xB9] == 0xAA) + Write_SoundChipTone(data); //Flavor SN76496Write(0, data); + break; + case 0xA2: // L CH DAC Control Register + ngpSoundExecute(); + if (cpuram[0xB8] == 0xAA) + dac_writeL(data); //Flavor DAC_data_w(0,data); + break; + /*case 0xA3: // R CH DAC Control Register //Flavor hack for mono only sound + ngpSoundExecute(); + if (cpuram[0xB8] == 0xAA) + dac_writeR(data);//Flavor DAC_data_w(1,data); + break;*/ + case 0xB8: // Z80 Reset +// if (data == 0x55) DAC_data_w(0,0); + case 0xB9: // Sourd Source Reset Control Register + switch(data) { + case 0x55: + ngpSoundStart(); + break; + case 0xAA: + ngpSoundExecute(); + ngpSoundOff(); + break; + } + break; + case 0xBA: + ngpSoundExecute(); +#if defined(DRZ80) || defined(CZ80) + Z80_Cause_Interrupt(Z80_NMI_INT); +#else + z80Interrupt(Z80NMI); +#endif + break; + } + cpuram[addr] = data; + return; +} + + +// write a word (data) to a memory address (addr) +inline void tlcsMemWriteW(unsigned long addr, unsigned short data) +{ + //Flavor: I think we're getting carried away with this addr&0xFFFFFF junk. It's all over, now. :( + if ((addr&0xFFFFFF)>0x00003fff && (addr&0xFFFFFF)<0x00018000) + { + tlcsFastMemWriteW(addr, data); + } + else + { + tlcsMemWriteB(addr, data & 0xFF); + tlcsMemWriteB(addr+1, data >> 8); + } +} + +// write a word (data) to a memory address (addr) +inline void tlcsMemWriteWaddrB(unsigned long addr, unsigned short data) +{ + tlcsMemWriteBaddrB(addr, data & 0xFF); + tlcsMemWriteBaddrB(addr+1, data >> 8); +} + + +#define mem_writeW tlcsMemWriteW +/*inline void mem_writeW(unsigned long addr, unsigned short data) { +// if (addr > 0x200000) memoryCycles+= 2; + tlcsMemWriteW(addr, data); +}*/ + +// write a long word (data) to a memory address (addr) +inline void tlcsMemWriteL(unsigned long addr, unsigned long data) +{ + //Flavor: I think we're getting carried away with this addr&0xFFFFFF junk. It's all over, now. :( + addr&=0xFFFFFF; + if (addr>0x00003fff && addr<0x00018000) + { + tlcsFastMemWriteL(addr, data); + } + else + { + tlcsMemWriteB(addr, (unsigned char)(data & 0xFF)); + tlcsFastMemWriteB(addr+1, (unsigned char)((data>>8) & 0xFF)); + tlcsFastMemWriteB(addr+2, (unsigned char)((data>>16) & 0xFF)); + tlcsFastMemWriteB(addr+3, (unsigned char)((data>>24) & 0xFF)); + } +} + +#define mem_writeL tlcsMemWriteL +/*inline void mem_writeL(unsigned long addr, unsigned long data) { +// if (addr > 0x200000) memoryCycles+= 4; + tlcsMemWriteL(addr, data); +}*/ + + +inline unsigned char readbyte() +{ +#ifdef TARGET_GP2X + unsigned char __val asm("r0");//%0 and r0 are the same, now +#ifdef GENREGSPC_AS_REG + + asm volatile( + "ldrb %0, [%2], #1\n\t" + "add %1, %1, #1" + : "=r" (__val) + : "r" (gen_regsPC), "r" (my_pc) + : ); +#else + + asm volatile( + "ldr r3, %1\n\t" + "ldrb %0, [%2], #1\n\t" + "add r3, r3, #1\n\t" + "str r3, %1" + : "=r" (__val) + : "m" (gen_regsPC), "r" (my_pc) + : "r3"); +#endif + + return __val; +#else + + gen_regsPC++; + return *(my_pc++); +#endif +} + +inline unsigned char readbyteSetLastbyte() +{ +#ifdef TARGET_GP2X + unsigned char __val asm("r0");//%0 and r0 are the same, now +#ifdef GENREGSPC_AS_REG + + asm volatile( + "ldrb %0, [%3], #1\n\t" + "ldrb %1, [%3], #1\n\t" + "add %2, %2, #2\n\t" + : "=r" (__val), "=r" (lastbyte) + : "r" (gen_regsPC), "r" (my_pc) + : ); +#else + + asm volatile( + "ldr r3, %2\n\t" + "ldrb %0, [%3], #1\n\t" + "ldrb %1, [%3], #1\n\t" + "add r3, r3, #2\n\t" + "str r3, %2" + : "=r" (__val), "=r" (lastbyte) + : "m" (gen_regsPC), "r" (my_pc) + : "r3"); +#endif + + return __val; +#else + + register unsigned char i; + register unsigned short j; + + gen_regsPC+= 2; + if((unsigned long)my_pc & 0x01) //not word aligned + { + i=*(my_pc++); + lastbyte = *(my_pc++); + return i; + } + else + { + j = *((unsigned short *)my_pc); + lastbyte = j>>8; + my_pc+=2; + //return (j & 0xFF); + return j; + } + return i; +#endif +} + +inline unsigned short readword() +{ +#ifdef TARGET_GP2X + unsigned short __val asm("r0");//%0 and r0 are the same, now +#ifdef GENREGSPC_AS_REG + + asm volatile( + "ldrb %0, [%2], #1\n\t" + "ldrb r2, [%2], #1\n\t" + "add %1, %1, #2\n\t" + "orr %0, %0, r2, asl #8" + : "=r" (__val) + : "r" (gen_regsPC), "r" (my_pc) + : "r2"); +#else + + asm volatile( + "ldr r3, %1\n\t" + "ldrb %0, [%2], #1\n\t" + "ldrb r2, [%2], #1\n\t" + "add r3, r3, #2\n\t" + "str r3, %1\n\t" + "orr %0, %0, r2, asl #8" + : "=r" (__val) + : "m" (gen_regsPC), "r" (my_pc) + : "r2","r3"); +#endif + + return __val; +#else + + register unsigned short i; + + gen_regsPC+= 2; + + if((unsigned long)my_pc & 0x01) //not word aligned + { + i = *(my_pc++); + i |= (*(my_pc++) << 8); + return i; + } + else + { + i = *((unsigned short *)my_pc); + my_pc+=2; + return i; + } + + return i; +#endif +} + +inline unsigned short readwordSetLastbyte() +{ +#ifdef TARGET_GP2X + unsigned short __val asm("r0");//%0 and r0 are the same, now +#ifdef GENREGSPC_AS_REG + + asm volatile( + "ldrb %0, [%3], #1\n\t" + "ldrb r2, [%3], #1\n\t" + "ldrb %1, [%3], #1\n\t" + "add %2, %2, #3\n\t" + "orr %0, %0, r2, asl #8" + : "=r" (__val), "=r" (lastbyte) + : "r" (gen_regsPC), "r" (my_pc) + : "r2"); +#else + + asm volatile( + "ldr r3, %2\n\t" + "ldrb %0, [%3], #1\n\t" + "ldrb r2, [%3], #1\n\t" + "ldrb %1, [%3], #1\n\t" + "add r3, r3, #3\n\t" + "str r3, %2\n\t" + "orr %0, %0, r2, asl #8" + : "=r" (__val), "=r" (lastbyte) + : "m" (gen_regsPC), "r" (my_pc) + : "r2","r3"); +#endif + + return __val; + +#else + + register unsigned short i; + register unsigned long j; + + gen_regsPC+= 3; + if((unsigned long)my_pc & 0x03) //not dword aligned + { + i = *(my_pc++); + i |= (*(my_pc++) << 8); + lastbyte = *(my_pc++); + + return i; + } + else + { + j = *((unsigned long *)my_pc); + + lastbyte = j>>16;//let "them" do the &0xFF + + my_pc+=3; + return j;//let "them" do the &0xFFFF + } + + return i; +#endif +} + +/* +read24 is a bit interesting, because we can test the LS bit of my_pc +if it's 0, we read a word and then a byte +if it's 1, we read a byte and then a word + +Or, we could just read a dword and forget about the MSB +*/ +inline unsigned long read24() +{ +#ifdef TARGET_GP2X + register unsigned long __val asm("r0");//%0 and r0 are the same, now + +#ifdef GENREGSPC_AS_REG + + asm volatile( + "add %2, %2, #3\n" + "bic r1,%1,#3 \n" + "ldmia r1,{r0,r3} \n" + "ands r1,%1,#3 \n" + "movne r2,r1,lsl #3 \n" + "movne r0,r0,lsr r2 \n" + "rsbne r1,r2,#32 \n" + "orrne r0,r0,r3,lsl r1\n" + "and r0, r0, #0xFFFFFF\n" + "add %1, %1, #3" + : "=r" (__val) + : "r"(my_pc), "r"(gen_regsPC) + : "r1","r2","r3"); +#else + + asm volatile( + "ldr r3, %2\n" + "add r3, r3, #3\n" + "str r3, %2\n" + "bic r1,%1,#3 \n" + "ldmia r1,{r0,r3} \n" + "ands r1,%1,#3 \n" + "movne r2,r1,lsl #3 \n" + "movne r0,r0,lsr r2 \n" + "rsbne r1,r2,#32 \n" + "orrne r0,r0,r3,lsl r1\n" + "and r0, r0, #0xFFFFFF\n" + "add %1, %1, #3" + : "=r" (__val) + : "r"(my_pc), "m"(gen_regsPC) + : "r1","r2","r3"); +#endif + + return __val; +#else + + register unsigned long i; + + gen_regsPC+= 3; + if((unsigned long)my_pc & 0x03) //not dword aligned + { + i = *(my_pc++); + i |= (*(my_pc++) << 8); + i |= (*(my_pc++) << 16); + return i; + } + else + { + i = *((unsigned long*)my_pc) & 0x00FFFFFF; + my_pc+=3; + return i; + } + + //return i; +#endif +} + +inline unsigned long read24SetLastbyte() +{ +#ifdef TARGET_GP2X + register unsigned long __val asm("r0");//%0 and r0 are the same, now + +#ifdef GENREGSPC_AS_REG + + asm volatile( + "add %3, %3, #4\n" + "bic r1,%2,#3 \n" + "ldmia r1,{r0,r3} \n" + "ands r1,%2,#3 \n" + "movne r2,r1,lsl #3 \n" + "movne r0,r0,lsr r2 \n" + "rsbne r1,r2,#32 \n" + "orrne r0,r0,r3,lsl r1\n" + "and %1, r0, #0xFF000000\n" + "mov %1, %1, lsr #24\n" + "and r0, r0, #0x00FFFFFF\n" + "add %2, %2, #4" + : "=r" (__val), "=r" (lastbyte) + : "r"(my_pc), "r"(gen_regsPC) + : "r1","r2","r3"); +#else + + asm volatile( + "ldr r3, %3\n" + "add r3, r3, #4\n" + "str r3, %3\n" + "bic r1,%2,#3 \n" + "ldmia r1,{r0,r3} \n" + "ands r1,%2,#3 \n" + "movne r2,r1,lsl #3 \n" + "movne r0,r0,lsr r2 \n" + "rsbne r1,r2,#32 \n" + "orrne r0,r0,r3,lsl r1\n" + "and %1, r0, #0xFF000000\n" + "mov %1, %1, lsr #24\n" + "and r0, r0, #0x00FFFFFF\n" + "add %2, %2, #4" + : "=r" (__val), "=r" (lastbyte) + : "r"(my_pc), "m"(gen_regsPC) + : "r1","r2","r3"); +#endif + + return __val; +#else + + register unsigned long i; + + gen_regsPC+= 4; + if((unsigned long)my_pc & 0x03) //not dword aligned + { + i = *(my_pc++); + i |= (*(my_pc++) << 8); + i |= (*(my_pc++) << 16); + lastbyte = *(my_pc++); + return i; + } + else + { + i = *((unsigned long*)my_pc); + lastbyte = i >> 24; + i &= 0x00FFFFFF; + + my_pc+=4; + return i; + } + + //return i; +#endif +} + +inline unsigned long readlong() +{ +#ifdef TARGET_GP2X + register unsigned long __val asm("r0");//%0 and r0 are the same, now + +#ifdef GENREGSPC_AS_REG + + asm volatile( + "add %2, %2, #4\n" + "bic r1,%1,#3 \n" + "ldmia r1,{r0,r3} \n" + "ands r1,%1,#3 \n" + "movne r2,r1,lsl #3 \n" + "movne r0,r0,lsr r2 \n" + "rsbne r1,r2,#32 \n" + "orrne r0,r0,r3,lsl r1\n" + "add %1, %1, #4" + : "=r" (__val) + : "r"(my_pc), "r"(gen_regsPC) + : "r1","r2","r3"); +#else + + asm volatile( + "ldr r3, %2\n" + "add r3, r3, #4\n" + "str r3, %2\n" + "bic r1,%1,#3 \n" + "ldmia r1,{r0,r3} \n" + "ands r1,%1,#3 \n" + "movne r2,r1,lsl #3 \n" + "movne r0,r0,lsr r2 \n" + "rsbne r1,r2,#32 \n" + "orrne r0,r0,r3,lsl r1\n" + "add %1, %1, #4" + : "=r" (__val) + : "r"(my_pc), "m"(gen_regsPC) + : "r1","r2","r3"); +#endif + + return __val; +#else + + register unsigned long i; + + gen_regsPC+= 4; + if((unsigned long)my_pc & 0x03) //not dword aligned + { + i = *(my_pc++); + i |= (*(my_pc++) << 8); + i |= (*(my_pc++) << 16); + i |= (*(my_pc++) << 24); + return i; + } + else + { + i = *((unsigned long*)my_pc); + my_pc+=4; + return i; + } + + return i; +#endif +} + +inline void doJumpByte() +{ +#ifdef TARGET_GP2X + #ifdef GENREGSPC_AS_REG + + asm volatile( + "ldrsb r0, [%1]\n\t" + "adds r0, r0, #1\n\t" + "adds %0, %0, r0\n\t" + "adds %1, %1, r0" + : + : "r" (gen_regsPC), "r" (my_pc) + : "r0"); + + #else + #error doJumpByte not implemented + #endif + +#else + signed char d8 = readbyte(); + gen_regsPC+=d8; + my_pc+=d8; +#endif +} + +inline void skipJumpByte() +{ +#ifdef TARGET_GP2X + #ifdef GENREGSPC_AS_REG + + asm volatile( + "add %0, %0, #1\n\t" + "add %1, %1, #1" + : + : "r" (gen_regsPC), "r" (my_pc) + :); + + #else + #error skipJumpByte not implemented + #endif + +#else + ++gen_regsPC; + ++my_pc; +#endif +} + +inline void doJumpWord() +{ +#ifdef TARGET_GP2X + #ifdef GENREGSPC_AS_REG + + asm volatile( + "ldrsb r0, [%1,#1]\n\t" + "ldrb r1, [%1]\n\t" + "orr r0, r1, r0, asl #8\n\t" + "add r0, r0, #2\n\t" + "add %0, %0, r0\n\t" + "add %1, %1, r0" + : + : "r" (gen_regsPC), "r" (my_pc) + : "r0", "r1"); + + #else + #error doJumpWord not implemented + #endif + +#else + signed short d16 = readword(); + gen_regsPC+=d16; + my_pc+=d16; +#endif +} + +inline void skipJumpWord() +{ +#ifdef TARGET_GP2X + #ifdef GENREGSPC_AS_REG + + asm volatile( + "add %0, %0, #2\n\t" + "add %1, %1, #2" + : + : "r" (gen_regsPC), "r" (my_pc) + :); + + #else + #error skipJumpWord not implemented + #endif + +#else + gen_regsPC+=2; + my_pc+=2; +#endif +} + + +#define cond0() (FALSE) +#define cond1() (((gen_regsSR & (SF|VF)) == SF) || ((gen_regsSR & (SF|VF)) == VF)) +#define cond2() ((gen_regsSR & ZF) || (((gen_regsSR & (SF|VF)) == SF) || ((gen_regsSR & (SF|VF)) == VF))) +#define cond3() (gen_regsSR & (ZF|CF)) +#define cond4() (gen_regsSR & VF) +#define cond5() (gen_regsSR & SF) +#define cond6() (gen_regsSR & ZF) +#define cond7() (gen_regsSR & CF) +#define cond8() (TRUE) +#define cond9() (!(((gen_regsSR & (SF|VF)) == SF) || ((gen_regsSR & (SF|VF)) == VF))) +#define notCond9() (((gen_regsSR & (SF|VF)) == SF) || ((gen_regsSR & (SF|VF)) == VF)) +#define condA() (!((gen_regsSR & ZF) || (((gen_regsSR & (SF|VF)) == SF) || ((gen_regsSR & (SF|VF)) == VF)))) +#define notCondA() ((gen_regsSR & ZF) || (((gen_regsSR & (SF|VF)) == SF) || ((gen_regsSR & (SF|VF)) == VF))) +#define condB() (!(gen_regsSR & (ZF|CF))) +#define notCondB() (gen_regsSR & (ZF|CF)) +#define condC() (!(gen_regsSR & VF)) +#define notCondC() (gen_regsSR & VF) +#define condD() (!(gen_regsSR & SF)) +#define notCondD() (gen_regsSR & SF) +#define condE() (!(gen_regsSR & ZF)) +#define notCondE() (gen_regsSR & ZF) +#define condF() (!(gen_regsSR & CF)) +#define notCondF() (gen_regsSR & CF) + +// status register check functions +inline unsigned char srF() +{ + return 0; +} +inline unsigned char srLT() +{ + return ((((gen_regsSR & (SF|VF)) == SF) + || ((gen_regsSR & (SF|VF)) == VF)) ? 1 : 0); +} +inline unsigned char srLE() +{ + return (((((gen_regsSR & (SF|VF)) == SF) + || ((gen_regsSR & (SF|VF)) == VF)) + || (gen_regsSR & ZF)) ? 1 : 0); +} +inline unsigned char srULE() +{ + return ((gen_regsSR & (ZF|CF)) ? 1 : 0); +} +inline unsigned char srOV() +{ + return ((gen_regsSR & VF) ? 1 : 0); +} +inline unsigned char srMI() +{ + return ((gen_regsSR & SF) ? 1 : 0); +} +inline unsigned char srZ() +{ + return ((gen_regsSR & ZF) ? 1 : 0); +} +inline unsigned char srC() +{ + return ((gen_regsSR & CF) ? 1 : 0); +} +inline unsigned char srT() +{ + return 1; +} +inline unsigned char srGE() +{ + return ((((gen_regsSR & (SF|VF)) == SF) + || ((gen_regsSR & (SF|VF)) == VF)) ? 0 : 1); +} +//unsigned char srGE() { return ((((gen_regsSR & (SF|VF)) == (VF|SF)) +// || ((gen_regsSR & (SF|VF)) == 0)) ? 1 : 0); } +inline unsigned char srGT() +{ + return (((((gen_regsSR & (SF|VF)) == SF) + || ((gen_regsSR & (SF|VF)) == VF)) + || (gen_regsSR & ZF)) ? 0 : 1); +} +//unsigned char srGT() { return (((((gen_regsSR & (SF|VF)) == (VF|SF)) +// || ((gen_regsSR & (SF|VF)) == 0)) +// && (gen_regsSR & ZF)) ? 1 : 0); } +inline unsigned char srUGT() +{ + return ((gen_regsSR & (ZF|CF)) ? 0 : 1); +} +inline unsigned char srNOV() +{ + return ((gen_regsSR & VF) ? 0 : 1); +} +inline unsigned char srPL() +{ + return ((gen_regsSR & SF) ? 0 : 1); +} +inline unsigned char srNZ() +{ + return ((gen_regsSR & ZF) ? 0 : 1); +} +inline unsigned char srNC() +{ + return ((gen_regsSR & CF) ? 0 : 1); +} + +#define valCond0 srF +#define valCond1 srLT +#define valCond2 srLE +#define valCond3 srULE +#define valCond4 srOV +#define valCond5 srMI +#define valCond6 srZ +#define valCond7 srC +#define valCond8 srT +#define valCond9 srGE +#define valCondA srGT +#define valCondB srUGT +#define valCondC srNOV +#define valCondD srPL +#define valCondE srNZ +#define valCondF srNC + + +inline void set_cregs() //optimized by Thor +{ + int i; + static int lastbank = -1; + + i = (gen_regsSR & 0x0700)>>4; + + if (i==lastbank) + return; + lastbank = i; + + if (i) + { + memcpy(&allregsB[0xd0], &allregsB[i-16],32*sizeof(allregsB[0])); + memcpy(&allregsW[0xd0], &allregsW[i-16],32*sizeof(allregsW[0])); + memcpy(&allregsL[0xd0], &allregsL[i-16],32*sizeof(allregsL[0])); + } + else + { + // set previous register bank registers + memcpy(&allregsB[0xd0], &allregsB[48],16*sizeof(allregsB[0])); + memcpy(&allregsW[0xd0], &allregsW[48],16*sizeof(allregsW[0])); + memcpy(&allregsL[0xd0], &allregsL[48],16*sizeof(allregsL[0])); + + // set current register bank registers + memcpy(&allregsB[0xe0], &allregsB[0], 16*sizeof(allregsB[0])); + memcpy(&allregsW[0xe0], &allregsW[0], 16*sizeof(allregsW[0])); + memcpy(&allregsL[0xe0], &allregsL[0], 16*sizeof(allregsL[0])); + } + + //This loop should get unrolled by the compiler + for (i=0;i<4;i++) + { + // set the current set byte pointers + // byte register are: W, A, B, C, D, E, H, L + // however, in the all byte registers table + // they are stored as: A W QA QW etc. + cregsB[i*2] = allregsB[0xe0+4*i+1]; + cregsB[i*2+1] = allregsB[0xe0+4*i]; + + // set the current set word and long word pointers + cregsW[i] = allregsW[0xe0+4*i]; + cregsL[i] = allregsL[0xe0+4*i]; + } +} + + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// LD //////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int ldRrB() +{ + *cregsB[lastbyte&7] = *regB; + return 4; +} +int ldRrW() +{ + *cregsW[lastbyte&7] = *regW; + return 4; +} +int ldRrL() +{ + *cregsL[lastbyte&7] = *regL; + return 4; +} +int ldrRB() +{ + *regB = *cregsB[lastbyte&7]; + return 4; +} +int ldrRW() +{ + *regW = *cregsW[lastbyte&7]; + return 4; +} +int ldrRL() +{ + *regL = *cregsL[lastbyte&7]; + return 4; +} +int ldr3B() +{ + *regB = lastbyte&7; + return 4; +} +int ldr3W() +{ + *regW = lastbyte&7; + return 4; +} +int ldr3L() +{ + *regL = lastbyte&7; + return 4; +} +int ldRIB() +{ + *cregsB[opcode&7] = readbyte(); + return 2; +} +int ldRIW() +{ + *cregsW[opcode&7] = readword(); + return 3; +} +int ldRIL() +{ + *cregsL[opcode&7] = readlong(); + return 5; +} +int ldrIB() +{ + *regB = readbyte(); + return 4; +} +int ldrIW() +{ + *regW = readword(); + return 4; +} +int ldrIL() +{ + *regL = readlong(); + return 6; +} +int ldRM00() +{ + *cregsB[lastbyte&7] = memB; + return 4; +} +int ldRM10() +{ + *cregsW[lastbyte&7] = memW; + return 4; +} +int ldRM20() +{ + *cregsL[lastbyte&7] = memL; + return 6; +} +int ldMR30B() +{ + mem_writeB(mem,*cregsB[lastbyte&7]); + return 4; +} +int ldMR30W() +{ + mem_writeW(mem,*cregsW[lastbyte&7]); + return 4; +} +int ldMR30L() +{ + mem_writeL(mem,*cregsL[lastbyte&7]); + return 6; +} +int ld8I() +{ + unsigned long num8 = readbyte(); + tlcsMemWriteBaddrB(num8,readbyte()); + return 5; +} +int ldw8I() +{ + unsigned long num8 = readbyte(); + tlcsMemWriteWaddrB(num8,readword()); + return 6; +} +int ldMI30() +{ + mem_writeB(mem,readbyte()); + return 5; +} +int ldwMI30() +{ + mem_writeW(mem,readword()); + return 6; +} +int ld16M00() +{ + mem_writeB(readword(),memB); + return 8; +} +int ldw16M10() +{ + mem_writeW(readword(),memW); + return 8; +} +int ldM1630() +{ + mem_writeB(mem,mem_readB(readword())); + return 8; +} +int ldwM1630() +{ + mem_writeW(mem,mem_readW(readword())); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// PUSH ////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +#define NG_PUSH_BYTE(src,s) tlcsFastMemWriteB(--gen_regsXSP,src); return s; +#define NG_PUSH_WORD(src,s) tlcsFastMemWriteW(gen_regsXSP-=2,src); return s; +#define NG_PUSH_LONG(src,s) tlcsFastMemWriteL(gen_regsXSP-=4,src); return s; + +int pushsr() +{ + NG_PUSH_WORD((unsigned short)gen_regsSR&0x0000ffff, 4); +} +int pushF() +{ + NG_PUSH_BYTE((unsigned char)gen_regsSR&0x000000ff, 3); +} +int pushA() +{ + NG_PUSH_BYTE(*cregsB[1], 3); +} +int pushRW() +{ + NG_PUSH_WORD(*cregsW[opcode&7], 3); +} +int pushRL() +{ + NG_PUSH_LONG(*cregsL[opcode&7], 5); +} +int pushrB() +{ + NG_PUSH_BYTE(*regB, 5); +} +int pushrW() +{ + NG_PUSH_WORD(*regW, 5); +} +int pushrL() +{ + NG_PUSH_LONG(*regL, 7); +} +int pushI() +{ + NG_PUSH_BYTE(readbyte(), 4); +} +int pushwI() +{ + NG_PUSH_WORD(readword(), 5); +} +int pushM00() +{ + NG_PUSH_BYTE(memB, 7); +} +int pushwM10() +{ + NG_PUSH_WORD(memW, 7); +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// POP /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int popsr() // POP SR 00000011 +{ + gen_regsSR = mem_readW(gen_regsXSP); + gen_regsXSP+=2; + set_cregs(); + return 6; +} + +int popF() // POP F 00011001 +{ + gen_regsSR = (gen_regsSR&0xff00)|mem_readB(gen_regsXSP); + gen_regsXSP+=1; + return 4; +} + +int popA() +{ + *cregsB[1] = mem_readB(gen_regsXSP); + gen_regsXSP+=1; + return 4; +} +int popRW() +{ + *cregsW[opcode&7] = mem_readW(gen_regsXSP); + gen_regsXSP+=2; + return 4; +} +int popRL() +{ + *cregsL[opcode&7] = mem_readL(gen_regsXSP); + gen_regsXSP+=4; + return 6; +} +int poprB() +{ + *regB = mem_readB(gen_regsXSP); + gen_regsXSP+=1; + return 6; +} +int poprW() +{ + *regW = mem_readW(gen_regsXSP); + gen_regsXSP+=2; + return 6; +} +int poprL() +{ + *regL = mem_readL(gen_regsXSP); + gen_regsXSP+=4; + return 8; +} +int popM30() +{ + mem_writeB(mem,mem_readB(gen_regsXSP)); + gen_regsXSP+=1; + return 6; +} +int popwM30() +{ + mem_writeW(mem,mem_readW(gen_regsXSP)); + gen_regsXSP+=2; + return 6; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// LDA /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int ldaRMW30() +{ + *cregsW[lastbyte&7] = (unsigned short)(mem&0x0000ffff); + return 4; +} +int ldaRML30() +{ + *cregsL[lastbyte&7] = mem; + return 4; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// LDAR ////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int ldar() // LDAR R,$+4+d16 11110011 00010011 xxxxxxxx xxxxxxxx 001s0RRR +{ + unsigned short i = readword(); + unsigned char j; + + j = readbyte(); + if (j & 0x10) + { // long + *cregsL[j&7] = gen_regsPC-1+(signed short)i; + } + else + { // word + *cregsW[j&7] = (unsigned short)((gen_regsPC-1+(signed short)i)&0x0000ffff); + } + return 11; +} + + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// EX //////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int exFF() // EX F,F' 00010110 +{ + unsigned char i = F2; + + F2 = (unsigned char)(gen_regsSR&0xff); + gen_regsSR = (gen_regsSR&0xff00)|i; + return 2; +} + +int exRrB() // EX R,r 11001rrr 10111RRR +{ + unsigned char i = *cregsB[lastbyte&7]; + *cregsB[lastbyte&7] = *regB; + *regB = i; + return 5; +} + +int exRrW() // EX R,r 11011rrr 10111RRR +{ + unsigned short i = *cregsW[lastbyte&7]; + *cregsW[lastbyte&7] = *regW; + *regW = i; + return 5; +} + +int exMRB00() // EX (mem),R 10000mmm 00110RRR +{ + unsigned char i = memB; + mem_writeB(mem,*cregsB[lastbyte&7]); + *cregsB[lastbyte&7] = i; + return 6; +} + +int exMRW10() // EX (mem),R 10010mmm 00110RRR +{ + unsigned short i = memW; + mem_writeW(mem,*cregsW[lastbyte&7]); + *cregsW[lastbyte&7] = i; + return 6; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// MIRR ////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +const unsigned char mirrTable[256] = { //Flavor speed hack + 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, + 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, + 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, + 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, + 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, + 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, + 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, + 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, + 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, + 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, + 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, + 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, + 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, + 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, + 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, + 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF}; + + +int mirrr() // MIRR r 11011rrr 00010110 +{ + unsigned short i=*regW; + + *regW=mirrTable[i&0xFF]<<8 | mirrTable[i>>8]; + + return 4; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// LDxx ////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int ldi() // LDI (XDE+),(XHL+) 10000011 00010000 +// LDI (XIX+),(XIY+) 10000101 00010000 +{ + if (opcode&2) + { + // XDE/XHL + mem_writeB((*cregsL[2])++,mem_readB((*cregsL[3])++)); + //*cregsL[2]+=1; + //*cregsL[3]+=1; + } + else + { + // XIX/XIY + mem_writeB(gen_regsXIX++,mem_readB(gen_regsXIY++)); + //mem_writeB(*cregsL[4],mem_readB(*cregsL[5])); + //*cregsL[4]+=1; + //*cregsL[5]+=1; + } + *cregsW[1]-=1; // BC + gen_regsSR = gen_regsSR & ~(HF|VF|NF); + gen_regsSR = gen_regsSR | ((*cregsW[1]) ? VF : 0); + return 10; +} + +int ldiw() // LDIW (XDE+),(XHL+) 10010011 00010000 +// LDIW (XIX+),(XIY+) 10010101 00010000 +{ + if (opcode&2) + { + // XDE/XHL + mem_writeW(*cregsL[2],mem_readW(*cregsL[3])); + *cregsL[2]+=2; + *cregsL[3]+=2; + } + else + { + // XIX/XIY + mem_writeW(gen_regsXIX,mem_readW(gen_regsXIY)); + gen_regsXIX+=2; + gen_regsXIY+=2; + /* + mem_writeW(*cregsL[4],mem_readW(*cregsL[5])); + *cregsL[4]+=2; + *cregsL[5]+=2; + */ + } + *cregsW[1]-=1; // BC + gen_regsSR = gen_regsSR & ~(HF|VF|NF); + gen_regsSR = gen_regsSR | ((*cregsW[1]) ? VF : 0); + return 10; +} + +int ldir() // LDIR (XDE+),(XHL+) 10000011 00010001 +// LDIR (XIX+),(XIY+) 10000101 00010001 +{ +#if 0 //causes problems when starting new game in CFC1 + unsigned char *dst,*src; + int cnt=*cregsW[1]; + + if(cnt==0) + cnt=0x10000; + + if (opcode&2) + { + dst=get_address(*cregsL[2]); + src=get_address(*cregsL[3]); + *cregsL[2]+=cnt; + *cregsL[3]+=cnt; + //dbg_print("ldir: 1-called with cnt=0x%04X dst=0x%06X src=0x%06X\n", cnt, *cregsL[2], *cregsL[3]); + } + else + { + dst=get_address(gen_regsXIX); + src=get_address(gen_regsXIY); + gen_regsXIX+=cnt; + gen_regsXIY+=cnt; + //dbg_print("ldir: 2-called with cnt=0x%04X dst=0x%06X src=0x%06X\n", cnt, gen_regsXIX, gen_regsXIY); + } + + if(dst && src) + { + //delta warp tries to read from 0x0FA000 (get_address returns NULL) + /*MOTM produces + ldir: 1-called with cnt=0x2BFF dst=0x006C00 src=0x006BFF + ldir: 1-called with cnt=0x0008 dst=0x0067DC src=0x0067E4 + so, memcpy won't work + */ + do + { + *dst++=*src++; + }while(--*cregsW[1]); + } + else + { +#ifdef TARGET_WIN + //dbg_print("ldir: invalid dst=0x%06X or src=0x%06X addr cnt=0x%04X\n", dst, src, cnt); + //dbg_print("ldir: XIX=0x%06X XIY=0x%06X\n", gen_regsXIX, gen_regsXIY); + //dbg_print("ldir: *cregsL[4]=0x%06X *cregsL[5]=0x%06X\n", *cregsL[4], *cregsL[5]); +#endif + if(dst) + memset(dst, 0xFF, cnt); + } + + gen_regsSR = gen_regsSR & ~(HF|VF|NF); + return 14*cnt+10; +#else + if (opcode&2) + { + // XDE/XHL + mem_writeB((*cregsL[2])++,mem_readB((*cregsL[3])++)); + } + else + { + // XIX/XIY + mem_writeB(gen_regsXIX++,mem_readB(gen_regsXIY++)); + } + + gen_regsSR = gen_regsSR & ~(HF|VF|NF); + if (--(*cregsW[1])) //BC + { + gen_regsPC-=2; + my_pc-=2; + gen_regsSR = gen_regsSR | VF; + return 14; + } + else + { + return 10; + } +#endif +} + +int ldirw() // LDIRW (XDE+),(XHL+) 10010011 00010001 +// LDIRW (XIX+),(XIY+) 10010101 00010001 +{ +#if 0 //causes problems when starting new game in CFC1 + unsigned char *dst,*src; + int cnt=*cregsW[1]; + + if(cnt==0) + cnt=0x10000; + + if (opcode&2) + { + dst=(unsigned char *)get_address(*cregsL[2]); + src=(unsigned char *)get_address(*cregsL[3]); + *cregsL[2]+= 2*cnt; + *cregsL[3]+= 2*cnt; + //dbg_print("ldirw: 1-called with cnt=0x%04X dst=0x%06X src=0x%06X\n", cnt, *cregsL[2], *cregsL[3]); + } + else + { + /*if(gen_regsXIY == 0xFA000) //Delta Warp stupidly does this + src=get_address(gen_regsXIY+0x200000);*/ + src=(unsigned char *)get_address(gen_regsXIY); + dst=(unsigned char *)get_address(gen_regsXIX); + gen_regsXIX+=2*cnt; + gen_regsXIY+=2*cnt; + //dbg_print("ldirw: 2-called with cnt=0x%04X dst=0x%06X src=0x%06X\n", cnt, gen_regsXIX, gen_regsXIY); + } + + if(dst && src) + { + //memmove(dst, src, cnt*2); //delta warp tries to read from 0x0FA000 (get_address returns NULL) + do + { + *dst++=*src++; + *dst++=*src++; + }while(--*cregsW[1]); + } + else + { +#ifdef TARGET_WIN + //dbg_print("ldirw: invalid dst=0x%06X or src=0x%06X addr cnt=0x%04X\n", dst, src, cnt); + //dbg_print("ldirw: XIX=0x%06X XIY=0x%06X\n", gen_regsXIX, gen_regsXIY); + //dbg_print("ldirw: *cregsL[4]=0x%06X *cregsL[5]=0x%06X\n", *cregsL[4], *cregsL[5]); +#endif + if(dst) + memset(dst, 0xFF, cnt*2); + } + + gen_regsSR = gen_regsSR & ~(HF|VF|NF); + return 14*cnt+10; +#else + if (opcode&2) + { // XDE/XHL + mem_writeW(*cregsL[2],mem_readW(*cregsL[3])); + *cregsL[2]+= 2; + *cregsL[3]+= 2; + } + else + { // XIX/XIY + mem_writeW(gen_regsXIX,mem_readW(gen_regsXIY)); + gen_regsXIX+=2; + gen_regsXIY+=2; +// mem_writeW(*cregsL[4],mem_readW(*cregsL[5])); +// *cregsL[4]+= 2; +// *cregsL[5]+= 2; + } + //*cregsW[1]-= 1; // BC + gen_regsSR = gen_regsSR & ~(HF|VF|NF); + if (--(*cregsW[1])) + { + gen_regsPC-=2; + my_pc-=2; + gen_regsSR = gen_regsSR | VF; + return 14; + // return 14+4; + } + else + { + return 10; + // return 10+4; + } +#endif +} + +int ldd() // LDD (XDE-),(XHL-) 10000011 00010010 +// LDD (XIX-),(XIY-) 10000101 00010010 +{ + if (opcode&2) + { // XDE/XHL + mem_writeB((*cregsL[2])--,mem_readB((*cregsL[3])--)); + //*cregsL[2]-= 1; + //*cregsL[3]-= 1; + } + else + { // XIX/XIY + mem_writeB(gen_regsXIX--,mem_readB(gen_regsXIY--)); + //mem_writeB(*cregsL[4],mem_readB(*cregsL[5])); + //*cregsL[4]-= 1; + //*cregsL[5]-= 1; + } + *cregsW[1]-=1; // BC + gen_regsSR = gen_regsSR & ~(HF|VF|NF); + gen_regsSR = gen_regsSR | ((*cregsW[1]) ? VF : 0); + return 10; +} + +int lddw() // LDDW (XDE-),(XHL-) 10010011 00010010 +// LDDW (XIX-),(XIY-) 10010101 00010010 +{ + if (opcode&2) + { // XDE/XHL + mem_writeW(*cregsL[2],mem_readW(*cregsL[3])); + *cregsL[2]-= 2; + *cregsL[3]-= 2; + } + else + { // XIX/XIY + mem_writeW(gen_regsXIX,mem_readW(gen_regsXIY)); + gen_regsXIX-=2; + gen_regsXIY-=2; +// mem_writeW(*cregsL[4],mem_readW(*cregsL[5])); +// *cregsL[4]-= 2; +// *cregsL[5]-= 2; + } + *cregsW[1]-=1; // BC + gen_regsSR = gen_regsSR & ~(HF|VF|NF); + gen_regsSR = gen_regsSR | ((*cregsW[1]) ? VF : 0); + return 10; +} + +int lddr() // LDDR (XDE-),(XHL-) 10000011 00010011 +// LDDR (XIX-),(XIY-) 10000101 00010011 +{ + if (opcode&2) + { // XDE/XHL + mem_writeB((*cregsL[2])--,mem_readB((*cregsL[3])--)); + //*cregsL[2]-= 1; + //*cregsL[3]-= 1; + } + else + { // XIX/XIY + mem_writeB(gen_regsXIX--,mem_readB(gen_regsXIY--)); + //mem_writeB(*cregsL[4],mem_readB(*cregsL[5])); + //*cregsL[4]-= 1; + //*cregsL[5]-= 1; + } +// *cregsW[1]-=1; // BC + gen_regsSR = gen_regsSR & ~(HF|VF|NF); + if (--(*cregsW[1])) + { + gen_regsPC-=2; + my_pc-=2; + gen_regsSR = gen_regsSR | VF; + return 14; + } + else + { + return 10; + } +} + +int lddrw() // LDDRW (XDE-),(XHL-) 10010011 00010011 +// LDDRW (XIX-),(XIY-) 10010101 00010011 +{ + if (opcode&2) + { // XDE/XHL + mem_writeW(*cregsL[2],mem_readW(*cregsL[3])); + *cregsL[2]-= 2; + *cregsL[3]-= 2; + } + else + { // XIX/XIY + mem_writeW(gen_regsXIX,mem_readW(gen_regsXIY)); + gen_regsXIX-=2; + gen_regsXIY-=2; + //mem_writeW(*cregsL[4],mem_readW(*cregsL[5])); + //*cregsL[4]-= 2; + //*cregsL[5]-= 2; + } + //*cregsW[1]-= 1; // BC + gen_regsSR = gen_regsSR & ~(HF|VF|NF); + if (--(*cregsW[1])) + { + gen_regsPC-=2; + my_pc-=2; + gen_regsSR = gen_regsSR | VF; + return 14; + } + else + { + return 10; + } +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// CPxx ////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +// +// H flag is always set to 0, instead of being set to 1 when a borrow from bit +// 3 to bit 4 occurs as a result of src1-src2 +// just hoping this never happens :/ + +int cpiB() // CPI A,(R+) 10000RRR 00010100 +{ + unsigned char i = (*cregsB[1]) - memB; + + *cregsL[opcode&7]+=1; + *cregsW[1]-=1; // BC + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF); + gen_regsSR = gen_regsSR | + (i & SF) | + ((i) ? NF : NF|ZF) | + ((*cregsW[1]) ? VF : 0); + return 8; +} + +int cpiW() // CPI WA,(R+) 10010RRR 00010100 +{ + unsigned short i = (*cregsW[0]) - memW; + + *cregsL[opcode&7]+= 2; + *cregsW[1]-=1; // BC + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF); + gen_regsSR = gen_regsSR | + ((i>>8) & SF) | + ((i) ? NF : NF|ZF) | + ((*cregsW[1]) ? VF : 0); + return 8; +} + +int cpirB() // CPIR A,(R+) 10000RRR 00010101 +{ + unsigned char i = (*cregsB[1]) - memB; + + *cregsL[opcode&7]+= 1; + *cregsW[1]-= 1; // BC + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF); + gen_regsSR = gen_regsSR | + (i & SF) | + NF | Ztable[i] | //((i) ? NF : NF|ZF) | + ((*cregsW[1]) ? VF : 0); + if ((gen_regsSR & (ZF|VF)) == VF) + { + gen_regsPC-=2; + my_pc-=2; + return 14; + } + else + { + return 10; + } +} + +int cpirW() // CPIR WA,(R+) 10010RRR 00010101 +{ + unsigned short i = (*cregsW[0]) - memW; + + *cregsL[opcode&7]+=2; + *cregsW[1]-=1; // BC + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF); + gen_regsSR = gen_regsSR | + ((i>>8) & SF) | + ((i) ? NF : NF|ZF) | + ((*cregsW[1]) ? VF : 0); + if ((gen_regsSR & (ZF|VF)) == VF) + { + gen_regsPC-=2; + my_pc-=2; + return 14; + } + else + { + return 10; + } +} + +int cpdB() // CPD A,(R-) 10000RRR 00010110 +{ + unsigned char i = (*cregsB[1]) - memB; + + *cregsL[opcode&7]-= 1; + *cregsW[1]-= 1; // BC + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF); + gen_regsSR = gen_regsSR | + (i & SF) | + NF | Ztable[i] | //((i) ? NF : NF|ZF) | + ((*cregsW[1]) ? VF : 0); + return 8; +} + +int cpdW() // CPD WA,(R-) 10010RRR 00010110 +{ + unsigned short i = (*cregsW[0]) - memW; + + *cregsL[opcode&7]-=2; + *cregsW[1]-=1; // BC + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF); + gen_regsSR = gen_regsSR | + ((i>>8) & SF) | + ((i) ? NF : NF|ZF) | + ((*cregsW[1]) ? VF : 0); + return 8; +} + +int cpdrB() // CPDR A,(R-) 10000RRR 00010111 +{ + unsigned char i = (*cregsB[1]) - memB; + + *cregsL[opcode&7]-= 1; + *cregsW[1]-= 1; // BC + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF); + gen_regsSR = gen_regsSR | + (i & SF) | + NF | Ztable[i] | //((i) ? NF : NF|ZF) | + ((*cregsW[1]) ? VF : 0); + if ((gen_regsSR & (ZF|VF)) == VF) + { + gen_regsPC-=2; + my_pc-=2; + return 14; + } + else + { + return 10; + } +} + +int cpdrW() // CPDR WA,(R-) 10010RRR 00010111 +{ + unsigned short i = (*cregsW[0]) - memW; + + *cregsL[opcode&7]-=2; + *cregsW[1]-=1; // BC + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF); + gen_regsSR = gen_regsSR | + ((i>>8) & SF) | + ((i) ? NF : NF|ZF) | + ((*cregsW[1]) ? VF : 0); + if ((gen_regsSR & (ZF|VF)) == VF) + { + gen_regsPC-=2; + my_pc-=2; + return 14; + } + else + { + return 10; + } +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// ADD /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +inline unsigned char MyAddB(unsigned char i, unsigned char j) +{ + // 100% correct + unsigned char oldi = i; + + i+= j; + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + (i & SF) | + ((i) ? 0 : ZF) | + (((oldi^j)^i) & HF) | + (((i^oldi) & (i^j) & 0x80) ? VF : 0) | + ((i>8) & SF) | + ((i) ? 0 : ZF) | + (((oldi^j)^i) & HF) | + (((i^oldi) & (i^j) & 0x8000) ? VF : 0) | + ((i>24) & SF) | + ((i) ? 0 : ZF) | + (((i^oldi) & (i^j) & 0x80000000) ? VF : 0) | + ((i>8) & SF) | + ((i) ? 0 : ZF) | + (((oldi^j)^i) & HF) | + (((i^oldi) & (i^j) & 0x8000) ? VF : 0) | + ((i>24) & SF) | + ((i) ? 0 : ZF) | + (((i^oldi) & (i^j) & 0x80000000) ? VF : 0) | + ((i> 5) | // V flag + ((res >> 8) & CF) | NF; // C/N flag + return res; + +#else + // 100% correct + unsigned char oldi = i; + + i-= j; + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + (i & SF) | + ((i) ? NF : NF|ZF) | + (((oldi^j)^i) & HF) | + (((j^oldi) & (i^oldi) & 0x80) ? VF : 0) | + ((i>oldi) ? CF : 0); + return i; +#endif +} + +inline unsigned short MySubW(unsigned short i, unsigned short j) +{ +#if 1//speed hack + int res = i - j; + gen_regsSR &= ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR |= ((res>>8) & SF) | + (Ztable[(res>>8) & 0xFF] & Ztable[res & 0xFF]) | + ((i ^ res ^ j) & HF) | // H flag + (((j ^ i) & (i ^ res) & 0x8000) >> 13) | // V flag + ((res >> 16) & CF) | NF; // C/N flag + return res; + +#else + unsigned short oldi = i; + + i-= j; + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF);//all of them + gen_regsSR = gen_regsSR | + ((i>>8) & SF) | + ((i) ? NF : NF|ZF) | + (((oldi^j)^i) & HF) | + (((j^oldi) & (i^oldi) & 0x8000) ? VF : 0) | + ((i>oldi) ? CF : 0); + return i; +#endif +} + +inline unsigned long MySubL(unsigned long i, unsigned long j) +{ +#if 1//speed hack + unsigned long oldi = i; + + i-= j; + gen_regsSR &= ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR |= ((i>>24) & SF) | + (Ztable[(i>>24) & 0xFF] & Ztable[(i>>16) & 0xFF] & Ztable[(i>>8) & 0xFF] & Ztable[i & 0xFF]) | + (((j^oldi) & (i^oldi) & 0x80000000) ? VF : 0) | + ((i>oldi) ? CF : 0) | + NF; + return i; +#else + unsigned long oldi = i; + + i-= j; + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + ((i>>24) & SF) | + ((i) ? NF : NF|ZF) | + (((j^oldi) & (i^oldi) & 0x80000000) ? VF : 0) | + ((i>oldi) ? CF : 0); + return i; +#endif +} + +int subRrB() +{ + *cregsB[lastbyte&7] = MySubB(*cregsB[lastbyte&7],*regB); + return 4; +} +int subRrW() +{ + *cregsW[lastbyte&7] = MySubW(*cregsW[lastbyte&7],*regW); + return 4; +} +int subRrL() +{ + *cregsL[lastbyte&7] = MySubL(*cregsL[lastbyte&7],*regL); + return 7; +} +int subrIB() +{ + *regB = MySubB(*regB,readbyte()); + return 4; +} +int subrIW() +{ + *regW = MySubW(*regW,readword()); + return 4; +} +int subrIL() +{ + *regL = MySubL(*regL,readlong()); + return 7; +} +int subRMB00() +{ + *cregsB[lastbyte&7] = MySubB(*cregsB[lastbyte&7],memB); + return 4; +} +int subRMW10() +{ + *cregsW[lastbyte&7] = MySubW(*cregsW[lastbyte&7],memW); + return 4; +} +int subRML20() +{ + *cregsL[lastbyte&7] = MySubL(*cregsL[lastbyte&7],memL); + return 6; +} +int subMRB00() +{ + mem_writeB(mem,MySubB(memB,*cregsB[lastbyte&7])); + return 6; +} +int subMRW10() +{ + mem_writeW(mem,MySubW(memW,*cregsW[lastbyte&7])); + return 6; +} +int subMRL20() +{ + mem_writeL(mem,MySubL(memL,*cregsL[lastbyte&7])); + return 10; +} +int subMI00() +{ + mem_writeB(mem,MySubB(memB,readbyte())); + return 7; +} +int subwMI10() +{ + mem_writeW(mem,MySubW(memW,readword())); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// SBC /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +inline unsigned char MySbcB(unsigned char i, unsigned char j) +{ + // 100% correct + unsigned char oldi = i; + unsigned char oldC = (unsigned char)(gen_regsSR & CF); + + i = i - j - oldC; + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + SZtable[i & 0xFF] | NF | + (((oldi^j)^i) & HF) | + (((j^oldi) & (i^oldi) & 0x80) >> 5) | + ((i>oldi || (oldC && (j==0xFF))) ? CF : 0); + return i; +} + +inline unsigned short MySbcW(unsigned short i, unsigned short j) +{ + unsigned short oldi = i; + unsigned short oldC = (unsigned short)(gen_regsSR & CF); + + i = i - j - oldC; + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + ((i>>8) & SF) | + ((i) ? NF : NF|ZF) | + (((oldi^j)^i) & HF) | + (((j^oldi) & (i^oldi) & 0x8000) ? VF : 0) | + ((i>oldi || (oldC && (j==0xFFFF))) ? CF : 0); + return i; +} + +inline unsigned long MySbcL(unsigned long i, unsigned long j) +{ + unsigned long oldi = i; + unsigned long oldC = gen_regsSR & CF; + + i = i - j - oldC; + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + ((i>>24) & SF) | + ((i) ? NF : NF|ZF) | + (((j^oldi) & (i^oldi) & 0x80000000) ? VF : 0) | + ((i>oldi || (oldC && (j==0xFFFFFFFF))) ? CF : 0); + return i; +} + +int sbcRrB() +{ + *cregsB[lastbyte&7] = MySbcB(*cregsB[lastbyte&7],*regB); + return 4; +} +int sbcRrW() +{ + *cregsW[lastbyte&7] = MySbcW(*cregsW[lastbyte&7],*regW); + return 4; +} +int sbcRrL() +{ + *cregsL[lastbyte&7] = MySbcL(*cregsL[lastbyte&7],*regL); + return 7; +} +int sbcrIB() +{ + *regB = MySbcB(*regB,readbyte()); + return 4; +} +int sbcrIW() +{ + *regW = MySbcW(*regW,readword()); + return 4; +} +int sbcrIL() +{ + *regL = MySbcL(*regL,readlong()); + return 7; +} +int sbcRMB00() +{ + *cregsB[lastbyte&7] = MySbcB(*cregsB[lastbyte&7],memB); + return 4; +} +int sbcRMW10() +{ + *cregsW[lastbyte&7] = MySbcW(*cregsW[lastbyte&7],memW); + return 4; +} +int sbcRML20() +{ + *cregsL[lastbyte&7] = MySbcL(*cregsL[lastbyte&7],memL); + return 6; +} +int sbcMRB00() +{ + mem_writeB(mem,MySbcB(memB,*cregsB[lastbyte&7])); + return 6; +} +int sbcMRW10() +{ + mem_writeW(mem,MySbcW(memW,*cregsW[lastbyte&7])); + return 6; +} +int sbcMRL20() +{ + mem_writeL(mem,MySbcL(memL,*cregsL[lastbyte&7])); + return 10; +} +int sbcMI00() +{ + mem_writeB(mem,MySbcB(memB,readbyte())); + return 7; +} +int sbcwMI10() +{ + mem_writeW(mem,MySbcW(memW,readword())); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// CP //////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int cpRrB() +{ + MySubB(*cregsB[lastbyte&7],*regB); + return 4; +} +int cpRrW() +{ + MySubW(*cregsW[lastbyte&7],*regW); + return 4; +} +int cpRrL() +{ + MySubL(*cregsL[lastbyte&7],*regL); + return 7; +} +int cpr3B() +{ + MySubB(*regB,lastbyte&7); + return 4; +} +int cpr3W() +{ + MySubW(*regW,lastbyte&7); + return 4; +} +int cprIB() +{ + MySubB(*regB,readbyte()); + return 4; +} +int cprIW() +{ + MySubW(*regW,readword()); + return 4; +} +int cprIL() +{ + MySubL(*regL,readlong()); + return 7; +} +int cpRMB00() +{ + MySubB(*cregsB[lastbyte&7],memB); + return 4; +} +int cpRMW10() +{ + MySubW(*cregsW[lastbyte&7],memW); + return 4; +} +int cpRML20() +{ + MySubL(*cregsL[lastbyte&7],memL); + return 6; +} +int cpMRB00() +{ + MySubB(memB,*cregsB[lastbyte&7]); + return 6; +} +int cpMRW10() +{ + MySubW(memW,*cregsW[lastbyte&7]); + return 6; +} +int cpMRL20() +{ + MySubL(memL,*cregsL[lastbyte&7]); + return 6; +} +int cpMI00() +{ + MySubB(memB,readbyte()); + return 6; +} +int cpwMI10() +{ + MySubW(memW,readword()); + return 6; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// INC /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int inc3rB() // INC #3,r 11001rrr 01100xxx +{ + unsigned long oldC = gen_regsSR & CF; + + *regB = MyAddB(*regB,((lastbyte&7) ? (lastbyte&7) : 8)); + gen_regsSR = (gen_regsSR & ~CF) | oldC; + return 4; +} + +int inc3rW() // INC #3,r 11011rrr 01100xxx +{ + *regW+= ((lastbyte&7) ? (lastbyte&7) : 8); + return 4; +} + +int inc3rL() // INC #3,r 11101rrr 01100xxx +{ + *regL+= ((lastbyte&7) ? (lastbyte&7) : 8); + return 4; +} + +int inc3M00() // INC #3,(mem) 10000mmm 01100xxx +{ + unsigned long oldC = gen_regsSR & CF; + + mem_writeB(mem,MyAddB(memB,((lastbyte&7) ? (lastbyte&7) : 8))); + gen_regsSR = (gen_regsSR & ~CF) | oldC; + return 6; +} + +int incw3M10() // INCW #3,(mem) 10010mmm 01100xxx +{ + unsigned long oldC = gen_regsSR & CF; + + mem_writeW(mem,MyAddW(memW,((lastbyte&7) ? (lastbyte&7) : 8))); + gen_regsSR = (gen_regsSR & ~CF) | oldC; + return 6; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// DEC /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int dec3rB() // DEC #3,r 11001rrr 01101xxx +{ + unsigned long oldC = gen_regsSR & CF; + + *regB = MySubB(*regB,((lastbyte&7) ? (lastbyte&7) : 8)); + gen_regsSR = (gen_regsSR & ~CF) | oldC; + return 4; +} + +int dec3rW() // DEC #3,r 11011rrr 01101xxx +{ + *regW-= ((lastbyte&7) ? (lastbyte&7) : 8); + return 4; +} + +int dec3rL() // DEC #3,r 11101rrr 01101xxx +{ + *regL-= ((lastbyte&7) ? (lastbyte&7) : 8); + return 5; +} + +int dec3M00() // DEC #3,(mem) 10000mmm 01101xxx +{ + unsigned long oldC = gen_regsSR & CF; + + mem_writeB(mem,MySubB(memB,((lastbyte&7) ? (lastbyte&7) : 8))); + gen_regsSR = (gen_regsSR & ~CF) | oldC; + return 6; +} + +int decw3M10() // DECW #3,(mem) 10010mmm 01101xxx +{ + unsigned long oldC = gen_regsSR & CF; + + mem_writeW(mem,MySubW(memW,((lastbyte&7) ? (lastbyte&7) : 8))); + gen_regsSR = (gen_regsSR & ~CF) | oldC; + return 6; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// NEG /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int negrB() +{ + *regB = MySubB(0,*regB); + return 5; +} +int negrW() +{ + *regW = MySubW(0,*regW); + return 5; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// EXTZ ////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int extzrW() +{ + *regW&=0x00ff; + return 4; +} +int extzrL() +{ + *regL&=0x0000ffff; + return 4; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// EXTS ////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int extsrW() // EXTS r 11011rrr 00010011 +{ + if (*regW&0x80) + *regW|=0xff00; + else + *regW&=0x00ff; + return 5; +} + +int extsrL() // EXTS r 11101rrr 00010011 +{ + if (*regL&0x8000) + *regL|=0xffff0000; + else + *regL&=0x0000ffff; + return 5; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// DAA /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +inline void parityB(unsigned char j) +{ +#ifdef USE_PARITY_TABLE //speed hack + gen_regsSR = (gen_regsSR & ~VF) | parityVtable[j]; +#else + unsigned char k=0, i; + + for (i=0;i<8;i++) + { + if (j&1) + k++; + j = j>>1; + } + gen_regsSR = (gen_regsSR & ~VF) | ((k&1) ? 0 : VF); +#endif +} + +inline void parityW(unsigned short j) +{ +#ifdef USE_PARITY_TABLE //speed hack + gen_regsSR = (gen_regsSR & ~VF) | (parityVtable[j>>8] ^ parityVtable[j&0xFF]); +#else + unsigned char k=0, i; + + for (i=0;i<16;i++) + { + if (j&1) + k++; + j = j>>1; + } + gen_regsSR = (gen_regsSR & ~VF) | ((k&1) ? 0 : VF); +#endif +} + +inline void parityL(unsigned long j) +{ +#ifdef USE_PARITY_TABLE //speed hack + gen_regsSR = (gen_regsSR & ~VF) | (parityVtable[(j>>24)&0xFF] ^ parityVtable[(j>>16)&0xFF] ^ parityVtable[(j>>8)&0xFF] ^ parityVtable[j&0xFF]); +#else + unsigned char k=0, i; + + for (i=0;i<32;i++) + { + if (j&1) + k++; + j = j>>1; + } + gen_regsSR = (gen_regsSR & ~VF) | ((k&1) ? 0 : VF); +#endif +} + +int daar() // DAA r 11001rrr 00010000 +{ + // 100% with hardware + unsigned char oldB = *regB; + unsigned char addVal = 0; + unsigned char setCy = 0; + unsigned char i = (*regB & 0xf0); + unsigned char j = (*regB & 0x0f); + + if (gen_regsSR & CF) + { // C + if (gen_regsSR & HF) + { // H + addVal = 0x66; + setCy = 1; + } + else + { // !H + if ((j<0x0a)) + { + addVal = 0x60; + } + else + { + addVal = 0x66; + } + setCy = 1; + } + } + else + { // !C + if (gen_regsSR & HF) + { // H + if (oldB<0x9A) + { + addVal = 0x06; + } + else + { + addVal = 0x66; + } + } + else + { // !H + if ((i<0x90) && (j>0x09)) + { + addVal = 0x06; + } + else if ((i>0x80) && (j>0x09)) + { + addVal = 0x66; + } + else if ((i>0x90) && (j<0x0a)) + { + addVal = 0x60; + } + } + } + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|CF|VF); + if (gen_regsSR & NF) + { // adjust after SUB, SBC or NEG operation + *regB = oldB - addVal; + gen_regsSR = gen_regsSR | ((*regB>oldB || setCy) ? CF : 0); + } + else + { // adjust after ADD or ADC operation + *regB = oldB + addVal; + gen_regsSR = gen_regsSR | ((*regB>1] = (*cregsB[lastbyte&7]) * (*regB); + return 18; +} + +int mulRrW() // MUL RR,r 11011rrr 01000RRR +{ + *cregsL[lastbyte&7] = (*cregsW[lastbyte&7]) * (*regW); + return 26; +} + +int mulrIB() // MUL rr,# 11001rrr 00001000 xxxxxxxx +{ + if (opcode>=0xc8) + { + *cregsW[(opcode&7)>>1] = (*cregsB[opcode&7]) * readbyte(); + } + else + { + *((unsigned short *)regB) = (*regB) * readbyte(); + } + return 18; +} + +int mulrIW() // MUL rr,# 11011rrr 00001000 xxxxxxxx xxxxxxxx +{ + *((unsigned long *)regW) = (*regW) * readword(); + return 26; +} + +int mulRMB00() // MUL RR,(mem) 10000mmm 01000RRR +{ + *cregsW[(lastbyte&7)>>1] = (*cregsB[lastbyte&7]) * memB; + return 18; +} + +int mulRMW10() // MUL RR,(mem) 10010mmm 01000RRR +{ + *cregsL[lastbyte&7] = (*cregsW[lastbyte&7]) * memW; + return 26; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// MULS ////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int mulsRrB() // MULS RR,r 11001rrr 01001RRR +{ + *cregsW[(lastbyte&7)>>1] = (signed char)(*cregsB[lastbyte&7]) * (signed char)(*regB); + return 18; +} + +int mulsRrW() // MULS RR,r 11011rrr 01001RRR +{ + *cregsL[lastbyte&7] = (signed short)(*cregsW[lastbyte&7]) * (signed short)(*regW); + return 26; +} + +int mulsrIB() // MULS rr,# 11001rrr 00001001 xxxxxxxx +{ + if (opcode>=0xc8) + { + *(cregsW[(opcode&7)>>1]) = (signed char)(*cregsB[opcode&7]) * (signed char)readbyte(); + } + else + { + *((unsigned short *)regB) = (signed char)(*regB) * (signed char)readbyte(); + } + return 18; +} + +int mulsrIW() // MULS rr,# 11011rrr 00001001 xxxxxxxx xxxxxxxx +{ + *((unsigned long *)regW) = (signed short)(*regW) * (signed short)readword(); + return 26; +} + +int mulsRMB00() // MULS RR,(mem) 10000mmm 01001RRR +{ + *cregsW[(lastbyte&7)>>1] = (signed char)(*cregsB[lastbyte&7]) * (signed char)memB; + return 18; +} + +int mulsRMW10() // MULS RR,(mem) 10010mmm 01001RRR +{ + *cregsL[lastbyte&7] = (signed short)(*cregsW[lastbyte&7]) * (signed short)memW; + return 26; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// DIV /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +inline unsigned short myDivB(unsigned short i, unsigned char j) +{ + if (!j) + { + gen_regsSR|= VF; + return (i<<8) | ((i>>8)^0xFF); + } + +/* ldiv_t res; + + if (i >= (0x0200 * j)) + { + int diff = i - (0x0200 * j); + int range = 256 - j; + res = ldiv(diff, range); + res.quot = 0x1FF - res.quot; + res.rem = res.rem + j; + } + else + { + res = ldiv(i,j); + } + */ + ldiv_t res = ldiv(i,j); + if (res.quot>0xFF) + gen_regsSR|= VF; + else + gen_regsSR&= ~VF; + return ((unsigned short)(res.quot & 0xFF)) | ((unsigned short)((res.rem & 0xFF) << 8)); +} + +inline unsigned int myDivW(unsigned int i, unsigned short j) +{ + if (!j) + { + gen_regsSR|= VF; + return (i<<16) | ((i>>16)^0xFFFF); + } +/* PacMan fix : when j>=128 -> overflow + ldiv_t res; + if (i >= (0x02000000 * (unsigned int)j)) + { + int diff = i - (0x02000000 * j); + int range = 0x1000000 - j; + res = ldiv(diff, range); + res.quot = 0x1FFFFFF - res.quot; + res.rem = res.rem + j; + } + else + { + res = ldiv(i,j); + } +*/ + ldiv_t res = ldiv(i,j); + if (res.quot>0xFFFF) + gen_regsSR|= VF; + else + gen_regsSR&= ~VF; + return (res.quot & 0xFFFF) | ((res.rem & 0xFFFF) << 16); +} + +int divRrB() // DIV RR,r 11001rrr 01010RRR +{ + *cregsW[(lastbyte&7)>>1] = myDivB(*cregsW[(lastbyte&7)>>1], *regB); + return 22; +} + +int divRrW() // DIV RR,r 11011rrr 01010RRR +{ + *cregsL[lastbyte&7] = myDivW(*cregsL[lastbyte&7], *regW); + return 30; +} + +int divrIB() // DIV rr,# 11001rrr 00001010 xxxxxxxx +{ + unsigned char i = readbyte(); + + if (opcode>=0xc8) + { + *cregsW[(opcode&7)>>1] = myDivB(*cregsW[(opcode&7)>>1], i); + } + else + { + *((unsigned short *)regB) = myDivB(*(unsigned short *)regB, i); + } + return 22; +} + +int divrIW() // DIV rr,# 11011rrr 00001010 xxxxxxxx xxxxxxxx +{ + unsigned short i = readword(); + + *((unsigned long *)regW) = myDivW(*(unsigned long *)regW, i); + return 30; +} + +int divRMB00() // DIV RR,(mem) 10000mmm 01010RRR +{ + unsigned char i = memB; + + *cregsW[(lastbyte&7)>>1] = myDivB(*cregsW[(lastbyte&7)>>1], i); + return 22; +} + +int divRMW10() // DIV RR,(mem) 10010mmm 01010RRR +{ + unsigned short i = memW; + + *cregsL[lastbyte&7] = myDivW(*cregsL[lastbyte&7], i); + return 30; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// DIVS ////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +unsigned short myDivsB(signed short i, signed char j) +{ + if (!j) + { + gen_regsSR|= VF; + if (i<1) + return (i<<8) | (i^0xFF); + else + return (i<<8); + } + + ldiv_t res = ldiv(i,j); + if (res.quot>0xFF) + gen_regsSR|= VF; + else + gen_regsSR&= ~VF; + return ((unsigned short)(res.quot & 0xFF)) | ((unsigned short)((res.rem & 0xFF) << 8)); +} + +unsigned int myDivsW(signed int i, signed short j) +{ + if (!j) + { + gen_regsSR|= VF; + return (i<<16) | (i^0xFFFF); + } + + ldiv_t res = ldiv(i,j); + if (res.quot>0xFFFF) + gen_regsSR|= VF; + else + gen_regsSR&= ~VF; + return (res.quot & 0xFFFF) | ((res.rem & 0xFFFF) << 16); +} + +int divsRrB() // DIVS RR,r 11001rrr 01011RRR +{ + *cregsW[(lastbyte&7)>>1] = myDivsB((signed short)(*cregsW[(lastbyte&7)>>1]), (signed char)(*regB)); + return 24; +} + +int divsRrW() // DIVS RR,r 11011rrr 01011RRR +{ + *cregsL[lastbyte&7] = myDivsW((signed long)(*cregsL[lastbyte&7]), (signed short)(*regW)); + return 32; +} + +int divsrIB() // DIVS rr,# 11001rrr 00001011 xxxxxxxx +{ + signed char i = readbyte(); + + if (opcode>=0xc8) + { + *cregsW[(opcode&7)>>1] = myDivsB((signed short)(*cregsW[(opcode&7)>>1]), i); + } + else + { + *((unsigned short *)regB) = myDivsB((*(signed short *)regB), i); + } + return 24; +} + +int divsrIW() // DIVS rr,# 11011rrr 00001011 xxxxxxxx xxxxxxxx +{ + signed short i = readword(); + + *((unsigned long *)regW) = myDivsW((*(signed long *)regW), i); + return 32; +} + +int divsRMB00() // DIVS RR,(mem) 10000mmm 01011RRR +{ + signed char i = memB; + + *cregsW[(lastbyte&7)>>1] = myDivsB((signed short)(*cregsW[(lastbyte&7)>>1]), i); + return 24; +} + +int divsRMW10() // DIVS RR,(mem) 10010mmm 01011RRR +{ + signed short i = memW; + + *cregsL[lastbyte&7] = myDivsW((signed long)(*cregsL[lastbyte&7]), i); + return 32; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// MULA ////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int mular() // MULA rr 11011rrr 00011001 +{ + unsigned long *p; + + p = cregsL[opcode&7]; + *p+= (signed long)(((signed short)mem_readW(*cregsL[2]))*((signed short)mem_readW(*cregsL[3]))); + *cregsL[3]-=2; // XHL + gen_regsSR = gen_regsSR & ~(SF|ZF|VF); + gen_regsSR = gen_regsSR | + ((*p >> 24) & SF) | + ((*p) ? 0 : ZF); + return 31; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// MINC ////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int minc1() // MINC1 #,r 11011rrr 00111000 xxxxxxxx xxxxxxxx +{ + unsigned short i; + + i = readword(); + *regW = (((*regW & i) == i) ? *regW - i : *regW + 1); + return 8; +} + +int minc2() // MINC2 #,r 11011rrr 00111001 xxxxxxxx xxxxxxxx +{ + unsigned short i; + + i = readword(); + *regW = (((*regW & i) == i) ? *regW - i : *regW + 2); + return 8; +} + +int minc4() // MINC4 #,r 11011rrr 00111010 xxxxxxxx xxxxxxxx +{ + unsigned short i; + + i = readword(); + *regW = (((*regW & i) == i) ? *regW - i : *regW + 4); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// MDEC ////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int mdec1() // MDEC1 #,r 11011rrr 00111100 xxxxxxxx xxxxxxxx +{ + unsigned short i; + + i = readword(); + *regW = (((*regW & i) == i) ? *regW + i : *regW - 1); + return 7; +} + +int mdec2() // MDEC2 #,r 11011rrr 00111101 xxxxxxxx xxxxxxxx +{ + unsigned short i; + + i = readword(); + *regW = (((*regW & i) == i) ? *regW + i : *regW - 2); + return 7; +} + +int mdec4() // MDEC4 #,r 11011rrr 00111110 xxxxxxxx xxxxxxxx +{ + unsigned short i; + + i = readword(); + *regW = (((*regW & i) == i) ? *regW + i : *regW - 4); + return 7; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// AND /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +unsigned char MyAndB(unsigned char i, unsigned char j) +{ + // 100% correct + i&= j; + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + (i & SF) | + ((i) ? HF : HF|ZF) +#ifdef USE_PARITY_TABLE + | parityVtable[i]; +#else + ; + parityB(i); +#endif + return i; +} + +unsigned short MyAndW(unsigned short i, unsigned short j) +{ + i&= j; + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + ((i>>8) & SF) | + ((i) ? HF : HF|ZF); + parityW(i); + return i; +} + +unsigned long MyAndL(unsigned long i, unsigned long j) +{ + i&= j; + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + ((i>>24) & SF) | + ((i) ? HF : HF|ZF); + return i; +} + +int andRrB() +{ + *cregsB[lastbyte&7] = MyAndB(*cregsB[lastbyte&7],*regB); + return 4; +} +int andRrW() +{ + *cregsW[lastbyte&7] = MyAndW(*cregsW[lastbyte&7],*regW); + return 4; +} +int andRrL() +{ + *cregsL[lastbyte&7] = MyAndL(*cregsL[lastbyte&7],*regL); + return 7; +} +int andrIB() +{ + *regB = MyAndB(*regB,readbyte()); + return 4; +} +int andrIW() +{ + *regW = MyAndW(*regW,readword()); + return 4; +} +int andrIL() +{ + *regL = MyAndL(*regL,readlong()); + return 7; +} +int andRMB00() +{ + *cregsB[lastbyte&7] = MyAndB(*cregsB[lastbyte&7],memB); + return 4; +} +int andRMW10() +{ + *cregsW[lastbyte&7] = MyAndW(*cregsW[lastbyte&7],memW); + return 4; +} +int andRML20() +{ + *cregsL[lastbyte&7] = MyAndL(*cregsL[lastbyte&7],memL); + return 6; +} +int andMRB00() +{ + mem_writeB(mem,MyAndB(memB,*cregsB[lastbyte&7])); + return 6; +} +int andMRW10() +{ + mem_writeW(mem,MyAndW(memW,*cregsW[lastbyte&7])); + return 6; +} +int andMRL20() +{ + mem_writeL(mem,MyAndL(memL,*cregsL[lastbyte&7])); + return 10; +} +int andMI00() +{ + mem_writeB(mem,MyAndB(memB,readbyte())); + return 7; +} +int andwMI10() +{ + mem_writeW(mem,MyAndW(memW,readword())); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// OR //////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +inline unsigned char MyOrB(unsigned char i, unsigned char j) +{ + // 100% correct + i|= j; + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + (i & SF) | + ((i) ? 0 : ZF) +#ifdef USE_PARITY_TABLE + | parityVtable[i]; +#else + ; + parityB(i); +#endif + + return i; +} + +inline unsigned short MyOrW(unsigned short i, unsigned short j) +{ + i|= j; + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + ((i>>8) & SF) | + ((i) ? 0 : ZF); + parityW(i); + return i; +} + +inline unsigned long MyOrL(unsigned long i, unsigned long j) +{ + i|= j; + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + ((i>>24) & SF) | + ((i) ? 0 : ZF); + return i; +} + +int orRrB() +{ + *cregsB[lastbyte&7] = MyOrB(*cregsB[lastbyte&7],*regB); + return 4; +} +int orRrW() +{ + *cregsW[lastbyte&7] = MyOrW(*cregsW[lastbyte&7],*regW); + return 4; +} +int orRrL() +{ + *cregsL[lastbyte&7] = MyOrL(*cregsL[lastbyte&7],*regL); + return 7; +} +int orrIB() +{ + *regB = MyOrB(*regB,readbyte()); + return 4; +} +int orrIW() +{ + *regW = MyOrW(*regW,readword()); + return 4; +} +int orrIL() +{ + *regL = MyOrL(*regL,readlong()); + return 7; +} +int orRMB00() +{ + *cregsB[lastbyte&7] = MyOrB(*cregsB[lastbyte&7],memB); + return 4; +} +int orRMW10() +{ + *cregsW[lastbyte&7] = MyOrW(*cregsW[lastbyte&7],memW); + return 4; +} +int orRML20() +{ + *cregsL[lastbyte&7] = MyOrL(*cregsL[lastbyte&7],memL); + return 6; +} +int orMRB00() +{ + mem_writeB(mem,MyOrB(memB,*cregsB[lastbyte&7])); + return 6; +} +int orMRW10() +{ + mem_writeW(mem,MyOrW(memW,*cregsW[lastbyte&7])); + return 6; +} +int orMRL20() +{ + mem_writeL(mem,MyOrL(memL,*cregsL[lastbyte&7])); + return 10; +} +int orMI00() +{ + mem_writeB(mem,MyOrB(memB,readbyte())); + return 7; +} +int orwMI10() +{ + mem_writeW(mem,MyOrW(memW,readword())); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// XOR /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +inline unsigned char MyXorB(unsigned char i, unsigned char j) +{ + // 100% correct + i^= j; + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + (i & SF) | + ((i) ? 0 : ZF) +#ifdef USE_PARITY_TABLE + | parityVtable[i]; +#else + ; + parityB(i); +#endif + + return i; +} + +inline unsigned short MyXorW(unsigned short i, unsigned short j) +{ + i^= j; + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + ((i>>8) & SF) | + ((i) ? 0 : ZF); + parityW(i); + return i; +} + +inline unsigned long MyXorL(unsigned long i, unsigned long j) +{ + i^= j; + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + ((i>>24) & SF) | + ((i) ? 0 : ZF); + return i; +} + +int xorRrB() +{ + *cregsB[lastbyte&7] = MyXorB(*cregsB[lastbyte&7],*regB); + return 4; +} +int xorRrW() +{ + *cregsW[lastbyte&7] = MyXorW(*cregsW[lastbyte&7],*regW); + return 4; +} +int xorRrL() +{ + *cregsL[lastbyte&7] = MyXorL(*cregsL[lastbyte&7],*regL); + return 7; +} +int xorrIB() +{ + *regB = MyXorB(*regB,readbyte()); + return 4; +} +int xorrIW() +{ + *regW = MyXorW(*regW,readword()); + return 4; +} +int xorrIL() +{ + *regL = MyXorL(*regL,readlong()); + return 7; +} +int xorRMB00() +{ + *cregsB[lastbyte&7] = MyXorB(*cregsB[lastbyte&7],memB); + return 4; +} +int xorRMW10() +{ + *cregsW[lastbyte&7] = MyXorW(*cregsW[lastbyte&7],memW); + return 4; +} +int xorRML20() +{ + *cregsL[lastbyte&7] = MyXorL(*cregsL[lastbyte&7],memL); + return 6; +} +int xorMRB00() +{ + mem_writeB(mem,MyXorB(memB,*cregsB[lastbyte&7])); + return 6; +} +int xorMRW10() +{ + mem_writeW(mem,MyXorW(memW,*cregsW[lastbyte&7])); + return 6; +} +int xorMRL20() +{ + mem_writeL(mem,MyXorL(memL,*cregsL[lastbyte&7])); + return 10; +} +int xorMI00() +{ + mem_writeB(mem,MyXorB(memB,readbyte())); + return 7; +} +int xorwMI10() +{ + mem_writeW(mem,MyXorW(memW,readword())); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// CPL /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int cplrB() +{ + *regB = ~*regB; + gen_regsSR|= HF|NF; + return 4; +} +int cplrW() +{ + *regW = ~*regW; + gen_regsSR|= HF|NF; + return 4; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// LDCF ////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +const unsigned short power2[16] = + { + 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, + 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000 + }; + +#define LDCF(A,B) if (A & power2[B]) gen_regsSR|= CF; \ + else gen_regsSR&= ~CF; + +int ldcf4rB() +{ + LDCF(*regB,readbyte()); + return 4; +} +int ldcf4rW() +{ + LDCF(*regW,readbyte()); + return 4; +} +int ldcfArB() +{ + LDCF(*regB,*cregsB[1]); + return 4; +} +int ldcfArW() +{ + LDCF(*regW,*cregsB[1]); + return 4; +} +int ldcf3M30() +{ + LDCF(mem_readB(mem),lastbyte&7); + return 8; +} +int ldcfAM30() +{ + LDCF(mem_readB(mem),*cregsB[1]); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// STCF ////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int stcf4rB() // STCF #4,r 11001rrr 00100100 0000xxxx +{ + if (gen_regsSR & CF) + *regB|= power2[readbyte()]; + else + *regB&= ~power2[readbyte()]; + return 4; +} + +int stcf4rW() // STCF #4,r 11011rrr 00100100 0000xxxx +{ + if (gen_regsSR & CF) + *regW|= power2[readbyte()]; + else + *regW&= ~power2[readbyte()]; + return 4; +} + +int stcfArB() // STCF A,r 11001rrr 00101100 +{ + if (gen_regsSR & CF) + *regB|= power2[*cregsB[1]]; + else + *regB&= ~power2[*cregsB[1]]; + return 4; +} + +int stcfArW() // STCF A,r 11011rrr 00101100 +{ + if (gen_regsSR & CF) + *regW|= power2[*cregsB[1]]; + else + *regW&= ~power2[*cregsB[1]]; + return 4; +} + +int stcf3M30() // STCF #3,(mem) 10110mmm 10100xxx +{ + if (gen_regsSR & CF) + mem_writeB(mem,mem_readB(mem) | power2[lastbyte&7]); + else + mem_writeB(mem,mem_readB(mem) & ~power2[lastbyte&7]); + return 8; +} + +int stcfAM30() // STCF A,(mem) 10110mmm 00101100 +{ + if (gen_regsSR & CF) + mem_writeB(mem,mem_readB(mem) | power2[*cregsB[1]]); + else + mem_writeB(mem,mem_readB(mem) & ~power2[*cregsB[1]]); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// ANDCF ///////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +#define ANDCF(A,B) if ((A & power2[B]) && (gen_regsSR & CF)) gen_regsSR|= CF; \ + else gen_regsSR&= ~CF; + +int andcf4rB() +{ + ANDCF(*regB, readbyte()); + return 4; +} +int andcf4rW() +{ + ANDCF(*regW, readbyte()); + return 4; +} +int andcfArB() +{ + ANDCF(*regB, *cregsB[1]); + return 4; +} +int andcfArW() +{ + ANDCF(*regW, *cregsB[1]); + return 4; +} +int andcf3M30() +{ + ANDCF(mem_readB(mem), lastbyte&7); + return 8; +} +int andcfAM30() +{ + ANDCF(mem_readB(mem), *cregsB[1]); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// ORCF ////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +#define ORCF(A,B) gen_regsSR|= ((A >> B) & CF); + +int orcf4rB() +{ + ORCF(*regB, readbyte()); + return 4; +} +int orcf4rW() +{ + ORCF(*regW, readbyte()); + return 4; +} +int orcfArB() +{ + ORCF(*regB, *cregsB[1]); + return 4; +} +int orcfArW() +{ + ORCF(*regW, *cregsB[1]); + return 4; +} +int orcf3M30() +{ + ORCF(mem_readB(mem), (lastbyte&7)); + return 8; +} +int orcfAM30() +{ + ORCF(mem_readB(mem), *cregsB[1]); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// XORCF ///////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +#define XORCF(A,B) gen_regsSR^= ((A >> B) & CF); + +int xorcf4rB() +{ + XORCF(*regB, readbyte()); + return 4; +} +int xorcf4rW() +{ + XORCF(*regW, readbyte()); + return 4; +} +int xorcfArB() +{ + XORCF(*regB, *cregsB[1]); + return 4; +} +int xorcfArW() +{ + XORCF(*regW, *cregsB[1]); + return 4; +} +int xorcf3M30() +{ + XORCF(mem_readB(mem), (lastbyte&7)); + return 8; +} +int xorcfAM30() +{ + XORCF(mem_readB(mem), *cregsB[1]); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// xCF /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int rcf() +{ + gen_regsSR&= ~(HF|NF|CF); + return 2; +} +int scf() +{ + gen_regsSR = (gen_regsSR & ~(HF|NF)) | CF; + return 2; +} +int ccf() +{ + gen_regsSR = (gen_regsSR & ~NF) ^ CF; + return 2; +} +int zcf() +{ + gen_regsSR = (gen_regsSR & ~(NF|CF)) | ((gen_regsSR & ZF) ? 0 : CF); + return 2; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// BIT /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +#define BIT(A,B) gen_regsSR = (gen_regsSR & ~(ZF|NF)) | ((A & power2[B]) ? HF : HF|ZF); + +int bit4rB() +{ + BIT(*regB, readbyte()); + return 4; +} +int bit4rW() +{ + BIT(*regW, readbyte()); + return 4; +} +int bit3M30() +{ + BIT(mem_readB(mem), lastbyte&7); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// RES /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int res4rB() +{ + *regB&= ~power2[readbyte()]; + return 4; +} +int res4rW() +{ + *regW&= ~power2[readbyte()]; + return 4; +} +int res3M30() +{ + mem_writeB(mem,mem_readB(mem) & ~power2[lastbyte&7]); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// SET /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int set4rB() +{ + *regB|= power2[readbyte()]; + return 4; +} +int set4rW() +{ + *regW|= power2[readbyte()]; + return 4; +} + +//Flavor +int set3M30() +{ + mem_writeB(mem, mem_readB(mem) | power2[lastbyte&7]); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// CHG /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int chg4rB() +{ + *regB^= power2[readbyte()]; + return 4; +} +int chg4rW() +{ + *regW^= power2[readbyte()]; + return 4; +} +int chg3M30() +{ + mem_writeB(mem,mem_readB(mem) ^ power2[lastbyte&7]); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// TSET ////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int tset4rB() // TSET #4,r 11001rrr 00110100 0000xxxx +{ + unsigned char i = readbyte(); + + gen_regsSR = gen_regsSR & ~(ZF|NF); + gen_regsSR = gen_regsSR | + ((*regB&power2[i]) ? HF : HF|ZF); + *regB |= power2[i]; + return 6; +} + +int tset4rW() // TSET #4,r 11011rrr 00110100 0000xxxx +{ + unsigned char i = readbyte(); + + gen_regsSR = gen_regsSR & ~(ZF|NF); + gen_regsSR = gen_regsSR | + ((*regW&power2[i]) ? HF : HF|ZF); + *regW |= power2[i]; + return 6; +} + +int tset3M30() // TSET #3,(mem) 10110mmm 10101xxx +{ + unsigned char i = mem_readB(mem); + + gen_regsSR = gen_regsSR & ~(ZF|NF); + gen_regsSR = gen_regsSR | + ((i&power2[i]) ? HF : HF|ZF); + mem_writeB(mem,i | power2[lastbyte&7]); + return 10; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// BS1 /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int bs1b() // BS1B A,r 11011rrr 00001111 +{ + unsigned short i = *regW; + + if (i==0) + { + gen_regsSR |= VF; + return 4; + } + + unsigned char ret = 15; + + gen_regsSR &= ~VF; + + while (i<0x8000) + { + i = i<<1; + ret -= 1; + } + + *cregsB[1] = ret; + return 4; +} + +int bs1f() // BS1F A,r 11011rrr 00001110 +{ + unsigned short i = *regW; + + if (i==0) + { + gen_regsSR|= VF; + return 4; + } + + unsigned char ret = 0; + + gen_regsSR&= ~VF; + + + while (!(i&1)) + { + i = i>>1; + ret+=1; + } + + *cregsB[1] = ret; + + return 4; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// MISC ////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int nop() +{ + return 1; +} +int normal() +{ + gen_regsSR = gen_regsSR & 0x7fff; + return 4; +} +int tmax() +{ + gen_regsSR = gen_regsSR | 0x0400; + return 4; +} +int ei() +{ + gen_regsSR = (gen_regsSR & 0x8fff) | (readbyte()<<12); + return 5; +} + +int swi() // SWI #3 11111xxx +{ + tlcsFastMemWriteL(gen_regsXSP-=4,gen_regsPC); + tlcsFastMemWriteW(gen_regsXSP-=2,gen_regsSR); + // SYSM = 1; + gen_regsPC = mem_readL(0x00FFFF00 + ((opcode&7)<<2)) & 0x00ffffff; + my_pc = get_address(gen_regsPC); + + return 16; +} + +int halt() +{ + --gen_regsPC; + --my_pc; + return 8; +} + +//link y unlink joden el rockman + +int link() // LINK r,d16 11101rrr 00001100 xxxxxxxx xxxxxxxx +{ + tlcsFastMemWriteL(gen_regsXSP-=4,*regL); + *regL = gen_regsXSP; + gen_regsXSP+= (signed short)readword(); + return 10; +} + +int unlk() // UNLK r 11101rrr 00001101 +{ + gen_regsXSP = *regL; + *regL = mem_readL(gen_regsXSP); + gen_regsXSP+=4; + return 8; +} + +int ldf() // LDF #3 00010111 00000xxx +{ + gen_regsSR = (gen_regsSR & 0xf8ff) | ((readbyte() & 7) << 8); + set_cregs(); + return 2; +} + +int incf() // INCF 00001100 +{ + unsigned long i = gen_regsSR & 0x0700; + + i = (i + 0x0100) & 0x0700; + // for MAX mode + i = i & 0x0300; + gen_regsSR = (gen_regsSR & 0xf8ff) | i; + set_cregs(); + return 2; +} + +int decf() // DECF 00001101 +{ + unsigned long i = gen_regsSR & 0x0700; + + i = (i - 0x0100) & 0x0700; + // for MAX mode + i = i & 0x0300; + gen_regsSR = (gen_regsSR & 0xf8ff) | i; + set_cregs(); + return 2; +} + +int sccB0() +{ + *regB = valCond0(); + return 6; +} +int sccB1() +{ + *regB = valCond1(); + return 6; +} +int sccB2() +{ + *regB = valCond2(); + return 6; +} +int sccB3() +{ + *regB = valCond3(); + return 6; +} +int sccB4() +{ + *regB = valCond4(); + return 6; +} +int sccB5() +{ + *regB = valCond5(); + return 6; +} +int sccB6() +{ + *regB = valCond6(); + return 6; +} +int sccB7() +{ + *regB = valCond7(); + return 6; +} +int sccB8() +{ + *regB = valCond8(); + return 6; +} +int sccB9() +{ + *regB = valCond9(); + return 6; +} +int sccBA() +{ + *regB = valCondA(); + return 6; +} +int sccBB() +{ + *regB = valCondB(); + return 6; +} +int sccBC() +{ + *regB = valCondC(); + return 6; +} +int sccBD() +{ + *regB = valCondD(); + return 6; +} +int sccBE() +{ + *regB = valCondE(); + return 6; +} +int sccBF() +{ + *regB = valCondF(); + return 6; +} + +int sccW0() +{ + *regW = valCond0(); + return 6; +} +int sccW1() +{ + *regW = valCond1(); + return 6; +} +int sccW2() +{ + *regW = valCond2(); + return 6; +} +int sccW3() +{ + *regW = valCond3(); + return 6; +} +int sccW4() +{ + *regW = valCond4(); + return 6; +} +int sccW5() +{ + *regW = valCond5(); + return 6; +} +int sccW6() +{ + *regW = valCond6(); + return 6; +} +int sccW7() +{ + *regW = valCond7(); + return 6; +} +int sccW8() +{ + *regW = valCond8(); + return 6; +} +int sccW9() +{ + *regW = valCond9(); + return 6; +} +int sccWA() +{ + *regW = valCondA(); + return 6; +} +int sccWB() +{ + *regW = valCondB(); + return 6; +} +int sccWC() +{ + *regW = valCondC(); + return 6; +} +int sccWD() +{ + *regW = valCondD(); + return 6; +} +int sccWE() +{ + *regW = valCondE(); + return 6; +} +int sccWF() +{ + *regW = valCondF(); + return 6; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// LDC/X ///////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int ldccrB() +{ + ldcRegs[readbyte()] = *regB; + return 8; +} +int ldccrW() +{ + *((unsigned short *)&ldcRegs[readbyte()]) = *regW; + return 8; +} +int ldccrL() +{ + *((unsigned long *)&ldcRegs[readbyte()]) = *regL; + return 8; +} +int ldcrcB() +{ + *regB = ldcRegs[readbyte()]; + return 8; +} +int ldcrcW() +{ + *regW = *((unsigned short *)&ldcRegs[readbyte()]); + return 8; +} +int ldcrcL() +{ + *regL = *((unsigned long *)&ldcRegs[readbyte()]); + return 8; +} +int ldx() // LDX (#8),# 11110111 00000000 xxxxxxxx 00000000 xxxxxxxx 00000000 +{ + unsigned char num8, data; + readbyte(); + num8 = readbyte(); + readbyte(); + data = readbyte(); + readbyte(); + mem_writeB(num8,data); + return 9; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// RLC /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +inline unsigned char MyRlcB(unsigned char i, unsigned char nr) +{ + nr = ((nr) ? nr : 16); + for(;nr>0;nr--) + { + if (i&0x80) + { + i = (i << 1)|1; + } + else + { + i = i << 1; + } + } + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + (i & SF) | + ((i) ? 0 : ZF) | + (i & CF) +#ifdef USE_PARITY_TABLE + | parityVtable[i]; +#else + ; + parityB(i); +#endif + + return i; +} + +inline unsigned short MyRlcW(unsigned short i, unsigned char nr) +{ + nr = ((nr) ? nr : 16); + for(;nr>0;nr--) + { + if (i&0x8000) + { + i = (i << 1)|1; + } + else + { + i = i << 1; + } + } + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + ((i>>8) & SF) | + ((i) ? 0 : ZF) | + (i & CF); + parityW(i); + return i; +} + +inline unsigned long MyRlcL(unsigned long i, unsigned char nr) +{ + nr = ((nr) ? nr : 16); + for(;nr>0;nr--) + { + if (i&0x80000000) + { + i = (i << 1)|1; + } + else + { + i = i << 1; + } + state+= 2; + } + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + ((i>>24) & SF) | + ((i) ? 0 : ZF) | + (i & CF); + parityL(i); + return i; +} + +int rlc4rB() +{ + *regB = MyRlcB(*regB,readbyte()); + return 6; +} +int rlc4rW() +{ + *regW = MyRlcW(*regW,readbyte()); + return 6; +} +int rlc4rL() +{ + *regL = MyRlcL(*regL,readbyte()); + return 8; +} +int rlcArB() +{ + *regB = MyRlcB(*regB,*cregsB[1] & 0x0F); + return 6; +} +int rlcArW() +{ + *regW = MyRlcW(*regW,*cregsB[1] & 0x0F); + return 6; +} +int rlcArL() +{ + *regL = MyRlcL(*regL,*cregsB[1] & 0x0F); + return 8; +} +int rlcM00() +{ + mem_writeB(mem,MyRlcB(memB,1)); + return 8; +} +int rlcwM10() +{ + mem_writeW(mem,MyRlcW(memW,1)); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// RRC /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +unsigned char MyRrcB(unsigned char i, unsigned char nr) +{ + nr = ((nr) ? nr : 16); + for(;nr>0;nr--) + { + if (i&1) + { + i = (i >> 1)|0x80; + } + else + { + i = i >> 1; + } + } + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + ((i & SF) ? SF|CF : 0) | + ((i) ? 0 : ZF) +#ifdef USE_PARITY_TABLE + | parityVtable[i]; +#else + ; + parityB(i); +#endif + + return i; +} + +unsigned short MyRrcW(unsigned short i, unsigned char nr) +{ + nr = ((nr) ? nr : 16); + for(;nr>0;nr--) + { + if (i&1) + { + i = (i >> 1)|0x8000; + } + else + { + i = i >> 1; + } + } + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + (((i>>8) & 0x80) ? SF|CF : 0) | + ((i) ? 0 : ZF); + parityW(i); + return i; +} + +unsigned long MyRrcL(unsigned long i, unsigned char nr) +{ + nr = ((nr) ? nr : 16); + for(;nr>0;nr--) + { + if (i&1) + { + i = (i >> 1)|0x80000000; + } + else + { + i = i >> 1; + } + state+= 2; + } + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + (((i>>24) & 0x80) ? SF|CF : 0) | + ((i) ? 0 : ZF); + parityL(i); + return i; +} + +int rrc4rB() +{ + *regB = MyRrcB(*regB,readbyte()); + return 6; +} +int rrc4rW() +{ + *regW = MyRrcW(*regW,readbyte()); + return 6; +} +int rrc4rL() +{ + *regL = MyRrcL(*regL,readbyte()); + return 8; +} +int rrcArB() +{ + *regB = MyRrcB(*regB,*cregsB[1] & 0x0F); + return 6; +} +int rrcArW() +{ + *regW = MyRrcW(*regW,*cregsB[1] & 0x0F); + return 6; +} +int rrcArL() +{ + *regL = MyRrcL(*regL,*cregsB[1] & 0x0F); + return 8; +} +int rrcM00() +{ + mem_writeB(mem,MyRrcB(memB,1)); + return 8; +} +int rrcwM10() +{ + mem_writeW(mem,MyRrcW(memW,1)); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// RL //////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +unsigned char MyRlB(unsigned char i, unsigned char nr) +{ + nr = ((nr) ? nr : 16); + for(;nr>0;nr--) + { + if (i&0x80) + { + i = (i << 1)|(unsigned char)(gen_regsSR & CF); + gen_regsSR|= CF; + } + else + { + i = (i << 1)|(unsigned char)(gen_regsSR & CF); + gen_regsSR&= ~CF; + } + } + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF); + gen_regsSR = gen_regsSR | + (i & SF) | + ((i) ? 0 : ZF) +#ifdef USE_PARITY_TABLE + | parityVtable[i]; +#else + ; + parityB(i); +#endif + + return i; +} + +unsigned short MyRlW(unsigned short i, unsigned char nr) +{ + nr = ((nr) ? nr : 16); + for(;nr>0;nr--) + { + if (i&0x8000) + { + i = (i << 1)|(unsigned char)(gen_regsSR & CF); + gen_regsSR|= CF; + } + else + { + i = (i << 1)|(unsigned char)(gen_regsSR & CF); + gen_regsSR&= ~CF; + } + } + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF); + gen_regsSR = gen_regsSR | + ((i>>8) & SF) | + ((i) ? 0 : ZF); + parityW(i); + return i; +} + +unsigned long MyRlL(unsigned long i, unsigned char nr) +{ + nr = ((nr) ? nr : 16); + for(;nr>0;nr--) + { + if (i&0x80000000) + { + i = (i << 1)|(gen_regsSR & CF); + gen_regsSR|= CF; + } + else + { + i = (i << 1)|(gen_regsSR & CF); + gen_regsSR&= ~CF; + } + state+= 2; + } + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF); + gen_regsSR = gen_regsSR | + ((i>>24) & SF) | + ((i) ? 0 : ZF); + parityL(i); + return i; +} + +int rl4rB() +{ + *regB = MyRlB(*regB,readbyte()); + return 6; +} +int rl4rW() +{ + *regW = MyRlW(*regW,readbyte()); + return 6; +} +int rl4rL() +{ + *regL = MyRlL(*regL,readbyte()); + return 8; +} +int rlArB() +{ + *regB = MyRlB(*regB,*cregsB[1] & 0x0F); + return 6; +} +int rlArW() +{ + *regW = MyRlW(*regW,*cregsB[1] & 0x0F); + return 6; +} +int rlArL() +{ + *regL = MyRlL(*regL,*cregsB[1] & 0x0F); + return 8; +} +int rlM00() +{ + mem_writeB(mem,MyRlB(memB,1)); + return 8; +} +int rlwM10() +{ + mem_writeW(mem,MyRlW(memW,1)); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// RR //////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +unsigned char MyRrB(unsigned char i, unsigned char nr) +{ + nr = ((nr) ? nr : 16); + for(;nr>0;nr--) + { + if (gen_regsSR & CF) + { + gen_regsSR = (gen_regsSR & ~CF) | (i & CF); + i = (i >> 1)|0x80; + } + else + { + gen_regsSR = (gen_regsSR & ~CF) | (i & CF); + i = i >> 1; + } + } + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF); + gen_regsSR = gen_regsSR | + (i & SF) | + ((i) ? 0 : ZF) +#ifdef USE_PARITY_TABLE + | parityVtable[i]; +#else + ; + parityB(i); +#endif + + return i; +} + +unsigned short MyRrW(unsigned short i, unsigned char nr) +{ + nr = ((nr) ? nr : 16); + for(;nr>0;nr--) + { + if (gen_regsSR & CF) + { + gen_regsSR = (gen_regsSR & ~CF) | (i & CF); + i = (i >> 1)|0x8000; + } + else + { + gen_regsSR = (gen_regsSR & ~CF) | (i & CF); + i = i >> 1; + } + } + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF); + gen_regsSR = gen_regsSR | + ((i>>8) & SF) | + ((i) ? 0 : ZF); + parityW(i); + return i; +} + +unsigned long MyRrL(unsigned long i, unsigned char nr) +{ + nr = ((nr) ? nr : 16); + for(;nr>0;nr--) + { + if (gen_regsSR & CF) + { + gen_regsSR = (gen_regsSR & ~CF) | (i & CF); + i = (i >> 1)|0x80000000; + } + else + { + gen_regsSR = (gen_regsSR & ~CF) | (i & CF); + i = i >> 1; + } + state+= 2; + } + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF); + gen_regsSR = gen_regsSR | + ((i>>24) & SF) | + ((i) ? 0 : ZF); + parityL(i); + return i; +} + +int rr4rB() +{ + *regB = MyRrB(*regB,readbyte()); + return 6; +} +int rr4rW() +{ + *regW = MyRrW(*regW,readbyte()); + return 6; +} +int rr4rL() +{ + *regL = MyRrL(*regL,readbyte()); + return 8; +} +int rrArB() +{ + *regB = MyRrB(*regB,*cregsB[1] & 0x0F); + return 6; +} +int rrArW() +{ + *regW = MyRrW(*regW,*cregsB[1] & 0x0F); + return 6; +} +int rrArL() +{ + *regL = MyRrL(*regL,*cregsB[1] & 0x0F); + return 8; +} +int rrM00() +{ + mem_writeB(mem,MyRrB(memB,1)); + return 8; +} +int rrwM10() +{ + mem_writeW(mem,MyRrW(memW,1)); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// SLA /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +unsigned char MySlaB(unsigned char i, unsigned char nr) +{ + nr = ((nr) ? nr : 16); + for(;nr>0;nr--) + { + if (i&0x80) + gen_regsSR|= CF; + else + gen_regsSR&= ~CF; + i = i << 1; + } + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF); + gen_regsSR = gen_regsSR | + (i & SF) | + ((i) ? 0 : ZF) +#ifdef USE_PARITY_TABLE + | parityVtable[i]; +#else + ; + parityB(i); +#endif + + return i; +} + +unsigned short MySlaW(unsigned short i, unsigned char nr) +{ + nr = ((nr) ? nr : 16); + for(;nr>0;nr--) + { + if (i&0x8000) + gen_regsSR|= CF; + else + gen_regsSR&= ~CF; + i = i << 1; + } + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF); + gen_regsSR = gen_regsSR | + ((i>>8) & SF) | + ((i) ? 0 : ZF); + parityW(i); + return i; +} + +unsigned long MySlaL(unsigned long i, unsigned char nr) +{ + nr = ((nr) ? nr : 16); + for(;nr>0;nr--) + { + if (i&0x80000000) + gen_regsSR|= CF; + else + gen_regsSR&= ~CF; + i = i << 1; + state+= 2; + } + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF); + gen_regsSR = gen_regsSR | + ((i>>24) & SF) | + ((i) ? 0 : ZF); + parityL(i); + return i; +} + +int sla4rB() +{ + *regB = MySlaB(*regB,readbyte()); + return 6; +} +int sla4rW() +{ + *regW = MySlaW(*regW,readbyte()); + return 6; +} +int sla4rL() +{ + *regL = MySlaL(*regL,readbyte()); + return 8; +} +int slaArB() +{ + *regB = MySlaB(*regB,*cregsB[1] & 0x0F); + return 6; +} +int slaArW() +{ + *regW = MySlaW(*regW,*cregsB[1] & 0x0F); + return 6; +} +int slaArL() +{ + *regL = MySlaL(*regL,*cregsB[1] & 0x0F); + return 8; +} +int slaM00() +{ + mem_writeB(mem,MySlaB(memB,1)); + return 8; +} +int slawM10() +{ + mem_writeW(mem,MySlaW(memW,1)); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// SRA /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +inline unsigned char MySraB(unsigned char i, unsigned char nr) +{ + nr = ((nr) ? nr : 16); + for(;nr>0;nr--) + { + gen_regsSR = (gen_regsSR & ~CF) | (i & CF); + if (i&0x80) + i = (i >> 1)|0x80; + else + i = i >> 1; + } + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF); + gen_regsSR = gen_regsSR | + (i & SF) | + ((i) ? 0 : ZF) +#ifdef USE_PARITY_TABLE + | parityVtable[i]; +#else + ; + parityB(i); +#endif + + return i; +} + +inline unsigned short MySraW(unsigned short i, unsigned char nr) +{ + nr = ((nr) ? nr : 16); + for(;nr>0;nr--) + { + gen_regsSR = (gen_regsSR & ~CF) | (i & CF); + if (i&0x8000) + i = (i >> 1)|0x8000; + else + i = i >> 1; + } + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF); + gen_regsSR = gen_regsSR | + ((i>>8) & SF) | + ((i) ? 0 : ZF); + parityW(i); + return i; +} + +inline unsigned long MySraL(unsigned long i, unsigned char nr) +{ + nr = ((nr) ? nr : 16); + for(;nr>0;nr--) + { + gen_regsSR = (gen_regsSR & ~CF) | (i & CF); + if (i&0x80000000) + i = (i >> 1)|0x80000000; + else + i = i >> 1; + state+= 2; + } + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF); + gen_regsSR = gen_regsSR | + ((i>>24) & SF) | + ((i) ? 0 : ZF); + parityL(i); + return i; +} + +int sra4rB() +{ + *regB = MySraB(*regB,readbyte()); + return 6; +} +int sra4rW() +{ + *regW = MySraW(*regW,readbyte()); + return 6; +} +int sra4rL() +{ + *regL = MySraL(*regL,readbyte()); + return 8; +} +int sraArB() +{ + *regB = MySraB(*regB,*cregsB[1] & 0x0F); + return 6; +} +int sraArW() +{ + *regW = MySraW(*regW,*cregsB[1] & 0x0F); + return 6; +} +int sraArL() +{ + *regL = MySraL(*regL,*cregsB[1] & 0x0F); + return 8; +} +int sraM00() +{ + mem_writeB(mem,MySraB(memB,1)); + return 8; +} +int srawM10() +{ + mem_writeW(mem,MySraW(memW,1)); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// SLL /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int sll4rB() +{ + *regB = MySlaB(*regB,readbyte()); + return 6; +} +int sll4rW() +{ + *regW = MySlaW(*regW,readbyte()); + return 6; +} +int sll4rL() +{ + *regL = MySlaL(*regL,readbyte()); + return 8; +} +int sllArB() +{ + *regB = MySlaB(*regB,*cregsB[1] & 0x0F); + return 6; +} +int sllArW() +{ + *regW = MySlaW(*regW,*cregsB[1] & 0x0F); + return 6; +} +int sllArL() +{ + *regL = MySlaL(*regL,*cregsB[1] & 0x0F); + return 8; +} +int sllM00() +{ + mem_writeB(mem,MySlaB(memB,1)); + return 8; +} +int sllwM10() +{ + mem_writeW(mem,MySlaW(memW,1)); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// SRL /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +inline unsigned char MySrlB(unsigned char i, unsigned char nr) +{ + nr = ((nr) ? nr : 16); + for(;nr>0;nr--) + { + gen_regsSR = (gen_regsSR & ~CF) | (i & CF); + i = i >> 1; + } + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF); + gen_regsSR = gen_regsSR | + (i & SF) | + ((i) ? 0 : ZF) +#ifdef USE_PARITY_TABLE + | parityVtable[i]; +#else + ; + parityB(i); +#endif + + return i; +} + +inline unsigned short MySrlW(unsigned short i, unsigned char nr) +{ + nr = ((nr) ? nr : 16); + for(;nr>0;nr--) + { + gen_regsSR = (gen_regsSR & ~CF) | (i & CF); + i = i >> 1; + } + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF); + gen_regsSR = gen_regsSR | + ((i>>8) & SF) | + ((i) ? 0 : ZF); + parityW(i); + return i; +} + +inline unsigned long MySrlL(unsigned long i, unsigned char nr) +{ + nr = ((nr) ? nr : 16); + for(;nr>0;nr--) + { + gen_regsSR = (gen_regsSR & ~CF) | (i & CF); + i = i >> 1; + state+= 2; + } + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF); + gen_regsSR = gen_regsSR | + ((i>>24) & SF) | + ((i) ? 0 : ZF); + parityL(i); + return i; +} + +int srl4rB() +{ + *regB = MySrlB(*regB,readbyte()); + return 6; +} +int srl4rW() +{ + *regW = MySrlW(*regW,readbyte()); + return 6; +} +int srl4rL() +{ + *regL = MySrlL(*regL,readbyte()); + return 8; +} +int srlArB() +{ + *regB = MySrlB(*regB,*cregsB[1] & 0x0F); + return 6; +} +int srlArW() +{ + *regW = MySrlW(*regW,*cregsB[1] & 0x0F); + return 6; +} +int srlArL() +{ + *regL = MySrlL(*regL,*cregsB[1] & 0x0F); + return 8; +} +int srlM00() +{ + mem_writeB(mem,MySrlB(memB,1)); + return 8; +} +int srlwM10() +{ + mem_writeW(mem,MySrlW(memW,1)); + return 8; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// RxD /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int rld00() // RLD A,(mem) 10000mmm 00000110 +{ + unsigned char i,j; + + i = memB; + j = (*cregsB[1])&0x0f; + *cregsB[1] = ((*cregsB[1])&0xf0)|((i&0xf0)>>4); + mem_writeB(mem,((i&0x0f)<<4)|j); + // update flags + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + (*cregsB[1] & SF) | + ((*cregsB[1]) ? 0 : ZF) +#ifdef USE_PARITY_TABLE + | parityVtable[*cregsB[1]]; +#else + ; + parityB(*cregsB[1]); +#endif + + return 12; +} + +int rrd00() // RRD A,(mem) 10000mmm 00000111 +{ + unsigned char i,j; + + i = memB; + j = (*cregsB[1])&0x0f; + *cregsB[1] = ((*cregsB[1])&0xf0)|(i&0x0f); + mem_writeB(mem,((i>>4)|(j<<4))); + // update flags + gen_regsSR = gen_regsSR & ~(SF|ZF|HF|VF|NF|CF); + gen_regsSR = gen_regsSR | + (*cregsB[1] & SF) | + ((*cregsB[1]) ? 0 : ZF) +#ifdef USE_PARITY_TABLE + | parityVtable[*cregsB[1]]; +#else + ; + parityB(*cregsB[1]); +#endif + return 12; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// JP/JR ///////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int jp16() // JP #16 00011010 xxxxxxxx xxxxxxxx +{ + gen_regsPC = readword(); + my_pc = get_address(gen_regsPC); + return 7; +} + +int jp24() // JP #24 00011011 xxxxxxxx xxxxxxxx xxxxxxxx +{ + gen_regsPC = read24(); + my_pc = get_address(gen_regsPC); + return 7; +} + +int jrcc0() // JR cc,$+2+d8 0110cccc xxxxxxxx +{ + /* + //cond0 always false + if (cond0()) + { + doJumpByte(); + return 8; + } +*/ + skipJumpByte(); + return 4; +} + +int jrcc1() // JR cc,$+2+d8 0110cccc xxxxxxxx +{ + if (cond1()) + { + doJumpByte(); + return 8; + } + + skipJumpByte(); + return 4; +} + +int jrcc2() // JR cc,$+2+d8 0110cccc xxxxxxxx +{ + if (cond2()) + { + doJumpByte(); + return 8; + } + + skipJumpByte(); + return 4; +} + +int jrcc3() // JR cc,$+2+d8 0110cccc xxxxxxxx +{ + if (cond3()) + { + doJumpByte(); + return 8; + } + + skipJumpByte(); + return 4; +} + +int jrcc4() // JR cc,$+2+d8 0110cccc xxxxxxxx +{ + if (cond4()) + { + doJumpByte(); + return 8; + } + + skipJumpByte(); + return 4; +} + +int jrcc5() // JR cc,$+2+d8 0110cccc xxxxxxxx +{ + if (cond5()) + { + doJumpByte(); + return 8; + } + + skipJumpByte(); + return 4; +} + +int jrcc6() // JR cc,$+2+d8 0110cccc xxxxxxxx +{ + if (cond6()) + { + doJumpByte(); + return 8; + } + skipJumpByte(); + return 4; +} + +int jrcc7() // JR cc,$+2+d8 0110cccc xxxxxxxx +{ + if (cond7()) + { + doJumpByte(); + return 8; + } + + skipJumpByte(); + return 4; +} + +int jrcc8() // JR cc,$+2+d8 0110cccc xxxxxxxx +{ + //if (cond8())//cond8 is always TRUE + //{ + doJumpByte(); + return 8; + //} + + //skipJumpByte(); + //return 4; +} + +int jrcc9() // JR cc,$+2+d8 0110cccc xxxxxxxx +{ + if(notCond9()) + { + skipJumpByte(); + return 4; + } + + doJumpByte(); + return 8; +} + +int jrccA() // JR cc,$+2+d8 0110cccc xxxxxxxx +{ + if(notCondA()) + { + skipJumpByte(); + return 4; + } + + doJumpByte(); + return 8; +} + +int jrccB() // JR cc,$+2+d8 0110cccc xxxxxxxx +{ + if(notCondB()) + { + skipJumpByte(); + return 4; + } + + doJumpByte(); + return 8; +} + +int jrccC() // JR cc,$+2+d8 0110cccc xxxxxxxx +{ + if(notCondC()) + { + skipJumpByte(); + return 4; + } + + doJumpByte(); + return 8; +} + +int jrccD() // JR cc,$+2+d8 0110cccc xxxxxxxx +{ + if(notCondD()) + { + skipJumpByte(); + return 4; + } + + doJumpByte(); + return 8; +} + +int jrccE() // JR cc,$+2+d8 0110cccc xxxxxxxx +{ + if (notCondE()) + { + // no need to read + skipJumpByte(); + return 4; + } + doJumpByte(); + return 8; +} + +int jrccF() // JR cc,$+2+d8 0110cccc xxxxxxxx +{ + if(notCondF()) + { + skipJumpByte(); + return 4; + } + + doJumpByte(); + return 8; +} + +int jrlcc0() // JR cc,$+2+d16 0110cccc xxxxxxxx +{ + /* + //cond0 always false + if (cond0()) + { + doJumpWord(); + return 8; + } +*/ + skipJumpWord(); + return 4; +} + +int jrlcc1() // JR cc,$+2+d16 0110cccc xxxxxxxx +{ + if (cond1()) + { + doJumpWord(); + return 8; + } + + skipJumpWord(); + return 4; +} + +int jrlcc2() // JR cc,$+2+d16 0110cccc xxxxxxxx +{ + if (cond2()) + { + doJumpWord(); + return 8; + } + + skipJumpWord(); + return 4; +} + +int jrlcc3() // JR cc,$+2+d16 0110cccc xxxxxxxx +{ + if (cond3()) + { + doJumpWord(); + return 8; + } + + skipJumpWord(); + return 4; +} + +int jrlcc4() // JR cc,$+2+d16 0110cccc xxxxxxxx +{ + if (cond4()) + { + doJumpWord(); + return 8; + } + + skipJumpWord(); + return 4; +} + +int jrlcc5() // JR cc,$+2+d16 0110cccc xxxxxxxx +{ + if (cond5()) + { + doJumpWord(); + return 8; + } + + skipJumpWord(); + return 4; +} + +int jrlcc6() // JR cc,$+2+d16 0110cccc xxxxxxxx +{ + if (cond6()) + { + doJumpWord(); + return 8; + } + + skipJumpWord(); + return 4; +} + +int jrlcc7() // JR cc,$+2+d16 0110cccc xxxxxxxx +{ + if (cond7()) + { + doJumpWord(); + return 8; + } + + skipJumpWord(); + return 4; +} + +int jrlcc8() // JR cc,$+2+d16 0110cccc xxxxxxxx +{ + //if (cond8()) //cond8 is always TRUE + //{ + doJumpWord(); + return 8; + //} + + //skipJumpWord(); + //return 4; +} + +int jrlcc9() // JR cc,$+2+d16 0110cccc xxxxxxxx +{ + if (notCond9()) + { + skipJumpWord(); + return 4; + } + + doJumpWord(); + return 8; +} + +int jrlccA() // JR cc,$+2+d16 0110cccc xxxxxxxx +{ + if (notCondA()) + { + skipJumpWord(); + return 4; + } + + doJumpWord(); + return 8; +} + +int jrlccB() // JR cc,$+2+d16 0110cccc xxxxxxxx +{ + if (notCondB()) + { + skipJumpWord(); + return 4; + } + + doJumpWord(); + return 8; +} + +int jrlccC() // JR cc,$+2+d16 0110cccc xxxxxxxx +{ + if (notCondC()) + { + skipJumpWord(); + return 4; + } + + doJumpWord(); + return 8; +} + +int jrlccD() // JR cc,$+2+d16 0110cccc xxxxxxxx +{ + if (notCondD()) + { + skipJumpWord(); + return 4; + } + + doJumpWord(); + return 8; +} + +int jrlccE() // JR cc,$+2+d16 0110cccc xxxxxxxx +{ + //Thor + if (notCondE()) + { + skipJumpWord(); + return 4; + } + doJumpWord(); + return 8; +} + +int jrlccF() // JR cc,$+2+d16 0110cccc xxxxxxxx +{ + if (notCondF()) + { + skipJumpWord(); + return 4; + } + + doJumpWord(); + return 8; +} + +int jpccM300() // JP cc,mem +{ + /* + //cond0 always false + if (cond0()) + { + gen_regsPC = mem; + my_pc = get_address(gen_regsPC); + return 8; + } + else +*/ + return 4; +} + +int jpccM301() // JP cc,mem +{ + if (cond1()) + { + gen_regsPC = mem; + my_pc = get_address(gen_regsPC); + return 8; + } + else + return 4; +} + +int jpccM302() // JP cc,mem +{ + if (cond2()) + { + gen_regsPC = mem; + my_pc = get_address(gen_regsPC); + return 8; + } + else + return 4; +} + +int jpccM303() // JP cc,mem +{ + if (cond3()) + { + gen_regsPC = mem; + my_pc = get_address(gen_regsPC); + return 8; + } + else + return 4; +} + +int jpccM304() // JP cc,mem +{ + if (cond4()) + { + gen_regsPC = mem; + my_pc = get_address(gen_regsPC); + return 8; + } + else + return 4; +} + +int jpccM305() // JP cc,mem +{ + if (cond5()) + { + gen_regsPC = mem; + my_pc = get_address(gen_regsPC); + return 8; + } + else + return 4; +} + +int jpccM306() // JP cc,mem +{ + if (gen_regsSR & ZF)//cond6()) + { + gen_regsPC = mem; + my_pc = get_address(gen_regsPC); + return 8; + } + else + return 4; +} + +int jpccM307() // JP cc,mem +{ + if (gen_regsSR & CF)//cond7()) + { + gen_regsPC = mem; + my_pc = get_address(gen_regsPC); + return 8; + } + else + return 4; +} + +int jpccM308() // JP cc,mem +{ + //if (cond8()) //always TRUE + //{ + gen_regsPC = mem; + my_pc = get_address(gen_regsPC); + return 8; + //} + //else + // return 4; +} + +int jpccM309() // JP cc,mem +{ + if (notCond9()) + { + return 4; + } + + gen_regsPC = mem; + my_pc = get_address(gen_regsPC); + return 8; +} + +int jpccM30A() // JP cc,mem +{ + if (notCondA()) + { + return 4; + } + + gen_regsPC = mem; + my_pc = get_address(gen_regsPC); + return 8; +} + +int jpccM30B() // JP cc,mem +{ + if (notCondB()) + { + return 4; + } + + gen_regsPC = mem; + my_pc = get_address(gen_regsPC); + return 8; +} + +int jpccM30C() // JP cc,mem +{ + if (notCondC()) + { + return 4; + } + + gen_regsPC = mem; + my_pc = get_address(gen_regsPC); + return 8; +} + +int jpccM30D() // JP cc,mem +{ + if (notCondD()) + { + return 4; + } + + gen_regsPC = mem; + my_pc = get_address(gen_regsPC); + return 8; +} + +int jpccM30E() // JP cc,mem +{ + if (notCondE()) + { + return 4; + } + + gen_regsPC = mem; + my_pc = get_address(gen_regsPC); + return 8; +} + +int jpccM30F() // JP cc,mem +{ + if (notCondF()) + { + return 4; + } + + gen_regsPC = mem; + my_pc = get_address(gen_regsPC); + return 8; +} + + + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// CALL ////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int call16() // CALL #16 00011100 xxxxxxxx xxxxxxxx +{ + unsigned long address = readword(); + + tlcsFastMemWriteL(gen_regsXSP-=4,gen_regsPC); + my_pc = get_address(gen_regsPC = address); + return 12; +} + +int call24() // CALL #24 00011101 xxxxxxxx xxxxxxxx xxxxxxxx +{ + unsigned long address = read24(); + + tlcsFastMemWriteL(gen_regsXSP-=4,gen_regsPC); + my_pc = get_address(gen_regsPC = address); + return 12; +} + +int calr() // CALR $+3+d16 00011110 xxxxxxxx xxxxxxxx +{ + signed short d16 = readword(); + + tlcsFastMemWriteL(gen_regsXSP-=4,gen_regsPC); + gen_regsPC+= d16; + my_pc+= d16; + return 12; +} + +int callccM300() // CALL cc,mem 10110mmm 1110cccc +{ + /* + //cond0 always false + if (cond0()) + { + tlcsFastMemWriteL(gen_regsXSP-=4,gen_regsPC); + my_pc = get_address(gen_regsPC = mem); + return 12; + } + else +*/ + return 6; +} + +int callccM301() // CALL cc,mem 10110mmm 1110cccc +{ + if (cond1()) + { + tlcsFastMemWriteL(gen_regsXSP-=4,gen_regsPC); + my_pc = get_address(gen_regsPC = mem); + return 12; + } + else + return 6; +} + +int callccM302() // CALL cc,mem 10110mmm 1110cccc +{ + if (cond2()) + { + tlcsFastMemWriteL(gen_regsXSP-=4,gen_regsPC); + my_pc = get_address(gen_regsPC = mem); + return 12; + } + else + return 6; +} + +int callccM303() // CALL cc,mem 10110mmm 1110cccc +{ + if (cond3()) + { + tlcsFastMemWriteL(gen_regsXSP-=4,gen_regsPC); + my_pc = get_address(gen_regsPC = mem); + return 12; + } + else + return 6; +} + +int callccM304() // CALL cc,mem 10110mmm 1110cccc +{ + if (cond4()) + { + tlcsFastMemWriteL(gen_regsXSP-=4,gen_regsPC); + my_pc = get_address(gen_regsPC = mem); + return 12; + } + else + return 6; +} + +int callccM305() // CALL cc,mem 10110mmm 1110cccc +{ + if (cond5()) + { + tlcsFastMemWriteL(gen_regsXSP-=4,gen_regsPC); + my_pc = get_address(gen_regsPC = mem); + return 12; + } + else + return 6; +} + +int callccM306() // CALL cc,mem 10110mmm 1110cccc +{ + if (gen_regsSR & ZF)//cond6()) + { + tlcsFastMemWriteL(gen_regsXSP-=4,gen_regsPC); + my_pc = get_address(gen_regsPC = mem); + return 12; + } + else + return 6; +} + +int callccM307() // CALL cc,mem 10110mmm 1110cccc +{ + if (gen_regsSR & CF)//cond7()) + { + tlcsFastMemWriteL(gen_regsXSP-=4,gen_regsPC); + my_pc = get_address(gen_regsPC = mem); + return 12; + } + else + return 6; +} + +int callccM308() // CALL cc,mem 10110mmm 1110cccc +{ + //if (cond8())//always TRUE + //{ + tlcsFastMemWriteL(gen_regsXSP-=4,gen_regsPC); + my_pc = get_address(gen_regsPC = mem); + return 12; + //} + //else + // return 6; +} + +int callccM309() // CALL cc,mem 10110mmm 1110cccc +{ + if (notCond9()) + return 6; + + tlcsFastMemWriteL(gen_regsXSP-=4,gen_regsPC); + my_pc = get_address(gen_regsPC = mem); + return 12; +} + +int callccM30A() // CALL cc,mem 10110mmm 1110cccc +{ + if (notCondA()) + return 6; + + tlcsFastMemWriteL(gen_regsXSP-=4,gen_regsPC); + my_pc = get_address(gen_regsPC = mem); + return 12; +} + +int callccM30B() // CALL cc,mem 10110mmm 1110cccc +{ + if (notCondB()) + return 6; + + tlcsFastMemWriteL(gen_regsXSP-=4,gen_regsPC); + my_pc = get_address(gen_regsPC = mem); + return 12; +} + +int callccM30C() // CALL cc,mem 10110mmm 1110cccc +{ + if (notCondC()) + return 6; + + tlcsFastMemWriteL(gen_regsXSP-=4,gen_regsPC); + my_pc = get_address(gen_regsPC = mem); + return 12; +} + +int callccM30D() // CALL cc,mem 10110mmm 1110cccc +{ + if (notCondD()) + return 6; + + tlcsFastMemWriteL(gen_regsXSP-=4,gen_regsPC); + my_pc = get_address(gen_regsPC = mem); + return 12; +} + +int callccM30E() // CALL cc,mem 10110mmm 1110cccc +{ + if (notCondE()) + return 6; + + tlcsFastMemWriteL(gen_regsXSP-=4,gen_regsPC); + my_pc = get_address(gen_regsPC = mem); + return 12; +} + +int callccM30F() // CALL cc,mem 10110mmm 1110cccc +{ + if (notCondF()) + return 6; + + tlcsFastMemWriteL(gen_regsXSP-=4,gen_regsPC); + my_pc = get_address(gen_regsPC = mem); + return 12; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// DJNZ ////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int djnzB() // DJNZ r,$+3+d8 11001rrr 00011100 xxxxxxxx +{ + if (--*regB) + { + signed char d8 = readbyte(); + gen_regsPC+= d8; + my_pc+= d8; + return 11; + } + else + { + ++gen_regsPC; + ++my_pc; + return 7; + } +} + +int djnzW() // DJNZ r,$+3+d8 11011rrr 00011100 xxxxxxxx +{ + if (--*regW) + { + signed char d8 = readbyte(); + gen_regsPC+= d8; + my_pc+= d8; + return 11; + } + else + { + ++gen_regsPC; + ++my_pc; + return 7; + } +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// RET /////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int ret() // RET 00001110 +{ + gen_regsPC = mem_readL(gen_regsXSP); + my_pc = get_address(gen_regsPC); + gen_regsXSP+= 4; + return 9; +} + +int retcc0() // RET cc 10110000 1111cccc +{ + /* + //cond0 always false + if (cond0()) + { + gen_regsPC = mem_readL(gen_regsXSP); + gen_regsXSP+= 4; + my_pc = get_address(gen_regsPC); + return 12; + } + else +*/ + return 6; +} + +int retcc1() // RET cc 10110000 1111cccc +{ + if (cond1()) + { + gen_regsPC = mem_readL(gen_regsXSP); + gen_regsXSP+= 4; + my_pc = get_address(gen_regsPC); + return 12; + } + else + return 6; +} + +int retcc2() // RET cc 10110000 1111cccc +{ + if (cond2()) + { + gen_regsPC = mem_readL(gen_regsXSP); + gen_regsXSP+= 4; + my_pc = get_address(gen_regsPC); + return 12; + } + else + return 6; +} + +int retcc3() // RET cc 10110000 1111cccc +{ + if (cond3()) + { + gen_regsPC = mem_readL(gen_regsXSP); + gen_regsXSP+= 4; + my_pc = get_address(gen_regsPC); + return 12; + } + else + return 6; +} + +int retcc4() // RET cc 10110000 1111cccc +{ + if (cond4()) + { + gen_regsPC = mem_readL(gen_regsXSP); + gen_regsXSP+= 4; + my_pc = get_address(gen_regsPC); + return 12; + } + else + return 6; +} + +int retcc5() // RET cc 10110000 1111cccc +{ + if (cond5()) + { + gen_regsPC = mem_readL(gen_regsXSP); + gen_regsXSP+= 4; + my_pc = get_address(gen_regsPC); + return 12; + } + else + return 6; +} + +int retcc6() // RET cc 10110000 1111cccc +{ + if (gen_regsSR & ZF)//cond6()) + { + gen_regsPC = mem_readL(gen_regsXSP); + gen_regsXSP+= 4; + my_pc = get_address(gen_regsPC); + return 12; + } + else + return 6; +} + +int retcc7() // RET cc 10110000 1111cccc +{ + if (gen_regsSR & CF)//cond7()) + { + gen_regsPC = mem_readL(gen_regsXSP); + gen_regsXSP+= 4; + my_pc = get_address(gen_regsPC); + return 12; + } + else + return 6; +} + +int retcc8() // RET cc 10110000 1111cccc +{ + //if (cond8())//always TRUE + //{ + gen_regsPC = mem_readL(gen_regsXSP); + gen_regsXSP+= 4; + my_pc = get_address(gen_regsPC); + return 12; + //} + //else + // return 6; +} + +int retcc9() // RET cc 10110000 1111cccc +{ + if (cond9()) + { + gen_regsPC = mem_readL(gen_regsXSP); + gen_regsXSP+= 4; + my_pc = get_address(gen_regsPC); + return 12; + } + else + return 6; +} + +int retccA() // RET cc 10110000 1111cccc +{ + if (condA()) + { + gen_regsPC = mem_readL(gen_regsXSP); + gen_regsXSP+= 4; + my_pc = get_address(gen_regsPC); + return 12; + } + else + return 6; +} + +int retccB() // RET cc 10110000 1111cccc +{ + if (condB()) + { + gen_regsPC = mem_readL(gen_regsXSP); + gen_regsXSP+= 4; + my_pc = get_address(gen_regsPC); + return 12; + } + else + return 6; +} + +int retccC() // RET cc 10110000 1111cccc +{ + if (condC()) + { + gen_regsPC = mem_readL(gen_regsXSP); + gen_regsXSP+= 4; + my_pc = get_address(gen_regsPC); + return 12; + } + else + return 6; +} + +int retccD() // RET cc 10110000 1111cccc +{ + if (condD()) + { + gen_regsPC = mem_readL(gen_regsXSP); + gen_regsXSP+= 4; + my_pc = get_address(gen_regsPC); + return 12; + } + else + return 6; +} + +int retccE() // RET cc 10110000 1111cccc +{ + if (notCondE()) + return 6; + gen_regsPC = mem_readL(gen_regsXSP); + gen_regsXSP+= 4; + my_pc = get_address(gen_regsPC); + return 12; +} + +int retccF() // RET cc 10110000 1111cccc +{ + if (condF()) + { + gen_regsPC = mem_readL(gen_regsXSP); + gen_regsXSP+= 4; + my_pc = get_address(gen_regsPC); + return 12; + } + else + return 6; +} + +int retd() // RETD d16 00001111 xxxxxxxx xxxxxxxx +{ + signed short d16 = readword(); + + gen_regsPC = mem_readL(gen_regsXSP); + my_pc = get_address(gen_regsPC); + gen_regsXSP+= d16 + 4; + return 9; +} + +int reti() // RETI 00000111 +{ +#ifdef TARGET_GP2X + register byte *gA asm("r4"); + register unsigned long localXSP = gen_regsXSP; + + gA = get_address(localXSP); + localXSP += 6; + gen_regsXSP = localXSP; + + + if(gA == 0) + { + gen_regsSR = gen_regsPC = 0; + } + else + { + asm volatile( + "ldrb %0, [%2], #1\n" + "ldrb r2, [%2], #1\n" + "orr %0, %0, r2, asl #8\n" + "bic r1,%2,#3 \n" + "ldmia r1,{r0,r3} \n" + "ands r1,%2,#3 \n" + "movne r2,r1,lsl #3 \n" + "movne r0,r0,lsr r2 \n" + "rsbne r1,r2,#32 \n" + "orrne r0,r0,r3,lsl r1\n" + "mov %1,r0" + : "=r"(gen_regsSR), "=r"(gen_regsPC) + : "r"(gA) + : "r0", "r1","r2","r3"); + } + +#else + gen_regsSR = mem_readW(gen_regsXSP); + gen_regsXSP+= 2; + gen_regsPC = mem_readL(gen_regsXSP); + gen_regsXSP+= 4; +#endif + + my_pc = get_address(gen_regsPC); + set_cregs(); + + return 12; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// undefined ///////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int udef() +{ + //dbg_print("*** Call to udef() in tlcs900h core ***\n"); + m_bIsActive = false; + return 1; +} + +////////////////////////////////////////////////////////////////////////////// +//////////////////////////////// BIOS calls ///////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +inline int VECT_SHUTDOWN() +{ + return 10; +} + +inline int VECT_CLOCKGEARSET(unsigned char speed, unsigned char regen) +{ + switch(speed) + { + case 0: + tlcsClockMulti = 1; + break; + case 1: + tlcsClockMulti = 2; + break; + case 2: + tlcsClockMulti = 4; + break; + case 3: + tlcsClockMulti = 8; + break; + case 4: + tlcsClockMulti = 16; + break; + } + return 10; +} + +inline unsigned char makeBCD(int i) +{ + int upper; + + if (i>=99) + return 0x99; + upper = i/10; + return (upper<<4)|(i-(upper*10)); +} + +extern "C" int sceUtilityGetSystemParamInt (int id, int *value); + +void initTimezone() +{ +#ifdef TARGET_PSP +#define PSP_SYSTEMPARAM_ID_INT_TIMEZONE 6 + static int tzInit=0; + + if(!tzInit) + { + int tzOffset = 0; + tzInit=1; + sceUtilityGetSystemParamInt (PSP_SYSTEMPARAM_ID_INT_TIMEZONE, &tzOffset); + int tzOffsetAbs = tzOffset < 0 ? -tzOffset : tzOffset; + int hours = tzOffsetAbs / 60; + int minutes = tzOffsetAbs - hours * 60; + static char tz[10]; + sprintf (tz, "GMT%s%02i:%02i", tzOffset < 0 ? "+" : "-", hours, minutes); + setenv ("TZ", tz, 1); + tzset (); + } +#else + tzset();//prob need more than just this +#endif +} + + +inline int VECT_RTCGET(unsigned int dest) +{ + // dest+0 // year + // dest+1 // month all in BCD + // dest+2 // day + // dest+3 // hours + // dest+4 // minutes + // dest+5 // nr year after leap : day of the week + unsigned char *d = get_address(dest); + + time_t now; + tm *lt; +#ifdef TARGET_PSP + sceKernelLibcTime(&now); +#else + now = time(NULL); +#endif + initTimezone(); //make sure TZ is set up + lt = localtime(&now); + //int year = (lt->tm_year+1900) % 100; + int year = lt->tm_year-100; + + d[0] = makeBCD(year); + d[1] = makeBCD(lt->tm_mon+1); + d[2] = makeBCD(lt->tm_mday); + d[3] = makeBCD(lt->tm_hour); + d[4] = makeBCD(lt->tm_min); + d[5] = makeBCD(lt->tm_sec); + d[6] = ((year % 4)<<4)|(lt->tm_wday & 0x0F); + + return 100; +} + + +inline int VECT_INTLVSET(unsigned char interrupt, unsigned char level) +{ + // 0 - Interrupt from RTC alarm + // 1 - Interrupt from the Z80 CPU + // 2 - Interrupt from the 8 bit timer 0 + // 3 - Interrupt from the 8 bit timer 1 + // 4 - Interrupt from the 8 bit timer 2 + // 5 - Interrupt from the 8 bit timer 3 + // 6 - End of transfer interrupt from DMA channel 0 + // 7 - End of transfer interrupt from DMA channel 1 + // 8 - End of transfer interrupt from DMA channel 2 + // 9 - End of transfer interrupt from DMA channel 3 + switch(interrupt) + { + case 0x00: + cpuram[0x70] = (cpuram[0x70] & 0xf0) | (level & 0x07); + break; + case 0x01: + cpuram[0x71] = (cpuram[0x71] & 0x0f) | ((level & 0x07)<<4); + break; + case 0x02: + cpuram[0x73] = (cpuram[0x73] & 0xf0) | (level & 0x07); + break; + case 0x03: + cpuram[0x73] = (cpuram[0x73] & 0x0f) | ((level & 0x07)<<4); + break; + case 0x04: + cpuram[0x74] = (cpuram[0x74] & 0xf0) | (level & 0x07); + break; + case 0x05: + cpuram[0x74] = (cpuram[0x74] & 0x0f) | ((level & 0x07)<<4); + break; + case 0x06: + cpuram[0x79] = (cpuram[0x79] & 0xf0) | (level & 0x07); + break; + case 0x07: + cpuram[0x79] = (cpuram[0x79] & 0x0f) | ((level & 0x07)<<4); + break; + case 0x08: + cpuram[0x7a] = (cpuram[0x7a] & 0xf0) | (level & 0x07); + break; + case 0x09: + cpuram[0x7a] = (cpuram[0x7a] & 0x0f) | ((level & 0x07)<<4); + break; + } + return 100; +} + +inline int VECT_SYSFONTSET(unsigned char parms) +{ + ngpBiosSYSFONTSET(get_address(0xA000),(parms>>4)&0x03,parms&0x03); + return 100; +} + +inline int VECT_ALARMSET(unsigned char day, unsigned char hour, unsigned char minute, unsigned char *result) +{ + *result = 0; // SYS_SUCCESS + return 100; +} + +inline int VECT_FLASHWRITE(unsigned char chip, unsigned short size, unsigned int from, unsigned int to, unsigned char *result) +{ + unsigned char *fromAddr; + //toAddr = get_address(((chip) ? 0x00800000 : 0x00200000)+to); + fromAddr = get_address(from); + + vectFlashWrite(chip, to, fromAddr, size * 256); + + *result = 0; + return 100; +} + +inline int VECT_FLASHERS(unsigned char chip, unsigned char blockNum, unsigned char *result) +{ + vectFlashErase(chip, blockNum); + *result = 0; + return 100; +} + +inline int VECT_FLASHALLERS(unsigned char chip, unsigned char *result) +{ + vectFlashChipErase(chip); + *result = 0; + return 100; +} + +inline int VECT_GEMODESET(unsigned char mode) +{ + mem_writeB(0x87F0,0xAA); // allow GE MODE registers to be written to + if (mode < 0x10) + { + // set B/W mode + mem_writeB(0x87E2,0x80); + mem_writeB(0x6F95,0x00); + } + else + { + // set color mode + mem_writeB(0x87E2,0x00); + mem_writeB(0x6F95,0x10); + } + mem_writeB(0x87F0,0x55); // disallow GE MODE registers to be written to + return 20; +} + +// execute a bios function +inline int doBios(unsigned char biosNr) +{ + switch (biosNr) + { + case 0x00: + // VECT_SHUTDOWN + // Power off the Neogeo pocket unit + // no params, no result + return VECT_SHUTDOWN(); + case 0x01: + // VECT_CLOCKGEARSET + // Change the CPU speed of the Neogeo Pocket + // param: RB3 - Set Clock Speed + // 00 - 6.144 MHz + // 01 - 3.072 MHz + // 02 - 1.536 MHz + // 03 - .768 MHz + // 04 - .384 MHz + // param: RC3 - Auto clock speed regeneration with panel switch input + // 0 - No + // !0 - Yes + return VECT_CLOCKGEARSET(*allregsB[0x35], *allregsB[0x34]); + break; + case 0x02: // VECT_RTCGET + // Obtain real time clock information + // param: XHL3 + // data written: + // +0 : Year (00-90 = 2000-2090, 91-99 = 1991 - 1999) + // +1 : Month (1 - 12) + // +2 : Day (1-31) + // +3 : Hour (0 - 23) + // +4 : Minute (0 - 59) + // +5 : Second (0 - 59) + // +6 : upper nibble: years after leap year + // lower nibble: 0 - sun, 1 - mon, 2 - tue,...., 6 - sat) + // all BCD + return VECT_RTCGET(*allregsL[0x3C]); + case 0x04: + // VECT_INTLVSET + // param: RB3 - interrupt level (0-5) + // param: RC3 - interrupt number to set + // 0 - Interrupt from RTC alarm + // 1 - Interrupt from the Z80 CPU + // 2 - Interrupt from the 8 bit timer 0 + // 3 - Interrupt from the 8 bit timer 1 + // 4 - Interrupt from the 8 bit timer 2 + // 5 - Interrupt from the 8 bit timer 3 + // 6 - End of transfer interrupt from DMA channel 0 + // 7 - End of transfer interrupt from DMA channel 1 + // 8 - End of transfer interrupt from DMA channel 2 + // 9 - End of transfer interrupt from DMA channel 3 + return VECT_INTLVSET(*allregsB[0x34], *allregsB[0x35]); + case 0x05: + return VECT_SYSFONTSET(*allregsB[0x30]); + case 0x06: // store something in saveram + // copy BC3*0x0100 bytes of data from XHL3 to saveram + DE3 + return VECT_FLASHWRITE(*allregsB[0x30],*allregsW[0x34],*allregsL[0x3C],*allregsL[0x38],allregsB[0x30]); + case 0x07: //erase the chip + return VECT_FLASHALLERS(*allregsB[0x30],allregsB[0x30]); + break; + case 0x08: // set current memory save block (64 kb blocks); prepare for write + //erase a block + // parm: RB3 + *cregsB[1] = 0; // ld a,00 + return VECT_FLASHERS(*allregsB[0x30],*allregsB[0x35],allregsB[0x30]); + case 0x09: + return VECT_ALARMSET(*allregsB[0x36],*allregsB[0x35],*allregsB[0x34],allregsB[0x30]); + case 0x0e: + return VECT_GEMODESET(0x10); // Implementation wrong in ngpc bios???, always set to color + case 0x14: + *cregsB[1] = 1; // ld a,01 + break; + case 0x17: + *cregsW[0] = 0; // ld wa,0000 + break; + case 0x18: + *cregsW[0] = 0; // ld wa,0000 + break; + case 0x19: + *cregsB[2] = 0; // ld b,00 + break; + } + return 100; // let's just take a value... correct? +} + +int bios() +{ + unsigned char biosNr = readbyte(); + + return doBios(biosNr); +} + +// instructions where the highest bit of the first byte is set to 1 +// x0000xxx xxxxxxxx +int (*decode_table80[256])() = + { + udef, udef, udef, udef, pushM00, udef, rld00, rrd00, + udef, udef, udef, udef, udef, udef, udef, udef, + ldi, ldir, ldd, lddr, cpiB, cpirB, cpdB, cpdrB, + udef, ld16M00, udef, udef, udef, udef, udef, udef, + ldRM00, ldRM00, ldRM00, ldRM00, ldRM00, ldRM00, ldRM00, ldRM00, + udef, udef, udef, udef, udef, udef, udef, udef, + exMRB00, exMRB00, exMRB00, exMRB00, exMRB00, exMRB00, exMRB00, exMRB00, + addMI00, adcMI00, subMI00, sbcMI00, andMI00, xorMI00, orMI00, cpMI00, + // + mulRMB00, mulRMB00, mulRMB00, mulRMB00, mulRMB00, mulRMB00, mulRMB00, mulRMB00, + mulsRMB00, mulsRMB00, mulsRMB00, mulsRMB00, mulsRMB00, mulsRMB00, mulsRMB00, mulsRMB00, + divRMB00, divRMB00, divRMB00, divRMB00, divRMB00, divRMB00, divRMB00, divRMB00, + divsRMB00, divsRMB00, divsRMB00, divsRMB00, divsRMB00, divsRMB00, divsRMB00, divsRMB00, + inc3M00, inc3M00, inc3M00, inc3M00, inc3M00, inc3M00, inc3M00, inc3M00, + dec3M00, dec3M00, dec3M00, dec3M00, dec3M00, dec3M00, dec3M00, dec3M00, + udef, udef, udef, udef, udef, udef, udef, udef, + rlcM00, rrcM00, rlM00, rrM00, slaM00, sraM00, sllM00, srlM00, + // + addRMB00, addRMB00, addRMB00, addRMB00, addRMB00, addRMB00, addRMB00, addRMB00, + addMRB00, addMRB00, addMRB00, addMRB00, addMRB00, addMRB00, addMRB00, addMRB00, + adcRMB00, adcRMB00, adcRMB00, adcRMB00, adcRMB00, adcRMB00, adcRMB00, adcRMB00, + adcMRB00, adcMRB00, adcMRB00, adcMRB00, adcMRB00, adcMRB00, adcMRB00, adcMRB00, + subRMB00, subRMB00, subRMB00, subRMB00, subRMB00, subRMB00, subRMB00, subRMB00, + subMRB00, subMRB00, subMRB00, subMRB00, subMRB00, subMRB00, subMRB00, subMRB00, + sbcRMB00, sbcRMB00, sbcRMB00, sbcRMB00, sbcRMB00, sbcRMB00, sbcRMB00, sbcRMB00, + sbcMRB00, sbcMRB00, sbcMRB00, sbcMRB00, sbcMRB00, sbcMRB00, sbcMRB00, sbcMRB00, + // + andRMB00, andRMB00, andRMB00, andRMB00, andRMB00, andRMB00, andRMB00, andRMB00, + andMRB00, andMRB00, andMRB00, andMRB00, andMRB00, andMRB00, andMRB00, andMRB00, + xorRMB00, xorRMB00, xorRMB00, xorRMB00, xorRMB00, xorRMB00, xorRMB00, xorRMB00, + xorMRB00, xorMRB00, xorMRB00, xorMRB00, xorMRB00, xorMRB00, xorMRB00, xorMRB00, + orRMB00, orRMB00, orRMB00, orRMB00, orRMB00, orRMB00, orRMB00, orRMB00, + orMRB00, orMRB00, orMRB00, orMRB00, orMRB00, orMRB00, orMRB00, orMRB00, + cpRMB00, cpRMB00, cpRMB00, cpRMB00, cpRMB00, cpRMB00, cpRMB00, cpRMB00, + cpMRB00, cpMRB00, cpMRB00, cpMRB00, cpMRB00, cpMRB00, cpMRB00, cpMRB00 + }; +// x0010xxx xxxxxxxx +int (*decode_table90[256])() = + { + udef, udef, udef, udef, pushwM10, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + ldiw, ldirw, lddw, lddrw, cpiW, cpirW, cpdW, cpdrW, + udef, ldw16M10, udef, udef, udef, udef, udef, udef, + ldRM10, ldRM10, ldRM10, ldRM10, ldRM10, ldRM10, ldRM10, ldRM10, + udef, udef, udef, udef, udef, udef, udef, udef, + exMRW10, exMRW10, exMRW10, exMRW10, exMRW10, exMRW10, exMRW10, exMRW10, + addwMI10, adcwMI10, subwMI10, sbcwMI10, andwMI10, xorwMI10, orwMI10, cpwMI10, + // + mulRMW10, mulRMW10, mulRMW10, mulRMW10, mulRMW10, mulRMW10, mulRMW10, mulRMW10, + mulsRMW10, mulsRMW10, mulsRMW10, mulsRMW10, mulsRMW10, mulsRMW10, mulsRMW10, mulsRMW10, + divRMW10, divRMW10, divRMW10, divRMW10, divRMW10, divRMW10, divRMW10, divRMW10, + divsRMW10, divsRMW10, divsRMW10, divsRMW10, divsRMW10, divsRMW10, divsRMW10, divsRMW10, + incw3M10, incw3M10, incw3M10, incw3M10, incw3M10, incw3M10, incw3M10, incw3M10, + decw3M10, decw3M10, decw3M10, decw3M10, decw3M10, decw3M10, decw3M10, decw3M10, + udef, udef, udef, udef, udef, udef, udef, udef, + rlcwM10, rrcwM10, rlwM10, rrwM10, slawM10, srawM10, sllwM10, srlwM10, + // + addRMW10, addRMW10, addRMW10, addRMW10, addRMW10, addRMW10, addRMW10, addRMW10, + addMRW10, addMRW10, addMRW10, addMRW10, addMRW10, addMRW10, addMRW10, addMRW10, + adcRMW10, adcRMW10, adcRMW10, adcRMW10, adcRMW10, adcRMW10, adcRMW10, adcRMW10, + adcMRW10, adcMRW10, adcMRW10, adcMRW10, adcMRW10, adcMRW10, adcMRW10, adcMRW10, + subRMW10, subRMW10, subRMW10, subRMW10, subRMW10, subRMW10, subRMW10, subRMW10, + subMRW10, subMRW10, subMRW10, subMRW10, subMRW10, subMRW10, subMRW10, subMRW10, + sbcRMW10, sbcRMW10, sbcRMW10, sbcRMW10, sbcRMW10, sbcRMW10, sbcRMW10, sbcRMW10, + sbcMRW10, sbcMRW10, sbcMRW10, sbcMRW10, sbcMRW10, sbcMRW10, sbcMRW10, sbcMRW10, + // + andRMW10, andRMW10, andRMW10, andRMW10, andRMW10, andRMW10, andRMW10, andRMW10, + andMRW10, andMRW10, andMRW10, andMRW10, andMRW10, andMRW10, andMRW10, andMRW10, + xorRMW10, xorRMW10, xorRMW10, xorRMW10, xorRMW10, xorRMW10, xorRMW10, xorRMW10, + xorMRW10, xorMRW10, xorMRW10, xorMRW10, xorMRW10, xorMRW10, xorMRW10, xorMRW10, + orRMW10, orRMW10, orRMW10, orRMW10, orRMW10, orRMW10, orRMW10, orRMW10, + orMRW10, orMRW10, orMRW10, orMRW10, orMRW10, orMRW10, orMRW10, orMRW10, + cpRMW10, cpRMW10, cpRMW10, cpRMW10, cpRMW10, cpRMW10, cpRMW10, cpRMW10, + cpMRW10, cpMRW10, cpMRW10, cpMRW10, cpMRW10, cpMRW10, cpMRW10, cpMRW10 + }; +// x0011xxx xxxxxxxx +int (*decode_table98[256])() = + { + udef, udef, udef, udef, pushwM10, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, ldw16M10, udef, udef, udef, udef, udef, udef, + ldRM10, ldRM10, ldRM10, ldRM10, ldRM10, ldRM10, ldRM10, ldRM10, + udef, udef, udef, udef, udef, udef, udef, udef, + exMRW10, exMRW10, exMRW10, exMRW10, exMRW10, exMRW10, exMRW10, exMRW10, + addwMI10, adcwMI10, subwMI10, sbcwMI10, andwMI10, xorwMI10, orwMI10, cpwMI10, + // + mulRMW10, mulRMW10, mulRMW10, mulRMW10, mulRMW10, mulRMW10, mulRMW10, mulRMW10, + mulsRMW10, mulsRMW10, mulsRMW10, mulsRMW10, mulsRMW10, mulsRMW10, mulsRMW10, mulsRMW10, + divRMW10, divRMW10, divRMW10, divRMW10, divRMW10, divRMW10, divRMW10, divRMW10, + divsRMW10, divsRMW10, divsRMW10, divsRMW10, divsRMW10, divsRMW10, divsRMW10, divsRMW10, + incw3M10, incw3M10, incw3M10, incw3M10, incw3M10, incw3M10, incw3M10, incw3M10, + decw3M10, decw3M10, decw3M10, decw3M10, decw3M10, decw3M10, decw3M10, decw3M10, + udef, udef, udef, udef, udef, udef, udef, udef, + rlcwM10, rrcwM10, rlwM10, rrwM10, slawM10, srawM10, sllwM10, srlwM10, + // + addRMW10, addRMW10, addRMW10, addRMW10, addRMW10, addRMW10, addRMW10, addRMW10, + addMRW10, addMRW10, addMRW10, addMRW10, addMRW10, addMRW10, addMRW10, addMRW10, + adcRMW10, adcRMW10, adcRMW10, adcRMW10, adcRMW10, adcRMW10, adcRMW10, adcRMW10, + adcMRW10, adcMRW10, adcMRW10, adcMRW10, adcMRW10, adcMRW10, adcMRW10, adcMRW10, + subRMW10, subRMW10, subRMW10, subRMW10, subRMW10, subRMW10, subRMW10, subRMW10, + subMRW10, subMRW10, subMRW10, subMRW10, subMRW10, subMRW10, subMRW10, subMRW10, + sbcRMW10, sbcRMW10, sbcRMW10, sbcRMW10, sbcRMW10, sbcRMW10, sbcRMW10, sbcRMW10, + sbcMRW10, sbcMRW10, sbcMRW10, sbcMRW10, sbcMRW10, sbcMRW10, sbcMRW10, sbcMRW10, + // + andRMW10, andRMW10, andRMW10, andRMW10, andRMW10, andRMW10, andRMW10, andRMW10, + andMRW10, andMRW10, andMRW10, andMRW10, andMRW10, andMRW10, andMRW10, andMRW10, + xorRMW10, xorRMW10, xorRMW10, xorRMW10, xorRMW10, xorRMW10, xorRMW10, xorRMW10, + xorMRW10, xorMRW10, xorMRW10, xorMRW10, xorMRW10, xorMRW10, xorMRW10, xorMRW10, + orRMW10, orRMW10, orRMW10, orRMW10, orRMW10, orRMW10, orRMW10, orRMW10, + orMRW10, orMRW10, orMRW10, orMRW10, orMRW10, orMRW10, orMRW10, orMRW10, + cpRMW10, cpRMW10, cpRMW10, cpRMW10, cpRMW10, cpRMW10, cpRMW10, cpRMW10, + cpMRW10, cpMRW10, cpMRW10, cpMRW10, cpMRW10, cpMRW10, cpMRW10, cpMRW10 + }; +// x0100xxx xxxxxxxx +int (*decode_tableA0[256])() = + { + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + ldRM20, ldRM20, ldRM20, ldRM20, ldRM20, ldRM20, ldRM20, ldRM20, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + // + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef , udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + // + addRML20, addRML20, addRML20, addRML20, addRML20, addRML20, addRML20, addRML20, + addMRL20, addMRL20, addMRL20, addMRL20, addMRL20, addMRL20, addMRL20, addMRL20, + adcRML20, adcRML20, adcRML20, adcRML20, adcRML20, adcRML20, adcRML20, adcRML20, + adcMRL20, adcMRL20, adcMRL20, adcMRL20, adcMRL20, adcMRL20, adcMRL20, adcMRL20, + subRML20, subRML20, subRML20, subRML20, subRML20, subRML20, subRML20, subRML20, + subMRL20, subMRL20, subMRL20, subMRL20, subMRL20, subMRL20, subMRL20, subMRL20, + sbcRML20, sbcRML20, sbcRML20, sbcRML20, sbcRML20, sbcRML20, sbcRML20, sbcRML20, + sbcMRL20, sbcMRL20, sbcMRL20, sbcMRL20, sbcMRL20, sbcMRL20, sbcMRL20, sbcMRL20, + // + andRML20, andRML20, andRML20, andRML20, andRML20, andRML20, andRML20, andRML20, + andMRL20, andMRL20, andMRL20, andMRL20, andMRL20, andMRL20, andMRL20, andMRL20, + xorRML20, xorRML20, xorRML20, xorRML20, xorRML20, xorRML20, xorRML20, xorRML20, + xorMRL20, xorMRL20, xorMRL20, xorMRL20, xorMRL20, xorMRL20, xorMRL20, xorMRL20, + orRML20, orRML20, orRML20, orRML20, orRML20, orRML20, orRML20, orRML20, + orMRL20, orMRL20, orMRL20, orMRL20, orMRL20, orMRL20, orMRL20, orMRL20, + cpRML20, cpRML20, cpRML20, cpRML20, cpRML20, cpRML20, cpRML20, cpRML20, + cpMRL20, cpMRL20, cpMRL20, cpMRL20, cpMRL20, cpMRL20, cpMRL20, cpMRL20 + }; +// x0110xxx xxxxxxxx +int (*decode_tableB0[256])() = + { + ldMI30, udef, ldwMI30, udef, popM30, udef, popwM30, udef, + udef, udef, udef, udef, udef , udef, udef, udef, + udef, udef, udef, udef, ldM1630, udef, ldwM1630, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + ldaRMW30, ldaRMW30, ldaRMW30, ldaRMW30, ldaRMW30, ldaRMW30, ldaRMW30, ldaRMW30, + andcfAM30, orcfAM30, xorcfAM30, ldcfAM30, stcfAM30, udef, udef, udef, + ldaRML30, ldaRML30, ldaRML30, ldaRML30, ldaRML30, ldaRML30, ldaRML30, ldaRML30, + udef, udef, udef, udef, udef, udef, udef, udef, + // + ldMR30B, ldMR30B, ldMR30B, ldMR30B, ldMR30B, ldMR30B, ldMR30B, ldMR30B, + udef, udef, udef, udef, udef, udef, udef, udef, + ldMR30W, ldMR30W, ldMR30W, ldMR30W, ldMR30W, ldMR30W, ldMR30W, ldMR30W, + udef, udef, udef , udef, udef, udef, udef, udef, + ldMR30L, ldMR30L, ldMR30L, ldMR30L, ldMR30L, ldMR30L, ldMR30L, ldMR30L, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef , udef, udef, udef, udef, udef, udef, + // + andcf3M30, andcf3M30, andcf3M30, andcf3M30, andcf3M30, andcf3M30, andcf3M30, andcf3M30, + orcf3M30, orcf3M30, orcf3M30, orcf3M30, orcf3M30, orcf3M30, orcf3M30, orcf3M30, + xorcf3M30, xorcf3M30, xorcf3M30, xorcf3M30, xorcf3M30, xorcf3M30, xorcf3M30, xorcf3M30, + ldcf3M30, ldcf3M30, ldcf3M30, ldcf3M30, ldcf3M30, ldcf3M30, ldcf3M30, ldcf3M30, + stcf3M30, stcf3M30, stcf3M30, stcf3M30, stcf3M30, stcf3M30, stcf3M30, stcf3M30, + tset3M30, tset3M30, tset3M30, tset3M30, tset3M30, tset3M30, tset3M30, tset3M30, + res3M30, res3M30, res3M30, res3M30, res3M30, res3M30, res3M30, res3M30, + set3M30, set3M30, set3M30, set3M30, set3M30, set3M30, set3M30, set3M30, + // + chg3M30, chg3M30, chg3M30, chg3M30, chg3M30, chg3M30, chg3M30, chg3M30, + bit3M30, bit3M30, bit3M30, bit3M30, bit3M30, bit3M30, bit3M30, bit3M30, + jpccM300, jpccM301, jpccM302, jpccM303, jpccM304, jpccM305, jpccM306, jpccM307, + jpccM308, jpccM309, jpccM30A, jpccM30B, jpccM30C, jpccM30D, jpccM30E, jpccM30F, + callccM300, callccM301, callccM302, callccM303, callccM304, callccM305, callccM306, callccM307, + callccM308, callccM309, callccM30A, callccM30B, callccM30C, callccM30D, callccM30E, callccM30F, + retcc0, retcc1, retcc2, retcc3, retcc4, retcc5, retcc6, retcc7, + retcc8, retcc9, retccA, retccB, retccC, retccD, retccE, retccF + }; +// x0111xxx xxxxxxxx +int (*decode_tableB8[256])() = + { + ldMI30, udef, ldwMI30, udef, popM30, udef, popwM30, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, ldM1630, udef, ldwM1630, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + ldaRMW30, ldaRMW30, ldaRMW30, ldaRMW30, ldaRMW30, ldaRMW30, ldaRMW30, ldaRMW30, + andcfAM30, orcfAM30, xorcfAM30, ldcfAM30, stcfAM30, udef, udef, udef, + ldaRML30, ldaRML30, ldaRML30, ldaRML30, ldaRML30, ldaRML30, ldaRML30, ldaRML30, + udef, udef, udef, udef, udef, udef, udef, udef, + // + ldMR30B, ldMR30B, ldMR30B, ldMR30B, ldMR30B, ldMR30B, ldMR30B, ldMR30B, + udef, udef, udef, udef, udef, udef, udef, udef, + ldMR30W, ldMR30W, ldMR30W, ldMR30W, ldMR30W, ldMR30W, ldMR30W, ldMR30W, + udef, udef, udef, udef, udef, udef, udef, udef, + ldMR30L, ldMR30L, ldMR30L, ldMR30L, ldMR30L, ldMR30L, ldMR30L, ldMR30L, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + // + andcf3M30, andcf3M30, andcf3M30, andcf3M30, andcf3M30, andcf3M30, andcf3M30, andcf3M30, + orcf3M30, orcf3M30, orcf3M30, orcf3M30, orcf3M30, orcf3M30, orcf3M30, orcf3M30, + xorcf3M30, xorcf3M30, xorcf3M30, xorcf3M30, xorcf3M30, xorcf3M30, xorcf3M30, xorcf3M30, + ldcf3M30, ldcf3M30, ldcf3M30, ldcf3M30, ldcf3M30, ldcf3M30, ldcf3M30, ldcf3M30, + stcf3M30, stcf3M30, stcf3M30, stcf3M30, stcf3M30, stcf3M30, stcf3M30, stcf3M30, + tset3M30, tset3M30, tset3M30, tset3M30, tset3M30, tset3M30, tset3M30, tset3M30, + res3M30, res3M30, res3M30, res3M30, res3M30, res3M30, res3M30, res3M30, + set3M30, set3M30, set3M30, set3M30, set3M30, set3M30, set3M30, set3M30, + // + chg3M30, chg3M30, chg3M30, chg3M30, chg3M30, chg3M30, chg3M30, chg3M30, + bit3M30, bit3M30, bit3M30, bit3M30, bit3M30, bit3M30, bit3M30, bit3M30, + jpccM300, jpccM301, jpccM302, jpccM303, jpccM304, jpccM305, jpccM306, jpccM307, + jpccM308, jpccM309, jpccM30A, jpccM30B, jpccM30C, jpccM30D, jpccM30E, jpccM30F, + callccM300, callccM301, callccM302, callccM303, callccM304, callccM305, callccM306, callccM307, + callccM308, callccM309, callccM30A, callccM30B, callccM30C, callccM30D, callccM30E, callccM30F, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef + }; +// x1000xxx xxxxxxxx +int (*decode_tableC0[256])() = + { + udef, udef, udef, udef, pushM00, udef, rld00, rrd00, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, ld16M00, udef, udef, udef, udef, udef, udef, + ldRM00, ldRM00, ldRM00, ldRM00, ldRM00, ldRM00, ldRM00, ldRM00, + udef, udef, udef, udef, udef, udef, udef, udef, + exMRB00, exMRB00, exMRB00, exMRB00, exMRB00, exMRB00, exMRB00, exMRB00, + addMI00, adcMI00, subMI00, sbcMI00, andMI00, xorMI00, orMI00, cpMI00, + // + mulRMB00, mulRMB00, mulRMB00, mulRMB00, mulRMB00, mulRMB00, mulRMB00, mulRMB00, + mulsRMB00, mulsRMB00, mulsRMB00, mulsRMB00, mulsRMB00, mulsRMB00, mulsRMB00, mulsRMB00, + divRMB00, divRMB00, divRMB00, divRMB00, divRMB00, divRMB00, divRMB00, divRMB00, + divsRMB00, divsRMB00, divsRMB00, divsRMB00, divsRMB00, divsRMB00, divsRMB00, divsRMB00, + inc3M00, inc3M00, inc3M00, inc3M00, inc3M00, inc3M00, inc3M00, inc3M00, + dec3M00, dec3M00, dec3M00, dec3M00, dec3M00, dec3M00, dec3M00, dec3M00, + udef, udef, udef, udef, udef, udef, udef, udef, + rlcM00, rrcM00, rlM00, rrM00, slaM00, sraM00, sllM00, srlM00, + // + addRMB00, addRMB00, addRMB00, addRMB00, addRMB00, addRMB00, addRMB00, addRMB00, + addMRB00, addMRB00, addMRB00, addMRB00, addMRB00, addMRB00, addMRB00, addMRB00, + adcRMB00, adcRMB00, adcRMB00, adcRMB00, adcRMB00, adcRMB00, adcRMB00, adcRMB00, + adcMRB00, adcMRB00, adcMRB00, adcMRB00, adcMRB00, adcMRB00, adcMRB00, adcMRB00, + subRMB00, subRMB00, subRMB00, subRMB00, subRMB00, subRMB00, subRMB00, subRMB00, + subMRB00, subMRB00, subMRB00, subMRB00, subMRB00, subMRB00, subMRB00, subMRB00, + sbcRMB00, sbcRMB00, sbcRMB00, sbcRMB00, sbcRMB00, sbcRMB00, sbcRMB00, sbcRMB00, + sbcMRB00, sbcMRB00, sbcMRB00, sbcMRB00, sbcMRB00, sbcMRB00, sbcMRB00, sbcMRB00, + // + andRMB00, andRMB00, andRMB00, andRMB00, andRMB00, andRMB00, andRMB00, andRMB00, + andMRB00, andMRB00, andMRB00, andMRB00, andMRB00, andMRB00, andMRB00, andMRB00, + xorRMB00, xorRMB00, xorRMB00, xorRMB00, xorRMB00, xorRMB00, xorRMB00, xorRMB00, + xorMRB00, xorMRB00, xorMRB00, xorMRB00, xorMRB00, xorMRB00, xorMRB00, xorMRB00, + orRMB00, orRMB00, orRMB00, orRMB00, orRMB00, orRMB00, orRMB00, orRMB00, + orMRB00, orMRB00, orMRB00, orMRB00, orMRB00, orMRB00, orMRB00, orMRB00, + cpRMB00, cpRMB00, cpRMB00, cpRMB00, cpRMB00, cpRMB00, cpRMB00, cpRMB00, + cpMRB00, cpMRB00, cpMRB00, cpMRB00, cpMRB00, cpMRB00, cpMRB00, cpMRB00 + }; +// x1001xxx xxxxxxxx +int (*decode_tableC8[256])() = + { + udef, udef, udef, ldrIB, pushrB, poprB, cplrB, negrB, + mulrIB, mulsrIB, divrIB, divsrIB, udef, udef, udef, udef, + daar, udef, udef, udef, udef, udef, udef, udef, + udef, udef, bios, udef, djnzB, udef, udef, udef, + andcf4rB, orcf4rB, xorcf4rB, ldcf4rB, stcf4rB, udef, udef, udef, + andcfArB, orcfArB, xorcfArB, ldcfArB, stcfArB, udef, ldccrB, ldcrcB, + res4rB, set4rB, chg4rB, bit4rB, tset4rB, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + // + mulRrB, mulRrB, mulRrB, mulRrB, mulRrB, mulRrB, mulRrB, mulRrB, + mulsRrB, mulsRrB, mulsRrB, mulsRrB, mulsRrB, mulsRrB, mulsRrB, mulsRrB, + divRrB, divRrB, divRrB, divRrB, divRrB, divRrB, divRrB, divRrB, + divsRrB, divsRrB, divsRrB, divsRrB, divsRrB, divsRrB, divsRrB, divsRrB, + inc3rB, inc3rB, inc3rB, inc3rB, inc3rB, inc3rB, inc3rB, inc3rB, + dec3rB, dec3rB, dec3rB, dec3rB, dec3rB, dec3rB, dec3rB, dec3rB, + sccB0, sccB1, sccB2, sccB3, sccB4, sccB5, sccB6, sccB7, + sccB8, sccB9, sccBA, sccBB, sccBC, sccBD, sccBE, sccBF, + // + addRrB, addRrB, addRrB, addRrB, addRrB, addRrB, addRrB, addRrB, + ldRrB, ldRrB, ldRrB, ldRrB, ldRrB, ldRrB, ldRrB, ldRrB, + adcRrB, adcRrB, adcRrB, adcRrB, adcRrB, adcRrB, adcRrB, adcRrB, + ldrRB, ldrRB, ldrRB, ldrRB, ldrRB, ldrRB, ldrRB, ldrRB, + subRrB, subRrB, subRrB, subRrB, subRrB, subRrB, subRrB, subRrB, + ldr3B, ldr3B, ldr3B, ldr3B, ldr3B, ldr3B, ldr3B, ldr3B, + sbcRrB, sbcRrB, sbcRrB, sbcRrB, sbcRrB, sbcRrB, sbcRrB, sbcRrB, + exRrB, exRrB, exRrB, exRrB, exRrB, exRrB, exRrB, exRrB, + // + andRrB, andRrB, andRrB, andRrB, andRrB, andRrB, andRrB, andRrB, + addrIB, adcrIB, subrIB, sbcrIB, andrIB, xorrIB, orrIB, cprIB, + xorRrB, xorRrB, xorRrB, xorRrB, xorRrB, xorRrB, xorRrB, xorRrB, + cpr3B, cpr3B, cpr3B, cpr3B, cpr3B, cpr3B, cpr3B, cpr3B, + orRrB, orRrB, orRrB, orRrB, orRrB, orRrB, orRrB, orRrB, + rlc4rB, rrc4rB, rl4rB, rr4rB, sla4rB, sra4rB, sll4rB, srl4rB, + cpRrB, cpRrB, cpRrB, cpRrB, cpRrB, cpRrB, cpRrB, cpRrB, + rlcArB, rrcArB, rlArB, rrArB, slaArB, sraArB, sllArB, srlArB + }; +// x1010xxx xxxxxxxx +int (*decode_tableD0[256])() = + { + udef, udef, udef, udef, pushwM10, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, ldw16M10, udef, udef, udef, udef, udef, udef, + ldRM10, ldRM10, ldRM10, ldRM10, ldRM10, ldRM10, ldRM10, ldRM10, + udef, udef, udef, udef, udef, udef, udef, udef, + exMRW10, exMRW10, exMRW10, exMRW10, exMRW10, exMRW10, exMRW10, exMRW10, + addwMI10, adcwMI10, subwMI10, sbcwMI10, andwMI10, xorwMI10, orwMI10, cpwMI10, + // + mulRMW10, mulRMW10, mulRMW10, mulRMW10, mulRMW10, mulRMW10, mulRMW10, mulRMW10, + mulsRMW10, mulsRMW10, mulsRMW10, mulsRMW10, mulsRMW10, mulsRMW10, mulsRMW10, mulsRMW10, + divRMW10, divRMW10, divRMW10, divRMW10, divRMW10, divRMW10, divRMW10, divRMW10, + divsRMW10, divsRMW10, divsRMW10, divsRMW10, divsRMW10, divsRMW10, divsRMW10, divsRMW10, + incw3M10, incw3M10, incw3M10, incw3M10, incw3M10, incw3M10, incw3M10, incw3M10, + decw3M10, decw3M10, decw3M10, decw3M10, decw3M10, decw3M10, decw3M10, decw3M10, + udef, udef, udef, udef, udef, udef, udef, udef, + rlcwM10, rrcwM10, rlwM10, rrwM10, slawM10, srawM10, sllwM10, srlwM10, + // + addRMW10, addRMW10, addRMW10, addRMW10, addRMW10, addRMW10, addRMW10, addRMW10, + addMRW10, addMRW10, addMRW10, addMRW10, addMRW10, addMRW10, addMRW10, addMRW10, + adcRMW10, adcRMW10, adcRMW10, adcRMW10, adcRMW10, adcRMW10, adcRMW10, adcRMW10, + adcMRW10, adcMRW10, adcMRW10, adcMRW10, adcMRW10, adcMRW10, adcMRW10, adcMRW10, + subRMW10, subRMW10, subRMW10, subRMW10, subRMW10, subRMW10, subRMW10, subRMW10, + subMRW10, subMRW10, subMRW10, subMRW10, subMRW10, subMRW10, subMRW10, subMRW10, + sbcRMW10, sbcRMW10, sbcRMW10, sbcRMW10, sbcRMW10, sbcRMW10, sbcRMW10, sbcRMW10, + sbcMRW10, sbcMRW10, sbcMRW10, sbcMRW10, sbcMRW10, sbcMRW10, sbcMRW10, sbcMRW10, + // + andRMW10, andRMW10, andRMW10, andRMW10, andRMW10, andRMW10, andRMW10, andRMW10, + andMRW10, andMRW10, andMRW10, andMRW10, andMRW10, andMRW10, andMRW10, andMRW10, + xorRMW10, xorRMW10, xorRMW10, xorRMW10, xorRMW10, xorRMW10, xorRMW10, xorRMW10, + xorMRW10, xorMRW10, xorMRW10, xorMRW10, xorMRW10, xorMRW10, xorMRW10, xorMRW10, + orRMW10, orRMW10, orRMW10, orRMW10, orRMW10, orRMW10, orRMW10, orRMW10, + orMRW10, orMRW10, orMRW10, orMRW10, orMRW10, orMRW10, orMRW10, orMRW10, + cpRMW10, cpRMW10, cpRMW10, cpRMW10, cpRMW10, cpRMW10, cpRMW10, cpRMW10, + cpMRW10, cpMRW10, cpMRW10, cpMRW10, cpMRW10, cpMRW10, cpMRW10, cpMRW10 + }; +// x1011xxx xxxxxxxx +int (*decode_tableD8[256])() = + { + udef, udef, udef, ldrIW, pushrW, poprW, cplrW, negrW, + mulrIW, mulsrIW, divrIW, divsrIW, udef, udef, bs1f, bs1b, + udef, udef, extzrW, extsrW, paarW, udef, mirrr, udef, + udef, mular, udef, udef, djnzW, udef, udef, udef, + andcf4rW, orcf4rW, xorcf4rW, ldcf4rW, stcf4rW, udef, udef, udef, + andcfArW, orcfArW, xorcfArW, ldcfArW, stcfArW, udef, ldccrW, ldcrcW, + res4rW, set4rW, chg4rW, bit4rW, tset4rW, udef, udef, udef, + minc1, minc2, minc4, udef, mdec1, mdec2, mdec4, udef, + // + mulRrW, mulRrW, mulRrW, mulRrW, mulRrW, mulRrW, mulRrW, mulRrW, + mulsRrW, mulsRrW, mulsRrW, mulsRrW, mulsRrW, mulsRrW, mulsRrW, mulsRrW, + divRrW, divRrW, divRrW, divRrW, divRrW, divRrW, divRrW, divRrW, + divsRrW, divsRrW, divsRrW, divsRrW, divsRrW, divsRrW, divsRrW, divsRrW, + inc3rW, inc3rW, inc3rW, inc3rW, inc3rW, inc3rW, inc3rW, inc3rW, + dec3rW, dec3rW, dec3rW, dec3rW, dec3rW, dec3rW, dec3rW, dec3rW, + sccW0, sccW1, sccW2, sccW3, sccW4, sccW5, sccW6, sccW7, + sccW8, sccW9, sccWA, sccWB, sccWC, sccWD, sccWE, sccWF, + // + addRrW, addRrW, addRrW, addRrW, addRrW, addRrW, addRrW, addRrW, + ldRrW, ldRrW, ldRrW, ldRrW, ldRrW, ldRrW, ldRrW, ldRrW, + adcRrW, adcRrW, adcRrW, adcRrW, adcRrW, adcRrW, adcRrW, adcRrW, + ldrRW, ldrRW, ldrRW, ldrRW, ldrRW, ldrRW, ldrRW, ldrRW, + subRrW, subRrW, subRrW, subRrW, subRrW, subRrW, subRrW, subRrW, + ldr3W, ldr3W, ldr3W, ldr3W, ldr3W, ldr3W, ldr3W, ldr3W, + sbcRrW, sbcRrW, sbcRrW, sbcRrW, sbcRrW, sbcRrW, sbcRrW, sbcRrW, + exRrW, exRrW, exRrW, exRrW, exRrW, exRrW, exRrW, exRrW, + // + andRrW, andRrW, andRrW, andRrW, andRrW, andRrW, andRrW, andRrW, + addrIW, adcrIW, subrIW, sbcrIW, andrIW, xorrIW, orrIW, cprIW, + xorRrW, xorRrW, xorRrW, xorRrW, xorRrW, xorRrW, xorRrW, xorRrW, + cpr3W, cpr3W, cpr3W, cpr3W, cpr3W, cpr3W, cpr3W, cpr3W, + orRrW, orRrW, orRrW, orRrW, orRrW, orRrW, orRrW, orRrW, + rlc4rW, rrc4rW, rl4rW, rr4rW, sla4rW, sra4rW, sll4rW, srl4rW, + cpRrW, cpRrW, cpRrW, cpRrW, cpRrW, cpRrW, cpRrW, cpRrW, + rlcArW, rrcArW, rlArW, rrArW, slaArW, sraArW, sllArW, srlArW + }; +// x1100xxx xxxxxxxx +int (*decode_tableE0[256])() = + { + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + ldRM20, ldRM20, ldRM20, ldRM20, ldRM20, ldRM20, ldRM20, ldRM20, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + // + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef , udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + // + addRML20, addRML20, addRML20, addRML20, addRML20, addRML20, addRML20, addRML20, + addMRL20, addMRL20, addMRL20, addMRL20, addMRL20, addMRL20, addMRL20, addMRL20, + adcRML20, adcRML20, adcRML20, adcRML20, adcRML20, adcRML20, adcRML20, adcRML20, + adcMRL20, adcMRL20, adcMRL20, adcMRL20, adcMRL20, adcMRL20, adcMRL20, adcMRL20, + subRML20, subRML20, subRML20, subRML20, subRML20, subRML20, subRML20, subRML20, + subMRL20, subMRL20, subMRL20, subMRL20, subMRL20, subMRL20, subMRL20, subMRL20, + sbcRML20, sbcRML20, sbcRML20, sbcRML20, sbcRML20, sbcRML20, sbcRML20, sbcRML20, + sbcMRL20, sbcMRL20, sbcMRL20, sbcMRL20, sbcMRL20, sbcMRL20, sbcMRL20, sbcMRL20, + // + andRML20, andRML20, andRML20, andRML20, andRML20, andRML20, andRML20, andRML20, + andMRL20, andMRL20, andMRL20, andMRL20, andMRL20, andMRL20, andMRL20, andMRL20, + xorRML20, xorRML20, xorRML20, xorRML20, xorRML20, xorRML20, xorRML20, xorRML20, + xorMRL20, xorMRL20, xorMRL20, xorMRL20, xorMRL20, xorMRL20, xorMRL20, xorMRL20, + orRML20, orRML20, orRML20, orRML20, orRML20, orRML20, orRML20, orRML20, + orMRL20, orMRL20, orMRL20, orMRL20, orMRL20, orMRL20, orMRL20, orMRL20, + cpRML20, cpRML20, cpRML20, cpRML20, cpRML20, cpRML20, cpRML20, cpRML20, + cpMRL20, cpMRL20, cpMRL20, cpMRL20, cpMRL20, cpMRL20, cpMRL20, cpMRL20 + }; +// x1101xxx xxxxxxxx +int (*decode_tableE8[256])() = + { + udef, udef, udef, ldrIL, pushrL, poprL, udef, udef, + udef, udef, udef, udef, link, unlk, udef, udef, + udef, udef, extzrL, extsrL, paarL, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, ldccrL, ldcrcL, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + // + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + inc3rL, inc3rL, inc3rL, inc3rL, inc3rL, inc3rL, inc3rL, inc3rL, + dec3rL, dec3rL, dec3rL, dec3rL, dec3rL, dec3rL, dec3rL, dec3rL, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + // + addRrL, addRrL, addRrL, addRrL, addRrL, addRrL, addRrL, addRrL, + ldRrL, ldRrL, ldRrL, ldRrL, ldRrL, ldRrL, ldRrL, ldRrL, + adcRrL, adcRrL, adcRrL, adcRrL, adcRrL, adcRrL, adcRrL, adcRrL, + ldrRL, ldrRL, ldrRL, ldrRL, ldrRL, ldrRL, ldrRL, ldrRL, + subRrL, subRrL, subRrL, subRrL, subRrL, subRrL, subRrL, subRrL, + ldr3L, ldr3L, ldr3L, ldr3L, ldr3L, ldr3L, ldr3L, ldr3L, + sbcRrL, sbcRrL, sbcRrL, sbcRrL, sbcRrL, sbcRrL, sbcRrL, sbcRrL, + udef, udef, udef, udef, udef, udef, udef, udef, + // + andRrL, andRrL, andRrL, andRrL, andRrL, andRrL, andRrL, andRrL, + addrIL, adcrIL, subrIL, sbcrIL, andrIL, xorrIL, orrIL, cprIL, + xorRrL, xorRrL, xorRrL, xorRrL, xorRrL, xorRrL, xorRrL, xorRrL, + udef, udef, udef, udef, udef, udef, udef, udef, + orRrL, orRrL, orRrL, orRrL, orRrL, orRrL, orRrL, orRrL, + rlc4rL, rrc4rL, rl4rL, rr4rL, sla4rL, sra4rL, sll4rL, srl4rL, + cpRrL, cpRrL, cpRrL, cpRrL, cpRrL, cpRrL, cpRrL, cpRrL, + rlcArL, rrcArL, rlArL, rrArL, slaArL, sraArL, sllArL, srlArL + }; +// x1110xxx xxxxxxxx +int (*decode_tableF0[256])() = + { + //00 + ldMI30, udef, ldwMI30, udef, popM30, udef, popwM30, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, ldM1630, udef, ldwM1630, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + ldaRMW30, ldaRMW30, ldaRMW30, ldaRMW30, ldaRMW30, ldaRMW30, ldaRMW30, ldaRMW30, + andcfAM30, orcfAM30, xorcfAM30, ldcfAM30, stcfAM30, udef, udef, udef, + ldaRML30, ldaRML30, ldaRML30, ldaRML30, ldaRML30, ldaRML30, ldaRML30, ldaRML30, + udef, udef, udef, udef, udef, udef, udef, udef, + //40 + ldMR30B, ldMR30B, ldMR30B, ldMR30B, ldMR30B, ldMR30B, ldMR30B, ldMR30B, + udef, udef, udef, udef, udef, udef, udef, udef, + ldMR30W, ldMR30W, ldMR30W, ldMR30W, ldMR30W, ldMR30W, ldMR30W, ldMR30W, + udef, udef, udef, udef, udef, udef, udef, udef, + ldMR30L, ldMR30L, ldMR30L, ldMR30L, ldMR30L, ldMR30L, ldMR30L, ldMR30L, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + //80 + andcf3M30, andcf3M30, andcf3M30, andcf3M30, andcf3M30, andcf3M30, andcf3M30, andcf3M30, + orcf3M30, orcf3M30, orcf3M30, orcf3M30, orcf3M30, orcf3M30, orcf3M30, orcf3M30, + xorcf3M30, xorcf3M30, xorcf3M30, xorcf3M30, xorcf3M30, xorcf3M30, xorcf3M30, xorcf3M30, + ldcf3M30, ldcf3M30, ldcf3M30, ldcf3M30, ldcf3M30, ldcf3M30, ldcf3M30, ldcf3M30, + stcf3M30, stcf3M30, stcf3M30, stcf3M30, stcf3M30, stcf3M30, stcf3M30, stcf3M30, + tset3M30, tset3M30, tset3M30, tset3M30, tset3M30, tset3M30, tset3M30, tset3M30, + res3M30, res3M30, res3M30, res3M30, res3M30, res3M30, res3M30, res3M30, + set3M30, set3M30, set3M30, set3M30, set3M30, set3M30, set3M30, set3M30, + //C0 + chg3M30, chg3M30, chg3M30, chg3M30, chg3M30, chg3M30, chg3M30, chg3M30, + bit3M30, bit3M30, bit3M30, bit3M30, bit3M30, bit3M30, bit3M30, bit3M30, + jpccM300, jpccM301, jpccM302, jpccM303, jpccM304, jpccM305, jpccM306, jpccM307, + jpccM308, jpccM309, jpccM30A, jpccM30B, jpccM30C, jpccM30D, jpccM30E, jpccM30F, + callccM300, callccM301, callccM302, callccM303, callccM304, callccM305, callccM306, callccM307, + callccM308, callccM309, callccM30A, callccM30B, callccM30C, callccM30D, callccM30E, callccM30F, + udef, udef, udef, udef, udef, udef, udef, udef, + udef, udef, udef, udef, udef, udef, udef, udef, + }; + +////////////////////////////////////////////////////////////////////////////// +//////////////////////// decode instructions ///////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int decode80() // (XWA) (XBC) (XDE) (XHL) (XIX) (XIY) (XIZ) (XSP) scr.B +{ + mem = *cregsL[opcode&7]; + memB = mem_readB(mem); + lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0x80].decode[lastbyte]++; +#endif + return decode_table80[lastbyte](); +} + +int decode88() // (XWA+d) (XBC+d) (XDE+d) (XHL+d) (XIX+d) (XIY+d) (XIZ+d) (XSP+d) scr.B +{ + mem = (*cregsL[opcode&7])+(signed char)readbyteSetLastbyte(); + memB = mem_readB(mem); + //lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0x80].decode[lastbyte]++; +#endif + return 2 + decode_table80[lastbyte](); +} + +int decode90() // (XWA) (XBC) (XDE) (XHL) (XIX) (XIY) (XIZ) (XSP) scr.W +{ + mem = *cregsL[opcode&7]; + memW = mem_readW(mem); + lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0x90].decode[lastbyte]++; +#endif + return decode_table90[lastbyte](); +} + +int decode98() // (XWA+d) (XBC+d) (XDE+d) (XHL+d) (XIX+d) (XIY+d) (XIZ+d) (XSP+d) scr.W +{ + mem = (*cregsL[opcode&7])+(signed char)readbyteSetLastbyte(); + memW = mem_readW(mem); + //lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0x98].decode[lastbyte]++; +#endif + return 2 + decode_table98[lastbyte](); +} + +int decodeA0() // (XWA) (XBC) (XDE) (XHL) (XIX) (XIY) (XIZ) (XSP) scr.L +{ + mem = *cregsL[opcode&7]; + memL = mem_readL(mem); + lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xa0].decode[lastbyte]++; +#endif + return decode_tableA0[lastbyte](); +} + +int decodeA8() // (XWA+d) (XBC+d) (XDE+d) (XHL+d) (XIX+d) (XIY+d) (XIZ+d) (XSP+d) scr.L +{ + mem = (*cregsL[opcode&7])+(signed char)readbyteSetLastbyte(); + memL = mem_readL(mem); + //lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xa0].decode[lastbyte]++; +#endif + return 2 + decode_tableA0[lastbyte](); +} + +int decodeB0() // (XWA) (XBC) (XDE) (XHL) (XIX) (XIY) (XIZ) (XSP) dst +{ + mem = *cregsL[opcode&7]; + lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xb0].decode[lastbyte]++; +#endif + return decode_tableB0[lastbyte](); +} + +int decodeB8() // (XWA+d) (XBC+d) (XDE+d) (XHL+d) (XIX+d) (XIY+d) (XIZ+d) (XSP+d) dst +{ + mem = (*cregsL[opcode&7])+(signed char)readbyteSetLastbyte(); + //lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xb8].decode[lastbyte]++; +#endif + return 2 + decode_tableB8[lastbyte](); +} + +int decodeBB() // (XWA+d) (XBC+d) (XDE+d) (XHL+d) (XIX+d) (XIY+d) (XIZ+d) (XSP+d) dst +{ + mem = (*cregsL[opcode&7])+(signed char)readbyteSetLastbyte(); + //lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xb8].decode[lastbyte]++; +#endif + return 2 + decode_tableB8[lastbyte](); +} + +int decodeC0() // (n) scr.B +{ + mem = readbyteSetLastbyte(); + memB = mem_readB(mem); +#ifdef TCLS900H_PROFILING + profile[0xc0].decode[lastbyte]++; +#endif + return 2 + decode_tableC0[lastbyte](); +} + +int decodeC1() // (nn) scr.B +{ + mem = readwordSetLastbyte(); + memB = mem_readB(mem); +#ifdef TCLS900H_PROFILING + profile[0xc0].decode[lastbyte]++; +#endif + return 2 + decode_tableC0[lastbyte](); +} + +int decodeC2() // (nnn) scr.B +{ + mem = read24SetLastbyte(); + memB = mem_readB(mem); +#ifdef TCLS900H_PROFILING + profile[0xc0].decode[lastbyte]++; +#endif + return 3 + decode_tableC0[lastbyte](); +} + +int decodeC3() // (mem) scr.B +{ + unsigned char reg = readbyte(); + signed short d16; + int retval = 0; + + switch(reg&0x03) + { + case 0x00: + mem = *allregsL[reg]; + retval = 5; + break; + case 0x01: + mem = *allregsL[reg]+(signed short)readword(); + retval = 5; + break; + case 0x02: + break; + case 0x03: + switch (reg) + { + case 0x03: + reg = readbyte(); + mem = *allregsL[reg]+(signed char)(*allregsB[readbyte()]); + // mem = *allregsL[reg]+*allregsB[readbyte()]; + retval = 8; + break; + case 0x07: + reg = readbyte(); + mem = *allregsL[reg]+(signed short)(*allregsW[readbyte()]); + // mem = *allregsL[reg]+*allregsW[readbyte()]; + retval = 8; + break; + case 0x13: + d16 = (signed short)readword(); + mem = gen_regsPC + d16; + retval = 5; + break; + default: + break; + } + } + memB = mem_readB(mem); + lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xc0].decode[lastbyte]++; +#endif + return retval + decode_tableC0[lastbyte](); +} + +int decodeC4() // (-xrr) scr.B +{ + unsigned char reg = readbyteSetLastbyte(); + + mem = ((*allregsL[reg])-= 1<<(reg&3)); // pre-decrement + memB = mem_readB(mem); + //lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xc0].decode[lastbyte]++; +#endif + return 3 + decode_tableC0[lastbyte](); +} + +int decodeC5() // (xrr+) scr.B +{ + unsigned char reg = readbyteSetLastbyte(); + + mem = *allregsL[reg]; + memB = mem_readB(mem); + *allregsL[reg]+= 1<<(reg&3); // post-increment + //lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xc0].decode[lastbyte]++; +#endif + return 3 + decode_tableC0[lastbyte](); +} + +int decodeC7() // r reg.B +{ + regB = allregsB[readbyteSetLastbyte()]; + //lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xc8].decode[lastbyte]++; +#endif + return 1 + decode_tableC8[lastbyte](); +} + +int decodeC8() // W A B C D E H L reg.B +{ + regB = cregsB[opcode&7]; + lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xc8].decode[lastbyte]++; +#endif + return decode_tableC8[lastbyte](); +} + +int decodeD0() // (n) scr.W +{ + mem = readbyteSetLastbyte(); + memW = mem_readW(mem); + //lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xd0].decode[lastbyte]++; +#endif + return 2 + decode_tableD0[lastbyte](); +} + +int decodeD1() // (nn) scr.W +{ + mem = readwordSetLastbyte(); + memW = mem_readW(mem); + //lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xd0].decode[lastbyte]++; +#endif + return 2 + decode_tableD0[lastbyte](); +} + +int decodeD2() // (nnn) scr.W +{ + mem = read24SetLastbyte(); + memW = mem_readW(mem); + //lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xd0].decode[lastbyte]++; +#endif + return 3 + decode_tableD0[lastbyte](); +} + +int decodeD3() // (mem) scr.W +{ + unsigned char reg = readbyte(); + signed short d16; + int retval = 0; + + switch(reg&0x03) + { + case 0x00: + mem = *allregsL[reg]; + retval = 5; + break; + case 0x01: + mem = *allregsL[reg]+(signed short)readword(); + retval = 5; + break; + case 0x02: + break; + case 0x03: + switch (reg) + { + case 0x03: + reg = readbyte(); + mem = *allregsL[reg]+(signed char)(*allregsB[readbyte()]); + // mem = *allregsL[reg]+*allregsB[readbyte()]; + retval = 8; + break; + case 0x07: + reg = readbyte(); + mem = *allregsL[reg]+(signed short)(*allregsW[readbyte()]); + // mem = *allregsL[reg]+*allregsW[readbyte()]; + retval = 8; + break; + case 0x13: + d16 = (signed short)readword(); + mem = gen_regsPC + d16; + retval = 5; + break; + default: + break; + } + } + memW = mem_readW(mem); + lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xd0].decode[lastbyte]++; +#endif + return retval + decode_tableD0[lastbyte](); +} + +int decodeD4() // (-xrr) scr.W +{ + unsigned char reg = readbyteSetLastbyte(); + + mem = ((*allregsL[reg])-= 1<<(reg&3)); // pre-decrement + memW = mem_readW(mem); + //lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xd0].decode[lastbyte]++; +#endif + return 3 + decode_tableD0[lastbyte](); +} + +int decodeD5() // (xrr+) scr.W +{ + unsigned char reg = readbyteSetLastbyte(); + + mem = (*allregsL[reg]); + memW = mem_readW(mem); + *allregsL[reg]+= 1<<(reg&3); // post-increment + //lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xd0].decode[lastbyte]++; +#endif + return 3 + decode_tableD0[lastbyte](); +} + +int decodeD7() // r reg.W +{ + regW = allregsW[readbyteSetLastbyte()]; + //lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xd8].decode[lastbyte]++; +#endif + return 1 + decode_tableD8[lastbyte](); +} + +int decodeD8() // WA BC DE HL IX IY IZ SP reg.W +{ + regW = cregsW[opcode&7]; + lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xd8].decode[lastbyte]++; +#endif + return decode_tableD8[lastbyte](); +} + +int decodeE0() // (n) scr.L +{ + mem = readbyteSetLastbyte(); + memL = mem_readL(mem); + //lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xe0].decode[lastbyte]++; +#endif + return 2 + decode_tableE0[lastbyte](); +} + +int decodeE1() // (nn) scr.L +{ + mem = readwordSetLastbyte(); + memL = mem_readL(mem); + //lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xe0].decode[lastbyte]++; +#endif + return 2 + decode_tableE0[lastbyte](); +} + +int decodeE2() // (nnn) scr.L +{ + mem = read24SetLastbyte(); + memL = mem_readL(mem); + //lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xe0].decode[lastbyte]++; +#endif + return 3 + decode_tableE0[lastbyte](); +} + +int decodeE3() // (mem) scr.L +{ + unsigned char reg = readbyte(); + signed short d16; + int retval = 0; + + switch(reg&0x03) + { + case 0x00: + mem = *allregsL[reg]; + retval = 5; + break; + case 0x01: + mem = *allregsL[reg]+(signed short)readword(); + retval = 5; + break; + case 0x02: + break; + case 0x03: + switch (reg) + { + case 0x03: + reg = readbyte(); + mem = *allregsL[reg]+(signed char)(*allregsB[readbyte()]); + // mem = *allregsL[reg]+*allregsB[readbyte()]; + retval = 8; + break; + case 0x07: + reg = readbyte(); + mem = *allregsL[reg]+(signed short)(*allregsW[readbyte()]); + // mem = *allregsL[reg]+*allregsW[readbyte()]; + retval = 8; + break; + case 0x13: + d16 = (signed short)readword(); + mem = gen_regsPC + d16; + retval = 5; + break; + default: + break; + } + } + memL = mem_readL(mem); + lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xe0].decode[lastbyte]++; +#endif + return retval + decode_tableE0[lastbyte](); +} + +int decodeE4() // (-xrr) scr.L +{ + unsigned char reg = readbyteSetLastbyte(); + + mem = ((*allregsL[reg])-= 1<<(reg&3)); // pre-decrement + memL = mem_readL(mem); + //lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xe0].decode[lastbyte]++; +#endif + return 3 + decode_tableE0[lastbyte](); +} + +int decodeE5() // (xrr+) scr.L +{ + unsigned char reg = readbyteSetLastbyte(); + + mem = (*allregsL[reg]); + memL = mem_readL(mem); + *allregsL[reg]+= 1<<(reg&3); // post-increment + //lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xe0].decode[lastbyte]++; +#endif + return 3 + decode_tableE0[lastbyte](); +} + +int decodeE7() // r reg.L +{ + regL = allregsL[readbyteSetLastbyte()]; + //lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xe8].decode[lastbyte]++; +#endif + return 1 + decode_tableE8[lastbyte](); +} + +int decodeE8() // XWA XBC XDE XHL XIX XIY XIZ XSP reg.L +{ + regL = cregsL[opcode&7]; + lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xe8].decode[lastbyte]++; +#endif + return decode_tableE8[lastbyte](); +} + +int decodeF0() // (n) dst +{ + mem = readbyteSetLastbyte(); +#ifdef TCLS900H_PROFILING + profile[0xf0].decode[lastbyte]++; +#endif + return 2 + decode_tableF0[lastbyte](); +} + +int decodeF1() // (nn) dst +{ + mem = readwordSetLastbyte(); +#ifdef TCLS900H_PROFILING + profile[0xf0].decode[lastbyte]++; +#endif + return 2 + decode_tableF0[lastbyte](); +} + +int decodeF2() // (nnn) dst +{ + mem = read24SetLastbyte(); +#ifdef TCLS900H_PROFILING + profile[0xf0].decode[lastbyte]++; +#endif + return 3 + decode_tableF0[lastbyte](); +} + +int decodeF3() // (mem) dst +{ + unsigned char reg = readbyte(); + signed short d16; + int retval = 0; + + switch(reg&0x03) + { + case 0x00: + mem = *allregsL[reg]; + retval = 5; + break; + case 0x01: + mem = *allregsL[reg]+(signed short)readword(); + retval = 5; + break; + case 0x02: + break; + case 0x03: + switch(reg) + { + case 0x03: + reg = readbyte(); + mem = *allregsL[reg]+(signed char)(*allregsB[readbyte()]); + // mem = *allregsL[reg]+*allregsB[readbyte()]; + retval = 8; + break; + case 0x07: + reg = readbyte(); + mem = *allregsL[reg]+(signed short)(*allregsW[readbyte()]); + // mem = *allregsL[reg]+*allregsW[readbyte()]; + retval = 8; + break; + case 0x13: + d16 = (signed short)readword(); + mem = gen_regsPC + d16; + retval = 5; + break; + default: + break; + } + } + lastbyte = readbyte(); +#ifdef TCLS900H_PROFILING + profile[0xf0].decode[lastbyte]++; +#endif + return retval + decode_tableF0[lastbyte](); +} + +int decodeF4() // (-xrr) dst +{ + unsigned char reg; + + reg = readbyteSetLastbyte(); + mem = (*allregsL[reg]-= 1<<(reg&3)); +#ifdef TCLS900H_PROFILING + profile[0xf0].decode[lastbyte]++; +#endif + return 3 + decode_tableF0[lastbyte](); +} + +int decodeF5() // (xrr+) dst +{ + unsigned char reg; + int retval; + + reg = readbyteSetLastbyte(); + mem = (*allregsL[reg]); +#ifdef TCLS900H_PROFILING + profile[0xf0].decode[lastbyte]++; +#endif + retval = 3 + decode_tableF0[lastbyte](); + *allregsL[reg]+= 1<<(reg&3); + return retval; +} + +// main instruction decode table +int (*instr_table[256])()= + { + nop, normal, pushsr, popsr, tmax, halt, ei, reti, + ld8I, pushI, ldw8I, pushwI, incf, decf, ret, retd, + rcf, scf, ccf, zcf, pushA, popA, exFF, ldf, + pushF, popF, jp16, jp24, call16, call24, calr, udef, + ldRIB, ldRIB, ldRIB, ldRIB, ldRIB, ldRIB, ldRIB, ldRIB, + pushRW, pushRW, pushRW, pushRW, pushRW, pushRW, pushRW, pushRW, + ldRIW, ldRIW, ldRIW, ldRIW, ldRIW, ldRIW, ldRIW, ldRIW, + pushRL, pushRL, pushRL, pushRL, pushRL, pushRL, pushRL, pushRL, + // + ldRIL, ldRIL, ldRIL, ldRIL, ldRIL, ldRIL, ldRIL, ldRIL, + popRW, popRW, popRW, popRW, popRW, popRW, popRW, popRW, + udef, udef, udef, udef, udef, udef, udef, udef, + popRL, popRL, popRL, popRL, popRL, popRL, popRL, popRL, + jrcc0, jrcc1, jrcc2, jrcc3, jrcc4, jrcc5, jrcc6, jrcc7, + jrcc8, jrcc9, jrccA, jrccB, jrccC, jrccD, jrccE, jrccF, + jrlcc0, jrlcc1, jrlcc2, jrlcc3, jrlcc4, jrlcc5, jrlcc6, jrlcc7, + jrlcc8, jrlcc9, jrlccA, jrlccB, jrlccC, jrlccD, jrlccE, jrlccF, + // + decode80, decode80, decode80, decode80, decode80, decode80, decode80, decode80, + decode88, decode88, decode88, decode88, decode88, decode88, decode88, decode88, + decode90, decode90, decode90, decode90, decode90, decode90, decode90, decode90, + decode98, decode98, decode98, decode98, decode98, decode98, decode98, decode98, + decodeA0, decodeA0, decodeA0, decodeA0, decodeA0, decodeA0, decodeA0, decodeA0, + decodeA8, decodeA8, decodeA8, decodeA8, decodeA8, decodeA8, decodeA8, decodeA8, + decodeB0, decodeB0, decodeB0, decodeB0, decodeB0, decodeB0, decodeB0, decodeB0, + decodeB8, decodeB8, decodeB8, decodeBB, decodeB8, decodeB8, decodeB8, decodeB8, + // + decodeC0, decodeC1, decodeC2, decodeC3, decodeC4, decodeC5, udef, decodeC7, + decodeC8, decodeC8, decodeC8, decodeC8, decodeC8, decodeC8, decodeC8, decodeC8, + decodeD0, decodeD1, decodeD2, decodeD3, decodeD4, decodeD5, udef, decodeD7, + decodeD8, decodeD8, decodeD8, decodeD8, decodeD8, decodeD8, decodeD8, decodeD8, + decodeE0, decodeE1, decodeE2, decodeE3, decodeE4, decodeE5, udef, decodeE7, + decodeE8, decodeE8, decodeE8, decodeE8, decodeE8, decodeE8, decodeE8, decodeE8, + decodeF0, decodeF1, decodeF2, decodeF3, decodeF4, decodeF5, udef, ldx, + swi, swi, swi, swi, swi, swi, swi, swi + }; + +void tlcs_init() +{ + int i,j; + +#ifdef TCLS900H_PROFILING + + initTlcs900hProfile(); +#endif + + // flags tables initialisation + for (i = 0; i < 256; i++) + { + if (!i) + Ztable[i] |= ZF; + SZtable[i] = (i & SF) | Ztable[i]; + +#ifdef USE_PARITY_TABLE + int k=0; + j=i; + for (int loop=0;loop<8;loop++) + { + if (j&1) + k++; + j = j>>1; + } + parityVtable[i] = ((k&1) ? 0 : VF); +#endif + } + + // initialize values of all registers + gen_regsXWA0 = gen_regsXBC0 = gen_regsXDE0 = gen_regsXHL0 = 0; + gen_regsXWA1 = gen_regsXBC1 = gen_regsXDE1 = gen_regsXHL1 = 0; + gen_regsXWA2 = gen_regsXBC2 = gen_regsXDE2 = gen_regsXHL2 = 0; + gen_regsXWA3 = gen_regsXBC3 = gen_regsXDE3 = gen_regsXHL3 = 0; + gen_regsXIX = gen_regsXIY = gen_regsXIZ = 0x00001000; + // these are the settings for a real 900H, we will set them to what we want + gen_regsXSSP = gen_regsXSP = 0x100; + gen_regsPC = mem_readL(0xFFFF00)&0x00ffffff; + gen_regsSR = 0; + F2 = 0; + for (j=0;j<64;j++) + ldcRegs[j] = 0; + // running in MAX and SYSTEM mode + gen_regsSR = 0xf800; // IFF 7, MAXM and SYSM + state = 0; + checkstate = 0; + + + // initialize pointer structure for access to all registers in byte mode + allregsB[0x00] = (unsigned char *)&gen_regsXWA0; + allregsB[0x04] = (unsigned char *)&gen_regsXBC0; + allregsB[0x08] = (unsigned char *)&gen_regsXDE0; + allregsB[0x0c] = (unsigned char *)&gen_regsXHL0; + allregsB[0x10] = (unsigned char *)&gen_regsXWA1; + allregsB[0x14] = (unsigned char *)&gen_regsXBC1; + allregsB[0x18] = (unsigned char *)&gen_regsXDE1; + allregsB[0x1c] = (unsigned char *)&gen_regsXHL1; + allregsB[0x20] = (unsigned char *)&gen_regsXWA2; + allregsB[0x24] = (unsigned char *)&gen_regsXBC2; + allregsB[0x28] = (unsigned char *)&gen_regsXDE2; + allregsB[0x2c] = (unsigned char *)&gen_regsXHL2; + allregsB[0x30] = (unsigned char *)&gen_regsXWA3; + allregsB[0x34] = (unsigned char *)&gen_regsXBC3; + allregsB[0x38] = (unsigned char *)&gen_regsXDE3; + allregsB[0x3c] = (unsigned char *)&gen_regsXHL3; + allregsB[0xf0] = (unsigned char *)&gen_regsXIX; + allregsB[0xf4] = (unsigned char *)&gen_regsXIY; + allregsB[0xf8] = (unsigned char *)&gen_regsXIZ; + allregsB[0xfc] = (unsigned char *)&gen_regsXSP; + + for (j=0;j<256;j+=4) + { + allregsB[j+1] = allregsB[j]+1; + allregsB[j+2] = allregsB[j]+2; + allregsB[j+3] = allregsB[j]+3; + } + + // initialize pointer structure for access to all registers in word mode + allregsW[0x00] = (unsigned short *)&gen_regsXWA0; + allregsW[0x04] = (unsigned short *)&gen_regsXBC0; + allregsW[0x08] = (unsigned short *)&gen_regsXDE0; + allregsW[0x0c] = (unsigned short *)&gen_regsXHL0; + allregsW[0x10] = (unsigned short *)&gen_regsXWA1; + allregsW[0x14] = (unsigned short *)&gen_regsXBC1; + allregsW[0x18] = (unsigned short *)&gen_regsXDE1; + allregsW[0x1c] = (unsigned short *)&gen_regsXHL1; + allregsW[0x20] = (unsigned short *)&gen_regsXWA2; + allregsW[0x24] = (unsigned short *)&gen_regsXBC2; + allregsW[0x28] = (unsigned short *)&gen_regsXDE2; + allregsW[0x2c] = (unsigned short *)&gen_regsXHL2; + allregsW[0x30] = (unsigned short *)&gen_regsXWA3; + allregsW[0x34] = (unsigned short *)&gen_regsXBC3; + allregsW[0x38] = (unsigned short *)&gen_regsXDE3; + allregsW[0x3c] = (unsigned short *)&gen_regsXHL3; + allregsW[0xf0] = (unsigned short *)&gen_regsXIX; + allregsW[0xf4] = (unsigned short *)&gen_regsXIY; + allregsW[0xf8] = (unsigned short *)&gen_regsXIZ; + allregsW[0xfc] = (unsigned short *)&gen_regsXSP; + + for (j=2;j<256;j+=4) + allregsW[j] = allregsW[j-2]+1; + + // initialize pointer structure for access to all registers in long mode + allregsL[0x00] = allregsL[0x01] = allregsL[0x02] = allregsL[0x03] = &gen_regsXWA0; + allregsL[0x04] = allregsL[0x05] = allregsL[0x06] = allregsL[0x07] = &gen_regsXBC0; + allregsL[0x08] = allregsL[0x09] = allregsL[0x0a] = allregsL[0x0b] = &gen_regsXDE0; + allregsL[0x0c] = allregsL[0x0d] = allregsL[0x0e] = allregsL[0x0f] = &gen_regsXHL0; + allregsL[0x10] = allregsL[0x11] = allregsL[0x12] = allregsL[0x13] = &gen_regsXWA1; + allregsL[0x14] = allregsL[0x15] = allregsL[0x16] = allregsL[0x17] = &gen_regsXBC1; + allregsL[0x18] = allregsL[0x19] = allregsL[0x1a] = allregsL[0x1b] = &gen_regsXDE1; + allregsL[0x1c] = allregsL[0x1d] = allregsL[0x1e] = allregsL[0x1f] = &gen_regsXHL1; + allregsL[0x20] = allregsL[0x21] = allregsL[0x22] = allregsL[0x23] = &gen_regsXWA2; + allregsL[0x24] = allregsL[0x25] = allregsL[0x26] = allregsL[0x27] = &gen_regsXBC2; + allregsL[0x28] = allregsL[0x29] = allregsL[0x2a] = allregsL[0x2b] = &gen_regsXDE2; + allregsL[0x2c] = allregsL[0x2d] = allregsL[0x2e] = allregsL[0x2f] = &gen_regsXHL2; + allregsL[0x30] = allregsL[0x31] = allregsL[0x32] = allregsL[0x33] = &gen_regsXWA3; + allregsL[0x34] = allregsL[0x35] = allregsL[0x36] = allregsL[0x37] = &gen_regsXBC3; + allregsL[0x38] = allregsL[0x39] = allregsL[0x3a] = allregsL[0x3b] = &gen_regsXDE3; + allregsL[0x3c] = allregsL[0x3d] = allregsL[0x3e] = allregsL[0x3f] = &gen_regsXHL3; + allregsL[0xf0] = allregsL[0xf1] = allregsL[0xf2] = allregsL[0xf3] = &gen_regsXIX; + allregsL[0xf4] = allregsL[0xf5] = allregsL[0xf6] = allregsL[0xf7] = &gen_regsXIY; + allregsL[0xf8] = allregsL[0xf9] = allregsL[0xfa] = allregsL[0xfb] = &gen_regsXIZ; + allregsL[0xfc] = allregsL[0xfd] = allregsL[0xfe] = allregsL[0xff] = &gen_regsXSP; + + cregsW[4] = allregsW[0xf0]; + cregsW[5] = allregsW[0xf4]; + cregsW[6] = allregsW[0xf8]; + cregsW[7] = allregsW[0xfc]; + + cregsL[4] = allregsL[0xf0]; + cregsL[5] = allregsL[0xf4]; + cregsL[6] = allregsL[0xf8]; + cregsL[7] = allregsL[0xfc]; + + set_cregs(); + + // neogeo pocket color specific settings for running rom dumps + gen_regsPC = mem_readL(0x0020001c) & 0x00ffffff; + +// if(realBIOSloaded) +// gen_regsPC = 0xFF1800; //this is where Koyote starts when loading BIOS, but it doesn't work for me + + gen_regsXNSP = gen_regsXSP = 0x00006C00; + my_pc = get_address(gen_regsPC); + + tlcsClockMulti = 1; + DMAstate = 0; + + interruptPendingLevel = 0; + for(i=0; i<7; i++) + { + for(j=0; j>1)])>>4)&7 : (cpuram[0x70+(irq>>1)])&7 ); + if (level==7) + level = 0; + + // Check for timer3 interrupt => generate irq to z80 + if (irq == 0x09) + { + ngpSoundExecute(); + ngpSoundInterrupt(); + } + if (DMAvector[irq]) + tlcsDMA(DMAvector[irq]); + if (level) + { + // acknowledge that we have an interrupt + i=0; + while (i interruptPendingLevel) + interruptPendingLevel = level; + } +} + +void tlcs_interrupt_wrapper(int irq) +{ + tlcs_interrupt(irq); +} + +#define DMAS0 ((unsigned long *)&ldcRegs[0x00]) +#define DMAS1 ((unsigned long *)&ldcRegs[0x04]) +#define DMAS2 ((unsigned long *)&ldcRegs[0x08]) +#define DMAS3 ((unsigned long *)&ldcRegs[0x0C]) +#define DMAD0 ((unsigned long *)&ldcRegs[0x10]) +#define DMAD1 ((unsigned long *)&ldcRegs[0x14]) +#define DMAD2 ((unsigned long *)&ldcRegs[0x18]) +#define DMAD3 ((unsigned long *)&ldcRegs[0x1C]) +#define DMAC0 ((unsigned short *)&ldcRegs[0x20]) +#define DMAC1 ((unsigned short *)&ldcRegs[0x24]) +#define DMAC2 ((unsigned short *)&ldcRegs[0x28]) +#define DMAC3 ((unsigned short *)&ldcRegs[0x2C]) +#define DMAM0 &ldcRegs[0x22] +#define DMAM1 &ldcRegs[0x26] +#define DMAM2 &ldcRegs[0x2A] +#define DMAM3 &ldcRegs[0x2E] +#define DMA0V cpuram[0x7C] +#define DMA1V cpuram[0x7D] +#define DMA2V cpuram[0x7E] +#define DMA3V cpuram[0x7F] + +// handle DMA +inline void tlcsDMAchannel(unsigned char *mode, unsigned long *src, unsigned long *dest, unsigned short *count, unsigned char *vector, int channel) +{ + switch (*mode) + { + case 0x00: + mem_writeB(*dest,mem_readB(*src)); + *dest+= 1; + DMAstate+= 8; + break; + case 0x01: + mem_writeW(*dest,mem_readW(*src)); + *dest+= 2; + DMAstate+= 8; + break; + case 0x02: + mem_writeL(*dest,mem_readL(*src)); + *dest+= 4; + DMAstate+= 12; + break; + case 0x04: + mem_writeB(*dest,mem_readB(*src)); + *dest-= 1; + DMAstate+= 8; + break; + case 0x05: + mem_writeW(*dest,mem_readW(*src)); + *dest-= 2; + DMAstate+= 8; + break; + case 0x06: + mem_writeL(*dest,mem_readL(*src)); + *dest-= 4; + DMAstate+= 12; + break; + case 0x08: + mem_writeB(*dest,mem_readB(*src)); + *src+= 1; + DMAstate+= 8; + break; + case 0x09: + mem_writeW(*dest,mem_readW(*src)); + *src+= 2; + DMAstate+= 8; + break; + case 0x0A: + mem_writeL(*dest,mem_readL(*src)); + *src+= 4; + DMAstate+= 12; + break; + case 0x0C: + mem_writeB(*dest,mem_readB(*src)); + *src-= 1; + DMAstate+= 8; + break; + case 0x0D: + mem_writeW(*dest,mem_readW(*src)); + *src-= 2; + DMAstate+= 8; + break; + case 0x0E: + mem_writeL(*dest,mem_readL(*src)); + *src-= 4; + DMAstate+= 12; + break; + case 0x10: + mem_writeB(*dest,mem_readB(*src)); + DMAstate+= 8; + break; + case 0x11: + mem_writeW(*dest,mem_readW(*src)); + DMAstate+= 8; + break; + case 0x12: + mem_writeL(*dest,mem_readL(*src)); + DMAstate+= 12; + break; + case 0x14: + *src+= 1; + DMAstate+= 5; + break; + } + *count-= 1; + if (!*count) + { + *vector = 0; + tlcs_interrupt(0x12 + channel); + } +} + +inline void tlcsDMA(unsigned char vector) +{ + if (vector == DMA0V) + { + tlcsDMAchannel(DMAM0, DMAS0, DMAD0, DMAC0, &DMA0V, 0); + return; + } + else if (vector == DMA1V) + { + tlcsDMAchannel(DMAM1, DMAS1, DMAD1, DMAC1, &DMA1V, 1); + return; + } + else if (vector == DMA2V) + { + tlcsDMAchannel(DMAM2, DMAS2, DMAD2, DMAC2, &DMA2V, 2); + return; + } + else if (vector == DMA3V) + { + tlcsDMAchannel(DMAM3, DMAS3, DMAD3, DMAC3, &DMA3V, 3); + return; + } +} + +// timer related cpu registers +#define T8RUN cpuram[0x20] +#define TREG0 cpuram[0x22] +#define TREG1 cpuram[0x23] +#define T01MOD cpuram[0x24] +#define TREG2 cpuram[0x26] +#define TREG3 cpuram[0x27] +#define T23MOD cpuram[0x28] +int timer0 = 0; +int timer1 = 0; +int timer2 = 0; +int timer3 = 0; + + +//Flavor Something is wrong with this timer code!!! +#define TIMER_BASE_RATE (240) //what NeoPop seemed to use +//#define TIMER_BASE_RATE (64*4) //what MHE originally used +//#define TIMER_BASE_RATE (56*2) //this seems to be okay for PacMan, but CFC2 is horribly sped up + +#define TIMER_T1_RATE (1 * TIMER_BASE_RATE) +#define TIMER_T4_RATE (4 * TIMER_BASE_RATE) +#define TIMER_T16_RATE (16 * TIMER_BASE_RATE) +#define TIMER_T256_RATE (256 * TIMER_BASE_RATE) + + +// only timer mode 00, and maybe the other two 8 bit timer modes as well +// 16bit combined timer mode not supported yet (might be easy to implement though) +inline void tlcs1Timer(int stateChange, int timerNr, int run, int mode, + int *t0, int *t1, + int check0, int check1) +{ + int overflow0 = 0, overflow1 = 0; + + if (run&1) + { + if (!check0) + check0 = 256; + switch(mode&3) + { + //Flavor hacking according to NeoPop + case 0: + if(timerNr==0) + { + if (*t0 >= check0) + { + overflow0 = 1; + *t0-= check0; + //horiz interrupt? + } + } + //else nothing + break; + case 1: + *t0+= stateChange; + if(timerNr==0) + { + if (*t0 >= check0*TIMER_T1_RATE) + { + overflow0 = 1; + *t0-= check0*TIMER_T1_RATE; + } + } + else + { + if (*t0 >= check0*56) //HACK - Fixes DAC + { + overflow0 = 1; + *t0-= check0*56; + } + } + break; + case 2: + *t0+= stateChange; + if (*t0 >= check0*TIMER_T4_RATE) + { + overflow0 = 1; + *t0-= check0*TIMER_T4_RATE; + } + break; + case 3: + *t0+= stateChange; + if (*t0 >= check0*TIMER_T16_RATE) + { + overflow0 = 1; + *t0-= check0*TIMER_T16_RATE; + } + break; + } + if (overflow0) + tlcs_interrupt(6+timerNr); + } + else + *t0 = 0; + + + if (run&2) + { + if (!check1) + check1 = 256; + switch((mode>>2)&3) + { + case 0: + *t1+= overflow0; + if (*t1 >= check1) + { + overflow1 = 1; + *t1-= check1; + } + break; + case 1: + *t1+= stateChange; + if (*t1 >= check1*TIMER_T1_RATE) + { + overflow1 = 1; + *t1-= check1*TIMER_T1_RATE; + } + break; + case 2: + *t1+= stateChange; + if (*t1 >= check1*TIMER_T16_RATE) + { + overflow1 = 1; + *t1-= check1*TIMER_T16_RATE; + } + break; + case 3: + *t1+= stateChange; + if (*t1 >= check1*TIMER_T256_RATE) + { + overflow1 = 1; + *t1-= check1*TIMER_T256_RATE; + } + break; + } + if (overflow1) + tlcs_interrupt(7+timerNr); + } + else + *t1 = 0; +} + +// check and perform timer functions +inline void tlcsTimers(int stateChange) +{ + //Flavor, unroll these two calls into one function + + // // check for updates + // if (0) { + // TREG0 = cpuram[0x22] ? cpuram[0x22] : 256; + // TREG1 = cpuram[0x23] ? cpuram[0x23] : 256; + // TREG2 = cpuram[0x26] ? cpuram[0x26] : 256; + // TREG3 = cpuram[0x27] ? cpuram[0x27] : 256; + // } + // timer 0 + 1 + tlcs1Timer(stateChange, 0, T8RUN&3, T01MOD, &timer0, &timer1, TREG0, TREG1); + // timer 2 + 3 + tlcs1Timer(stateChange, 2, (T8RUN>>2)&3, T23MOD, &timer2, &timer3, TREG2, TREG3); +} + +inline void tlcsTI0() +{ + + if (((T01MOD & 3) == 0) && (T8RUN & 1)) + timer0+= 1; + + if (gfx_hacks==1){ + //Arregla Samurai 2 + if (mainrom[0x000020] == 0x30) { + + contador++; + if (contador==100) + timer0+= 1; + + if (contador==152) + contador=0;} + + //Arregla el tablero del Super Real Mahjong, NO modo historia + //Arregla Ohanabi 0x10 + + if ((mainrom[0x000020] == 0x11 || mainrom[0x000020] == 0x10) && *scanlineY>182) + timer0 = 0; + + //Arregla Oelsol 0x07 + if (mainrom[0x000020] == 0x07 && *rasterY>0 ) + {if (*scanlineY==2) + timer0-= 1; } + + //Arregla Dekahel 0x08 + if (mainrom[0x000020] == 0x08 && *rasterY==0 ) + timer0 = 0; + + //Arregla ecup 0x12 + //if (mainrom[0x000020] == 0x12 && *scrollBackY==0 ) + // timer0 = 0; + + if (mainrom[0x000020] == 0x12) + {if (*scanlineY>122 && *rasterY==0 ) + timer0 = 0; + if (*scanlineY==2) + timer0+= 1; }} + + + + } + +inline int tlcs_step() +{ + int clocks = DMAstate; +#ifdef TCLS900H_PROFILING + + unsigned int startTime = 0; +#endif + + DMAstate = 0; + memoryCycles = 0; + + // check and handle a pending interrupt + if (interruptPendingLevel > (unsigned char)((gen_regsSR & 0x7000)>>12)) + { + int i; + // push PC + tlcsFastMemWriteL(gen_regsXSP-=4,gen_regsPC); + // push SR + tlcsFastMemWriteW(gen_regsXSP-=2,gen_regsSR); + gen_regsSR = (gen_regsSR & 0x8fff) | (interruptPendingLevel<<12); + gen_regsPC = mem_readL(0x00FFFF00 + pendingInterrupts[interruptPendingLevel-1][0]); + my_pc = get_address(gen_regsPC); + + // remove interrupt vector from interrupt queue + for(i=1; i=0; i--) + { + if (pendingInterrupts[i][0] != 0) + { + interruptPendingLevel = i+1; + break; + } + } + clocks+= 18; + } + + + opcode = readbyte(); + + //printf("tlcs_step: PC=0x%X opcode=0x%X\n", gen_regsPC-1, opcode); + + +#ifdef TCLS900H_PROFILING + + startTime = SDL_GetTicks(); +#endif + + clocks+= instr_table[opcode](); + +#ifdef TCLS900H_PROFILING + + profile[opcode].ticks += SDL_GetTicks() - startTime; + profile[opcode].calls++; +#endif + + clocks+= memoryCycles; + + // Timer processing + //tlcsTimers(clocks); //Flavor: should it be (tlcsClockMulti*clocks)??? + + return /*tlcsClockMulti * */ clocks; +} + + +//extern unsigned char *ngpScX; +extern unsigned char *ngpScY; +int ngOverflow = 0; + +#define FRAME_RATE_LIMIT //should we limit the framerate or let it run wild? +#define FRAMESKIP //undef this to do no FRAME skipping + +#ifdef FRAMESKIP +//#define AUTO_FRAMESKIP +//#define FIXED_FRAMESKIP 1 +//#define MAX_SKIPFRAMES 2 +#endif + +#ifdef TARGET_PSP +#define FIXED_FRAMESKIP (psp_options.frame_skip) +int frame=FIXED_FRAMESKIP; +#endif + +#ifdef AUTO_FRAMESKIP +inline void tlcs_execute(int cycles, int skipFrames)// skipFrames=how many frames to skip for each frame rendered +#else +inline void tlcs_execute(int cycles) +#endif +{ + int elapsed; + int hCounter = ngOverflow; + +#ifdef FRAMESKIP +#ifdef FIXED_FRAMESKIP +// static int frame=FIXED_FRAMESKIP; +#else + + static int frame=1; +#endif +#endif + +#ifdef TCLS900H_PROFILING + + static unsigned int steps=1; +#endif + + UpdateInputState(); + + while(cycles > 0) + { + /* AKTODO */ +// if(options[TURBO_OPTION]) + if (1) + { + //call a bunch of steps + for (elapsed = tlcs_step();elapsed<(515>>(tlcsClockMulti-1)); elapsed += tlcs_step()); + } + else + { + //call enough steps that would fit in the smallest timer increment + for (elapsed = tlcs_step();elapsed<56; elapsed += tlcs_step()); + } + tlcsTimers(elapsed); + elapsed*=tlcsClockMulti; + soundStep(elapsed); + + hCounter-= elapsed; + // *ngpScX = hCounter>>2; + +#ifdef TCLS900H_PROFILING + + if(steps++ == 25000000) + { + m_bIsActive = false; + break; + } +#endif + + if (hCounter < 0) + { + // time equivalent to 1 horizontal line has passed +#ifdef FRAMESKIP + //graphicsBlitLine(frame == 0); + myGraphicsBlitLine(frame==0); +#else + + //graphicsBlitLine(true); + myGraphicsBlitLine(true); +#endif + + + //NOTA + + hCounter+= 515; + // now check what needs to be done at the + // beginning of this new line + // NOTA originalmente *scanlineY == 199 arregla Gals Fighter + if (*scanlineY < 151 || *scanlineY == finscan) + { + // HBlank + if (tlcsMemReadB(0x8000)&0x40) + tlcsTI0(); + + } + else if (*scanlineY == 152) + { + system_sound_update(1); + + // VBlank + if (tlcsMemReadB(0x8000)&0x80) + tlcs_interrupt(2); +#ifdef FRAMESKIP +#ifdef FIXED_FRAMESKIP + + if(frame == 0) + frame = FIXED_FRAMESKIP; +#else + + if(frame == 0) + { + frame = skipFrames; + SDL_Rect numRect = drawNumber(skipFrames, 10, 24); + //SDL_UpdateRect(screen, numRect.x, numRect.y, numRect.w, numRect.h); + } +#endif + else + frame--; +#endif + } + + } + cycles-= elapsed; + } + ngOverflow = hCounter + cycles; + + //graphics_paint(); //paint the screen, if it's dirty + + //MHE used to sound update here!?!? + + return; +} + + +//Flavor, this auto-frameskip code is messed up +void ngpc_run() +{ +#ifndef TARGET_PSP + int currTick=0,lastTick=0; + u32 ticks_per_sec = 1000; +#endif /* !TARGET_PSP */ + +#ifdef AUTO_FRAMESKIP + unsigned int skipFrames=0; +#endif /* AUTO_FRAMESKIP */ + + while(m_bIsActive) //should be some way to exit + { +#ifndef TARGET_PSP +#ifndef __GP32__ + currTick = SDL_GetTicks(); + + //if ((currTick - lastTick) >= (1000/m_emuInfo.fps)) + if((currTick - lastTick) < (ticks_per_sec/HOST_FPS)) + { +#ifdef AUTO_FRAMESKIP + if(skipFrames) + { + skipFrames--; + } +#endif /* AUTO_FRAMESKIP */ +#ifdef FRAME_RATE_LIMIT + while((currTick - lastTick) < (ticks_per_sec/HOST_FPS)) + { + currTick = SDL_GetTicks(); + } +#endif /* FRAME_RATE_LIMIT */ + } +#ifdef AUTO_FRAMESKIP + else + { + if(skipFrames 1000 +#pragma once +#endif // _MSC_VER > 1000 + +extern unsigned long gen_regsPC, gen_regsSR; +extern unsigned char F2; +extern unsigned long + gen_regsXWA0, gen_regsXBC0, gen_regsXDE0, gen_regsXHL0, + gen_regsXWA1, gen_regsXBC1, gen_regsXDE1, gen_regsXHL1, + gen_regsXWA2, gen_regsXBC2, gen_regsXDE2, gen_regsXHL2, + gen_regsXWA3, gen_regsXBC3, gen_regsXDE3, gen_regsXHL3, + gen_regsXIX, gen_regsXIY, gen_regsXIZ, gen_regsXSP, + gen_regsSP, gen_regsXSSP, gen_regsXNSP; +extern int timer0, timer1, timer2, timer3; +extern unsigned char ldcRegs[64]; +extern int idioma; + +#define XWA0 0 +#define XBC0 1 +#define XDE0 2 +#define XHL0 3 +#define XWA1 4 +#define XBC1 5 +#define XDE1 6 +#define XHL1 7 +#define XWA2 8 +#define XBC2 9 +#define XDE2 10 +#define XHL2 11 +#define XWA3 12 +#define XBC3 13 +#define XDE3 14 +#define XHL3 15 +#define XIX 16 +#define XIY 17 +#define XIZ 18 +#define XSP 19 +#define PC 20 +#define SR 21 +#define XSSP 22 +#define XNSP 23 +// initialize registers, etc.. +void tlcs_init(); +void tlcs_reinit(); +// perform one cpu step +int tlcs_step(); +// output the current contents of the registers to a file +//void tlcs_print(FILE *output); +// execute interrupt +void tlcs_interrupt_wrapper(int irq); +// check PC +//int check_pc(unsigned long addr); +// input from TI0 +void tlcsTI0(); +// +//void tlcs_test(); +// +//void setErrorLog(FILE *errorlog, FILE *outputram); +//void closeLog(); +void ngpc_run(); + +#endif // !defined(AFX_TLCS900H_H__41E77E01_8224_11D3_8644_00A0241D2A65__INCLUDED_) diff --git a/unzip.c b/unzip.c new file mode 100644 index 0000000..5ed48c8 --- /dev/null +++ b/unzip.c @@ -0,0 +1,1562 @@ +/* unzip.c -- IO for uncompress .zip files using zlib + Version 1.00, September 10th, 2003 + + Copyright (C) 1998-2003 Gilles Vollant + + Read unzip.h for more info +*/ + +/* Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of +compatibility with older software. The following is from the original crypt.c. Code +woven in by Terry Thorsen 1/2003. +*/ +/* + Copyright (c) 1990-2000 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.h) for terms of use. + If, for some reason, all these files are missing, the Info-ZIP license + also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html +*/ +/* + crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + */ + +/* + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + */ + + +#include +#include +#include +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + + +#ifndef CASESENSITIVITYDEFAULT_NO +# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) +# define CASESENSITIVITYDEFAULT_NO +# endif +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + + + +const char unz_copyright[] = + " unzip 1.00 Copyright 1998-2003 Gilles Vollant - http://www.winimage.com/zLibDll"; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info_internal_s +{ + uLong offset_curfile;/* relative offset of local header 4 bytes */ +} unz_file_info_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + + uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + uLong offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + uLong pos_local_extrafield; /* position in the local extra field in read*/ + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + uLong rest_read_compressed; /* number of byte to be decompressed */ + uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + zlib_filefunc_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + int raw; +} file_in_zip_read_info_s; + + +/* unz_s contain internal information about the zipfile +*/ +typedef struct +{ + zlib_filefunc_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + unz_global_info gi; /* public global information */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + uLong num_file; /* number of the current file in the zipfile*/ + uLong pos_in_central_dir; /* pos of the current file in the central dir*/ + uLong current_file_ok; /* flag about the usability of the current file*/ + uLong central_pos; /* position of the beginning of the central dir*/ + + uLong size_central_dir; /* size of the central directory */ + uLong offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info cur_file_info; /* public info about the current file in zip*/ + unz_file_info_internal cur_file_info_internal; /* private info about it*/ + file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ + int encrypted; +# ifndef NOUNCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; +# endif +} unz_s; + + +#ifndef NOUNCRYPT +#include "crypt.h" +#endif + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + + +local int unzlocal_getByte OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int unzlocal_getByte(pzlib_filefunc_def,filestream,pi) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + int *pi; +{ + unsigned char c; + int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ZERROR(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unzlocal_getShort OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unzlocal_getShort (pzlib_filefunc_def,filestream,pX) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong *pX; +{ + uLong x ; + int i; + int err; + + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unzlocal_getLong OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unzlocal_getLong (pzlib_filefunc_def,filestream,pX) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong *pX; +{ + uLong x ; + int i; + int err; + + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (fileName1,fileName2) + const char* fileName1; + const char* fileName2; +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity) + const char* fileName1; + const char* fileName2; + int iCaseSensitivity; +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local uLong unzlocal_SearchCentralDir OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream)); + +local uLong unzlocal_SearchCentralDir(pzlib_filefunc_def,filestream) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer + "zlib/zlib114.zip". + If the zipfile cannot be opened (file doesn't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +extern unzFile ZEXPORT unzOpen2 (path, pzlib_filefunc_def) + const char *path; + zlib_filefunc_def* pzlib_filefunc_def; +{ + unz_s us; + unz_s *s; + uLong central_pos,uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + if (pzlib_filefunc_def==NULL) + fill_fopen_filefunc(&us.z_filefunc); + else + us.z_filefunc = *pzlib_filefunc_def; + + us.filestream= (*(us.z_filefunc.zopen_file))(us.z_filefunc.opaque, + path, + ZLIB_FILEFUNC_MODE_READ | + ZLIB_FILEFUNC_MODE_EXISTING); + if (us.filestream==NULL) + return NULL; + + central_pos = unzlocal_SearchCentralDir(&us.z_filefunc,us.filestream); + if (central_pos==0) + err=UNZ_ERRNO; + + if (ZSEEK(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unzlocal_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* zipfile comment length */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + ZCLOSE(s->z_filefunc, s->filestream); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info) + unzFile file; + unz_global_info *pglobal_info; +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + + +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unzlocal_DosDateToTmuDate (ulDosDate, ptm) + uLong ulDosDate; + tm_unz* ptm; +{ + uLong uDate; + uDate = (uLong)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info *pfile_info, + unz_file_info_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unzlocal_GetCurrentFileInfoInternal (file, + pfile_info, + pfile_info_internal, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + unz_file_info_internal *pfile_info_internal; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + unz_s* s; + unz_file_info file_info; + unz_file_info_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (ZSEEK(s->z_filefunc, s->filestream, + s->pos_in_central_dir+s->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + { + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (ZREAD(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + + if ((err==UNZ_OK) && (extraField!=NULL)) + { + uLong uSizeRead ; + + if (file_info.size_file_extraz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + { + if (ZREAD(s->z_filefunc, s->filestream,extraField,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + } + lSeek += file_info.size_file_extra - uSizeRead; + } + else + lSeek+=file_info.size_file_extra; + + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + { + if (ZREAD(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + } + + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int ZEXPORT unzGetCurrentFileInfo (file, + pfile_info, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (file) + unzFile file; +{ + int err=UNZ_OK; + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int ZEXPORT unzGoToNextFile (file) + unzFile file; +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity) + unzFile file; + const char *szFileName; + int iCaseSensitivity; +{ + unz_s* s; + int err; + + /* We remember the 'current' position in the file so that we can jump + * back there if we fail. + */ + unz_file_info cur_file_infoSaved; + unz_file_info_internal cur_file_info_internalSaved; + uLong num_fileSaved; + uLong pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + /* Save the current state */ + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + cur_file_infoSaved = s->cur_file_info; + cur_file_info_internalSaved = s->cur_file_info_internal; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + err = unzGetCurrentFileInfo(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (err == UNZ_OK) + { + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + } + + /* We failed, so restore the state of the 'current file' to where we + * were. + */ + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + s->cur_file_info = cur_file_infoSaved; + s->cur_file_info_internal = cur_file_info_internalSaved; + return err; +} + + +/* +/////////////////////////////////////////// +// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) +// I need random access +// +// Further optimization could be realized by adding an ability +// to cache the directory in memory. The goal being a single +// comprehensive file read to put the file I need in a memory. +*/ + +/* +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; // offset in file + uLong num_of_file; // # of file +} unz_file_pos; +*/ + +extern int ZEXPORT unzGetFilePos(file, file_pos) + unzFile file; + unz_file_pos* file_pos; +{ + unz_s* s; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + file_pos->pos_in_zip_directory = s->pos_in_central_dir; + file_pos->num_of_file = s->num_file; + + return UNZ_OK; +} + +extern int ZEXPORT unzGoToFilePos(file, file_pos) + unzFile file; + unz_file_pos* file_pos; +{ + unz_s* s; + int err; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + /* jump to the right spot */ + s->pos_in_central_dir = file_pos->pos_in_zip_directory; + s->num_file = file_pos->num_of_file; + + /* set the current file */ + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + /* return results */ + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* +// Unzip Helper Functions - should be here? +/////////////////////////////////////////// +*/ + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) +*/ +local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar, + poffset_local_extrafield, + psize_local_extrafield) + unz_s* s; + uInt* piSizeVar; + uLong *poffset_local_extrafield; + uInt *psize_local_extrafield; +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (ZSEEK(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + { + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password) + unzFile file; + int* method; + int* level; + int raw; + const char* password; +{ + int err=UNZ_OK; + uInt iSizeVar; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uLong offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ +# ifndef NOUNCRYPT + char source[12]; +# else + if (password != NULL) + return UNZ_PARAMERROR; +# endif + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, + &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip_read_info_s*) + ALLOC(sizeof(file_in_zip_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + pfile_in_zip_read_info->raw=raw; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if (method!=NULL) + *method = (int)s->cur_file_info.compression_method; + + if (level!=NULL) + { + *level = 6; + switch (s->cur_file_info.flag & 0x06) + { + case 6 : *level = 1; break; + case 4 : *level = 2; break; + case 2 : *level = 9; break; + } + } + + if ((s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->compression_method = + s->cur_file_info.compression_method; + pfile_in_zip_read_info->filestream=s->filestream; + pfile_in_zip_read_info->z_filefunc=s->z_filefunc; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if ((s->cur_file_info.compression_method==Z_DEFLATED) && + (!raw)) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = (voidpf)0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=1; + else + return err; + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + +# ifndef NOUNCRYPT + if (password != NULL) + { + int i; + s->pcrc_32_tab = get_crc_table(); + init_keys(password,s->keys,s->pcrc_32_tab); + if (ZSEEK(s->z_filefunc, s->filestream, + s->pfile_in_zip_read->pos_in_zipfile + + s->pfile_in_zip_read->byte_before_the_zipfile, + SEEK_SET)!=0) + return UNZ_INTERNALERROR; + if(ZREAD(s->z_filefunc, s->filestream,source, 12)<12) + return UNZ_INTERNALERROR; + + for (i = 0; i<12; i++) + zdecode(s->keys,s->pcrc_32_tab,source[i]); + + s->pfile_in_zip_read->pos_in_zipfile+=12; + s->encrypted=1; + } +# endif + + + return UNZ_OK; +} + +extern int ZEXPORT unzOpenCurrentFile (file) + unzFile file; +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +extern int ZEXPORT unzOpenCurrentFilePassword (file, password) + unzFile file; + const char* password; +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +extern int ZEXPORT unzOpenCurrentFile2 (file,method,level,raw) + unzFile file; + int* method; + int* level; + int raw; +{ + return unzOpenCurrentFile3(file, method, level, raw, NULL); +} + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int ZEXPORT unzReadCurrentFile (file, buf, len) + unzFile file; + voidp buf; + unsigned len; +{ + int err=UNZ_OK; + uInt iRead = 0; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->read_buffer == NULL)) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if (len>pfile_in_zip_read_info->rest_read_uncompressed) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (ZSEEK(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + if (ZREAD(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->read_buffer, + uReadThis)!=uReadThis) + return UNZ_ERRNO; + + +# ifndef NOUNCRYPT + if(s->encrypted) + { + uInt i; + for(i=0;iread_buffer[i] = + zdecode(s->keys,s->pcrc_32_tab, + pfile_in_zip_read_info->read_buffer[i]); + } +# endif + + + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) + { + uInt uDoCopy,i ; + + if ((pfile_in_zip_read_info->stream.avail_in == 0) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + return (iRead==0) ? UNZ_EOF : iRead; + + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else + { + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (file,buf,len) + unzFile file; + voidp buf; + unsigned len; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uInt read_now; + uLong size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (ZSEEK(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (ZREAD(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + buf,size_to_read)!=size_to_read) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (file) + unzFile file; +{ + int err=UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && + (!pfile_in_zip_read_info->raw)) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised) + inflateEnd(&pfile_in_zip_read_info->stream); + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf) + unzFile file; + char *szComment; + uLong uSizeBuf; +{ +/* int err=UNZ_OK; */ + unz_s* s; + uLong uReadThis ; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (ZSEEK(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (ZREAD(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} diff --git a/unzip.h b/unzip.h new file mode 100644 index 0000000..4e50979 --- /dev/null +++ b/unzip.h @@ -0,0 +1,342 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.00, September 10th, 2003 + + Copyright (C) 1998-2003 Gilles Vollant + + This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + Encryption and multi volume ZipFile (span) are not supported. + Old compressions used by old PKZip 1.x are not supported + + + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + +*/ + +/* for more info about .ZIP format, see + http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip + http://www.info-zip.org/pub/infozip/doc/ + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip +*/ + +#ifndef _unz_H +#define _unz_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer + "zlib/zlib113.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ + +extern unzFile ZEXPORT unzOpen2 OF((const char *path, + zlib_filefunc_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +/* ****************************************** */ +/* Ryan supplied functions */ +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ +} unz_file_pos; + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos); + +/* ****************************************** */ + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, + const char* password)); +/* + Open for reading data the current file in the zipfile. + password is a crypting password + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, + int* method, + int* level, + int raw)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + +extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, + int* method, + int* level, + int raw, + const char* password)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _unz_H */