yabause-0.9.15/CMakeLists.txt000644 001750 001750 00000002332 12755623101 020013 0ustar00guillaumeguillaume000000 000000 project(yabause) cmake_minimum_required(VERSION 2.8) set(YAB_PACKAGE yabause) set(YAB_VERSION_MAJOR 0) set(YAB_VERSION_MINOR 9) set(YAB_VERSION_PATCH 15) set(YAB_VERSION "${YAB_VERSION_MAJOR}.${YAB_VERSION_MINOR}.${YAB_VERSION_PATCH}") set(CPACK_SOURCE_GENERATOR TGZ) set(CPACK_PACKAGE_VERSION_MAJOR ${YAB_VERSION_MAJOR}) set(CPACK_PACKAGE_VERSION_MINOR ${YAB_VERSION_MINOR}) set(CPACK_PACKAGE_VERSION_PATCH ${YAB_VERSION_PATCH}) set(CPACK_PACKAGE_VENDOR "Yabause team") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING") set(CPACK_SOURCE_PACKAGE_FILE_NAME "yabause-${YAB_VERSION}") if (APPLE) set(CPACK_GENERATOR DragNDrop) set(CPACK_PACKAGE_FILE_NAME yabause-${YAB_VERSION}-mac) endif () if (WIN32) SET(CPACK_NSIS_INSTALLED_ICON_NAME yabause.exe) set(CPACK_NSIS_MENU_LINKS yabause.exe;Yabause) set(CPACK_NSIS_URL_INFO_ABOUT "http://yabause.org") set(CPACK_NSIS_COMPRESSOR "/SOLID lzma") if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(CPACK_SYSTEM_NAME "win64") set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64") set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "${CPACK_PACKAGE_NAME}${CPACK_PACKAGE_VERSION} (Win64)") endif () endif () include(CPack) add_subdirectory(doc) add_subdirectory(l10n) add_subdirectory(src) yabause-0.9.15/src/000755 001750 001750 00000000000 12757373644 016062 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/sh7034.c000644 001750 001750 00000400525 12757373537 017165 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2005 Guillaume Duhamel Copyright 2004-2005, 2013 Theo Berkau Copyright 2016 James Laird-Wah This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file sh7034.c \brief SH7034 cpu implementation (CD block controller) */ #include "core.h" #include "sh7034.h" #include "assert.h" #include "memory.h" #include "ygr.h" #include "debug.h" #include #include "cd_drive.h" #include "tsunami/yab_tsunami.h" #include "mpeg_card.h" //#define SH1_MEM_DEBUG #ifdef SH1_MEM_DEBUG #define SH1MEMLOG(...) DebugPrintf(MainLog, __FILE__, __LINE__, __VA_ARGS__) #else #define SH1MEMLOG(...) #endif //#define WANT_TIMER_TRACE #ifdef WANT_TIMER_TRACE #define TIMERTRACE(...) cd_trace_log(__VA_ARGS__) #else #define TIMERTRACE(...) #endif //#define WANT_PORT_TRACE #ifdef WANT_PORT_TRACE #define PORTTRACE(...) cd_trace_log(__VA_ARGS__) #else #define PORTTRACE(...) #endif u8 transfer_buffer[13] = { 0 }; void update_transfer_buffer() { int i; for (i = 0; i < 13; i++) { transfer_buffer[i] = T2ReadByte(sh1_cxt.ram, 0x0002D0 + i);//0xF0002D0 } } u16 cr_response[4] = { 0 }; void update_cr_response_values(u32 addr) { int updated = 0; if (addr >= 0x0F00026C && addr <= 0x0F000273) { updated = 1; //0x0F00026C cr_response[0] = T2ReadWord(sh1_cxt.ram, 0x00026C + 0); cr_response[1] = T2ReadWord(sh1_cxt.ram, 0x00026C + 2); cr_response[2] = T2ReadWord(sh1_cxt.ram, 0x00026C + 4); cr_response[3] = T2ReadWord(sh1_cxt.ram, 0x00026C + 6); } if (updated) { int q = 1; } } void cd_trace_log(const char * format, ...) { static int started = 0; static FILE* fp = NULL; va_list l; if (!started) { fp = fopen("C:/yabause/log.txt", "w"); if (!fp) { return; } started = 1; } va_start(l, format); vfprintf(fp, format, l); va_end(l); } void print_tocr() { TIMERTRACE("Timer Output Control Register(TOCR)\n"); //tocr if (sh1_cxt.onchip.itu.tocr & (1 << 1)) TIMERTRACE("\tTIOCA3, TIOCA4, and TIOCB4 are output directly \n"); else TIMERTRACE("\tTIOCA3, TIOCA4, and TIOCB4 are inverted and output\n"); if (sh1_cxt.onchip.itu.tocr & (1 << 0)) TIMERTRACE("\tTIOCB3, TOCXA4, and TOCXB4 are output directly\n"); else TIMERTRACE("\tTIOCB3, TOCXA4, and TOCXB4 are inverted and output\n"); } void print_tcr(int which) { TIMERTRACE("Timer Control Register(TCR)\n"); switch ((sh1_cxt.onchip.itu.channel[which].tcr >> 5) & 3) { case 0: TIMERTRACE("\tTCNT is not cleared\n"); break; case 1: TIMERTRACE("\tTCNT is cleared by general register A (GRA) compare match or input capture\n"); break; case 2: TIMERTRACE("\tTCNT is cleared by general register B (GRB) compare match or input capture\n"); break; case 3: TIMERTRACE("\tSynchronizing clear: TCNT is cleared in synchronization with clear of other timer counters operating in sync\n"); break; } if (sh1_cxt.onchip.itu.channel[which].tcr & (1 << 4)) TIMERTRACE("\tCount both rising and falling edges\n"); else { if (sh1_cxt.onchip.itu.channel[which].tcr & (1 << 3)) TIMERTRACE("\tCount falling edges.\n", which); else TIMERTRACE("\tCount rising edges.\n", which); } switch (sh1_cxt.onchip.itu.channel[which].tcr & 7) { case 0: TIMERTRACE("\tInternal clock phi\n"); break; case 1: TIMERTRACE("\tInternal clock phi/2\n"); break; case 2: TIMERTRACE("\tInternal clock phi/4\n"); break; case 3: TIMERTRACE("\tInternal clock phi/8\n"); break; case 4: TIMERTRACE("\tExternal clock A\n"); break; case 5: TIMERTRACE("\tExternal clock B\n"); break; case 6: TIMERTRACE("\tExternal clock C\n"); break; case 7: TIMERTRACE("\tExternal clock D\n"); break; } } void print_tior(int which) { TIMERTRACE("Timer I/O Control Register (TIOR)\n"); //tior3 switch ((sh1_cxt.onchip.itu.channel[which].tior >> 4) & 7) { //output compare case 0: TIMERTRACE("\tGRB Compare match with pin output disabled\n"); break; case 1: TIMERTRACE("\tGRB 0 output at GRB compare match\n"); break; case 2: TIMERTRACE("\tGRB 1 output at GRB compare match\n"); break; case 3: TIMERTRACE("\tGRB Output toggles at GRB compare match \n"); break; //input capture case 4: TIMERTRACE("\tGRB captures rising edge of input\n"); break; case 5: TIMERTRACE("\tGRB captures falling edge of input\n"); break; case 6: case 7: TIMERTRACE("\tGRB captures both edges of input\n"); break; } switch ((sh1_cxt.onchip.itu.channel[which].tior >> 4) & 7) { //output compare case 0: TIMERTRACE("\tGRA Compare match with pin output disabled\n"); break; case 1: TIMERTRACE("\tGRA 0 output at GRA compare match\n"); break; case 2: TIMERTRACE("\tGRA 1 output at GRA compare match\n"); break; case 3: TIMERTRACE("\tGRA Output toggles at GRA compare match \n"); break; //input capture case 4: TIMERTRACE("\tGRA captures rising edge of input\n"); break; case 5: TIMERTRACE("\tGRA captures falling edge of input\n"); break; case 6: case 7: TIMERTRACE("\tGRA captures both edges of input\n"); break; } } void print_tier(int which) { TIMERTRACE("Timer Interrupt Enable Register (TIER)\n"); //tier3 if (sh1_cxt.onchip.itu.channel[which].tier & (1 << 2)) TIMERTRACE("\tEnables interrupt requests from OVF\n"); else TIMERTRACE("\tDisables interrupt requests by OVF\n"); if (sh1_cxt.onchip.itu.channel[which].tier & (1 << 1)) TIMERTRACE("\tEnables interrupt requests by IMFB (IMIB)\n"); else TIMERTRACE("\tDisables interrupt requests by IMFB (IMIB)\n"); if (sh1_cxt.onchip.itu.channel[which].tier & (1 << 0)) TIMERTRACE("\tEnables interrupt requests by IMFA (IMIA)\n"); else TIMERTRACE("\tDisables interrupt requests by IMFA (IMIA)\n"); } void print_tsr(int which) { TIMERTRACE("Timer Status Register(TSR)\n"); //tsr3 if (sh1_cxt.onchip.itu.channel[which].tsr & (1 << 2)) TIMERTRACE("\tSetting condition: TCNT overflow from H'FFFF to H'0000 or underflow from H'0000 to H'FFFF\n"); else TIMERTRACE("\tClearing condition: Read OVF when OVF = 1, then write 0 in OVF\n"); if (sh1_cxt.onchip.itu.channel[which].tsr & (1 << 1)) TIMERTRACE("\tSetting conditions: !!!!!!!!\n"); else TIMERTRACE("\tClearing condition: Read IMFB when IMFB = 1, then write 0 in IMFB\n"); if (sh1_cxt.onchip.itu.channel[which].tsr & (1 << 0)) TIMERTRACE("\tSetting conditions: !!!!!!!!\n"); else TIMERTRACE("\tClearing condition: Read IMFA when IMFA = 1, then write 0 in IMFA. DMAC is activated by an IMIA interrupt (only channels 0E)\n"); } void print_tmdr(int which) { TIMERTRACE("TMDR\n"); if (which == 2) { if (sh1_cxt.onchip.itu.tmdr & (1 << 6)) TIMERTRACE("\tChannel 2 operates in phase counting mode\n"); else TIMERTRACE("\tChannel 2 operates normally .\n"); if (sh1_cxt.onchip.itu.tmdr & (1 << 5)) TIMERTRACE("\tOVF of TSR2 is set to 1 when TCNT2 overflows\n"); else TIMERTRACE("\tOVF of TSR2 is set to 1 when TCNT2 overflows or underflows.\n"); } if (sh1_cxt.onchip.itu.tmdr & (1 << which)) TIMERTRACE("\toperates in PWM mode\n"); else TIMERTRACE("\toperates normally.\n"); } void print_tsnc(int which) { //tsnc TIMERTRACE("Timer Synchro Register (TSNC)\n"); if (sh1_cxt.onchip.itu.tstr & (1 << which)) TIMERTRACE("\toperates synchronously\n"); else TIMERTRACE("\toperates independently\n"); } void print_tstr(int which) { //tstr TIMERTRACE("Timer Start Register(TSTR)\n"); if (sh1_cxt.onchip.itu.tstr & (1 << which)) TIMERTRACE("\tTimer is counting\n"); else TIMERTRACE("\tTimer is halted\n"); } void print_tfcr(int which) { TIMERTRACE("Timer Function Control Register (TFCR) \n"); if (which == 3 || which == 4) { //tfcr switch ((sh1_cxt.onchip.itu.tfcr >> 4) & 3) { case 0: case 1: TIMERTRACE("\tChannels 3 and 4 operate normally\n"); break; case 2: TIMERTRACE("\tChannels 3 and 4 operate together in complementary PWM mode\n"); break; case 3: TIMERTRACE("\tChannels 3 and 4 operate together in reset-synchronized PWM mode\n"); break; } } if (which == 4) { if (sh1_cxt.onchip.itu.tfcr & (1 << 3)) TIMERTRACE("\tBuffer operation of GRB4 and BRB4\n"); else TIMERTRACE("\tGRB4 operates normally\n"); if (sh1_cxt.onchip.itu.tfcr & (1 << 2)) TIMERTRACE("\tBuffer operation of GRA4 and BRA4\n"); else TIMERTRACE("\tGRA4 operates normally\n"); } if (which == 3) { if (sh1_cxt.onchip.itu.tfcr & (1 << 1)) TIMERTRACE("\tBuffer operation of GRB3 and BRB3\n"); else TIMERTRACE("\tGRB4 operates normally\n"); if (sh1_cxt.onchip.itu.tfcr & (1 << 0)) TIMERTRACE("\tBuffer operation of GRA3 and BRA3\n"); else TIMERTRACE("\tGRA4 operates normally\n"); } } void print_timers() { //do timer 3 //tcr3 int which = 3; TIMERTRACE("***TIMER %d***\n", which); print_tstr(which); print_tsnc(which); print_tmdr(which); print_tfcr(which); print_tcr(which); print_tior(which); print_tier(which); print_tsr(which); //tcnt3 TIMERTRACE("\tTCNT: %04X\n", sh1_cxt.onchip.itu.channel[which].tcnt); //gra3 TIMERTRACE("\tGRA: %04X\n", sh1_cxt.onchip.itu.channel[which].gra); //grb3 TIMERTRACE("\tGRB: %04X\n", sh1_cxt.onchip.itu.channel[which].grb); //bra3 TIMERTRACE("\tBRA: %04X\n", sh1_cxt.onchip.itu.channel[which].bra); //brb3 TIMERTRACE("\tBRB: %04X\n", sh1_cxt.onchip.itu.channel[which].brb); print_tocr(); #if 0 TIMERTRACE("TSTR\n"); int i; for (i = 4; i >= 0; i--) { } TIMERTRACE("TSTR\n"); for (i = 4; i >= 0; i--) { if (sh1_cxt.onchip.itu.tsnc & (1 << i)) TIMERTRACE("\tThe timer counter for TCNT%d operates independently\n", i); else TIMERTRACE("\tTCNT%d operates synchronously.\n", i); } for (i = 4; i >= 0; i--) { TIMERTRACE("TIER%d\n", i); } #endif #if 0 TIMERTRACE("SCR\n"); for (i = 0; i < 2; i++) { if (sh1_cxt.onchip.sci[i].scr & SCI_TIE) TIMERTRACE("\tSCI Channel %d Transmit-data-empty interrupt request (TXI) is enabled\n", i); else TIMERTRACE("\tSCI Channel %d Transmit-data-empty interrupt request (TXI) is disabled\n", i); if (sh1_cxt.onchip.sci[i].scr & SCI_RIE) TIMERTRACE("\tSCI Channel %d Receive-data-full interrupt (RXI) and receive-error interrupt (ERI) requests are enabled\n", i); else TIMERTRACE("\tSCI Channel %d Receive-data-full interrupt (RXI) and receive-error interrupt (ERI) requests are disabled \n", i); if (sh1_cxt.onchip.sci[i].scr & SCI_MPIE) TIMERTRACE("\tSCI Channel %d Multiprocessor interrupts are enabled\n", i); else TIMERTRACE("\tSCI Channel %d Multiprocessor interrupts are disabled\n", i); if (sh1_cxt.onchip.sci[i].scr & SCI_TEIE) TIMERTRACE("\tSCI Channel %d Transmit-end interrupt (TEI) requests are enabled\n", i); else TIMERTRACE("\tSCI Channel %d Transmit-end interrupt (TEI) requests are disabled\n", i); } #endif //TIMERTRACE("TCSR\n"); //if (sh1_cxt.onchip.wdt.tcsr & (1 << 6)) // TIMERTRACE("\tSCI Channel %d Transmit-data-empty interrupt request (TXI) is enabled\n", i); //else // TIMERTRACE("\tSCI Channel %d Transmit-data-empty interrupt request (TXI) is disabled\n", i); #if 0 for (i = 4; i >= 0; i--) { TIMERTRACE("TIOR%d\n", i); } #endif } void print_pacr1() { PORTTRACE("PACR1\n"); PORTTRACE(" Pin 15\n"); switch ((sh1_cxt.onchip.pfc.pacr1 >> 14) & 3) { case 0: PORTTRACE("\tInput / output(PA15)\n"); break; case 1: PORTTRACE("\tInterrupt request input (IRQ3)\n"); break; case 2: PORTTRACE("\tReserved\n"); break; case 3: PORTTRACE("\tDMA transfer request input (DREQ1)\n"); break; } PORTTRACE(" Pin 14\n"); switch ((sh1_cxt.onchip.pfc.pacr1 >> 12) & 3) { case 0: PORTTRACE("\tInput / output(PA14)\n"); break; case 1: PORTTRACE("\tInterrupt request input (IRQ2)\n"); break; case 2: PORTTRACE("\tReserved\n"); break; case 3: PORTTRACE("\tDMA transfer acknowledge output (DACK1)\n"); break; } PORTTRACE(" Pin 13\n"); switch ((sh1_cxt.onchip.pfc.pacr1 >> 10) & 3) { case 0: PORTTRACE("\tInput / output(PA13)\n"); break; case 1: PORTTRACE("\tInterrupt request input (IRQ1)\n"); break; case 2: PORTTRACE("\tITU timer clock input (TCLKB)\n"); break; case 3: PORTTRACE("\tDMA transfer request input (DREQ0)\n"); break; } PORTTRACE(" Pin 12\n"); switch ((sh1_cxt.onchip.pfc.pacr1 >> 8) & 3) { case 0: PORTTRACE("\tInput / output(PA12)\n"); break; case 1: PORTTRACE("\tInterrupt request input (IRQ0)\n"); break; case 2: PORTTRACE("\tITU timer clock input (TCLKA)\n"); break; case 3: PORTTRACE("\tDMA transfer acknowledge output (DACK0)\n"); break; } PORTTRACE(" Pin 11\n"); switch ((sh1_cxt.onchip.pfc.pacr1 >> 6) & 3) { case 0: PORTTRACE("\tInput / output(PA11)\n"); break; case 1: PORTTRACE("\tUpper data bus parity input/output (DPH)\n"); break; case 2: PORTTRACE("\tITU input capture/output compare (TIOCB1)\n"); break; case 3: PORTTRACE("\tReserved\n"); break; } PORTTRACE(" Pin 10\n"); switch ((sh1_cxt.onchip.pfc.pacr1 >> 4) & 3) { case 0: PORTTRACE("\tInput / output(PA10)\n"); break; case 1: PORTTRACE("\tLower data bus parity input/output (DPL)\n"); break; case 2: PORTTRACE("\tITU input capture/output compare (TIOCA1)\n"); break; case 3: PORTTRACE("\tReserved\n"); break; } PORTTRACE(" Pin 9\n"); switch ((sh1_cxt.onchip.pfc.pacr1 >> 2) & 3) { case 0: PORTTRACE("\tInput / output(PA9)\n"); break; case 1: PORTTRACE("\tAddress hold output (AH)\n"); break; case 2: PORTTRACE("\tA/D conversion trigger input (ADTRG)\n"); break; case 3: PORTTRACE("\tInterrupt request output (IRQOUT)\n"); break; } PORTTRACE(" Pin 8\n"); switch ((sh1_cxt.onchip.pfc.pacr1) & 1) { case 0: PORTTRACE("\tInput / output(PA8)\n"); break; case 1: PORTTRACE("\tBus request input (BREQ)\n"); break; } } void print_pacr2() { PORTTRACE("PACR2\n"); PORTTRACE(" Pin 7\n"); if(!((sh1_cxt.onchip.pfc.pacr2) & (1 << 14))) PORTTRACE("\tInput / output(PA7)\n"); else PORTTRACE("\tBus request acknowledge output (BACK)\n"); PORTTRACE(" Pin 6\n"); if (!((sh1_cxt.onchip.pfc.pacr2) & (1 << 12))) PORTTRACE("\tInput / output(PA6)\n"); else PORTTRACE("\tRead output (RD) \n"); PORTTRACE(" Pin 5\n"); if (!((sh1_cxt.onchip.pfc.pacr2) & (1 << 10))) PORTTRACE("\tInput / output(PA5)\n"); else PORTTRACE("\tUpper write output (WRH) or lower byte strobe output (LBS) \n"); PORTTRACE(" Pin 4\n"); if (!((sh1_cxt.onchip.pfc.pacr2) & (1 << 8))) PORTTRACE("\tInput / output(PA4)\n"); else PORTTRACE("\tLower write output (WRL) or write output (WR) \n"); PORTTRACE(" Pin 3\n"); switch ((sh1_cxt.onchip.pfc.pacr2 >> 6) & 3) { case 0: PORTTRACE("\tInput / output(PA3)\n"); break; case 1: PORTTRACE("\tChip select output (CS7)\n"); break; case 2: PORTTRACE("\tWait state input (WAIT) \n"); break; case 3: PORTTRACE("\tReserved\n"); break; } PORTTRACE(" Pin 2\n"); switch ((sh1_cxt.onchip.pfc.pacr2 >> 4) & 3) { case 0: PORTTRACE("\tInput / output(PA2)\n"); break; case 1: PORTTRACE("\tChip select output (CS6)\n"); break; case 2: PORTTRACE("\tITU input capture/output compare (TIOCB0)\n"); break; case 3: PORTTRACE("\tReserved\n"); break; } PORTTRACE(" Pin 1\n"); switch ((sh1_cxt.onchip.pfc.pacr2 >> 2) & 3) { case 0: PORTTRACE("\tInput / output(PA1)\n"); break; case 1: PORTTRACE("\tChip select output (CS5)\n"); break; case 2: PORTTRACE("\tRow address strobe output (RAS)\n"); break; case 3: PORTTRACE("\tReserved\n"); break; } PORTTRACE(" Pin 0\n"); switch (sh1_cxt.onchip.pfc.pacr2 & 3) { case 0: PORTTRACE("\tInput / output(PA0)\n"); break; case 1: PORTTRACE("\tChip select output (CS4)\n"); break; case 2: PORTTRACE("\tITU input capture/output compare (TIOCA0)\n"); break; case 3: PORTTRACE("\tReserved\n"); break; } } void print_pbcr1() { PORTTRACE("PBCR1\n"); PORTTRACE(" Pin 15\n"); switch ((sh1_cxt.onchip.pfc.pbcr1 >> 14) & 3) { case 0: PORTTRACE("\tInput / output(PB15)\n"); break; case 1: PORTTRACE("\tInterrupt request input (IRQ7)\n"); break; case 2: PORTTRACE("\tReserved\n"); break; case 3: PORTTRACE("\tTiming pattern output (TP15)\n"); break; } PORTTRACE(" Pin 14\n"); switch ((sh1_cxt.onchip.pfc.pbcr1 >> 12) & 3) { case 0: PORTTRACE("\tInput / output(PB14)\n"); break; case 1: PORTTRACE("\tInterrupt request input (IRQ6)\n"); break; case 2: PORTTRACE("\tReserved\n"); break; case 3: PORTTRACE("\tTiming pattern output (TP14)\n"); break; } PORTTRACE(" Pin 13\n"); switch ((sh1_cxt.onchip.pfc.pbcr1 >> 10) & 3) { case 0: PORTTRACE("\tInput / output(PB13)\n"); break; case 1: PORTTRACE("\tInterrupt request input (IRQ5)\n"); break; case 2: PORTTRACE("\tSerial clock input/output (SCK1)\n"); break; case 3: PORTTRACE("\tTiming pattern output (TP13)\n"); break; } PORTTRACE(" Pin 12\n"); switch ((sh1_cxt.onchip.pfc.pbcr1 >> 8) & 3) { case 0: PORTTRACE("\tInput / output(PB12)\n"); break; case 1: PORTTRACE("\tInterrupt request input (IRQ4)\n"); break; case 2: PORTTRACE("\tSerial clock input/output (SCK0)\n"); break; case 3: PORTTRACE("\tTiming pattern output (TP12)\n"); break; } PORTTRACE(" Pin 11\n"); switch ((sh1_cxt.onchip.pfc.pbcr1 >> 6) & 3) { case 0: PORTTRACE("\tInput / output(PB11)\n"); break; case 1: PORTTRACE("\tReserved\n"); break; case 2: PORTTRACE("\tTransmit data output (TxD1)\n"); break; case 3: PORTTRACE("\tTiming pattern output (TP11)\n"); break; } PORTTRACE(" Pin 10\n"); switch ((sh1_cxt.onchip.pfc.pbcr1 >> 4) & 3) { case 0: PORTTRACE("\tInput / output(PB10)\n"); break; case 1: PORTTRACE("\tReserved\n"); break; case 2: PORTTRACE("\tReceive data input (RxD1)\n"); break; case 3: PORTTRACE("\tTiming pattern output (TP10)\n"); break; } PORTTRACE(" Pin 9\n"); switch ((sh1_cxt.onchip.pfc.pbcr1 >> 2) & 3) { case 0: PORTTRACE("\tInput / output(PB9)\n"); break; case 1: PORTTRACE("\tReserved\n"); break; case 2: PORTTRACE("\tTransmit data output (TxD0)\n"); break; case 3: PORTTRACE("\tTiming pattern output (TP9)\n"); break; } PORTTRACE(" Pin 8\n"); switch ((sh1_cxt.onchip.pfc.pbcr1 >> 0) & 3) { case 0: PORTTRACE("\tInput / output(PB8)\n"); break; case 1: PORTTRACE("\tReserved\n"); break; case 2: PORTTRACE("\tReceive data input (RxD0)\n"); break; case 3: PORTTRACE("\tTiming pattern output (TP8)\n"); break; } } void print_pbcr2() { PORTTRACE("PBCR2\n"); PORTTRACE(" Pin 7\n"); switch ((sh1_cxt.onchip.pfc.pbcr2 >> 14) & 3) { case 0: PORTTRACE("\tInput / output(PB7)\n"); break; case 1: PORTTRACE("\tITU timer clock input (TCLKD)\n"); break; case 2: PORTTRACE("\tITU output compare (TOCXB4)\n"); break; case 3: PORTTRACE("\tTiming pattern output (TP7)\n"); break; } PORTTRACE(" Pin 6\n"); switch ((sh1_cxt.onchip.pfc.pbcr2 >> 12) & 3) { case 0: PORTTRACE("\tInput / output(PB6)\n"); break; case 1: PORTTRACE("\tITU timer clock input (TCLKC)\n"); break; case 2: PORTTRACE("\tITU output compare (TOCXA4)\n"); break; case 3: PORTTRACE("\tTiming pattern output (TP6)\n"); break; } PORTTRACE(" Pin 5\n"); switch ((sh1_cxt.onchip.pfc.pbcr2 >> 10) & 3) { case 0: PORTTRACE("\tInput / output(PB5)\n"); break; case 1: PORTTRACE("\tReserved\n"); break; case 2: PORTTRACE("\tITU input capture/output compare (TIOCB4)\n"); break; case 3: PORTTRACE("\tTiming pattern output (TP5)\n"); break; } PORTTRACE(" Pin 4\n"); switch ((sh1_cxt.onchip.pfc.pbcr2 >> 8) & 3) { case 0: PORTTRACE("\tInput / output(PB4)\n"); break; case 1: PORTTRACE("\tReserved\n"); break; case 2: PORTTRACE("\tITU input capture/output compare (TIOCA4)\n"); break; case 3: PORTTRACE("\tTiming pattern output (TP4)\n"); break; } PORTTRACE(" Pin 3\n"); switch ((sh1_cxt.onchip.pfc.pbcr2 >> 6) & 3) { case 0: PORTTRACE("\tInput / output(PB3)\n"); break; case 1: PORTTRACE("\tReserved\n"); break; case 2: PORTTRACE("\tITU input capture/output compare (TIOCB3)\n"); break; case 3: PORTTRACE("\tTiming pattern output (TP3)\n"); break; } PORTTRACE(" Pin 2\n"); switch ((sh1_cxt.onchip.pfc.pbcr2 >> 4) & 3) { case 0: PORTTRACE("\tInput / output(PB2)\n"); break; case 1: PORTTRACE("\tReserved\n"); break; case 2: PORTTRACE("\tITU input capture/output compare (TIOCA3)\n"); break; case 3: PORTTRACE("\tTiming pattern output (TP2)\n"); break; } PORTTRACE(" Pin 1\n"); switch ((sh1_cxt.onchip.pfc.pbcr2 >> 2) & 3) { case 0: PORTTRACE("\tInput / output(PB1)\n"); break; case 1: PORTTRACE("\tReserved\n"); break; case 2: PORTTRACE("\tITU input capture/output compare (TIOCB2)\n"); break; case 3: PORTTRACE("\tTiming pattern output (TP1)\n"); break; } PORTTRACE(" Pin 0\n"); switch ((sh1_cxt.onchip.pfc.pbcr2 >> 0) & 3) { case 0: PORTTRACE("\tInput / output(PB0)\n"); break; case 1: PORTTRACE("\tReserved\n"); break; case 2: PORTTRACE("\tITU input capture/output compare (TIOCA2)\n"); break; case 3: PORTTRACE("\tTiming pattern output (TP0)\n"); break; } } void port_debug() { int i; PORTTRACE("PAIOR\n"); for (i = 0; i < 16; i++) { if (sh1_cxt.onchip.pfc.paior & (1 << i)) PORTTRACE("\tPin %d is an output\n", i); else PORTTRACE("\tPin %d is an input\n", i); } PORTTRACE("PBIOR\n"); for (i = 0; i < 16; i++) { if (sh1_cxt.onchip.pfc.pbior & (1 << i)) PORTTRACE("\tPin %d is an output\n", i); else PORTTRACE("\tPin %d is an input\n", i); } print_pacr1(); print_pacr2(); print_pbcr1(); print_pbcr2(); } void print_serial(int which) { PORTTRACE("SCI channel %d\n", which); if (!(sh1_cxt.onchip.sci[which].smr & (1 << 7))) PORTTRACE("\tAsynchronous mode\n"); else PORTTRACE("\tSynchronous mode\n"); if (!(sh1_cxt.onchip.sci[which].smr & (1 << 6))) PORTTRACE("\tEight-bit data\n"); else PORTTRACE("\tSeven-bit data.\n"); if (!(sh1_cxt.onchip.sci[which].smr & (1 << 5))) PORTTRACE("\tParity bit not added or checked \n"); else PORTTRACE("\tParity bit added and checked.\n"); if (!(sh1_cxt.onchip.sci[which].smr & (1 << 4))) PORTTRACE("\tEven parity \n"); else PORTTRACE("\tOdd parity\n"); if (!(sh1_cxt.onchip.sci[which].smr & (1 << 3))) PORTTRACE("\tOne stop bit\n"); else PORTTRACE("\tTwo stop bits\n"); if (!(sh1_cxt.onchip.sci[which].smr & (1 << 2))) PORTTRACE("\tMultiprocessor function disabled \n"); else PORTTRACE("\tMultiprocessor format selected\n"); switch (sh1_cxt.onchip.sci[which].smr & 3) { case 0: PORTTRACE("\tSystem clock\n"); break; case 1: PORTTRACE("\tphi/4\n"); break; case 2: PORTTRACE("\tphi/16\n"); break; case 3: PORTTRACE("\tphi/64\n"); break; } PORTTRACE("SCR"); if (!(sh1_cxt.onchip.sci[which].scr & SCI_TIE)) PORTTRACE("\tTransmit-data-empty interrupt request (TXI) is disabled \n"); else PORTTRACE("\tTransmit-data-empty interrupt request (TXI) is enabled\n"); if (!(sh1_cxt.onchip.sci[which].scr & SCI_RIE)) PORTTRACE("\tReceive-data-full interrupt (RXI) and receive-error interrupt (ERI) requests are disabled \n"); else PORTTRACE("\tReceive-data-full interrupt (RXI) and receive-error interrupt (ERI) requests are enabled\n"); if (!(sh1_cxt.onchip.sci[which].scr & SCI_TE)) PORTTRACE("\tTransmitter disabled \n"); else PORTTRACE("\tTransmitter enabled.\n"); if (!(sh1_cxt.onchip.sci[which].scr & SCI_RE)) PORTTRACE("\tReceiver disabled \n"); else PORTTRACE("\tReceiver enabled.\n"); if (!(sh1_cxt.onchip.sci[which].scr & SCI_MPIE)) PORTTRACE("\tMultiprocessor interrupts are disabled \n"); else PORTTRACE("\tMultiprocessor interrupts are enabled\n"); if (!(sh1_cxt.onchip.sci[which].scr & SCI_TEIE)) PORTTRACE("\tTransmit-end interrupt (TEI) requests are disabled \n"); else PORTTRACE("\tTransmit-end interrupt (TEI) requests are enabled.\n"); if (sh1_cxt.onchip.sci[which].smr & (1 << 7)) { //synchronous mode switch (sh1_cxt.onchip.sci[which].scr & 3) { case 0: case 1: PORTTRACE("\tInternal clock, SCK pin used for serial clock output\n"); break; case 2: case 3: PORTTRACE("\tExternal clock, SCK pin used for serial clock input\n"); break; } } else { //async switch (sh1_cxt.onchip.sci[which].scr & 3) { case 0: PORTTRACE("\tInternal clock, SCK pin used for input pin\n"); break; case 1: PORTTRACE("\tInternal clock, SCK pin used for clock output\n"); break; case 2: case 3: PORTTRACE("\tExternal clock, SCK pin used for clock input\n"); break; } } PORTTRACE("\tBitrate %02X\n", sh1_cxt.onchip.sci[which].brr); //serial pin PORTTRACE("\tSCK0 %d\n", ((sh1_cxt.onchip.pfc.pbcr1 >> 8) & 3)); PORTTRACE("\tIn/out %d (1 means output)\n", ((sh1_cxt.onchip.pfc.pbior >> 12) & 1)); } struct Sh1 sh1_cxt; void onchip_write_timer_byte(struct Onchip * regs, u32 addr, int which_timer, u8 data) { //print_serial(1); //port_debug(); //print_timers(); switch (addr) { case 0: regs->itu.channel[which_timer].tcr = data; return; break; case 1: regs->itu.channel[which_timer].tior = data; return; break; case 2: regs->itu.channel[which_timer].tier = data; return; break; case 3: //can only clear flags if (!(data & 1)) regs->itu.channel[which_timer].tsr &= ~1; if (!(data & 2)) regs->itu.channel[which_timer].tsr &= ~2; if (!(data & 4)) regs->itu.channel[which_timer].tsr &= ~4; return; break; case 4: regs->itu.channel[which_timer].tcnt = (regs->itu.channel[which_timer].tcnt & 0xff) | (data << 8); return; break; case 5: regs->itu.channel[which_timer].tcnt = (regs->itu.channel[which_timer].tcnt & 0xff00) | data; return; break; case 6: regs->itu.channel[which_timer].gra = (regs->itu.channel[which_timer].gra & 0xff) | (data << 8); return; break; case 7: regs->itu.channel[which_timer].gra = (regs->itu.channel[which_timer].gra & 0xff00) | data; return; break; case 8: regs->itu.channel[which_timer].grb = (regs->itu.channel[which_timer].grb & 0xff) | (data << 8); return; break; case 9: regs->itu.channel[which_timer].grb = (regs->itu.channel[which_timer].grb & 0xff00) | data; return; break; case 0xa: regs->itu.channel[which_timer].bra = (regs->itu.channel[which_timer].bra & 0xff) | (data << 8); return; break; case 0xb: regs->itu.channel[which_timer].bra = (regs->itu.channel[which_timer].bra & 0xff00) | data; return; break; case 0xc: regs->itu.channel[which_timer].brb = (regs->itu.channel[which_timer].brb & 0xff) | (data << 8); return; break; case 0xd: regs->itu.channel[which_timer].brb = (regs->itu.channel[which_timer].brb & 0xff00) | data; return; break; } assert(0); } u8 onchip_read_timer_byte(struct Onchip * regs, u32 addr, int which_timer) { //print_timers(); switch (addr) { case 0: return regs->itu.channel[which_timer].tcr; break; case 1: return regs->itu.channel[which_timer].tior; break; case 2: return regs->itu.channel[which_timer].tier; break; case 3: return regs->itu.channel[which_timer].tsr; break; case 4: return regs->itu.channel[which_timer].tcnt >> 8; break; case 5: return regs->itu.channel[which_timer].tcnt & 0xff; break; case 6: return regs->itu.channel[which_timer].gra >> 8; break; case 7: return regs->itu.channel[which_timer].gra & 0xff; break; case 8: return regs->itu.channel[which_timer].grb >> 8; break; case 9: return regs->itu.channel[which_timer].grb & 0xff; break; case 0xa: return regs->itu.channel[which_timer].bra >> 8; break; case 0xb: return regs->itu.channel[which_timer].bra & 0xff; break; case 0xc: return regs->itu.channel[which_timer].brb >> 8; break; case 0xd: return regs->itu.channel[which_timer].brb & 0xff; break; } assert(0); return 0; } void onchip_write_timer_word(struct Onchip * regs, u32 addr, int which_timer, u16 data) { switch (addr) { case 0: case 1: case 2: case 3: //byte access only return; break; case 4: regs->itu.channel[which_timer].tcnt = data; return; break; case 6: regs->itu.channel[which_timer].gra = data; return; break; case 8: regs->itu.channel[which_timer].grb = data; return; break; case 0xa: regs->itu.channel[which_timer].bra = data; return; break; case 0xc: regs->itu.channel[which_timer].brb = data; return; break; } assert(0); } void onchip_write_byte(struct Onchip * regs, u32 addr, u8 data) { CDTRACE("wbreg: %08X %02X\n", addr, data); print_serial(0); if (addr == 0x5FFFF25) { int q = 1; } if (addr >= 0x5FFFE00 && addr <= 0x5FFFEBF) { //unmapped return; } //sci else if (addr >= 0x5FFFEC0 && addr <= 0x5FFFECD) { switch (addr - 0x5FFFEC0) { case 0: regs->sci[0].smr = data; return; break; case 1: regs->sci[0].brr = data; return; break; case 2: regs->sci[0].scr = data; if((data & SCI_TE ) == 0) regs->sci[0].ssr |= SCI_TEND;//tend is set return; break; case 3: regs->sci[0].tdr = data; if (regs->sci[0].tsr_counter == 0) { // If TSR empty, load it immediately regs->sci[0].tsr = data; regs->sci[0].tsr_counter = 8; regs->sci[0].ssr |= SCI_TDRE; } else { regs->sci[0].tdr_written = 1; // flag TDR as pending for next time TSR empties regs->sci[0].ssr &= ~SCI_TDRE; } return; break; case 4: { if (data == 0) { int clear_te = 0; if (regs->sci[0].ssr & SCI_TDRE) clear_te = 1; regs->sci[0].ssr &= 0x6;//save tend/mpb bits (read only) //tend is cleared when software //reads tdre after it has been set to 1 //then writes 0 in tdre if(clear_te) regs->sci[0].ssr &= ~SCI_TEND; return; } else assert(0); } return; break; case 5: //read only return; break; case 6: //nothing return; break; case 7: //nothing return; break; case 8: regs->sci[1].smr = data; return; break; case 9: regs->sci[1].brr = data; return; break; case 0xa: regs->sci[1].scr = data; return; break; case 0xb: regs->sci[1].tdr = data; regs->sci[1].tdr_written = 1;//data is present to transmit return; break; case 0xc: if (data == 0)//only 0 can be written regs->sci[1].ssr = data; return; break; case 0xd: //read only return; break; case 0xe: case 0xf: //nothing return; break; } } else if (addr >= 0x5FFFECE && addr <= 0x5FFFEDF) { //unmapped return; } else if (addr >= 0x5FFFEE0 && addr <= 0x5FFFEEF) { //a/d //read only return; } else if (addr >= 0x5FFFEF0 && addr <= 0x5FFFEFF) { //unmapped return; } else if (addr >= 0x5FFFF00 && addr <= 0x5FFFF03) { switch (addr - 0x5FFFF00) { case 0: regs->itu.tstr = data; return; case 1: regs->itu.tsnc = data; return; case 2: regs->itu.tmdr = data; return; case 3: regs->itu.tfcr = data; return; } } //timer writes else if (addr >= 0x5FFFF04 && addr <= 0x5FFFF3F) { if (addr <= 0x5FFFF0D) onchip_write_timer_byte(regs, addr - 0x5FFFF04, 0, data); else if (addr <= 0x5FFFF17) onchip_write_timer_byte(regs, addr - 0x5FFFF0E, 1, data); else if (addr <= 0x5FFFF21) onchip_write_timer_byte(regs, addr - 0x5FFFF18, 2, data); else if (addr <= 0x5FFFF2F) onchip_write_timer_byte(regs, addr - 0x5FFFF22, 3, data); else if (addr == 0x5FFFF30) { return;//unmapped } else if (addr == 0x5FFFF31) { regs->itu.tocr = data; return; } else onchip_write_timer_byte(regs, addr - 0x5FFFF32, 4, data); return; } else if (addr >= 0x5FFFF40 && addr <= 0x5FFFF7F) { if (addr == 0x5FFFF4e) { regs->dmac.channel[0].chcr = (regs->dmac.channel[0].chcr & 0xff) | data << 8; return; } if (addr == 0x5FFFF4F) { regs->dmac.channel[0].chcr = (regs->dmac.channel[0].chcr & 0xff00) | (data & 0xfd); return; } if (addr == 0x5FFFF5e) { regs->dmac.channel[1].chcr = (regs->dmac.channel[1].chcr & 0xff) | data << 8; return; } if (addr == 0x5FFFF5F) { regs->dmac.channel[1].chcr = (regs->dmac.channel[1].chcr & 0xff00) | (data & 0xfd); return; } if (addr == 0x5FFFF6e) { regs->dmac.channel[2].chcr = (regs->dmac.channel[2].chcr & 0xff) | data << 8; return; } if (addr == 0x5FFFF6F) { regs->dmac.channel[2].chcr = (regs->dmac.channel[2].chcr & 0xff00) | (data & 0xfd); return; } if (addr == 0x5FFFF7e) { regs->dmac.channel[3].chcr = (regs->dmac.channel[3].chcr & 0xff) | data << 8; return; } if (addr == 0x5FFFF7F) { regs->dmac.channel[3].chcr = (regs->dmac.channel[3].chcr & 0xff00) | (data & 0xfd); return; } //dmac //rest is inaccessible from byte writes return; } else if (addr >= 0x5FFFF80 && addr <= 0x5FFFF8F) { //intc switch (addr - 0x5FFFF80) { case 0: case 1: case 2: case 3: return; break; //ipra case 4: regs->intc.ipra = (regs->intc.ipra & 0xff) | data << 8; return; break; case 5: regs->intc.ipra = (regs->intc.ipra & 0xff00) | data; return; break; //iprb case 6: regs->intc.iprb = (regs->intc.iprb & 0xff) | data << 8; return; break; case 7: regs->intc.iprb = (regs->intc.iprb & 0xff00) | data; return; break; //iprc case 8: regs->intc.iprc = (regs->intc.iprc & 0xff) | data << 8; return; break; case 9: regs->intc.iprc = (regs->intc.iprc & 0xff00) | data; return; break; //iprd case 0xa: regs->intc.iprd = (regs->intc.iprd & 0xff) | data << 8; return; break; case 0xb: regs->intc.iprd = (regs->intc.iprd & 0xff00) | data; return; break; //ipre case 0xc: regs->intc.ipre = (regs->intc.ipre & 0xff) | data << 8; return; break; case 0xd: regs->intc.ipre = (regs->intc.ipre & 0xff00) | data; return; break; //icr case 0xe: regs->intc.icr = (regs->intc.icr & 0xff) | data << 8; return; break; case 0xf: regs->intc.icr = (regs->intc.icr & 0xff00) | data; return; break; } } else if (addr >= 0x5FFFF90 && addr <= 0x5FFFF99) { //ubc switch (addr - 0x5FFFF90) { //bar case 0: regs->ubc.bar = (regs->ubc.bar & 0x00ffffff) | data << 24; return; break; case 1: regs->ubc.bar = (regs->ubc.bar & 0xff00ffff) | data << 16; return; break; case 2: regs->ubc.bar = (regs->ubc.bar & 0xffff00ff) | data << 8; return; break; case 3: regs->ubc.bar = (regs->ubc.bar & 0xffffff00) | data; return; break; //bamr case 4: regs->ubc.bamr = (regs->ubc.bamr & 0x00ffffff) | data << 24; return; break; case 5: regs->ubc.bamr = (regs->ubc.bamr & 0xff00ffff) | data << 16; return; break; case 6: regs->ubc.bamr = (regs->ubc.bamr & 0xffff00ff) | data << 8; return; break; case 7: regs->ubc.bamr = (regs->ubc.bamr & 0xffffff00) | data; return; break; //bbr case 8: regs->ubc.bbr = (regs->ubc.bar & 0x00ff) | data << 8; return; break; case 9: regs->ubc.bbr = (regs->ubc.bar & 0xff00) | data; return; break; } } else if (addr >= 0x5FFFF9A && addr <= 0x5FFFF9F) { //unmapped return; } else if (addr >= 0x5FFFFA0 && addr <= 0x5FFFFB3) { //bsc switch (addr - 0x5FFFFA0) { case 0: regs->bsc.bcr = (regs->bsc.bcr & 0x00ff) | data << 8; return; break; case 1: regs->bsc.bcr = (regs->bsc.bcr & 0xff00) | data; return; break; case 2: regs->bsc.wcr1 = (regs->bsc.wcr1 & 0x00ff) | data << 8; return; break; case 3: regs->bsc.wcr1 = (regs->bsc.wcr1 & 0xff00) | data; return; break; case 4: regs->bsc.wcr2 = (regs->bsc.wcr2 & 0x00ff) | data << 8; return; break; case 5: regs->bsc.wcr2 = (regs->bsc.wcr2 & 0xff00) | data; return; break; case 6: regs->bsc.wcr3 = (regs->bsc.wcr3 & 0x00ff) | data << 8; return; break; case 7: regs->bsc.wcr3 = (regs->bsc.wcr3 & 0xff00) | data; return; break; case 8: regs->bsc.dcr = (regs->bsc.dcr & 0x00ff) | data << 8; return; break; case 9: regs->bsc.dcr = (regs->bsc.dcr & 0xff00) | data; return; break; case 0xa: regs->bsc.pcr = (regs->bsc.pcr & 0x00ff) | data << 8; return; break; case 0xb: regs->bsc.pcr = (regs->bsc.pcr & 0xff00) | data; return; break; case 0xc: regs->bsc.rcr = (regs->bsc.rcr & 0x00ff) | data << 8; return; break; case 0xd: regs->bsc.rcr = (regs->bsc.rcr & 0xff00) | data; return; break; case 0xe: regs->bsc.rtcsr = (regs->bsc.rtcsr & 0x00ff) | data << 8; return; break; case 0xf: regs->bsc.rtcsr = (regs->bsc.rtcsr & 0xff00) | data; return; break; //rtcnt case 0x10: regs->bsc.rtcnt = (regs->bsc.rtcnt & 0x00ff) | data << 8; return; break; case 0x11: regs->bsc.rtcnt = (regs->bsc.rtcnt & 0xff00) | data; return; break; //rtcor case 0x12: regs->bsc.rtcor = (regs->bsc.rtcor & 0x00ff) | data << 8; return; break; case 0x13: regs->bsc.rtcor = (regs->bsc.rtcor & 0xff00) | data; return; break; } } else if (addr >= 0x5FFFFb4 && addr <= 0x5FFFFb7) { //unmapped return; } else if (addr >= 0x5FFFFB8 && addr <= 0x5FFFFBB) { //wdt //TODO return; } else if (addr == 0x5FFFFbc) { regs->sbycr = data; return; } else if (addr >= 0x5FFFFBD && addr <= 0x5FFFFBF) { //unmapped return; } else if (addr >= 0x5FFFFC0 && addr <= 0x5FFFFC3) { //port a / b switch (addr - 0x5FFFFC0) { case 0: regs->padr = (regs->padr & 0x00ff) | data << 8; return; break; case 1: regs->padr = (regs->padr & 0xff00) | data; return; break; case 2: regs->pbdr = (regs->pbdr & 0x00ff) | data << 8; return; break; case 3: regs->pbdr = (regs->pbdr & 0xff00) | data; return; break; } } else if (addr >= 0x5FFFFC4 && addr <= 0x5FFFFCF) { //pfc switch (addr - 0x5FFFFC0) { //paior case 4: regs->pfc.paior = (regs->pfc.paior & 0x00ff) | data << 8; return; break; case 5: regs->pfc.paior = (regs->pfc.paior & 0xff00) | data; return; break; //pbior case 6: regs->pfc.pbior = (regs->pfc.pbior & 0x00ff) | data << 8; return; break; case 7: regs->pfc.pbior = (regs->pfc.pbior & 0xff00) | data; return; break; //pacr1 case 8: regs->pfc.pacr1 = (regs->pfc.pacr1 & 0x00ff) | data << 8; return; break; case 9: regs->pfc.pacr1 = (regs->pfc.pacr1 & 0xff00) | data; return; break; //pacr2 case 0xa: regs->pfc.pacr2 = (regs->pfc.pacr2 & 0x00ff) | data << 8; return; break; case 0xb: regs->pfc.pacr2 = (regs->pfc.pacr2 & 0xff00) | data; return; break; //pbcr1 case 0xc: regs->pfc.pbcr1 = (regs->pfc.pbcr1 & 0x00ff) | data << 8; return; break; case 0xd: regs->pfc.pbcr1 = (regs->pfc.pbcr1 & 0xff00) | data; return; break; //pbcr2 case 0xe: regs->pfc.pbcr2 = (regs->pfc.pbcr2 & 0x00ff) | data << 8; return; break; case 0xf: regs->pfc.pbcr2 = (regs->pfc.pbcr2 & 0xff00) | data; return; break; } } else if (addr >= 0x5FFFFD0 && addr <= 0x5FFFFD1) { //port a / b switch (addr - 0x5FFFFD0) { case 0: regs->pcdr = (regs->pcdr & 0x00ff) | data << 8; return; break; case 1: regs->pcdr = (regs->pcdr & 0xff00) | data; return; break; } } else if (addr >= 0x5FFFFD2 && addr <= 0x5FFFFED) { //unmapped return; } else if (addr == 0x5FFFFEE) { //cascr regs->cascr = data; return; } else if (addr == 0x5FFFFEF) { //unmapped return; } else if (addr >= 0x5FFFFF0 && addr <= 0x5FFFFF7) { //tpc switch (addr - 0x5FFFFF0) { case 0: regs->tpc.tpmr = data; return; case 1: regs->tpc.tpcr = data; return; case 2: regs->tpc.nderb = data; return; case 3: regs->tpc.ndera = data; return; case 4: regs->tpc.ndrb = data; return; case 5: regs->tpc.ndra = data; return; case 6: regs->tpc.ndrb = data; return; case 7: regs->tpc.ndra = data; return; } } else if (addr >= 0x5FFFFF8 && addr <= 0x5FFFFFF) { //unmapped return; } assert(0); } u8 onchip_sci_read_byte(struct Onchip * regs, u32 addr, int which) { switch (addr) { case 0: return regs->sci[which].smr; case 1: return regs->sci[which].brr; case 2: return regs->sci[which].scr; case 3: return regs->sci[which].tdr; case 4: return regs->sci[which].ssr; case 5: return regs->sci[which].rdr; } assert(0); return 0; } u8 onchip_read_byte(struct Onchip * regs, u32 addr) { CDTRACE("rbreg: %08X \n", addr); if (addr >= 0x5FFFE00 && addr <= 0x5FFFEBF) { //unmapped return 0; } //sci else if (addr >= 0x5FFFEC0 && addr <= 0x5FFFECD) { if (addr >= 0x5FFFEC0 && addr <= 0x5FFFEC5) { //channel 0 return onchip_sci_read_byte(regs, addr - 0x5FFFEC0, 0); } else if (addr >= 0x5FFFEC6 && addr <= 0x5FFFEC7) { return 0;//unmapped } else if (addr >= 0x5FFFEC8 && addr <= 0x5FFFECD) { //channel 1 return onchip_sci_read_byte(regs, addr - 0x5FFFEC8, 1); } else if (addr >= 0x5FFFECE && addr <= 0x5FFFECF) { return 0;//unmapped } } else if (addr >= 0x5FFFECE && addr <= 0x5FFFEDF) { //unmapped return 0; } else if (addr >= 0x5FFFEE0 && addr <= 0x5FFFEE9) { //a/d switch (addr - 0x5FFFEE0) { //addra case 0: return (regs->addra & 0xff00) >> 8; break; case 1: return regs->addra & 0xff; break; //addrb case 2: return (regs->addrb & 0xff00) >> 8; break; case 3: return regs->addrb & 0xff; break; //addrc case 4: return (regs->addrc & 0xff00) >> 8; break; case 5: return regs->addrc & 0xff; break; //addrd case 6: return (regs->addrd & 0xff00) >> 8; break; case 7: return regs->addrd & 0xff; break; case 8: return regs->adcsr; break; case 9: return regs->adcr; break; } } else if (addr >= 0x5FFFEEa && addr <= 0x5FFFEEf) { return 0;//unmapped } else if (addr >= 0x5FFFEF0 && addr <= 0x5FFFEFF) { //unmapped return 0; } else if (addr >= 0x5FFFF00 && addr <= 0x5FFFF03) { //itu shared switch (addr - 0x5FFFF00) { case 0: return regs->itu.tstr; case 1: return regs->itu.tsnc; case 2: return regs->itu.tmdr; case 3: return regs->itu.tfcr; } } //timer else if (addr >= 0x5FFFF04 && addr <= 0x5FFFF3F) { if (addr <= 0x5FFFF0D) return onchip_read_timer_byte(regs, addr - 0x5FFFF04, 0); else if (addr >= 0x5FFFF0e && addr <= 0x5FFFF17) return onchip_read_timer_byte(regs, addr - 0x5FFFF0E, 1); else if (addr >= 0x5FFFF18 && addr <= 0x5FFFF21) return onchip_read_timer_byte(regs, addr - 0x5FFFF18, 2); else if (addr >= 0x5FFFF22 && addr <= 0x5FFFF2F) return onchip_read_timer_byte(regs, addr - 0x5FFFF22, 3); else if (addr >= 0x5FFFF32 && addr <= 0x5FFFF3F) return onchip_read_timer_byte(regs, addr - 0x5FFFF32, 4); if (addr == 0x05ffff30) return 0;//unmapped if (addr == 0x05ffff31) return regs->itu.tocr; } else if (addr >= 0x5FFFF40 && addr <= 0x5FFFF7F) { //dmac if (addr == 0x5FFFF4E) return regs->dmac.channel[0].chcr >> 8; else if (addr == 0x5FFFF4F) return regs->dmac.channel[0].chcr & 0xff; if (addr == 0x5FFFF48) return regs->dmac.dmaor >> 8; else if (addr == 0x5FFFF49) return regs->dmac.dmaor & 0xff; if (addr == 0x5FFFF5E) return regs->dmac.channel[1].chcr >> 8; else if (addr == 0x5FFFF5F) return regs->dmac.channel[1].chcr & 0xff; if (addr == 0x5FFFF6E) return regs->dmac.channel[2].chcr >> 8; else if (addr == 0x5FFFF6F) return regs->dmac.channel[2].chcr & 0xff; if (addr == 0x5FFFF7E) return regs->dmac.channel[3].chcr >> 8; else if (addr == 0x5FFFF7F) return regs->dmac.channel[3].chcr & 0xff; //the rest is inacessible return 0; } else if (addr >= 0x5FFFF80 && addr <= 0x5FFFF83) { //unmapped? return 0; } else if (addr >= 0x5FFFF84 && addr <= 0x5FFFF8F) { //intc switch (addr - 0x5FFFF80) { case 0: case 1: case 2: case 3: assert(0); break; //ipra case 4: return regs->intc.ipra >> 8; case 5: return regs->intc.ipra & 0xff; //iprb case 6: return regs->intc.iprb >> 8; case 7: return regs->intc.iprb & 0xff; //iprc case 8: return regs->intc.iprc >> 8; case 9: return regs->intc.iprc & 0xff; //iprd case 0xa: return regs->intc.iprd >> 8; case 0xb: return regs->intc.iprd & 0xff; //ipre case 0xc: return regs->intc.ipre >> 8; case 0xd: return regs->intc.ipre & 0xff; //icr case 0xe: return regs->intc.icr >> 8; case 0xf: return regs->intc.icr & 0xff; } } else if (addr >= 0x5FFFF90 && addr <= 0x5FFFF99) { //ubc switch (addr - 0x5FFFF90) { //bar case 0: return regs->ubc.bar & 0xff000000 >> 24; case 1: return regs->ubc.bar & 0x00ff0000 >> 16; case 2: return regs->ubc.bar & 0x0000ff00 >> 8; case 3: return regs->ubc.bar & 0x000000ff >> 0; //bamr case 4: return regs->ubc.bamr & 0xff000000 >> 24; case 5: return regs->ubc.bamr & 0x00ff0000 >> 16; case 6: return regs->ubc.bamr & 0x0000ff00 >> 8; case 7: return regs->ubc.bamr & 0x000000ff >> 0; //bbr case 8: return regs->ubc.bbr >> 8; case 9: return regs->ubc.bbr & 0xff; } } else if (addr >= 0x5FFFF9A && addr <= 0x5FFFF9F) { //unmapped return 0; } else if (addr >= 0x5FFFFA0 && addr <= 0x5FFFFB3) { //bsc switch (addr - 0x5FFFFA0) { case 0: return regs->bsc.bcr >> 8; case 1: return regs->bsc.bcr & 0xff; case 2: return regs->bsc.wcr1 >> 8; case 3: return regs->bsc.wcr1 & 0xff; case 4: return regs->bsc.wcr2 >> 8; case 5: return regs->bsc.wcr2 & 0xff; case 6: return regs->bsc.wcr3 >> 8; case 7: return regs->bsc.wcr3 & 0xff; case 8: return regs->bsc.dcr >> 8; case 9: return regs->bsc.dcr & 0xff; case 0xa: return regs->bsc.pcr >> 8; case 0xb: return regs->bsc.pcr & 0xff; case 0xc: return regs->bsc.rcr >> 8; case 0xd: return regs->bsc.rcr & 0xff; case 0xe: return regs->bsc.rtcsr >> 8; case 0xf: return regs->bsc.rtcsr & 0xff; //rtcnt case 0x10: return regs->bsc.rtcnt >> 8; case 0x11: return regs->bsc.rtcnt & 0xff; //rtcor case 0x12: return regs->bsc.rtcor >> 8; case 0x13: return regs->bsc.rtcor & 0xff; } } else if (addr >= 0x5FFFFb4 && addr <= 0x5FFFFb7) { //unmapped return 0; } else if (addr >= 0x5FFFFB8 && addr <= 0x5FFFFBB) { //wdt //TODO return 0; } else if (addr == 0x5FFFFbc) { //sbycr return regs->sbycr; } else if (addr >= 0x5FFFFBD && addr <= 0x5FFFFBF) { //unmapped return 0; } else if (addr >= 0x5FFFFC0 && addr <= 0x5FFFFC3) { //port a/b data reg switch (addr - 0x5FFFFC0) { case 0: return regs->padr >> 8; case 1: return regs->padr & 0xff; case 2: return regs->pbdr >> 8; case 3: return regs->pbdr & 0xff; } } else if (addr >= 0x5FFFFC4 && addr <= 0x5FFFFCF) { //pfc switch (addr - 0x5FFFFC0) { //paior case 4: return regs->pfc.paior >> 8; case 5: return regs->pfc.paior & 0xff; //pbior case 6: return regs->pfc.pbior >> 8; case 7: return regs->pfc.pbior & 0xff; //pacr1 case 8: return regs->pfc.pacr1 >> 8; case 9: return regs->pfc.pacr1 & 0xff; //pacr2 case 0xa: return regs->pfc.pacr2 >> 8; case 0xb: return regs->pfc.pacr2 & 0xff; //pbcr1 case 0xc: return regs->pfc.pbcr1 >> 8; case 0xd: return regs->pfc.pbcr1 & 0xff; //pbcr2 case 0xe: return regs->pfc.pbcr2 >> 8; case 0xf: return regs->pfc.pbcr2 & 0xff; } } else if (addr == 0x5FFFFD0) { return regs->pcdr >> 8; } else if (addr == 0x5FFFFD1) { return regs->pcdr & 0xff; } else if (addr >= 0x5FFFFD2 && addr <= 0x5FFFFED) { //unmapped return 0; } else if (addr == 0x5FFFFEE) { //cascr return regs->cascr >> 8; } else if (addr == 0x5FFFFEF) { return regs->cascr & 0xff; } else if (addr >= 0x5FFFFF0 && addr <= 0x5FFFFF7) { //tpc switch (addr - 0x5FFFFF0) { case 0: return regs->tpc.tpmr; case 1: return regs->tpc.tpcr; case 2: return regs->tpc.nderb; case 3: return regs->tpc.ndera; case 4: return regs->tpc.ndrb; case 5: return regs->tpc.ndra; case 6: return regs->tpc.ndrb; case 7: return regs->tpc.ndra; } } else if (addr >= 0x5FFFFF8 && addr <= 0x5FFFFFF) { //unmapped return 0; } assert(0); return 0; } void onchip_sci_write_word(struct Onchip * regs, u32 addr, int which, u16 data) { switch (addr) { case 0: regs->sci[which].smr = data >> 8; regs->sci[which].brr = data & 0xff; return; case 2: regs->sci[which].scr = data >> 8; regs->sci[which].tdr = data & 0xff; return; case 4: regs->sci[which].ssr = data >> 8; //rdr is read only return; } assert(0); } void onchip_dmac_write_word(struct Onchip * regs, u32 addr, int which, u16 data) { switch (addr) { case 0: regs->dmac.channel[which].sar = (regs->dmac.channel[which].sar & 0x0000ffff) | data << 16; return; case 2: regs->dmac.channel[which].sar = (regs->dmac.channel[which].sar & 0xffff0000) | data; return; case 4: regs->dmac.channel[which].dar = (regs->dmac.channel[which].dar & 0x0000ffff) | data << 16; return; case 6: regs->dmac.channel[which].dar = (regs->dmac.channel[which].dar & 0xffff0000) | data; return; case 8: //unmapped return; case 0xa: regs->dmac.channel[which].tcr = data; return; case 0xc: //unmapped return; case 0xe: regs->dmac.channel[which].chcr = data & 0xfffd; return; } assert(0); } void onchip_write_word(struct Onchip * regs, u32 addr, u16 data) { print_serial(0); CDTRACE("wwreg: %08X %04X\n", addr, data); if (addr >= 0x5FFFE00 && addr <= 0x5FFFEBF) { //unmapped return; } //sci else if (addr >= 0x5FFFEC0 && addr <= 0x5FFFECD) { if (addr >= 0x5FFFEC0 && addr <= 0x5FFFEC5) { //channel 0 onchip_sci_write_word(regs, addr - 0x5FFFEC0, 0, data); return; } else if (addr >= 0x5FFFEC6 && addr <= 0x5FFFEC7) { return;//unmapped } else if (addr >= 0x5FFFEC8 && addr <= 0x5FFFECD) { //channel 1 onchip_sci_write_word(regs, addr - 0x5FFFEC8, 1, data); return; } else if (addr >= 0x5FFFECE && addr <= 0x5FFFECF) { return;//unmapped } } else if (addr >= 0x5FFFECE && addr <= 0x5FFFEDF) { //unmapped return; } else if (addr >= 0x5FFFEE0 && addr <= 0x5FFFEE9) { //a/d return;//read only } else if (addr >= 0x5FFFEEa && addr <= 0x5FFFEEf) { return;//unmapped } else if (addr >= 0x5FFFEF0 && addr <= 0x5FFFEFF) { //unmapped return; } else if (addr >= 0x5FFFF00 && addr <= 0x5FFFF3F) { if (addr >= 0x5FFFF00 && addr <= 0x5FFFF03) { //not 16-bit accessible return; } if (addr >= 0x5FFFF04 && addr <= 0x5FFFF07) { return;//not 16-bit accessible } if (addr >= 0x5FFFF0E && addr <= 0x5FFFF11) { return;//not 16-bit accessible } if (addr >= 0x5FFFF18 && addr <= 0x5FFFF1B) { return;//not 16-bit accessible } if (addr >= 0x5FFFF22 && addr <= 0x5FFFF25) { return;//not 16-bit accessible } if (addr >= 0x5FFFF32 && addr <= 0x5FFFF35) { return;//not 16-bit accessible } if (addr == 0x5FFFF30) { //unmapped return; } //channel 0 if (addr == 0x5FFFF08) { regs->itu.channel[0].tcnt = data; return; } else if (addr == 0x5FFFF0a) { regs->itu.channel[0].gra = data; return; } else if (addr == 0x5FFFF0c) { regs->itu.channel[0].grb = data; return; } //channel 1 else if (addr == 0x5FFFF12) { regs->itu.channel[1].tcnt = data; return; } else if (addr == 0x5FFFF14) { regs->itu.channel[1].gra = data; return; } else if (addr == 0x5FFFF16) { regs->itu.channel[1].grb = data; return; } //channel 2 else if (addr == 0x5FFFF1c) { regs->itu.channel[2].tcnt = data; return; } else if (addr == 0x5FFFF1e) { regs->itu.channel[2].gra = data; return; } else if (addr == 0x5FFFF20) { regs->itu.channel[2].grb = data; return; } //channel 3 else if (addr == 0x5FFFF26) { regs->itu.channel[3].tcnt = data; return; } else if (addr == 0x5FFFF28) { regs->itu.channel[3].gra = data; return; } else if (addr == 0x5FFFF2a) { regs->itu.channel[3].grb = data; return; } else if (addr == 0x5FFFF2c) { regs->itu.channel[3].bra = data; return; } else if (addr == 0x5FFFF2e) { regs->itu.channel[3].brb = data; return; } //channel 4 else if (addr == 0x5FFFF36) { regs->itu.channel[4].tcnt = data; return; } else if (addr == 0x5FFFF38) { regs->itu.channel[4].gra = data; return; } else if (addr == 0x5FFFF3a) { regs->itu.channel[4].grb = data; return; } else if (addr == 0x5FFFF3c) { regs->itu.channel[4].bra = data; return; } else if (addr == 0x5FFFF3e) { regs->itu.channel[4].brb = data; return; } //everywhere else is inacessible assert(0); } else if (addr >= 0x5FFFF40 && addr <= 0x5FFFF7F) { //dmac if (addr == 0x5FFFF48) { regs->dmac.dmaor = data & 0xfff9; return; } if (addr >= 0x5FFFF40 && addr <= 0x5FFFF4E) { onchip_dmac_write_word(regs, addr - 0x5FFFF40, 0, data); return; } else if (addr >= 0x5FFFF50 && addr <= 0x5FFFF5E) { onchip_dmac_write_word(regs, addr - 0x5FFFF50, 1, data); return; } else if (addr >= 0x5FFFF60 && addr <= 0x5FFFF6E) { onchip_dmac_write_word(regs, addr - 0x5FFFF60, 2, data); return; } else if (addr >= 0x5FFFF70 && addr <= 0x5FFFF7E) { onchip_dmac_write_word(regs, addr - 0x5FFFF70, 3, data); return; } assert(0); } else if (addr >= 0x5FFFF80 && addr <= 0x5FFFF83) { //unmapped? return; } else if (addr >= 0x5FFFF84 && addr <= 0x5FFFF8F) { //intc switch (addr - 0x5FFFF80) { case 0: case 2: return;//unmapped case 4: regs->intc.ipra = data; return; case 6: regs->intc.iprb = data; return; case 8: regs->intc.iprc = data; return; case 0xa: regs->intc.iprd = data; return; case 0xc: regs->intc.ipre = data; return; case 0xe: regs->intc.icr = data; return; } assert(0); } else if (addr >= 0x5FFFF90 && addr <= 0x5FFFF99) { //ubc switch (addr - 0x5FFFF90) { case 0: regs->ubc.bar = (regs->ubc.bar & 0xffff) | data << 16; return; case 2: regs->ubc.bar = (regs->ubc.bar & 0xffff0000) | data; return; case 4: regs->ubc.bamr = (regs->ubc.bamr & 0xffff) | data << 16; return; case 6: regs->ubc.bamr = (regs->ubc.bamr & 0xffff0000) | data; return; case 8: regs->ubc.bbr = data; return; } assert(0); } else if (addr >= 0x5FFFF9A && addr <= 0x5FFFF9F) { //unmapped return; } else if (addr >= 0x5FFFFA0 && addr <= 0x5FFFFB3) { //bsc switch (addr - 0x5FFFFA0) { case 0: regs->bsc.bcr = data; return; case 2: regs->bsc.wcr1 = data; return; case 4: regs->bsc.wcr2 = data; return; case 6: regs->bsc.wcr3 = data; return; case 8: regs->bsc.dcr = data; return; case 0xa: regs->bsc.pcr = data; return; case 0xc: regs->bsc.rcr = data; return; case 0xe: regs->bsc.rtcsr = data; return; case 0x10: regs->bsc.rtcnt = data; return; case 0x12: regs->bsc.rtcor = data; return; } assert(0); } else if (addr >= 0x5FFFFb4 && addr <= 0x5FFFFb7) { //unmapped return; } else if (addr >= 0x5FFFFB8 && addr <= 0x5FFFFBB) { //wdt //TODO return; } else if (addr == 0x5FFFFbc) { //sbycr //what happens to the lower 8 bits? regs->sbycr = data >> 8; return; } else if (addr >= 0x5FFFFBD && addr <= 0x5FFFFBF) { //unmapped return; } else if (addr >= 0x5FFFFC0 && addr <= 0x5FFFFC3) { //port a/b data reg switch (addr - 0x5FFFFC0) { case 0: regs->padr = data; return; case 2: regs->pbdr = data; return; } assert(0); } else if (addr >= 0x5FFFFC4 && addr <= 0x5FFFFCF) { //pfc switch (addr - 0x5FFFFC0) { //paior case 4: regs->pfc.paior = data; return; case 6: regs->pfc.pbior = data; return; case 8: regs->pfc.pacr1 = data; return; case 0xa: regs->pfc.pacr2 = data; return; case 0xc: regs->pfc.pbcr1 = data; return; case 0xe: regs->pfc.pbcr2 = data; return; } assert(0); } else if (addr == 0x5FFFFD0) { regs->pcdr = data; return; } else if (addr >= 0x5FFFFD2 && addr <= 0x5FFFFED) { //unmapped return; } else if (addr == 0x5FFFFEE) { //cascr regs->cascr = data; return; } else if (addr >= 0x5FFFFF0 && addr <= 0x5FFFFF7) { //tpc switch (addr - 0x5FFFFF0) { case 0: regs->tpc.tpmr = data >> 8; regs->tpc.tpcr = data & 0xff; return; case 2: regs->tpc.nderb = data >> 8; regs->tpc.ndera = data & 0xff; return; case 4: regs->tpc.ndrb = data >> 8; regs->tpc.ndra = data & 0xff; return; case 6: regs->tpc.ndrb = data >> 8; regs->tpc.ndra = data & 0xff; return; } assert(0); } else if (addr >= 0x5FFFFF8 && addr <= 0x5FFFFFF) { //unmapped return; } assert(0); return; } u16 onchip_sci_read_word(struct Onchip * regs, u32 addr, int which) { switch (addr) { case 0: return regs->sci[which].smr << 8 | regs->sci[which].brr; case 2: return regs->sci[which].scr << 8 | regs->sci[which].tdr; case 4: return regs->sci[which].ssr << 8 | regs->sci[which].rdr; } assert(0); return 0; } u16 onchip_timer_read_word(struct Onchip * regs, u32 addr, int which_timer) { switch (addr) { case 0: case 1: case 2: case 3: //byte access only break; case 4: return regs->itu.channel[which_timer].tcnt; break; case 6: return regs->itu.channel[which_timer].gra; break; case 8: return regs->itu.channel[which_timer].grb; break; case 0xa: return regs->itu.channel[which_timer].bra; break; case 0xc: return regs->itu.channel[which_timer].brb; break; } assert(0); return 0; } u16 onchip_dmac_read_word(struct Onchip * regs, u32 addr, int which) { switch (addr) { case 0: return regs->dmac.channel[which].sar >> 16; case 2: return regs->dmac.channel[which].sar & 0xffff; case 4: return regs->dmac.channel[which].dar >> 16; case 6: return regs->dmac.channel[which].dar & 0xffff; case 8: //unmapped return 0; case 0xa: return regs->dmac.channel[which].tcr; case 0xc: return 0; case 0xe: return regs->dmac.channel[which].chcr; } assert(0); return 0; } u16 onchip_read_word(struct Onchip * regs, u32 addr) { CDTRACE("rwreg: %08X %04X\n", addr); if (addr >= 0x5FFFE00 && addr <= 0x5FFFEBF) { //unmapped return 0; } //sci else if (addr >= 0x5FFFEC0 && addr <= 0x5FFFECD) { if (addr >= 0x5FFFEC0 && addr <= 0x5FFFEC5) { //channel 0 return onchip_sci_read_word(regs, addr - 0x5FFFEC0, 0); } else if (addr >= 0x5FFFEC6 && addr <= 0x5FFFEC7) { return 0;//unmapped } else if (addr >= 0x5FFFEC8 && addr <= 0x5FFFECD) { //channel 1 return onchip_sci_read_word(regs, addr - 0x5FFFEC8, 1); } else if (addr >= 0x5FFFECE && addr <= 0x5FFFECF) { return 0;//unmapped } } else if (addr >= 0x5FFFECE && addr <= 0x5FFFEDF) { //unmapped return 0; } else if (addr >= 0x5FFFEE0 && addr <= 0x5FFFEE9) { //a/d switch (addr - 0x5FFFEE0) { case 0: return regs->addra; case 2: return regs->addrb; case 4: return regs->addrc; case 6: return regs->addrd; case 8: return regs->adcsr << 8 | regs->adcr; } assert(0); } else if (addr >= 0x5FFFEEa && addr <= 0x5FFFEEf) { return 0;//unmapped } else if (addr >= 0x5FFFEF0 && addr <= 0x5FFFEFF) { //unmapped return 0; } else if (addr >= 0x5FFFF00 && addr <= 0x5FFFF3F) { if (addr >= 0x5FFFF00 && addr <= 0x5FFFF03) { //not 16-bit accessible return 0; } if (addr >= 0x5FFFF04 && addr <= 0x5FFFF07) { return 0;//not 16-bit accessible } if (addr >= 0x5FFFF0E && addr <= 0x5FFFF11) { return 0;//not 16-bit accessible } if (addr >= 0x5FFFF18 && addr <= 0x5FFFF1B) { return 0;//not 16-bit accessible } if (addr >= 0x5FFFF22 && addr <= 0x5FFFF25) { return 0;//not 16-bit accessible } if (addr >= 0x5FFFF32 && addr <= 0x5FFFF35) { return 0;//not 16-bit accessible } if (addr == 0x5FFFF30) { //unmapped return 0; } if (addr >= 0x5FFFF04 && addr <= 0x5FFFF3F) { if (addr <= 0x5FFFF0D) return onchip_timer_read_word(regs, addr - 0x5FFFF04, 0); else if (addr <= 0x5FFFF17) return onchip_timer_read_word(regs, addr - 0x5FFFF0E, 1); else if (addr <= 0x5FFFF21) return onchip_timer_read_word(regs, addr - 0x5FFFF18, 2); else if (addr <= 0x5FFFF2F) return onchip_timer_read_word(regs, addr - 0x5FFFF22, 3); else return onchip_timer_read_word(regs, addr - 0x5FFFF32, 4); } //everywhere else is inacessible assert(0); } else if (addr >= 0x5FFFF40 && addr <= 0x5FFFF7F) { //dmac if (addr == 0x5FFFF48) { return regs->dmac.dmaor; } if (addr >= 0x5FFFF40 && addr <= 0x5FFFF4E) { return onchip_dmac_read_word(regs, addr - 0x5FFFF40, 0); } else if (addr >= 0x5FFFF50 && addr <= 0x5FFFF5E) { return onchip_dmac_read_word(regs, addr - 0x5FFFF50, 1); } else if (addr >= 0x5FFFF60 && addr <= 0x5FFFF6E) { return onchip_dmac_read_word(regs, addr - 0x5FFFF60, 2); } else if (addr >= 0x5FFFF70 && addr <= 0x5FFFF7E) { return onchip_dmac_read_word(regs, addr - 0x5FFFF70, 3); } assert(0); } else if (addr >= 0x5FFFF80 && addr <= 0x5FFFF83) { //unmapped? return 0; } else if (addr >= 0x5FFFF84 && addr <= 0x5FFFF8F) { //intc switch (addr - 0x5FFFF80) { case 0: case 2: return 0;//unmapped case 4: return regs->intc.ipra; case 6: return regs->intc.iprb; case 8: return regs->intc.iprc; case 0xa: return regs->intc.iprd; case 0xc: return regs->intc.ipre; case 0xe: return regs->intc.icr; } assert(0); } else if (addr >= 0x5FFFF90 && addr <= 0x5FFFF99) { //ubc switch (addr - 0x5FFFF90) { case 0: return regs->ubc.bar >> 16; case 2: return regs->ubc.bar & 0xffff; case 4: return regs->ubc.bamr >> 16; case 6: return regs->ubc.bamr & 0xffff; case 8: return regs->ubc.bbr; } assert(0); } else if (addr >= 0x5FFFF9A && addr <= 0x5FFFF9F) { //unmapped return 0; } else if (addr >= 0x5FFFFA0 && addr <= 0x5FFFFB3) { //bsc switch (addr - 0x5FFFFA0) { case 0: return regs->bsc.bcr; case 2: return regs->bsc.wcr1; case 4: return regs->bsc.wcr2; case 6: return regs->bsc.wcr3; case 8: return regs->bsc.dcr; case 0xa: return regs->bsc.pcr; case 0xc: return regs->bsc.rcr; case 0xe: return regs->bsc.rtcsr; case 0x10: return regs->bsc.rtcnt; case 0x12: return regs->bsc.rtcor; } assert(0); } else if (addr >= 0x5FFFFb4 && addr <= 0x5FFFFb7) { //unmapped return 0; } else if (addr >= 0x5FFFFB8 && addr <= 0x5FFFFBB) { //wdt //TODO return 0; } else if (addr == 0x5FFFFbc) { //sbycr //what happens to the lower 8 bits? return regs->sbycr << 8 | 0; } else if (addr >= 0x5FFFFBD && addr <= 0x5FFFFBF) { //unmapped return 0; } else if (addr >= 0x5FFFFC0 && addr <= 0x5FFFFC3) { //port a/b data reg switch (addr - 0x5FFFFC0) { case 0: return regs->padr; case 2: return regs->pbdr; } assert(0); } else if (addr >= 0x5FFFFC4 && addr <= 0x5FFFFCF) { //pfc switch (addr - 0x5FFFFC0) { //paior case 4: return regs->pfc.paior; case 6: return regs->pfc.pbior; case 8: return regs->pfc.pacr1; case 0xa: return regs->pfc.pacr2; case 0xc: return regs->pfc.pbcr1; case 0xe: return regs->pfc.pbcr2; } assert(0); } else if (addr == 0x5FFFFD0) { return regs->pcdr; } else if (addr >= 0x5FFFFD2 && addr <= 0x5FFFFED) { //unmapped return 0; } else if (addr == 0x5FFFFEE) { //cascr return regs->cascr; } else if (addr >= 0x5FFFFF0 && addr <= 0x5FFFFF7) { //tpc switch (addr - 0x5FFFFF0) { case 0: return regs->tpc.tpmr << 8 | regs->tpc.tpcr; case 2: return regs->tpc.nderb << 8 | regs->tpc.ndera; case 4: return regs->tpc.ndrb << 8 | regs->tpc.ndra; case 6: return regs->tpc.ndrb << 8 | regs->tpc.ndra; } assert(0); } else if (addr >= 0x5FFFFF8 && addr <= 0x5FFFFFF) { //unmapped return 0; } assert(0); return 0; } void onchip_dmac_write_long(struct Onchip * regs, u32 addr, int which, u32 data) { switch (addr) { case 0: regs->dmac.channel[which].sar = data; return; case 4: regs->dmac.channel[which].dar = data; return; case 8: //unmapped return; case 0xa: regs->dmac.channel[which].tcr = data; return; case 0xc: //unmapped? return; case 0xe: regs->dmac.channel[which].chcr = (data >> 16) & 0xfffd; return; } assert(0); } void onchip_write_long(struct Onchip * regs, u32 addr, u32 data) { print_serial(0); CDTRACE("wlreg: %08X %08X\n", addr, data); if (addr >= 0x5FFFE00 && addr <= 0x5FFFEBF) { //unmapped return; } //sci else if (addr >= 0x5FFFEC0 && addr <= 0x5FFFECD) { return;//inaccessible from 32 } else if (addr >= 0x5FFFECE && addr <= 0x5FFFEDF) { //unmapped return; } else if (addr >= 0x5FFFEE0 && addr <= 0x5FFFEE9) { //a/d return;//read only } else if (addr >= 0x5FFFEEa && addr <= 0x5FFFEEf) { return;//unmapped } else if (addr >= 0x5FFFEF0 && addr <= 0x5FFFEFF) { //unmapped return; } else if (addr >= 0x5FFFF00 && addr <= 0x5FFFF3F) { if (addr >= 0x5FFFF00 && addr <= 0x5FFFF03) { //not 16-bit accessible return; } if (addr >= 0x5FFFF04 && addr <= 0x5FFFF07) { return;//not 16-bit accessible } if (addr >= 0x5FFFF0E && addr <= 0x5FFFF11) { return;//not 16-bit accessible } if (addr >= 0x5FFFF18 && addr <= 0x5FFFF1B) { return;//not 16-bit accessible } if (addr >= 0x5FFFF22 && addr <= 0x5FFFF25) { return;//not 16-bit accessible } if (addr >= 0x5FFFF32 && addr <= 0x5FFFF35) { return;//not 16-bit accessible } if (addr == 0x5FFFF30) { //unmapped return; } //channel 0 if (addr == 0x5FFFF08) { regs->itu.channel[0].tcnt = data >> 16; regs->itu.channel[0].gra = (data >> 16) & 0xffff; return; } else if (addr == 0x5FFFF0a) { regs->itu.channel[0].gra = data >> 16; regs->itu.channel[0].grb = (data >> 16) & 0xffff; return; } else if (addr == 0x5FFFF0c) { //not allowed return; } //channel 1 else if (addr == 0x5FFFF12) { //not allowed return; } else if (addr == 0x5FFFF14) { regs->itu.channel[1].gra = data >> 16; regs->itu.channel[1].grb = (data >> 16) & 0xffff; return; } else if (addr == 0x5FFFF16) { regs->itu.channel[1].grb = data >> 16; //the rest is ignored? return; } //channel 2 else if (addr == 0x5FFFF1c) { regs->itu.channel[2].tcnt = data >> 16; regs->itu.channel[2].gra = (data >> 16) & 0xffff; return; } else if (addr == 0x5FFFF1e) { regs->itu.channel[2].gra = data >> 16; regs->itu.channel[2].grb = (data >> 16) & 0xffff; return; } else if (addr == 0x5FFFF20) { //not allowed return; } //channel 3 else if (addr == 0x5FFFF26) { //not allowed return; } else if (addr == 0x5FFFF28) { regs->itu.channel[3].gra = data >> 16; regs->itu.channel[3].grb = (data >> 16) & 0xffff; return; } else if (addr == 0x5FFFF2a) { regs->itu.channel[3].grb = data >> 16; regs->itu.channel[3].bra = (data >> 16) & 0xffff; return; } else if (addr == 0x5FFFF2c) { regs->itu.channel[3].bra = data >> 16; regs->itu.channel[3].brb = (data >> 16) & 0xffff; return; } else if (addr == 0x5FFFF2e) { regs->itu.channel[3].brb = data >> 16; //ignored? return; } //channel 4 else if (addr == 0x5FFFF36) { //not allowed return; } else if (addr == 0x5FFFF38) { regs->itu.channel[4].gra = data >> 16; regs->itu.channel[4].grb = (data >> 16) & 0xffff; return; } else if (addr == 0x5FFFF3a) { regs->itu.channel[4].grb = data >> 16; regs->itu.channel[4].bra = (data >> 16) & 0xffff; return; } else if (addr == 0x5FFFF3c) { regs->itu.channel[4].bra = data >> 16; regs->itu.channel[4].brb = (data >> 16) & 0xffff; return; } else if (addr == 0x5FFFF3e) { regs->itu.channel[4].brb = data >> 16; //ignored? return; } assert(0); } else if (addr >= 0x5FFFF40 && addr <= 0x5FFFF7F) { //dmac if (addr == 0x5FFFF48)//dmaor { regs->dmac.dmaor = data & 0xfff9; return; } if (addr >= 0x5FFFF40 && addr <= 0x5FFFF4E) { onchip_dmac_write_long(regs, addr - 0x5FFFF40, 0, data); return; } else if (addr >= 0x5FFFF50 && addr <= 0x5FFFF5E) { onchip_dmac_write_long(regs, addr - 0x5FFFF50, 1, data); return; } else if (addr >= 0x5FFFF60 && addr <= 0x5FFFF6E) { onchip_dmac_write_long(regs, addr - 0x5FFFF60, 2, data); return; } else if (addr >= 0x5FFFF70 && addr <= 0x5FFFF7E) { onchip_dmac_write_long(regs, addr - 0x5FFFF70, 3, data); return; } assert(0); } else if (addr >= 0x5FFFF80 && addr <= 0x5FFFF83) { //unmapped? return; } else if (addr >= 0x5FFFF84 && addr <= 0x5FFFF8F) { //intc switch (addr - 0x5FFFF80) { case 0: case 2: return;//unmapped case 4: regs->intc.ipra = data >> 16; regs->intc.iprb = data & 0xffff; return; case 6: regs->intc.iprb = data >> 16; regs->intc.iprc = data & 0xffff; return; case 8: regs->intc.iprc = data >> 16; regs->intc.iprd = data & 0xffff; return; case 0xa: regs->intc.iprd = data >> 16; regs->intc.ipre = data & 0xffff; return; case 0xc: regs->intc.ipre = data >> 16; regs->intc.icr = data & 0xffff; return; case 0xe: regs->intc.icr = data >> 16; //ignored? return; } assert(0); } else if (addr >= 0x5FFFF90 && addr <= 0x5FFFF99) { //ubc switch (addr - 0x5FFFF90) { case 0: regs->ubc.bar = data; return; case 2://apparently possible? return; case 4: regs->ubc.bamr = data; return; case 6://apparently possible? return; case 8: regs->ubc.bbr = data >> 16; return; } assert(0); } else if (addr >= 0x5FFFF9A && addr <= 0x5FFFF9F) { //unmapped return; } else if (addr >= 0x5FFFFA0 && addr <= 0x5FFFFB3) { //bsc switch (addr - 0x5FFFFA0) { case 0: regs->bsc.bcr = data >> 16; regs->bsc.wcr1 = data & 0xffff; return; case 2: regs->bsc.wcr1 = data >> 16; regs->bsc.wcr2 = data & 0xffff; return; case 4: regs->bsc.wcr2 = data >> 16; regs->bsc.wcr3 = data & 0xffff; return; case 6: regs->bsc.wcr3 = data >> 16; regs->bsc.dcr = data & 0xffff; return; case 8: regs->bsc.dcr = data >> 16; regs->bsc.pcr = data & 0xffff; return; case 0xa: regs->bsc.pcr = data >> 16; regs->bsc.rcr = data & 0xffff; return; //write only with word transfer instructions? case 0xc: return; case 0xe: return; case 0x10: return; case 0x12: return; } assert(0); } else if (addr >= 0x5FFFFb4 && addr <= 0x5FFFFb7) { //unmapped return; } else if (addr >= 0x5FFFFB8 && addr <= 0x5FFFFBB) { //wdt //TODO return; } else if (addr == 0x5FFFFbc) { //sbycr //extra bits? regs->sbycr = data >> 24; return; } else if (addr >= 0x5FFFFBD && addr <= 0x5FFFFBF) { //unmapped return; } else if (addr >= 0x5FFFFC0 && addr <= 0x5FFFFC3) { //port a/b data reg switch (addr - 0x5FFFFC0) { case 0: //init routine requires pbdr to be set { u16 val = 0; val = ((data >> 16) & 0xffff); regs->padr &= ~regs->pfc.paior; regs->padr |= val & regs->pfc.paior; val = data & 0xffff; regs->pbdr &= ~regs->pfc.pbior; regs->pbdr |= val & regs->pfc.pbior; } return; case 2: regs->pbdr = data >> 16; regs->pfc.paior = data & 0xffff;//check this return; } assert(0); } else if (addr >= 0x5FFFFC4 && addr <= 0x5FFFFCF) { //pfc switch (addr - 0x5FFFFC0) { //paior case 4: regs->pfc.paior = data >> 16; regs->pfc.pbior = data & 0xffff; return; case 6: regs->pfc.pbior = data >> 16; regs->pfc.pacr1 = data & 0xffff; return; case 8: regs->pfc.pacr1 = data >> 16; regs->pfc.pacr2 = data & 0xffff; return; case 0xa: regs->pfc.pacr2 = data >> 16; regs->pfc.pbcr1 = data & 0xffff; return; case 0xc: //not allowed according to tpc section but the rom writes this... regs->pfc.pbcr1 = data >> 16; regs->pfc.pbcr2 = data & 0xffff; return; case 0xe: regs->pfc.pbcr2 = data >> 16; regs->pcdr = data & 0xffff;//check this return; } assert(0); } else if (addr == 0x5FFFFD0) { regs->pcdr = data >> 16; return; } else if (addr >= 0x5FFFFD2 && addr <= 0x5FFFFED) { //unmapped return; } else if (addr == 0x5FFFFEE) { //cascr regs->cascr = data >> 16; return; } else if (addr >= 0x5FFFFF0 && addr <= 0x5FFFFF7) { //tpc //not accessible from 32 bit return; assert(0); } else if (addr >= 0x5FFFFF8 && addr <= 0x5FFFFFF) { //unmapped return; } assert(0); return; } u32 onchip_dmac_read_long(struct Onchip * regs, u32 addr, int which) { switch (addr) { case 0: return regs->dmac.channel[which].sar; case 4: return regs->dmac.channel[which].dar; case 8: //unmapped return 0; case 0xa: return regs->dmac.channel[which].tcr; case 0xc: //unmapped? return 0; case 0xe: return regs->dmac.channel[which].chcr << 16 | 0; } assert(0); return 0; } u32 onchip_read_long(struct Onchip * regs, u32 addr) { CDTRACE("rlreg: %08X\n", addr); if (addr >= 0x5FFFE00 && addr <= 0x5FFFEBF) { //unmapped return 0; } //sci else if (addr >= 0x5FFFEC0 && addr <= 0x5FFFECD) { return 0;//inaccessible from 32 } else if (addr >= 0x5FFFECE && addr <= 0x5FFFEDF) { //unmapped return 0; } else if (addr >= 0x5FFFEE0 && addr <= 0x5FFFEE9) { //a/d return 0;//read only } else if (addr >= 0x5FFFEEa && addr <= 0x5FFFEEf) { return 0;//unmapped } else if (addr >= 0x5FFFEF0 && addr <= 0x5FFFEFF) { //unmapped return 0; } //itu else if (addr >= 0x5FFFF00 && addr <= 0x5FFFF3F) { if (addr >= 0x5FFFF00 && addr <= 0x5FFFF03) { //not 16-bit accessible return 0; } if (addr >= 0x5FFFF04 && addr <= 0x5FFFF07) { return 0;//not 16-bit accessible } if (addr >= 0x5FFFF0E && addr <= 0x5FFFF11) { return 0;//not 16-bit accessible } if (addr >= 0x5FFFF18 && addr <= 0x5FFFF1B) { return 0;//not 16-bit accessible } if (addr >= 0x5FFFF22 && addr <= 0x5FFFF25) { return 0;//not 16-bit accessible } if (addr >= 0x5FFFF32 && addr <= 0x5FFFF35) { return 0;//not 16-bit accessible } if (addr == 0x5FFFF30) { //unmapped return 0; } //channel 0 if (addr == 0x5FFFF08) { return regs->itu.channel[0].tcnt << 16 | regs->itu.channel[0].gra; } else if (addr == 0x5FFFF0a) { return regs->itu.channel[0].gra << 16 | regs->itu.channel[0].grb; } else if (addr == 0x5FFFF0c) { //not allowed return 0; } //channel 1 else if (addr == 0x5FFFF12) { //not allowed return 0; } else if (addr == 0x5FFFF14) { return regs->itu.channel[1].gra << 16 | regs->itu.channel[1].grb; } else if (addr == 0x5FFFF16) { //lower part? return regs->itu.channel[1].grb << 16 | 0; } //channel 2 else if (addr == 0x5FFFF1c) { return regs->itu.channel[2].tcnt << 16 | regs->itu.channel[2].gra; } else if (addr == 0x5FFFF1e) { return regs->itu.channel[2].gra << 16 | regs->itu.channel[2].grb; } else if (addr == 0x5FFFF20) { //not allowed return 0; } //channel 3 else if (addr == 0x5FFFF26) { //not allowed return 0; } else if (addr == 0x5FFFF28) { return regs->itu.channel[3].gra << 16 | regs->itu.channel[3].grb; } else if (addr == 0x5FFFF2a) { return regs->itu.channel[3].grb << 16 | regs->itu.channel[3].bra; } else if (addr == 0x5FFFF2c) { return regs->itu.channel[3].bra << 16 | regs->itu.channel[3].brb; } else if (addr == 0x5FFFF2e) { //lower part? return regs->itu.channel[3].brb << 16 | 0; } //channel 4 else if (addr == 0x5FFFF36) { //not allowed return 0 ; } else if (addr == 0x5FFFF38) { return regs->itu.channel[4].gra << 16 | regs->itu.channel[4].grb; } else if (addr == 0x5FFFF3a) { return regs->itu.channel[4].grb << 16 | regs->itu.channel[4].bra; } else if (addr == 0x5FFFF3c) { return regs->itu.channel[4].bra << 16 | regs->itu.channel[4].brb; } else if (addr == 0x5FFFF3e) { //lower part? return regs->itu.channel[4].brb << 16 | 0; } assert(0); } else if (addr >= 0x5FFFF40 && addr <= 0x5FFFF7F) { //dmac if (addr == 0x5FFFF48)//dmaor { return regs->dmac.dmaor << 16; } if (addr >= 0x5FFFF40 && addr <= 0x5FFFF4E) { return onchip_dmac_read_long(regs, addr - 0x5FFFF40, 0); } else if (addr >= 0x5FFFF50 && addr <= 0x5FFFF5E) { return onchip_dmac_read_long(regs, addr - 0x5FFFF50, 1); } else if (addr >= 0x5FFFF60 && addr <= 0x5FFFF6E) { return onchip_dmac_read_long(regs, addr - 0x5FFFF60, 2); } else if (addr >= 0x5FFFF70 && addr <= 0x5FFFF7E) { return onchip_dmac_read_long(regs, addr - 0x5FFFF70, 3); } assert(0); } else if (addr >= 0x5FFFF80 && addr <= 0x5FFFF83) { //unmapped? return 0; } else if (addr >= 0x5FFFF84 && addr <= 0x5FFFF8F) { //intc switch (addr - 0x5FFFF80) { case 0: case 2: return 0;//unmapped case 4: return regs->intc.ipra << 16 | regs->intc.iprb; case 6: return regs->intc.iprb << 16 | regs->intc.iprc; case 8: return regs->intc.iprc << 16 | regs->intc.iprd; case 0xa: return regs->intc.iprd << 16 | regs->intc.ipre; case 0xc: return regs->intc.ipre << 16 | regs->intc.icr; case 0xe: return regs->intc.icr << 16 | 0; } assert(0); } else if (addr >= 0x5FFFF90 && addr <= 0x5FFFF99) { //ubc switch (addr - 0x5FFFF90) { case 0: return regs->ubc.bar; case 2://apparently possible? return 0; case 4: return regs->ubc.bamr; case 6://apparently possible? return 0; case 8: return regs->ubc.bar << 16 | 0; } assert(0); } else if (addr >= 0x5FFFF9A && addr <= 0x5FFFF9F) { //unmapped return 0; } else if (addr >= 0x5FFFFA0 && addr <= 0x5FFFFB3) { //bsc switch (addr - 0x5FFFFA0) { case 0: return regs->bsc.bcr << 16 | regs->bsc.wcr1; case 2: return regs->bsc.wcr1 << 16 | regs->bsc.wcr2; case 4: return regs->bsc.wcr2 << 16 | regs->bsc.wcr3; case 6: return regs->bsc.wcr3 << 16 | regs->bsc.dcr; case 8: return regs->bsc.dcr << 16 | regs->bsc.pcr; case 0xa: return regs->bsc.pcr << 16 | regs->bsc.rcr; case 0xc: return regs->bsc.rcr << 16 | regs->bsc.rtcsr; case 0xe: return regs->bsc.rtcsr << 16 | regs->bsc.rtcnt; case 0x10: return regs->bsc.rtcnt << 16 | regs->bsc.rtcor; case 0x12: return regs->bsc.rtcor << 16 | 0; } assert(0); } else if (addr >= 0x5FFFFb4 && addr <= 0x5FFFFb7) { //unmapped return 0; } else if (addr >= 0x5FFFFB8 && addr <= 0x5FFFFBB) { //wdt //TODO return 0; } else if (addr == 0x5FFFFbc) { //sbycr //extra bits? return regs->sbycr << 24 | 0; } else if (addr >= 0x5FFFFBD && addr <= 0x5FFFFBF) { //unmapped return 0; } else if (addr >= 0x5FFFFC0 && addr <= 0x5FFFFC3) { //port a/b data reg switch (addr - 0x5FFFFC0) { case 0: return regs->padr << 16 | regs->pbdr; case 2: return regs->pbdr << 16 | regs->pfc.paior;//check this } assert(0); } else if (addr >= 0x5FFFFC4 && addr <= 0x5FFFFCF) { //pfc switch (addr - 0x5FFFFC0) { //paior case 4: return regs->pfc.paior << 16 | regs->pfc.pbior; case 6: return regs->pfc.pbior << 16 | regs->pfc.pacr1; case 8: return regs->pfc.pacr1 << 16 | regs->pfc.pacr2; case 0xa: return regs->pfc.pacr2 << 16 | regs->pfc.pbcr1; //not allowed according to tpc section case 0xc: //regs->pfc.pbcr1 = data >> 16; //regs->pfc.pbcr2 = data & 0xffff; return 0; case 0xe: //regs->pfc.pbcr2 = data >> 16; //regs->pcdr = data & 0xffff;//check this return 0; } assert(0); } else if (addr == 0x5FFFFD0) { return regs->pcdr << 16 | 0; } else if (addr >= 0x5FFFFD2 && addr <= 0x5FFFFED) { //unmapped return 0; } else if (addr == 0x5FFFFEE) { //cascr return regs->cascr << 16; } else if (addr >= 0x5FFFFF0 && addr <= 0x5FFFFF7) { //tpc //not accessible from 32 bit return 0; assert(0); } else if (addr >= 0x5FFFFF8 && addr <= 0x5FFFFFF) { //unmapped return 0; } assert(0); return 0; } void memory_map_write_byte(struct Sh1* sh1, u32 addr, u8 data) { u8 area = (addr >> 24) & 7; u8 a27 = (addr >> 27) & 1; int mode_pins = 0; SH1MEMLOG("memory_map_write_byte 0x%08x 0x%04x", addr, data); switch (area) { case 0: //ignore a27 in area 0 if (mode_pins == 2)//010 { // return sh1->rom[addr & 0xffff]; } else { //mode 000 or 001 //external memory space addr &= 0x3FFFFF; } break; case 1: if (!sh1->onchip.bsc.bcr) { //extern memory space } else { } if (a27) { CDTRACE("wbdram: %08X %02X\n", addr, data); T2WriteByte(SH1Dram, addr & 0x7FFFF, data); return; } break; case 2: case 3: case 4: //external memory space if (a27) { ygr_sh1_write_byte(addr, data); return; } break; case 5: //onchip area if (!a27) { onchip_write_byte(&sh1->onchip, addr, data); return; } else { //external memory space } break; case 6: if (a27) { //external memory space //mpeg rom read only return; } else if (!sh1->onchip.bsc.bcr) { //external memory space } break; case 7: //onchip ram CDTRACE("wbram: %08X %02X\n", addr, data); T2WriteByte(sh1->ram, addr & 0x1fff, data); // update_cr_response_values(addr); // update_transfer_buffer(); return; if (a27) { sh1->ram[addr & 0xFFF] = data; } else { //onchip peripherals } break; } assert(0); } u8 memory_map_read_byte(struct Sh1* sh1, u32 addr) { u8 area = (addr >> 24) & 7; u8 a27 = (addr >> 27) & 1; int mode_pins = 0; SH1MEMLOG("memory_map_read_byte 0x%08x", addr); if (addr == 0xF0002D0) { int i = 1; } switch (area) { case 0: //ignore a27 in area 0 CDTRACE("rbrom: %08X %02X\n", addr); return T2ReadByte(SH1Rom, addr & 0xffff); // if (mode_pins == 2)//010 // return sh1->rom[addr & 0xffff]; // else { //mode 000 or 001 //external memory space addr &= 0x3FFFFF; } break; case 1: if (!sh1->onchip.bsc.bcr) { //extern memory space } else { } if (a27) { CDTRACE("rbdram: %08X %02X\n", addr); return T2ReadByte(SH1Dram, addr & 0x7FFFF); } break; case 2: case 3: case 4: //external memory space if (a27) { return ygr_sh1_read_byte(addr); } break; case 5: //onchip area if (!a27) return onchip_read_byte(&sh1->onchip, addr); else { //external memory space } break; case 6: if (a27) { //external memory space //mpeg rom return T2ReadByte(SH1MpegRom, addr & 0x7FFFF); } else if (!sh1->onchip.bsc.bcr) { //external memory space } break; case 7: CDTRACE("rbram: %08X %02X\n", addr); return T2ReadByte(sh1->ram, addr & 0x1fff); //onchip ram if (a27) return sh1->ram[addr & 0xFFF]; else { //onchip peripherals } break; } assert(0); return 0; } u16 memory_map_read_word(struct Sh1* sh1, u32 addr) { u8 area = (addr >> 24) & 7; u8 a27 = (addr >> 27) & 1; int mode_pins = 0; if (addr == 0xF00026C) { int q = 1; } SH1MEMLOG("memory_map_read_word 0x%08x", addr); switch (area) { case 0: //ignore a27 in area 0 CDTRACE("rwrom: %08X %04X\n", addr); return T2ReadWord(SH1Rom, addr & 0xffff); // if (mode_pins == 2)//010 // return sh1->rom[addr & 0xffff]; // else // { //mode 000 or 001 //external memory space addr &= 0x3FFFFF; // } break; case 1: if (!sh1->onchip.bsc.bcr) { //extern memory space } else { } if (a27) { CDTRACE("rwdram: %08X %08X\n", addr); return T2ReadWord(SH1Dram, addr & 0x7FFFF); } break; case 2: case 3: case 4: //external memory space if (a27) { return ygr_sh1_read_word(addr); } break; case 5: //onchip area if (!a27) return onchip_read_word(&sh1->onchip, addr); else { //external memory space } break; case 6: if (a27) { //external memory space //mpeg rom return T2ReadWord(SH1MpegRom, addr & 0x7FFFF); } else if (!sh1->onchip.bsc.bcr) { //external memory space } break; case 7: //onchip ram CDTRACE("rwram: %08X %04X\n", addr); return T2ReadWord(sh1->ram, addr & 0x1fff); if(a27) return sh1->ram[addr & 0xFFF]; else { //onchip peripherals } break; } assert(0); return 0; } void memory_map_write_word(struct Sh1* sh1, u32 addr, u16 data) { u8 area = (addr >> 24) & 7; u8 a27 = (addr >> 27) & 1; int mode_pins = 0; if (addr == 0x0F00026C) { int q = 1; } if (data == 0x20ff) { int q = 1; } SH1MEMLOG("memory_map_write_word 0x%08x 0x%04x", addr, data); switch (area) { case 0: //ignore a27 in area 0 if (mode_pins == 2)//010 { //sh1->rom[addr & 0xffff]; } else { //mode 000 or 001 //external memory space addr &= 0x3FFFFF; } break; case 1: if (!sh1->onchip.bsc.bcr) { //extern memory space } else { } if (a27) { CDTRACE("wwdram: %08X %04X\n", addr, data); T2WriteWord(SH1Dram, addr & 0x7FFFF, data); return; } break; case 2: case 3: case 4: //external memory space if (a27) { ygr_sh1_write_word(addr, data); return; } break; case 5: //onchip area if (!a27) { onchip_write_word(&sh1->onchip, addr, data); return; } else { //external memory space } break; case 6: if (a27) { //external memory space //mpeg rom read only return; } else if (!sh1->onchip.bsc.bcr) { //external memory space } break; case 7: //onchip ram CDTRACE("wwram: %08X %04X\n", addr, data); T2WriteWord(sh1->ram, addr & 0x1fff,data); //update_cr_response_values(addr); return; if (a27) { // return sh1->ram[addr & 0xFFF]; } else { //onchip peripherals } break; } assert(0); return; } u32 memory_map_read_long(struct Sh1* sh1, u32 addr) { u8 area = (addr >> 24) & 7; u8 a27 = (addr >> 27) & 1; int mode_pins = 0; SH1MEMLOG("memory_map_read_long 0x%08x", addr); switch (area) { case 0: //ignore a27 in area 0 return T2ReadLong(SH1Rom, addr & 0xffff); //if (mode_pins == 2)//010 // return sh1->rom[addr & 0xffff]; // else // { //mode 000 or 001 //external memory space addr &= 0x3FFFFF; // } break; case 1: if (!sh1->onchip.bsc.bcr) { //extern memory space } else { } if (a27) { CDTRACE("rlram: %08X\n", addr); return T2ReadLong(SH1Dram, addr & 0x7FFFF); } break; case 2: case 3: case 4: //external memory space if (a27) { return ygr_sh1_read_long(addr); } break; case 5: //onchip area if (!a27) return onchip_read_long(&sh1->onchip, addr); else { //external memory space } break; case 6: if (a27) { //external memory space //mpeg rom area return T2ReadLong(SH1MpegRom, addr & 0x7FFFF); } else if (!sh1->onchip.bsc.bcr) { //external memory space } break; case 7: //onchip ram // if (a27) //apparently both are ram? CDTRACE("rlram: %08X\n", addr); return T2ReadLong(sh1->ram, addr & 0x1fff);//sh1->ram[addr & 0x1FFF]; // else // { //onchip peripherals // } break; } return 0; } void memory_map_write_long(struct Sh1* sh1, u32 addr, u32 data) { u8 area = (addr >> 24) & 7; u8 a27 = (addr >> 27) & 1; int mode_pins = 0; if (addr == 0x0F00026C && data != 0) { int q = 1; } SH1MEMLOG("memory_map_write_long 0x%08x 0x%04x", addr, data); switch (area) { case 0: //ignore a27 in area 0 if (mode_pins == 2)//010 { //sh1->rom[addr & 0xffff]; } else { //mode 000 or 001 //external memory space addr &= 0x3FFFFF; } break; case 1: if (!sh1->onchip.bsc.bcr) { //extern memory space } else { } if (a27) { CDTRACE("wldram: %08X %08X\n", addr, data); T2WriteLong(SH1Dram, addr & 0x7FFFF, data); return; } break; case 2: case 3: case 4: //external memory space //ygr area if (a27) { ygr_sh1_write_long(addr, data); return; } break; case 5: //onchip area if (!a27) { onchip_write_long(&sh1->onchip, addr, data); return; } else { //external memory space } break; case 6: if (a27) { //external memory space //mpeg rom area read only return; } else if (!sh1->onchip.bsc.bcr) { //external memory space } break; case 7: //onchip ram CDTRACE("wlram: %08X %08X\n", addr, data); T2WriteLong(sh1->ram, addr & 0x1fff, data); //update_cr_response_values(addr); return; if (a27) { // return sh1->ram[addr & 0xFFF]; } else { //onchip peripherals } break; } //triggered by yabauseut // assert(0); return; } u8 FASTCALL Sh1MemoryReadByte(UNUSED SH2_struct *sh, USED_IF_DEBUG u32 addr) { return memory_map_read_byte(&sh1_cxt, addr); } u16 FASTCALL Sh1MemoryReadWord(UNUSED SH2_struct *sh, USED_IF_DEBUG u32 addr) { return memory_map_read_word(&sh1_cxt, addr); } u32 FASTCALL Sh1MemoryReadLong(UNUSED SH2_struct *sh, USED_IF_DEBUG u32 addr) { return memory_map_read_long(&sh1_cxt, addr); } void FASTCALL Sh1MemoryWriteByte(UNUSED SH2_struct *sh, USED_IF_DEBUG u32 addr, UNUSED u8 val) { memory_map_write_byte(&sh1_cxt, addr, val); } void FASTCALL Sh1MemoryWriteWord(UNUSED SH2_struct *sh, USED_IF_DEBUG u32 addr, UNUSED u16 val) { memory_map_write_word(&sh1_cxt, addr, val); } void FASTCALL Sh1MemoryWriteLong(UNUSED SH2_struct *sh, USED_IF_DEBUG u32 addr, UNUSED u32 val) { memory_map_write_long(&sh1_cxt, addr, val); } void onchip_sci_init(struct Onchip * regs) { int i; for (i = 0; i < 2; i++) { regs->sci[i].smr = 0; regs->sci[i].brr = 0xff; regs->sci[i].scr = 0; regs->sci[i].tdr = 0xff; regs->sci[i].ssr = 0x84; regs->sci[i].rdr = 0; } } void onchip_ad_init(struct Onchip * regs) { regs->addra = 0; regs->addrb = 0; regs->addrc = 0; regs->addrd = 0; regs->adcsr = 0; regs->adcr = 0x7f; } void onchip_itu_init(struct Onchip * regs)//init values depend on config { int i; regs->itu.tstr = 0xe0; regs->itu.tsnc = 0xe0; regs->itu.tmdr = 0x80; regs->itu.tfcr = 0xc0; regs->itu.tocr = 0xff; for (i = 0; i < 5; i++) { regs->itu.channel[i].tcr = 0x80; regs->itu.channel[i].tior = 0x88; regs->itu.channel[i].tier = 0xf8; regs->itu.channel[i].tsr = 0xf8; regs->itu.channel[i].tcnt = 0; regs->itu.channel[i].gra = 0xff; regs->itu.channel[i].grb = 0xff; //not used for channels 0-2 regs->itu.channel[i].bra = 0xff; regs->itu.channel[i].brb = 0xff; } } void onchip_dmac_init(struct Onchip * regs) { int i; for (i = 0; i < 4; i++) { regs->dmac.channel[i].sar = 0;//undefined regs->dmac.channel[i].dar = 0;//undefined regs->dmac.channel[i].tcr = 0;//undefined regs->dmac.channel[i].chcr = 0; } regs->dmac.dmaor = 0; } void onchip_intc_init(struct Onchip * regs) { regs->intc.ipra = 0; regs->intc.iprb = 0; regs->intc.iprc = 0; regs->intc.iprd = 0; regs->intc.ipre = 0; } void onchip_ubc_init(struct Onchip * regs) { regs->ubc.bar = 0; regs->ubc.bamr = 0; regs->ubc.bbr = 0; } void onchip_bsc_init(struct Onchip * regs) { regs->bsc.bcr = 0; regs->bsc.wcr1 = 0; regs->bsc.wcr2 = 0; regs->bsc.wcr3 = 0; regs->bsc.dcr = 0; regs->bsc.pcr = 0; regs->bsc.rcr = 0; regs->bsc.rtcsr = 0; regs->bsc.rtcnt = 0; regs->bsc.rtcor = 0; } void onchip_wdt_init(struct Onchip * regs) { regs->wdt.tcsr = 0; regs->wdt.tcnt = 0; regs->wdt.rstcsr = 0; } void onchip_pfc_init(struct Onchip * regs) { regs->pfc.paior = 0; regs->pfc.pacr1 = 0x3302; regs->pfc.pacr2 = 0xff95; regs->pfc.pbior = 0; regs->pfc.pbcr1 = 0; regs->pfc.pbcr2 = 0; regs->cascr = 0x5fff; } void onchip_tpc_init(struct Onchip * regs) { regs->tpc.tpmr = 0xf0; regs->tpc.tpcr = 0xff; regs->tpc.nderb = 0; regs->tpc.ndera = 0; regs->tpc.ndrb = 0; regs->tpc.ndra = 0; } void onchip_init(struct Sh1 * sh1) { onchip_sci_init(&sh1->onchip); onchip_ad_init(&sh1->onchip); onchip_itu_init(&sh1->onchip); onchip_dmac_init(&sh1->onchip); onchip_intc_init(&sh1->onchip); onchip_ubc_init(&sh1->onchip); onchip_bsc_init(&sh1->onchip); onchip_wdt_init(&sh1->onchip); sh1->onchip.sbycr = 0; sh1->onchip.padr = 0; sh1->onchip.pbdr = 0; onchip_pfc_init(&sh1->onchip); sh1->onchip.pcdr = 0; onchip_tpc_init(&sh1->onchip); } void sh1_init(struct Sh1* sh1) { memset(sh1, 0, sizeof(struct Sh1)); onchip_init(sh1); } void sh1_init_func() { sh1_init(&sh1_cxt); memset(SH1Dram, 0, 0x80000); cdd_reset(); mpeg_card_init(); sh1_cxt.onchip.pbdr = 0x40c; } static int cycles_since = 0; void tick_timer(int which) { if (sh1_cxt.onchip.itu.tstr & (1 << which))//timer is counting { u16 old_tcnt = sh1_cxt.onchip.itu.channel[which].tcnt; switch (sh1_cxt.onchip.itu.channel[which].tcr & 7) { case 0: sh1_cxt.onchip.itu.channel[which].tcnt++; //internal clock speed break; case 1: if (sh1_cxt.onchip.itu.channel[which].tcnt_fraction == 2) { sh1_cxt.onchip.itu.channel[which].tcnt++; // phi/2 sh1_cxt.onchip.itu.channel[which].tcnt_fraction = 0; } sh1_cxt.onchip.itu.channel[which].tcnt_fraction++; break; case 2: if (sh1_cxt.onchip.itu.channel[which].tcnt_fraction == 4) { sh1_cxt.onchip.itu.channel[which].tcnt++; // phi/4 sh1_cxt.onchip.itu.channel[which].tcnt_fraction = 0; } sh1_cxt.onchip.itu.channel[which].tcnt_fraction++; break; case 3: if (sh1_cxt.onchip.itu.channel[which].tcnt_fraction == 8) { sh1_cxt.onchip.itu.channel[which].tcnt++; // phi/8 sh1_cxt.onchip.itu.channel[which].tcnt_fraction = 0; } sh1_cxt.onchip.itu.channel[which].tcnt_fraction++; break; default: assert(0); } if (sh1_cxt.onchip.itu.channel[which].tier & (1 << 2)) { if (sh1_cxt.onchip.itu.channel[which].tcnt < old_tcnt) { //overflow interrupt TIMERTRACE("*****TCNT4 OVF interrupt*******\n"); if (which == 4) SH2SendInterrupt(SH1, 98, (sh1_cxt.onchip.intc.iprd >> 4) & 0xf); cycles_since = 0; } } } //timer compare a if (sh1_cxt.onchip.itu.channel[which].gra == sh1_cxt.onchip.itu.channel[which].tcnt) { switch (sh1_cxt.onchip.itu.channel[which].tior & 7) { case 0: sh1_cxt.onchip.itu.channel[which].tsr |= 1; //cleared by gra compare match if(((sh1_cxt.onchip.itu.channel[which].tcr >> 5) & 3) == 1) sh1_cxt.onchip.itu.channel[which].tcnt = 0; if (sh1_cxt.onchip.itu.channel[which].tier & 1) SH2SendInterrupt(SH1, 96, (sh1_cxt.onchip.intc.iprd >> 4) & 0xf); break; case 1: //output 0 sh1_cxt.onchip.itu.channel[which].tsr &= ~(1 << 1); break; case 2: //output 1 sh1_cxt.onchip.itu.channel[which].tsr |= (1 << 1); break; case 3: //toggles break; case 4: break; case 5: break; case 6: break; case 7: break; } } //timer compare b if (sh1_cxt.onchip.itu.channel[which].grb == sh1_cxt.onchip.itu.channel[which].tcnt) { switch ((sh1_cxt.onchip.itu.channel[which].tior >> 4) & 7) { case 0: sh1_cxt.onchip.itu.channel[which].tsr |= 2; if (((sh1_cxt.onchip.itu.channel[which].tcr >> 5) & 3) == 2) sh1_cxt.onchip.itu.channel[which].tcnt = 0; if (sh1_cxt.onchip.itu.channel[which].tier & 2) SH2SendInterrupt(SH1, 97, (sh1_cxt.onchip.intc.iprd >> 4) & 0xf); break; case 1: //output 0 sh1_cxt.onchip.itu.channel[which].tsr &= ~(1 << 1); break; case 2: //output 1 sh1_cxt.onchip.itu.channel[which].tsr |= (1 << 1); break; case 3: //toggles break; case 4: break; case 5: break; case 6: break; case 7: break; } } } u16 update_tcnt_fraction(int which, s32 cycles, u8 division) { int remainder = 0; sh1_cxt.onchip.itu.channel[which].tcnt_fraction += cycles % division; if (sh1_cxt.onchip.itu.channel[which].tcnt_fraction >= division) { remainder = 1; sh1_cxt.onchip.itu.channel[which].tcnt_fraction -= division; } return sh1_cxt.onchip.itu.channel[which].tcnt + (cycles / division) + remainder; } u16 update_tcnt_fast(int which, s32 cycles) { switch (sh1_cxt.onchip.itu.channel[which].tcr & 7) { case 0: return sh1_cxt.onchip.itu.channel[which].tcnt + cycles; //internal clock speed break; case 1: return update_tcnt_fraction(which, cycles, 2); break; case 2: return update_tcnt_fraction(which, cycles, 4); break; case 3: return update_tcnt_fraction(which, cycles, 8); break; default: assert(0); } return 0; } int check_gr_range(u16 gr, u16 old_tcnt, u16 new_tcnt) { if (new_tcnt < old_tcnt) { //overflow occured if (gr >= old_tcnt || gr <= new_tcnt) { return 1; } } else { //linear range check if (gr >= old_tcnt && gr <= new_tcnt) { return 1; } } return 0; } void tick_timer_fast(int which, s32 cycles) { u16 old_tcnt = sh1_cxt.onchip.itu.channel[which].tcnt; u16 new_tcnt = 0; int timer_is_counting = sh1_cxt.onchip.itu.tstr & (1 << which); int gra_match = 0, grb_match = 0; if (timer_is_counting) { new_tcnt = update_tcnt_fast(which, cycles); } gra_match = check_gr_range(sh1_cxt.onchip.itu.channel[which].gra, old_tcnt, new_tcnt); grb_match = check_gr_range(sh1_cxt.onchip.itu.channel[which].grb, old_tcnt, new_tcnt); if (timer_is_counting && (sh1_cxt.onchip.itu.channel[which].tier & (1 << 2))) { if (new_tcnt < old_tcnt) { //overflow interrupt TIMERTRACE("*****TCNT4 OVF interrupt*******\n"); if (which == 4) SH2SendInterrupt(SH1, 98, (sh1_cxt.onchip.intc.iprd >> 4) & 0xf); cycles_since = 0; } } //timer compare a if (gra_match) { switch (sh1_cxt.onchip.itu.channel[which].tior & 7) { case 0: sh1_cxt.onchip.itu.channel[which].tsr |= 1; //cleared by gra compare match if (((sh1_cxt.onchip.itu.channel[which].tcr >> 5) & 3) == 1) new_tcnt = 0; if (sh1_cxt.onchip.itu.channel[which].tier & 1) SH2SendInterrupt(SH1, 96, (sh1_cxt.onchip.intc.iprd >> 4) & 0xf); break; case 1: //output 0 sh1_cxt.onchip.itu.channel[which].tsr &= ~(1 << 1); break; case 2: //output 1 sh1_cxt.onchip.itu.channel[which].tsr |= (1 << 1); break; case 3: //toggles break; case 4: break; case 5: break; case 6: break; case 7: break; } } //timer compare b if (grb_match) { switch ((sh1_cxt.onchip.itu.channel[which].tior >> 4) & 7) { case 0: sh1_cxt.onchip.itu.channel[which].tsr |= 2; if (((sh1_cxt.onchip.itu.channel[which].tcr >> 5) & 3) == 2) new_tcnt = 0; if (sh1_cxt.onchip.itu.channel[which].tier & 2) SH2SendInterrupt(SH1, 97, (sh1_cxt.onchip.intc.iprd >> 4) & 0xf); break; case 1: //output 0 sh1_cxt.onchip.itu.channel[which].tsr &= ~(1 << 1); break; case 2: //output 1 sh1_cxt.onchip.itu.channel[which].tsr |= (1 << 1); break; case 3: //toggles break; case 4: break; case 5: break; case 6: break; case 7: break; } } sh1_cxt.onchip.itu.channel[which].tcnt = new_tcnt; } void sh1_serial_recieve_bit(int bit, int channel); void sh1_serial_transmit_bit(int channel, int* output_bit); void receive_bit_from_cdd() { u8 receive_from_cdd = cd_drive_get_serial_bit(); sh1_serial_recieve_bit(receive_from_cdd, 0); } void transmit_bit_to_cdd() { int send_to_cdd = 0; sh1_serial_transmit_bit(0, &send_to_cdd); cd_drive_set_serial_bit(send_to_cdd); } void cd_serial_exec(); void tick_serial(int channel) { u8 bit_rate = sh1_cxt.onchip.sci[channel].brr; //number of cycles per bit is determined by //(brr+1)*4 for settings with an error rate of 0 //sh1 uses 0x63 == 50,000 bits per second int cycles_per_bit = (bit_rate + 1) * 4; u8 clock_mode; static int was_printed = 0; if (sh1_cxt.onchip.sci[0].ssr & SCI_TEND) { if (!was_printed) { was_printed = 1; } sh1_cxt.onchip.sci[channel].serial_clock_counter = 0; //tend is set, no transmission return; } was_printed = 0; //if (!sh1_cxt.onchip.sci[channel].tdr_written) // return; clock_mode = sh1_cxt.onchip.sci[channel].smr & 3; if (clock_mode == 3 || clock_mode == 2)//clock pin set as input assert(0); sh1_cxt.onchip.sci[channel].serial_clock_counter++; if (sh1_cxt.onchip.sci[channel].serial_clock_counter > cycles_per_bit) { if (sh1_cxt.onchip.sci[channel].scr & SCI_TE && sh1_cxt.onchip.sci[channel].scr & SCI_RE) { receive_bit_from_cdd(); transmit_bit_to_cdd(); } sh1_cxt.onchip.sci[channel].serial_clock_counter = 0; } } #define FAST_TIMERS void sh1_onchip_run_cycle() { #ifndef FAST_TIMERS tick_timer(3); tick_timer(4); #endif tick_serial(0); cycles_since++; } void sh1_onchip_run_cycles(s32 cycles) { int i; #ifdef FAST_TIMERS tick_timer_fast(3, cycles); tick_timer_fast(4, cycles); #endif for (i = 0; i < cycles; i++) sh1_onchip_run_cycle(); } //u16 sh1_fetch(struct Sh1* sh1) //{ // u32 PC = 0; // return sh1->rom[PC & 0xffff]; //} //int sh1_execute_instruction(struct Sh1 * sh1) //{ // u16 instruction = sh1_fetch(sh1); // int cycles_executed = 1; // return cycles_executed; //} void test_byte_access(struct Sh1* sh1, u32 addr) { u8 test_val = 0xff, result; memory_map_write_byte(sh1, addr, test_val); result = memory_map_read_byte(sh1, addr); } void test_word_access(struct Sh1* sh1, u32 addr) { u16 test_val = 0xffff, result; memory_map_write_word(sh1, addr, test_val); result = memory_map_read_word(sh1, addr); } void test_long_access(struct Sh1* sh1, u32 addr) { u32 test_val = 0xffffffff, result; memory_map_write_long(sh1, addr, test_val); result = memory_map_read_long(sh1, addr); } void test_mem_map(struct Sh1* sh1) { int i; //ygr memory_map_write_long(sh1, 0xa000000, 0xdeadbeef); //sh1 dram for (i = 0; i < 0x7FFFF; i += 4) { memory_map_write_long(sh1, 0x9000000 + i, 0xdeadbeef); memory_map_read_long(sh1, 0x9000000 + i); } for (i = 0; i < 0x7FFFF; i += 2) { memory_map_write_word(sh1, 0x9000000 + i, 0xdead); memory_map_read_word(sh1, 0x9000000 + i); } for (i = 0; i < 0x7FFFF; i++) { memory_map_write_byte(sh1, 0x9000000 + i, 0xde); memory_map_read_byte(sh1, 0x9000000 + i); } //mpeg rom for (i = 0; i < 0x7FFFF; i += 4) { memory_map_write_long(sh1, 0xe000000 + i, 0xdeadbeef); memory_map_read_long(sh1, 0xe000000 + i); } for (i = 0; i < 0x7FFFF; i += 2) { memory_map_write_word(sh1, 0xe000000 + i, 0xdead); memory_map_read_word(sh1, 0xe000000 + i); } for (i = 0; i < 0x7FFFF; i++) { memory_map_write_byte(sh1, 0xe000000 + i, 0xde); memory_map_read_byte(sh1, 0xe000000 + i); } } void sh1_exec(struct Sh1 * sh1, s32 cycles) { #if 0 u32 i; for (i = 0x5FFFEC0; i < 0x5FFFFFF; i++) { test_byte_access(sh1, i); } for (i = 0x5FFFEC0; i < 0x5FFFFFF; i+=2) { test_word_access(sh1, i); } for (i = 0x5FFFEC0; i < 0x5FFFFFF; i += 4) { test_long_access(sh1, i); } test_mem_map(sh1); s32 cycles_temp = sh1->cycles_remainder - cycles; while (cycles_temp < 0) { int cycles = sh1_execute_instruction(sh1); cycles_temp += cycles; } sh1->cycles_remainder = cycles_temp; #endif } #if 0 int sh1_load_rom(struct Sh1* sh1, const char* filename) { size_t size = 0; FILE * fp = NULL; if (!sh1) return -1; if (!filename) return -1; fp = fopen(filename, "rb"); if (!fp) return -1; if (!fseek(fp, 0, SEEK_END)) return -1; size = ftell(fp); if (size != 0x8000) return -1; if (!fseek(fp, 0, SEEK_SET)) return -1; size = fread(&sh1->rom, sizeof(u8), 0x8000, fp); if (size != 0x8000) return -1; return 1; } #endif int num_output_enables = 0; void sh1_set_output_enable_rising_edge() { tsunami_log_value("OE", 1, 1); } //signal from the cd drive board microcontroller //falling edge void sh1_set_output_enable_falling_edge() { //input capture tsunami_log_value("OE", 0, 1); if (sh1_cxt.onchip.itu.channel[3].tsr & (1 << 1)) { //imfb is set, don't overflow again? return; } if (((sh1_cxt.onchip.itu.channel[3].tior >> 4) & 7) != 5) { //grb is not an input capture reg //capturing the falling edge return; } if (!(sh1_cxt.onchip.itu.channel[3].tier & (1 << 1))) { //imieb intterupt is disbaled return; } num_output_enables++; //store old grb value in brb sh1_cxt.onchip.itu.channel[3].brb = sh1_cxt.onchip.itu.channel[3].grb; //put tcnt value in grb sh1_cxt.onchip.itu.channel[3].grb = sh1_cxt.onchip.itu.channel[3].tcnt; //clear tcnt if(((sh1_cxt.onchip.itu.channel[3].tcr >> 5) & 3) == 2) sh1_cxt.onchip.itu.channel[3].tcnt = 0; sh1_cxt.onchip.itu.channel[3].tsr |= (1 << 1); //trigger an interrupt SH2SendInterrupt(SH1, 93, (sh1_cxt.onchip.intc.iprd >> 8) & 0xf); } //extern int serial_counter; void sh1_serial_recieve_bit(int bit, int channel) { sh1_cxt.onchip.sci[channel].rsr <<= 1; sh1_cxt.onchip.sci[channel].rsr |= bit; sh1_cxt.onchip.sci[channel].rsr_counter++; tsunami_log_value("SCK", sh1_cxt.onchip.sci[channel].rsr_counter, 4); //a full byte has been received, transfer data to rdr if (sh1_cxt.onchip.sci[channel].rsr_counter == 8) { sh1_cxt.onchip.sci[channel].rsr_counter = 0; sh1_cxt.onchip.sci[channel].rdr = sh1_cxt.onchip.sci[channel].rsr; sh1_cxt.onchip.sci[channel].rsr = 0; sh1_cxt.onchip.sci[channel].ssr |= SCI_RDRF; tsunami_log_value("STA", sh1_cxt.onchip.sci[channel].rdr, 8); //trigger interrupt if (sh1_cxt.onchip.sci[0].scr & SCI_RIE)//receive data full interrupt is enabled { SH2SendInterrupt(SH1, 101, sh1_cxt.onchip.intc.iprd & 0xf); tsunami_log_pulse("RXIO", 1); } } } void sh1_serial_transmit_bit(int channel, int* output_bit) { *output_bit = sh1_cxt.onchip.sci[channel].tsr & 1; if (sh1_cxt.onchip.sci[channel].tsr_counter) { sh1_cxt.onchip.sci[channel].tsr >>= 1; sh1_cxt.onchip.sci[channel].tsr_counter--; } //a full byte has been transferred, fill tsr again if (sh1_cxt.onchip.sci[channel].tsr_counter == 0) { if (sh1_cxt.onchip.sci[channel].tdr_written) { sh1_cxt.onchip.sci[channel].tsr = sh1_cxt.onchip.sci[channel].tdr; sh1_cxt.onchip.sci[channel].tsr_counter = 8; sh1_cxt.onchip.sci[channel].tdr_written = 0; sh1_cxt.onchip.sci[channel].ssr |= SCI_TDRE; } else { //end of transmission sh1_cxt.onchip.sci[channel].ssr |= SCI_TEND; } if (sh1_cxt.onchip.sci[0].scr & SCI_TIE) { assert(0); // SH2SendInterrupt(SH1, 101, sh1_cxt.onchip.intc.iprd & 0xf); } } } //pb2 void sh1_set_start(int state) { tsunami_log_value("START", state,1); if (state) sh1_cxt.onchip.pbdr &= ~0x04; else sh1_cxt.onchip.pbdr |= 0x04; } void tick_dma(int which) { u8 destination_mode, source_mode, is_word_size; s8 source_increment, dest_increment; u8 mode = (sh1_cxt.onchip.dmac.channel[which].chcr >> 8) & 0xf; if ((sh1_cxt.onchip.dmac.dmaor & 7) != 1 || //ae, nmif == 0, dme == 1 (sh1_cxt.onchip.dmac.channel[which].chcr & 3) != 1) //te == 0, de == 1 return; //not dreq based dma if (!(mode == 2 || mode == 3))//put / get sector data uses mode 3 return; if (!ygr_dreq_asserted()) return; destination_mode = sh1_cxt.onchip.dmac.channel[which].chcr >> 14; source_mode = (sh1_cxt.onchip.dmac.channel[which].chcr >> 12) & 3; is_word_size = (sh1_cxt.onchip.dmac.channel[which].chcr >> 3) & 1;//otherwise byte size source_increment = 0; dest_increment = 0; //update addresses //mode 0 means fixed if (source_mode == 1) source_increment = 2; else if (source_mode == 2) source_increment = -2; if (destination_mode == 1) dest_increment = 2; else if (destination_mode == 2) dest_increment = -2; if (is_word_size) { u16 src_val = memory_map_read_word(&sh1_cxt, sh1_cxt.onchip.dmac.channel[which].sar); memory_map_write_word(&sh1_cxt, sh1_cxt.onchip.dmac.channel[which].dar, src_val); } else { u8 src_val = memory_map_read_byte(&sh1_cxt, sh1_cxt.onchip.dmac.channel[which].sar); memory_map_write_byte(&sh1_cxt, sh1_cxt.onchip.dmac.channel[which].dar, src_val); } sh1_cxt.onchip.dmac.channel[which].sar += source_increment; sh1_cxt.onchip.dmac.channel[which].dar += dest_increment; sh1_cxt.onchip.dmac.channel[which].tcr--; if (sh1_cxt.onchip.dmac.channel[which].tcr == 0) { sh1_cxt.onchip.dmac.channel[which].is_active = 0; sh1_cxt.onchip.dmac.channel[which].chcr |= 2;//te dma has ended normally if (sh1_cxt.onchip.dmac.channel[which].chcr & 4) { //just do dma1 for now SH2SendInterrupt(SH1, 74, (sh1_cxt.onchip.intc.iprc >> 12) & 0xf); } } } int print_mpeg_jump = 0; void sh1_dma_exec(s32 cycles) { int i; if (SH1->regs.PC == 0xf914) print_mpeg_jump = 1; if (SH1->regs.PC == 0xf91c) print_mpeg_jump = 0; if (print_mpeg_jump && (SH1->regs.PC == 0xf926)) CDLOG("MPEG Jump to %08x\n", SH1->regs.R[0]); //pass mpeg card presence test if (SH1->regs.PC == 0x4c6) { mpeg_card_set_all_irqs(); } //sh1_cxt.onchip.dmac.channel[2].chcr & 2 must not be set at 0xbd1c to pass test //must trigger imia1 to pass test? if (SH1->regs.PC == 0xbd38) sh1_cxt.onchip.dmac.channel[2].chcr |= 2; if (SH1->regs.PC == 0xbece) sh1_cxt.onchip.dmac.channel[3].chcr |= 2; for (i = 0; i < cycles; i++) tick_dma(1); } void sh1_dma_init(int which) { //de, dme, mnif, ae, te must all be zero to start a dma //but just check de and dme for now if (sh1_cxt.onchip.dmac.dmaor & 1 && //dma enabled on all channels sh1_cxt.onchip.dmac.channel[which].chcr & 1)//dma enabled on this channel { sh1_cxt.onchip.dmac.channel[which].is_active = 1; sh1_cxt.onchip.dmac.channel[which].chcr &= 0xfffd;//clear te bit to indicate dma is active } } void sh1_dreq_asserted(int which) { if (!sh1_cxt.onchip.dmac.channel[which].is_active) sh1_dma_init(which); tick_dma(which); } void sh1_assert_tioca(int which) { //capture falling edge of input if ((sh1_cxt.onchip.itu.channel[which].tior & 7) == 5) { //store tcnt in gra sh1_cxt.onchip.itu.channel[which].gra = sh1_cxt.onchip.itu.channel[which].tcnt; //set imfa sh1_cxt.onchip.itu.channel[which].tsr |= 1; if (sh1_cxt.onchip.itu.channel[which].tier & 1) { //imia if(which == 0) SH2SendInterrupt(SH1, 80, (sh1_cxt.onchip.intc.iprc >> 4) & 0xf); else if (which == 1) SH2SendInterrupt(SH1, 84, (sh1_cxt.onchip.intc.iprc >> 0) & 0xf); else if (which == 2) SH2SendInterrupt(SH1, 88, (sh1_cxt.onchip.intc.iprd >> 12) & 0xf); else if (which == 3) SH2SendInterrupt(SH1, 92, (sh1_cxt.onchip.intc.iprd >> 8) & 0xf); else if (which == 4) SH2SendInterrupt(SH1, 96, (sh1_cxt.onchip.intc.iprd >> 4) & 0xf); } } } void sh1_assert_tiocb(int which) { //capture falling edge of input if (((sh1_cxt.onchip.itu.channel[which].tior >> 4) & 7) == 5) { //store tcnt in gra sh1_cxt.onchip.itu.channel[which].grb = sh1_cxt.onchip.itu.channel[which].tcnt; //set imfa sh1_cxt.onchip.itu.channel[which].tsr |= 2; if (sh1_cxt.onchip.itu.channel[which].tier & 2) { //imib if (which == 0) SH2SendInterrupt(SH1, 81, (sh1_cxt.onchip.intc.iprc >> 4) & 0xf); else if (which == 1) SH2SendInterrupt(SH1, 85, (sh1_cxt.onchip.intc.iprc >> 0) & 0xf); else if (which == 2) SH2SendInterrupt(SH1, 89, (sh1_cxt.onchip.intc.iprd >> 12) & 0xf); else if (which == 3) SH2SendInterrupt(SH1, 93, (sh1_cxt.onchip.intc.iprd >> 8) & 0xf); else if (which == 4) SH2SendInterrupt(SH1, 97, (sh1_cxt.onchip.intc.iprd >> 4) & 0xf); } } }yabause-0.9.15/src/movie.c000644 001750 001750 00000030177 12755623101 017335 0ustar00guillaumeguillaume000000 000000 /* This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file movie.c \brief Movie recording functions. */ #include "peripheral.h" #include "scsp.h" #include "movie.h" #include "cs2.h" #include "vdp2.h" // for DisplayMessage() prototype #include "yabause.h" #include "error.h" int RecordingFileOpened; int PlaybackFileOpened; struct MovieStruct Movie; char MovieStatus[40]; int movieLoaded = 0; //Boolean value, 1 if a movie is playing or recording //Counting int framecounter; int lagframecounter; int LagFrameFlag; int FrameAdvanceVariable=0; int headersize=512; ////////////////////////////////////////////////////////////////////////////// static void ReadHeader(FILE* fp) { size_t num_read = 0; fseek(fp, 0, SEEK_SET); fseek(fp, 172, SEEK_SET); num_read = fread(&Movie.Rerecords, sizeof(Movie.Rerecords), 1, fp); fseek(fp, headersize, SEEK_SET); } ////////////////////////////////////////////////////////////////////////////// static void WriteHeader(FILE* fp) { fseek(fp, 0, SEEK_SET); fwrite("YMV", sizeof("YMV"), 1, fp); fwrite(VERSION, sizeof(VERSION), 1, fp); fwrite(cdip->cdinfo, sizeof(cdip->cdinfo), 1, fp); fwrite(cdip->itemnum, sizeof(cdip->itemnum), 1, fp); fwrite(cdip->version, sizeof(cdip->version), 1, fp); fwrite(cdip->date, sizeof(cdip->date), 1, fp); fwrite(cdip->gamename, sizeof(cdip->gamename), 1, fp); fwrite(cdip->region, sizeof(cdip->region), 1, fp); fwrite(&Movie.Rerecords, sizeof(Movie.Rerecords), 1, fp); fwrite(&yabsys.emulatebios, sizeof(yabsys.emulatebios), 1, fp); fwrite(&yabsys.IsPal, sizeof(yabsys.IsPal), 1, fp); fseek(fp, headersize, SEEK_SET); } ////////////////////////////////////////////////////////////////////////////// static void ClearInput(void) { //do something.... } ////////////////////////////////////////////////////////////////////////////// const char* Buttons[8] = {"B", "C", "A", "S", "U", "D", "R", "L"}; const char* Spaces[8] = {" ", " ", " ", " ", " ", " ", " ", " "}; const char* Buttons2[8] = {"", "", "", "L", "Z", "Y", "X", "R"}; const char* Spaces2[8] = {"", "", "", " ", " ", " ", " ", " "}; char str[40]; char InputDisplayString[40]; static void SetInputDisplayCharacters(void) { int x; strcpy(str, ""); for (x = 0; x < 8; x++) { if(PORTDATA1.data[2] & (1 << x)) { size_t spaces_len = strlen(Spaces[x]); if (spaces_len >= 40) return; strcat(str, Spaces[x]); } else { size_t buttons_len = strlen(Buttons[x]); if (buttons_len >= 40) return; strcat(str, Buttons[x]); } } for (x = 0; x < 8; x++) { if(PORTDATA1.data[3] & (1 << x)) { size_t spaces2_len = strlen(Spaces2[x]); if (spaces2_len >= 40) return; strcat(str, Spaces2[x]); } else { size_t buttons2_len = strlen(Buttons2[x]); if (buttons2_len >= 40) return; strcat(str, Buttons2[x]); } } strcpy(InputDisplayString, str); } ////////////////////////////////////////////////////////////////////////////// static void IncrementLagAndFrameCounter(void) { if(LagFrameFlag == 1) lagframecounter++; framecounter++; } ////////////////////////////////////////////////////////////////////////////// int framelength=16; void DoMovie(void) { int x; size_t num_read = 0; if (Movie.Status == 0) return; IncrementLagAndFrameCounter(); LagFrameFlag=1; SetInputDisplayCharacters(); //Read/Write Controller Data if(Movie.Status == Recording) { for (x = 0; x < 8; x++) { fwrite(&PORTDATA1.data[x], 1, 1, Movie.fp); } for (x = 0; x < 8; x++) { fwrite(&PORTDATA2.data[x], 1, 1, Movie.fp); } } if(Movie.Status == Playback) { for (x = 0; x < 8; x++) { num_read = fread(&PORTDATA1.data[x], 1, 1, Movie.fp); } for (x = 0; x < 8; x++) { num_read = fread(&PORTDATA2.data[x], 1, 1, Movie.fp); } //if we get to the end of the movie if(((ftell(Movie.fp)-headersize)/framelength) >= Movie.Frames) { fclose(Movie.fp); PlaybackFileOpened=0; Movie.Status = Stopped; ClearInput(); strcpy(MovieStatus, "Playback Stopped"); } } //Stop Recording/Playback if(Movie.Status != Recording && RecordingFileOpened) { fclose(Movie.fp); RecordingFileOpened=0; Movie.Status = Stopped; strcpy(MovieStatus, "Recording Stopped"); } if(Movie.Status != Playback && PlaybackFileOpened && Movie.ReadOnly != 0) { fclose(Movie.fp); PlaybackFileOpened=0; Movie.Status = Stopped; strcpy(MovieStatus, "Playback Stopped"); } } ////////////////////////////////////////////////////////////////////////////// void MovieLoadState(void) { if (Movie.ReadOnly == 1 && Movie.Status == Playback) { //Movie.Status = Playback; fseek (Movie.fp,headersize+(framecounter * framelength),SEEK_SET); } if(Movie.Status == Recording) { fseek (Movie.fp,headersize+(framecounter * framelength),SEEK_SET); Movie.Rerecords++; } if(Movie.Status == Playback && Movie.ReadOnly == 0) { Movie.Status = Recording; RecordingFileOpened=1; strcpy(MovieStatus, "Recording Resumed"); TruncateMovie(Movie); fseek (Movie.fp,headersize+(framecounter * framelength),SEEK_SET); Movie.Rerecords++; } } ////////////////////////////////////////////////////////////////////////////// void TruncateMovie(struct MovieStruct Movie) { //when we resume recording, shorten the movie so that there isn't //potential garbage data at the end /*//TODO struct MovieBufferStruct tempbuffer; fseek(Movie.fp,0,SEEK_SET); tempbuffer=ReadMovieIntoABuffer(Movie.fp); fclose(Movie.fp); //clear the file and write it again Movie.fp=fopen(Movie.filename,"wb"); fwrite(tempbuffer.data,framelength,framecounter,Movie.fp); fclose(Movie.fp); Movie.fp=fopen(Movie.filename,"r+b"); */ } ////////////////////////////////////////////////////////////////////////////// static int MovieGetSize(FILE* fp) { int size; int fpos; fpos = ftell(fp);//save current pos if (fpos < 0) { YabSetError(YAB_ERR_OTHER, "MovieGetSize fpos is negative"); return 0; } fseek (fp,0,SEEK_END); size=ftell(fp); Movie.Frames=(size-headersize)/ framelength; fseek(fp, fpos, SEEK_SET); //reset back to correct pos return(size); } ////////////////////////////////////////////////////////////////////////////// void MovieToggleReadOnly(void) { if(Movie.Status == Playback) { if(Movie.ReadOnly == 1) { Movie.ReadOnly=0; DisplayMessage("Movie is now read+write."); } else { Movie.ReadOnly=1; DisplayMessage("Movie is now read only."); } } } ////////////////////////////////////////////////////////////////////////////// void StopMovie(void) { if(Movie.Status == Recording && RecordingFileOpened) { WriteHeader(Movie.fp); fclose(Movie.fp); RecordingFileOpened=0; Movie.Status = Stopped; ClearInput(); strcpy(MovieStatus, "Recording Stopped"); } if(Movie.Status == Playback && PlaybackFileOpened && Movie.ReadOnly != 0) { fclose(Movie.fp); PlaybackFileOpened=0; Movie.Status = Stopped; ClearInput(); strcpy(MovieStatus, "Playback Stopped"); } } ////////////////////////////////////////////////////////////////////////////// int SaveMovie(const char *filename) { char* str=malloc(1024); if(Movie.Status == Playback) StopMovie(); if ((Movie.fp = fopen(filename, "w+b")) == NULL) { free(str); return -1; } strcpy(str, filename); Movie.filename=str; RecordingFileOpened=1; framecounter=0; Movie.Status=Recording; strcpy(MovieStatus, "Recording Started"); Movie.Rerecords=0; WriteHeader(Movie.fp); YabauseReset(); return 0; } ////////////////////////////////////////////////////////////////////////////// int PlayMovie(const char *filename) { char* str=malloc(1024); if(Movie.Status == Recording) StopMovie(); if ((Movie.fp = fopen(filename, "r+b")) == NULL) { free(str); return -1; } strcpy(str, filename); Movie.filename=str; PlaybackFileOpened=1; framecounter=0; Movie.ReadOnly = 1; Movie.Status=Playback; Movie.Size = MovieGetSize(Movie.fp); strcpy(MovieStatus, "Playback Started"); ReadHeader(Movie.fp); YabauseReset(); return 0; } ////////////////////////////////////////////////////////////////////////////// void SaveMovieInState(FILE* fp, IOCheck_struct check) { struct MovieBufferStruct tempbuffer; fseek(fp, 0, SEEK_END); if(Movie.Status == Recording || Movie.Status == Playback) { tempbuffer=ReadMovieIntoABuffer(Movie.fp); fwrite(&tempbuffer.size, 4, 1, fp); fwrite(tempbuffer.data, tempbuffer.size, 1, fp); } } ////////////////////////////////////////////////////////////////////////////// void MovieReadState(FILE* fp) { ReadMovieInState(fp); MovieLoadState();//file pointer and truncation } void ReadMovieInState(FILE* fp) { struct MovieBufferStruct tempbuffer; int fpos; size_t num_read = 0; //overwrite the main movie on disk if we are recording or read+write playback if(Movie.Status == Recording || (Movie.Status == Playback && Movie.ReadOnly == 0)) { fpos=ftell(fp);//where we are in the savestate if (fpos < 0) { YabSetError(YAB_ERR_OTHER, "ReadMovieInState fpos is negative"); return; } num_read = fread(&tempbuffer.size, 4, 1, fp);//size if ((tempbuffer.data = (char *)malloc(tempbuffer.size)) == NULL) { return; } num_read = fread(tempbuffer.data, 1, tempbuffer.size, fp);//movie fseek(fp, fpos, SEEK_SET);//reset savestate position rewind(Movie.fp); fwrite(tempbuffer.data, 1, tempbuffer.size, Movie.fp); rewind(Movie.fp); } } ////////////////////////////////////////////////////////////////////////////// struct MovieBufferStruct ReadMovieIntoABuffer(FILE* fp) { int fpos; struct MovieBufferStruct tempbuffer = { 0 }; size_t num_read = 0; fpos = ftell(fp);//save current pos if (fpos < 0) { YabSetError(YAB_ERR_OTHER, "ReadMovieIntoABuffer fpos is negative"); return tempbuffer; } fseek (fp,0,SEEK_END); tempbuffer.size=ftell(fp); //get size rewind(fp); tempbuffer.data = (char*) malloc (sizeof(char)*tempbuffer.size); num_read = fread(tempbuffer.data, 1, tempbuffer.size, fp); fseek(fp, fpos, SEEK_SET); //reset back to correct pos return(tempbuffer); } ////////////////////////////////////////////////////////////////////////////// const char *MakeMovieStateName(const char *filename) { static char *retbuf = NULL; // Save the pointer to avoid memory leaks if(Movie.Status == Recording || Movie.Status == Playback) { const size_t newsize = strlen(filename) + 5 + 1; free(retbuf); retbuf = malloc(newsize); if (!retbuf) { return NULL; // out of memory } sprintf(retbuf, "%smovie", filename); return retbuf; } else { return filename; // unchanged } } ////////////////////////////////////////////////////////////////////////////// //debugging only void TestWrite(struct MovieBufferStruct tempbuffer) { FILE* tempbuffertest; tempbuffertest=fopen("rmiab.txt", "wb"); if (!tempbuffertest) return; fwrite (tempbuffer.data, 1, tempbuffer.size, tempbuffertest); fclose(tempbuffertest); } ////////////////////////////////////////////////////////////////////////////// void PauseOrUnpause(void) { if(FrameAdvanceVariable == RunNormal) { FrameAdvanceVariable=Paused; ScspMuteAudio(SCSP_MUTE_SYSTEM); } else { FrameAdvanceVariable=RunNormal; ScspUnMuteAudio(SCSP_MUTE_SYSTEM); } } ////////////////////////////////////////////////////////////////////////////// int IsMovieLoaded(void) { if (RecordingFileOpened || PlaybackFileOpened) return 1; else return 0; } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/cd-netbsd.c000644 001750 001750 00000011301 12755623101 020045 0ustar00guillaumeguillaume000000 000000 /* Copyright 2004-2005 Theo Berkau Copyright 2004-2005 Guillaume Duhamel Copyright 2005 Joost Peters This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include "cdbase.h" #include "debug.h" static int NetBSDCDInit(const char *); static void NetBSDCDDeInit(void); static s32 NetBSDCDReadTOC(u32 *); static int NetBSDCDGetStatus(void); static int NetBSDCDReadSectorFAD(u32, void *); static void NetBSDCDReadAheadFAD(u32); CDInterface ArchCD = { CDCORE_ARCH, "NetBSD CD Drive", NetBSDCDInit, NetBSDCDDeInit, NetBSDCDGetStatus, NetBSDCDReadTOC, NetBSDCDReadSectorFAD, NetBSDCDReadAheadFAD, }; static int hCDROM; static int NetBSDCDInit(const char * cdrom_name) { if ((hCDROM = open(cdrom_name, O_RDONLY | O_NONBLOCK)) == -1) { LOG("CDInit (%s) failed\n", cdrom_name); return -1; } LOG("CDInit (%s) OK\n", cdrom_name); return 0; } static void NetBSDCDDeInit(void) { if (hCDROM != -1) { close(hCDROM); } LOG("CDDeInit OK\n"); } static s32 NetBSDCDReadTOC(u32 * TOC) { int success; struct ioc_toc_header ctTOC; struct ioc_read_toc_entry ctTOCent; struct cd_toc_entry data; int i, j; int add150 = 0; ctTOCent.address_format = CD_LBA_FORMAT; ctTOCent.data_len = sizeof (struct cd_toc_entry); ctTOCent.data = &data; if (hCDROM != -1) { memset(TOC, 0xFF, 0xCC * 2); memset(&ctTOC, 0xFF, sizeof(struct ioc_toc_header)); if (ioctl(hCDROM, CDIOREADTOCHEADER, &ctTOC) == -1) { return 0; } ctTOCent.starting_track = ctTOC.starting_track; ioctl(hCDROM, CDIOREADTOCENTRYS, &ctTOCent); if (ctTOCent.data->addr.lba == 0) add150 = 150; TOC[0] = ((ctTOCent.data->control << 28) | (ctTOCent.data->addr_type << 24) | ctTOCent.data->addr.lba + add150); // convert TOC to saturn format for (i = ctTOC.starting_track + 1; i <= ctTOC.ending_track; i++) { ctTOCent.starting_track = i; ioctl(hCDROM, CDIOREADTOCENTRYS, &ctTOCent); TOC[i - 1] = (ctTOCent.data->control << 28) | (ctTOCent.data->addr_type << 24) | (ctTOCent.data->addr.lba + add150); } // Do First, Last, and Lead out sections here ctTOCent.starting_track = ctTOC.starting_track; ioctl(hCDROM, CDIOREADTOCENTRYS, &ctTOCent); TOC[99] = (ctTOCent.data->control << 28) | (ctTOCent.data->addr_type << 24) | (ctTOC.starting_track << 16); ctTOCent.starting_track = ctTOC.ending_track; ioctl(hCDROM, CDIOREADTOCENTRYS, &ctTOCent); TOC[100] = (ctTOCent.data->control << 28) | (ctTOCent.data->addr_type << 24) | (ctTOC.starting_track << 16); ctTOCent.starting_track = 0xAA; ioctl(hCDROM, CDIOREADTOCENTRYS, &ctTOCent); TOC[101] = (ctTOCent.data->control << 28) | (ctTOCent.data->addr_type << 24) | (ctTOCent.data->addr.lba + add150); return (0xCC * 2); } return 0; } static int NetBSDCDGetStatus(void) { // 0 - CD Present, disc spinning // 1 - CD Present, disc not spinning // 2 - CD not present // 3 - Tray open // see ../windows/cd.cc for more info return 0; } static int NetBSDCDReadSectorFAD(u32 FAD, void *buffer) { static const s8 syncHdr[] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00 }; if (hCDROM != -1) { memcpy(buffer, syncHdr, sizeof (syncHdr)); lseek(hCDROM, (FAD - 150) * 2048, SEEK_SET); read(hCDROM, (char *)buffer + 0x10, 2048); return 1; } return 0; } static void NetBSDCDReadAheadFAD(UNUSED u32 FAD) { // No-op } yabause-0.9.15/src/sndmac.h000644 001750 001750 00000001611 12755623101 017457 0ustar00guillaumeguillaume000000 000000 /* Copyright 2010 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SNDMAC_H #define SNDMAC_H #define SNDCORE_MAC 3 extern SoundInterface_struct SNDMac; #endif /* !SNDMAC_H */ yabause-0.9.15/src/vidogl.c000644 001750 001750 00000534726 12755623101 017513 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2006 Guillaume Duhamel Copyright 2004 Lawrence Sebald Copyright 2004-2007 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file vidogl.c \brief OpenGL video renderer */ #if defined(HAVE_LIBGL) || defined(__ANDROID__) #include #define EPSILON (1e-10 ) #include "vidogl.h" #include "vidshared.h" #include "debug.h" #include "vdp2.h" #include "yabause.h" #include "ygl.h" #include "yui.h" #if defined WORDS_BIGENDIAN #define SAT2YAB1(alpha,temp) (alpha | (temp & 0x7C00) << 1 | (temp & 0x3E0) << 14 | (temp & 0x1F) << 27) #else #define SAT2YAB1(alpha,temp) (alpha << 24 | (temp & 0x1F) << 3 | (temp & 0x3E0) << 6 | (temp & 0x7C00) << 9) #endif #if defined WORDS_BIGENDIAN #define SAT2YAB2(alpha,dot1,dot2) ((dot2 & 0xFF << 24) | ((dot2 & 0xFF00) << 8) | ((dot1 & 0xFF) << 8) | alpha) #else #define SAT2YAB2(alpha,dot1,dot2) (alpha << 24 | ((dot1 & 0xFF) << 16) | (dot2 & 0xFF00) | (dot2 & 0xFF)) #endif #define COLOR_ADDt(b) (b>0xFF?0xFF:(b<0?0:b)) #define COLOR_ADDb(b1,b2) COLOR_ADDt((signed) (b1) + (b2)) #ifdef WORDS_BIGENDIAN #define COLOR_ADD(l,r,g,b) (COLOR_ADDb((l >> 24) & 0xFF, r) << 24) | \ (COLOR_ADDb((l >> 16) & 0xFF, g) << 16) | \ (COLOR_ADDb((l >> 8) & 0xFF, b) << 8) | \ (l & 0xFF) #else #define COLOR_ADD(l,r,g,b) COLOR_ADDb((l & 0xFF), r) | \ (COLOR_ADDb((l >> 8 ) & 0xFF, g) << 8) | \ (COLOR_ADDb((l >> 16 ) & 0xFF, b) << 16) | \ (l & 0xFF000000) #endif int VIDOGLInit(void); void VIDOGLDeInit(void); void VIDOGLResize(unsigned int, unsigned int, int); int VIDOGLIsFullscreen(void); int VIDOGLVdp1Reset(void); void VIDOGLVdp1DrawStart(void); void VIDOGLVdp1DrawEnd(void); void VIDOGLVdp1NormalSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDOGLVdp1ScaledSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDOGLVdp1DistortedSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDOGLVdp1PolygonDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDOGLVdp1PolylineDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDOGLVdp1LineDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDOGLVdp1UserClipping(u8 * ram, Vdp1 * regs); void VIDOGLVdp1SystemClipping(u8 * ram, Vdp1 * regs); void VIDOGLVdp1LocalCoordinate(u8 * ram, Vdp1 * regs); int VIDOGLVdp2Reset(void); void VIDOGLVdp2DrawStart(void); void VIDOGLVdp2DrawEnd(void); void VIDOGLVdp2DrawScreens(void); void VIDOGLVdp2SetResolution(u16 TVMD); void YglGetGlSize(int *width, int *height); void VIDOGLGetNativeResolution(int *width, int *height, int*interlace); void VIDOGLVdp1ReadFrameBuffer(u32 type, u32 addr, void * out); void VIDOGLVdp2DispOff(void); VideoInterface_struct VIDOGL = { VIDCORE_OGL, "OpenGL Video Interface", VIDOGLInit, VIDOGLDeInit, VIDOGLResize, VIDOGLIsFullscreen, VIDOGLVdp1Reset, VIDOGLVdp1DrawStart, VIDOGLVdp1DrawEnd, VIDOGLVdp1NormalSpriteDraw, VIDOGLVdp1ScaledSpriteDraw, VIDOGLVdp1DistortedSpriteDraw, VIDOGLVdp1PolygonDraw, VIDOGLVdp1PolylineDraw, VIDOGLVdp1LineDraw, VIDOGLVdp1UserClipping, VIDOGLVdp1SystemClipping, VIDOGLVdp1LocalCoordinate, VIDOGLVdp1ReadFrameBuffer, NULL, VIDOGLVdp2Reset, VIDOGLVdp2DrawStart, VIDOGLVdp2DrawEnd, VIDOGLVdp2DrawScreens, YglGetGlSize, VIDOGLGetNativeResolution, VIDOGLVdp2DispOff }; float vdp1wratio=1; float vdp1hratio=1; int GlWidth=320; int GlHeight=224; int vdp1cor=0; int vdp1cog=0; int vdp1cob=0; static int vdp2width; static int vdp2height; static int nbg0priority=0; static int nbg1priority=0; static int nbg2priority=0; static int nbg3priority=0; static int rbg0priority=0; static u32 Vdp2ColorRamGetColor(u32 colorindex, int alpha); static void Vdp2PatternAddrPos(vdp2draw_struct *info, int planex, int x, int planey, int y); static void Vdp2DrawPatternPos(vdp2draw_struct *info, YglTexture *texture, int x, int y, int cx, int cy); static INLINE void ReadVdp2ColorOffset(Vdp2 * regs, vdp2draw_struct *info, int mask); // Window Parameter static vdp2WindowInfo * m_vWindinfo0 = NULL; static int m_vWindinfo0_size = -1; static int m_b0WindowChg; static vdp2WindowInfo * m_vWindinfo1 = NULL; static int m_vWindinfo1_size = -1; static int m_b1WindowChg; static vdp2Lineinfo lineNBG0[512]; static vdp2Lineinfo lineNBG1[512]; // Rotate Screen static vdp2rotationparameter_struct paraA; static vdp2rotationparameter_struct paraB; vdp2rotationparameter_struct * FASTCALL vdp2rGetKValue2W( vdp2rotationparameter_struct * param, int index ); vdp2rotationparameter_struct * FASTCALL vdp2rGetKValue1W( vdp2rotationparameter_struct * param, int index ); vdp2rotationparameter_struct * FASTCALL vdp2rGetKValue2Wm3( vdp2rotationparameter_struct * param, int index ); vdp2rotationparameter_struct * FASTCALL vdp2rGetKValue1Wm3( vdp2rotationparameter_struct * param, int index ); vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode00NoK( vdp2draw_struct * info, int h, int v ); vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode00WithK( vdp2draw_struct * info,int h, int v ); vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode01NoK( vdp2draw_struct * info,int h, int v ); vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode01WithK( vdp2draw_struct * info,int h, int v ); vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode02NoK( vdp2draw_struct * info,int h, int v ); vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode02WithKA( vdp2draw_struct * info,int h, int v ); vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode02WithKB( vdp2draw_struct * info,int h, int v ); vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode03NoK( vdp2draw_struct * info,int h, int v ); vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode03WithKA( vdp2draw_struct * info,int h, int v ); vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode03WithKB( vdp2draw_struct * info,int h, int v ); vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode03WithK( vdp2draw_struct * info,int h, int v ); static void FASTCALL Vdp1ReadPriority(vdp1cmd_struct *cmd, int * priority, int * colorcl, int * normal_shadow ); static void FASTCALL Vdp1ReadTexture(vdp1cmd_struct *cmd, YglSprite *sprite, YglTexture *texture); u32 FASTCALL Vdp2ColorRamGetColorCM01SC0(vdp2draw_struct * info, u32 colorindex, int alpha ); u32 FASTCALL Vdp2ColorRamGetColorCM01SC1(vdp2draw_struct * info, u32 colorindex, int alpha ); u32 FASTCALL Vdp2ColorRamGetColorCM01SC3(vdp2draw_struct * info, u32 colorindex, int alpha ); u32 FASTCALL Vdp2ColorRamGetColorCM2(vdp2draw_struct * info, u32 colorindex, int alpha ); ////////////////////////////////////////////////////////////////////////////// static u32 FASTCALL Vdp1ReadPolygonColor(vdp1cmd_struct *cmd) { int shadow = 0; int priority = 0; int colorcl = 0; int endcnt = 0; int nromal_shadow = 0; u8 SPD = ((cmd->CMDPMOD & 0x40) != 0); u8 END = ((cmd->CMDPMOD & 0x80) != 0); u8 MSB = ((cmd->CMDPMOD & 0x8000) != 0); u32 alpha = 0xFF; u32 color = 0x00; int SPCCCS = (Vdp2Regs->SPCTL >> 12) & 0x3; VDP1LOG("Making new sprite %08X\n", charAddr); Vdp1ReadPriority(cmd, &priority, &colorcl, &nromal_shadow); alpha = 0xF8; if (((Vdp2Regs->CCCTL >> 6) & 0x01) == 0x01) { switch (SPCCCS) { case 0: if (priority <= ((Vdp2Regs->SPCTL >> 8) & 0x07)) alpha = 0xF8 - ((colorcl << 3) & 0xF8); break; case 1: if (priority == ((Vdp2Regs->SPCTL >> 8) & 0x07)) alpha = 0xF8 - ((colorcl << 3) & 0xF8); break; case 2: if (priority >= ((Vdp2Regs->SPCTL >> 8) & 0x07)) alpha = 0xF8 - ((colorcl << 3) & 0xF8); break; case 3: //if( priority <= (Vdp2Regs->SPCTL>>8)&0x07 ) // alpha = 0xF8-((colorcl<<3)&0xF8); break; } } alpha |= priority; switch ((cmd->CMDPMOD >> 3) & 0x7) { case 0: { // 4 bpp Bank mode u32 colorBank = cmd->CMDCOLR; u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4; // Pixel 1 if (!SPD) color = 0x00; else if (MSB) color = (alpha << 24); else if (colorBank == 0x0000){ u32 talpha = 0xF8 - ((colorcl << 3) & 0xF8); talpha |= priority; color = Vdp2ColorRamGetColor(colorBank + colorOffset, talpha); } else if (colorBank == nromal_shadow){ u32 talpha = (u8)0xF8 - (u8)0x80; talpha |= priority; color = (talpha << 24); } else{ if (SPCCCS == 0x03 ){ u16 checkcol = T2ReadWord(Vdp2ColorRam, ((colorBank + colorOffset)<<2)&0xFFF ); if (checkcol & 0x8000){ u32 talpha = 0xF8 - ((colorcl << 3) & 0xF8); talpha |= priority; color = Vdp2ColorRamGetColor(colorBank + colorOffset, talpha); } else{ color = Vdp2ColorRamGetColor(colorBank + colorOffset, alpha); } } else{ color = Vdp2ColorRamGetColor(colorBank + colorOffset, alpha); } } break; } case 1: { // 4 bpp LUT mode u16 temp; u32 colorLut = cmd->CMDCOLR * 8; u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4; if (!SPD) color = 0; else{ temp = T1ReadWord(Vdp1Ram, colorLut & 0x7FFFF); if (temp & 0x8000) { if (MSB) color = (alpha << 24); else color = SAT2YAB1(alpha, temp); }else if (temp != 0x0000) { Vdp1ProcessSpritePixel(Vdp2Regs->SPCTL & 0xF, &temp, &shadow, &priority, &colorcl); if (shadow != 0) { u32 talpha = (u8)0xF8 - (u8)0x80; talpha |= priority; color = (talpha << 24); } else{ #ifdef WORDS_BIGENDIAN priority = ((u8 *)&Vdp2Regs->PRISA)[priority ^ 1] & 0x7; colorcl = ((u8 *)&Vdp2Regs->CCRSA)[colorcl ^ 1] & 0x1F; #else priority = ((u8 *)&Vdp2Regs->PRISA)[priority] & 0x7; colorcl = ((u8 *)&Vdp2Regs->CCRSA)[colorcl] & 0x1F; #endif alpha = 0xF8; if (((Vdp2Regs->CCCTL >> 6) & 0x01) == 0x01) { switch ((Vdp2Regs->SPCTL >> 12) & 0x03) { case 0: if (priority <= ((Vdp2Regs->SPCTL >> 8) & 0x07)) alpha = 0xF8 - ((colorcl << 3) & 0xF8); break; case 1: if (priority == ((Vdp2Regs->SPCTL >> 8) & 0x07)) alpha = 0xF8 - ((colorcl << 3) & 0xF8); break; case 2: if (priority >= ((Vdp2Regs->SPCTL >> 8) & 0x07)) alpha = 0xF8 - ((colorcl << 3) & 0xF8); break; case 3: { u16 checkcol = T2ReadWord(Vdp2ColorRam, ((temp + colorOffset) << Vdp2Internal.ColorMode) & 0xFFF); if (checkcol & 0x8000){ alpha = 0xF8 - ((colorcl << 3) & 0xF8); } } break; } } alpha |= priority; if (MSB) color = (alpha << 24); else color = Vdp2ColorRamGetColor(temp + colorOffset, alpha); } }else{ color = 0x0; } } break; } case 2: { // 8 bpp(64 color) Bank mode u32 colorBank = cmd->CMDCOLR & 0xFFC0; u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4; if (!SPD) color = 0x00; else if (MSB) color = (alpha << 24); else if ( colorBank == nromal_shadow){ u32 talpha = (u8)0xF8 - (u8)0x80; talpha |= priority; color = (talpha << 24); }else{ const int colorindex = (colorBank) + colorOffset; if (SPCCCS == 0x03){ u16 checkcol = T2ReadWord(Vdp2ColorRam, ((colorindex) << Vdp2Internal.ColorMode) & 0xFFF); if (checkcol & 0x8000){ u32 talpha = 0xF8 - ((colorcl << 3) & 0xF8); talpha |= priority; color = Vdp2ColorRamGetColor(colorindex, talpha); } else{ color = Vdp2ColorRamGetColor(colorindex, alpha); } } else{ color = Vdp2ColorRamGetColor(colorindex, alpha); } } break; } case 3: { // 8 bpp(128 color) Bank mode u32 colorBank = cmd->CMDCOLR & 0xFF80; u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4; if (!SPD) color = 0x00; else if (MSB) color= (alpha << 24); else if (colorBank == nromal_shadow){ u32 talpha = (u8)0xF8 - (u8)0x80; talpha |= priority; color = (talpha << 24); } else{ const int colorindex = (colorBank)+colorOffset; if (SPCCCS == 0x03){ u16 checkcol = T2ReadWord(Vdp2ColorRam, ((colorindex) << Vdp2Internal.ColorMode) & 0xFFF); if (checkcol & 0x8000){ u32 talpha = 0xF8 - ((colorcl << 3) & 0xF8); talpha |= priority; color = Vdp2ColorRamGetColor(colorindex, talpha); } else{ color = Vdp2ColorRamGetColor(colorindex, alpha); } } else{ color = Vdp2ColorRamGetColor(colorindex, alpha); } } break; } case 4: { // 8 bpp(256 color) Bank mode u32 colorBank = cmd->CMDCOLR & 0xFF00; u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4; if (!SPD) color = 0x00; else if (MSB) color = (alpha << 24); else if (color == nromal_shadow){ u32 talpha = (u8)0xF8 - (u8)0x80; talpha |= priority; color = (talpha << 24); } else{ const int colorindex = (colorBank)+colorOffset; if (SPCCCS == 0x03){ u16 checkcol = T2ReadWord(Vdp2ColorRam, ((colorindex) << Vdp2Internal.ColorMode) & 0xFFF); if (checkcol & 0x8000){ u32 talpha = 0xF8 - ((colorcl << 3) & 0xF8); talpha |= priority; color = Vdp2ColorRamGetColor(colorindex, talpha); } else{ color = Vdp2ColorRamGetColor(colorindex, alpha); } } else{ color = Vdp2ColorRamGetColor(colorindex, alpha); } } } break; case 5: { // 16 bpp Bank mode u32 charAddr = cmd->CMDSRCA * 8; u16 dot = T1ReadWord(Vdp1Ram, charAddr & 0x7FFFF); //if (!(dot & 0x8000) && (Vdp2Regs->SPCTL & 0x20)) printf("mixed mode\n"); if (!(dot & 0x8000) && !SPD) color = 0x00; else if ((dot == 0x7FFF) && !END) color = 0x0; else if (MSB) color = (alpha << 24); else if (dot == nromal_shadow){ u32 talpha = (u8)0xF8 - (u8)0x80; talpha |= priority; color = (talpha << 24); }else if (SPCCCS == 0x03 && (dot & 0x8000)){ u32 talpha = 0xF8 - ((colorcl << 3) & 0xF8); talpha |= priority; color = SAT2YAB1(talpha, dot); } else{ color = SAT2YAB1(alpha, dot); } } break; default: VDP1LOG("Unimplemented sprite color mode: %X\n", (cmd->CMDPMOD >> 3) & 0x7); break; } return color; } static void FASTCALL Vdp1ReadTexture(vdp1cmd_struct *cmd, YglSprite *sprite, YglTexture *texture) { int shadow = 0; int priority = 0; int colorcl = 0; int ednmode; int endcnt = 0; int nromal_shadow = 0; u32 charAddr = cmd->CMDSRCA * 8; u32 dot; u8 SPD = ((cmd->CMDPMOD & 0x40) != 0); u8 END = ((cmd->CMDPMOD & 0x80) != 0); u8 MSB = ((cmd->CMDPMOD & 0x8000) != 0); u32 alpha = 0xFF; int SPCCCS = (Vdp2Regs->SPCTL >> 12) & 0x3; VDP1LOG("Making new sprite %08X\n", charAddr); if( (cmd->CMDPMOD & 0x20) == 0) ednmode = 1; else ednmode = 0; Vdp1ReadPriority(cmd, &priority, &colorcl, &nromal_shadow ); alpha = 0xF8; if( ((Vdp2Regs->CCCTL >> 6) & 0x01) == 0x01 ) { switch (SPCCCS) { case 0: if( priority <= ((Vdp2Regs->SPCTL>>8)&0x07) ) alpha = 0xF8-((colorcl<<3)&0xF8); break; case 1: if( priority == ((Vdp2Regs->SPCTL>>8)&0x07) ) alpha = 0xF8-((colorcl<<3)&0xF8); break; case 2: if( priority >= ((Vdp2Regs->SPCTL>>8)&0x07) ) alpha = 0xF8-((colorcl<<3)&0xF8); break; case 3: //if( priority <= (Vdp2Regs->SPCTL>>8)&0x07 ) // alpha = 0xF8-((colorcl<<3)&0xF8); break; } } alpha |= priority; switch((cmd->CMDPMOD >> 3) & 0x7) { case 0: { // 4 bpp Bank mode u32 colorBank = cmd->CMDCOLR; u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4; u16 i; for(i = 0;i < sprite->h;i++) { u16 j; j = 0; while(j < sprite->w) { dot = T1ReadByte(Vdp1Ram, charAddr & 0x7FFFF); // Pixel 1 if (((dot >> 4) == 0) && !SPD) *texture->textdata++ = 0x00; else if( ((dot >> 4) == 0x0F) && !END ) *texture->textdata++ = 0x00; else if( MSB ) *texture->textdata++ = (alpha<<24); else if (((dot >> 4) | colorBank) == 0x0000){ //u32 talpha = 0xF8 - ((colorcl << 3) & 0xF8); //talpha |= priority; *texture->textdata++ = 0; //Vdp2ColorRamGetColor(((dot >> 4) | colorBank) + colorOffset, talpha); } else if (((dot >> 4) | colorBank) == nromal_shadow){ u32 talpha = (u8)0xF8 - (u8)0x80; talpha |= priority; *texture->textdata++ = (talpha << 24); } else{ int colorindex = ((dot >> 4) | colorBank) + colorOffset; if (SPCCCS == 0x03){ u16 checkcol = T2ReadWord(Vdp2ColorRam, ((colorindex) << Vdp2Internal.ColorMode) & 0xFFF); if (checkcol & 0x8000){ u32 talpha = 0xF8 - ((colorcl << 3) & 0xF8); talpha |= priority; *texture->textdata++ = Vdp2ColorRamGetColor(colorindex, talpha); } else{ *texture->textdata++ = Vdp2ColorRamGetColor(colorindex, alpha); } } else{ *texture->textdata++ = Vdp2ColorRamGetColor(colorindex, alpha); } } j += 1; // Pixel 2 if (((dot & 0xF) == 0) && !SPD) *texture->textdata++ = 0x00; else if( ((dot & 0xF) == 0x0F) && !END ) *texture->textdata++ = 0x00; else if( MSB ) *texture->textdata++ = (alpha<<24); else if (((dot & 0x0F) | colorBank) == 0x0000){ //u32 talpha = 0xF8 - ((colorcl << 3) & 0xF8); //talpha |= priority; *texture->textdata++ = 0; // Vdp2ColorRamGetColor(((dot & 0xF) | colorBank) + colorOffset, talpha); } else if (((dot & 0xF) | colorBank) == nromal_shadow){ u32 talpha = (u8)0xF8 - (u8)0x80; talpha |= priority; *texture->textdata++ = (talpha << 24); } else{ int colorindex = ((dot & 0xF) | colorBank) + colorOffset; if (SPCCCS == 0x03){ u16 checkcol = T2ReadWord(Vdp2ColorRam, ((colorindex) << Vdp2Internal.ColorMode) & 0xFFF); if (checkcol & 0x8000){ u32 talpha = 0xF8 - ((colorcl << 3) & 0xF8); talpha |= priority; *texture->textdata++ = Vdp2ColorRamGetColor(colorindex, talpha); } else{ *texture->textdata++ = Vdp2ColorRamGetColor(colorindex, alpha); } } else{ *texture->textdata++ = Vdp2ColorRamGetColor(colorindex, alpha); } } j += 1; charAddr += 1; } texture->textdata += texture->w; } break; } case 1: { // 4 bpp LUT mode u16 temp; u32 colorLut = cmd->CMDCOLR * 8; u16 i; u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4; for(i = 0;i < sprite->h;i++) { u16 j; j = 0; endcnt = 0; while(j < sprite->w) { dot = T1ReadByte(Vdp1Ram, charAddr & 0x7FFFF); if( ednmode && endcnt >= 2 ) { *texture->textdata++ = 0x00; }else if (((dot >> 4) == 0) && !SPD) { *texture->textdata++ = 0; }else if (((dot >> 4) == 0x0F) && !END ) // 6. Commandtable end code { *texture->textdata++ = 0x0; endcnt++; }else{ temp = T1ReadWord(Vdp1Ram, ((dot >> 4) * 2 + colorLut) & 0x7FFFF); if (temp & 0x8000) { if( MSB ) *texture->textdata++ = (alpha<<24); else *texture->textdata++ = SAT2YAB1(alpha, temp); }else if( temp != 0x0000) { Vdp1ProcessSpritePixel(Vdp2Regs->SPCTL & 0xF, &temp, &shadow, &priority, &colorcl); if( shadow != 0 ) { u32 talpha = (u8)0xF8 - (u8)0x80; talpha |= priority; *texture->textdata++ = (talpha << 24); }else{ #ifdef WORDS_BIGENDIAN priority = ((u8 *)&Vdp2Regs->PRISA)[priority^1]&0x7; colorcl = ((u8 *)&Vdp2Regs->CCRSA)[colorcl^1]&0x1F; #else priority = ((u8 *)&Vdp2Regs->PRISA)[priority]&0x7; colorcl = ((u8 *)&Vdp2Regs->CCRSA)[colorcl]&0x1F; #endif alpha = 0xF8; if( ((Vdp2Regs->CCCTL >> 6) & 0x01) == 0x01 ) { switch (SPCCCS) { case 0: if( priority <= ((Vdp2Regs->SPCTL>>8)&0x07) ) alpha = 0xF8-((colorcl<<3)&0xF8); break; case 1: if( priority == ((Vdp2Regs->SPCTL>>8)&0x07) ) alpha = 0xF8-((colorcl<<3)&0xF8); break; case 2: if( priority >= ((Vdp2Regs->SPCTL>>8)&0x07) ) alpha = 0xF8-((colorcl<<3)&0xF8); break; case 3: { u16 checkcol = T2ReadWord(Vdp2ColorRam, ((temp + colorOffset) << Vdp2Internal.ColorMode) & 0xFFF); if (checkcol & 0x8000){ alpha = 0xF8 - ((colorcl << 3) & 0xF8); } } break; } } alpha |= priority; if( MSB ) *texture->textdata++ = (alpha<<24); else *texture->textdata++ = Vdp2ColorRamGetColor(temp+colorOffset, alpha); } }else{ *texture->textdata++ = 0x0; } } j += 1; if( ednmode && endcnt >= 2 ) { *texture->textdata++ = 0x00; }else if (((dot & 0xF) == 0) && !SPD) { *texture->textdata++ = 0x00; }else if (((dot&0x0F) == 0x0F) && !END ) { *texture->textdata++ = 0x0; endcnt++; }else{ temp = T1ReadWord(Vdp1Ram, ((dot & 0xF) * 2 + colorLut) & 0x7FFFF); if (temp & 0x8000) { if( MSB ) *texture->textdata++ = (alpha<<24); else *texture->textdata++ = SAT2YAB1(alpha, temp); }else if( temp != 0x0000) { Vdp1ProcessSpritePixel(Vdp2Regs->SPCTL & 0xF, &temp, &shadow, &priority, &colorcl); if( shadow != 0 ) { u32 talpha = (u8)0xF8 - (u8)0x80; talpha |= priority; *texture->textdata++ = (talpha << 24); }else{ #ifdef WORDS_BIGENDIAN priority = ((u8 *)&Vdp2Regs->PRISA)[priority^1]&0x7; colorcl = ((u8 *)&Vdp2Regs->CCRSA)[colorcl^1]&0x1F; #else priority = ((u8 *)&Vdp2Regs->PRISA)[priority]&0x7; colorcl = ((u8 *)&Vdp2Regs->CCRSA)[colorcl]&0x1F; #endif alpha = 0xF8; if( ((Vdp2Regs->CCCTL >> 6) & 0x01) == 0x01 ) { switch (SPCCCS) { case 0: if( priority <= ((Vdp2Regs->SPCTL>>8)&0x07) ) alpha = 0xF8-((colorcl<<3)&0xF8); break; case 1: if( priority == ((Vdp2Regs->SPCTL>>8)&0x07) ) alpha = 0xF8-((colorcl<<3)&0xF8); break; case 2: if( priority >= ((Vdp2Regs->SPCTL>>8)&0x07) ) alpha = 0xF8-((colorcl<<3)&0xF8); break; case 3: { u16 checkcol = T2ReadWord(Vdp2ColorRam, ((temp + colorOffset) << Vdp2Internal.ColorMode) & 0xFFF); if (checkcol & 0x8000){ alpha = 0xF8 - ((colorcl << 3) & 0xF8); } } break; } } alpha |= priority; if( MSB ) *texture->textdata++ = (alpha<<24); else *texture->textdata++ = Vdp2ColorRamGetColor(temp+colorOffset, alpha); } }else *texture->textdata++ = 0x0; } j += 1; charAddr += 1; } texture->textdata += texture->w; } break; } case 2: { // 8 bpp(64 color) Bank mode u32 colorBank = cmd->CMDCOLR & 0xFFC0; u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4; u16 i, j; for(i = 0;i < sprite->h;i++) { for(j = 0;j < sprite->w;j++) { dot = T1ReadByte(Vdp1Ram, charAddr & 0x7FFFF) & 0x3F; charAddr++; if ((dot == 0) && !SPD) *texture->textdata++ = 0x00; else if (dot == 0x0000){ *texture->textdata++ = 0x00; } else if( (dot == 0x3F) && !END ) *texture->textdata++ = 0x00; else if( MSB ) *texture->textdata++ = (alpha<<24); else if ((dot | colorBank) == nromal_shadow){ u32 talpha = (u8)0xF8 - (u8)0x80; talpha |= priority; *texture->textdata++ = (talpha << 24); } else{ const int colorindex = (dot | colorBank) + colorOffset; if (SPCCCS == 0x03){ u16 checkcol = T2ReadWord(Vdp2ColorRam, ((colorindex) << Vdp2Internal.ColorMode) & 0xFFF); if (checkcol & 0x8000){ u32 talpha = 0xF8 - ((colorcl << 3) & 0xF8); talpha |= priority; *texture->textdata++ = Vdp2ColorRamGetColor(colorindex, talpha); } else{ *texture->textdata++ = Vdp2ColorRamGetColor(colorindex, alpha); } } else{ *texture->textdata++ = Vdp2ColorRamGetColor(colorindex, alpha); } } } texture->textdata += texture->w; } break; } case 3: { // 8 bpp(128 color) Bank mode u32 colorBank = cmd->CMDCOLR & 0xFF80; u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4; u16 i, j; for(i = 0;i < sprite->h;i++) { for(j = 0;j < sprite->w;j++) { dot = T1ReadByte(Vdp1Ram, charAddr & 0x7FFFF) &0x7F; charAddr++; if ((dot == 0) && !SPD) *texture->textdata++ = 0x00; else if (dot == 0x0000){ *texture->textdata++ = 0x00; } else if( (dot == 0x7F) && !END ) *texture->textdata++ = 0x00; else if( MSB ) *texture->textdata++ = (alpha<<24); else if ((dot | colorBank) == nromal_shadow){ u32 talpha = (u8)0xF8 - (u8)0x80; talpha |= priority; *texture->textdata++ = (talpha << 24); }else{ const int colorindex = (dot | colorBank) + colorOffset; if (SPCCCS == 0x03){ u16 checkcol = T2ReadWord(Vdp2ColorRam, ((colorindex) << Vdp2Internal.ColorMode) & 0xFFF); if (checkcol & 0x8000){ u32 talpha = 0xF8 - ((colorcl << 3) & 0xF8); talpha |= priority; *texture->textdata++ = Vdp2ColorRamGetColor(colorindex, talpha); } else{ *texture->textdata++ = Vdp2ColorRamGetColor(colorindex, alpha); } } else{ *texture->textdata++ = Vdp2ColorRamGetColor(colorindex, alpha); } } } texture->textdata += texture->w; } break; } case 4: { // 8 bpp(256 color) Bank mode u32 colorBank = cmd->CMDCOLR & 0xFF00; u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4; u16 i, j; for(i = 0;i < sprite->h;i++) { for(j = 0;j < sprite->w;j++) { dot = T1ReadByte(Vdp1Ram, charAddr & 0x7FFFF); charAddr++; if ((dot == 0) && !SPD) *texture->textdata++ = 0x00; else if (dot == 0x0000){ *texture->textdata++ = 0x00; } else if( (dot == 0xFF) && !END ) *texture->textdata++ = 0x0; else if( MSB ) *texture->textdata++ = (alpha<<24); else if ((dot | colorBank) == nromal_shadow){ u32 talpha = (u8)0xF8 - (u8)0x80; talpha |= priority; *texture->textdata++ = (talpha << 24); } else{ const int colorindex = (dot | colorBank) + colorOffset; if (SPCCCS == 0x03){ u16 checkcol = T2ReadWord(Vdp2ColorRam, ((colorindex) << Vdp2Internal.ColorMode) & 0xFFF); if (checkcol & 0x8000){ u32 talpha = 0xF8 - ((colorcl << 3) & 0xF8); talpha |= priority; *texture->textdata++ = Vdp2ColorRamGetColor(colorindex, talpha); } else{ *texture->textdata++ = Vdp2ColorRamGetColor(colorindex, alpha); } } else{ *texture->textdata++ = Vdp2ColorRamGetColor(colorindex, alpha); } } } texture->textdata += texture->w; } break; } case 5: { // 16 bpp Bank mode u16 i, j; for(i = 0;i < sprite->h;i++) { for(j = 0;j < sprite->w;j++) { dot = T1ReadWord(Vdp1Ram, charAddr & 0x7FFFF); charAddr += 2; //if (!(dot & 0x8000) && (Vdp2Regs->SPCTL & 0x20)) printf("mixed mode\n"); if (!(dot & 0x8000) && !SPD) *texture->textdata++ = 0x00; else if (dot == 0x0000){ *texture->textdata++ = 0x00; } else if( (dot == 0x7FFF) && !END ) *texture->textdata++ = 0x0; else if( MSB ) *texture->textdata++ = (alpha<<24); else if (dot == nromal_shadow){ u32 talpha = (u8)0xF8 - (u8)0x80; talpha |= priority; *texture->textdata++ = (talpha << 24); } else if (SPCCCS == 0x03 && (dot&0x8000) ){ u32 talpha = 0xF8 - ((colorcl << 3) & 0xF8); talpha |= priority; *texture->textdata++ = SAT2YAB1(talpha, dot); } else *texture->textdata++ = SAT2YAB1(alpha, dot); } texture->textdata += texture->w; } break; } default: VDP1LOG("Unimplemented sprite color mode: %X\n", (cmd->CMDPMOD >> 3) & 0x7); break; } } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL Vdp1ReadPriority(vdp1cmd_struct *cmd, int * priority, int * colorcl, int * normal_shadow ) { u8 SPCLMD = Vdp2Regs->SPCTL; u8 sprite_register; u8 *sprprilist = (u8 *)&Vdp2Regs->PRISA; u8 *cclist = (u8 *)&Vdp2Regs->CCRSA; u16 lutPri; u16 *reg_src = &cmd->CMDCOLR; int not_lut = 1; // is the sprite is RGB or LUT (in fact, LUT can use bank color, we just hope it won't...) if ((SPCLMD & 0x20) && (cmd->CMDCOLR & 0x8000)) { // RGB data, use register 0 *priority = Vdp2Regs->PRISA & 0x7; return; } if (((cmd->CMDPMOD >> 3) & 0x7) == 1) { u32 charAddr, dot, colorLut; *priority = Vdp2Regs->PRISA & 0x7; charAddr = cmd->CMDSRCA * 8; dot = T1ReadByte(Vdp1Ram, charAddr & 0x7FFFF); colorLut = cmd->CMDCOLR * 8; lutPri = T1ReadWord(Vdp1Ram, (dot >> 4) * 2 + colorLut); if (!(lutPri & 0x8000)) { not_lut = 0; reg_src = &lutPri; } else return; } { u8 sprite_type = SPCLMD & 0xF; switch(sprite_type) { case 0: sprite_register = (*reg_src & 0xC000) >> 14; #ifdef WORDS_BIGENDIAN *priority = sprprilist[sprite_register^1] & 0x7; *colorcl = cclist[((cmd->CMDCOLR>>11)&0x07)^1]&0x1F; #else *priority = sprprilist[sprite_register] & 0x7; *colorcl = cclist[(cmd->CMDCOLR>>11)&0x07]&0x1F; #endif *normal_shadow = 0x7FE; if (not_lut) cmd->CMDCOLR &= 0x7FF; break; case 1: sprite_register = (*reg_src & 0xE000) >> 13; #ifdef WORDS_BIGENDIAN *priority = sprprilist[sprite_register^1] & 0x7; *colorcl = cclist[((cmd->CMDCOLR>>11)&0x03)^1]&0x1F; #else *priority = sprprilist[sprite_register] & 0x7; *colorcl = cclist[(cmd->CMDCOLR>>11)&0x03]&0x1F; #endif *normal_shadow = 0x7FE; if (not_lut) cmd->CMDCOLR &= 0x7FF; break; case 2: sprite_register = (*reg_src >> 14) & 0x1; #ifdef WORDS_BIGENDIAN *priority = sprprilist[sprite_register^1] & 0x7; *colorcl = cclist[((cmd->CMDCOLR>>11)&0x07)^1]&0x1F; #else *priority = sprprilist[sprite_register] & 0x7; *colorcl = cclist[(cmd->CMDCOLR>>11)&0x07]&0x1F; #endif *normal_shadow = 0x7FE; if (not_lut) cmd->CMDCOLR &= 0x7FF; break; case 3: sprite_register = (*reg_src & 0x6000) >> 13; #ifdef WORDS_BIGENDIAN *priority = sprprilist[sprite_register^1] & 0x7; *colorcl = cclist[((cmd->CMDCOLR>>11)&0x03)^1]&0x1F; #else *priority = sprprilist[sprite_register] & 0x7; *colorcl = cclist[((cmd->CMDCOLR>>11)&0x03)]&0x1F; #endif *normal_shadow = 0x7FE; if (not_lut) cmd->CMDCOLR &= 0x7FF; break; case 4: sprite_register = (*reg_src & 0x6000) >> 13; #ifdef WORDS_BIGENDIAN *priority = sprprilist[sprite_register^1] & 0x7; *colorcl = cclist[((cmd->CMDCOLR>>10)&0x07)^1]&0x1F; #else *priority = sprprilist[sprite_register] & 0x7; *colorcl = cclist[((cmd->CMDCOLR>>10)&0x07)]&0x1F; #endif *normal_shadow = 0x3FE; if (not_lut) cmd->CMDCOLR &= 0x3FF; break; case 5: sprite_register = (*reg_src & 0x7000) >> 12; #ifdef WORDS_BIGENDIAN *priority = sprprilist[sprite_register^1] & 0x7; *colorcl = cclist[((cmd->CMDCOLR>>11)&0x01)^1]&0x1F; #else *priority = sprprilist[sprite_register] & 0x7; *colorcl = cclist[((cmd->CMDCOLR>>11)&0x01)]&0x1F; #endif *normal_shadow = 0x7FE; if (not_lut) cmd->CMDCOLR &= 0x7FF; break; case 6: sprite_register = (*reg_src & 0x7000) >> 12; #ifdef WORDS_BIGENDIAN *priority = sprprilist[sprite_register^1] & 0x7; *colorcl = cclist[((cmd->CMDCOLR>>10)&0x03)^1]&0x1F; #else *priority = sprprilist[sprite_register] & 0x7; *colorcl = cclist[((cmd->CMDCOLR>>10)&0x03)]&0x1F; #endif *normal_shadow = 0x3FE; if (not_lut) cmd->CMDCOLR &= 0x3FF; break; case 7: sprite_register = (*reg_src & 0x7000) >> 12; #ifdef WORDS_BIGENDIAN *priority = sprprilist[sprite_register^1] & 0x7; *colorcl = cclist[((cmd->CMDCOLR>>9)&0x07)^1]&0x1F; #else *priority = sprprilist[sprite_register] & 0x7; *colorcl = cclist[((cmd->CMDCOLR>>9)&0x07)]&0x1F; #endif *normal_shadow = 0x1FE; if (not_lut) cmd->CMDCOLR &= 0x1FF; break; case 8: sprite_register = (*reg_src & 0x80) >> 7; #ifdef WORDS_BIGENDIAN *priority = sprprilist[sprite_register^1] & 0x7; #else *priority = sprprilist[sprite_register] & 0x7; #endif *normal_shadow = 0x7E; *colorcl = cclist[0]&0x1F; if (not_lut) cmd->CMDCOLR &= 0x7F; break; case 9: sprite_register = (*reg_src & 0x80) >> 7; #ifdef WORDS_BIGENDIAN *priority = sprprilist[sprite_register^1] & 0x7; *colorcl = cclist[((cmd->CMDCOLR>>6)&0x01)^1]&0x1F; #else *priority = sprprilist[sprite_register] & 0x7; *colorcl = cclist[((cmd->CMDCOLR>>6)&0x01)]&0x1F; #endif *normal_shadow = 0x3E; if (not_lut) cmd->CMDCOLR &= 0x3F; break; case 10: sprite_register = (*reg_src & 0xC0) >> 6; #ifdef WORDS_BIGENDIAN *priority = sprprilist[sprite_register^1] & 0x7; #else *priority = sprprilist[sprite_register] & 0x7; #endif *colorcl = cclist[0]&0x1F; if (not_lut) cmd->CMDCOLR &= 0x3F; break; case 11: sprite_register = 0; #ifdef WORDS_BIGENDIAN *priority = sprprilist[sprite_register^1] & 0x7; *colorcl = cclist[((cmd->CMDCOLR>>6)&0x03)^1]&0x1F; #else *priority = sprprilist[sprite_register] & 0x7; *colorcl = cclist[((cmd->CMDCOLR>>6)&0x03)]&0x1F; #endif *normal_shadow = 0x3E; if (not_lut) cmd->CMDCOLR &= 0x3F; break; case 12: sprite_register = (*reg_src & 0x80) >> 7; #ifdef WORDS_BIGENDIAN *priority = sprprilist[sprite_register^1] & 0x7; #else *priority = sprprilist[sprite_register] & 0x7; #endif *colorcl = cclist[0]&0x1F; *normal_shadow = 0x3E; if (not_lut) cmd->CMDCOLR &= 0xFF; break; case 13: sprite_register = (*reg_src & 0x80) >> 7; #ifdef WORDS_BIGENDIAN *priority = sprprilist[sprite_register^1] & 0x7; *colorcl = cclist[((cmd->CMDCOLR>>6)&0x01)^1]&0x1F; #else *priority = sprprilist[sprite_register] & 0x7; *colorcl = cclist[((cmd->CMDCOLR>>6)&0x01)]&0x1F; #endif *normal_shadow = 0xFE; if (not_lut) cmd->CMDCOLR &= 0xFF; break; case 14: sprite_register = (*reg_src & 0xC0) >> 6; #ifdef WORDS_BIGENDIAN *priority = sprprilist[sprite_register^1] & 0x7; *colorcl = cclist[1]&0x1F; #else *priority = sprprilist[sprite_register] & 0x7; *colorcl = cclist[0]&0x1F; #endif *normal_shadow = 0xFE; if (not_lut) cmd->CMDCOLR &= 0xFF; break; case 15: sprite_register = 0; #ifdef WORDS_BIGENDIAN *priority = sprprilist[sprite_register^1] & 0x7; *colorcl = cclist[((cmd->CMDCOLR>>6)&0x03)^1]&0x1F; #else *priority = sprprilist[sprite_register] & 0x7; *colorcl = cclist[((cmd->CMDCOLR>>6)&0x03)]&0x1F; #endif *normal_shadow = 0xFE; if (not_lut) cmd->CMDCOLR &= 0xFF; break; default: VDP1LOG("sprite type %d not implemented\n", sprite_type); // if we don't know what to do with a sprite, we put it on top *priority = 7; break; } } } ////////////////////////////////////////////////////////////////////////////// static void Vdp1SetTextureRatio(int vdp2widthratio, int vdp2heightratio) { float vdp1w=1; float vdp1h=1; // may need some tweaking // Figure out which vdp1 screen mode to use switch (Vdp1Regs->TVMR & 7) { case 0: case 2: case 3: vdp1w=1; break; case 1: vdp1w=2; break; default: vdp1w=1; vdp1h=1; break; } // Is double-interlace enabled? if (Vdp1Regs->FBCR & 0x8) vdp1h=2; vdp1wratio = (float)vdp2widthratio / vdp1w; vdp1hratio = (float)vdp2heightratio / vdp1h; } ////////////////////////////////////////////////////////////////////////////// static u32 Vdp2ColorRamGetColor(u32 colorindex, int alpha) { switch(Vdp2Internal.ColorMode) { case 0: case 1: { u32 tmp; colorindex <<= 1; tmp = T2ReadWord(Vdp2ColorRam, colorindex & 0xFFF); return SAT2YAB1(alpha, tmp); } case 2: { u32 tmp1, tmp2; colorindex <<= 2; colorindex &= 0xFFF; tmp1 = T2ReadWord(Vdp2ColorRam, colorindex); tmp2 = T2ReadWord(Vdp2ColorRam, colorindex+2); return SAT2YAB2(alpha, tmp1, tmp2); } default: break; } return 0; } u32 FASTCALL Vdp2ColorRamGetColorCM01SC0(vdp2draw_struct * info, u32 colorindex, int alpha ) { u32 tmp; tmp = T2ReadWord(Vdp2ColorRam, (colorindex<<1) & 0xFFF); return SAT2YAB1(alpha,tmp); } u32 FASTCALL Vdp2ColorRamGetColorCM01SC1(vdp2draw_struct * info, u32 colorindex, int alpha ) { u32 tmp; tmp = T2ReadWord(Vdp2ColorRam, (colorindex<<1) & 0xFFF); if( (info->specialcolorfunction & 1) == 0 ) { return SAT2YAB1(0xFF,tmp); } return SAT2YAB1(alpha,tmp); } u32 FASTCALL Vdp2ColorRamGetColorCM01SC3(vdp2draw_struct * info, u32 colorindex, int alpha ) { u32 tmp; colorindex <<= 1; tmp = T2ReadWord(Vdp2ColorRam, colorindex & 0xFFF); if( ((tmp & 0x8000) == 0) ) { return SAT2YAB1(0xFF,tmp); } return SAT2YAB1(alpha,tmp); } u32 FASTCALL Vdp2ColorRamGetColorCM2(vdp2draw_struct * info, u32 colorindex, int alpha ) { u32 tmp1, tmp2; colorindex <<= 2; colorindex &= 0xFFF; tmp1 = T2ReadWord(Vdp2ColorRam, colorindex); tmp2 = T2ReadWord(Vdp2ColorRam, colorindex+2); return SAT2YAB2(alpha, tmp1, tmp2); } static int Vdp2SetGetColor( vdp2draw_struct * info ) { switch(Vdp2Internal.ColorMode) { case 0: case 1: switch( info->specialcolormode ) { case 0: info->Vdp2ColorRamGetColor = (Vdp2ColorRamGetColor_func) Vdp2ColorRamGetColorCM01SC0; break; case 1: info->Vdp2ColorRamGetColor = (Vdp2ColorRamGetColor_func) Vdp2ColorRamGetColorCM01SC1; break; case 2: info->Vdp2ColorRamGetColor = (Vdp2ColorRamGetColor_func) Vdp2ColorRamGetColorCM01SC0; // Not Supported Yet! break; case 3: info->Vdp2ColorRamGetColor = (Vdp2ColorRamGetColor_func) Vdp2ColorRamGetColorCM01SC3; break; default: info->Vdp2ColorRamGetColor = (Vdp2ColorRamGetColor_func) Vdp2ColorRamGetColorCM01SC0; break; } break; case 2: info->Vdp2ColorRamGetColor = (Vdp2ColorRamGetColor_func) Vdp2ColorRamGetColorCM2; break; default: info->Vdp2ColorRamGetColor = (Vdp2ColorRamGetColor_func) Vdp2ColorRamGetColorCM01SC0; break; } return 0; } ////////////////////////////////////////////////////////////////////////////// // Window static void Vdp2GenerateWindowInfo(void) { int i; int HShift; int v = 0; u32 LineWinAddr; // Is there BG uses Window0? if( (Vdp2Regs->WCTLA & 0X2) || (Vdp2Regs->WCTLA & 0X200) || (Vdp2Regs->WCTLB & 0X2) || (Vdp2Regs->WCTLB & 0X200) || (Vdp2Regs->WCTLC & 0X2) || (Vdp2Regs->WCTLC & 0X200) || (Vdp2Regs->WCTLD & 0X2) || (Vdp2Regs->WCTLD & 0X200) || (Vdp2Regs->RPMD == 0X03) ) { // resize to fit resolusion if( m_vWindinfo0_size != vdp2height ) { if(m_vWindinfo0 != NULL) free(m_vWindinfo0); m_vWindinfo0 = (vdp2WindowInfo*)malloc(sizeof(vdp2WindowInfo)*(vdp2height+8)); for( i=0; i=640 ) HShift = 0; else HShift = 1; // Line Table mode if( (Vdp2Regs->LWTA0.part.U & 0x8000) ) { int preHStart = -1; int preHEnd = -1; // start address LineWinAddr = (u32)((( (Vdp2Regs->LWTA0.part.U & 0x07) << 15) | (Vdp2Regs->LWTA0.part.L >> 1) ) << 2); _Ygl->win0_vertexcnt = 0; for( v = 0; v < vdp2height; v++ ) { if( v < Vdp2Regs->WPSY0 || v > Vdp2Regs->WPEY0 ) { if( m_vWindinfo0[v].WinShowLine ) m_b0WindowChg = 1; m_vWindinfo0[v].WinShowLine = 0; }else{ short HStart = T1ReadWord(Vdp2Ram, LineWinAddr + (v << 2)); short HEnd = T1ReadWord(Vdp2Ram, LineWinAddr + (v << 2) + 2); if( HStart < HEnd ) { HStart >>= HShift; HEnd >>= HShift; if( !( m_vWindinfo0[v].WinHStart == HStart && m_vWindinfo0[v].WinHEnd == HEnd ) ) { m_b0WindowChg = 1; } m_vWindinfo0[v].WinHStart = HStart; m_vWindinfo0[v].WinHEnd = HEnd; m_vWindinfo0[v].WinShowLine = 1; }else{ if( m_vWindinfo0[v].WinShowLine ) m_b0WindowChg = 1; m_vWindinfo0[v].WinHStart = 0; m_vWindinfo0[v].WinHEnd = 0; m_vWindinfo0[v].WinShowLine = 0; } if (v == Vdp2Regs->WPSY0) { _Ygl->win0v[_Ygl->win0_vertexcnt * 2 + 0] = HStart; _Ygl->win0v[_Ygl->win0_vertexcnt * 2 + 1] = v; _Ygl->win0_vertexcnt++; _Ygl->win0v[_Ygl->win0_vertexcnt * 2 + 0] = HEnd; _Ygl->win0v[_Ygl->win0_vertexcnt * 2 + 1] = v; _Ygl->win0_vertexcnt++; } else if ((HStart != preHStart || HEnd != preHEnd) || v == (Vdp2Regs->WPEY0 - 1)) { if ((v - 1) != _Ygl->win0v[(_Ygl->win0_vertexcnt - 1) * 2 + 1]) { _Ygl->win0v[_Ygl->win0_vertexcnt * 2 + 0] = preHStart; _Ygl->win0v[_Ygl->win0_vertexcnt * 2 + 1] = v - 1; _Ygl->win0_vertexcnt++; _Ygl->win0v[_Ygl->win0_vertexcnt * 2 + 0] = preHEnd; _Ygl->win0v[_Ygl->win0_vertexcnt * 2 + 1] = v - 1; _Ygl->win0_vertexcnt++; } _Ygl->win0v[_Ygl->win0_vertexcnt * 2 + 0] = HStart; _Ygl->win0v[_Ygl->win0_vertexcnt * 2 + 1] = v; _Ygl->win0_vertexcnt++; _Ygl->win0v[_Ygl->win0_vertexcnt * 2 + 0] = HEnd; _Ygl->win0v[_Ygl->win0_vertexcnt * 2 + 1] = v; _Ygl->win0_vertexcnt++; } preHStart = HStart; preHEnd = HEnd; } } // Parameter Mode }else{ // Check Update if( !( m_vWindinfo0[0].WinHStart == (Vdp2Regs->WPSX0>>HShift) && m_vWindinfo0[0].WinHEnd == (Vdp2Regs->WPEX0>>HShift) ) ) { m_b0WindowChg = 1; } for( v = 0; v < vdp2height; v++ ) { m_vWindinfo0[v].WinHStart = Vdp2Regs->WPSX0 >> HShift; m_vWindinfo0[v].WinHEnd = Vdp2Regs->WPEX0 >> HShift; if( v < Vdp2Regs->WPSY0 || v >= Vdp2Regs->WPEY0 ) { if( m_vWindinfo0[v].WinShowLine ) m_b0WindowChg = 1; m_vWindinfo0[v].WinShowLine = 0; }else{ if( m_vWindinfo0[v].WinShowLine == 0) m_b0WindowChg = 1; m_vWindinfo0[v].WinShowLine = 1; } } _Ygl->win0v[0]= Vdp2Regs->WPSX0 >> HShift; _Ygl->win0v[1]= Vdp2Regs->WPSY0; _Ygl->win0v[2]= Vdp2Regs->WPEX0 >> HShift; _Ygl->win0v[3]= Vdp2Regs->WPSY0; _Ygl->win0v[4]= Vdp2Regs->WPSX0 >> HShift; _Ygl->win0v[5]= Vdp2Regs->WPEY0; _Ygl->win0v[6]= Vdp2Regs->WPEX0 >> HShift; _Ygl->win0v[7]= Vdp2Regs->WPEY0; _Ygl->win0_vertexcnt = 4; } // there is no Window BG }else{ if( m_vWindinfo0_size != 0 ) { m_b0WindowChg = 1; } if( m_vWindinfo0 != NULL ) { free(m_vWindinfo0); m_vWindinfo0 = NULL; } m_vWindinfo0_size = 0; _Ygl->win0_vertexcnt = 0; } // Is there BG uses Window1? if( (Vdp2Regs->WCTLA & 0x8) || (Vdp2Regs->WCTLA & 0x800) || (Vdp2Regs->WCTLB & 0x8) || (Vdp2Regs->WCTLB & 0x800) || (Vdp2Regs->WCTLC & 0x8) || (Vdp2Regs->WCTLC & 0x800) || (Vdp2Regs->WCTLD & 0x8) || (Vdp2Regs->WCTLD & 0x800) ) { // resize to fit resolution if( m_vWindinfo1_size != vdp2height ) { if(m_vWindinfo1 != NULL) free(m_vWindinfo1); m_vWindinfo1 = (vdp2WindowInfo*)malloc(sizeof(vdp2WindowInfo)*vdp2height); for( i=0; i=640 ) HShift = 0; else HShift = 1; // LineTable mode if( (Vdp2Regs->LWTA1.part.U & 0x8000) ) { int preHStart = -1; int preHEnd = -1; _Ygl->win1_vertexcnt = 0; // start address for Window table LineWinAddr = (u32)((( (Vdp2Regs->LWTA1.part.U & 0x07) << 15) | (Vdp2Regs->LWTA1.part.L >> 1) ) << 2); for( v = 0; v < vdp2height; v++ ) { if( v < Vdp2Regs->WPSY1 || v > Vdp2Regs->WPEY1 ) { if( m_vWindinfo1[v].WinShowLine ) m_b1WindowChg = 1; m_vWindinfo1[v].WinShowLine = 0; }else{ short HStart = T1ReadWord(Vdp2Ram, LineWinAddr + (v << 2)); short HEnd = T1ReadWord(Vdp2Ram, LineWinAddr + (v << 2) + 2); if( HStart < HEnd ) { HStart >>= HShift; HEnd >>= HShift; if( !( m_vWindinfo1[v].WinHStart == HStart && m_vWindinfo1[v].WinHEnd == HEnd ) ) { m_b1WindowChg = 1; } m_vWindinfo1[v].WinHStart = HStart; m_vWindinfo1[v].WinHEnd = HEnd; m_vWindinfo1[v].WinShowLine = 1; }else{ if( m_vWindinfo1[v].WinShowLine ) m_b1WindowChg = 1; m_vWindinfo1[v].WinShowLine = 0; } if( v == Vdp2Regs->WPSY1 ) { _Ygl->win1v[_Ygl->win1_vertexcnt*2+0]= HStart; _Ygl->win1v[_Ygl->win1_vertexcnt*2+1]= v; _Ygl->win1_vertexcnt++; _Ygl->win1v[_Ygl->win1_vertexcnt*2+0]= HEnd; _Ygl->win1v[_Ygl->win1_vertexcnt*2+1]= v; _Ygl->win1_vertexcnt++; }else if( ( HStart != preHStart || HEnd != preHEnd) || v == (Vdp2Regs->WPEY1-1) ) { if( (v-1) != _Ygl->win1v[(_Ygl->win1_vertexcnt-1)*2+1] ) { _Ygl->win1v[_Ygl->win1_vertexcnt*2+0]= preHStart; _Ygl->win1v[_Ygl->win1_vertexcnt*2+1]= v-1; _Ygl->win1_vertexcnt++; _Ygl->win1v[_Ygl->win1_vertexcnt*2+0]= preHEnd; _Ygl->win1v[_Ygl->win1_vertexcnt*2+1]= v-1; _Ygl->win1_vertexcnt++; } _Ygl->win1v[_Ygl->win1_vertexcnt*2+0]= HStart; _Ygl->win1v[_Ygl->win1_vertexcnt*2+1]= v; _Ygl->win1_vertexcnt++; _Ygl->win1v[_Ygl->win1_vertexcnt*2+0]= HEnd; _Ygl->win1v[_Ygl->win1_vertexcnt*2+1]= v; _Ygl->win1_vertexcnt++; } preHStart = HStart; preHEnd = HEnd; } } // parameter mode }else{ // check update if( !( m_vWindinfo1[0].WinHStart == (Vdp2Regs->WPSX1>>HShift) && m_vWindinfo1[0].WinHEnd == (Vdp2Regs->WPEX1>>HShift) ) ) { m_b1WindowChg = 1; } for( v = 0; v < vdp2height; v++ ) { m_vWindinfo1[v].WinHStart = Vdp2Regs->WPSX1 >> HShift; m_vWindinfo1[v].WinHEnd = Vdp2Regs->WPEX1 >> HShift; if( v < Vdp2Regs->WPSY1 || v > Vdp2Regs->WPEY1 ) { if( m_vWindinfo1[v].WinShowLine ) m_b1WindowChg = 1; m_vWindinfo1[v].WinShowLine = 0; }else{ if( m_vWindinfo1[v].WinShowLine == 0) m_b1WindowChg = 1; m_vWindinfo1[v].WinShowLine = 1; } } _Ygl->win1v[0]= Vdp2Regs->WPSX1 >> HShift; _Ygl->win1v[1]= Vdp2Regs->WPSY1; _Ygl->win1v[2]= Vdp2Regs->WPEX1 >> HShift; _Ygl->win1v[3]= Vdp2Regs->WPSY1; _Ygl->win1v[4]= Vdp2Regs->WPSX1 >> HShift; _Ygl->win1v[5]= Vdp2Regs->WPEY1; _Ygl->win1v[6]= Vdp2Regs->WPEX1 >> HShift; _Ygl->win1v[7]= Vdp2Regs->WPEY1; _Ygl->win1_vertexcnt = 4; } // no BG uses Window1 }else{ if( m_vWindinfo1_size != 0 ) { m_b1WindowChg = 1; } if( m_vWindinfo1 != NULL ) { free(m_vWindinfo1); m_vWindinfo1 = NULL; } m_vWindinfo1_size = 0; _Ygl->win1_vertexcnt = 0; } if( m_b1WindowChg || m_b0WindowChg ) { YglNeedToUpdateWindow(); m_b0WindowChg = 0; m_b1WindowChg = 0; } } // 0 .. outside,1 .. inside static INLINE int Vdp2CheckWindow(vdp2draw_struct *info, int x, int y, int area, vdp2WindowInfo * vWindinfo ) { // inside if( area == 1 ) { if( vWindinfo[y].WinShowLine == 0 ) return 0; if( x > vWindinfo[y].WinHStart && x < vWindinfo[y].WinHEnd ) { return 1; }else{ return 0; } // outside }else{ if( vWindinfo[y].WinShowLine == 0 ) return 1; if( x < vWindinfo[y].WinHStart ) return 1; if( x > vWindinfo[y].WinHEnd ) return 1; return 0; } return 0; } // 0 .. outside,1 .. inside static int FASTCALL Vdp2CheckWindowDot(vdp2draw_struct *info, int x, int y ) { if( info->bEnWin0 != 0 && info->bEnWin1 == 0 ) { if (m_vWindinfo0==NULL) Vdp2GenerateWindowInfo(); return Vdp2CheckWindow(info, x, y, info->WindowArea0, m_vWindinfo0 ); }else if( info->bEnWin0 == 0 && info->bEnWin1 != 0 ) { if (m_vWindinfo1 == NULL) Vdp2GenerateWindowInfo(); return Vdp2CheckWindow(info, x, y, info->WindowArea1, m_vWindinfo1 ); }else if( info->bEnWin0 != 0 && info->bEnWin1 != 0 ) { if (m_vWindinfo0 == NULL || m_vWindinfo1 == NULL) Vdp2GenerateWindowInfo(); if( info->LogicWin == 0 ) { return (Vdp2CheckWindow(info, x, y, info->WindowArea0, m_vWindinfo0 )& Vdp2CheckWindow(info, x, y, info->WindowArea1, m_vWindinfo1 )); }else{ return (Vdp2CheckWindow(info, x, y, info->WindowArea0, m_vWindinfo0 )| Vdp2CheckWindow(info, x, y, info->WindowArea1, m_vWindinfo1 )); } } return 0; } // 0 .. all outsize, 1~3 .. partly inside, 4.. all inside static int FASTCALL Vdp2CheckWindowRange(vdp2draw_struct *info, int x, int y, int w, int h ) { int rtn=0; if( info->bEnWin0 != 0 && info->bEnWin1 == 0 ) { rtn += Vdp2CheckWindow(info, x, y, info->WindowArea0, m_vWindinfo0 ); rtn += Vdp2CheckWindow(info, x+w, y, info->WindowArea0, m_vWindinfo0 ); rtn += Vdp2CheckWindow(info, x+w, y+h, info->WindowArea0, m_vWindinfo0 ); rtn += Vdp2CheckWindow(info, x, y+h, info->WindowArea0, m_vWindinfo0 ); return rtn; }else if( info->bEnWin0 == 0 && info->bEnWin1 != 0 ) { rtn += Vdp2CheckWindow(info, x, y, info->WindowArea1, m_vWindinfo1 ); rtn += Vdp2CheckWindow(info, x+w, y, info->WindowArea1, m_vWindinfo1 ); rtn += Vdp2CheckWindow(info, x+w, y+h, info->WindowArea1, m_vWindinfo1 ); rtn += Vdp2CheckWindow(info, x, y+h, info->WindowArea1, m_vWindinfo1 ); return rtn; }else if( info->bEnWin0 != 0 && info->bEnWin1 != 0 ) { if( info->LogicWin == 0 ) { rtn += (Vdp2CheckWindow(info, x, y, info->WindowArea0, m_vWindinfo0 ) & Vdp2CheckWindow(info, x, y, info->WindowArea1, m_vWindinfo1 ) ); rtn += (Vdp2CheckWindow(info, x+w, y, info->WindowArea0, m_vWindinfo0 )& Vdp2CheckWindow(info, x+w, y, info->WindowArea1, m_vWindinfo1 ) ); rtn += (Vdp2CheckWindow(info, x+w, y+h, info->WindowArea0, m_vWindinfo0 )& Vdp2CheckWindow(info, x+w, y+h, info->WindowArea1, m_vWindinfo1 ) ); rtn += (Vdp2CheckWindow(info, x, y+h, info->WindowArea0, m_vWindinfo0 ) & Vdp2CheckWindow(info, x, y+h, info->WindowArea1, m_vWindinfo1 ) ); return rtn; }else{ rtn += (Vdp2CheckWindow(info, x, y, info->WindowArea0, m_vWindinfo0 ) | Vdp2CheckWindow(info, x, y, info->WindowArea1, m_vWindinfo1 ) ); rtn += (Vdp2CheckWindow(info, x+w, y, info->WindowArea0, m_vWindinfo0 ) | Vdp2CheckWindow(info, x+w, y, info->WindowArea1, m_vWindinfo1 ) ); rtn += (Vdp2CheckWindow(info, x+w, y+h, info->WindowArea0, m_vWindinfo0 ) | Vdp2CheckWindow(info, x+w, y+h, info->WindowArea1, m_vWindinfo1 ) ); rtn += (Vdp2CheckWindow(info, x, y+h, info->WindowArea0, m_vWindinfo0 ) | Vdp2CheckWindow(info, x, y+h, info->WindowArea1, m_vWindinfo1 ) ); return rtn; } } return 0; } void Vdp2GenLineinfo( vdp2draw_struct *info ) { int bound = 0; int i; u16 val1,val2; int index = 0; int lineindex = 0; if( info->lineinc == 0 || info->islinescroll == 0 ) return; if( VDPLINE_SY(info->islinescroll)) bound += 0x04; if( VDPLINE_SX(info->islinescroll)) bound += 0x04; if( VDPLINE_SZ(info->islinescroll)) bound += 0x04; for( i = 0; i < vdp2height; i += info->lineinc ) { index = 0; if( VDPLINE_SX(info->islinescroll)) { info->lineinfo[lineindex].LineScrollValH = T1ReadWord(Vdp2Ram, info->linescrolltbl + (i / info->lineinc)*bound); if ((info->lineinfo[lineindex].LineScrollValH & 0x400)) info->lineinfo[lineindex].LineScrollValH |= 0xF800; else info->lineinfo[lineindex].LineScrollValH &= 0x07FF; index += 4; }else{ info->lineinfo[lineindex].LineScrollValH = 0; } if( VDPLINE_SY(info->islinescroll)) { info->lineinfo[lineindex].LineScrollValV = T1ReadWord(Vdp2Ram, info->linescrolltbl + (i / info->lineinc)*bound + index); if ((info->lineinfo[lineindex].LineScrollValV & 0x400)) info->lineinfo[lineindex].LineScrollValV |= 0xF800; else info->lineinfo[lineindex].LineScrollValV &= 0x07FF; index += 4; }else{ info->lineinfo[lineindex].LineScrollValV = 0; } if( VDPLINE_SZ(info->islinescroll)) { val1=T1ReadWord(Vdp2Ram, info->linescrolltbl+(i/info->lineinc)*bound+index); val2=T1ReadWord(Vdp2Ram, info->linescrolltbl+(i/info->lineinc)*bound+index+2); //info->lineinfo[i].CoordinateIncH = (float)( (int)((val1) & 0x07) + (float)( (val2) >> 8) / 255.0f ); info->lineinfo[lineindex].CoordinateIncH = (((int)((val1)& 0x07) << 8) | (int)((val2) >> 8)); if (info->lineinfo[lineindex].CoordinateIncH == 0){ info->lineinfo[lineindex].CoordinateIncH = 0x0100; } index += 4; }else{ info->lineinfo[lineindex].CoordinateIncH = 0x0100; } lineindex++; } } static void FASTCALL Vdp2DrawCell(vdp2draw_struct *info, YglTexture *texture) { u32 color; int i, j; switch(info->colornumber) { case 0: // 4 BPP for(i = 0;i < info->cellh;i++) { for(j = 0;j < info->cellw;j+=4) { u16 dot = T1ReadWord(Vdp2Ram, info->charaddr & 0x7FFFF); info->charaddr += 2; if (!(dot & 0xF000) && info->transparencyenable) color = 0x00000000; else color = info->Vdp2ColorRamGetColor(info,info->coloroffset + ((info->paladdr << 4) | ((dot & 0xF000) >> 12)), info->alpha); *texture->textdata++ = info->PostPixelFetchCalc(info, color); if (!(dot & 0xF00) && info->transparencyenable) color = 0x00000000; else color = info->Vdp2ColorRamGetColor(info,info->coloroffset + ((info->paladdr << 4) | ((dot & 0xF00) >> 8)), info->alpha); *texture->textdata++ = info->PostPixelFetchCalc(info, color); if (!(dot & 0xF0) && info->transparencyenable) color = 0x00000000; else color = info->Vdp2ColorRamGetColor(info,info->coloroffset + ((info->paladdr << 4) | ((dot & 0xF0) >> 4)), info->alpha); *texture->textdata++ = info->PostPixelFetchCalc(info, color); if (!(dot & 0xF) && info->transparencyenable) color = 0x00000000; else color = info->Vdp2ColorRamGetColor(info,info->coloroffset + ((info->paladdr << 4) | (dot & 0xF)), info->alpha); *texture->textdata++ = info->PostPixelFetchCalc(info, color); } texture->textdata += texture->w; } break; case 1: // 8 BPP for(i = 0;i < info->cellh;i++) { for(j = 0;j < info->cellw;j+=2) { u16 dot = T1ReadWord(Vdp2Ram, info->charaddr & 0x7FFFF); info->charaddr += 2; if (!(dot & 0xFF00) && info->transparencyenable) color = 0x00000000; else color = info->Vdp2ColorRamGetColor(info,info->coloroffset + ((info->paladdr << 4) | ((dot & 0xFF00) >> 8)), info->alpha); *texture->textdata++ = info->PostPixelFetchCalc(info, color); if (!(dot & 0xFF) && info->transparencyenable) color = 0x00000000; else color = info->Vdp2ColorRamGetColor(info,info->coloroffset + ((info->paladdr << 4) | (dot & 0xFF)), info->alpha); *texture->textdata++ = info->PostPixelFetchCalc(info, color); } texture->textdata += texture->w; } break; case 2: // 16 BPP(palette) for(i = 0;i < info->cellh;i++) { for(j = 0;j < info->cellw;j++) { u16 dot = T1ReadWord(Vdp2Ram, info->charaddr & 0x7FFFF); if ((dot == 0) && info->transparencyenable) color = 0x00000000; else color = info->Vdp2ColorRamGetColor(info,info->coloroffset + dot, info->alpha); info->charaddr += 2; *texture->textdata++ = info->PostPixelFetchCalc(info, color); } texture->textdata += texture->w; } break; case 3: // 16 BPP(RGB) if (info->isbitmap && info->islinescroll) // Nights Movie { for(i = 0;i < info->cellh;i++) { int sh,sv; u32 baseaddr; vdp2Lineinfo * line; baseaddr = (u32)info->charaddr; line = &(info->lineinfo[i*info->lineinc]); if( VDPLINE_SX(info->islinescroll) ) sh = line->LineScrollValH+info->sh; else sh = info->sh; if( VDPLINE_SY(info->islinescroll) ) sv = line->LineScrollValV; else sv = i+info->sv; sh &= (info->cellw-1); sv &= (info->cellh-1); if( line->LineScrollValH < sh ) sv-=1; baseaddr += ((sh+ sv * info->cellw)<<1); for(j = 0;j < info->cellw;j++) { u16 dot; u32 addr; if( Vdp2CheckWindowDot(info,j,i)==0 ){ *texture->textdata++=0; continue; } addr = baseaddr + (j<<1); dot = T1ReadWord(Vdp2Ram, addr & 0x7FFFF); if (!(dot & 0x8000) && info->transparencyenable) color = 0x00000000; else color = SAT2YAB1(0xFF,dot); *texture->textdata++ = info->PostPixelFetchCalc(info, color); } texture->textdata += texture->w; } }else{ for(i = 0;i < info->cellh;i++) { for(j = 0;j < info->cellw;j++) { u16 dot = T1ReadWord(Vdp2Ram, info->charaddr & 0x7FFFF); info->charaddr += 2; if (!(dot & 0x8000) && info->transparencyenable) color = 0x00000000; else color = SAT2YAB1(0xFF, dot); *texture->textdata++ = info->PostPixelFetchCalc(info, color); } texture->textdata += texture->w; } } break; case 4: // 32 BPP if (info->isbitmap && info->islinescroll) // Nights Movie { for(i = 0;i < info->cellh;i++) { int sh,sv; u32 baseaddr; vdp2Lineinfo * line; baseaddr = (u32)info->charaddr; line = &(info->lineinfo[i*info->lineinc]); if( VDPLINE_SX(info->islinescroll) ) sh = line->LineScrollValH+info->sh; else sh = info->sh; if( VDPLINE_SY(info->islinescroll) ) sv = line->LineScrollValV; else sv = i+info->sv; sh &= (info->cellw-1); sv &= (info->cellh-1); if( line->LineScrollValH < sh ) sv-=1; baseaddr += ((sh+ sv * info->cellw)<<2); for(j = 0;j < info->cellw;j++) { u16 dot1, dot2; u32 addr; if( Vdp2CheckWindowDot(info,j,i)==0 ){ *texture->textdata++=0; continue; } addr = baseaddr + (j<<2); dot1 = T1ReadWord(Vdp2Ram, addr & 0x7FFFF); dot2 = T1ReadWord(Vdp2Ram, (addr+2) & 0x7FFFF); if (!(dot1 & 0x8000) && info->transparencyenable) color = 0x00000000; else color = SAT2YAB2(info->alpha, dot1, dot2); *texture->textdata++ = info->PostPixelFetchCalc(info, color); } texture->textdata += texture->w; } }else{ for(i = 0;i < info->cellh;i++) { for(j = 0;j < info->cellw;j++) { u16 dot1, dot2; dot1 = T1ReadWord(Vdp2Ram, info->charaddr & 0x7FFFF); info->charaddr += 2; dot2 = T1ReadWord(Vdp2Ram, info->charaddr & 0x7FFFF); info->charaddr += 2; if (!(dot1 & 0x8000) && info->transparencyenable) color = 0x00000000; else color = SAT2YAB2(info->alpha, dot1, dot2); *texture->textdata++ = info->PostPixelFetchCalc(info, color); } texture->textdata += texture->w; } } break; } } static void Vdp2DrawPatternPos(vdp2draw_struct *info, YglTexture *texture, int x, int y, int cx, int cy ) { u32 cacheaddr = ((u32)(info->alpha >> 3) << 27) | (info->paladdr << 20) | info->charaddr | info->transparencyenable; YglCache c; YglSprite tile; int winmode = 0; tile.dst = 0; tile.uclipmode = 0; tile.blendmode = info->blendmode; tile.linescreen = info->linescreen; tile.w = tile.h = info->patternpixelwh; tile.flip = info->flipfunction; if (info->specialprimode == 1) tile.priority = (info->priority & 0xFFFFFFFE) | info->specialfunction; else tile.priority = info->priority; tile.vertices[0] = x; tile.vertices[1] = y; tile.vertices[2] = (x + tile.w); tile.vertices[3] = y; tile.vertices[4] = (x + tile.w); tile.vertices[5] = (y + (float)info->lineinc); tile.vertices[6] = x; tile.vertices[7] = (y + (float)info->lineinc); // Screen culling //if (tile.vertices[0] >= vdp2width || tile.vertices[1] >= vdp2height || tile.vertices[2] < 0 || tile.vertices[5] < 0) //{ // return; //} if ((info->bEnWin0 != 0 || info->bEnWin1 != 0) && info->coordincx == 1.0f) { // coordinate inc is not supported yet. winmode = Vdp2CheckWindowRange(info, x-cx, y-cy, tile.w, info->lineinc); if (winmode == 0) // all outside, no need to draw { return; } } tile.cor = info->cor; tile.cog = info->cog; tile.cob = info->cob; if (1 == YglIsCached(cacheaddr, &c)) { YglCachedQuadOffset(&tile, &c, cx, cy, info->coordincx, info->coordincy); return; } YglQuadOffset(&tile, texture, &c, cx, cy, info->coordincx, info->coordincy); YglCacheAdd(cacheaddr, &c); switch (info->patternwh) { case 1: Vdp2DrawCell(info, texture); break; case 2: texture->w += 8; Vdp2DrawCell(info, texture); texture->textdata -= (texture->w + 8) * 8 - 8; Vdp2DrawCell(info, texture); texture->textdata -= 8; Vdp2DrawCell(info, texture); texture->textdata -= (texture->w + 8) * 8 - 8; Vdp2DrawCell(info, texture); break; } } static void Vdp2DrawPattern(vdp2draw_struct *info, YglTexture *texture) { u32 cacheaddr = ((u32)(info->alpha >> 3) << 27) | (info->paladdr << 20) | info->charaddr | info->transparencyenable; YglCache c; YglSprite tile; int winmode=0; tile.dst = 0; tile.uclipmode = 0; tile.blendmode = info->blendmode; tile.linescreen = info->linescreen; tile.w = tile.h = info->patternpixelwh; tile.flip = info->flipfunction; if (info->islinescroll){ tile.h = info->lineinc; } if (info->specialprimode == 1) tile.priority = (info->priority & 0xFFFFFFFE) | info->specialfunction; else tile.priority = info->priority; tile.vertices[0] = info->x * info->coordincx; tile.vertices[1] = info->y * info->coordincy; tile.vertices[2] = (info->x + tile.w) * info->coordincx; tile.vertices[3] = info->y * info->coordincy; tile.vertices[4] = (info->x + tile.w) * info->coordincx; tile.vertices[5] = (info->y + tile.h) * info->coordincy; tile.vertices[6] = info->x * info->coordincx; tile.vertices[7] = (info->y + tile.h) * info->coordincy; // Screen culling if( tile.vertices[0] >= vdp2width || tile.vertices[1] >= vdp2height || tile.vertices[2] < 0 || tile.vertices[5] < 0 ) { info->x += tile.w; info->y += tile.h; return; } if( (info->bEnWin0 != 0 || info->bEnWin1 != 0) && info->coordincy == 1.0f ) { // coordinate inc is not supported yet. winmode=Vdp2CheckWindowRange( info,info->x,info->y,tile.w,tile.h); if( winmode == 0 ) // all outside, no need to draw { info->x += tile.w; info->y += tile.h; return; } } tile.cor = info->cor; tile.cog = info->cog; tile.cob = info->cob; if (1 == YglIsCached(cacheaddr,&c) ) { YglCachedQuad(&tile, &c); info->x += tile.w; info->y += tile.h; return; } YglQuad(&tile, texture, &c); YglCacheAdd(cacheaddr, &c); switch(info->patternwh) { case 1: Vdp2DrawCell(info, texture); break; case 2: texture->w += 8; Vdp2DrawCell(info, texture); texture->textdata -= (texture->w + 8) * 8 - 8; Vdp2DrawCell(info, texture); texture->textdata -= 8; Vdp2DrawCell(info, texture); texture->textdata -= (texture->w + 8) * 8 - 8; Vdp2DrawCell(info, texture); break; } info->x += tile.w; info->y += tile.h; } ////////////////////////////////////////////////////////////////////////////// static void Vdp2PatternAddr(vdp2draw_struct *info) { switch(info->patterndatasize) { case 1: { u16 tmp = T1ReadWord(Vdp2Ram, info->addr); info->addr += 2; info->specialfunction = (info->supplementdata >> 9) & 0x1; info->specialcolorfunction = (info->supplementdata >> 8) & 0x1; switch(info->colornumber) { case 0: // in 16 colors info->paladdr = ((tmp & 0xF000) >> 12) | ((info->supplementdata & 0xE0) >> 1); break; default: // not in 16 colors info->paladdr = (tmp & 0x7000) >> 8; break; } switch(info->auxmode) { case 0: info->flipfunction = (tmp & 0xC00) >> 10; switch(info->patternwh) { case 1: info->charaddr = (tmp & 0x3FF) | ((info->supplementdata & 0x1F) << 10); break; case 2: info->charaddr = ((tmp & 0x3FF) << 2) | (info->supplementdata & 0x3) | ((info->supplementdata & 0x1C) << 10); break; } break; case 1: info->flipfunction = 0; switch(info->patternwh) { case 1: info->charaddr = (tmp & 0xFFF) | ((info->supplementdata & 0x1C) << 10); break; case 2: info->charaddr = ((tmp & 0xFFF) << 2) | (info->supplementdata & 0x3) | ((info->supplementdata & 0x10) << 10); break; } break; } break; } case 2: { u16 tmp1 = T1ReadWord(Vdp2Ram, info->addr); u16 tmp2 = T1ReadWord(Vdp2Ram, info->addr+2); info->addr += 4; info->charaddr = tmp2 & 0x7FFF; info->flipfunction = (tmp1 & 0xC000) >> 14; switch(info->colornumber) { case 0: info->paladdr = (tmp1 & 0x7F); break; default: info->paladdr = (tmp1 & 0x70); break; } info->specialfunction = (tmp1 & 0x2000) >> 13; info->specialcolorfunction = (tmp1 & 0x1000) >> 12; break; } } if (!(Vdp2Regs->VRSIZE & 0x8000)) info->charaddr &= 0x3FFF; info->charaddr *= 0x20; // thanks Runik } static void Vdp2PatternAddrPos(vdp2draw_struct *info, int planex, int x, int planey, int y ) { u32 addr = info->addr + (info->pagewh*info->pagewh*info->planew*planey + info->pagewh*info->pagewh*planex + info->pagewh*y + x)*info->patterndatasize*2; switch (info->patterndatasize) { case 1: { u16 tmp = T1ReadWord(Vdp2Ram, addr); info->specialfunction = (info->supplementdata >> 9) & 0x1; info->specialcolorfunction = (info->supplementdata >> 8) & 0x1; switch (info->colornumber) { case 0: // in 16 colors info->paladdr = ((tmp & 0xF000) >> 12) | ((info->supplementdata & 0xE0) >> 1); break; default: // not in 16 colors info->paladdr = (tmp & 0x7000) >> 8; break; } switch (info->auxmode) { case 0: info->flipfunction = (tmp & 0xC00) >> 10; switch (info->patternwh) { case 1: info->charaddr = (tmp & 0x3FF) | ((info->supplementdata & 0x1F) << 10); break; case 2: info->charaddr = ((tmp & 0x3FF) << 2) | (info->supplementdata & 0x3) | ((info->supplementdata & 0x1C) << 10); break; } break; case 1: info->flipfunction = 0; switch (info->patternwh) { case 1: info->charaddr = (tmp & 0xFFF) | ((info->supplementdata & 0x1C) << 10); break; case 2: info->charaddr = ((tmp & 0xFFF) << 2) | (info->supplementdata & 0x3) | ((info->supplementdata & 0x10) << 10); break; } break; } break; } case 2: { u16 tmp1 = T1ReadWord(Vdp2Ram, addr); u16 tmp2 = T1ReadWord(Vdp2Ram, addr+2); info->charaddr = tmp2 & 0x7FFF; info->flipfunction = (tmp1 & 0xC000) >> 14; switch (info->colornumber) { case 0: info->paladdr = (tmp1 & 0x7F); break; default: info->paladdr = (tmp1 & 0x70); break; } info->specialfunction = (tmp1 & 0x2000) >> 13; info->specialcolorfunction = (tmp1 & 0x1000) >> 12; break; } } if (!(Vdp2Regs->VRSIZE & 0x8000)) info->charaddr &= 0x3FFF; info->charaddr *= 0x20; // thanks Runik } static void Vdp2DrawPage(vdp2draw_struct *info, YglTexture *texture) { int X, Y; int i, j; X = info->x; for(i = 0;i < info->pagewh;i++) { Y = info->y; info->x = X; for(j = 0;j < info->pagewh;j++) { info->y = Y; if ((info->x >= -info->patternpixelwh) && (info->y >= -info->patternpixelwh) && (info->x <= info->draww) && (info->y <= info->drawh)) { Vdp2PatternAddr(info); Vdp2DrawPattern(info, texture); } else { info->addr += info->patterndatasize * 2; info->x += info->patternpixelwh; info->y += info->patternpixelwh; } } } } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawPlane(vdp2draw_struct *info, YglTexture *texture) { int X, Y; int i, j; X = info->x; for(i = 0;i < info->planeh;i++) { Y = info->y; info->x = X; for(j = 0;j < info->planew;j++) { info->y = Y; Vdp2DrawPage(info, texture); } } } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawMapPerLine(vdp2draw_struct *info, YglTexture *texture){ int lineindex = 0; int sx; //, sy; int mapx, mapy; int planex, planey; int pagex, pagey; int charx, chary; int dot_on_planey; int dot_on_pagey; int dot_on_planex; int dot_on_pagex; int h,v; const int planeh_shift = 9 + (info->planeh-1); const int planew_shift = 9 + (info->planew-1); const int plane_shift = 9; const int plane_mask = 0x1FF; const int page_shift = 9 - 7 + (64/info->pagewh); const int page_mask = 0x0f >> ((info->pagewh/32)-1); info->patternpixelwh = 8*info->patternwh; info->draww = (int)((float)vdp2width / info->coordincx); info->drawh = (int)((float)vdp2height / info->coordincy); for (v = 0; v < info->drawh; v += info->lineinc){ // ToDo: info->coordincy int targetv = 0; Vdp2 * regs; sx = info->x + info->lineinfo[lineindex].LineScrollValH; if (VDPLINE_SY(info->islinescroll)) { targetv = info->y + info->lineinfo[lineindex].LineScrollValV; }else{ targetv = info->y + v; } if (info->isverticalscroll) { // this is *wrong*, vertical scroll use a different value per cell // info->verticalscrolltbl should be incremented by info->verticalscrollinc // each time there's a cell change and reseted at the end of the line... // or something like that :) targetv += T1ReadLong(Vdp2Ram, info->verticalscrolltbl) >> 16; } info->coordincx = info->lineinfo[lineindex].CoordinateIncH / 256.0f; info->coordincx = 1.0f / info->coordincx; if (info->coordincx < info->maxzoom) info->coordincx = info->maxzoom; info->draww = (int)((float)vdp2width / info->coordincx); regs = Vdp2RestoreRegs(v, Vdp2Lines); if (regs) ReadVdp2ColorOffset(regs, info, info->linecheck_mask); // determine which chara shoud be used. //mapy = (v+sy) / (512 * info->planeh); mapy = (targetv) >> planeh_shift; //int dot_on_planey = (v + sy) - mapy*(512 * info->planeh); dot_on_planey = (targetv)-(mapy << planeh_shift); mapy = mapy & 0x01; //planey = dot_on_planey / 512; planey = dot_on_planey >> plane_shift; //int dot_on_pagey = dot_on_planey - planey * 512; dot_on_pagey = dot_on_planey & plane_mask; planey = planey & (info->planeh - 1); //pagey = dot_on_pagey / (512 / info->pagewh); pagey = dot_on_pagey >> page_shift; //chary = dot_on_pagey - pagey*(512 / info->pagewh); chary = dot_on_pagey & page_mask; if (pagey < 0) pagey = info->pagewh - 1 + pagey; for (h = -info->patternpixelwh; h < info->draww + info->patternpixelwh; h += info->patternpixelwh){ //mapx = (h + sx) / (512 * info->planew); mapx = (h + sx) >> planew_shift; //int dot_on_planex = (h + sx) - mapx*(512 * info->planew); dot_on_planex = (h + sx) - (mapx << planew_shift); mapx = mapx & 0x01; //planex = dot_on_planex / 512; planex = dot_on_planex >> plane_shift; //int dot_on_pagex = dot_on_planex - planex * 512; dot_on_pagex = dot_on_planex & plane_mask; planex = planex & (info->planew - 1); //pagex = dot_on_pagex / (512 / info->pagewh); pagex = dot_on_pagex >> page_shift; //charx = dot_on_pagex - pagex*(512 / info->pagewh); charx = dot_on_pagex & page_mask; if (pagex < 0) pagex = info->pagewh - 1 + pagex; info->PlaneAddr(info, info->mapwh * mapy + mapx, Vdp2Regs); Vdp2PatternAddrPos(info, planex,pagex, planey,pagey); Vdp2DrawPatternPos(info, texture, h, v, charx, chary); } lineindex++; } } static void Vdp2DrawMapTest(vdp2draw_struct *info, YglTexture *texture){ int lineindex = 0; int sx; //, sy; int mapx, mapy; int planex, planey; int pagex, pagey; int charx, chary; int dot_on_planey; int dot_on_pagey; int dot_on_planex; int dot_on_pagex; int h, v; const int planeh_shift = 9 + (info->planeh - 1); const int planew_shift = 9 + (info->planew - 1); const int plane_shift = 9; const int plane_mask = 0x1FF; const int page_shift = 9 - 7 + (64 / info->pagewh); const int page_mask = 0x0f >> ((info->pagewh / 32) - 1); info->patternpixelwh = 8 * info->patternwh; info->draww = (int)((float)vdp2width / info->coordincx); info->drawh = (int)((float)vdp2height / info->coordincy); info->lineinc = info->patternpixelwh; //info->coordincx = 1.0f; for (v = -info->patternpixelwh; v < info->drawh + info->patternpixelwh; v += info->patternpixelwh){ int targetv = 0; sx = info->x; targetv = info->y + v; if (info->isverticalscroll) { // this is *wrong*, vertical scroll use a different value per cell // info->verticalscrolltbl should be incremented by info->verticalscrollinc // each time there's a cell change and reseted at the end of the line... // or something like that :) targetv += T1ReadLong(Vdp2Ram, info->verticalscrolltbl) >> 16; } // determine which chara shoud be used. //mapy = (v+sy) / (512 * info->planeh); mapy = (targetv) >> planeh_shift; //int dot_on_planey = (v + sy) - mapy*(512 * info->planeh); dot_on_planey = (targetv)-(mapy << planeh_shift); mapy = mapy & 0x01; //planey = dot_on_planey / 512; planey = dot_on_planey >> plane_shift; //int dot_on_pagey = dot_on_planey - planey * 512; dot_on_pagey = dot_on_planey & plane_mask; planey = planey & (info->planeh - 1); //pagey = dot_on_pagey / (512 / info->pagewh); pagey = dot_on_pagey >> page_shift; //chary = dot_on_pagey - pagey*(512 / info->pagewh); chary = dot_on_pagey & page_mask; if (pagey < 0) pagey = info->pagewh - 1 + pagey; for (h = -info->patternpixelwh; h < info->draww + info->patternpixelwh; h += info->patternpixelwh){ //mapx = (h + sx) / (512 * info->planew); mapx = (h + sx) >> planew_shift; //int dot_on_planex = (h + sx) - mapx*(512 * info->planew); dot_on_planex = (h + sx) - (mapx << planew_shift); mapx = mapx & 0x01; //planex = dot_on_planex / 512; planex = dot_on_planex >> plane_shift; //int dot_on_pagex = dot_on_planex - planex * 512; dot_on_pagex = dot_on_planex & plane_mask; planex = planex & (info->planew - 1); //pagex = dot_on_pagex / (512 / info->pagewh); pagex = dot_on_pagex >> page_shift; //charx = dot_on_pagex - pagex*(512 / info->pagewh); charx = dot_on_pagex & page_mask; if (pagex < 0) pagex = info->pagewh - 1 + pagex; info->PlaneAddr(info, info->mapwh * mapy + mapx, Vdp2Regs); Vdp2PatternAddrPos(info, planex, pagex, planey, pagey); Vdp2DrawPatternPos(info, texture, h - charx, v - chary, 0, 0); } lineindex++; } } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawMap(vdp2draw_struct *info, YglTexture *texture) { int i, j; int X, Y; int xx,yy; info->patternpixelwh = 8 * info->patternwh; info->draww = (int)((float)vdp2width / info->coordincx); info->drawh = (int)((float)vdp2height / info->coordincy); i=0; X = info->x; yy = info->y*info->coordincy; while( yy < vdp2height ) { Y = info->y; j=0; info->x = X; xx = info->x*info->coordincx; while( xx < vdp2width ) { info->y = Y; info->PlaneAddr(info, info->mapwh * i + j, Vdp2Regs); Vdp2DrawPlane(info, texture); j++; j &= (info->mapwh-1); xx += (info->patternpixelwh*info->pagewh*info->planew) * info->coordincx; } i++; i&=(info->mapwh-1); yy += (info->patternpixelwh*info->pagewh*info->planeh) * info->coordincy; } } ////////////////////////////////////////////////////////////////////////////// static u32 FASTCALL DoNothing(UNUSED void *info, u32 pixel) { return pixel; } ////////////////////////////////////////////////////////////////////////////// static u32 FASTCALL DoColorOffset(void *info, u32 pixel) { return pixel; } #if 0 static u32 FASTCALL DoColorOffset(void *info, u32 pixel) { return COLOR_ADD(pixel, ((vdp2draw_struct *)info)->cor, ((vdp2draw_struct *)info)->cog, ((vdp2draw_struct *)info)->cob); } #endif ////////////////////////////////////////////////////////////////////////////// static INLINE void ReadVdp2ColorOffset(Vdp2 * regs, vdp2draw_struct *info, int mask) { if (regs->CLOFEN & mask) { // color offset enable if (regs->CLOFSL & mask) { // color offset B info->cor = regs->COBR & 0xFF; if (regs->COBR & 0x100) info->cor |= 0xFFFFFF00; info->cog = regs->COBG & 0xFF; if (regs->COBG & 0x100) info->cog |= 0xFFFFFF00; info->cob = regs->COBB & 0xFF; if (regs->COBB & 0x100) info->cob |= 0xFFFFFF00; } else { // color offset A info->cor = regs->COAR & 0xFF; if (regs->COAR & 0x100) info->cor |= 0xFFFFFF00; info->cog = regs->COAG & 0xFF; if (regs->COAG & 0x100) info->cog |= 0xFFFFFF00; info->cob = regs->COAB & 0xFF; if (regs->COAB & 0x100) info->cob |= 0xFFFFFF00; } info->PostPixelFetchCalc = &DoColorOffset; } else{ // color offset disable info->PostPixelFetchCalc = &DoNothing; info->cor=0; info->cob=0; info->cog=0; } } ////////////////////////////////////////////////////////////////////////////// static INLINE u32 Vdp2RotationFetchPixel(vdp2draw_struct *info, int x, int y, int cellw) { u32 dot; switch(info->colornumber) { case 0: // 4 BPP dot = T1ReadByte(Vdp2Ram, ((info->charaddr + ((y * cellw) + x) / 2) & 0x7FFFF)); if (!(x & 0x1)) dot >>= 4; if (!(dot & 0xF) && info->transparencyenable) return 0x00000000; else return Vdp2ColorRamGetColor(info->coloroffset + ((info->paladdr << 4) | (dot & 0xF)), info->alpha); case 1: // 8 BPP dot = T1ReadByte(Vdp2Ram, ((info->charaddr + (y * cellw) + x) & 0x7FFFF)); if (!(dot & 0xFF) && info->transparencyenable) return 0x00000000; else return Vdp2ColorRamGetColor(info->coloroffset + ((info->paladdr << 4) | (dot & 0xFF)), info->alpha); case 2: // 16 BPP(palette) dot = T1ReadWord(Vdp2Ram, ((info->charaddr + ((y * cellw) + x) * 2) & 0x7FFFF)); if ((dot == 0) && info->transparencyenable) return 0x00000000; else return Vdp2ColorRamGetColor(info->coloroffset + dot, info->alpha); case 3: // 16 BPP(RGB) dot = T1ReadWord(Vdp2Ram, ((info->charaddr + ((y * cellw) + x) * 2) & 0x7FFFF)); if (!(dot & 0x8000) && info->transparencyenable) return 0x00000000; else return SAT2YAB1(0xFF, dot); case 4: // 32 BPP dot = T1ReadLong(Vdp2Ram, ((info->charaddr + ((y * cellw) + x) * 4) & 0x7FFFF)); if (!(dot & 0x80000000) && info->transparencyenable) return 0x00000000; else return SAT2YAB2(info->alpha, (dot >> 16), dot); default: return 0; } } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL Vdp2DrawRotation(vdp2draw_struct *info, vdp2rotationparameter_struct *dmy, YglTexture *texture) { int useb = 0; int i, j; int x, y; int cellw, cellh; int pagepixelwh; int planepixelwidth; int planepixelheight; int screenwidth; int screenheight; int oldcellx=-1, oldcelly=-1; u32 color; int vres,hres; int h; int v; int pagesize; int patternshift; u32 LineColorRamAdress; vdp2draw_struct line_info; YglTexture line_texture; int lineInc = Vdp2Regs->LCTA.part.U & 0x8000 ? 2 : 0; int linecl = 0xFF; vdp2rotationparameter_struct *parameter; Vdp2 * regs; if ((Vdp2Regs->CCCTL >> 5) & 0x01){ linecl = ((~Vdp2Regs->CCRLB & 0x1F) << 3) + 0x7; } if( vdp2height >= 448 ) vres = (vdp2height>>1); else vres = vdp2height; if( vdp2width >= 640 ) hres = (vdp2width>>1); else hres = vdp2width; info->vertices[0] = 0; info->vertices[1] = 0; info->vertices[2] = vdp2width; info->vertices[3] = 0; info->vertices[4] = vdp2width; info->vertices[5] = vdp2height; info->vertices[6] = 0; info->vertices[7] = vdp2height; cellw = info->cellw; cellh = info->cellh; info->cellw = hres; info->cellh = vres; info->flipfunction = 0; info->linescreen = 0; info->cor = 0x00; info->cog = 0x00; info->cob = 0x00; if( Vdp2Regs->RPMD != 0 ) useb = 1; if (!info->isbitmap) { pagepixelwh=64*8; planepixelwidth=info->planew*pagepixelwh; planepixelheight=info->planeh*pagepixelwh; screenwidth=4*planepixelwidth; screenheight=4*planepixelheight; oldcellx=-1; oldcelly=-1; pagesize=info->pagewh*info->pagewh; patternshift = (2+info->patternwh); } else { pagepixelwh=0; planepixelwidth=0; planepixelheight=0; screenwidth=0; screenheight=0; oldcellx=0; oldcelly=0; pagesize=0; patternshift = 0; } regs = Vdp2RestoreRegs(3, Vdp2Lines); if (regs) ReadVdp2ColorOffset(regs, info, info->linecheck_mask); line_texture.textdata = NULL; if( info->LineColorBase !=0 ) { memcpy(&line_info, info, sizeof(vdp2draw_struct)); line_info.blendmode = 0; YglQuad((YglSprite *)&line_info, &line_texture, NULL); LineColorRamAdress = (T1ReadWord(Vdp2Ram, info->LineColorBase) & 0x7FF);// +info->coloroffset; }else{ LineColorRamAdress = 0x00; } YglQuad((YglSprite *)info, texture, NULL); info->cellw = cellw; info->cellh = cellh; x = 0; y = 0; paraA.dx = paraA.A * paraA.deltaX + paraA.B * paraA.deltaY; paraA.dy = paraA.D * paraA.deltaX + paraA.E * paraA.deltaY; paraA.Xp = paraA.A * (paraA.Px - paraA.Cx) + paraA.B * (paraA.Py - paraA.Cy) + paraA.C * (paraA.Pz - paraA.Cz) + paraA.Cx + paraA.Mx; paraA.Yp = paraA.D * (paraA.Px - paraA.Cx) + paraA.E * (paraA.Py - paraA.Cy) + paraA.F * (paraA.Pz - paraA.Cz) + paraA.Cy + paraA.My; if(useb) { paraB.dx = paraB.A * paraB.deltaX + paraB.B * paraB.deltaY; paraB.dy = paraB.D * paraB.deltaX + paraB.E * paraB.deltaY; paraB.Xp = paraB.A * (paraB.Px - paraB.Cx) + paraB.B * (paraB.Py - paraB.Cy) + paraB.C * (paraB.Pz - paraB.Cz) + paraB.Cx + paraB.Mx; paraB.Yp = paraB.D * (paraB.Px - paraB.Cx) + paraB.E * (paraB.Py - paraB.Cy) + paraB.F * (paraB.Pz - paraB.Cz) + paraB.Cy + paraB.My; } for (j = 0; j < vres; j++) { paraA.Xsp = paraA.A * ((paraA.Xst + paraA.deltaXst * j) - paraA.Px) + paraA.B * ((paraA.Yst + paraA.deltaYst * j) - paraA.Py) + paraA.C * (paraA.Zst - paraA.Pz); paraA.Ysp = paraA.D * ((paraA.Xst + paraA.deltaXst *j) - paraA.Px) + paraA.E * ((paraA.Yst + paraA.deltaYst * j) - paraA.Py) + paraA.F * (paraA.Zst - paraA.Pz); paraA.KtablV = paraA.deltaKAst* j; if(useb) { paraB.Xsp = paraB.A * ((paraB.Xst + paraB.deltaXst * j) - paraB.Px) + paraB.B * ((paraB.Yst + paraB.deltaYst * j) - paraB.Py) + paraB.C * (paraB.Zst - paraB.Pz); paraB.Ysp = paraB.D * ((paraB.Xst + paraB.deltaXst * j) - paraB.Px) + paraB.E * ((paraB.Yst + paraB.deltaYst * j) - paraB.Py) + paraB.F * (paraB.Zst - paraB.Pz); paraB.KtablV = paraB.deltaKAst * j; } if( (Vdp2Regs->LCTA.part.U & 0x8000) != 0 && info->LineColorBase !=0 ) { LineColorRamAdress = (T1ReadWord(Vdp2Ram, info->LineColorBase) & 0x7FF); info->LineColorBase += lineInc; } // Vdp2 * regs = Vdp2RestoreRegs(j); // if (regs) ReadVdp2ColorOffset(regs, info, info->linecheck_mask); for (i = 0; i < hres; i++) { parameter = info->GetRParam(info, i, j); if (parameter == NULL) { *(texture->textdata++) = 0x00000000; if (line_texture.textdata) *(line_texture.textdata++) = 0x00000000; continue; } h = (parameter->ky * (parameter->Xsp + parameter->dx * i) + parameter->Xp); v = (parameter->ky * (parameter->Ysp + parameter->dy * i) + parameter->Yp); if (info->isbitmap) { h &= cellw - 1; v &= cellh - 1; // Fetch Pixel color = Vdp2RotationFetchPixel(info, h, v, cellw); } else { // Tile int planenum; if ((h < 0 || h >= parameter->MaxH) || (v < 0 || v >= parameter->MaxV)) { switch (parameter->screenover) { case OVERMODE_REPEAT: h &= (parameter->MaxH - 1); v &= (parameter->MaxH - 1); break; case OVERMODE_SELPATNAME: *(texture->textdata++) = 0x00; // ToDO if (line_texture.textdata) *(line_texture.textdata++) = 0x00000000; continue; break; default: *(texture->textdata++) = 0x00; if (line_texture.textdata) *(line_texture.textdata++) = 0x00000000; continue; } } x = h; y = v; if ((x >> patternshift) != oldcellx || (y >> patternshift) != oldcelly) { oldcellx = x >> patternshift; oldcelly = y >> patternshift; // Calculate which plane we're dealing with planenum = (x >> parameter->ShiftPaneX) + ((y >> parameter->ShiftPaneY) << 2); x &= parameter->MskH; y &= parameter->MskV; info->addr = parameter->PlaneAddrv[planenum]; // Figure out which page it's on(if plane size is not 1x1) info->addr += (((y >> 9) * pagesize * info->planew) + ((x >> 9) * pagesize) + (((y & 511) >> patternshift) * info->pagewh) + ((x & 511) >> patternshift)) << info->patterndatasize; Vdp2PatternAddr(info); // Heh, this could be optimized } // Figure out which pixel in the tile we want if (info->patternwh == 1) { x &= 8 - 1; y &= 8 - 1; // vertical flip if (info->flipfunction & 0x2) y = 8 - 1 - y; // horizontal flip if (info->flipfunction & 0x1) x = 8 - 1 - x; } else { if (info->flipfunction) { y &= 16 - 1; if (info->flipfunction & 0x2) { if (!(y & 8)) y = 8 - 1 - y + 16; else y = 16 - 1 - y; } else if (y & 8) y += 8; if (info->flipfunction & 0x1) { if (!(x & 8)) y += 8; x &= 8 - 1; x = 8 - 1 - x; } else if (x & 8) { y += 8; x &= 8 - 1; } else x &= 8 - 1; } else { y &= 16 - 1; if (y & 8) y += 8; if (x & 8) y += 8; x &= 8 - 1; } } // Fetch pixel color = Vdp2RotationFetchPixel(info, x, y, 8); } if (line_texture.textdata) { if ((color & 0xFF000000) == 0) { *(line_texture.textdata++) = 0x00000000; }else{ if (parameter->lineaddr != 0xFFFFFFFF) { u32 linecolor = Vdp2ColorRamGetColor(LineColorRamAdress | parameter->lineaddr, linecl); *(line_texture.textdata++) = linecolor; } else{ *(line_texture.textdata++) = 0x0 | (linecl << 24); } } } *(texture->textdata++) = color; } if (line_texture.textdata) line_texture.textdata += line_texture.w; texture->textdata += texture->w; } } ////////////////////////////////////////////////////////////////////////////// static void SetSaturnResolution(int width, int height) { YglChangeResolution(width, height); vdp2width=width; vdp2height=height; } ////////////////////////////////////////////////////////////////////////////// int VIDOGLInit(void) { if (YglInit(2048, 1024, 8) != 0) return -1; SetSaturnResolution(320, 224); vdp1wratio = 1; vdp1hratio = 1; return 0; } ////////////////////////////////////////////////////////////////////////////// void VIDOGLDeInit(void) { YglDeInit(); } ////////////////////////////////////////////////////////////////////////////// int _VIDOGLIsFullscreen; void VIDOGLResize(unsigned int w, unsigned int h, int on) { // glDeleteTextures(1, &_Ygl->texture); _VIDOGLIsFullscreen = on; GlHeight=h; GlWidth=w; _Ygl->width = w; _Ygl->height = h; YglGLInit(2048, 1024); glViewport(0, 0, w, h); YglNeedToUpdateWindow(); SetSaturnResolution(vdp2width, vdp2height); } ////////////////////////////////////////////////////////////////////////////// int VIDOGLIsFullscreen(void) { return _VIDOGLIsFullscreen; } ////////////////////////////////////////////////////////////////////////////// int VIDOGLVdp1Reset(void) { return 0; } ////////////////////////////////////////////////////////////////////////////// void VIDOGLVdp1DrawStart(void) { int i; int maxpri; int minpri; u8 *sprprilist = (u8 *)&Vdp2Regs->PRISA; if (YglTM->texture == NULL) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, _Ygl->texture); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _Ygl->pixelBufferID); YglTM->texture = (unsigned int*)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, 2048 * 1024 * 4, GL_MAP_WRITE_BIT); if (YglTM->texture == NULL){ abort(); } } YglCacheReset(); maxpri = 0x00; minpri = 0x07; for( i=0; i<8; i++ ) { if( (sprprilist[i]&0x07) < minpri ) minpri = (sprprilist[i]&0x07); if( (sprprilist[i]&0x07) > maxpri ) maxpri = (sprprilist[i]&0x07); } _Ygl->vdp1_maxpri = maxpri; _Ygl->vdp1_minpri = minpri; if (Vdp2Regs->CLOFEN & 0x40) { // color offset enable if (Vdp2Regs->CLOFSL & 0x40) { // color offset B vdp1cor = Vdp2Regs->COBR & 0xFF; if (Vdp2Regs->COBR & 0x100) vdp1cor |= 0xFFFFFF00; vdp1cog = Vdp2Regs->COBG & 0xFF; if (Vdp2Regs->COBG & 0x100) vdp1cog |= 0xFFFFFF00; vdp1cob = Vdp2Regs->COBB & 0xFF; if (Vdp2Regs->COBB & 0x100) vdp1cob |= 0xFFFFFF00; } else { // color offset A vdp1cor = Vdp2Regs->COAR & 0xFF; if (Vdp2Regs->COAR & 0x100) vdp1cor |= 0xFFFFFF00; vdp1cog = Vdp2Regs->COAG & 0xFF; if (Vdp2Regs->COAG & 0x100) vdp1cog |= 0xFFFFFF00; vdp1cob = Vdp2Regs->COAB & 0xFF; if (Vdp2Regs->COAB & 0x100) vdp1cob |= 0xFFFFFF00; } } else // color offset disable vdp1cor = vdp1cog = vdp1cob = 0; Vdp1DrawCommands(Vdp1Ram, Vdp1Regs, NULL); } ////////////////////////////////////////////////////////////////////////////// void VIDOGLVdp1DrawEnd(void) { YglRenderVDP1(); } ////////////////////////////////////////////////////////////////////////////// void VIDOGLVdp1NormalSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer) { vdp1cmd_struct cmd; YglSprite sprite; YglTexture texture; YglCache cash; u32 tmp; s16 x, y; u16 CMDPMOD; u16 color2; float col[4*4]; int i; short CMDXA; short CMDYA; Vdp1ReadCommand(&cmd, Vdp1Regs->addr, Vdp1Ram); sprite.dst=0; sprite.blendmode=0; sprite.linescreen = 0; CMDXA = cmd.CMDXA; CMDYA = cmd.CMDYA; if ((CMDXA & 0x800)) CMDXA |= 0xF800; else CMDXA &= ~(0xF800); if ((CMDYA & 0x800)) CMDYA |= 0xF800; else CMDYA &= ~(0xF800); x = CMDXA + Vdp1Regs->localX; y = CMDYA + Vdp1Regs->localY; sprite.w = ((cmd.CMDSIZE >> 8) & 0x3F) * 8; sprite.h = cmd.CMDSIZE & 0xFF; sprite.flip = (cmd.CMDCTRL & 0x30) >> 4; sprite.vertices[0] = (int)((float)x * vdp1wratio); sprite.vertices[1] = (int)((float)y * vdp1hratio); sprite.vertices[2] = (int)((float)(x + sprite.w) * vdp1wratio); sprite.vertices[3] = (int)((float)y * vdp1hratio); sprite.vertices[4] = (int)((float)(x + sprite.w) * vdp1wratio); sprite.vertices[5] = (int)((float)(y + sprite.h) * vdp1hratio); sprite.vertices[6] = (int)((float)x * vdp1wratio); sprite.vertices[7] = (int)((float)(y + sprite.h) * vdp1hratio); tmp = cmd.CMDSRCA; tmp <<= 16; tmp |= cmd.CMDCOLR; sprite.priority = 8; CMDPMOD = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x4); sprite.uclipmode=(CMDPMOD>>9)&0x03; // Half trans parent to VDP1 Framebuffer if( (CMDPMOD & 0x3)==0x03 || (CMDPMOD & 0x100) ) { tmp |= 0x00010000; sprite.blendmode = 0x80; } if((CMDPMOD & 0x8000) != 0) { tmp |= 0x00020000; } if( (CMDPMOD & 4) ) { for (i=0; i<4; i++) { color2 = T1ReadWord(Vdp1Ram, (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x1C) << 3) + (i << 1)); col[(i << 2) + 0] = (float)((color2 & 0x001F))/(float)(0x1F)-0.5f; col[(i << 2) + 1] = (float)((color2 & 0x03E0)>>5)/(float)(0x1F)-0.5f; col[(i << 2) + 2] = (float)((color2 & 0x7C00)>>10)/(float)(0x1F)-0.5f; col[(i << 2) + 3] = 1.0f; } if (sprite.w > 0 && sprite.h > 0) { if (1 == YglIsCached(tmp,&cash) ) { YglCacheQuadGrowShading(&sprite, col,&cash); return; } YglQuadGrowShading(&sprite, &texture,col,&cash); YglCacheAdd(tmp,&cash); Vdp1ReadTexture(&cmd, &sprite, &texture); return; } } else // No Gouraud shading, use same color for all 4 vertices { if (sprite.w > 0 && sprite.h > 0) { if (1 == YglIsCached(tmp,&cash) ) { YglCacheQuadGrowShading(&sprite, NULL,&cash); return; } YglQuadGrowShading(&sprite, &texture,NULL,&cash); YglCacheAdd(tmp,&cash); Vdp1ReadTexture(&cmd, &sprite, &texture); } } } ////////////////////////////////////////////////////////////////////////////// void VIDOGLVdp1ScaledSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer) { vdp1cmd_struct cmd; YglSprite sprite; YglTexture texture; YglCache cash; u32 tmp; s16 rw=0, rh=0; s16 x, y; u16 CMDPMOD; u16 color2; float col[4*4]; int i; Vdp1ReadCommand(&cmd, Vdp1Regs->addr, Vdp1Ram); sprite.dst=0; sprite.blendmode=0; sprite.linescreen = 0; if ((cmd.CMDYA & 0x800)) cmd.CMDYA |= 0xF800; else cmd.CMDYA &= ~(0xF800); if ((cmd.CMDYC & 0x800)) cmd.CMDYC |= 0xF800; else cmd.CMDYC &= ~(0xF800); if ((cmd.CMDYB & 0x800)) cmd.CMDYB |= 0xF800; else cmd.CMDYB &= ~(0xF800); if ((cmd.CMDYD & 0x800)) cmd.CMDYD |= 0xF800; else cmd.CMDYD &= ~(0xF800); x = cmd.CMDXA + Vdp1Regs->localX; y = cmd.CMDYA + Vdp1Regs->localY; sprite.w = ((cmd.CMDSIZE >> 8) & 0x3F) * 8; sprite.h = cmd.CMDSIZE & 0xFF; sprite.flip = (cmd.CMDCTRL & 0x30) >> 4; // Setup Zoom Point switch ((cmd.CMDCTRL & 0xF00) >> 8) { case 0x0: // Only two coordinates rw = cmd.CMDXC - x + Vdp1Regs->localX + 1; rh = cmd.CMDYC - y + Vdp1Regs->localY + 1; break; case 0x5: // Upper-left rw = cmd.CMDXB + 1; rh = cmd.CMDYB + 1; break; case 0x6: // Upper-Center rw = cmd.CMDXB; rh = cmd.CMDYB; x = x - rw/2; rw++; rh++; break; case 0x7: // Upper-Right rw = cmd.CMDXB; rh = cmd.CMDYB; x = x - rw; rw++; rh++; break; case 0x9: // Center-left rw = cmd.CMDXB; rh = cmd.CMDYB; y = y - rh/2; rw++; rh++; break; case 0xA: // Center-center rw = cmd.CMDXB; rh = cmd.CMDYB; x = x - rw/2; y = y - rh/2; rw++; rh++; break; case 0xB: // Center-right rw = cmd.CMDXB; rh = cmd.CMDYB; x = x - rw; y = y - rh/2; rw++; rh++; break; case 0xD: // Lower-left rw = cmd.CMDXB; rh = cmd.CMDYB; y = y - rh; rw++; rh++; break; case 0xE: // Lower-center rw = cmd.CMDXB; rh = cmd.CMDYB; x = x - rw/2; y = y - rh; rw++; rh++; break; case 0xF: // Lower-right rw = cmd.CMDXB; rh = cmd.CMDYB; x = x - rw; y = y - rh; rw++; rh++; break; default: break; } sprite.vertices[0] = (int)((float)x * vdp1wratio); sprite.vertices[1] = (int)((float)y * vdp1hratio); sprite.vertices[2] = (int)((float)(x + rw) * vdp1wratio); sprite.vertices[3] = (int)((float)y * vdp1hratio); sprite.vertices[4] = (int)((float)(x + rw) * vdp1wratio); sprite.vertices[5] = (int)((float)(y + rh) * vdp1hratio); sprite.vertices[6] = (int)((float)x * vdp1wratio); sprite.vertices[7] = (int)((float)(y + rh) * vdp1hratio); tmp = cmd.CMDSRCA; tmp <<= 16; tmp |= cmd.CMDCOLR; CMDPMOD = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x4); sprite.uclipmode=(CMDPMOD>>9)&0x03; sprite.priority = 8; // Half trans parent to VDP1 Framebuffer if( (CMDPMOD & 0x3)==0x03 || (CMDPMOD & 0x100) ) { tmp |= 0x00010000; sprite.blendmode = 0x80; } // MSB if((CMDPMOD & 0x8000) != 0) { tmp |= 0x00020000; } if ( (CMDPMOD & 4) ) { for (i=0; i<4; i++) { color2 = T1ReadWord(Vdp1Ram, (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x1C) << 3) + (i << 1)); col[(i << 2) + 0] = (float)((color2 & 0x001F))/(float)(0x1F)-0.5f; col[(i << 2) + 1] = (float)((color2 & 0x03E0)>>5)/(float)(0x1F)-0.5f; col[(i << 2) + 2] = (float)((color2 & 0x7C00)>>10)/(float)(0x1F)-0.5f; col[(i << 2) + 3] = 1.0f; } if (sprite.w > 0 && sprite.h > 0) { if (1 == YglIsCached(tmp,&cash) ) { YglCacheQuadGrowShading(&sprite, col,&cash); return; } YglQuadGrowShading(&sprite, &texture,col,&cash); YglCacheAdd(tmp,&cash); Vdp1ReadTexture(&cmd, &sprite, &texture); return; } } else // No Gouraud shading, use same color for all 4 vertices { if (sprite.w > 0 && sprite.h > 0) { if (1 == YglIsCached(tmp,&cash) ) { YglCacheQuadGrowShading(&sprite, NULL,&cash); return; } YglQuadGrowShading(&sprite, &texture,NULL,&cash); YglCacheAdd(tmp,&cash); Vdp1ReadTexture(&cmd, &sprite, &texture); } } } ////////////////////////////////////////////////////////////////////////////// void VIDOGLVdp1DistortedSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer) { vdp1cmd_struct cmd; YglSprite sprite; YglTexture texture; YglCache cash; u32 tmp; u16 CMDPMOD; u16 color2; int i; float col[4*4]; int isSquare; Vdp1ReadCommand(&cmd, Vdp1Regs->addr, Vdp1Ram); sprite.blendmode=0; sprite.linescreen = 0; sprite.dst = 1; sprite.w = ((cmd.CMDSIZE >> 8) & 0x3F) * 8; sprite.h = cmd.CMDSIZE & 0xFF; sprite.cor = 0; sprite.cog = 0; sprite.cob = 0; sprite.flip = (cmd.CMDCTRL & 0x30) >> 4; if ((cmd.CMDYA & 0x800)) cmd.CMDYA |= 0xF800; else cmd.CMDYA &= ~(0xF800); if ((cmd.CMDYC & 0x800)) cmd.CMDYC |= 0xF800; else cmd.CMDYC &= ~(0xF800); if ((cmd.CMDYB & 0x800)) cmd.CMDYB |= 0xF800; else cmd.CMDYB &= ~(0xF800); if ((cmd.CMDYD & 0x800)) cmd.CMDYD |= 0xF800; else cmd.CMDYD &= ~(0xF800); sprite.vertices[0] = (s16)cmd.CMDXA; sprite.vertices[1] = (s16)cmd.CMDYA; sprite.vertices[2] = (s16)cmd.CMDXB; sprite.vertices[3] = (s16)cmd.CMDYB; sprite.vertices[4] = (s16)cmd.CMDXC; sprite.vertices[5] = (s16)cmd.CMDYC; sprite.vertices[6] = (s16)cmd.CMDXD; sprite.vertices[7] = (s16)cmd.CMDYD; isSquare = 1; for (i = 0; i < 3; i++){ float dx = sprite.vertices[((i + 1) << 1) + 0] - sprite.vertices[((i + 0) << 1) + 0]; float dy = sprite.vertices[((i + 1) << 1) + 1] - sprite.vertices[((i + 0) << 1) + 1]; float d2x = sprite.vertices[(((i + 2)&0x3) << 1) + 0] - sprite.vertices[((i + 1) << 1) + 0]; float d2y = sprite.vertices[(((i + 2)&0x3) << 1) + 1] - sprite.vertices[((i + 1) << 1) + 1]; float dot = dx*d2x + dy*d2y; if (dot >= EPSILON || dot <= -EPSILON){ isSquare = 0; break; } } if (isSquare){ float minx; float miny; int lt_index; sprite.dst = 0; // find upper left opsition minx = 65535.0f; miny = 65535.0f; lt_index = -1; for( i = 0; i < 4; i++){ if (sprite.vertices[(i << 1) + 0] <= minx && sprite.vertices[(i << 1) + 1] <= miny){ minx = sprite.vertices[(i << 1) + 0]; miny = sprite.vertices[(i << 1) + 1]; lt_index = i; } } for (i = 0; i < 4; i++){ if (i != lt_index){ float nx; float ny; // vectorize float dx = sprite.vertices[(i << 1) + 0] - sprite.vertices[((lt_index) << 1) + 0]; float dy = sprite.vertices[(i << 1) + 1] - sprite.vertices[((lt_index) << 1) + 1]; // normalize float len = fabsf(sqrtf(dx*dx + dy*dy)); if (len <= EPSILON){ continue; } nx = dx / len; ny = dy / len; if (nx >= EPSILON) nx = 1.0f; else nx = 0.0f; if (ny >= EPSILON) ny = 1.0f; else ny = 0.0f; // expand vertex sprite.vertices[(i << 1) + 0] += nx; sprite.vertices[(i << 1) + 1] += ny; } } } sprite.vertices[0] = (sprite.vertices[0] + Vdp1Regs->localX) * vdp1wratio; sprite.vertices[1] = (sprite.vertices[1] + Vdp1Regs->localY) * vdp1hratio; sprite.vertices[2] = (sprite.vertices[2] + Vdp1Regs->localX) * vdp1wratio; sprite.vertices[3] = (sprite.vertices[3] + Vdp1Regs->localY) * vdp1hratio; sprite.vertices[4] = (sprite.vertices[4] + Vdp1Regs->localX) * vdp1wratio; sprite.vertices[5] = (sprite.vertices[5] + Vdp1Regs->localY) * vdp1hratio; sprite.vertices[6] = (sprite.vertices[6] + Vdp1Regs->localX) * vdp1wratio; sprite.vertices[7] = (sprite.vertices[7] + Vdp1Regs->localY) * vdp1hratio; tmp = cmd.CMDSRCA; tmp <<= 16; tmp |= cmd.CMDCOLR; CMDPMOD = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x4); sprite.priority = 8; sprite.uclipmode=(CMDPMOD>>9)&0x03; // Half trans parent to VDP1 Framebuffer if( (CMDPMOD & 0x3)==0x03 || (CMDPMOD & 0x100) ) { tmp |= 0x00010000; sprite.blendmode = 0x80; } // MSB if((CMDPMOD & 0x8000) != 0) { tmp |= 0x00020000; } // Check if the Gouraud shading bit is set and the color mode is RGB if ( (CMDPMOD & 4) ) { for (i=0; i<4; i++) { color2 = T1ReadWord(Vdp1Ram, (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x1C) << 3) + (i << 1)); col[(i << 2) + 0] = (float)((color2 & 0x001F))/(float)(0x1F)-0.5f; col[(i << 2) + 1] = (float)((color2 & 0x03E0)>>5)/(float)(0x1F)-0.5f; col[(i << 2) + 2] = (float)((color2 & 0x7C00)>>10)/(float)(0x1F)-0.5f; col[(i << 2) + 3] = 1.0f; } if (1 == YglIsCached(tmp,&cash) ) { YglCacheQuadGrowShading(&sprite, col,&cash); return; } YglQuadGrowShading(&sprite, &texture,col,&cash); YglCacheAdd(tmp,&cash); Vdp1ReadTexture(&cmd, &sprite, &texture); return; } else // No Gouraud shading, use same color for all 4 vertices { if (1 == YglIsCached(tmp,&cash) ) { YglCacheQuadGrowShading(&sprite, NULL,&cash); return; } YglQuadGrowShading(&sprite, &texture,NULL,&cash); YglCacheAdd(tmp,&cash); Vdp1ReadTexture(&cmd, &sprite, &texture); } return ; } ////////////////////////////////////////////////////////////////////////////// #define IS_MESH(a) (a&0x100) #define IS_GLOWSHADING(a) (a&0x04) #define IS_REPLACE(a) ((a&0x03)==0x00) #define IS_DONOT_DRAW_OR_SHADOW(a) ((a&0x03)==0x01) #define IS_HALF_LUMINANCE(a) ((a&0x03)==0x02) #define IS_REPLACE_OR_HALF_TRANSPARENT(a) ((a&0x03)==0x03) void VIDOGLVdp1PolygonDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer) { u16 color; u16 CMDPMOD; u8 alpha; YglSprite sprite; YglTexture texture; u16 color2; int i; float col[4*4]; int gouraud=0; int priority; short CMDYA; short CMDYB; short CMDYC; short CMDYD; int isSquare; vdp1cmd_struct cmd; sprite.linescreen = 0; Vdp1ReadCommand(&cmd, Vdp1Regs->addr, Vdp1Ram); CMDYA = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0xE); CMDYB = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x12); CMDYC = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x16); CMDYD = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x1A); if ((CMDYA & 0x800)) CMDYA |= 0xF800; else CMDYA &= ~(0xF800); if ((CMDYC & 0x800)) CMDYC |= 0xF800; else CMDYC &= ~(0xF800); if ((CMDYB & 0x800)) CMDYB |= 0xF800; else CMDYB &= ~(0xF800); if ((CMDYD & 0x800)) CMDYD |= 0xF800; else CMDYD &= ~(0xF800); sprite.blendmode = 0; sprite.dst = 0; sprite.vertices[0] = (s16)cmd.CMDXA; sprite.vertices[1] = (s16)cmd.CMDYA; sprite.vertices[2] = (s16)cmd.CMDXB; sprite.vertices[3] = (s16)cmd.CMDYB; sprite.vertices[4] = (s16)cmd.CMDXC; sprite.vertices[5] = (s16)cmd.CMDYC; sprite.vertices[6] = (s16)cmd.CMDXD; sprite.vertices[7] = (s16)cmd.CMDYD; isSquare = 1; for (i = 0; i < 3; i++){ float dx = sprite.vertices[((i + 1) << 1) + 0] - sprite.vertices[((i + 0) << 1) + 0]; float dy = sprite.vertices[((i + 1) << 1) + 1] - sprite.vertices[((i + 0) << 1) + 1]; float d2x = sprite.vertices[(((i + 2) & 0x3) << 1) + 0] - sprite.vertices[((i + 1) << 1) + 0]; float d2y = sprite.vertices[(((i + 2) & 0x3) << 1) + 1] - sprite.vertices[((i + 1) << 1) + 1]; float dot = dx*d2x + dy*d2y; if (dot >= EPSILON || dot <= -EPSILON){ isSquare = 0; break; } } if (isSquare){ // find upper left opsition float minx = 65535.0f; float miny = 65535.0f; int lt_index = -1; sprite.dst = 0; for (i = 0; i < 4; i++){ if (sprite.vertices[(i << 1) + 0] <= minx && sprite.vertices[(i << 1) + 1] <= miny){ minx = sprite.vertices[(i << 1) + 0]; miny = sprite.vertices[(i << 1) + 1]; lt_index = i; } } for (i = 0; i < 4; i++){ if (i != lt_index){ // vectorize float dx = sprite.vertices[(i << 1) + 0] - sprite.vertices[((lt_index) << 1) + 0]; float dy = sprite.vertices[(i << 1) + 1] - sprite.vertices[((lt_index) << 1) + 1]; float nx; float ny; // normalize float len = fabsf(sqrtf(dx*dx + dy*dy)); if (len <= EPSILON){ continue; } nx = dx / len; ny = dy / len; if (nx >= EPSILON) nx = 1.0f; else nx = 0.0f; if (ny >= EPSILON) ny = 1.0f; else ny = 0.0f; // expand vertex sprite.vertices[(i << 1) + 0] += nx; sprite.vertices[(i << 1) + 1] += ny; } } } // Line Polygon if ( (sprite.vertices[1] == sprite.vertices[3]) && (sprite.vertices[3] == sprite.vertices[5]) && (sprite.vertices[5] == sprite.vertices[7])) { sprite.vertices[5] += 1; sprite.vertices[7] += 1; } sprite.vertices[0] = (sprite.vertices[0] + Vdp1Regs->localX) * vdp1wratio; sprite.vertices[1] = (sprite.vertices[1] + Vdp1Regs->localY) * vdp1hratio; sprite.vertices[2] = (sprite.vertices[2] + Vdp1Regs->localX) * vdp1wratio; sprite.vertices[3] = (sprite.vertices[3] + Vdp1Regs->localY) * vdp1hratio; sprite.vertices[4] = (sprite.vertices[4] + Vdp1Regs->localX) * vdp1wratio; sprite.vertices[5] = (sprite.vertices[5] + Vdp1Regs->localY) * vdp1hratio; sprite.vertices[6] = (sprite.vertices[6] + Vdp1Regs->localX) * vdp1wratio; sprite.vertices[7] = (sprite.vertices[7] + Vdp1Regs->localY) * vdp1hratio; color = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x6); CMDPMOD = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x4); sprite.uclipmode = (CMDPMOD >> 9) & 0x03; // Half trans parent to VDP1 Framebuffer if( (CMDPMOD & 0x3)==0x03 || (CMDPMOD & 0x100) ) { sprite.blendmode = 0x80; } // Check if the Gouraud shading bit is set and the color mode is RGB if( (CMDPMOD & 4) ) { for (i=0; i<4; i++) { color2 = T1ReadWord(Vdp1Ram, (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x1C) << 3) + (i << 1)); col[(i << 2) + 0] = (float)((color2 & 0x001F))/(float)(0x1F)-0.5f; col[(i << 2) + 1] = (float)((color2 & 0x03E0)>>5)/(float)(0x1F)-0.5f; col[(i << 2) + 2] = (float)((color2 & 0x7C00)>>10)/(float)(0x1F)-0.5f; col[(i << 2) + 3] = 1.0f; } gouraud = 1; } if (color & 0x8000) priority = Vdp2Regs->PRISA & 0x7; else { int shadow, colorcalc; priority = 0; // Avoid compiler warning Vdp1ProcessSpritePixel(Vdp2Regs->SPCTL & 0xF, &color, &shadow, &priority, &colorcalc); #ifdef WORDS_BIGENDIAN priority = ((u8 *)&Vdp2Regs->PRISA)[priority^1] & 0x7; #else priority = ((u8 *)&Vdp2Regs->PRISA)[priority] & 0x7; #endif } sprite.priority = 8; sprite.w = 1; sprite.h = 1; sprite.flip = 0; sprite.cor = 0x00; sprite.cog = 0x00; sprite.cob = 0x00; if (color == 0 || color == 0x8000 ) { YglQuad(&sprite, &texture, NULL); alpha = 0; priority = 0; *texture.textdata = 0; return; } alpha = 0xF8; if (gouraud == 1) { YglQuadGrowShading(&sprite, &texture, col, NULL); } else{ YglQuadGrowShading(&sprite, &texture, NULL, NULL); } if (IS_REPLACE(CMDPMOD)){ alpha = 0xF8; } else if (IS_DONOT_DRAW_OR_SHADOW(CMDPMOD)){ alpha = 0x00; } else if (IS_HALF_LUMINANCE(CMDPMOD)){ alpha = 0xF8; } else if (IS_REPLACE_OR_HALF_TRANSPARENT(CMDPMOD)){ alpha = 0x80; } if (IS_MESH(CMDPMOD)){ alpha = 0x80; } if (Vdp2Regs->SDCTL & 0x100 ){ } /* if( (CMDPMOD & 0x100) || (CMDPMOD & 0x7) == 0x3) { alpha = 0x80; } */ alpha |= priority; if (color & 0x8000){ *texture.textdata = SAT2YAB1(alpha, color); }else{ *texture.textdata = Vdp1ReadPolygonColor(&cmd); } } ////////////////////////////////////////////////////////////////////////////// static void makeLinePolygon(s16 *v1, s16 *v2, float *outv){ float dx; float dy; float len; float nx; float ny; float ex; float ey; float offset; if (v1[0] == v2[0] && v1[1] == v2[1]){ outv[0] = v1[0]; outv[1] = v1[1]; outv[2] = v2[0]; outv[3] = v2[1]; outv[4] = v2[0]; outv[5] = v2[1]; outv[6] = v1[0]; outv[7] = v1[1]; return; } // vectorize; dx = v2[0] - v1[0]; dy = v2[1] - v1[1]; // normalize len = fabs( sqrtf((dx*dx) + (dy*dy)) ); if (len < EPSILON ){ // fail; outv[0] = v1[0]; outv[1] = v1[1]; outv[2] = v2[0]; outv[3] = v2[1]; outv[4] = v2[0]; outv[5] = v2[1]; outv[6] = v1[0]; outv[7] = v1[1]; return; } nx = dx / len; ny = dy / len; // turn dx = ny * 0.5f; dy = -nx * 0.5f; // extend ex = nx * 0.5f; ey = ny * 0.5f; // offset offset = 0.5f; // triangle outv[0] = v1[0] - ex - dx + offset; outv[1] = v1[1] - ey - dy + offset; outv[2] = v1[0] - ex + dx + offset; outv[3] = v1[1] - ey + dy + offset; outv[4] = v2[0] + ex + dx + offset; outv[5] = v2[1] + ey + dy + offset; outv[6] = v2[0] + ex - dx + offset; outv[7] = v2[1] + ey - dy + offset; } void VIDOGLVdp1PolylineDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer) { s16 v[8]; float line_poygon[8]; u16 color; u16 CMDPMOD; u8 alpha; YglSprite polygon; YglTexture texture; YglCache c; int priority; vdp1cmd_struct cmd; float col[4 * 4]; float linecol[4 * 4]; int gouraud = 0; u16 color2; polygon.blendmode=0; polygon.linescreen = 0; polygon.dst = 0; v[0] = Vdp1Regs->localX + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x0C) ); v[1] = Vdp1Regs->localY + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x0E) ); v[2] = Vdp1Regs->localX + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x10) ); v[3] = Vdp1Regs->localY + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x12) ); v[4] = Vdp1Regs->localX + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x14) ); v[5] = Vdp1Regs->localY + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x16) ); v[6] = Vdp1Regs->localX + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x18) ); v[7] = Vdp1Regs->localY + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x1A) ); color = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x6); CMDPMOD = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x4); polygon.uclipmode=(CMDPMOD>>9)&0x03; // Half trans parent to VDP1 Framebuffer if( (CMDPMOD & 0x3)==0x03 || (CMDPMOD & 0x100) ) { polygon.blendmode = 0x80; } if (color & 0x8000) priority = Vdp2Regs->PRISA & 0x7; else { int shadow, colorcalc; priority = 0; // Avoid compiler warning Vdp1ProcessSpritePixel(Vdp2Regs->SPCTL & 0xF, &color, &shadow, &priority, &colorcalc); #ifdef WORDS_BIGENDIAN priority = ((u8 *)&Vdp2Regs->PRISA)[priority^1] & 0x7; #else priority = ((u8 *)&Vdp2Regs->PRISA)[priority] & 0x7; #endif } polygon.priority = 8; polygon.w = 1; polygon.h = 1; polygon.flip = 0; if ((CMDPMOD & 4)) { int i; for (i = 0; i<4; i++) { color2 = T1ReadWord(Vdp1Ram, (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x1C) << 3) + (i << 1)); col[(i << 2) + 0] = (float)((color2 & 0x001F)) / (float)(0x1F) - 0.5f; col[(i << 2) + 1] = (float)((color2 & 0x03E0) >> 5) / (float)(0x1F) - 0.5f; col[(i << 2) + 2] = (float)((color2 & 0x7C00) >> 10) / (float)(0x1F) - 0.5f; col[(i << 2) + 3] = 1.0f; } gouraud = 1; } makeLinePolygon(&v[0], &v[2], line_poygon); polygon.vertices[0] = line_poygon[0] * vdp1wratio; polygon.vertices[1] = line_poygon[1] * vdp1hratio; polygon.vertices[2] = line_poygon[2] * vdp1wratio; polygon.vertices[3] = line_poygon[3] * vdp1hratio; polygon.vertices[4] = line_poygon[4] * vdp1wratio; polygon.vertices[5] = line_poygon[5] * vdp1hratio; polygon.vertices[6] = line_poygon[6] * vdp1wratio; polygon.vertices[7] = line_poygon[7] * vdp1hratio; if (gouraud){ linecol[0] = col[(0 << 2) + 0]; linecol[1] = col[(0 << 2) + 1]; linecol[2] = col[(0 << 2) + 2]; linecol[3] = col[(0 << 2) + 3]; linecol[4] = col[(0 << 2) + 0]; linecol[5] = col[(0 << 2) + 1]; linecol[6] = col[(0 << 2) + 2]; linecol[7] = col[(0 << 2) + 3]; linecol[8] = col[(1 << 2) + 0]; linecol[9] = col[(1 << 2) + 1]; linecol[10] = col[(1 << 2) + 2]; linecol[11] = col[(1 << 2) + 3]; linecol[12] = col[(1 << 2) + 0]; linecol[13] = col[(1 << 2) + 1]; linecol[14] = col[(1 << 2) + 2]; linecol[15] = col[(1 << 2) + 3]; YglQuadGrowShading(&polygon, &texture, linecol, &c); } else{ YglQuadGrowShading(&polygon, &texture, NULL, &c); } if (color == 0) { alpha = 0; priority = 0; } else{ alpha = 0xF8; if (CMDPMOD & 0x100) { alpha = 0x80; } } alpha |= priority; if (color & 0x8000) *texture.textdata = SAT2YAB1(alpha, color); else{ Vdp1ReadCommand(&cmd, Vdp1Regs->addr, Vdp1Ram); *texture.textdata = Vdp1ReadPolygonColor(&cmd); } makeLinePolygon(&v[2], &v[4], line_poygon); polygon.vertices[0] = line_poygon[0] * vdp1wratio; polygon.vertices[1] = line_poygon[1] * vdp1hratio; polygon.vertices[2] = line_poygon[2] * vdp1wratio; polygon.vertices[3] = line_poygon[3] * vdp1hratio; polygon.vertices[4] = line_poygon[4] * vdp1wratio; polygon.vertices[5] = line_poygon[5] * vdp1hratio; polygon.vertices[6] = line_poygon[6] * vdp1wratio; polygon.vertices[7] = line_poygon[7] * vdp1hratio; if (gouraud){ linecol[0] = col[(1 << 2) + 0]; linecol[1] = col[(1 << 2) + 1]; linecol[2] = col[(1 << 2) + 2]; linecol[3] = col[(1 << 2) + 3]; linecol[4] = col[(1 << 2) + 0]; linecol[5] = col[(1 << 2) + 1]; linecol[6] = col[(1 << 2) + 2]; linecol[7] = col[(1 << 2) + 3]; linecol[8] = col[(2 << 2) + 0]; linecol[9] = col[(2 << 2) + 1]; linecol[10] = col[(2 << 2) + 2]; linecol[11] = col[(2 << 2) + 3]; linecol[12] = col[(2 << 2) + 0]; linecol[13] = col[(2 << 2) + 1]; linecol[14] = col[(2 << 2) + 2]; linecol[15] = col[(2 << 2) + 3]; YglCacheQuadGrowShading(&polygon, linecol, &c); } else{ YglCacheQuadGrowShading(&polygon, NULL, &c); } makeLinePolygon(&v[4], &v[6], line_poygon); polygon.vertices[0] = line_poygon[0] * vdp1wratio; polygon.vertices[1] = line_poygon[1] * vdp1hratio; polygon.vertices[2] = line_poygon[2] * vdp1wratio; polygon.vertices[3] = line_poygon[3] * vdp1hratio; polygon.vertices[4] = line_poygon[4] * vdp1wratio; polygon.vertices[5] = line_poygon[5] * vdp1hratio; polygon.vertices[6] = line_poygon[6] * vdp1wratio; polygon.vertices[7] = line_poygon[7] * vdp1hratio; if (gouraud){ linecol[0] = col[(2 << 2) + 0]; linecol[1] = col[(2 << 2) + 1]; linecol[2] = col[(2 << 2) + 2]; linecol[3] = col[(2 << 2) + 3]; linecol[4] = col[(2 << 2) + 0]; linecol[5] = col[(2 << 2) + 1]; linecol[6] = col[(2 << 2) + 2]; linecol[7] = col[(2 << 2) + 3]; linecol[8] = col[(3 << 2) + 0]; linecol[9] = col[(3 << 2) + 1]; linecol[10] = col[(3 << 2) + 2]; linecol[11] = col[(3 << 2) + 3]; linecol[12] = col[(3 << 2) + 0]; linecol[13] = col[(3 << 2) + 1]; linecol[14] = col[(3 << 2) + 2]; linecol[15] = col[(3 << 2) + 3]; YglCacheQuadGrowShading(&polygon, linecol, &c); } else{ YglCacheQuadGrowShading(&polygon, NULL, &c); } if ( !(v[6] == v[0] && v[7] == v[1]) ){ makeLinePolygon(&v[6], &v[0], line_poygon); polygon.vertices[0] = line_poygon[0] * vdp1wratio; polygon.vertices[1] = line_poygon[1] * vdp1hratio; polygon.vertices[2] = line_poygon[2] * vdp1wratio; polygon.vertices[3] = line_poygon[3] * vdp1hratio; polygon.vertices[4] = line_poygon[4] * vdp1wratio; polygon.vertices[5] = line_poygon[5] * vdp1hratio; polygon.vertices[6] = line_poygon[6] * vdp1wratio; polygon.vertices[7] = line_poygon[7] * vdp1hratio; if (gouraud){ linecol[0] = col[(3 << 2) + 0]; linecol[1] = col[(3 << 2) + 1]; linecol[2] = col[(3 << 2) + 2]; linecol[3] = col[(3 << 2) + 3]; linecol[4] = col[(3 << 2) + 0]; linecol[5] = col[(3 << 2) + 1]; linecol[6] = col[(3 << 2) + 2]; linecol[7] = col[(3 << 2) + 3]; linecol[8] = col[(0 << 2) + 0]; linecol[9] = col[(0 << 2) + 1]; linecol[10] = col[(0 << 2) + 2]; linecol[11] = col[(0 << 2) + 3]; linecol[12] = col[(0 << 2) + 0]; linecol[13] = col[(0 << 2) + 1]; linecol[14] = col[(0 << 2) + 2]; linecol[15] = col[(0 << 2) + 3]; YglCacheQuadGrowShading(&polygon, linecol, &c); } else{ YglCacheQuadGrowShading(&polygon, NULL, &c); } } } ////////////////////////////////////////////////////////////////////////////// void VIDOGLVdp1LineDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer) { s16 v[4]; u16 color; u16 CMDPMOD; u8 alpha; YglSprite polygon; YglTexture texture; int priority; float line_poygon[8]; vdp1cmd_struct cmd; float col[4 * 2]; int gouraud = 0; u16 color2; polygon.blendmode=0; polygon.linescreen = 0; polygon.dst = 0; v[0] = Vdp1Regs->localX + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x0C)); v[1] = Vdp1Regs->localY + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x0E)); v[2] = Vdp1Regs->localX + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x10)); v[3] = Vdp1Regs->localY + (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x12)); color = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x6); CMDPMOD = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x4); polygon.uclipmode=(CMDPMOD>>9)&0x03; // Half trans parent to VDP1 Framebuffer if( (CMDPMOD & 0x3)==0x03 || (CMDPMOD & 0x100) ) { polygon.blendmode = 0x80; } if (color & 0x8000) priority = Vdp2Regs->PRISA & 0x7; else { int shadow, colorcalc; priority = 0; // Avoid compiler warning Vdp1ProcessSpritePixel(Vdp2Regs->SPCTL & 0xF, &color, &shadow, &priority, &colorcalc); #ifdef WORDS_BIGENDIAN priority = ((u8 *)&Vdp2Regs->PRISA)[priority^1] & 0x7; #else priority = ((u8 *)&Vdp2Regs->PRISA)[priority] & 0x7; #endif } polygon.priority = 8; // Check if the Gouraud shading bit is set and the color mode is RGB if ((CMDPMOD & 4)) { int i; for (i = 0; i<2; i++) { color2 = T1ReadWord(Vdp1Ram, (T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x1C) << 3) + (i << 1)); col[(i << 2) + 0] = (float)((color2 & 0x001F)) / (float)(0x1F) - 0.5f; col[(i << 2) + 1] = (float)((color2 & 0x03E0) >> 5) / (float)(0x1F) - 0.5f; col[(i << 2) + 2] = (float)((color2 & 0x7C00) >> 10) / (float)(0x1F) - 0.5f; col[(i << 2) + 3] = 1.0f; } gouraud = 1; } makeLinePolygon(&v[0], &v[2], line_poygon); polygon.vertices[0] = line_poygon[0] * vdp1wratio; polygon.vertices[1] = line_poygon[1] * vdp1hratio; polygon.vertices[2] = line_poygon[2] * vdp1wratio; polygon.vertices[3] = line_poygon[3] * vdp1hratio; polygon.vertices[4] = line_poygon[4] * vdp1wratio; polygon.vertices[5] = line_poygon[5] * vdp1hratio; polygon.vertices[6] = line_poygon[6] * vdp1wratio; polygon.vertices[7] = line_poygon[7] * vdp1hratio; polygon.w = 1; polygon.h = 1; polygon.flip = 0; if (gouraud == 1){ YglQuadGrowShading(&polygon, &texture, col, NULL); } else{ YglQuadGrowShading(&polygon, &texture, NULL, NULL); } if (color == 0) { alpha = 0; priority = 0; }else{ alpha = 0xF8; if (CMDPMOD & 0x100) { alpha = 0x80; } } alpha |= priority; if (color & 0x8000) *texture.textdata = SAT2YAB1(alpha,color); else{ Vdp1ReadCommand(&cmd, Vdp1Regs->addr, Vdp1Ram); *texture.textdata = Vdp1ReadPolygonColor(&cmd); } } ////////////////////////////////////////////////////////////////////////////// void VIDOGLVdp1UserClipping(u8 * ram, Vdp1 * regs) { Vdp1Regs->userclipX1 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0xC); Vdp1Regs->userclipY1 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0xE); Vdp1Regs->userclipX2 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x14); Vdp1Regs->userclipY2 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x16); } ////////////////////////////////////////////////////////////////////////////// void VIDOGLVdp1SystemClipping(u8 * ram, Vdp1 * regs) { Vdp1Regs->systemclipX1 = 0; Vdp1Regs->systemclipY1 = 0; Vdp1Regs->systemclipX2 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x14); Vdp1Regs->systemclipY2 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x16); } ////////////////////////////////////////////////////////////////////////////// void VIDOGLVdp1LocalCoordinate(u8 * ram, Vdp1 * regs) { Vdp1Regs->localX = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0xC); Vdp1Regs->localY = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0xE); } ////////////////////////////////////////////////////////////////////////////// int VIDOGLVdp2Reset(void) { return 0; } ////////////////////////////////////////////////////////////////////////////// void VIDOGLVdp2DrawStart(void) { YglReset(); YglCacheReset(); } ////////////////////////////////////////////////////////////////////////////// void VIDOGLVdp2DrawEnd(void) { YglRender(); /* It would be better to reset manualchange in a Vdp1SwapFrameBuffer function that would be called here and during a manual change */ //Vdp1External.manualchange = 0; } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawBackScreen(void) { u32 scrAddr; int dot; static unsigned char lineColors[512 * 3]; static int line[512*4]; if (Vdp2Regs->VRSIZE & 0x8000) scrAddr = (((Vdp2Regs->BKTAU & 0x7) << 16) | Vdp2Regs->BKTAL) * 2; else scrAddr = (((Vdp2Regs->BKTAU & 0x3) << 16) | Vdp2Regs->BKTAL) * 2; #if defined(__ANDROID__) || defined(_OGLES3_) || defined(_OGL3_) dot = T1ReadWord(Vdp2Ram, scrAddr); YglSetClearColor( (float)(dot & 0x1F) / (float)(0x1F), (float)((dot & 0x3E0) >> 5) / (float)(0x1F), (float)((dot & 0x7C00) >> 10)/ (float)(0x1F) ); #else if (Vdp2Regs->BKTAU & 0x8000) { int y; for(y = 0; y < vdp2height; y++) { dot = T1ReadWord(Vdp2Ram, scrAddr); scrAddr += 2; lineColors[3*y+0] = (dot & 0x1F) << 3; lineColors[3*y+1] = (dot & 0x3E0) >> 2; lineColors[3*y+2] = (dot & 0x7C00) >> 7; line[4*y+0] = 0; line[4*y+1] = y; line[4*y+2] = vdp2width; line[4*y+3] = y; } glColorPointer(3, GL_UNSIGNED_BYTE, 0, lineColors); glEnableClientState(GL_COLOR_ARRAY); glVertexPointer(2, GL_INT, 0, line); glEnableClientState(GL_VERTEX_ARRAY); glDrawArrays(GL_LINES,0,vdp2height*2); glDisableClientState(GL_COLOR_ARRAY); glColor3ub(0xFF, 0xFF, 0xFF); } else { dot = T1ReadWord(Vdp2Ram, scrAddr); glColor3ub((dot & 0x1F) << 3, (dot & 0x3E0) >> 2, (dot & 0x7C00) >> 7); line[0] = 0; line[1] = 0; line[2] = vdp2width; line[3] = 0; line[4] = vdp2width; line[5] = vdp2height; line[6] = 0; line[7] = vdp2height; glDisable(GL_TEXTURE_2D); glVertexPointer(2, GL_INT, 0, line); glEnableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDrawArrays(GL_TRIANGLE_FAN,0,8); glColor3ub(0xFF, 0xFF, 0xFF); glEnableClientState(GL_TEXTURE_COORD_ARRAY); } #endif } ////////////////////////////////////////////////////////////////////////////// // 11.3 Line Color insertion // 7.1 Line Color Screen static void Vdp2DrawLineColorScreen(void) { u32 cacheaddr = 0xFFFFFFFF; int inc = 0; int line_cnt = vdp2height; int i; u32 * line_pixel_data; u32 addr; if ( Vdp2Regs->LNCLEN == 0) return; line_pixel_data = YglGetLineColorPointer(); if( line_pixel_data == NULL ){ return; } if ((Vdp2Regs->LCTA.part.U & 0x8000)){ inc = 0x02; // single color } else{ inc = 0x00; // color per line } addr = (Vdp2Regs->LCTA.all & 0x7FFFF) * 0x2; for (i = 0; i < line_cnt; i++){ u16 LineColorRamAdress = T1ReadWord(Vdp2Ram, addr); *(line_pixel_data) = Vdp2ColorRamGetColor(LineColorRamAdress, 0xFF); line_pixel_data++; addr += inc; } YglSetLineColor( line_pixel_data, line_cnt ); } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawNBG0(void) { vdp2draw_struct info = { 0 }; YglTexture texture; YglCache tmpc; vdp2rotationparameter_struct parameter; info.dst=0; info.uclipmode=0; info.coordincx = 1.0f; info.coordincy = 1.0f; info.cor = 0; info.cog = 0; info.cob = 0; info.cellw = 512; info.cellh = 256; if (Vdp2Regs->BGON & 0x20) { // RBG1 mode info.enable = Vdp2Regs->BGON & 0x20; // Read in Parameter B Vdp2ReadRotationTable(1, ¶meter, Vdp2Regs, Vdp2Ram); if((info.isbitmap = Vdp2Regs->CHCTLA & 0x2) != 0) { // Bitmap Mode ReadBitmapSize(&info, Vdp2Regs->CHCTLA >> 2, 0x3); info.charaddr = (Vdp2Regs->MPOFR & 0x70) * 0x2000; info.paladdr = (Vdp2Regs->BMPNA & 0x7) << 4; info.flipfunction = 0; info.specialfunction = 0; } else { // Tile Mode info.mapwh = 4; ReadPlaneSize(&info, Vdp2Regs->PLSZ >> 12); ReadPatternData(&info, Vdp2Regs->PNCN0, Vdp2Regs->CHCTLA & 0x1); } info.rotatenum = 1; info.PlaneAddr = (void FASTCALL (*)(void *, int, Vdp2*))&Vdp2ParameterBPlaneAddr; parameter.coefenab = Vdp2Regs->KTCTL & 0x100; info.LineColorBase = 0x00; if (paraB.coefenab) info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode01WithK; else info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode01NoK; } else if (Vdp2Regs->BGON & 0x1) { // NBG0 mode info.enable = Vdp2Regs->BGON & 0x1; if((info.isbitmap = Vdp2Regs->CHCTLA & 0x2) != 0) { // Bitmap Mode ReadBitmapSize(&info, Vdp2Regs->CHCTLA >> 2, 0x3); info.x = - ((Vdp2Regs->SCXIN0 & 0x7FF) % info.cellw); info.y = - ((Vdp2Regs->SCYIN0 & 0x7FF) % info.cellh); info.charaddr = (Vdp2Regs->MPOFN & 0x7) * 0x20000; info.paladdr = (Vdp2Regs->BMPNA & 0x7) << 4; info.flipfunction = 0; info.specialfunction = 0; } else { // Tile Mode info.mapwh = 2; ReadPlaneSize(&info, Vdp2Regs->PLSZ); info.x = - ((Vdp2Regs->SCXIN0 & 0x7FF) % (512 * info.planew)); info.y = - ((Vdp2Regs->SCYIN0 & 0x7FF) % (512 * info.planeh)); ReadPatternData(&info, Vdp2Regs->PNCN0, Vdp2Regs->CHCTLA & 0x1); } if( (Vdp2Regs->ZMXN0.all & 0x7FF00) == 0 ) info.coordincx = 1.0f; else info.coordincx = (float) 65536 / (Vdp2Regs->ZMXN0.all & 0x7FF00); switch(Vdp2Regs->ZMCTL&0x03) { case 0: info.maxzoom = 1.0f; break; case 1: info.maxzoom = 0.5f; if( info.coordincx < 0.5f ) info.coordincx = 0.5f; break; case 2: case 3: info.maxzoom = 0.25f; if( info.coordincx < 0.25f ) info.coordincx = 0.25f; break; } if( (Vdp2Regs->ZMYN0.all & 0x7FF00) == 0 ) info.coordincy = 1.0f; else info.coordincy = (float) 65536 / (Vdp2Regs->ZMYN0.all & 0x7FF00); info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2NBG0PlaneAddr; } else // Not enabled return; info.transparencyenable = !(Vdp2Regs->BGON & 0x100); info.specialprimode = Vdp2Regs->SFPRMD & 0x3; info.specialcolormode = Vdp2Regs->SFCCMD & 0x3; info.colornumber = (Vdp2Regs->CHCTLA & 0x70) >> 4; if(Vdp2Regs->CCCTL & 0x1) { info.alpha = ((~Vdp2Regs->CCRNA & 0x1F) << 3) + 0x7; if(Vdp2Regs->CCCTL & 0x100 && info.specialcolormode == 0) info.blendmode=2; else info.blendmode=1; }else{ info.alpha = 0xFF; info.blendmode=0; } info.linescreen = 0; if (Vdp2Regs->LNCLEN & 0x1) info.linescreen = 1; info.coloroffset = (Vdp2Regs->CRAOFA & 0x7) << 8; ReadVdp2ColorOffset(Vdp2Regs,&info, 0x1); info.linecheck_mask = 0x01; info.priority = Vdp2Regs->PRINA & 0x7; if (!(info.enable & Vdp2External.disptoggle) || (info.priority == 0)) return; // Window Mode info.bEnWin0 = (Vdp2Regs->WCTLA >> 1) &0x01; info.WindowArea0 = (Vdp2Regs->WCTLA >> 0) & 0x01; info.bEnWin1 = (Vdp2Regs->WCTLA >> 3) &0x01; info.WindowArea1 = (Vdp2Regs->WCTLA >> 2) & 0x01; info.LogicWin = (Vdp2Regs->WCTLA >> 7 ) & 0x01; if( info.bEnWin0 || info.bEnWin1 ) YglStartWindow(&info,info.bEnWin0, info.WindowArea0,info.bEnWin1, info.WindowArea1,info.LogicWin); ReadLineScrollData(&info, Vdp2Regs->SCRCTL & 0xFF, Vdp2Regs->LSTA0.all); info.lineinfo = lineNBG0; Vdp2GenLineinfo( &info ); Vdp2SetGetColor( &info ); if (Vdp2Regs->SCRCTL & 1) { info.isverticalscroll = 1; info.verticalscrolltbl = (Vdp2Regs->VCSTA.all & 0x7FFFE) << 1; if (Vdp2Regs->SCRCTL & 0x100) info.verticalscrollinc = 8; else info.verticalscrollinc = 4; } else info.isverticalscroll = 0; if (info.enable == 1) { // NBG0 draw if (info.isbitmap) { int xx,yy; int isCached = 0; if(info.islinescroll) // Nights Movie { info.sh = (Vdp2Regs->SCXIN0 & 0x7FF); info.sv = (Vdp2Regs->SCYIN0 & 0x7FF); info.x = 0; info.y = 0; } yy = info.y; while( yy < vdp2height ) { xx = info.x; while( xx < vdp2width ) { info.vertices[0] = xx * info.coordincx; info.vertices[1] = yy * info.coordincy; info.vertices[2] = (xx + info.cellw) * info.coordincx; info.vertices[3] = yy * info.coordincy; info.vertices[4] = (xx + info.cellw) * info.coordincx; info.vertices[5] = (yy + info.cellh) * info.coordincy; info.vertices[6] = xx * info.coordincx; info.vertices[7] = (yy + info.cellh) * info.coordincy; if( isCached == 0 ) { YglQuad((YglSprite *)&info, &texture,&tmpc); Vdp2DrawCell(&info, &texture); isCached = 1; }else{ YglCachedQuad((YglSprite *)&info, &tmpc); } xx += info.cellw* info.coordincx; } yy += info.cellh* info.coordincy; } } else { if (info.islinescroll){ info.x = Vdp2Regs->SCXIN0 & 0x7FF; info.y = Vdp2Regs->SCYIN0 & 0x7FF; Vdp2DrawMapPerLine(&info, &texture); } else{ info.x = Vdp2Regs->SCXIN0 & 0x7FF; info.y = Vdp2Regs->SCYIN0 & 0x7FF; Vdp2DrawMapTest(&info, &texture); } } } else { // RBG1 draw Vdp2DrawRotation(&info, ¶meter, &texture); } if( info.bEnWin0 || info.bEnWin1 ) YglEndWindow(&info); } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawNBG1(void) { vdp2draw_struct info; YglTexture texture; YglCache tmpc; info.dst=0; info.uclipmode=0; info.cor = 0; info.cog = 0; info.cob = 0; info.enable = Vdp2Regs->BGON & 0x2; info.transparencyenable = !(Vdp2Regs->BGON & 0x200); info.specialprimode = (Vdp2Regs->SFPRMD >> 2) & 0x3; info.colornumber = (Vdp2Regs->CHCTLA & 0x3000) >> 12; if((info.isbitmap = Vdp2Regs->CHCTLA & 0x200) != 0) { ReadBitmapSize(&info, Vdp2Regs->CHCTLA >> 10, 0x3); info.x = -((Vdp2Regs->SCXIN1 & 0x7FF) % info.cellw); info.y = -((Vdp2Regs->SCYIN1 & 0x7FF) % info.cellh); info.charaddr = ((Vdp2Regs->MPOFN & 0x70) >> 4) * 0x20000; info.paladdr = (Vdp2Regs->BMPNA & 0x700) >> 4; info.flipfunction = 0; info.specialfunction = 0; } else { info.mapwh = 2; ReadPlaneSize(&info, Vdp2Regs->PLSZ >> 2); info.x = - ((Vdp2Regs->SCXIN1 & 0x7FF) % (512 * info.planew)); info.y = - ((Vdp2Regs->SCYIN1 & 0x7FF) % (512 * info.planeh)); ReadPatternData(&info, Vdp2Regs->PNCN1, Vdp2Regs->CHCTLA & 0x100); } info.specialcolormode = (Vdp2Regs->SFCCMD>>2) & 0x3; if (Vdp2Regs->CCCTL & 0x2) { info.alpha = ((~Vdp2Regs->CCRNA & 0x1F00) >> 5) + 0x7; if(Vdp2Regs->CCCTL & 0x100 && info.specialcolormode == 0 ) { info.blendmode=2; }else{ info.blendmode=1; } }else{ info.alpha = 0xFF; info.blendmode=0; } info.linescreen = 0; if (Vdp2Regs->LNCLEN & 0x2) info.linescreen = 1; info.coloroffset = (Vdp2Regs->CRAOFA & 0x70) << 4; ReadVdp2ColorOffset(Vdp2Regs,&info, 0x2); info.linecheck_mask = 0x02; if( (Vdp2Regs->ZMXN1.all & 0x7FF00) == 0 ) info.coordincx = 1.0f; else info.coordincx = (float) 65536 / (Vdp2Regs->ZMXN1.all & 0x7FF00); switch((Vdp2Regs->ZMCTL>>8)&0x03) { case 0: info.maxzoom = 1.0f; break; case 1: info.maxzoom = 0.5f; if( info.coordincx < 0.5f ) info.coordincx = 0.5f; break; case 2: case 3: info.maxzoom = 0.25f; if( info.coordincx < 0.25f ) info.coordincx = 0.25f; break; } if( (Vdp2Regs->ZMYN1.all & 0x7FF00) == 0 ) info.coordincy = 1.0f; else info.coordincy = (float) 65536 / (Vdp2Regs->ZMYN1.all & 0x7FF00); info.priority = (Vdp2Regs->PRINA >> 8) & 0x7;; info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2NBG1PlaneAddr; if (!(info.enable & Vdp2External.disptoggle) || (info.priority == 0) || (Vdp2Regs->BGON & 0x1 && (Vdp2Regs->CHCTLA & 0x70) >> 4 == 4)) // If NBG0 16M mode is enabled, don't draw return; // Window Mode info.bEnWin0 = (Vdp2Regs->WCTLA >> 9) &0x01; info.WindowArea0 = (Vdp2Regs->WCTLA >> 8) & 0x01; info.bEnWin1 = (Vdp2Regs->WCTLA >> 11) &0x01; info.WindowArea1 = (Vdp2Regs->WCTLA >> 10) & 0x01; info.LogicWin = (Vdp2Regs->WCTLA >> 15 ) & 0x01; if( info.bEnWin0 || info.bEnWin1 ) YglStartWindow(&info,info.bEnWin0, info.WindowArea0,info.bEnWin1, info.WindowArea1,info.LogicWin); ReadLineScrollData(&info, Vdp2Regs->SCRCTL >> 8, Vdp2Regs->LSTA1.all); info.lineinfo = lineNBG1; Vdp2GenLineinfo( &info ); Vdp2SetGetColor( &info ); if (Vdp2Regs->SCRCTL & 0x100) { info.isverticalscroll = 1; if (Vdp2Regs->SCRCTL & 0x1) { info.verticalscrolltbl = 4 + ((Vdp2Regs->VCSTA.all & 0x7FFFE) << 1); info.verticalscrollinc = 8; } else { info.verticalscrolltbl = (Vdp2Regs->VCSTA.all & 0x7FFFE) << 1; info.verticalscrollinc = 4; } } else info.isverticalscroll = 0; if (info.isbitmap) { int xx,yy; int isCached = 0; if(info.islinescroll) { info.sh = (Vdp2Regs->SCXIN1 & 0x7FF); info.sv = (Vdp2Regs->SCYIN1 & 0x7FF); info.x = 0; info.y = 0; } yy = info.y; while( yy < vdp2height ) { xx = info.x; while( xx < vdp2width ) { info.vertices[0] = xx * info.coordincx; info.vertices[1] = yy * info.coordincy; info.vertices[2] = (xx + info.cellw) * info.coordincx; info.vertices[3] = yy * info.coordincy; info.vertices[4] = (xx + info.cellw) * info.coordincx; info.vertices[5] = (yy + info.cellh) * info.coordincy; info.vertices[6] = xx * info.coordincx; info.vertices[7] = (yy + info.cellh) * info.coordincy; if( isCached == 0 ) { YglQuad((YglSprite *)&info, &texture,&tmpc); Vdp2DrawCell(&info, &texture); isCached = 1; }else{ YglCachedQuad((YglSprite *)&info, &tmpc); } xx += info.cellw* info.coordincx; } yy += info.cellh* info.coordincy; } } else{ if (info.islinescroll){ info.x = (Vdp2Regs->SCXIN1 & 0x7FF); info.y = (Vdp2Regs->SCYIN1 & 0x7FF); Vdp2DrawMapPerLine(&info, &texture); } else{ //Vdp2DrawMap(&info, &texture); info.x = Vdp2Regs->SCXIN1 & 0x7FF; info.y = Vdp2Regs->SCYIN1 & 0x7FF; Vdp2DrawMapTest(&info, &texture); } } if( info.bEnWin0 || info.bEnWin1 ) YglEndWindow(&info); } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawNBG2(void) { vdp2draw_struct info; YglTexture texture; info.dst=0; info.uclipmode=0; info.cor = 0; info.cog = 0; info.cob = 0; info.enable = Vdp2Regs->BGON & 0x4; info.transparencyenable = !(Vdp2Regs->BGON & 0x400); info.specialprimode = (Vdp2Regs->SFPRMD >> 4) & 0x3; info.colornumber = (Vdp2Regs->CHCTLB & 0x2) >> 1; info.mapwh = 2; ReadPlaneSize(&info, Vdp2Regs->PLSZ >> 4); info.x = - ((Vdp2Regs->SCXN2 & 0x7FF) % (512 * info.planew)); info.y = - ((Vdp2Regs->SCYN2 & 0x7FF) % (512 * info.planeh)); ReadPatternData(&info, Vdp2Regs->PNCN2, Vdp2Regs->CHCTLB & 0x1); info.specialcolormode = (Vdp2Regs->SFCCMD>>4) & 0x3; if (Vdp2Regs->CCCTL & 0x4) { info.alpha = ((~Vdp2Regs->CCRNB & 0x1F) << 3) + 0x7; if(Vdp2Regs->CCCTL & 0x100 && info.specialcolormode == 0 ) { info.blendmode=2; }else{ info.blendmode=1; } }else{ info.alpha = 0xFF; info.blendmode=0; } info.linescreen = 0; if (Vdp2Regs->LNCLEN & 0x4) info.linescreen = 1; info.coloroffset = Vdp2Regs->CRAOFA & 0x700; ReadVdp2ColorOffset(Vdp2Regs,&info, 0x4); info.linecheck_mask = 0x04; info.coordincx = info.coordincy = 1; info.priority = Vdp2Regs->PRINB & 0x7;; info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2NBG2PlaneAddr; if (!(info.enable & Vdp2External.disptoggle) || (info.priority == 0) || (Vdp2Regs->BGON & 0x1 && (Vdp2Regs->CHCTLA & 0x70) >> 4 >= 2)) // If NBG0 2048/32786/16M mode is enabled, don't draw return; // Window Mode info.bEnWin0 = (Vdp2Regs->WCTLB >> 1) &0x01; info.WindowArea0 = (Vdp2Regs->WCTLB >> 0) & 0x01; info.bEnWin1 = (Vdp2Regs->WCTLB >> 3) &0x01; info.WindowArea1 = (Vdp2Regs->WCTLB >> 2) & 0x01; info.LogicWin = (Vdp2Regs->WCTLB >> 7 ) & 0x01; Vdp2SetGetColor( &info ); if( info.bEnWin0 || info.bEnWin1 ) YglStartWindow(&info,info.bEnWin0, info.WindowArea0,info.bEnWin1, info.WindowArea1,info.LogicWin); info.islinescroll = 0; info.linescrolltbl = 0; info.lineinc = 0; info.isverticalscroll = 0; info.x = Vdp2Regs->SCXN2 & 0x7FF; info.y = Vdp2Regs->SCYN2 & 0x7FF; Vdp2DrawMapTest(&info, &texture); if( info.bEnWin0 || info.bEnWin1 ) YglEndWindow(&info); } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawNBG3(void) { vdp2draw_struct info; YglTexture texture; info.dst=0; info.uclipmode=0; info.cor = 0; info.cog = 0; info.cob = 0; info.enable = Vdp2Regs->BGON & 0x8; info.transparencyenable = !(Vdp2Regs->BGON & 0x800); info.specialprimode = (Vdp2Regs->SFPRMD >> 6) & 0x3; info.colornumber = (Vdp2Regs->CHCTLB & 0x20) >> 5; info.mapwh = 2; ReadPlaneSize(&info, Vdp2Regs->PLSZ >> 6); info.x = - ((Vdp2Regs->SCXN3 & 0x7FF) % (512 * info.planew)); info.y = - ((Vdp2Regs->SCYN3 & 0x7FF) % (512 * info.planeh)); ReadPatternData(&info, Vdp2Regs->PNCN3, Vdp2Regs->CHCTLB & 0x10); info.specialcolormode = (Vdp2Regs->SFCCMD>>6) & 0x03; if (Vdp2Regs->CCCTL & 0x8) { info.alpha = ((~Vdp2Regs->CCRNB & 0x1F00) >> 5) + 0x7; if(Vdp2Regs->CCCTL & 0x100 && info.specialcolormode == 0 ) { info.blendmode=2; }else{ info.blendmode=1; } }else{ info.alpha = 0xFF; info.blendmode=0; } info.linescreen = 0; if (Vdp2Regs->LNCLEN & 0x8) info.linescreen = 1; info.coloroffset = (Vdp2Regs->CRAOFA & 0x7000) >> 4; ReadVdp2ColorOffset(Vdp2Regs,&info, 0x8); info.linecheck_mask = 0x08; info.coordincx = info.coordincy = 1; info.priority = (Vdp2Regs->PRINB >> 8) & 0x7; info.PlaneAddr = (void FASTCALL (*)(void *, int, Vdp2*))&Vdp2NBG3PlaneAddr; if (!(info.enable & Vdp2External.disptoggle) || (info.priority == 0) || (Vdp2Regs->BGON & 0x1 && (Vdp2Regs->CHCTLA & 0x70) >> 4 == 4) || // If NBG0 16M mode is enabled, don't draw (Vdp2Regs->BGON & 0x2 && (Vdp2Regs->CHCTLA & 0x3000) >> 12 >= 2)) // If NBG1 2048/32786 is enabled, don't draw return; // Window Mode info.bEnWin0 = (Vdp2Regs->WCTLB >> 9) &0x01; info.WindowArea0 = (Vdp2Regs->WCTLB >> 8) & 0x01; info.bEnWin1 = (Vdp2Regs->WCTLB >> 11) &0x01; info.WindowArea1 = (Vdp2Regs->WCTLB >> 10) & 0x01; info.LogicWin = (Vdp2Regs->WCTLB >> 15 ) & 0x01; Vdp2SetGetColor( &info ); if( info.bEnWin0 || info.bEnWin1 ) YglStartWindow(&info,info.bEnWin0, info.WindowArea0,info.bEnWin1, info.WindowArea1,info.LogicWin); info.islinescroll = 0; info.linescrolltbl = 0; info.lineinc = 0; info.isverticalscroll = 0; info.x = Vdp2Regs->SCXN3 & 0x7FF; info.y = Vdp2Regs->SCYN3 & 0x7FF; Vdp2DrawMapTest(&info, &texture); if( info.bEnWin0 || info.bEnWin1 ) YglEndWindow(&info); } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawRBG0(void) { vdp2draw_struct info; YglTexture texture; vdp2rotationparameter_struct parameter; info.dst=0; info.uclipmode=0; info.cor = 0; info.cog = 0; info.cob = 0; info.enable = Vdp2Regs->BGON & 0x10; info.priority = Vdp2Regs->PRIR & 0x7; if (!(info.enable & Vdp2External.disptoggle) || (info.priority == 0)) return; info.transparencyenable = !(Vdp2Regs->BGON & 0x1000); info.specialprimode = (Vdp2Regs->SFPRMD >> 8) & 0x3; info.colornumber = (Vdp2Regs->CHCTLB & 0x7000) >> 12; info.bEnWin0 = (Vdp2Regs->WCTLC >> 1) & 0x01; info.WindowArea0 = (Vdp2Regs->WCTLC >> 0) & 0x01; info.bEnWin1 = (Vdp2Regs->WCTLC >> 3) & 0x01; info.WindowArea1 = (Vdp2Regs->WCTLC >> 2) & 0x01; info.LogicWin = (Vdp2Regs->WCTLC >> 7 ) & 0x01; info.islinescroll = 0; info.linescrolltbl = 0; info.lineinc = 0; Vdp2ReadRotationTable(0, ¶A, Vdp2Regs, Vdp2Ram); Vdp2ReadRotationTable(1, ¶B, Vdp2Regs, Vdp2Ram); paraA.PlaneAddr = (void FASTCALL (*)(void *, int, Vdp2*))&Vdp2ParameterAPlaneAddr; paraB.PlaneAddr = (void FASTCALL (*)(void *, int, Vdp2*))&Vdp2ParameterBPlaneAddr; paraA.charaddr = (Vdp2Regs->MPOFR & 0x7) * 0x20000; paraB.charaddr = (Vdp2Regs->MPOFR & 0x70) * 0x2000; ReadPlaneSizeR(¶A,Vdp2Regs->PLSZ >> 8); ReadPlaneSizeR(¶B,Vdp2Regs->PLSZ >> 12); if( paraA.coefdatasize == 2) { if(paraA.coefmode < 3 ) { info.GetKValueA = vdp2rGetKValue1W; }else{ info.GetKValueA = vdp2rGetKValue1Wm3; } }else{ if(paraA.coefmode < 3 ) { info.GetKValueA = vdp2rGetKValue2W; }else{ info.GetKValueA = vdp2rGetKValue2Wm3; } } if( paraB.coefdatasize == 2) { if(paraB.coefmode < 3 ) { info.GetKValueB = vdp2rGetKValue1W; }else{ info.GetKValueB = vdp2rGetKValue1Wm3; } }else{ if(paraB.coefmode < 3 ) { info.GetKValueB = vdp2rGetKValue2W; }else{ info.GetKValueB = vdp2rGetKValue2Wm3; } } if( Vdp2Regs->RPMD == 0x00 ) { if(!(paraA.coefenab)) { info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode00NoK; }else{ info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode00WithK; } }else if( Vdp2Regs->RPMD == 0x01 ) { if(!(paraB.coefenab)) { info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode01NoK; }else{ info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode01WithK; } }else if( Vdp2Regs->RPMD == 0x02 ) { if(!(paraA.coefenab)) { info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode02NoK; }else{ info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode02WithKA; } }else if( Vdp2Regs->RPMD == 0x03 ) { // Window0 if( ((Vdp2Regs->WCTLD >> 1) & 0x01) == 0x01 ) { info.pWinInfo = m_vWindinfo0; info.WindwAreaMode = (Vdp2Regs->WCTLD & 0x01) ; }else if( ((Vdp2Regs->WCTLD >> 3) & 0x01) == 0x01 ) { info.pWinInfo = m_vWindinfo1; info.WindwAreaMode = ((Vdp2Regs->WCTLD >>2)& 0x01) ; }else{ info.pWinInfo = m_vWindinfo0; info.WindwAreaMode = (Vdp2Regs->WCTLD & 0x01) ; } if( paraA.coefenab == 0 && paraB.coefenab == 0 ) { info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode03NoK; }else if( paraA.coefenab && paraB.coefenab == 0 ) { info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode03WithKA; }else if( paraA.coefenab == 0 && paraB.coefenab ) { info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode03WithKB; }else if( paraA.coefenab && paraB.coefenab ) { info.GetRParam = (Vdp2GetRParam_func) vdp2RGetParamMode03WithK; } } paraA.screenover = (Vdp2Regs->PLSZ >> 10) & 0x03; paraB.screenover = (Vdp2Regs->PLSZ >> 14) & 0x03; // Figure out which Rotation Parameter we're uqrt switch (Vdp2Regs->RPMD & 0x3) { case 0: // Parameter A info.rotatenum = 0; info.rotatemode = 0; info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2ParameterAPlaneAddr; break; case 1: // Parameter B info.rotatenum = 1; info.rotatemode = 0; info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2ParameterBPlaneAddr; break; case 2: // Parameter A+B switched via coefficients // FIX ME(need to figure out which Parameter is being used) case 3: default: // Parameter A+B switched via rotation parameter window // FIX ME(need to figure out which Parameter is being used) VDP2LOG("Rotation Parameter Mode %d not supported!\n", Vdp2Regs->RPMD & 0x3); info.rotatenum = 0; info.rotatemode = 1 + (Vdp2Regs->RPMD & 0x1); info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2ParameterAPlaneAddr; break; } if((info.isbitmap = Vdp2Regs->CHCTLB & 0x200) != 0) { // Bitmap Mode ReadBitmapSize(&info, Vdp2Regs->CHCTLB >> 10, 0x1); if (info.rotatenum == 0) // Parameter A info.charaddr = (Vdp2Regs->MPOFR & 0x7) * 0x20000; else // Parameter B info.charaddr = (Vdp2Regs->MPOFR & 0x70) * 0x2000; info.paladdr = (Vdp2Regs->BMPNB & 0x7) << 4; info.flipfunction = 0; info.specialfunction = 0; } else { int i; // Tile Mode info.mapwh = 4; if (info.rotatenum == 0) // Parameter A ReadPlaneSize(&info, Vdp2Regs->PLSZ >> 8); else // Parameter B ReadPlaneSize(&info, Vdp2Regs->PLSZ >> 12); ReadPatternData(&info, Vdp2Regs->PNCR, Vdp2Regs->CHCTLB & 0x100); paraA.ShiftPaneX = 8 + paraA.planew; paraA.ShiftPaneY = 8 + paraA.planeh; paraB.ShiftPaneX = 8 + paraB.planew; paraB.ShiftPaneY = 8 + paraB.planeh; paraA.MskH = (8 * 64 * paraA.planew)-1; paraA.MskV = (8 * 64 * paraA.planeh)-1; paraB.MskH = (8 * 64 * paraB.planew)-1; paraB.MskV = (8 * 64 * paraB.planeh)-1; paraA.MaxH = 8 * 64 * paraA.planew * 4; paraA.MaxV = 8 * 64 * paraA.planeh * 4; paraB.MaxH = 8 * 64 * paraB.planew * 4; paraB.MaxV = 8 * 64 * paraB.planeh * 4; if( paraA.screenover == OVERMODE_512 ) { paraA.MaxH = 512; paraA.MaxV = 512; } if( paraB.screenover == OVERMODE_512 ) { paraB.MaxH = 512; paraB.MaxV = 512; } for( i=0; i<16; i++ ) { paraA.PlaneAddr(&info,i, Vdp2Regs); paraA.PlaneAddrv[i] = info.addr; paraB.PlaneAddr(&info, i, Vdp2Regs); paraB.PlaneAddrv[i] = info.addr; } } info.specialcolormode = (Vdp2Regs->SFCCMD>>8) & 0x03; info.blendmode=0; if( (Vdp2Regs->LNCLEN & 0x10) == 0x00 ) { info.LineColorBase = 0x00; paraA.lineaddr = 0xFFFFFFFF; paraB.lineaddr = 0xFFFFFFFF; }else{ // info.alpha = 0xFF; info.LineColorBase = ((Vdp2Regs->LCTA.all)&0x7FFFF) << 1; if( info.LineColorBase >= 0x80000 ) info.LineColorBase = 0x00; paraA.lineaddr = 0xFFFFFFFF; paraB.lineaddr = 0xFFFFFFFF; } if ( (Vdp2Regs->CCCTL & 0x410) == 0x10 ) { info.alpha = ((~Vdp2Regs->CCRR & 0x1F) << 3) + 0x7; if (Vdp2Regs->CCCTL & 0x100 && info.specialcolormode == 0) { info.blendmode = 2; } else{ info.blendmode = 1; } } else{ info.alpha = 0xFF; } info.coloroffset = (Vdp2Regs->CRAOFB & 0x7) << 8; ReadVdp2ColorOffset(Vdp2Regs,&info, 0x10); info.linecheck_mask = 0x10; info.coordincx = info.coordincy = 1; // Window Mode info.bEnWin0 = (Vdp2Regs->WCTLC >> 1) &0x01; info.WindowArea0 = (Vdp2Regs->WCTLC >> 0) & 0x01; info.bEnWin1 = (Vdp2Regs->WCTLC >> 3) &0x01; info.WindowArea1 = (Vdp2Regs->WCTLC >> 2) & 0x01; info.LogicWin = (Vdp2Regs->WCTLC >> 7 ) & 0x01; Vdp2SetGetColor( &info ); if( info.bEnWin0 || info.bEnWin1 ) YglStartWindow(&info,info.bEnWin0, info.WindowArea0,info.bEnWin1, info.WindowArea1,info.LogicWin); Vdp2DrawRotation(&info, ¶meter, &texture); if( info.bEnWin0 || info.bEnWin1 ) YglEndWindow(&info); } ////////////////////////////////////////////////////////////////////////////// void VIDOGLVdp2DrawScreens(void) { if (YglTM->texture == NULL) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, _Ygl->texture); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _Ygl->pixelBufferID); YglTM->texture = (unsigned int*)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, 2048 * 1024 * 4, GL_MAP_WRITE_BIT); if (YglTM->texture == NULL){ abort(); } } VIDOGLVdp2SetResolution(Vdp2Regs->TVMD); Vdp2GenerateWindowInfo(); Vdp2DrawBackScreen(); Vdp2DrawLineColorScreen(); Vdp2DrawNBG3(); Vdp2DrawNBG2(); Vdp2DrawNBG1(); Vdp2DrawNBG0(); Vdp2DrawRBG0(); } ////////////////////////////////////////////////////////////////////////////// void VIDOGLVdp2SetResolution(u16 TVMD) { int width=0, height=0; int wratio=1, hratio=1; // Horizontal Resolution switch (TVMD & 0x7) { case 0: width = 320; wratio = 1; break; case 1: width = 352; wratio = 1; break; case 2: width = 640; wratio = 2; break; case 3: width = 704; wratio = 2; break; case 4: width = 320; wratio = 1; break; case 5: width = 352; wratio = 1; break; case 6: width = 640; wratio = 2; break; case 7: width = 704; wratio = 2; break; } // Vertical Resolution switch ((TVMD >> 4) & 0x3) { case 0: height = 224; break; case 1: height = 240; break; case 2: height = 256; break; default: break; } hratio = 1; // Check for interlace switch ((TVMD >> 6) & 0x3) { case 3: // Double-density Interlace height *= 2; hratio = 2; break; case 2: // Single-density Interlace case 0: // Non-interlace default: break; } SetSaturnResolution(width, height); Vdp1SetTextureRatio(wratio, hratio); } ////////////////////////////////////////////////////////////////////////////// void YglGetGlSize(int *width, int *height) { *width = GlWidth; *height = GlHeight; } void VIDOGLGetNativeResolution(int *width, int *height, int*interlace) { *width = 0; *height = 0; *interlace = 0; } void VIDOGLVdp2DispOff() { } vdp2rotationparameter_struct * FASTCALL vdp2rGetKValue2W( vdp2rotationparameter_struct * param, int index ) { float kval; int kdata; kdata = T1ReadLong(Vdp2Ram, (param->coeftbladdr&0x7FFFF) + (index<<2) ); if( kdata & 0x80000000 ) return NULL; kval = (float) (int) ((kdata & 0x00FFFFFF) | (kdata & 0x00800000 ? 0xFF800000 : 0x00000000)) / 65536.0f; switch( param->coefmode ) { case 0: param->kx = kval; param->ky = kval; break; case 1: param->kx = kval; break; case 2: param->ky = kval; break; } param->lineaddr = (kdata >> 24)&0x7F; return param; } vdp2rotationparameter_struct * FASTCALL vdp2rGetKValue1W( vdp2rotationparameter_struct * param, int index ) { float kval; u16 kdata; kdata = T1ReadWord(Vdp2Ram, param->coeftbladdr + (index<<1) ); if( kdata & 0x8000 ) return NULL; kval = (float) (signed) ((kdata & 0x7FFF) | (kdata & 0x4000 ? 0x8000 : 0x0000)) / 1024.0f; switch( param->coefmode ) { case 0: param->kx = kval; param->ky = kval; break; case 1: param->kx = kval; break; case 2: param->ky = kval; break; } return param; } vdp2rotationparameter_struct * FASTCALL vdp2rGetKValue2Wm3( vdp2rotationparameter_struct * param, int index ) { return param; // ToDo: } vdp2rotationparameter_struct * FASTCALL vdp2rGetKValue1Wm3( vdp2rotationparameter_struct * param, int index ) { return param; // ToDo: } vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode00NoK( vdp2draw_struct * info, int h, int v ) { return ¶A; } vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode00WithK( vdp2draw_struct * info,int h, int v ) { h = paraA.KtablV+(paraA.deltaKAx * h); return info->GetKValueA( ¶A, h ); } vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode01NoK( vdp2draw_struct * info,int h, int v ) { return ¶B; } vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode01WithK( vdp2draw_struct * info,int h, int v ) { h = (paraB.KtablV+(paraB.deltaKAx * h)); return info->GetKValueB( ¶B, h ); } vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode02NoK( vdp2draw_struct * info,int h, int v ) { return ¶A; } vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode02WithKA( vdp2draw_struct * info,int h, int v ) { h = (paraA.KtablV+(paraA.deltaKAx * h)); if( info->GetKValueA( ¶A, h ) == NULL ) { return ¶B; } return ¶A; } vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode02WithKB( vdp2draw_struct * info,int h, int v ) { return ¶A; } vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode03NoK( vdp2draw_struct * info,int h, int v ) { if( info->WindwAreaMode == 0 ) { if( info->pWinInfo[v].WinShowLine == 0 ) { return (¶B); }else{ if( h < info->pWinInfo[v].WinHStart || h >= info->pWinInfo[v].WinHEnd ) { return (¶B); }else{ return (¶A); } } } else { if( info->pWinInfo[v].WinShowLine == 0 ) { return (¶B); }else{ if( h < info->pWinInfo[v].WinHStart || h >= info->pWinInfo[v].WinHEnd ) { return (¶A); }else{ return (¶B); } } } return NULL; } vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode03WithKA( vdp2draw_struct * info,int h, int v ) { if( info->WindwAreaMode == 0 ) { if( info->pWinInfo[v].WinShowLine == 0 ) { return (¶B); }else{ if( h < info->pWinInfo[v].WinHStart || h >= info->pWinInfo[v].WinHEnd ) { return (¶B); }else{ h = (paraA.KtablV+(paraA.deltaKAx * h)); return info->GetKValueA( ¶A, h ); } } }else{ if( info->pWinInfo[v].WinShowLine == 0 ) { h = (paraA.KtablV+(paraA.deltaKAx * h)); return info->GetKValueA( ¶A, h ); }else{ if( h < info->pWinInfo[v].WinHStart || h >= info->pWinInfo[v].WinHEnd ) { h = (paraA.KtablV+(paraA.deltaKAx * h)); return info->GetKValueA( ¶A, h ); }else{ return (¶B); } } } return NULL; } vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode03WithKB( vdp2draw_struct * info,int h, int v ) { if( info->WindwAreaMode == 0 ) { if( info->pWinInfo[v].WinShowLine == 0 ) { h = (paraB.KtablV+(paraB.deltaKAx * h)); return info->GetKValueB( ¶B, h ); }else{ if( h < info->pWinInfo[v].WinHStart || h >= info->pWinInfo[v].WinHEnd ) { h = (paraB.KtablV+(paraB.deltaKAx * h)); return info->GetKValueB( ¶B, h ); }else{ return ¶A; } } }else{ { if( info->pWinInfo[v].WinShowLine == 0 ) { return ¶A; }else{ if( h < info->pWinInfo[v].WinHStart || h >= info->pWinInfo[v].WinHEnd ) { h = (paraA.KtablV+(paraA.deltaKAx * h)); return info->GetKValueA( ¶A, h ); }else{ h = (paraB.KtablV+(paraB.deltaKAx * h)); return info->GetKValueB( ¶B, h ); } } } } return NULL; } vdp2rotationparameter_struct * FASTCALL vdp2RGetParamMode03WithK( vdp2draw_struct * info,int h, int v ) { vdp2rotationparameter_struct * p; if( info->WindwAreaMode == 0 ) { if( info->pWinInfo[v].WinShowLine == 0 ) { h = (paraB.KtablV + (paraB.deltaKAx * h)); p = info->GetKValueB(¶B, h); if (p) return p; h = (paraA.KtablV + (paraA.deltaKAx * h)); return info->GetKValueA(¶A, h); }else{ if( h < info->pWinInfo[v].WinHStart || h >= info->pWinInfo[v].WinHEnd ) { h = (paraB.KtablV+(paraB.deltaKAx * h)); p = info->GetKValueB(¶B, h); if (p) return p; h = (paraA.KtablV + (paraA.deltaKAx * h)); return info->GetKValueA(¶A, h); }else{ h = (paraA.KtablV+(paraA.deltaKAx * h)); p = info->GetKValueA(¶A, h); if (p) return p; h = (paraB.KtablV + (paraB.deltaKAx * h)); return info->GetKValueB(¶B, h); } } }else{ if( info->pWinInfo[v].WinShowLine == 0 ) { h = (paraB.KtablV + (paraB.deltaKAx * h)); p = info->GetKValueB(¶B, h); if (p) return p; h = (paraA.KtablV + (paraA.deltaKAx * h)); return info->GetKValueA(¶A, h); }else{ if( h < info->pWinInfo[v].WinHStart || h >= info->pWinInfo[v].WinHEnd ) { h = (paraB.KtablV + (paraB.deltaKAx * h)); p = info->GetKValueB(¶B, h); if (p) return p; h = (paraA.KtablV + (paraA.deltaKAx * h)); return info->GetKValueA(¶A, h); }else{ h = (paraA.KtablV + (paraA.deltaKAx * h)); p = info->GetKValueA(¶A, h); if (p) return p; h = (paraB.KtablV + (paraB.deltaKAx * h)); return info->GetKValueB(¶B, h); } } } return NULL; } #endif yabause-0.9.15/src/ygles.c000755 001750 001750 00000215455 12755623101 017350 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005-2006 Guillaume Duhamel Copyright 2005-2006 Theo Berkau Copyright 2011-2015 Shinya Miyamoto(devmiyax) This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_LIBGL #include #include #include "ygl.h" #include "yui.h" #include "vidshared.h" #include "debug.h" static int YglCalcTextureQ( float *pnts,float *q); #define PI 3.1415926535897932384626433832795f #define ATLAS_BIAS (0.025f) void YglScalef(YglMatrix *result, GLfloat sx, GLfloat sy, GLfloat sz) { result->m[0][0] *= sx; result->m[0][1] *= sx; result->m[0][2] *= sx; result->m[0][3] *= sx; result->m[1][0] *= sy; result->m[1][1] *= sy; result->m[1][2] *= sy; result->m[1][3] *= sy; result->m[2][0] *= sz; result->m[2][1] *= sz; result->m[2][2] *= sz; result->m[2][3] *= sz; } void YglTranslatef(YglMatrix *result, GLfloat tx, GLfloat ty, GLfloat tz) { result->m[0][3] += (result->m[0][0] * tx + result->m[0][1] * ty + result->m[0][2] * tz); result->m[1][3] += (result->m[1][0] * tx + result->m[1][1] * ty + result->m[1][2] * tz); result->m[2][3] += (result->m[2][0] * tx + result->m[2][1] * ty + result->m[2][2] * tz); result->m[3][3] += (result->m[3][0] * tx + result->m[3][1] * ty + result->m[3][2] * tz); } void YglRotatef(YglMatrix *result, GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { GLfloat sinAngle, cosAngle; GLfloat mag = sqrtf(x * x + y * y + z * z); sinAngle = sinf ( angle * PI / 180.0f ); cosAngle = cosf ( angle * PI / 180.0f ); if ( mag > 0.0f ) { GLfloat xx, yy, zz, xy, yz, zx, xs, ys, zs; GLfloat oneMinusCos; YglMatrix rotMat; x /= mag; y /= mag; z /= mag; xx = x * x; yy = y * y; zz = z * z; xy = x * y; yz = y * z; zx = z * x; xs = x * sinAngle; ys = y * sinAngle; zs = z * sinAngle; oneMinusCos = 1.0f - cosAngle; rotMat.m[0][0] = (oneMinusCos * xx) + cosAngle; rotMat.m[0][1] = (oneMinusCos * xy) - zs; rotMat.m[0][2] = (oneMinusCos * zx) + ys; rotMat.m[0][3] = 0.0F; rotMat.m[1][0] = (oneMinusCos * xy) + zs; rotMat.m[1][1] = (oneMinusCos * yy) + cosAngle; rotMat.m[1][2] = (oneMinusCos * yz) - xs; rotMat.m[1][3] = 0.0F; rotMat.m[2][0] = (oneMinusCos * zx) - ys; rotMat.m[2][1] = (oneMinusCos * yz) + xs; rotMat.m[2][2] = (oneMinusCos * zz) + cosAngle; rotMat.m[2][3] = 0.0F; rotMat.m[3][0] = 0.0F; rotMat.m[3][1] = 0.0F; rotMat.m[3][2] = 0.0F; rotMat.m[3][3] = 1.0F; YglMatrixMultiply( result, &rotMat, result ); } } void YglFrustum(YglMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ) { float deltaX = right - left; float deltaY = top - bottom; float deltaZ = farZ - nearZ; YglMatrix frust; if ( (nearZ <= 0.0f) || (farZ <= 0.0f) || (deltaX <= 0.0f) || (deltaY <= 0.0f) || (deltaZ <= 0.0f) ) return; frust.m[0][0] = 2.0f * nearZ / deltaX; frust.m[0][1] = frust.m[0][2] = frust.m[0][3] = 0.0f; frust.m[1][1] = 2.0f * nearZ / deltaY; frust.m[1][0] = frust.m[1][2] = frust.m[1][3] = 0.0f; frust.m[2][0] = (right + left) / deltaX; frust.m[2][1] = (top + bottom) / deltaY; frust.m[2][2] = -(nearZ + farZ) / deltaZ; frust.m[2][3] = -1.0f; frust.m[3][2] = -2.0f * nearZ * farZ / deltaZ; frust.m[3][0] = frust.m[3][1] = frust.m[3][3] = 0.0f; YglMatrixMultiply(result, &frust, result); } void YglPerspective(YglMatrix *result, float fovy, float aspect, float nearZ, float farZ) { GLfloat frustumW, frustumH; frustumH = tanf( fovy / 360.0f * PI ) * nearZ; frustumW = frustumH * aspect; YglFrustum( result, -frustumW, frustumW, -frustumH, frustumH, nearZ, farZ ); } void YglOrtho(YglMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ) { float deltaX = right - left; float deltaY = top - bottom; float deltaZ = farZ - nearZ; YglMatrix ortho; if ( (deltaX == 0.0f) || (deltaY == 0.0f) || (deltaZ == 0.0f) ) return; YglLoadIdentity(&ortho); ortho.m[0][0] = 2.0f / deltaX; ortho.m[0][3] = -(right + left) / deltaX; ortho.m[1][1] = 2.0f / deltaY; ortho.m[1][3] = -(top + bottom) / deltaY; ortho.m[2][2] = -2.0f / deltaZ; ortho.m[2][3] = -(nearZ + farZ) / deltaZ; YglMatrixMultiply(result, &ortho, result); } void YglTransform(YglMatrix *mtx, float * inXyz, float * outXyz ) { outXyz[0] = inXyz[0] * mtx->m[0][0] + inXyz[0] * mtx->m[0][1] + inXyz[0] * mtx->m[0][2] + mtx->m[0][3]; outXyz[1] = inXyz[0] * mtx->m[1][0] + inXyz[0] * mtx->m[1][1] + inXyz[0] * mtx->m[1][2] + mtx->m[1][3]; outXyz[2] = inXyz[0] * mtx->m[2][0] + inXyz[0] * mtx->m[2][1] + inXyz[0] * mtx->m[2][2] + mtx->m[2][3]; } void YglMatrixMultiply(YglMatrix *result, YglMatrix *srcA, YglMatrix *srcB) { YglMatrix tmp; int i; for (i=0; i<4; i++) { tmp.m[i][0] = (srcA->m[i][0] * srcB->m[0][0]) + (srcA->m[i][1] * srcB->m[1][0]) + (srcA->m[i][2] * srcB->m[2][0]) + (srcA->m[i][3] * srcB->m[3][0]) ; tmp.m[i][1] = (srcA->m[i][0] * srcB->m[0][1]) + (srcA->m[i][1] * srcB->m[1][1]) + (srcA->m[i][2] * srcB->m[2][1]) + (srcA->m[i][3] * srcB->m[3][1]) ; tmp.m[i][2] = (srcA->m[i][0] * srcB->m[0][2]) + (srcA->m[i][1] * srcB->m[1][2]) + (srcA->m[i][2] * srcB->m[2][2]) + (srcA->m[i][3] * srcB->m[3][2]) ; tmp.m[i][3] = (srcA->m[i][0] * srcB->m[0][3]) + (srcA->m[i][1] * srcB->m[1][3]) + (srcA->m[i][2] * srcB->m[2][3]) + (srcA->m[i][3] * srcB->m[3][3]) ; } memcpy(result, &tmp, sizeof(YglMatrix)); } void YglLoadIdentity(YglMatrix *result) { memset(result, 0x0, sizeof(YglMatrix)); result->m[0][0] = 1.0f; result->m[1][1] = 1.0f; result->m[2][2] = 1.0f; result->m[3][3] = 1.0f; } YglTextureManager * YglTM; Ygl * _Ygl; typedef struct { float s, t, r, q; } texturecoordinate_struct; extern int GlHeight; extern int GlWidth; extern int vdp1cor; extern int vdp1cog; extern int vdp1cob; #define STD_Q2 (1.0f) #define EPS (1e-10) #define EQ(a,b) (abs((a)-(b)) < EPS) #define IS_ZERO(a) ( (a) < EPS && (a) > -EPS) // AXB = |A||B|sin static INLINE float cross2d( float veca[2], float vecb[2] ) { return (veca[0]*vecb[1])-(vecb[0]*veca[1]); } /*----------------------------------------- b1+--+ a1 / / \ / / \ a2+-+-----+b2 ans get intersection point for opssite edge. --------------------------------------------*/ int FASTCALL YglIntersectionOppsiteEdge(float * a1, float * a2, float * b1, float * b2, float * out ) { float veca[2]; float vecb[2]; float vecc[2]; float d1; float d2; veca[0]=a2[0]-a1[0]; veca[1]=a2[1]-a1[1]; vecb[0]=b1[0]-a1[0]; vecb[1]=b1[1]-a1[1]; vecc[0]=b2[0]-a1[0]; vecc[1]=b2[1]-a1[1]; d1 = cross2d(vecb,vecc); if( IS_ZERO(d1) ) return -1; d2 = cross2d(vecb,veca); out[0] = a1[0]+vecc[0]*d2/d1; out[1] = a1[1]+vecc[1]*d2/d1; return 0; } int YglCalcTextureQ( float *pnts, float *q ) { float p1[2],p2[2],p3[2],p4[2],o[2]; float q1, q3, q4, qw; float dx, w; float ww; // fast calculation for triangle if (( pnts[2*0+0] == pnts[2*1+0] ) && ( pnts[2*0+1] == pnts[2*1+1] )) { q[0] = 1.0f; q[1] = 1.0f; q[2] = 1.0f; q[3] = 1.0f; return 0; } else if (( pnts[2*1+0] == pnts[2*2+0] ) && ( pnts[2*1+1] == pnts[2*2+1] )) { q[0] = 1.0f; q[1] = 1.0f; q[2] = 1.0f; q[3] = 1.0f; return 0; } else if (( pnts[2*2+0] == pnts[2*3+0] ) && ( pnts[2*2+1] == pnts[2*3+1] )) { q[0] = 1.0f; q[1] = 1.0f; q[2] = 1.0f; q[3] = 1.0f; return 0; } else if (( pnts[2*3+0] == pnts[2*0+0] ) && ( pnts[2*3+1] == pnts[2*0+1] )) { q[0] = 1.0f; q[1] = 1.0f; q[2] = 1.0f; q[3] = 1.0f; return 0; } p1[0]=pnts[0]; p1[1]=pnts[1]; p2[0]=pnts[2]; p2[1]=pnts[3]; p3[0]=pnts[4]; p3[1]=pnts[5]; p4[0]=pnts[6]; p4[1]=pnts[7]; // calcurate Q1 if( YglIntersectionOppsiteEdge( p3, p1, p2, p4, o ) == 0 ) { dx = o[0]-p1[0]; if( !IS_ZERO(dx) ) { w = p3[0]-p2[0]; if( !IS_ZERO(w) ) q1 = fabs(dx/w); else q1 = 0.0f; }else{ w = p3[1] - p2[1]; if ( !IS_ZERO(w) ) { ww = ( o[1] - p1[1] ); if ( !IS_ZERO(ww) ) q1 = fabs(ww / w); else q1 = 0.0f; } else { q1 = 0.0f; } } }else{ q1 = 1.0f; } /* q2 = 1.0f; */ // calcurate Q3 if( YglIntersectionOppsiteEdge( p1, p3, p2,p4, o ) == 0 ) { dx = o[0]-p3[0]; if( !IS_ZERO(dx) ) { w = p1[0]-p2[0]; if( !IS_ZERO(w) ) q3 = fabs(dx/w); else q3 = 0.0f; }else{ w = p1[1] - p2[1]; if ( !IS_ZERO(w) ) { ww = ( o[1] - p3[1] ); if ( !IS_ZERO(ww) ) q3 = fabs(ww / w); else q3 = 0.0f; } else { q3 = 0.0f; } } }else{ q3 = 1.0f; } // calcurate Q4 if( YglIntersectionOppsiteEdge( p3, p1, p4, p2, o ) == 0 ) { dx = o[0]-p1[0]; if( !IS_ZERO(dx) ) { w = p3[0]-p4[0]; if( !IS_ZERO(w) ) qw = fabs(dx/w); else qw = 0.0f; }else{ w = p3[1] - p4[1]; if ( !IS_ZERO(w) ) { ww = ( o[1] - p1[1] ); if ( !IS_ZERO(ww) ) qw = fabs(ww / w); else qw = 0.0f; } else { qw = 0.0f; } } if ( !IS_ZERO(qw) ) { w = qw / q1; } else { w = 0.0f; } if ( IS_ZERO(w) ) { q4 = 1.0f; } else { q4 = 1.0f / w; } }else{ q4 = 1.0f; } qw = q1; if ( qw < 1.0f ) /* q2 = 1.0f */ qw = 1.0f; if ( qw < q3 ) qw = q3; if ( qw < q4 ) qw = q4; if ( 1.0f != qw ) { qw = 1.0f / qw; q[0] = q1 * qw; q[1] = 1.0f * qw; q[2] = q3 * qw; q[3] = q4 * qw; } else { q[0] = q1; q[1] = 1.0f; q[2] = q3; q[3] = q4; } return 0; } ////////////////////////////////////////////////////////////////////////////// void YglTMInit(unsigned int w, unsigned int h) { YglTM = (YglTextureManager *) malloc(sizeof(YglTextureManager)); YglTM->texture = (unsigned int *) malloc(sizeof(unsigned int) * w * h); memset(YglTM->texture,0,sizeof(unsigned int) * w * h); YglTM->width = w; YglTM->height = h; YglTMReset(); } ////////////////////////////////////////////////////////////////////////////// void YglTMDeInit(void) { //free(YglTM->texture); if( YglTM->texture != NULL ) { glUnmapBuffer (GL_PIXEL_UNPACK_BUFFER); YglTM->texture = NULL; } free(YglTM); } ////////////////////////////////////////////////////////////////////////////// void YglTMReset(void) { YglTM->currentX = 0; YglTM->currentY = 0; YglTM->yMax = 0; } ////////////////////////////////////////////////////////////////////////////// void YglTMAllocate(YglTexture * output, unsigned int w, unsigned int h, unsigned int * x, unsigned int * y) { if ((YglTM->height - YglTM->currentY) < h) { fprintf(stderr, "can't allocate texture: %dx%d\n", w, h); *x = *y = 0; output->w = 0; output->textdata = YglTM->texture; return; } if ((YglTM->width - YglTM->currentX) >= w) { *x = YglTM->currentX; *y = YglTM->currentY; output->w = YglTM->width - w; output->textdata = YglTM->texture + YglTM->currentY * YglTM->width + YglTM->currentX; YglTM->currentX += w; //YglTM->currentX += 0x0F; //YglTM->currentX &= ~(0x0F); if ((YglTM->currentY + h) > YglTM->yMax) { YglTM->yMax = YglTM->currentY + h; //YglTM->yMax += 0x0F; //YglTM->yMax &= ~(0x0F); } } else { YglTM->currentX = 0; YglTM->currentY = YglTM->yMax; YglTMAllocate(output, w, h, x, y); } } void VIDOGLVdp1ReadFrameBuffer(u32 type, u32 addr, void * out) { if (_Ygl->smallfbo == 0) { glGenFramebuffers(1, &_Ygl->smallfbo); YGLLOG("glGenFramebuffers %d\n", _Ygl->smallfbo ); glGenTextures(1, &_Ygl->smallfbotex); YGLLOG("glGenTextures %d\n",_Ygl->smallfbotex ); glBindTexture(GL_TEXTURE_2D, _Ygl->smallfbotex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _Ygl->rwidth, _Ygl->rheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); YGLLOG("glTexImage2D %d\n",_Ygl->smallfbotex ); glBindFramebuffer(GL_FRAMEBUFFER, _Ygl->smallfbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _Ygl->smallfbotex, 0); glGenBuffers(1, &_Ygl->vdp1pixelBufferID); YGLLOG("glGenBuffers %d\n",_Ygl->vdp1pixelBufferID); if( _Ygl->vdp1pixelBufferID == 0 ){ YGLLOG("Fail to glGenBuffers %X",glGetError()); } glBindBuffer(GL_PIXEL_PACK_BUFFER, _Ygl->vdp1pixelBufferID); glBufferData(GL_PIXEL_PACK_BUFFER, _Ygl->rwidth*_Ygl->rheight * 4, NULL, GL_DYNAMIC_READ); glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); } if (_Ygl->pFrameBuffer == NULL){ #if 0 glBindFramebuffer(GL_FRAMEBUFFER, _Ygl->vdp1fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _Ygl->vdp1FrameBuff[((_Ygl->drawframe ^ 0x01) & 0x01)], 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, _Ygl->vdp1fbo); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _Ygl->smallfbo); glBlitFramebuffer(0, 0, GlWidth, GlHeight, 0, 0, _Ygl->rwidth, _Ygl->rheight, GL_COLOR_BUFFER_BIT, GL_LINEAR); #else YglBlitFramebuffer(_Ygl->vdp1FrameBuff[_Ygl->readframe], _Ygl->smallfbo, (float)_Ygl->rwidth / (float)GlWidth, (float)_Ygl->rheight / (float)GlHeight); #endif glBindFramebuffer(GL_FRAMEBUFFER, _Ygl->smallfbo); glBindBuffer(GL_PIXEL_PACK_BUFFER, _Ygl->vdp1pixelBufferID); YGLLOG("glReadPixels %d\n",_Ygl->vdp1pixelBufferID); glReadPixels(0, 0, _Ygl->rwidth, _Ygl->rheight, GL_RGBA, GL_UNSIGNED_BYTE, 0); YGLLOG("VIDOGLVdp1ReadFrameBuffer %d\n", _Ygl->drawframe); _Ygl->pFrameBuffer = (unsigned int *)glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, _Ygl->rwidth * _Ygl->rheight * 4, GL_MAP_READ_BIT); glBindFramebuffer(GL_FRAMEBUFFER,0); if (_Ygl->pFrameBuffer==NULL) { switch (type) { case 1: *(u16*)out = 0x0000; break; case 2: *(u32*)out = 0x00000000; break; } return; } } { const int Line = (addr >> 10); // *((float)(GlHeight) / (float)_Ygl->rheight); const int Pix = ((addr & 0x3FF) >> 1); // *((float)(GlWidth) / (float)_Ygl->rwidth); const int index = (_Ygl->rheight - 1 - Line)*(_Ygl->rwidth* 4) + Pix * 4; switch (type) { case 1: { u8 r = *((u8*)(_Ygl->pFrameBuffer) + index); u8 g = *((u8*)(_Ygl->pFrameBuffer) + index + 1); u8 b = *((u8*)(_Ygl->pFrameBuffer) + index + 2); //*(u16*)out = ((val & 0x1f) << 10) | ((val >> 1) & 0x3e0) | ((val >> 11) & 0x1F) | 0x8000; *(u16*)out = ((r >> 3) & 0x1f) | (((g >> 3) & 0x1f) << 5) | (((b >> 3) & 0x1F)<<10) | 0x8000; } break; case 2: { u32 r = *((u8*)(_Ygl->pFrameBuffer) + index); u32 g = *((u8*)(_Ygl->pFrameBuffer) + index + 1); u32 b = *((u8*)(_Ygl->pFrameBuffer) + index + 2); u32 r2 = *((u8*)(_Ygl->pFrameBuffer) + index+4); u32 g2 = *((u8*)(_Ygl->pFrameBuffer) + index + 5); u32 b2 = *((u8*)(_Ygl->pFrameBuffer) + index + 6); if (r != 0) { int a=0; } /* BBBBBGGGGGRRRRR */ //*(u16*)out = ((val & 0x1f) << 10) | ((val >> 1) & 0x3e0) | ((val >> 11) & 0x1F) | 0x8000; *(u32*)out = (((r2 >> 3) & 0x1f) | (((g2 >> 3) & 0x1f) << 5) | (((b2 >> 3) & 0x1F)<<10) | 0x8000) | ((((r >> 3) & 0x1f) | (((g >> 3) & 0x1f) << 5) | (((b >> 3) & 0x1F)<<10) | 0x8000) << 16) ; } break; } } } ////////////////////////////////////////////////////////////////////////////// int YglGLInit(int width, int height) { int status; GLuint error; glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); YglLoadIdentity(&_Ygl->mtxModelView); YglOrtho(&_Ygl->mtxModelView,0.0f, 320.0f, 224.0f, 0.0f, 10.0f, 0.0f); YglLoadIdentity(&_Ygl->mtxTexture); YglOrtho(&_Ygl->mtxTexture,-width, width, -height, height, 1.0f, 0.0f ); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_DEPTH_TEST); glDepthFunc(GL_GEQUAL); glClearDepthf(0.0f); glCullFace(GL_FRONT_AND_BACK); glDisable(GL_CULL_FACE); glDisable(GL_DITHER); glGetError(); glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); YGLLOG("YglGLInit(%d,%d)\n",GlWidth,GlHeight ); if( _Ygl->texture == 0 ) glGenTextures(1, &_Ygl->texture); glGenBuffers(1, &_Ygl->pixelBufferID); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _Ygl->pixelBufferID); glBufferData(GL_PIXEL_UNPACK_BUFFER, width * height * 4, NULL, GL_STREAM_DRAW); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); glBindTexture(GL_TEXTURE_2D, _Ygl->texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); if( (error = glGetError()) != GL_NO_ERROR ) { YGLLOG("Fail to init YglTM->texture %04X", error); return -1; } glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glBindTexture(GL_TEXTURE_2D, _Ygl->texture); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _Ygl->pixelBufferID); YglTM->texture = (unsigned int *)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, width * height * 4, GL_MAP_WRITE_BIT|GL_MAP_INVALIDATE_BUFFER_BIT); if( (error = glGetError()) != GL_NO_ERROR ) { YGLLOG("Fail to init YglTM->texture %04X", error); return -1; } glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); if( _Ygl->vdp1FrameBuff != 0 ) glDeleteTextures(2,_Ygl->vdp1FrameBuff); glGenTextures(2,_Ygl->vdp1FrameBuff); glBindTexture(GL_TEXTURE_2D,_Ygl->vdp1FrameBuff[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GlWidth, GlHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,NULL); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glBindTexture(GL_TEXTURE_2D,_Ygl->vdp1FrameBuff[1]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GlWidth, GlHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,NULL); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); _Ygl->pFrameBuffer = NULL; if( strstr((const char*)glGetString(GL_EXTENSIONS),"packed_depth_stencil") != NULL ) { if( _Ygl->rboid_depth != 0 ) glDeleteRenderbuffers(1,&_Ygl->rboid_depth); glGenRenderbuffers(1, &_Ygl->rboid_depth); glBindRenderbuffer(GL_RENDERBUFFER,_Ygl->rboid_depth); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, GlWidth, GlHeight); _Ygl->rboid_stencil = _Ygl->rboid_depth; }else{ if( _Ygl->rboid_depth != 0 ) glDeleteRenderbuffers(1,&_Ygl->rboid_depth); glGenRenderbuffers(1, &_Ygl->rboid_depth); glBindRenderbuffer(GL_RENDERBUFFER,_Ygl->rboid_depth); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, GlWidth, GlHeight); if( _Ygl->rboid_stencil != 0 ) glDeleteRenderbuffers(1,&_Ygl->rboid_stencil); glGenRenderbuffers(1, &_Ygl->rboid_stencil); glBindRenderbuffer(GL_RENDERBUFFER,_Ygl->rboid_stencil); glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, GlWidth, GlHeight); } glBindFramebuffer(GL_FRAMEBUFFER, _Ygl->vdp1fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _Ygl->vdp1FrameBuff[0], 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _Ygl->rboid_depth); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _Ygl->rboid_stencil); status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if( status != GL_FRAMEBUFFER_COMPLETE ) { YGLLOG("YglGLInit:Framebuffer status = %08X\n", status ); } glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glBindFramebuffer(GL_FRAMEBUFFER, _Ygl->vdp1fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _Ygl->vdp1FrameBuff[1], 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _Ygl->rboid_depth); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _Ygl->rboid_stencil); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glBindFramebuffer(GL_FRAMEBUFFER, 0 ); glBindTexture(GL_TEXTURE_2D,_Ygl->texture); return 0; } ////////////////////////////////////////////////////////////////////////////// int YglScreenInit(int r, int g, int b, int d) { return 0; /* YuiSetVideoAttribute(RED_SIZE, r); YuiSetVideoAttribute(GREEN_SIZE, g); YuiSetVideoAttribute(BLUE_SIZE, b); YuiSetVideoAttribute(DEPTH_SIZE, d); return (YuiSetVideoMode(320, 224, 32, 0) == 0); */ } void YuiSetVideoAttribute(int type, int val){return;} ////////////////////////////////////////////////////////////////////////////// int YglInit(int width, int height, unsigned int depth) { unsigned int i,j; GLuint status; void * dataPointer=NULL; YGLLOG("YglInit(%d,%d,%d);",width,height,depth ); YglTMInit(width, height); if ((_Ygl = (Ygl *) malloc(sizeof(Ygl))) == NULL) return -1; memset(_Ygl,0,sizeof(Ygl)); _Ygl->depth = depth; _Ygl->rwidth = 320; _Ygl->rheight = 240; if ((_Ygl->levels = (YglLevel *) malloc(sizeof(YglLevel) * (depth+1))) == NULL) return -1; memset(_Ygl->levels,0,sizeof(YglLevel) * (depth+1) ); for(i = 0;i < (depth+1) ;i++) { _Ygl->levels[i].prgcurrent = 0; _Ygl->levels[i].uclipcurrent = 0; _Ygl->levels[i].prgcount = 1; _Ygl->levels[i].prg = (YglProgram*)malloc(sizeof(YglProgram)*_Ygl->levels[i].prgcount); memset( _Ygl->levels[i].prg,0,sizeof(YglProgram)*_Ygl->levels[i].prgcount); if( _Ygl->levels[i].prg == NULL ) return -1; for(j = 0;j < _Ygl->levels[i].prgcount; j++) { _Ygl->levels[i].prg[j].prg=0; _Ygl->levels[i].prg[j].currentQuad = 0; _Ygl->levels[i].prg[j].maxQuad = 12 * 2000; if ((_Ygl->levels[i].prg[j].quads = (float *) malloc(_Ygl->levels[i].prg[j].maxQuad * sizeof(float))) == NULL) return -1; if ((_Ygl->levels[i].prg[j].textcoords = (float *) malloc(_Ygl->levels[i].prg[j].maxQuad * sizeof(float) * 2)) == NULL) return -1; if ((_Ygl->levels[i].prg[j].vertexAttribute = (float *) malloc(_Ygl->levels[i].prg[j].maxQuad * sizeof(float)*2)) == NULL) return -1; } } #if defined(_USEGLEW_) glewInit(); #endif YglGLInit(width, height); if( YglProgramInit() != 0 ) { YuiErrorMsg("Fail to YglProgramInit\n"); return -1; } _Ygl->drawframe = 0; _Ygl->readframe = 1; glGenTextures(2,_Ygl->vdp1FrameBuff); glBindTexture(GL_TEXTURE_2D,_Ygl->vdp1FrameBuff[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GlWidth, GlHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,NULL); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glBindTexture(GL_TEXTURE_2D,_Ygl->vdp1FrameBuff[1]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GlWidth, GlHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,NULL); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); if( strstr((const char*)glGetString(GL_EXTENSIONS),"packed_depth_stencil") != NULL ) { if( _Ygl->rboid_depth != 0 ) glDeleteRenderbuffers(1,&_Ygl->rboid_depth); glGenRenderbuffers(1, &_Ygl->rboid_depth); glBindRenderbuffer(GL_RENDERBUFFER,_Ygl->rboid_depth); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, GlWidth, GlHeight); _Ygl->rboid_stencil = _Ygl->rboid_depth; }else{ if( _Ygl->rboid_depth != 0 ) glDeleteRenderbuffers(1,&_Ygl->rboid_depth); glGenRenderbuffers(1, &_Ygl->rboid_depth); glBindRenderbuffer(GL_RENDERBUFFER,_Ygl->rboid_depth); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, GlWidth, GlHeight); if( _Ygl->rboid_stencil != 0 ) glDeleteRenderbuffers(1,&_Ygl->rboid_stencil); glGenRenderbuffers(1, &_Ygl->rboid_stencil); glBindRenderbuffer(GL_RENDERBUFFER,_Ygl->rboid_stencil); glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, GlWidth, GlHeight); } glGenFramebuffers(1,&_Ygl->vdp1fbo); glBindFramebuffer(GL_FRAMEBUFFER, _Ygl->vdp1fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _Ygl->vdp1FrameBuff[0], 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _Ygl->rboid_depth); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _Ygl->rboid_stencil); status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if( status != GL_FRAMEBUFFER_COMPLETE ) { YGLLOG("YglInit: Framebuffer status = %08X\n", status ); return -1; } _Ygl->smallfbo = 0; _Ygl->smallfbotex = 0; glBindFramebuffer(GL_FRAMEBUFFER, 0 ); _Ygl->st = 0; _Ygl->msglength = 0; return 0; } ////////////////////////////////////////////////////////////////////////////// void YglDeInit(void) { unsigned int i,j; YglTMDeInit(); if (_Ygl) { if (_Ygl->levels) { for (i = 0; i < (_Ygl->depth+1); i++) { for (j = 0; j < _Ygl->levels[i].prgcount; j++) { if (_Ygl->levels[i].prg[j].quads) free(_Ygl->levels[i].prg[j].quads); if (_Ygl->levels[i].prg[j].textcoords) free(_Ygl->levels[i].prg[j].textcoords); if (_Ygl->levels[i].prg[j].vertexAttribute) free(_Ygl->levels[i].prg[j].vertexAttribute); } free(_Ygl->levels[i].prg); } free(_Ygl->levels); } free(_Ygl); } } void YglStartWindow( vdp2draw_struct * info, int win0, int logwin0, int win1, int logwin1, int mode ) { YglLevel *level; YglProgram *program; level = &_Ygl->levels[info->priority]; YglProgramChange(level,PG_VDP2_STARTWINDOW); program = &level->prg[level->prgcurrent]; program->bwin0 = win0; program->logwin0 = logwin0; program->bwin1 = win1; program->logwin1 = logwin1; program->winmode = mode; } void YglEndWindow( vdp2draw_struct * info ) { YglLevel *level; level = &_Ygl->levels[info->priority]; YglProgramChange(level,PG_VDP2_ENDWINDOW); } ////////////////////////////////////////////////////////////////////////////// YglProgram * YglGetProgram( YglSprite * input, int prg ) { YglLevel *level; YglProgram *program; float checkval; if (input->priority > 8) { VDP1LOG("sprite with priority %d\n", input->priority); return NULL; } level = &_Ygl->levels[input->priority]; level->blendmode |= (input->blendmode&0x03); if( input->uclipmode != level->uclipcurrent ) { if( input->uclipmode == 0x02 || input->uclipmode == 0x03 ) { YglProgramChange(level,PG_VFP1_STARTUSERCLIP); program = &level->prg[level->prgcurrent]; program->uClipMode = input->uclipmode; if( level->ux1 != Vdp1Regs->userclipX1 || level->uy1 != Vdp1Regs->userclipY1 || level->ux2 != Vdp1Regs->userclipX2 || level->uy2 != Vdp1Regs->userclipY2 ) { program->ux1=Vdp1Regs->userclipX1; program->uy1=Vdp1Regs->userclipY1; program->ux2=Vdp1Regs->userclipX2; program->uy2=Vdp1Regs->userclipY2; level->ux1=Vdp1Regs->userclipX1; level->uy1=Vdp1Regs->userclipY1; level->ux2=Vdp1Regs->userclipX2; level->uy2=Vdp1Regs->userclipY2; }else{ program->ux1=-1; program->uy1=-1; program->ux2=-1; program->uy2=-1; } }else{ YglProgramChange(level,PG_VFP1_ENDUSERCLIP); program = &level->prg[level->prgcurrent]; program->uClipMode = input->uclipmode; } level->uclipcurrent = input->uclipmode; } checkval = (float)(input->cor) / 255.0f; if (checkval != level->prg[level->prgcurrent].color_offset_val[0]) { YglProgramChange(level, prg); } else if( level->prg[level->prgcurrent].prgid != prg ) { YglProgramChange(level,prg); } // for polygon debug // else if (prg == PG_VFP1_GOURAUDSAHDING ){ // YglProgramChange(level, prg); // } program = &level->prg[level->prgcurrent]; if (program->currentQuad == program->maxQuad) { program->maxQuad += 12*128; program->quads = (float *)realloc(program->quads, program->maxQuad * sizeof(float)); program->textcoords = (float *) realloc(program->textcoords, program->maxQuad * sizeof(float) * 2); program->vertexAttribute = (float *) realloc(program->vertexAttribute, program->maxQuad * sizeof(float)*2); YglCacheReset(); } return program; } void YglQuadOffset(YglSprite * input, YglTexture * output, YglCache * c, int cx, int cy, float sx, float sy ) { unsigned int x, y; YglProgram *program; texturecoordinate_struct *tmp; int prg = PG_NORMAL; float * pos; //float * vtxa; int vHeight; if ((input->blendmode & 0x03) == 2) { prg = PG_VDP2_ADDBLEND; } if (input->linescreen){ prg = PG_LINECOLOR_INSERT; } program = YglGetProgram(input, prg); if (program == NULL) return; program->color_offset_val[0] = (float)(input->cor) / 255.0f; program->color_offset_val[1] = (float)(input->cog) / 255.0f; program->color_offset_val[2] = (float)(input->cob) / 255.0f; program->color_offset_val[3] = 0; //info->cor vHeight = input->vertices[5] - input->vertices[1]; pos = program->quads + program->currentQuad; pos[0] = (input->vertices[0] - cx) * sx; pos[1] = input->vertices[1] * sy; pos[2] = (input->vertices[2] - cx) * sx; pos[3] = input->vertices[3] * sy; pos[4] = (input->vertices[4] - cx) * sx; pos[5] = input->vertices[5] * sy; pos[6] = (input->vertices[0] - cx) * sx; pos[7] = (input->vertices[1]) * sy; pos[8] = (input->vertices[4] - cx)*sx; pos[9] = input->vertices[5] * sy; pos[10] = (input->vertices[6] - cx) * sx; pos[11] = input->vertices[7] * sy; // vtxa = (program->vertexAttribute + (program->currentQuad * 2)); // memset(vtxa,0,sizeof(float)*24); tmp = (texturecoordinate_struct *)(program->textcoords + (program->currentQuad * 2)); program->currentQuad += 12; YglTMAllocate(output, input->w, input->h, &x, &y); if (output->textdata == NULL){ abort(); } tmp[0].r = tmp[1].r = tmp[2].r = tmp[3].r = tmp[4].r = tmp[5].r = 0; // these can stay at 0 /* 0 +---+ 1 | | +---+ 2 3 +---+ | | 5 +---+ 4 */ if (input->flip & 0x1) { tmp[0].s = tmp[3].s = tmp[5].s = (float)(x + input->w) - ATLAS_BIAS; tmp[1].s = tmp[2].s = tmp[4].s = (float)(x)+ATLAS_BIAS; } else { tmp[0].s = tmp[3].s = tmp[5].s = (float)(x)+ATLAS_BIAS; tmp[1].s = tmp[2].s = tmp[4].s = (float)(x + input->w) - ATLAS_BIAS; } if (input->flip & 0x2) { tmp[0].t = tmp[1].t = tmp[3].t = (float)(y + input->h - cy) - ATLAS_BIAS; tmp[2].t = tmp[4].t = tmp[5].t = (float)(y + input->h - (cy+vHeight) ) + ATLAS_BIAS; } else { tmp[0].t = tmp[1].t = tmp[3].t = (float)(y + cy ) + ATLAS_BIAS; tmp[2].t = tmp[4].t = tmp[5].t = (float)(y + (cy + vHeight)) - ATLAS_BIAS; } c->x = x; c->y = y; tmp[0].q = 1.0f; tmp[1].q = 1.0f; tmp[2].q = 1.0f; tmp[3].q = 1.0f; tmp[4].q = 1.0f; tmp[5].q = 1.0f; } float * YglQuad(YglSprite * input, YglTexture * output, YglCache * c) { unsigned int x, y; YglProgram *program; texturecoordinate_struct *tmp; float q[4]; int prg = PG_NORMAL; float * pos; //float * vtxa; if( (input->blendmode&0x03) == 2 ) { prg = PG_VDP2_ADDBLEND; }else if( input->blendmode == 0x80 ) { prg = PG_VFP1_HALFTRANS; }else if( input->priority == 8 ) { prg = PG_VDP1_NORMAL; } if (input->linescreen){ prg = PG_LINECOLOR_INSERT; } program = YglGetProgram(input,prg); if( program == NULL ) return NULL; program->color_offset_val[0] = (float)(input->cor)/255.0f; program->color_offset_val[1] = (float)(input->cog)/255.0f; program->color_offset_val[2] = (float)(input->cob)/255.0f; program->color_offset_val[3] = 0; //info->cor pos = program->quads + program->currentQuad; pos[0] = input->vertices[0]; pos[1] = input->vertices[1]; pos[2] = input->vertices[2]; pos[3] = input->vertices[3]; pos[4] = input->vertices[4]; pos[5] = input->vertices[5]; pos[6] = input->vertices[0]; pos[7] = input->vertices[1]; pos[8] = input->vertices[4]; pos[9] = input->vertices[5]; pos[10] = input->vertices[6]; pos[11] = input->vertices[7]; // vtxa = (program->vertexAttribute + (program->currentQuad * 2)); // memset(vtxa,0,sizeof(float)*24); tmp = (texturecoordinate_struct *)(program->textcoords + (program->currentQuad * 2)); program->currentQuad += 12; YglTMAllocate(output, input->w, input->h, &x, &y); if (output->textdata == NULL){ abort(); } tmp[0].r = tmp[1].r = tmp[2].r = tmp[3].r = tmp[4].r = tmp[5].r = 0; // these can stay at 0 /* 0 +---+ 1 | | +---+ 2 3 +---+ | | 5 +---+ 4 */ if (input->flip & 0x1) { tmp[0].s = tmp[3].s = tmp[5].s = (float)(x + input->w) - ATLAS_BIAS; tmp[1].s = tmp[2].s = tmp[4].s = (float)(x)+ ATLAS_BIAS; } else { tmp[0].s = tmp[3].s = tmp[5].s = (float)(x) + ATLAS_BIAS; tmp[1].s = tmp[2].s = tmp[4].s = (float)(x + input->w)-ATLAS_BIAS; } if (input->flip & 0x2) { tmp[0].t = tmp[1].t = tmp[3].t = (float)(y + input->h)-ATLAS_BIAS; tmp[2].t = tmp[4].t = tmp[5].t = (float)(y)+ATLAS_BIAS; } else { tmp[0].t = tmp[1].t = tmp[3].t = (float)(y) + ATLAS_BIAS; tmp[2].t = tmp[4].t = tmp[5].t = (float)(y + input->h)-ATLAS_BIAS; } if( c != NULL ) { switch(input->flip) { case 0: c->x = *(program->textcoords + ((program->currentQuad - 12) * 2)); // upper left coordinates(0) c->y = *(program->textcoords + ((program->currentQuad - 12) * 2) + 1); // upper left coordinates(0) break; case 1: c->x = *(program->textcoords + ((program->currentQuad - 10) * 2)); // upper left coordinates(0) c->y = *(program->textcoords + ((program->currentQuad - 10) * 2) + 1); // upper left coordinates(0) break; case 2: c->x = *(program->textcoords + ((program->currentQuad - 2) * 2)); // upper left coordinates(0) c->y = *(program->textcoords + ((program->currentQuad - 2) * 2) + 1); // upper left coordinates(0) break; case 3: c->x = *(program->textcoords + ((program->currentQuad - 4) * 2)); // upper left coordinates(0) c->y = *(program->textcoords + ((program->currentQuad - 4) * 2) + 1); // upper left coordinates(0) break; } } if( input->dst == 1 ) { YglCalcTextureQ(input->vertices,q); tmp[0].s *= q[0]; tmp[0].t *= q[0]; tmp[1].s *= q[1]; tmp[1].t *= q[1]; tmp[2].s *= q[2]; tmp[2].t *= q[2]; tmp[3].s *= q[0]; tmp[3].t *= q[0]; tmp[4].s *= q[2]; tmp[4].t *= q[2]; tmp[5].s *= q[3]; tmp[5].t *= q[3]; tmp[0].q = q[0]; tmp[1].q = q[1]; tmp[2].q = q[2]; tmp[3].q = q[0]; tmp[4].q = q[2]; tmp[5].q = q[3]; }else{ tmp[0].q = 1.0f; tmp[1].q = 1.0f; tmp[2].q = 1.0f; tmp[3].q = 1.0f; tmp[4].q = 1.0f; tmp[5].q = 1.0f; } return 0; } ////////////////////////////////////////////////////////////////////////////// int YglQuadGrowShading(YglSprite * input, YglTexture * output, float * colors,YglCache * c) { unsigned int x, y; YglProgram *program; texturecoordinate_struct *tmp; float * vtxa; float q[4]; int prg = PG_VFP1_GOURAUDSAHDING; float * pos; if( (input->blendmode&0x03) == 2 ) { prg = PG_VDP2_ADDBLEND; }else if( input->blendmode == 0x80 ) { prg = PG_VFP1_GOURAUDSAHDING_HALFTRANS; } if (input->linescreen){ prg = PG_LINECOLOR_INSERT; } program = YglGetProgram(input,prg); if( program == NULL ) return -1; //YGLLOG( "program->quads = %X,%X,%d/%d\n",program->quads,program->vertexBuffer,program->currentQuad,program->maxQuad ); if( program->quads == NULL ) { int a=0; } program->color_offset_val[0] = (float)(input->cor)/255.0f; program->color_offset_val[1] = (float)(input->cog)/255.0f; program->color_offset_val[2] = (float)(input->cob)/255.0f; program->color_offset_val[3] = 0; // Vertex pos = program->quads + program->currentQuad; /* float dx = input->vertices[4] - input->vertices[0]; float dy = input->vertices[5] - input->vertices[1]; if (dx < 0.0 && dy < 0.0 ){ pos[0] = input->vertices[2*1 + 0]; // 1 pos[1] = input->vertices[2*1 + 1]; pos[2] = input->vertices[2 * 0 + 0]; // 0 pos[3] = input->vertices[2 * 0 + 1]; pos[4] = input->vertices[2 * 2 + 0]; // 2 pos[5] = input->vertices[2 * 2 + 1]; pos[6] = input->vertices[2 * 1 + 0]; // 1 pos[7] = input->vertices[2 * 1 + 1]; pos[8] = input->vertices[2 * 2 + 0]; // 2 pos[9] = input->vertices[2 * 2 + 1]; pos[10] = input->vertices[2 * 3 + 0]; //3 pos[11] = input->vertices[2 * 3 + 1]; } else */ { pos[0] = input->vertices[0]; pos[1] = input->vertices[1]; pos[2] = input->vertices[2]; pos[3] = input->vertices[3]; pos[4] = input->vertices[4]; pos[5] = input->vertices[5]; pos[6] = input->vertices[0]; pos[7] = input->vertices[1]; pos[8] = input->vertices[4]; pos[9] = input->vertices[5]; pos[10] = input->vertices[6]; pos[11] = input->vertices[7]; } // Color vtxa = (program->vertexAttribute + (program->currentQuad * 2)); if( colors == NULL ) { memset(vtxa,0,sizeof(float)*24); } else { vtxa[0] = colors[0]; vtxa[1] = colors[1]; vtxa[2] = colors[2]; vtxa[3] = colors[3]; vtxa[4] = colors[4]; vtxa[5] = colors[5]; vtxa[6] = colors[6]; vtxa[7] = colors[7]; vtxa[8] = colors[8]; vtxa[9] = colors[9]; vtxa[10] = colors[10]; vtxa[11] = colors[11]; vtxa[12] = colors[0]; vtxa[13] = colors[1]; vtxa[14] = colors[2]; vtxa[15] = colors[3]; vtxa[16] = colors[8]; vtxa[17] = colors[9]; vtxa[18] = colors[10]; vtxa[19] = colors[11]; vtxa[20] = colors[12]; vtxa[21] = colors[13]; vtxa[22] = colors[14]; vtxa[23] = colors[15]; } // texture tmp = (texturecoordinate_struct *)(program->textcoords + (program->currentQuad * 2)); program->currentQuad += 12; YglTMAllocate(output, input->w, input->h, &x, &y); tmp[0].r = tmp[1].r = tmp[2].r = tmp[3].r = tmp[4].r = tmp[5].r = 0; // these can stay at 0 if (input->flip & 0x1) { tmp[0].s = tmp[3].s = tmp[5].s = (float)(x + input->w)-ATLAS_BIAS; tmp[1].s = tmp[2].s = tmp[4].s = (float)(x)+ATLAS_BIAS; } else { tmp[0].s = tmp[3].s = tmp[5].s = (float)(x)+ATLAS_BIAS; tmp[1].s = tmp[2].s = tmp[4].s = (float)(x + input->w)-ATLAS_BIAS; } if (input->flip & 0x2) { tmp[0].t = tmp[1].t = tmp[3].t = (float)(y + input->h)-ATLAS_BIAS; tmp[2].t = tmp[4].t = tmp[5].t = (float)(y)+ATLAS_BIAS; } else { tmp[0].t = tmp[1].t = tmp[3].t = (float)(y)+ATLAS_BIAS; tmp[2].t = tmp[4].t = tmp[5].t = (float)(y + input->h)-ATLAS_BIAS; } if( c != NULL ) { switch(input->flip) { case 0: c->x = *(program->textcoords + ((program->currentQuad - 12) * 2)); // upper left coordinates(0) c->y = *(program->textcoords + ((program->currentQuad - 12) * 2)+1); // upper left coordinates(0) break; case 1: c->x = *(program->textcoords + ((program->currentQuad - 10) * 2)); // upper left coordinates(0) c->y = *(program->textcoords + ((program->currentQuad - 10) * 2)+1); // upper left coordinates(0) break; case 2: c->x = *(program->textcoords + ((program->currentQuad - 2) * 2)); // upper left coordinates(0) c->y = *(program->textcoords + ((program->currentQuad - 2) * 2)+1); // upper left coordinates(0) break; case 3: c->x = *(program->textcoords + ((program->currentQuad - 4) * 2)); // upper left coordinates(0) c->y = *(program->textcoords + ((program->currentQuad - 4) * 2)+1); // upper left coordinates(0) break; } } if( input->dst == 1 ) { YglCalcTextureQ(input->vertices,q); tmp[0].s *= q[0]; tmp[0].t *= q[0]; tmp[1].s *= q[1]; tmp[1].t *= q[1]; tmp[2].s *= q[2]; tmp[2].t *= q[2]; tmp[3].s *= q[0]; tmp[3].t *= q[0]; tmp[4].s *= q[2]; tmp[4].t *= q[2]; tmp[5].s *= q[3]; tmp[5].t *= q[3]; tmp[0].q = q[0]; tmp[1].q = q[1]; tmp[2].q = q[2]; tmp[3].q = q[0]; tmp[4].q = q[2]; tmp[5].q = q[3]; }else{ tmp[0].q = 1.0f; tmp[1].q = 1.0f; tmp[2].q = 1.0f; tmp[3].q = 1.0f; tmp[4].q = 1.0f; tmp[5].q = 1.0f; } return 0; } ////////////////////////////////////////////////////////////////////////////// void YglCachedQuadOffset(YglSprite * input, YglCache * cache, int cx, int cy, float sx, float sy ) { YglProgram * program; unsigned int x, y; texturecoordinate_struct *tmp; float * pos; float * vtxa; int vHeight; int prg = PG_NORMAL; if ((input->blendmode & 0x03) == 2) { prg = PG_VDP2_ADDBLEND; } if (input->linescreen){ prg = PG_LINECOLOR_INSERT; } program = YglGetProgram(input, prg); if (program == NULL) return; program->color_offset_val[0] = (float)(input->cor) / 255.0f; program->color_offset_val[1] = (float)(input->cog) / 255.0f; program->color_offset_val[2] = (float)(input->cob) / 255.0f; program->color_offset_val[3] = 0; x = cache->x; y = cache->y; // Vertex vHeight = input->vertices[5] - input->vertices[1]; pos = program->quads + program->currentQuad; pos[0] = (input->vertices[0] - cx) * sx; pos[1] = input->vertices[1] * sy; pos[2] = (input->vertices[2] - cx) * sx; pos[3] = input->vertices[3] * sy; pos[4] = (input->vertices[4] - cx) * sx; pos[5] = input->vertices[5] * sy; pos[6] = (input->vertices[0] - cx) * sx; pos[7] = (input->vertices[1]) * sy; pos[8] = (input->vertices[4] - cx)*sx; pos[9] = input->vertices[5] * sy; pos[10] = (input->vertices[6] - cx) * sx; pos[11] = input->vertices[7] * sy; // Color tmp = (texturecoordinate_struct *)(program->textcoords + (program->currentQuad * 2)); vtxa = (program->vertexAttribute + (program->currentQuad * 2)); memset(vtxa, 0, sizeof(float) * 24); program->currentQuad += 12; tmp[0].r = tmp[1].r = tmp[2].r = tmp[3].r = tmp[4].r = tmp[5].r = 0; // these can stay at 0 if (input->flip & 0x1) { tmp[0].s = tmp[3].s = tmp[5].s = (float)(x + input->w) - ATLAS_BIAS; tmp[1].s = tmp[2].s = tmp[4].s = (float)(x)+ATLAS_BIAS; } else { tmp[0].s = tmp[3].s = tmp[5].s = (float)(x)+ATLAS_BIAS; tmp[1].s = tmp[2].s = tmp[4].s = (float)(x + input->w) - ATLAS_BIAS; } if (input->flip & 0x2) { tmp[0].t = tmp[1].t = tmp[3].t = (float)(y + input->h - cy) - ATLAS_BIAS; tmp[2].t = tmp[4].t = tmp[5].t = (float)(y + input->h - (cy + vHeight)) + ATLAS_BIAS; } else { tmp[0].t = tmp[1].t = tmp[3].t = (float)(y + cy) + ATLAS_BIAS; tmp[2].t = tmp[4].t = tmp[5].t = (float)(y + (cy + vHeight)) - ATLAS_BIAS; } tmp[0].q = 1.0f; tmp[1].q = 1.0f; tmp[2].q = 1.0f; tmp[3].q = 1.0f; tmp[4].q = 1.0f; tmp[5].q = 1.0f; } void YglCachedQuad(YglSprite * input, YglCache * cache) { YglProgram * program; unsigned int x,y; texturecoordinate_struct *tmp; float q[4]; float * pos; float * vtxa; int prg = PG_NORMAL; if( (input->blendmode&0x03) == 2 ) { prg = PG_VDP2_ADDBLEND; }else if( input->blendmode == 0x80 ) { prg = PG_VFP1_HALFTRANS; }else if( input->priority == 8 ) { prg = PG_VDP1_NORMAL; } if (input->linescreen){ prg = PG_LINECOLOR_INSERT; } program = YglGetProgram(input,prg); if( program == NULL ) return; program->color_offset_val[0] = (float)(input->cor)/255.0f; program->color_offset_val[1] = (float)(input->cog)/255.0f; program->color_offset_val[2] = (float)(input->cob)/255.0f; program->color_offset_val[3] = 0; x = cache->x; y = cache->y; // Vertex pos = program->quads + program->currentQuad; pos[0] = input->vertices[0]; pos[1] = input->vertices[1]; pos[2] = input->vertices[2]; pos[3] = input->vertices[3]; pos[4] = input->vertices[4]; pos[5] = input->vertices[5]; pos[6] = input->vertices[0]; pos[7] = input->vertices[1]; pos[8] = input->vertices[4]; pos[9] = input->vertices[5]; pos[10] = input->vertices[6]; pos[11] = input->vertices[7]; // Color tmp = (texturecoordinate_struct *)(program->textcoords + (program->currentQuad * 2)); vtxa = (program->vertexAttribute + (program->currentQuad * 2)); memset(vtxa,0,sizeof(float)*24); program->currentQuad += 12; tmp[0].r = tmp[1].r = tmp[2].r = tmp[3].r = tmp[4].r = tmp[5].r = 0; // these can stay at 0 if (input->flip & 0x1) { tmp[0].s = tmp[3].s = tmp[5].s = (float)(x + input->w)-ATLAS_BIAS; tmp[1].s = tmp[2].s = tmp[4].s = (float)(x)+ATLAS_BIAS; } else { tmp[0].s = tmp[3].s = tmp[5].s = (float)(x)+ATLAS_BIAS; tmp[1].s = tmp[2].s = tmp[4].s = (float)(x + input->w)-ATLAS_BIAS; } if (input->flip & 0x2) { tmp[0].t = tmp[1].t = tmp[3].t = (float)(y + input->h)-ATLAS_BIAS; tmp[2].t = tmp[4].t = tmp[5].t = (float)(y)+ATLAS_BIAS; } else { tmp[0].t = tmp[1].t = tmp[3].t = (float)(y)+ATLAS_BIAS; tmp[2].t = tmp[4].t = tmp[5].t = (float)(y + input->h)-ATLAS_BIAS; } if( input->dst == 1 ) { YglCalcTextureQ(input->vertices,q); tmp[0].s *= q[0]; tmp[0].t *= q[0]; tmp[1].s *= q[1]; tmp[1].t *= q[1]; tmp[2].s *= q[2]; tmp[2].t *= q[2]; tmp[3].s *= q[0]; tmp[3].t *= q[0]; tmp[4].s *= q[2]; tmp[4].t *= q[2]; tmp[5].s *= q[3]; tmp[5].t *= q[3]; tmp[0].q = q[0]; tmp[1].q = q[1]; tmp[2].q = q[2]; tmp[3].q = q[0]; tmp[4].q = q[2]; tmp[5].q = q[3]; }else{ tmp[0].q = 1.0f; tmp[1].q = 1.0f; tmp[2].q = 1.0f; tmp[3].q = 1.0f; tmp[4].q = 1.0f; tmp[5].q = 1.0f; } } ////////////////////////////////////////////////////////////////////////////// void YglCacheQuadGrowShading(YglSprite * input, float * colors,YglCache * cache) { YglProgram * program; unsigned int x,y; texturecoordinate_struct *tmp; float q[4]; int prg = PG_VFP1_GOURAUDSAHDING; int currentpg = 0; float * vtxa; float *pos; if( (input->blendmode&0x03) == 2 ) { prg = PG_VDP2_ADDBLEND; }else if( input->blendmode == 0x80 ) { prg = PG_VFP1_GOURAUDSAHDING_HALFTRANS; } if (input->linescreen){ prg = PG_LINECOLOR_INSERT; } program = YglGetProgram(input,prg); if( program == NULL ) return; program->color_offset_val[0] = (float)(input->cor)/255.0f; program->color_offset_val[1] = (float)(input->cog)/255.0f; program->color_offset_val[2] = (float)(input->cob)/255.0f; program->color_offset_val[3] = 0; x = cache->x; y = cache->y; // Vertex pos = program->quads + program->currentQuad; pos[0] = input->vertices[0]; pos[1] = input->vertices[1]; pos[2] = input->vertices[2]; pos[3] = input->vertices[3]; pos[4] = input->vertices[4]; pos[5] = input->vertices[5]; pos[6] = input->vertices[0]; pos[7] = input->vertices[1]; pos[8] = input->vertices[4]; pos[9] = input->vertices[5]; pos[10] = input->vertices[6]; pos[11] = input->vertices[7]; // Color vtxa = (program->vertexAttribute + (program->currentQuad * 2)); if( colors == NULL ) { memset(vtxa,0,sizeof(float)*24); }else{ vtxa[0] = colors[0]; vtxa[1] = colors[1]; vtxa[2] = colors[2]; vtxa[3] = colors[3]; vtxa[4] = colors[4]; vtxa[5] = colors[5]; vtxa[6] = colors[6]; vtxa[7] = colors[7]; vtxa[8] = colors[8]; vtxa[9] = colors[9]; vtxa[10] = colors[10]; vtxa[11] = colors[11]; vtxa[12] = colors[0]; vtxa[13] = colors[1]; vtxa[14] = colors[2]; vtxa[15] = colors[3]; vtxa[16] = colors[8]; vtxa[17] = colors[9]; vtxa[18] = colors[10]; vtxa[19] = colors[11]; vtxa[20] = colors[12]; vtxa[21] = colors[13]; vtxa[22] = colors[14]; vtxa[23] = colors[15]; } // Texture tmp = (texturecoordinate_struct *)(program->textcoords + (program->currentQuad * 2)); program->currentQuad += 12; tmp[0].r = tmp[1].r = tmp[2].r = tmp[3].r = tmp[4].r = tmp[5].r = 0; // these can stay at 0 if (input->flip & 0x1) { tmp[0].s = tmp[3].s = tmp[5].s = (float)(x + input->w)-ATLAS_BIAS; tmp[1].s = tmp[2].s = tmp[4].s = (float)(x)+ATLAS_BIAS; } else { tmp[0].s = tmp[3].s = tmp[5].s = (float)(x)+ATLAS_BIAS; tmp[1].s = tmp[2].s = tmp[4].s = (float)(x + input->w)-ATLAS_BIAS; } if (input->flip & 0x2) { tmp[0].t = tmp[1].t = tmp[3].t = (float)(y + input->h)-ATLAS_BIAS; tmp[2].t = tmp[4].t = tmp[5].t = (float)(y)+ATLAS_BIAS; } else { tmp[0].t = tmp[1].t = tmp[3].t = (float)(y)+ATLAS_BIAS; tmp[2].t = tmp[4].t = tmp[5].t = (float)(y + input->h)-ATLAS_BIAS; } if( input->dst == 1 ) { YglCalcTextureQ(input->vertices,q); tmp[0].s *= q[0]; tmp[0].t *= q[0]; tmp[1].s *= q[1]; tmp[1].t *= q[1]; tmp[2].s *= q[2]; tmp[2].t *= q[2]; tmp[3].s *= q[0]; tmp[3].t *= q[0]; tmp[4].s *= q[2]; tmp[4].t *= q[2]; tmp[5].s *= q[3]; tmp[5].t *= q[3]; tmp[0].q = q[0]; tmp[1].q = q[1]; tmp[2].q = q[2]; tmp[3].q = q[0]; tmp[4].q = q[2]; tmp[5].q = q[3]; }else{ tmp[0].q = 1.0f; tmp[1].q = 1.0f; tmp[2].q = 1.0f; tmp[3].q = 1.0f; tmp[4].q = 1.0f; tmp[5].q = 1.0f; } } ////////////////////////////////////////////////////////////////////////////// void YglRenderVDP1(void) { YglLevel * level; GLuint cprg=0; int j; int status; if (_Ygl->pFrameBuffer != NULL) { _Ygl->pFrameBuffer = NULL; glBindBuffer(GL_PIXEL_PACK_BUFFER, _Ygl->vdp1pixelBufferID); glUnmapBuffer(GL_PIXEL_PACK_BUFFER); glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); } YGLLOG("YglRenderVDP1 %d, PTMR = %d\n", _Ygl->drawframe, Vdp1Regs->PTMR); level = &(_Ygl->levels[_Ygl->depth]); glDisable(GL_STENCIL_TEST); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, _Ygl->texture); if (YglTM->texture != NULL) { glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _Ygl->pixelBufferID); glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, YglTM->width, YglTM->yMax, GL_RGBA, GL_UNSIGNED_BYTE, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); YglTM->texture = NULL; } cprg = -1; glBindFramebuffer(GL_FRAMEBUFFER, _Ygl->vdp1fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _Ygl->vdp1FrameBuff[_Ygl->drawframe], 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _Ygl->rboid_depth); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _Ygl->rboid_stencil); status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if( status != GL_FRAMEBUFFER_COMPLETE ) { YGLLOG("YglRenderVDP1: Framebuffer status = %08X\n", status ); return; }else{ //YGLLOG("Framebuffer status OK = %08X\n", status ); } // Many regressions to Enable it //if( ((Vdp1Regs->TVMR & 0x08) && (Vdp1Regs->FBCR&0x03)==0x03) || ((Vdp1Regs->FBCR & 2) == 0) || Vdp1External.manualerase) { u16 color; int priority; u16 alpha; #if 0 h = (Vdp1Regs->EWRR & 0x1FF) + 1; if (h > vdp1height) h = vdp1height; w = ((Vdp1Regs->EWRR >> 6) & 0x3F8) + 8; if (w > vdp1width) w = vdp1width; if (vdp1pixelsize == 2) { for (i2 = (Vdp1Regs->EWLR & 0x1FF); i2 < h; i2++) { for (i = ((Vdp1Regs->EWLR >> 6) & 0x1F8); i < w; i++) ((u16 *)vdp1backframebuffer)[(i2 * vdp1width) + i] = Vdp1Regs->EWDR; } } else { for (i2 = (Vdp1Regs->EWLR & 0x1FF); i2 < h; i2++) { for (i = ((Vdp1Regs->EWLR >> 6) & 0x1F8); i < w; i++) vdp1backframebuffer[(i2 * vdp1width) + i] = Vdp1Regs->EWDR & 0xFF; } } #endif color = Vdp1Regs->EWDR; priority = 0; if (color & 0x8000) priority = Vdp2Regs->PRISA & 0x7; else { int shadow, colorcalc; Vdp1ProcessSpritePixel(Vdp2Regs->SPCTL & 0xF, &color, &shadow, &priority, &colorcalc); #ifdef WORDS_BIGENDIAN priority = ((u8 *)&Vdp2Regs->PRISA)[priority ^ 1] & 0x7; #else priority = ((u8 *)&Vdp2Regs->PRISA)[priority] & 0x7; #endif } if (color == 0) { alpha = 0; priority = 0; } else{ alpha = 0xF8; } alpha |= priority; glClearColor((color & 0x1F) / 31.0f, ((color >> 5) & 0x1F) / 31.0f, ((color >> 10) & 0x1F) / 31.0f, alpha / 255.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); Vdp1External.manualerase = 0; YGLLOG("YglRenderVDP1: clear %d\n", _Ygl->drawframe); } glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND); glCullFace(GL_FRONT_AND_BACK); glDisable(GL_CULL_FACE); for( j=0;j<(level->prgcurrent+1); j++ ) { if( level->prg[j].prgid != cprg ) { cprg = level->prg[j].prgid; glUseProgram(level->prg[j].prg); } if(level->prg[j].setupUniform) { level->prg[j].setupUniform((void*)&level->prg[j]); } if( level->prg[j].currentQuad != 0 ) { glUniformMatrix4fv(level->prg[j].mtxModelView, 1, GL_FALSE, (GLfloat*)&_Ygl->mtxModelView.m[0][0]); glVertexAttribPointer(level->prg[j].vertexp, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid *)level->prg[j].quads); glVertexAttribPointer(level->prg[j].texcoordp,4,GL_FLOAT,GL_FALSE,0,(GLvoid *)level->prg[j].textcoords ); if( level->prg[j].vaid != 0 ) { glVertexAttribPointer(level->prg[j].vaid,4, GL_FLOAT, GL_FALSE, 0, level->prg[j].vertexAttribute); } glDrawArrays(GL_TRIANGLES, 0, level->prg[j].currentQuad/2); level->prg[j].currentQuad = 0; } if( level->prg[j].cleanupUniform ) { level->prg[j].cleanupUniform((void*)&level->prg[j]); } } level->prgcurrent = 0; #if 0 if ( (((Vdp1Regs->TVMR & 0x08)==0) && ((Vdp1Regs->FBCR & 0x03)==0x03) ) ) { u32 current_drawframe = 0; current_drawframe = _Ygl->drawframe; _Ygl->drawframe = _Ygl->readframe; _Ygl->readframe = current_drawframe; Vdp1External.manualchange = 0; YGLLOG("YglRenderVDP1: swap drawframe =%d readframe = %d\n", _Ygl->drawframe, _Ygl->readframe); } #endif if ((((Vdp1Regs->TVMR & 0x08) == 0) && ((Vdp1Regs->FBCR & 0x03) == 0x03)) || ((Vdp1Regs->FBCR & 2) == 0) || Vdp1External.manualchange) { u32 current_drawframe = 0; current_drawframe = _Ygl->drawframe; _Ygl->drawframe = _Ygl->readframe; _Ygl->readframe = current_drawframe; Vdp1External.manualchange = 0; YGLLOG("YglRenderVDP1: swap drawframe =%d readframe = %d\n", _Ygl->drawframe, _Ygl->readframe); } // glFlush(); need?? glBindFramebuffer(GL_FRAMEBUFFER, 0); glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); } void YglDmyRenderVDP1(void) { Vdp1External.manualerase = 0; if ( (((Vdp1Regs->TVMR & 0x08)==0) && ((Vdp1Regs->FBCR & 0x03)==0x03) ) || ((Vdp1Regs->FBCR & 2) == 0) || Vdp1External.manualchange ) { u32 current_drawframe = 0; current_drawframe = _Ygl->drawframe; _Ygl->drawframe = _Ygl->readframe; _Ygl->readframe = current_drawframe; Vdp1External.manualchange = 0; YGLLOG("YglRenderVDP1: swap drawframe =%d readframe = %d\n", _Ygl->drawframe, _Ygl->readframe); } } void YglNeedToUpdateWindow() { _Ygl->bUpdateWindow = 1; } void YglSetVdp2Window() { int bwin0,bwin1; //if( _Ygl->bUpdateWindow && (_Ygl->win0_vertexcnt != 0 || _Ygl->win1_vertexcnt != 0 ) ) bwin0 = (Vdp2Regs->WCTLC >> 9) &0x01; bwin1 = (Vdp2Regs->WCTLC >> 11) &0x01; if( (_Ygl->win0_vertexcnt != 0 || _Ygl->win1_vertexcnt != 0 ) ) { Ygl_uniformWindow(&_Ygl->windowpg); glUniformMatrix4fv( _Ygl->windowpg.mtxModelView, 1, GL_FALSE, (GLfloat*) &_Ygl->mtxModelView.m[0][0] ); // glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE); glDepthMask(GL_FALSE); glDisable(GL_TEXTURE_2D); glDisable(GL_DEPTH_TEST); //glClearStencil(0); //glClear(GL_STENCIL_BUFFER_BIT); glEnable(GL_STENCIL_TEST); glDisable(GL_TEXTURE_2D); glStencilOp(GL_REPLACE,GL_REPLACE,GL_REPLACE); if( _Ygl->win0_vertexcnt != 0 ) { glStencilMask(0x01); glStencilFunc(GL_ALWAYS,0x01,0x01); glVertexAttribPointer(_Ygl->windowpg.vertexp,2,GL_INT, GL_FALSE,0,(GLvoid *)_Ygl->win0v ); glDrawArrays(GL_TRIANGLE_STRIP,0,_Ygl->win0_vertexcnt); } if( _Ygl->win1_vertexcnt != 0 ) { glStencilMask(0x02); glStencilFunc(GL_ALWAYS,0x02,0x02); glVertexAttribPointer(_Ygl->windowpg.vertexp,2,GL_INT, GL_FALSE,0,(GLvoid *)_Ygl->win1v ); glDrawArrays(GL_TRIANGLE_STRIP,0,_Ygl->win1_vertexcnt); } glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE); glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST); glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP); glStencilFunc(GL_ALWAYS,0,0xFF); glStencilMask(0xFFFFFFFF); _Ygl->bUpdateWindow = 0; } return; } void YglRenderFrameBuffer( int from , int to ) { GLint vertices[12]; GLfloat texcord[12]; float offsetcol[4]; int bwin0,bwin1,logwin0,logwin1,winmode; // Out of range, do nothing if( _Ygl->vdp1_maxpri < from ) return; if( _Ygl->vdp1_minpri > to ) return; //YGLLOG("YglRenderFrameBuffer: %d to %d\n", from , to ); offsetcol[0] = vdp1cor / 255.0f; offsetcol[1] = vdp1cog / 255.0f; offsetcol[2] = vdp1cob / 255.0f; offsetcol[3] = 0.0f; if ( (Vdp2Regs->CCCTL & 0x540) == 0x140 ){ // Sprite Add Color Ygl_uniformVDP2DrawFramebuffer_addcolor(&_Ygl->renderfb, (float)(from) / 10.0f, (float)(to) / 10.0f, offsetcol); }else if (Vdp2Regs->LNCLEN & 0x20){ Ygl_uniformVDP2DrawFramebuffer_linecolor(&_Ygl->renderfb, (float)(from) / 10.0f, (float)(to) / 10.0f, offsetcol); } else{ Ygl_uniformVDP2DrawFramebuffer(&_Ygl->renderfb, (float)(from) / 10.0f, (float)(to) / 10.0f, offsetcol); } glBindTexture(GL_TEXTURE_2D, _Ygl->vdp1FrameBuff[_Ygl->readframe]); //glBindTexture(GL_TEXTURE_2D, _Ygl->vdp1FrameBuff[_Ygl->drawframe]); YGLLOG("YglRenderFrameBuffer: %d to %d: fb %d\n", from, to, _Ygl->readframe); // Window Mode bwin0 = (Vdp2Regs->WCTLC >> 9) &0x01; logwin0 = (Vdp2Regs->WCTLC >> 8) & 0x01; bwin1 = (Vdp2Regs->WCTLC >> 11) &0x01; logwin1 = (Vdp2Regs->WCTLC >> 10) & 0x01; winmode = (Vdp2Regs->WCTLC >> 15 ) & 0x01; if( bwin0 || bwin1 ) { glEnable(GL_STENCIL_TEST); glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP); if( bwin0 && !bwin1 ) { if( logwin0 ) { glStencilFunc(GL_EQUAL,0x01,0x01); }else{ glStencilFunc(GL_NOTEQUAL,0x01,0x01); } }else if( !bwin0 && bwin1 ) { if( logwin1 ) { glStencilFunc(GL_EQUAL,0x02,0x02); }else{ glStencilFunc(GL_NOTEQUAL,0x02,0x02); } }else if( bwin0 && bwin1 ) { // and if( winmode == 0x0 ) { if (logwin0 == 1 && logwin1 == 1){ // show inside glStencilFunc(GL_EQUAL, 0x03, 0x03); } else if(logwin0 == 0 && logwin1 == 0) { glStencilFunc(GL_NOTEQUAL, 0x03, 0x03); } else{ glStencilFunc(GL_ALWAYS, 0x00, 0x00); } // OR }else if( winmode == 0x01 ) { // OR if (logwin0 == 1 && logwin1 == 1){ // show inside glStencilFunc(GL_LEQUAL, 0x01, 0x03); } else if (logwin0 == 0 && logwin1 == 0) { glStencilFunc(GL_GREATER, 0x01, 0x03); } else{ glStencilFunc(GL_ALWAYS, 0x00, 0x00); } } } } // render vertices[0] = 0; vertices[1] = 0; vertices[2] = _Ygl->rwidth+1; vertices[3] = 0; vertices[4] = _Ygl->rwidth+1; vertices[5] = _Ygl->rheight+1; vertices[6] = 0; vertices[7] = 0; vertices[8] = _Ygl->rwidth+1; vertices[9] = _Ygl->rheight+1; vertices[10] = 0; vertices[11] = _Ygl->rheight+1; texcord[0] = 0.0f; texcord[1] = 1.0f; texcord[2] = 1.0f; texcord[3] = 1.0f; texcord[4] = 1.0f; texcord[5] = 0.0f; texcord[6] = 0.0f; texcord[7] = 1.0f; texcord[8] = 1.0f; texcord[9] = 0.0f; texcord[10] = 0.0f; texcord[11] = 0.0f; glUniformMatrix4fv( _Ygl->renderfb.mtxModelView, 1, GL_FALSE, (GLfloat*)&_Ygl->mtxModelView.m[0][0] ); glVertexAttribPointer(_Ygl->renderfb.vertexp,2,GL_INT, GL_FALSE,0,(GLvoid *)vertices ); glVertexAttribPointer(_Ygl->renderfb.texcoordp,2,GL_FLOAT,GL_FALSE,0,(GLvoid *)texcord ); glDrawArrays(GL_TRIANGLES, 0, 6); if( bwin0 || bwin1 ) { glDisable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS,0,0xFF); } } void YglSetClearColor(float r, float g, float b){ _Ygl->clear_r = r; _Ygl->clear_g = g; _Ygl->clear_b = b; } void YglRender(void) { YglLevel * level; GLuint cprg=0; int from = 0; int to = 0; YglMatrix mtx; YglMatrix dmtx; unsigned int i,j; YGLLOG("YglRender\n"); glBindFramebuffer(GL_FRAMEBUFFER,0); glClearColor(_Ygl->clear_r, _Ygl->clear_g, _Ygl->clear_b, 1.0f); glClearDepthf(0.0f); glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, _Ygl->texture); if (YglTM->texture != NULL) { glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _Ygl->pixelBufferID); glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, YglTM->width, YglTM->yMax, GL_RGBA, GL_UNSIGNED_BYTE, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); YglTM->texture = NULL; } #if 0 // Test ShaderDrawTest(); #else glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //YglRenderVDP1(); YglLoadIdentity(&mtx); cprg = -1; YglSetVdp2Window(); YglTranslatef(&mtx,0.0f,0.0f,-1.0f); for(i = 0;i < _Ygl->depth;i++) { level = _Ygl->levels + i; if( level->blendmode != 0 ) { to = i; glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); if(Vdp1External.disptoggle&0x01) YglRenderFrameBuffer(from, to); from = to; // clean up cprg = -1; glUseProgram(0); glBindTexture(GL_TEXTURE_2D, _Ygl->texture); } glDisable(GL_STENCIL_TEST); for( j=0;j<(level->prgcurrent+1); j++ ) { if( level->prg[j].prgid != cprg ) { cprg = level->prg[j].prgid; glUseProgram(level->prg[j].prg); } if(level->prg[j].setupUniform) { level->prg[j].setupUniform((void*)&level->prg[j]); } YglMatrixMultiply(&dmtx, &mtx, &_Ygl->mtxModelView); if( level->prg[j].currentQuad != 0 ) { #if 0 if (level->blendmode == 0){ glDisable(GL_BLEND); } else if (level->blendmode == 1){ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else if (level->blendmode == 2){ glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); } #endif glUniformMatrix4fv(level->prg[j].mtxModelView, 1, GL_FALSE, (GLfloat*)&dmtx.m[0][0]); glVertexAttribPointer(level->prg[j].vertexp,2,GL_FLOAT, GL_FALSE,0,(GLvoid *)level->prg[j].quads ); glVertexAttribPointer(level->prg[j].texcoordp,4,GL_FLOAT,GL_FALSE,0,(GLvoid *)level->prg[j].textcoords ); if( level->prg[j].vaid != 0 ) { glVertexAttribPointer(level->prg[j].vaid,4, GL_FLOAT, GL_FALSE, 0, level->prg[j].vertexAttribute); } glDrawArrays(GL_TRIANGLES, 0, level->prg[j].currentQuad/2); level->prg[j].currentQuad = 0; } if( level->prg[j].cleanupUniform ) { level->prg[j].cleanupUniform((void*)&level->prg[j]); } } level->prgcurrent = 0; YglTranslatef(&mtx,0.0f,0.0f,0.1f); } glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); if (Vdp1External.disptoggle & 0x01) YglRenderFrameBuffer(from, 8); #endif glDisable(GL_TEXTURE_2D); glUseProgram(0); glGetError(); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER,0); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glDisableVertexAttribArray(2); glDisable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); YuiSwapBuffers(); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _Ygl->pixelBufferID); YglTM->texture = (unsigned int*)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, 2048 * 1024 * 4, GL_MAP_WRITE_BIT); if (YglTM->texture == NULL){ abort(); } #if 0 if ( ((Vdp1Regs->FBCR & 2) == 0) ) { YabThreadLock(_Ygl->mutex); u32 current_drawframe = 0; current_drawframe = _Ygl->drawframe; _Ygl->drawframe = _Ygl->readframe; _Ygl->readframe = current_drawframe; Vdp1External.manualchange = 0; YGLLOG("YglRenderVDP1: swap drawframe =%d readframe = %d\n", _Ygl->drawframe, _Ygl->readframe); YabThreadUnLock(_Ygl->mutex); } #endif return; } ////////////////////////////////////////////////////////////////////////////// void YglReset(void) { YglLevel * level; unsigned int i,j; YglTMReset(); for(i = 0;i < (_Ygl->depth+1) ;i++) { level = _Ygl->levels + i; level->blendmode = 0; level->prgcurrent = 0; level->uclipcurrent = 0; level->ux1 = 0; level->uy1 = 0; level->ux2 = 0; level->uy2 = 0; for( j=0; j< level->prgcount; j++ ) { _Ygl->levels[i].prg[j].currentQuad = 0; } } _Ygl->msglength = 0; } ////////////////////////////////////////////////////////////////////////////// void YglShowTexture(void) { _Ygl->st = !_Ygl->st; } u32 * YglGetLineColorPointer(){ int error; if (_Ygl->lincolor_tex == 0){ glGetError(); glGenTextures(1, &_Ygl->lincolor_tex); glGenBuffers(1, &_Ygl->linecolor_pbo); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _Ygl->linecolor_pbo); glBufferData(GL_PIXEL_UNPACK_BUFFER, 512 * 4, NULL, GL_STREAM_DRAW); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); glBindTexture(GL_TEXTURE_2D, _Ygl->lincolor_tex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); if ((error = glGetError()) != GL_NO_ERROR) { YGLLOG("Fail to init lincolor_tex %04X", error); return NULL; } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } glBindTexture(GL_TEXTURE_2D, _Ygl->lincolor_tex); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _Ygl->linecolor_pbo); _Ygl->lincolor_buf = (u32 *)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, 512 * 4, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); if ((error = glGetError()) != GL_NO_ERROR) { YGLLOG("Fail to init YglTM->texture %04X", error); return NULL; } glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); return _Ygl->lincolor_buf; } void YglSetLineColor(u32 * pbuf, int size){ glBindTexture(GL_TEXTURE_2D, _Ygl->lincolor_tex); //if (_Ygl->lincolor_buf == pbuf) { glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _Ygl->linecolor_pbo); glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, 1, GL_RGBA, GL_UNSIGNED_BYTE, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); _Ygl->lincolor_buf = NULL; //} glBindTexture(GL_TEXTURE_2D, 0 ); return; } ////////////////////////////////////////////////////////////////////////////// void YglChangeResolution(int w, int h) { YglLoadIdentity(&_Ygl->mtxModelView); YglOrtho(&_Ygl->mtxModelView, 0.0f, (float)w, (float)h, 0.0f, 10.0f, 0.0f); if( _Ygl->rwidth != w || _Ygl->rheight != h ) { if (_Ygl->smallfbo != 0) { glDeleteFramebuffers(1, &_Ygl->smallfbo); _Ygl->smallfbo = 0; glDeleteTextures(1, &_Ygl->smallfbotex); _Ygl->smallfbotex = 0; glDeleteBuffers(1, &_Ygl->vdp1pixelBufferID); _Ygl->vdp1pixelBufferID = 0; _Ygl->pFrameBuffer = NULL; } } _Ygl->rwidth = w; _Ygl->rheight = h; } ////////////////////////////////////////////////////////////////////////////// void YglOnScreenDebugMessage(char *string, ...) { va_list arglist; va_start(arglist, string); vsprintf(_Ygl->message, string, arglist); va_end(arglist); _Ygl->msglength = (int)strlen(_Ygl->message); } #endif yabause-0.9.15/src/CMakeLists.txt000755 001750 001750 00000061072 12757373537 020634 0ustar00guillaumeguillaume000000 000000 project(yabause) include (CheckCSourceCompiles) include(CheckFunctionExists) include(CheckIncludeFile) cmake_minimum_required(VERSION 2.8) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/CMakeTests) set(yabause_HEADERS bios.h cdbase.h cheat.h coffelf.h core.h cs0.h cs1.h cs2.h debug.h error.h gameinfo.h japmodem.h m68kcore.h m68kd.h memory.h movie.h netlink.h osdcore.h peripheral.h profile.h scsp.h scspdsp.h scu.h sh2core.h sh2d.h sh2iasm.h sh2idle.h sh2int.h sh2trace.h smpc.h sock.h threads.h titan/titan.h vdp1.h vdp2.h vdp2debug.h vidogl.h vidshared.h vidsoft.h yabause.h ygl.h yui.h sh2cache.h sh7034.h ygr.h cd_drive.h tsunami/yab_tsunami.h mpeg_card.h) set(yabause_SOURCES bios.c cdbase.c cheat.c coffelf.c cs0.c cs1.c cs2.c debug.c error.c gameinfo.c japmodem.c m68kcore.c m68kd.c memory.c movie.c netlink.c osdcore.c peripheral.c profile.c scspdsp.c scu.c sh2core.c sh2d.c sh2iasm.c sh2idle.c sh2int.c sh2trace.c smpc.c snddummy.c titan/titan.c vdp1.c vdp2.c vdp2debug.c vidogl.c vidshared.c vidsoft.c yabause.c ygles.c yglshaderes.c sh2cache.c sh7034.c ygr.c cd_drive.c tsunami/yab_tsunami.c tsunami/Tsunami.c mpeg_card.c) option(YAB_USE_CXX "Allow C++ in the emulation core.") if (YAB_USE_CXX) set(yabause_SOURCES ${yabause_SOURCES} yglcache.cpp) else() set(yabause_SOURCES ${yabause_SOURCES} yglcache.c) endif() option(YAB_WANT_MPEG "Enable MPEG decoding" OFF) if(YAB_WANT_MPEG) find_package(FFmpeg) if(FFMPEG_FOUND) add_definitions(-DHAVE_MPEG=1) include_directories(${FFMPEG_INCLUDE_DIRS}) set(YABAUSE_LIBRARIES ${YABAUSE_LIBRARIES} ${FFMPEG_LIBRARIES}) endif() endif() option(YAB_USE_SSF "Include SSF player." ON) if (YAB_USE_SSF) find_package(ZLIB) if (ZLIB_FOUND) add_definitions(-DYAB_WANT_SSF=1) include_directories(${ZLIB_INCLUDE_DIRS}) set(YABAUSE_LIBRARIES ${YABAUSE_LIBRARIES} ${ZLIB_LIBRARIES}) set(yabause_SOURCES ${yabause_SOURCES} aosdk/corlett.c aosdk/eng_ssf.c aosdk/ssf.c) set(yabause_HEADERS ${yabause_HEADERS} aosdk/ao.h aosdk/corlett.h aosdk/ssf.h) endif() endif() # new SCSP option(YAB_USE_SCSP2 "Use the new SCSP implementation.") if (YAB_USE_SCSP2) add_definitions(-DUSE_SCSP2=1) set(yabause_SOURCES ${yabause_SOURCES} scsp2.c) set(yabause_HEADERS ${yabause_HEADERS} scsp2.h) else() set(yabause_SOURCES ${yabause_SOURCES} scsp.c) endif() # Enable SCSP MIDI hooks in sound interface option(YAB_USE_SCSPMIDI "Enable SCSP Midi support") if (YAB_USE_SCSPMIDI) add_definitions(-DUSE_SCSPMIDI=1) endif() # disable strdup warning in MSVC if (MSVC) add_definitions(/wd4996) endif () # math library if (UNIX) set(YABAUSE_LIBRARIES ${YABAUSE_LIBRARIES} "m -pthread") endif() # Bigendian include(TestBigEndian) test_big_endian(WORDS_BIGENDIAN) if (WORDS_BIGENDIAN) add_definitions(-DWORDS_BIGENDIAN=1) endif (WORDS_BIGENDIAN) include(CheckCSourceCompiles) # variadic macros check_c_source_compiles("#define MACRO(...) puts(__VA_ARGS__) int main(int argc, char ** argv) { MACRO(\"foo\"); }" VARIADIC_MACROS_OK) if (VARIADIC_MACROS_OK) add_definitions(-DHAVE_C99_VARIADIC_MACROS=1) endif (VARIADIC_MACROS_OK) # gettimeofday check_function_exists(gettimeofday GETTIMEOFDAY_OK) if (GETTIMEOFDAY_OK) add_definitions(-DHAVE_GETTIMEOFDAY=1) endif () # floorf set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} "-lm") check_function_exists(floorf FLOORF_OK) if (FLOORF_OK) add_definitions(-DHAVE_FLOORF=1) endif () # _wfopen check_function_exists(_wfopen WFOPEN_OK) if (WFOPEN_OK) add_definitions(-DHAVE_WFOPEN=1) endif () # stricmp/strcasecmp check_function_exists(strcasecmp STRCASECMP_OK) if (STRCASECMP_OK) add_definitions(-DHAVE_STRCASECMP=1) endif () check_function_exists(stricmp STRICMP_OK) if (STRICMP_OK) add_definitions(-DHAVE_STRICMP=1) endif () # __builtin_bswap16 check_c_source_compiles ( " int main(void) { return !__builtin_bswap16(0xabcd) == 0xcdab; } " BSWAP16_OK) if (BSWAP16_OK) add_definitions(-DHAVE_BUILTIN_BSWAP16=1) endif() # __builtin_bswap32 check_c_source_compiles ( " int main(void) { return !__builtin_bswap32(0xdeadbeef) == 0xefbeadde; } " BSWAP32_OK) if (BSWAP32_OK) add_definitions(-DHAVE_BUILTIN_BSWAP32=1) endif() # sys/time.h check_include_file("sys/time.h" SYSTIME_OK) if (SYSTIME_OK) add_definitions(-DHAVE_SYS_TIME_H=1) endif() # Find stdint.h check_include_file("stdint.h" STDINT_H_FOUND) if (STDINT_H_FOUND) add_definitions(-DHAVE_STDINT_H=1) endif() # 16BPP set(YAB_RGB "" CACHE STRING "Bit configuration of pixels in the display buffer.") if (YAB_RGB STREQUAL "555") add_definitions(-DUSE_16BPP=1 -DUSE_RGB_555=1) elseif (YAB_RGB STREQUAL "565") add_definitions(-DUSE_16BPP=1 -DUSE_RGB_565=1) endif () # OpenGL option(YAB_WANT_OPENGL "use OpenGL for video output (most ports require it)" ON) if (YAB_WANT_OPENGL AND (YAB_RGB STREQUAL "")) include(FindOpenGL) if (OPENGL_FOUND) add_definitions(-DHAVE_LIBGL=1) set(YABAUSE_LIBRARIES ${YABAUSE_LIBRARIES} ${OPENGL_LIBRARIES}) include(FindGLUT) if (GLUT_FOUND) message (WARNING "Deprecated Glut found. Support will be removed in the future. ") include_directories(${GLUT_INCLUDE_DIR}) add_definitions(-DHAVE_LIBGLUT=1) set(YABAUSE_LIBRARIES ${YABAUSE_LIBRARIES} ${GLUT_LIBRARIES}) endif() # glXGetProcAddress set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${OPENGL_LIBRARIES}) check_function_exists(glXGetProcAddress GLXGETPROCADDRESS_OK) if (GLXGETPROCADDRESS_OK) add_definitions(-DHAVE_GLXGETPROCADDRESS=1) endif() add_definitions(-D_OGL3_) include(FindGLEW) add_definitions(-D_USEGLEW_) if (GLEW_FOUND) include_directories( ${GLEW_INCLUDE_DIRS}) set(YABAUSE_LIBRARIES ${YABAUSE_LIBRARIES} ${GLEW_LIBRARIES}) else() add_definitions(-DGLEW_STATIC) include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/gllibs/include/ ) set(yabause_SOURCES ${yabause_SOURCES} gllibs/glew/glew.c) endif() endif(OPENGL_FOUND) endif () # SDL option(YAB_WANT_SDL "use SDL cores if available" ON) if (YAB_WANT_SDL) include(FindSDL2 OPTIONAL) if (SDL2_FOUND) add_definitions(-DHAVE_LIBSDL2=1) include_directories(${SDL2_INCLUDE_DIR}) set(YABAUSE_LIBRARIES ${YABAUSE_LIBRARIES} ${SDL2_LIBRARY}) else() include(FindSDL) if (SDL_FOUND) message (WARNING "Deprecated version of SDL found. Support will be removed in the future. ") include_directories(${SDL_INCLUDE_DIR}) set(YABAUSE_LIBRARIES ${YABAUSE_LIBRARIES} ${SDL_LIBRARY}) endif() endif() if (SDL_FOUND OR SDL2_FOUND) add_definitions(-DHAVE_LIBSDL=1) set(yabause_SOURCES ${yabause_SOURCES} persdljoy.c sndsdl.c) set(yabause_HEADERS ${yabause_HEADERS} persdljoy.h sndsdl.h) endif() endif() # OpenAL option(YAB_WANT_OPENAL "use OpenAL sound core if available" ON) if (YAB_WANT_OPENAL) include(FindOpenAL) if (OPENAL_FOUND) find_package(Threads) add_definitions(-DHAVE_LIBAL=1) include_directories(${OPENAL_INCLUDE_DIR}) set(yabause_SOURCES ${yabause_SOURCES} sndal.c) set(yabause_HEADERS ${yabause_HEADERS} sndal.h) set(YABAUSE_LIBRARIES ${YABAUSE_LIBRARIES} ${OPENAL_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) endif (OPENAL_FOUND) endif (YAB_WANT_OPENAL) # OpenSL (Android) option(YAB_WANT_OPENSL "use OpenSL sound core (for Android port)" ON) # mini18n find_path(MINI18N_INCLUDE_DIR mini18n.h) find_library(MINI18N_LIBRARY mini18n) if (NOT MINI18N_INCLUDE_DIR STREQUAL "MINI18N_INCLUDE_DIR-NOTFOUND" AND NOT MINI18N_LIBRARY STREQUAL "MINI18N_LIBRARY-NOTFOUND") set(MINI18N_FOUND TRUE) include_directories(${MINI18N_INCLUDE_DIR}) add_definitions(-DHAVE_LIBMINI18N=1) set(YABAUSE_LIBRARIES ${YABAUSE_LIBRARIES} ${MINI18N_LIBRARY}) endif (NOT MINI18N_INCLUDE_DIR STREQUAL "MINI18N_INCLUDE_DIR-NOTFOUND" AND NOT MINI18N_LIBRARY STREQUAL "MINI18N_LIBRARY-NOTFOUND") # xrandr if (NOT APPLE) find_library(XRANDR_LIBRARY Xrandr) if(XRANDR_LIBRARY) add_definitions(-DHAVE_LIBXRANDR=1) set(yabause_SOURCES ${yabause_SOURCES} scr-x.c) set(yabause_HEADERS ${yabause_HEADERS} screen.h) set(YABAUSE_LIBRARIES ${YABAUSE_LIBRARIES} Xrandr X11) endif() endif() if (MINI18N_FOUND) if (UNIX) add_definitions(-DYTSDIR=\"${CMAKE_INSTALL_PREFIX}/share/${YAB_PACKAGE}/yts\") elseif (WIN32) add_definitions(-DYTSDIR=\"trans\") endif() endif() # APPLE // not necessary mac os x, but i don't care ;) if (APPLE) FIND_LIBRARY(COREFOUNDATION_LIBRARY NAMES CoreFoundation ) FIND_LIBRARY(IOKIT_LIBRARY NAMES IOKit ) set(yabause_SOURCES ${yabause_SOURCES} macjoy.c permacjoy.c cd-macosx.c sndmac.c) set(yabause_HEADERS ${yabause_HEADERS} macjoy.h permacjoy.h sndmac.h) set(YABAUSE_LIBRARIES ${YABAUSE_LIBRARIES} ${COREFOUNDATION_LIBRARY} ${IOKIT_LIBRARY}) check_function_exists(glBindRenderbuffer HAVE_FBO) if (HAVE_FBO) add_definitions(-DHAVE_FBO=1) endif() endif (APPLE) # Visual Studio if (MSVC) # Find DDK if (EXISTS "$ENV{SYSTEMDRIVE}/WINDDK/3790.1830/") set(DDK_DIR "$ENV{SYSTEMDRIVE}/WINDDK/3790.1830/") elseif (EXISTS "$ENV{SYSTEMDRIVE}/WINDDK/6000/") set(DDK_DIR "$ENV{SYSTEMDRIVE}/WINDDK/6000/") elseif (EXISTS "$ENV{SYSTEMDRIVE}/WINDDK/7600.16385.0/") set(DDK_DIR "$ENV{SYSTEMDRIVE}/WINDDK/7600.16385.0/") endif (EXISTS "$ENV{SYSTEMDRIVE}/WINDDK/3790.1830/") add_definitions(-DHAVE_C99_VARIADIC_MACROS -D_CRT_SECURE_NO_WARNINGS -DC68K_NO_JUMP_TABLE -D_UNICODE -DUNICODE) endif (MSVC) if (WIN32) # Windows ddk option(YAB_WANT_DDK "Use the real DDK instead of the built-in one") if(YAB_WANT_DDK) message (WARNING "Windows DDK/WDK use is deprecated. Support will be removed in the future. ") # Find ntddcdrm.h find_path(ntddcdrm_INCLUDE_DIR ntddcdrm.h PATHS "${DDK_DIR}" "${DDK_DIR}/inc" PATH_SUFFIXES ddk api) if (ntddcdrm_INCLUDE_DIR) include_directories(${ntddcdrm_INCLUDE_DIR}) message(STATUS "Found ntddcdrm.h: ${ntddcdrm_INCLUDE_DIR}") add_definitions(-DHAVE_NTDDCDRM=1) else (ntddcdrm_INCLUDE_DIR) message(STATUS "Could not find ntddcdrm.h") endif (ntddcdrm_INCLUDE_DIR) endif(YAB_WANT_DDK) set(yabause_SOURCES ${yabause_SOURCES} cd-windows.c) option(YAB_WANT_DIRECTSOUND "use DirectX sound core if available") option(YAB_WANT_DIRECTINPUT "use DirectX input core if available") # Direct X if (YAB_WANT_DIRECTSOUND OR YAB_WANT_DIRECTINPUT) find_path(DirectX_INCLUDE_DIR dxerr9.h "$ENV{DXSDK_DIR}/Include") if (NOT DirectX_INCLUDE_DIR) find_path(DirectX_INCLUDE_DIR "dxerr.h" "$ENV{DXSDK_DIR}/Include") if (DirectX_INCLUDE_DIR) set(DXERRH_IS_BROKEN 1 CACHE INTERNAL "dxerr is broken") endif (DirectX_INCLUDE_DIR) endif(NOT DirectX_INCLUDE_DIR) message (STATUS "system processor = ${CMAKE_SYSTEM_PROCESSOR}") if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "AMD64") set (DIRECTX_SEARCH_PATH "$ENV{DXSDK_DIR}/Lib/x64") else() set (DIRECTX_SEARCH_PATH "$ENV{DXSDK_DIR}/Lib/x86") endif() find_library(DirectX_GUID_LIBRARY dxguid "${DIRECTX_SEARCH_PATH}" "$ENV{DXSDK_DIR}/Lib") if (YAB_WANT_DIRECTINPUT) find_library(DirectX_INPUT8_LIBRARY dinput8 "${DIRECTX_SEARCH_PATH}" "$ENV{DXSDK_DIR}/Lib") find_library(DirectX_XINPUT_LIBRARY xinput "${DIRECTX_SEARCH_PATH}" "$ENV{DXSDK_DIR}/Lib") endif(YAB_WANT_DIRECTINPUT) if (YAB_WANT_DIRECTSOUND) find_library(DirectX_SOUND_LIBRARY dsound "${DIRECTX_SEARCH_PATH}" "$ENV{DXSDK_DIR}/Lib") endif(YAB_WANT_DIRECTSOUND) if (DXERRH_IS_BROKEN) find_library(DirectX_ERR_LIBRARY dxerr "${DIRECTX_SEARCH_PATH}" "$ENV{DXSDK_DIR}/Lib") elseif(MINGW) find_library(DirectX_ERR_LIBRARY dxerr8 "${DIRECTX_SEARCH_PATH}" "$ENV{DXSDK_DIR}/Lib") else() find_library(DirectX_ERR_LIBRARY dxerr9 "${DIRECTX_SEARCH_PATH}" "$ENV{DXSDK_DIR}/Lib") endif() if (DirectX_INCLUDE_DIR AND DirectX_GUID_LIBRARY AND DirectX_ERR_LIBRARY) include_directories(${DirectX_INCLUDE_DIR}) set(YABAUSE_LIBRARIES ${YABAUSE_LIBRARIES} ${DirectX_GUID_LIBRARY} ${DirectX_ERR_LIBRARY}) if (YAB_WANT_DIRECTINPUT AND DirectX_INPUT8_LIBRARY) add_definitions(-DHAVE_DIRECTINPUT) set(yabause_SOURCES ${yabause_SOURCES} perdx.c) set(yabause_HEADERS ${yabause_HEADERS} perdx.h) set(YABAUSE_LIBRARIES ${YABAUSE_LIBRARIES} ${DirectX_INPUT8_LIBRARY}) if (DirectX_XINPUT_LIBRARY) add_definitions(-DHAVE_XINPUT) set(YABAUSE_LIBRARIES ${YABAUSE_LIBRARIES} ${DirectX_XINPUT_LIBRARY} wbemuuid) endif() endif () if (YAB_WANT_DIRECTSOUND AND DirectX_SOUND_LIBRARY) add_definitions(-DHAVE_DIRECTSOUND) set(yabause_SOURCES ${yabause_SOURCES} snddx.c) set(yabause_HEADERS ${yabause_HEADERS} snddx.h) set(YABAUSE_LIBRARIES ${YABAUSE_LIBRARIES} ${DirectX_SOUND_LIBRARY}) endif () if (DXERRH_IS_BROKEN) add_definitions(-DDXERRH_IS_BROKEN) message(STATUS "Using work-around for dxerr.h") set(yabause_HEADERS ${yabause_HEADERS} dx.h) endif(DXERRH_IS_BROKEN) endif (DirectX_INCLUDE_DIR AND DirectX_GUID_LIBRARY AND DirectX_ERR_LIBRARY) endif (YAB_WANT_DIRECTSOUND OR YAB_WANT_DIRECTINPUT) if (YAB_NETWORK OR YAB_WANT_GDBSTUB) # Add Winsock if necessary set(YABAUSE_LIBRARIES ${YABAUSE_LIBRARIES} "wsock32") set(YABAUSE_LIBRARIES ${YABAUSE_LIBRARIES} "ws2_32") endif() if (YAB_USE_SCSPMIDI) set(YABAUSE_LIBRARIES ${YABAUSE_LIBRARIES} winmm) endif() endif (WIN32) option(YAB_WANT_ARM7 "Build a binary with arm7 support") # SH2 dynamic recompiler message(STATUS "CMAKE_SYSTEM_NAME ${CMAKE_SYSTEM_NAME}") message(STATUS "CMAKE_SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR}") option(SH2_DYNAREC "SH2 dynamic recompiler" ON) if (SH2_DYNAREC) if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "i686") enable_language(ASM-ATT) set(yabause_SOURCES ${yabause_SOURCES} sh2_dynarec/sh2_dynarec.c sh2_dynarec/linkage_x86.s) set(yabause_HEADERS ${yabause_HEADERS} sh2_dynarec/sh2_dynarec.h) set_source_files_properties(sh2_dynarec/sh2_dynarec.c PROPERTIES COMPILE_FLAGS "-Wno-pointer-to-int-cast -Wno-int-to-pointer-cast") add_definitions(-DSH2_DYNAREC=1) endif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "i686") if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64") enable_language(ASM-ATT) set(yabause_SOURCES ${yabause_SOURCES} sh2_dynarec/sh2_dynarec.c sh2_dynarec/linkage_x64.s) set(yabause_HEADERS ${yabause_HEADERS} sh2_dynarec/sh2_dynarec.h) set_source_files_properties(sh2_dynarec/sh2_dynarec.c PROPERTIES COMPILE_FLAGS "-Wno-pointer-to-int-cast -Wno-int-to-pointer-cast") add_definitions(-DSH2_DYNAREC=1) endif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64") if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv5tel") enable_language(ASM-ATT) set(yabause_SOURCES ${yabause_SOURCES} sh2_dynarec/sh2_dynarec.c sh2_dynarec/linkage_arm.s) set(yabause_HEADERS ${yabause_HEADERS} sh2_dynarec/sh2_dynarec.h) set_source_files_properties(sh2_dynarec/sh2_dynarec.c PROPERTIES COMPILE_FLAGS "-Wno-pointer-to-int-cast -Wno-int-to-pointer-cast") add_definitions(-DSH2_DYNAREC=1) endif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv5tel") if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv7l") enable_language(ASM-ATT) set(yabause_SOURCES ${yabause_SOURCES} sh2_dynarec/sh2_dynarec.c sh2_dynarec/linkage_arm.s) set(yabause_HEADERS ${yabause_HEADERS} sh2_dynarec/sh2_dynarec.h) set_source_files_properties(sh2_dynarec/sh2_dynarec.c PROPERTIES COMPILE_FLAGS "-Wno-pointer-to-int-cast -Wno-int-to-pointer-cast") add_definitions(-DSH2_DYNAREC=1 -DHAVE_ARMv6=1 -DHAVE_ARMv7=1) endif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv7l") if (ANDROID) enable_language(ASM-ATT) set(yabause_SOURCES ${yabause_SOURCES} sh2_dynarec/sh2_dynarec.c sh2_dynarec/linkage_arm.s) set(yabause_HEADERS ${yabause_HEADERS} sh2_dynarec/sh2_dynarec.h) set_source_files_properties(sh2_dynarec/sh2_dynarec.c PROPERTIES COMPILE_FLAGS "-Wno-pointer-to-int-cast -Wno-int-to-pointer-cast") add_definitions(-DSH2_DYNAREC=1) add_definitions(-DANDROID=1) if (YAB_WANT_ARM7) add_definitions(-DHAVE_ARMv6=1 -DHAVE_ARMv7=1) endif() endif () endif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") endif (SH2_DYNAREC) # c68k option(YAB_WANT_C68K "enable c68k compilation" ON) if (YAB_WANT_C68K) include(ExternalProject) ExternalProject_Add(c68kinc DOWNLOAD_COMMAND "" SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/c68k CMAKE_GENERATOR "${CMAKE_GENERATOR}" INSTALL_COMMAND "" BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/c68k ) add_definitions(-DHAVE_C68K=1) include_directories(${CMAKE_CURRENT_BINARY_DIR}/c68k) set(yabause_SOURCES ${yabause_SOURCES} c68k/c68kexec.c c68k/c68k.c m68kc68k.c) set(yabause_HEADERS ${yabause_HEADERS} c68k/c68k.h m68kc68k.h) if (MSVC) set_source_files_properties(c68k/c68kexec.c PROPERTIES COMPILE_FLAGS "/Od /wd4146") else() set_source_files_properties(c68k/c68kexec.c PROPERTIES COMPILE_FLAGS "-O0") endif() endif(YAB_WANT_C68K) option(YAB_WANT_MUSASHI "Enable musashi 68k" ON) #TODO cross compile builds m68kmake for the target platform instead #of the native one, making it impossible to generate the core if (YAB_WANT_MUSASHI) set (MUSASHI_GENERATED_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/musashi/m68kopac.c ${CMAKE_CURRENT_BINARY_DIR}/musashi/m68kopdm.c ${CMAKE_CURRENT_BINARY_DIR}/musashi/m68kopnz.c ${CMAKE_CURRENT_BINARY_DIR}/musashi/m68kops.c) set (MUSASHI_GENERATED_HEADERS ${CMAKE_CURRENT_BINARY_DIR}/musashi/m68kops.h) include(ExternalProject) ExternalProject_Add(m68kmake DOWNLOAD_COMMAND "" SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/musashi CMAKE_GENERATOR "${CMAKE_GENERATOR}" INSTALL_COMMAND "" BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/musashi ) add_definitions(-DHAVE_MUSASHI=1) include_directories( ${CMAKE_CURRENT_BINARY_DIR}/musashi ${CMAKE_CURRENT_SOURCE_DIR}/musashi ) set(yabause_SOURCES ${yabause_SOURCES} ${MUSASHI_GENERATED_SOURCES} musashi/m68kdasm.c musashi/m68kcpu.c m68kmusashi.c ) set(yabause_HEADERS ${yabause_HEADERS} musashi/m68k.h musashi/m68kcpu.h ${MUSASHI_GENERATED_HEADERS} m68kmusashi.h ) set_property(SOURCE ${MUSASHI_GENERATED_SOURCES} ${MUSASHI_GENERATED_HEADERS} PROPERTY GENERATED ON) endif(YAB_WANT_MUSASHI) # q68 option(YAB_WANT_Q68 "enable q68 compilation" OFF) if (YAB_WANT_Q68) add_definitions(-DHAVE_Q68=1) set(yabause_SOURCES ${yabause_SOURCES} m68kq68.c q68/q68.c q68/q68-core.c q68/q68-disasm.c) set(yabause_HEADERS ${yabause_HEADERS} q68/q68-const.h q68/q68.h q68/q68-internal.h q68/q68-jit.h q68/q68-jit-psp.h q68/q68-jit-x86.h) endif() # gdb stub option(YAB_WANT_GDBSTUB "enable gdb stub" OFF) if (YAB_WANT_GDBSTUB) add_definitions(-DHAVE_GDBSTUB=1) set(yabause_SOURCES ${yabause_SOURCES} gdb/stub.c gdb/client.c gdb/packet.c) set(yabause_HEADERS ${yabause_HEADERS} gdb/stub.h gdb/client.h gdb/packet.h) endif() # *DEBUG set(YAB_DEBUG "" CACHE STRING "List of enabled debug information") foreach(DEBUG IN LISTS YAB_DEBUG) if (${DEBUG} STREQUAL "main") add_definitions(-DDEBUG=1) elseif (${DEBUG} STREQUAL "cd") add_definitions(-DCDDEBUG=1) elseif (${DEBUG} STREQUAL "idle") add_definitions(-DIDLE_DETECT_VERBOSE=1) else (${DEBUG} STREQUAL "main") string(TOUPPER ${DEBUG} UPDEBUG) add_definitions(-D${UPDEBUG}_DEBUG=1) endif (${DEBUG} STREQUAL "main") endforeach(DEBUG) # Network option(YAB_NETWORK "Enable network") if (YAB_NETWORK) add_definitions(-DUSESOCKET=1) endif() option(YAB_PORT_OSD "Let ports provides their own OSD core list" OFF) if (YAB_PORT_OSD) add_definitions(-DYAB_PORT_OSD=1) endif() # Optimized DMA option(YAB_OPTIMIZED_DMA "Use optimized DMA when possible" OFF) if (YAB_OPTIMIZED_DMA) add_definitions(-DOPTIMIZED_DMA=1) endif() # SH2 Trace option(SH2_TRACE "Enable SH2 tracing" OFF) if (SH2_TRACE) add_definitions(-DSH2_TRACE=1) endif() # SH2 UBC option(SH2_UBC "Enable SH2 User Break Controller" OFF) if (SH2_UBC) add_definitions(-DSH2_UBC=1) endif() # Yabause Arch if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") add_definitions(-DARCH_IS_MACOSX=1) set(yabause_SOURCES ${yabause_SOURCES} sock-dummy.c thr-macosx.c) elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") add_definitions(-DARCH_IS_FREEBSD=1) set(yabause_SOURCES ${yabause_SOURCES} sock-dummy.c thr-dummy.c cd-freebsd.c) elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") add_definitions(-DARCH_IS_LINUX=1) set(yabause_SOURCES ${yabause_SOURCES} sock-linux.c thr-linux.c cd-linux.c) check_include_file("linux/joystick.h" LINUX_HAS_JOYSTICK) if (LINUX_HAS_JOYSTICK) set(yabause_SOURCES ${yabause_SOURCES} perlinuxjoy.c) set(yabause_HEADERS ${yabause_HEADERS} perlinuxjoy.h) endif() check_c_source_compiles(" #include int main(int argc, char ** argv) { int i = CDSL_CURRENT; } " LINUX_CDROM_H_OK) if (NOT LINUX_CDROM_H_OK) add_definitions(-DLINUX_CDROM_H_IS_BROKEN) endif (NOT LINUX_CDROM_H_OK) elseif (${CMAKE_SYSTEM_NAME} MATCHES "NetBSD") add_definitions(-DARCH_IS_NETBSD=1) set(yabause_SOURCES ${yabause_SOURCES} sock-dummy.c thr-dummy.c cd-netbsd.c) elseif (${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD") add_definitions(-DARCH_IS_NETBSD=1) set(yabause_SOURCES ${yabause_SOURCES} sock-dummy.c thr-dummy.c cd-netbsd.c) elseif (${CMAKE_SYSTEM_NAME} MATCHES "Windows") add_definitions(-DARCH_IS_WINDOWS=1) set(yabause_SOURCES ${yabause_SOURCES} sock-windows.c thr-windows.c) else () add_definitions(-DUNKNOWN_ARCH=1) set(yabause_SOURCES ${yabause_SOURCES} sock-dummy.c thr-dummy.c) endif () set(YAB_OPTIMIZATION "-O3" CACHE STRING "Override optimization level") if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "i686") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${YAB_OPTIMIZATION} -march=i686 -msse") endif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "i686") if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${YAB_OPTIMIZATION}") endif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64") if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv5tel") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${YAB_OPTIMIZATION}") endif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv5tel") if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv7l") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${YAB_OPTIMIZATION}") endif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv7l") if(ANDROID) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${YAB_OPTIMIZATION}") endif() # Warnings defined to know when we're breaking compilation with MSVC if (CMAKE_COMPILER_IS_GNUCC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wdeclaration-after-statement") endif () if (MSVC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4018 /wd4244") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4244") endif () # Turn string format security warnings into errors. Some Linux distros enable this by default and travis-ci, etc. needs a way to catch them option(YAB_FORCE_SECURE_STRINGS "Turns all string format warnings into errors." OFF) if (CMAKE_COMPILER_IS_GNUCC AND YAB_FORCE_SECURE_STRINGS) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat -Werror=format-security") endif() option(YAB_WERROR "Treat all warnings as errors." OFF) if (YAB_WERROR) if(MSVC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") else() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") endif() endif() add_definitions(-DPACKAGE=\"${YAB_PACKAGE}\") add_definitions(-DVERSION=\"${YAB_VERSION}\") add_library(yabause ${yabause_SOURCES} ${yabause_HEADERS}) if (YAB_WANT_C68K) add_dependencies(yabause c68kinc) endif(YAB_WANT_C68K) if (YAB_WANT_MUSASHI) add_dependencies(yabause m68kmake) endif(YAB_WANT_MUSASHI) macro(yab_port_start) if (YAB_PORT_BUILT AND NOT YAB_MULTIBUILD) return() endif () endmacro(yab_port_start) macro(yab_port_stop) set(YAB_PORT_BUILT TRUE PARENT_SCOPE) endmacro(yab_port_stop) macro(yab_port_success YAB_TARGET) if (NOT YAB_MULTIBUILD) set_target_properties(${YAB_TARGET} PROPERTIES OUTPUT_NAME yabause) set(YAB_PORT_NAME "yabause") else () set(YAB_PORT_NAME ${YAB_TARGET}) endif () set(YAB_PORT_BUILT TRUE PARENT_SCOPE) endmacro(yab_port_success) set(YAB_MAN_DIR "share/man") if (NOT $ENV{PKGMANDIR} STREQUAL "") set(YAB_MAN_DIR $ENV{PKGMANDIR}) endif () option(YAB_MULTIBUILD "Choose wether to build all ports or only a single one") set(YAB_PORT_BUILT FALSE) set(YAB_PORTS "gtk;qt;dreamcast;cocoa;runner" CACHE STRING "List of ports to build") foreach(PORT IN LISTS YAB_PORTS) add_subdirectory(${PORT}) endforeach(PORT) # this is stupid, but CMake automatic definitions are based on variables... if (YAB_WANT_C68K) set(HAVE_C68K ON) endif() if (YAB_WANT_MUSASHI) set(HAVE_MUSASHI ON) endif() if (YAB_WANT_Q68) set(HAVE_Q68 ON) endif() if (YAB_WANT_OPENSL) set(HAVE_OPENSL ON) endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) if (YAB_NETWORK AND UNIX) set(YABAUSE_LIBRARIES ${YABAUSE_LIBRARIES} "socket") endif() option(YAB_TESTS "Build test programs for cores" OFF) if (YAB_TESTS) add_subdirectory("tools") endif() yabause-0.9.15/src/error.c000644 001750 001750 00000011213 12755623101 017335 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005-2006 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file error.c \brief Error handling functions. */ #include #include #include #include #include "error.h" #include "yui.h" ////////////////////////////////////////////////////////////////////////////// static void AllocAmendPrintString(const char *string1, const char *string2) { char *string; if ((string = (char *)malloc(strlen(string1) + strlen(string2) + 2)) == NULL) return; sprintf(string, "%s%s\n", string1, string2); YuiErrorMsg(string); free(string); } ////////////////////////////////////////////////////////////////////////////// void YabSetError(int type, const void *extra) { char tempstr[512]; SH2_struct *sh; switch (type) { case YAB_ERR_FILENOTFOUND: AllocAmendPrintString(_("File not found: "), extra); break; case YAB_ERR_MEMORYALLOC: YuiErrorMsg(_("Error allocating memory\n")); break; case YAB_ERR_FILEREAD: AllocAmendPrintString(_("Error reading file: "), extra); break; case YAB_ERR_FILEWRITE: AllocAmendPrintString(_("Error writing file: "), extra); break; case YAB_ERR_CANNOTINIT: AllocAmendPrintString(_("Cannot initialize "), extra); break; case YAB_ERR_SH2INVALIDOPCODE: sh = (SH2_struct *)extra; SH2GetRegisters(sh, &sh->regs); sprintf(tempstr, "%s SH2 invalid opcode\n\n" "R0 = %08lX\tR12 = %08lX\n" "R1 = %08lX\tR13 = %08lX\n" "R2 = %08lX\tR14 = %08lX\n" "R3 = %08lX\tR15 = %08lX\n" "R4 = %08lX\tSR = %08lX\n" "R5 = %08lX\tGBR = %08lX\n" "R6 = %08lX\tVBR = %08lX\n" "R7 = %08lX\tMACH = %08lX\n" "R8 = %08lX\tMACL = %08lX\n" "R9 = %08lX\tPR = %08lX\n" "R10 = %08lX\tPC = %08lX\n" "R11 = %08lX\n", sh->isslave ? "Slave" : "Master", (long)sh->regs.R[0], (long)sh->regs.R[12], (long)sh->regs.R[1], (long)sh->regs.R[13], (long)sh->regs.R[2], (long)sh->regs.R[14], (long)sh->regs.R[3], (long)sh->regs.R[15], (long)sh->regs.R[4], (long)sh->regs.SR.all, (long)sh->regs.R[5], (long)sh->regs.GBR, (long)sh->regs.R[6], (long)sh->regs.VBR, (long)sh->regs.R[7], (long)sh->regs.MACH, (long)sh->regs.R[8], (long)sh->regs.MACL, (long)sh->regs.R[9], (long)sh->regs.PR, (long)sh->regs.R[10], (long)sh->regs.PC, (long)sh->regs.R[11]); YuiErrorMsg(tempstr); break; case YAB_ERR_SH2READ: YuiErrorMsg(_("SH2 read error\n")); // fix me break; case YAB_ERR_SH2WRITE: YuiErrorMsg(_("SH2 write error\n")); // fix me break; case YAB_ERR_SDL: AllocAmendPrintString(_("SDL Error: "), extra); break; case YAB_ERR_OTHER: YuiErrorMsg((char *)extra); break; case YAB_ERR_UNKNOWN: default: YuiErrorMsg(_("Unknown error occurred\n")); break; } } ////////////////////////////////////////////////////////////////////////////// void YabErrorMsg(const char * format, ...) { va_list l; int n; char * buffer; va_start(l, format); n = vsnprintf(NULL, 0, format, l); va_end(l); buffer = malloc(n + 1); va_start(l, format); vsprintf(buffer, format, l); va_end(l); YuiErrorMsg(buffer); free(buffer); } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/cheat.h000644 001750 001750 00000003367 12755623101 017310 0ustar00guillaumeguillaume000000 000000 /* Copyright 2007 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file cheat.c \brief Header for cheat engine to apply codes to SH2 addresses */ #ifndef CHEAT_H #define CHEAT_H #include "core.h" enum { CHEATTYPE_NONE=0, CHEATTYPE_ENABLE, CHEATTYPE_BYTEWRITE, CHEATTYPE_WORDWRITE, CHEATTYPE_LONGWRITE }; typedef struct { int type; u32 addr; u32 val; char *desc; int enable; } cheatlist_struct; int CheatInit(void); void CheatDeInit(void); int CheatAddCode(int type, u32 addr, u32 val); int CheatAddARCode(const char *code); int CheatChangeDescription(int type, u32 addr, u32 val, char *desc); int CheatChangeDescriptionByIndex(int i, char *desc); int CheatRemoveCode(int type, u32 addr, u32 val); int CheatRemoveCodeByIndex(int i); int CheatRemoveARCode(const char *code); void CheatClearCodes(void); void CheatEnableCode(int index); void CheatDisableCode(int index); void CheatDoPatches(void); cheatlist_struct *CheatGetList(int *cheatnum); int CheatSave(const char *filename); int CheatLoad(const char *filename); #endif yabause-0.9.15/src/sock.h000644 001750 001750 00000004613 12755623101 017156 0ustar00guillaumeguillaume000000 000000 /* Copyright 2013 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SOCK_H #define SOCK_H typedef int YabSock; // YabSockInit: Initializes socket code. // Returns 0 on success. -1 on error. int YabSockInit(); // YabSockDeInit: DeInitialize/frees socket code. // Returns 0 on success. -1 on error. int YabSockDeInit(); // YabSockConnectSocket: Attempts to connect to specified ip and port. // Returns 0 on success. -1 on error. int YabSockConnectSocket(const char *ip, int port, YabSock *sock); // YabSockListenSocket: Listen for connection attempts on specified port. // Returns 0 on success. -1 on error. int YabSockListenSocket(int port, YabSock *sock); // YabSockCloseSocket: Closes previously opened socket. // Returns 0 on success. -1 on error. int YabSockCloseSocket(YabSock sock); // YabSockSelect: Determines the status of one or more sockets. // Returns 0 on success. -1 on error. int YabSockSelect(YabSock sock, int check_read, int check_write); // YabSockIsReadSet: Is socket's read flag set // Returns 1 on true. 0 on false. int YabSockIsReadSet(YabSock sock); // YabSockIsWriteSet: Is socket's write flag set // Returns 1 on true. 0 on false. int YabSockIsWriteSet(YabSock sock); // YabSockAccept: Accept connection from socket. // Returns opened connected socket. YabSock YabSockAccept(YabSock sock); // YabSockSend: Sends data via specified socket // Returns 0 on success. -1 on error. int YabSockSend(YabSock sock, const void *buf, int len, int flags); // YabSockSend: Receive data via specified socket // Returns 0 on success. -1 on error. int YabSockReceive(YabSock sock, void *buf, int len, int flags); #endif // SOCK_H yabause-0.9.15/src/sh2trace.h000644 001750 001750 00000002430 12755623101 017725 0ustar00guillaumeguillaume000000 000000 /* src/sh2trace.h: SH-2 tracing header for debugging Copyright 2009 Andrew Church This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SH2TRACE_H #define SH2TRACE_H #include "core.h" void SH2SetInsTracing(int enable); extern FASTCALL u64 sh2_cycle_count(void); extern FASTCALL void sh2_trace_add_cycles(s32 cycles); extern FASTCALL void sh2_trace_writeb(u32 address, u32 value); extern FASTCALL void sh2_trace_writew(u32 address, u32 value); extern FASTCALL void sh2_trace_writel(u32 address, u32 value); extern FASTCALL void sh2_trace(SH2_struct *state, u32 address); #endif // SH2TRACE_H yabause-0.9.15/src/m68kd.h000644 001750 001750 00000001571 12755623101 017150 0ustar00guillaumeguillaume000000 000000 /* Copyright 2004 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef M68KD_H #define M68KD_H #include "core.h" u32 M68KDisasm(u32 addr, char *outstring); #endif yabause-0.9.15/src/vdp2debug.c000644 001750 001750 00000146077 12755623101 020107 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005-2008 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file vdp2debug.c \brief VDP2 debug functions */ #include "vdp2.h" #include "ygl.h" #include "vdp2debug.h" #include "vidshared.h" #include "vidsoft.h" #include "titan/titan.h" ////////////////////////////////////////////////////////////////////////////// static INLINE void Vdp2GetPlaneSize(int planedata, int *planew, int *planeh) { switch(planedata) { case 0: *planew = *planeh = 1; break; case 1: *planew = 2; *planeh = 1; break; case 3: *planew = *planeh = 2; break; default: *planew = *planeh = 1; break; } } ////////////////////////////////////////////////////////////////////////////// static INLINE char *AddBppString(char *outstring, int bpp) { switch (bpp) { case 0: AddString(outstring, "4-bit(16 colors)\r\n"); break; case 1: AddString(outstring, "8-bit(256 colors)\r\n"); break; case 2: AddString(outstring, "16-bit(2048 colors)\r\n"); break; case 3: AddString(outstring, "16-bit(32,768 colors)\r\n"); break; case 4: AddString(outstring, "32-bit(16.7 mil colors)\r\n"); break; default: AddString(outstring, "Unsupported BPP\r\n"); break; } return outstring; } ////////////////////////////////////////////////////////////////////////////// static INLINE char *AddMosaicString(char *outstring, int mask) { if (Vdp2Regs->MZCTL & mask) { AddString(outstring, "Mosaic Size = width %d height %d\r\n", ((Vdp2Regs->MZCTL >> 8) & 0xf) + 1, (Vdp2Regs->MZCTL >> 12) + 1); } return outstring; } ////////////////////////////////////////////////////////////////////////////// static INLINE char *AddBitmapInfoString(char *outstring, int wh, int palnum, int mapofn) { int cellw=0, cellh=0; // Bitmap switch(wh) { case 0: cellw = 512; cellh = 256; break; case 1: cellw = 512; cellh = 512; break; case 2: cellw = 1024; cellh = 256; break; case 3: cellw = 1024; cellh = 512; break; } AddString(outstring, "Bitmap(%dx%d)\r\n", cellw, cellh); if (palnum & 0x20) { AddString(outstring, "Bitmap Special Priority enabled\r\n"); } if (palnum & 0x10) { AddString(outstring, "Bitmap Special Color Calculation enabled\r\n"); } AddString(outstring, "Bitmap Address = %X\r\n", (mapofn & 0x7) * 0x20000); AddString(outstring, "Bitmap Palette Address = %X\r\n", (palnum & 0x7) << 4); return outstring; } ////////////////////////////////////////////////////////////////////////////// static void CalcWindowCoordinates(int num, int *hstart, int *vstart, int *hend, int *vend) { clipping_struct clip; ReadWindowCoordinates(num, &clip, Vdp2Regs); *hstart = clip.xstart; *vstart = clip.ystart; *hend = clip.xend; *vend = clip.yend; } ////////////////////////////////////////////////////////////////////////////// static INLINE char *AddWindowInfoString(char *outstring, int wctl, int issprite) { if (wctl & 0x2) { int hstart=0, vstart=0, hend=0, vend=0; AddString(outstring, "Window W0 Enabled:\r\n"); // Retrieve Window Points if (Vdp2Regs->LWTA0.all & 0x80000000) { // Line Window AddString(outstring, "Line Window Table Address = %08lX\r\n", 0x05E00000UL | ((Vdp2Regs->LWTA0.all & 0x7FFFEUL) << 1)); } else { // Normal Window CalcWindowCoordinates(0, &hstart, &vstart, &hend, &vend); AddString(outstring, "Horizontal start = %d\r\n", hstart); AddString(outstring, "Vertical start = %d\r\n", vstart); AddString(outstring, "Horizontal end = %d\r\n", hend); AddString(outstring, "Vertical end = %d\r\n", vend); } AddString(outstring, "Display %s of Window\r\n", (wctl & 0x1) ? "inside" : "outside"); } if (wctl & 0x8) { int hstart=0, vstart=0, hend=0, vend=0; AddString(outstring, "Window W1 Enabled:\r\n"); // Retrieve Window Points if (Vdp2Regs->LWTA1.all & 0x80000000) { // Line Window AddString(outstring, "Line Table address = %08lX\r\n", 0x05E00000UL | ((Vdp2Regs->LWTA1.all & 0x7FFFEUL) << 1)); } else { // Normal Window CalcWindowCoordinates(1, &hstart, &vstart, &hend, &vend); AddString(outstring, "Horizontal start = %d\r\n", hstart); AddString(outstring, "Vertical start = %d\r\n", vstart); AddString(outstring, "Horizontal end = %d\r\n", hend); AddString(outstring, "Vertical end = %d\r\n", vend); } AddString(outstring, "Display %s of Window\r\n", (wctl & 0x4) ? "inside" : "outside"); } if (wctl & 0x20) { AddString(outstring, "Sprite Window Enabled:\r\n"); AddString(outstring, "Display %s of Window\r\n", (wctl & 0x10) ? "inside" : "outside"); } if (wctl & 0x2A) { AddString(outstring, "Window Overlap Logic: %s\r\n", (wctl & 0x80) ? "AND" : "OR"); } else { if (wctl & 0x80) { // Whole screen window enabled AddString(outstring, "Window enabled whole screen\r\n"); } else { // Whole screen window disabled AddString(outstring, "Window disabled whole screen\r\n"); } } return outstring; } ////////////////////////////////////////////////////////////////////////////// static INLINE char *AddMapInfo(char *outstring, int patternwh, u16 PNC, u8 PLSZ, int mapoffset, int numplanes, u8 *map) { int deca; int multi; int i; int patterndatasize; int planew, planeh; u32 tmp=0; u32 addr; if(PNC & 0x8000) patterndatasize = 1; else patterndatasize = 2; Vdp2GetPlaneSize(PLSZ, &planew, &planeh); deca = planeh + planew - 2; multi = planeh * planew; // Map Planes A-D for (i = 0; i < numplanes; i++) { tmp = mapoffset | map[i]; if (patterndatasize == 1) { if (patternwh == 1) addr = ((tmp & 0x3F) >> deca) * (multi * 0x2000); else addr = (tmp >> deca) * (multi * 0x800); } else { if (patternwh == 1) addr = ((tmp & 0x1F) >> deca) * (multi * 0x4000); else addr = ((tmp & 0x7F) >> deca) * (multi * 0x1000); } AddString(outstring, "Plane %C Address = %08X\r\n", 0x41+i, (unsigned int)addr); } return outstring; } ////////////////////////////////////////////////////////////////////////////// static INLINE char *AddColorCalcInfo(char *outstring, u16 calcenab, u16 gradnum, u16 calcratio, u16 sfcnum) { if (Vdp2Regs->CCCTL & calcenab) { AddString(outstring, "Color Calculation Enabled\r\n"); if (Vdp2Regs->CCCTL & 0x8000 && (Vdp2Regs->CCCTL & 0x0700) == gradnum) { AddString(outstring, "Gradation Calculation Enabled\r\n"); } else if (Vdp2Regs->CCCTL & 0x0400) { AddString(outstring, "Extended Color Calculation Enabled\r\n"); } else { AddString(outstring, "Special Color Calculation Mode = %d\r\n", sfcnum); } AddString(outstring, "Color Calculation Ratio = %d:%d\r\n", 31 - calcratio, 1 + calcratio); } return outstring; } ////////////////////////////////////////////////////////////////////////////// static INLINE char *AddColorOffsetInfo(char *outstring, u16 offsetselectenab) { s32 r, g, b; if (Vdp2Regs->CLOFEN & offsetselectenab) { if (Vdp2Regs->CLOFSL & offsetselectenab) { r = Vdp2Regs->COBR & 0xFF; if (Vdp2Regs->COBR & 0x100) r |= 0xFFFFFF00; g = Vdp2Regs->COBG & 0xFF; if (Vdp2Regs->COBG & 0x100) g |= 0xFFFFFF00; b = Vdp2Regs->COBB & 0xFF; if (Vdp2Regs->COBB & 0x100) b |= 0xFFFFFF00; AddString(outstring, "Color Offset B Enabled\r\n"); AddString(outstring, "R = %ld, G = %ld, B = %ld\r\n", (long)r, (long)g, (long)b); } else { r = Vdp2Regs->COAR & 0xFF; if (Vdp2Regs->COAR & 0x100) r |= 0xFFFFFF00; g = Vdp2Regs->COAG & 0xFF; if (Vdp2Regs->COAG & 0x100) g |= 0xFFFFFF00; b = Vdp2Regs->COAB & 0xFF; if (Vdp2Regs->COAB & 0x100) b |= 0xFFFFFF00; AddString(outstring, "Color Offset A Enabled\r\n"); AddString(outstring, "R = %ld, G = %ld, B = %ld\r\n", (long)r, (long)g, (long)b); } } return outstring; } ////////////////////////////////////////////////////////////////////////////// static INLINE char *AddSpecialPriorityInfo(char *outstring, u16 spriority) { if (spriority & 0x3) { AddString(outstring, "Special Priority Mode %d used", spriority & 0x3); switch (spriority & 0x3) { case 1: AddString(outstring, "(per tile)\r\n"); break; case 2: AddString(outstring, "(per pixel)\r\n"); break; case 3: AddString(outstring, "(undocumented)\r\n"); break; default: break; } } return outstring; } ////////////////////////////////////////////////////////////////////////////// void Vdp2DebugStatsRBG0(char *outstring, int *isenabled) { int patternwh=((Vdp2Regs->CHCTLB & 0x100) >> 8) + 1; u8 map[16]; int hstart, vstart, hend, vend; if (Vdp2Regs->BGON & 0x10) { // enabled int rotatenum=0; int coeftbl=0, coefmode=0; *isenabled = 1; // Which Rotation Parameter is being used switch (Vdp2Regs->RPMD & 0x3) { case 0: // Parameter A rotatenum = 0; coeftbl = Vdp2Regs->KTCTL & 0x1; coefmode = (Vdp2Regs->KTCTL >> 2) & 0x3; AddString(outstring, "Using Parameter %C\r\n", 'A' + rotatenum); break; case 1: // Parameter B rotatenum = 1; coeftbl = Vdp2Regs->KTCTL & 0x100; coefmode = (Vdp2Regs->KTCTL >> 10) & 0x3; AddString(outstring, "Using Parameter B\r\n"); break; case 2: // Parameter A+B switched via coefficients AddString(outstring, "Parameter A/B switched via coefficients\r\n"); break; case 3: // Parameter A+B switched via rotation parameter window AddString(outstring, "Parameter A/B switched parameter window\r\n"); if (Vdp2Regs->WCTLD & 0x2) { AddString(outstring, "Rotation Window 0 Enabled\r\n"); CalcWindowCoordinates(0, &hstart, &vstart, &hend, &vend); AddString(outstring, "Horizontal start = %d\r\n", hstart); AddString(outstring, "Vertical start = %d\r\n", vstart); AddString(outstring, "Horizontal end = %d\r\n", hend); AddString(outstring, "Vertical end = %d\r\n", vend); } else if (Vdp2Regs->WCTLD & 0x4) { AddString(outstring, "Rotation Window 1 Enabled\r\n"); CalcWindowCoordinates(1, &hstart, &vstart, &hend, &vend); AddString(outstring, "Horizontal start = %d\r\n", hstart); AddString(outstring, "Vertical start = %d\r\n", vstart); AddString(outstring, "Horizontal end = %d\r\n", hend); AddString(outstring, "Vertical end = %d\r\n", vend); } break; } if (coeftbl) { AddString(outstring, "Coefficient Table Enabled(Mode %d)\r\n", coefmode); } // Mosaic outstring = AddMosaicString(outstring, 0x10); // BPP outstring = AddBppString(outstring, (Vdp2Regs->CHCTLB >> 12) & 0x7); // Bitmap or Tile mode? if (Vdp2Regs->CHCTLB & 0x200) { // Bitmap mode if (rotatenum == 0) { // Parameter A outstring = AddBitmapInfoString(outstring, (Vdp2Regs->CHCTLB & 0x400) >> 10, Vdp2Regs->BMPNB, Vdp2Regs->MPOFR); } else { // Parameter B outstring = AddBitmapInfoString(outstring, (Vdp2Regs->CHCTLB & 0x400) >> 10, Vdp2Regs->BMPNB, Vdp2Regs->MPOFR >> 4); } } else { // Tile mode int patterndatasize; u16 supplementdata=Vdp2Regs->PNCR & 0x3FF; int planew=0, planeh=0; if(Vdp2Regs->PNCR & 0x8000) patterndatasize = 1; else patterndatasize = 2; AddString(outstring, "Tile(%dH x %dV)\r\n", patternwh, patternwh); if (rotatenum == 0) { // Parameter A Vdp2GetPlaneSize((Vdp2Regs->PLSZ & 0x300) >> 8, &planew, &planeh); } else { // Parameter B Vdp2GetPlaneSize((Vdp2Regs->PLSZ & 0x3000) >> 8, &planew, &planeh); } AddString(outstring, "Plane Size = %dH x %dV\r\n", planew, planeh); // Pattern Name Control stuff if (patterndatasize == 2) { AddString(outstring, "Pattern Name data size = 2 words\r\n"); } else { AddString(outstring, "Pattern Name data size = 1 word\r\n"); AddString(outstring, "Character Number Supplement bit = %d\r\n", (supplementdata >> 14) & 0x1); AddString(outstring, "Special Priority bit = %d\r\n", (supplementdata >> 9) & 0x1); AddString(outstring, "Special Color Calculation bit = %d\r\n", (supplementdata >> 8) & 0x1); AddString(outstring, "Supplementary Palette number = %d\r\n", (supplementdata >> 5) & 0x7); AddString(outstring, "Supplementary Color number = %d\r\n", supplementdata & 0x1f); } if (rotatenum == 0) { // Parameter A map[0] = Vdp2Regs->MPABRA & 0xFF; map[1] = Vdp2Regs->MPABRA >> 8; map[2] = Vdp2Regs->MPCDRA & 0xFF; map[3] = Vdp2Regs->MPCDRA >> 8; map[4] = Vdp2Regs->MPEFRA & 0xFF; map[5] = Vdp2Regs->MPEFRA >> 8; map[6] = Vdp2Regs->MPGHRA & 0xFF; map[7] = Vdp2Regs->MPGHRA >> 8; map[8] = Vdp2Regs->MPIJRA & 0xFF; map[9] = Vdp2Regs->MPIJRA >> 8; map[10] = Vdp2Regs->MPKLRA & 0xFF; map[11] = Vdp2Regs->MPKLRA >> 8; map[12] = Vdp2Regs->MPMNRA & 0xFF; map[13] = Vdp2Regs->MPMNRA >> 8; map[14] = Vdp2Regs->MPOPRA & 0xFF; map[15] = Vdp2Regs->MPOPRA >> 8; outstring = AddMapInfo(outstring, patternwh, Vdp2Regs->PNCR, (Vdp2Regs->PLSZ >> 8) & 0x3, (Vdp2Regs->MPOFR & 0x7) << 6, 16, map); } else { // Parameter B map[0] = Vdp2Regs->MPABRB & 0xFF; map[1] = Vdp2Regs->MPABRB >> 8; map[2] = Vdp2Regs->MPCDRB & 0xFF; map[3] = Vdp2Regs->MPCDRB >> 8; map[4] = Vdp2Regs->MPEFRB & 0xFF; map[5] = Vdp2Regs->MPEFRB >> 8; map[6] = Vdp2Regs->MPGHRB & 0xFF; map[7] = Vdp2Regs->MPGHRB >> 8; map[8] = Vdp2Regs->MPIJRB & 0xFF; map[9] = Vdp2Regs->MPIJRB >> 8; map[10] = Vdp2Regs->MPKLRB & 0xFF; map[11] = Vdp2Regs->MPKLRB >> 8; map[12] = Vdp2Regs->MPMNRB & 0xFF; map[13] = Vdp2Regs->MPMNRB >> 8; map[14] = Vdp2Regs->MPOPRB & 0xFF; map[15] = Vdp2Regs->MPOPRB >> 8; outstring = AddMapInfo(outstring, patternwh, Vdp2Regs->PNCR, (Vdp2Regs->PLSZ >> 12) & 0x3, (Vdp2Regs->MPOFR & 0x70) << 2, 16, map); } /* // Figure out Cell start address switch(patterndatasize) { case 1: { tmp = readWord(vram, addr); switch(auxMode) { case 0: switch(patternwh) { case 1: charAddr = (tmp & 0x3FF) | ((supplementdata & 0x1F) << 10); break; case 2: charAddr = ((tmp & 0x3FF) << 2) | (supplementdata & 0x3) | ((supplementdata & 0x1C) << 10); break; } break; case 1: switch(patternwh) { case 1: charAddr = (tmp & 0xFFF) | ((supplementdata & 0x1C) << 10); break; case 4: charAddr = ((tmp & 0xFFF) << 2) | (supplementdata & 0x3) | ((supplementdata & 0x10) << 10); break; } break; } break; } case 2: { unsigned short tmp1 = readWord(vram, addr); unsigned short tmp2 = readWord(vram, addr+2); charAddr = tmp2 & 0x7FFF; break; } } if (!(readWord(reg, 0x6) & 0x8000)) charAddr &= 0x3FFF; charAddr *= 0x20; // selon Runik AddString(outstring, "Cell Data Address = %X\r\n", charAddr); */ } // Window Control outstring = AddWindowInfoString(outstring, Vdp2Regs->WCTLC, 0); // Shadow Control here // Color Ram Address Offset AddString(outstring, "Color Ram Address Offset = %X\r\n", (Vdp2Regs->CRAOFB & 0x7) << 8); // Special Priority Mode outstring = AddSpecialPriorityInfo(outstring, Vdp2Regs->SFPRMD >> 8); // Color Calculation Control here // Special Color Calculation Mode here // Priority Number AddString(outstring, "Priority = %d\r\n", Vdp2Regs->PRIR & 0x7); // Color Calculation outstring = AddColorCalcInfo(outstring, 0x0010, 0x0001, Vdp2Regs->CCRR & 0x1F, (Vdp2Regs->SFCCMD >> 8) & 0x3); // Color Offset outstring = AddColorOffsetInfo(outstring, 0x0010); AddString(outstring, "Special Color Calculation %d\r\n",(Vdp2Regs->SFCCMD>>8)&0x03); } else { // disabled *isenabled = 0; } } ////////////////////////////////////////////////////////////////////////////// void Vdp2DebugStatsNBG0(char *outstring, int *isenabled) { u16 lineVerticalScrollReg = Vdp2Regs->SCRCTL & 0x3F; int isbitmap=Vdp2Regs->CHCTLA & 0x2; int patternwh=(Vdp2Regs->CHCTLA & 0x1) + 1; u8 map[4]; if (Vdp2Regs->BGON & 0x1 || Vdp2Regs->BGON & 0x20) { // enabled *isenabled = 1; // Generate specific Info for NBG0/RBG1 if (Vdp2Regs->BGON & 0x20) { AddString(outstring, "RBG1 mode\r\n"); if (Vdp2Regs->KTCTL & 0x100) { AddString(outstring, "Coefficient Table Enabled(Mode %d)\r\n", (Vdp2Regs->KTCTL >> 10) & 0x3); } } else { AddString(outstring, "NBG0 mode\r\n"); } // Mosaic outstring = AddMosaicString(outstring, 0x1); // BPP outstring = AddBppString(outstring, (Vdp2Regs->CHCTLA & 0x70) >> 4); // Bitmap or Tile mode?(RBG1 can only do Tile mode) if (isbitmap && !(Vdp2Regs->BGON & 0x20)) { // Bitmap outstring = AddBitmapInfoString(outstring, (Vdp2Regs->CHCTLA & 0xC) >> 2, Vdp2Regs->BMPNA, Vdp2Regs->MPOFN); } else { // Tile int patterndatasize; u16 supplementdata=Vdp2Regs->PNCN0 & 0x3FF; int planew=0, planeh=0; if(Vdp2Regs->PNCN0 & 0x8000) patterndatasize = 1; else patterndatasize = 2; AddString(outstring, "Tile(%dH x %dV)\r\n", patternwh, patternwh); Vdp2GetPlaneSize(Vdp2Regs->PLSZ & 0x3, &planew, &planeh); AddString(outstring, "Plane Size = %dH x %dV\r\n", planew, planeh); // Pattern Name Control stuff if (patterndatasize == 2) { AddString(outstring, "Pattern Name data size = 2 words\r\n"); } else { AddString(outstring, "Pattern Name data size = 1 word\r\n"); AddString(outstring, "Character Number Supplement bit = %d\r\n", (supplementdata >> 14) & 0x1); AddString(outstring, "Special Priority bit = %d\r\n", (supplementdata >> 9) & 0x1); AddString(outstring, "Special Color Calculation bit = %d\r\n", (supplementdata >> 8) & 0x1); AddString(outstring, "Supplementary Palette number = %d\r\n", (supplementdata >> 5) & 0x7); AddString(outstring, "Supplementary Color number = %d\r\n", supplementdata & 0x1f); } map[0] = Vdp2Regs->MPABN0 & 0xFF; map[1] = Vdp2Regs->MPABN0 >> 8; map[2] = Vdp2Regs->MPCDN0 & 0xFF; map[3] = Vdp2Regs->MPCDN0 >> 8; outstring = AddMapInfo(outstring, patternwh, Vdp2Regs->PNCN0, Vdp2Regs->PLSZ & 0x3, (Vdp2Regs->MPOFN & 0x7) << 6, 4, map); /* // Figure out Cell start address switch(patterndatasize) { case 1: { tmp = T1ReadWord(Vdp2Ram, addr); switch(auxMode) { case 0: switch(patternwh) { case 1: charAddr = (tmp & 0x3FF) | ((supplementdata & 0x1F) << 10); break; case 2: charAddr = ((tmp & 0x3FF) << 2) | (supplementdata & 0x3) | ((supplementdata & 0x1C) << 10); break; } break; case 1: switch(patternwh) { case 1: charAddr = (tmp & 0xFFF) | ((supplementdata & 0x1C) << 10); break; case 4: charAddr = ((tmp & 0xFFF) << 2) | (supplementdata & 0x3) | ((supplementdata & 0x10) << 10); break; } break; } break; } case 2: { u16 tmp1 = T1ReadWord(Vdp2Ram, addr); u16 tmp2 = T1ReadWord(Vdp2Ram, addr+2); charAddr = tmp2 & 0x7FFF; break; } } if (!(readWord(reg, 0x6) & 0x8000)) charAddr &= 0x3FFF; charAddr *= 0x20; // selon Runik AddString(outstring, "Cell Data Address = %X\r\n", charAddr); */ } if (Vdp2Regs->BGON & 0x20) { // unsigned long mapOffsetReg=(readWord(reg, 0x3E) & 0x70) << 2; // RBG1 // Map Planes A-P here // Rotation Parameter Read Control if (Vdp2Regs->RPRCTL & 0x400) { AddString(outstring, "Read KAst Parameter = TRUE\r\n"); } else { AddString(outstring, "Read KAst Parameter = FALSE\r\n"); } if (Vdp2Regs->RPRCTL & 0x200) { AddString(outstring, "Read Yst Parameter = TRUE\r\n"); } else { AddString(outstring, "Read Yst Parameter = FALSE\r\n"); } if (Vdp2Regs->RPRCTL & 0x100) { AddString(outstring, "Read Xst Parameter = TRUE\r\n"); } else { AddString(outstring, "Read Xst Parameter = FALSE\r\n"); } // Coefficient Table Control // Coefficient Table Address Offset // Screen Over Pattern Name(should this be moved?) // Rotation Parameter Table Address } else { // NBG0 /* // Screen scroll values AddString(outstring, "Screen Scroll x = %f, y = %f\r\n", (float)(reg->getLong(0x70) & 0x7FFFF00) / 65536, (float)(reg->getLong(0x74) & 0x7FFFF00) / 65536); */ AddString(outstring, "Screen Scroll x = %d, y = %d\r\n", - ((Vdp2Regs->SCXIN0 & 0x7FF) % 512), - ((Vdp2Regs->SCYIN0 & 0x7FF) % 512)); // Coordinate Increments AddString(outstring, "Coordinate Increments x = %f, y = %f\r\n", (float) 65536 / (Vdp2Regs->ZMXN0.all & 0x7FF00), (float) 65536 / (Vdp2Regs->ZMYN0.all & 0x7FF00)); // Reduction Enable switch (Vdp2Regs->ZMCTL & 3) { case 1: AddString(outstring, "Horizontal Reduction = 1/2\r\n"); break; case 2: case 3: AddString(outstring, "Horizontal Reduction = 1/4\r\n"); break; default: break; } if (lineVerticalScrollReg & 0x8) { AddString(outstring, "Line Zoom enabled\r\n"); } if (lineVerticalScrollReg & 0x4) { AddString(outstring, "Line Scroll Vertical enabled\r\n"); } if (lineVerticalScrollReg & 0x2) { AddString(outstring, "Line Scroll Horizontal enabled\r\n"); } if (lineVerticalScrollReg & 0x6) { AddString(outstring, "Line Scroll Enabled\r\n"); AddString(outstring, "Line Scroll Table Address = %08X\r\n", (int)(0x05E00000 + ((Vdp2Regs->LSTA0.all & 0x7FFFE) << 1))); switch (lineVerticalScrollReg >> 4) { case 0: AddString(outstring, "Line Scroll Interval = Each Line\r\n"); break; case 1: AddString(outstring, "Line Scroll Interval = Every 2 Lines\r\n"); break; case 2: AddString(outstring, "Line Scroll Interval = Every 4 Lines\r\n"); break; case 3: AddString(outstring, "Line Scroll Interval = Every 8 Lines\r\n"); break; } } if (lineVerticalScrollReg & 0x1) { AddString(outstring, "Vertical Cell Scroll enabled\r\n"); AddString(outstring, "Vertical Cell Scroll Table Address = %08X\r\n", (int)(0x05E00000 + ((Vdp2Regs->VCSTA.all & 0x7FFFE) << 1))); } } // Window Control outstring = AddWindowInfoString(outstring, Vdp2Regs->WCTLA, 0); // Shadow Control here // Color Ram Address Offset AddString(outstring, "Color Ram Address Offset = %X\r\n", (Vdp2Regs->CRAOFA & 0x7) << 8); // Special Priority Mode outstring = AddSpecialPriorityInfo(outstring, Vdp2Regs->SFPRMD); // Color Calculation Control here // Special Color Calculation Mode here // Priority Number AddString(outstring, "Priority = %d\r\n", Vdp2Regs->PRINA & 0x7); // Color Calculation outstring = AddColorCalcInfo(outstring, 0x0001, 0x0002, Vdp2Regs->CCRNA & 0x1F, Vdp2Regs->SFCCMD & 0x3); // Color Offset outstring = AddColorOffsetInfo(outstring, 0x0001); AddString(outstring, "Special Color Calculation %d\r\n",(Vdp2Regs->SFCCMD>>0)&0x03); } else { // disabled *isenabled = 0; } } ////////////////////////////////////////////////////////////////////////////// void Vdp2DebugStatsNBG1(char *outstring, int *isenabled) { u16 lineVerticalScrollReg = (Vdp2Regs->SCRCTL >> 8) & 0x3F; int isbitmap=Vdp2Regs->CHCTLA & 0x200; int patternwh=((Vdp2Regs->CHCTLA & 0x100) >> 8) + 1; u8 map[4]; if (Vdp2Regs->BGON & 0x2) { // enabled *isenabled = 1; // Mosaic outstring = AddMosaicString(outstring, 0x2); // BPP outstring = AddBppString(outstring, (Vdp2Regs->CHCTLA & 0x3000) >> 12); // Bitmap or Tile mode? if (isbitmap) { // Bitmap outstring = AddBitmapInfoString(outstring, (Vdp2Regs->CHCTLA & 0xC00) >> 10, Vdp2Regs->BMPNA >> 8, Vdp2Regs->MPOFN >> 4); } else { int patterndatasize; u16 supplementdata=Vdp2Regs->PNCN1 & 0x3FF; int planew=0, planeh=0; if(Vdp2Regs->PNCN1 & 0x8000) patterndatasize = 1; else patterndatasize = 2; // Tile AddString(outstring, "Tile(%dH x %dV)\r\n", patternwh, patternwh); Vdp2GetPlaneSize((Vdp2Regs->PLSZ & 0xC) >> 2, &planew, &planeh); AddString(outstring, "Plane Size = %dH x %dV\r\n", planew, planeh); // Pattern Name Control stuff if (patterndatasize == 2) { AddString(outstring, "Pattern Name data size = 2 words\r\n"); } else { AddString(outstring, "Pattern Name data size = 1 word\r\n"); AddString(outstring, "Character Number Supplement bit = %d\r\n", (supplementdata >> 14) & 0x1); AddString(outstring, "Special Priority bit = %d\r\n", (supplementdata >> 9) & 0x1); AddString(outstring, "Special Color Calculation bit = %d\r\n", (supplementdata >> 8) & 0x1); AddString(outstring, "Supplementary Palette number = %d\r\n", (supplementdata >> 5) & 0x7); AddString(outstring, "Supplementary Color number = %d\r\n", supplementdata & 0x1f); } map[0] = Vdp2Regs->MPABN1 & 0xFF; map[1] = Vdp2Regs->MPABN1 >> 8; map[2] = Vdp2Regs->MPCDN1 & 0xFF; map[3] = Vdp2Regs->MPCDN1 >> 8; outstring = AddMapInfo(outstring, patternwh, Vdp2Regs->PNCN1, (Vdp2Regs->PLSZ & 0xC) >> 2, (Vdp2Regs->MPOFN & 0x70) << 2, 4, map); /* // Figure out Cell start address switch(patterndatasize) { case 1: { tmp = readWord(vram, addr); switch(auxMode) { case 0: switch(patternwh) { case 1: charAddr = (tmp & 0x3FF) | ((supplementdata & 0x1F) << 10); break; case 2: charAddr = ((tmp & 0x3FF) << 2) | (supplementdata & 0x3) | ((supplementdata & 0x1C) << 10); break; } break; case 1: switch(patternwh) { case 1: charAddr = (tmp & 0xFFF) | ((supplementdata & 0x1C) << 10); break; case 4: charAddr = ((tmp & 0xFFF) << 2) | (supplementdata & 0x3) | ((supplementdata & 0x10) << 10); break; } break; } break; } case 2: { unsigned short tmp1 = readWord(vram, addr); unsigned short tmp2 = readWord(vram, addr+2); charAddr = tmp2 & 0x7FFF; break; } } if (!(readWord(reg, 0x6) & 0x8000)) charAddr &= 0x3FFF; charAddr *= 0x20; // selon Runik AddString(outstring, "Cell Data Address = %X\r\n", charAddr); */ } /* // Screen scroll values AddString(outstring, "Screen Scroll x = %f, y = %f\r\n", (float)(reg->getLong(0x80) & 0x7FFFF00) / 65536, (float)(reg->getLong(0x84) & 0x7FFFF00) / 65536); */ AddString(outstring, "Screen Scroll x = %d, y = %d\r\n", - ((Vdp2Regs->SCXIN1 & 0x7FF) % 512), - ((Vdp2Regs->SCYIN1 & 0x7FF) % 512)); // Coordinate Increments AddString(outstring, "Coordinate Increments x = %f, y = %f\r\n", (float) 65536 / (Vdp2Regs->ZMXN1.all & 0x7FF00), (float) 65536 / (Vdp2Regs->ZMXN1.all & 0x7FF00)); // Reduction Enable switch ((Vdp2Regs->ZMCTL >> 8) & 3) { case 1: AddString(outstring, "Horizontal Reduction = 1/2\r\n"); break; case 2: case 3: AddString(outstring, "Horizontal Reduction = 1/4\r\n"); break; default: break; } if (lineVerticalScrollReg & 0x8) { AddString(outstring, "Line Zoom X enabled\r\n"); } if (lineVerticalScrollReg & 0x4) { AddString(outstring, "Line Scroll Vertical enabled\r\n"); } if (lineVerticalScrollReg & 0x2) { AddString(outstring, "Line Scroll Horizontal enabled\r\n"); } if (lineVerticalScrollReg & 0x6) { AddString(outstring, "Line Scroll Enabled\r\n"); AddString(outstring, "Line Scroll Table Address = %08X\r\n", (int)(0x05E00000 + ((Vdp2Regs->LSTA1.all & 0x7FFFE) << 1))); switch (lineVerticalScrollReg >> 4) { case 0: AddString(outstring, "Line Scroll Interval = Each Line\r\n"); break; case 1: AddString(outstring, "Line Scroll Interval = Every 2 Lines\r\n"); break; case 2: AddString(outstring, "Line Scroll Interval = Every 4 Lines\r\n"); break; case 3: AddString(outstring, "Line Scroll Interval = Every 8 Lines\r\n"); break; } } if (lineVerticalScrollReg & 0x1) { AddString(outstring, "Vertical Cell Scroll enabled\r\n"); AddString(outstring, "Vertical Cell Scroll Table Address = %08X\r\n", (int)(0x05E00000 + ((Vdp2Regs->VCSTA.all & 0x7FFFE) << 1))); } // Window Control outstring = AddWindowInfoString(outstring, Vdp2Regs->WCTLA >> 8, 0); // Shadow Control here // Color Ram Address Offset AddString(outstring, "Color Ram Address Offset = %X\r\n", (Vdp2Regs->CRAOFA & 0x70) << 4); // Special Priority Mode outstring = AddSpecialPriorityInfo(outstring, Vdp2Regs->SFPRMD >> 2); // Color Calculation Control here // Special Color Calculation Mode here // Priority Number AddString(outstring, "Priority = %d\r\n", (Vdp2Regs->PRINA >> 8) & 0x7); // Color Calculation outstring = AddColorCalcInfo(outstring, 0x0002, 0x0004, (Vdp2Regs->CCRNA >> 8) & 0x1F, (Vdp2Regs->SFCCMD >> 2) & 0x3); // Color Offset outstring = AddColorOffsetInfo(outstring, 0x0002); AddString(outstring, "Special Color Calculation %d\r\n",(Vdp2Regs->SFCCMD>>2)&0x03); } else // disabled *isenabled = 0; } ////////////////////////////////////////////////////////////////////////////// void Vdp2DebugStatsNBG2(char *outstring, int *isenabled) { u8 map[4]; if (Vdp2Regs->BGON & 0x4) { int patterndatasize; u16 supplementdata=Vdp2Regs->PNCN2 & 0x3FF; int planew=0, planeh=0; int patternwh=(Vdp2Regs->CHCTLB & 0x1) + 1; // enabled *isenabled = 1; // Mosaic outstring = AddMosaicString(outstring, 0x4); // BPP outstring = AddBppString(outstring, (Vdp2Regs->CHCTLB & 0x2) >> 1); if(Vdp2Regs->PNCN2 & 0x8000) patterndatasize = 1; else patterndatasize = 2; AddString(outstring, "Tile(%dH x %dV)\r\n", patternwh, patternwh); Vdp2GetPlaneSize((Vdp2Regs->PLSZ & 0x30) >> 4, &planew, &planeh); AddString(outstring, "Plane Size = %dH x %dV\r\n", planew, planeh); // Pattern Name Control stuff if (patterndatasize == 2) { AddString(outstring, "Pattern Name data size = 2 words\r\n"); } else { AddString(outstring, "Pattern Name data size = 1 word\r\n"); AddString(outstring, "Character Number Supplement bit = %d\r\n", (supplementdata >> 14) & 0x1); AddString(outstring, "Special Priority bit = %d\r\n", (supplementdata >> 9) & 0x1); AddString(outstring, "Special Color Calculation bit = %d\r\n", (supplementdata >> 8) & 0x1); AddString(outstring, "Supplementary Palette number = %d\r\n", (supplementdata >> 5) & 0x7); AddString(outstring, "Supplementary Color number = %d\r\n", supplementdata & 0x1f); } map[0] = Vdp2Regs->MPABN2 & 0xFF; map[1] = Vdp2Regs->MPABN2 >> 8; map[2] = Vdp2Regs->MPCDN2 & 0xFF; map[3] = Vdp2Regs->MPCDN2 >> 8; outstring = AddMapInfo(outstring, patternwh, Vdp2Regs->PNCN2, (Vdp2Regs->PLSZ >> 4) & 0x3, (Vdp2Regs->MPOFN & 0x700) >> 2, 4, map); /* // Figure out Cell start address switch(patterndatasize) { case 1: { tmp = readWord(vram, addr); switch(auxMode) { case 0: switch(patternwh) { case 1: charAddr = (tmp & 0x3FF) | ((supplementdata & 0x1F) << 10); break; case 2: charAddr = ((tmp & 0x3FF) << 2) | (supplementdata & 0x3) | ((supplementdata & 0x1C) << 10); break; } break; case 1: switch(patternwh) { case 1: charAddr = (tmp & 0xFFF) | ((supplementdata & 0x1C) << 10); break; case 4: charAddr = ((tmp & 0xFFF) << 2) | (supplementdata & 0x3) | ((supplementdata & 0x10) << 10); break; } break; } break; } case 2: { unsigned short tmp1 = readWord(vram, addr); unsigned short tmp2 = readWord(vram, addr+2); charAddr = tmp2 & 0x7FFF; break; } } if (!(readWord(reg, 0x6) & 0x8000)) charAddr &= 0x3FFF; charAddr *= 0x20; // selon Runik AddString(outstring, "Cell Data Address = %X\r\n", charAddr); */ // Screen scroll values AddString(outstring, "Screen Scroll x = %d, y = %d\r\n", - ((Vdp2Regs->SCXN2 & 0x7FF) % 512), - ((Vdp2Regs->SCYN2 & 0x7FF) % 512)); // Window Control outstring = AddWindowInfoString(outstring, Vdp2Regs->WCTLB, 0); // Shadow Control here // Color Ram Address Offset AddString(outstring, "Color Ram Address Offset = %X\r\n", Vdp2Regs->CRAOFA & 0x700); // Special Priority Mode outstring = AddSpecialPriorityInfo(outstring, Vdp2Regs->SFPRMD >> 4); // Color Calculation Control here // Special Color Calculation Mode here // Priority Number AddString(outstring, "Priority = %d\r\n", Vdp2Regs->PRINB & 0x7); // Color Calculation outstring = AddColorCalcInfo(outstring, 0x0004, 0x0005, Vdp2Regs->CCRNB & 0x1F, (Vdp2Regs->SFCCMD >> 4) & 0x3); // Color Offset outstring = AddColorOffsetInfo(outstring, 0x0004); AddString(outstring, "Special Color Calculation %d\r\n",(Vdp2Regs->SFCCMD>>4)&0x03); } else { // disabled *isenabled = 0; } } ////////////////////////////////////////////////////////////////////////////// void Vdp2DebugStatsNBG3(char *outstring, int *isenabled) { u8 map[4]; if (Vdp2Regs->BGON & 0x8) { int patterndatasize; u16 supplementdata=Vdp2Regs->PNCN3 & 0x3FF; int planew=0, planeh=0; int patternwh=((Vdp2Regs->CHCTLB & 0x10) >> 4) + 1; // enabled *isenabled = 1; // Mosaic outstring = AddMosaicString(outstring, 0x8); // BPP outstring = AddBppString(outstring, (Vdp2Regs->CHCTLB & 0x20) >> 5); if(Vdp2Regs->PNCN3 & 0x8000) patterndatasize = 1; else patterndatasize = 2; AddString(outstring, "Tile(%dH x %dV)\r\n", patternwh, patternwh); Vdp2GetPlaneSize((Vdp2Regs->PLSZ & 0xC0) >> 6, &planew, &planeh); AddString(outstring, "Plane Size = %dH x %dV\r\n", planew, planeh); // Pattern Name Control stuff if (patterndatasize == 2) { AddString(outstring, "Pattern Name data size = 2 words\r\n"); } else { AddString(outstring, "Pattern Name data size = 1 word\r\n"); AddString(outstring, "Character Number Supplement bit = %d\r\n", (supplementdata >> 14) & 0x1); AddString(outstring, "Special Priority bit = %d\r\n", (supplementdata >> 9) & 0x1); AddString(outstring, "Special Color Calculation bit = %d\r\n", (supplementdata >> 8) & 0x1); AddString(outstring, "Supplementary Palette number = %d\r\n", (supplementdata >> 5) & 0x7); AddString(outstring, "Supplementary Color number = %d\r\n", supplementdata & 0x1f); } map[0] = Vdp2Regs->MPABN3 & 0xFF; map[1] = Vdp2Regs->MPABN3 >> 8; map[2] = Vdp2Regs->MPCDN3 & 0xFF; map[3] = Vdp2Regs->MPCDN3 >> 8; outstring = AddMapInfo(outstring, patternwh, Vdp2Regs->PNCN3, (Vdp2Regs->PLSZ & 0xC0) >> 6, (Vdp2Regs->MPOFN & 0x7000) >> 6, 4, map); /* // Figure out Cell start address switch(patterndatasize) { case 1: { tmp = readWord(vram, addr); switch(auxMode) { case 0: switch(patternwh) { case 1: charAddr = (tmp & 0x3FF) | ((supplementdata & 0x1F) << 10); break; case 2: charAddr = ((tmp & 0x3FF) << 2) | (supplementdata & 0x3) | ((supplementdata & 0x1C) << 10); break; } break; case 1: switch(patternwh) { case 1: charAddr = (tmp & 0xFFF) | ((supplementdata & 0x1C) << 10); break; case 4: charAddr = ((tmp & 0xFFF) << 2) | (supplementdata & 0x3) | ((supplementdata & 0x10) << 10); break; } break; } break; } case 2: { unsigned short tmp1 = readWord(vram, addr); unsigned short tmp2 = readWord(vram, addr+2); charAddr = tmp2 & 0x7FFF; break; } } if (!(readWord(reg, 0x6) & 0x8000)) charAddr &= 0x3FFF; charAddr *= 0x20; // selon Runik AddString(outstring, "Cell Data Address = %X\r\n", charAddr); */ // Screen scroll values AddString(outstring, "Screen Scroll x = %d, y = %d\r\n", - ((Vdp2Regs->SCXN3 & 0x7FF) % 512), - ((Vdp2Regs->SCYN3 & 0x7FF) % 512)); // Window Control outstring = AddWindowInfoString(outstring, Vdp2Regs->WCTLB >> 8, 0); // Shadow Control here // Color Ram Address Offset AddString(outstring, "Color Ram Address Offset = %X\r\n", Vdp2Regs->CRAOFA & 0x7000); // Special Priority Mode outstring = AddSpecialPriorityInfo(outstring, Vdp2Regs->SFPRMD >> 6); // Special Color Calculation Mode here // Priority Number AddString(outstring, "Priority = %d\r\n", (Vdp2Regs->PRINB >> 8) & 0x7); // Color Calculation outstring = AddColorCalcInfo(outstring, 0x0008, 0x0006, (Vdp2Regs->CCRNB >> 8) & 0x1F, (Vdp2Regs->SFCCMD >> 6) & 0x3); // Color Offset outstring = AddColorOffsetInfo(outstring, 0x0008); AddString(outstring, "Special Color Calculation %d\r\n",(Vdp2Regs->SFCCMD>>6)&0x03); } else { // disabled *isenabled = 0; } } ////////////////////////////////////////////////////////////////////////////// void Vdp2DebugStatsGeneral(char *outstring, int *isenabled) { u8 *sprprilist = (u8 *)&Vdp2Regs->PRISA; u8 *sprccrlist = (u8 *)&Vdp2Regs->CCRSA; int i; if (Vdp2Regs->TVMD & 0x8000) { // TVMD stuff AddString(outstring, "Border Color Mode = %s\r\n", Vdp2Regs->TVMD & 0x100 ? "Back screen" : "Black"); AddString(outstring, "Display Resolution = "); switch (Vdp2Regs->TVMD & 0x7) { case 0: case 4: AddString(outstring, "320"); break; case 1: case 5: AddString(outstring, "352"); break; case 2: case 6: AddString(outstring, "640"); break; case 3: case 7: AddString(outstring, "704"); break; default: AddString(outstring, "Invalid"); break; } AddString(outstring, " x "); switch ((Vdp2Regs->TVMD >> 4) & 0x3) { case 0: AddString(outstring, "224"); break; case 1: AddString(outstring, "240"); break; case 2: AddString(outstring, "256"); break; default: AddString(outstring, "Invalid"); break; } if (Vdp2Regs->TVSTAT & 0x1) { AddString(outstring, "(PAL)\r\n"); } else { AddString(outstring, "(NTSC)\r\n"); } AddString(outstring, "Interlace Mode = "); switch ((Vdp2Regs->TVMD >> 6) & 0x3) { case 0: AddString(outstring, "Non-Interlace\r\n"); break; case 2: AddString(outstring, "Single-Density Interlace\r\n"); break; case 3: AddString(outstring, "Double-Density Interlace\r\n"); break; default: AddString(outstring, "Invalid\r\n"); break; } // Latch stuff AddString(outstring, "Latches HV counter when %s\r\n", Vdp2Regs->EXTEN & 0x200 ? "external signal triggers it" : "external latch flag is read"); if (Vdp2Regs->EXTEN & 0x100) { AddString(outstring, "External Sync is being inputed\r\n"); } // Screen status stuff if (Vdp2Regs->TVSTAT & 0x200) { AddString(outstring, "HV is latched\r\n"); } if (Vdp2Regs->TVSTAT & 0x4) { AddString(outstring, "During H-Blank\r\n"); } if (Vdp2Regs->TVSTAT & 0x8) { AddString(outstring, "During V-Blank\r\n"); } if ((Vdp2Regs->TVMD >> 6) & 0x2) { AddString(outstring, "During %s Field\r\n", Vdp2Regs->TVSTAT & 0x2 ? "Odd" : "Even"); } AddString(outstring, "H Counter = %d\r\n", Vdp2Regs->HCNT); AddString(outstring, "V Counter = %d\r\n", Vdp2Regs->VCNT); AddString(outstring, "\r\n"); // Line color screen stuff AddString(outstring, "Line Color Screen Stuff\r\n"); AddString(outstring, "-----------------------\r\n"); AddString(outstring, "Mode = %s\r\n", Vdp2Regs->LCTA.part.U & 0x8000 ? "Color per line" : "Single color"); AddString(outstring, "Address = %08lX\r\n", 0x05E00000UL | ((Vdp2Regs->LCTA.all & 0x7FFFFUL) * 2)); AddString(outstring, "\r\n"); // Back screen stuff AddString(outstring, "Back Screen Stuff\r\n"); AddString(outstring, "-----------------\r\n"); AddString(outstring, "Mode = %s\r\n", Vdp2Regs->BKTAU & 0x8000 ? "Color per line" : "Single color"); AddString(outstring, "Address = %08X\r\n", 0x05E00000 | (((Vdp2Regs->BKTAU & 0x7) << 16) | Vdp2Regs->BKTAL) * 2); outstring = AddColorOffsetInfo(outstring, 0x0020); AddString(outstring, "\r\n"); // Cycle patterns here // Sprite stuff AddString(outstring, "Sprite Stuff\r\n"); AddString(outstring, "------------\r\n"); AddString(outstring, "Sprite Type = %X\r\n", Vdp2Regs->SPCTL & 0xF); AddString(outstring, "VDP1 Framebuffer Data Format = %s\r\n", Vdp2Regs->SPCTL & 0x20 ? "RGB and palette" : "Palette only"); if (Vdp2Regs->SDCTL & 0x100) { AddString(outstring, "Transparent Shadow Enabled\r\n"); } if (Vdp2Regs->SPCTL & 0x20) { AddString(outstring, "Sprite Window Enabled\r\n"); } outstring = AddWindowInfoString(outstring, Vdp2Regs->WCTLC >> 8, 1); AddString(outstring, "Color RAM Offset = %X\r\n", (Vdp2Regs->CRAOFB >> 4) & 0x7); if (Vdp2Regs->CCCTL & 0x40) { AddString(outstring, "Color Calculation Enabled\r\n"); if (Vdp2Regs->CCCTL & 0x8000 && (Vdp2Regs->CCCTL & 0x0700) == 0) { AddString(outstring, "Gradation Calculation Enabled\r\n"); } else if (Vdp2Regs->CCCTL & 0x0400) { AddString(outstring, "Extended Color Calculation Enabled\r\n"); } AddString(outstring, "Color Calculation Condition = "); switch ((Vdp2Regs->SPCTL >> 12) & 0x3) { case 0: AddString(outstring, "Priority <= CC Condition Number"); break; case 1: AddString(outstring, "Priority == CC Condition Number"); break; case 2: AddString(outstring, "Priority >= CC Condition Number"); break; case 3: AddString(outstring, "Color Data MSB"); break; default: break; } AddString(outstring, "\r\n"); if (((Vdp2Regs->SPCTL >> 12) & 0x3) != 0x3) { AddString(outstring, "Color Calculation Condition Number = %d\r\n", (Vdp2Regs->SPCTL >> 8) & 0x7); } for (i = 0; i < 8; i++) { #ifdef WORDS_BIGENDIAN int ratio = sprccrlist[i ^ 1] & 0x7; #else int ratio = sprccrlist[i] & 0x7; #endif AddString(outstring, "Color Calculation Ratio %d = %d:%d\r\n", i, 31 - ratio, 1 + ratio); } } for (i = 0; i < 8; i++) { #ifdef WORDS_BIGENDIAN int priority = sprprilist[i ^ 1] & 0x7; #else int priority = sprprilist[i] & 0x7; #endif AddString(outstring, "Priority %d = %d\r\n", i, priority); } outstring = AddColorOffsetInfo(outstring, 0x0040); *isenabled = 1; } else { *isenabled = 0; } } ////////////////////////////////////////////////////////////////////////////// static u32 FASTCALL DoNothing(UNUSED void *info, u32 pixel) { return pixel; } ////////////////////////////////////////////////////////////////////////////// static void ClearTextureToColor(u32 *texture, u32 color, int w, int h) { int i; for (i = 0; i < (w * h); i++) texture[i] = color; } ////////////////////////////////////////////////////////////////////////////// pixel_t *Vdp2DebugTexture(u32 screen, int * w, int * h) { pixel_t * bitmap; TitanInit(); TitanSetBlendingMode(TITAN_BLEND_TOP); VIDSoftVdp2DrawScreen(screen); if ((bitmap = (pixel_t *)calloc(sizeof(pixel_t), 704 * 512)) == NULL) return NULL; TitanGetResolution(w, h); TitanRender(bitmap); return bitmap; } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/scsp.h000644 001750 001750 00000013177 12755623101 017174 0ustar00guillaumeguillaume000000 000000 /* Copyright 2004 Stephane Dallongeville Copyright 2004-2006 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ // Quick hack so nobody else needs to know we're using a different header file #ifdef USE_SCSP2 #include "scsp2.h" // defines SCSP_H #endif #ifndef SCSP_H #define SCSP_H #include "core.h" #include "memory.h" #define SNDCORE_DEFAULT -1 #define SNDCORE_DUMMY 0 #define SNDCORE_WAV 10 // should really be 1, but I'll probably break people's stuff #define SCSP_MUTE_SYSTEM 1 #define SCSP_MUTE_USER 2 typedef struct { int id; const char *Name; int (*Init)(void); void (*DeInit)(void); int (*Reset)(void); int (*ChangeVideoFormat)(int vertfreq); void (*UpdateAudio)(u32 *leftchanbuffer, u32 *rightchanbuffer, u32 num_samples); u32 (*GetAudioSpace)(void); void (*MuteAudio)(void); void (*UnMuteAudio)(void); void (*SetVolume)(int volume); #ifdef USE_SCSPMIDI int (*MidiChangePorts)(int inport, int outport); u8 (*MidiIn)(int *isdata); int (*MidiOut)(u8 data); #endif } SoundInterface_struct; typedef struct { u32 D[8]; u32 A[8]; u32 SR; u32 PC; } m68kregs_struct; typedef struct { u32 addr; } m68kcodebreakpoint_struct; #define MAX_BREAKPOINTS 10 typedef struct { u32 scsptiming1; u32 scsptiming2; // 16.16 fixed point m68kcodebreakpoint_struct codebreakpoint[MAX_BREAKPOINTS]; int numcodebreakpoints; void (*BreakpointCallBack)(u32); int inbreakpoint; } ScspInternal; extern SoundInterface_struct SNDDummy; extern SoundInterface_struct SNDWave; extern u8 *SoundRam; extern int use_new_scsp; u8 FASTCALL SoundRamReadByte(u32 addr); u16 FASTCALL SoundRamReadWord(u32 addr); u32 FASTCALL SoundRamReadLong(u32 addr); void FASTCALL SoundRamWriteByte(u32 addr, u8 val); void FASTCALL SoundRamWriteWord(u32 addr, u16 val); void FASTCALL SoundRamWriteLong(u32 addr, u32 val); u8 FASTCALL Sh2SoundRamReadByte(SH2_struct *sh, u32 addr); u16 FASTCALL Sh2SoundRamReadWord(SH2_struct *sh, u32 addr); u32 FASTCALL Sh2SoundRamReadLong(SH2_struct *sh, u32 addr); void FASTCALL Sh2SoundRamWriteByte(SH2_struct *sh, u32 addr, u8 val); void FASTCALL Sh2SoundRamWriteWord(SH2_struct *sh, u32 addr, u16 val); void FASTCALL Sh2SoundRamWriteLong(SH2_struct *sh, u32 addr, u32 val); int ScspInit(int coreid); int ScspChangeSoundCore(int coreid); void ScspDeInit(void); void M68KStart(void); void M68KStop(void); void ScspReset(void); int ScspChangeVideoFormat(int type); void M68KExec(s32 cycles); void ScspExec(void); void ScspConvert32uto16s(s32 *srcL, s32 *srcR, s16 *dst, u32 len); void ScspReceiveCDDA(const u8 *sector); void ScspReceiveMpeg (const u8 *samples, int len); int SoundSaveState(FILE *fp); int SoundLoadState(FILE *fp, int version, int size); void ScspSlotDebugStats(u8 slotnum, char *outstring); void ScspCommonControlRegisterDebugStats(char *outstring); int ScspSlotDebugSaveRegisters(u8 slotnum, const char *filename); u32 ScspSlotDebugAudio (u32 *workbuf, s16 *buf, u32 len); void ScspSlotResetDebug(u8 slotnum); int ScspSlotDebugAudioSaveWav(u8 slotnum, const char *filename); void ScspMuteAudio(int flags); void ScspUnMuteAudio(int flags); void ScspSetVolume(int volume); u8 FASTCALL ScspReadByte(u32 addr); void FASTCALL ScspWriteByte(u32 addr, u8 val); u16 FASTCALL ScspReadWord(u32 addr); void FASTCALL ScspWriteWord(u32 addr, u16 val); u32 FASTCALL ScspReadLong(u32 addr); void FASTCALL ScspWriteLong(u32 addr, u32 val); u8 FASTCALL Sh2ScspReadByte(SH2_struct *sh, u32 addr); void FASTCALL Sh2ScspWriteByte(SH2_struct *sh, u32 addr, u8 val); u16 FASTCALL Sh2ScspReadWord(SH2_struct *sh, u32 addr); void FASTCALL Sh2ScspWriteWord(SH2_struct *sh, u32 addr, u16 val); u32 FASTCALL Sh2ScspReadLong(SH2_struct *sh, u32 addr); void FASTCALL Sh2ScspWriteLong(SH2_struct *sh, u32 addr, u32 val); void scsp_init(u8 *scsp_ram, void (*sint_hand)(u32), void (*mint_hand)(void)); void scsp_shutdown(void); void scsp_reset(void); void scsp_midi_in_send(u8 data); void scsp_midi_out_send(u8 data); u8 scsp_midi_in_read(void); u8 scsp_midi_out_read(void); void scsp_update(s32 *bufL, s32 *bufR, u32 len); void scsp_update_monitor(void); void scsp_update_timer(u32 len); u32 FASTCALL c68k_byte_read(const u32 adr); u32 FASTCALL c68k_word_read(const u32 adr); void M68KStep(void); void M68KSync(void); void M68KWriteNotify(u32 address, u32 size); void M68KGetRegisters(m68kregs_struct *regs); void M68KSetRegisters(m68kregs_struct *regs); void M68KSetBreakpointCallBack(void (*func)(u32)); int M68KAddCodeBreakpoint(u32 addr); void M68KSortCodeBreakpoints(void); int M68KDelCodeBreakpoint(u32 addr); m68kcodebreakpoint_struct *M68KGetBreakpointList(void); void M68KClearCodeBreakpoints(void); void scsp_debug_instrument_get_data(int i, u32 * sa, int * is_muted); void scsp_debug_instrument_set_mute(u32 sa, int mute); void scsp_debug_instrument_clear(); void scsp_debug_get_envelope(int chan, int * env, int * state); void scsp_debug_set_mode(int mode); void scsp_set_use_new(int which); void new_scsp_exec(s32 cycles); extern int use_new_scsp; #endif yabause-0.9.15/src/yglcache.cpp000755 001750 001750 00000003410 12755623101 020326 0ustar00guillaumeguillaume000000 000000 /* Copyright 2011-2015 Shinya Miyamoto(devmiyax) This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_LIBGL extern "C" { #include "ygl.h" #include "yui.h" #include "vidshared.h" } #ifdef _WINDOWS #include using std::hash_map; #else #include using __gnu_cxx::hash_map; #endif hash_map< u32 , YglCache > g_TexHash; extern "C" { void YglCacheInit() { } ////////////////////////////////////////////////////////////////////////////// void YglCacheDeInit() { } ////////////////////////////////////////////////////////////////////////////// int YglIsCached(u32 addr, YglCache * c ) { hash_map< u32 , YglCache >::iterator pos = g_TexHash.find(addr); if( pos == g_TexHash.end() ) { return 0; } c->x=pos->second.x; c->y=pos->second.y; return 1; } ////////////////////////////////////////////////////////////////////////////// void YglCacheAdd(u32 addr, YglCache * c) { g_TexHash[addr] = *c; } ////////////////////////////////////////////////////////////////////////////// void YglCacheReset(void) { g_TexHash.clear(); } } #endif yabause-0.9.15/src/tools/000755 001750 001750 00000000000 12757373644 017222 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/tools/cdtest.c000644 001750 001750 00000015411 12755623101 020636 0ustar00guillaumeguillaume000000 000000 /******************************************************************************* CDTEST - Yabause CD interface tester (c) Copyright 2004-2005 Theo Berkau(cwx@cyberwarriorx.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 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 Street, Fifth Floor, Boston, MA 02110-1301 USA *******************************************************************************/ // This program is designed to be linked with any port's cd.c file. // example: gcc windows\cd.c tools\cdtest.c -o cdtest.exe // Once it's compiled, run it with the cdrom path as your argument // example: cdtest g: // SPECIAL NOTE: You need to use a regular saturn disc as your test cd to have // accurate test results. #include #include #include #include "../core.h" #include "../cdbase.h" #include "../m68kcore.h" #include "../peripheral.h" #include "../sh2core.h" #include "../scsp.h" #include "../vdp1.h" #define PROG_NAME "CDTEST" #define VER_NAME "1.01" #define COPYRIGHT_YEAR "2004-2005, 2014" int testspassed=0; u8 cdbuffer[2352]; u32 cdTOC[102]; // Unused functions and variables SH2Interface_struct *SH2CoreList[] = { NULL }; VideoInterface_struct *VIDCoreList[] = { NULL }; SoundInterface_struct *SNDCoreList[] = { NULL }; M68K_struct * M68KCoreList[] = { NULL }; CDInterface *CDCoreList[] = { NULL }; PerInterface_struct *PERCoreList[] = { NULL }; void YuiErrorMsg(const char *string) { } void YuiSwapBuffers() { } ////////////////////////////////////////////////////////////////////////////// void ProgramUsage() { printf("%s v%s - by Cyber Warrior X (c)%s\n", PROG_NAME, VER_NAME, COPYRIGHT_YEAR); printf("usage: %s \n", PROG_NAME); exit (1); } ////////////////////////////////////////////////////////////////////////////// void cleanup(void) { ArchCD.DeInit(); testspassed++; printf("Test Score: %d/11 \n", testspassed); } ////////////////////////////////////////////////////////////////////////////// int IsTOCValid(u32 *TOC) { u8 lasttrack=1; int i; // Make sure first track's FAD is 150 if ((TOC[0] & 0xFFFFFF) != 150) return 0; // Go through each track and make sure they start at FAD that's higher // than the previous track for (i = 1; i < 99; i++) { if (TOC[i] == 0xFFFFFFFF) break; lasttrack++; if ((TOC[i-1] & 0xFFFFFF) >= (TOC[i] & 0xFFFFFF)) return 0; } // Check Point A0 information if (TOC[99] & 0xFF) // PFRAME - Should always be 0 return 0; if (TOC[99] & 0xFF00) // PSEC - Saturn discs will be 0 return 0; if (((TOC[99] & 0xFF0000) >> 16) != 0x01) // PMIN - First track's number return 0; if ((TOC[99] & 0xFF000000) != (TOC[0] & 0xFF000000)) // First track's addr/ctrl return 0; // Check Point A1 information if (TOC[100] & 0xFF) // PFRAME - Should always be 0 return 0; if (TOC[100] & 0xFF00) // PSEC - Saturn discs will be 0 return 0; if (((TOC[100] & 0xFF0000) >> 16) != lasttrack) // PMIN - Last track's number return 0; if ((TOC[100] & 0xFF000000) != (TOC[lasttrack-1] & 0xFF000000)) // Last track's addr/ctrl return 0; // Check Point A2 information if ((TOC[101] & 0xFFFFFF) <= (TOC[lasttrack-1] & 0xFFFFFF)) // Lead out FAD should be larger than last track's FAD return 0; if ((TOC[101] & 0xFF000000) != (TOC[lasttrack-1] & 0xFF000000)) // Lead out's addr/ctrl should be the same as last track's return 0; return 1; } ////////////////////////////////////////////////////////////////////////////// int main(int argc, char *argv[]) { char *cdrom_name = NULL; u32 f_size=0; int status; char syncheader[12] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; atexit(cleanup); #ifndef _arch_dreamcast if (argc != 2) { ProgramUsage(); } printf("%s v%s - by Cyber Warrior X(c)%s\n", PROG_NAME, VER_NAME, COPYRIGHT_YEAR); cdrom_name = argv[1]; #endif if (ArchCD.Init(cdrom_name) != 0) { printf("CDInit error: Unable to initialize cdrom\n"); exit(1); } else testspassed++; // Let's make sure we're returning the proper status status = ArchCD.GetStatus(); if (status == 0 || status == 1) { testspassed++; if (ArchCD.ReadTOC(cdTOC) != (0xCC * 2)) { printf("CDReadToc error: return value was not the correct size\n"); } else testspassed++; // Make sure TOC is valid if (!IsTOCValid(cdTOC)) { printf("CDReadToc error: TOC data has some issues\n"); } else testspassed++; // Read sector 0 if (ArchCD.ReadSectorFAD(150, cdbuffer) != 1) { printf("CDReadSectorFAD error: Reading of LBA 0(FAD 150) returned false\n"); } else testspassed++; // Check cdbuffer to make sure contents are correct if (memcmp(syncheader, cdbuffer, 12) != 0) { printf("CDReadSectorFAD error: LBA 0(FAD 150) read is missing sync header\n"); } else testspassed++; // look for "SEGA SEGASATURN" if (memcmp("SEGA SEGASATURN", cdbuffer+0x10, 15) != 0) { printf("CDReadSectorFAD error: LBA 0(FAD 150)'s sector contents were not as expected\n"); } else testspassed++; // Read sector 16(I figured it makes a good random test sector) if (ArchCD.ReadSectorFAD(166, cdbuffer) != 1) { printf("CDReadSectorFAD error: Reading of LBA 16(FAD 166) returned false\n"); } else testspassed++; // Check cdbuffer to make sure contents are correct if (memcmp(syncheader, cdbuffer, 12) != 0) { printf("CDReadSectorFAD error: LBA 16(FAD 166) read is missing sync header\n"); } else testspassed++; // look for "CD001" if (memcmp("CD001", cdbuffer+0x11, 5) != 0) { printf("CDReadSectorFAD error: LBA 16(FAD 166)'s sector contents were not as expected\n"); } else testspassed++; } else { printf("CDGetStatus error: Can't continue the rest of the test - There's either no CD present or the tray is open\n"); exit(1); } } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/tools/CMakeLists.txt000644 001750 001750 00000000652 12755623101 021745 0ustar00guillaumeguillaume000000 000000 project( cdtest ) # C sources set( cdtest_SOURCES cdtest.c ) add_executable( cdtest ${cdtest_SOURCES} ) target_link_libraries( cdtest yabause ) target_link_libraries( cdtest ${YABAUSE_LIBRARIES} ) project( pertest ) # C sources set( pertest_SOURCES pertest.c ) add_executable( pertest ${pertest_SOURCES} ) target_link_libraries( pertest yabause ) target_link_libraries( pertest ${YABAUSE_LIBRARIES} ) yabause-0.9.15/src/tools/pertest.c000644 001750 001750 00000012201 12755623101 021030 0ustar00guillaumeguillaume000000 000000 /******************************************************************************* CDTEST - Yabause Peripheral interface tester (c) Copyright 2014 Theo Berkau(cwx@cyberwarriorx.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 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 Street, Fifth Floor, Boston, MA 02110-1301 USA *******************************************************************************/ // This program is designed to be linked with any port's per*.c file. // example: gcc perdx.c tools\pertest.c -o pertest.exe // Once it's compiled, run it with the peripheral core indexh as your argument // example: pertest 0 #include #include #include #include "../core.h" #include "../cdbase.h" #include "../m68kcore.h" #include "../peripheral.h" #include "../sh2core.h" #include "../scsp.h" #include "../vdp1.h" #ifdef __linux__ #include "../perlinuxjoy.h" #endif #include "../persdljoy.h" #ifdef __APPLE__ #include "../permacjoy.h" #endif #ifdef HAVE_DIRECTINPUT #include "../perdx.h" #endif #define PROG_NAME "PERTEST" #define VER_NAME "1.0" #define COPYRIGHT_YEAR "2014" int testspassed=0; PerInterface_struct *PERCoreList[] = { &PERDummy, #ifdef __linux__ &PERLinuxJoy, #endif #ifdef HAVE_LIBSDL &PERSDLJoy, #endif #ifdef __APPLE__ &PERMacJoy, #endif #ifdef HAVE_DIRECTINPUT &PERDIRECTX, #endif NULL }; PerInterface_struct *CurPer; // Unused functions and variables SH2Interface_struct *SH2CoreList[] = { NULL }; VideoInterface_struct *VIDCoreList[] = { NULL }; SoundInterface_struct *SNDCoreList[] = { NULL }; M68K_struct * M68KCoreList[] = { NULL }; CDInterface *CDCoreList[] = { NULL }; void YuiErrorMsg(const char *string) { } void YuiSwapBuffers() { } #ifdef HAVE_DIRECTINPUT HWND DXGetWindow() { return HWND_DESKTOP; } #endif ////////////////////////////////////////////////////////////////////////////// void ProgramUsage() { printf("%s v%s - by Cyber Warrior X (c)%s\n", PROG_NAME, VER_NAME, COPYRIGHT_YEAR); printf("usage: %s \n", PROG_NAME); exit (1); } ////////////////////////////////////////////////////////////////////////////// void cleanup(void) { if (CurPer) { CurPer->DeInit(); testspassed++; printf("Test Score: %d/11 \n", testspassed); } } ////////////////////////////////////////////////////////////////////////////// int TestInput(const char *msg, u32 flags, u64 timeout, u64 tickfreq) { u64 time1, time2; u32 id; u32 startid; startid = CurPer->Scan(flags); printf("%s Timeout in %d seconds\n", msg, timeout); time1 = YabauseGetTicks(); time2 = YabauseGetTicks(); timeout = timeout * tickfreq; while ((id = CurPer->Scan(flags)) == 0 && (time2-time1) < timeout) time2 = YabauseGetTicks(); if (startid != 0) { printf("Data present before press. result code: %08X", startid); return 0; } if (id != 0) { printf("result code: %08X", id); return 1; } else return 0; } ////////////////////////////////////////////////////////////////////////////// u64 GetTickFreq() { u64 tickfreq; #ifdef WIN32 QueryPerformanceFrequency((LARGE_INTEGER *)&tickfreq); #elif defined(_arch_dreamcast) tickfreq = 1000; #elif defined(GEKKO) tickfreq = secs_to_ticks(1); #elif defined(PSP) tickfreq = 1000000; #elif defined(HAVE_GETTIMEOFDAY) tickfreq = 1000000; #elif defined(HAVE_LIBSDL) tickfreq = 1000; #endif return tickfreq; } ////////////////////////////////////////////////////////////////////////////// int main(int argc, char *argv[]) { char *cdrom_name = NULL; u32 f_size=0; int per_index=0; u64 tickfreq; tickfreq = GetTickFreq(); atexit(cleanup); #ifndef _arch_dreamcast if (argc != 2) { ProgramUsage(); } printf("%s v%s - by Cyber Warrior X(c)%s\n", PROG_NAME, VER_NAME, COPYRIGHT_YEAR); per_index = atoi(argv[1]); #endif if (per_index < 0 || per_index >= (sizeof(PERCoreList) / sizeof(PerInterface_struct *))) { printf("peripheral core index out of range\n"); exit(1); } CurPer = PERCoreList[per_index]; printf("Testing %s\n", CurPer->Name); if (CurPer->Init() != 0) { printf("PerInit error: Unable to initialize peripheral core\n"); exit(1); } else testspassed++; testspassed += TestInput("Press a button on a gamepad/joystick...", PERSF_BUTTON, 10, tickfreq); testspassed += TestInput("Press a key on the keyboard...", PERSF_KEY, 10, tickfreq); testspassed += TestInput("Move d-pad/stick on a gamepad/joystick...", PERSF_AXIS|PERSF_BUTTON, 10, tickfreq); testspassed += TestInput("Move mouse...", PERSF_MOUSEMOVE, 10, tickfreq); } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/scsp.c000644 001750 001750 00000500420 12757373537 017200 0ustar00guillaumeguillaume000000 000000 /* * Copyright 2004 Stephane Dallongeville * Copyright 2004-2007 Theo Berkau * Copyright 2006 Guillaume Duhamel * Copyright 2012 Chris Lord * * This file is part of Yabause. * * Yabause 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. * * Yabause 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 Yabause; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file scsp.c \brief SCSP emulation functions. */ //////////////////////////////////////////////////////////////// // Custom Sound Processor // note: model2 scsp is mapped to 0x100000~0x100ee4 of the space, but seems to // have additional hw ports ($40a~$410) // note: it seems that the user interrupt is used by the sound driver to reset // the subsystem //-------------------------------------------------------------- // // Common Control Register (CCR) // // $+00 $+01 // $400 ---- --12 3333 4444 1:MEM4MB memory size 2:DAC18B dac for digital output 3:VER version number 4:MVOL // $402 ---- ---1 1222 2222 1:RBL ring buffer length 2:RBP lead address // $404 ---1 2345 6666 6666 1:MOFULL out fifo full 2:MOEMP empty 3:MIOVF overflow 4:MIFULL in 5:MIEMP 6:MIBUF // $406 ---- ---- 1111 1111 1:MOBUF midi output data buffer // $408 1111 1222 2334 4444 1:MSLC monitor slot 2:CA call address 3:SGC Slot phase 4:EG Slot envelope // $40a ---- ---- ---- ---- // $40c ---- ---- ---- ---- // $40e ---- ---- ---- ---- // $410 ---- ---- ---- ---- // $412 1111 1111 1111 111- 1:DMEAL transfer start address (sound) // $414 1111 2222 2222 222- 1:DMEAH transfer start address hi 2:DRGA start register address (dsp) // $416 -123 4444 4444 444- 1:DGATE transfer gate 0 clear 2:DDIR direction 3:DEXE start 4:DTLG data count // $418 ---- -111 2222 2222 1:TACTL timer a prescalar control 2:TIMA timer a count data // $41a ---- -111 2222 2222 1:TBCTL timer b prescalar control 2:TIMB timer b count data // $41c ---- -111 2222 2222 2:TCCTL timer c prescalar control 2:TIMC timer c count data // $41e ---- -111 1111 1111 1:SCIEB allow sound cpu interrupt // $420 ---- -111 1111 1111 1:SCIPD request sound cpu interrupt // $422 ---- -111 1111 1111 1:SCIRE reset sound cpu interrupt // $424 ---- ---- 1111 1111 1:SCILV0 sound cpu interrupt level bit0 // $426 ---- ---- 1111 1111 1:SCILV1 sound cpu interrupt level bit1 // $428 ---- ---- 1111 1111 1:SCILV2 sound cpu interrupt level bit2 // $42a ---- -111 1111 1111 1:MCIEB allow main cpu interrupt // $42c ---- -111 1111 1111 1:MCIPD request main cpu interrupt // $42e ---- -111 1111 1111 1:MCIRE reset main cpu interrupt // //-------------------------------------------------------------- // // Individual Slot Register (ISR) // // $+00 $+01 // $00 ---1 2334 4556 7777 1:KYONEX 2:KYONB 3:SBCTL 4:SSCTL 5:LPCTL 6:PCM8B 7:SA start address // $02 1111 1111 1111 1111 1:SA start address // $04 1111 1111 1111 1111 1:LSA loop start address // $06 1111 1111 1111 1111 1:LEA loop end address // $08 1111 1222 2234 4444 1:D2R decay 2 rate 2:D1R decay 1 rate 3:EGHOLD eg hold mode 4:AR attack rate // $0a -122 2233 3334 4444 1:LPSLNK loop start link 2:KRS key rate scaling 3:DL decay level 4:RR release rate // $0c ---- --12 3333 3333 1:STWINH stack write inhibit 2:SDIR sound direct 3:TL total level // $0e 1111 2222 2233 3333 1:MDL modulation level 2:MDXSL modulation input x 3:MDYSL modulation input y // $10 -111 1-22 2222 2222 1:OCT octave 2:FNS frequency number switch // $12 1222 2233 4445 5666 1:LFORE 2:LFOF 3:PLFOWS 4:PLFOS 5:ALFOWS 6:ALFOS // $14 ---- ---- -111 1222 1:ISEL input select 2:OMXL input mix level // $16 1112 2222 3334 4444 1:DISDL 2:DIPAN 3:EFSDL 4:EFPAN // //-------------------------------------------------------------- #include #include #include #include #include "c68k/c68k.h" #include "cs2.h" #include "debug.h" #include "error.h" #include "memory.h" #include "m68kcore.h" #include "scu.h" #include "yabause.h" #include "scsp.h" #include "scspdsp.h" #if 0 #include "windows/aviout.h" #endif #ifdef PSP # include "psp/common.h" /* Macro to write a variable's value through the cache to main memory */ # define WRITE_THROUGH(var) (*(u32 *)((u32)&(var) | 0x40000000) = (var)) /* Macro to flush SCSP state so it can be read from the ME */ # define FLUSH_SCSP() sceKernelDcacheWritebackRange(&scsp, sizeof(scsp)) #else // !PSP # define WRITE_THROUGH(var) /*nothing*/ # define FLUSH_SCSP() /*nothing*/ #endif int use_new_scsp = 0; int new_scsp_outbuf_pos = 0; s32 new_scsp_outbuf_l[900] = { 0 }; s32 new_scsp_outbuf_r[900] = { 0 }; int new_scsp_cycles = 0; enum EnvelopeStates { ATTACK, DECAY1, DECAY2, RELEASE }; //0x30 to 0x3f only const u8 attack_rate_table[][4] = { { 4,4,4,4 },//0x30 { 3,4,4,4 }, { 3,4,3,4 }, { 3,3,3,4 }, { 3,3,3,3 }, { 2,3,3,3 }, { 2,3,2,3 }, { 2,2,2,3 }, { 2,2,2,2 }, { 1,2,2,2 }, { 1,2,1,2 }, { 1,1,1,2 }, { 1,1,1,1 },//0x3c { 1,1,1,1 },//0x3d { 1,1,1,1 },//0x3e { 1,1,1,1 },//0x3f }; const u8 decay_rate_table[][4] = { { 1,1,1,1 },//0x30 { 2,1,1,1 }, { 2,1,2,1 }, { 2,2,2,1 }, { 2,2,2,2 }, { 4,2,2,2 }, { 4,2,4,2 }, { 4,4,4,2 }, { 4,4,4,4 }, { 8,4,4,4 }, { 8,4,8,4 }, { 8,8,8,4 }, { 8,8,8,8 },//0x3c { 8,8,8,8 },//0x3d { 8,8,8,8 },//0x3e { 8,8,8,8 },//0x3f }; #define EFFECTIVE_RATE_END 0xffff //effective rate step table //settings 0x2 to 0x5, then repeats with bigger shifts //EFFECTIVE_RATE_END represents going back to the beginning of a row since //the number of steps is not the same for each setting #define MAKE_TABLE(SHIFT) \ { 8192 >> SHIFT, 4096 >> SHIFT, 4096 >> SHIFT, EFFECTIVE_RATE_END,EFFECTIVE_RATE_END,EFFECTIVE_RATE_END,EFFECTIVE_RATE_END, EFFECTIVE_RATE_END }, \ { 8192 >> SHIFT, 4096 >> SHIFT, 4096 >> SHIFT, 4096 >> SHIFT, 4096 >> SHIFT, 4096 >> SHIFT, 4096 >> SHIFT, EFFECTIVE_RATE_END }, \ { 4096 >> SHIFT, EFFECTIVE_RATE_END,EFFECTIVE_RATE_END,EFFECTIVE_RATE_END,EFFECTIVE_RATE_END, EFFECTIVE_RATE_END,EFFECTIVE_RATE_END , EFFECTIVE_RATE_END }, \ { 4096 >> SHIFT, 4096 >> SHIFT, 4096 >> SHIFT, 2048 >> SHIFT, 2048 >> SHIFT, EFFECTIVE_RATE_END, EFFECTIVE_RATE_END, EFFECTIVE_RATE_END }, const u16 envelope_table[][8] = { MAKE_TABLE(0) MAKE_TABLE(1) MAKE_TABLE(2) MAKE_TABLE(3) MAKE_TABLE(4) MAKE_TABLE(5) MAKE_TABLE(6) MAKE_TABLE(7) MAKE_TABLE(8) MAKE_TABLE(9) MAKE_TABLE(10) MAKE_TABLE(11) MAKE_TABLE(12) }; //unknown stored bits are unknown1-5 struct SlotRegs { u8 kx; u8 kb; u8 sbctl; u8 ssctl; u8 lpctl; u8 pcm8b; u32 sa; u16 lsa; u16 lea; u8 d2r; u8 d1r; u8 hold; u8 ar; u8 unknown1; u8 ls; u8 krs; u8 dl; u8 rr; u8 unknown2; u8 si; u8 sd; u16 tl; u8 mdl; u8 mdxsl; u8 mdysl; u8 unknown3; u8 oct; u8 unknown4; u16 fns; u8 re; u8 lfof; u8 plfows; u8 plfos; u8 alfows; u8 alfos; u8 unknown5; u8 isel; u8 imxl; u8 disdl; u8 dipan; u8 efsdl; u8 efpan; }; struct SlotState { u16 wave; int backwards; enum EnvelopeStates envelope; s16 output; u16 attenuation; int step_count; u32 sample_counter; u32 envelope_steps_taken; s32 waveform_phase_value; s32 sample_offset; u32 address_pointer; u32 lfo_counter; u32 lfo_pos; int num; int is_muted; }; struct Slot { //registers struct SlotRegs regs; //internal state struct SlotState state; }; struct Scsp { u16 sound_stack[64]; struct Slot slots[32]; int debug_mode; }new_scsp; //samples per step through a 256 entry lfo table const int lfo_step_table[0x20] = { 0x3fc,//0 0x37c,//1 0x2fc,//2 0x27c,//3 0x1fc,//4 0x1bc,//5 0x17c,//6 0x13c,//7 0x0fc,//8 0x0bc,//9 0x0dc,//0xa 0x08c,//0xb 0x07c,//0xc 0x06c,//0xd 0x05c,//0xe 0x04c,//0xf 0x03c,//0x10 0x034,//0x11 0x02c,//0x12 0x024,//0x13 0x01c,//0x14 0x018,//0x15 0x014,//0x16 0x010,//0x17 0x00c,//0x18 0x00a,//0x19 0x008,//0x1a 0x006,//0x1b 0x004,//0x1c 0x003,//0x1d 0x002,//0x1e 0x001,//0x1f }; struct PlfoTables { s8 saw_table[256]; s8 square_table[256]; s8 tri_table[256]; s8 noise_table[256]; }; struct PlfoTables plfo; struct AlfoTables { u8 saw_table[256]; u8 square_table[256]; u8 tri_table[256]; u8 noise_table[256]; }; struct AlfoTables alfo; void fill_plfo_tables() { int i; //saw for (i = 0; i < 256; i++) { if (i < 128) plfo.saw_table[i] = i; else plfo.saw_table[i] = -256 + i; } //square for (i = 0; i < 256; i++) { if (i < 128) plfo.square_table[i] = 127; else plfo.square_table[i] = -128; } //triangular for (i = 0; i < 256; i++) { if (i < 64) plfo.tri_table[i] = i * 2; else if (i < 192) plfo.tri_table[i] = 255 - (i * 2); else plfo.tri_table[i] = (i * 2) - 512; } //noise for (i = 0; i < 256; i++) { plfo.noise_table[i] = rand() & 0xff; } } void fill_alfo_tables() { int i; //saw for (i = 0; i < 256; i++) { alfo.saw_table[i] = i; } //square for (i = 0; i < 256; i++) { if (i < 128) alfo.square_table[i] = 0; else alfo.square_table[i] = 0xff; } //triangular for (i = 0; i < 256; i++) { if (i < 128) alfo.tri_table[i] = i * 2; else alfo.tri_table[i] = 255 - (i * 2); } //noise for (i = 0; i < 256; i++) { alfo.noise_table[i] = rand() & 0xff; } } //pg, plfo void op1(struct Slot * slot) { u32 oct = slot->regs.oct ^ 8; u32 fns = slot->regs.fns ^ 0x400; u32 phase_increment = fns << oct; int plfo_val = 0; int plfo_shifted = 0; if (slot->state.attenuation > 0x3bf) return; if (slot->state.lfo_counter % lfo_step_table[slot->regs.lfof] == 0) { slot->state.lfo_counter = 0; slot->state.lfo_pos++; if (slot->state.lfo_pos > 0xff) slot->state.lfo_pos = 0; } if (slot->regs.plfows == 0) plfo_val = plfo.saw_table[slot->state.lfo_pos]; else if (slot->regs.plfows == 1) plfo_val = plfo.square_table[slot->state.lfo_pos]; else if (slot->regs.plfows == 2) plfo_val = plfo.tri_table[slot->state.lfo_pos]; else if (slot->regs.plfows == 3) plfo_val = plfo.noise_table[slot->state.lfo_pos]; plfo_shifted = (plfo_val << slot->regs.plfos) >> 2; slot->state.waveform_phase_value &= (1 << 18) - 1;//18 fractional bits slot->state.waveform_phase_value += (phase_increment + plfo_shifted); } int get_slot(struct Slot * slot, int mdsl) { return (mdsl + slot->state.num) & 0x1f; } //address pointer calculation //modulation data read void op2(struct Slot * slot, struct Scsp * s) { s32 md_out = 0; s32 sample_delta = slot->state.waveform_phase_value >> 18; if (slot->state.attenuation > 0x3bf) return; if (slot->regs.mdl) { //averaging operation u32 x_sel = get_slot(slot, slot->regs.mdxsl); u32 y_sel = get_slot(slot, slot->regs.mdysl); s16 xd = s->sound_stack[x_sel]; s16 yd = s->sound_stack[y_sel]; s32 zd = (xd + yd) / 2; //modulation operation u16 shift = 0xf - (slot->regs.mdl); zd >>= shift; md_out = zd; } //address pointer if (slot->regs.lpctl == 0)//no loop { slot->state.sample_offset += sample_delta; if (slot->state.sample_offset >= slot->regs.lea) slot->state.attenuation = 0x3ff; } else if (slot->regs.lpctl == 1)//normal loop { slot->state.sample_offset += sample_delta; if (slot->state.sample_offset >= slot->regs.lea) slot->state.sample_offset = slot->regs.lsa; } else if (slot->regs.lpctl == 2)//reverse { if (!slot->state.backwards) slot->state.sample_offset += sample_delta; else slot->state.sample_offset -= sample_delta; if (!slot->state.backwards) { if (slot->state.sample_offset >= slot->regs.lea) { slot->state.sample_offset = slot->regs.lea; slot->state.backwards = 1; } } else { //backwards if (slot->state.sample_offset <= slot->regs.lsa) slot->state.sample_offset = slot->regs.lea; } } else if (slot->regs.lpctl == 3)//ping pong { if(!slot->state.backwards) slot->state.sample_offset += sample_delta; else slot->state.sample_offset -= sample_delta; if (!slot->state.backwards) { if (slot->state.sample_offset >= slot->regs.lea) { slot->state.sample_offset = slot->regs.lea; slot->state.backwards = 1; } } else { if (slot->state.sample_offset <= slot->regs.lsa) { slot->state.sample_offset = slot->regs.lsa; slot->state.backwards = 0; } } } if (!slot->regs.pcm8b) slot->state.address_pointer = (s32)slot->regs.sa + (slot->state.sample_offset + md_out) * 2; else slot->state.address_pointer = (s32)slot->regs.sa + (slot->state.sample_offset + md_out); } //waveform dram read void op3(struct Slot * slot) { u32 addr = (slot->state.address_pointer) & 0x7FFFF; if (slot->state.attenuation > 0x3bf) return; if (!slot->regs.pcm8b) slot->state.wave = c68k_word_read(addr); else slot->state.wave = c68k_byte_read(addr) << 8; slot->state.output = slot->state.wave; } void change_envelope_state(struct Slot * slot, enum EnvelopeStates new_state) { slot->state.envelope = new_state; slot->state.step_count = 0; } int need_envelope_step(int effective_rate, u32 sample_counter, struct Slot* slot) { if (sample_counter == 0) return 0; if (effective_rate == 0 || effective_rate == 1) { return 0;//never step } else if (effective_rate >= 0x30) { if ((sample_counter & 1) == 0) { slot->state.envelope_steps_taken++; return 1; } else return 0; } else { int pos = effective_rate - 2; int result = 0; int value = envelope_table[pos][slot->state.step_count]; if (sample_counter % value == 0) { result = 1; slot->state.envelope_steps_taken++; slot->state.step_count++; if (envelope_table[pos][slot->state.step_count] == EFFECTIVE_RATE_END) slot->state.step_count = 0;//reached the end of the array } return result; } return 0; } s32 get_rate(struct Slot * slot, int rate) { s32 result = 0; if (slot->regs.krs == 0xf) result = rate * 2; else { result = (slot->regs.krs * 2) + (rate * 2) + ((slot->regs.fns >> 9) & 1); result = (8 ^ slot->regs.oct) + (result - 8); } if (result <= 0) return 0; if (result >= 0x3c) return 0x3c; return result; } void do_decay(struct Slot * slot, int rate_in) { int rate = get_rate(slot, rate_in); int sample_mod_4 = slot->state.envelope_steps_taken & 3; int decay_rate; if (rate <= 0x30) decay_rate = decay_rate_table[0][sample_mod_4]; else decay_rate = decay_rate_table[rate - 0x30][sample_mod_4]; if (need_envelope_step(rate, slot->state.sample_counter, slot)) { if (slot->state.attenuation < 0x3bf) slot->state.attenuation += decay_rate; } } //interpolation //eg void op4(struct Slot * slot) { int sample_mod_4 = slot->state.envelope_steps_taken & 3; if (slot->state.attenuation >= 0x3bf) return; if (slot->state.envelope == ATTACK) { int rate = get_rate(slot, slot->regs.ar); int need_step = need_envelope_step(rate, slot->state.sample_counter, slot); if (need_step) { int attack_rate = 0; if (rate <= 0x30) attack_rate = attack_rate_table[0][sample_mod_4]; else attack_rate = attack_rate_table[rate - 0x30][sample_mod_4]; slot->state.attenuation -= ((slot->state.attenuation >> attack_rate)) + 1; if (slot->state.attenuation == 0) change_envelope_state(slot, DECAY1); } } else if (slot->state.envelope == DECAY1) { do_decay(slot,slot->regs.d1r); if ((slot->state.attenuation >> 5) >= slot->regs.dl) change_envelope_state(slot, DECAY2); } else if (slot->state.envelope == DECAY2) do_decay(slot, slot->regs.d2r); else if (slot->state.envelope == RELEASE) do_decay(slot, slot->regs.rr); } s16 apply_volume(u16 tl, u16 slot_att, const s16 s) { u32 tl_att = tl * 4; u32 att_clipped = 0; s32 sample_att = 0; u32 shift = 0; tl_att += slot_att; att_clipped = tl_att; att_clipped &= 0x3f; att_clipped ^= 0x7f; att_clipped += 1; sample_att = s * att_clipped; shift = tl_att >> 6; sample_att = sample_att >> (shift + 7); return sample_att; } //level 1 void op5(struct Slot * slot) { if (slot->state.attenuation > 0x3bf) { slot->state.output = 0; return; } else { int alfo_val = 0; int lfo_add = 0; s16 sample = 0; if (slot->regs.alfows == 0) alfo_val = alfo.saw_table[slot->state.lfo_pos]; else if (slot->regs.alfows == 1) alfo_val = alfo.square_table[slot->state.lfo_pos]; else if (slot->regs.alfows == 2) alfo_val = alfo.tri_table[slot->state.lfo_pos]; else if (slot->regs.alfows == 3) alfo_val = alfo.noise_table[slot->state.lfo_pos]; lfo_add = (((alfo_val + 1)) >> (7 - slot->regs.alfos)) << 1; sample = apply_volume(slot->regs.tl, slot->state.attenuation + lfo_add, slot->state.output); slot->state.output = sample; } } //level 2 void op6(struct Slot * slot) { } //sound stack write void op7(struct Slot * slot, struct Scsp*s) { u32 previous = s->sound_stack[slot->state.num + 32]; s->sound_stack[slot->state.num + 32] = slot->state.output; s->sound_stack[slot->state.num] = previous; slot->state.sample_counter++; slot->state.lfo_counter++; } struct DebugInstrument { u32 sa; int is_muted; }; #define NUM_DEBUG_INSTRUMENTS 24 struct DebugInstrument debug_instruments[NUM_DEBUG_INSTRUMENTS] = { 0 }; int debug_instrument_pos = 0; void scsp_debug_search_instruments(const u32 sa, int* found, int * offset) { int i = 0; *found = 0; for (i = 0; i < NUM_DEBUG_INSTRUMENTS; i++) { if (debug_instruments[i].sa == sa) { *found = 1; break; } } *offset = i; } void scsp_debug_add_instrument(u32 sa) { int i = 0, found = 0, offset = 0; if (debug_instrument_pos >= NUM_DEBUG_INSTRUMENTS) return; scsp_debug_search_instruments(sa, &found, &offset); //new instrument discovered if (!found) debug_instruments[debug_instrument_pos++].sa = sa; } void scsp_debug_instrument_set_mute(u32 sa, int mute) { int found = 0, offset = 0; scsp_debug_search_instruments(sa, &found, &offset); if (offset >= NUM_DEBUG_INSTRUMENTS) return; if (found) debug_instruments[offset].is_muted = mute; } int scsp_debug_instrument_check_is_muted(u32 sa) { int found = 0, offset = 0; scsp_debug_search_instruments(sa, &found, &offset); if (offset >= NUM_DEBUG_INSTRUMENTS) return 0; if (found && debug_instruments[offset].is_muted) return 1; return 0; } void scsp_debug_instrument_get_data(int i, u32 * sa, int * is_muted) { if(i >= NUM_DEBUG_INSTRUMENTS) return; *sa = debug_instruments[i].sa; *is_muted = debug_instruments[i].is_muted; } void scsp_debug_set_mode(int mode) { new_scsp.debug_mode = mode; } void scsp_debug_instrument_clear() { debug_instrument_pos = 0; memset(debug_instruments, 0, sizeof(struct DebugInstrument) * NUM_DEBUG_INSTRUMENTS); } void scsp_debug_get_envelope(int chan, int * env, int * state) { *env = new_scsp.slots[chan].state.attenuation; *state = new_scsp.slots[chan].state.envelope; } void keyon(struct Slot * slot) { if (slot->state.envelope == RELEASE) { slot->state.envelope = ATTACK; slot->state.attenuation = 0x280; slot->state.sample_counter = 0; slot->state.step_count = 0; slot->state.sample_offset = 0; slot->state.envelope_steps_taken = 0; if (new_scsp.debug_mode) scsp_debug_add_instrument(slot->regs.sa); } //otherwise ignore } void keyoff(struct Slot * slot) { change_envelope_state(slot, RELEASE); } void keyonex(struct Scsp *s) { int channel; for (channel = 0; channel < 32; channel++) { if (s->slots[channel].regs.kb) keyon(&s->slots[channel]); else keyoff(&s->slots[channel]); } } void scsp_slot_write_byte(struct Scsp *s, u32 addr, u8 data) { int slot_num = (addr >> 5) & 0x1f; struct Slot * slot = &s->slots[slot_num]; u32 offset = (addr - (0x20 * slot_num)); switch (offset) { case 0: slot->regs.kb = (data >> 3) & 1;//has to be done first if ((data >> 4) & 1)//keyonex keyonex(s); slot->regs.sbctl = (data >> 1) & 3; slot->regs.ssctl = (slot->regs.ssctl & 1) | ((data & 1) << 1); break; case 1: slot->regs.ssctl = (slot->regs.ssctl & 2) | ((data >> 7) & 1); slot->regs.lpctl = (data >> 5) & 3; slot->regs.pcm8b = (data >> 4) & 1; slot->regs.sa = (slot->regs.sa & 0xffff) | ((data & 0xf) << 16); break; case 2: slot->regs.sa = (slot->regs.sa & 0xf00ff) | (data << 8); break; case 3: slot->regs.sa = (slot->regs.sa & 0xfff00) | data; break; case 4: slot->regs.lsa = (slot->regs.lsa & 0x00ff) | (data << 8); break; case 5: slot->regs.lsa = (slot->regs.lsa & 0xff00) | data; break; case 6: slot->regs.lea = (slot->regs.lea & 0x00ff) | (data << 8); break; case 7: slot->regs.lea = (slot->regs.lea & 0xff00) | data; break; case 8: slot->regs.d2r = (data >> 3) & 0x1f; slot->regs.d1r = (slot->regs.d1r & 3) | ((data & 0x7) << 2); break; case 9: slot->regs.d1r = (slot->regs.d1r & 0x1c) | ((data >> 6) & 3); slot->regs.hold = (data >> 5) & 1; slot->regs.ar = data & 0x1f; break; case 10: slot->regs.unknown1 = (data >> 7) & 1; slot->regs.ls = (data >> 6) & 1; slot->regs.krs = (data >> 2) & 0xf; slot->regs.dl = (slot->regs.dl & 0x7) | ((data & 3) << 3); break; case 11: slot->regs.dl = (slot->regs.dl & 0x18) | ((data >> 5) & 7); slot->regs.rr = data & 0x1f; break; case 12: slot->regs.unknown2 = (data >> 2) & 3; slot->regs.si = (data >> 1) & 1; slot->regs.sd = data & 1; break; case 13: slot->regs.tl = data; break; case 14: slot->regs.mdl = (data >> 4) & 0xf; slot->regs.mdxsl = (slot->regs.mdxsl & 0x3) | ((data & 0xf) << 2); break; case 15: slot->regs.mdxsl = (slot->regs.mdxsl & 0x3C) | ((data >> 6) & 3); slot->regs.mdysl = data & 0x3f; break; case 16: slot->regs.unknown3 = (data >> 7) & 1; slot->regs.oct = (data >> 3) & 0xf; slot->regs.unknown4 = (data >> 2) & 1; slot->regs.fns = (slot->regs.fns & 0xff) | ((data & 3) << 8); break; case 17: slot->regs.fns = (slot->regs.fns & 0x300) | data; break; case 18: slot->regs.re = (data >> 7) & 1; slot->regs.lfof = (data >> 2) & 0x1f; slot->regs.plfows = data & 3; break; case 19: slot->regs.plfos = (data >> 5) & 7; slot->regs.alfows = (data >> 3) & 3; slot->regs.alfos = data & 7; break; case 20: //nothing here break; case 21: slot->regs.unknown5 = (data >> 7) & 1; slot->regs.isel = (data >> 3) & 0xf; slot->regs.imxl = data & 7; break; case 22: slot->regs.disdl = (data >> 5) & 7; slot->regs.dipan = data & 0x1f; break; case 23: slot->regs.efsdl = (data >> 5) & 7; slot->regs.efpan = data & 0x1f; break; default: break; } } u8 scsp_slot_read_byte(struct Scsp *s, u32 addr) { int slot_num = (addr >> 5) & 0x1f; struct Slot * slot = &s->slots[slot_num]; u32 offset = (addr - (0x20 * slot_num)); u8 data = 0; switch (offset) { case 0: data |= slot->regs.kb << 3; data |= slot->regs.sbctl << 1; data |= (slot->regs.ssctl >> 1) & 1; break; case 1: data |= (slot->regs.ssctl & 1) << 7; data |= slot->regs.lpctl << 5; data |= slot->regs.pcm8b << 4; data |= (slot->regs.sa & 0xf0000) >> 16; break; case 2: data |= (slot->regs.sa & 0xff00) >> 8; break; case 3: data |= slot->regs.sa & 0xff; break; case 4: data |= (slot->regs.lsa & 0xff00) >> 8; break; case 5: data |= slot->regs.lsa & 0xff; break; case 6: data |= (slot->regs.lea & 0xff00) >> 8; break; case 7: data |= slot->regs.lea & 0xff; break; case 8: data |= slot->regs.d2r << 3; data |= slot->regs.d1r >> 2; break; case 9: data |= slot->regs.d1r << 6; data |= slot->regs.hold << 5; data |= slot->regs.ar; break; case 10: data |= slot->regs.unknown1 << 7; data |= slot->regs.ls << 6; data |= slot->regs.krs << 2; data |= slot->regs.dl >> 3; break; case 11: data |= slot->regs.dl << 5; data |= slot->regs.rr; break; case 12: data |= slot->regs.unknown2 << 2; data |= slot->regs.si << 1; data |= slot->regs.sd; break; case 13: data |= slot->regs.tl; break; case 14: data |= slot->regs.mdl << 4; data |= slot->regs.mdxsl >> 2; break; case 15: data |= slot->regs.mdxsl << 6; data |= slot->regs.mdysl; break; case 16: data |= slot->regs.unknown3 << 7; data |= slot->regs.oct << 3; data |= slot->regs.unknown4 << 2; data |= slot->regs.fns >> 8; break; case 17: data |= slot->regs.fns; break; case 18: data |= slot->regs.re << 7; data |= slot->regs.lfof << 2; data |= slot->regs.plfows; break; case 19: data |= slot->regs.plfos << 5; data |= slot->regs.alfows << 3; data |= slot->regs.alfos; break; case 20: //nothing break; case 21: data |= slot->regs.unknown5 << 7; data |= slot->regs.isel << 3; data |= slot->regs.imxl; break; case 22: data |= slot->regs.disdl << 5; data |= slot->regs.dipan; break; case 23: data |= slot->regs.efsdl << 5; data |= slot->regs.efpan; break; } return data; } void scsp_slot_write_word(struct Scsp *s, u32 addr, u16 data) { int slot_num = (addr >> 5) & 0x1f; struct Slot * slot = &s->slots[slot_num]; u32 offset = (addr - (0x20 * slot_num)); switch (offset >> 1) { case 0: slot->regs.kb = (data >> 11) & 1;//has to be done before keyonex if (data & (1 << 12)) keyonex(s); slot->regs.sbctl = (data >> 9) & 3; slot->regs.ssctl = (data >> 7) & 3; slot->regs.lpctl = (data >> 5) & 3; slot->regs.pcm8b = (data >> 4) & 1; slot->regs.sa = (slot->regs.sa & 0xffff) | ((data & 0xf) << 16); break; case 1: slot->regs.sa = (slot->regs.sa & 0xf0000) | data; break; case 2: slot->regs.lsa = data; break; case 3: slot->regs.lea = data; break; case 4: slot->regs.d2r = data >> 11; slot->regs.d1r = (data >> 6) & 0x1f; slot->regs.hold = (data >> 5) & 1; slot->regs.ar = data & 0x1f; break; case 5: slot->regs.unknown1 = (data >> 15) & 1; slot->regs.ls = (data >> 14) & 1; slot->regs.krs = (data >> 10) & 0xf; slot->regs.dl = (data >> 5) & 0x1f; slot->regs.rr = data & 0x1f; break; case 6: slot->regs.unknown2 = (data >> 10) & 3; slot->regs.si = (data >> 9) & 1; slot->regs.sd = (data >> 8) & 1; slot->regs.tl = data & 0xff; break; case 7: slot->regs.mdl = (data >> 12) & 0xf; slot->regs.mdxsl = (data >> 6) & 0x3f; slot->regs.mdysl = data & 0x3f; break; case 8: slot->regs.unknown3 = (data >> 15) & 1; slot->regs.unknown4 = (data >> 10) & 1; slot->regs.oct = (data >> 11) & 0xf; slot->regs.fns = data & 0x3ff; break; case 9: slot->regs.re = (data >> 15) & 1; slot->regs.lfof = (data >> 10) & 0x1f; slot->regs.plfows = (data >> 8) & 3; slot->regs.plfos = (data >> 5) & 7; slot->regs.alfows = (data >> 3) & 3; slot->regs.alfos = data & 7; break; case 10: slot->regs.unknown5 = (data >> 7) & 1; slot->regs.isel = (data >> 3) & 0xf; slot->regs.imxl = data & 7; break; case 11: slot->regs.disdl = (data >> 13) & 7; slot->regs.dipan = (data >> 8) & 0x1f; slot->regs.efsdl = (data >> 5) & 7; slot->regs.efpan = data & 0x1f; break; default: break; } } u16 scsp_slot_read_word(struct Scsp *s, u32 addr) { int slot_num = (addr >> 5) & 0x1f; struct Slot * slot = &s->slots[slot_num]; u32 offset = (addr - (0x20 * slot_num)); u16 data = 0; switch (offset >> 1) { case 0: //keyonex not stored data |= slot->regs.kb << 11; data |= slot->regs.sbctl << 9; data |= slot->regs.ssctl << 7; data |= slot->regs.lpctl << 5; data |= slot->regs.pcm8b << 4; data |= (slot->regs.sa >> 16) & 0xf; break; case 1: data = slot->regs.sa & 0xffff; break; case 2: data = slot->regs.lsa; break; case 3: data = slot->regs.lea; break; case 4: data |= slot->regs.d2r << 11; data |= slot->regs.d1r << 6; data |= slot->regs.hold << 5; data |= slot->regs.ar; break; case 5: data |= slot->regs.unknown1 << 15; data |= slot->regs.ls << 14; data |= slot->regs.krs << 10; data |= slot->regs.dl << 5; data |= slot->regs.rr; break; case 6: data |= slot->regs.unknown2 << 10; data |= slot->regs.si << 9; data |= slot->regs.sd << 8; data |= slot->regs.tl; break; case 7: data |= slot->regs.mdl << 12; data |= slot->regs.mdxsl << 6; data |= slot->regs.mdysl; break; case 8: data |= slot->regs.unknown3 << 15; data |= slot->regs.oct << 11; data |= slot->regs.unknown4 << 10; data |= slot->regs.fns; break; case 9: data |= slot->regs.re << 15; data |= slot->regs.lfof << 10; data |= slot->regs.plfows << 8; data |= slot->regs.plfos << 5; data |= slot->regs.alfows << 3; data |= slot->regs.alfos; break; case 10: data |= slot->regs.unknown5 << 7; data |= slot->regs.isel << 3; data |= slot->regs.imxl; break; case 11: data |= slot->regs.disdl << 13; data |= slot->regs.dipan << 8; data |= slot->regs.efsdl << 5; data |= slot->regs.efpan; break; } return data; } void get_panning(int pan, int * pan_val_l, int * pan_val_r) { if (pan & 0x10) { //negative values *pan_val_l = 0; *pan_val_r = pan & 0xf; } else { *pan_val_l = pan & 0xf; *pan_val_r = 0; } } int get_sdl_shift(int sdl) { if (sdl == 0) return 16;//-infinity else return (7 - sdl); } void generate_sample(struct Scsp * s, int rbp, int rbl, s16 * out_l, s16* out_r, int mvol, s16 cd_in_l, s16 cd_in_r) { int step_num = 0; int i = 0; int mvol_shift = 0; //run 32 steps to generate 1 full sample (512 clock cycles at 22579200hz) //7 operations happen simultaneously on different channels due to pipelining for (step_num = 0; step_num < 32; step_num++) { int last_step = (step_num - 6) & 0x1f; int debug_muted = 0; op1(&s->slots[step_num]);//phase, pitch lfo op2(&s->slots[(step_num - 1) & 0x1f],s);//address pointer, modulation data read op3(&s->slots[(step_num - 2) & 0x1f]);//waveform dram read op4(&s->slots[(step_num - 3) & 0x1f]);//interpolation, eg, amplitude lfo op5(&s->slots[(step_num - 4) & 0x1f]);//level calc 1 op6(&s->slots[(step_num - 5) & 0x1f]);//level calc 2 op7(&s->slots[(step_num - 6) & 0x1f],s);//sound stack write if (s->debug_mode) { if (scsp_debug_instrument_check_is_muted(s->slots[last_step].regs.sa)) debug_muted = 1; } if (!debug_muted) { int disdl = get_sdl_shift(s->slots[last_step].regs.disdl); s16 disdl_applied = (s->slots[last_step].state.output >> disdl); s16 mixs_input = s->slots[last_step].state.output >> get_sdl_shift(s->slots[last_step].regs.imxl); int pan_val_l = 0, pan_val_r = 0; get_panning(s->slots[last_step].regs.dipan, &pan_val_l, &pan_val_r); *out_l = *out_l + ((disdl_applied >> pan_val_l) >> 2); *out_r = *out_r + ((disdl_applied >> pan_val_r) >> 2); scsp_dsp.mixs[s->slots[last_step].regs.isel] += mixs_input << 4; } } scsp_dsp.rbp = rbp; scsp_dsp.rbl = rbl; scsp_dsp.exts[0] = cd_in_l; scsp_dsp.exts[1] = cd_in_r; for (i = 0; i < 128; i++) ScspDspExec(&scsp_dsp, i, SoundRam); scsp_dsp.mdec_ct--; for (i = 0; i < 16; i++) scsp_dsp.mixs[i] = 0; for (i = 0; i < 18; i++)//16,17 are exts0/1 { int efsdl = get_sdl_shift(s->slots[i].regs.efsdl); s16 efsdl_applied = 0; int pan_val_l = 0, pan_val_r = 0; s16 panned_l = 0, panned_r = 0; if (i < 16) efsdl_applied = (scsp_dsp.efreg[i] >> efsdl); else if (i == 16) efsdl_applied = scsp_dsp.exts[0] >> efsdl; else if (i == 17) efsdl_applied = scsp_dsp.exts[1] >> efsdl; get_panning(s->slots[i].regs.efpan, &pan_val_l, &pan_val_r); panned_l = (efsdl_applied >> pan_val_l) >> 2; panned_r = (efsdl_applied >> pan_val_r) >> 2; *out_l = *out_l + panned_l; *out_r = *out_r + panned_r; } mvol_shift = 0xf - mvol; *out_l = *out_l >> mvol_shift; *out_r = *out_r >> mvol_shift; } void new_scsp_reset(struct Scsp* s) { int slot_num; memset(s, 0, sizeof(struct Scsp)); for (slot_num = 0; slot_num < 32; slot_num++) { s->slots[slot_num].state.attenuation = 0x3FF; s->slots[slot_num].state.envelope = RELEASE; s->slots[slot_num].state.num = slot_num; } fill_plfo_tables(); fill_alfo_tables(); memset(&scsp_dsp, 0, sizeof(ScspDsp)); new_scsp_outbuf_pos = 0; new_scsp_cycles = 0; } void scsp_set_use_new(int which) { if (which && !use_new_scsp) new_scsp_reset(&new_scsp); use_new_scsp = which; } //////////////////////////////////////////////////////////////// #ifndef PI #define PI 3.14159265358979323846 #endif #define SCSP_FREQ 44100 // SCSP frequency #define SCSP_RAM_SIZE 0x080000 // SCSP RAM size #define SCSP_RAM_MASK (SCSP_RAM_SIZE - 1) #define SCSP_MIDI_IN_EMP 0x01 // MIDI flags #define SCSP_MIDI_IN_FUL 0x02 #define SCSP_MIDI_IN_OVF 0x04 #define SCSP_MIDI_OUT_EMP 0x08 #define SCSP_MIDI_OUT_FUL 0x10 #define SCSP_ENV_RELEASE 3 // Envelope phase #define SCSP_ENV_SUSTAIN 2 #define SCSP_ENV_DECAY 1 #define SCSP_ENV_ATTACK 0 #define SCSP_FREQ_HB 19 // Freq counter int part #define SCSP_FREQ_LB 10 // Freq counter float part #define SCSP_ENV_HB 10 // Env counter int part #define SCSP_ENV_LB 10 // Env counter float part #define SCSP_LFO_HB 10 // LFO counter int part #define SCSP_LFO_LB 10 // LFO counter float part #define SCSP_ENV_LEN (1 << SCSP_ENV_HB) // Env table len #define SCSP_ENV_MASK (SCSP_ENV_LEN - 1) // Env table mask #define SCSP_FREQ_LEN (1 << SCSP_FREQ_HB) // Freq table len #define SCSP_FREQ_MASK (SCSP_FREQ_LEN - 1) // Freq table mask #define SCSP_LFO_LEN (1 << SCSP_LFO_HB) // LFO table len #define SCSP_LFO_MASK (SCSP_LFO_LEN - 1) // LFO table mask #define SCSP_ENV_AS 0 // Env Attack Start #define SCSP_ENV_DS (SCSP_ENV_LEN << SCSP_ENV_LB) // Env Decay Start #define SCSP_ENV_AE (SCSP_ENV_DS - 1) // Env Attack End #define SCSP_ENV_DE (((2 * SCSP_ENV_LEN) << SCSP_ENV_LB) - 1) // Env Decay End #define SCSP_ATTACK_R (u32) (8 * 44100) #define SCSP_DECAY_R (u32) (12 * SCSP_ATTACK_R) //////////////////////////////////////////////////////////////// typedef struct slot_t { u8 swe; // stack write enable u8 sdir; // sound direct u8 pcm8b; // PCM sound format u8 sbctl; // source bit control u8 ssctl; // sound source control u8 lpctl; // loop control u8 key; // KEY_ state u8 keyx; // still playing regardless the KEY_ state (hold, decay) s8 *buf8; // sample buffer 8 bits s16 *buf16; // sample buffer 16 bits u32 fcnt; // phase counter u32 finc; // phase step adder u32 finct; // non adjusted phase step s32 ecnt; // envelope counter s32 *einc; // envelope current step adder s32 einca; // envelope step adder for attack s32 eincd; // envelope step adder for decay 1 s32 eincs; // envelope step adder for decay 2 s32 eincr; // envelope step adder for release s32 ecmp; // envelope compare to raise next phase u32 ecurp; // envelope current phase (attack / decay / release ...) s32 env; // envelope multiplier (at time of last update) void (*enxt)(struct slot_t *); // envelope function pointer for next phase event u32 lfocnt; // lfo counter s32 lfoinc; // lfo step adder u32 sa; // start address u32 lsa; // loop start address u32 lea; // loop end address s32 tl; // total level s32 sl; // sustain level s32 ar; // attack rate s32 dr; // decay rate s32 sr; // sustain rate s32 rr; // release rate s32 *arp; // attack rate table pointer s32 *drp; // decay rate table pointer s32 *srp; // sustain rate table pointer s32 *rrp; // release rate table pointer u32 krs; // key rate scale s32 *lfofmw; // lfo frequency modulation waveform pointer s32 *lfoemw; // lfo envelope modulation waveform pointer u8 lfofms; // lfo frequency modulation sensitivity u8 lfoems; // lfo envelope modulation sensitivity u8 fsft; // frequency shift (used for freq lfo) u8 mdl; // modulation level u8 mdx; // modulation source X u8 mdy; // modulation source Y u8 imxl; // input sound level u8 disll; // direct sound level left u8 dislr; // direct sound level right u8 efsll; // effect sound level left u8 efslr; // effect sound level right u8 eghold; // eg type envelope hold u8 lslnk; // loop start link (start D1R when start loop adr is reached) // NOTE: Previously there were u8 pads here to maintain 4-byte alignment. // There are current 22 u8's in this struct and 1 u16. This makes 24 // bytes, so there are no pads at the moment. // // I'm not sure this is at all necessary either, but keeping this note // in case. } slot_t; typedef struct scsp_t { u32 mem4b; // 4mbit memory u32 mvol; // master volume u32 rbl; // ring buffer lenght u32 rbp; // ring buffer address (pointer) u32 mslc; // monitor slot u32 ca; // call address u32 sgc; // phase u32 eg; // envelope u32 dmea; // dma memory address start u32 drga; // dma register address start u32 dmfl; // dma flags (direction / gate 0 ...) u32 dmlen; // dma transfer len u8 midinbuf[4]; // midi in buffer u8 midoutbuf[4]; // midi out buffer u8 midincnt; // midi in buffer size u8 midoutcnt; // midi out buffer size u8 midflag; // midi flag (empty, full, overflow ...) u8 midflag2; // midi flag 2 (here only for alignement) s32 timacnt; // timer A counter u32 timasd; // timer A step diviser s32 timbcnt; // timer B counter u32 timbsd; // timer B step diviser s32 timccnt; // timer C counter u32 timcsd; // timer C step diviser u32 scieb; // allow sound cpu interrupt u32 scipd; // pending sound cpu interrupt u32 scilv0; // IL0 M68000 interrupt pin state u32 scilv1; // IL1 M68000 interrupt pin state u32 scilv2; // IL2 M68000 interrupt pin state u32 mcieb; // allow main cpu interrupt u32 mcipd; // pending main cpu interrupt u8 *scsp_ram; // scsp ram pointer void (*mintf)(void); // main cpu interupt function pointer void (*sintf)(u32); // sound cpu interrupt function pointer s32 stack[32 * 2]; // two last generation slot output (SCSP STACK) slot_t slot[32]; // 32 slots } scsp_t; //////////////////////////////////////////////////////////////// static s32 scsp_env_table[SCSP_ENV_LEN * 2]; // envelope curve table (attack & decay) static s32 scsp_lfo_sawt_e[SCSP_LFO_LEN]; // lfo sawtooth waveform for envelope static s32 scsp_lfo_squa_e[SCSP_LFO_LEN]; // lfo square waveform for envelope static s32 scsp_lfo_tri_e[SCSP_LFO_LEN]; // lfo triangle waveform for envelope static s32 scsp_lfo_noi_e[SCSP_LFO_LEN]; // lfo noise waveform for envelope static s32 scsp_lfo_sawt_f[SCSP_LFO_LEN]; // lfo sawtooth waveform for frequency static s32 scsp_lfo_squa_f[SCSP_LFO_LEN]; // lfo square waveform for frequency static s32 scsp_lfo_tri_f[SCSP_LFO_LEN]; // lfo triangle waveform for frequency static s32 scsp_lfo_noi_f[SCSP_LFO_LEN]; // lfo noise waveform frequency static s32 scsp_attack_rate[0x40 + 0x20]; // envelope step for attack static s32 scsp_decay_rate[0x40 + 0x20]; // envelope step for decay static s32 scsp_null_rate[0x20]; // null envelope step static s32 scsp_lfo_step[32]; // directly give the lfo counter step static s32 scsp_tl_table[256]; // table of values for total level attentuation static u8 scsp_reg[0x1000]; static u8 *scsp_isr; static u8 *scsp_ccr; static u8 *scsp_dcr; static s32 *scsp_bufL; static s32 *scsp_bufR; static u32 scsp_buf_len; static u32 scsp_buf_pos; static scsp_t scsp; // SCSP structure #define CDDA_NUM_BUFFERS 2*75 static union { u8 data[CDDA_NUM_BUFFERS*2352]; } cddabuf; static unsigned int cdda_next_in=0; // Next sector buffer offset to receive into static u32 cdda_out_left; // Bytes of CDDA left to output //////////////////////////////////////////////////////////////// static void scsp_env_null_next(slot_t *slot); static void scsp_release_next(slot_t *slot); static void scsp_sustain_next(slot_t *slot); static void scsp_decay_next(slot_t *slot); static void scsp_attack_next(slot_t *slot); static void scsp_slot_update_keyon(slot_t *slot); ////////////////////////////////////////////////////////////////////////////// static int scsp_mute_flags = 0; static int scsp_volume = 100; //////////////////////////////////////////////////////////////// // Misc static int scsp_round (double val) { return (int)(val + 0.5); } //////////////////////////////////////////////////////////////// // Interrupts static INLINE void scsp_trigger_main_interrupt (u32 id) { SCSPLOG ("scsp main interrupt accepted %.4X\n", id); scsp.mintf (); } static INLINE void scsp_trigger_sound_interrupt (u32 id) { u32 level; level = 0; if (id > 0x80) id = 0x80; if (scsp.scilv0 & id) level |= 1; if (scsp.scilv1 & id) level |= 2; if (scsp.scilv2 & id) level |= 4; #ifdef SCSP_DEBUG if (id == 0x8) SCSPLOG ("scsp sound interrupt accepted %.2X lev=%d\n", id, level); #endif scsp.sintf (level); } static void scsp_main_interrupt (u32 id) { // if (scsp.mcipd & id) return; // if (id != 0x400) SCSPLOG("scsp main interrupt %.4X\n", id); scsp.mcipd |= id; WRITE_THROUGH (scsp.mcipd); if (scsp.mcieb & id) scsp_trigger_main_interrupt (id); } static void scsp_sound_interrupt (u32 id) { // if (scsp.scipd & id) return; // SCSPLOG ("scsp sound interrupt %.4X\n", id); scsp.scipd |= id; WRITE_THROUGH (scsp.scipd); if (scsp.scieb & id) scsp_trigger_sound_interrupt (id); } //////////////////////////////////////////////////////////////// // Direct Memory Access static void scsp_dma (void) { if (scsp.dmfl & 0x20) { // dsp -> scsp_ram SCSPLOG ("scsp dma: scsp_ram(%08lx) <- reg(%08lx) * %08lx\n", scsp.dmea, scsp.drga, scsp.dmlen); } else { // scsp_ram -> dsp SCSPLOG ("scsp dma: scsp_ram(%08lx) -> reg(%08lx) * %08lx\n", scsp.dmea, scsp.drga, scsp.dmlen); } scsp_ccr[0x16 ^ 3] &= 0xE0; scsp_sound_interrupt (0x10); scsp_main_interrupt (0x10); } //////////////////////////////////////////////////////////////// // Key ON/OFF event handler static void scsp_slot_keyon (slot_t *slot) { // key need to be released before being pressed ;) if (slot->ecurp == SCSP_ENV_RELEASE) { SCSPLOG ("key on slot %d. 68K PC = %08X slot->sa = %08X slot->lsa = %08X " "slot->lea = %08X\n", slot - &(scsp.slot[0]), M68K->GetPC(), slot->sa, slot->lsa, slot->lea >> SCSP_FREQ_LB); // set buffer, loop start/end address of the slot if (slot->pcm8b) { slot->buf8 = (s8*) &(scsp.scsp_ram[slot->sa]); if ((slot->sa + (slot->lea >> SCSP_FREQ_LB)) > SCSP_RAM_MASK) slot->lea = (SCSP_RAM_MASK - slot->sa) << SCSP_FREQ_LB; } else { slot->buf16 = (s16*) &(scsp.scsp_ram[slot->sa & ~1]); if ((slot->sa + (slot->lea >> (SCSP_FREQ_LB - 1))) > SCSP_RAM_MASK) slot->lea = (SCSP_RAM_MASK - slot->sa) << (SCSP_FREQ_LB - 1); } slot->fcnt = 0; // reset frequency counter slot->ecnt = SCSP_ENV_AS; // reset envelope counter (probably wrong, // should convert decay to attack?) slot->env = 0; // reset envelope slot->einc = &slot->einca; // envelope counter step is attack step slot->ecurp = SCSP_ENV_ATTACK; // current envelope phase is attack slot->ecmp = SCSP_ENV_AE; // limit reach to next event (Attack End) slot->enxt = scsp_attack_next; // function pointer to next event } } static void scsp_slot_keyoff (slot_t *slot) { // key need to be pressed before being released ;) if (slot->ecurp != SCSP_ENV_RELEASE) { SCSPLOG ("key off slot %d\n", slot - &(scsp.slot[0])); // if we still are in attack phase at release time, convert attack to decay if (slot->ecurp == SCSP_ENV_ATTACK) slot->ecnt = SCSP_ENV_DE - slot->ecnt; slot->einc = &slot->eincr; slot->ecmp = SCSP_ENV_DE; slot->ecurp = SCSP_ENV_RELEASE; slot->enxt = scsp_release_next; } } static void scsp_slot_keyonoff (void) { slot_t *slot; for(slot = &(scsp.slot[0]); slot < &(scsp.slot[32]); slot++) { if (slot->key) scsp_slot_keyon (slot); else scsp_slot_keyoff (slot); } } /* Envelope Events Handler Max EG level = 0x3FF /|\ / | \ / | \_____ Min EG level = 0x000 __/ | | |\___ A D1 D2 R */ static void scsp_env_null_next (UNUSED slot_t *slot) { // only to prevent null call pointer... } static void scsp_release_next (slot_t *slot) { // end of release happened, update to process the next phase... slot->ecnt = SCSP_ENV_DE; slot->einc = NULL; slot->ecmp = SCSP_ENV_DE + 1; slot->enxt = scsp_env_null_next; } static void scsp_sustain_next (slot_t *slot) { // end of sustain happened, update to process the next phase... slot->ecnt = SCSP_ENV_DE; slot->einc = NULL; slot->ecmp = SCSP_ENV_DE + 1; slot->enxt = scsp_env_null_next; } static void scsp_decay_next (slot_t *slot) { // end of decay happened, update to process the next phase... slot->ecnt = slot->sl; slot->einc = &slot->eincs; slot->ecmp = SCSP_ENV_DE; slot->ecurp = SCSP_ENV_SUSTAIN; slot->enxt = scsp_sustain_next; } static void scsp_attack_next (slot_t *slot) { // end of attack happened, update to process the next phase... slot->ecnt = SCSP_ENV_DS; slot->einc = &slot->eincd; slot->ecmp = slot->sl; slot->ecurp = SCSP_ENV_DECAY; slot->enxt = scsp_decay_next; } //////////////////////////////////////////////////////////////// // Slot Access static void scsp_slot_refresh_einc (slot_t *slot, u32 adsr_bitmask) { if (slot->arp && (adsr_bitmask & 0x1)) slot->einca = slot->arp[(14 - slot->fsft) >> slot->krs]; if (slot->drp && (adsr_bitmask & 0x2)) slot->eincd = slot->drp[(14 - slot->fsft) >> slot->krs]; if (slot->srp && (adsr_bitmask & 0x4)) slot->eincs = slot->srp[(14 - slot->fsft) >> slot->krs]; if (slot->rrp && (adsr_bitmask & 0x8)) slot->eincr = slot->rrp[(14 - slot->fsft) >> slot->krs]; } static void scsp_slot_set_b (u32 s, u32 a, u8 d) { slot_t *slot = &(scsp.slot[s]); SCSPLOG("slot %d : reg %.2X = %.2X\n", s, a & 0x1F, d); scsp_isr[a ^ 3] = d; switch (a & 0x1F) { case 0x00: // KX/KB/SBCTL/SSCTL(high bit) slot->key = (d >> 3) & 1; slot->sbctl = (d >> 1) & 3; slot->ssctl = (slot->ssctl & 1) + ((d & 1) << 1); if (d & 0x10) scsp_slot_keyonoff (); return; case 0x01: // SSCTL(low bit)/LPCTL/8B/SA(highest 4 bits) slot->ssctl = (slot->ssctl & 2) + ((d >> 7) & 1); slot->lpctl = (d >> 5) & 3; slot->pcm8b = d & 0x10; slot->sa = (slot->sa & 0x0FFFF) + ((d & 0xF) << 16); slot->sa &= SCSP_RAM_MASK; if (slot->ecnt < SCSP_ENV_DE) scsp_slot_update_keyon (slot); return; case 0x02: // SA(next highest byte) slot->sa = (slot->sa & 0xF00FF) + (d << 8); slot->sa &= SCSP_RAM_MASK; if (slot->ecnt < SCSP_ENV_DE) scsp_slot_update_keyon (slot); return; case 0x03: // SA(low byte) slot->sa = (slot->sa & 0xFFF00) + d; slot->sa &= SCSP_RAM_MASK; if (slot->ecnt < SCSP_ENV_DE) scsp_slot_update_keyon (slot); return; case 0x04: // LSA(high byte) slot->lsa = (slot->lsa & (0x00FF << SCSP_FREQ_LB)) + (d << (8 + SCSP_FREQ_LB)); return; case 0x05: // LSA(low byte) slot->lsa = (slot->lsa & (0xFF00 << SCSP_FREQ_LB)) + (d << SCSP_FREQ_LB); return; case 0x06: // LEA(high byte) slot->lea = (slot->lea & (0x00FF << SCSP_FREQ_LB)) + (d << (8 + SCSP_FREQ_LB)); return; case 0x07: // LEA(low byte) slot->lea = (slot->lea & (0xFF00 << SCSP_FREQ_LB)) + (d << SCSP_FREQ_LB); return; case 0x08: // D2R/D1R(highest 3 bits) slot->sr = (d >> 3) & 0x1F; slot->dr = (slot->dr & 0x03) + ((d & 7) << 2); if (slot->sr) slot->srp = &scsp_decay_rate[slot->sr << 1]; else slot->srp = &scsp_null_rate[0]; if (slot->dr) slot->drp = &scsp_decay_rate[slot->dr << 1]; else slot->drp = &scsp_null_rate[0]; scsp_slot_refresh_einc (slot, 0x2 | 0x4); return; case 0x09: // D1R(lowest 2 bits)/EGHOLD/AR slot->dr = (slot->dr & 0x1C) + ((d >> 6) & 3); slot->eghold = d & 0x20; slot->ar = d & 0x1F; if (slot->dr) slot->drp = &scsp_decay_rate[slot->dr << 1]; else slot->drp = &scsp_null_rate[0]; if (slot->ar) slot->arp = &scsp_attack_rate[slot->ar << 1]; else slot->arp = &scsp_null_rate[0]; scsp_slot_refresh_einc (slot, 0x1 | 0x2); return; case 0x0A: // LPSLNK/KRS/DL(highest 2 bits) slot->lslnk = d & 0x40; slot->krs = (d >> 2) & 0xF; if (slot->krs == 0xF) slot->krs = 4; else slot->krs >>= 2; slot->sl &= 0xE0 << SCSP_ENV_LB; slot->sl += (d & 3) << (8 + SCSP_ENV_LB); slot->sl += SCSP_ENV_DS; // adjusted for envelope compare (ecmp) scsp_slot_refresh_einc (slot, 0xF); return; case 0x0B: // DL(lowest 3 bits)/RR slot->sl &= 0x300 << SCSP_ENV_LB; slot->sl += (d & 0xE0) << SCSP_ENV_LB; slot->sl += SCSP_ENV_DS; // adjusted for envelope compare (ecmp) slot->rr = d & 0x1F; if (slot->rr) slot->rrp = &scsp_decay_rate[slot->rr << 1]; else slot->rrp = &scsp_null_rate[0]; scsp_slot_refresh_einc (slot, 0x8); return; case 0x0C: // STWINH/SDIR slot->sdir = d & 2; slot->swe = d & 1; return; case 0x0D: // TL slot->tl = scsp_tl_table[(d & 0xFF)]; return; case 0x0E: // MDL/MDXSL(highest 4 bits) slot->mdl = (d >> 4) & 0xF; // need to adjust for correct shift slot->mdx = (slot->mdx & 3) + ((d & 0xF) << 2); return; case 0x0F: // MDXSL(lowest 2 bits)/MDYSL slot->mdx = (slot->mdx & 0x3C) + ((d >> 6) & 3); slot->mdy = d & 0x3F; return; case 0x10: // OCT/FNS(highest 2 bits) if (d & 0x40) slot->fsft = 23 - ((d >> 3) & 0xF); else slot->fsft = ((d >> 3) & 7) ^ 7; slot->finct = (slot->finct & 0x7F80) + ((d & 3) << (8 + 7)); slot->finc = (0x20000 + slot->finct) >> slot->fsft; scsp_slot_refresh_einc (slot, 0xF); return; case 0x11: // FNS(low byte) slot->finct = (slot->finct & 0x18000) + (d << 7); slot->finc = (0x20000 + slot->finct) >> slot->fsft; return; case 0x12: // LFORE/LFOF/PLFOWS if (d & 0x80) { slot->lfoinc = -1; return; } else if (slot->lfoinc == -1) { slot->lfocnt = 0; } slot->lfoinc = scsp_lfo_step[(d >> 2) & 0x1F]; switch (d & 3) { case 0: slot->lfofmw = scsp_lfo_sawt_f; return; case 1: slot->lfofmw = scsp_lfo_squa_f; return; case 2: slot->lfofmw = scsp_lfo_tri_f; return; case 3: slot->lfofmw = scsp_lfo_noi_f; return; } case 0x13: // PLFOS/ALFOWS/ALFOS if ((d >> 5) & 7) slot->lfofms = ((d >> 5) & 7) + 7; else slot->lfofms = 31; if (d & 7) slot->lfoems = ((d & 7) ^ 7) + 4; else slot->lfoems = 31; switch ((d >> 3) & 3) { case 0: slot->lfoemw = scsp_lfo_sawt_e; return; case 1: slot->lfoemw = scsp_lfo_squa_e; return; case 2: slot->lfoemw = scsp_lfo_tri_e; return; case 3: slot->lfoemw = scsp_lfo_noi_e; } return; case 0x15: // ISEL/OMXL if (d & 7) slot->imxl = ((d & 7) ^ 7) + SCSP_ENV_HB; else slot->imxl = 31; return; case 0x16: // DISDL/DIPAN if (d & 0xE0) { // adjusted for envelope calculation // some inaccuracy in panning though... slot->dislr = slot->disll = (((d >> 5) & 7) ^ 7) + SCSP_ENV_HB; if (d & 0x10) { // Panning Left if ((d & 0xF) == 0xF) slot->dislr = 31; else slot->dislr += (d >> 1) & 7; } else { // Panning Right if ((d & 0xF) == 0xF) slot->disll = 31; else slot->disll += (d >> 1) & 7; } } else { slot->dislr = slot->disll = 31; // muted } return; case 0x17: // EFSDL/EFPAN if (d & 0xE0) { slot->efslr = slot->efsll = (((d >> 5) & 7) ^ 7) + SCSP_ENV_HB; if (d & 0x10) { // Panning Left if ((d & 0xF) == 0xF) slot->efslr = 31; else slot->efslr += (d >> 1) & 7; } else { // Panning Right if ((d & 0xF) == 0xF) slot->efsll = 31; else slot->efsll += (d >> 1) & 7; } } else { slot->efslr = slot->efsll = 31; // muted } return; } } static void scsp_slot_set_w (u32 s, s32 a, u16 d) { slot_t *slot = &(scsp.slot[s]); SCSPLOG ("slot %d : reg %.2X = %.4X\n", s, a & 0x1E, d); *(u16 *)&scsp_isr[a ^ 2] = d; switch (a & 0x1E) { case 0x00: // KYONEX/KYONB/SBCTL/SSCTL/LPCTL/PCM8B/SA(highest 4 bits) slot->key = (d >> 11) & 1; slot->sbctl = (d >> 9) & 3; slot->ssctl = (d >> 7) & 3; slot->lpctl = (d >> 5) & 3; slot->pcm8b = d & 0x10; slot->sa = (slot->sa & 0x0FFFF) | ((d & 0xF) << 16); slot->sa &= SCSP_RAM_MASK; if (slot->ecnt < SCSP_ENV_DE) scsp_slot_update_keyon(slot); if (d & 0x1000) scsp_slot_keyonoff(); return; case 0x02: // SA(low word) slot->sa = (slot->sa & 0xF0000) | d; slot->sa &= SCSP_RAM_MASK; if (slot->ecnt < SCSP_ENV_DE) scsp_slot_update_keyon(slot); return; case 0x04: // LSA slot->lsa = d << SCSP_FREQ_LB; return; case 0x06: // LEA slot->lea = d << SCSP_FREQ_LB; return; case 0x08: // D2R/D1R/EGHOLD/AR slot->sr = (d >> 11) & 0x1F; slot->dr = (d >> 6) & 0x1F; slot->eghold = d & 0x20; slot->ar = d & 0x1F; if (slot->sr) slot->srp = &scsp_decay_rate[slot->sr << 1]; else slot->srp = &scsp_null_rate[0]; if (slot->dr) slot->drp = &scsp_decay_rate[slot->dr << 1]; else slot->drp = &scsp_null_rate[0]; if (slot->ar) slot->arp = &scsp_attack_rate[slot->ar << 1]; else slot->arp = &scsp_null_rate[0]; scsp_slot_refresh_einc (slot, 0x1 | 0x2 | 0x4); return; case 0x0A: // LPSLNK/KRS/DL/RR slot->lslnk = (d >> 8) & 0x40; slot->krs = (d >> 10) & 0xF; if (slot->krs == 0xF) slot->krs = 4; else slot->krs >>= 2; slot->sl = ((d & 0x3E0) << SCSP_ENV_LB) + SCSP_ENV_DS; // adjusted for envelope compare (ecmp) slot->rr = d & 0x1F; if (slot->rr) slot->rrp = &scsp_decay_rate[slot->rr << 1]; else slot->rrp = &scsp_null_rate[0]; scsp_slot_refresh_einc (slot, 0xF); return; case 0x0C: // STWINH/SDIR slot->sdir = (d >> 8) & 2; slot->swe = (d >> 8) & 1; slot->tl = scsp_tl_table[(d & 0xFF)]; return; case 0x0E: // MDL/MDXSL/MDYSL slot->mdl = (d >> 12) & 0xF; // need to adjust for correct shift slot->mdx = (d >> 6) & 0x3F; slot->mdy = d & 0x3F; return; case 0x10: // OCT/FNS if (d & 0x4000) slot->fsft = 23 - ((d >> 11) & 0xF); else slot->fsft = (((d >> 11) & 7) ^ 7); slot->finc = ((0x400 + (d & 0x3FF)) << 7) >> slot->fsft; scsp_slot_refresh_einc (slot, 0xF); return; case 0x12: // LFORE/LFOF/PLFOWS/PLFOS/ALFOWS/ALFOS if (d & 0x8000) { slot->lfoinc = -1; return; } else if (slot->lfoinc == -1) { slot->lfocnt = 0; } slot->lfoinc = scsp_lfo_step[(d >> 10) & 0x1F]; if ((d >> 5) & 7) slot->lfofms = ((d >> 5) & 7) + 7; else slot->lfofms = 31; if (d & 7) slot->lfoems = ((d & 7) ^ 7) + 4; else slot->lfoems = 31; switch ((d >> 8) & 3) { case 0: slot->lfofmw = scsp_lfo_sawt_f; break; case 1: slot->lfofmw = scsp_lfo_squa_f; break; case 2: slot->lfofmw = scsp_lfo_tri_f; break; case 3: slot->lfofmw = scsp_lfo_noi_f; break; } switch ((d >> 3) & 3) { case 0: slot->lfoemw = scsp_lfo_sawt_e; return; case 1: slot->lfoemw = scsp_lfo_squa_e; return; case 2: slot->lfoemw = scsp_lfo_tri_e; return; case 3: slot->lfoemw = scsp_lfo_noi_e; } return; case 0x14: // ISEL/OMXL if (d & 7) slot->imxl = ((d & 7) ^ 7) + SCSP_ENV_HB; else slot->imxl = 31; return; case 0x16: // DISDL/DIPAN/EFSDL/EFPAN if (d & 0xE000) { // adjusted fr enveloppe calculation // some accuracy lose for panning here... slot->dislr = slot->disll = (((d >> 13) & 7) ^ 7) + SCSP_ENV_HB; if (d & 0x1000) { // Panning Left if ((d & 0xF00) == 0xF00) slot->dislr = 31; else slot->dislr += (d >> 9) & 7; } else { // Panning Right if ((d & 0xF00) == 0xF00) slot->disll = 31; else slot->disll += (d >> 9) & 7; } } else { slot->dislr = slot->disll = 31; // muted } if (d & 0xE0) { slot->efslr = slot->efsll = (((d >> 5) & 7) ^ 7) + SCSP_ENV_HB; if (d & 0x10) { // Panning Left if ((d & 0xF) == 0xF) slot->efslr = 31; else slot->efslr += (d >> 1) & 7; } else { // Panning Right if ((d & 0xF) == 0xF) slot->efsll = 31; else slot->efsll += (d >> 1) & 7; } } else { slot->efslr = slot->efsll = 31; // muted } return; } } static u8 scsp_slot_get_b (u32 s, u32 a) { u8 val = scsp_isr[a ^ 3]; // Mask out keyonx if ((a & 0x1F) == 0x00) val &= 0xEF; SCSPLOG ("r_b slot %d (%.2X) : reg %.2X = %.2X\n", s, a, a & 0x1F, val); return val; } static u16 scsp_slot_get_w(u32 s, u32 a) { u16 val = *(u16 *)&scsp_isr[a ^ 2]; if ((a & 0x1E) == 0x00) return val &= 0xEFFF; SCSPLOG ("r_w slot %d (%.2X) : reg %.2X = %.4X\n", s, a, a & 0x1E, val); return val; } //////////////////////////////////////////////////////////////// // SCSP Access static void scsp_set_b (u32 a, u8 d) { if ((a != 0x408) && (a != 0x41D)) { SCSPLOG("scsp : reg %.2X = %.2X\n", a & 0x3F, d); } scsp_ccr[a ^ 3] = d; switch (a & 0x3F) { case 0x00: // MEM4MB/DAC18B scsp.mem4b = (d >> 1) & 0x1; if (scsp.mem4b) { M68K->SetFetch(0x000000, 0x080000, (pointer)SoundRam); } else { M68K->SetFetch(0x000000, 0x040000, (pointer)SoundRam); M68K->SetFetch(0x040000, 0x080000, (pointer)SoundRam); M68K->SetFetch(0x080000, 0x0C0000, (pointer)SoundRam); M68K->SetFetch(0x0C0000, 0x100000, (pointer)SoundRam); } return; case 0x01: // VER/MVOL scsp.mvol = d & 0xF; return; case 0x02: // RBL(high bit) scsp.rbl = (scsp.rbl & 1) + ((d & 1) << 1); return; case 0x03: // RBL(low bit)/RBP scsp.rbl = (scsp.rbl & 2) + ((d >> 7) & 1); if (use_new_scsp) scsp.rbp = (d & 0x7F); else scsp.rbp = (d & 0x7F) * (4 * 1024 * 2); return; case 0x07: // MOBUF scsp_midi_out_send(d); return; case 0x08: // MSLC scsp.mslc = (d >> 3) & 0x1F; scsp_update_monitor (); return; case 0x12: // DMEAL(high byte) scsp.dmea = (scsp.dmea & 0x700FE) + (d << 8); return; case 0x13: // DMEAL(low byte) scsp.dmea = (scsp.dmea & 0x7FF00) + (d & 0xFE); return; case 0x14: // DMEAH(high byte) scsp.dmea = (scsp.dmea & 0xFFFE) + ((d & 0x70) << 12); scsp.drga = (scsp.drga & 0xFE) + ((d & 0xF) << 8); return; case 0x15: // DMEAH(low byte) scsp.drga = (scsp.drga & 0xF00) + (d & 0xFE); return; case 0x16: // DGATE/DDIR/DEXE/DTLG(upper 4 bits) scsp.dmlen = (scsp.dmlen & 0xFE) + ((d & 0xF) << 8); if ((scsp.dmfl = d & 0xF0) & 0x10) scsp_dma (); return; case 0x17: // DTLG(lower byte) scsp.dmlen = (scsp.dmlen & 0xF00) + (d & 0xFE); return; case 0x18: // TACTL scsp.timasd = d & 7; return; case 0x19: // TIMA scsp.timacnt = d << 8; return; case 0x1A: // TBCTL scsp.timbsd = d & 7; return; case 0x1B: // TIMB scsp.timbcnt = d << 8; return; case 0x1C: // TCCTL scsp.timcsd = d & 7; return; case 0x1D: // TIMC scsp.timccnt = d << 8; return; case 0x1E: // SCIEB(high byte) { int i; scsp.scieb = (scsp.scieb & 0xFF) + (d << 8); for (i = 0; i < 3; i++) { if (scsp.scieb & (1 << i) && scsp.scipd & (1 << i)) scsp_trigger_sound_interrupt ((1 << (i+8))); } return; } case 0x1F: // SCIEB(low byte) { int i; scsp.scieb = (scsp.scieb & 0x700) + d; for (i = 0; i < 8; i++) { if (scsp.scieb & (1 << i) && scsp.scipd & (1 << i)) scsp_trigger_sound_interrupt ((1 << i)); } return; } case 0x21: // SCIPD(low byte) if (d & 0x20) scsp_sound_interrupt (0x20); return; case 0x22: // SCIRE(high byte) scsp.scipd &= ~(d << 8); return; case 0x23: // SCIRE(low byte) scsp.scipd &= ~(u32)d; return; case 0x25: // SCILV0 scsp.scilv0 = d; return; case 0x27: // SCILV1 scsp.scilv1 = d; return; case 0x29: // SCILV2 scsp.scilv2 = d; return; case 0x2A: // MCIEB(high byte) scsp.mcieb = (scsp.mcieb & 0xFF) + (d << 8); return; case 0x2B: // MCIEB(low byte) scsp.mcieb = (scsp.mcieb & 0x700) + d; return; case 0x2D: // MCIPD(low byte) if (d & 0x20) scsp_main_interrupt(0x20); return; case 0x2E: // MCIRE(high byte) scsp.mcipd &= ~(d << 8); return; case 0x2F: // MCIRE(low byte) scsp.mcipd &= ~(u32)d; return; } } static void scsp_set_w (u32 a, u16 d) { if ((a != 0x418) && (a != 0x41A) && (a != 0x422)) { SCSPLOG("scsp : reg %.2X = %.4X\n", a & 0x3E, d); } *(u16 *)&scsp_ccr[a ^ 2] = d; switch (a & 0x3E) { case 0x00: // MEM4MB/DAC18B/VER/MVOL scsp.mem4b = (d >> 9) & 0x1; scsp.mvol = d & 0xF; if (scsp.mem4b) { M68K->SetFetch(0x000000, 0x080000, (pointer)SoundRam); } else { M68K->SetFetch(0x000000, 0x040000, (pointer)SoundRam); M68K->SetFetch(0x040000, 0x080000, (pointer)SoundRam); M68K->SetFetch(0x080000, 0x0C0000, (pointer)SoundRam); M68K->SetFetch(0x0C0000, 0x100000, (pointer)SoundRam); } return; case 0x02: // RBL/RBP scsp.rbl = (d >> 7) & 3; if (use_new_scsp) scsp.rbp = (d & 0x7F); else scsp.rbp = (d & 0x7F) * (4 * 1024 * 2); return; case 0x06: // MOBUF scsp_midi_out_send(d & 0xFF); return; case 0x08: // MSLC scsp.mslc = (d >> 11) & 0x1F; scsp_update_monitor(); return; case 0x12: // DMEAL scsp.dmea = (scsp.dmea & 0x70000) + (d & 0xFFFE); return; case 0x14: // DMEAH/DRGA scsp.dmea = (scsp.dmea & 0xFFFE) + ((d & 0x7000) << 4); scsp.drga = d & 0xFFE; return; case 0x16: // DGATE/DDIR/DEXE/DTLG scsp.dmlen = d & 0xFFE; if ((scsp.dmfl = ((d >> 8) & 0xF0)) & 0x10) scsp_dma (); return; case 0x18: // TACTL/TIMA scsp.timasd = (d >> 8) & 7; scsp.timacnt = (d & 0xFF) << 8; return; case 0x1A: // TBCTL/TIMB scsp.timbsd = (d >> 8) & 7; scsp.timbcnt = (d & 0xFF) << 8; return; case 0x1C: // TCCTL/TIMC scsp.timcsd = (d >> 8) & 7; scsp.timccnt = (d & 0xFF) << 8; return; case 0x1E: // SCIEB { int i; scsp.scieb = d; for (i = 0; i < 11; i++) { if (scsp.scieb & (1 << i) && scsp.scipd & (1 << i)) scsp_trigger_sound_interrupt ((1 << i)); } return; } case 0x20: // SCIPD if (d & 0x20) scsp_sound_interrupt (0x20); return; case 0x22: // SCIRE scsp.scipd &= ~d; return; case 0x24: // SCILV0 scsp.scilv0 = d; return; case 0x26: // SCILV1 scsp.scilv1 = d; return; case 0x28: // SCILV2 scsp.scilv2 = d; return; case 0x2A: // MCIEB { int i; scsp.mcieb = d; for (i = 0; i < 11; i++) { if (scsp.mcieb & (1 << i) && scsp.mcipd & (1 << i)) scsp_trigger_main_interrupt ((1 << i)); } return; } case 0x2C: // MCIPD if (d & 0x20) scsp_main_interrupt (0x20); return; case 0x2E: // MCIRE scsp.mcipd &= ~d; return; } } static u8 scsp_get_b (u32 a) { a &= 0x3F; if ((a != 0x09) && (a != 0x21)) { SCSPLOG("r_b scsp : reg %.2X\n", a); } // if (a == 0x09) SCSPLOG("r_b scsp 09 = %.2X\n", ((scsp.slot[scsp.mslc].fcnt >> (SCSP_FREQ_LB + 12)) & 0x1) << 7); switch (a) { case 0x01: // VER/MVOL scsp_ccr[a ^ 3] &= 0x0F; break; case 0x04: // Midi flags register return scsp.midflag; case 0x05: // MIBUF return scsp_midi_in_read(); case 0x07: // MOBUF return scsp_midi_out_read(); case 0x08: // CA(highest 3 bits) return (scsp.ca >> 8); case 0x09: // CA(lowest bit)/SGC/EG return (scsp.ca & 0xE0) | (scsp.sgc << 5) | scsp.eg; case 0x1E: // SCIEB(high byte) return (scsp.scieb >> 8); case 0x1F: // SCIEB(low byte) return scsp.scieb; case 0x20: // SCIPD(high byte) return (scsp.scipd >> 8); case 0x21: // SCIPD(low byte) return scsp.scipd; case 0x2C: // MCIPD(high byte) return (scsp.mcipd >> 8); case 0x2D: // MCIPD(low byte) return scsp.mcipd; } return scsp_ccr[a ^ 3]; } static u16 scsp_get_w (u32 a) { a &= 0x3E; if ((a != 0x20) && (a != 0x08)) { SCSPLOG("r_w scsp : reg %.2X\n", a * 2); } switch (a) { case 0x00: // MEM4MB/DAC18B/VER/MVOL *(u16 *)&scsp_ccr[a ^ 2] &= 0xFF0F; break; case 0x04: // Midi flags/MIBUF { u16 d = (scsp.midflag << 8); // this needs to be done to keep midfi status before midi in read d |= scsp_midi_in_read(); return d; } case 0x06: // MOBUF return scsp_midi_out_read(); case 0x08: // CA/SGC/EG return (scsp.ca & 0x780) | (scsp.sgc << 5) | scsp.eg; case 0x18: // TACTL return (scsp.timasd << 8); case 0x1A: // TBCTL return (scsp.timbsd << 8); case 0x1C: // TCCTL return (scsp.timcsd << 8); case 0x1E: // SCIEB return scsp.scieb; case 0x20: // SCIPD return scsp.scipd; case 0x2C: // MCIPD return scsp.mcipd; } return *(u16 *)&scsp_ccr[a ^ 2]; } //////////////////////////////////////////////////////////////// // Synth Slot // // SCSPLOG("outL=%.8X bufL=%.8X disll=%d\n", outL, scsp_bufL[scsp_buf_pos], slot->disll); //////////////////////////////////////////////////////////////// #ifdef WORDS_BIGENDIAN #define SCSP_GET_OUT_8B \ out = (s32) slot->buf8[(slot->fcnt >> SCSP_FREQ_LB)]; #else #define SCSP_GET_OUT_8B \ out = (s32) slot->buf8[(slot->fcnt >> SCSP_FREQ_LB) ^ 1]; #endif #define SCSP_GET_OUT_16B \ out = (s32) slot->buf16[slot->fcnt >> SCSP_FREQ_LB]; #define SCSP_GET_ENV \ slot->env = scsp_env_table[slot->ecnt >> SCSP_ENV_LB] * slot->tl / 1024; #define SCSP_GET_ENV_LFO \ slot->env = (scsp_env_table[slot->ecnt >> SCSP_ENV_LB] * slot->tl / 1024) - \ (slot->lfoemw[(slot->lfocnt >> SCSP_LFO_LB) & SCSP_LFO_MASK] >> \ slot->lfoems); #define SCSP_OUT_8B_L \ if ((out) && (slot->env > 0)) \ { \ out *= slot->env; \ scsp_bufL[scsp_buf_pos] += out >> (slot->disll - 8); \ } #define SCSP_OUT_8B_R \ if ((out) && (slot->env > 0)) \ { \ out *= slot->env; \ scsp_bufR[scsp_buf_pos] += out >> (slot->dislr - 8); \ } #define SCSP_OUT_8B_LR \ if ((out) && (slot->env > 0)) \ { \ out *= slot->env; \ scsp_bufL[scsp_buf_pos] += out >> (slot->disll - 8); \ scsp_bufR[scsp_buf_pos] += out >> (slot->dislr - 8); \ } #define SCSP_OUT_16B_L \ if ((out) && (slot->env > 0)) \ { \ out *= slot->env; \ scsp_bufL[scsp_buf_pos] += out >> slot->disll; \ } #define SCSP_OUT_16B_R \ if ((out) && (slot->env > 0)) \ { \ out *= slot->env; \ scsp_bufR[scsp_buf_pos] += out >> slot->dislr; \ } #define SCSP_OUT_16B_LR \ if ((out) && (slot->env > 0)) \ { \ out *= slot->env; \ scsp_bufL[scsp_buf_pos] += out >> slot->disll; \ scsp_bufR[scsp_buf_pos] += out >> slot->dislr; \ } #define SCSP_UPDATE_PHASE \ if ((slot->fcnt += slot->finc) > slot->lea) \ { \ if (slot->lpctl) \ { \ slot->fcnt = slot->lsa; \ } \ else \ { \ slot->ecnt = SCSP_ENV_DE; \ return; \ } \ } #define SCSP_UPDATE_PHASE_LFO \ slot->fcnt += \ ((slot->lfofmw[(slot->lfocnt >> SCSP_LFO_LB) & SCSP_LFO_MASK] << \ (slot->lfofms-7)) >> (slot->fsft+1)); \ if ((slot->fcnt += slot->finc) > slot->lea) \ { \ if (slot->lpctl) \ { \ slot->fcnt = slot->lsa; \ } \ else \ { \ slot->ecnt = SCSP_ENV_DE; \ return; \ } \ } #define SCSP_UPDATE_ENV \ if (slot->einc) slot->ecnt += *slot->einc; \ if (slot->ecnt >= slot->ecmp) \ { \ slot->enxt(slot); \ if (slot->ecnt >= SCSP_ENV_DE) return; \ } #define SCSP_UPDATE_LFO \ slot->lfocnt += slot->lfoinc; //////////////////////////////////////////////////////////////// static void scsp_slot_update_keyon (slot_t *slot) { // set buffer, loop start/end address of the slot if (slot->pcm8b) { slot->buf8 = (s8*)&(scsp.scsp_ram[slot->sa]); if ((slot->sa + (slot->lea >> SCSP_FREQ_LB)) > SCSP_RAM_MASK) slot->lea = (SCSP_RAM_MASK - slot->sa) << SCSP_FREQ_LB; } else { slot->buf16 = (s16*)&(scsp.scsp_ram[slot->sa & ~1]); if ((slot->sa + (slot->lea >> (SCSP_FREQ_LB - 1))) > SCSP_RAM_MASK) slot->lea = (SCSP_RAM_MASK - slot->sa) << (SCSP_FREQ_LB - 1); } SCSP_UPDATE_PHASE } //////////////////////////////////////////////////////////////// static void scsp_slot_update_null (slot_t *slot) { for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_ENV SCSP_UPDATE_PHASE SCSP_UPDATE_ENV } } //////////////////////////////////////////////////////////////// // Normal 8 bits static void scsp_slot_update_8B_L (slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { // env = [0..0x3FF] - slot->tl SCSP_GET_OUT_8B SCSP_GET_ENV // don't waste time if no sound... SCSP_OUT_8B_L // calculate new frequency (phase) counter and enveloppe counter SCSP_UPDATE_PHASE SCSP_UPDATE_ENV } } static void scsp_slot_update_8B_R (slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_8B SCSP_GET_ENV SCSP_OUT_8B_R SCSP_UPDATE_PHASE SCSP_UPDATE_ENV } } static void scsp_slot_update_8B_LR(slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_8B SCSP_GET_ENV SCSP_OUT_8B_LR SCSP_UPDATE_PHASE SCSP_UPDATE_ENV } } //////////////////////////////////////////////////////////////// // Envelope LFO modulation 8 bits static void scsp_slot_update_E_8B_L (slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_8B SCSP_GET_ENV_LFO SCSP_OUT_8B_L SCSP_UPDATE_PHASE SCSP_UPDATE_ENV SCSP_UPDATE_LFO } } static void scsp_slot_update_E_8B_R (slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_8B SCSP_GET_ENV_LFO SCSP_OUT_8B_R SCSP_UPDATE_PHASE SCSP_UPDATE_ENV SCSP_UPDATE_LFO } } static void scsp_slot_update_E_8B_LR (slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_8B SCSP_GET_ENV_LFO SCSP_OUT_8B_LR SCSP_UPDATE_PHASE SCSP_UPDATE_ENV SCSP_UPDATE_LFO } } //////////////////////////////////////////////////////////////// // Frequency LFO modulation 8 bits static void scsp_slot_update_F_8B_L (slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_8B SCSP_GET_ENV SCSP_OUT_8B_L SCSP_UPDATE_PHASE_LFO SCSP_UPDATE_ENV SCSP_UPDATE_LFO } } static void scsp_slot_update_F_8B_R (slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_8B SCSP_GET_ENV SCSP_OUT_8B_R SCSP_UPDATE_PHASE_LFO SCSP_UPDATE_ENV SCSP_UPDATE_LFO } } static void scsp_slot_update_F_8B_LR (slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_8B SCSP_GET_ENV SCSP_OUT_8B_LR SCSP_UPDATE_PHASE_LFO SCSP_UPDATE_ENV SCSP_UPDATE_LFO } } //////////////////////////////////////////////////////////////// // Enveloppe & Frequency LFO modulation 8 bits static void scsp_slot_update_F_E_8B_L (slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_8B SCSP_GET_ENV_LFO SCSP_OUT_8B_L SCSP_UPDATE_PHASE_LFO SCSP_UPDATE_ENV SCSP_UPDATE_LFO } } static void scsp_slot_update_F_E_8B_R (slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_8B SCSP_GET_ENV_LFO SCSP_OUT_8B_R SCSP_UPDATE_PHASE_LFO SCSP_UPDATE_ENV SCSP_UPDATE_LFO } } static void scsp_slot_update_F_E_8B_LR(slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_8B SCSP_GET_ENV_LFO SCSP_OUT_8B_LR SCSP_UPDATE_PHASE_LFO SCSP_UPDATE_ENV SCSP_UPDATE_LFO } } //////////////////////////////////////////////////////////////// // Normal 16 bits static void scsp_slot_update_16B_L (slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_16B SCSP_GET_ENV SCSP_OUT_16B_L SCSP_UPDATE_PHASE SCSP_UPDATE_ENV } } static void scsp_slot_update_16B_R (slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_16B SCSP_GET_ENV SCSP_OUT_16B_R SCSP_UPDATE_PHASE SCSP_UPDATE_ENV } } static void scsp_slot_update_16B_LR (slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_16B SCSP_GET_ENV SCSP_OUT_16B_LR SCSP_UPDATE_PHASE SCSP_UPDATE_ENV } } //////////////////////////////////////////////////////////////// // Envelope LFO modulation 16 bits static void scsp_slot_update_E_16B_L (slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_16B SCSP_GET_ENV_LFO SCSP_OUT_16B_L SCSP_UPDATE_PHASE SCSP_UPDATE_ENV SCSP_UPDATE_LFO } } static void scsp_slot_update_E_16B_R (slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_16B SCSP_GET_ENV_LFO SCSP_OUT_16B_R SCSP_UPDATE_PHASE SCSP_UPDATE_ENV SCSP_UPDATE_LFO } } static void scsp_slot_update_E_16B_LR (slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_16B SCSP_GET_ENV_LFO SCSP_OUT_16B_LR SCSP_UPDATE_PHASE SCSP_UPDATE_ENV SCSP_UPDATE_LFO } } //////////////////////////////////////////////////////////////// // Frequency LFO modulation 16 bits static void scsp_slot_update_F_16B_L (slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_16B SCSP_GET_ENV SCSP_OUT_16B_L SCSP_UPDATE_PHASE_LFO SCSP_UPDATE_ENV SCSP_UPDATE_LFO } } static void scsp_slot_update_F_16B_R (slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_16B SCSP_GET_ENV SCSP_OUT_16B_R SCSP_UPDATE_PHASE_LFO SCSP_UPDATE_ENV SCSP_UPDATE_LFO } } static void scsp_slot_update_F_16B_LR (slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_16B SCSP_GET_ENV SCSP_OUT_16B_LR SCSP_UPDATE_PHASE_LFO SCSP_UPDATE_ENV SCSP_UPDATE_LFO } } //////////////////////////////////////////////////////////////// // Envelope & Frequency LFO modulation 16 bits static void scsp_slot_update_F_E_16B_L (slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_16B SCSP_GET_ENV_LFO SCSP_OUT_16B_L SCSP_UPDATE_PHASE_LFO SCSP_UPDATE_ENV SCSP_UPDATE_LFO } } static void scsp_slot_update_F_E_16B_R (slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_16B SCSP_GET_ENV_LFO SCSP_OUT_16B_R SCSP_UPDATE_PHASE_LFO SCSP_UPDATE_ENV SCSP_UPDATE_LFO } } static void scsp_slot_update_F_E_16B_LR (slot_t *slot) { s32 out; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { SCSP_GET_OUT_16B SCSP_GET_ENV_LFO SCSP_OUT_16B_LR SCSP_UPDATE_PHASE_LFO SCSP_UPDATE_ENV SCSP_UPDATE_LFO } } //////////////////////////////////////////////////////////////// // Update functions static void (*scsp_slot_update_p[2][2][2][2][2])(slot_t *slot) = { // NO FMS { // NO EMS { // 8 BITS { // NO LEFT { // NO RIGHT scsp_slot_update_null, // RIGHT scsp_slot_update_8B_R }, // LEFT { // NO RIGHT scsp_slot_update_8B_L, // RIGHT scsp_slot_update_8B_LR }, }, // 16 BITS { // NO LEFT { // NO RIGHT scsp_slot_update_null, // RIGHT scsp_slot_update_16B_R }, // LEFT { // NO RIGHT scsp_slot_update_16B_L, // RIGHT scsp_slot_update_16B_LR }, } }, // EMS { // 8 BITS { // NO LEFT { // NO RIGHT scsp_slot_update_null, // RIGHT scsp_slot_update_E_8B_R }, // LEFT { // NO RIGHT scsp_slot_update_E_8B_L, // RIGHT scsp_slot_update_E_8B_LR }, }, // 16 BITS { // NO LEFT { // NO RIGHT scsp_slot_update_null, // RIGHT scsp_slot_update_E_16B_R }, // LEFT { // NO RIGHT scsp_slot_update_E_16B_L, // RIGHT scsp_slot_update_E_16B_LR }, } } }, // FMS { // NO EMS { // 8 BITS { // NO LEFT { // NO RIGHT scsp_slot_update_null, // RIGHT scsp_slot_update_F_8B_R }, // LEFT { // NO RIGHT scsp_slot_update_F_8B_L, // RIGHT scsp_slot_update_F_8B_LR }, }, // 16 BITS { // NO LEFT { // NO RIGHT scsp_slot_update_null, // RIGHT scsp_slot_update_F_16B_R }, // LEFT { // NO RIGHT scsp_slot_update_F_16B_L, // RIGHT scsp_slot_update_F_16B_LR }, } }, // EMS { // 8 BITS { // NO LEFT { // NO RIGHT scsp_slot_update_null, // RIGHT scsp_slot_update_F_E_8B_R }, // LEFT { // NO RIGHT scsp_slot_update_F_E_8B_L, // RIGHT scsp_slot_update_F_E_8B_LR }, }, // 16 BITS { // NO LEFT { // NO RIGHT scsp_slot_update_null, // RIGHT scsp_slot_update_F_E_16B_R }, // LEFT { // NO RIGHT scsp_slot_update_F_E_16B_L, // RIGHT scsp_slot_update_F_E_16B_LR }, } } } }; void scsp_update (s32 *bufL, s32 *bufR, u32 len) { slot_t *slot; scsp_bufL = bufL; scsp_bufR = bufR; for (slot = &(scsp.slot[0]); slot < &(scsp.slot[32]); slot++) { if (slot->ecnt >= SCSP_ENV_DE) continue; // enveloppe null... if (slot->ssctl) { // Still not correct, but at least this fixes games // that rely on Call Address information scsp_buf_len = len; scsp_buf_pos = 0; for (; scsp_buf_pos < scsp_buf_len; scsp_buf_pos++) { if ((slot->fcnt += slot->finc) > slot->lea) { if (slot->lpctl) slot->fcnt = slot->lsa; else { slot->ecnt = SCSP_ENV_DE; break; } } } continue; // not yet supported! } scsp_buf_len = len; scsp_buf_pos = 0; // take effect sound volume if no direct sound volume... if ((slot->disll == 31) && (slot->dislr == 31)) { slot->disll = slot->efsll; slot->dislr = slot->efslr; } // SCSPLOG("update : VL=%d VR=%d CNT=%.8X STEP=%.8X\n", slot->disll, slot->dislr, slot->fcnt, slot->finc); scsp_slot_update_p[(slot->lfofms == 31) ? 0 : 1] [(slot->lfoems == 31) ? 0 : 1] [(slot->pcm8b == 0) ? 1 : 0] [(slot->disll == 31) ? 0 : 1] [(slot->dislr == 31) ? 0 : 1](slot); } if (cdda_out_left > 0) { if (len > cdda_out_left / 4) scsp_buf_len = cdda_out_left / 4; else scsp_buf_len = len; scsp_buf_pos = 0; /* May need to wrap around the buffer, so use nested loops */ while (scsp_buf_pos < scsp_buf_len) { s32 temp = cdda_next_in - cdda_out_left; s32 outpos = (temp < 0) ? temp + sizeof(cddabuf.data) : temp; u8 *buf = &cddabuf.data[outpos]; u32 scsp_buf_target; u32 this_len = scsp_buf_len - scsp_buf_pos; if (this_len > (sizeof(cddabuf.data) - outpos) / 4) this_len = (sizeof(cddabuf.data) - outpos) / 4; scsp_buf_target = scsp_buf_pos + this_len; for (; scsp_buf_pos < scsp_buf_target; scsp_buf_pos++, buf += 4) { s32 out; out = (s32)(s16)((buf[1] << 8) | buf[0]); if (out) scsp_bufL[scsp_buf_pos] += out; out = (s32)(s16)((buf[3] << 8) | buf[2]); if (out) scsp_bufR[scsp_buf_pos] += out; } cdda_out_left -= this_len * 4; } } else if (Cs2Area->isaudio) { SCSPLOG("WARNING: CDDA buffer underrun\n"); } } void scsp_update_monitor(void) { if (use_new_scsp) { scsp.ca = new_scsp.slots[scsp.mslc].state.sample_offset >> 5; scsp.sgc = new_scsp.slots[scsp.mslc].state.envelope; scsp.eg = new_scsp.slots[scsp.mslc].state.attenuation >> 5; } else { slot_t *slot = &scsp.slot[scsp.mslc]; scsp.ca = ((slot->fcnt >> (SCSP_FREQ_LB + 12)) & 0xF) << 7; scsp.sgc = slot->ecurp; scsp.eg = 0x1f - (slot->env >> (SCSP_ENV_HB - 5)); } #ifdef PSP WRITE_THROUGH(scsp.ca); WRITE_THROUGH(scsp.sgc); WRITE_THROUGH(scsp.eg); #endif } void scsp_update_timer (u32 len) { scsp.timacnt += len << (8 - scsp.timasd); if (scsp.timacnt >= 0xFF00) { if (!(scsp.scipd & 0x40)) scsp_sound_interrupt(0x40); if (!(scsp.mcipd & 0x40)) scsp_main_interrupt(0x40); scsp.timacnt -= 0xFF00; } scsp.timbcnt += len << (8 - scsp.timbsd); if (scsp.timbcnt >= 0xFF00) { if (!(scsp.scipd & 0x80)) scsp_sound_interrupt(0x80); if (!(scsp.mcipd & 0x80)) scsp_main_interrupt(0x80); scsp.timbcnt -= 0xFF00; } scsp.timccnt += len << (8 - scsp.timcsd); if (scsp.timccnt >= 0xFF00) { if (!(scsp.scipd & 0x100)) scsp_sound_interrupt(0x100); if (!(scsp.mcipd & 0x100)) scsp_main_interrupt(0x100); scsp.timccnt -= 0xFF00; } // 1F interrupt can't be accurate here... if (len) { if (!(scsp.scipd & 0x400)) scsp_sound_interrupt(0x400); if (!(scsp.mcipd & 0x400)) scsp_main_interrupt(0x400); } } //////////////////////////////////////////////////////////////// // MIDI void scsp_midi_in_send (u8 data) { if (scsp.midflag & SCSP_MIDI_IN_EMP) { scsp_sound_interrupt(0x8); scsp_main_interrupt(0x8); } scsp.midflag &= ~SCSP_MIDI_IN_EMP; if (scsp.midincnt > 3) { scsp.midflag |= SCSP_MIDI_IN_OVF; return; } scsp.midinbuf[scsp.midincnt++] = data; if (scsp.midincnt > 3) scsp.midflag |= SCSP_MIDI_IN_FUL; } void scsp_midi_out_send (u8 data) { scsp.midflag &= ~SCSP_MIDI_OUT_EMP; if (scsp.midoutcnt > 3) return; scsp.midoutbuf[scsp.midoutcnt++] = data; if (scsp.midoutcnt > 3) scsp.midflag |= SCSP_MIDI_OUT_FUL; } u8 scsp_midi_in_read (void) { u8 data; scsp.midflag &= ~(SCSP_MIDI_IN_OVF | SCSP_MIDI_IN_FUL); if (scsp.midincnt > 0) { if (scsp.midincnt > 1) { scsp_sound_interrupt(0x8); scsp_main_interrupt(0x8); } else { scsp.midflag |= SCSP_MIDI_IN_EMP; } data = scsp.midinbuf[0]; switch ((--scsp.midincnt) & 3) { case 1: scsp.midinbuf[0] = scsp.midinbuf[1]; break; case 2: scsp.midinbuf[0] = scsp.midinbuf[1]; scsp.midinbuf[1] = scsp.midinbuf[2]; break; case 3: scsp.midinbuf[0] = scsp.midinbuf[1]; scsp.midinbuf[1] = scsp.midinbuf[2]; scsp.midinbuf[2] = scsp.midinbuf[3]; break; } return data; } return 0xFF; } u8 scsp_midi_out_read (void) { u8 data; scsp.midflag &= ~SCSP_MIDI_OUT_FUL; if (scsp.midoutcnt > 0) { if (scsp.midoutcnt == 1) { scsp.midflag |= SCSP_MIDI_OUT_EMP; scsp_sound_interrupt(0x200); scsp_main_interrupt(0x200); } data = scsp.midoutbuf[0]; switch (--scsp.midoutcnt & 3) { case 1: scsp.midoutbuf[0] = scsp.midoutbuf[1]; break; case 2: scsp.midoutbuf[0] = scsp.midoutbuf[1]; scsp.midoutbuf[1] = scsp.midoutbuf[2]; break; case 3: scsp.midoutbuf[0] = scsp.midoutbuf[1]; scsp.midoutbuf[1] = scsp.midoutbuf[2]; scsp.midoutbuf[2] = scsp.midoutbuf[3]; break; } return data; } return 0xFF; } //////////////////////////////////////////////////////////////// // Access void FASTCALL scsp_w_b (u32 a, u8 d) { a &= 0xFFF; if (a < 0x400) { if (use_new_scsp) scsp_slot_write_byte(&new_scsp, a, d); else scsp_slot_set_b(a >> 5, a, d); FLUSH_SCSP (); return; } else if (a < 0x600) { if (a < 0x440) { scsp_set_b (a, d); FLUSH_SCSP (); return; } } else if (a < 0x700) { } else if (a < 0xee4) { a &= 0x3ff; scsp_dcr[a ^ 3] = d; return; } SCSPLOG("WARNING: scsp w_b to %08lx w/ %02x\n", a, d); } //////////////////////////////////////////////////////////////// void FASTCALL scsp_w_w (u32 a, u16 d) { if (a & 1) { SCSPLOG ("ERROR: scsp w_w misaligned : %.8X\n", a); } a &= 0xFFE; if (a < 0x400) { if (use_new_scsp) scsp_slot_write_word(&new_scsp, a, d); else scsp_slot_set_w(a >> 5, a, d); FLUSH_SCSP (); return; } else if (a < 0x600) { if (a < 0x440) { scsp_set_w (a, d); FLUSH_SCSP (); return; } } else if (a < 0x700) { } else if (a >= 0x700 && a < 0x780) { u32 address = (a - 0x700) / 2; scsp_dsp.coef[address] = d >> 3;//lower 3 bits seem to be discarded } else if (a >= 0x780 && a < 0x7A0) { u32 address = (a - 0x780) / 2; scsp_dsp.madrs[address] = d; } else if (a >= 0x7A0 && a < 0x7C0) { //madrs mirror //seems to read only (todo test) } else if (a >= 0x800 && a < 0xC00) { u32 address = (a - 0x800) / 8; u64 current_val = scsp_dsp.mpro[address]; switch (a & 0xf) { case 0: case 8: scsp_dsp.mpro[address] = (current_val & 0x0000ffffffffffff) | (u64)d << (u64)48; break; case 2: case 0xa: scsp_dsp.mpro[address] = (current_val & 0xffff0000ffffffff) | (u64)d << (u64)32; break; case 4: case 0xc: scsp_dsp.mpro[address] = (current_val & 0xffffffff0000ffff) | (u64)d << (u64)16; break; case 6: case 0xe: scsp_dsp.mpro[address] = (current_val & 0xffffffffffff0000) | d; break; default: break; } } else if (a < 0xee4) { a &= 0x3ff; *(u16 *)&scsp_dcr[a ^ 2] = d; return; } SCSPLOG ("WARNING: scsp w_w to %08lx w/ %04x\n", a, d); } //////////////////////////////////////////////////////////////// void FASTCALL scsp_w_d (u32 a, u32 d) { if (a & 3) { SCSPLOG ("ERROR: scsp w_d misaligned : %.8X\n", a); } a &= 0xFFC; if (a < 0x400) { if (use_new_scsp) { scsp_slot_write_word(&new_scsp, a + 0, d >> 16); scsp_slot_write_word(&new_scsp, a + 2, d & 0xffff); } else { scsp_slot_set_w(a >> 5, a + 0, d >> 16); scsp_slot_set_w(a >> 5, a + 2, d & 0xFFFF); } FLUSH_SCSP (); return; } else if (a < 0x600) { if (a < 0x440) { scsp_set_w (a + 0, d >> 16); scsp_set_w (a + 2, d & 0xFFFF); FLUSH_SCSP (); return; } } else if (a < 0x700) { } else if (a < 0xee4) { a &= 0x3ff; *(u32 *)&scsp_dcr[a] = d; return; } SCSPLOG ("WARNING: scsp w_d to %08lx w/ %08lx\n", a, d); } //////////////////////////////////////////////////////////////// u8 FASTCALL scsp_r_b (u32 a) { a &= 0xFFF; if (a < 0x400) { if (use_new_scsp) return scsp_slot_read_byte(&new_scsp, a); else return scsp_slot_get_b(a >> 5, a); } else if (a < 0x600) { if (a < 0x440) return scsp_get_b(a); } else if (a < 0x700) { } else if (a < 0xee4) { } SCSPLOG("WARNING: scsp r_b to %08lx\n", a); return 0; } //////////////////////////////////////////////////////////////// u16 FASTCALL scsp_r_w (u32 a) { if (a & 1) { SCSPLOG ("ERROR: scsp r_w misaligned : %.8X\n", a); } a &= 0xFFE; if (a < 0x400) { if (use_new_scsp) return scsp_slot_read_word(&new_scsp, a); else return scsp_slot_get_w(a >> 5, a); } else if (a < 0x600) { if (a < 0x440) return scsp_get_w (a); } else if (a < 0x700) { if (use_new_scsp) { u32 addr = a - 0x600; return new_scsp.sound_stack[(addr / 2) & 0x3f]; } } else if (a >= 0x700 && a < 0x780) { u32 address = (a - 0x700) / 2; return scsp_dsp.coef[address] << 3; } else if (a >= 0x780 && a < 0x7A0) { u32 address = (a - 0x780) / 2; return scsp_dsp.madrs[address]; } else if (a >= 0x7A0 && a < 0x7C0) { //madrs mirror u32 address = (a - 0x7A0) / 2; return scsp_dsp.madrs[address]; } else if (a >= 0x800 && a < 0xC00) { u32 address = (a - 0x800) / 8; switch (a & 0xf) { case 0: case 8: return (scsp_dsp.mpro[address] >> (u64)48) & 0xffff; break; case 2: case 0xa: return (scsp_dsp.mpro[address] >> (u64)32) & 0xffff; break; case 4: case 0xc: return (scsp_dsp.mpro[address] >> (u64)16) & 0xffff; break; case 6: case 0xe: return scsp_dsp.mpro[address] & 0xffff; break; default: break; } } else if (a >= 0xE00 && a <= 0xE7F) { u32 address = (a - 0xE00) / 2; return scsp_dsp.mems[address]; } else if (a >= 0xEE0 && a <= 0xEE3) { u32 address = (a - 0xEE0) / 2; return scsp_dsp.exts[address]; } else if (a < 0xee4) { } SCSPLOG ("WARNING: scsp r_w to %08lx\n", a); return 0; } //////////////////////////////////////////////////////////////// u32 FASTCALL scsp_r_d (u32 a) { if (a & 3) { SCSPLOG ("ERROR: scsp r_d misaligned : %.8X\n", a); } a &= 0xFFC; if (a < 0x400) { if (use_new_scsp) return (scsp_slot_read_word(&new_scsp, a + 0) << 16) | scsp_slot_read_word(&new_scsp, a + 2); else return (scsp_slot_get_w(a >> 5, a + 0) << 16) | scsp_slot_get_w(a >> 5, a + 2); } else if (a < 0x600) { if (a < 0x440) return (scsp_get_w (a + 0) << 16) | scsp_get_w (a + 2); } else if (a < 0x700) { } else if (a < 0xee4) { } SCSPLOG("WARNING: scsp r_d to %08lx\n", a); return 0; } //////////////////////////////////////////////////////////////// // Interface void scsp_shutdown (void) { } void scsp_reset (void) { slot_t *slot; memset(scsp_reg, 0, 0x1000); scsp.mem4b = 0; scsp.mvol = 0; scsp.rbl = 0; scsp.rbp = 0; scsp.mslc = 0; scsp.ca = 0; scsp.dmea = 0; scsp.drga = 0; scsp.dmfl = 0; scsp.dmlen = 0; scsp.midincnt = 0; scsp.midoutcnt = 0; scsp.midflag = SCSP_MIDI_IN_EMP | SCSP_MIDI_OUT_EMP; scsp.midflag2 = 0; scsp.timacnt = 0xFF00; scsp.timbcnt = 0xFF00; scsp.timccnt = 0xFF00; scsp.timasd = 0; scsp.timbsd = 0; scsp.timcsd = 0; scsp.mcieb = 0; scsp.mcipd = 0; scsp.scieb = 0; scsp.scipd = 0; scsp.scilv0 = 0; scsp.scilv1 = 0; scsp.scilv2 = 0; for(slot = &(scsp.slot[0]); slot < &(scsp.slot[32]); slot++) { memset(slot, 0, sizeof(slot_t)); slot->ecnt = SCSP_ENV_DE; // slot off slot->ecurp = SCSP_ENV_RELEASE; slot->dislr = slot->disll = 31; // direct level sound off slot->efslr = slot->efsll = 31; // effect level sound off // Make sure lfofmw/lfoemw have sane values slot->lfofmw = scsp_lfo_sawt_f; slot->lfoemw = scsp_lfo_sawt_e; } if (use_new_scsp) new_scsp_reset(&new_scsp); } void scsp_init (u8 *scsp_ram, void (*sint_hand)(u32), void (*mint_hand)(void)) { u32 i, j; double x; scsp_shutdown (); scsp_isr = &scsp_reg[0x0000]; scsp_ccr = &scsp_reg[0x0400]; scsp_dcr = &scsp_reg[0x0700]; scsp.scsp_ram = scsp_ram; scsp.sintf = sint_hand; scsp.mintf = mint_hand; for (i = 0; i < SCSP_ENV_LEN; i++) { // Attack Curve (x^7 ?) x = pow (((double)(SCSP_ENV_MASK - i) / (double)SCSP_ENV_LEN), 7); x *= (double)SCSP_ENV_LEN; scsp_env_table[i] = SCSP_ENV_MASK - (s32)x; // Decay curve (x = linear) x = pow (((double)i / (double)SCSP_ENV_LEN), 1); x *= (double)SCSP_ENV_LEN; scsp_env_table[i + SCSP_ENV_LEN] = SCSP_ENV_MASK - (s32)x; } for (i = 0, j = 0; i < 32; i++) { j += 1 << (i >> 2); // lfo freq x = (SCSP_FREQ / 256.0) / (double)j; // converting lfo freq in lfo step scsp_lfo_step[31 - i] = scsp_round(x * ((double)SCSP_LFO_LEN / (double)SCSP_FREQ) * (double)(1 << SCSP_LFO_LB)); } // Calculate LFO (modulation) values for (i = 0; i < SCSP_LFO_LEN; i++) { // Envelope modulation scsp_lfo_sawt_e[i] = SCSP_LFO_MASK - i; if (i < (SCSP_LFO_LEN / 2)) scsp_lfo_squa_e[i] = SCSP_LFO_MASK; else scsp_lfo_squa_e[i] = 0; if (i < (SCSP_LFO_LEN / 2)) scsp_lfo_tri_e[i] = SCSP_LFO_MASK - (i * 2); else scsp_lfo_tri_e[i] = (i - (SCSP_LFO_LEN / 2)) * 2; scsp_lfo_noi_e[i] = rand() & SCSP_LFO_MASK; // Frequency modulation scsp_lfo_sawt_f[(i + 512) & SCSP_LFO_MASK] = i - (SCSP_LFO_LEN / 2); if (i < (SCSP_LFO_LEN / 2)) scsp_lfo_squa_f[i] = SCSP_LFO_MASK - (SCSP_LFO_LEN / 2) - 128; else scsp_lfo_squa_f[i] = 0 - (SCSP_LFO_LEN / 2) + 128; if (i < (SCSP_LFO_LEN / 2)) scsp_lfo_tri_f[(i + 768) & SCSP_LFO_MASK] = (i * 2) - (SCSP_LFO_LEN / 2); else scsp_lfo_tri_f[(i + 768) & SCSP_LFO_MASK] = (SCSP_LFO_MASK - ((i - (SCSP_LFO_LEN / 2)) * 2)) - (SCSP_LFO_LEN / 2) + 1; scsp_lfo_noi_f[i] = scsp_lfo_noi_e[i] - (SCSP_LFO_LEN / 2); } for(i = 0; i < 4; i++) { scsp_attack_rate[i] = 0; scsp_decay_rate[i] = 0; } for(i = 0; i < 60; i++) { x = 1.0 + ((i & 3) * 0.25); // bits 0-1 : x1.00, x1.25, x1.50, x1.75 x *= (double)(1 << ((i >> 2))); // bits 2-5 : shift bits (x2^0 - x2^15) x *= (double)(SCSP_ENV_LEN << SCSP_ENV_LB); // adjust for table scsp_env_table scsp_attack_rate[i + 4] = scsp_round(x / (double)SCSP_ATTACK_R); scsp_decay_rate[i + 4] = scsp_round(x / (double)SCSP_DECAY_R); if (scsp_attack_rate[i + 4] == 0) scsp_attack_rate[i + 4] = 1; if (scsp_decay_rate[i + 4] == 0) scsp_decay_rate[i + 4] = 1; } scsp_attack_rate[63] = SCSP_ENV_AE; scsp_decay_rate[61] = scsp_decay_rate[60]; scsp_decay_rate[62] = scsp_decay_rate[60]; scsp_decay_rate[63] = scsp_decay_rate[60]; for(i = 64; i < 96; i++) { scsp_attack_rate[i] = scsp_attack_rate[63]; scsp_decay_rate[i] = scsp_decay_rate[63]; scsp_null_rate[i - 64] = 0; } for(i = 0; i < 96; i++) { SCSPLOG ("attack rate[%d] = %.8X -> %.8X\n", i, scsp_attack_rate[i], scsp_attack_rate[i] >> SCSP_ENV_LB); SCSPLOG ("decay rate[%d] = %.8X -> %.8X\n", i, scsp_decay_rate[i], scsp_decay_rate[i] >> SCSP_ENV_LB); } for(i = 0; i < 256; i++) scsp_tl_table[i] = scsp_round(pow(10, ((double)i * -0.3762) / 20) * 1024.0); scsp_reset(); } ////////////////////////////////////////////////////////////////////////////// // Yabause specific ////////////////////////////////////////////////////////////////////////////// u8 *SoundRam = NULL; ScspInternal *ScspInternalVars; static SoundInterface_struct *SNDCore = NULL; extern SoundInterface_struct *SNDCoreList[]; struct sounddata { u32 *data32; } scspchannel[2]; static u32 scspsoundlen; // Samples to output per frame static u32 scsplines; // Lines per frame static u32 scspsoundbufs; // Number of "scspsoundlen"-sample buffers static u32 scspsoundbufsize; // scspsoundlen * scspsoundbufs static u32 scspsoundgenpos; // Offset of next byte to generate static u32 scspsoundoutleft; // Samples not yet sent to host driver static int scsp_alloc_bufs (void) { if (scspchannel[0].data32) free(scspchannel[0].data32); scspchannel[0].data32 = NULL; if (scspchannel[1].data32) free(scspchannel[1].data32); scspchannel[1].data32 = NULL; scspchannel[0].data32 = (u32 *)calloc(scspsoundbufsize, sizeof(u32)); if (scspchannel[0].data32 == NULL) return -1; scspchannel[1].data32 = (u32 *)calloc(scspsoundbufsize, sizeof(u32)); if (scspchannel[1].data32 == NULL) return -1; return 0; } static u8 IsM68KRunning; static s32 FASTCALL (*m68kexecptr)(s32 cycles); // M68K->Exec or M68KExecBP static s32 savedcycles; // Cycles left over from the last M68KExec() call ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL c68k_byte_read (const u32 adr) { if (adr < 0x100000) return T2ReadByte(SoundRam, adr & 0x7FFFF); else return scsp_r_b(adr); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL c68k_byte_write (const u32 adr, u32 data) { if (adr < 0x100000) T2WriteByte(SoundRam, adr & 0x7FFFF, data); else scsp_w_b(adr, data); } ////////////////////////////////////////////////////////////////////////////// /* exported to m68kd.c */ u32 FASTCALL c68k_word_read (const u32 adr) { if (adr < 0x100000) return T2ReadWord(SoundRam, adr & 0x7FFFF); else return scsp_r_w(adr); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL c68k_word_write (const u32 adr, u32 data) { if (adr < 0x100000) T2WriteWord (SoundRam, adr & 0x7FFFF, data); else scsp_w_w (adr, data); } ////////////////////////////////////////////////////////////////////////////// static void c68k_interrupt_handler (u32 level) { // send interrupt to 68k M68K->SetIRQ ((s32)level); } ////////////////////////////////////////////////////////////////////////////// static void scu_interrupt_handler (void) { // send interrupt to scu ScuSendSoundRequest (); } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL ScspReadByte (u32 addr) { return scsp_r_b(addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL ScspWriteByte (u32 addr, u8 val) { scsp_w_b(addr, val); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL ScspReadWord (u32 addr) { return scsp_r_w(addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL ScspWriteWord (u32 addr, u16 val) { scsp_w_w(addr, val); } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL ScspReadLong (u32 addr) { return scsp_r_d(addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL ScspWriteLong (u32 addr, u32 val) { scsp_w_d(addr, val); } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL SoundRamReadByte (u32 addr) { addr &= 0xFFFFF; // If mem4b is set, mirror ram every 256k if (scsp.mem4b == 0) addr &= 0x3FFFF; else if (addr > 0x7FFFF) return 0xFF; return T2ReadByte (SoundRam, addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL SoundRamWriteByte (u32 addr, u8 val) { addr &= 0xFFFFF; // If mem4b is set, mirror ram every 256k if (scsp.mem4b == 0) addr &= 0x3FFFF; else if (addr > 0x7FFFF) return; T2WriteByte (SoundRam, addr, val); M68K->WriteNotify (addr, 1); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL SoundRamReadWord (u32 addr) { addr &= 0xFFFFF; if (scsp.mem4b == 0) addr &= 0x3FFFF; else if (addr > 0x7FFFF) return 0xFFFF; return T2ReadWord (SoundRam, addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL SoundRamWriteWord (u32 addr, u16 val) { addr &= 0xFFFFF; // If mem4b is set, mirror ram every 256k if (scsp.mem4b == 0) addr &= 0x3FFFF; else if (addr > 0x7FFFF) return; T2WriteWord (SoundRam, addr, val); M68K->WriteNotify (addr, 2); } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL SoundRamReadLong (u32 addr) { addr &= 0xFFFFF; // If mem4b is set, mirror ram every 256k if (scsp.mem4b == 0) addr &= 0x3FFFF; else if (addr > 0x7FFFF) return 0xFFFFFFFF; return T2ReadLong (SoundRam, addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL SoundRamWriteLong (u32 addr, u32 val) { addr &= 0xFFFFF; // If mem4b is set, mirror ram every 256k if (scsp.mem4b == 0) addr &= 0x3FFFF; else if (addr > 0x7FFFF) return; T2WriteLong (SoundRam, addr, val); M68K->WriteNotify (addr, 4); } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL Sh2ScspReadByte(SH2_struct *sh, u32 addr) { return ScspReadByte(addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2ScspWriteByte(SH2_struct *sh, u32 addr, u8 val) { ScspWriteByte(addr, val); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL Sh2ScspReadWord(SH2_struct *sh, u32 addr) { return ScspReadWord(addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2ScspWriteWord(SH2_struct *sh, u32 addr, u16 val) { ScspWriteWord(addr, val); } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL Sh2ScspReadLong(SH2_struct *sh, u32 addr) { return ScspReadLong(addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2ScspWriteLong(SH2_struct *sh, u32 addr, u32 val) { ScspWriteLong(addr, val); } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL Sh2SoundRamReadByte(SH2_struct *sh, u32 addr) { return SoundRamReadByte(addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2SoundRamWriteByte(SH2_struct *sh, u32 addr, u8 val) { SoundRamWriteByte(addr, val); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL Sh2SoundRamReadWord(SH2_struct *sh, u32 addr) { return SoundRamReadWord(addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2SoundRamWriteWord(SH2_struct *sh, u32 addr, u16 val) { SoundRamWriteWord(addr, val); } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL Sh2SoundRamReadLong(SH2_struct *sh, u32 addr) { return SoundRamReadLong(addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2SoundRamWriteLong(SH2_struct *sh, u32 addr, u32 val) { SoundRamWriteLong(addr, val); } ////////////////////////////////////////////////////////////////////////////// int ScspInit (int coreid) { int i; if ((SoundRam = T2MemoryInit (0x80000)) == NULL) return -1; if ((ScspInternalVars = (ScspInternal *)calloc(1, sizeof(ScspInternal))) == NULL) return -1; if (M68K->Init () != 0) return -1; M68K->SetReadB ((C68K_READ *)c68k_byte_read); M68K->SetReadW ((C68K_READ *)c68k_word_read); M68K->SetWriteB ((C68K_WRITE *)c68k_byte_write); M68K->SetWriteW ((C68K_WRITE *)c68k_word_write); M68K->SetFetch (0x000000, 0x040000, (pointer)SoundRam); M68K->SetFetch (0x040000, 0x080000, (pointer)SoundRam); M68K->SetFetch (0x080000, 0x0C0000, (pointer)SoundRam); M68K->SetFetch (0x0C0000, 0x100000, (pointer)SoundRam); IsM68KRunning = 0; scsp_init (SoundRam, &c68k_interrupt_handler, &scu_interrupt_handler); ScspInternalVars->scsptiming1 = 0; ScspInternalVars->scsptiming2 = 0; for (i = 0; i < MAX_BREAKPOINTS; i++) ScspInternalVars->codebreakpoint[i].addr = 0xFFFFFFFF; ScspInternalVars->numcodebreakpoints = 0; ScspInternalVars->BreakpointCallBack = NULL; ScspInternalVars->inbreakpoint = 0; m68kexecptr = M68K->Exec; // Allocate enough memory for each channel buffer(may have to change) scspsoundlen = 44100 / 60; // assume it's NTSC timing scsplines = 263; scspsoundbufs = 10; // should be enough to prevent skipping scspsoundbufsize = scspsoundlen * scspsoundbufs; if (scsp_alloc_bufs () < 0) return -1; // Reset output pointers scspsoundgenpos = 0; scspsoundoutleft = 0; return ScspChangeSoundCore (coreid); } ////////////////////////////////////////////////////////////////////////////// int ScspChangeSoundCore (int coreid) { int i; // Make sure the old core is freed if (SNDCore) SNDCore->DeInit(); // So which core do we want? if (coreid == SNDCORE_DEFAULT) coreid = 0; // Assume we want the first one // Go through core list and find the id for (i = 0; SNDCoreList[i] != NULL; i++) { if (SNDCoreList[i]->id == coreid) { // Set to current core SNDCore = SNDCoreList[i]; break; } } if (SNDCore == NULL) { SNDCore = &SNDDummy; return -1; } if (SNDCore->Init () == -1) { // Since it failed, instead of it being fatal, we'll just use the dummy // core instead // This might be helpful though. YabSetError (YAB_ERR_CANNOTINIT, (void *)SNDCore->Name); SNDCore = &SNDDummy; } if (SNDCore) { if (scsp_mute_flags) SNDCore->MuteAudio(); else SNDCore->UnMuteAudio(); SNDCore->SetVolume(scsp_volume); } return 0; } ////////////////////////////////////////////////////////////////////////////// void ScspDeInit (void) { if (scspchannel[0].data32) free(scspchannel[0].data32); scspchannel[0].data32 = NULL; if (scspchannel[1].data32) free(scspchannel[1].data32); scspchannel[1].data32 = NULL; if (SNDCore) SNDCore->DeInit(); SNDCore = NULL; scsp_shutdown(); if (SoundRam) T2MemoryDeInit (SoundRam); SoundRam = NULL; } ////////////////////////////////////////////////////////////////////////////// void M68KStart (void) { M68K->Reset (); savedcycles = 0; IsM68KRunning = 1; } ////////////////////////////////////////////////////////////////////////////// void M68KStop (void) { IsM68KRunning = 0; } ////////////////////////////////////////////////////////////////////////////// void ScspReset (void) { scsp_reset(); } ////////////////////////////////////////////////////////////////////////////// int ScspChangeVideoFormat (int type) { scspsoundlen = 44100 / (type ? 50 : 60); scsplines = type ? 313 : 263; scspsoundbufsize = scspsoundlen * scspsoundbufs; if (scsp_alloc_bufs () < 0) return -1; SNDCore->ChangeVideoFormat (type ? 50 : 60); return 0; } ////////////////////////////////////////////////////////////////////////////// /* Process breakpoints in a separate function to avoid unnecessary register * spillage on the fast path (and to avoid too much block nesting) */ #ifdef __GNUC__ __attribute__((noinline)) #endif static s32 FASTCALL M68KExecBP (s32 cycles); void M68KExec (s32 cycles) { s32 newcycles = savedcycles - cycles; if (LIKELY(IsM68KRunning)) { if (LIKELY(newcycles < 0)) { s32 cyclestoexec = -newcycles; newcycles += (*m68kexecptr)(cyclestoexec); } savedcycles = newcycles; } } void new_scsp_run_sample() { s32 temp = cdda_next_in - cdda_out_left; s32 outpos = (temp < 0) ? temp + sizeof(cddabuf.data) : temp; u8 *buf = &cddabuf.data[outpos]; s16 out_l = 0; s16 out_r = 0; s16 cd_in_l = 0; s16 cd_in_r = 0; if ((s32)cdda_out_left > 0) { cd_in_l = (s16)((buf[1] << 8) | buf[0]); cd_in_r = (s16)((buf[3] << 8) | buf[2]); cdda_out_left -= 4; } scsp_update_timer(1); generate_sample(&new_scsp, scsp.rbp, scsp.rbl, &out_l, &out_r, scsp.mvol, cd_in_l, cd_in_r); if (new_scsp_outbuf_pos < 900) { new_scsp_outbuf_l[new_scsp_outbuf_pos] = out_l; new_scsp_outbuf_r[new_scsp_outbuf_pos] = out_r; } else { //buffer overrun } scsp_update_monitor(); new_scsp_outbuf_pos++; } void new_scsp_exec(s32 cycles) { s32 cycles_temp = new_scsp_cycles - cycles; if (cycles_temp < 0) { new_scsp_run_sample(); cycles_temp += 512; } new_scsp_cycles = cycles_temp; } //---------------------------------------------------------------------------- static s32 FASTCALL M68KExecBP (s32 cycles) { s32 cyclestoexec=cycles; s32 cyclesexecuted=0; int i; while (cyclesexecuted < cyclestoexec) { // Make sure it isn't one of our breakpoints for (i = 0; i < ScspInternalVars->numcodebreakpoints; i++) { if ((M68K->GetPC () == ScspInternalVars->codebreakpoint[i].addr) && ScspInternalVars->inbreakpoint == 0) { ScspInternalVars->inbreakpoint = 1; if (ScspInternalVars->BreakpointCallBack) ScspInternalVars->BreakpointCallBack (ScspInternalVars->codebreakpoint[i].addr); ScspInternalVars->inbreakpoint = 0; } } // execute instructions individually cyclesexecuted += M68K->Exec(1); } return cyclesexecuted; } ////////////////////////////////////////////////////////////////////////////// void M68KStep (void) { M68K->Exec(1); } ////////////////////////////////////////////////////////////////////////////// // Wait for background execution to finish (used on PSP) void M68KSync (void) { M68K->Sync(); } ////////////////////////////////////////////////////////////////////////////// void ScspConvert32uto16s (s32 *srcL, s32 *srcR, s16 *dst, u32 len) { u32 i; for (i = 0; i < len; i++) { // Left Channel if (*srcL > 0x7FFF) *dst = 0x7FFF; else if (*srcL < -0x8000) *dst = -0x8000; else *dst = *srcL; srcL++; dst++; // Right Channel if (*srcR > 0x7FFF) *dst = 0x7FFF; else if (*srcR < -0x8000) *dst = -0x8000; else *dst = *srcR; srcR++; dst++; } } ////////////////////////////////////////////////////////////////////////////// void ScspReceiveCDDA (const u8 *sector) { // If buffer is half empty or less, boost timing for a bit until we've buffered a few sectors if (cdda_out_left < (sizeof(cddabuf.data) / 2)) { Cs2Area->isaudio = 0; Cs2SetTiming(1); Cs2Area->isaudio = 1; } else if (cdda_out_left > (sizeof(cddabuf.data) * 3 / 4 )) Cs2SetTiming(0); else { Cs2Area->isaudio = 1; Cs2SetTiming(1); } memcpy(cddabuf.data+cdda_next_in, sector, 2352); if (sizeof(cddabuf.data)-cdda_next_in <= 2352) cdda_next_in = 0; else cdda_next_in += 2352; cdda_out_left += 2352; if (cdda_out_left > sizeof(cddabuf.data)) { SCSPLOG ("WARNING: CDDA buffer overrun\n"); cdda_out_left = sizeof(cddabuf.data); } } ////////////////////////////////////////////////////////////////////////////// void ScspReceiveMpeg (const u8 *samples, int len) { memcpy(cddabuf.data+cdda_next_in, samples, len); if (sizeof(cddabuf.data)-cdda_next_in <= len) cdda_next_in = 0; else cdda_next_in += len; cdda_out_left += len; if (cdda_out_left > sizeof(cddabuf.data)) { SCSPLOG ("WARNING: CDDA buffer overrun\n"); cdda_out_left = sizeof(cddabuf.data); } } ////////////////////////////////////////////////////////////////////////////// void new_scsp_update_samples(s32 *bufL, s32 *bufR, int scspsoundlen) { int i; for (i = 0; i < new_scsp_outbuf_pos; i++) { if (i >= scspsoundlen) break; bufL[i] = new_scsp_outbuf_l[i]; bufR[i] = new_scsp_outbuf_r[i]; } new_scsp_outbuf_pos = 0; } void ScspExec () { u32 audiosize; ScspInternalVars->scsptiming2 += ((scspsoundlen << 16) + scsplines / 2) / scsplines; if (!use_new_scsp) scsp_update_timer (ScspInternalVars->scsptiming2 >> 16); // Pass integer part ScspInternalVars->scsptiming2 &= 0xFFFF; // Keep fractional part ScspInternalVars->scsptiming1++; if (ScspInternalVars->scsptiming1 >= scsplines) { s32 *bufL, *bufR; ScspInternalVars->scsptiming1 -= scsplines; ScspInternalVars->scsptiming2 = 0; // Update sound buffers if (scspsoundgenpos + scspsoundlen > scspsoundbufsize) scspsoundgenpos = 0; if (scspsoundoutleft + scspsoundlen > scspsoundbufsize) { u32 overrun = (scspsoundoutleft + scspsoundlen) - scspsoundbufsize; SCSPLOG("WARNING: Sound buffer overrun, %lu samples\n", (long)overrun); scspsoundoutleft -= overrun; } bufL = (s32 *)&scspchannel[0].data32[scspsoundgenpos]; bufR = (s32 *)&scspchannel[1].data32[scspsoundgenpos]; memset(bufL, 0, sizeof(u32) * scspsoundlen); memset(bufR, 0, sizeof(u32) * scspsoundlen); if (use_new_scsp) new_scsp_update_samples(bufL, bufR, scspsoundlen); else scsp_update(bufL, bufR, scspsoundlen); scspsoundgenpos += scspsoundlen; scspsoundoutleft += scspsoundlen; } while (scspsoundoutleft > 0 && (audiosize = SNDCore->GetAudioSpace()) > 0) { s32 outstart = (s32)scspsoundgenpos - (s32)scspsoundoutleft; if (outstart < 0) outstart += scspsoundbufsize; if (audiosize > scspsoundoutleft) audiosize = scspsoundoutleft; if (audiosize > scspsoundbufsize - outstart) audiosize = scspsoundbufsize - outstart; SNDCore->UpdateAudio(&scspchannel[0].data32[outstart], &scspchannel[1].data32[outstart], audiosize); scspsoundoutleft -= audiosize; #if 0 ScspConvert32uto16s(&scspchannel[0].data32[outstart], &scspchannel[1].data32[outstart], (s16 *)stereodata16, audiosize); DRV_AviSoundUpdate(stereodata16, audiosize); #endif } if (!use_new_scsp) scsp_update_monitor(); #ifdef USE_SCSPMIDI // Process Midi ports while (scsp.midincnt < 4) { u8 data; int isdata; data = SNDCore->MidiIn(&isdata); if (!isdata) break; scsp_midi_in_send(data); } while (scsp.midoutcnt) { SNDCore->MidiOut(scsp_midi_out_read()); } #endif } ////////////////////////////////////////////////////////////////////////////// void M68KWriteNotify (u32 address, u32 size) { M68K->WriteNotify (address, size); } ////////////////////////////////////////////////////////////////////////////// void M68KGetRegisters (m68kregs_struct *regs) { int i; if (regs != NULL) { for (i = 0; i < 8; i++) { regs->D[i] = M68K->GetDReg (i); regs->A[i] = M68K->GetAReg (i); } regs->SR = M68K->GetSR (); regs->PC = M68K->GetPC (); } } ////////////////////////////////////////////////////////////////////////////// void M68KSetRegisters (m68kregs_struct *regs) { int i; if (regs != NULL) { for (i = 0; i < 8; i++) { M68K->SetDReg (i, regs->D[i]); M68K->SetAReg (i, regs->A[i]); } M68K->SetSR (regs->SR); M68K->SetPC (regs->PC); } } ////////////////////////////////////////////////////////////////////////////// void ScspMuteAudio (int flags) { scsp_mute_flags |= flags; if (SNDCore && scsp_mute_flags) SNDCore->MuteAudio (); } ////////////////////////////////////////////////////////////////////////////// void ScspUnMuteAudio (int flags) { scsp_mute_flags &= ~flags; if (SNDCore && (scsp_mute_flags == 0)) SNDCore->UnMuteAudio (); } ////////////////////////////////////////////////////////////////////////////// void ScspSetVolume (int volume) { scsp_volume = volume; if (SNDCore) SNDCore->SetVolume (volume); } ////////////////////////////////////////////////////////////////////////////// void M68KSetBreakpointCallBack (void (*func)(u32)) { ScspInternalVars->BreakpointCallBack = func; } ////////////////////////////////////////////////////////////////////////////// int M68KAddCodeBreakpoint (u32 addr) { int i; if (ScspInternalVars->numcodebreakpoints < MAX_BREAKPOINTS) { // Make sure it isn't already on the list for (i = 0; i < ScspInternalVars->numcodebreakpoints; i++) { if (addr == ScspInternalVars->codebreakpoint[i].addr) return -1; } ScspInternalVars->codebreakpoint[i].addr = addr; ScspInternalVars->numcodebreakpoints++; m68kexecptr = M68KExecBP; return 0; } return -1; } ////////////////////////////////////////////////////////////////////////////// void M68KSortCodeBreakpoints (void) { int i, i2; u32 tmp; for (i = 0; i < (MAX_BREAKPOINTS - 1); i++) { for (i2 = i+1; i2 < MAX_BREAKPOINTS; i2++) { if (ScspInternalVars->codebreakpoint[i].addr == 0xFFFFFFFF && ScspInternalVars->codebreakpoint[i2].addr != 0xFFFFFFFF) { tmp = ScspInternalVars->codebreakpoint[i].addr; ScspInternalVars->codebreakpoint[i].addr = ScspInternalVars->codebreakpoint[i2].addr; ScspInternalVars->codebreakpoint[i2].addr = tmp; } } } } ////////////////////////////////////////////////////////////////////////////// int M68KDelCodeBreakpoint (u32 addr) { int i; if (ScspInternalVars->numcodebreakpoints > 0) { for (i = 0; i < ScspInternalVars->numcodebreakpoints; i++) { if (ScspInternalVars->codebreakpoint[i].addr == addr) { ScspInternalVars->codebreakpoint[i].addr = 0xFFFFFFFF; M68KSortCodeBreakpoints (); ScspInternalVars->numcodebreakpoints--; if (ScspInternalVars->numcodebreakpoints == 0) m68kexecptr = M68K->Exec; return 0; } } } return -1; } ////////////////////////////////////////////////////////////////////////////// m68kcodebreakpoint_struct * M68KGetBreakpointList () { return ScspInternalVars->codebreakpoint; } ////////////////////////////////////////////////////////////////////////////// void M68KClearCodeBreakpoints () { int i; for (i = 0; i < MAX_BREAKPOINTS; i++) ScspInternalVars->codebreakpoint[i].addr = 0xFFFFFFFF; ScspInternalVars->numcodebreakpoints = 0; } ////////////////////////////////////////////////////////////////////////////// int SoundSaveState (FILE *fp) { int i; u32 temp; int offset; u8 nextphase; IOCheck_struct check = { 0, 0 }; offset = StateWriteHeader (fp, "SCSP", 2); // Save 68k registers first ywrite (&check, (void *)&IsM68KRunning, 1, 1, fp); #ifdef IMPROVED_SAVESTATES M68K->SaveState(fp); #else for (i = 0; i < 8; i++) { temp = M68K->GetDReg (i); ywrite (&check, (void *)&temp, 4, 1, fp); } for (i = 0; i < 8; i++) { temp = M68K->GetAReg (i); ywrite (&check, (void *)&temp, 4, 1, fp); } temp = M68K->GetSR (); ywrite (&check, (void *)&temp, 4, 1, fp); temp = M68K->GetPC (); ywrite (&check, (void *)&temp, 4, 1, fp); #endif // Now for the SCSP registers ywrite (&check, (void *)scsp_reg, 0x1000, 1, fp); // Sound RAM is important ywrite (&check, (void *)SoundRam, 0x80000, 1, fp); // Write slot internal variables for (i = 0; i < 32; i++) { s32 einc; #ifdef IMPROVED_SAVESTATES ywrite(&check, (void *)&scsp.slot[i].swe, sizeof(u8), 1, fp); ywrite(&check, (void *)&scsp.slot[i].sdir, sizeof(u8), 1, fp); ywrite(&check, (void *)&scsp.slot[i].pcm8b, sizeof(u8), 1, fp); ywrite(&check, (void *)&scsp.slot[i].sbctl, sizeof(u8), 1, fp); ywrite(&check, (void *)&scsp.slot[i].ssctl, sizeof(u8), 1, fp); ywrite(&check, (void *)&scsp.slot[i].lpctl, sizeof(u8), 1, fp); #endif ywrite (&check, (void *)&scsp.slot[i].key, 1, 1, fp); #ifdef IMPROVED_SAVESTATES ywrite(&check, (void *)&scsp.slot[i].keyx, sizeof(u8), 1, fp); #endif //buf8,16 get regenerated on state load ywrite (&check, (void *)&scsp.slot[i].fcnt, 4, 1, fp); #ifdef IMPROVED_SAVESTATES ywrite(&check, (void *)&scsp.slot[i].finc, sizeof(u32), 1, fp); ywrite(&check, (void *)&scsp.slot[i].finct, sizeof(u32), 1, fp); #endif ywrite (&check, (void *)&scsp.slot[i].ecnt, 4, 1, fp); if (scsp.slot[i].einc == &scsp.slot[i].einca) einc = 0; else if (scsp.slot[i].einc == &scsp.slot[i].eincd) einc = 1; else if (scsp.slot[i].einc == &scsp.slot[i].eincs) einc = 2; else if (scsp.slot[i].einc == &scsp.slot[i].eincr) einc = 3; else einc = 4; ywrite (&check, (void *)&einc, 4, 1, fp); //einca,eincd,eincs,eincr ywrite (&check, (void *)&scsp.slot[i].ecmp, 4, 1, fp); ywrite (&check, (void *)&scsp.slot[i].ecurp, 4, 1, fp); #ifdef IMPROVED_SAVESTATES ywrite(&check, (void *)&scsp.slot[i].env, sizeof(s32), 1, fp); #endif if (scsp.slot[i].enxt == scsp_env_null_next) nextphase = 0; else if (scsp.slot[i].enxt == scsp_release_next) nextphase = 1; else if (scsp.slot[i].enxt == scsp_sustain_next) nextphase = 2; else if (scsp.slot[i].enxt == scsp_decay_next) nextphase = 3; else if (scsp.slot[i].enxt == scsp_attack_next) nextphase = 4; ywrite (&check, (void *)&nextphase, 1, 1, fp); ywrite (&check, (void *)&scsp.slot[i].lfocnt, 4, 1, fp); ywrite (&check, (void *)&scsp.slot[i].lfoinc, 4, 1, fp); #ifdef IMPROVED_SAVESTATES ywrite(&check, (void *)&scsp.slot[i].sa, sizeof(u32), 1, fp); ywrite(&check, (void *)&scsp.slot[i].lsa, sizeof(u32), 1, fp); ywrite(&check, (void *)&scsp.slot[i].lea , sizeof(u32), 1, fp); ywrite(&check, (void *)&scsp.slot[i].tl, sizeof(s32), 1, fp); ywrite(&check, (void *)&scsp.slot[i].sl, sizeof(s32), 1, fp); ywrite(&check, (void *)&scsp.slot[i].ar, sizeof(s32), 1, fp); ywrite(&check, (void *)&scsp.slot[i].dr, sizeof(s32), 1, fp); ywrite(&check, (void *)&scsp.slot[i].sr, sizeof(s32), 1, fp); ywrite(&check, (void *)&scsp.slot[i].rr, sizeof(s32), 1, fp); //arp //drp //srp //rrp ywrite(&check, (void *)&scsp.slot[i].krs, sizeof(u32), 1, fp); //lfofmw //lfoemw ywrite(&check, (void *)&scsp.slot[i].lfofms, sizeof(u8), 1, fp); ywrite(&check, (void *)&scsp.slot[i].lfoems, sizeof(u8), 1, fp); ywrite(&check, (void *)&scsp.slot[i].fsft, sizeof(u8), 1, fp); ywrite(&check, (void *)&scsp.slot[i].mdl, sizeof(u8), 1, fp); ywrite(&check, (void *)&scsp.slot[i].mdx, sizeof(u8), 1, fp); ywrite(&check, (void *)&scsp.slot[i].mdy, sizeof(u8), 1, fp); ywrite(&check, (void *)&scsp.slot[i].imxl, sizeof(u8), 1, fp); ywrite(&check, (void *)&scsp.slot[i].disll, sizeof(u8), 1, fp); ywrite(&check, (void *)&scsp.slot[i].dislr, sizeof(u8), 1, fp); ywrite(&check, (void *)&scsp.slot[i].efsll, sizeof(u8), 1, fp); ywrite(&check, (void *)&scsp.slot[i].efslr, sizeof(u8), 1, fp); ywrite(&check, (void *)&scsp.slot[i].eghold, sizeof(u8), 1, fp); ywrite(&check, (void *)&scsp.slot[i].lslnk, sizeof(u8), 1, fp); #endif } // Write main internal variables ywrite (&check, (void *)&scsp.mem4b, 4, 1, fp); ywrite (&check, (void *)&scsp.mvol, 4, 1, fp); ywrite (&check, (void *)&scsp.rbl, 4, 1, fp); ywrite (&check, (void *)&scsp.rbp, 4, 1, fp); ywrite (&check, (void *)&scsp.mslc, 4, 1, fp); ywrite (&check, (void *)&scsp.dmea, 4, 1, fp); ywrite (&check, (void *)&scsp.drga, 4, 1, fp); ywrite (&check, (void *)&scsp.dmfl, 4, 1, fp); ywrite (&check, (void *)&scsp.dmlen, 4, 1, fp); ywrite (&check, (void *)scsp.midinbuf, 1, 4, fp); ywrite (&check, (void *)scsp.midoutbuf, 1, 4, fp); ywrite (&check, (void *)&scsp.midincnt, 1, 1, fp); ywrite (&check, (void *)&scsp.midoutcnt, 1, 1, fp); ywrite (&check, (void *)&scsp.midflag, 1, 1, fp); ywrite (&check, (void *)&scsp.timacnt, 4, 1, fp); ywrite (&check, (void *)&scsp.timasd, 4, 1, fp); ywrite (&check, (void *)&scsp.timbcnt, 4, 1, fp); ywrite (&check, (void *)&scsp.timbsd, 4, 1, fp); ywrite (&check, (void *)&scsp.timccnt, 4, 1, fp); ywrite (&check, (void *)&scsp.timcsd, 4, 1, fp); ywrite (&check, (void *)&scsp.scieb, 4, 1, fp); ywrite (&check, (void *)&scsp.scipd, 4, 1, fp); ywrite (&check, (void *)&scsp.scilv0, 4, 1, fp); ywrite (&check, (void *)&scsp.scilv1, 4, 1, fp); ywrite (&check, (void *)&scsp.scilv2, 4, 1, fp); ywrite (&check, (void *)&scsp.mcieb, 4, 1, fp); ywrite (&check, (void *)&scsp.mcipd, 4, 1, fp); ywrite (&check, (void *)scsp.stack, 4, 32 * 2, fp); return StateFinishHeader (fp, offset); } ////////////////////////////////////////////////////////////////////////////// int SoundLoadState (FILE *fp, int version, int size) { int i, i2; u32 temp; u8 nextphase; IOCheck_struct check = { 0, 0 }; // Read 68k registers first yread (&check, (void *)&IsM68KRunning, 1, 1, fp); #ifdef IMPROVED_SAVESTATES M68K->LoadState(fp); #else for (i = 0; i < 8; i++) { yread (&check, (void *)&temp, 4, 1, fp); M68K->SetDReg (i, temp); } for (i = 0; i < 8; i++) { yread (&check, (void *)&temp, 4, 1, fp); M68K->SetAReg (i, temp); } yread (&check, (void *)&temp, 4, 1, fp); M68K->SetSR (temp); yread (&check, (void *)&temp, 4, 1, fp); M68K->SetPC (temp); #endif // Now for the SCSP registers yread (&check, (void *)scsp_reg, 0x1000, 1, fp); // Lastly, sound ram yread (&check, (void *)SoundRam, 0x80000, 1, fp); if (version > 1) { // Internal variables need to be regenerated for(i = 0; i < 32; i++) { for (i2 = 0; i2 < 0x20; i2+=2) scsp_slot_set_w (i, 0x1E - i2, scsp_slot_get_w (i, 0x1E - i2)); } scsp_set_w (0x402, scsp_get_w (0x402)); // Read slot internal variables for (i = 0; i < 32; i++) { s32 einc; #ifdef IMPROVED_SAVESTATES yread(&check, (void *)&scsp.slot[i].swe, sizeof(u8), 1, fp); yread(&check, (void *)&scsp.slot[i].sdir, sizeof(u8), 1, fp); yread(&check, (void *)&scsp.slot[i].pcm8b, sizeof(u8), 1, fp); yread(&check, (void *)&scsp.slot[i].sbctl, sizeof(u8), 1, fp); yread(&check, (void *)&scsp.slot[i].ssctl, sizeof(u8), 1, fp); yread(&check, (void *)&scsp.slot[i].lpctl, sizeof(u8), 1, fp); #endif yread (&check, (void *)&scsp.slot[i].key, 1, 1, fp); #ifdef IMPROVED_SAVESTATES yread(&check, (void *)&scsp.slot[i].keyx, sizeof(u8), 1, fp); #endif //buf8,16 regenerated at end yread (&check, (void *)&scsp.slot[i].fcnt, 4, 1, fp); #ifdef IMPROVED_SAVESTATES yread(&check, (void *)&scsp.slot[i].finc, sizeof(u32), 1, fp); yread(&check, (void *)&scsp.slot[i].finct, sizeof(u32), 1, fp); #endif yread (&check, (void *)&scsp.slot[i].ecnt, 4, 1, fp); yread (&check, (void *)&einc, 4, 1, fp); switch (einc) { case 0: scsp.slot[i].einc = &scsp.slot[i].einca; break; case 1: scsp.slot[i].einc = &scsp.slot[i].eincd; break; case 2: scsp.slot[i].einc = &scsp.slot[i].eincs; break; case 3: scsp.slot[i].einc = &scsp.slot[i].eincr; break; default: scsp.slot[i].einc = NULL; break; } //einca,eincd,eincs,eincr yread (&check, (void *)&scsp.slot[i].ecmp, 4, 1, fp); yread (&check, (void *)&scsp.slot[i].ecurp, 4, 1, fp); #ifdef IMPROVED_SAVESTATES yread(&check, (void *)&scsp.slot[i].env, sizeof(s32), 1, fp); #endif yread (&check, (void *)&nextphase, 1, 1, fp); switch (nextphase) { case 0: scsp.slot[i].enxt = scsp_env_null_next; break; case 1: scsp.slot[i].enxt = scsp_release_next; break; case 2: scsp.slot[i].enxt = scsp_sustain_next; break; case 3: scsp.slot[i].enxt = scsp_decay_next; break; case 4: scsp.slot[i].enxt = scsp_attack_next; break; default: break; } yread (&check, (void *)&scsp.slot[i].lfocnt, 4, 1, fp); yread (&check, (void *)&scsp.slot[i].lfoinc, 4, 1, fp); #ifdef IMPROVED_SAVESTATES yread(&check, (void *)&scsp.slot[i].sa, sizeof(u32), 1, fp); yread(&check, (void *)&scsp.slot[i].lsa, sizeof(u32), 1, fp); yread(&check, (void *)&scsp.slot[i].lea, sizeof(u32), 1, fp); yread(&check, (void *)&scsp.slot[i].tl, sizeof(s32), 1, fp); yread(&check, (void *)&scsp.slot[i].sl, sizeof(s32), 1, fp); yread(&check, (void *)&scsp.slot[i].ar, sizeof(s32), 1, fp); yread(&check, (void *)&scsp.slot[i].dr, sizeof(s32), 1, fp); yread(&check, (void *)&scsp.slot[i].sr, sizeof(s32), 1, fp); yread(&check, (void *)&scsp.slot[i].rr, sizeof(s32), 1, fp); //arp //drp //srp //rrp yread(&check, (void *)&scsp.slot[i].krs, sizeof(u32), 1, fp); //lfofmw //lfoemw yread(&check, (void *)&scsp.slot[i].lfofms, sizeof(u8), 1, fp); yread(&check, (void *)&scsp.slot[i].lfoems, sizeof(u8), 1, fp); yread(&check, (void *)&scsp.slot[i].fsft, sizeof(u8), 1, fp); yread(&check, (void *)&scsp.slot[i].mdl, sizeof(u8), 1, fp); yread(&check, (void *)&scsp.slot[i].mdx, sizeof(u8), 1, fp); yread(&check, (void *)&scsp.slot[i].mdy, sizeof(u8), 1, fp); yread(&check, (void *)&scsp.slot[i].imxl, sizeof(u8), 1, fp); yread(&check, (void *)&scsp.slot[i].disll, sizeof(u8), 1, fp); yread(&check, (void *)&scsp.slot[i].dislr, sizeof(u8), 1, fp); yread(&check, (void *)&scsp.slot[i].efsll, sizeof(u8), 1, fp); yread(&check, (void *)&scsp.slot[i].efslr, sizeof(u8), 1, fp); yread(&check, (void *)&scsp.slot[i].eghold, sizeof(u8), 1, fp); yread(&check, (void *)&scsp.slot[i].lslnk, sizeof(u8), 1, fp); #endif // depends on pcm8b, sa, lea being loaded first // Rebuild the buf8/buf16 variables if (scsp.slot[i].pcm8b) { scsp.slot[i].buf8 = (s8*)&(scsp.scsp_ram[scsp.slot[i].sa]); if ((scsp.slot[i].sa + (scsp.slot[i].lea >> SCSP_FREQ_LB)) > SCSP_RAM_MASK) scsp.slot[i].lea = (SCSP_RAM_MASK - scsp.slot[i].sa) << SCSP_FREQ_LB; } else { scsp.slot[i].buf16 = (s16*)&(scsp.scsp_ram[scsp.slot[i].sa & ~1]); if ((scsp.slot[i].sa + (scsp.slot[i].lea >> (SCSP_FREQ_LB - 1))) > SCSP_RAM_MASK) scsp.slot[i].lea = (SCSP_RAM_MASK - scsp.slot[i].sa) << (SCSP_FREQ_LB - 1); } } // Read main internal variables yread (&check, (void *)&scsp.mem4b, 4, 1, fp); yread (&check, (void *)&scsp.mvol, 4, 1, fp); yread (&check, (void *)&scsp.rbl, 4, 1, fp); yread (&check, (void *)&scsp.rbp, 4, 1, fp); yread (&check, (void *)&scsp.mslc, 4, 1, fp); yread (&check, (void *)&scsp.dmea, 4, 1, fp); yread (&check, (void *)&scsp.drga, 4, 1, fp); yread (&check, (void *)&scsp.dmfl, 4, 1, fp); yread (&check, (void *)&scsp.dmlen, 4, 1, fp); yread (&check, (void *)scsp.midinbuf, 1, 4, fp); yread (&check, (void *)scsp.midoutbuf, 1, 4, fp); yread (&check, (void *)&scsp.midincnt, 1, 1, fp); yread (&check, (void *)&scsp.midoutcnt, 1, 1, fp); yread (&check, (void *)&scsp.midflag, 1, 1, fp); yread (&check, (void *)&scsp.timacnt, 4, 1, fp); yread (&check, (void *)&scsp.timasd, 4, 1, fp); yread (&check, (void *)&scsp.timbcnt, 4, 1, fp); yread (&check, (void *)&scsp.timbsd, 4, 1, fp); yread (&check, (void *)&scsp.timccnt, 4, 1, fp); yread (&check, (void *)&scsp.timcsd, 4, 1, fp); yread (&check, (void *)&scsp.scieb, 4, 1, fp); yread (&check, (void *)&scsp.scipd, 4, 1, fp); yread (&check, (void *)&scsp.scilv0, 4, 1, fp); yread (&check, (void *)&scsp.scilv1, 4, 1, fp); yread (&check, (void *)&scsp.scilv2, 4, 1, fp); yread (&check, (void *)&scsp.mcieb, 4, 1, fp); yread (&check, (void *)&scsp.mcipd, 4, 1, fp); yread (&check, (void *)scsp.stack, 4, 32 * 2, fp); } return size; } ////////////////////////////////////////////////////////////////////////////// static char * AddSoundLFO (char *outstring, const char *string, u16 level, u16 waveform) { if (level > 0) { switch (waveform) { case 0: AddString(outstring, "%s Sawtooth\r\n", string); break; case 1: AddString(outstring, "%s Square\r\n", string); break; case 2: AddString(outstring, "%s Triangle\r\n", string); break; case 3: AddString(outstring, "%s Noise\r\n", string); break; } } return outstring; } ////////////////////////////////////////////////////////////////////////////// static char * AddSoundPan (char *outstring, u16 pan) { if (pan == 0x0F) { AddString(outstring, "Left = -MAX dB, Right = -0 dB\r\n"); } else if (pan == 0x1F) { AddString(outstring, "Left = -0 dB, Right = -MAX dB\r\n"); } else { AddString(outstring, "Left = -%d dB, Right = -%d dB\r\n", (pan & 0xF) * 3, (pan >> 4) * 3); } return outstring; } ////////////////////////////////////////////////////////////////////////////// static char * AddSoundLevel (char *outstring, u16 level) { if (level == 0) { AddString(outstring, "-MAX dB\r\n"); } else { AddString(outstring, "-%d dB\r\n", (7-level) * 6); } return outstring; } ////////////////////////////////////////////////////////////////////////////// void ScspSlotDebugStats (u8 slotnum, char *outstring) { u32 slotoffset = slotnum * 0x20; AddString (outstring, "Sound Source = "); switch (scsp.slot[slotnum].ssctl) { case 0: AddString (outstring, "External DRAM data\r\n"); break; case 1: AddString (outstring, "Internal(Noise)\r\n"); break; case 2: AddString (outstring, "Internal(0's)\r\n"); break; default: AddString (outstring, "Invalid setting\r\n"); break; } AddString (outstring, "Source bit = "); switch(scsp.slot[slotnum].sbctl) { case 0: AddString (outstring, "No bit reversal\r\n"); break; case 1: AddString (outstring, "Reverse other bits\r\n"); break; case 2: AddString (outstring, "Reverse sign bit\r\n"); break; case 3: AddString (outstring, "Reverse sign and other bits\r\n"); break; } // Loop Control AddString (outstring, "Loop Mode = "); switch (scsp.slot[slotnum].lpctl) { case 0: AddString (outstring, "Off\r\n"); break; case 1: AddString (outstring, "Normal\r\n"); break; case 2: AddString (outstring, "Reverse\r\n"); break; case 3: AddString (outstring, "Alternating\r\n"); break; } // PCM8B // NOTE: Need curly braces here, as AddString is a macro. if (scsp.slot[slotnum].pcm8b) { AddString (outstring, "8-bit samples\r\n"); } else { AddString (outstring, "16-bit samples\r\n"); } AddString (outstring, "Start Address = %05lX\r\n", (unsigned long)scsp.slot[slotnum].sa); AddString (outstring, "Loop Start Address = %04lX\r\n", (unsigned long)scsp.slot[slotnum].lsa >> SCSP_FREQ_LB); AddString (outstring, "Loop End Address = %04lX\r\n", (unsigned long)scsp.slot[slotnum].lea >> SCSP_FREQ_LB); AddString (outstring, "Decay 1 Rate = %ld\r\n", (unsigned long)scsp.slot[slotnum].dr); AddString (outstring, "Decay 2 Rate = %ld\r\n", (unsigned long)scsp.slot[slotnum].sr); if (scsp.slot[slotnum].eghold) AddString (outstring, "EG Hold Enabled\r\n"); AddString (outstring, "Attack Rate = %ld\r\n", (unsigned long)scsp.slot[slotnum].ar); if (scsp.slot[slotnum].lslnk) AddString (outstring, "Loop Start Link Enabled\r\n"); if (scsp.slot[slotnum].krs != 0) AddString (outstring, "Key rate scaling = %ld\r\n", (unsigned long)scsp.slot[slotnum].krs); AddString (outstring, "Decay Level = %d\r\n", (scsp_r_w(slotoffset + 0xA) >> 5) & 0x1F); AddString (outstring, "Release Rate = %ld\r\n", (unsigned long)scsp.slot[slotnum].rr); if (scsp.slot[slotnum].swe) AddString (outstring, "Stack Write Inhibited\r\n"); if (scsp.slot[slotnum].sdir) AddString (outstring, "Sound Direct Enabled\r\n"); AddString (outstring, "Total Level = %ld\r\n", (unsigned long)scsp.slot[slotnum].tl); AddString (outstring, "Modulation Level = %d\r\n", scsp.slot[slotnum].mdl); AddString (outstring, "Modulation Input X = %d\r\n", scsp.slot[slotnum].mdx); AddString (outstring, "Modulation Input Y = %d\r\n", scsp.slot[slotnum].mdy); AddString (outstring, "Octave = %d\r\n", (scsp_r_w(slotoffset + 0x10) >> 11) & 0xF); AddString (outstring, "Frequency Number Switch = %d\r\n", scsp_r_w(slotoffset + 0x10) & 0x3FF); AddString (outstring, "LFO Reset = %s\r\n", ((scsp_r_w(slotoffset + 0x12) >> 15) & 0x1) ? "TRUE" : "FALSE"); AddString (outstring, "LFO Frequency = %d\r\n", (scsp_r_w(slotoffset + 0x12) >> 10) & 0x1F); outstring = AddSoundLFO (outstring, "LFO Frequency modulation waveform = ", (scsp_r_w(slotoffset + 0x12) >> 5) & 0x7, (scsp_r_w(slotoffset + 0x12) >> 8) & 0x3); AddString (outstring, "LFO Frequency modulation level = %d\r\n", (scsp_r_w(slotoffset + 0x12) >> 5) & 0x7); outstring = AddSoundLFO (outstring, "LFO Amplitude modulation waveform = ", scsp_r_w(slotoffset + 0x12) & 0x7, (scsp_r_w(slotoffset + 0x12) >> 3) & 0x3); AddString (outstring, "LFO Amplitude modulation level = %d\r\n", scsp_r_w(slotoffset + 0x12) & 0x7); AddString (outstring, "Input mix level = "); outstring = AddSoundLevel (outstring, scsp_r_w(slotoffset + 0x14) & 0x7); AddString (outstring, "Input Select = %d\r\n", (scsp_r_w(slotoffset + 0x14) >> 3) & 0x1F); AddString (outstring, "Direct data send level = "); outstring = AddSoundLevel (outstring, (scsp_r_w(slotoffset + 0x16) >> 13) & 0x7); AddString (outstring, "Direct data panpot = "); outstring = AddSoundPan (outstring, (scsp_r_w(slotoffset + 0x16) >> 8) & 0x1F); AddString (outstring, "Effect data send level = "); outstring = AddSoundLevel (outstring, (scsp_r_w(slotoffset + 0x16) >> 5) & 0x7); AddString (outstring, "Effect data panpot = "); outstring = AddSoundPan (outstring, scsp_r_w(slotoffset + 0x16) & 0x1F); } ////////////////////////////////////////////////////////////////////////////// void ScspCommonControlRegisterDebugStats (char *outstring) { AddString (outstring, "Memory: %s\r\n", scsp.mem4b ? "4 Mbit" : "2 Mbit"); AddString (outstring, "Master volume: %ld\r\n", (unsigned long)scsp.mvol); AddString (outstring, "Ring buffer length: %ld\r\n", (unsigned long)scsp.rbl); AddString (outstring, "Ring buffer address: %08lX\r\n", (unsigned long)scsp.rbp); AddString (outstring, "\r\n"); AddString (outstring, "Slot Status Registers\r\n"); AddString (outstring, "-----------------\r\n"); AddString (outstring, "Monitor slot: %ld\r\n", (unsigned long)scsp.mslc); AddString (outstring, "Call address: %ld\r\n", (unsigned long)scsp.ca); AddString (outstring, "\r\n"); AddString (outstring, "DMA Registers\r\n"); AddString (outstring, "-----------------\r\n"); AddString (outstring, "DMA memory address start: %08lX\r\n", (unsigned long)scsp.dmea); AddString (outstring, "DMA register address start: %08lX\r\n", (unsigned long)scsp.drga); AddString (outstring, "DMA Flags: %lX\r\n", (unsigned long)scsp.dmlen); AddString (outstring, "\r\n"); AddString (outstring, "Timer Registers\r\n"); AddString (outstring, "-----------------\r\n"); AddString (outstring, "Timer A counter: %02lX\r\n", (unsigned long)scsp.timacnt >> 8); AddString (outstring, "Timer A increment: Every %d sample(s)\r\n", (int)pow(2, (double)scsp.timasd)); AddString (outstring, "Timer B counter: %02lX\r\n", (unsigned long)scsp.timbcnt >> 8); AddString (outstring, "Timer B increment: Every %d sample(s)\r\n", (int)pow(2, (double)scsp.timbsd)); AddString (outstring, "Timer C counter: %02lX\r\n", (unsigned long)scsp.timccnt >> 8); AddString (outstring, "Timer C increment: Every %d sample(s)\r\n", (int)pow(2, (double)scsp.timcsd)); AddString (outstring, "\r\n"); AddString (outstring, "Interrupt Registers\r\n"); AddString (outstring, "-----------------\r\n"); AddString (outstring, "Sound cpu interrupt pending: %04lX\r\n", (unsigned long)scsp.scipd); AddString (outstring, "Sound cpu interrupt enable: %04lX\r\n", (unsigned long)scsp.scieb); AddString (outstring, "Sound cpu interrupt level 0: %04lX\r\n", (unsigned long)scsp.scilv0); AddString (outstring, "Sound cpu interrupt level 1: %04lX\r\n", (unsigned long)scsp.scilv1); AddString (outstring, "Sound cpu interrupt level 2: %04lX\r\n", (unsigned long)scsp.scilv2); AddString (outstring, "Main cpu interrupt pending: %04lX\r\n", (unsigned long)scsp.mcipd); AddString (outstring, "Main cpu interrupt enable: %04lX\r\n", (unsigned long)scsp.mcieb); AddString (outstring, "\r\n"); } ////////////////////////////////////////////////////////////////////////////// int ScspSlotDebugSaveRegisters (u8 slotnum, const char *filename) { FILE *fp; int i; IOCheck_struct check = { 0, 0 }; if ((fp = fopen (filename, "wb")) == NULL) return -1; for (i = (slotnum * 0x20); i < ((slotnum+1) * 0x20); i += 2) { #ifdef WORDS_BIGENDIAN ywrite (&check, (void *)&scsp_isr[i ^ 2], 1, 2, fp); #else ywrite (&check, (void *)&scsp_isr[(i + 1) ^ 2], 1, 1, fp); ywrite (&check, (void *)&scsp_isr[i ^ 2], 1, 1, fp); #endif } fclose (fp); return 0; } ////////////////////////////////////////////////////////////////////////////// static slot_t debugslot; u32 ScspSlotDebugAudio (u32 *workbuf, s16 *buf, u32 len) { u32 *bufL, *bufR; bufL = workbuf; bufR = workbuf+len; scsp_bufL = (s32 *)bufL; scsp_bufR = (s32 *)bufR; if (debugslot.ecnt >= SCSP_ENV_DE) { // envelope null... memset (buf, 0, sizeof(s16) * 2 * len); return 0; } if (debugslot.ssctl) { memset (buf, 0, sizeof(s16) * 2 * len); return 0; // not yet supported! } scsp_buf_len = len; scsp_buf_pos = 0; // take effect sound volume if no direct sound volume... if ((debugslot.disll == 31) && (debugslot.dislr == 31)) { debugslot.disll = debugslot.efsll; debugslot.dislr = debugslot.efslr; } memset (bufL, 0, sizeof(u32) * len); memset (bufR, 0, sizeof(u32) * len); scsp_slot_update_p[(debugslot.lfofms == 31)?0:1] [(debugslot.lfoems == 31)?0:1] [(debugslot.pcm8b == 0)?1:0] [(debugslot.disll == 31)?0:1] [(debugslot.dislr == 31)?0:1](&debugslot); ScspConvert32uto16s ((s32 *)bufL, (s32 *)bufR, (s16 *)buf, len); return len; } ////////////////////////////////////////////////////////////////////////////// typedef struct { char id[4]; u32 size; } chunk_struct; typedef struct { chunk_struct riff; char rifftype[4]; } waveheader_struct; typedef struct { chunk_struct chunk; u16 compress; u16 numchan; u32 rate; u32 bytespersec; u16 blockalign; u16 bitspersample; } fmt_struct; ////////////////////////////////////////////////////////////////////////////// void ScspSlotResetDebug(u8 slotnum) { memcpy (&debugslot, &scsp.slot[slotnum], sizeof(slot_t)); // Clear out the phase counter, etc. debugslot.fcnt = 0; debugslot.ecnt = SCSP_ENV_AS; debugslot.einc = &debugslot.einca; debugslot.ecmp = SCSP_ENV_AE; debugslot.ecurp = SCSP_ENV_ATTACK; debugslot.enxt = scsp_attack_next; } ////////////////////////////////////////////////////////////////////////////// int ScspSlotDebugAudioSaveWav (u8 slotnum, const char *filename) { u32 workbuf[512*2*2]; s16 buf[512*2]; FILE *fp; u32 counter = 0; waveheader_struct waveheader; fmt_struct fmt; chunk_struct data; long length; IOCheck_struct check = { 0, 0 }; if (scsp.slot[slotnum].lea == 0) return 0; if ((fp = fopen (filename, "wb")) == NULL) return -1; // Do wave header memcpy (waveheader.riff.id, "RIFF", 4); waveheader.riff.size = 0; // we'll fix this after the file is closed memcpy (waveheader.rifftype, "WAVE", 4); ywrite (&check, (void *)&waveheader, 1, sizeof(waveheader_struct), fp); // fmt chunk memcpy (fmt.chunk.id, "fmt ", 4); fmt.chunk.size = 16; // we'll fix this at the end fmt.compress = 1; // PCM fmt.numchan = 2; // Stereo fmt.rate = 44100; fmt.bitspersample = 16; fmt.blockalign = fmt.bitspersample / 8 * fmt.numchan; fmt.bytespersec = fmt.rate * fmt.blockalign; ywrite (&check, (void *)&fmt, 1, sizeof(fmt_struct), fp); // data chunk memcpy (data.id, "data", 4); data.size = 0; // we'll fix this at the end ywrite (&check, (void *)&data, 1, sizeof(chunk_struct), fp); ScspSlotResetDebug(slotnum); // Mix the audio, and then write it to the file for (;;) { if (ScspSlotDebugAudio (workbuf, buf, 512) == 0) break; counter += 512; ywrite (&check, (void *)buf, 2, 512 * 2, fp); if (debugslot.lpctl != 0 && counter >= (44100 * 2 * 5)) break; } length = ftell (fp); // Let's fix the riff chunk size and the data chunk size fseek (fp, sizeof(waveheader_struct)-0x8, SEEK_SET); length -= 0x4; ywrite (&check, (void *)&length, 1, 4, fp); fseek (fp, sizeof(waveheader_struct) + sizeof(fmt_struct) + 0x4, SEEK_SET); length -= sizeof(waveheader_struct) + sizeof(fmt_struct); ywrite (&check, (void *)&length, 1, 4, fp); fclose (fp); return 0; } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/sndal.c000644 001750 001750 00000017363 12755623101 017321 0ustar00guillaumeguillaume000000 000000 /* Copyright 2009 Lawrence Sebald Copyright 2005-2006 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_LIBAL #ifdef __APPLE__ #include #include #else #include #include #endif #include "threads.h" #include #include #include "error.h" #include "scsp.h" #include "sndal.h" #include "debug.h" int SNDALInit(void); void SNDALDeInit(void); int SNDALReset(void); int SNDALChangeVideoFormat(int vertfreq); void SNDALUpdateAudio(u32 *left, u32 *right, u32 samples); u32 SNDALGetAudioSpace(void); void SNDALMuteAudio(void); void SNDALUnMuteAudio(void); void SNDALSetVolume(int vol); SoundInterface_struct SNDAL = { SNDCORE_AL, "OpenAL Sound Interface", SNDALInit, SNDALDeInit, SNDALReset, SNDALChangeVideoFormat, SNDALUpdateAudio, SNDALGetAudioSpace, SNDALMuteAudio, SNDALUnMuteAudio, SNDALSetVolume }; #define SOUND_BUFFERS 4 #define SOUND_FREQ 44100 static ALCdevice *device = NULL; static ALCcontext *context = NULL; static ALuint source; static ALuint bufs[SOUND_BUFFERS]; static u16 *buffer; static u32 soundbufsize = 0; static u32 soundoffset; static volatile u32 soundpos; static int thd_done = 0; static int soundvolume = 1; static int soundlen; static void sound_update_thd(void *ptr) { ALint proc; ALuint buf; u8 data[2048]; u8 *soundbuf = (u8 *)buffer; int i; while(!thd_done) { /* See if the stream needs updating yet. */ alGetSourcei(source, AL_BUFFERS_PROCESSED, &proc); if(alGetError() != AL_NO_ERROR) { continue; } /* Go through each buffer that needs more data. */ while(proc--) { /* Unqueue the old buffer, so that it can be filled again. */ alSourceUnqueueBuffers(source, 1, &buf); if(alGetError() != AL_NO_ERROR) { continue; } for(i = 0; i < 2048; ++i) { if(soundpos >= soundbufsize) soundpos = 0; data[i] = soundbuf[soundpos]; ++soundpos; } alBufferData(buf, AL_FORMAT_STEREO16, data, 2048, SOUND_FREQ); alSourceQueueBuffers(source, 1, &buf); } YabThreadYield(); } //return NULL; } static void sdlConvert32uto16s(s32 *srcL, s32 *srcR, s16 *dst, u32 len) { u32 i; for (i = 0; i < len; i++) { // Left Channel *srcL = ( *srcL *soundvolume ) / 100; if (*srcL > 0x7FFF) *dst = 0x7FFF; else if (*srcL < -0x8000) *dst = -0x8000; else *dst = *srcL; srcL++; dst++; // Right Channel *srcR = ( *srcR *soundvolume ) / 100; if (*srcR > 0x7FFF) *dst = 0x7FFF; else if (*srcR < -0x8000) *dst = -0x8000; else *dst = *srcR; srcR++; dst++; } } void SNDALUpdateAudio(u32 *left, u32 *right, u32 num_samples) { u32 copy1size = 0, copy2size = 0; if((soundbufsize - soundoffset) < (num_samples * sizeof(s16) * 2)) { copy1size = (soundbufsize - soundoffset); copy2size = (num_samples * sizeof(s16) * 2) - copy1size; } else { copy1size = (num_samples * sizeof(s16) * 2); copy2size = 0; } sdlConvert32uto16s((s32 *)left, (s32 *)right, (s16 *)(((u8 *)buffer)+soundoffset), copy1size / sizeof(s16) / 2); if(copy2size) sdlConvert32uto16s((s32 *)left + (copy1size / sizeof(s16) / 2), (s32 *)right + (copy1size / sizeof(s16) / 2), (s16 *)buffer, copy2size / sizeof(s16) / 2); soundoffset += copy1size + copy2size; soundoffset %= soundbufsize; } int SNDALInit() { int rv = 0, i; /* Attempt to grab the preferred device from OpenAL. */ device = alcOpenDevice(NULL); if(!device) { rv = -1; goto err1; } context = alcCreateContext(device, NULL); if(!context) { rv = -2; goto err2; } alcMakeContextCurrent(context); /* Clear any error states. */ alGetError(); /* Create our sound buffers. */ alGenBuffers(SOUND_BUFFERS, bufs); if(alGetError() != AL_NO_ERROR) { rv = -3; goto err3; } /* Create the source for the stream. */ alGenSources(1, &source); if(alGetError() != AL_NO_ERROR) { rv = -4; goto err4; } /* Set up the source for basic playback. */ alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); alSource3f(source, AL_POSITION, 0.0f, 0.0f, 0.0f); alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); soundlen = SOUND_FREQ / 60; soundbufsize = soundlen * SOUND_BUFFERS * 2 * 2; soundvolume = 100; if((buffer = (u16 *)malloc(soundbufsize)) == NULL) { rv = -5; goto err5; } memset(buffer, 0, soundbufsize); for(i = 0; i < SOUND_BUFFERS; ++i) { /* Fill the buffer with empty sound. */ alBufferData(bufs[i], AL_FORMAT_STEREO16, buffer + i * 2048, 2048, SOUND_FREQ); alSourceQueueBuffers(source, 1, bufs + i); } /* Start the sound playback. */ alSourcePlay(source); /* Start the update thread. */ YabThreadStart(YAB_THREAD_OPENAL,sound_update_thd,(void *)buffer); return 0; /* Error conditions. Errors cause cascading deinitialization, so hence this chain of labels. */ err5: alDeleteSources(1, &source); err4: alDeleteBuffers(SOUND_BUFFERS, bufs); err3: alcMakeContextCurrent(NULL); alcDestroyContext(context); err2: alcCloseDevice(device); err1: context = NULL; device = NULL; return rv; } void SNDALDeInit() { /* Stop our update thread. */ thd_done = 1; //pthread_join(thd, NULL); YabThreadWait(YAB_THREAD_OPENAL); /* Stop playback. */ alSourceStop(source); /* Clean up our buffers and such. */ alDeleteSources(1, &source); alDeleteBuffers(SOUND_BUFFERS, bufs); /* Release our context and close the sound device. */ alcMakeContextCurrent(NULL); alcDestroyContext(context); alcCloseDevice(device); context = NULL; device = NULL; thd_done = 0; } int SNDALReset() { return 0; } int SNDALChangeVideoFormat(int vertfreq) { soundlen = SOUND_FREQ / vertfreq; soundbufsize = soundlen * SOUND_BUFFERS * 2 * 2; if(buffer) free(buffer); if((buffer = (u16 *)malloc(soundbufsize)) == NULL) return -1; memset(buffer, 0, soundbufsize); return 0; } u32 SNDALGetAudioSpace() { u32 freespace=0; if(soundoffset > soundpos) freespace = soundbufsize - soundoffset + soundpos; else freespace = soundpos - soundoffset; return (freespace / sizeof(s16) / 2); } void SNDALMuteAudio() { alSourcePause(source); } void SNDALUnMuteAudio() { alSourcePlay(source); } void SNDALSetVolume(int vol) { soundvolume = (int)((128.0 / 100.0) * vol); } #endif /* HAVE_LIBAL */ yabause-0.9.15/src/cd_drive.h000644 001750 001750 00000003477 12755623101 020005 0ustar00guillaumeguillaume000000 000000 /* Copyright 2014-2016 James Laird-Wah Copyright 2004-2006, 2013 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef CD_DRIVE_H #define CD_DRIVE_H #include "core.h" #include "cdbase.h" struct CdState { u8 current_operation;//0 u8 q_subcode;//1 u8 track_number;//2 u8 index_field;//3 u8 minutes;//4 u8 seconds;//5 u8 frame;//6 //7 zero u8 absolute_minutes;//8 u8 absolute_seconds;//9 u8 absolute_frame;//10 //11 parity //12 zero }; struct CdDriveContext { s32 cycles_remainder; int num_execs; int output_enabled; int bit_counter; int byte_counter; struct CdState state; u8 state_data[13]; u8 received_data[13]; int received_data_counter; u8 post_seek_state; CDInterfaceToc10 toc[103*3], tracks[100]; int toc_entry; int num_toc_entries, num_tracks; u32 disc_fad; u32 target_fad; int seek_time; int speed; }; extern struct CdDriveContext cdd_cxt; void cd_drive_exec(struct CdDriveContext * drive, s32 cycles); u8 cd_drive_get_serial_bit(); void cd_drive_set_serial_bit(u8 bit); void cd_drive_start_transfer(); void cdd_reset(); #endif yabause-0.9.15/src/sock-dummy.c000644 001750 001750 00000003157 12755623101 020304 0ustar00guillaumeguillaume000000 000000 /* Copyright 2013 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "core.h" #include "sock.h" ////////////////////////////////////////////////////////////////////////////// int YabSockInit() { return -1; } int YabSockDeInit() { return -1; } int YabSockConnectSocket(const char *ip, int port, YabSock *sock) { return -1; } int YabSockListenSocket(int port, YabSock *sock) { return -1; } int YabSockCloseSocket(YabSock sock) { return -1; } int YabSockSelect(YabSock sock, int check_read, int check_write ) { return -1; } int YabSockIsReadSet(YabSock sock) { return -1; } int YabSockIsWriteSet(YabSock sock) { return -1; } YabSock YabSockAccept(YabSock sock) { return 0; } int YabSockSend(YabSock sock, const void *buf, int len, int flags) { return -1; } int YabSockReceive(YabSock sock, void *buf, int len, int flags) { return -1; } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/coffelf.c000644 001750 001750 00000024767 12755623101 017632 0ustar00guillaumeguillaume000000 000000 /* Copyright 2007 Theo Berkau Copyright 2009 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file coffelf.c \brief Coff/Elf loader function. */ #include "core.h" #include "debug.h" #include "sh2core.h" #include "yabause.h" #include "coffelf.h" typedef struct { u8 magic[2]; u16 numsections; u32 timedate; u32 symtabptr; u32 numsymtabs; u16 optheader; u16 flags; } coff_header_struct; typedef struct { u8 magic[2]; u16 versionstamp; u32 textsize; u32 datasize; u32 bsssize; u32 entrypoint; u32 textaddr; u32 dataaddr; } aout_header_struct; typedef struct { s8 name[8]; u32 physaddr; u32 virtaddr; u32 sectionsize; u32 sectionptr; u32 relptr; u32 linenoptr; u16 numreloc; u16 numlineno; u32 flags; } section_header_struct; typedef struct { u8 ident[16]; u16 type; u16 machine; u32 version; u32 entry; u32 phdr; u32 shdr; u32 flags; u16 hdrsize; u16 phdrsize; u16 phdrcount; u16 shdrsize; u16 shdrcount; u16 shdrstridx; } elf_header_struct; #define ELF_MACHINE_SH 42 typedef struct { u32 name; u32 type; u32 flags; u32 addr; u32 offs; u32 size; u32 link; u32 inf; u32 align; u32 esize; } elf_section_header_struct; #define ELF_SECTION_TYPE_NODATA 8 #define ELF_SECTION_FLAG_ALLOC 2 #define WordSwap(x) x = ((x & 0xFF00) >> 8) + ((x & 0x00FF) << 8); #define DoubleWordSwap(x) x = (((x & 0xFF000000) >> 24) + \ ((x & 0x00FF0000) >> 8) + \ ((x & 0x0000FF00) << 8) + \ ((x & 0x000000FF) << 24)); ////////////////////////////////////////////////////////////////////////////// int MappedMemoryLoadCoff(const char *filename) { coff_header_struct coff_header; aout_header_struct aout_header; section_header_struct *section_headers=NULL; FILE *fp; u8 *buffer; u32 i, j; size_t num_read = 0; if ((fp = fopen(filename, "rb")) == NULL) return -1; num_read = fread((void *)&coff_header, sizeof(coff_header), 1, fp); #ifndef WORDS_BIGENDIAN WordSwap(coff_header.numsections); DoubleWordSwap(coff_header.timedate); DoubleWordSwap(coff_header.timedate); DoubleWordSwap(coff_header.symtabptr); DoubleWordSwap(coff_header.numsymtabs); WordSwap(coff_header.optheader); WordSwap(coff_header.flags); #endif if (coff_header.magic[0] != 0x05 || coff_header.magic[1] != 0x00 || coff_header.optheader != sizeof(aout_header)) { // Not SH COFF or is missing the optional header fclose(fp); return -1; } num_read = fread((void *)&aout_header, sizeof(aout_header), 1, fp); #ifndef WORDS_BIGENDIAN WordSwap(aout_header.versionstamp); DoubleWordSwap(aout_header.textsize); DoubleWordSwap(aout_header.datasize); DoubleWordSwap(aout_header.bsssize); DoubleWordSwap(aout_header.entrypoint); DoubleWordSwap(aout_header.textaddr); DoubleWordSwap(aout_header.dataaddr); #endif // Read in each section header if ((section_headers = (section_header_struct *)malloc(sizeof(section_header_struct) * coff_header.numsections)) == NULL) { fclose(fp); return -2; } // read in section headers for (i = 0; i < coff_header.numsections; i++) { num_read = fread((void *)§ion_headers[i], sizeof(section_header_struct), 1, fp); #ifndef WORDS_BIGENDIAN DoubleWordSwap(section_headers[i].physaddr); DoubleWordSwap(section_headers[i].virtaddr); DoubleWordSwap(section_headers[i].sectionsize); DoubleWordSwap(section_headers[i].sectionptr); DoubleWordSwap(section_headers[i].relptr); DoubleWordSwap(section_headers[i].linenoptr); WordSwap(section_headers[i].numreloc); WordSwap(section_headers[i].numlineno); DoubleWordSwap(section_headers[i].flags); #endif } YabauseResetNoLoad(); // Setup the vector table area, etc. YabauseSpeedySetup(); // Read in sections, load them to ram for (i = 0; i < coff_header.numsections; i++) { if (section_headers[i].sectionsize == 0 || section_headers[i].sectionptr == 0) // Skip to the next section continue; if ((buffer = (u8 *)malloc(section_headers[i].sectionsize)) == NULL) { fclose(fp); free(section_headers); return -2; } fseek(fp, section_headers[i].sectionptr, SEEK_SET); num_read = fread((void *)buffer, 1, section_headers[i].sectionsize, fp); for (j = 0; j < section_headers[i].sectionsize; j++) MappedMemoryWriteByteNocache(MSH2, section_headers[i].physaddr+j, buffer[j]); SH2WriteNotify(section_headers[i].physaddr, section_headers[i].sectionsize); free(buffer); } // Clean up free(section_headers); fclose(fp); SH2GetRegisters(MSH2, &MSH2->regs); MSH2->regs.PC = aout_header.entrypoint; SH2SetRegisters(MSH2, &MSH2->regs); return 0; } ////////////////////////////////////////////////////////////////////////////// int MappedMemoryLoadElf(const char *filename) { elf_header_struct elf_hdr; elf_section_header_struct *sections = NULL; FILE *fp; u16 i; u32 j; u8 *buffer; size_t num_read = 0; fp = fopen(filename, "rb"); if(fp == NULL) return -1; num_read = fread(&elf_hdr, sizeof(elf_header_struct), 1, fp); if(elf_hdr.ident[0] != 0x7F || elf_hdr.ident[1] != 'E' || elf_hdr.ident[2] != 'L' || elf_hdr.ident[3] != 'F' || elf_hdr.ident[4] != 1) { /* Doesn't appear to be a valid ELF file. */ fclose(fp); return -1; } if(elf_hdr.ident[5] != 2) { /* Doesn't appear to be a big-endian file. */ fclose(fp); return -1; } #ifndef WORDS_BIGENDIAN WordSwap(elf_hdr.type); WordSwap(elf_hdr.machine); DoubleWordSwap(elf_hdr.version); DoubleWordSwap(elf_hdr.entry); DoubleWordSwap(elf_hdr.phdr); DoubleWordSwap(elf_hdr.shdr); DoubleWordSwap(elf_hdr.flags); WordSwap(elf_hdr.hdrsize); WordSwap(elf_hdr.phdrsize); WordSwap(elf_hdr.phdrcount); WordSwap(elf_hdr.shdrsize); WordSwap(elf_hdr.shdrcount); WordSwap(elf_hdr.shdrstridx); #endif LOG("Loading ELF file %s\n", filename); LOG("Type: %d\n", elf_hdr.type); LOG("Machine code: %d\n", elf_hdr.machine); LOG("Version: %d\n", elf_hdr.version); LOG("Entry point: 0x%08X\n", elf_hdr.entry); LOG("Program header offset: %d\n", elf_hdr.phdr); LOG("Section header offset: %d\n", elf_hdr.shdr); LOG("Flags: %d\n", elf_hdr.flags); LOG("ELF Header Size: %d\n", elf_hdr.hdrsize); LOG("Program header size: %d\n", elf_hdr.phdrsize); LOG("Program header count: %d\n", elf_hdr.phdrcount); LOG("Section header size: %d\n", elf_hdr.shdrsize); LOG("Section header count: %d\n", elf_hdr.shdrcount); LOG("String table section: %d\n", elf_hdr.shdrstridx); if(elf_hdr.machine != ELF_MACHINE_SH) { /* Not a SuperH ELF file. */ fclose(fp); return -1; } /* Allocate space for the section headers. */ sections = (elf_section_header_struct *)malloc(sizeof(elf_section_header_struct) * elf_hdr.shdrcount); if(sections == NULL) { fclose(fp); return -2; } /* Look at the actual section headers. */ fseek(fp, elf_hdr.shdr, SEEK_SET); /* Read in each section header. */ for(i = 0; i < elf_hdr.shdrcount; ++i) { num_read = fread(sections + i, sizeof(elf_section_header_struct), 1, fp); #ifndef WORDS_BIGENDIAN DoubleWordSwap(sections[i].name); DoubleWordSwap(sections[i].type); DoubleWordSwap(sections[i].flags); DoubleWordSwap(sections[i].addr); DoubleWordSwap(sections[i].offs); DoubleWordSwap(sections[i].size); DoubleWordSwap(sections[i].link); DoubleWordSwap(sections[i].inf); DoubleWordSwap(sections[i].align); DoubleWordSwap(sections[i].esize); #endif LOG("Section header %d:\n", i); LOG("Name index: %d\n", sections[i].name); LOG("Type: %d\n", sections[i].type); LOG("Flags: 0x%X\n", sections[i].flags); LOG("In-memory address: 0x%08X\n", sections[i].addr); LOG("In-file offset: %d\n", sections[i].offs); LOG("Size: %d\n", sections[i].size); LOG("Link field: %d\n", sections[i].link); LOG("Info field: %d\n", sections[i].inf); LOG("Alignment: %d\n", sections[i].align); LOG("Entry size: %d\n", sections[i].esize); } YabauseResetNoLoad(); /* Set up the vector table area, etc. */ YabauseSpeedySetup(); /* Read in the sections and load them to RAM. */ for(i = 0; i < elf_hdr.shdrcount; ++i) { /* Does the header request actual storage for this section? */ if(sections[i].flags & ELF_SECTION_FLAG_ALLOC) { /* Check if the section contains data, or if its just a marker for a section of zero bytes. */ if(sections[i].type == ELF_SECTION_TYPE_NODATA) { for(j = 0; j < sections[i].size; ++j) { MappedMemoryWriteByteNocache(MSH2, sections[i].addr + j, 0); } } else { buffer = (u8 *)malloc(sections[i].size); if(buffer == NULL) { fclose(fp); free(sections); return -2; } fseek(fp, sections[i].offs, SEEK_SET); num_read = fread(buffer, 1, sections[i].size, fp); for(j = 0; j < sections[i].size; ++j) { MappedMemoryWriteByteNocache(MSH2, sections[i].addr + j, buffer[j]); } free(buffer); } } } /* Clean up. */ free(sections); fclose(fp); /* Set up our entry point. */ SH2GetRegisters(MSH2, &MSH2->regs); MSH2->regs.PC = elf_hdr.entry; SH2SetRegisters(MSH2, &MSH2->regs); return 0; } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/threads.h000644 001750 001750 00000005757 12755623101 017663 0ustar00guillaumeguillaume000000 000000 /* src/threads.h: Constants and prototypes for thread handling Copyright 2010 Andrew Church This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef THREADS_H #define THREADS_H /////////////////////////////////////////////////////////////////////////// // Thread constants /////////////////////////////////////////////////////////////////////////// // Thread IDs enum { YAB_THREAD_SCSP = 0, YAB_THREAD_GDBSTUBCLIENT, YAB_THREAD_GDBSTUBLISTENER, YAB_THREAD_NETLINKLISTENER, YAB_THREAD_NETLINKCONNECT, YAB_THREAD_NETLINKCLIENT, YAB_THREAD_OPENAL, YAB_THREAD_VIDSOFT_LAYER_NBG3, YAB_THREAD_VIDSOFT_LAYER_NBG2, YAB_THREAD_VIDSOFT_LAYER_NBG1, YAB_THREAD_VIDSOFT_LAYER_NBG0, YAB_THREAD_VIDSOFT_LAYER_RBG0, YAB_THREAD_VIDSOFT_VDP1, YAB_THREAD_VIDSOFT_PRIORITY_0, YAB_THREAD_VIDSOFT_PRIORITY_1, YAB_THREAD_VIDSOFT_PRIORITY_2, YAB_THREAD_VIDSOFT_PRIORITY_3, YAB_THREAD_VIDSOFT_PRIORITY_4, YAB_THREAD_VIDSOFT_LAYER_SPRITE, YAB_NUM_THREADS // Total number of subthreads }; // Number of (boolean) semaphores available per thread #define YAB_NUM_SEMAPHORES 2 /////////////////////////////////////////////////////////////////////////// // Thread functions (must be implemented by the port; only used if // yabauseinit_struct.usethreads != 0 at YabauseInit() time) /////////////////////////////////////////////////////////////////////////// // YabThreadStart: Start a new thread for the given function. Only one // thread will be started for each thread ID (YAB_THREAD_*). Returns 0 on // success, -1 on error. int YabThreadStart(unsigned int id, void (*func)(void *), void *arg); // YabThreadWait: Wait for the given ID's thread to terminate. Returns // immediately if no thread has been started on the given ID. void YabThreadWait(unsigned int id); // YabThreadYield: Yield CPU execution to another thread. void YabThreadYield(void); // YabThreadSleep: Put the current thread to sleep. void YabThreadSleep(void); // YabThreadSleep: Put the specified thread to sleep. void YabThreadRemoteSleep(unsigned int id); // YabThreadWake: Wake up the given thread if it is asleep. void YabThreadWake(unsigned int id); /////////////////////////////////////////////////////////////////////////// #endif // THREADS_H yabause-0.9.15/src/mpeg_card.h000644 001750 001750 00000002046 12755623101 020136 0ustar00guillaumeguillaume000000 000000 /* Copyright 2014-2016 James Laird-Wah Copyright 2004-2006, 2013 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MPEG_CARD_H #define MPEG_CARD_H #include "core.h" void mpeg_card_write_word(u32 addr, u16 data); u16 mpeg_card_read_word(u32 addr); void mpeg_card_set_all_irqs(); void mpeg_card_init(); void set_mpeg_video_irq(); #endif yabause-0.9.15/src/persdljoy.c000755 001750 001750 00000020456 12755623101 020233 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005 Guillaume Duhamel Copyright 2005-2006 Theo Berkau Copyright 2008 Filipe Azevedo This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file persdljoy.c \brief SDL joystick peripheral interface. */ #ifdef HAVE_LIBSDL #if defined(__APPLE__) || defined(GEKKO) #ifdef HAVE_LIBSDL2 #include #else #include #endif #else #include "SDL.h" #endif #include "debug.h" #include "persdljoy.h" #define SDL_MAX_AXIS_VALUE 0x110000 #define SDL_MIN_AXIS_VALUE 0x100000 #define SDL_HAT_VALUE 0x200000 #define SDL_MEDIUM_AXIS_VALUE (int)(32768 / 2) #define SDL_BUTTON_PRESSED 1 #define SDL_BUTTON_RELEASED 0 int PERSDLJoyInit(void); void PERSDLJoyDeInit(void); int PERSDLJoyHandleEvents(void); u32 PERSDLJoyScan(u32 flags); void PERSDLJoyFlush(void); void PERSDLKeyName(u32 key, char * name, int size); PerInterface_struct PERSDLJoy = { PERCORE_SDLJOY, "SDL Joystick Interface", PERSDLJoyInit, PERSDLJoyDeInit, PERSDLJoyHandleEvents, PERSDLJoyScan, 1, PERSDLJoyFlush, PERSDLKeyName }; typedef struct { SDL_Joystick* mJoystick; s16* mScanStatus; Uint8* mHatStatus; } PERSDLJoystick; unsigned int SDL_PERCORE_INITIALIZED = 0; unsigned int SDL_PERCORE_JOYSTICKS_INITIALIZED = 0; PERSDLJoystick* SDL_PERCORE_JOYSTICKS = 0; unsigned int SDL_HAT_VALUES[] = { SDL_HAT_UP, SDL_HAT_RIGHT, SDL_HAT_LEFT, SDL_HAT_DOWN }; const unsigned int SDL_HAT_VALUES_NUM = sizeof(SDL_HAT_VALUES) / sizeof(SDL_HAT_VALUES[0]); ////////////////////////////////////////////////////////////////////////////// int PERSDLJoyInit(void) { int i, j; // does not need init if already done if ( SDL_PERCORE_INITIALIZED ) { return 0; } #if defined (_MSC_VER) && SDL_VERSION_ATLEAST(2,0,0) SDL_SetMainReady(); #endif // init joysticks if ( SDL_InitSubSystem( SDL_INIT_JOYSTICK ) == -1 ) { return -1; } // ignore joysticks event in sdl event loop SDL_JoystickEventState( SDL_IGNORE ); // open joysticks SDL_PERCORE_JOYSTICKS_INITIALIZED = SDL_NumJoysticks(); SDL_PERCORE_JOYSTICKS = malloc(sizeof(PERSDLJoystick) * SDL_PERCORE_JOYSTICKS_INITIALIZED); for ( i = 0; i < SDL_PERCORE_JOYSTICKS_INITIALIZED; i++ ) { SDL_Joystick* joy = SDL_JoystickOpen( i ); SDL_JoystickUpdate(); SDL_PERCORE_JOYSTICKS[ i ].mJoystick = joy; SDL_PERCORE_JOYSTICKS[ i ].mScanStatus = joy ? malloc(sizeof(s16) * SDL_JoystickNumAxes( joy )) : 0; SDL_PERCORE_JOYSTICKS[ i ].mHatStatus = joy ? malloc(sizeof(Uint8) * SDL_JoystickNumHats( joy )) : 0; if ( joy ) { for ( j = 0; j < SDL_JoystickNumAxes( joy ); j++ ) { SDL_PERCORE_JOYSTICKS[ i ].mScanStatus[ j ] = SDL_JoystickGetAxis( joy, j ); } for ( j = 0; j < SDL_JoystickNumHats( joy ); j++ ) { SDL_PERCORE_JOYSTICKS[ i ].mHatStatus[ j ] = SDL_JoystickGetHat( joy, j ); } } } // success SDL_PERCORE_INITIALIZED = 1; return 0; } ////////////////////////////////////////////////////////////////////////////// void PERSDLJoyDeInit(void) { // close joysticks if ( SDL_PERCORE_INITIALIZED == 1 ) { int i; for ( i = 0; i < SDL_PERCORE_JOYSTICKS_INITIALIZED; i++ ) { #if SDL_VERSION_ATLEAST(2,0,0) if ( SDL_PERCORE_JOYSTICKS[ i ].mJoystick ) #else if ( SDL_JoystickOpened( i ) ) #endif { SDL_JoystickClose( SDL_PERCORE_JOYSTICKS[ i ].mJoystick ); free( SDL_PERCORE_JOYSTICKS[ i ].mScanStatus ); free( SDL_PERCORE_JOYSTICKS[ i ].mHatStatus ); } } free( SDL_PERCORE_JOYSTICKS ); } SDL_PERCORE_JOYSTICKS_INITIALIZED = 0; SDL_PERCORE_INITIALIZED = 0; // close sdl joysticks SDL_QuitSubSystem( SDL_INIT_JOYSTICK ); } ////////////////////////////////////////////////////////////////////////////// int PERSDLJoyHandleEvents(void) { int joyId; int i; int j; SDL_Joystick* joy; Sint16 cur; Uint8 buttonState; Uint8 newHatState; Uint8 oldHatState; int hatValue; // update joysticks states SDL_JoystickUpdate(); // check each joysticks for ( joyId = 0; joyId < SDL_PERCORE_JOYSTICKS_INITIALIZED; joyId++ ) { joy = SDL_PERCORE_JOYSTICKS[ joyId ].mJoystick; if ( !joy ) { continue; } // check axis for ( i = 0; i < SDL_JoystickNumAxes( joy ); i++ ) { cur = SDL_JoystickGetAxis( joy, i ); PerAxisValue((joyId << 18) | SDL_MEDIUM_AXIS_VALUE | i, (u8)(((int)cur+32768) >> 8)); if ( cur < -SDL_MEDIUM_AXIS_VALUE ) { PerKeyUp( (joyId << 18) | SDL_MAX_AXIS_VALUE | i ); PerKeyDown( (joyId << 18) | SDL_MIN_AXIS_VALUE | i ); } else if ( cur > SDL_MEDIUM_AXIS_VALUE ) { PerKeyUp( (joyId << 18) | SDL_MIN_AXIS_VALUE | i ); PerKeyDown( (joyId << 18) | SDL_MAX_AXIS_VALUE | i ); } else { PerKeyUp( (joyId << 18) | SDL_MIN_AXIS_VALUE | i ); PerKeyUp( (joyId << 18) | SDL_MAX_AXIS_VALUE | i ); } } // check buttons for ( i = 0; i < SDL_JoystickNumButtons( joy ); i++ ) { buttonState = SDL_JoystickGetButton( joy, i ); if ( buttonState == SDL_BUTTON_PRESSED ) { PerKeyDown( (joyId << 18) | (i +1) ); } else if ( buttonState == SDL_BUTTON_RELEASED ) { PerKeyUp( (joyId << 18) | (i +1) ); } } // check hats for ( i = 0; i < SDL_JoystickNumHats( joy ); i++ ) { newHatState = SDL_JoystickGetHat( joy, i ); oldHatState = SDL_PERCORE_JOYSTICKS[ joyId ].mHatStatus[ i ]; for ( j = 0 ; j < SDL_HAT_VALUES_NUM; j++ ) { hatValue = SDL_HAT_VALUES[ j ]; if ( oldHatState & hatValue && ~newHatState & hatValue ) { PerKeyUp( (joyId << 18) | SDL_HAT_VALUE | (hatValue << 4) | i ); } } for ( j = 0 ; j < SDL_HAT_VALUES_NUM; j++ ) { hatValue = SDL_HAT_VALUES[ j ]; if ( ~oldHatState & hatValue && newHatState & hatValue ) { PerKeyDown( (joyId << 18) | SDL_HAT_VALUE | (hatValue << 4) | i); } } SDL_PERCORE_JOYSTICKS[ joyId ].mHatStatus[ i ] = newHatState; } } // execute yabause if ( YabauseExec() != 0 ) { return -1; } // return success return 0; } ////////////////////////////////////////////////////////////////////////////// u32 PERSDLJoyScan( u32 flags ) { // init vars int joyId; int i; SDL_Joystick* joy; Sint16 cur; Uint8 hatState; // update joysticks states SDL_JoystickUpdate(); // check each joysticks for ( joyId = 0; joyId < SDL_PERCORE_JOYSTICKS_INITIALIZED; joyId++ ) { joy = SDL_PERCORE_JOYSTICKS[ joyId ].mJoystick; if ( !joy ) { continue; } // check axis for ( i = 0; i < SDL_JoystickNumAxes( joy ); i++ ) { cur = SDL_JoystickGetAxis( joy, i ); if ( cur != SDL_PERCORE_JOYSTICKS[ joyId ].mScanStatus[ i ] ) { if ( cur < -SDL_MEDIUM_AXIS_VALUE ) { if (flags & PERSF_AXIS) return (joyId << 18) | SDL_MEDIUM_AXIS_VALUE | i; if (flags & PERSF_HAT) return (joyId << 18) | SDL_MIN_AXIS_VALUE | i; } else if ( cur > SDL_MEDIUM_AXIS_VALUE ) { if (flags & PERSF_AXIS) return (joyId << 18) | SDL_MEDIUM_AXIS_VALUE | i; if (flags & PERSF_HAT) return (joyId << 18) | SDL_MAX_AXIS_VALUE | i; } } } if (flags & PERSF_BUTTON) { // check buttons for ( i = 0; i < SDL_JoystickNumButtons( joy ); i++ ) { if ( SDL_JoystickGetButton( joy, i ) == SDL_BUTTON_PRESSED ) { return (joyId << 18) | (i +1); break; } } } if (flags & PERSF_HAT) { // check hats for ( i = 0; i < SDL_JoystickNumHats( joy ); i++ ) { hatState = SDL_JoystickGetHat( joy, i ); switch (hatState) { case SDL_HAT_UP: case SDL_HAT_RIGHT: case SDL_HAT_DOWN: case SDL_HAT_LEFT: return (joyId << 18) | SDL_HAT_VALUE | (hatState << 4) | i; break; default: break; } } } } return 0; } void PERSDLJoyFlush(void) { } void PERSDLKeyName(u32 key, char * name, UNUSED int size) { sprintf(name, "%x", (int)key); } #endif yabause-0.9.15/src/cs0.c000644 001750 001750 00000120115 12755623101 016673 0ustar00guillaumeguillaume000000 000000 /* Copyright 2004-2005 Theo Berkau Copyright 2006 Ex-Cyber Copyright 2005 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file cs0.c \brief A-bus CS0 emulation functions. Most of the cartridge related code is here. */ #include #include "cs0.h" #include "error.h" #include "japmodem.h" #include "netlink.h" cartridge_struct *CartridgeArea; ////////////////////////////////////////////////////////////////////////////// // Dummy/No Cart Functions ////////////////////////////////////////////////////////////////////////////// static u8 FASTCALL DummyCs0ReadByte(UNUSED SH2_struct *sh, UNUSED u32 addr) { return 0xFF; } ////////////////////////////////////////////////////////////////////////////// static u16 FASTCALL DummyCs0ReadWord(UNUSED SH2_struct *sh, UNUSED u32 addr) { return 0xFFFF; } ////////////////////////////////////////////////////////////////////////////// static u32 FASTCALL DummyCs0ReadLong(UNUSED SH2_struct *sh, UNUSED u32 addr) { return 0xFFFFFFFF; } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL DummyCs0WriteByte(UNUSED SH2_struct *sh, UNUSED u32 addr, UNUSED u8 val) { } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL DummyCs0WriteWord(UNUSED SH2_struct *sh, UNUSED u32 addr, UNUSED u16 val) { } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL DummyCs0WriteLong(UNUSED SH2_struct *sh, UNUSED u32 addr, UNUSED u32 val) { } ////////////////////////////////////////////////////////////////////////////// static u8 FASTCALL DummyCs1ReadByte(UNUSED SH2_struct *sh, UNUSED u32 addr) { return 0xFF; } ////////////////////////////////////////////////////////////////////////////// static u16 FASTCALL DummyCs1ReadWord(UNUSED SH2_struct *sh, UNUSED u32 addr) { return 0xFFFF; } ////////////////////////////////////////////////////////////////////////////// static u32 FASTCALL DummyCs1ReadLong(UNUSED SH2_struct *sh, UNUSED u32 addr) { return 0xFFFFFFFF; } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL DummyCs1WriteByte(UNUSED SH2_struct *sh, UNUSED u32 addr, UNUSED u8 val) { } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL DummyCs1WriteWord(UNUSED SH2_struct *sh, UNUSED u32 addr, UNUSED u16 val) { } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL DummyCs1WriteLong(UNUSED SH2_struct *sh, UNUSED u32 addr, UNUSED u32 val) { } ////////////////////////////////////////////////////////////////////////////// static u8 FASTCALL DummyCs2ReadByte(UNUSED SH2_struct *sh, UNUSED u32 addr) { return 0xFF; } ////////////////////////////////////////////////////////////////////////////// static u16 FASTCALL DummyCs2ReadWord(UNUSED SH2_struct *sh, UNUSED u32 addr) { return 0xFFFF; } ////////////////////////////////////////////////////////////////////////////// static u32 FASTCALL DummyCs2ReadLong(UNUSED SH2_struct *sh, UNUSED u32 addr) { return 0xFFFFFFFF; } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL DummyCs2WriteByte(UNUSED SH2_struct *sh, UNUSED u32 addr, UNUSED u8 val) { } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL DummyCs2WriteWord(UNUSED SH2_struct *sh, UNUSED u32 addr, UNUSED u16 val) { } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL DummyCs2WriteLong(UNUSED SH2_struct *sh, UNUSED u32 addr, UNUSED u32 val) { } ////////////////////////////////////////////////////////////////////////////// // Action Replay 4M Plus funcions ////////////////////////////////////////////////////////////////////////////// typedef enum { FL_READ, FL_SDP, FL_CMD, FL_ID, FL_IDSDP, FL_IDCMD, FL_WRITEBUF, FL_WRITEARRAY } flashstate; u8 flreg0 = 0; u8 flreg1 = 0; // Default value is for chip AT29C010 u8 vendorid=0x1F; u8 deviceid=0xD5; flashstate flstate0; flashstate flstate1; u8 flbuf0[128]; u8 flbuf1[128]; ////////////////////////////////////////////////////////////////////////////// static u8 FASTCALL FlashCs0ReadByte(u32 addr) { flashstate* state; u8* reg; if (addr & 1) { state = &flstate1; reg = &flreg1; } else { state = &flstate0; reg = &flreg0; } switch (*state) { case FL_ID: case FL_IDSDP: case FL_IDCMD: if (addr & 2) return deviceid; else return vendorid; case FL_WRITEARRAY: *reg ^= 0x02; case FL_WRITEBUF: return *reg; case FL_SDP: case FL_CMD: *state = FL_READ; case FL_READ: default: return T2ReadByte(CartridgeArea->rom, addr); } } ////////////////////////////////////////////////////////////////////////////// static u16 FASTCALL FlashCs0ReadWord(u32 addr) { return ((u16)(FlashCs0ReadByte(addr) << 8) | (u16)(FlashCs0ReadByte(addr+1))); } ////////////////////////////////////////////////////////////////////////////// static u32 FASTCALL FlashCs0ReadLong(u32 addr) { return ((u32)FlashCs0ReadWord(addr) << 16) |(u32) FlashCs0ReadWord(addr + 2); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL FlashCs0WriteByte(u32 addr, u8 val) { flashstate* state; u8* reg; u8* buf; if (addr & 1) { state = &flstate1; reg = &flreg1; buf = flbuf1; } else { state = &flstate0; reg = &flreg0; buf = flbuf0; } switch (*state) { case FL_READ: if (((addr & 0xfffe) == 0xaaaa) && (val == 0xaa)) *state = FL_SDP; return; case FL_WRITEBUF: buf[(addr >> 1) & 0x7f] = val; if (((addr >> 1) & 0x7f) == 0x7f) { int i; int j = addr & 0x1; addr &= 0xffffff00; for (i = 0; i <= 127; i++) { T2WriteByte(CartridgeArea->rom, (addr + i*2 + j), buf[i]); } *state = FL_READ; } return; case FL_SDP: if (((addr & 0xfffe) == 0x5554) && (val == 0x55)) *state = FL_CMD; else *state = FL_READ; return; case FL_ID: if (((addr & 0xfffe) == 0xaaaa) && (val == 0xaa)) *state = FL_IDSDP; else *state = FL_ID; return; case FL_IDSDP: if (((addr & 0xfffe) == 0x5554) && (val == 0x55)) *state = FL_READ; else *state=FL_ID; return; case FL_IDCMD: if (((addr & 0xfffe) == 0xaaaa) && (val == 0xf0)) *state = FL_READ; else *state = FL_ID; return; case FL_CMD: if ((addr & 0xfffe) != 0xaaaa) { *state = FL_READ; return; } switch (val) { case 0xa0: *state = FL_WRITEBUF; return; case 0x90: *state = FL_ID; return; default: *state = FL_READ; return; } default: break; } } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL FlashCs0WriteWord(u32 addr, u16 val) { FlashCs0WriteByte(addr, (u8)(val >> 8)); FlashCs0WriteByte(addr + 1, (u8)(val & 0xff)); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL FlashCs0WriteLong(u32 addr, u32 val) { FlashCs0WriteWord(addr, (u16)(val >> 16)); FlashCs0WriteWord(addr + 2, (u16)(val & 0xffff)); } ////////////////////////////////////////////////////////////////////////////// static u8 FASTCALL AR4MCs0ReadByte(SH2_struct *sh, u32 addr) { addr &= 0x1FFFFFF; switch (addr >> 20) { case 0x00: { if ((addr & 0x80000) == 0) // EEPROM return FlashCs0ReadByte(addr); // return biosarea->getByte(addr); // else // Outport // fprintf(stderr, "Commlink Outport Byte read\n"); break; } case 0x01: { // if ((addr & 0x80000) == 0) // Commlink Status flag // fprintf(stderr, "Commlink Status Flag read\n"); // else // Inport for Commlink // fprintf(stderr, "Commlink Inport Byte read\n"); break; } case 0x04: case 0x05: case 0x06: case 0x07: // Dram area return T1ReadByte(CartridgeArea->dram, addr & 0x3FFFFF); default: // The rest doesn't matter break; } return 0xFF; } ////////////////////////////////////////////////////////////////////////////// static u16 FASTCALL AR4MCs0ReadWord(SH2_struct *sh, u32 addr) { addr &= 0x1FFFFFF; switch (addr >> 20) { case 0x00: { if ((addr & 0x80000) == 0) // EEPROM return FlashCs0ReadWord(addr); // else // Outport // fprintf(stderr, "Commlink Outport Word read\n"); break; } case 0x01: { // if ((addr & 0x80000) == 0) // Commlink Status flag // fprintf(stderr, "Commlink Status Flag read\n"); // else // Inport for Commlink // fprintf(stderr, "Commlink Inport Word read\n"); break; } case 0x04: case 0x05: case 0x06: case 0x07: // Ram cart area return T1ReadWord(CartridgeArea->dram, addr & 0x3FFFFF); case 0x12: case 0x1E: if (0x80000) return 0xFFFD; break; case 0x13: case 0x16: case 0x17: case 0x1A: case 0x1B: case 0x1F: return 0xFFFD; default: // The rest doesn't matter break; } return 0xFFFF; } ////////////////////////////////////////////////////////////////////////////// static u32 FASTCALL AR4MCs0ReadLong(SH2_struct *sh, u32 addr) { addr &= 0x1FFFFFF; switch (addr >> 20) { case 0x00: { if ((addr & 0x80000) == 0) // EEPROM return FlashCs0ReadLong(addr); // else // Outport // fprintf(stderr, "Commlink Outport Long read\n"); break; } case 0x01: { // if ((addr & 0x80000) == 0) // Commlink Status flag // fprintf(stderr, "Commlink Status Flag read\n"); // else // Inport for Commlink // fprintf(stderr, "Commlink Inport Long read\n"); break; } case 0x04: case 0x05: case 0x06: case 0x07: // Ram cart area return T1ReadLong(CartridgeArea->dram, addr & 0x3FFFFF); case 0x12: case 0x1E: if (0x80000) return 0xFFFDFFFD; break; case 0x13: case 0x16: case 0x17: case 0x1A: case 0x1B: case 0x1F: return 0xFFFDFFFD; default: // The rest doesn't matter break; } return 0xFFFFFFFF; } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL AR4MCs0WriteByte(SH2_struct *sh, u32 addr, u8 val) { addr &= 0x1FFFFFF; switch (addr >> 20) { case 0x00: { if ((addr & 0x80000) == 0) // EEPROM FlashCs0WriteByte(addr, val); // else // Outport // fprintf(stderr, "Commlink Outport byte write\n"); break; } case 0x01: { // if ((addr & 0x80000) == 0) // Commlink Status flag // fprintf(stderr, "Commlink Status Flag write\n"); // else // Inport for Commlink // fprintf(stderr, "Commlink Inport Byte write\n"); break; } case 0x04: case 0x05: case 0x06: case 0x07: // Ram cart area T1WriteByte(CartridgeArea->dram, addr & 0x3FFFFF, val); break; default: // The rest doesn't matter break; } } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL AR4MCs0WriteWord(SH2_struct *sh, u32 addr, u16 val) { addr &= 0x1FFFFFF; switch (addr >> 20) { case 0x00: { if ((addr & 0x80000) == 0) // EEPROM FlashCs0WriteWord(addr, val); // else // Outport // fprintf(stderr, "Commlink Outport Word write\n"); break; } case 0x01: { // if ((addr & 0x80000) == 0) // Commlink Status flag // fprintf(stderr, "Commlink Status Flag write\n"); // else // Inport for Commlink // fprintf(stderr, "Commlink Inport Word write\n"); break; } case 0x04: case 0x05: case 0x06: case 0x07: // Ram cart area T1WriteWord(CartridgeArea->dram, addr & 0x3FFFFF, val); break; default: // The rest doesn't matter break; } } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL AR4MCs0WriteLong(SH2_struct *sh, u32 addr, u32 val) { addr &= 0x1FFFFFF; switch (addr >> 20) { case 0x00: { if ((addr & 0x80000) == 0) // EEPROM FlashCs0WriteLong(addr, val); // else // Outport // fprintf(stderr, "Commlink Outport Long write\n"); break; } case 0x01: { // if ((addr & 0x80000) == 0) // Commlink Status flag // fprintf(stderr, "Commlink Status Flag write\n"); // else // Inport for Commlink // fprintf(stderr, "Commlink Inport Long write\n"); break; } case 0x04: case 0x05: case 0x06: case 0x07: // Ram cart area T1WriteLong(CartridgeArea->dram, addr & 0x3FFFFF, val); break; default: // The rest doesn't matter break; } } ////////////////////////////////////////////////////////////////////////////// // 8 Mbit Dram ////////////////////////////////////////////////////////////////////////////// static u8 FASTCALL DRAM8MBITCs0ReadByte(SH2_struct *sh, u32 addr) { addr &= 0x1FFFFFF; switch (addr >> 20) { case 0x04: // Dram area return T1ReadByte(CartridgeArea->dram, addr & 0x7FFFF); case 0x06: // Dram area return T1ReadByte(CartridgeArea->dram, 0x80000 | (addr & 0x7FFFF)); default: // The rest doesn't matter break; } return 0xFF; } ////////////////////////////////////////////////////////////////////////////// static u16 FASTCALL DRAM8MBITCs0ReadWord(SH2_struct *sh, u32 addr) { addr &= 0x1FFFFFF; switch (addr >> 20) { case 0x04: // Dram area return T1ReadWord(CartridgeArea->dram, addr & 0x7FFFF); case 0x06: // Dram area return T1ReadWord(CartridgeArea->dram, 0x80000 | (addr & 0x7FFFF)); default: // The rest doesn't matter break; } return 0xFFFF; } ////////////////////////////////////////////////////////////////////////////// static u32 FASTCALL DRAM8MBITCs0ReadLong(SH2_struct *sh, u32 addr) { addr &= 0x1FFFFFF; switch (addr >> 20) { case 0x04: // Dram area return T1ReadLong(CartridgeArea->dram, addr & 0x7FFFF); case 0x06: // Dram area return T1ReadLong(CartridgeArea->dram, 0x80000 | (addr & 0x7FFFF)); default: // The rest doesn't matter break; } return 0xFFFFFFFF; } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL DRAM8MBITCs0WriteByte(SH2_struct *sh, u32 addr, u8 val) { addr &= 0x1FFFFFF; switch (addr >> 20) { case 0x04: // Dram area T1WriteByte(CartridgeArea->dram, addr & 0x7FFFF, val); break; case 0x06: // Dram area T1WriteByte(CartridgeArea->dram, 0x80000 | (addr & 0x7FFFF), val); break; default: // The rest doesn't matter break; } } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL DRAM8MBITCs0WriteWord(SH2_struct *sh, u32 addr, u16 val) { addr &= 0x1FFFFFF; switch (addr >> 20) { case 0x04: // Dram area T1WriteWord(CartridgeArea->dram, addr & 0x7FFFF, val); break; case 0x06: // Dram area T1WriteWord(CartridgeArea->dram, 0x80000 | (addr & 0x7FFFF), val); break; default: // The rest doesn't matter break; } } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL DRAM8MBITCs0WriteLong(SH2_struct *sh, u32 addr, u32 val) { addr &= 0x1FFFFFF; switch (addr >> 20) { case 0x04: // Dram area T1WriteLong(CartridgeArea->dram, addr & 0x7FFFF, val); break; case 0x06: // Dram area T1WriteLong(CartridgeArea->dram, 0x80000 | (addr & 0x7FFFF), val); break; default: // The rest doesn't matter break; } } ////////////////////////////////////////////////////////////////////////////// // 32 Mbit Dram ////////////////////////////////////////////////////////////////////////////// static u8 FASTCALL DRAM32MBITCs0ReadByte(SH2_struct *sh, u32 addr) { addr &= 0x1FFFFFF; switch (addr >> 20) { case 0x04: case 0x05: case 0x06: case 0x07: // Dram area return T1ReadByte(CartridgeArea->dram, addr & 0x3FFFFF); default: // The rest doesn't matter break; } return 0xFF; } ////////////////////////////////////////////////////////////////////////////// static u16 FASTCALL DRAM32MBITCs0ReadWord(SH2_struct *sh, u32 addr) { addr &= 0x1FFFFFF; switch (addr >> 20) { case 0x04: case 0x05: case 0x06: case 0x07: // Ram cart area return T1ReadWord(CartridgeArea->dram, addr & 0x3FFFFF); default: // The rest doesn't matter break; } return 0xFFFF; } ////////////////////////////////////////////////////////////////////////////// static u32 FASTCALL DRAM32MBITCs0ReadLong(SH2_struct *sh, u32 addr) { addr &= 0x1FFFFFF; switch (addr >> 20) { case 0x04: case 0x05: case 0x06: case 0x07: // Ram cart area return T1ReadLong(CartridgeArea->dram, addr & 0x3FFFFF); default: // The rest doesn't matter break; } return 0xFFFFFFFF; } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL DRAM32MBITCs0WriteByte(SH2_struct *sh, u32 addr, u8 val) { addr &= 0x1FFFFFF; switch (addr >> 20) { case 0x04: case 0x05: case 0x06: case 0x07: // Ram cart area T1WriteByte(CartridgeArea->dram, addr & 0x3FFFFF, val); break; default: // The rest doesn't matter break; } } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL DRAM32MBITCs0WriteWord(SH2_struct *sh, u32 addr, u16 val) { addr &= 0x1FFFFFF; switch (addr >> 20) { case 0x04: case 0x05: case 0x06: case 0x07: // Ram cart area T1WriteWord(CartridgeArea->dram, addr & 0x3FFFFF, val); break; default: // The rest doesn't matter break; } } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL DRAM32MBITCs0WriteLong(SH2_struct *sh, u32 addr, u32 val) { addr &= 0x1FFFFFF; switch (addr >> 20) { case 0x04: case 0x05: case 0x06: case 0x07: // Ram cart area T1WriteLong(CartridgeArea->dram, addr & 0x3FFFFF, val); break; default: // The rest doesn't matter break; } } ////////////////////////////////////////////////////////////////////////////// // 4 Mbit Backup Ram ////////////////////////////////////////////////////////////////////////////// static u8 FASTCALL BUP4MBITCs1ReadByte(SH2_struct *sh, u32 addr) { return T1ReadByte(CartridgeArea->bupram, addr & 0xFFFFF); } ////////////////////////////////////////////////////////////////////////////// static u16 FASTCALL BUP4MBITCs1ReadWord(SH2_struct *sh, u32 addr) { return T1ReadWord(CartridgeArea->bupram, addr & 0xFFFFF); } ////////////////////////////////////////////////////////////////////////////// static u32 FASTCALL BUP4MBITCs1ReadLong(SH2_struct *sh, u32 addr) { return T1ReadLong(CartridgeArea->bupram, addr & 0xFFFFF); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BUP4MBITCs1WriteByte(SH2_struct *sh, u32 addr, u8 val) { T1WriteByte(CartridgeArea->bupram, addr & 0xFFFFF, val); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BUP4MBITCs1WriteWord(SH2_struct *sh, u32 addr, u16 val) { T1WriteWord(CartridgeArea->bupram, addr & 0xFFFFF, val); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BUP4MBITCs1WriteLong(SH2_struct *sh, u32 addr, u32 val) { T1WriteLong(CartridgeArea->bupram, addr & 0xFFFFF, val); } ////////////////////////////////////////////////////////////////////////////// // 8 Mbit Backup Ram ////////////////////////////////////////////////////////////////////////////// static u8 FASTCALL BUP8MBITCs1ReadByte(SH2_struct *sh, u32 addr) { return T1ReadByte(CartridgeArea->bupram, addr & 0x1FFFFF); } ////////////////////////////////////////////////////////////////////////////// static u16 FASTCALL BUP8MBITCs1ReadWord(SH2_struct *sh, u32 addr) { return T1ReadWord(CartridgeArea->bupram, addr & 0x1FFFFF); } ////////////////////////////////////////////////////////////////////////////// static u32 FASTCALL BUP8MBITCs1ReadLong(SH2_struct *sh, u32 addr) { return T1ReadLong(CartridgeArea->bupram, addr & 0x1FFFFF); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BUP8MBITCs1WriteByte(SH2_struct *sh, u32 addr, u8 val) { T1WriteByte(CartridgeArea->bupram, addr & 0x1FFFFF, val); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BUP8MBITCs1WriteWord(SH2_struct *sh, u32 addr, u16 val) { T1WriteWord(CartridgeArea->bupram, addr & 0x1FFFFF, val); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BUP8MBITCs1WriteLong(SH2_struct *sh, u32 addr, u32 val) { T1WriteLong(CartridgeArea->bupram, addr & 0x1FFFFF, val); } ////////////////////////////////////////////////////////////////////////////// // 16 Mbit Backup Ram ////////////////////////////////////////////////////////////////////////////// static u8 FASTCALL BUP16MBITCs1ReadByte(SH2_struct *sh, u32 addr) { return T1ReadByte(CartridgeArea->bupram, addr & 0x3FFFFF); } ////////////////////////////////////////////////////////////////////////////// static u16 FASTCALL BUP16MBITCs1ReadWord(SH2_struct *sh, u32 addr) { return T1ReadWord(CartridgeArea->bupram, addr & 0x3FFFFF); } ////////////////////////////////////////////////////////////////////////////// static u32 FASTCALL BUP16MBITCs1ReadLong(SH2_struct *sh, u32 addr) { return T1ReadLong(CartridgeArea->bupram, addr & 0x3FFFFF); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BUP16MBITCs1WriteByte(SH2_struct *sh, u32 addr, u8 val) { T1WriteByte(CartridgeArea->bupram, addr & 0x3FFFFF, val); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BUP16MBITCs1WriteWord(SH2_struct *sh, u32 addr, u16 val) { T1WriteWord(CartridgeArea->bupram, addr & 0x3FFFFF, val); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BUP16MBITCs1WriteLong(SH2_struct *sh, u32 addr, u32 val) { T1WriteLong(CartridgeArea->bupram, addr & 0x3FFFFF, val); } ////////////////////////////////////////////////////////////////////////////// // 32 Mbit Backup Ram ////////////////////////////////////////////////////////////////////////////// static u8 FASTCALL BUP32MBITCs1ReadByte(SH2_struct *sh, u32 addr) { return T1ReadByte(CartridgeArea->bupram, addr & 0x7FFFFF); } ////////////////////////////////////////////////////////////////////////////// static u16 FASTCALL BUP32MBITCs1ReadWord(SH2_struct *sh, u32 addr) { return T1ReadWord(CartridgeArea->bupram, addr & 0x7FFFFF); } ////////////////////////////////////////////////////////////////////////////// static u32 FASTCALL BUP32MBITCs1ReadLong(SH2_struct *sh, u32 addr) { return T1ReadLong(CartridgeArea->bupram, addr & 0x7FFFFF); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BUP32MBITCs1WriteByte(SH2_struct *sh, u32 addr, u8 val) { T1WriteByte(CartridgeArea->bupram, addr & 0x7FFFFF, val); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BUP32MBITCs1WriteWord(SH2_struct *sh, u32 addr, u16 val) { T1WriteWord(CartridgeArea->bupram, addr & 0x7FFFFF, val); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BUP32MBITCs1WriteLong(SH2_struct *sh, u32 addr, u32 val) { T1WriteLong(CartridgeArea->bupram, addr & 0x7FFFFF, val); } ////////////////////////////////////////////////////////////////////////////// // 16 Mbit Rom ////////////////////////////////////////////////////////////////////////////// static u8 FASTCALL ROM16MBITCs0ReadByte(SH2_struct *sh, u32 addr) { return T1ReadByte(CartridgeArea->rom, addr & 0x1FFFFF); } ////////////////////////////////////////////////////////////////////////////// static u16 FASTCALL ROM16MBITCs0ReadWord(SH2_struct *sh, u32 addr) { return T1ReadWord(CartridgeArea->rom, addr & 0x1FFFFF); } ////////////////////////////////////////////////////////////////////////////// static u32 FASTCALL ROM16MBITCs0ReadLong(SH2_struct *sh, u32 addr) { return T1ReadLong(CartridgeArea->rom, addr & 0x1FFFFF); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL ROM16MBITCs0WriteByte(SH2_struct *sh, u32 addr, u8 val) { T1WriteByte(CartridgeArea->rom, addr & 0x1FFFFF, val); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL ROM16MBITCs0WriteWord(SH2_struct *sh, u32 addr, u16 val) { T1WriteWord(CartridgeArea->rom, addr & 0x1FFFFF, val); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL ROM16MBITCs0WriteLong(SH2_struct *sh, u32 addr, u32 val) { T1WriteLong(CartridgeArea->rom, addr & 0x1FFFFF, val); } ////////////////////////////////////////////////////////////////////////////// // General Cart functions ////////////////////////////////////////////////////////////////////////////// int CartInit(const char * filename, int type) { if ((CartridgeArea = (cartridge_struct *)calloc(1, sizeof(cartridge_struct))) == NULL) return -1; CartridgeArea->carttype = type; CartridgeArea->filename = filename; // Setup default mappings CartridgeArea->Cs0ReadByte = &DummyCs0ReadByte; CartridgeArea->Cs0ReadWord = &DummyCs0ReadWord; CartridgeArea->Cs0ReadLong = &DummyCs0ReadLong; CartridgeArea->Cs0WriteByte = &DummyCs0WriteByte; CartridgeArea->Cs0WriteWord = &DummyCs0WriteWord; CartridgeArea->Cs0WriteLong = &DummyCs0WriteLong; CartridgeArea->Cs1ReadByte = &DummyCs1ReadByte; CartridgeArea->Cs1ReadWord = &DummyCs1ReadWord; CartridgeArea->Cs1ReadLong = &DummyCs1ReadLong; CartridgeArea->Cs1WriteByte = &DummyCs1WriteByte; CartridgeArea->Cs1WriteWord = &DummyCs1WriteWord; CartridgeArea->Cs1WriteLong = &DummyCs1WriteLong; CartridgeArea->Cs2ReadByte = &DummyCs2ReadByte; CartridgeArea->Cs2ReadWord = &DummyCs2ReadWord; CartridgeArea->Cs2ReadLong = &DummyCs2ReadLong; CartridgeArea->Cs2WriteByte = &DummyCs2WriteByte; CartridgeArea->Cs2WriteWord = &DummyCs2WriteWord; CartridgeArea->Cs2WriteLong = &DummyCs2WriteLong; switch(type) { case CART_PAR: // Action Replay 4M Plus(or equivalent) { if ((CartridgeArea->rom = T2MemoryInit(0x40000)) == NULL) return -1; if ((CartridgeArea->dram = T1MemoryInit(0x400000)) == NULL) return -1; // Use 32 Mbit Dram id CartridgeArea->cartid = 0x5C; // Load AR firmware to memory if (T123Load(CartridgeArea->rom, 0x40000, 2, filename) != 0) return -1; vendorid = 0x1F; deviceid = 0xD5; flstate0 = FL_READ; flstate1 = FL_READ; // Setup Functions CartridgeArea->Cs0ReadByte = &AR4MCs0ReadByte; CartridgeArea->Cs0ReadWord = &AR4MCs0ReadWord; CartridgeArea->Cs0ReadLong = &AR4MCs0ReadLong; CartridgeArea->Cs0WriteByte = &AR4MCs0WriteByte; CartridgeArea->Cs0WriteWord = &AR4MCs0WriteWord; CartridgeArea->Cs0WriteLong = &AR4MCs0WriteLong; break; } case CART_BACKUPRAM4MBIT: // 4 Mbit Backup Ram { if ((CartridgeArea->bupram = T1MemoryInit(0x100000)) == NULL) return -1; CartridgeArea->cartid = 0x21; // Load Backup Ram data from file if (T123Load(CartridgeArea->bupram, 0x100000, 1, filename) != 0) FormatBackupRam(CartridgeArea->bupram, 0x100000); // Setup Functions CartridgeArea->Cs1ReadByte = &BUP4MBITCs1ReadByte; CartridgeArea->Cs1ReadWord = &BUP4MBITCs1ReadWord; CartridgeArea->Cs1ReadLong = &BUP4MBITCs1ReadLong; CartridgeArea->Cs1WriteByte = &BUP4MBITCs1WriteByte; CartridgeArea->Cs1WriteWord = &BUP4MBITCs1WriteWord; CartridgeArea->Cs1WriteLong = &BUP4MBITCs1WriteLong; break; } case CART_BACKUPRAM8MBIT: // 8 Mbit Backup Ram { if ((CartridgeArea->bupram = T1MemoryInit(0x200000)) == NULL) return -1; CartridgeArea->cartid = 0x22; // Load Backup Ram data from file if (T123Load(CartridgeArea->bupram, 0x200000, 1, filename) != 0) FormatBackupRam(CartridgeArea->bupram, 0x200000); // Setup Functions CartridgeArea->Cs1ReadByte = &BUP8MBITCs1ReadByte; CartridgeArea->Cs1ReadWord = &BUP8MBITCs1ReadWord; CartridgeArea->Cs1ReadLong = &BUP8MBITCs1ReadLong; CartridgeArea->Cs1WriteByte = &BUP8MBITCs1WriteByte; CartridgeArea->Cs1WriteWord = &BUP8MBITCs1WriteWord; CartridgeArea->Cs1WriteLong = &BUP8MBITCs1WriteLong; break; } case CART_BACKUPRAM16MBIT: // 16 Mbit Backup Ram { if ((CartridgeArea->bupram = T1MemoryInit(0x400000)) == NULL) return -1; CartridgeArea->cartid = 0x23; // Load Backup Ram data from file if (T123Load(CartridgeArea->bupram, 0x400000, 1, filename) != 0) FormatBackupRam(CartridgeArea->bupram, 0x400000); // Setup Functions CartridgeArea->Cs1ReadByte = &BUP16MBITCs1ReadByte; CartridgeArea->Cs1ReadWord = &BUP16MBITCs1ReadWord; CartridgeArea->Cs1ReadLong = &BUP16MBITCs1ReadLong; CartridgeArea->Cs1WriteByte = &BUP16MBITCs1WriteByte; CartridgeArea->Cs1WriteWord = &BUP16MBITCs1WriteWord; CartridgeArea->Cs1WriteLong = &BUP16MBITCs1WriteLong; break; } case CART_BACKUPRAM32MBIT: // 32 Mbit Backup Ram { if ((CartridgeArea->bupram = T1MemoryInit(0x800000)) == NULL) return -1; CartridgeArea->cartid = 0x24; // Load Backup Ram data from file if (T123Load(CartridgeArea->bupram, 0x800000, 1, filename) != 0) FormatBackupRam(CartridgeArea->bupram, 0x800000); // Setup Functions CartridgeArea->Cs1ReadByte = &BUP32MBITCs1ReadByte; CartridgeArea->Cs1ReadWord = &BUP32MBITCs1ReadWord; CartridgeArea->Cs1ReadLong = &BUP32MBITCs1ReadLong; CartridgeArea->Cs1WriteByte = &BUP32MBITCs1WriteByte; CartridgeArea->Cs1WriteWord = &BUP32MBITCs1WriteWord; CartridgeArea->Cs1WriteLong = &BUP32MBITCs1WriteLong; break; } case CART_DRAM8MBIT: // 8 Mbit Dram Cart { if ((CartridgeArea->dram = T1MemoryInit(0x100000)) == NULL) return -1; CartridgeArea->cartid = 0x5A; // Setup Functions CartridgeArea->Cs0ReadByte = &DRAM8MBITCs0ReadByte; CartridgeArea->Cs0ReadWord = &DRAM8MBITCs0ReadWord; CartridgeArea->Cs0ReadLong = &DRAM8MBITCs0ReadLong; CartridgeArea->Cs0WriteByte = &DRAM8MBITCs0WriteByte; CartridgeArea->Cs0WriteWord = &DRAM8MBITCs0WriteWord; CartridgeArea->Cs0WriteLong = &DRAM8MBITCs0WriteLong; break; } case CART_DRAM32MBIT: // 32 Mbit Dram Cart { if ((CartridgeArea->dram = T1MemoryInit(0x400000)) == NULL) return -1; CartridgeArea->cartid = 0x5C; // Setup Functions CartridgeArea->Cs0ReadByte = &DRAM32MBITCs0ReadByte; CartridgeArea->Cs0ReadWord = &DRAM32MBITCs0ReadWord; CartridgeArea->Cs0ReadLong = &DRAM32MBITCs0ReadLong; CartridgeArea->Cs0WriteByte = &DRAM32MBITCs0WriteByte; CartridgeArea->Cs0WriteWord = &DRAM32MBITCs0WriteWord; CartridgeArea->Cs0WriteLong = &DRAM32MBITCs0WriteLong; break; } case CART_NETLINK: { CartridgeArea->cartid = 0xFF; CartridgeArea->Cs2ReadByte = &NetlinkReadByte; CartridgeArea->Cs2WriteByte = &NetlinkWriteByte; break; } case CART_ROM16MBIT: // 16 Mbit Rom Cart { if ((CartridgeArea->rom = T1MemoryInit(0x200000)) == NULL) return -1; CartridgeArea->cartid = 0xFF; // I have no idea what the real id is // Load Rom to memory if (T123Load(CartridgeArea->rom, 0x200000, 1, filename) != 0) return -1; // Setup Functions CartridgeArea->Cs0ReadByte = &ROM16MBITCs0ReadByte; CartridgeArea->Cs0ReadWord = &ROM16MBITCs0ReadWord; CartridgeArea->Cs0ReadLong = &ROM16MBITCs0ReadLong; CartridgeArea->Cs0WriteByte = &ROM16MBITCs0WriteByte; CartridgeArea->Cs0WriteWord = &ROM16MBITCs0WriteWord; CartridgeArea->Cs0WriteLong = &ROM16MBITCs0WriteLong; break; } case CART_JAPMODEM: // Sega Saturn Modem(Japanese) { CartridgeArea->cartid = 0xFF; CartridgeArea->Cs0ReadByte = &JapModemCs0ReadByte; CartridgeArea->Cs0ReadWord = &JapModemCs0ReadWord; CartridgeArea->Cs0ReadLong = &JapModemCs0ReadLong; CartridgeArea->Cs1ReadByte = &JapModemCs1ReadByte; CartridgeArea->Cs1ReadWord = &JapModemCs1ReadWord; CartridgeArea->Cs1ReadLong = &JapModemCs1ReadLong; CartridgeArea->Cs1WriteByte = &JapModemCs1WriteByte; CartridgeArea->Cs1WriteWord = &JapModemCs1WriteWord; CartridgeArea->Cs1WriteLong = &JapModemCs1WriteLong; CartridgeArea->Cs2ReadByte = &JapModemCs2ReadByte; CartridgeArea->Cs2WriteByte = &JapModemCs2WriteByte; break; } case CART_USBDEV: // USB Dev Cartridge { if ((CartridgeArea->rom = T2MemoryInit(0x40000)) == NULL) return -1; if ((CartridgeArea->dram = T1MemoryInit(0x400000)) == NULL) return -1; // No extra dram, etc. built-in CartridgeArea->cartid = 0; // Load AR firmware to memory if (T123Load(CartridgeArea->rom, 0x40000, 2, filename) != 0) return -1; // ID for SST39SF010A vendorid = 0xBF; deviceid = 0xB5; flstate0 = FL_READ; flstate1 = FL_READ; // Setup Functions CartridgeArea->Cs0ReadByte = &AR4MCs0ReadByte; CartridgeArea->Cs0ReadWord = &AR4MCs0ReadWord; CartridgeArea->Cs0ReadLong = &AR4MCs0ReadLong; CartridgeArea->Cs0WriteByte = &AR4MCs0WriteByte; CartridgeArea->Cs0WriteWord = &AR4MCs0WriteWord; CartridgeArea->Cs0WriteLong = &AR4MCs0WriteLong; break; } default: // No Cart { CartridgeArea->cartid = 0xFF; break; } } return 0; } ////////////////////////////////////////////////////////////////////////////// void CartFlush(void){ if (CartridgeArea) { if (CartridgeArea->carttype == CART_PAR) { if (CartridgeArea->rom) { if (T123Save(CartridgeArea->rom, 0x40000, 2, CartridgeArea->filename) != 0) YabSetError(YAB_ERR_FILEWRITE, (void *)CartridgeArea->filename); } } if (CartridgeArea->bupram) { u32 size = 0; switch (CartridgeArea->carttype) { case CART_BACKUPRAM4MBIT: // 4 Mbit Backup Ram { size = 0x100000; break; } case CART_BACKUPRAM8MBIT: // 8 Mbit Backup Ram { size = 0x200000; break; } case CART_BACKUPRAM16MBIT: // 16 Mbit Backup Ram { size = 0x400000; break; } case CART_BACKUPRAM32MBIT: // 32 Mbit Backup Ram { size = 0x800000; break; } } if (size != 0) { if (T123Save(CartridgeArea->bupram, size, 1, CartridgeArea->filename) != 0) YabSetError(YAB_ERR_FILEWRITE, (void *)CartridgeArea->filename); } } } } ////////////////////////////////////////////////////////////////////////////// void CartDeInit(void) { if (CartridgeArea) { if (CartridgeArea->carttype == CART_PAR) { if (CartridgeArea->rom) { if (T123Save(CartridgeArea->rom, 0x40000, 2, CartridgeArea->filename) != 0) YabSetError(YAB_ERR_FILEWRITE, (void *)CartridgeArea->filename); T2MemoryDeInit(CartridgeArea->rom); } } else { if (CartridgeArea->rom) T1MemoryDeInit(CartridgeArea->rom); } if (CartridgeArea->bupram) { u32 size=0; switch (CartridgeArea->carttype) { case CART_BACKUPRAM4MBIT: // 4 Mbit Backup Ram { size = 0x100000; break; } case CART_BACKUPRAM8MBIT: // 8 Mbit Backup Ram { size = 0x200000; break; } case CART_BACKUPRAM16MBIT: // 16 Mbit Backup Ram { size = 0x400000; break; } case CART_BACKUPRAM32MBIT: // 32 Mbit Backup Ram { size = 0x800000; break; } } if (size != 0) { if (T123Save(CartridgeArea->bupram, size, 1, CartridgeArea->filename) != 0) YabSetError(YAB_ERR_FILEWRITE, (void *)CartridgeArea->filename); T1MemoryDeInit(CartridgeArea->bupram); } } if (CartridgeArea->dram) T1MemoryDeInit(CartridgeArea->dram); free(CartridgeArea); } CartridgeArea = NULL; } ////////////////////////////////////////////////////////////////////////////// int CartSaveState(FILE * fp) { int offset; offset = StateWriteHeader(fp, "CART", 1); // Write cart type fwrite((void *)&CartridgeArea->carttype, 4, 1, fp); // Write the areas associated with the cart type here return StateFinishHeader(fp, offset); } ////////////////////////////////////////////////////////////////////////////// int CartLoadState(FILE * fp, UNUSED int version, int size) { int newtype; size_t num_read = 0; // Read cart type num_read = fread((void *)&newtype, 4, 1, fp); // Check to see if old cart type and new cart type match, if they don't, // reallocate memory areas // Read the areas associated with the cart type here return size; } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/titan/000755 001750 001750 00000000000 12757373644 017201 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/titan/titan.h000644 001750 001750 00000003353 12755623101 020455 0ustar00guillaumeguillaume000000 000000 /* Copyright 2012 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef TITAN_H #define TITAN_H #include "../core.h" #include "../vidshared.h" #define TITAN_BLEND_TOP 0 #define TITAN_BLEND_BOTTOM 1 #define TITAN_BLEND_ADD 2 #define TITAN_SPRITE 5 #define TITAN_RBG0 4 #define TITAN_NBG0 3 #define TITAN_NBG1 2 #define TITAN_NBG2 1 #define TITAN_NBG3 0 #define TITAN_BACK -1 #define TITAN_NORMAL_SHADOW 1 #define TITAN_MSB_SHADOW 2 int TitanInit(); int TitanDeInit(); void TitanErase(); void TitanSetResolution(int width, int height); void TitanGetResolution(int * width, int * height); void TitanSetBlendingMode(int blend_mode); void TitanPutBackHLine(s32 y, u32 color); void TitanPutLineHLine(int linescreen, s32 y, u32 color); void TitanPutPixel(int priority, s32 x, s32 y, u32 color, int linescreen, vdp2draw_struct* info); void TitanPutHLine(int priority, s32 x, s32 y, s32 width, u32 color); void TitanRender(pixel_t * dispbuffer); void TitanWriteColor(pixel_t * dispbuffer, s32 bufwidth, s32 x, s32 y, u32 color); #endif yabause-0.9.15/src/titan/titan.c000644 001750 001750 00000046113 12755623101 020451 0ustar00guillaumeguillaume000000 000000 /* Copyright 2012 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "titan.h" #include "../vidshared.h" #include "../vidsoft.h" #include "../threads.h" #include /* private */ typedef u32 (*TitanBlendFunc)(u32 top, u32 bottom); typedef int FASTCALL (*TitanTransFunc)(u32 pixel); void TitanRenderLines(pixel_t * dispbuffer, int start_line, int end_line); extern int vdp2_interlace; int vidsoft_num_priority_threads = 0; struct PixelData { u32 pixel; u8 priority; u8 linescreen; u8 shadow_type; u8 shadow_enabled; }; static struct TitanContext { int inited; struct PixelData * vdp2framebuffer[6]; u32 * linescreen[4]; int vdp2width; int vdp2height; TitanBlendFunc blend; TitanTransFunc trans; struct PixelData * backscreen; int layer_priority[6]; } tt_context = { 0, { NULL, NULL, NULL, NULL, NULL, NULL }, { NULL, NULL, NULL, NULL }, 320, 224, NULL,NULL,NULL }; struct { volatile int need_draw[5]; volatile int draw_finished[5]; struct { volatile int start; volatile int end; }lines[5]; pixel_t * dispbuffer; int use_simplified; }priority_thread_context; #if defined WORDS_BIGENDIAN #ifdef USE_RGB_555 static INLINE u32 TitanFixAlpha(u32 pixel) { return (((pixel >> 27) & 0x1F) | ((pixel >> 14) & 0x7C0) | (pixel >> 1) & 0xF8); } #elif USE_RGB_565 static INLINE u32 TitanFixAlpha(u32 pixel) { return (((pixel >> 27) & 0x1F) | ((pixel >> 13) & 0x7E0) | (pixel & 0xF8)); } #else static INLINE u32 TitanFixAlpha(u32 pixel) { return ((((pixel & 0x3F) << 2) + 0x03) | (pixel & 0xFFFFFF00)); } #endif static INLINE u8 TitanGetAlpha(u32 pixel) { return pixel & 0x3F; } static INLINE u8 TitanGetRed(u32 pixel) { return (pixel >> 8) & 0xFF; } static INLINE u8 TitanGetGreen(u32 pixel) { return (pixel >> 16) & 0xFF; } static INLINE u8 TitanGetBlue(u32 pixel) { return (pixel >> 24) & 0xFF; } static INLINE u32 TitanCreatePixel(u8 alpha, u8 red, u8 green, u8 blue) { return alpha | (red << 8) | (green << 16) | (blue << 24); } #else #ifdef USE_RGB_555 static INLINE u32 TitanFixAlpha(u32 pixel) { return (((pixel << 7) & 0x7C00) | ((pixel >> 6) & 0x3C0) | ((pixel >> 19) & 0x1F)); } #elif USE_RGB_565 static INLINE u32 TitanFixAlpha(u32 pixel) { return (((pixel << 8) & 0xF800) | ((pixel >> 5) & 0x7C0) | ((pixel >> 19) & 0x1F)); } #else static INLINE u32 TitanFixAlpha(u32 pixel) { return ((((pixel & 0x3F000000) << 2) + 0x03000000) | (pixel & 0x00FFFFFF)); } #endif static INLINE u8 TitanGetAlpha(u32 pixel) { return (pixel >> 24) & 0x3F; } static INLINE u8 TitanGetRed(u32 pixel) { return (pixel >> 16) & 0xFF; } static INLINE u8 TitanGetGreen(u32 pixel) { return (pixel >> 8) & 0xFF; } static INLINE u8 TitanGetBlue(u32 pixel) { return pixel & 0xFF; } static INLINE u32 TitanCreatePixel(u8 alpha, u8 red, u8 green, u8 blue) { return (alpha << 24) | (red << 16) | (green << 8) | blue; } #endif void set_layer_y(const int start_line, int * layer_y) { if (vdp2_interlace) *layer_y = start_line / 2; else *layer_y = start_line; } void TitanRenderLinesSimplified(pixel_t * dispbuffer, int start_line, int end_line) { int x, y, i, layer, j, layer_y; int line_increment, interlace_line; int sorted_layers[8] = { 0 }; int num_layers = 0; if (!tt_context.inited || (!tt_context.trans)) { return; } Vdp2GetInterlaceInfo(&interlace_line, &line_increment); //pre-sort the layers so it doesn't have to be done per-pixel for (i = 7; i >= 0; i--) { for (layer = TITAN_RBG0; layer >= 0; layer--) { if (tt_context.layer_priority[layer] > 0 && tt_context.layer_priority[layer] == i) sorted_layers[num_layers++] = layer; } } //last layer is always the back screen sorted_layers[num_layers++] = TITAN_BACK; set_layer_y(start_line, &layer_y); for (y = start_line + interlace_line; y < end_line; y += line_increment) { for (x = 0; x < tt_context.vdp2width; x++) { int layer_pos = (layer_y * tt_context.vdp2width) + x; i = (y * tt_context.vdp2width) + x; dispbuffer[i] = 0; for (j = 0; j < num_layers; j++) { struct PixelData sprite = tt_context.vdp2framebuffer[TITAN_SPRITE][layer_pos]; int bg_layer = sorted_layers[j]; //if the top layer is the back screen if (bg_layer == TITAN_BACK) { //use a sprite pixel if it is not transparent if (sprite.pixel) { dispbuffer[i] = TitanFixAlpha(sprite.pixel); break; } else { //otherwise use the back screen pixel dispbuffer[i] = TitanFixAlpha(tt_context.backscreen[y].pixel); break; } } //if the top layer is a sprite pixel else if (sprite.priority >= tt_context.layer_priority[bg_layer]) { //use the sprite pixel if it is not transparent if (sprite.pixel) { dispbuffer[i] = TitanFixAlpha(sprite.pixel); break; } } else { //use the bg layer if it is not covered with a sprite pixel and not transparent if (tt_context.vdp2framebuffer[bg_layer][layer_pos].pixel) { dispbuffer[i] = TitanFixAlpha(tt_context.vdp2framebuffer[bg_layer][layer_pos].pixel); break; } } } } layer_y++; } } void TitanRenderSimplifiedCheck(pixel_t * buf, int start, int end, int can_use_simplified_rendering) { if (can_use_simplified_rendering) TitanRenderLinesSimplified(buf, start, end); else TitanRenderLines(buf, start, end); } #define DECLARE_PRIORITY_THREAD(FUNC_NAME, THREAD_NUMBER) \ void FUNC_NAME(void* data) \ { \ for (;;) \ { \ if (priority_thread_context.need_draw[THREAD_NUMBER]) \ { \ priority_thread_context.need_draw[THREAD_NUMBER] = 0; \ TitanRenderSimplifiedCheck(priority_thread_context.dispbuffer, priority_thread_context.lines[THREAD_NUMBER].start, priority_thread_context.lines[THREAD_NUMBER].end, priority_thread_context.use_simplified); \ priority_thread_context.draw_finished[THREAD_NUMBER] = 1; \ } \ YabThreadSleep(); \ } \ } DECLARE_PRIORITY_THREAD(VidsoftPriorityThread0, 0); DECLARE_PRIORITY_THREAD(VidsoftPriorityThread1, 1); DECLARE_PRIORITY_THREAD(VidsoftPriorityThread2, 2); DECLARE_PRIORITY_THREAD(VidsoftPriorityThread3, 3); DECLARE_PRIORITY_THREAD(VidsoftPriorityThread4, 4); static u32 TitanBlendPixelsTop(u32 top, u32 bottom) { u8 alpha, ralpha, tr, tg, tb, br, bg, bb; alpha = (TitanGetAlpha(top) << 2) + 3; ralpha = 0xFF - alpha; tr = (TitanGetRed(top) * alpha) / 0xFF; tg = (TitanGetGreen(top) * alpha) / 0xFF; tb = (TitanGetBlue(top) * alpha) / 0xFF; br = (TitanGetRed(bottom) * ralpha) / 0xFF; bg = (TitanGetGreen(bottom) * ralpha) / 0xFF; bb = (TitanGetBlue(bottom) * ralpha) / 0xFF; return TitanCreatePixel(0x3F, tr + br, tg + bg, tb + bb); } static u32 TitanBlendPixelsBottom(u32 top, u32 bottom) { u8 alpha, ralpha, tr, tg, tb, br, bg, bb; if ((top & 0x80000000) == 0) return top; alpha = (TitanGetAlpha(bottom) << 2) + 3; ralpha = 0xFF - alpha; tr = (TitanGetRed(top) * alpha) / 0xFF; tg = (TitanGetGreen(top) * alpha) / 0xFF; tb = (TitanGetBlue(top) * alpha) / 0xFF; br = (TitanGetRed(bottom) * ralpha) / 0xFF; bg = (TitanGetGreen(bottom) * ralpha) / 0xFF; bb = (TitanGetBlue(bottom) * ralpha) / 0xFF; return TitanCreatePixel(TitanGetAlpha(top), tr + br, tg + bg, tb + bb); } static u32 TitanBlendPixelsAdd(u32 top, u32 bottom) { u32 r, g, b; r = TitanGetRed(top) + TitanGetRed(bottom); if (r > 0xFF) r = 0xFF; g = TitanGetGreen(top) + TitanGetGreen(bottom); if (g > 0xFF) g = 0xFF; b = TitanGetBlue(top) + TitanGetBlue(bottom); if (b > 0xFF) b = 0xFF; return TitanCreatePixel(0x3F, r, g, b); } static INLINE int FASTCALL TitanTransAlpha(u32 pixel) { return TitanGetAlpha(pixel) < 0x3F; } static INLINE int FASTCALL TitanTransBit(u32 pixel) { return pixel & 0x80000000; } static u32 TitanDigPixel(int pos, int y) { struct PixelData pixel_stack[2] = { 0 }; int pixel_stack_pos = 0; int priority; //sort the pixels from highest to lowest priority for (priority = 7; priority > 0; priority--) { int which_layer; for (which_layer = TITAN_SPRITE; which_layer >= 0; which_layer--) { if (tt_context.vdp2framebuffer[which_layer][pos].priority == priority) { pixel_stack[pixel_stack_pos] = tt_context.vdp2framebuffer[which_layer][pos]; pixel_stack_pos++; if (pixel_stack_pos == 2) goto finished;//backscreen is unnecessary in this case } } } pixel_stack[pixel_stack_pos] = tt_context.backscreen[pos]; finished: if (pixel_stack[0].linescreen) { pixel_stack[0].pixel = tt_context.blend(pixel_stack[0].pixel, tt_context.linescreen[pixel_stack[0].linescreen][y]); } if ((pixel_stack[0].shadow_type == TITAN_MSB_SHADOW) && ((pixel_stack[0].pixel & 0xFFFFFF) == 0)) { //transparent sprite shadow if (pixel_stack[1].shadow_enabled) { pixel_stack[0].pixel = TitanBlendPixelsTop(0x20000000, pixel_stack[1].pixel); } else { pixel_stack[0].pixel = pixel_stack[1].pixel; } } else if (pixel_stack[0].shadow_type == TITAN_MSB_SHADOW && ((pixel_stack[0].pixel & 0xFFFFFF) != 0)) { if (tt_context.trans(pixel_stack[0].pixel)) { u32 bottom = pixel_stack[1].pixel; pixel_stack[0].pixel = tt_context.blend(pixel_stack[0].pixel, bottom); } //sprite self-shadowing, only if sprite window is not enabled if (!(Vdp2Regs->SPCTL & 0x10)) pixel_stack[0].pixel = TitanBlendPixelsTop(0x20000000, pixel_stack[0].pixel); } else if (pixel_stack[0].shadow_type == TITAN_NORMAL_SHADOW) { if (pixel_stack[1].shadow_enabled) { pixel_stack[0].pixel = TitanBlendPixelsTop(0x20000000, pixel_stack[1].pixel); } else { pixel_stack[0].pixel = pixel_stack[1].pixel; } } else { if (tt_context.trans(pixel_stack[0].pixel)) { u32 bottom = pixel_stack[1].pixel; pixel_stack[0].pixel = tt_context.blend(pixel_stack[0].pixel, bottom); } } return pixel_stack[0].pixel; } /* public */ int TitanInit() { int i; if (! tt_context.inited) { for(i = 0;i < 6;i++) { if ((tt_context.vdp2framebuffer[i] = (struct PixelData *)calloc(sizeof(struct PixelData), 704 * 256)) == NULL) return -1; } /* linescreen 0 is not initialized as it's not used... */ for(i = 1;i < 4;i++) { if ((tt_context.linescreen[i] = (u32 *)calloc(sizeof(u32), 512)) == NULL) return -1; } if ((tt_context.backscreen = (struct PixelData *)calloc(sizeof(struct PixelData), 704 * 512)) == NULL) return -1; for (i = 0; i < 5; i++) { priority_thread_context.draw_finished[i] = 1; priority_thread_context.need_draw[i] = 0; } YabThreadStart(YAB_THREAD_VIDSOFT_PRIORITY_0, VidsoftPriorityThread0, NULL); YabThreadStart(YAB_THREAD_VIDSOFT_PRIORITY_1, VidsoftPriorityThread1, NULL); YabThreadStart(YAB_THREAD_VIDSOFT_PRIORITY_2, VidsoftPriorityThread2, NULL); YabThreadStart(YAB_THREAD_VIDSOFT_PRIORITY_3, VidsoftPriorityThread3, NULL); YabThreadStart(YAB_THREAD_VIDSOFT_PRIORITY_4, VidsoftPriorityThread4, NULL); tt_context.inited = 1; } for(i = 0;i < 6;i++) memset(tt_context.vdp2framebuffer[i], 0, sizeof(u32) * 704 * 256); for(i = 1;i < 4;i++) memset(tt_context.linescreen[i], 0, sizeof(u32) * 512); return 0; } void TitanErase() { int i = 0; int height = tt_context.vdp2height; if (vdp2_interlace) height /= 2; for (i = 0; i < 6; i++) memset(tt_context.vdp2framebuffer[i], 0, sizeof(struct PixelData) * tt_context.vdp2width * height); } int TitanDeInit() { int i; for(i = 0;i < 6;i++) free(tt_context.vdp2framebuffer[i]); for(i = 1;i < 4;i++) free(tt_context.linescreen[i]); return 0; } void TitanSetResolution(int width, int height) { tt_context.vdp2width = width; tt_context.vdp2height = height; } void TitanGetResolution(int * width, int * height) { *width = tt_context.vdp2width; *height = tt_context.vdp2height; } void TitanSetBlendingMode(int blend_mode) { if (blend_mode == TITAN_BLEND_BOTTOM) { tt_context.blend = TitanBlendPixelsBottom; tt_context.trans = TitanTransBit; } else if (blend_mode == TITAN_BLEND_ADD) { tt_context.blend = TitanBlendPixelsAdd; tt_context.trans = TitanTransBit; } else { tt_context.blend = TitanBlendPixelsTop; tt_context.trans = TitanTransAlpha; } } void TitanPutBackHLine(s32 y, u32 color) { struct PixelData* buffer = &tt_context.backscreen[(y * tt_context.vdp2width)]; int i; for (i = 0; i < tt_context.vdp2width; i++) buffer[i].pixel = color; } void TitanPutLineHLine(int linescreen, s32 y, u32 color) { if (linescreen == 0) return; { u32 * buffer = tt_context.linescreen[linescreen] + y; *buffer = color; } } void TitanPutPixel(int priority, s32 x, s32 y, u32 color, int linescreen, vdp2draw_struct* info) { if (priority == 0) return; { int pos = (y * tt_context.vdp2width) + x; tt_context.vdp2framebuffer[info->titan_which_layer][pos].pixel = color; tt_context.vdp2framebuffer[info->titan_which_layer][pos].priority = priority; tt_context.vdp2framebuffer[info->titan_which_layer][pos].linescreen = linescreen; tt_context.vdp2framebuffer[info->titan_which_layer][pos].shadow_enabled = info->titan_shadow_enabled; tt_context.vdp2framebuffer[info->titan_which_layer][pos].shadow_type = info->titan_shadow_type; } } void TitanPutHLine(int priority, s32 x, s32 y, s32 width, u32 color) { if (priority == 0) return; { struct PixelData * buffer = &tt_context.vdp2framebuffer[priority][ (y * tt_context.vdp2width) + x]; int i; for (i = 0; i < width; i++) buffer[i].pixel = color; } } void TitanRenderLines(pixel_t * dispbuffer, int start_line, int end_line) { int x, y, layer_y; u32 dot; int line_increment, interlace_line; if (!tt_context.inited || (!tt_context.trans)) { return; } Vdp2GetInterlaceInfo(&interlace_line, &line_increment); set_layer_y(start_line, &layer_y); for (y = start_line + interlace_line; y < end_line; y += line_increment) { for (x = 0; x < tt_context.vdp2width; x++) { int i = (y * tt_context.vdp2width) + x; int layer_pos = (layer_y * tt_context.vdp2width) + x; dispbuffer[i] = 0; dot = TitanDigPixel(layer_pos, y); if (dot) { dispbuffer[i] = TitanFixAlpha(dot); } } layer_y++; } } //num + 1 needs to be an even number to avoid issues with interlace modes void VIDSoftSetNumPriorityThreads(int num) { vidsoft_num_priority_threads = num > 5 ? 5 : num; if (num == 2) vidsoft_num_priority_threads = 1; if (num == 4) vidsoft_num_priority_threads = 3; } void TitanStartPriorityThread(int which) { priority_thread_context.need_draw[which] = 1; priority_thread_context.draw_finished[which] = 0; YabThreadWake(YAB_THREAD_VIDSOFT_PRIORITY_0 + which); } void TitanWaitForPriorityThread(int which) { while (!priority_thread_context.draw_finished[which]){} } void TitanRenderThreads(pixel_t * dispbuffer, int can_use_simplified) { int i; int total_jobs = vidsoft_num_priority_threads + 1;//main thread runs a job int num_lines_per_job = tt_context.vdp2height / total_jobs; int remainder = tt_context.vdp2height % total_jobs; int starts[6] = { 0 }; int ends[6] = { 0 }; priority_thread_context.dispbuffer = dispbuffer; priority_thread_context.use_simplified = can_use_simplified; for (i = 0; i < total_jobs; i++) { starts[i] = num_lines_per_job * i; ends[i] = ((i + 1) * num_lines_per_job); } for (i = 0; i < vidsoft_num_priority_threads; i++) { priority_thread_context.lines[i].start = starts[i+1]; priority_thread_context.lines[i].end = ends[i+1]; } //put any remaining lines on the last thread priority_thread_context.lines[vidsoft_num_priority_threads - 1].end += remainder; for (i = 0; i < vidsoft_num_priority_threads; i++) { TitanStartPriorityThread(i); } TitanRenderSimplifiedCheck(dispbuffer, starts[0], ends[0], can_use_simplified); for (i = 0; i < vidsoft_num_priority_threads; i++) { TitanWaitForPriorityThread(i); } } void TitanRender(pixel_t * dispbuffer) { int can_use_simplified_rendering = 1; if (!tt_context.inited || (!tt_context.trans)) { return; } //using color calculation if ((Vdp2Regs->CCCTL & 0x807f) != 0) can_use_simplified_rendering = 0; //using special priority if ((Vdp2Regs->SFPRMD & 0x3ff) != 0) can_use_simplified_rendering = 0; //using line screen if ((Vdp2Regs->LNCLEN & 0x1f) != 0) can_use_simplified_rendering = 0; //using shadow if ((Vdp2Regs->SDCTL & 0x13F) != 0) can_use_simplified_rendering = 0; tt_context.layer_priority[TITAN_NBG0] = Vdp2Regs->PRINA & 0x7; tt_context.layer_priority[TITAN_NBG1] = ((Vdp2Regs->PRINA >> 8) & 0x7); tt_context.layer_priority[TITAN_NBG2] = (Vdp2Regs->PRINB & 0x7); tt_context.layer_priority[TITAN_NBG3] = ((Vdp2Regs->PRINB >> 8) & 0x7); tt_context.layer_priority[TITAN_RBG0] = (Vdp2Regs->PRIR & 0x7); if (vidsoft_num_priority_threads > 0) { TitanRenderThreads(dispbuffer, can_use_simplified_rendering); } else { TitanRenderSimplifiedCheck(dispbuffer, 0, tt_context.vdp2height, can_use_simplified_rendering); } } #ifdef WORDS_BIGENDIAN void TitanWriteColor(pixel_t * dispbuffer, s32 bufwidth, s32 x, s32 y, u32 color) { int pos = (y * bufwidth) + x; pixel_t * buffer = dispbuffer + pos; *buffer = ((color >> 24) & 0xFF) | ((color >> 8) & 0xFF00) | ((color & 0xFF00) << 8) | ((color & 0xFF) << 24); } #else void TitanWriteColor(pixel_t * dispbuffer, s32 bufwidth, s32 x, s32 y, u32 color) { int pos = (y * bufwidth) + x; pixel_t * buffer = dispbuffer + pos; *buffer = color; } #endif yabause-0.9.15/src/yabause.c000755 001750 001750 00000110000 12757373537 017653 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2005 Guillaume Duhamel Copyright 2004-2006 Theo Berkau Copyright 2006 Anders Montonen This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file yabause.c \brief Yabause main emulation functions and interface for the ports */ #include #ifdef WIN32 #include #endif #include #include "yabause.h" #include "cheat.h" #include "cs0.h" #include "cs2.h" #include "debug.h" #include "error.h" #include "memory.h" #include "m68kcore.h" #include "peripheral.h" #include "scsp.h" #include "scspdsp.h" #include "scu.h" #include "sh2core.h" #include "smpc.h" #include "vidsoft.h" #include "vdp2.h" #include "yui.h" #include "bios.h" #include "movie.h" #include "osdcore.h" #ifdef HAVE_LIBSDL #if defined(__APPLE__) || defined(GEKKO) #ifdef HAVE_LIBSDL2 #include #else #include #endif #else #include "SDL.h" #endif #endif #if defined(_MSC_VER) || !defined(HAVE_SYS_TIME_H) #include #else #include #endif #ifdef _arch_dreamcast #include #endif #ifdef GEKKO #include #endif #ifdef PSP #include "psp/common.h" #endif #ifdef SYS_PROFILE_H #include SYS_PROFILE_H #else #define DONT_PROFILE #include "profile.h" #endif #if defined(SH2_DYNAREC) #include "sh2_dynarec/sh2_dynarec.h" #endif #if HAVE_GDBSTUB #include "gdb/stub.h" #endif #ifdef YAB_WANT_SSF #include "aosdk/ssf.h" #endif #include "sh7034.h" #include "cd_drive.h" #include "tsunami/yab_tsunami.h" #include "mpeg_card.h" ////////////////////////////////////////////////////////////////////////////// yabsys_struct yabsys; const char *bupfilename = NULL; u64 tickfreq; //todo this ought to be in scspdsp.c ScspDsp scsp_dsp = { 0 }; char ssf_track_name[256] = { 0 }; char ssf_artist[256] = { 0 }; #define SCSP_FRACTIONAL_BITS 20 u32 saved_scsp_cycles = 0;//fixed point u32 saved_m68k_cycles = 0;//fixed point u32 saved_sh1_cycles = 0; u32 saved_cdd_cycles = 0; ////////////////////////////////////////////////////////////////////////////// #ifndef NO_CLI void print_usage(const char *program_name) { printf("Yabause v" VERSION "\n"); printf("\n" "Purpose:\n" " This program is intended to be a Sega Saturn emulator\n" "\n" "Usage: %s [OPTIONS]...\n", program_name); printf(" -h --help Print help and exit\n"); printf(" -b STRING --bios=STRING bios file\n"); printf(" -i STRING --iso=STRING iso/cue file\n"); printf(" -c STRING --cdrom=STRING cdrom path\n"); printf(" -ns --nosound turn sound off\n"); printf(" -a --autostart autostart emulation\n"); printf(" -f --fullscreen start in fullscreen mode\n"); } #endif ////////////////////////////////////////////////////////////////////////////// void YabauseChangeTiming(int freqtype) { // Setup all the variables related to timing const double freq_base = yabsys.IsPal ? 28437500.0 : (39375000.0 / 11.0) * 8.0; // i.e. 8 * 3.579545... = 28.636363... MHz const double freq_mult = (freqtype == CLKTYPE_26MHZ) ? 15.0/16.0 : 1.0; const double freq_shifted = (freq_base * freq_mult) * (1 << YABSYS_TIMING_BITS); const double usec_shifted = 1.0e6 * (1 << YABSYS_TIMING_BITS); const double deciline_time = yabsys.IsPal ? 1.0 / 50 / 313 / 10 : 1.0 / (60/1.001) / 263 / 10; yabsys.DecilineCount = 0; yabsys.LineCount = 0; yabsys.CurSH2FreqType = freqtype; yabsys.DecilineStop = (u32) (freq_shifted * deciline_time + 0.5); yabsys.SH2CycleFrac = 0; yabsys.DecilineUsec = (u32) (usec_shifted * deciline_time + 0.5); yabsys.UsecFrac = 0; } ////////////////////////////////////////////////////////////////////////////// int YabauseInit(yabauseinit_struct *init) { tsunami_init(); // Need to set this first, so init routines see it yabsys.UseThreads = init->usethreads; yabsys.NumThreads = init->numthreads; yabsys.use_cd_block_lle = init->use_cd_block_lle; if (yabsys.use_cd_block_lle) { yabsys.use_sh2_dma_timing = 1; yabsys.use_scu_dma_timing = 1; yabsys.sh2_cache_enabled = 1; } else { yabsys.use_sh2_dma_timing = init->use_sh2_dma_timing; yabsys.use_scu_dma_timing = init->use_scu_dma_timing; yabsys.sh2_cache_enabled = init->sh2_cache_enabled; } // Initialize both cpu's if (SH2Init(init->sh2coretype) != 0) { YabSetError(YAB_ERR_CANNOTINIT, _("SH2")); return -1; } if ((BiosRom = T2MemoryInit(0x80000)) == NULL) return -1; if ((HighWram = T2MemoryInit(0x100000)) == NULL) return -1; if ((LowWram = T2MemoryInit(0x100000)) == NULL) return -1; if ((BupRam = T1MemoryInit(0x10000)) == NULL) return -1; if (LoadBackupRam(init->buppath) != 0) FormatBackupRam(BupRam, 0x10000); BupRamWritten = 0; bupfilename = init->buppath; if (CartInit(init->cartpath, init->carttype) != 0) { YabSetError(YAB_ERR_CANNOTINIT, _("Cartridge")); return -1; } if (VideoInit(init->vidcoretype) != 0) { YabSetError(YAB_ERR_CANNOTINIT, _("Video")); return -1; } // Initialize input core if (PerInit(init->percoretype) != 0) { YabSetError(YAB_ERR_CANNOTINIT, _("Peripheral")); return -1; } if ((SH1Rom = T2MemoryInit(0x10000)) == NULL) return -1; if ((SH1Dram = T2MemoryInit(0x80000)) == NULL) return -1; if ((SH1MpegRom = T2MemoryInit(0x80000)) == NULL) return -1; // Initialize CD Block if (init->use_cd_block_lle) { #if defined(SH2_DYNAREC) if (init->sh1coretype == SH2CORE_DYNAREC) { YabSetError(YAB_ERR_CANNOTINIT, _("SH1. Dynarec core not supported for SH1 emulation.")); return -1; } #endif if (SH1Init(init->sh1coretype) != 0) { YabSetError(YAB_ERR_CANNOTINIT, _("SH1")); return -1; } else { if (init->sh1rompath != NULL && strlen(init->sh1rompath)) { if (LoadSH1Rom(init->sh1rompath) != 0) { YabSetError(YAB_ERR_FILENOTFOUND, (void *)init->sh1rompath); return -2; } } else { YabSetError(YAB_ERR_CANNOTINIT, _("CD Block. It needs a SH1 ROM Defined.")); return -1; } if (init->mpegpath != NULL && strlen(init->mpegpath)) { if (LoadMpegRom(init->mpegpath) != 0) { YabSetError(YAB_ERR_FILENOTFOUND, (void *)init->mpegpath); return -2; } } } } if (Cs2Init(init->carttype, init->cdcoretype, init->cdpath, init->mpegpath, init->modemip, init->modemport) != 0) { YabSetError(YAB_ERR_CANNOTINIT, _("CS2")); return -1; } if (ScuInit() != 0) { YabSetError(YAB_ERR_CANNOTINIT, _("SCU")); return -1; } if (M68KInit(init->m68kcoretype) != 0) { YabSetError(YAB_ERR_CANNOTINIT, _("M68K")); return -1; } if (ScspInit(init->sndcoretype) != 0) { YabSetError(YAB_ERR_CANNOTINIT, _("SCSP/M68K")); return -1; } if (Vdp1Init() != 0) { YabSetError(YAB_ERR_CANNOTINIT, _("VDP1")); return -1; } if (Vdp2Init() != 0) { YabSetError(YAB_ERR_CANNOTINIT, _("VDP2")); return -1; } if (SmpcInit(init->regionid, init->clocksync, init->basetime) != 0) { YabSetError(YAB_ERR_CANNOTINIT, _("SMPC")); return -1; } if (CheatInit() != 0) { YabSetError(YAB_ERR_CANNOTINIT, _("Cheat System")); return -1; } MappedMemoryInit(MSH2, SSH2, SH1); YabauseSetVideoFormat(init->videoformattype); YabauseChangeTiming(CLKTYPE_26MHZ); yabsys.DecilineMode = 1; if (init->frameskip) EnableAutoFrameSkip(); #ifdef YAB_PORT_OSD OSDChangeCore(init->osdcoretype); #else OSDChangeCore(OSDCORE_DEFAULT); #endif if (init->biospath != NULL && strlen(init->biospath)) { if (LoadBios(init->biospath) != 0) { YabSetError(YAB_ERR_FILENOTFOUND, (void *)init->biospath); return -2; } yabsys.emulatebios = 0; } else yabsys.emulatebios = 1; if (yabsys.emulatebios && yabsys.use_cd_block_lle) { YabSetError(YAB_ERR_CANNOTINIT, _("CD Block. A real bios must be defined and enabled for CD Block LLE. Emulated bios not supported.")); return -1; } yabsys.usequickload = 0; #if defined(SH2_DYNAREC) if(SH2Core->id==2) { sh2_dynarec_init(); } #endif YabauseResetNoLoad(); #ifdef YAB_WANT_SSF if (init->play_ssf && init->ssfpath != NULL && strlen(init->ssfpath)) { if (!load_ssf((char*)init->ssfpath, init->m68kcoretype, init->sndcoretype)) { YabSetError(YAB_ERR_FILENOTFOUND, (void *)init->ssfpath); yabsys.playing_ssf = 0; return -2; } yabsys.playing_ssf = 1; get_ssf_info(1, ssf_track_name); get_ssf_info(3, ssf_artist); return 0; } else yabsys.playing_ssf = 0; #endif if (init->skip_load) { return 0; } if (yabsys.usequickload || yabsys.emulatebios) { if (YabauseQuickLoadGame() != 0) { if (yabsys.emulatebios) { YabSetError(YAB_ERR_CANNOTINIT, _("Game")); return -2; } else YabauseResetNoLoad(); } } #ifdef HAVE_GDBSTUB GdbStubInit(MSH2, 43434); #endif if (yabsys.UseThreads) { int num = yabsys.NumThreads < 1 ? 1 : yabsys.NumThreads; VIDSoftSetVdp1ThreadEnable(num == 1 ? 0 : 1); VIDSoftSetNumLayerThreads(num); VIDSoftSetNumPriorityThreads(num); } else { VIDSoftSetVdp1ThreadEnable(0); VIDSoftSetNumLayerThreads(0); VIDSoftSetNumPriorityThreads(0); } scsp_set_use_new(init->use_new_scsp); return 0; } ////////////////////////////////////////////////////////////////////////////// void YabFlushBackups(void) { if (BupRam) { if (T123Save(BupRam, 0x10000, 1, bupfilename) != 0) YabSetError(YAB_ERR_FILEWRITE, (void *)bupfilename); } CartFlush(); } ////////////////////////////////////////////////////////////////////////////// void YabauseDeInit(void) { SH2DeInit(); if (BiosRom) T2MemoryDeInit(BiosRom); BiosRom = NULL; if (HighWram) T2MemoryDeInit(HighWram); HighWram = NULL; if (LowWram) T2MemoryDeInit(LowWram); LowWram = NULL; if (BupRam) { if (T123Save(BupRam, 0x10000, 1, bupfilename) != 0) YabSetError(YAB_ERR_FILEWRITE, (void *)bupfilename); T1MemoryDeInit(BupRam); } BupRam = NULL; CartDeInit(); Cs2DeInit(); ScuDeInit(); ScspDeInit(); Vdp1DeInit(); Vdp2DeInit(); SmpcDeInit(); PerDeInit(); VideoDeInit(); CheatDeInit(); } ////////////////////////////////////////////////////////////////////////////// void YabauseSetDecilineMode(int on) { yabsys.DecilineMode = (on != 0); } ////////////////////////////////////////////////////////////////////////////// void YabauseResetNoLoad(void) { SH2Reset(MSH2); YabauseStopSlave(); memset(HighWram, 0, 0x100000); memset(LowWram, 0, 0x100000); // Reset CS0 area here // Reset CS1 area here if (yabsys.use_cd_block_lle) SH2Reset(SH1); Cs2Reset(); ScuReset(); ScspReset(); Vdp1Reset(); Vdp2Reset(); SmpcReset(); SH2PowerOn(MSH2); if (yabsys.use_cd_block_lle) { sh1_init_func(); SH2PowerOn(SH1); } } ////////////////////////////////////////////////////////////////////////////// void YabauseReset(void) { if (yabsys.playing_ssf) yabsys.playing_ssf = 0; YabauseResetNoLoad(); if (yabsys.usequickload || yabsys.emulatebios) { if (YabauseQuickLoadGame() != 0) { if (yabsys.emulatebios) YabSetError(YAB_ERR_CANNOTINIT, _("Game")); else YabauseResetNoLoad(); } } } ////////////////////////////////////////////////////////////////////////////// void YabauseResetButton(void) { // This basically emulates the reset button behaviour of the saturn. This // is the better way of reseting the system since some operations (like // backup ram access) shouldn't be interrupted and this allows for that. SmpcResetButton(); } ////////////////////////////////////////////////////////////////////////////// int YabauseExec(void) { //automatically advance lag frames, this should be optional later if (FrameAdvanceVariable > 0 && LagFrameFlag == 1){ FrameAdvanceVariable = NeedAdvance; //advance a frame YabauseEmulate(); FrameAdvanceVariable = Paused; //pause next time return(0); } if (FrameAdvanceVariable == Paused){ ScspMuteAudio(SCSP_MUTE_SYSTEM); return(0); } if (FrameAdvanceVariable == NeedAdvance){ //advance a frame FrameAdvanceVariable = Paused; //pause next time ScspUnMuteAudio(SCSP_MUTE_SYSTEM); YabauseEmulate(); } if (FrameAdvanceVariable == RunNormal ) { //run normally ScspUnMuteAudio(SCSP_MUTE_SYSTEM); YabauseEmulate(); } return 0; } ////////////////////////////////////////////////////////////////////////////// #ifndef USE_SCSP2 int saved_centicycles; #endif static INLINE u32 get_cycles_per_line_division(u32 clock, int frames, int lines, int divisions_per_line) { return ((u64)(clock / frames) << SCSP_FRACTIONAL_BITS) / (lines * divisions_per_line); } int YabauseEmulate(void) { int oneframeexec = 0; const u32 cyclesinc = yabsys.DecilineMode ? yabsys.DecilineStop : yabsys.DecilineStop * 10; const u32 usecinc = yabsys.DecilineMode ? yabsys.DecilineUsec : yabsys.DecilineUsec * 10; #ifndef USE_SCSP2 unsigned int m68kcycles; // Integral M68k cycles per call unsigned int m68kcenticycles; // 1/100 M68k cycles per call u32 m68k_cycles_per_deciline, scsp_cycles_per_deciline, sh1_cycles_per_deciline, cdd_cycles_per_deciline; int lines, frames = 0; m68k_cycles_per_deciline = 0; scsp_cycles_per_deciline = 0; sh1_cycles_per_deciline = 0; lines = 0; frames = 0; if (yabsys.IsPal) { lines = 313; frames = 50; } else { lines = 263; frames = 60; } if (yabsys.use_cd_block_lle) { sh1_cycles_per_deciline = get_cycles_per_line_division(20 * 1000000, frames, lines, 10);//20mhz cdd_cycles_per_deciline = get_cycles_per_line_division(1000000, frames, lines, 10);//timing is now in usec } if(use_new_scsp) { scsp_cycles_per_deciline = get_cycles_per_line_division(44100 * 512, frames, lines, 10); m68k_cycles_per_deciline = get_cycles_per_line_division(44100 * 256, frames, lines, 10); } else { if (yabsys.IsPal) { /* 11.2896MHz / 50Hz / 313 lines / 10 calls/line = 72.20 cycles/call */ m68kcycles = yabsys.DecilineMode ? 72 : 722; m68kcenticycles = yabsys.DecilineMode ? 20 : 0; } else { /* 11.2896MHz / 60Hz / 263 lines / 10 calls/line = 71.62 cycles/call */ m68kcycles = yabsys.DecilineMode ? 71 : 716; m68kcenticycles = yabsys.DecilineMode ? 62 : 20; } } #endif DoMovie(); #if defined(SH2_DYNAREC) if(SH2Core->id==2) { if (yabsys.IsPal) YabauseDynarecOneFrameExec(722,0); // m68kcycles,m68kcenticycles else YabauseDynarecOneFrameExec(716,20); return 0; } #endif while (!oneframeexec) { PROFILE_START("Total Emulation"); if (yabsys.DecilineMode) { // Since we run the SCU with half the number of cycles we send // to SH2Exec(), we always compute an even number of cycles here // and leave any odd remainder in SH2CycleFrac. u32 sh2cycles; yabsys.SH2CycleFrac += cyclesinc; sh2cycles = (yabsys.SH2CycleFrac >> (YABSYS_TIMING_BITS + 1)) << 1; yabsys.SH2CycleFrac &= ((YABSYS_TIMING_MASK << 1) | 1); if (!yabsys.playing_ssf) { PROFILE_START("MSH2"); SH2Exec(MSH2, sh2cycles); PROFILE_STOP("MSH2"); PROFILE_START("SSH2"); if (yabsys.IsSSH2Running) SH2Exec(SSH2, sh2cycles); PROFILE_STOP("SSH2"); } #ifdef USE_SCSP2 PROFILE_START("SCSP"); ScspExec(1); PROFILE_STOP("SCSP"); #endif yabsys.DecilineCount++; if(yabsys.DecilineCount == 9) { // HBlankIN PROFILE_START("hblankin"); Vdp2HBlankIN(); PROFILE_STOP("hblankin"); } PROFILE_START("SCU"); ScuExec(sh2cycles); PROFILE_STOP("SCU"); } else { // !DecilineMode const u32 decilinecycles = yabsys.DecilineStop >> YABSYS_TIMING_BITS; u32 sh2cycles; yabsys.SH2CycleFrac += cyclesinc; sh2cycles = (yabsys.SH2CycleFrac >> (YABSYS_TIMING_BITS + 1)) << 1; yabsys.SH2CycleFrac &= ((YABSYS_TIMING_MASK << 1) | 1); if (!yabsys.playing_ssf) { PROFILE_START("MSH2"); SH2Exec(MSH2, sh2cycles - decilinecycles); PROFILE_STOP("MSH2"); PROFILE_START("SSH2"); if (yabsys.IsSSH2Running) SH2Exec(SSH2, sh2cycles - decilinecycles); PROFILE_STOP("SSH2"); } PROFILE_START("hblankin"); Vdp2HBlankIN(); PROFILE_STOP("hblankin"); if (!yabsys.playing_ssf) { PROFILE_START("MSH2"); SH2Exec(MSH2, decilinecycles); PROFILE_STOP("MSH2"); PROFILE_START("SSH2"); if (yabsys.IsSSH2Running) SH2Exec(SSH2, decilinecycles); PROFILE_STOP("SSH2"); } #ifdef USE_SCSP2 PROFILE_START("SCSP"); ScspExec(10); PROFILE_STOP("SCSP"); #endif PROFILE_START("SCU"); ScuExec(sh2cycles); PROFILE_STOP("SCU"); } // if (yabsys.DecilineMode) #ifndef USE_SCSP2 PROFILE_START("68K"); M68KSync(); // Wait for the previous iteration to finish PROFILE_STOP("68K"); #endif if (!yabsys.DecilineMode || yabsys.DecilineCount == 10) { // HBlankOUT PROFILE_START("hblankout"); Vdp2HBlankOUT(); PROFILE_STOP("hblankout"); #ifndef USE_SCSP2 PROFILE_START("SCSP"); ScspExec(); PROFILE_STOP("SCSP"); #endif yabsys.DecilineCount = 0; yabsys.LineCount++; if (yabsys.LineCount == yabsys.VBlankLineCount) { PROFILE_START("vblankin"); // VBlankIN SmpcINTBACKEnd(); Vdp2VBlankIN(); PROFILE_STOP("vblankin"); CheatDoPatches(); } else if (yabsys.LineCount == yabsys.MaxLineCount) { // VBlankOUT PROFILE_START("VDP1/VDP2"); Vdp2VBlankOUT(); set_mpeg_video_irq();//guessing: set video irq once per frame yabsys.LineCount = 0; oneframeexec = 1; PROFILE_STOP("VDP1/VDP2"); } } yabsys.UsecFrac += usecinc; PROFILE_START("SMPC"); SmpcExec(yabsys.UsecFrac >> YABSYS_TIMING_BITS); PROFILE_STOP("SMPC"); PROFILE_START("CDB"); Cs2Exec(yabsys.UsecFrac >> YABSYS_TIMING_BITS); PROFILE_STOP("CDB"); yabsys.UsecFrac &= YABSYS_TIMING_MASK; #ifndef USE_SCSP2 if(!use_new_scsp) { int cycles; PROFILE_START("68K"); cycles = m68kcycles; saved_centicycles += m68kcenticycles; if (saved_centicycles >= 100) { cycles++; saved_centicycles -= 100; } M68KExec(cycles); PROFILE_STOP("68K"); } else { u32 m68k_integer_part = 0, scsp_integer_part = 0; saved_m68k_cycles += m68k_cycles_per_deciline; m68k_integer_part = saved_m68k_cycles >> SCSP_FRACTIONAL_BITS; M68KExec(m68k_integer_part); saved_m68k_cycles -= m68k_integer_part << SCSP_FRACTIONAL_BITS; saved_scsp_cycles += scsp_cycles_per_deciline; scsp_integer_part = saved_scsp_cycles >> SCSP_FRACTIONAL_BITS; new_scsp_exec(scsp_integer_part); saved_scsp_cycles -= scsp_integer_part << SCSP_FRACTIONAL_BITS; } #endif if(yabsys.use_cd_block_lle) { u32 sh1_integer_part = 0; u32 cdd_integer_part = 0; saved_sh1_cycles += sh1_cycles_per_deciline; sh1_integer_part = saved_sh1_cycles >> SCSP_FRACTIONAL_BITS; //sh1_exec(&sh1_cxt, sh1_integer_part); SH2Exec(SH1, sh1_integer_part); saved_sh1_cycles -= sh1_integer_part << SCSP_FRACTIONAL_BITS; saved_cdd_cycles += cdd_cycles_per_deciline; cdd_integer_part = saved_cdd_cycles >> SCSP_FRACTIONAL_BITS; cd_drive_exec(&cdd_cxt, cdd_integer_part); saved_cdd_cycles -= cdd_integer_part << SCSP_FRACTIONAL_BITS; } PROFILE_STOP("Total Emulation"); } #ifndef USE_SCSP2 M68KSync(); #endif #ifdef YAB_WANT_SSF if (yabsys.playing_ssf) { OSDPushMessage(OSDMSG_FPS, 1, "NAME %s", ssf_track_name); OSDPushMessage(OSDMSG_STATUS, 1, "ARTIST %s", ssf_artist); } #endif //flush tsunami output once per frame tsunami_flush(); return 0; } ////////////////////////////////////////////////////////////////////////////// void YabauseStartSlave(void) { if (yabsys.emulatebios) { SSH2->MappedMemoryWriteLong(SSH2, 0xFFFFFFE0, 0xA55A03F1); // BCR1 SSH2->MappedMemoryWriteLong(SSH2, 0xFFFFFFE4, 0xA55A00FC); // BCR2 SSH2->MappedMemoryWriteLong(SSH2, 0xFFFFFFE8, 0xA55A5555); // WCR SSH2->MappedMemoryWriteLong(SSH2, 0xFFFFFFEC, 0xA55A0070); // MCR SSH2->MappedMemoryWriteWord(SSH2, 0xFFFFFEE0, 0x0000); // ICR SSH2->MappedMemoryWriteWord(SSH2, 0xFFFFFEE2, 0x0000); // IPRA SSH2->MappedMemoryWriteWord(SSH2, 0xFFFFFE60, 0x0F00); // VCRWDT SSH2->MappedMemoryWriteWord(SSH2, 0xFFFFFE62, 0x6061); // VCRA SSH2->MappedMemoryWriteWord(SSH2, 0xFFFFFE64, 0x6263); // VCRB SSH2->MappedMemoryWriteWord(SSH2, 0xFFFFFE66, 0x6465); // VCRC SSH2->MappedMemoryWriteWord(SSH2, 0xFFFFFE68, 0x6600); // VCRD SSH2->MappedMemoryWriteWord(SSH2, 0xFFFFFEE4, 0x6869); // VCRWDT SSH2->MappedMemoryWriteLong(SSH2, 0xFFFFFFA8, 0x0000006C); // VCRDMA1 SSH2->MappedMemoryWriteLong(SSH2, 0xFFFFFFA0, 0x0000006D); // VCRDMA0 SSH2->MappedMemoryWriteLong(SSH2, 0xFFFFFF0C, 0x0000006E); // VCRDIV SSH2->MappedMemoryWriteLong(SSH2, 0xFFFFFE10, 0x00000081); // TIER SH2GetRegisters(SSH2, &SSH2->regs); SSH2->regs.R[15] = Cs2GetSlaveStackAdress(); SSH2->regs.VBR = 0x06000400; SSH2->regs.PC = MSH2->MappedMemoryReadLong(MSH2, 0x06000250); if (MSH2->MappedMemoryReadLong(MSH2, 0x060002AC) != 0) SSH2->regs.R[15] = MSH2->MappedMemoryReadLong(MSH2, 0x060002AC); SH2SetRegisters(SSH2, &SSH2->regs); } else SH2PowerOn(SSH2); yabsys.IsSSH2Running = 1; } ////////////////////////////////////////////////////////////////////////////// void YabauseStopSlave(void) { SH2Reset(SSH2); yabsys.IsSSH2Running = 0; } ////////////////////////////////////////////////////////////////////////////// u64 YabauseGetTicks(void) { #ifdef WIN32 u64 ticks; QueryPerformanceCounter((LARGE_INTEGER *)&ticks); return ticks; #elif defined(_arch_dreamcast) return (u64) timer_ms_gettime64(); #elif defined(GEKKO) return gettime(); #elif defined(PSP) return sceKernelGetSystemTimeWide(); #elif defined(HAVE_GETTIMEOFDAY) struct timeval tv; gettimeofday(&tv, NULL); return (u64)tv.tv_sec * 1000000 + tv.tv_usec; #elif defined(HAVE_LIBSDL) return (u64)SDL_GetTicks(); #endif } ////////////////////////////////////////////////////////////////////////////// void YabauseSetVideoFormat(int type) { yabsys.IsPal = type; yabsys.MaxLineCount = type ? 313 : 263; #ifdef WIN32 QueryPerformanceFrequency((LARGE_INTEGER *)&yabsys.tickfreq); #elif defined(_arch_dreamcast) yabsys.tickfreq = 1000; #elif defined(GEKKO) yabsys.tickfreq = secs_to_ticks(1); #elif defined(PSP) yabsys.tickfreq = 1000000; #elif defined(HAVE_GETTIMEOFDAY) yabsys.tickfreq = 1000000; #elif defined(HAVE_LIBSDL) yabsys.tickfreq = 1000; #endif yabsys.OneFrameTime = type ? (yabsys.tickfreq / 50) : (yabsys.tickfreq * 1001 / 60000); Vdp2Regs->TVSTAT = Vdp2Regs->TVSTAT | (type & 0x1); ScspChangeVideoFormat(type); YabauseChangeTiming(yabsys.CurSH2FreqType); lastticks = YabauseGetTicks(); } ////////////////////////////////////////////////////////////////////////////// void YabauseSpeedySetup(void) { u32 data; int i; if (yabsys.emulatebios) BiosInit(); else { // Setup the vector table area, etc.(all bioses have it at 0x00000600-0x00000810) for (i = 0; i < 0x210; i+=4) { data = MappedMemoryReadLongNocache(MSH2, 0x00000600+i); MappedMemoryWriteLongNocache(MSH2, 0x06000000+i, data); } // Setup the bios function pointers, etc.(all bioses have it at 0x00000820-0x00001100) for (i = 0; i < 0x8E0; i+=4) { data = MappedMemoryReadLongNocache(MSH2, 0x00000820+i); MappedMemoryWriteLongNocache(MSH2, 0x06000220+i, data); } // I'm not sure this is really needed for (i = 0; i < 0x700; i+=4) { data = MappedMemoryReadLongNocache(MSH2, 0x00001100+i); MappedMemoryWriteLongNocache(MSH2, 0x06001100+i, data); } // Fix some spots in 0x06000210-0x0600032C area MappedMemoryWriteLongNocache(MSH2, 0x06000234, 0x000002AC); MappedMemoryWriteLongNocache(MSH2, 0x06000238, 0x000002BC); MappedMemoryWriteLongNocache(MSH2, 0x0600023C, 0x00000350); MappedMemoryWriteLongNocache(MSH2, 0x06000240, 0x32524459); MappedMemoryWriteLongNocache(MSH2, 0x0600024C, 0x00000000); MappedMemoryWriteLongNocache(MSH2, 0x06000268, MappedMemoryReadLongNocache(MSH2, 0x00001344)); MappedMemoryWriteLongNocache(MSH2, 0x0600026C, MappedMemoryReadLongNocache(MSH2, 0x00001348)); MappedMemoryWriteLongNocache(MSH2, 0x0600029C, MappedMemoryReadLongNocache(MSH2, 0x00001354)); MappedMemoryWriteLongNocache(MSH2, 0x060002C4, MappedMemoryReadLongNocache(MSH2, 0x00001104)); MappedMemoryWriteLongNocache(MSH2, 0x060002C8, MappedMemoryReadLongNocache(MSH2, 0x00001108)); MappedMemoryWriteLongNocache(MSH2, 0x060002CC, MappedMemoryReadLongNocache(MSH2, 0x0000110C)); MappedMemoryWriteLongNocache(MSH2, 0x060002D0, MappedMemoryReadLongNocache(MSH2, 0x00001110)); MappedMemoryWriteLongNocache(MSH2, 0x060002D4, MappedMemoryReadLongNocache(MSH2, 0x00001114)); MappedMemoryWriteLongNocache(MSH2, 0x060002D8, MappedMemoryReadLongNocache(MSH2, 0x00001118)); MappedMemoryWriteLongNocache(MSH2, 0x060002DC, MappedMemoryReadLongNocache(MSH2, 0x0000111C)); MappedMemoryWriteLongNocache(MSH2, 0x06000328, 0x000004C8); MappedMemoryWriteLongNocache(MSH2, 0x0600032C, 0x00001800); // Fix SCU interrupts for (i = 0; i < 0x80; i+=4) MappedMemoryWriteLongNocache(MSH2, 0x06000A00+i, 0x0600083C); } // Set the cpu's, etc. to sane states // Set CD block to a sane state Cs2Area->reg.HIRQ = 0xFC1; Cs2Area->isdiskchanged = 0; Cs2Area->reg.CR1 = (Cs2Area->status << 8) | ((Cs2Area->options & 0xF) << 4) | (Cs2Area->repcnt & 0xF); Cs2Area->reg.CR2 = (Cs2Area->ctrladdr << 8) | Cs2Area->track; Cs2Area->reg.CR3 = (Cs2Area->index << 8) | ((Cs2Area->FAD >> 16) & 0xFF); Cs2Area->reg.CR4 = (u16) Cs2Area->FAD; Cs2Area->satauth = 4; // Set Master SH2 registers accordingly SH2GetRegisters(MSH2, &MSH2->regs); for (i = 0; i < 15; i++) MSH2->regs.R[i] = 0x00000000; MSH2->regs.R[15] = 0x06002000; MSH2->regs.SR.all = 0x00000000; MSH2->regs.GBR = 0x00000000; MSH2->regs.VBR = 0x06000000; MSH2->regs.MACH = 0x00000000; MSH2->regs.MACL = 0x00000000; MSH2->regs.PR = 0x00000000; SH2SetRegisters(MSH2, &MSH2->regs); // Set SCU registers to sane states ScuRegs->D1AD = ScuRegs->D2AD = 0; ScuRegs->D0EN = 0x101; ScuRegs->IST = 0x2006; ScuRegs->AIACK = 0x1; ScuRegs->ASR0 = ScuRegs->ASR1 = 0x1FF01FF0; ScuRegs->AREF = 0x1F; ScuRegs->RSEL = 0x1; // Set SMPC registers to sane states SmpcRegs->COMREG = 0x10; SmpcInternalVars->resd = 0; // Set VDP1 registers to sane states Vdp1Regs->EDSR = 3; Vdp1Regs->localX = 160; Vdp1Regs->localY = 112; Vdp1Regs->systemclipX2 = 319; Vdp1Regs->systemclipY2 = 223; // Set VDP2 registers to sane states memset(Vdp2Regs, 0, sizeof(Vdp2)); Vdp2Regs->TVMD = 0x8000; Vdp2Regs->TVSTAT = 0x020A; Vdp2Regs->CYCA0L = 0x0F44; Vdp2Regs->CYCA0U = 0xFFFF; Vdp2Regs->CYCA1L = 0xFFFF; Vdp2Regs->CYCA1U = 0xFFFF; Vdp2Regs->CYCB0L = 0xFFFF; Vdp2Regs->CYCB0U = 0xFFFF; Vdp2Regs->CYCB1L = 0xFFFF; Vdp2Regs->CYCB1U = 0xFFFF; Vdp2Regs->BGON = 0x0001; Vdp2Regs->PNCN0 = 0x8000; Vdp2Regs->MPABN0 = 0x0303; Vdp2Regs->MPCDN0 = 0x0303; Vdp2Regs->ZMXN0.all = 0x00010000; Vdp2Regs->ZMYN0.all = 0x00010000; Vdp2Regs->ZMXN1.all = 0x00010000; Vdp2Regs->ZMYN1.all = 0x00010000; Vdp2Regs->BKTAL = 0x4000; Vdp2Regs->SPCTL = 0x0020; Vdp2Regs->PRINA = 0x0007; Vdp2Regs->CLOFEN = 0x0001; Vdp2Regs->COAR = 0x0200; Vdp2Regs->COAG = 0x0200; Vdp2Regs->COAB = 0x0200; } ////////////////////////////////////////////////////////////////////////////// int YabauseQuickLoadGame(void) { partition_struct * lgpartition; u8 *buffer; u32 addr; u32 size; u32 blocks; unsigned int i, i2; dirrec_struct dirrec; Cs2Area->outconcddev = Cs2Area->filter + 0; Cs2Area->outconcddevnum = 0; // read in lba 0/FAD 150 if ((lgpartition = Cs2ReadUnFilteredSector(150)) == NULL) return -1; // Make sure we're dealing with a saturn game buffer = lgpartition->block[lgpartition->numblocks - 1]->data; YabauseSpeedySetup(); if (memcmp(buffer, "SEGA SEGASATURN", 15) == 0) { // figure out how many more sectors we need to read size = (buffer[0xE0] << 24) | (buffer[0xE1] << 16) | (buffer[0xE2] << 8) | buffer[0xE3]; blocks = size >> 11; if ((size % 2048) != 0) blocks++; // Figure out where to load the first program addr = (buffer[0xF0] << 24) | (buffer[0xF1] << 16) | (buffer[0xF2] << 8) | buffer[0xF3]; // Free Block lgpartition->size = 0; Cs2FreeBlock(lgpartition->block[lgpartition->numblocks - 1]); lgpartition->blocknum[lgpartition->numblocks - 1] = 0xFF; lgpartition->numblocks = 0; // Copy over ip to 0x06002000 for (i = 0; i < blocks; i++) { if ((lgpartition = Cs2ReadUnFilteredSector(150+i)) == NULL) return -1; buffer = lgpartition->block[lgpartition->numblocks - 1]->data; if (size >= 2048) { for (i2 = 0; i2 < 2048; i2++) MappedMemoryWriteByteNocache(MSH2, 0x06002000 + (i * 0x800) + i2, buffer[i2]); } else { for (i2 = 0; i2 < size; i2++) MappedMemoryWriteByteNocache(MSH2, 0x06002000 + (i * 0x800) + i2, buffer[i2]); } size -= 2048; // Free Block lgpartition->size = 0; Cs2FreeBlock(lgpartition->block[lgpartition->numblocks - 1]); lgpartition->blocknum[lgpartition->numblocks - 1] = 0xFF; lgpartition->numblocks = 0; } SH2WriteNotify(0x6002000, blocks<<11); // Ok, now that we've loaded the ip, now it's time to load the // First Program // Figure out where the first program is located if ((lgpartition = Cs2ReadUnFilteredSector(166)) == NULL) return -1; // Figure out root directory's location // Retrieve directory record's lba Cs2CopyDirRecord(lgpartition->block[lgpartition->numblocks - 1]->data + 0x9C, &dirrec); // Free Block lgpartition->size = 0; Cs2FreeBlock(lgpartition->block[lgpartition->numblocks - 1]); lgpartition->blocknum[lgpartition->numblocks - 1] = 0xFF; lgpartition->numblocks = 0; // Now then, fetch the root directory's records if ((lgpartition = Cs2ReadUnFilteredSector(dirrec.lba+150)) == NULL) return -1; buffer = lgpartition->block[lgpartition->numblocks - 1]->data; // Skip the first two records, read in the last one for (i = 0; i < 3; i++) { Cs2CopyDirRecord(buffer, &dirrec); buffer += dirrec.recordsize; } size = dirrec.size; blocks = size >> 11; if ((dirrec.size % 2048) != 0) blocks++; // Free Block lgpartition->size = 0; Cs2FreeBlock(lgpartition->block[lgpartition->numblocks - 1]); lgpartition->blocknum[lgpartition->numblocks - 1] = 0xFF; lgpartition->numblocks = 0; // Copy over First Program to addr for (i = 0; i < blocks; i++) { if ((lgpartition = Cs2ReadUnFilteredSector(150+dirrec.lba+i)) == NULL) return -1; buffer = lgpartition->block[lgpartition->numblocks - 1]->data; if (size >= 2048) { for (i2 = 0; i2 < 2048; i2++) MappedMemoryWriteByteNocache(MSH2, addr + (i * 0x800) + i2, buffer[i2]); } else { for (i2 = 0; i2 < size; i2++) MappedMemoryWriteByteNocache(MSH2, addr + (i * 0x800) + i2, buffer[i2]); } size -= 2048; // Free Block lgpartition->size = 0; Cs2FreeBlock(lgpartition->block[lgpartition->numblocks - 1]); lgpartition->blocknum[lgpartition->numblocks - 1] = 0xFF; lgpartition->numblocks = 0; } SH2WriteNotify(addr, blocks<<11); // Now setup SH2 registers to start executing at ip code SH2GetRegisters(MSH2, &MSH2->regs); MSH2->regs.PC = 0x06002E00; MSH2->regs.R[15] = Cs2GetMasterStackAdress(); SH2SetRegisters(MSH2, &MSH2->regs); } else { // Ok, we're not. Time to bail! // Free Block lgpartition->size = 0; Cs2FreeBlock(lgpartition->block[lgpartition->numblocks - 1]); lgpartition->blocknum[lgpartition->numblocks - 1] = 0xFF; lgpartition->numblocks = 0; return -1; } return 0; } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/cd-windows.c000644 001750 001750 00000030251 12755623101 020265 0ustar00guillaumeguillaume000000 000000 /* Copyright 2004-2005 Theo Berkau Copyright 2005 Joost Peters This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file cd-windows.c \brief Windows port's cd interface using SPTI. */ #include #include #include #ifdef HAVE_NTDDCDRM #include #include #else #include "fakeddk.h" #endif #include "cdbase.h" #include "yabause.h" ////////////////////////////////////////////////////////////////////////////// static HANDLE hCDROM; static SCSI_PASS_THROUGH_DIRECT sptd; static int KillCDThread=0; static HANDLE thread_handle=INVALID_HANDLE_VALUE; static CRITICAL_SECTION cd_cs; static int drivestatus=0; static DWORD thread_id; static struct { volatile int enable_read_ahead; u32 FAD; unsigned char data[2352]; int num_sectors_read; int error_flag; } cd_buf; static int SPTICDInit(const char *); static void SPTICDDeInit(void); static s32 SPTICDReadTOC(u32 *); static int SPTICDGetStatus(void); static int SPTICDReadSectorFAD(u32, void *); static void SPTICDReadAheadFAD(u32); static s32 SPTICDReadTOC10 (CDInterfaceToc10 *TOC); CDInterface ArchCD = { CDCORE_ARCH, "Windows SPTI Driver", SPTICDInit, SPTICDDeInit, SPTICDGetStatus, SPTICDReadTOC, SPTICDReadTOC10, SPTICDReadSectorFAD, SPTICDReadAheadFAD, }; ////////////////////////////////////////////////////////////////////////////// // SPTI Interface ////////////////////////////////////////////////////////////////////////////// DWORD WINAPI __stdcall SPTICDThread(void *b); int SPTICDInit(const char *cdrom_name) { char pipe_name[7]; sprintf(pipe_name, "\\\\.\\?:"); pipe_name[4] = cdrom_name[0]; if ((hCDROM = CreateFileA(pipe_name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) { return -1; } // Setup a separate thread for handling SPTI commands(that way the emulation // code doesn't have to wait for a response) KillCDThread=0; memset(&cd_buf, 0, sizeof(cd_buf)); thread_handle = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) SPTICDThread,(void *) &KillCDThread,0,&thread_id); InitializeCriticalSection(&cd_cs); return 0; } ////////////////////////////////////////////////////////////////////////////// void SPTICDDeInit() { if (thread_handle != INVALID_HANDLE_VALUE) { // Set the flag telling it to stop KillCDThread=1; if (WaitForSingleObject(thread_handle,INFINITE) == WAIT_TIMEOUT) { // Couldn't close thread cleanly TerminateThread(thread_handle,0); } CloseHandle(thread_handle); thread_handle = INVALID_HANDLE_VALUE; } DeleteCriticalSection(&cd_cs); CloseHandle(hCDROM); } ////////////////////////////////////////////////////////////////////////////// DWORD WINAPI __stdcall SPTICDThread(void *b) { u64 curticks, lastticks = YabauseGetTicks(); while (KillCDThread != 1) { DWORD dwBytesReturned; unsigned char statusbuf[8]; BOOL success; EnterCriticalSection (&cd_cs); // Check to see if we have any work to do(for now, let's just do a drive // status check once a second) if (cd_buf.enable_read_ahead) { u32 FAD; DWORD dwBytesReturned; BOOL success; memset(&sptd, 0, sizeof(sptd)); sptd.Length=sizeof(sptd); sptd.CdbLength=12; sptd.SenseInfoLength=0; // No sense data sptd.DataIn=SCSI_IOCTL_DATA_IN; sptd.TimeOutValue=60; // may need to be changed sptd.DataBuffer=(PVOID)cd_buf.data; sptd.SenseInfoOffset=0; sptd.DataTransferLength=2352; sptd.Cdb[0]=0xBE; // CDB12 code sptd.Cdb[1]=0; // Sector Type, RELADR FAD = cd_buf.FAD - 150; sptd.Cdb[2]=(unsigned char)((FAD & 0xFF000000) >> 24); // lba(byte 1) sptd.Cdb[3]=(unsigned char)((FAD & 0x00FF0000) >> 16); // lba(byte 2) sptd.Cdb[4]=(unsigned char)((FAD & 0x0000FF00) >> 8); // lba(byte 3) sptd.Cdb[5]=(unsigned char)(FAD & 0x000000FF); // lba(byte 4) sptd.Cdb[6]=0; // number of sectors(byte 1) sptd.Cdb[7]=0; // number of sectors(byte 2) sptd.Cdb[8]=1; // number of sectors(byte 3) sptd.Cdb[9]=0xF8; // Sync + All Headers + User data + EDC/ECC success=DeviceIoControl(hCDROM, IOCTL_SCSI_PASS_THROUGH_DIRECT, (PVOID)&sptd, (DWORD)sizeof(SCSI_PASS_THROUGH_DIRECT), NULL, 0, &dwBytesReturned, NULL); if (success) cd_buf.num_sectors_read++; cd_buf.error_flag = success; cd_buf.enable_read_ahead = 0; } curticks = YabauseGetTicks(); if (curticks-lastticks >= yabsys.tickfreq) { memset(&sptd, 0, sizeof(sptd)); sptd.Length=sizeof(sptd); sptd.CdbLength=12; sptd.SenseInfoLength=0; // No sense data sptd.DataIn=SCSI_IOCTL_DATA_IN; sptd.TimeOutValue=60; // may need to be changed sptd.DataBuffer=(PVOID)&(statusbuf); sptd.SenseInfoOffset=0; sptd.DataTransferLength=8; // may need to change this sptd.Cdb[0]=0xBD; // CDB12 code sptd.Cdb[8]=0; // Allocation Length(byte 1) sptd.Cdb[9]=8; // Allocation Length(byte 2) (may have to change this) success=DeviceIoControl(hCDROM, IOCTL_SCSI_PASS_THROUGH_DIRECT, (PVOID)&sptd, (DWORD)sizeof(SCSI_PASS_THROUGH_DIRECT), NULL, 0, &dwBytesReturned, NULL); if (success) { // Figure out drive status // Is door open? if (statusbuf[1] & 0x10) drivestatus = 3; else { // Ok, so the door is closed, now is there a disc there? success = DeviceIoControl(hCDROM, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, NULL, 0, &dwBytesReturned, NULL); if (!success) drivestatus = 2; else drivestatus = 0; } } //else //drivestatus = 2; lastticks = curticks; } LeaveCriticalSection(&cd_cs); SwitchToThread(); } return 0; } ////////////////////////////////////////////////////////////////////////////// int SPTICDGetStatus() { // This function is called periodically to see what the status of the // drive is. // // Should return one of the following values: // 0 - CD Present, disc spinning // 1 - CD Present, disc not spinning // 2 - CD not present // 3 - Tray open // // If you really don't want to bother too much with this function, just // return status 0. Though it is kind of nice when the bios's cd player, // etc. recognizes when you've ejected the tray and popped in another disc. int status; EnterCriticalSection(&cd_cs); status = drivestatus; LeaveCriticalSection(&cd_cs); return status; } ////////////////////////////////////////////////////////////////////////////// #define MSF_TO_FAD(m,s,f) ((m * 4500) + (s * 75) + f) s32 SPTICDReadTOC(u32 *TOC) { CDROM_TOC ctTOC; DWORD dwNotUsed; int i; if (hCDROM != INVALID_HANDLE_VALUE) { memset(TOC, 0xFF, 0xCC * 2); memset(&ctTOC, 0xFF, sizeof(CDROM_TOC)); if (DeviceIoControl (hCDROM, IOCTL_CDROM_READ_TOC, NULL, 0, &ctTOC, sizeof(ctTOC), &dwNotUsed, NULL) == 0) { return 0; } // convert TOC to saturn format for (i = 0; i < ctTOC.LastTrack; i++) { TOC[i] = (ctTOC.TrackData[i].Control << 28) | (ctTOC.TrackData[i].Adr << 24) | MSF_TO_FAD(ctTOC.TrackData[i].Address[1], ctTOC.TrackData[i].Address[2], ctTOC.TrackData[i].Address[3]); } // Do First, Last, and Lead out sections here TOC[99] = (ctTOC.TrackData[0].Control << 28) | (ctTOC.TrackData[0].Adr << 24) | (ctTOC.FirstTrack << 16); TOC[100] = (ctTOC.TrackData[ctTOC.LastTrack - 1].Control << 28) | (ctTOC.TrackData[ctTOC.LastTrack - 1].Adr << 24) | (ctTOC.LastTrack << 16); TOC[101] = (ctTOC.TrackData[ctTOC.LastTrack].Control << 28) | (ctTOC.TrackData[ctTOC.LastTrack].Adr << 24) | MSF_TO_FAD(ctTOC.TrackData[ctTOC.LastTrack].Address[1], ctTOC.TrackData[ctTOC.LastTrack].Address[2], ctTOC.TrackData[ctTOC.LastTrack].Address[3]); return (0xCC * 2); } return 0; } static s32 SPTICDReadTOC10(CDInterfaceToc10 *TOC) { if (hCDROM != INVALID_HANDLE_VALUE) { BOOL success; DWORD dwBytesReturned=0; int size = 256 * sizeof(CDROM_TOC_FULL_TOC_DATA_BLOCK) + sizeof(CDROM_TOC_FULL_TOC_DATA); unsigned char buf[256 * sizeof(CDROM_TOC_FULL_TOC_DATA_BLOCK) + sizeof(CDROM_TOC_FULL_TOC_DATA)]; CDROM_TOC_FULL_TOC_DATA *full_toc = (CDROM_TOC_FULL_TOC_DATA *)buf; CDROM_READ_TOC_EX toc_ex; ZeroMemory(&toc_ex, sizeof(toc_ex)); toc_ex.Format = CDROM_READ_TOC_EX_FORMAT_FULL_TOC; toc_ex.Msf = TRUE; toc_ex.SessionTrack = 1; success=DeviceIoControl(hCDROM, IOCTL_CDROM_READ_TOC_EX, &toc_ex, sizeof(CDROM_READ_TOC_EX), full_toc, size, &dwBytesReturned, NULL); if (success) { int i; int num_toc=0; for (i = 0; i < 256; i++) { if (full_toc->Descriptors[i].Adr == 1 && full_toc->Descriptors[i].SessionNumber == 1) { u8 point = full_toc->Descriptors[i].Point; if (point < MAXIMUM_NUMBER_TRACKS || point == 0xA0 || point == 0xA1 || point == 0xA2) { TOC[num_toc].ctrladr = (full_toc->Descriptors[i].Control << 4) | full_toc->Descriptors[i].Adr; TOC[num_toc].tno = full_toc->Descriptors[i].Reserved1; TOC[num_toc].point = full_toc->Descriptors[i].Point; TOC[num_toc].min = full_toc->Descriptors[i].MsfExtra[0]; TOC[num_toc].sec = full_toc->Descriptors[i].MsfExtra[1]; TOC[num_toc].frame = full_toc->Descriptors[i].MsfExtra[2]; TOC[num_toc].zero = full_toc->Descriptors[i].Zero; TOC[num_toc].pmin = full_toc->Descriptors[i].Msf[0]; TOC[num_toc].psec = full_toc->Descriptors[i].Msf[1]; TOC[num_toc].pframe = full_toc->Descriptors[i].Msf[2]; num_toc++; } } } return num_toc; } } return 0; } ////////////////////////////////////////////////////////////////////////////// int SPTICDReadSectorFAD(u32 FAD, void *buffer) { // This function is supposed to read exactly 1 -RAW- 2352-byte sector at // the specified FAD address to buffer. Should return true if successful, // false if there was an error. // // Special Note: To convert from FAD to LBA/LSN, minus 150. // // The whole process needed to be changed since I need more control over // sector detection, etc. Not to mention it means less work for the porter // since they only have to implement raw sector reading as opposed to // implementing mode 1, mode 2 form1/form2, -and- raw sector reading. for (;;) { EnterCriticalSection(&cd_cs); if (cd_buf.enable_read_ahead == 0) { if (cd_buf.FAD == FAD) { int ret; memcpy(buffer, cd_buf.data, 2352); ret = cd_buf.error_flag; LeaveCriticalSection(&cd_cs); return ret; } else { cd_buf.FAD = FAD; cd_buf.num_sectors_read = 0; cd_buf.error_flag = 0; cd_buf.enable_read_ahead = 1; } } LeaveCriticalSection(&cd_cs); SwitchToThread(); } } ////////////////////////////////////////////////////////////////////////////// void SPTICDReadAheadFAD(u32 FAD) { EnterCriticalSection(&cd_cs); cd_buf.FAD = FAD; cd_buf.num_sectors_read = 0; cd_buf.error_flag = 0; cd_buf.enable_read_ahead = 1; LeaveCriticalSection(&cd_cs); } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/cs2.c000644 001750 001750 00000420357 12757373537 016731 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003 Guillaume Duhamel Copyright 2004-2006, 2013 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file cs2.c \brief A-bus CS2 emulation functions. Mainly CD-Block code. */ #include #include #include "cs2.h" #include "debug.h" #include "error.h" #include "japmodem.h" #include "netlink.h" #include "scsp.h" #include "scu.h" #include "smpc.h" #include "yui.h" #define CDB_HIRQ_CMOK 0x0001 #define CDB_HIRQ_DRDY 0x0002 #define CDB_HIRQ_CSCT 0x0004 #define CDB_HIRQ_BFUL 0x0008 #define CDB_HIRQ_PEND 0x0010 #define CDB_HIRQ_DCHG 0x0020 #define CDB_HIRQ_ESEL 0x0040 #define CDB_HIRQ_EHST 0x0080 #define CDB_HIRQ_ECPY 0x0100 #define CDB_HIRQ_EFLS 0x0200 #define CDB_HIRQ_SCDQ 0x0400 #define CDB_HIRQ_MPED 0x0800 #define CDB_HIRQ_MPCM 0x1000 #define CDB_HIRQ_MPST 0x2000 #define CDB_STAT_BUSY 0x00 #define CDB_STAT_PAUSE 0x01 #define CDB_STAT_STANDBY 0x02 #define CDB_STAT_PLAY 0x03 #define CDB_STAT_SEEK 0x04 #define CDB_STAT_SCAN 0x05 #define CDB_STAT_OPEN 0x06 #define CDB_STAT_NODISC 0x07 #define CDB_STAT_RETRY 0x08 #define CDB_STAT_ERROR 0x09 #define CDB_STAT_FATAL 0x0A #define CDB_STAT_PERI 0x20 #define CDB_STAT_TRNS 0x40 #define CDB_STAT_WAIT 0x80 #define CDB_STAT_REJECT 0xFF #define CDB_PLAYTYPE_SECTOR 0x01 #define CDB_PLAYTYPE_FILE 0x02 enum CDB_DATATRANSTYPE { CDB_DATATRANSTYPE_INVALID=-1, CDB_DATATRANSTYPE_GETSECTOR=0, CDB_DATATRANSTYPE_GETDELSECTOR=2, CDB_DATATRANSTYPE_PUTSECTOR=3 }; #define ToBCD(val) ((val % 10 ) + ((val / 10 ) << 4)) Cs2 * Cs2Area = NULL; ip_struct *cdip = NULL; extern CDInterface *CDCoreList[]; ////////////////////////////////////////////////////////////////////////////// static INLINE void doCDReport(u8 status) { Cs2Area->reg.CR1 = (status << 8) | ((Cs2Area->options & 0xF) << 4) | (Cs2Area->repcnt & 0xF); Cs2Area->reg.CR2 = (Cs2Area->ctrladdr << 8) | Cs2Area->track; Cs2Area->reg.CR3 = (u16)((Cs2Area->index << 8) | ((Cs2Area->FAD >> 16) & 0xFF)); Cs2Area->reg.CR4 = (u16) Cs2Area->FAD; } ////////////////////////////////////////////////////////////////////////////// static INLINE void doMPEGReport(u8 status) { Cs2Area->reg.CR1 = (status << 8) | Cs2Area->actionstatus; Cs2Area->reg.CR2 = Cs2Area->vcounter; Cs2Area->reg.CR3 = (Cs2Area->pictureinfo << 8) | Cs2Area->mpegaudiostatus; Cs2Area->reg.CR4 = Cs2Area->mpegvideostatus; } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL Cs2ReadByte(SH2_struct *sh, u32 addr) { return CartridgeArea->Cs2ReadByte(sh, addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Cs2WriteByte(SH2_struct *sh, u32 addr, u8 val) { CartridgeArea->Cs2WriteByte(sh, addr, val); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL Cs2ReadWord(SH2_struct *sh, u32 addr) { u16 val = 0; addr &= 0xFFFFF; // fix me(I should really have proper mapping) switch(addr) { case 0x90008: case 0x9000A: val = Cs2Area->reg.HIRQ; if (Cs2Area->isbufferfull) val |= CDB_HIRQ_BFUL; else val &= ~CDB_HIRQ_BFUL; if (Cs2Area->isdiskchanged) val |= CDB_HIRQ_DCHG; else val &= ~CDB_HIRQ_DCHG; if (Cs2Area->isonesectorstored) val |= CDB_HIRQ_CSCT; else val &= ~CDB_HIRQ_CSCT; Cs2Area->reg.HIRQ = val; // CDLOG("cs2\t: Hirq read, Hirq mask = %x - ret: %x\n", Memory::getWord(0x9000C), val); return val; case 0x9000C: case 0x9000E: return Cs2Area->reg.HIRQMASK; case 0x90018: case 0x9001A: return Cs2Area->reg.CR1; case 0x9001C: case 0x9001E: return Cs2Area->reg.CR2; case 0x90020: case 0x90022: return Cs2Area->reg.CR3; case 0x90024: case 0x90026: Cs2Area->_command = 0; return Cs2Area->reg.CR4; case 0x90028: case 0x9002A: return Cs2Area->reg.MPEGRGB; case 0x98000: // transfer info switch (Cs2Area->infotranstype) { case 0: // Get Toc Data if (Cs2Area->transfercount % 4 == 0) val = (u16)((Cs2Area->TOC[Cs2Area->transfercount >> 2] & 0xFFFF0000) >> 16); else val = (u16)Cs2Area->TOC[Cs2Area->transfercount >> 2]; Cs2Area->transfercount += 2; Cs2Area->cdwnum += 2; if (Cs2Area->transfercount > (0xCC * 2)) { Cs2Area->transfercount = 0; Cs2Area->infotranstype = -1; } break; case 1: // Get File Info(1 file info) val = (Cs2Area->transfileinfo[Cs2Area->transfercount] << 8) | Cs2Area->transfileinfo[Cs2Area->transfercount + 1]; Cs2Area->transfercount += 2; Cs2Area->cdwnum += 2; if (Cs2Area->transfercount > (0x6 * 2)) { Cs2Area->transfercount = 0; Cs2Area->infotranstype = -1; } break; case 2: // Get File Info(254 file info) // Do we need to retrieve the next file info? if (Cs2Area->transfercount % (0x6 * 2) == 0) { // yes we do Cs2SetupFileInfoTransfer(2 + (Cs2Area->transfercount / (0x6 * 2))); } val = (Cs2Area->transfileinfo[Cs2Area->transfercount % (0x6 * 2)] << 8) | Cs2Area->transfileinfo[Cs2Area->transfercount % (0x6 * 2) + 1]; Cs2Area->transfercount += 2; Cs2Area->cdwnum += 2; if (Cs2Area->transfercount > (254 * (0x6 * 2))) { Cs2Area->transfercount = 0; Cs2Area->infotranstype = -1; } break; case 3: // Get Subcode Q val = (Cs2Area->transscodeq[Cs2Area->transfercount] << 8) | Cs2Area->transscodeq[Cs2Area->transfercount + 1]; Cs2Area->transfercount += 2; Cs2Area->cdwnum += 2; if (Cs2Area->transfercount > (5 * 2)) { Cs2Area->transfercount = 0; Cs2Area->infotranstype = -1; } break; case 4: // Get Subcode RW val = (Cs2Area->transscoderw[Cs2Area->transfercount] << 8) | Cs2Area->transscoderw[Cs2Area->transfercount + 1]; Cs2Area->transfercount += 2; Cs2Area->cdwnum += 2; if (Cs2Area->transfercount > (12 * 2)) { Cs2Area->transfercount = 0; Cs2Area->infotranstype = -1; } break; default: break; } break; default: LOG("cs2\t: Undocumented register read %08X\n", addr); // val = T3ReadWord(Cs2Area->mem, addr); break; } return val; } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Cs2WriteWord(SH2_struct *sh, u32 addr, u16 val) { addr &= 0xFFFFF; // fix me(I should really have proper mapping) switch(addr) { case 0x90008: case 0x9000A: Cs2Area->reg.HIRQ &= val; return; case 0x9000C: case 0x9000E: Cs2Area->reg.HIRQMASK = val; return; case 0x90018: case 0x9001A: Cs2Area->status &= ~CDB_STAT_PERI; Cs2Area->_command = 1; Cs2Area->reg.CR1 = val; return; case 0x9001C: case 0x9001E: Cs2Area->reg.CR2 = val; return; case 0x90020: case 0x90022: Cs2Area->reg.CR3 = val; return; case 0x90024: case 0x90026: Cs2Area->reg.CR4 = val; Cs2SetCommandTiming(Cs2Area->reg.CR1 >> 8); return; case 0x90028: case 0x9002A: Cs2Area->reg.MPEGRGB = val; return; default: LOG("cs2\t:Undocumented register write %08X\n", addr); // T3WriteWord(Cs2Area->mem, addr, val); break; } } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL Cs2ReadLong(SH2_struct *sh, u32 addr) { s32 i; u32 val = 0; addr &= 0xFFFFF; // fix me(I should really have proper mapping) switch(addr) { case 0x90008: val = Cs2Area->reg.HIRQ; if (Cs2Area->isbufferfull) val |= CDB_HIRQ_BFUL; else val &= ~CDB_HIRQ_BFUL; if (Cs2Area->isdiskchanged) val |= CDB_HIRQ_DCHG; else val &= ~CDB_HIRQ_DCHG; if (Cs2Area->isonesectorstored) val |= CDB_HIRQ_CSCT; else val &= ~CDB_HIRQ_CSCT; Cs2Area->reg.HIRQ = (u16)val; val |= (val << 16); return val; case 0x9000C: return ((Cs2Area->reg.HIRQMASK << 16) | Cs2Area->reg.HIRQMASK); case 0x90018: return ((Cs2Area->reg.CR1 << 16) | Cs2Area->reg.CR1); case 0x9001C: return ((Cs2Area->reg.CR2 << 16) | Cs2Area->reg.CR2); case 0x90020: return ((Cs2Area->reg.CR3 << 16) | Cs2Area->reg.CR3); case 0x90024: Cs2Area->_command = 0; return ((Cs2Area->reg.CR4 << 16) | Cs2Area->reg.CR4); case 0x90028: return ((Cs2Area->reg.MPEGRGB << 16) | Cs2Area->reg.MPEGRGB); case 0x18000: // transfer data if (Cs2Area->datatranstype != CDB_DATATRANSTYPE_INVALID) { // get sector // Make sure we still have sectors to transfer if (Cs2Area->datanumsecttrans < Cs2Area->datasectstotrans) { // Transfer Data const u8 *ptr = &Cs2Area->datatranspartition->block[Cs2Area->datanumsecttrans]->data[Cs2Area->datatransoffset]; if (Cs2Area->datatranspartition->block[Cs2Area->datanumsecttrans] == NULL) { CDLOG("cs2\t: datatranspartition->block[Cs2Area->datanumsecttrans] was NULL"); return 0; } #ifdef WORDS_BIGENDIAN val = *((const u32 *) ptr); #else val = BSWAP32(*((const u32 *) ptr)); #endif // increment datatransoffset/cdwnum Cs2Area->cdwnum += 4; Cs2Area->datatransoffset += 4; // Make sure we're not beyond the sector size boundary if (Cs2Area->datatransoffset >= Cs2Area->datatranspartition->block[Cs2Area->datanumsecttrans]->size) { Cs2Area->datatransoffset = 0; Cs2Area->datanumsecttrans++; } } else { if (Cs2Area->datatranstype == CDB_DATATRANSTYPE_GETDELSECTOR) { // Ok, so we don't have any more sectors to // transfer, might as well delete them all. Cs2Area->datatranstype = CDB_DATATRANSTYPE_INVALID; // free blocks for (i = Cs2Area->datatranssectpos; i < (Cs2Area->datatranssectpos+Cs2Area->datasectstotrans); i++) { Cs2FreeBlock(Cs2Area->datatranspartition->block[i]); Cs2Area->datatranspartition->block[i] = NULL; Cs2Area->datatranspartition->blocknum[i] = 0xFF; } // sort remaining blocks Cs2SortBlocks(Cs2Area->datatranspartition); Cs2Area->datatranspartition->size -= Cs2Area->cdwnum; Cs2Area->datatranspartition->numblocks -= Cs2Area->datasectstotrans; CDLOG("cs2\t: datatranspartition->size = %x\n", Cs2Area->datatranspartition->size); } } } break; default: LOG("cs2\t: Undocumented register read %08X\n", addr); // val = T3ReadLong(Cs2Area->mem, addr); break; } return val; } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Cs2WriteLong(SH2_struct *sh, u32 addr, u32 val) { addr &= 0xFFFFF; // fix me(I should really have proper mapping) switch (addr) { case 0x18000: // transfer data if (Cs2Area->datatranstype == CDB_DATATRANSTYPE_PUTSECTOR) { // put sector // Make sure we still have sectors to transfer if (Cs2Area->datanumsecttrans < Cs2Area->datasectstotrans) { // Transfer Data const u8 *ptr = &Cs2Area->datatranspartition->block[Cs2Area->datanumsecttrans]->data[Cs2Area->datatransoffset]; if (Cs2Area->datatranspartition->block[Cs2Area->datanumsecttrans] == NULL) { CDLOG("cs2\t: datatranspartition->block[Cs2Area->datanumsecttrans] was NULL"); return; } #ifdef WORDS_BIGENDIAN *((u32 *) ptr) = val; #else *((u32 *) ptr) = BSWAP32(val); #endif // increment datatransoffset/cdwnum Cs2Area->cdwnum += 4; Cs2Area->datatransoffset += 4; // Make sure we're not beyond the sector size boundary if (Cs2Area->datatransoffset >= Cs2Area->datatranspartition->block[Cs2Area->datanumsecttrans]->size) { Cs2Area->datatransoffset = 0; Cs2Area->datanumsecttrans++; if (Cs2Area->datanumsecttrans >= Cs2Area->datasectstotrans) Cs2Area->reg.HIRQ |= CDB_HIRQ_EHST; } } } break; default: LOG("cs2\t: Undocumented register write %08X\n", addr); // T3WriteLong(Cs2Area->mem, addr, val); break; } } ////////////////////////////////////////////////////////////////////////////// /* Copy "count" 32-bit words from the CD buffer to type-1 memory "dest" (a * native pointer), as though 0x25818000 had been read that many times */ void FASTCALL Cs2RapidCopyT1(void *dest, u32 count) { u8 *dest8 = (u8 *) dest; if (Cs2Area->datatranstype != CDB_DATATRANSTYPE_INVALID) { // Copy as many sectors as we have left, one sector at a time while (count > 0 && Cs2Area->datanumsecttrans < Cs2Area->datasectstotrans) { const u8 *src = &Cs2Area->datatranspartition->block[Cs2Area->datanumsecttrans]->data[Cs2Area->datatransoffset]; const u32 size = Cs2Area->datatranspartition->block[Cs2Area->datanumsecttrans]->size; const u32 max = size - Cs2Area->datatransoffset; const u32 copy = (max < count*4) ? max : count*4; memcpy(dest8, src, copy); dest8 += copy; count -= copy/4; Cs2Area->datatransoffset += copy; Cs2Area->cdwnum += copy; // Update the sector index if we reached the end of the sector if (Cs2Area->datatransoffset >= size) { Cs2Area->datatransoffset = 0; Cs2Area->datanumsecttrans++; } } // If we're in delete mode and we read through everything in memory, // delete the sectors if (Cs2Area->datatranstype == CDB_DATATRANSTYPE_GETDELSECTOR && Cs2Area->datanumsecttrans >= Cs2Area->datasectstotrans) { u32 i; Cs2Area->datatranstype = CDB_DATATRANSTYPE_INVALID; for (i = Cs2Area->datatranssectpos; i < (Cs2Area->datatranssectpos+Cs2Area->datasectstotrans); i++) { Cs2FreeBlock(Cs2Area->datatranspartition->block[i]); Cs2Area->datatranspartition->block[i] = NULL; Cs2Area->datatranspartition->blocknum[i] = 0xFF; } Cs2SortBlocks(Cs2Area->datatranspartition); Cs2Area->datatranspartition->size -= Cs2Area->cdwnum; Cs2Area->datatranspartition->numblocks -= Cs2Area->datasectstotrans; CDLOG("cs2\t: datatranspartition->size = %x\n", Cs2Area->datatranspartition->size); } } if (count > 0) { // We tried to copy more data than was stored, so fill the rest of // the buffer with dummy data memset(dest8, 0xCD, count*4); } } ////////////////////////////////////////////////////////////////////////////// /* Copy "count" 32-bit words from the CD buffer to type-2 memory "dest" (a * native pointer), as though 0x25818000 had been read that many times */ void FASTCALL Cs2RapidCopyT2(void *dest, u32 count) { u32 *dest32 = (u32 *) dest; if (Cs2Area->datatranstype != CDB_DATATRANSTYPE_INVALID) { // Copy as many sectors as we have left, one sector at a time; copy // four words at a time where possible to improve data parallelism while (count > 0 && Cs2Area->datanumsecttrans < Cs2Area->datasectstotrans) { const u8 *src = &Cs2Area->datatranspartition->block[Cs2Area->datanumsecttrans]->data[Cs2Area->datatransoffset]; const u32 size = Cs2Area->datatranspartition->block[Cs2Area->datanumsecttrans]->size; const u32 max = size - Cs2Area->datatransoffset; const u32 copy = (max < count*4) ? max : count*4; u32 i = 0; if (copy >= 16) { for (; i < copy-12; i += 16, src += 16, dest32 += 4) { u32 word0, word1, word2, word3; #ifdef WORDS_BIGENDIAN word0 = ((u32 *)src)[0]; word1 = ((u32 *)src)[1]; word2 = ((u32 *)src)[2]; word3 = ((u32 *)src)[3]; #else word0 = BSWAP16(((u32 *)src)[0]); word1 = BSWAP16(((u32 *)src)[1]); word2 = BSWAP16(((u32 *)src)[2]); word3 = BSWAP16(((u32 *)src)[3]); #endif dest32[0] = word0; dest32[1] = word1; dest32[2] = word2; dest32[3] = word3; } } for (; i < copy; i += 4, src += 4, dest32++) { #ifdef WORDS_BIGENDIAN *dest32 = *(u32 *)src; #else *dest32 = BSWAP16(*(u32 *)src); #endif } count -= copy/4; Cs2Area->datatransoffset += copy; Cs2Area->cdwnum += copy; if (Cs2Area->datatransoffset >= size) { Cs2Area->datatransoffset = 0; Cs2Area->datanumsecttrans++; } } if (Cs2Area->datatranstype == CDB_DATATRANSTYPE_GETDELSECTOR && Cs2Area->datanumsecttrans >= Cs2Area->datasectstotrans) { u32 i; Cs2Area->datatranstype = CDB_DATATRANSTYPE_INVALID; for (i = Cs2Area->datatranssectpos; i < (Cs2Area->datatranssectpos+Cs2Area->datasectstotrans); i++) { Cs2FreeBlock(Cs2Area->datatranspartition->block[i]); Cs2Area->datatranspartition->block[i] = NULL; Cs2Area->datatranspartition->blocknum[i] = 0xFF; } Cs2SortBlocks(Cs2Area->datatranspartition); Cs2Area->datatranspartition->size -= Cs2Area->cdwnum; Cs2Area->datatranspartition->numblocks -= Cs2Area->datasectstotrans; CDLOG("cs2\t: datatranspartition->size = %x\n", Cs2Area->datatranspartition->size); } } if (count > 0) { memset(dest32, 0xCD, count*4); } } ////////////////////////////////////////////////////////////////////////////// int Cs2Init(int carttype, int coreid, const char *cdpath, const char *mpegpath, const char *modemip, const char *modemport) { int ret; if ((Cs2Area = (Cs2 *) malloc(sizeof(Cs2))) == NULL) return -1; memset(Cs2Area, 0, sizeof(*Cs2Area)); Cs2Area->carttype = carttype; Cs2Area->mpegpath = mpegpath; Cs2Area->cdi=NULL; if ((ret = Cs2ChangeCDCore(coreid, cdpath)) != 0) return ret; Cs2Reset(); // If Modem is connected, set the registers if(Cs2Area->carttype == CART_NETLINK) { if ((ret = NetlinkInit(modemip, modemport)) != 0) return ret; } else if (Cs2Area->carttype == CART_JAPMODEM) { if ((ret = JapModemInit(modemip, modemport)) != 0) return ret; } if ((cdip = (ip_struct *) calloc(sizeof(ip_struct), 1)) == NULL) return -1; return 0; } ////////////////////////////////////////////////////////////////////////////// int Cs2ChangeCDCore(int coreid, const char *cdpath) { int i; // Make sure the old core is freed if (Cs2Area->cdi != NULL) Cs2Area->cdi->DeInit(); // So which core do we want? if (coreid == CDCORE_DEFAULT) coreid = 0; // Assume we want the first one // Go through core list and find the id for (i = 0; CDCoreList[i] != NULL; i++) { if (CDCoreList[i]->id == coreid) { // Set to current core Cs2Area->cdi = CDCoreList[i]; break; } } if (Cs2Area->cdi == NULL) { Cs2Area->cdi = &DummyCD; return -1; } if (Cs2Area->cdi->Init(cdpath) != 0) { // This might be helpful. YabSetError(YAB_ERR_CANNOTINIT, (void *)Cs2Area->cdi->Name); // Since it failed, instead of it being fatal, we'll just use the dummy // core instead Cs2Area->cdi = &DummyCD; } Cs2Area->isdiskchanged = 1; Cs2Area->status = CDB_STAT_PAUSE; SmpcRecheckRegion(); return 0; } ////////////////////////////////////////////////////////////////////////////// void Cs2DeInit(void) { if(Cs2Area != NULL) { if (Cs2Area->cdi != NULL) { Cs2Area->cdi->DeInit(); } if(Cs2Area->carttype == CART_NETLINK) NetlinkDeInit(); else if (Cs2Area->carttype == CART_JAPMODEM) JapModemDeInit(); free(Cs2Area); } Cs2Area = NULL; if (cdip) free(cdip); cdip = NULL; } ////////////////////////////////////////////////////////////////////////////// void Cs2Reset(void) { u32 i, i2; switch (Cs2Area->cdi->GetStatus()) { case 0: case 1: Cs2Area->status = CDB_STAT_PAUSE; Cs2Area->FAD = 150; Cs2Area->options = 0; Cs2Area->repcnt = 0; Cs2Area->ctrladdr = 0x41; Cs2Area->track = 1; Cs2Area->index = 1; break; case 2: Cs2Area->status = CDB_STAT_NODISC; Cs2Area->FAD = 0xFFFFFFFF; Cs2Area->options = 0xFF; Cs2Area->repcnt = 0xFF; Cs2Area->ctrladdr = 0xFF; Cs2Area->track = 0xFF; Cs2Area->index = 0xFF; break; case 3: Cs2Area->status = CDB_STAT_OPEN; Cs2Area->FAD = 0xFFFFFFFF; Cs2Area->options = 0xFF; Cs2Area->repcnt = 0xFF; Cs2Area->ctrladdr = 0xFF; Cs2Area->track = 0xFF; Cs2Area->index = 0xFF; break; default: break; } Cs2Area->infotranstype = -1; Cs2Area->datatranstype = CDB_DATATRANSTYPE_INVALID; Cs2Area->transfercount = 0; Cs2Area->cdwnum = 0; Cs2Area->getsectsize = Cs2Area->putsectsize = 2048; Cs2Area->isdiskchanged = 1; Cs2Area->isbufferfull = 0; Cs2Area->isonesectorstored = 0; Cs2Area->isaudio = 0; Cs2Area->reg.CR1 = ( 0 <<8) | 'C'; Cs2Area->reg.CR2 = ('D'<<8) | 'B'; Cs2Area->reg.CR3 = ('L'<<8) | 'O'; Cs2Area->reg.CR4 = ('C'<<8) | 'K'; Cs2Area->reg.HIRQ = 0xFFFF; Cs2Area->reg.HIRQMASK = 0xFFFF; Cs2Area->playFAD = 0xFFFFFFFF; Cs2Area->playendFAD = 0xFFFFFFFF; Cs2Area->playtype = 0; Cs2Area->maxrepeat = 0; // set authentication variables to 0(not authenticated) Cs2Area->satauth = 0; Cs2Area->mpgauth = 0; // clear filter conditions for (i = 0; i < MAX_SELECTORS; i++) { Cs2Area->filter[i].FAD = 0; Cs2Area->filter[i].range = 0xFFFFFFFF; Cs2Area->filter[i].mode = 0; Cs2Area->filter[i].chan = 0; Cs2Area->filter[i].smmask = 0; Cs2Area->filter[i].cimask = 0; Cs2Area->filter[i].fid = 0; Cs2Area->filter[i].smval = 0; Cs2Area->filter[i].cival = 0; Cs2Area->filter[i].condtrue = 0; Cs2Area->filter[i].condfalse = 0xFF; } // clear partitions for (i = 0; i < MAX_SELECTORS; i++) { Cs2Area->partition[i].size = -1; Cs2Area->partition[i].numblocks = 0; for (i2 = 0; i2 < MAX_BLOCKS; i2++) { Cs2Area->partition[i].block[i2] = NULL; Cs2Area->partition[i].blocknum[i2] = 0xFF; } } // clear blocks for (i = 0; i < MAX_BLOCKS; i++) { Cs2Area->block[i].size = -1; memset(Cs2Area->block[i].data, 0, 2352); } Cs2Area->blockfreespace = 200; // initialize TOC memset(Cs2Area->TOC, 0xFF, sizeof(Cs2Area->TOC)); // clear filesystem stuff Cs2Area->curdirsect = 0; Cs2Area->curdirsize = 0; Cs2Area->curdirfidoffset = 0; memset(&Cs2Area->fileinfo, 0, sizeof(Cs2Area->fileinfo)); Cs2Area->numfiles = 0; Cs2Area->lastbuffer = 0xFF; Cs2Area->_command = 0; Cs2Area->_statuscycles = 0; Cs2Area->_statustiming = 1000000; Cs2Area->_periodiccycles = 0; Cs2Area->_commandtiming = 0; Cs2SetTiming(0); // MPEG specific stuff Cs2Area->mpegcon[0].audcon = Cs2Area->mpegcon[0].vidcon = 0x00; Cs2Area->mpegcon[0].audlay = Cs2Area->mpegcon[0].vidlay = 0x00; Cs2Area->mpegcon[0].audbufnum = Cs2Area->mpegcon[0].vidbufnum = 0xFF; Cs2Area->mpegcon[1].audcon = Cs2Area->mpegcon[1].vidcon = 0x00; Cs2Area->mpegcon[1].audlay = Cs2Area->mpegcon[1].vidlay = 0x00; Cs2Area->mpegcon[1].audbufnum = Cs2Area->mpegcon[1].vidbufnum = 0xFF; // should verify the following Cs2Area->mpegstm[0].audstm = Cs2Area->mpegstm[0].vidstm = 0x00; Cs2Area->mpegstm[0].audstmid = Cs2Area->mpegstm[0].vidstmid = 0x00; Cs2Area->mpegstm[0].audchannum = Cs2Area->mpegstm[0].vidchannum = 0x00; Cs2Area->mpegstm[1].audstm = Cs2Area->mpegstm[1].vidstm = 0x00; Cs2Area->mpegstm[1].audstmid = Cs2Area->mpegstm[1].vidstmid = 0x00; Cs2Area->mpegstm[1].audchannum = Cs2Area->mpegstm[1].vidchannum = 0x00; } ////////////////////////////////////////////////////////////////////////////// void Cs2Exec(u32 timing) { Cs2Area->_statuscycles += timing * 3; Cs2Area->_periodiccycles += timing * 3; if (Cs2Area->_commandtiming > 0) { if (Cs2Area->_commandtiming < timing) { Cs2Execute(); Cs2Area->_commandtiming = 0; } else Cs2Area->_commandtiming -= timing; } if (Cs2Area->_statuscycles >= Cs2Area->_statustiming) { Cs2Area->_statuscycles -= Cs2Area->_statustiming; switch(Cs2Area->cdi->GetStatus()) { case 0: case 1: if ((Cs2Area->status & 0xF) == CDB_STAT_NODISC || (Cs2Area->status & 0xF) == CDB_STAT_OPEN) { Cs2Area->status = CDB_STAT_PAUSE; Cs2Area->isdiskchanged = 1; } break; case 2: // may need to change this if ((Cs2Area->status & 0xF) != CDB_STAT_NODISC) Cs2Area->status = CDB_STAT_NODISC; break; case 3: // may need to change this if ((Cs2Area->status & 0xF) != CDB_STAT_OPEN) Cs2Area->status = CDB_STAT_OPEN; break; default: break; } } if (Cs2Area->_periodiccycles >= Cs2Area->_periodictiming) { Cs2Area->_periodiccycles -= Cs2Area->_periodictiming; // Get Drive's current status and compare with old status switch (Cs2Area->status & 0xF) { case CDB_STAT_PAUSE: { // if (FAD >= playFAD && FAD < playendFAD) // status = CDB_STAT_PLAY; // else break; } case CDB_STAT_PLAY: { partition_struct * playpartition; int ret = Cs2ReadFilteredSector(Cs2Area->FAD, &playpartition); switch (ret) { case 0: // Sector Read OK Cs2Area->FAD++; Cs2Area->cdi->ReadAheadFAD(Cs2Area->FAD); if (playpartition != NULL) { // We can use this sector CDLOG("partition number = %d blocks = %d blockfreespace = %d fad = %x playpartition->size = %x isbufferfull = %x\n", (playpartition - Cs2Area->partition), playpartition->numblocks, Cs2Area->blockfreespace, Cs2Area->FAD, playpartition->size, Cs2Area->isbufferfull); Cs2Area->reg.HIRQ |= CDB_HIRQ_CSCT; Cs2Area->isonesectorstored = 1; if (Cs2Area->FAD >= Cs2Area->playendFAD) { // Make sure we don't have to do a repeat if (Cs2Area->repcnt >= Cs2Area->maxrepeat) { // we're done Cs2Area->status = CDB_STAT_PAUSE; Cs2SetTiming(0); Cs2Area->reg.HIRQ |= CDB_HIRQ_PEND; if (Cs2Area->playtype == CDB_PLAYTYPE_FILE) Cs2Area->reg.HIRQ |= CDB_HIRQ_EFLS; CDLOG("PLAY HAS ENDED\n"); } else { Cs2Area->FAD = Cs2Area->playFAD; if (Cs2Area->repcnt < 0xE) Cs2Area->repcnt++; Cs2Area->track = Cs2FADToTrack(Cs2Area->FAD); CDLOG("PLAY HAS REPEATED\n"); } } if (Cs2Area->isbufferfull) { CDLOG("BUFFER IS FULL\n"); // status = CDB_STAT_PAUSE; } } else { CDLOG("Sector filtered out\n"); if (Cs2Area->FAD >= Cs2Area->playendFAD) { // Make sure we don't have to do a repeat if (Cs2Area->repcnt >= Cs2Area->maxrepeat) { // we're done Cs2Area->status = CDB_STAT_PAUSE; Cs2SetTiming(0); Cs2Area->reg.HIRQ |= CDB_HIRQ_PEND; if (Cs2Area->playtype == CDB_PLAYTYPE_FILE) Cs2Area->reg.HIRQ |= CDB_HIRQ_EFLS; CDLOG("PLAY HAS ENDED\n"); } else { Cs2Area->FAD = Cs2Area->playFAD; if (Cs2Area->repcnt < 0xE) Cs2Area->repcnt++; Cs2Area->track = Cs2FADToTrack(Cs2Area->FAD); CDLOG("PLAY HAS REPEATED\n"); } } } break; case -1: // Things weren't setup correctly break; case -2: // Do a read retry break; } break; } case CDB_STAT_SEEK: break; case CDB_STAT_SCAN: break; case CDB_STAT_RETRY: break; default: break; } if (Cs2Area->_command) return; Cs2Area->status |= CDB_STAT_PERI; // adjust registers appropriately here(fix me) doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_SCDQ; } if(Cs2Area->carttype == CART_NETLINK) NetlinkExec(timing); else if (Cs2Area->carttype == CART_JAPMODEM) JapModemExec(timing); } ////////////////////////////////////////////////////////////////////////////// /* Returns the number of (emulated) microseconds before the next sector * will have been completely read in */ int Cs2GetTimeToNextSector(void) { if ((Cs2Area->status & 0xF) != CDB_STAT_PLAY) { return 0; } else { // Round up, since the caller wants to know when it'll be safe to check int time = (Cs2Area->_periodictiming - Cs2Area->_periodiccycles + 2) / 3; return time<0 ? 0 : time; } } ////////////////////////////////////////////////////////////////////////////// void Cs2Command(void) { Cs2Area->_command = 1; } ////////////////////////////////////////////////////////////////////////////// void Cs2SetTiming(int playing) { if (playing) { if (Cs2Area->isaudio || Cs2Area->speed1x == 1) Cs2Area->_periodictiming = 40000; // 13333.333... * 3 else Cs2Area->_periodictiming = 20000; // 6666.666... * 3 } else { Cs2Area->_periodictiming = 50000; // 16666.666... * 3 } } ////////////////////////////////////////////////////////////////////////////// void Cs2SetCommandTiming(u8 cmd) { switch(cmd) { default: Cs2Area->_commandtiming = 1; break; } } ////////////////////////////////////////////////////////////////////////////// void Cs2Execute(void) { u16 instruction = Cs2Area->reg.CR1 >> 8; Cs2Area->reg.HIRQ &= ~CDB_HIRQ_CMOK; switch (instruction) { case 0x00: CDLOG("cs2\t: Command: getStatus\n"); Cs2GetStatus(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x01: CDLOG("cs2\t: Command: getHardwareInfo\n"); Cs2GetHardwareInfo(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x02: CDLOG("cs2\t: Command: getToc\n"); Cs2GetToc(); break; case 0x03: CDLOG("cs2\t: Command: getSessionInfo\n"); Cs2GetSessionInfo(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x04: CDLOG("cs2\t: Command: initializeCDSystem %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2InitializeCDSystem(); break; case 0x05: CDLOG("cs2\t: Command: Open Tray %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2OpenTray(); break; case 0x06: CDLOG("cs2\t: Command: endDataTransfer %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2EndDataTransfer(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x10: CDLOG("cs2\t: Command: playDisc %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2PlayDisc(); break; case 0x11: CDLOG("cs2\t: Command: seekDisc %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2SeekDisc(); break; case 0x12: CDLOG("cs2\t: Command: Scan Disc %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2ScanDisc(); break; case 0x20: CDLOG("cs2\t: Command: getSubcodeQRW %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2GetSubcodeQRW(); break; case 0x30: CDLOG("cs2\t: Command: setCDDeviceConnection %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2SetCDDeviceConnection(); break; case 0x31: CDLOG("cs2\t: Command: Get CD Device Connection\n"); Cs2SetCDDeviceConnection(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x32: CDLOG("cs2\t: Command: getLastBufferDestination %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2GetLastBufferDestination(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x40: CDLOG("cs2\t: Command: setFilterRange %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2SetFilterRange(); break; case 0x41: CDLOG("cs2\t: Command: Get Filter Range\n"); Cs2GetFilterRange(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x42: CDLOG("cs2\t: Command: setFilterSubheaderConditions %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2SetFilterSubheaderConditions(); break; case 0x43: CDLOG("cs2\t: Command: getFilterSubheaderConditions\n"); Cs2GetFilterSubheaderConditions(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x44: CDLOG("cs2\t: Command: setFilterMode %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2SetFilterMode(); break; case 0x45: CDLOG("cs2\t: Command: getFilterMode\n"); Cs2GetFilterMode(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x46: CDLOG("cs2\t: Command: setFilterConnection %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2SetFilterConnection(); break; case 0x47: CDLOG("cs2\t: Command: getFilterConnection %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2GetFilterConnection(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x48: CDLOG("cs2\t: Command: resetSelector %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2ResetSelector(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x50: CDLOG("cs2\t: Command: getBufferSize\n"); Cs2GetBufferSize(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x51: // CDLOG("cs2\t: Command: getSectorNumber %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2GetSectorNumber(); // CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x52: CDLOG("cs2\t: Command: calculateActualSize %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2CalculateActualSize(); break; case 0x53: CDLOG("cs2\t: Command: getActualSize\n"); Cs2GetActualSize(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x54: CDLOG("cs2\t: Command: getSectorInfo %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2GetSectorInfo(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x55: CDLOG("cs2\t: Command: Exec FAD Search %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2ExecFadSearch(); break; case 0x56: CDLOG("cs2\t: Command: Get FAD Search Results %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2GetFadSearchResults(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x60: CDLOG("cs2\t: Command: setSectorLength %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2SetSectorLength(); break; case 0x61: CDLOG("cs2\t: Command: getSectorData %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2GetSectorData(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x62: CDLOG("cs2\t: Command: deleteSectorData %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2DeleteSectorData(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x63: CDLOG("cs2\t: Command: getThenDeleteSectorData %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2GetThenDeleteSectorData(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x64: CDLOG("cs2\t: Command: putSectorData %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2PutSectorData(); break; case 0x65: CDLOG("cs2\t: Command: copySectorData %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2CopySectorData(); break; case 0x66: CDLOG("cs2\t: Command: moveSectorData %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2MoveSectorData(); break; case 0x67: CDLOG("cs2\t: Command: getCopyError\n"); Cs2GetCopyError(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x70: CDLOG("cs2\t: Command: changeDirectory %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2ChangeDirectory(); break; case 0x71: CDLOG("cs2\t: Command: readDirectory %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2ReadDirectory(); break; case 0x72: CDLOG("cs2\t: Command: getFileSystemScope\n"); Cs2GetFileSystemScope(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x73: CDLOG("cs2\t: Command: getFileInfo %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2GetFileInfo(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x74: CDLOG("cs2\t: Command: readFile %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2ReadFile(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x75: CDLOG("cs2\t: Command: abortFile\n"); Cs2AbortFile(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x90: CDLOG("cs2\t: Command: mpegGetStatus\n"); Cs2MpegGetStatus(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x91: CDLOG("cs2\t: Command: mpegGetInterrupt\n"); Cs2MpegGetInterrupt(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x92: CDLOG("cs2\t: Command: mpegSetInterruptMask %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2); Cs2MpegSetInterruptMask(); break; case 0x93: CDLOG("cs2\t: Command: mpegInit %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2); Cs2MpegInit(); break; case 0x94: CDLOG("cs2\t: Command: mpegSetMode %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3); Cs2MpegSetMode(); break; case 0x95: CDLOG("cs2\t: Command: mpegPlay %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR4); Cs2MpegPlay(); break; case 0x96: CDLOG("cs2\t: Command: mpegSetDecodingMethod %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR4); Cs2MpegSetDecodingMethod(); break; case 0x9A: CDLOG("cs2\t: Command: mpegSetConnection %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2MpegSetConnection(); break; case 0x9B: CDLOG("cs2\t: Command: mpegGetConnection\n"); Cs2MpegGetConnection(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0x9D: CDLOG("cs2\t: Command: mpegSetStream %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2MpegSetStream(); break; case 0x9E: CDLOG("cs2\t: Command: mpegGetStream\n"); Cs2MpegGetStream(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0xA0: CDLOG("cs2\t: Command: mpegDisplay %04x %04x %04x \n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2); Cs2MpegDisplay(); break; case 0xA1: CDLOG("cs2\t: Command: mpegSetWindow %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2MpegSetWindow(); break; case 0xA2: CDLOG("cs2\t: Command: mpegSetBorderColor %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2); Cs2MpegSetBorderColor(); break; case 0xA3: CDLOG("cs2\t: Command: mpegSetFade %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2); Cs2MpegSetFade(); break; case 0xA4: CDLOG("cs2\t: Command: mpegSetVideoEffects %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2MpegSetVideoEffects(); break; case 0xAF: CDLOG("cs2\t: Command: mpegSetLSI %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2MpegSetLSI(); break; case 0xE0: CDLOG("cs2\t: Command: authenticateDevice %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2AuthenticateDevice(); break; case 0xE1: CDLOG("cs2\t: Command: isDeviceAuthenticated %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2IsDeviceAuthenticated(); CDLOG("cs2\t: ret: %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); break; case 0xE2: CDLOG("cs2\t: Command: getMPEGRom %04x %04x %04x %04x %04x\n", Cs2Area->reg.HIRQ, Cs2Area->reg.CR1, Cs2Area->reg.CR2, Cs2Area->reg.CR3, Cs2Area->reg.CR4); Cs2GetMPEGRom(); break; default: CDLOG("cs2\t: Command %02x not implemented\n", instruction); break; } } ////////////////////////////////////////////////////////////////////////////// void Cs2GetStatus(void) { doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetHardwareInfo(void) { if ((Cs2Area->status & 0xF) != CDB_STAT_OPEN && (Cs2Area->status & 0xF) != CDB_STAT_NODISC) Cs2Area->isdiskchanged = 0; Cs2Area->reg.CR1 = Cs2Area->status << 8; // hardware flags/CD Version Cs2Area->reg.CR2 = 0x0201; // mpeg card exists // mpeg version, it actually is required(at least by the bios) if (Cs2Area->mpgauth) Cs2Area->reg.CR3 = 0x1; else Cs2Area->reg.CR3 = 0; // drive info/revision Cs2Area->reg.CR4 = 0x0400; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetToc(void) { Cs2Area->cdi->ReadTOC(Cs2Area->TOC); Cs2Area->transfercount = 0; Cs2Area->infotranstype = 0; Cs2Area->reg.CR1 = Cs2Area->status << 8; Cs2Area->reg.CR2 = 0xCC; Cs2Area->reg.CR3 = 0x0; Cs2Area->reg.CR4 = 0x0; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_DRDY; Cs2Area->status = CDB_STAT_PAUSE; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetSessionInfo(void) { switch (Cs2Area->reg.CR1 & 0xFF) { case 0: Cs2Area->reg.CR3 = (u16)(0x0100 | ((Cs2Area->TOC[101] & 0xFF0000) >> 16)); Cs2Area->reg.CR4 = (u16)Cs2Area->TOC[101]; break; case 1: Cs2Area->reg.CR3 = 0x0100; // return Session number(high byte)/and first byte of Session lba Cs2Area->reg.CR4 = 0; // lower word of Session lba break; default: Cs2Area->reg.CR3 = 0xFFFF; Cs2Area->reg.CR4 = 0xFFFF; break; } Cs2Area->status = CDB_STAT_PAUSE; Cs2Area->reg.CR1 = Cs2Area->status << 8; Cs2Area->reg.CR2 = 0; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2InitializeCDSystem(void) { u16 val = 0; u8 initflag = Cs2Area->reg.CR1 & 0xFF; if ((Cs2Area->status & 0xF) != CDB_STAT_OPEN && (Cs2Area->status & 0xF) != CDB_STAT_NODISC) { Cs2Area->status = CDB_STAT_PAUSE; Cs2Area->FAD = 150; } if (initflag & 0x1) { // Reset CD block software } if (initflag & 0x2) { // Decode RW subcode } if (initflag & 0x4) { // Don't confirm Mode 2 subheader } if (initflag & 0x8) { // Retry reading Form 2 sectors } if (initflag & 0x10) Cs2Area->speed1x = 1; else Cs2Area->speed1x = 0; val = Cs2Area->reg.HIRQ & 0xFFE5; Cs2Area->isbufferfull = 0; if (Cs2Area->isdiskchanged) val |= CDB_HIRQ_DCHG; else val &= ~CDB_HIRQ_DCHG; doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ = val | CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2OpenTray(void) { u16 val = 0; Cs2Area->status = CDB_STAT_OPEN; doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ = val | CDB_HIRQ_CMOK | CDB_HIRQ_DCHG; } ////////////////////////////////////////////////////////////////////////////// void Cs2EndDataTransfer(void) { s32 i; if (Cs2Area->cdwnum) { Cs2Area->reg.CR1 = (u16)((Cs2Area->status << 8) | ((Cs2Area->cdwnum >> 17) & 0xFF)); Cs2Area->reg.CR2 = (u16)(Cs2Area->cdwnum >> 1); Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; } else { Cs2Area->reg.CR1 = (Cs2Area->status << 8) | 0xFF; // FIXME Cs2Area->reg.CR2 = 0xFFFF; Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; } // stop any transfers that may be going(this is still probably wrong), and // set/clear the appropriate flags switch (Cs2Area->datatranstype) { case 0: // Get Sector Data Cs2Area->reg.HIRQ |= CDB_HIRQ_EHST; break; case 2: { // Get Then Delete Sector // Make sure we actually have to free something if (Cs2Area->datatranspartition->size <= 0) break; Cs2Area->datatranstype = CDB_DATATRANSTYPE_INVALID; // free blocks for (i = Cs2Area->datatranssectpos; i < (Cs2Area->datatranssectpos + Cs2Area->datasectstotrans); i++) { Cs2FreeBlock(Cs2Area->datatranspartition->block[i]); Cs2Area->datatranspartition->block[i] = NULL; Cs2Area->datatranspartition->blocknum[i] = 0xFF; } // sort remaining blocks Cs2SortBlocks(Cs2Area->datatranspartition); Cs2Area->datatranspartition->size -= Cs2Area->cdwnum; Cs2Area->datatranspartition->numblocks -= Cs2Area->datasectstotrans; if (Cs2Area->blockfreespace == 200) Cs2Area->isonesectorstored = 0; Cs2Area->reg.HIRQ |= CDB_HIRQ_EHST; break; } default: break; } Cs2Area->cdwnum = 0; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2PlayDisc(void) { u32 pdspos; u32 pdepos; u32 pdpmode; // Get all the arguments pdspos = ((Cs2Area->reg.CR1 & 0xFF) << 16) | Cs2Area->reg.CR2; pdepos = ((Cs2Area->reg.CR3 & 0xFF) << 16) | Cs2Area->reg.CR4; pdpmode = Cs2Area->reg.CR3 >> 8; // Convert Start Position to playFAD if (pdspos == 0xFFFFFF || pdpmode == 0xFF) // This still isn't right { // No Change } else if (pdspos & 0x800000) { // FAD Mode Cs2Area->playFAD = (pdspos & 0xFFFFF); Cs2SetupDefaultPlayStats(Cs2FADToTrack(Cs2Area->playFAD), 0); if (!(pdpmode & 0x80)) // Move pickup to start position Cs2Area->FAD = Cs2Area->playFAD; } else { // Track Mode // If track == 0, set it to the first available track, or something like that if (pdspos == 0) pdspos = 0x0100; if (!(pdpmode & 0x80)) { Cs2SetupDefaultPlayStats((u8)(pdspos >> 8), 1); Cs2Area->playFAD = Cs2Area->FAD; Cs2Area->track = (u8)(pdspos >> 8); Cs2Area->index = (u8)pdspos; } else { // Preserve Pickup Position Cs2SetupDefaultPlayStats((u8)(pdspos >> 8), 0); } } pdpmode &= 0x7F; // Only update max repeat if bits 0-6 aren't all set if (pdpmode != 0x7F) Cs2Area->maxrepeat = pdpmode; // Convert End Position to playendFAD if (pdepos == 0xFFFFFF) { // No Change } else if (pdepos & 0x800000) { // FAD Mode Cs2Area->playendFAD = Cs2Area->playFAD+(pdepos & 0xFFFFF); } else if (pdepos != 0) { // Track Mode if ((pdepos & 0xFF) == 0) Cs2Area->playendFAD = Cs2TrackToFAD((u16)(pdepos | 0x0063)); else Cs2Area->playendFAD = Cs2TrackToFAD((u16)pdepos); } else { // Default Mode Cs2Area->playendFAD = Cs2TrackToFAD(0xFFFF); } // setup play mode here #ifdef CDDEBUG if (pdpmode != 0) CDLOG("cs2\t: playDisc: Unsupported play mode = %02X\n", pdpmode); #endif Cs2SetTiming(1); Cs2Area->status = CDB_STAT_PLAY; Cs2Area->playtype = CDB_PLAYTYPE_SECTOR; Cs2Area->cdi->ReadAheadFAD(Cs2Area->FAD); doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2SeekDisc(void) { if (Cs2Area->reg.CR1 & 0x80) { // Seek by FAD u32 sdFAD; int i; sdFAD = ((Cs2Area->reg.CR1 & 0x0F) << 16) | Cs2Area->reg.CR2; Cs2Area->status = CDB_STAT_PAUSE; for (i = 0; i < 16; i++){ u32 tfad = Cs2Area->TOC[i] & 0x00FFFFFF; if (tfad >= sdFAD){ Cs2SetupDefaultPlayStats(i, 1); Cs2Area->FAD = sdFAD; break; } } } else { // Were we given a valid track number? if (Cs2Area->reg.CR2 >> 8) { // Seek by index Cs2Area->status = CDB_STAT_PAUSE; Cs2SetupDefaultPlayStats((Cs2Area->reg.CR2 >> 8), 1); Cs2Area->index = Cs2Area->reg.CR2 & 0xFF; } else { // Error Cs2Area->status = CDB_STAT_STANDBY; Cs2Area->options = 0xFF; Cs2Area->repcnt = 0xFF; Cs2Area->ctrladdr = 0xFF; Cs2Area->track = 0xFF; Cs2Area->index = 0xFF; Cs2Area->FAD = 0xFFFFFFFF; } } Cs2SetTiming(0); doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2ScanDisc(void) { Cs2Area->status = CDB_STAT_SCAN; // finish me Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetSubcodeQRW(void) { u32 rel_fad; u8 rel_m, rel_s, rel_f, m, s, f; // According to Tyranid's doc, the subcode type is stored in the low byte // of CR2. However, Sega's CDC library writes the type to the low byte // of CR1. Somehow I'd sooner believe Sega is right. switch(Cs2Area->reg.CR1 & 0xFF) { case 0: // Get Q Channel Cs2Area->reg.CR1 = (Cs2Area->status << 8) | 0; Cs2Area->reg.CR2 = 5; Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; rel_fad = Cs2Area->FAD-(Cs2Area->TOC[Cs2Area->track-1] & 0xFFFFFF); Cs2FADToMSF(rel_fad, &rel_m, &rel_s, &rel_f); Cs2FADToMSF(Cs2Area->FAD, &m, &s, &f); Cs2Area->transscodeq[0] = Cs2Area->ctrladdr; // ctl/adr Cs2Area->transscodeq[1] = ToBCD(Cs2Area->track); // track number Cs2Area->transscodeq[2] = ToBCD(Cs2Area->index); // index Cs2Area->transscodeq[3] = ToBCD(rel_m); // relative M Cs2Area->transscodeq[4] = ToBCD(rel_s); // relative S Cs2Area->transscodeq[5] = ToBCD(rel_f); // relative F Cs2Area->transscodeq[6] = 0; Cs2Area->transscodeq[7] = ToBCD(m); // M Cs2Area->transscodeq[8] = ToBCD(s); // S Cs2Area->transscodeq[9] = ToBCD(f); // F Cs2Area->transfercount = 0; Cs2Area->infotranstype = 3; break; case 1: { // Get RW Channel static int lastfad=0; static u16 group=0; int i; Cs2Area->reg.CR1 = (Cs2Area->status << 8) | 0; Cs2Area->reg.CR2 = 12; Cs2Area->reg.CR3 = 0; if (Cs2Area->FAD != lastfad) { lastfad = Cs2Area->FAD; group = 0; } else group++; Cs2Area->reg.CR4 = group; // Subcode flag for (i = 0; i < 24; i++) Cs2Area->transscoderw[i] = Cs2Area->workblock.data[2352+i+(24*group)] & 0x3F; Cs2Area->transfercount = 0; Cs2Area->infotranstype = 4; break; } default: break; } Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_DRDY; } ////////////////////////////////////////////////////////////////////////////// void Cs2SetCDDeviceConnection(void) { u32 scdcfilternum; scdcfilternum = (Cs2Area->reg.CR3 >> 8); if (scdcfilternum == 0xFF) Cs2Area->outconcddev = NULL; else if (scdcfilternum < 0x24) Cs2Area->outconcddev = Cs2Area->filter + scdcfilternum; Cs2Area->outconcddevnum = (u8)scdcfilternum; doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetCDDeviceConnection(void) { Cs2Area->reg.CR1 = (Cs2Area->status << 8); Cs2Area->reg.CR2 = 0; Cs2Area->reg.CR3 = Cs2Area->outconcddevnum << 8; Cs2Area->reg.CR4 = 0; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetLastBufferDestination(void) { Cs2Area->reg.CR1 = (Cs2Area->status << 8); Cs2Area->reg.CR2 = 0; Cs2Area->reg.CR3 = Cs2Area->lastbuffer << 8; Cs2Area->reg.CR4 = 0; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2SetFilterRange(void) { u8 sfrfilternum; sfrfilternum = Cs2Area->reg.CR3 >> 8; Cs2Area->filter[sfrfilternum].FAD = ((Cs2Area->reg.CR1 & 0xFF) << 16) | Cs2Area->reg.CR2; Cs2Area->filter[sfrfilternum].range = ((Cs2Area->reg.CR3 & 0xFF) << 16) | Cs2Area->reg.CR4; // return default cd stats doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetFilterRange(void) { u8 sfrfilternum; sfrfilternum = Cs2Area->reg.CR3 >> 8; Cs2Area->reg.CR1 = (Cs2Area->status << 8) | ((Cs2Area->filter[sfrfilternum].FAD & 0xFF0000) >> 16); Cs2Area->reg.CR2 = Cs2Area->filter[sfrfilternum].FAD & 0xFFFF; Cs2Area->reg.CR3 = ((Cs2Area->filter[sfrfilternum].range & 0xFF0000) >> 16); Cs2Area->reg.CR4 = Cs2Area->filter[sfrfilternum].range & 0xFFFF; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2SetFilterSubheaderConditions(void) { u8 sfscfilternum; sfscfilternum = Cs2Area->reg.CR3 >> 8; Cs2Area->filter[sfscfilternum].chan = Cs2Area->reg.CR1 & 0xFF; Cs2Area->filter[sfscfilternum].smmask = Cs2Area->reg.CR2 >> 8; Cs2Area->filter[sfscfilternum].cimask = Cs2Area->reg.CR2 & 0xFF; Cs2Area->filter[sfscfilternum].fid = Cs2Area->reg.CR3 & 0xFF;; Cs2Area->filter[sfscfilternum].smval = Cs2Area->reg.CR4 >> 8; Cs2Area->filter[sfscfilternum].cival = Cs2Area->reg.CR4 & 0xFF; doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetFilterSubheaderConditions(void) { u8 gfscfilternum; gfscfilternum = Cs2Area->reg.CR3 >> 8; Cs2Area->reg.CR1 = (Cs2Area->status << 8) | Cs2Area->filter[gfscfilternum].chan; Cs2Area->reg.CR2 = (Cs2Area->filter[gfscfilternum].smmask << 8) | Cs2Area->filter[gfscfilternum].cimask; Cs2Area->reg.CR3 = Cs2Area->filter[gfscfilternum].fid; Cs2Area->reg.CR4 = (Cs2Area->filter[gfscfilternum].smval << 8) | Cs2Area->filter[gfscfilternum].cival; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2SetFilterMode(void) { u8 sfmfilternum; sfmfilternum = Cs2Area->reg.CR3 >> 8; Cs2Area->filter[sfmfilternum].mode = Cs2Area->reg.CR1 & 0xFF; if (Cs2Area->filter[sfmfilternum].mode & 0x80) { // Initialize filter conditions Cs2Area->filter[sfmfilternum].mode = 0; Cs2Area->filter[sfmfilternum].FAD = 0; Cs2Area->filter[sfmfilternum].range = 0; Cs2Area->filter[sfmfilternum].chan = 0; Cs2Area->filter[sfmfilternum].smmask = 0; Cs2Area->filter[sfmfilternum].cimask = 0; Cs2Area->filter[sfmfilternum].smval = 0; Cs2Area->filter[sfmfilternum].cival = 0; } doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetFilterMode(void) { u8 gfmfilternum; gfmfilternum = Cs2Area->reg.CR3 >> 8; Cs2Area->reg.CR1 = (Cs2Area->status << 8) | Cs2Area->filter[gfmfilternum].mode; Cs2Area->reg.CR2 = 0; Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2SetFilterConnection(void) { u8 sfcfilternum; sfcfilternum = Cs2Area->reg.CR3 >> 8; if (Cs2Area->reg.CR1 & 0x1) { // Set connection for true condition Cs2Area->filter[sfcfilternum].condtrue = Cs2Area->reg.CR2 >> 8; } if (Cs2Area->reg.CR1 & 0x2) { // Set connection for false condition Cs2Area->filter[sfcfilternum].condfalse = Cs2Area->reg.CR2 & 0xFF; } doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetFilterConnection(void) { u8 sfcfilternum; sfcfilternum = Cs2Area->reg.CR3 >> 8; Cs2Area->reg.CR1 = (Cs2Area->status << 8); Cs2Area->reg.CR2 = (Cs2Area->filter[sfcfilternum].condtrue << 8) | Cs2Area->filter[sfcfilternum].condfalse; Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2ResetSelector(void) { // still needs a bit of work u32 i, i2; if ((Cs2Area->reg.CR1 & 0xFF) == 0) { // Reset specified partition buffer only u32 rsbufno = Cs2Area->reg.CR3 >> 8; // sort remaining blocks if (rsbufno < MAX_SELECTORS) { // clear partition for (i = 0; i < Cs2Area->partition[rsbufno].numblocks; i++) { Cs2FreeBlock(Cs2Area->partition[rsbufno].block[i]); Cs2Area->partition[rsbufno].block[i] = NULL; Cs2Area->partition[rsbufno].blocknum[i] = 0xFF; } Cs2Area->partition[rsbufno].size = -1; Cs2Area->partition[rsbufno].numblocks = 0; } if (Cs2Area->blockfreespace > 0) Cs2Area->isbufferfull = 0; if (Cs2Area->blockfreespace == 200) { Cs2Area->isonesectorstored = 0; Cs2Area->datatranstype = CDB_DATATRANSTYPE_INVALID; } else if (Cs2Area->datatranspartitionnum == rsbufno) Cs2Area->datatranstype = CDB_DATATRANSTYPE_INVALID; doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; return; } // parse flags and reset the specified area(fix me) if (Cs2Area->reg.CR1 & 0x80) { // reset false filter output connections for (i = 0; i < MAX_SELECTORS; i++) Cs2Area->filter[i].condfalse = 0xFF; } if (Cs2Area->reg.CR1 & 0x40) { // reset true filter output connections for (i = 0; i < MAX_SELECTORS; i++) Cs2Area->filter[i].condtrue = (u8)i; } if (Cs2Area->reg.CR1 & 0x10) { // reset filter conditions for (i = 0; i < MAX_SELECTORS; i++) { Cs2Area->filter[i].FAD = 0; Cs2Area->filter[i].range = 0xFFFFFFFF; Cs2Area->filter[i].mode = 0; Cs2Area->filter[i].chan = 0; Cs2Area->filter[i].smmask = 0; Cs2Area->filter[i].cimask = 0; Cs2Area->filter[i].fid = 0; Cs2Area->filter[i].smval = 0; Cs2Area->filter[i].cival = 0; } } if (Cs2Area->reg.CR1 & 0x8) { // reset partition output connectors } if (Cs2Area->reg.CR1 & 0x4) { // reset partitions buffer data Cs2Area->isbufferfull = 0; // clear partitions for (i = 0; i < MAX_SELECTORS; i++) { Cs2Area->partition[i].size = -1; Cs2Area->partition[i].numblocks = 0; for (i2 = 0; i2 < MAX_BLOCKS; i2++) { Cs2Area->partition[i].block[i2] = NULL; Cs2Area->partition[i].blocknum[i2] = 0xFF; } } // clear blocks for (i = 0; i < MAX_BLOCKS; i++) { Cs2Area->block[i].size = -1; memset(Cs2Area->block[i].data, 0, 2352); } Cs2Area->isonesectorstored = 0; Cs2Area->datatranstype = CDB_DATATRANSTYPE_INVALID; } doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetBufferSize(void) { Cs2Area->reg.CR1 = Cs2Area->status << 8; Cs2Area->reg.CR2 = (u16)Cs2Area->blockfreespace; Cs2Area->reg.CR3 = MAX_SELECTORS << 8; Cs2Area->reg.CR4 = MAX_BLOCKS; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetSectorNumber(void) { u32 gsnbufno; gsnbufno = Cs2Area->reg.CR3 >> 8; if (Cs2Area->partition[gsnbufno].size == -1) Cs2Area->reg.CR4 = 0; else Cs2Area->reg.CR4 = Cs2Area->partition[gsnbufno].numblocks; Cs2Area->reg.CR1 = Cs2Area->status << 8; Cs2Area->reg.CR2 = 0; Cs2Area->reg.CR3 = 0; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_DRDY; } ////////////////////////////////////////////////////////////////////////////// void Cs2CalculateActualSize(void) { u16 i; u32 casbufno; u16 cassectoffset; u16 casnumsect; cassectoffset = Cs2Area->reg.CR2; casbufno = Cs2Area->reg.CR3 >> 8; casnumsect = Cs2Area->reg.CR4; if (Cs2Area->partition[casbufno].size != 0) { Cs2Area->calcsize = 0; for (i = 0; i < casnumsect; i++) { if (Cs2Area->partition[casbufno].block[cassectoffset]) Cs2Area->calcsize += (Cs2Area->partition[casbufno].block[cassectoffset]->size / 2); } } else Cs2Area->calcsize = 0; doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetActualSize(void) { Cs2Area->reg.CR1 = (u16)((Cs2Area->status << 8) | ((Cs2Area->calcsize >> 16) & 0xFF)); Cs2Area->reg.CR2 = (u16)Cs2Area->calcsize; Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetSectorInfo(void) { u32 gsisctnum; u32 gsibufno; gsisctnum = Cs2Area->reg.CR2 & 0xFF; gsibufno = Cs2Area->reg.CR3 >> 8; if (gsibufno < MAX_SELECTORS) { if (gsisctnum < Cs2Area->partition[gsibufno].numblocks) { Cs2Area->reg.CR1 = (u16)((Cs2Area->status << 8) | ((Cs2Area->partition[gsibufno].block[gsisctnum]->FAD >> 16) & 0xFF)); Cs2Area->reg.CR2 = (u16)Cs2Area->partition[gsibufno].block[gsisctnum]->FAD; Cs2Area->reg.CR3 = (Cs2Area->partition[gsibufno].block[gsisctnum]->fn << 8) | Cs2Area->partition[gsibufno].block[gsisctnum]->cn; Cs2Area->reg.CR4 = (Cs2Area->partition[gsibufno].block[gsisctnum]->sm << 8) | Cs2Area->partition[gsibufno].block[gsisctnum]->ci; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; return; } else { CDLOG("cs2\t: getSectorInfo: Unsupported Partition Number\n"); } } Cs2Area->reg.CR1 = (CDB_STAT_REJECT << 8) | (Cs2Area->reg.CR1 & 0xFF); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2ExecFadSearch(void) { // finish me doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetFadSearchResults(void) { // finish me Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2SetSectorLength(void) { switch (Cs2Area->reg.CR1 & 0xFF) { case 0: Cs2Area->getsectsize = 2048; break; case 1: Cs2Area->getsectsize = 2336; break; case 2: Cs2Area->getsectsize = 2340; break; case 3: Cs2Area->getsectsize = 2352; break; default: break; } switch (Cs2Area->reg.CR2 >> 8) { case 0: Cs2Area->putsectsize = 2048; break; case 1: Cs2Area->putsectsize = 2336; break; case 2: Cs2Area->putsectsize = 2340; break; case 3: Cs2Area->putsectsize = 2352; break; default: break; } doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ESEL; } ////////////////////////////////////////////////////////////////////////////// static INLINE void CalcSectorOffsetNumber(u32 bufno, u32 *sectoffset, u32 *sectnum) { if (*sectoffset == 0xFFFF) { // Last sector CDLOG("FIXME - Sector offset of 0xFFFF not supported\n"); } else if (*sectnum == 0xFFFF) { // From sectoffset to last sector in partition *sectnum = Cs2Area->partition[bufno].numblocks - *sectoffset; } } ////////////////////////////////////////////////////////////////////////////// void Cs2GetSectorData(void) { u32 gsdsectoffset; u32 gsdbufno; u32 gsdsectnum; gsdsectoffset = Cs2Area->reg.CR2; gsdbufno = Cs2Area->reg.CR3 >> 8; gsdsectnum = Cs2Area->reg.CR4; if (gsdbufno >= MAX_SELECTORS) { doCDReport(CDB_STAT_REJECT); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EHST; return; } if (Cs2Area->partition[gsdbufno].numblocks == 0) { CDLOG("No sectors available\n"); doCDReport(CDB_STAT_REJECT); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EHST; return; } CalcSectorOffsetNumber(gsdbufno, &gsdsectoffset, &gsdsectnum); // Setup Data Transfer Cs2Area->cdwnum = 0; Cs2Area->datatranstype = CDB_DATATRANSTYPE_GETSECTOR; Cs2Area->datatranspartition = Cs2Area->partition + gsdbufno; Cs2Area->datatranspartitionnum = (u8)gsdbufno; Cs2Area->datatransoffset = 0; Cs2Area->datanumsecttrans = 0; Cs2Area->datatranssectpos = (u16)gsdsectoffset; Cs2Area->datasectstotrans = (u16)gsdsectnum; doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_DRDY | CDB_HIRQ_EHST; } ////////////////////////////////////////////////////////////////////////////// void Cs2DeleteSectorData(void) { u32 dsdsectoffset; u32 dsdbufno; u32 dsdsectnum; u32 i; dsdsectoffset = Cs2Area->reg.CR2; dsdbufno = Cs2Area->reg.CR3 >> 8; dsdsectnum = Cs2Area->reg.CR4; if (dsdbufno >= MAX_SELECTORS) { doCDReport(CDB_STAT_REJECT); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EHST; return; } if (Cs2Area->partition[dsdbufno].numblocks == 0) { CDLOG("No sectors available\n"); doCDReport(CDB_STAT_REJECT); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EHST; return; } CalcSectorOffsetNumber(dsdbufno, &dsdsectoffset, &dsdsectnum); for (i = dsdsectoffset; i < (dsdsectoffset+dsdsectnum); i++) { Cs2Area->partition[dsdbufno].size -= Cs2Area->partition[dsdbufno].block[i]->size; Cs2FreeBlock(Cs2Area->partition[dsdbufno].block[i]); Cs2Area->partition[dsdbufno].block[i] = NULL; Cs2Area->partition[dsdbufno].blocknum[i] = 0xFF; } // sort remaining blocks Cs2SortBlocks(&Cs2Area->partition[dsdbufno]); Cs2Area->partition[dsdbufno].numblocks -= (u8)dsdsectnum; if (Cs2Area->blockfreespace == 200) Cs2Area->isonesectorstored = 0; doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EHST; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetThenDeleteSectorData(void) { u32 gtdsdsectoffset; u32 gtdsdbufno; u32 gtdsdsectnum; gtdsdsectoffset = Cs2Area->reg.CR2; gtdsdbufno = Cs2Area->reg.CR3 >> 8; gtdsdsectnum = Cs2Area->reg.CR4; if (gtdsdbufno >= MAX_SELECTORS) { doCDReport(CDB_STAT_REJECT); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EHST; return; } if (Cs2Area->partition[gtdsdbufno].numblocks == 0) { CDLOG("No sectors available\n"); doCDReport(CDB_STAT_REJECT); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EHST; return; } CalcSectorOffsetNumber(gtdsdbufno, >dsdsectoffset, >dsdsectnum); // Setup Data Transfer Cs2Area->cdwnum = 0; Cs2Area->datatranstype = CDB_DATATRANSTYPE_GETDELSECTOR; Cs2Area->datatranspartition = Cs2Area->partition + gtdsdbufno; Cs2Area->datatransoffset = 0; Cs2Area->datanumsecttrans = 0; Cs2Area->datatranssectpos = (u16)gtdsdsectoffset; Cs2Area->datasectstotrans = (u16)gtdsdsectnum; doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_DRDY | CDB_HIRQ_EHST; return; } ////////////////////////////////////////////////////////////////////////////// void Cs2PutSectorData(void) { u32 psdbufno; u32 psdsectnum; psdbufno = Cs2Area->reg.CR3 >> 8; psdsectnum = Cs2Area->reg.CR4; if (psdbufno < MAX_SELECTORS) { // Make sure there's enough free space if (psdsectnum > Cs2Area->blockfreespace) Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EHST; else { // Allocate buffer IOCheck_struct check = { 0, 0 }; partition_struct *putpartition = &Cs2Area->partition[psdbufno]; u32 i; putpartition->size = 0; for (i = 0; i < psdsectnum; i++) { putpartition->block[putpartition->numblocks] = Cs2AllocateBlock(&putpartition->blocknum[putpartition->numblocks], Cs2Area->putsectsize); putpartition->block[putpartition->numblocks]->FAD = i; putpartition->numblocks++; putpartition->size += Cs2Area->putsectsize; } // Setup Data Transfer Cs2Area->cdwnum = 0; Cs2Area->datatranstype = CDB_DATATRANSTYPE_PUTSECTOR; Cs2Area->datatranspartition = Cs2Area->partition + psdbufno; Cs2Area->datatranspartitionnum = (u8)psdbufno; Cs2Area->datatransoffset = 0; Cs2Area->datanumsecttrans = 0; Cs2Area->datatranssectpos = 0; Cs2Area->datasectstotrans = (u16)psdsectnum; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_DRDY; } } else { doCDReport(CDB_STAT_REJECT); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EHST; } } ////////////////////////////////////////////////////////////////////////////// void Cs2CopySectorData(void) { // finish me doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ECPY; } ////////////////////////////////////////////////////////////////////////////// void Cs2MoveSectorData(void) { // finish me doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_ECPY; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetCopyError(void) { Cs2Area->reg.CR1 = Cs2Area->status << 8; Cs2Area->reg.CR2 = 0; Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2ChangeDirectory(void) { u32 cdfilternum; cdfilternum = (Cs2Area->reg.CR3 >> 8); if (cdfilternum == 0xFF) { doCDReport(CDB_STAT_REJECT); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EFLS; return; } else if (cdfilternum < 0x24) { if (Cs2ReadFileSystem(Cs2Area->filter + cdfilternum, ((Cs2Area->reg.CR3 & 0xFF) << 16) | Cs2Area->reg.CR4, 0) != 0) { CDLOG("cs2\t: ReadFileSystem failed\n"); doCDReport(CDB_STAT_REJECT); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EFLS; return; } } doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EFLS; } ////////////////////////////////////////////////////////////////////////////// void Cs2ReadDirectory(void) { u32 rdfilternum; rdfilternum = (Cs2Area->reg.CR3 >> 8); if (rdfilternum == 0xFF) { doCDReport(CDB_STAT_REJECT); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EFLS; return; } else if (rdfilternum < 0x24) { if (Cs2ReadFileSystem(Cs2Area->filter + rdfilternum, ((Cs2Area->reg.CR3 & 0xFF) << 8) | Cs2Area->reg.CR4, 1) != 0) { CDLOG("cs2\t: ReadFileSystem failed\n"); doCDReport(CDB_STAT_REJECT); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EFLS; return; } } doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EFLS; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetFileSystemScope(void) { // may need to fix this Cs2Area->reg.CR1 = Cs2Area->status << 8; Cs2Area->reg.CR2 = (u16)(Cs2Area->numfiles - 2); Cs2Area->reg.CR3 = 0x0100; Cs2Area->reg.CR4 = 0x0002; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EFLS; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetFileInfo(void) { u32 gfifid; gfifid = ((Cs2Area->reg.CR3 & 0xFF) << 16) | Cs2Area->reg.CR4; if (gfifid == 0xFFFFFF) { Cs2Area->transfercount = 0; Cs2Area->infotranstype = 2; Cs2Area->reg.CR1 = Cs2Area->status << 8; Cs2Area->reg.CR2 = 0x05F4; Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; } else { Cs2SetupFileInfoTransfer(gfifid); Cs2Area->transfercount = 0; Cs2Area->infotranstype = 1; Cs2Area->reg.CR1 = Cs2Area->status << 8; Cs2Area->reg.CR2 = 0x06; Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; } Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_DRDY; } ////////////////////////////////////////////////////////////////////////////// void Cs2ReadFile(void) { u32 rfoffset, rffilternum, rffid, rfsize; rfoffset = ((Cs2Area->reg.CR1 & 0xFF) << 8) | Cs2Area->reg.CR2; rffilternum = Cs2Area->reg.CR3 >> 8; rffid = ((Cs2Area->reg.CR3 & 0xFF) << 8) | Cs2Area->reg.CR4; rfsize = ((Cs2Area->fileinfo[rffid].size + Cs2Area->getsectsize - 1) / Cs2Area->getsectsize) - rfoffset; Cs2SetupDefaultPlayStats(Cs2FADToTrack(Cs2Area->fileinfo[rffid].lba + rfoffset), 0); Cs2Area->maxrepeat = 0; Cs2Area->playFAD = Cs2Area->FAD = Cs2Area->fileinfo[rffid].lba + rfoffset; Cs2Area->playendFAD = Cs2Area->playFAD + rfsize; Cs2Area->options = 0x8; Cs2SetTiming(1); Cs2Area->outconcddev = Cs2Area->filter + rffilternum; Cs2Area->status = CDB_STAT_PLAY; Cs2Area->playtype = CDB_PLAYTYPE_FILE; Cs2Area->cdi->ReadAheadFAD(Cs2Area->FAD); doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2AbortFile(void) { if ((Cs2Area->status & 0xF) != CDB_STAT_OPEN && (Cs2Area->status & 0xF) != CDB_STAT_NODISC) Cs2Area->status = CDB_STAT_PAUSE; Cs2Area->isonesectorstored = 0; Cs2Area->datatranstype = CDB_DATATRANSTYPE_INVALID; Cs2Area->cdwnum = 0; doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_EFLS; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegGetStatus(void) { doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegGetInterrupt(void) { u32 mgiworkinterrupt; // mpeg interrupt should be retrieved here mgiworkinterrupt = 0; // mask interupt mgiworkinterrupt &= Cs2Area->mpegintmask; Cs2Area->reg.CR1 = (u16)((Cs2Area->status << 8) | ((mgiworkinterrupt >> 16) & 0xFF)); Cs2Area->reg.CR2 = (u16) mgiworkinterrupt; Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegSetInterruptMask(void) { Cs2Area->mpegintmask = ((Cs2Area->reg.CR1 & 0xFF) << 16) | Cs2Area->reg.CR2; doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegInit(void) { if (Cs2Area->mpgauth) Cs2Area->reg.CR1 = Cs2Area->status << 8; else Cs2Area->reg.CR1 = 0xFF00; // double-check this if (Cs2Area->reg.CR2 == 0x0001) // software timer/reset? Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM | CDB_HIRQ_MPED | CDB_HIRQ_MPST; else Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPED | CDB_HIRQ_MPST; Cs2Area->reg.CR2 = 0; Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; // future mpeg-related variables should be initialized here } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegSetMode(void) { u8 vidplaymode=Cs2Area->reg.CR1 & 0xFF; u8 dectimingmode=Cs2Area->reg.CR2 >> 8; u8 outmode=Cs2Area->reg.CR2 & 0xFF; u8 slmode=Cs2Area->reg.CR3 >> 8; if (vidplaymode != 0xFF) Cs2Area->mpegmode.vidplaymode = vidplaymode; if (dectimingmode != 0xFF) Cs2Area->mpegmode.dectimingmode = dectimingmode; if (outmode != 0xFF) Cs2Area->mpegmode.outmode = outmode; if (slmode != 0xFF) Cs2Area->mpegmode.slmode = slmode; doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegPlay(void) { // fix me doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegSetDecodingMethod(void) { // fix me doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegSetConnection(void) { int mscnext = (Cs2Area->reg.CR3 >> 8); if (mscnext == 0) { // Current Cs2Area->mpegcon[0].audcon = Cs2Area->reg.CR1 & 0xFF; Cs2Area->mpegcon[0].audlay = Cs2Area->reg.CR2 >> 8; Cs2Area->mpegcon[0].audbufnum = Cs2Area->reg.CR2 & 0xFF; Cs2Area->mpegcon[0].vidcon = Cs2Area->reg.CR3 & 0xFF; Cs2Area->mpegcon[0].vidlay = Cs2Area->reg.CR4 >> 8; Cs2Area->mpegcon[0].vidbufnum = Cs2Area->reg.CR4 & 0xFF; } else { // Next Cs2Area->mpegcon[1].audcon = Cs2Area->reg.CR1 & 0xFF; Cs2Area->mpegcon[1].audlay = Cs2Area->reg.CR2 >> 8; Cs2Area->mpegcon[1].audbufnum = Cs2Area->reg.CR2 & 0xFF; Cs2Area->mpegcon[1].vidcon = Cs2Area->reg.CR3 & 0xFF; Cs2Area->mpegcon[1].vidlay = Cs2Area->reg.CR4 >> 8; Cs2Area->mpegcon[1].vidbufnum = Cs2Area->reg.CR4 & 0xFF; } doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegGetConnection(void) { int mgcnext = (Cs2Area->reg.CR3 >> 8); if (mgcnext == 0) { // Current Cs2Area->reg.CR1 = (Cs2Area->status << 8) | Cs2Area->mpegcon[0].audcon; Cs2Area->reg.CR2 = (Cs2Area->mpegcon[0].audlay << 8) | Cs2Area->mpegcon[0].audbufnum; Cs2Area->reg.CR3 = Cs2Area->mpegcon[0].vidcon; Cs2Area->reg.CR4 = (Cs2Area->mpegcon[0].vidlay << 8) | Cs2Area->mpegcon[0].vidbufnum; } else { // Next Cs2Area->reg.CR1 = (Cs2Area->status << 8) | Cs2Area->mpegcon[1].audcon; Cs2Area->reg.CR2 = (Cs2Area->mpegcon[1].audlay << 8) | Cs2Area->mpegcon[1].audbufnum; Cs2Area->reg.CR3 = Cs2Area->mpegcon[1].vidcon; Cs2Area->reg.CR4 = (Cs2Area->mpegcon[1].vidlay << 8) | Cs2Area->mpegcon[1].vidbufnum; } Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegSetStream(void) { int mssnext = (Cs2Area->reg.CR3 >> 8); if (mssnext == 0) { // Current Cs2Area->mpegstm[0].audstm = Cs2Area->reg.CR1 & 0xFF; Cs2Area->mpegstm[0].audstmid = Cs2Area->reg.CR2 >> 8; Cs2Area->mpegstm[0].audchannum = Cs2Area->reg.CR2 & 0xFF; Cs2Area->mpegstm[0].vidstm = Cs2Area->reg.CR3 & 0xFF; Cs2Area->mpegstm[0].vidstmid = Cs2Area->reg.CR4 >> 8; Cs2Area->mpegstm[0].vidchannum = Cs2Area->reg.CR4 & 0xFF; } else { // Next Cs2Area->mpegstm[1].audstm = Cs2Area->reg.CR1 & 0xFF; Cs2Area->mpegstm[1].audstmid = Cs2Area->reg.CR2 >> 8; Cs2Area->mpegstm[1].audchannum = Cs2Area->reg.CR2 & 0xFF; Cs2Area->mpegstm[1].vidstm = Cs2Area->reg.CR3 & 0xFF; Cs2Area->mpegstm[1].vidstmid = Cs2Area->reg.CR4 >> 8; Cs2Area->mpegstm[1].vidchannum = Cs2Area->reg.CR4 & 0xFF; } doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegGetStream(void) { int mgsnext = (Cs2Area->reg.CR3 >> 8); if (mgsnext == 0) { // Current Cs2Area->reg.CR1 = (Cs2Area->status << 8) | Cs2Area->mpegstm[0].audstm; Cs2Area->reg.CR2 = (Cs2Area->mpegstm[0].audstmid << 8) | Cs2Area->mpegstm[0].audchannum; Cs2Area->reg.CR3 = Cs2Area->mpegstm[0].vidstm; Cs2Area->reg.CR4 = (Cs2Area->mpegstm[0].vidstmid << 8) | Cs2Area->mpegstm[0].vidchannum; } else { // Next Cs2Area->reg.CR1 = (Cs2Area->status << 8) | Cs2Area->mpegstm[1].audstm; Cs2Area->reg.CR2 = (Cs2Area->mpegstm[1].audstmid << 8) | Cs2Area->mpegstm[1].audchannum; Cs2Area->reg.CR3 = Cs2Area->mpegstm[1].vidstm; Cs2Area->reg.CR4 = (Cs2Area->mpegstm[1].vidstmid << 8) | Cs2Area->mpegstm[1].vidchannum; } Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegDisplay(void) { // fix me(should be setting display setting) doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegSetWindow(void) { // fix me(should be setting windows settings) // return default mpeg stats doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegSetBorderColor(void) { // fix me(should be setting border color) doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegSetFade(void) { // fix me(should be setting fade setting) doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegSetVideoEffects(void) { // fix me(should be setting video effects settings) doMPEGReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2MpegSetLSI(void) { // fix me(should be setting the LSI, among other things) Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPCM; } ////////////////////////////////////////////////////////////////////////////// void Cs2AuthenticateDevice(void) { int mpegauth; mpegauth = Cs2Area->reg.CR2 & 0xFF; if ((Cs2Area->status & 0xF) != CDB_STAT_NODISC && (Cs2Area->status & 0xF) != CDB_STAT_OPEN) { // Set registers all to invalid values(aside from status) Cs2Area->status = CDB_STAT_BUSY; Cs2Area->reg.CR1 = (Cs2Area->status << 8) | 0xFF; Cs2Area->reg.CR2 = 0xFFFF; Cs2Area->reg.CR3 = 0xFFFF; Cs2Area->reg.CR4 = 0xFFFF; if (mpegauth == 1) { Cs2Area->reg.HIRQ |= CDB_HIRQ_MPED; Cs2Area->mpgauth = 2; } else { // if authentication passes(obviously it always does), CDB_HIRQ_CSCT is set Cs2Area->isonesectorstored = 1; Cs2Area->reg.HIRQ |= CDB_HIRQ_EFLS | CDB_HIRQ_CSCT; Cs2Area->satauth = 4; } // Set registers all back to normal values Cs2Area->status = CDB_STAT_PAUSE; } else { if (mpegauth == 1) { Cs2Area->reg.HIRQ |= CDB_HIRQ_MPED; Cs2Area->mpgauth = 2; } else Cs2Area->reg.HIRQ |= CDB_HIRQ_EFLS | CDB_HIRQ_CSCT; } doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2IsDeviceAuthenticated(void) { Cs2Area->reg.CR1 = (Cs2Area->status << 8); if (Cs2Area->reg.CR2) Cs2Area->reg.CR2 = Cs2Area->mpgauth; else Cs2Area->reg.CR2 = Cs2Area->satauth; Cs2Area->reg.CR3 = 0; Cs2Area->reg.CR4 = 0; Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK; } ////////////////////////////////////////////////////////////////////////////// void Cs2GetMPEGRom(void) { u16 i; FILE * mpgfp; partition_struct * mpgpartition; // fix me Cs2Area->mpgauth |= 0x300; Cs2Area->outconmpegrom = Cs2Area->filter + 0; Cs2Area->outconmpegromnum = 0; if (Cs2Area->mpegpath && (mpgfp = fopen(Cs2Area->mpegpath, "rb")) != NULL) { u32 readoffset = ((Cs2Area->reg.CR1 & 0xFF) << 8) | Cs2Area->reg.CR2; u16 readsize = Cs2Area->reg.CR4; fseek(mpgfp, readoffset * Cs2Area->getsectsize, SEEK_SET); if ((mpgpartition = Cs2GetPartition(Cs2Area->outconmpegrom)) != NULL && !Cs2Area->isbufferfull) { IOCheck_struct check = { 0, 0 }; mpgpartition->size = 0; for (i = 0; i < readsize; i++) { mpgpartition->block[mpgpartition->numblocks] = Cs2AllocateBlock(&mpgpartition->blocknum[mpgpartition->numblocks], Cs2Area->getsectsize); if (mpgpartition->block[mpgpartition->numblocks] != NULL) { // read data yread(&check, (void *)mpgpartition->block[mpgpartition->numblocks]->data, 1, Cs2Area->getsectsize, mpgfp); mpgpartition->numblocks++; mpgpartition->size += Cs2Area->getsectsize; } } Cs2Area->isonesectorstored = 1; Cs2Area->reg.HIRQ |= CDB_HIRQ_CSCT; } fclose(mpgfp); } doCDReport(Cs2Area->status); Cs2Area->reg.HIRQ |= CDB_HIRQ_CMOK | CDB_HIRQ_MPED; } ////////////////////////////////////////////////////////////////////////////// u8 Cs2FADToTrack(u32 val) { int i; for (i = 0; i < 99; i++) { if (Cs2Area->TOC[i] == 0xFFFFFFFF) return 0xFF; if (val >= (Cs2Area->TOC[i] & 0xFFFFFF) && val < (Cs2Area->TOC[i + 1] & 0xFFFFFF)) return (i + 1); } return 0; } ////////////////////////////////////////////////////////////////////////////// u32 Cs2TrackToFAD(u16 trackandindex) { if (trackandindex == 0xFFFF) // leadout position return (Cs2Area->TOC[101] & 0x00FFFFFF); if (trackandindex != 0x0000) { // regular track // (really, we should be fetching subcode q's here) if ((trackandindex & 0xFF) == 0x01) // Return Start of Track return (Cs2Area->TOC[(trackandindex >> 8) - 1] & 0x00FFFFFF); else if ((trackandindex & 0xFF) == 0x63) // Return End of Track return ((Cs2Area->TOC[(trackandindex >> 8)] & 0x00FFFFFF) - 1); } // assume it's leadin return 0; } ////////////////////////////////////////////////////////////////////////////// void Cs2FADToMSF(u32 val, u8 *m, u8 *s, u8 *f) { u32 temp; m[0] = val / 4500; temp = val % 4500; s[0] = temp / 75; f[0] = temp % 75; } ////////////////////////////////////////////////////////////////////////////// void Cs2SetupDefaultPlayStats(u8 track_number, int writeFAD) { if (track_number != 0xFF) { Cs2Area->options = 0; Cs2Area->repcnt = 0; Cs2Area->ctrladdr = (u8)(Cs2Area->TOC[track_number - 1] >> 24); Cs2Area->index = 1; Cs2Area->track = track_number; if (writeFAD) Cs2Area->FAD = Cs2Area->TOC[track_number - 1] & 0x00FFFFFF; } } ////////////////////////////////////////////////////////////////////////////// block_struct * Cs2AllocateBlock(u8 * blocknum, s32 sectsize) { u32 i; // find a free block for(i = 0; i < 200; i++) { if (Cs2Area->block[i].size == -1) { Cs2Area->blockfreespace--; if (Cs2Area->blockfreespace <= 0) Cs2Area->isbufferfull = 1; Cs2Area->block[i].size = sectsize; *blocknum = (u8)i; return (Cs2Area->block + i); } } Cs2Area->isbufferfull = 1; return NULL; } ////////////////////////////////////////////////////////////////////////////// void Cs2FreeBlock(block_struct * blk) { if (blk == NULL) return; blk->size = -1; Cs2Area->blockfreespace++; Cs2Area->isbufferfull = 0; Cs2Area->reg.HIRQ &= ~CDB_HIRQ_BFUL; } ////////////////////////////////////////////////////////////////////////////// void Cs2SortBlocks(partition_struct * part) { unsigned int from, to; for (from = to = 0; from < MAX_BLOCKS; from++) { if (part->block[from] != NULL) { if (to != from) { part->block[to] = part->block[from]; } to++; } } for (; to < MAX_BLOCKS; to++) { part->block[to] = NULL; } } ////////////////////////////////////////////////////////////////////////////// partition_struct * Cs2GetPartition(filter_struct * curfilter) { // go through various filter conditions here(fix me) return &Cs2Area->partition[curfilter->condtrue]; } ////////////////////////////////////////////////////////////////////////////// partition_struct * Cs2FilterData(filter_struct * curfilter, int isaudio) { int condresults; partition_struct * fltpartition = NULL; for (;;) { // reset result condresults = 1; // detect which type of sector we're dealing with // If it's not mode 2, ignore the subheader conditions if (Cs2Area->workblock.data[0xF] == 0x02 && !isaudio) { // Mode 2 // go through various subheader filter conditions if (curfilter->mode & 0x01) { // File Number Check if (Cs2Area->workblock.fn != curfilter->fid) condresults = 0; } if (curfilter->mode & 0x02) { // Channel Number Check if (Cs2Area->workblock.cn != curfilter->chan) condresults = 0; } if (curfilter->mode & 0x04) { // Sub Mode Check if ((Cs2Area->workblock.sm & curfilter->smmask) != curfilter->smval) condresults = 0; } if (curfilter->mode & 0x08) { // Coding Information Check CDLOG("cs2\t: FilterData: Coding Information Check. Coding Information = %02X. Filter's Coding Information Mask = %02X, Coding Information Value = %02X\n", Cs2Area->workblock.ci, curfilter->cimask, curfilter->cival); if ((Cs2Area->workblock.ci & curfilter->cimask) != curfilter->cival) condresults = 0; } if (curfilter->mode & 0x10) { // Reverse Subheader Conditions CDLOG("cs2\t: FilterData: Reverse Subheader Conditions\n"); condresults ^= 1; } } if (curfilter->mode & 0x40) { // FAD Range Check if (Cs2Area->workblock.FAD < curfilter->FAD || Cs2Area->workblock.FAD >= (curfilter->FAD+curfilter->range)) condresults = 0; } if (condresults == 1) { Cs2Area->lastbuffer = curfilter->condtrue; fltpartition = &Cs2Area->partition[curfilter->condtrue]; break; } else { Cs2Area->lastbuffer = curfilter->condfalse; if (curfilter->condfalse == 0xFF) return NULL; // loop and try filter that was connected to the false connector curfilter = &Cs2Area->filter[curfilter->condfalse]; } } // Allocate block fltpartition->block[fltpartition->numblocks] = Cs2AllocateBlock(&fltpartition->blocknum[fltpartition->numblocks], Cs2Area->getsectsize); if (fltpartition->block[fltpartition->numblocks] == NULL) return NULL; // Copy workblock settings to allocated block fltpartition->block[fltpartition->numblocks]->size = Cs2Area->workblock.size; fltpartition->block[fltpartition->numblocks]->FAD = Cs2Area->workblock.FAD; fltpartition->block[fltpartition->numblocks]->cn = Cs2Area->workblock.cn; fltpartition->block[fltpartition->numblocks]->fn = Cs2Area->workblock.fn; fltpartition->block[fltpartition->numblocks]->sm = Cs2Area->workblock.sm; fltpartition->block[fltpartition->numblocks]->ci = Cs2Area->workblock.ci; // convert raw sector to type specified in getsectsize switch(Cs2Area->workblock.size) { case 2048: // user data only if (Cs2Area->workblock.data[0xF] == 0x02) // m2f1 memcpy(fltpartition->block[fltpartition->numblocks]->data, Cs2Area->workblock.data + 24, Cs2Area->workblock.size); else // m1 memcpy(fltpartition->block[fltpartition->numblocks]->data, Cs2Area->workblock.data + 16, Cs2Area->workblock.size); break; case 2324: // m2f2 user data only memcpy(fltpartition->block[fltpartition->numblocks]->data, Cs2Area->workblock.data + 24, Cs2Area->workblock.size); break; case 2336: // m2f2 skip sync+header data memcpy(fltpartition->block[fltpartition->numblocks]->data, Cs2Area->workblock.data + 16, Cs2Area->workblock.size); break; case 2340: // m2f2 skip sync data memcpy(fltpartition->block[fltpartition->numblocks]->data, Cs2Area->workblock.data + 12, Cs2Area->workblock.size); break; case 2352: // Copy data as is memcpy(fltpartition->block[fltpartition->numblocks]->data, Cs2Area->workblock.data, Cs2Area->workblock.size); break; default: break; } // Modify Partition values if (fltpartition->size == -1) fltpartition->size = 0; fltpartition->size += fltpartition->block[fltpartition->numblocks]->size; fltpartition->numblocks++; return fltpartition; } ////////////////////////////////////////////////////////////////////////////// int Cs2CopyDirRecord(u8 * buffer, dirrec_struct * dirrec) { u8 * temp_pointer; temp_pointer = buffer; memcpy(&dirrec->recordsize, buffer, sizeof(dirrec->recordsize)); buffer += sizeof(dirrec->recordsize); memcpy(&dirrec->xarecordsize, buffer, sizeof(dirrec->xarecordsize)); buffer += sizeof(dirrec->xarecordsize); #ifdef WORDS_BIGENDIAN buffer += sizeof(dirrec->lba); memcpy(&dirrec->lba, buffer, sizeof(dirrec->lba)); buffer += sizeof(dirrec->lba); #else memcpy(&dirrec->lba, buffer, sizeof(dirrec->lba)); buffer += (sizeof(dirrec->lba) * 2); #endif #ifdef WORDS_BIGENDIAN buffer += sizeof(dirrec->size); memcpy(&dirrec->size, buffer, sizeof(dirrec->size)); buffer += sizeof(dirrec->size); #else memcpy(&dirrec->size, buffer, sizeof(dirrec->size)); buffer += (sizeof(dirrec->size) * 2); #endif dirrec->dateyear = buffer[0]; dirrec->datemonth = buffer[1]; dirrec->dateday = buffer[2]; dirrec->datehour = buffer[3]; dirrec->dateminute = buffer[4]; dirrec->datesecond = buffer[5]; dirrec->gmtoffset = buffer[6]; buffer += 7; dirrec->flags = buffer[0]; buffer += sizeof(dirrec->flags); dirrec->fileunitsize = buffer[0]; buffer += sizeof(dirrec->fileunitsize); dirrec->interleavegapsize = buffer[0]; buffer += sizeof(dirrec->interleavegapsize); #ifdef WORDS_BIGENDIAN buffer += sizeof(dirrec->volumesequencenumber); memcpy(&dirrec->volumesequencenumber, buffer, sizeof(dirrec->volumesequencenumber)); buffer += sizeof(dirrec->volumesequencenumber); #else memcpy(&dirrec->volumesequencenumber, buffer, sizeof(dirrec->volumesequencenumber)); buffer += (sizeof(dirrec->volumesequencenumber) * 2); #endif dirrec->namelength = buffer[0]; buffer += sizeof(dirrec->namelength); memset(dirrec->name, 0, sizeof(dirrec->name)); memcpy(dirrec->name, buffer, dirrec->namelength); buffer += dirrec->namelength; // handle padding buffer += (1 - dirrec->namelength % 2); memset(&dirrec->xarecord, 0, sizeof(dirrec->xarecord)); // sadily, this is the best way I can think of for detecting XA records if ((dirrec->recordsize - (buffer - temp_pointer)) == 14) { memcpy(&dirrec->xarecord.groupid, buffer, sizeof(dirrec->xarecord.groupid)); buffer += sizeof(dirrec->xarecord.groupid); memcpy(&dirrec->xarecord.userid, buffer, sizeof(dirrec->xarecord.userid)); buffer += sizeof(dirrec->xarecord.userid); memcpy(&dirrec->xarecord.attributes, buffer, sizeof(dirrec->xarecord.attributes)); buffer += sizeof(dirrec->xarecord.attributes); #ifndef WORDS_BIGENDIAN // byte swap it dirrec->xarecord.attributes = ((dirrec->xarecord.attributes & 0xFF00) >> 8) + ((dirrec->xarecord.attributes & 0x00FF) << 8); #endif memcpy(&dirrec->xarecord.signature, buffer, sizeof(dirrec->xarecord.signature)); buffer += sizeof(dirrec->xarecord.signature); memcpy(&dirrec->xarecord.filenumber, buffer, sizeof(dirrec->xarecord.filenumber)); buffer += sizeof(dirrec->xarecord.filenumber); memcpy(dirrec->xarecord.reserved, buffer, sizeof(dirrec->xarecord.reserved)); buffer += sizeof(dirrec->xarecord.reserved); } return 0; } ////////////////////////////////////////////////////////////////////////////// int Cs2ReadFileSystem(filter_struct * curfilter, u32 fid, int isoffset) { u8 * workbuffer; u32 i; dirrec_struct dirrec; u8 numsectorsleft = 0; u32 curdirlba = 0; partition_struct * rfspartition; u32 blocksectsize = Cs2Area->getsectsize; Cs2Area->outconcddev = curfilter; if (isoffset) { // readDirectory operation // make sure we have a valid current directory if (Cs2Area->curdirsect == 0) return -1; Cs2Area->curdirfidoffset = fid - 2; curdirlba = Cs2Area->curdirsect; numsectorsleft = (u8)Cs2Area->curdirsize; } else { // changeDirectory operation if (fid == 0xFFFFFF) { // Figure out root directory's location // Read sector 16 if ((rfspartition = Cs2ReadUnFilteredSector(166)) == NULL) return -2; blocksectsize = rfspartition->block[rfspartition->numblocks - 1]->size; // Retrieve directory record's lba Cs2CopyDirRecord(rfspartition->block[rfspartition->numblocks - 1]->data + 0x9C, &dirrec); // Free Block rfspartition->size -= rfspartition->block[rfspartition->numblocks - 1]->size; Cs2FreeBlock(rfspartition->block[rfspartition->numblocks - 1]); rfspartition->blocknum[rfspartition->numblocks - 1] = 0xFF; // Sort remaining blocks Cs2SortBlocks(rfspartition); rfspartition->numblocks -= 1; curdirlba = Cs2Area->curdirsect = dirrec.lba; Cs2Area->curdirsize = (dirrec.size / blocksectsize) - 1; numsectorsleft = (u8)Cs2Area->curdirsize; Cs2Area->curdirfidoffset = 0; } else { // Read in new directory record of specified directory // make sure we have a valid current directory if (Cs2Area->curdirsect == 0) return -1; curdirlba = Cs2Area->curdirsect = Cs2Area->fileinfo[fid - Cs2Area->curdirfidoffset].lba - 150; Cs2Area->curdirsize = (Cs2Area->fileinfo[fid - Cs2Area->curdirfidoffset].size / blocksectsize) - 1; numsectorsleft = (u8)Cs2Area->curdirsize; Cs2Area->curdirfidoffset = 0; } } // Make sure any old records are cleared memset(Cs2Area->fileinfo, 0, sizeof(dirrec_struct) * MAX_FILES); // now read in first sector of directory record if ((rfspartition = Cs2ReadUnFilteredSector(curdirlba+150)) == NULL) return -2; curdirlba++; workbuffer = rfspartition->block[rfspartition->numblocks - 1]->data; // Fill in first two entries of fileinfo for (i = 0; i < 2; i++) { Cs2CopyDirRecord(workbuffer, Cs2Area->fileinfo + i); Cs2Area->fileinfo[i].lba += 150; workbuffer += Cs2Area->fileinfo[i].recordsize; if (workbuffer[0] == 0) { Cs2Area->numfiles = i; break; } } // If doing a ReadDirectory operation, parse sector entries until we've // found the fid that matches fid if (isoffset) { for (i = 2; i < fid; i++) { Cs2CopyDirRecord(workbuffer, Cs2Area->fileinfo + 2); workbuffer += Cs2Area->fileinfo[2].recordsize; if (workbuffer[0] == 0) { if (numsectorsleft > 0) { // Free previous read sector rfspartition->size -= rfspartition->block[rfspartition->numblocks - 1]->size; Cs2FreeBlock(rfspartition->block[rfspartition->numblocks - 1]); rfspartition->blocknum[rfspartition->numblocks - 1] = 0xFF; // Sort remaining blocks Cs2SortBlocks(rfspartition); rfspartition->numblocks -= 1; // Read in next sector of directory record if ((rfspartition = Cs2ReadUnFilteredSector(curdirlba+150)) == NULL) return -2; curdirlba++; numsectorsleft--; workbuffer = rfspartition->block[rfspartition->numblocks - 1]->data; } else { break; } } } } // Now generate the last 254 entries(the first two should've already been // generated earlier) for (i = 2; i < MAX_FILES; i++) { Cs2CopyDirRecord(workbuffer, Cs2Area->fileinfo + i); Cs2Area->fileinfo[i].lba += 150; workbuffer += Cs2Area->fileinfo[i].recordsize; if (workbuffer[0] == 0) { if (numsectorsleft > 0) { // Free previous read sector rfspartition->size -= rfspartition->block[rfspartition->numblocks - 1]->size; Cs2FreeBlock(rfspartition->block[rfspartition->numblocks - 1]); rfspartition->blocknum[rfspartition->numblocks - 1] = 0xFF; // Sort remaining blocks Cs2SortBlocks(rfspartition); rfspartition->numblocks -= 1; // Read in next sector of directory record if ((rfspartition = Cs2ReadUnFilteredSector(curdirlba+150)) == NULL) return -2; curdirlba++; numsectorsleft--; workbuffer = rfspartition->block[rfspartition->numblocks - 1]->data; } else { Cs2Area->numfiles = i; break; } } } // Free the remaining sector rfspartition->size -= rfspartition->block[rfspartition->numblocks - 1]->size; Cs2FreeBlock(rfspartition->block[rfspartition->numblocks - 1]); rfspartition->blocknum[rfspartition->numblocks - 1] = 0xFF; // Sort remaining blocks Cs2SortBlocks(rfspartition); rfspartition->numblocks -= 1; //#if CDDEBUG // for (i = 0; i < MAX_FILES; i++) // { // CDLOG("fileinfo[%d].name = %s\n", i, Cs2Area->fileinfo[i].name); // } //#endif return 0; } ////////////////////////////////////////////////////////////////////////////// void Cs2SetupFileInfoTransfer(u32 fid) { Cs2Area->transfileinfo[0] = (u8)(Cs2Area->fileinfo[fid].lba >> 24); Cs2Area->transfileinfo[1] = (u8)(Cs2Area->fileinfo[fid].lba >> 16); Cs2Area->transfileinfo[2] = (u8)(Cs2Area->fileinfo[fid].lba >> 8); Cs2Area->transfileinfo[3] = (u8)Cs2Area->fileinfo[fid].lba; Cs2Area->transfileinfo[4] = (u8)(Cs2Area->fileinfo[fid].size >> 24); Cs2Area->transfileinfo[5] = (u8)(Cs2Area->fileinfo[fid].size >> 16); Cs2Area->transfileinfo[6] = (u8)(Cs2Area->fileinfo[fid].size >> 8); Cs2Area->transfileinfo[7] = (u8)Cs2Area->fileinfo[fid].size; Cs2Area->transfileinfo[8] = Cs2Area->fileinfo[fid].interleavegapsize; Cs2Area->transfileinfo[9] = Cs2Area->fileinfo[fid].fileunitsize; Cs2Area->transfileinfo[10] = (u8) fid; Cs2Area->transfileinfo[11] = Cs2Area->fileinfo[fid].flags; } ////////////////////////////////////////////////////////////////////////////// partition_struct * Cs2ReadUnFilteredSector(u32 rufsFAD) { partition_struct * rufspartition; char syncheader[12] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; if ((rufspartition = Cs2GetPartition(Cs2Area->outconcddev)) != NULL && !Cs2Area->isbufferfull) { // Allocate Block rufspartition->block[rufspartition->numblocks] = Cs2AllocateBlock(&rufspartition->blocknum[rufspartition->numblocks], Cs2Area->getsectsize); if (rufspartition->block[rufspartition->numblocks] == NULL) return NULL; // read a sector using cd interface function if (!Cs2Area->cdi->ReadSectorFAD(rufsFAD, Cs2Area->workblock.data)) return NULL; // convert raw sector to type specified in getsectsize switch(Cs2Area->getsectsize) { case 2048: // user data only if (Cs2Area->workblock.data[0xF] == 0x02) { // is it form1/form2 data? if (!(Cs2Area->workblock.data[0x12] & 0x20)) { // form 1 memcpy(rufspartition->block[rufspartition->numblocks]->data, Cs2Area->workblock.data + 24, 2048); Cs2Area->workblock.size = Cs2Area->getsectsize; } else { // form 2 memcpy(rufspartition->block[rufspartition->numblocks]->data, Cs2Area->workblock.data + 24, 2324); Cs2Area->workblock.size = 2324; } } else { memcpy(rufspartition->block[rufspartition->numblocks]->data, Cs2Area->workblock.data + 16, 2048); Cs2Area->workblock.size = Cs2Area->getsectsize; } break; case 2336: // skip sync+header data memcpy(rufspartition->block[rufspartition->numblocks]->data, Cs2Area->workblock.data + 16, 2336); Cs2Area->workblock.size = Cs2Area->getsectsize; break; case 2340: // skip sync data memcpy(rufspartition->block[rufspartition->numblocks]->data, Cs2Area->workblock.data + 12, 2340); Cs2Area->workblock.size = Cs2Area->getsectsize; break; case 2352: // no conversion needed Cs2Area->workblock.size = Cs2Area->getsectsize; break; default: break; } // if mode 2 track, setup the subheader values if (memcmp(syncheader, Cs2Area->workblock.data, 12) == 0 && Cs2Area->workblock.data[0xF] == 0x02) { rufspartition->block[rufspartition->numblocks]->fn = Cs2Area->workblock.data[0x10]; rufspartition->block[rufspartition->numblocks]->cn = Cs2Area->workblock.data[0x11]; rufspartition->block[rufspartition->numblocks]->sm = Cs2Area->workblock.data[0x12]; rufspartition->block[rufspartition->numblocks]->ci = Cs2Area->workblock.data[0x13]; } Cs2Area->workblock.FAD = rufsFAD; // Modify Partition values if (rufspartition->size == -1) rufspartition->size = 0; rufspartition->size += rufspartition->block[rufspartition->numblocks]->size; rufspartition->numblocks++; return rufspartition; } return NULL; } ////////////////////////////////////////////////////////////////////////////// int Cs2ReadFilteredSector(u32 rfsFAD, partition_struct **partition) { char syncheader[12] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; int isaudio = 0; if (Cs2Area->outconcddev != NULL && !Cs2Area->isbufferfull) { // read a sector using cd interface function to workblock.data if (!Cs2Area->cdi->ReadSectorFAD(rfsFAD, Cs2Area->workblock.data)) { *partition = NULL; return -2; } Cs2Area->workblock.size = Cs2Area->getsectsize; Cs2Area->workblock.FAD = rfsFAD; if (memcmp(syncheader, Cs2Area->workblock.data, 12) != 0) isaudio = 1; // force 1x speed if reading from an audio track Cs2Area->isaudio = isaudio; Cs2SetTiming(1); // if mode 2 track, setup the subheader values if (isaudio) { ScspReceiveCDDA(Cs2Area->workblock.data); *partition = NULL; return 0; } else if (Cs2Area->workblock.data[0xF] == 0x02) { // if it's form 2 data the sector size should be 2324 if (Cs2Area->workblock.data[0x12] & 0x20) Cs2Area->workblock.size = 2324; Cs2Area->workblock.fn = Cs2Area->workblock.data[0x10]; Cs2Area->workblock.cn = Cs2Area->workblock.data[0x11]; Cs2Area->workblock.sm = Cs2Area->workblock.data[0x12]; Cs2Area->workblock.ci = Cs2Area->workblock.data[0x13]; } // pass workblock to filter function(after it identifies partition, // it should allocate the partition block, setup/change the partition // values, and copy workblock to the allocated block) *partition = Cs2FilterData(Cs2Area->outconcddev, isaudio); return 0; } *partition = NULL; return -1; } ////////////////////////////////////////////////////////////////////////////// u8 Cs2GetIP(int autoregion) { partition_struct * gripartition; u8 ret = 0; Cs2Area->outconcddev = Cs2Area->filter + 0; Cs2Area->outconcddevnum = 0; // read in lba 0/FAD 150 if ((gripartition = Cs2ReadUnFilteredSector(150)) != NULL) { char *buf=(char*)gripartition->block[gripartition->numblocks - 1]->data; // Make sure we're dealing with a saturn game if (memcmp(buf, "SEGA SEGASATURN", 15) == 0) { memcpy(cdip->system, buf, 16); cdip->system[16]='\0'; memcpy(cdip->company, buf+0x10, 16); cdip->company[16]='\0'; sscanf(buf+0x20, "%s", cdip->itemnum); memcpy(cdip->version, buf+0x2A, 6); cdip->version[6]='\0'; sprintf(cdip->date, "%c%c/%c%c/%c%c%c%c", buf[0x34], buf[0x35], buf[0x36], buf[0x37], buf[0x30], buf[0x31], buf[0x32], buf[0x33]); sscanf(buf+0x38, "%s", cdip->cdinfo); sscanf(buf+0x40, "%s", cdip->region); sscanf(buf+0x50, "%s", cdip->peripheral); memcpy(cdip->gamename, buf+0x60, 112); cdip->gamename[112]='\0'; #ifdef WORDS_BIGENDIAN memcpy(&cdip->ipsize, buf+0xE0, sizeof(u32)); memcpy(&cdip->msh2stack, buf+0xE8, sizeof(u32)); memcpy(&cdip->ssh2stack, buf+0xEC, sizeof(u32)); memcpy(&cdip->firstprogaddr, buf+0xF0, sizeof(u32)); memcpy(&cdip->firstprogsize, buf+0xF4, sizeof(u32)); #else cdip->ipsize = (buf[0xE0] << 24) | (buf[0xE1] << 16) | (buf[0xE2] << 8) | buf[0xE3]; cdip->msh2stack = (buf[0xE8] << 24) | (buf[0xE9] << 16) | (buf[0xEA] << 8) | buf[0xEB]; cdip->ssh2stack = (buf[0xEC] << 24) | (buf[0xED] << 16) | (buf[0xEE] << 8) | buf[0xEF]; cdip->firstprogaddr = (buf[0xF0] << 24) | (buf[0xF1] << 16) | (buf[0xF2] << 8) | buf[0xF3]; cdip->firstprogsize = (buf[0xF4] << 24) | (buf[0xF5] << 16) | (buf[0xF6] << 8) | buf[0xF7]; if (cdip->msh2stack == 0 ) { cdip->msh2stack = 0x6002000; } // for Panzer Dragoon Zwei. This operation is not written in the document. if (cdip->msh2stack & 0x80000000) { cdip->msh2stack = 0x06000000 + (cdip->msh2stack & 0x0000FFFF ); } if (cdip->ssh2stack == 0 ) { cdip->ssh2stack = 0x6001000; } if (cdip->ssh2stack & 0x80000000) { cdip->ssh2stack = 0x06000000 + (cdip->ssh2stack & 0x0000FFFF); } #endif if (autoregion) { // Read first available region, that'll be what we'll use switch (cdip->region[0]) { case 'J': ret = 1; break; case 'T': ret = 2; break; case 'U': ret = 4; break; case 'B': ret = 5; break; case 'K': ret = 6; break; case 'A': ret = 0xA; break; case 'E': ret = 0xC; break; case 'L': ret = 0xD; break; default: break; } } } // Free Block gripartition->size -= gripartition->block[gripartition->numblocks - 1]->size; Cs2FreeBlock(gripartition->block[gripartition->numblocks - 1]); gripartition->blocknum[gripartition->numblocks - 1] = 0xFF; // Sort remaining blocks Cs2SortBlocks(gripartition); gripartition->numblocks -= 1; } return ret; } ////////////////////////////////////////////////////////////////////////////// u8 Cs2GetRegionID(void) { return Cs2GetIP(1); } ////////////////////////////////////////////////////////////////////////////// int Cs2SaveState(FILE * fp) { int offset, i; IOCheck_struct check = { 0, 0 }; // This is mostly kludge, but it will have to do until I have time to rewrite it all offset = StateWriteHeader(fp, "CS2 ", 2); // Write cart type ywrite(&check, (void *) &Cs2Area->carttype, 4, 1, fp); // Write cd block registers ywrite(&check, (void *) &Cs2Area->reg, sizeof(blockregs_struct), 1, fp); // Write current Status variables(needs a rewrite) ywrite(&check, (void *) &Cs2Area->FAD, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->status, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->options, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->repcnt, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->ctrladdr, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->track, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->index, 1, 1, fp); // Write other cd block internal variables ywrite(&check, (void *) &Cs2Area->satauth, 2, 1, fp); ywrite(&check, (void *) &Cs2Area->mpgauth, 2, 1, fp); ywrite(&check, (void *) &Cs2Area->transfercount, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->cdwnum, 4, 1, fp); ywrite(&check, (void *) Cs2Area->TOC, 4, 102, fp); ywrite(&check, (void *) &Cs2Area->playFAD, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->playendFAD, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->getsectsize, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->putsectsize, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->calcsize, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->infotranstype, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->datatranstype, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->isonesectorstored, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->isdiskchanged, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->isbufferfull, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->speed1x, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->isaudio, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->transfileinfo, 1, 12, fp); ywrite(&check, (void *) &Cs2Area->lastbuffer, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->_command, 1, 1, fp); { u32 temp = (Cs2Area->_periodictiming + 3) / 3; ywrite(&check, (void *) &temp, 4, 1, fp); } ywrite(&check, (void *) &Cs2Area->_commandtiming, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->outconcddevnum, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->outconmpegfbnum, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->outconmpegbufnum, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->outconmpegromnum, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->outconhostnum, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->datatranspartitionnum, 1, 1, fp); ywrite(&check, (void *) &Cs2Area->datatransoffset, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->datanumsecttrans, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->datatranssectpos, 2, 1, fp); ywrite(&check, (void *) &Cs2Area->datasectstotrans, 2, 1, fp); ywrite(&check, (void *) &Cs2Area->blockfreespace, 4, 1, fp); ywrite(&check, (void *) &Cs2Area->curdirsect, 4, 1, fp); // Write CD buffer ywrite(&check, (void *)Cs2Area->block, sizeof(block_struct), MAX_BLOCKS, fp); // Write partition data for (i = 0; i < MAX_SELECTORS; i++) { ywrite(&check, (void *)&Cs2Area->partition[i].size, 4, 1, fp); ywrite(&check, (void *)Cs2Area->partition[i].blocknum, 1, MAX_BLOCKS, fp); ywrite(&check, (void *)&Cs2Area->partition[i].numblocks, 1, 1, fp); } // Write filter data ywrite(&check, (void *)Cs2Area->filter, sizeof(filter_struct), MAX_SELECTORS, fp); // Write File Info Table ywrite(&check, (void *)Cs2Area->fileinfo, sizeof(dirrec_struct), MAX_FILES, fp); // Write MPEG card registers here // Write current MPEG card status variables ywrite(&check, (void *)&Cs2Area->actionstatus, 1, 1, fp); ywrite(&check, (void *)&Cs2Area->pictureinfo, 1, 1, fp); ywrite(&check, (void *)&Cs2Area->mpegaudiostatus, 1, 1, fp); ywrite(&check, (void *)&Cs2Area->mpegvideostatus, 2, 1, fp); ywrite(&check, (void *)&Cs2Area->vcounter, 2, 1, fp); // Write other MPEG card internal variables ywrite(&check, (void *)&Cs2Area->mpegintmask, 4, 1, fp); ywrite(&check, (void *)Cs2Area->mpegcon, sizeof(mpegcon_struct), 2, fp); ywrite(&check, (void *)Cs2Area->mpegstm, sizeof(mpegstm_struct), 2, fp); return StateFinishHeader(fp, offset); } ////////////////////////////////////////////////////////////////////////////// int Cs2LoadState(FILE * fp, int version, int size) { int i, i2; IOCheck_struct check = { 0, 0 }; // This is mostly kludge, but it will have to do until I have time to rewrite it all // Read cart type yread(&check, (void *)&Cs2Area->carttype, 4, 1, fp); // Read cd block registers yread(&check, (void *)&Cs2Area->reg, sizeof(blockregs_struct), 1, fp); // Read current Status variables(needs a reRead) yread(&check, (void *)&Cs2Area->FAD, 4, 1, fp); yread(&check, (void *)&Cs2Area->status, 1, 1, fp); yread(&check, (void *)&Cs2Area->options, 1, 1, fp); yread(&check, (void *)&Cs2Area->repcnt, 1, 1, fp); yread(&check, (void *)&Cs2Area->ctrladdr, 1, 1, fp); yread(&check, (void *)&Cs2Area->track, 1, 1, fp); yread(&check, (void *)&Cs2Area->index, 1, 1, fp); // Read other cd block internal variables yread(&check, (void *)&Cs2Area->satauth, 2, 1, fp); yread(&check, (void *)&Cs2Area->mpgauth, 2, 1, fp); yread(&check, (void *)&Cs2Area->transfercount, 4, 1, fp); yread(&check, (void *)&Cs2Area->cdwnum, 4, 1, fp); yread(&check, (void *)Cs2Area->TOC, 4, 102, fp); yread(&check, (void *)&Cs2Area->playFAD, 4, 1, fp); yread(&check, (void *)&Cs2Area->playendFAD, 4, 1, fp); yread(&check, (void *)&Cs2Area->getsectsize, 4, 1, fp); yread(&check, (void *)&Cs2Area->putsectsize, 4, 1, fp); yread(&check, (void *)&Cs2Area->calcsize, 4, 1, fp); yread(&check, (void *)&Cs2Area->infotranstype, 4, 1, fp); yread(&check, (void *)&Cs2Area->datatranstype, 4, 1, fp); yread(&check, (void *)&Cs2Area->isonesectorstored, 1, 1, fp); yread(&check, (void *)&Cs2Area->isdiskchanged, 1, 1, fp); yread(&check, (void *)&Cs2Area->isbufferfull, 1, 1, fp); yread(&check, (void *)&Cs2Area->speed1x, 1, 1, fp); if (version > 1) yread(&check, (void *)&Cs2Area->isaudio, 1, 1, fp); yread(&check, (void *)&Cs2Area->transfileinfo, 1, 12, fp); yread(&check, (void *)&Cs2Area->lastbuffer, 1, 1, fp); yread(&check, (void *)&Cs2Area->_command, 1, 1, fp); { u32 temp; yread(&check, (void *)&temp, 4, 1, fp); // Derive the actual, accurate value (always a multiple of 10) Cs2Area->_periodictiming = ((temp * 3) / 10) * 10; } yread(&check, (void *)&Cs2Area->_commandtiming, 4, 1, fp); yread(&check, (void *)&Cs2Area->outconcddevnum, 1, 1, fp); if (Cs2Area->outconcddevnum == 0xFF) Cs2Area->outconcddev = NULL; else Cs2Area->outconcddev = Cs2Area->filter + Cs2Area->outconcddevnum; yread(&check, (void *)&Cs2Area->outconmpegfbnum, 1, 1, fp); if (Cs2Area->outconmpegfbnum == 0xFF) Cs2Area->outconmpegfb = NULL; else Cs2Area->outconmpegfb = Cs2Area->filter + Cs2Area->outconmpegfbnum; yread(&check, (void *)&Cs2Area->outconmpegbufnum, 1, 1, fp); if (Cs2Area->outconmpegbufnum == 0xFF) Cs2Area->outconmpegbuf = NULL; else Cs2Area->outconmpegbuf = Cs2Area->filter + Cs2Area->outconmpegbufnum; yread(&check, (void *)&Cs2Area->outconmpegromnum, 1, 1, fp); if (Cs2Area->outconmpegromnum == 0xFF) Cs2Area->outconmpegrom = NULL; else Cs2Area->outconmpegrom = Cs2Area->filter + Cs2Area->outconmpegromnum; yread(&check, (void *)&Cs2Area->outconhostnum, 1, 1, fp); if (Cs2Area->outconhostnum == 0xFF) Cs2Area->outconhost = NULL; else Cs2Area->outconhost = Cs2Area->filter + Cs2Area->outconhostnum; yread(&check, (void *)&Cs2Area->datatranspartitionnum, 1, 1, fp); yread(&check, (void *)&Cs2Area->datatransoffset, 4, 1, fp); yread(&check, (void *)&Cs2Area->datanumsecttrans, 4, 1, fp); yread(&check, (void *)&Cs2Area->datatranssectpos, 2, 1, fp); yread(&check, (void *)&Cs2Area->datasectstotrans, 2, 1, fp); yread(&check, (void *)&Cs2Area->blockfreespace, 4, 1, fp); yread(&check, (void *)&Cs2Area->curdirsect, 4, 1, fp); // Read CD buffer yread(&check, (void *)Cs2Area->block, sizeof(block_struct), MAX_BLOCKS, fp); // Read partition data for (i = 0; i < MAX_SELECTORS; i++) { yread(&check, (void *)&Cs2Area->partition[i].size, 4, 1, fp); yread(&check, (void *)Cs2Area->partition[i].blocknum, 1, MAX_BLOCKS, fp); yread(&check, (void *)&Cs2Area->partition[i].numblocks, 1, 1, fp); for (i2 = 0; i2 < MAX_BLOCKS; i2++) { if (Cs2Area->partition[i].blocknum[i2] == 0xFF) Cs2Area->partition[i].block[i2] = NULL; else Cs2Area->partition[i].block[i2] = Cs2Area->block + Cs2Area->partition[i].blocknum[i2]; } } // Read filter data yread(&check, (void *)Cs2Area->filter, sizeof(filter_struct), MAX_SELECTORS, fp); // Read File Info Table yread(&check, (void *)Cs2Area->fileinfo, sizeof(dirrec_struct), MAX_FILES, fp); // Read MPEG card registers here // Read current MPEG card status variables yread(&check, (void *)&Cs2Area->actionstatus, 1, 1, fp); yread(&check, (void *)&Cs2Area->pictureinfo, 1, 1, fp); yread(&check, (void *)&Cs2Area->mpegaudiostatus, 1, 1, fp); yread(&check, (void *)&Cs2Area->mpegvideostatus, 2, 1, fp); yread(&check, (void *)&Cs2Area->vcounter, 2, 1, fp); // Read other MPEG card internal variables yread(&check, (void *)&Cs2Area->mpegintmask, 4, 1, fp); yread(&check, (void *)Cs2Area->mpegcon, sizeof(mpegcon_struct), 2, fp); yread(&check, (void *)Cs2Area->mpegstm, sizeof(mpegstm_struct), 2, fp); return size; } u32 Cs2GetMasterStackAdress(){ if (cdip) return cdip->msh2stack; else return 0x6002000; } u32 Cs2GetSlaveStackAdress(){ if (cdip) return cdip->ssh2stack; else return 0x6001000; } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/cocoa/000755 001750 001750 00000000000 12757373644 017146 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/cocoa/YabauseController.m000644 001750 001750 00000024340 12757373537 022765 0ustar00guillaumeguillaume000000 000000 /* Copyright 2010, 2012, 2014 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "YabauseController.h" #include "YabauseGLView.h" #include "YabausePrefsController.h" #include "vdp1.h" #include "vdp2.h" #include "scsp.h" #include "peripheral.h" #include "cdbase.h" #include "yabause.h" #include "yui.h" #include "PerCocoa.h" #include "m68kc68k.h" #include "cs0.h" YabauseController *controller; @interface YabauseController (InternalFunctions) - (void)startEmulationWithCDCore:(int)cdcore CDPath:(const char *)fn; - (void)emulationThread:(id)ignored; - (void)terminateEmulation; @end /* Menu Item tags. */ enum { tagVDP1 = 1, tagNBG0 = 2, tagNBG1 = 3, tagNBG2 = 4, tagNBG3 = 5, tagRBG0 = 6, tagFPS = 7 }; static void FlipToggle(NSMenuItem *item) { if([item state] == NSOffState) { [item setState:NSOnState]; } else { [item setState:NSOffState]; } } @implementation YabauseController - (void)awakeFromNib { NSUserDefaults *p = [NSUserDefaults standardUserDefaults]; controller = self; _running = NO; _paused = NO; _runLock = [[NSLock alloc] init]; _emuThd = nil; _bramFile = NULL; _doneExecuting = NO; if([p boolForKey:@"Enable Frameskip"]) { [frameskip setState:NSOnState]; EnableAutoFrameSkip(); } else { [frameskip setState:NSOffState]; DisableAutoFrameSkip(); } } - (void)dealloc { [_runLock release]; [super dealloc]; } - (BOOL)windowShouldClose:(id)sender { [self terminateEmulation]; return YES; } - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)app { [self terminateEmulation]; return NSTerminateNow; } - (IBAction)showPreferences:(id)sender { [prefsPane makeKeyAndOrderFront:self]; } - (IBAction)runBIOS:(id)sender { /* This will simply start up the system with the dummy CD core, so there's no way it'll actually read that there's a disc to be played. */ [self startEmulationWithCDCore:CDCORE_DUMMY CDPath:NULL]; } - (IBAction)runCD:(id)sender { [self startEmulationWithCDCore:CDCORE_ARCH CDPath:NULL]; } - (IBAction)runISO:(id)sender { NSOpenPanel *p = [NSOpenPanel openPanel]; NSArray *types = [NSArray arrayWithObjects:@"iso", @"cue", @"mds", @"ccd", nil]; [p setAllowedFileTypes:types]; if([p runModal] == NSFileHandlingPanelOKButton) { NSString *fn = [[[p URLs] objectAtIndex:0] path]; [self startEmulationWithCDCore:CDCORE_ISO CDPath:[fn fileSystemRepresentation]]; } } - (IBAction)toggleFullscreen:(id)sender { /* The view handles any heavy lifting here... */ [view toggleFullscreen]; } - (IBAction)toggle:(id)sender { /* None of these will work unless we're running... */ if(!_running) { return; } /* Flip the checkmark on the button. */ FlipToggle((NSMenuItem *)sender); /* Do whatever this toggle is asking us to do. */ switch([sender tag]) { case tagVDP1: ToggleVDP1(); break; case tagNBG0: ToggleNBG0(); break; case tagNBG1: ToggleNBG1(); break; case tagNBG2: ToggleNBG2(); break; case tagNBG3: ToggleNBG3(); break; case tagRBG0: ToggleRBG0(); break; case tagFPS: ToggleFPS(); break; } } - (IBAction)toggleFrameskip:(id)sender { NSUserDefaults *p = [NSUserDefaults standardUserDefaults]; if([sender state] == NSOnState) { DisableAutoFrameSkip(); [sender setState:NSOffState]; [p setBool:NO forKey:@"Enable Frameskip"]; } else { EnableAutoFrameSkip(); [sender setState:NSOnState]; [p setBool:YES forKey:@"Enable Frameskip"]; } } - (IBAction)pause:(id)sender { if(_running) { if(!_paused) { _paused = YES; /* Mute the audio before we actually pause otherwise the user might not like the result... */ ScspMuteAudio(SCSP_MUTE_SYSTEM); [_runLock lock]; [sender setState:NSOnState]; } else { _paused = NO; [_runLock unlock]; ScspUnMuteAudio(SCSP_MUTE_SYSTEM); [sender setState:NSOffState]; } } } - (IBAction)reset:(id)sender { if(_running) { /* Act as if the user pressed the reset button on the console. */ YabauseResetButton(); } } - (YabauseGLView *)view { return view; } @end /* @implementation YabauseController */ @implementation YabauseController (InternalFunctions) - (void)startEmulationWithCDCore:(int)cdcore CDPath:(const char *)fn { if(!_running) { yabauseinit_struct yinit = {0}; int initok; NSString *bios = [prefs biosPath]; NSString *mpeg = [prefs mpegPath]; NSString *bram = [prefs bramPath]; NSString *cart = [prefs cartPath]; yinit.percoretype = PERCORE_COCOA; yinit.sh2coretype = SH2CORE_DEFAULT; yinit.vidcoretype = [prefs videoCore]; yinit.sndcoretype = [prefs soundCore]; yinit.m68kcoretype = M68KCORE_C68K; yinit.cdcoretype = cdcore; yinit.carttype = [prefs cartType]; yinit.regionid = [prefs region]; yinit.biospath = ([bios length] > 0 && ![prefs emulateBios]) ? [bios UTF8String] : NULL; yinit.cdpath = fn; yinit.buppath = NULL; yinit.mpegpath = ([mpeg length] > 0) ? [mpeg UTF8String] : NULL; yinit.videoformattype = ([prefs region] < 10) ? VIDEOFORMATTYPE_NTSC : VIDEOFORMATTYPE_PAL; yinit.frameskip = [frameskip state] == NSOnState; yinit.clocksync = 0; yinit.basetime = 0; if([prefs enableThreads]) { int num_threads = [[NSProcessInfo processInfo] processorCount]; if(num_threads > 1) { yinit.usethreads = 1; yinit.numthreads = num_threads; } } NSString *sh1 = [prefs sh1Path]; if([prefs cdbLLE] && [sh1 length] > 0) { yinit.sh1rompath = [sh1 UTF8String]; yinit.use_cd_block_lle = 1; yinit.use_scu_dma_timing = 1; yinit.use_sh2_dma_timing = 1; yinit.sh2_cache_enabled = 1; } yinit.use_new_scsp = [prefs newScsp]; yinit.skip_load = 0; /* Set up the internal save ram if specified. */ if([bram length] > 0) { const char *tmp = [bram UTF8String]; yinit.buppath = _bramFile = strdup(tmp); } if(fn) _isoFile = strdup(fn); /* Set up the cartridge stuff based on what was selected. */ if(yinit.carttype == CART_NETLINK) { yinit.cartpath = NULL; yinit.modemip = ([cart length] > 0) ? [cart UTF8String] : NULL; yinit.modemport = NULL; } else { yinit.cartpath = ([cart length] > 0) ? [cart UTF8String] : NULL; yinit.modemip = NULL; yinit.modemport = NULL; } if(cdcore == CDCORE_DUMMY && !yinit.biospath) { NSRunAlertPanel(@"Yabause Error", @"You must specify a BIOS file " "(and have BIOS emulation disabled) in order to " "run the BIOS.", @"OK", NULL, NULL); return; } [[view openGLContext] makeCurrentContext]; initok = YabauseInit(&yinit); [NSOpenGLContext clearCurrentContext]; if (initok != 0) { return; } YabauseSetDecilineMode(1); _running = YES; _doneExecuting = NO; [view showWindow]; /* The emulation itself takes place in a separate thread from the main GUI thread. */ [NSThread detachNewThreadSelector:@selector(emulationThread:) toTarget:self withObject:nil]; } } - (void)emulationThread:(id)ignored { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; CGLContextObj cxt; _emuThd = [NSThread currentThread]; /* Make the OpenGL context current for this thread, otherwise we will be drawing to nothingness. */ [[view openGLContext] makeCurrentContext]; /* Make sure the video core knows the size of the display... */ [view reshape]; ScspUnMuteAudio(SCSP_MUTE_SYSTEM); while(_running) { /* If we get paused from the GUI, we'll end up waiting in this lock here... Maybe not the most clear way to do it, but it works. */ [_runLock lock]; /* Make sure the main thread doesn't attempt to flip the buffer before this thread is done rendering. */ cxt = CGLGetCurrentContext(); CGLLockContext(cxt); /* Shortcut a function call here... We should technically be doing a PERCore->HandleEvents(), but that function simply calls YabauseExec() anyway... so cut out the middleman. */ YabauseExec(); CGLUnlockContext(cxt); [_runLock unlock]; } ScspMuteAudio(SCSP_MUTE_SYSTEM); _doneExecuting = YES; [pool release]; } - (void)terminateEmulation { _running = NO; /* Wait for the thread to die, and then clean up after it. */ if(_emuThd) { while(!_doneExecuting) { sched_yield(); } YabauseDeInit(); free(_bramFile); _bramFile = NULL; free(_isoFile); _isoFile = NULL; _emuThd = nil; } } @end /* @implementation YabauseController (InternalFunctions) */ yabause-0.9.15/src/cocoa/resources/000755 001750 001750 00000000000 12757373644 021160 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/cocoa/resources/controller.png000644 001750 001750 00000275347 12755623101 024053 0ustar00guillaumeguillaume000000 000000 ‰PNG  IHDRmxøÎ gAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<zyIDATxÚì½ ˜eeu.¼«zé꡺ª‡ªžGl¦F„€J@‚J"¿½Æ ‰xM$×)¼šâuÄ\yþK¢ð«QPŒ‰ ¢(* MÏóX=0ô =Ô¿Þ]ç-V/Ö·‡sNUWw«žýœSûì³Ïž¾õ½ë]SCggg%J”(Q¢D‰¥oKc¼Q¢D‰%J”(´E‰%J”(Q¢D‰ -J”(Q¢D‰%‚¶(Q¢D‰%J”(´E‰%J”(Q¢D‰ -J”(Q¢D‰%‚¶(Q¢D‰%J”(´E‰%J”(Q¢D‰ -J”(Q¢D‰%‚¶(Q¢D‰%J”(´E‰%J”(Q¢DÐ%J”(Q¢D‰%‚¶(Q¢D‰%J”(´E‰%J”(Q¢DÐ%J”(Q¢D‰%‚¶(Q¢D‰%J”(´E‰%J”(Q¢DÐ%J”(Q¢D‰%‚¶(Q¢D‰%J”(´E‰%J”(Q¢DÐ%J”(Q¢D‰%‚¶(Q¢D‰%J”Ú¢D‰%J”(Q¢DÐ%J”(Q¢D‰%‚¶(Q¢D‰%J”Ú¢D‰%J”(Q¢DÐ%J”(Q¢D‰%‚¶(Q¢D‰%J”Ú¢D‰%J”(Q¢DÐ%J”(Q¢D‰A[”(Q¢D‰%J”Ú¢D‰%J”(Q¢T)ýã%ˆr¢ÉáÇ“'Ÿ|²ÿF=ûì³£6lØÐܯ_¿Ñµzõê1ýû÷ÙØØ8LÖ ‘×! é÷øzôèѤ³³3}=räÈAy=ðÜsÏu:th,‡d?{f̘ñÌСC;† Ò1sæÌŽ &ì6lX¼øQ¢ô€ìر£¿,—/_Þ,ãtüÖ­[ÇuttŒ18LÆóÀ “¥AÆó×Ëò>]0–±@äµSôÃ^ŒiÛ{äó§fÍšõ´¬~Z¾·}êÔ©OÊwŸ7nÜî&².^ü('”4ða¥¯‰€2(ó1[¶l™$¯³×­[7sß¾}Óž~úéiòY«<»£T’׃Nä}‚WQî 2•2(w(zµ XKð¥Ëþýû“½{÷&{öìIžyæ™DöŸ<õÔS†XI`WSSÓã/{ÙËîºþúëÿuþüùOÅ»%Jíòãÿø¬/~ñ‹o]±bÅÅ2ΦÈXzÚi§%£GNF•.#GŽLFŒ‘ÀhÂ4hP:ÆCãZì®DŒ°ôã[Œ°tÁ{îûŸ”ߨ%¿·®µµuìså´iÓVŽ?~Õĉ·Œ3æ ö%JmQ¢ WÀYÓªU«f¯Y³fáæÍ›ÏÚµk×gSEA7‹Å*n*òáǧ 9±ÊS…ŽŠ— ­b…§J J` @m÷îÝÝ ‹ünúŠuø ÛÔíܹ@pÅ×¾öµ7^yå•¿w-J”êDŒ¯ä/þâ/þîî»ïþ;cÄ(J0ÆÐÚ°€J|Nð†m9Þ Ü8¾¡KÀÆ´á〠¯01î1®q ã0Ôð¿è„gEWl}²²¥¥å¡Y³f=ÜÞÞþ¸¹5ãÆ;ïZ”Ú¢œ²‚çN€YÓâÅ‹._¾ü%[·n}‰(Ð3ä£V(í±cÇv+n*jmis8ƒâÆpåM7¨jTÞkPÖaPÔ–Y`£"Çvø¾OwjE¹w|ûÛß~ñYgµ6ÞÉ(QÊË?øÁÿ!ÆÏ?·µµ¥Œ8Æ0Æ8 4€5€6è Üȼ¼iVÝê2prqši§N€. À" `m•裇fΜù˹sç>0þü¥¢£Ç»å”m«W¯N~ûÛS“´€¢zÕ«^•œ*±R}ú“2!<)LJ ç9þmòÿ¶I“&=%û|R€è)†R&³ÚzI0F¶lÙ’:}E0VdLŽ×¦M›6&h¼€š±ëÖ­k‘qÐ*ã¶yÍš5S:::^"€gÆ7ÇcÔ°`?éeXs,z,êqÊm9Þ ì S cpÀÚ?>5ÁÜa=>ðely†Phfz:gë֭髜Çö 6üzÛ¶mw ¨û‘üü¦ødž¼rÍ5×$ÿþïÿ~\á¸gžhVb=…n“MÀRýîw¿[ðÀ\³lÙ²«Dùp6{ö줹¹¹;È@Ö0cÓÒ°42(GQŠ©¢%ÉÐÂ…’& «Z»[xµl•¾v«êÉ`‘“‘s-r|×Èyv»Oï½÷Þô½üÎQ¹·{ä·wÉä°Kþß$Úº‘#G®joo_'Ç·^@]‡\‡'S‡ë…{A[ï®õñ`u`ˆÉÒ¼yóæñdÚÄðl 3}ýúõmH&ñÚ,ãaŒ¬"ÿ7h£ˆ! 0Ú´ÁÄçG¿×ç–už[l‡\´Æ¨+ kØâ`hЈDXÖC/ñ'ˆƒ1ˆE3p0Rdi–åê;w^-ºéª¿PúmyÿŸ¢÷vƧôä3”Ž·Ä’Qê&¢¬šï¹çžW?òÈ#× °ºP@É€3f¤–-”#€Y5+²iP¤P´i`ÐÐdRHA”#”%0 ð=ìƒ@‹ž lYþOPf­y~N«]3un´òñçÃ}èØym”ó9MVŸ&Ê}š¼?W”y÷$Ru»äû›å­œ8qâò¶¶¶'Ю0·VÖíŠn×(Ç[*1Ÿ-Æ&Ëxœ%Ë'–ø¸ 6¼H®[º¾dz]®ÕZ™8–{T@ïby]*€®#¹(=Èž5ˆ4AžÇ9ò<ž¹nݺ³e\Îß¿›ŒÓ&2TŒ!Ãx$£a¤Ý›Ú@² M‡"èX6k8ñûÏ\§œ¯zìéE×eÔ,ÿg\,³I1¡g ³àF€Ã0Ocn¡Ûø=²o*‘aüœ9sÞ&×ômrM/î6Ñoß‘m·Æ§-JmQz]vìØ1ðÞ{ï½ê¿þë¿Þ)ŠýÒ–––†óÎ;ï÷'Ý Ppˆ8HÛ¸qcú® (;X¿éC)¾ÃÀa Êt"‚ž$8iè€`k­k׋(p=yXfͳúõDÁÿõ¢Y:ý™=y¨ì¶fsÍË–-[´xñât½\»§ÆŒ³J¬þGeòøýé§ŸþûiÓ¦-—u{ã“¥¬à9ci´³9&Î[ºté¹;wîœ/ cª<irƘpŒc†qp¼ic‰cÆ#h𥳺9Ž´Q¥Çž6˜hDÜY#ÊcÙø9›á “¬Ñèbü+ '&&€I‹æÅŠ©± ½*2^ÉÄ1»•ñrºÞ# ¾?uêÔsæÍ›wŽè¼._¾üŽ5kÖü‹ló8€!@_¬à%‚¶(=&¢x†ßu×]×=ðÀ!JûL(00k,Ñ Æà^€.(T5‚4™(R6 Ê Ê@ ,X€;ÈÕ`Å4­µ®' k½{‚׆߿ÿú3o¢Ð Ö?k0G H†ÍwÌÙ¡•„üß$“ȹ¢ðÏ ÷6dhÊ5^/“Ä£Þ~=wîÜßÌš5k‰L(;bQÐ(V Ä8jCàLiçË\$cp¾¬o¡[ c˜cN—ÑÑ,™.«¡ &/,ÁƉf1lü\2ÏÀ² œMJÐÛX gÇžvŸr¼¼Áªë»!)aÆ éw*@ Tè¾ööö”…ƒþc‚ƒeß ïdÛ±2^ß-zðzùÿû¯xÅ+¾tÑEÝÇ8P 0û¨îOþäOþ$½>Q"h‹Ò÷ÁÚißûÞ÷Þ,`í]¬fΟ??UTÚÊ P(u(9€´õë×w5¸  Ìh] ¨Ñª'PÃzZçøŒ“€ž,¼x5= p¢±.˘ىC·ºÒ‡¶è58ó& ËÄé‰COv´øõ¾9‰ÓŒ\¥dIûŽ;Úeù“{î¹×o‡€¸%“&Mú€¸_Ξ=û2Il‰.ÕSO` uttLöÒ¥K/\³fÍæÉs4Œñ w,¡ Q´q¼ÐJ`•ÔôX´Ì¶eØìØòÆnÜÙ±¥Ç4A5¨4˜Ócã‹cŽã%€tw„t ÞvåÊ•©î€û6uêÔT/Òp…nÄýÀço²Ý -[¶ü™`¶}ûöœþùŸ¿òÊ+Ò×K…Ær&´Eéû`mè]wÝõæßüæ7ï‹|ú‚ R¥D‹’±j°Ö¡ìàê$XÃ+€˜6(<(B(\fв'|¦6º[4@Ó M+}ý¹žÿæeŠÚÉB—`)›Å¦'/ýûzRÑÕÚUÃßщ|ó×™ª¸.ºÂ»võ°†œž`'VýÅ2 \,÷ ¿ÿt…‰» N@6ª»ïèI¥‹ã…K)Jïî;Ƙ k`ÒÎ}衇. ÿb ³åÙHA¶ëÏ˜Ž ÕLš~µ ¶f¶5ˆ²,·bzœzî?]+MG;Ër{@O'Yã‹áÖà²F~ÓÆŸâ=Ý¥ÐW,ÎMðÆd–Þpœ<òÈ#Ý.T0pp¡Ò Õ%G° @ž´¯úú׿þªýèGÿqÍ5×|梋.º¿¯²å8×(Ç_Ž{¶[o½5yÛÛÞvJ^|(Q±†Ó‚}}M@íß~ûío¼ï¾ûÞ?tèÐy³fÍz³FV J jXP„ë¨ä‚à‚!«f[NiwŒ¶ò­»Å²cZtBÄL©do¾€°nNÍ éIˆÀIƒE;èßÖû׿eêôz›‘ÊãÖ19Ö¥J ÇõœLX·N®÷N¹Hløå¼yóî“×GeBy²ž ¿sÇwDå^o%]Xp¹É8¿iÓ¦³_ô¢]$†ÕEN—û>¢֩u,šM°qgVŒiãȲÚvYЦÙo Þlý5/–4ô¬ZÖMŸjcç8¦,CncNuÌÙ72oÌng}8–hû7* ]\{|ú•]Xøà{Ú)Û|û5¯yÍM^xáâ¾öâQ¶‰!-§¢¼á oHþíßþ-‚¶Úúhƒ‚ vá7¿ù͉Rº` ![É€YøÂv û1aaÂý –…à€‚ M7zæD¢“ È6YW¦cVékPÇ€g­Œ­ËÅí´,ßk Ýî+dõë Ä›4, ´û %1艌“‡—j4 %‹… ÷H&•mbñ?<}úô{.\øK¹ÏÅþ+rïšV®\yæO<ñ2¸<;::Êä?÷•åshü0þS»:­K“l›çæÔÍcÍ<÷¥BÖhñŒ,/50ôܵz‚Ä5ò:1àXð™ ª&xö6þM7φ寘‚±ô¯øÅ/~qÅÏþs°¦&Nœø;QÊ÷Λ7ïiÓ¦=!M¤ÌŽ“ «€€³3dL^ ùÅ2&Ï’qÖÂâÑlÓ¤C Îð¿eЬ«S3>wÌÖÔãP?£hÓë´Ñä±âúy¶F—pàL!Ãdž:èßÖc6« NÀ:Ž+~F7*õÇRÅJï þgöƒñ‡÷0l垦  ]pàB…ËߥûúVôî+VÜø©O}êÚóÎ;ï¦k¯½öÿˆASL£DÐ¥K `î¸ãŽwÝwß}/Öภ/¼°»t–± €ÚÚµkÓ2°mÆ“ Ôè Õýɪ°ÙEƒ4;)XvËSÐ*Ú墙³P`³u«„J€xßÑ ,t¬º]Vh’Ò —i§Ý®^á_3®-]¥:CÕY+׆ ÃU«V]s÷Ýw¬š4iÒƒbéÿB@Üod’YA\ÏÉ“O>9BÀÙ<™Ô/ û"¸>wïÞ=Ù–Þ “Fp¦™´»“`ŒF’u?êWûœYCDO[CͲlûf šPÌ›7ÞøûÚÒû÷X8ÓfÏË‚8^';Þôqj㈅‚5£Í¨t›‚Ýf/UlÝ = w) cxZÖ sÙ‰ž-[¶´=úè£_}ä‘GþŸ7¼á 7^tÑEÅ‘%‚¶S\~ñ‹_œ!€íE)½âüóÏOc0Xº .O¤¹CÉ [бT\ŒYc‡‚5Ë®qÂÐL¨<€V’ …b_40ò8YÓPˆ9³,ƒ—Uj»Œv2±ÀÍžuIé"¡–éÐǧkZ¤ò¾XVÎ&7¼á¾+wÏŒ7ÎwÝ÷¿ÿý£#FŒX3qâćfÏžý+€8÷ËdÒÙ³ÉÊ ®»Œ¥Ñ+W®œÿÄOœ/ÆÐKvíÚµð™gžiýc^0Üt±qìèp Ö¼âÒÚ ò@•5NtGýÜyì2Å‚(ï™×á6ŽÓº3íµÌœØôØäÿ¶„†“^¬Ç[ÆûÔ™ë¶S AØ5èCèLdâ²tXÇX`°oAû†€9€7°ox/º÷’[o½õ—?ü𧯽öÚ} Ž¢Ú¢œb"Ö^£(‚Å’û»Y³f C°,¬;‚5ÄX ©`mçÎÝ}>©,9ñCɳ€.Á›ÎTã{ä¬AŠ*žµío½uiz ß4Ð11¶4ˆe%ø»Ö:nþ–vIÙííï艆´­þ®Y<òÕ%Fè†ÖnU[!^ÇÂU@]£Üÿ›7ož±zõêkQ'NîçF™<O™2å·2Ù€‘{büøñ›äYˆnœ²h¶nÝÚ¾nݺӗ-[vÞ¦M›Î“1uº\Óñtw’MÓàL³j\4h³1iúÑà‹Ï‹eu=×¢}³ê†öA¶Û1–}óŒ!ËtÙßÒLzÈpÒã]0LêZn›®™9ºFuÖ+¯£eÜxï ¡7 âà­ÀÀ†ûŠÏ±IJ¡:1ˆaÔ]6ìÝà2¶ Àÿû~ðƒW p{ïå—_~Y´E9ED,¶é·ÝvÛ—EÁ¼â¥/}iš‚ζ4h,"‰ì&LÜ6Š J– Ý¡lTFzâ±e4pðâÁBŒšW›ÉNN3fÝ&–}ãÿ^›7™hðe-òÐ1[¦Í›¬ôÄaY;ÙY׎þcãlB‡-mÀãÖ‰ t¡’‰Ó±q•ìÉF&oÙ²åÊûî»÷t/Ø¸æææÇÈ¡cÃcíííËåÙÚ*Ï‘SelɘA ®‰2Ï^³fÍ‹¨% mÁ¦È5ÄÂÑ`ÑðÞëö¡ãû›ßüæ=K—.ýè›ßüæO ÐFRmQNV"ýÖ·¾õúÿüÏÿüç3fŒŸ9sf:y@É ¡ÊU¯™jÁ,?&Ð@ FwŽŽ[ÓJÎSâ:@_ÕëIÀ›xì$ ­ã¬þ̶;çα¢­rCoÒ 1fÖÕi3L½€m;Iz“«÷ÇC X_¼ç$£Ÿ[5Þ+†¹ÖòÙyŠS«¼à5tíÚµ#å³ÓdiB4™ ›äœÇifÚG6®Õc’½´¨ 1cº°ÇÂy,¥e!¬½/ž~á}äqP‡Òðë† ›fcyÎh›…8cØHZ@‚œ9sæZ~üã[Œ‹¿ýíoÿ(â"£DÐå–ïÿû/¿óÎ;ÿ¯Lz^Ž }‘ JfM³%ZùBqÊ·qk^Í„Šfj@`-éPf¦çN Åàx¾VÐ!ëÝ_(£ÓSØTÒlÓe{0z…’Œzì†Çôy““uöúfU ·etéͺY’f\lW+gc#õö•ÿûËkœôa\èïþô§?}ðxþR3(çÜ;H±ç-ÖÁ¥KhØÖjž;ÓÖ@óÜœü-ÛͲµösëÚ³c$T|6ÄBÙg…ìŽÕ²‰¶o¯çö·€.j[»eNý<†Æž~V=CÅ»f›¯fˆ5´Ì·½VšÑÖã÷ž@ž ¡&`ÏàùÀsϸa}_4xóÆLÄ%?úè£ùøÇ?>ï/ÿò/¯Ÿ>}úSqæ‹ -Ê (_øÂnxøá‡ÿiÞ¼yýÁ®ÁJcÙ]5ßNºP>,á¡Ëw0¥]ׇ²˜eØ,8ųiåéYêÚ7[Þƒû×iúÖêϪ·fËx® óâÖô±‡z&Ú‰'TOÊNÆ€³Û–Eð\½¡–Eº«€(ÔéÉÏÆÅÙLW‚5Ý‹U÷\õbuí9§¯dƒvkÐk™UËŠè ͆yYš˜…¶ó˜ËÜx /Öé¹Ç½òYl±ç ÌrÍ{l±çºµfÓãÆ ðŽ+”`Ç´vëz‰ž+×;çPé>s6^ÍÖDôB64ø³†(=<6ÝVŒº•uùPË%BùÖVÀxCÒÂüùó¡ßÿô“Ÿü䬷¼å-o¸ð ‹3`mQNÁ`þâ¿øÙ7þÍܹsÓx 4o'³¦ƒÊ­ò$]ÏX5/+T»{l+)f»Yw…â)Sën´JÕ«½dÝ3àóX½ÐDæ^{ÀÌ‚$›}j•¶ž¼‰Í‚©P ,/nÍN,¶è°ä,ˆ¶.W}/íoYÖD = "ôD¦]]v×ŒŠ¾§@Ïrýy•ûí±Úÿul™ Ì×÷X±õög^L—evìsé1žÞsÀëFw·ÍdöÀ}V½C J4¸¶Ï¨jÙa}ì¶{‰£ÖhóŽÝ²tú:iöÍc*µ‘äa!&Ú`!†1k¬êX9ºÜñÊÖWԳпÐãoÌB¥cÁ¶a3zÑÕg|éK_ºGÖ½þª«®º'Ά´Eéã"ƒuðM7ÝtëîÝ»ÿ 5"t;Ä=°F¥ÉàX]Wg…z.PËâ„”®Uêpó•m9¯3€­µê`àõ?ôXPüŠ=w0zŒ›]o­u †lÑP¯Â{´èLW›mçÅYPÊ´àS_' ö,[j7¤Y8ËÌZ€‘7Iz-Ì,8°Ï¢>í"´nJ½½fÙ¼kä¹ÒBîµP°{¨}›³fŸwÏH á[@¤[RÙvjsì%Xý¢ÙTÏòÀ“YFHŒYpnï§“!Fß²6œÀê”P9í…€è–~:^˜ìÜ¡0¼¹ÞŠ„ÄZΘ1cÜw¾ó»÷ïßÿ¶×½îu·Ç…Ú¢ÔQ0ë%K—.}Ë-·|K륈`cTn•´®äí%ð½×³Ðº‚tL‡Wõ<4iXi™3/nÄ.E•9ðŠ`(z:í¾ìÄŽÚUk«Í{Jßüõ¼½Ì7oÒÕ@!KgA•Þsd6 ê-ÐÕ®¢PH Î-(ó€xÖ$å5<÷\—ÚÅjÝw¶&ž½~ðØs·ÏyÖ5·Ûyׯ«sfëAÄN}œ^ÿ_Í‚Ù{á#>Ü¿eÓ¬Ñçi¡ß´`0dPdõ9պ̧ú½8=«hèØøI7fù#QA»ñuÖ6{œ¢¤ 簾¦!ßýîw¿±mÛ¶ñ7ÜpÃ?׸Õs®ŠAÛ )¼èç `U‹`ðnß¾½õK_úÒ]òïy´Î,»f•™fÖtÌšk:6ÈkÄìeMy T¨¨§7Ùh¥êõëÆêž»Î+/â±N!¶ÏÆ …²2C“i¨‡!!ð©33½FØ^ ç&µµðôÿ–ɳlD¨Ö¿§cÇB(4ùÙ ÐÆEêû–åJ¢gÕÐóž ËY¶Ë^{ êB.1ϘÉ+¾lÁ…Ç4f¹ûm+5»ñ¡û{†ÀFˆ}óê+ÚºgÞyz@J¯Ó: ËXñÆŸe—½lOíNöš×{Oì1k–ÒËVµ]"l\"™3½0c™ºÙÖfø__+\èk¼3Öíþûï¿YÖ¿âŠ+>a]ùeåGòúÄF‰ í¤€ªK/½4©Å ‚r5jTë¹çžûb]-ÄÀµ‰(Ò5Ö¨¯¦ lv ²ñ˜k°g3!mŒ—·äe+z±-Z!{¶^gûzñ3¡Éκ|t\•d½ ð^,VVË 5¥kR»*­;Ë;Iê,Pˆ®Ýg_uW½­f^¼IÞcC‹°dCæMÎ! è¹.óâ=P•æôgœ(½:l¶N›®z’µW¢¬8³Ðõ±J–õ‚ùCãÏ3b¼Ô,ãM?ç`áÙ²ÀÇë5l:/«•††×ò+ [`j /ý{zÿ6¾Öô6V’…ÊuÆ)f˜¤é{F¯ Á’ɸ}ü¶ÛnúØc} 4~Š’ ˜³¢DÐvJK­,› ʶ… Þ-VÕ LÕ¥ìÎò¤ßIÁ{­tòÒè³&P!°JÔ&xÀ)dÍkËØënŠ«óÀ’e1ô„®Ý@Öµ˜W Ô›@¼šUÞ5Õ§mnK'𻕢¶Ç”q±=Em¯Qý¹W_Ÿë¬Né™èlìdˆ)jÁ[*ÔšÚ줒¬Ï½ò.`³LµÎ´©ÚE¦cHu“xÀ®×éÿõö ¶¼£´¡6v+T»Ï²R¶(­»Ö J†°l+ŸoËÆz l^9!ízõâÞB¬›W~'豑^Üžç }Lð¥õ2CY°°'4ÖY=£{ â{Ó§O?²Q—.]ú8ëFÐå8Ɉ#Z-ZtWSSÓº?¤ÖȺ€]#«ÆW;XW¨el|Z¨¦Y[bZBV«uù؉‚Š;TdÔÆ™xŠÝþF(3Ïs™XÅžÕÁs‹ècÖîF(fïéöQ,VËæîº­]ã¦CA÷¢›v¡kPfßgu®(RËÞ—¬¸7Ï}zŽBÏUÖ³bk<†*ëw<·ì¤o5[.D—Óñû¹n0ï5œ·=u‹% ü43è%Y·©W8—ÏM^ )=v=ß–úÐ÷Æ‚*/éÇ{,سàËcéóÜÄ6ÌÀ—¡bÀ!–Ó‹Ól-ï'´$pó~›à ß™?þûeýÑ'žxâCqöŒ -J/ËðáÛÎ=÷Üï p[Èd]ã¦uFEÍB¢Úšçà¶“ˆµ8CYuše YÏÖ¢´@I»mss¯,W6ÂS²6E³X^ñ_O±êó,ÆËNô\ œlÈŽj †u\ø¿]¯A?³ ÌöÕÏ„žtaX>|F4Û£X€ØµPÇŒ…úË]çMz^ÜXˆ½ =hÐÛXæÑ~Oà0¶÷É2™ëÅrçöÕ&é2>ºà«ft¸?[óÀ[¨c„ÖÖõÌÏ<–Ôsw3{Ð@Ë:iÎçÁ>'Þó¢ã_« A³ç•ÊÉêÊšÖn]]ŽÃÓ;61$TúÇ«ág}Bq€¶N[è¹±¸öóPbU¨Î¢u·kÚŒbݨ<½I½7cÆŒOËû§W®\ùÕ8›FÐ¥ç[rÆg|­©©é26ÏÚä §rµq2´ÙÚk¡ÀjüÌø•P+ÍÂh Ø /@­•˜-™¡]r6Ë,䢳å6²2ÿ¼Tþ¯Þxaå‚l.|Ž÷´á3º2m@2'StµÀýdX6œÖ“©žlum=ïÞ‡èCI'p‡€‹É!Àã¦<€–=6¯È¾òj—å8ï¹õbþBål,XóÜÓœyï-ÀÓÏ•ee¹ ž?$.ér@CºZ¿~ÆøœÙD&Vó·åƒtOV­ý;¢×.Ú·o߆8ÃFÐ¥Ž2f̘K°}N»½²:xXOäöÿP†T(kÎ&#è,.Ï•rizÕÿ-ë¥SñCíŠBUÐmAQ›Ð`A• Ý”bpi€¦2hœ¤¨8±Œ92a#FŒH Î4Ûb'tиÝ–AËkušä½æì¶ëDØ(²”aÎúzÑÎ2®ÓjÏÍ!·a€gYèÈóX:ýjAœ °@ެ²f—é~%CDCÆ7m¸è÷+ôè‚Ρúyz|Ûø1ª¡¯×¡Ä+ýáíËs͆Ê!ylZ¨¹WûÑêPàÕ53ñ à†ÖVLbðž¹¶í3gμýñÇ¿LîéÁ8ÓFÐ¥" «]äë2ð„Ú«` BÑÙÉ‹-”i'{ÍÎØúG–­²Ö¢Í Íêùé%X±] ä²2 Z™ÌÐZ]‡'2àêI¶-技»¬&òžq¦1Íî„Jžde³zlœÎ¨Ö ¯»2c— =à{‚8Œ_‚8ÝêÉf¡f•±±dv\y¡–±ô@™çðÆL˜³á :¹ ïq-h ã:lÞ¼9ýï™Õ/ãÆûgÑký›8óFÐ¥ ÅóÚ¦¦¦w‡Ë@°÷$] ^ƒw È4«pó©ÓÂ$±µ¡B½ ½85[Ķ›ÑÙ\ìP†~|Pîx%`#Pc -Q\·ÖÖÖ ¤Y—¦Ç˜Ñ½iÝ™YÌ™Í^{}ý«ù, å•稘å±r§ãVäÕЪ9®"à®ZVφY0YÆÖÌœrs^|œMúÁ˜~úé§»õÙ86¼Ç+3±éjÕ«^¢’u;†âר“¼ztž1l“l)!¯$ˆU¸^¸Óá$ºV$´žGœ›. ¢[î× nÿ¯\ãE²ÝqŽ -J ‘AÕ6f̘¯xYŸÛTÚ«nOåÁl+=ˆ5ð²Ô¹ÇºY¦}µ"³ûÉ˵–¬µ^ùÊÚRt£X€FàÆ"£dѹ‰²X´‹SÇÇhp¦cͪfÞ±kà•U­(@+ʆ…þ/úUËÈeÉ(µ±mEX.k[k¸e=/X—§ð²]u„u©jN³q {À+bäàdÇ‚8]FÇ&Ѹ e¨Z&˺N½‚½xy=‡C%a¼±aÝ©Vwê8<ëÕീÞãz0n¸†Ì,ÕDÎijjúÜÎ;ßGamQŠ+ì~2Ⱦ&¨YÇhp b°Aáx-ƒ¸Äé8ãa™6M¯[EJ‡÷”ŒVR¡ÆÑ^2…ýœï™ÕIPÆ…  ë¡´ÉâÚL˜0!UTdÑt³-þiÁ™×ëÑK °À¬È’޲ص"ý\C®ÑÐÿµ±²@-²jõgáz¨aá<0gŸƒÐïÚ. ÖÍJVÎs­j&Ž œ.Ë&n×®]ÝYõnL â{Æ­²kŒ—hå±q^‘pV¢=üœŒ¿×tÞ²mVGZPæy.ì{fëâ›››ÓßÞ¸qcz½pÎÜëFŠÞ|³\ÇŸÉòõ8GÐ¥€È@z·(’—“Ê×ì3«¬ËÔ–÷ðbàlH=±2îC"‡ÊwXå`Óâ=å‘URÄÖNÂÿPÊPÀfH[›†W6üÎ$Œ––Ó¦@ ͺ9½ í^Z}=Ë‚²²àÍÛwÖ](•kõfßB¬À‰äúJf©šêµŸ"¯!¦­ §·Ë­«Èz‡€œeâôÂä#,hó„LÊ £Ô¿JæM‡Jè¤m€ZýfÇf¨æšeÛl«>ͨÙkf8Ï  ×c×P¾iӦܸ1ºÂÌý³\¿{eŸ›âŒA[”le5KÌǙήÁ›ŽMÓÌ×’ŠÎZrº0¥M µnòU óã)kó%ÖŒ ^a-ó(á ¨M“ššš^ÒÔ²4›¥™Õ©7–z°kàÊ`õiYÉ'X;žà¬¶­^îÑzÄ»e1n¡uE[Ì›àÂ9#ç¹R Þ˜ˆ´}ûö´{[B‘uÓà ú…ì¼×)ÆÓ‹^âƒÍœ×qº6Íúõ®¨u¡o:ÛU·%ƒ‘‹’E0nnºm™\±d?/º÷µqVŽ -J†î–õ%0#Xõžƒƒ Ö .«! Öl_¾¬ªîšÅ³ B-`,ób)õ5¤þÃ9¸a݆ ÒëÁkÇ:’rί‘kôzÃwÄ©9‚¶(Žˆ"x»(‹ËȲi† ŠD+ *)=±ë>¢¶„„תÅ+4i3™Þ8˜­KÀ«mäe‹j—„eÒð ° E…IFM'脬’61À*ÿÞbÔ<–Çì9yàª,ó–·Mˆ e–ép²€³zºÞÊ0Íú½²nT`uæ=Ý_8ÔA÷ã…þd¢ƒqÀ±†ã¶mÛR޵5ó¦ÛÚ2^Qr¯Æš>¯˜¹ï!†Í²l܇ž/tæ+³èL5ã¦[¥ÞÍ¢—.›l‹3tmQŽ•QH>Âv- ˆÕ.Q(ºõ4¨ój|ém BêjØ:c”Ý‚/Òìø}€o[Uy™VZ´fˆ-!³†ëñ]fy¨1Ë“@ÍcÒŠ¸9- ÕJ«·]¢!ð–ǰ•aÙjI@(²M™.!€3G«REÀS=X¶z²tyÌ[ íG¤¡þ£º©:ƒò-ˆÓ­êX× À@³0±ì¸iæ_·‹Ò¨7mv½uej¶-äõðB]lácíÉÐÉ\z&æœ ¾ à†ëÀëTn-¢ŸÿFÎáÆ8 #h‹r¬‚ý#@Yÿ  `ÊÅ*›€ ³=m=·,MȲΛ-ßa¿ª·æ±ztE¨aHÃ+5œ#Üžj:€@-ĤU“¹™ÅlÕ eȬߪՕXÆ ZüŠY } ¬Õ“ë ß)òõv\‘$…j¬w½Š8Y ŽI À1K%E °FªN‚Â]¥ÈÛÚ–dzñmö^Ùïx€Íöwö2Yµ.'x#Åz¸J ÜT»½?•kóùú8SGÐåye3‰Ö cØt‰/Éb?³JÊ£ßmusKËë ðlì„V¬¡FF †u°øt2*Š“ãpàÀ[[[_bÛIÙúk¶Bh·½B5XÓ왵ð´u Ñõ~ÔªÁRå±àº?Ñ× @ͺ>³µ,`Ú“ª§bØò˜¿,†­–2e²Ak­ã– O…ăjXµ@0 l•eåª-ïQÏR"!¥ðfÒ¨ËnZgÚ¢µLcãz&$0yÆ+Šù’}hÃ+¼ xϤ3Û2Ë‚·¬^šq³‰ t…Ò=ê%™Ù{ãÁ÷pN“&Mb­»ŸóÒáçãTAÛ©.é@8í´Ó¦,X°`¬S°Ùþuú½×óÓVñöºØâŽ:T‹ø($5¾b¾ƒN…e¦›«ç5Oïé¬Íã]<·7iË–”ÊfŠVÔ²J}„ .Ÿª å'³Wä·ê Ü<2«Ðn(\#«¶[H³bÙ´HóšÂÛíÞèF…d  ‡1 wãÖ­[ÓÐÔG#úR϶i^9ë¶@MW °-°l-7&¥lN™2^“W­[·îÿÈÇ{"p‹ -6Ç{ÁÜ)ƒ~¶­b­[Ryì· )Höžó[¶M‹VLÌ%£F°ÆJÚ`ÕXKå9Bí¡Ê.µº@û*C—ǰգÌGv­Z V¶6[”ÚÀYY†­Þëj]«VŠå-ÜB­¨,ˆó€šWºC8ÍÀ!T„à:ºàq¾:qÇb[]ÙR úX5³€O£i4Æõ6uLB œ3gÎ%DÿuÛ¶m¯“ÍÅAÛ©,20†œsÎ9wØy‘.¾èõÕqg^{©¬ÔnkÕÚ V ³Á85(Ðýxã„Ò¦Y5f}æ°“e+û›E&¬¢. |•]_¨yÇxª¶Þrƒö¯lÒ"îјàöjn_”ùàqÚŽ í” ŠóÎ;ï+2P/ƒëQ/¯Ä‡Í&õ&MO1Zú[SîšÉ㶺.›,CÉ@Ø¥€µ Э«VÜÕ þ4x²@*Äx•=ž¼ø¶j¶jË|”e׊2j'Rm¶¾”zðeÎzƒÅ+ÂÒy`¬'ÀYQà–ä¼–ÞØ$˜Ó…ÐÁÂÁåp¦[÷ÁuŠÄ7èZ°ndátÏS{=m]6ï>èƒ6$ÆîÏ&:ðüpü8n×/^¼xÃþýûoJ¢›4‚¶SA0[ZZ’õë×§üüùóÿ¾µµõM¬Vmk²e KéÛØ5¯µ”–jX³¦ °¬áXHáƒa³Íì‹ô÷,Ðê• ê²Þr{Ö¿*…ÅleÕF«‡‹ÔŽYÝBÙÉ̦õÛV+ëI`Vö|Ë7ÏÈ©ÐYÏBpóX7ßæ·ht’ô&ËQƒÌš–ˆy#hƒî¥Î…¡Ìzoš Ó¼§GÇÆ¹Ycß^fÍ¢¶æ¬Y³>¹dÉ’u2g}?³`Á‚Ns)ãWo°ýéOêÞ¯Ú¢ôŠTJd¤€Mþ7Íž=û£:nA»D½,Q«ølM0›T épÛÚŠßÇÀYÍBQ@i`Áÿ`Ñš››SÅEÃìÏ, V sVMæe=¶žøÝÐ>ʲkY¨ˆ›²'2L=&. TžÈ¬Û‰Ìðõ6¨«`–q—†€[ óÊe·,Ö-ëVä9g‹+¿p…‚ÉbÓzíÅ+ô.õ/Áݦ–IÓ:Å‚:Ë zF½>?½_^//€#J8pà_V­ZµAæ®ûåxn¿ýöNöÁ®§€}œ}zrã7FTA[XðÝvÛmi°"‚k¬q¥ÏG‡æØ~¥Üs%ž}öÙO¬Y³f±Ì+?|ë[ßÚð£ý¨óÌ3ÏŒƒ8‚¶S÷â9Ÿ8qâųgÏþG;èÞô&vm yÙTÖ5jâÖà XÃj ®dÄ­±ï]»V,Ñ,VM¼ZQF+T­Lvg=›ÐçM¦Õ$ xŠ·^`­( +òÙÉ æú×ÓîDaÛŠ‚7ï÷=ðbÕ,X ¹I³˜é<=áé-‚7fü¯[·.mˆKÆ:&+ FÙ3è¼kdDZ7'Ùóf ^kkkÿ}ûöݺyóæ ;::V]wÝu ÷ß'd”ÚN8À&lÒ‹^ô¢ÿ+ù n=hBÝ ,•®ÞŽÙ§ü ,³BÉ®á=kÄ´‘Yó¶¢@ÍK¨µUUmìš§øêQú# Ùov­ €«7XË:žS¥!|=»ôp;Q\=[Ñd†¢ãÎ,€ó:&h KY¬»èn9ÐñÐшeƒñÍR!xxCì6»,°Dˆe-8³ý§³æ#½ O˜0¡eÿþý·É\óò%K–ìË[ÞÒpçwFÚ=‚¶ °ÉÀêöÙgß*v;øZàæYwö½X6à”ÿ¬aਰa°3X•m¦4h ¹A˸?³ÀZ½Ëe”q€Õ°w^ï×jòÀ[“f÷f5 °CaYŽžwYq9y1;õnå”5 —•ðèiðy<\O±m¡÷¡{˜æ¬ÞõôwV­l«Ao±Àßg²’ÞT†Úfxã†1oøàJ5[ßÍ;N[”×^+ê=vLhkk»@æ Ïx{÷]wÝ•|ö³ŸMÞ÷¾÷E4AÛ‰#óçÏÿˆ¦Wèx!Ô ›,^<‚­³¦ !\Ÿd×¶oßžX¶LÑ Ü­K´˦kÇe¶z'Ô«BQƬ֬Ðj“ªeߊvA( Äì¤çM¬z¿ìiHÅ®ÿÇ¢3Ðô6Y v „:€Øº…Y®¥PGï³j’EŠ´)ó&=ï;E³kaЏ ‹l[ïx·2À¬LüZÓæu(2>CÏ‹‰ƒþÔý=ñÉhˆoÆ+ô7{ˆêÞÒZÇZgAt<Œs0k˜à2xüÀÊp«êVˆœK¬Ñc_'Ë鱬ױP0~¿µµõ¯ä·-Çtûûßÿþ™;ÿøÿ8‚Úú>Ë6yòäWM›6íC¶xnˆñJuxu5»ƒÁƒ:œ±k`×° *¬/5 ÚŠºDC€-¯¦ZXó&_ïX×jH™ý­žoõÎ ­Ö5Z+Ó@‹ &ýžÿóŽÞž öƒmò@]8…€Pˆ•Åé„úBf·j™1ŸšU[ïÛö1ºú»úù/b()È›€ŽÛVaÔŠî'œ—‚7Ž™¤žèk,H¢ƒw„㈿çñhˆƒgÝ̼ v|ºû†«T3nìgÊOo„ ñÚúvœ×XëøÛ¿¸mÛ¶ÅòÙão~ó›~ÿûßwNš4)"ƒÚú.`1bÄäÓO?ýyøiÍh ¥“¼š>:kÇ6 Æ÷1è¨È®!ÑÖ¶œ*ʰÙöYy€-¯V„Yó€™7Éé‰>äôñ{®g ìªneÖÛu¡‰¨¬k4¤D³€¯ŸZx¥uWû^/0Öô¶z±@÷‹Ÿ…Àšu»xî# tò@›w«aÚŠLÎYF—w ¡gD3E !Nºž!£ÇCÙÌí3˜ÅFÕʶe±lEãÖjq“æ¹@‹²—ž°Ÿ3ÂàAìþçØâ¸ÑÇKÝKý 07'^ÁªéÚžÞÂí7lØ‚E°n˜3 ÀD4K ØsÅo`Ük7°ŽiÓs~ ­­­Mò[·>óÌ3—tttìÓ›ÞÔðÓŸþ´³ž-"h‹R7À&o¿… Þ"–ÑD°jhÈåCpfË}ðŠ€ìã×°§´Èòâ׊fˆ†[hÈE^!]&OäMðÞ„¬'Ï` þO[ï’YlG5“¿·Þ›€híZ&L..x^°ð½^Ï÷Ú]ã4˼i€ÆûÄÉÇsƒzÁÚ¥X®m‘úwÕL.yîÎЫ58ŠôçÍ2¨ô8× .oüçé€,wuQ¶®ˆk¶—m=âàB ®Lè‚6–0–”c¶yóæîì}2k€'Í c;n Ù»oo·¾Ç¶pCênx£ ôuƒQûë†8gèH+§¯§u—zúNëeý6€Ë–––óP äàÁƒƒ‚öùÈG’O|â%DÐÖ÷dΜ9#â Æ(h& ƒC§a‡jö謙9üK ²·@v E¶ZÊy”Éü,Â8ñ|4°ÀÀ¯@¤Uúü4xƒbÃʼnﱟ‡˜2à-‹E+¸Y¦‡ F³Vi†:|xW,\Ç÷záw¼x}4{¦tV 8Š5Ûª|ÞÿynVì…s2t!ÒOYáE\´EÀ\`ÕS€-ÒÊ€yŽ€",Ä•°¼aY±bEª£adã¼/¿ü“«^uU2eJ»œÿnàækävÊ(×mè°¡)p1b¤€©!ɤ‰“’ë®».¹è¢‹’ÿøÁ$?þÉÓ}3 ¿Íи±Üè9ŽL ݰnpkòûžñf“BÉé&P9At×çåw^‹ß{ûÛßÞðï|'Zƒ´WÀ–Êüùóo’ ÿ >m‰Ø¢¸¶¾—Í÷Tlˆ`²„ŽÕ ËÍcײ²2ËôÝÔŒš%ž;ÎÆL‘ýñ€˜ÝÑŠD/DZ©h§ãÜè.¥ËŠŒ  qX 4 æ¬2´|;Õ!;wvÅ ¯_·>Ù¸aC²m[GòÌîgº\§‡töÐKÐ?ãÇ7'“ÛÚ’öö¶´]Ö]ó§šÌ˜1#ùæ·¾™lÞ²9=6¸Rñ wi¸Ù{‡mpŒÛ¶m;Fç`™f‰ÚD >;özêŽ=<9®Woڴ鲯[¾ûÝï6Üzë­É[ßúÖˆ"h;~‘I“&]9yòä¿Â$kÝš°YpfÝ~Ú E€ÁDw(hq PÜ !Å—å-ã-⥢'`²î°q!øÀ~éÂ$¨"èÌ ‚ö˜$›À ã²x,TŠ6ÞM»KÔº¬Ü©å‰ï Þ{¢™3ðF0¦Ù3íÒÔÀÌÆôÙ^= ŽÊì¿·b­û¯ÖUy¢·j›½‡^ÜYÈò¨óXo/QHƒ7»Î38­¨¥®›÷ý²l¿k1¾qãÆ”aK ÛîÛ›L›:-¹æµ×$mííÉ~Ñ7nHV®X™¬Z¹:5¾¡¼Î4Ô¡ó{ìqlã’éÔfÍš™Œ`6uÚ´äoxcòÝ;¿›¬X¹"ý>À®[/ô®7@¦ÖEp_B'z ¨Ö»–ѵs>Ç~åœ>³cÇŽûeKn¸á††—¾ô¥³gÏŽè!‚¶Þw‹ÊC9nÞ¼y_´!T4Óúý=E§&}Ö^ÂÉB¹y€­ÚVTEêžñ\¬«O5í¾#`ãDZ4éàè,pè)MÛVÆËfÔ1\Œd´ð{pšycœ8,XOPIe­Ý›dδ+Óº1½$‹ã Æz °h±q'2óV¬•¹Yµÿôxô2½iÄz! !àV„‘Ëcå<7f^òAž»ÔføcŒ0!† € z»}r{rù+/ãï´tÝÆ “¥O<‘lÞ¼%Õ ^ÿèе‡>Ù ßß¾£‹¡›3wNÒ>¥=5._ñòWŠ>’¬Y»:Ý {èT¸Jó2åíý`’õ9À[`éóåqé6]6ƒÔäПÜF¢~›\ŸWÈëáw¼ã ÷Þ{ot“FÐÖû"€í&y0§êö èôÊzxS+¦Š3~ V]xYŠ,«æšW ÀF aÙ%‚ ÞRX-› H'Kd¹e5¨ÍºnZ™ä±oº(,'A”–žPl¹ÍXàj31 ̪u_æ}§€,¶Ú¿ž€®-µ²Ž¯H<`*Ì\d_4X¬ÁêÕ% 9+g3[½’BEA\Q ¦×a¬C?¯Y³&õˆì?°?LçŸw¾èº!ÉÞ½{’µk×%Ë—-Oõ¹îfPöþæ ¿5}ú´dÐàAÉù‹ÎcqŸ€ºíé5pÓeDB€MǹqÜ¥›6mêöà\NS™­,¦ë1µ¡®&¬3‡ã]{±ìûùíºï¾û?úÑv~ìc‹ "‚¶ÞcÙ&MštukkëÛu‘A/~ÍfÚX·)& «Mµâ*’Z&vÍ{ÕŠUƒ§ec ÈZáU·Ñò@d¨0iÞdª¯¥]g—PÅÍâl™.k –f]ïjb¨ú:h«ÕÅx2g ÖâJíÉ~¢µ²jy¿W¤dG0§k—é¢ÃY‰E€³Y®ÞØ´¡Žé+Ô4ëcnQ%èÀý$sfÎI‹Þƒ.\½jU²råªÔ D–h- ŸÇйá‰%KÒý#ÃtРɜYs“Ý{vwüð̰‹‚Õåy¬ôÎG‡²ÐÃÃý°Ä‡fÝ8÷y]|ð] ìÿïwîÜùcÙä±›nº©áŠ+®è\´hQD´õ<`“‡°yîܹÿ;d¥Ù,B[òÃ94Pä ÁCNv*T­'\¡ZYi7¨-A¡]€Ø–±A«{ýNCY–yLd–Uï¹h¼Eÿ6ŽG8…¥Dfpâ3*+/6ǺnòŽZÕ‰ØNv°ÖÓ ^µ€± X+ÃÂ…¶ e–|Þ±X7«6N.ÄÀ…<žqêoV9è èj$@’ÿ'ŒoM†ˆîÃvs«VÂeºßLêéeß³g¯ÂÕéû1cF Hœ´4·&6¯OuØ?- ÚøšWÄ×䎳E\ší @°¦cÛl¼÷‰ûƒyAö3\t*²I_)û=týõ×7<øàƒ˜ç¢DÐÖ£ mΜ9àÖŽ ]'è€M›íè5ˆg« 4v8€pÐe¹Có€Z5½:9ø,³æe8ÌÀŠb© .ËTWÏšÔŠNç1sZ9óøX[ˆ—yÞpIã\YIœºl#†m<ðf;^Ô”õ W ¨8ÕÀÚñL\(Óü½ °+ 芀µj>ůÈ1áK³r¶‰W‚Ä®Ï*œw<Ð ˆe³…ãØ@2xPW¯g¸0QÞF8[O£ãÝt§lyBös±\³w‰ýÜâÅ‹?ñ‰OtÞtÓMYDÐÖc€íèøñã_·¨.1a³Eu9/ù€lÀ(o,mØ–}ãòqCÀ­Úž ¬±€£ldÖ°?–ǰ±jžk¢L,G–U^¦økѲÖ%£ƒh™]Š{Ö q¸¸FØ> ¼ÙÄ“´õVØ(I)Àe·Õ®½"ÏxcVf»](9¡( ÌÊè £—Íjõ_¨°î<ï…×%…] ``Câ> 2¼Ëƒr´3Ù¶u[òÌÓÏôè˜À¾w?³;ý-ĞᇚìÞûLw è+è.&rÞ¼y7ËÙêj™5ec96|‡eÄÌÊ,×[Q†­(P³¡k¶ò>Á~Ÿe0Øt8Ĭå±iµ‚x«¦~™ÝÖ‚lÒûp¬¯Æ>6Uf&ªeCÍËëÍÂõ&ÁZï³md3Ê€½ZÝ›yÛMN( Ôò’òX9^/éÁ+œÞBe” Â2ïýú§ >Ã:àlUgK»µàŸzêÉ4!A×£‚¶º³l³fÍú[V§S)èø4* ¯h®N8`:6Ðè|˜Cñk^±ÙPVh™E—ÆðÀÙ5ìñjlÖ ª³UË0jµ°lõRˆE]J¤øqž,Bð†ë¦“t橳úš–­¯¶j÷S¤z¾÷;'êÄb¶Ê²fE®¿WK2 ÐÙGÑïu«aóô8÷âäl‘`ËÎyï¬O£mÀ€ç{wB—CgÖª“t‰$ÔiÃYnïØþàvðà³)ãF4pPrð¹ƒÝs ô‘޳%Yìµð7â³È60nÜ/·cIyå|¥Ù6¹NW‹îüoò½oüîw¿küüç?ßùž÷¼'"ÚêØÄjYØÖÖö׺8¬×‹ÍN$úߢ;“>b¶¼˜‹ZãÕ¼.,äËb°º/Ž®AÄØéŒôÄ„]æó2îÒZ€Î÷ ÷Ž1oº3Pm¹jcÝúhëK1oE“¼¶'ÛVô8jty ^µ±jÕ~*l:žÁFƒíTc eê<¸F±¤¯²‹þýº÷é£,ÑUhŽ52M2hßœ®{ðßï÷¾ýûR°–’ýi` ýÊ"µeH²ºà°è/…}¯5Èôz‘jW©.@öù¿öìÙsìnÛ‡?üá†Ë/¿<Ý ­.€­Aº~sæÌùy‡°¬ªV6¡ìA¾°¬¥u}*1:CÔKYÕ4+Ôô€¤ÂÒµÊl¯K|†Á… «ˆI^3èzOØÕIJ٦çÞRõÈ®e«²oì‚ Áu«'è:[-É)'2ë–ʲÎ; Ðeí;ì…Ͳ€¬ ãæu ñÆiѬU½íø`{H#”Eg•35”¡%Ež[5è„Ô(n•Œ9"ýqÍc»;°`›ûïûe²sÇΤÿº>ôÜ¡¤±¡±{¶b’¾Ëã±Þž~ źq¾ÁüÀÊ{À7/üÇ+{¥ë`Âð•¹e²ã‡\¾{ïÞ½ 7Þxcç÷¿ÿýˆ:"h«ekooÓèÑ£/ÓY¡6èÒ³Zô¶dØØ`ᡵAü¶X¤-”[­+TÇב]cË% Øè EÜ\¡Úe›8zb¢®5¡“chÓ÷×…ñ}oìAÖ™©Y åñLP8¶™!+[§­°U/v¬PU óA‘®¥¨™¯OÈÀ,ä,˜Ã諒B>­4Öòž·4Ô䴮ޢб8ÝÈÔÜ´9iÐ’ÉÐØ÷¯î u‹â\²˜:Ö¹óׯQôK¿®sÆzLÈ2öuV¨ÕwnÈ,åg˜+p¼Öò2Jé©Ðñ°Êõ¼^Þÿ²í¯î¾ûîÆo|ãG¯»îºˆ<"h«°¡†LËôéÓ?¦„¶X¼@Q«°XÖƒ´:¶"îÐjÜŸ!«“®²kŒ_ƒò€…‡AˆÁ„¥ûÖ«xl-@­·A›Zpßrq½4릻2xݪ™0ëÉÂÕ›‰+ËîôàÖÛ¬[µ…oCüë]v£Ègeö™ÅÖ…ÀKf±3lC÷/¶û¡þdèÆ£Öµy‚¬ë  §ûh”åhCwUÓå >Ÿ0qBrú‚ù©û³ckGòè'{vïIž}îÙdÆÌÉì9³»cgÀ¶eó–îC¡RBÔëÌ&ÇÖØAÀKÐG†’®KK.h§]ž¸±×±oVÉ+ý»n•n?åÞ~Zöy°ï>ð†W¿úÕY@5‚¶ST00n¼ñÆ”âµòÉO~+eÙf̘ñ?囬b/‹Ë+šK ŒíG €X­:”yé1k!ÀV¦±;Ù5‚56 @ü&À›cRyéNPë„UÄ .ë«'P(ºér.¿¸vÌ0£òädcï{ÞDx¢¸N#ÚWX·¾Öl¾š® Eƒü˺@ó:%Xæˆq¶€Ç ²kyBÖàF(b¨˜D2BóÂt0ZGñ?ÿòžsù¸SŽ,ÛŽŽÉïü}¥i’L›>59ãE ºùÁ_ÿ6Y·v}Ò¯WèÅ”iSÒóXòØ’tqH¯YúÛø®B¾ÜÕS¬éNd±n¥7ÏX"Çœ;BiÜl ,}muÁ]ö&•ûûR™'ß,úñ–76~êSŸê|ßûÞZm/Øý×6ÇÕòÃþ“-“Îmmm}'{µñAôÚPy‰IlL×ǽÞyE\ EcØlû)](–îP‘mnn>&34K±•Œke‡a ŶÕ;ÎÍ‹ÿ c—Î ÃõÕ5ŒlFïÉÚN$©•uëIàVm=·2,r5ñnÞ=Ϫ»ú#èL¸ß‰IKh`LMž49mš>qÂÄTgA¥ýƒ÷ìNkŠmX¿!Y¿a}ºNw7Á>uÞö¹Ï}®áœsÎ鼅‡*JmÝÅ Aú;ßùÎQòœ5ô›5kÖ'äá¬k²…²‘X³‹(‹â¡Ã÷½¢¡lÐ"@Í‚*ÝÎɵ™¡hØ,ãØ±cSeÆøºZ‚åë1i÷t,[¨®[(iÁsIå¹N ıî;²×õdIP8‘ÁZ¦·è>Žç5¨&3´–b¸yû/:–¨/aPB_Bo2v 2wÎÜäâ‹/NÎ9÷ÜdJû#» Kêcê<´yÚ¸qCòÐÃ'÷Ý{oòèâG»Ës0Ž— V¡°–¾Ð¸~®òy±{žö,ÀƦí0–Ê\ þýÃ)`7nl2fìèÐÁÅ»ì‰åÉ“»žLAÜðÃÓİ{@jG+z$Õ/X×3`}¨V›ÜB ž±ŠmØ1‡Ý|0—P÷ñ;6Þ›úןáBÇŸ(÷üoåÿ÷Ê<Õø¾÷½¯ûŽA[¦|úÓŸF߸”ekmm½F@Í+ñPi×§¶FlQ=!CÁÁjñbÕ<·§ÒlCtÝS“€ŠJw4À±´´´¤  ÖŒùè 6¦žà­7~;4é„@v·¥’e au}Ï4ãæ]ÿ¾ëv¢‚¸²íšêµ²±L׃z7‘/ʪ­½Æ,G0aЗdÈ°í¼¹ó’«¯¾:YtÞ¢¤itSº=ÀÎŽ;*MͧlâËú÷ Ð?6nò䤭­-¹ìÒK“?üá‘ä{ß»+ùýC¿ïv¯‚"`*Ê´qLw$‡¤À©=F“|–•€mô˜ÑÉ9‹ÎîÎÎ ‡s8ïüóRÆlÿ¾ýÉúµëÅÐ>Ð5Y‹~2dp³ÖuHTe;ta8zôHZ³MÞ¥Åu9àu¹`;Ý9Åž£MX •(²ó–fÜØÕG7  °uü!æÇʱ«õoò½‡×¬YÓôD°ÚNY¾|yróÍ7§O¯;nœìgX²`Á‚dÊ”)É/ï¿?ùÎßé*+`çèŽç{j¨*b°j±_‡ž;œÆ’ueä?øÍ1cÇ$½ì¥ÉP9¾û&;¶oJ::¶'{÷ìM:¶ut1ð4¢3RÔ¿_Ò/=¾Æ >p•À#‡ÓŸÇkrøP÷q´q³:)Ôª‹s]ž¾öJ‚ ¨ `q‹ÌëŒRfûªÄ„Áþ>&Ë«`‹À-‚6_>ô¡–OY6±Ò®+ìtÒóÖ7¯-3ËÀ±a/ãÅl}³+ÔþO—«h¸Yw“hý°a-L/®£–€ø² Á‚¬¼˜3[Ä8+¬^Åt‹¸ŠÄ¸éEtOëØ6ƺõFrB-Û–-Z„~£ H- ~Š\›ZZ½î‡Q"{QïB¶erÞúPïP6LôÔUˆU{ÝŸ½.™7o^ºíæM›’ 6$+W®‚$yêɧºˆ¨ÀP÷lÒ¤IÉŒÓSÀ†hçž{n ò­ÿ¶ìkE ð»ø›¡‡\‚ú\ìxîìì*¨ÛØ/ŸiÃ>0þgΚ‘lÚ´9Ù²ykz>ô~ 28mþ>p í™Qe<^φÖƒµÜÀ¶Øq>!³hÝ“€ózE{-´ôu×ÍçYÚŠŒ®©Ö¿v~£1‹ãcí6yÿ*Y®”ÏQ°­1‚¶Ú\ùÉO~’Üu×])+N[{{ûº!¼¥Œ5G‹‹J‰°ÙA hcwþ3 C -4Añ»°aÁ`Æ:ÐðãÇO_R¤Hn=&]õ›å1˜Á`Të2¶çÅó`¥ï.÷ȡĖb)ëÁ¾É*ÕÁ ÔX=5‹,ƒR¤xññ.šÛ×cØêáöì  Vû2+Ð?¯#B™fíeŽ· C§cØØÚÚÚ“×\ýêd„ ©»¬Úҥ˒µkצMص­ã´ôþ1®ÐHõÍV ÐkkoKæÎ›Lš<)ÍŽÍÕ¯I~ð?HžXº$Ý€ƧÎ~ v] 65º\á#0ý Ð/ÿºaÌ?ô»‡»z‡Ž1<X)±¤Ûà `ë_émÚ¯ÑeáSýtÓ¯1eãŽöëx$ °oß¾»äã'³Ø¶×¾öµÉ¢E‹rÏ 1æŸýìgO8ÝA›>yy˜…ôþ÷¿Dʲ͜9óÊúáH°4ƒ ¬äÎzlxøðÀå±j¨U;qf6¼”¢ZµîbÙªu‘’Ão¨!^¿ÅzK[·ní®·²æÊt[àB7)ëø0†ÎyÆŒéõÁç¸Ï¸?te× ™ð4c¦³Jq<Œq#Ø%ÈÔ -«†[o2oõJBèíòeê…½§Õ>7õkE[™ºlEظ¼D‘¬û }Áß]F^C2¥mª€Ÿ¡éÿkÖ¬IV®X™‚ºzÔ½ãù`+d¿‡å7&Mš˜êŠ)íS“={÷tÝÐWtM†Î“F#!ôÍîgv§ïS`Õ¯Ïhpv6kxh Ð&¯`ںݤýÓ¬R´AoìÞR&Ï¥å>ta]êú¢íºŠ€¸PÁ]}M¸ ÜxM=’€:Žñ¾ ‘s›&Ë;äºÞ”Ŷ½æ5¯IÞð†7䞀ûÍ7ßAÛ‰,W_ýêW“•+W¦,[SSÓãÆ»V³lº¿¤´z0€)! «eÁšgEØ´¢®Ža³€ Ç”6"®´Ñ}ø¼8¶jÊ|\¬AáÀpAA2Øž¿ç)ÂjHˆ!cM"ü>¬*v&Ë8kÖ¬ô3 \ZÝ^·‡PbD=7Ó;îYãbbÜ4Ðî Pv<’Šî'+›²L1ØPmÅ2Ï] æ1je€Z5÷­§[ ^Æ= Å‚ÓiÙ§%ÆKŸï26׬^Ó Øêñœéñ‡ð‰uk×¥¿Ý0dð¤é´¦dç“;Ó1‡Ï±^èö\llWZTvÔiÉöŽI¿ÃmýÒlÏPRË®e`°=Þ¸¾Ko<¦®gê…>­ËHöíß'ºöà1Œ·¯¦]W‘yÇ^[«Ó¸/7Ö*¥›”Ç©¿OІ{@à†ùDtâ»QD¾²1ĶáY*"x¦N ²éTm¸‰·ÜrKCåahœ:uêÿ”×:³ÅSÜzðr 0ÂkµÄOeÅŒÙ,Q¶I3¨*€M÷ 1€E' ¦‘ã»jD€ÖÍ›7§ÇÀkÃjSÉ«l!ক¡m2{ëŠ÷Ùc­­­)°Û´iSúy¼Õ“Ýñ²±tb ®ã|R×I%07ïzÏD„ZÙ·2à®Ú.µ0be®µfÝ˰ˆEYµ,f«€­lüZÑs³û뻚®ír'24}…Ûºek:Á×£> ôt ~“ã }°i㦴–[ZCqбø.@z&BÏ;çÆcáwЩ] ^È<=º‚î»–6‚7²mæ-eÛRWé€î¸¹þìW\<Ð]èA ³¡óÀVƃ‘¸‹¸,ðàF¾eä4A¢3ì+®ãñrOþBîå’ÛA[eRL — ¹’Y¡Z[Сk ‘ækÇØ­2ñiÕ”sÐí©4`£rbð'6ß`™Ÿ2–kø¿££#U|Ø 3 ´Uܲ&pýJ‹÷“bdpŸ”qÆg¤ÿ¯_¿Þoµ´ ÊJFá%pÃ3ÅÿµKÙ‚? ÔÊàVnú²»áxt6¨€•Ýg=[ÆØ/! é­³uÃŽ9š 2¬»¹ùÓ2aLÕò<¥Æìá#)(š=wv Œ–=±ìÛ@èìþ¡ƒ‡&{öïî6œlïZ£¾¥µ%Y·f]òÜ¡g+ã4IÝ™ÇL¸ýúWâÕ˜pWè  ³Ôµ "ëV‰o <%ý+: ìbñ Ó$€Ef˜ÚVõгyá3!}‡ëŒûÍŒR0™¶L•.¥Å….dYà"½Uv½:é c:±ý›´ÕF†T‚Æööö¿•¥Ÿ'²ŠVǦ(°‘j/Óײ,X³ ’Î%`ÃdãÓ1lº ¯LZä™, °ƒßEœÎ]SÛeÝ­š¨¤Y—£Ç¶ñUãøQï ׇà 7×­[—2Ö®†Y }r“ê¬Ò®àâ}©{Û^ÏP<^ðt*—©7X«&þ¬VPgû÷`«—£Ëô¤5Õê.¡ôôÓ{’ZÚ±ZK{K2cÖ 1 ɽ?»/ý= ° ça°A§¡«Aê8Ø¿;ÄǪÛF¡!LýˆñÚ:±5-Ì*»ú??f"Òl? cxXaÜ\l*9!eåug’b·ûöîKct7lXß•Dѯ±;V— }-LZ³^„Óº.ûÐã˜Éö¦Ë”L!KAÉÒ$sÜ r_n¨Ì×§t Údü677_9vìØ—ë¶Pv’Õ±Y2 |1É$åMšeÝX! BÀ¦ËzaÃg`Á˜%lYnJ{ lr*ãØ.PÍ…X4 ø². \¥Ø5ðê¾iÁq’þJªpµåkï™ÑÀáØp>P ¨_·páÂ4k M§yµ‚·j²J™‹{ +Õ²•õª«W´6W=úÈöÕ Õ&#T[W­Ð)Sc-o_y…që¿V„qÓE^©g¤Áõ]S{#í*Qã[Æ'3gÏ=8:¹ïg¿Hõ£Ç˜A0¾Œðƒ`©Ò„Ǻ3+k•çIØåŠ`‚éCá\´¢Â2 s`ʸ ÐïùÄ‚L2èÊíŠãêZºbÛT’‚[¸GÑÅaŸõQhxe²}{G7 Ô±lxÏòAÕ>õ`àì³]Ðfû½j½¦;MèWrÿ\Îé+²é²Ú"ËÖ¯­­í½ò€5ØÉQ+› %ƒuϪ©à^¨y€ k°±ÎÛ±x=N½†óYÇI·‹ñ"°ŸU®™ä1kÚÂKYKù5rTZéU½*Ê…cŸ7è Öä…õR§^CÔA9"w×®'“½û÷t+›Rî7Íâ8Ö` ¢Š:/Zšáþ†~5àÀsg7N8áºá²¶Üku‡–qEÕºB¿Ó›`®Ú²ÕÄÓ•-RaW°ɘ-»®Úšr é  è?°û=tX®ÒPî™Òã*5Â,Í_0O^·$[·lË¿tÕò8û÷‚6²ñ,á‘õû؆^ ö5Ü69ýíÚu•Ϧ`­klw½P)éA÷çÀ «––Œ`C­Oè´~=·+ å@¡a0l¬R@·"Ï•u*«Í¼-ëRÍÛžz—±jŒoÃyê9µÛˆ¯Ì1LTI;E æžY°¦Ý±:ÞI˜8V­Z•&+œy晩 `®È5+ãzÊ[´ÕŒkÈ÷nTleʤÔÕ hÕ;•eÈêXP ËcßBרÚI»L¢AËÂÙšâ3ÀñEŸl‹òiRÃÝMØçÌ-zfXòÀý¿.=w¨ò vÓA€º6/T‚á4Зœ plÓ¦OK†žÖšÛ»wO¥·iCWAÝA“!Gwé°I3ƒvÖMâ”-ëʲEI’;¶§^tˆ@ƒxfbÒs@7­-­TrÕ¸xÃ5B※áèd#ºHYÃ’^¥Š[ù2ï}Y6]z*³m§*hcÆè€)S¦¼:D?0!&Š ÊõÈÊ(àjéjx@–V»/0¨6 °…ZVikû‡B€Ëq eCeô,ìô:íÛŸ<µ««¸â¡8ÆaI〶’{Áøî QÇ®CšûN9F(4d¢5i:†ô\JÖUª?gWœ7” Šõ"ãtÙ²e™n–<7–«ä±m:£”FŸ7Æ·y%Dê Ìz£øn½]à*s¼µ|§^¥=êQ€·³Xm92É º<‘fSU†½M¸ êÁ#G“á#‡'ÓgLKY©¥K–v5m—q 6±l+–­HŠÄ¦òw;˯3ÿóž)²r0õ:­½½=iל,[¾,eþ~&ÕS‡‹@öìsH {69ˆEtô%bÜ£ýVíé§žîʆm•êfyŽãÁ¶˜“Š\Çj“Ê|/Þpq¬˜¶Q½ ‹!x«$eŒ”¹™¤ï>•Ù¶S ´©H³l¯°-–™4óZ8YÀÆìB¼Â-jK{”aÙ´ŒX.ü2CÓÌ® 0-°Y¯K’ìoìjKà ԣeØé0_ ¨…˜1 ,µÔ{øPêz°mWB€ÍcÄôÂï2K–íüùó“Õ«W§.ŠzĹå7­¸CI×·Žoó&ã"ÌTWTo1cÇÛ˜«Ws÷zÆÎåº"Œ—÷ìce»%xûÖÿë~À]c½ò—£+¡kÛ§¶§ìôC*æÀXé|þØà6=¼ýpÌöÊV@-µnŸKg—ÎOõHçáÔÌÊú ]ŒO†«0\ÚÚ&§†v‡›;wîHû«¦%£öï;&–:ßEÁÞÑM£“‘£F¦%Bè^¦N€þÃþXB%‹@èÉzmEY8}ýX» çO²!Üðªú±6Éö×Ë}_¿tÊ6§p;¥@Û7¾ñn–M&â ey%kiÚžãžtcr2Õ(—xÖ-JÀFj®;ÖòÑ€-«&›çÀ¶°äà eÿ=ÝA¡XóÀàÑ"X÷pŸ—E½ ìB6»&„ÄíXQ„i³L€VìIˆk>uêÔJ€ñÚÌå¬I9T²Ë¬x@gõS-˨•q7¯ø·bÝëÖ<Z^&hÞ1u–]—4«éGZ4☠ð—~ÄÈéü݃¿Ý;8C± äbØÐ4t€±eŸçžwNÊ’oÙ¼5YS…$¨Æ÷RÏvvux®!9|ôÇœ§§¸Ž5Æ+Ž‹àû„ž…7ƒÛb>Iãê:ãL{Žöëß LuRô~‡Y®õUõún^i³†yŒ UÏ·ºØ.î)ëæUZþýw¹&_”]mÀÏȼAÛÉ(`L¾üå/3c´³­­í]ò@  [PSâ:®A³.°¢ˆú‹Ö^ÊS–¡Z::[” ïqƒ+íN,`³Ve–kûÄ:€?*X=zŸ`+â"¥BlxþƒÔ²­¶qÞ䨠Òì¹ç1my“ ]ÃP®è €n 8+V¼À:, Š€_/9Ç@V•φe†{¼õ­fÑï×ã;õÈÍcMªé^PÄ%ZM|\gc7“ Û–wÿ:¶u¤Á÷ϳñÏÆÃ%—^œ–ú€ dbù²åÉöí;RWç0uдU˜´ÊHKãÌ@¼ÁÈìwèù¡{2¾´ç‚ٰЩ™oˆ;fœ*3$Y Î2’Ú5ËkÉÞ¨k:C´,«…‰+[p7´ŽsÙ6\ {Út±ÝJ|Û8™Ü> óÕ¯~µó]ïzW'®sm'‘|îsŸ“”v? h¡X–)Öë‰z¶¢ý^Ë0nڨ˩žK8ù_U÷?­‰Ö>9yæéÝÉ’ÇžHõådѳN%ŠØö«µ)ÛF£¶¡ÂþwÇ!‹•F,Ô€[Ñ–vY`['y±¯)À› ÚáyWè ª¦7h5ŒZµ†u€Ëkƒy ×ó«öðغm¶K‚\Ë6Yÿ:¹6Ÿ޹å–[ŽFÐvÉwܘHãdéžiµ‚5»Þ¾Ïr‹z [È%j…€ ÁõˆÁ~™p`[Y—è1ßkHºc1mÈôj à>rLǯY‘ÉË2nzÑÅ+Ñó±)Ó§OO«“ç%'d)ý2qnü}f.ëàîjV½AY_y½Á´Õcûz¹jzkµ¹G¹Ng<ÓØ@¹OíÊÎãªNuWú ª«êÔ±™;W®½÷ÚÐhÄŠ¤0X$V›oò›°i9ßEê‰sËÉÎÜ•¹¬*e*õ9íÊ,I™¦0 §-†Õm®µm»*Ç„±bqíw\ðÆû›àÆ`xLÆÂ㜬òCÕ+ …ÿ­·ù½ÉÍßÿþ÷ÙW_}µøÔSO-€¶ù¾ 1ˆX¶©+Vü™~à½ÏÅ (H¬ †]R(™}犲Y6váb†ÆñtAnÑ ÀÂ+3vÐad†­Àô*ãÌä¾²ÙôA[Ö¸F1S.Æ0\µfÇÉÒ]h/^ôˆQ·”u¡’Ä·Å1ÔÒÊI ,ü)åjMJ˜Ol[#Å´5*ÓÔU ÀâLz‚ú·Ól>§¦Æ ‹”-UÚò,Lkа3{ÐÑÚœn¾{´ =[¶½ÓR²?Åa¹’¸¤Ï¾ÚX² }Ùž^eª´9ÌrÙ•vÂlzÜJ Ø/‰$¶'À|ÿ9 Cž‹9Ûôg_××òc`™¿ÿû¿/~ãßH5nz´ÍÁòÃþ™DÔbôC^¦ÙïÉX6›Y‘µÜ8cÔË–°Åc“,ƒ,Oœëÿ„űÕ¨ä}"{ nVìÏfíjq‡:8ºÇʬÿïô˜¶Œ)k¥w:=s Šë HHØ p,„xQú ÏnÓ(AÏj7ˆF›”±mµ«4AÙ­Ê´¥ÅxÌ&Ó–vÙª¤ÍfU|¹b®sj2ãÙ;fÁâÖ±3†šœÐfkBÍNʸ4å ´yÖódßrTãÔô³COçáűM‹‰²´«òÜ]“ë°¸á$ -)¬ÄÙnZIìE’5¢]v‰ë¥ùEíͤ߮””}þx\ry-ìJ1\MA¿þom ÿ CܻロùøãK÷Þ{ïh›ÏË¿þë¿*fÙžnkk[/å\C7Æ`Ì$i,[\—©Ü/w,žõH]™ ¦(ï—+p|žÃ7N- ¤U|žaPå¹0ëãÍø³ærÍÓL$ëT+€ã> î%ÜÌp“"« ÏÊ–©FàÕuO¥å€dYÅ#ª´Õ­Â¶U{?keÚ’©zm[K6iœÏªt®÷Aç*“„Ð y1%ãÍbô?°jÃÖB¯ Úˆmk®´•Þš£¢ímÜO&' ¾Ñ”)ogá×›e«õ·qvÇb,ƒ‡¯xÏã‹—Zd6''@Ú„+òH†2Ƀ³Gylr±³RþC<ÛGõûô¶o¡iüÓ?ýÓ4¡@Û<]~ñ‹_¨?ü\£úÁw¬\¹ò/dã¶“¸±x!³]’eKZ34 ó&uÙ˜  Û¶6'-íε'/à=:-ËzÄlÕ°lÞµq‘áI…áÓm|LcÀ3&€˜k&aÚì™4Ö} RkgàÆŒf‰HLøì³Ï*ªT F#X76IJlN#²FxsÓV˶IXŒ$Ÿ…ÜGU?ˆo®}HàÖ•û š¦½Ìͨ‰k±± ó[KÙEJÀ‹°ç©8{…wBƒ6®Ð1ÝoGÆF½Ò€…É ]AL[÷c½\œ¶Ã¬O&a£8Nš÷…ëEÕ—+V¨ËW¨¾¾>²)ô}ÆÓ„»rùŠ:wþœ<;¨.^¾äÇã±ÝCè@¤£à¤‹3è<]mŠcÛ¤ªLÀàqŽÙ6bU››súzþ—^߯åüô§?-þÃ?üCiÆ  m>.ÿüÏÿì³lÝÝÝéFõ€íNb¶BºF¹Á£q ÒS«†isýVÆ0UÍÚpÜ ¢âØ‚´ØX¼Œ+cÉAéîq^+…E•q_f+‚keIüûÆ÷!ã¹<ä3²2]‚¦ö±pO`€`ˆàFŽ¢ô9«Û±Ø1·}ûöùF+¬ÚEµ¬¿ç2cv¦U5ìÒ|bi°lÕ2mõrƒÆÝ6j›¤ šL²±µÁ¤-‹›oög¶„ Vsk‹Wô=ã1mpeXMy_|ìZKpkf¦­É€·r)Ž?j€Ìˆ¶¯lèK’EŠº¯IV\Ö) –½D°c°ù,öËIh î¸ãuÿ}÷«Ûo¿C­^³šÓZ,¦Œ÷t©ëׯQe›Ý»w«÷ß_íٻǗÂâòŽm؈gⲾ؞ì™m³í-ïÇCóÙk0ºUïë;3ÿò/ÿRúÇüÇÐ6ß–={ö¨7Þxƒe>Šz&ñ]e ûf€ Üø•ýüh[(U6”ô’âµA¢²<óÇ}Æ °‡™+âÛäl³Zð”X™ÍXíYmµàêVcÚÒt6*Ó7ù H´›Y}h“}ÌŠ#rê‹Åo°±­EMÑIŠ­š$F¾YeœGHE¿ÉdžÔ¸D¸1ûV.ydVfÜr~Ñõ¡êÊ•+>HpÙÖZX¶4Ù·$ žuáÖ0å˜l,Èvâ‰'Ô£_}TmÜ´‰´ì×WÐm`Xo{µ0Enb€´’¨ÐÀÀ·Uƒ=”ó»í¶ÛÕsß~N9zDýæ7¿Q¿úÕ¯ÔÅKý)úŸMÌ›«Þ¬Ý^Ø–2Àä )Û:éá š¬ÆÓ¡·íÒëŸèmþ˜æ?øAéïþîïJ2u´ÍƒE?8øàš1!F€&È¥j3—ål\ĉ8‘´º¹¬ŸF÷®Ï¥€ßÀÀ}úé§Tž ׆éý°R5.ãÃr,Ø'ž%€*&¸Šw×zÍòo<ç¸u,¿hlÛ|aÚâî·¦'…\çR Ëm¤&¦«³K-Ò2û›#7Õµ«×ˆEÁ`.+´°}ä BW¢ Áûá™bÔ]¼¸K]¿vÝ+oe‚Ó9Ο&“ J1kådƒfɸ!£tpk"oll\]¸xA°q#‡[û‘ŠÒ.Ðew6¦b†@cpPƒXéŽ (QC[YSÇ1#ÏeøþäMqúißð¸jÊóÆÌ³P5¸`”ð7^íd‚(Ð&‹=ãžcC I(áݤl‘ÀFL¶Õze‘Χ¸¶ù´¥µýìÙ®ð$”Ý¡¼ \]>ø lï¢Idô}™Œ°€ƒZ»|ø!Å2;7XábÅþeö`XÌ›«–èI€Í¹sçõ@~R?vœô·®^»J²RÃ‹Ø =x.Ò ª Ÿb]×oX¯V®\©A_›züñ'ÔªU«ÕO~òcuìø1úͨ© %[sÄö `ÛH²ÝÅïÑwp~`Ì&4ŸS£c#ªýæjmk÷bêÀÆ4åIV¨dl8®dtÄckšš)®ªMŸ³Œb{Ë’Õ¸5ƒ@W-¬\˜Ý’¶çÀÍÚfÝÝ=êñ¯=AÏ ×0µßº‡”à‘²¸¹pÃ>˜=‹Òuƒ­ÀypÜ€ÿ1Sˆ·C\‚è±~Öœ¤Ä#š‹W„_àß!¡L7&c’ý§ë2q`\ƒ9,™'­X¶ZÙ7Y³çÏš’¬ ðÀ}÷«^T½Ñ6ð„ã$·i­bßqûÎ cðĤW& ™ª½½}êþûPo½ý[ ³l ˆ‰°ªD«ÆíX2´rÒ-bÚ`o7éçù¨¾G?żãßÿýßKó7Sº•ê‘ÞR íÇ?þ1:aÆ{¶™î%K–ü‰«–š,¥K‰ã*ØÕ€%P‚D-¥°`œbða,ƒ[j#Œqtý #Éû²;•ý*+:LMMS°°Ated¥a,Xò¢ǃ:­Ó¡©òv’‚,SÖ‚ ¬ë^H¶ pSØT Èmʘ¶t@_œmd­d dÔWúŠÚuç.Šm<{VØôµ¥É¶1,®Iì9@\ŽgÏœUÛ¶oS4€`xìѯÑq±of°ÐÖ9ž6ªÜú@ö×(\h°Ã,§ƒìG8€ÅÕƒ?ú93‰ˆmű =wk{G; ÷]ç>Î"°8ö%\šòõdßXZˆ'–Ûv@ÂÖ'OT‡" *‘¶-ƹABš™È@îèS}}ýjÛÖmj÷Þݪ0Uð«òÈ×õòó’‰e’h‘ Í*(ÿ“PúüóÏ‹o¾ùæ-•pË€6<ÌŸüä'Äêãmww÷ºóÞδ·Œa€Qž¡ºôêÅ´I† ïy†Ç-jÏ^y,NÈ/(–-.ëæ2èAÀσÄKÊ””iöÓ¶ëeŽMnž„l[œª a,›}?L²[Ù¤nA3¾¤ȶ.–Kd÷Vkk$¦­ÛVÃÜ1»=)Âvnß©6mÚL™˜ì‡ÍéS§}fÒþè':MˆQøáº»°;wïº[¿R—._ô]´R¦(ˆi“žŽ-Ã9¼a*ÅYÁš¡/9ë¦MÆg«™5€5œwXÂRÒRRIë·ÖYC”[Áó*,_¶R ô/!=:„y9t„ØÈ¹ê£8.ãáÇ)v`zÉÀRZ/\<¯&³“¼ñ9-×½ävƒgÇàζ{4à‹BòÆ+ô¸~Ý¢·9€]"d  íV‘ÿ¸e@ÛG}¤Þ{ï=v–À²é‡–±Õ·%3cj—lEZ5Eã0m²3ÚºAîQ{¡ãt}Ž ˆ*sßæiAEºE'' ~†Ï´9¦¢‚c`x`(LêclBµ¶´9Õ¸£@ZØwA€Í+' Ø6°Õf’º˜U{Ò’&°JËàß*L[£gŽòd‰K_?e/Sø=€:¤Îœ9[11­µý!žêÀþ”¸°fír¿nÖ qhè%°­uÉ6¹#ù:89 ¬%CÃî²eóT¥÷‚¥“˜•b@UN)­x¶¤2 qöÍ2,+P¯µ¥¹•ž5Dpq}'Oœô3ÖçšDk¶ùD³Z»n-=·¾uíúUÿÙ²~h‡€m( AˬSfØØžJi,½vêïÿH·øës/½ôRQƒõ’µºÚæxùþ÷¿Ï,[F?œ•z6ö )£!éU©zÍ€}çÒ5šF¦hø³]£Ô uÃd?TšHFM WU ˆË´E:ûXê‚ï#€”)3R7šž 7:+Êáà"šHí‡`g“©UhŸ·Ì0•Ï$,~-(ùÀfÛd 7<›ÅFõ=Èàe•• ª šqms%ëQo€IJ‘f_Ñc\—,£× mWN>M€­' ¼Çާýv÷ô{rIÿuzð´À¤~[P6¤ ž¤«Çà ËŠ°Æ›Ü¯¬øPÀÙ³|oÂúRZñli°lAŸs XHd(©®îÅzrêMŒÏŸ¿@L›ëZçb!W©>ŸÖ6O”—²‘ixýŠŸù W6W.½Q\ëøIŠ­IénßÖ¿ùýõ8B¦~þóŸ—¾ùÍo.€¶†¸&Ý_y宀0ÝÛÛûUÝ@–s ·dÙ¸sË-Ö(rQ¯Õ°jQÛJ†Mfò¹ÆIB°Y6™b•-Þ’üm»gÙ½ × Š7C/©Up¸f¸ö]-FØO}±ÎÖvÊvƒ^ä à&Í™zƒvì„í2•† ¨ D¹E¥+VÆ\°Š7Ü:˜}†M ÂZ`«f2±À´5f©ª8쎋eƒ ›RD-OORÒÈáÊä>X  Ò!ÔÖuC¿xC@:ƒ(ŽmuõŸ°÷kÌîV0o²¤–+LĶ­aö,.`ª'˼±”_»Ù‹áƒ0˜üz>çjŒ H Á˜6ç‹°„ìg7©ë>ñ8Ɖò™Ë±Î‘Ez¯Þf—Þæìæ‡?üauWoé¼m@ê/¿ü²:{ö¬¯ÍÖßßÿœ+!½0’·¿«Óf»Fð¹4à ÿ³Ofœ‚2FÃ’\@Nþm‹eÚ5NÙõ€N‰ŒQÌ„± S‹Ó*n_ÉÄ’ ¸èeŒêûF«b/©¤0¡ Ci”î,£b¡¨$ˆYs%5ÈgÇÏ÷m•õ‡‚ÜðÕ»Žãlª¦-{–@sõYCm}g rΟ?O¬s-÷™‚øuŸFpyÐ6Sôàܵ¸Ë“ïhë ÐÆIœÙîšh$yï wܯ°xÛ° N’rTq@Y öy²” _{[»?Y¿võªmÈ1€’2°ÍhŸízr}ãæ ?†‘í¡´]6‹Æmœ™/-+¬(¯×§õ1Úrï½÷Þôûï¿_@”z|  m<¼Ÿþô§Þx¯HTvcWW×W]´ùU¢uY> *H†!Mgӻ쳗%>âH|0 5×]13‰Òä ‹o bõf¸õ¬ÿÌ.î\L ê˜m{¨ €'lçc™Ú+ð2•&'&ÉU€Ì±l[Ö+…£=Qð\ \§ÐUÎ+޹lO2™Åuol¶ ¯86«!/â2PõC_T¶­Ñ™¶4Ü¥Ì2û±­í¾}âÆÕÚV,ø€[5*ƒ&8¿³Ë’ôZ˜ö›í ¨¼ÅeÏ‚ÀZ\¦­žnÒ¤1nóÌJ{áþRâ™=Hi·¨«mø-ëìU9સ®VªRá¾v´'Üù:]DŒ%¹Ðöÿé¯kûŸýÑ~4q²–>±Új\ð<ˆ*̲ûûûŸÐŸwá!I]Ødñ䤂ºÕ¸H%}ÏñlÜø¢’ìkáMv=ÄÑv³ˆë{—KUž3¹= ^QâE‹TG{‡ÿªS§AÅ·M™VO}zHíŸ4Ç$º¨Ã¿'™N .áZ©¸×2–"¬è}6ÇkÒPóì÷ ±pcTd¢~×횘jD06›L[£Ä³±=A;ƒŠmÄeY¢šýã®/í"÷çõ«×ýÉXÐÂY|Ž-zU)øvʶ»qÀZj6Üõ]=ÒØ·üœÝÌü¬á%Û’ËÒ„”íZ£.ã&ÎÒ,ÜNÇÆÇüØE&-\¶LÖ•‰e/,“ö8ñËL¶ê×/écüLþ/~ñ‹¢~_Ró|™×  ./h³]ºt‰A[sOOÏ·¤«SfëÉZJ%H÷i ,Ëfë³%jüžgÙ £›‹e‹Ò0“ E¦Ñ a¦·¸«[uuv’m«<-'ÎԈ¶*`K#Ò€èvm¼²Æ%ÙÙÕI®RÆ6J/î¦XŠñ‰q*– ÷ͤUA¡ò~ãúÕ ÀêŠI”í˾Ç2ñ…ƒ¨Ù^ Û`~QëÎ…€nÚ-Šå‘íýÛKßT˰¡ÜÓ®»î¤ òÏ>ùƒ8¿€ Û ÉŸ|YÉ>L:)àJã·Q aÌ\Ð3ª6+5Îç×ç¹3ÄVE.æ2[4Ž 7WpàöÙœoVã™qß}Ε‚Ú>{7\É`¶GC&€é¿¿e@[NZ)µÚær¯üÅ_¤gj@ܦÎÎÎûÙ@Ø™|.%g©õÌu ü 4Xt5N©*{–Í¢‘L#Kà ã?¢\žaçÎ3P؈£ðj¶“y‘ܤÞý×@³'€6 Lcgg1ø“ƒu•¹Tfñb?–‚fx™Õ¹hÁÄb‰…€ ÄÄ‘ëÜ^u…UY( Ä¶ˆé‘퉪2÷y„‚„'gdBñ¬_q>,>šÆDÀn_I$Eæ[\[’cÞj¥ª\¼¬‰…0Ó’͘Nβa×X‰2DK—¨?ú„&r@µk9Ë…â“ò9ê{Ù¬Wpž¥8˜½‹Ã¤Õ ¬¹¶ MAbÛ.Ìz2m2.ì|6O÷6 vªžÉ/¡0œKÉØTG²Uœ¾911IIb2Ö—Û'ÒÅ"â’`q‹2A•ÿº¶ëKôf—Sâ@[- >½ú®ÑÞÞÞÇ›››;8ÐP‚1™1*¶™A²Ë¥Þ\_‚6?FÁŒ¬ø¼íßòuÁhg©1ç¨ó¡ÉÊ``|ŽY5ölÎ×CiŠ™â¸p9ʘ”ëËQvhÁdv ù¥UX¼r.ʇ°–ƒI¯JJÚp2Š×cššÏä©n¡WK©ÊGÈFÊëé%~chA‹FÐ@Aß—¨LKÞévæZ Š(ËSv,M€µÀ´Í.Ó–t[ö —Ëû‰ú_±”ø^q-^TLV§OœÒûÎV„ º1cËý„ xtIëÔßV X“ ¹Ê8g›…g0Àúsl3íLÖ4™¶’¨ê@“ô\“?~’f,›”ÉÂ5!31Âzm3:y^â3¨£I½¶y»?ÛCí&8îc]Ž/ŽÀg±4]q}®ûÆŸó³± ¶­åê9¿’†þÍý÷=úõCîç;Ûv+è´1hkíïïÚ¦‰¥£|ÈÒíÔÉÒiaL+øËX(›sul™ Ï¢²öŒ‡¾kmS«V®R‹»»©¤K–™8Þ`÷øs:>ó‰ò]„†Uò݃˜ý±Hâð0µ›7G|6›Ýœíçðˆû‹×öávÕ¹¨Ó°„­>ÍÑ=ðš‘wº™¤VŽf‰×¯]S—/]ö’2Ú[+2Um@s“„$€&®xólª¦mv¥=¢ø¬™yØu6ãô–]ðbÒ2j݆uêð¡#ÔÇ»º:©Øz§žøôõ÷0<|ð°Ç¦e²þ$¦r‚’¥á‘änŠÓž ÄŸz‚5i7%@a–‡WžD»dCì¾ÌÌú:À Mr…&=ù®ÀI %K òµV×hY¯4G¶iqÏbÕ××§úûûœ#Á ™©£y1ºwð,_±Luw/¦±vôıêêå«vŸ=<'†§fÒÄ<ÛaJöýd„í’íJÊeñ÷ÆEúšmóÞE:ßAk³•4xÙ¨ÜÝÜá\Y|üÀÙÈqa´x½X6™9æ ¤kÔN¬ ]›Lž„f;»ŠzÆÔêg˜Ê›rææ8^q˜"u˜iÒ?›œœPc£ãêæÈM5¢Ú('LO§"¢‡HºqŒ2˜ ÐÖ ‘N}O âÞL‰M*—7>“ൌãʃ€w8 ðH.ÀëXÓæüŒç"){6ò¸o¶ÐnµU6d›H Í0û¢0mõÎL”R<Ñ*Åî}^³n Õ8ëÓƒ5€޼rõ _(5ŠÌöñgÔß èedm¹³äó9oR7^»ÌGÌšì²ä¯¤?=‰ n-,›íÒàX…°——±x²¶ŸìdŒ&¼X¹¦æ&ÕCb²s|Ã.:¯Ç¤•|)tPŠí2"ˆpB]þãFmœËÍxçâ©pT‡×2ä¦-Ï~§fÌœdrDu´?$A¦i¦8<ñcHl)%çq‹%üÉZÞ¡(ûΓd»Â½Ø yú¼à"Ý¥ïãë/Ìké|mYUÎýº µM[Ë%hV×=Z €³™6»ƒm„ÃŒ5S»¶¦,ç‚ÙÀÐùs9¢¢‘5©ŒaçàR?³ËßM=5í³ä6˜*P€þ”‰Ÿp©WK®ñ3‚¡C-Ã! ¨~LÜP‘èîß°0hªiðׯcªè]_Å®˜U3P¦òCIgxR#F?‰dÙÙÕì×cž¬%Gi±mó9®­Q˜¶zij¹·5q—¥p>'|ÛwnW;ôŠ>fÛD¸ÃÓ†í–-[¦>ûèS5xv€X4ЇÍe Ó–¡¸·Œ_áÅ9™sÏå²°œ¦Íf$¹Ä‹¹2³†e``@Ý}÷ÝêT;¶o§ëíX´ˆâzq%Çý›4Úhg4xÛ½{·zçÝwèûg+lX7¸Ñß9&ØuîA.ÈÖò;SÊTÝ/vÞq›Z³vuÅd€h÷g»ÕÉ“§fxf\m.i=O/6¸œ•oÇaGX¯üØj7-%eD"oÿ„~}Ãà…©Ð67K†M“nh뺺ºîã`F{–"k–ÉÂ~t; ¡Z•ú¤¢º2 ÂÖ\¿—†ÃUA·£™ßø„שKŠ\þñKîó²ý-ïeüJÍPïÆïÂÅ êÜùs4‹%ƒZœ®< êaø– ,QË—/§Ø4rÚÆ™À2_—¢,ÎŒ÷|/x¬,Z`Íâü¼`Ä]ƒË\£[‘m›ïL[übå[î äø²¡“¯;îºC­\¹‚´³®]½F.0Ø‹·ïTï½óž:{fÚö굫Ôɧ(é:ÌD“¬±l–Ìe4=ÆÙ ®aÒBÕ¼«çƼ¬EÊ6˶­ÛÔ7¾ñ õàƒªå+Vx‚¯f¢z‰JB(œ&ª¢¹¬/ÛÜì uoÞ´YmÙºU=ýôÓêèÑ£êÍ7ßT¿úõ¯(\‚Y<ö ÷]ƼE=cÛîW”z*Uß÷0Aß¼m³Ú°q½€Ø6á\Ï ž«(9V¯¾ëyg2å#]÷FÖ —¿s•oäD³ý×ô.zõz]Ísé|gÚØ5úndÝÜeê°ô}ËìQ鸒qØTØÝõÊÆˆ+(m÷æ±gÚpLTfÌÎ GÂÂÏY¯Ö:Ä?OŸ>¥5`ÁNñ‚ì3bà '2rS­]³VõööÑ€1ã>×Rß´š«•l𵇰Šì2‰*=§ŽmZÌp½AÙ|eÚfÈU³MyÐB-ùŠYåŽmärTpƒž=}FíýÃ^2)lwìºjãž==HYƒ°/ˆY‹ÖI.Âe¨zƒaÖdŸK¦Í£¦!¡355éË4d²™Š‡4ãÛlfÍž”3»Æ®XÖ¬Y£žûãçÔC_~ˆ\ÀØIDC¸"ÔáâÅKêÊåËêúëúúG=qôS0ä-­ËÕÛÛ£úÔ’%KT_ݟիר?ÿóïª'žxR½öú«êµW_SÃ7‡+°¬¸nãmAôjûÚÀêÕ«fj§ÅøgÒcì'~EÒ@œÉ1vŒ›«_XÞ­úõ6½ÿ·Õ}šÜ¾ÇW'O¢âæˆ5å²IAÏ÷À‚ÝË–/SëׯSëÖ­SK–.%`ö'/ü©Úuç]êÅÿúäÓO*äD AÄîÒ(–M~Wa#Kª¦¤¯¼)7fWâxŰ’eÒÛƒkÀ$‰nœ¼ÀqÚa}ÏN0ªåìºrü“ÛIðhkÈé¿súïGõ6o©yî"Ï  OCÛÜRÝIàØ0Fá¶Ô‡|ÈòÁW3@V˲¹˜6{À;hÙfÄÀ™øÖ KzŒz\÷¥ËzF{éb…{Úåž•€”; \9p§rF[1Á̰>×$¨úŒ ­Da«vW#ûĶÅIÔ˜Ë,Ò¦­v€æšä•º¢·ã¦[&ç܃^³ºaírök0S,zr>¬Ç…Áì \£e¶­´q»&w`a’ÌOaÊ ô—lJ½5ÚlÀÆñeˆ[ûS©]»° ¸ý©“'ÕÁƒ‡ÔÉ'©nª-¿Æa;¸–û‡d„ƒÒ16nÜ ¶lÝB@nÅòåê/¾÷Äì½òÊ+t_¤§Ä‹ÌGjºÙ¬óWÙ—ð{€ª«W®¨¥KH]À.«¸aÓzb¹jKP.²îo»c§Z»n­ïÅ:î<ÝÇPÐÆ o@O–\UÔÄÕŽkc6·R¯Ðw‰ú«q•~Ueõ15]¤ó´1ËVÒ³‚;õ¬pµ”î°E]%—Æ%8¶¤¿•ï㦗íÃîP3@‚b—_¦¡@Œé•+—ýZrA€-ˆòÆríú5u]¯¬/ÕL›_W&ÀèÊ÷œ©·ôYµ@äV«Œ0Ù£Õn[mFhÜX6û{,4ѵL6²ÏÃBgûŽmjdxDæW‰ƒ1m´uËÆ2¬)!Wá… oŽÎ™õk2ÞɈ®û€mýºõêùç_ ð„ì÷‹§N©û¨#GŽP<Ÿ¬_™¸Ï3€ÓÇ;¥÷‹øÜ£ÇŽ©­[·ª-[6«öÈÃè×Åêçÿù³Šbåø=&ž.WiÓ†˜_¿JA5l‡ÞÏç{öQˆ X2×…)ÿþÁåûÀC÷«cG©¡ÃåJ ФÓmçÜÓÛM2!=½=#-7\[)F6+g®Òu ×yŠƒ«ýMð¥ä‡-j®?»CµA¯{Õ<Úï -ÓÝÝý°«cÛ™7®ÒUA%jpq˜69[©e?R¼ÕÙÐ-–m®Aw*ÄyÀ K¹‹8…Ù+KšL©C7T__?‘¹*^>P0…¶¡ç™|P­¨ù¢3mQ} MíµzƲŸ‘äm¦§³†ÅÈE‚¶­Û·Ñà¼oï> ¶‡(w3¶æÀÍs“æü o׆nbbœjܤx¸Lh2B\pÅÒ±ç ›lÖoTÏ<ý´êëí%Pvmß¾ýêÜÙApÒŽÖÒÿyAlàéS§ ‚Û±c•C·Ÿ}N½ôòS¬œnavÃNö(qö?¤‡’Fض7õ¦Ú¸iƒZ³vêZ¼ØK®hi&&oÕšUÐ-÷²âÇ`:×c.zRU—/^Qǧç|sØÓÂŒª‚À ®|lBç/ iá*UÉÇf¯›Íë×½¢Ìåƒæ¥Ðî|m$õ¡D§^‘ ®´a[i™¥6jgIÉ8ñsÕìÇÕɽWó?“g;› Íu(š÷jƒ²0pÒA«bv;>FÙ]ííms FËÞèRÄ3qM,â<÷(~ó­i­ç™$غZF®VÍsõíŸÌ3Å ±eh a+àÕö2ˆcC<[¹|]U!ÐfâÚ¼·r '?‹ÔÄ©¢þ0ÜcÃ6>#3>¨&g­5He–(gˆ¢Ìc>F™›ÃT;z”Ü¡ÐYã½8d‡ô±à¶B d¾í±ÇÕëo¼FIXØåö¨\”¾÷aù’i+æ4`)x)W•£L)îÑþ}ÔÑ#ÇHP±lÚX§c™ÄÒì,L›“é™U#T‰ö‡rWE[§+¾¯h»ªd2ì‹äf·UO‚«²FT›ŽGõï¨ßÔ‡[ •ZZZiÀæZÃ-¦Þ0â–ÊÀ-O•Cf²mY¨Ú \ °víÚÕÀ ó$`,næ(€ŽÏú’ÝÝ=ê¾{笠±ÑÑ1uìØ1uäðQ³‹ý#& ÷‚Þ87è¿!îíÞ{îU¿{çwtž™²VfP C5îĩҔÉvÇ.Æ9?î>’2mA`/Î`à ™”bÚÒø=Ï&¥ÐdP /×uÛ:|síöužw)Þ}‹“êÕæøÞ„•™MÆm>ƒ·¤m<éïÒÔf =®a?0¡awš«}°ì •r£¤ƒ²þX“©Œà­ÆUê·|EÁtôË›##Ä`AB¬)ƒC^ë{yÍ<ùæ °ó8çÛvÜFÌĉ'|À6›<w4x„}n==ÝjéÒej˦-jß}~ ë·UHaEŸç¼X0²‡X©ntük(ƒ»»Ifs‚IÞcNÙíÍ€MjuÚ•sÖ¤î)XÞ<ƒ6r•OQ[¤íŒûîôœ#‘%Žý±Cœ$û&ÇÛíj˜¶•úózû³¸­­­1JÓgÏžUßûÞ÷—2[mV£ÿÚ×¾¦V¬XAïß{ï=&¨ ÂâÅ‹¿”P`ûºm³ZX’ïk•`Œ‘±`¬ìŸÜÔ˨ù‚‡b–îªÀWv`Àmg9áÚò†boˆ˜6•It/ƒÄuãĸU«øEgàâþ&ˆsefzÙ4±Ú¬6oÞL÷qÙ²å”=ùÊe:O„ŒŒˆå&µm Š2…ÓE |Š^|X\ûÛl˜S/¹¤ÉÚLµ ‡œKcÆ™Êl Ú¦<ÐF"ÅS†‰-xåQ‘§8é醶¶µÌØÜ„{{î ¶äa±l̲>¨7ûÜF ˜cUzì±ÇÔàà`C$ëÍkІ™—W^y…]£úÐ3©»¥ ®«¤EPvIš Z¦-Éï¢Üf®äi,Êõ231m™Y·`žhšÚð9bOP¼:G0*x¶xþø`í$Ûµœ§2*³ßÑʬZÉ>Î&*¾êr÷&m.˜f±øÙH³ö¼fÀÕã7AñÊYôü=ÐÒ¤¡óÍþ@ɬ^›àM2nä*­nM”EŠø¥Ã#ÄP ž¤>ŠìI)·Àçe÷ºî¤•p,lX;;:©äÎvºa¨æ0×}€|/_Ö÷²E­^³Zµjp6з„Α¯öMºHå}ÉXu:±Ýä¸Ç,²+3ªýÓ³1Šeàf@¸`Os’iËf- Ê1‡2̈ï?ƒ6*Ô^ÐÀ-W ˆýàóq³¾N›eKâa°í¨-ʱì’Í3 îý]‡þɰÄþçŸzê© ¬±ÚRXNž<©>øàeX¶R{{ûVÝWÉ„[ ÕV›ç>(1M€ÆŒ…eKÆaÕbe[r+¨ä‹jlWš“ÿEœŽŽøq'P&ïëë#Á\€6m¨IŠ™*Ü/صmðÛzÎŽ¢÷]Ä$±D±kIÜFh«`õfÒj|vF;Au„,õ/«´DÌŠ·]΋O3qjì.+¯ÆUÚ$ݤހ䃂W¯]%qÚ³ƒƒjdä&Än1 ‡m9A Œes±8¬ƒT\Ûú®Î.º>¼¿pþÙŽFiÕ@y+È¡ªâ-êT×o\«p“r‰;W’n¿|SŽö9 6«˜ n ؈55Lª;+Ø{nù\®RƒO(˜yªð|‰9«K  Ú `ËitÈ+÷°véÒEªkŒ2s8& ÆbXóc)‹ûÞKj*ølOGû"BÍÍ-¿)™ÇFXðÀF®lZ©ZZõ¤SÛ/Äz gŠîY“©VÆ´aýž&û‡g”˜æ¶–JðÝ\ Ò+*^¼ääèHûÆ Í›x÷ÞIJ™¬QŠcÃ~4`+d ž,Éø¸˦w‚JAÂðImµ])ÁžÈ¤|»õŸwêõ 69qâDæøñã%Ü—ЖâòÖ[oyã£ÚÚô`ÿ VáÀõ€mmœ´ÀY’ý$9¾«”Gä12Y¿³5‚VÎ`kù²å4Ã;@ +ÀÞ¤Á€xŸm~Ò^y& i‚¥K°g¦ªŸÊõ(e x³DYv­–­– È[˜Í WOWhÒí9ƒÒ“nh­p¡OuóZ-ÛîW¥æŠ"Û9ês4?¦Â餦W€!cAk‘²$''¨`Æ`®>¬vi¡4ÁK71ã‘àq£ÃÖh âþnègÁÉ8ï¡›7|VÏ.(!Á¶%à¥Aõ举ÿ¹‚ÿü¤‹Äl-•Œ)³mÍä"mò¥\ò¹²›´ìRâá%ÏêyîQvýgAnQ´0 Ù‚/¸Lß¡”˜>®Q Ëæ²²*‚Í>»Æ=s]÷ëß¼ˆMõv…_þò—ê¹çž[mi,ìòüíoËñlýЗéÝí®lBùj—‰’îÓ¤™{i±lòó sˆë™ša'i¦av½LǬZ¾|…*–¼:|jXñ7³j ÃJ*]Ã(t´w¨ö¶ŽÐ’)³q©lË2™dñHv¡å(V-ª´KµÏu!!×ì¾G@ú’oõÀ‹ú¢7n Qaô¡á´íøä8¯Ž‘vbÉÐ÷¸î¨ÚXNc‚\ [ªašÓÅì{6° —²ÁVT¼ZÜí%ˆÏ[[Ú|Æl€Ñl´mÓE¿€;‚ù£%î žª ÀMHîê±<é—±»Wf×ÛÏ\ŽeШ„l ~Ã0Êú外q©dÛšý˜Æ¼È öÊ”å¼Re×f\¤2{´83žA˜¿BÁcþð7Ä–!ƒ] ]Ù€­Ú‰Œ,YéŠ_çrV¶4ß!¾S¿EJqö7Þ˜~æ™g@[ 4vöìÙà Æh«nlö€Í‘]vU›é¨8K˜…ét3þÍÔ¸¶É̳d¢œ7Í&uǵÁ>‡ã`R¾NkÄàCiýùfÛVšs—/gŽúÏSEβ‘«¥Í¹& · @Kó\Ó´ à\!°‹`Äð7ú}c˜›Z¶”àfpsx˜^áE<ì-ÒvSž¸*ú¡ÏÃ"éXn2òØ,á¸lÒ%•$^-îö |WaK«FõõàÔÛ†áÐMÝ=^ò˜ÅÁ3ƒ¦”Xø3Ľjoó²ß3¸Ÿð„a×`]û‰vXðluvг,LRWÆË mn*6ÖÛƒë¸Ìº5U$˜äEÙŠ,Ò@÷¨Ébm¶¼زÙIúl¢0©FF½8do"­ Ql÷eR;h{Ù˜u“,›Œyàm³~]©¿CZqö“O>É\¸p¡$ãà@[• ïo~óe`>Î7£g„wñC`´”ö.Q¶|˜iƒ³¸L›Ýàªaù$h u£ffJ~4BJ3c6©:<À\:4ÃoªÌ,ezŸÜÈͪÇF»žÁ£qï•Ì~ò’>¢Á– Ú’²lAŒm£‚³¹<§Z“æ ÀU Þ¸˜a°DØú³a˜!‹ž#¦ ¢ªS¥Y¬¤ßf\hím‹T›'Œ XCûe6`` +þvéH¦Ï&m9%=ä›üÁ•RêÕÞØæâþ­Z½R ,ðËPQFçdA ž -6ÏlÛ¸n †ZšZHƒ¿£¬PK[Oj2JíQ0¤ˆ+ô²3ÄŠåô³*˸4Yº{ö*cÛšL&)g‘ ¦M< –ü(gz,d>Ø(St|\·Áët^Ù|v`c&,ª BP—2P.QbžÐº˜[ýy—þ{»þl?šÐ™3g2{÷î-a¬A^m5\ÚЊ[»ºº¾d?,éB“Ì›ëÁÛ¿­ËÞìj Qúk.p»xnEº¸ÊTˆ"F¥V[«kQ6ÄÄù Ë ³|0nœÇô?¿‚ ¸rùŠºvõ*ýŽgùi‚2WmXº %«H1ß³RùÔèCìÆôTd{°A[’,Ò4b0o%@Vë¹6²H’ã¸ìÚ\•p893›™7ÎÜ^’[R®¦ l£´ÒÆõÇMŒÀ!»CƒôÔÒo2ž·Ù”]bwL=ì‰ãöö¨-Û¶PY*隣X:Ø ÄbÙ¥âþ&}p—óuïJ3XDyýLPð3d×7þ†mà ¢í¯Ød²€}9ã*m)»I›-ñäœIJð³Hg€6e£²U´e'½û¶z}”½«ÿa_%U®ÄÀYÎIË@Êçá*ÏÞ6y¿lר÷èþ ›éÉMæw¿ûšÉ Úps!óðþûïûñlÐgÓ3›6H‘€Í@”µGãÔ8K›e cÚ€]p“³ΆíSØÓþß±ª((é^ÍÙ¥j¬½Yñ8uz0¾té²êèS‹»“AA¬D1Ñ.ëï º>)ƒ›“& ˆó†ÛgÚÜ??cjÊîŸ6JßEºåÙe…±€°1ZÄ>4åA \9³.Nör€KÄ¿ Àl6Y¸F’qmÃEÔÑÖ0ñãÆZˆ`ˆäo8ÙÇ5‘” ZX ³oqõ×¢ÞÛt>g|‹ÚÆöä½f¯€¾>Htlß±M­\µ’ØþK/©¥Ë–úƒ<^?ùðýùeM.Ü6F²þ)\pG²}±‰yùw<ÁåØ>Ê+—¯RüU•i'æiò5—5ù|–­¥²êE³—” A[ÎèµùL=Ò¢qNšÑ¶y̰kçΟS—/_òÜꆜȰÉç\«2¬î¨]1Á÷kö.ÝžÛõÛ›øè7¿ùÍt£³l ÚИ<Ek¿t•nˆ›t#X!ŠÔ_“Ù5<+a¶FÖ,KcPªµ”•=àºbÓãÕ¨øzaf•±?håÜ, px’ 6:¥¯œ-˜´Œ’îS/[AȈJº=BÇ'/„e iˆ Q|€AÆ€ÎWïWÖ¯óŸ[6¡š¢!¯œ ÅNP€"4d7áá~±š÷´i?\4¹|‹ó&8œŒG÷çiP ¢êe{eAPWy¡¸Ù£IâÙ¾èàìVpq«(Øß1ØBÛØ"­°ŽZÁ¶á=¨Ò#Áñè'ø='ð v>i»Dƒ&/¹l^q$i”»-É‚ëÃ=Ù±c»Z»aºzåŠzû·¿S7®]§àú{ï¿Wmݶ…úòîÏv«S§N©•«WÐon\¢{Ö?™Q“ž—âTÑ^aq‹SeÀnK–Pæìˆ~Fì²m5Ü„KÔw¶°€r¹Î¬¬/Ëc¨ õÙXâc̸¥ÏŸ?¯Nž:I¯ø®ÉLb9Iûá’ciõW Ãl°¬–#±aš·êóX®¿:‚Ÿh¬áÏë@[• ä;# MYoôN}³3ÌRð¬ÊÖh‘™¢A±\ië²%aÚäL,Nå¼Ij+Žó5ãÁÀNDŸ–TY%¨’qoB°æ=Ðæ´¶Ð3i#É /Æ¥Ù¤pû .iua 4éUC(çÌ”jà%kÆ ©÷ ƒ‚ì·áadÀyÁ×`›ô˜2ÜGÐ*žA71~ÀdNiw6vâØ®™tR÷è=k4*f®Ü\I}Ç6í,6Çò Êƒ4ÛT{Òd— s}†±fµ‚7xN¶Þ¿¾ÚY6RË–/SÛvl%ûñÁ»ï«+ ÉJаÃy  «Î®Nõð£ûY—##£êÝß½šÝ^YRÑ‹UCNùK–ŠA À΀à‹5ñÀ "”䦶wCu>óªYƒ·¶\¶\K•Y¥ÍMM¢TYž®‡µÚ”ï©ðX6œ„Ò/]¾D5^Oœ€•Œ¢‰t•™Áý†±D¬‹L×w•cÑà f-î«LïŸom¶äêp«MDH“MKÞ‚>gûi³Á:™H@–ô³¤`-(ÉÌg½U±&›I6­W«V¯RR>?àY7‚ߨæŽ]·« 7Pÿëè÷cʤtvz™—A÷_“çÐ!ͧjgìbcÊç‡Ïqîˆ'놺°3ê:¸?ÛÚІL~x2pÍ~­Y9&ãÁ»{Ô®kµ?lìö"½)ü™­ §ÿÞ¤_zõz΀¶†w‘·2V¾¨®î›uCjã‡a£kà‹±šÏí€Äz¹n’‚—w)ÓÎì"Eç”ׇAFÛ¡#ÊûäZƒÜÉ O‰@~ ¬TÞfl”€LjÝS™^Õ>ËÀÍ Ð¤Ùäå+—)©áŠ6,(n )®m £ÆJáRŽÐ Ý5»ÄÖÚ@ØŽ3dà€ƒœ«eÚjq÷¥9I Jžq¹›íHºvq¯¶mÛ¦n»í6ŠÁìÏê±ÇS¿þõ¯ÕòåËé»·ß~›ˆ;3îãû￯V¬X¡vîÜ©~ö³ŸQ¦ñí·ß®xàj§o¼ñE3(Â1}ôQzþü1ղݰaƒZ¹r%÷½÷Þ£}á\~ûÛßR›Ùµk <8¶Û¾}»zñÅiðsõ™  Q–Ì®9Yû´šX·4?¯–u«F"Äö$]À¨oÚ´É‹Õv‹ë¶úýMÿÛqÛvmC6Ñâíß¾­†o û†þ {èW‘Ðï:¬öüa/±VüØ/¶ÎœG=ü íëÃ÷?"a]¸s>`3²HøÃšwÞÐ6ÃEŒOdœ.ý°>jeœ•ŽW°n¬}Éûƒû“H£ `D÷›±ñ ²áèe×Λ >qíèŸl?™å“¤ -c,°CwRB‚ÆŽí ²ÍÒ³%%šõºYÿý‘š'qmÚ˜eÃÚ¦AÛNév5ǘŰ™4YÇR2 i2lQ¿o̶„izD¦ã%3»ø;îp‚nÀ0© >Ð)щÁˆ`övñÂEoùËy?C Á¬,RoFˆ$NFn’ñáÀ9‚Y¾b¹_‹ KõHvÍ5 ¸Oi„øo¨Ý7Ž?Á쳚¬Q¹º¤Bê ÐB‹€ª ®‰ˆË}ŠgÀt×]w»ÀuôèQZÑÞ §à:ž#Úáž={èý#ñ=ܨoŒLu)x”äzÖqEŽë©åV ³6ßX7;¦—®KÙ’ªµ† lÂþ}(“NY±¤]œ›6¨O?ùŒÚ \¦ˆ;ðù~’]Á$€˜üº>Û&&Æ2iÅÄ ç ¹Ð¤ƒ0–-è™Â>£`|€=æXM¶ƒr?*nOZm9->.KJ¡oâ8잓藆ݑã•ç·.2GùùìÔç Ÿž.Òù´¡‘­Ðë’ rU2ûKvh#âbRêíb ŠM“ÁÐQô®«Ózõî&½ĺù€_K4jµœÁ…`ú™ÕÃÀKYwdvI曚êê&‚¼ ‚bÇôqÇá.nïP«V­¢Ù1VÌ€°¹D]iöAY¼.PeƒnÓÆq2å<è·aí  ÌuRBØD(ÈÏ¿Ã@‚@p°mŸ}ö­Ï>û,0€1Ü7×@.AÜÝwßMnQÅ`éúúú(f ìÀ¼d¢ÁÈ!mtóæÍ4H¿õÖ[3À¹«$Žë‡e&e©ªfÕ2ksɺÅeâ\çì?—ŠþQªš,A›AáuÈ|Üu÷®„uÖ©ÅÝ‹©:ÂÙÓgÕàà9g°-äQ±±9'çÚÒîz'oX1=ñ-ä*ܶ¸'\ŒÞäUŒ=ªÄX”Sº”a41#µƒ×ƒ~´ÿ QæÙ4–a®Ñ$ŒïÇ=÷ÜCÏ ±dTðÌ>LÌ™tErv)r:$ÀþÉ'ŸP†€±/}éK´ âåÀ¶¡=`’߃CÆ)6쌞?°áZÅ€†óÁoáf gA #*1íº¤ó%Ö­A^{R^*ÍZ¢ø¶Zæ†xÖGQëÖ­%Á\Ø ´O¯’Ê„:°ÿ 1d²Š‰ËÒO¶­b,¨nÛ¬à'ž-阽#ìÊDŸá¦¬½iÛqé!à„7®^cgfÎ@°4W]ž,™ˆ`' êRý~ÞæŒš"»ÚØÏœÓd‹ @ÂX˜H›a‹³¯0éÎB’ƒ|X°»Mõbå— }‰ Çl®û.ƒø@!K 5èµÉÅÔu,ª¨kX 8 ¾·žöY‚paL½LQΈbÀ'°7Œe‹jaLÎ>€,ÇXÆÙ§ë»ZD¡ë=I©Ö-0ûÒK/Àfiž_ýêW±hœ°€ä—_~ÙÜð& ¯¿þº?È2‹äºœ”ƒlT$q, `¯½öš/óÁ®1¼ÊcÕ³¾h-îÓ¨˜§¤€«v-ì:˜²jAž´ûÅ¢éÙÚ$%XFiïžÏÕC_yìö{âøIÊ õ<­­´þÊ¡>p+3mYË=Ê.LbÄŠÓT aFyÀôƒîƒô8ùÚ›Ùòµ´ézØ&Û+d»pƒîC@†i^¯›ôoßîѦ­J–™¶Ýy¶Ú:OvQ]ȰðlZqËY±z´]OU Úné&ÃïÀ¶±‘qýÖÅ8º€Bðf ò5𬬻{±º1ìÍδÄ È­Õ22AK±P$ƒ7Míæ>õØÂŒA”V^£ËÆ®‰8‚ÏaîÑ[µÖ(ÎAšl[ò~¡=!ƒÓÞÆ•¨pª`T&`vÍžôÈmù˜ö±\²%à⬧ɺÙí×Îvõ팣T^W`˜{Ôa2Ìñš­ÑÃ…ý¢¿„]8„r¯^½¦Zµ-k”Ø©¼ãF=O«z€W³3ï»GË™˜ ȼámŠJVy÷‹…g]‰Qi´Ÿ$îÆù`7\¡ A1xòÞÙn\61A¤\dw>0mz‚’éjnnÞ`7,ŽÃHÄÕ@›-¦M~Δ´kÀ—0®m¸¾G@(Ü Û»\Ò ›’ÏðÅ"×£C‡ª#GŽÐ{Y?ší³ Þb±çîeK—d5Ï¿ñÿ3TE¥’Uk*T‡%½çâêÀ‘Ý1l[¾¬QÉlÕcÖ§:Bõ‡ÇÈ> ݠ󎪓TöãVaÕž•IîÒ¸³=)ÒîŠm—ë¿ôë%ÕಠÚ8 !«áµvƧdÖìr0—Í.ÎÞ(L8.ükþ®Ø4W)ö¦ AÝ\_Q–øpŵÙl›íRÆ>¡)†ÁÁAÒ΂ ÖÜ\ŒÛtašš~P¡î4ï1ƒ_»þgXã6@õꫯÒïQd‹ Ô xP‹ˆÁ €šãþâ®öÀ¥Û´ÎÄÕÀÅ`M Þ\“^6¬ß ~äaõÀý¨7úavÿðöm\ƒ° / vå~mS0Qzïý÷(ÎPþVÊgÄoå‰Î´ššÆñ¦ 8USîë–™Xµ¦¦¼Úš›ÊÂá Üò’uËKÆ-GàÑ»†²ës²0I‰Z^u¯»«>i\F5Mö*ªm4ÊäÐÖe³•!‚d¿dÝQyŸõ3êÔcÊYíS žŒÐ¨ }ÊÜÚÚÚ6ØÒRÞvÛÙÐ%Yw–:[Žur¤”L[X\7F€ Öž bÛÂÊy¹ ñBï òØ7j9¸¡4”*ig›€hvÌ›S°°ÉÇO´¡Mm&:¶•¶v}|!|ï½÷Òõ! ¿…tÄ“O>YÉæÅnvÕ< ¸Fm;{瀢°ñœM2¾ÈKZ ®‘“ìï‚â5±ÜvÛíêÙgžQ÷Üs¯êëë¥ÏÐo.^¼D5ˆGGPŸrŒ€M¨1ÈhÛ~$I‘àvk›ZÔÑ¡zè!uß}÷«³gÏP–/2xÏ迹º Û®êâbZÊc‚çŽõÜ‘bº’.Þ¤Sf…J`VŽiknòJZ5 Æ­ ÜL\[^JdH*ä&ªnܸNÀ öv"*Y*m·~’¾Ÿ¶MHk®¶ «"±lOÑ!ë’›±l½*{ø6a>0m­zð_ç*d3jr†(µfä`i«(ÏÕ èŠkc©W|› ¼´zm¶ Lfoœ9É®† ,R€ãýq OdcÂ5Š5˜7üÍ3ë ß2hT™r©™z*“1ǵ2Ò‚À/èØ(V neÔ£„N4½PÖßI·+öÌàXˆ3iÜ+ j¶ÌG ®=“¬§ ¤Z½Î)­{˜ÆàÙÈÉ.À†eõªÕêùçŸW>ø MѾ‘Y{ùòunp„fQêš¶£” Í󄃔ÕÝÓÛ«–-[J%Æ–-_®zzºµ-éVß~î9õàª×ßx]½òÊ+TŽŽûöÓZûúgL³%’ýåÚ™Ù!ÞÄ/ç6J0 Ö-G¯yö±kÔs•VºP}mFúg929¢®^»ªmê5m†éo™ˆa3GQÏq6ûÁ\ˆç&½ÛUêÄvýÆüNf6l2B#3m2steV˜T­vÑ¢’¡`æˆ?o”†ÈŸ3Sf6y]Òoïšmð>ànl›ÍP†%#HÕxÜ+”‚ø)bUÀFÕ–“éüž^QÖã™Kõ. mŽ›ËÆfÙd»€+ . *ÿÑý‰²þþ÷¿§x™¥äŠa³ž˜h|á9¸J…¹U]±·@k´ÄˆzĵÎv2B5•‚~/c1%ƒÿøc«§Ÿy†Øu¢“'O©ÓÚ9rTÛ‚Óêªn£c£~Ù'×yÉ㡟ÁŽ`¢´ný:µqãµ\ƒ8°püÇßV;¶ïP?ý??UŸïû¼â\8¹ÁŽeª°_d{<¶-Sð†‘¦|üfš<çôqòÆ=jÜœ’mËW¸D›ÀÍzRlÇ7ÌÚ=1¹9BöãøøØA¶x>¯zÛ¶‰Ü^m+ï•+{Ô%®¯?ß _PÎjR5pe„FmÈí× ‹J¥æ 'šœØ( 5(®M–â @Æ;ØåU¤Áa7)êÅĶE1Ž¡ùÖ·¾EAÆ`Ý@l§¤»Dw™m£Î£$KM J†Áb626$¨4~‡6ðà *ú¬é”x`ƒ-™|€ýàorÛíØ$LƒÉù"³Fr³MZK<›v.w(&}Ï}ûyuÿ}÷QÍK/`;pàU­¸qý†Ô8ž4΂>ºxÈØÞ»g¯Ú ÛÖm[©®'*[üÅ÷þB½úÚ«ê×oþzÆ+›œ(úï?Vò²@3Ž#Ö+òžfo¹Jmà–÷]“‘ã‡IÜ•+—ÕéÓ§È5 [Ê@l+±ÊÉpµ¡;õLN¨WÿN²_Û«æ’ö²Y6Wb¢ ;2ý`¹þx‘^‡U'#4¾ïp“ÊΦÉ&Vf€?h³ñ,:Ž„‹k¦‡e[HJ¨ßµ5B6iœßÖÞ\±™ý}ýêùçž§¬PØ’ÁsçÔ}û‰]»ví*ÕúE?®†–}”ö=8H“£SnÓÀmÓ–ÍŽñÄãOP áW_Õ¯`7¾6ŒÌÌqGR‚þ½q4pËeEíм·6™5×ä±m9ÓÍp&W/¾­Ùd˜6Ж1€ ÉHG£W¸D/kÇö‘½!\§ÖöÓèzŒiM¬Hï™,[%ãm[.Ç(Q<¾O¿öê÷T'#42hËжJ¦êÚ4¾!â Nt1A `€]½­«S"öCºH%X bØ\` i˜É|tI¶-Lõ_Î<`8ad#'³¸¢*+T€¶L¶Üò3^Aç´'‚œÛɨк}AÀ-HÄÖåú sâùØÂíÈÖJš9Wlv Í?W- Wðf6Hv<óô³jÅŠ•jllœcdzž9s–2Ü©m¦$ÝÃç`Ãd–îØ±]uw÷¨;î¸CÛþiõ?¿|ƒºmû"mgÌc¬ ´ “5 plÓd„ÌÎC:*À›Y›rf9~Þr6ãæÅ¹QV)VØp¿Îj[€Œôóøâú`ü U«Ç‰aí#j¢<íAÒý¹â×eb`]Þ Ç±»ôöKôç@[䉹i9ij…•I±u­$õérÚà†¥+fk  Û· ¸•ÐÖg‹ª­Æ³77¸8a$`L\…‹Ã·êy UÅÿùçšÍT†tfÒwÒª2NYŒ µö8å¨Â[P¶(äCàòx«FâÃ68³œæ‹î¬¡˜®©FÍ& Þì6ß¹¨S=úÈc”:11®NŸ>£ìßOÙ¡.[™æýÆña¯ì?@Î;v¨ÞÞµyÓf52rS½ýû·}[Èucåä+€lú"kŸkà‰kÁ÷ÍÅfŠU³“•Ê.ÊJà–•uDs9¿¶¨Ÿ!*3K›9‹4Oå´†® ©Óˆ;z”€(4®\½âËq8 €ŒLÚ>nµ¾Et¸bº]™ö.ÛÊ“qû-{‹e¥$@[ü…3GuûίræRò—”©ì˜A2ÕúÒëŶ±{™XÃfƒ»1³ñ[Ö Ä´±Hc5ãq1n@SU¾¦5˜rj&ëvÕÄaÙ‚\žanQW¶(I6Ë{›D“-ê¾ß*m®Ï!Ê„ š®ŒéZlD½“˜¹Ì|éî{4Pê¥ö|êäi ‹@{–R õ^&Æ'ÈU –lÛömjñâ.µnÝzr¡îÝ·×ïo¶ýã,mLVŠX:„¼Ã7M}ÏiZ tåÊZŽ,€›5òÞ²9¿–hÖˆææüÄuk¦^†¸RÃ7‡é\!%tòÔ)5¬(Ü´øœ…¿¹â tY 2.Ã6W‚º³Yö1êú]Ù xVRæÃåµë“:ޱRF ™AÚ¨L[Ö¬mº‘/w JÃ)µÌì‡êBèü7:hé°,«z4Ú(‡ŽÍÕìk cÛ쉈±‚‹ûíéé©p-T“÷~y3ã' $2:q SÅ5‡½°‚ïIÀ›$‚ÆYµpñØ1ua±k.0Y/ñá/0 »—®I\Øùºâ%í!¶šßW›Ij_ÃÆ›(ÛÁ^:x˜›v2#&›ˆ£Ã‚¸:Èh¬]»N]º|I]¸x¡"km—ŒÃ¹b’JâÞ&¾ !"ÃCžú+i¬™ƒ¬‘'Êpõ‚,3lY#!€–îR#éÑTþ=Ž344¦nh€vÑ„Gà\ùþ˜<ò>p}°<þ$yþ²PÍùÕJžÈP§è ™0‹½[£WdŽ5li#3mûèÔb©üÂ6 ÒðÈÎkæ–±\nQÆRjBÒiÏô9e?ÔÙ b´ä• `°88ìÒí]uîj餒åœÁÉ'š­ >K´eýY6#ëlÜ–¢Ü£QŒDZa;vì ’e³%<\ça3-ó-¥¿Q‘°{Äž¹4 íßÉix¾xee,Z5¿Ošu(ß÷t÷¨%KÈ^\¿v]=rÌlsµLiûC°Zk×­Ó ¬U­^¹š€×ÄäD…GÅÿ™@áÚ »ˆI+_þîZÜEzrp¿Næ&)€“r&Á€Ú€aß|×h–]§& _ÿ+h †g_(LÒþ¼¬Ð+”¨1U˜¢Œ[vÃáØls,ÁÊKÀVow|£ôóZK?ÊqË~vUHˆš¸KÎËMáø±ЖœiƒÜG~=r° Ê"åƒ5™¤ k>ʇÏÁõU3íÛÆ A)ËüÞvŸJÇîVüA° ì¡¹foãœâºEm0=£Ó0Ñr¼ªÑ=¶¬÷ª¡U «æê¼q„rƒÀŒ1 /³ˆnH li ì_Dpv¾3Î9£üìe›yjÿ¶Ýá¶ŽgM@@ƒØˆã2$õ’‰Ã¼Éö @Òß; Z5(B›>£mÜ{s Øx)p;¯P ¹mÛÚÚUoOŸ:waÐgºÙ–óõ2pÃ÷ëÆ6Ï á+AØÀ+h»Á @81Ù¦ÚÌ+žé˜`Í£M~uTw™š*Ðw8ö­:fõ:»:ýóãßpÖj3Eo5–-Îö²UŽpŵË6”tÈX@d.ÓuèuH-¸G“ƒ6ý€ôºHÊ^ØF”]£²\“ëaK  +&àw\ ¸–ÆWk°¨ý=×Ï ªñÅ.Ø  Ô<®2 Øïš5küý²he˜Iêv™‘IšÉ˜©O"‚Iz(N—fˆÇeÚ‚5ÛÆ€ †ÿСC”€`³»A-°Å³ 嬔(•Ö¢Zô¤„u±²ô J~;ã˜G\Ø<7 Ì““Þ«PîOe,#Ž`€ÐÒ£MÄ !¨w6iÐ6ö³]ÔÑI€ ,ì'4Êfê<€›~ΘÌBç;n’ ìøež´ãwœ  ÈÛ,[¾L-]¶”&²`Þ¤P¡¥¸FFšývÕÔÒìÛâkN†³TaØÀƒP(Çü–c×ÀbbÇÃ|aØêMR$ÙN&žØ“*þÛî϶7MÊ‚Ø@O׫ÿîÑßW šAÚˆ ãÙ ÷±Ä6>’AsF»Tÿ^²Q2³”gAµ ÖÃϲvÌ^Ø9ÚiãÜÈq˜bA6)>GQt¾6Û­€w`c®²e`•¦âYI‹ÐsŒÏp•¥ bÙdûK—.‘Ð(iWÕƒ¸`-îàûEh-†aèP½}}ª·§Wuuuú5,›òM~å ¯d¼i±$z3Æà9ÒóÃ:¥ý ØÉµuý±KˆC‚[à+¨íÛ™—Üð=’}à*w1øi¸jÁ·OÓw´u+oRŸ/ Üý¶TPvw{åóµw#ƶÊ.ïÇŸ³ëׄçVv•í"Ä|QR ß#Yahxˆê§ÐŽ*¥Wí¸p£@Âv¬£-²€6Ÿ‹Žk8×! †­Ö¸É¹°#I6{²æJ(Þ6×DÝž٠δŸNýQªLFXm,[Óf«u»hN)"ôËϤV›K¯­–àÏZim¹dÛìD6šŒ“ŒpÇõ²~¶úx\¶' ÜÚ©Ø3Ϋ¼eÚõâ­P¹¥ÛG·(×hô—¨bÀרk0ð b ͰÎÕ¶iã&µ~ýzµté2’¡à Eر½‚µ˜ÂßÄxL™lAÛ {f…³ý r7Ú¹hÁ6zåÞtÛ×-¤XräèQuæÌéá.Ù!¤ ¶nÝJí£™ŒjR’€7iGÚÛÚ)È÷bèÆ‹F\¨ŠÂµë#ØìÉe´4·ÛƶÎU›”Vý FL=T\ÀܦgFl£nÈR]]íÿ†™4îÿ²ž2 õf3@MŽ?8X<€Ö`‹ÌkIDiT¦­Z€6c‚Áµ¬ø²ãÛdíQe×—r_–½ÎÝЖ¸áfåuÇ\j»¨OWÉ~H.?³Ýª\>$ŽYÚŒ[\¶Í5³°}™–/…y¨rAyTI€QpÃv̸±«4LÔÕž­ÅU‚&CK›âÍ^•ù¸™1†V•8êÈufK¿¢ÿ)>DÑ·X ò£¤7ÂbÙä6œtÀ¶ÿ~ÊsÕ8±k®6Uã;ŸâÐÖ¯[O5_‘%Hî¯ñ rY]¾ä•üP„Aàãî´¶t‹2ë3²¢&.4·¼àžÛ­µ­•X à]‹Õ}÷Þ§îÕ+˜ÔÝ»ÿ öìÝC°Ý?ìÄœ#@Á† Èu^˳KðÙ.%°•l0É-j/è{]y‹ÜÖÒFmAö× i'fÝÀ~âù œvω³˜¥GÙ)´é…°Ÿµ‹(àóXƒ}µsÓbØÒòT4Š„GÜ磊̖ûr¹Kù=K¸$Â\ÊzY¢*U,*®­™6_£Mß쥮 p¾é²ƒºJ4Ùe*lñ½°ÙsP‰Ó8ÓfÛ8“T~o³nrÆ!œÍáZ9õq Ü@õó1åÀd³haŠ &§H{ † î,;No FÕå­¿ågb[¸H0 £óØøµ »ÍØÇJ.úŒgÞ0º’a Š™‹Ö¢ØË[¤ñ‚ÁñË~YíÜy=ç‹.’«+dÐNY,Õåòà¿Ëâ¨yÒ8³¸,;ÃåÆ&K>3' <Ú[{¹a{zz©BÀ#|•D^ßzû-5xnp†Í°>pÈg á:jÕx¬GÒ˜*–·@?âji1cÞ9dÌ3¨=,÷6vÊÓ¡l©ˆe¶Ù6×½“à û‚+öÀ]lçk¾ÛbÚxÎhŸØ^ñ^Vï©vl˜Ëp‰Ù"$â0lráça4iGe“v©wj³s¶-Ö¯ý‡,0m €[KsssŸ(ˆH f‘w× Û3ûƒå2tÕ”I³qs&©Ì6’³[ËM–½²õĸR‚TäÆŠ˜ ìõêÕäÚ¡†!ꕺfÿöý sÞ¹I€ 5÷óƒ"à  SôÀZ KèMÿ ®,C‚c#kË%Â¦ÇÆ®1`£r4gÏ’Ø(bkdlX[5àþVirAû»ïžûõ¤aµ:{æŒ:áÝ_¨Ç#q ä˜˜Ø÷0gŠy˲Cž\C9Ö‘b)U¦‚ØõÛ1³ÓóVœ.ú8¦üêKT¿oÜÿ zçÝßSíHn.&†AËÒ¥K ´¥ñœÓ~²½´á~€Ǥ*-– ûY¹j%Ék ݸ¡'U#´Óå’rÅ¥Ù ž U0bÚ`IÁ¶Ù”¨{'í"€× –v‘m¥Œ£â®ƒU²½Qý;ip=¶´mHZIa¡7ç²ßÏ&ËæÒXcÁ¥{)'u®ú¢arÒó&–å ìæÔ‚{4h£UwxëvÛƒlPµ¸¸hЬӋíh¥›¨¥©§Öˆ™m³UŸm–ÑõêZ¸áºáÀ W×ÍCÀ%Wx l.aR ’G)ƒêšª§ÍáŒ7ÖIc Ú¢˜7¬¸ßœ(°‚}‘ìJÒØµjÛ­Z´ÚJ±D¢Ï¸¯¨ ö4JúÄ“RÈ›D&ÚÊjõÙ¤\ùƒ7¥$ÕÆ1L’±•  É (VŽBå`ý®\¹êOBplèzE ² ,ƒb›f“u³õ®H¢¤œ,Q5ûÆ>¶nÛ¢6oÛì3œ|ý-­-ª»»Ë€£¢ŸÑ96:¦ïç¨êèh'¶ôØÍä¦*&´Aí°Ie˜÷ h*ûn«UŸo6¶ÙdÚ’¸A]ŸI–ÍÎ º÷6X³e?ä8jýîÑV½ L²À´E0mm]úæµËB{•@!(HQÒî6óÆ €]¤ì÷Ž*Ö—qK+#°4Üê«}»fv,›+¦ÍÚæ¬RÄs 0±D,:‰870’Åp•óqUš¥Â:»QF=KÁ¨©Š¬Rñ>Ã!3ãïŠ_d”? #£ !§ÞK uF½ÿÎût¸CAÛt´QbS&볞òÆv%eâÂ]›§oχ‚ð³‘hàúœ•˜icñj› «ld.Û»ŒuûìÕk›*{ýjiXЦ—Ezmå”k×CB @uÍš$H ³­†qK›mãx fmvÈŽe³]¤Aâ±l@»ƒ"¡ˆß‚;:F¨ö&ëf+ÊÛY;<ÓF‰Š=1Aº¶!Œz­n—„tõr…k†årcºDs‘öì‘»‚¤,Û|0Îi°gIfß“(GÔ'P=CìÚ¿—œãÕ~äv™7R¹¼´ÉöZÆlΉ ƒö<60m°é5WÈ©‰ŒW²HeÂkKán´¥jd?ê Üp¿8_ÛÈ®æ>?yò$±kǶ[¸V0óE`Ô¤¶`Ô‚Î$ãœq—T#`ŽçKk“ŸUME¿á*å¸6Á {Å¿³^lœßFù¾«rLÀšÚ°å˜i+(ÌïÁ²Mip0¡ÛÅtiÚÓê M‚6>>²GÓÎN¸e2Ù@&¢ês1}ñã>¡2Q=½=$©Ñ×ß«Öo\Op,诟ïý\}úñ§T”=vy;?³Ü¼ÉðÑ£ïË­–„u‹Ðê!:Û“¿z³laŸñ²\aã8ûr|´%Á¸l¥Í„[cX¶NÕ »ìí±kWY"û³ ÄÂñ Í  nANHcÜæ*¾ Ç@â»Iíì&Qå™xEÇ€;Æ  êîß=rä%)@”±nˆ d2,Á^8]Æ-ˆe‰[–Ïç$Áz³ÆÍÈ@Pe5|éBJZ’ªZ€?ßéʳu­ˆÕÀ­µ¹µ\R-›s0©Í”㵉^¸y ­Éw“r|€ƒ¶lE%/®Øk´M{ÕØþ ÝXðX(ä`ØC)?kµ]É®q[wUVhàV*'¥c w3³sƒçhýÊ#_VçΞS»ÿ°Gõj ·óöæ>úðcµw÷ÞŠ¸´¤¶±Dun†L5¬[à-.€«…ak=ÇjÝ qÁì3ÇUËe—çŒÁÇ}ÛŠ¶À~D]RŒïXm A›¾±Ý®Îb+!ÛÀE2#A¶-DËÆ€ˆKÒ$eÜâȃÔÚá˜=Ccæàû  &“2‚jiº2*99a``€@bÛ= }2H^€‰Ãw\Fl¶c“l0Êjaµ\õç‚î wp¸¯PÖ ` ®PWô¶/Jœî+SÇä"j¡81èæNù\“çæÌæ|×w³aØHŽÁ6€7v‘únRWih“‰R8Y€6ò“ôÌ;J|Ý ×&³5WØd?à놖_\ÆqÖ›#;;­óPFB²¹zøAŠS{û7¿#à‹>ÖíÀþƒjÿçû6 ÖìóÊrO㳨ÉW½ã×ÒÈ®7 K Ò\ŸÛï9Öœ«Sà>ÈP()Ý!Ù6{ÜŠS·“ÍvذK‰ÄHÕ@¤êÍi#Ü#}Ór¶†LFµ¬¥i[t¿c¶M~V+ã–vv3̹€[X ú\ÞgNN`¶ +Þçà†Ì9.ãbÞì:°6Ãd※óI|Øl#@9ž1\WË#‚ûȃ®ỵ́ش0CûEjöý#…ö—:«Ð‡-ÐÁhåóS*?÷\¡My¯zI˜!×d¹Hhk"¶M¸Hs•µi}÷(—RÑmSS’¦ÀdhÈ(Û¤á`cdt¤2#U¸AÙƒkƵ½à–fÖh\;‹­ñ¯?öÉ®è’q9°=òØÃä&ýøÃÉ´ã^mذ^=|T9t”žaµ U*k9ª÷Úl0lõŽ_k´úÃi&¸Æ7ÙA·m°-ùe‹åJI&鉓Urloœ{,Ö}wiKÜrpÚE"b9HKUlWY¥  'g2CTƒ¯ZÆ-­Dù[4h¦ƒ@JT}Í @G™Ÿd‘°f͵nÝ:µsçNm(å„2=p©¼±&•Ôä« ž£bÕ왯k†TcÔ·Ö„ O°A΃gm¶òyƒT‹{à‹Ü Æ–âšúúè~,-TjzŒbÅ8²üL¤î¹J3ÍʸݛH¿ÙpÍeù¼—Á˜#Ж«`Ú¼¬QSè©pÑ’ôÄMj¨Â0ts˜„a¯]¿ækÇIÁiÙ®ñ9"ÀCÛµÏ&`Kκ•Ru‹–ÎiÕ½c×TÙb÷g»+úÖ©“§ ć6ÛåìVÀÏÊeïÂ@ðU xK‹aK›]K{œ©Ëư±íÆ8ÌZv² ãÒ“d‡<¹¤¿‚Ž%Aùl±ª,cµÚߤ®}#í#ž‹Ù`0c×µÑùÿeï˃+¹ªó[»F3šñŒÆË0ã¼€1l0üH)Ö !lBØRP€Y0«Y*˜"@U¡ä,U ˜@’"l±Íx÷xöE³f´ïÛëßùZýIGgÎm=IOÒ“æÕ­÷ôÖ~Ý÷žóÝïlúõ Èç.¹ˆ-)j‹Çä} vöÖÇï%#x€mº&ÕÙƒçàÆ—®R7°n7Þxãë†à},06cf«,´ÙÆÎsQh³7 Ø` p-aLÙI_[ ÖæRoÍSìç2P 7œk€šÍ›7g Ì&ÀQè\¡¤Ø·‘±‘,Ãt÷tOÆ•­Éz³Œ52Ï0×Pô¶©i"n¥´!©ÇüΊÚNϽR®ÌÒFGF3F ¥h‡óVDƒI_?¶îl¾pžh÷ÿ”â=5ß… Ø[°¶˜_ø\¯Gp5·’ê.²Ðò!š½C‚Ã3žyC²ã‰É®'wåþ´%9´˜Ñv8®ÉËÕÌÐÕ£5#“}Šç‘lPè*€0W·›¾å(éáérÞ'yBw¨×¾R1Ú«fÄk¡K|xÇ©\«ë h‹îÑ"¦]Fƒœ¼ËÙ–^‘= Ðl?N àxqg ŶÑMZ´ûZ(Ûb‘æ* ú.nEÃV€ç} ÞpÞ`¤] —)ÁÛå—_ž1oHV€ëq<`ô`ÌÀ¾áøÈRÌÆ´Ív=—¥­³Fw›7ƒáaÿJÝe.»ÄÐ÷†æB”ia7 \€zd"€‘yÓ}uÏbÞ†&ƒÿëëû2÷(É7k ÖÜ”e•62³4+¶K÷H%r7 “ ÆóìP‚·l®ÈqÀj2Íú°‰xÖP^ÀÖCÖ1áÌ™lC€9f t/´‹Áb·IÝ ]Z¹2Tø&$ƒ<öðÎd§€6°Ÿ³ýn2•~"»Y¨ÂȹéĵC鱉1·#Îb2l+]«¬dgƒÙ€›eÙ°l.]dW»>õu] Û8^Ïݹ¤‘|¦l‘i+`ÚpÛ('°%TlO'Ø ¯Û\Ù´_ë÷6 ™%(áP‰ŠJ•©uÍ6W^Ù"GP¦66ûNl2 p‰‚=Aë+€¸+¯¼29räH–´€LL2°PÞìº0il›Îqå*8ˤ¤ÁXÂøä­r0t]8-±Ùf‘][<ÁuˆÆ5“ 6à›€¬µ‘<§›ÂŸÅ¾å &6Ø>ºÓÝê2`ê¶ Ò~>×2E/Ÿ1’Í•4È\ŸÝ=ÝÙ÷³p'™4|&æ*Ž— ÅaLð~Š/ƒ5Äœ³¥‚f›3ËÜf„…L±ð•cÚ&?wš]]׺nFÏd¬Éõšª±WvÝdÊÌ’œ-­Q¿i$™*ªÇµX Û|ãת]›Ï÷V"Ù`¶Í8Y6Û«yÄ‹òâ›u½N›¼H›€9ä•“×ÁÓW—T¡‹´Z³Gѯ¥(VIgŽh…¤Q¸fßôëu°¢ö}ë÷¸A™‡´ÙÀÚ|wSóY¸øL3{ùñ÷z=Hõm‘‹Ô‚7¨@ƒ†ÅF Œ0@Ø™ ðV œ~ït¡Ô†©Z<^ÇÍ¢ÑxÃÀPbÀ€â¿]gëé&ÃÞnn>ìÚYÆ/¶9 Ë«| aî`Mº('ÓôÊàz{­çðyÛ.ß–ÜvÛmɵ×NöÀ0„ëss€khh0Ó8,Ñyˆ9ÍAVeð9˜×˜Ï8VÝ}®Fo©œ$™n@¦,  `íÂç0{½âº]|éÅIcSc¦?w<¾ã¬×²1ûY}cY¹¶vªnÛ v>ûÄxòè:ó\®ËÁ°U»¶P»²Ø%=Bà ó†µ ªlì7rV{$@¨ü—.¬ïàŒ ÉtÓøª’jÌEÆ-¢T[Š f‘?Üf“h ÕÆµià¦wõ¬Y¦ãŸB‹¼Œ[¥sÖ1.: Sƒ·"À¦Ý¢6¾Íº«©€±ÈÈNÀÀÑ}ã‰C àcMŒqx¡ÅæÅ.zÒ¾Ÿ -Ôf£çgÆå€¾(³ÏU.ÌÌÌÜÈa~¼Ñ({néÐõc\*Úš æ¼ÀüÉâØT£r¬ÌU®n$4;‡ã£†ù‹Mæn¥¬/•Ñöô'²eÑï3ë÷š.¼Ì ×Ý•W^‘}î÷ýê¬ø¢ÌhCÞÉ"¿v‘æ ­Nµ «™nC6UôZưbG½þÒóaÓ*™€P©Mz¥Ùª‰eÓëš›¦,f1ßyÝG¼ób±‚íÏímÂmmS´Õ†¤ kµU£{ ·YF£võÙ¦ñÞÎ[§úÚ j ¼W»ES©Œmƒ! ¥È-:Û¢®Ô«œÜŠŠ˜¶r2Lõî™eBÔ‡ K5`1â\Ó ë:ï;¼ÅFZŽ-X¡¤†"Fu¡-¢øÌÀ]‘[l*Žù‚[ÃZ䢯\„ûn{$Ìà9|>—îyÎG<†ï&ˆ#PÃq8¨é9»˜€j)Ù–lÍ5LÆù¥µu úþ4ïv€sºsç®äÁœZ«ümY½©¾±Ó‘§Û±LKî"­«u[æeï(e1ƒ³¨…$%”˜æÊ*­û+ý•,éQîãdÙ²^¿*TBw>²U$¼khí iJâ¦Ïßßœã£ÓVØÔ|®Y#£©È€{‘5º¶Œ›-îª/žmuûPИ@tÛè‚~s]Ô‹½SòĦJ% Ø$u ] ËŽ1#Š™Ezqu¥j(iI.L통`q¶ïh•ÔÊeÊf”pzàF©œàübÅPâÜ¡û,A–w1ÿð¸èQ¦¯ÅÆó @ ÷¹Î¹YàÎßϘH~W(.k%ƒ·,+OÀ]¤“ºp~ö çnãÆµÙ9G‰G~tFüè$ƒ™w±´ «Ë€[Ýt²ÚÉø¶© ÒšÉ R°ƒ¬Í†¬ßŒu««]†m©b׿Ulx‘ËzTŠeó×-±‰â¦Éó²i{æÅ¬é˜X/)…öÉÖ}åÛºm5dýV²¦×Î!€R ]¥5 sú;-Y\+µ ¤åƒ¬[öxãY½cÙ‚¬^%$@†‡‡ò8ÃɘGdózú})¶åfÖ*aW*ÕŠo>Ù£\—H\Ãõg¨ƒ·ª¯©“ÒB±o¶¨¾Å:AA±v`Ùš"ÓV&p““Ø*šçÀ{®º¢£ ïê §8/$À |îp©è î!ð6×¾”pˆZšn!ºŸB€M›{Ô6‹/ê¸å4Ÿæíœ[†1ºAW¾ðš.F†çjbÝÎj÷—NdnÒš¤1s=f,f]ý¼?댉Ó ¬q*áì7Ý7vfÝ6ÄØÑ=ޏbd‹=vt*`<ô›*ɰ­´æï‹¾æúÚr:à²ÃCxt‚€.c3‰5¸ó@¡g¶"…&|L–)@[£!”"h3`mêääÙ£n}5½@u,š¾šµ‹Õ‹ƒ³‰ö‚k7)v(Ì¢jC‹w¾Ôùbì²øÝf¬èðÆ¢¦tm°~–Wd×;šQ³`m.àm¾ç¦œó¯ZL0ˆr.²n\t+ÁMŠ„„ºÚÉD¹ššIàV72 ÔîhœiS ŒÛY‰ õó7Y±~,éèOÚO·gzêø‰ãSñüý:°€;WVÍìÚb®J±rEɸ¾èˆ‚ëÇîC,Ýåp[ÂÃÞ¹Ö8Â<½Ñ0)êsЙ¶ÙX¶|4èàBÍ®XÊÔfŒÚÀDïBz¾m‹Äí„A<ëqÓnRoÁÏ%Ab¹vfü~…2DlŠnE`Ìp9íž¶IÚEe?—Ë´Í÷÷†v[d_VZS”(‹Áº‘¥ÂšÖ¥Fs–-ŸTÇx~®ÀM‡[d£¡>âšò~±3bÜ&ßW›Å'}ý}YÖogW§·ÓYÖ/7;ž”“0T)†m)âÖ#¬f1\§E¯™­9<æ Š_sÒ-ªKpY[Ê*Ö–{öÚë;nY:Ï‹§^[™¶òA[’—ü˜q2­!Ö Kw4Ŧ٠ìÕpá}]ÿE_`¸FZÀ¶±*ºÄŸmg7Û"_*Ö'¤x˜M72ì0pŸ@Îsã±ÅþÝ6a>âç»sÔl vïF %‚·ia?Ö¯^Ïn êó¦lÏÞ"°qh«¯Ï³Cë•›”±m3X7ÝÎÇÓÝÕ´>œœ& ékhÙ3¯´—k¶ºöîÌvß…Ëß0ŠÒ(•€Ò OyÊS’­[·f…JÑEKÑ_;%°Žpóºè2 ³eŸu[(ê;kû‘Z¦ÝŸQ¢œkà­\6€‡ì¹.v¸6AYÉh¶ÆJp›¬½V;«þ`< ¦ºäÀ­¡£a*ž­Q¹Lñ¶QѧϜNµµ%§NžHºº»³là‰ñ‰)‡Ïär>¿}>àm.€l6\‰¥´ é3jKpàÚÁ-J"DÇ{=C½yfí¾×Á2^X”eÝØDÞ·ª’juÖ† §zuÚ4÷ZYhÎÖ³Ñ^t;QX» @l”×V®›´ÀZˆÄä%ãvðàÁì÷jàðŠ7¼Êñ't·bà,P‚: ¯Kƒw?Ô3•†&ÖU‹en¬;¿°ä‚.¬°©üh)ëMÚXjšêÇú\†DÔOu8¨Ÿ¾¯þŸÞÂä>ŽºOt˜5lÜÀ𣾾ñµ°CÏÑ\‡Ì´½v±|-ó6—²ö>6û¨ÉÆÍ½W*TͶ¦š­Ð{ȶyýImr¦´aÙbÉpƒ{Ô."`ïk·¦½o3Pôó º÷z‘†èS€w ˜tP,–m+×MºP¶m1©t}>ð›Ac;v,Ù±cGưañ]tÑEÉ…^˜ (Uv;`Ù8 ÛÈvY Ó Z¨/jìT%ÊÂÁÙqºJYà”kktdt*A©±†«!+Çfí5ÉLý<Ýð½n*ûspËÊzœ]XG9(ú¡«§;ó^?~,é«=Óqfj“ÌN Œ¹ 8”ˈ•ÎR$½Ú7ëå~Æ|›Âk€»ýyg“¾&:ÙÐ+ßá%*xÉ‹¡"½º–«~:ž5éä‡D÷hRkÝœ¶ž T 5÷ŠóZ`WîÂÕ &@ iúP¡_oñΗ[.z\ŸWü^dÐbìÚµkF«!Vª§›„ Ãî%8³õt,³¯‹rî èbLÐÐ\ùa|„®ÝOó•l)›Õ^¤œ!΀: ç–ëkzxh8ÛtOÈyŸl;Ÿ*v•@-cÛêØK´nÚ=š%?L7n³^¯ý› Qıe×ml4;& A ®Ø{¼§œÐ‡¹¸Kç Ê–Bg{Þš¥Öý -ë¡®%<3Ü(XÀdËyYhQëH>æ¹<-(³@c ƒ!¦ZkVÓz®V÷hE¾ @õZyľÆ.†èRàÙ…M7)v{ˆË ”WÐ[|åtM¨¦]™}-TˆÅeŠ1M=Ý»>QVŸ0“` n:$û`GÎlm”¤ÁZƒâçÆ€ ½öyKw½`|9g1´ Ÿ‰F«ÔÍÆ>¸áuw`–8þÇýÖõ­ š¬S9š3nõS}BkòÞ  Í&{»«ò>ò‡¡è:(ïsRø,œûîžž¤_náŽÅgfýE 1V‚ײõX¨lÃBÛ\ÀØb—pZJm.¯ŸKYý?æ ¼2ì ëª­çÅ3ë/^Ü[Ȇë×i6N'0z¥»Ô¦ ÆÜFÐæœ¯´‡pE麳-"¯™ì,‹§éWíV€‘Á­UŠ@Y(Îm±°…vƒ^ oΦ䪩q”ʃ3€® 8À€k®vÜâãØèµm¦lv¨& ÈÊÙ–T–©³àÍzæl'%{½Möj]µ¶ªeÚ º¤Í´¬—_^Q¼XD=k–N Ë.Q¡@y±H ””}hñÎ¥ÐãJYг^Ô u@ˆ²r„uýXíëãüóÏÏ67¸H#{Ö,« ¦Šjê¸Ef"ë,a]oOß÷”¹­¨ã¯8ÀæáXlÝEºWad˜XƒõÍÙ©S§²[ vY)s5¤wX‚`pÝpù:Ü?ÿ‚ó“¡Á¡¤»§;éíé ð5<2œ4 N²p¹[Tƒí”º“^®;Î;\ÛÑŒ‰Å}œsfœ[¯kÉ|j].ë¶n©Ãbæ¿æm¦¸ÖØtË9¯Ç¨&Ot±]{>­ý¶@-ÔIA“4ácZd"¶> K´….:.. @†Üd–"õ. k/¤Þ½é×ò1/ð‘…CúÇ e3×öV•dÛ–šV êÜhØAœ19À ;k‚3€6(m|‚3Ëv1æŒ.Lý?“W&OpE£îm®Îj”·k#“‡[ÞçÐÿãØ^tI Ö9\vnŒñÄ ÃcÕÎÈy: ׅŵX º® l›75gà-{-bÞ`”3z£M£›óü<¯‘ϧûHãµÌ>Çy8ƹåu®ÀZ Öm6ݸTEÕ—²¬G°A/`îðº²D‹&QlA][kMÛjÛh^—çÙl Ì,éãÅ¿éužD÷hyäLQº¯‡–m)•F(˜Ñ+ bôwuW€@Qa;Ê`9r${¬@¶Ð¬£ÅL+å3£,½@Q²0&€æ<â:Yþ ‡É(\GLD¡!ÆzÁÈÑÜp,(d*k¹$ï›÷OÈ:œÏ›Ïˆ¬õHyèWy.ͯ$§ò¼·–Ç,¯¯Ëü: yÉNõò\­Œº†††:9Þ:i5º…›x à¿ ôŠ+®Èt›×ƒxC%dC²æ!~;Ûõ¬ðFw)® Žà zŽ ®1®õùlÊê¸MI\Žšä,–C³4®Ád2Á\²å\˜¡Ån•dÌŠtáRW¨DYÐã¸y"BÀf;h–ÇŠyñkÚóæáyóH”P™/åiIb«b°–L' ÔÚL¼mlí·ñi¶^›eÕìÄðZd苪}ïZ ØXKè’K.É€›ÎŽ)§­•7I—KyW ‹`¯:@Œ5@ÙÅ_œWÆ`»†çt¸Þ˜ÎÏøº1Ÿ”wÙ ËDÖÊ”¤|ߨ ÜŽã¾€¨‰¦¦&´ ¤a¿–+àÒ$›š i=ñ†,ü"ߢd-œ ¹zU r8 XÐJ¯I^×$/opÒ ÇÒ(ÇRGöç…@•®^Ô1¼üòË3ÐCÀÐð†úcHZ¨@)7r¹À‹ðp"Ë“ñˆdOqí'ß6½qNê’Y½ ¹º–£Mþ˜k–æb±¥ˆY[H|Ùbþ\³HÁPCW@`ÝÓ>†€UèÚ Þ& ¨E™fåì:³½HmE U¤Z™¶Q[,Õ»x¼t·pGoÝ™¡‰`cX4«f³Smß2 !P@4r0lnsíy·\øE¡xŒ€A8Ã\†Æ®c~³uùÄ0ÿÁÌè ~cQÚNFdmËü’µ5(ïc?"Ÿ5*÷a¥'&—t©$¯+ÉÚOå³Kò>»©ÇòÛì~iRÒ\¨dS³c¯Q·5òÝ5ò}`×jr– ÌZ-Ãû5D²ûxmÞƒ°N¾¯^F£O£ü¦fYÛ-ò=kä5kä|5¯]»¶.aœ'ÜØ€•"yýõ×gÆ ç   à …cq‹ø8žÃjoZoL*Áodf/G¼ø@º¶Yó‘L«vu/ˆÍŒ-¤0n5Æ"Ïõýsu‹ÎØ`1ßæ™)j™0û¯{vsÚÒ¡–“6QE»[õwhoœ×s<å.¤ ¥*cÚäŽØ“i©LoáY¿¸G›jÑLØl=DC™2:`aWÁVW˜¸pÌ¥òöR·åèsdu æ+Ø# €4t»ÀÀ}.Ê¥r.VéÅôxÌ×-:Ûk²°ÁÃÆEÕ­ÇÉÖIó>ƒ%9<ÖÌËøÔlËKÛMÁ^'ÎGý½ù{†“ØÆªl¦mØ2j:=Ø&Dªµf‹òzÁˆºŒWZÄ2ndútÖØX |“ç×¶vq|U§`Î@9}ò¾ùÜa4fcÀpèÆå3ƨeCD°Û8ÐY6=Jέ7R3ŠüŒ.XËo37)bàò8¸ºüñ:=‘ß ×°fÍšl¨m#U/ç `@.Ö&9_-rŽÖïØ±c½¼·U€ñpµÃlvŽŒæ 7Ücœ[7¸RÁÄÁ­ºÜ,\Q¡R]ȸl%ˆ[ª$+¶¬ÛR¸…êÓJµ¢×ñÜAŸ€°`X„¼,³e™5¯/¸=×$ŽWöÃiþ~‰£?Ãio ½4–ʶ¹6o7æùÁ½ e'A¨ŽX¨u†ez·@ i'.ÂÖVØUãµPÄå(‘P7……(‚嬨Y¶êj iW^ye²mÛ¶ŒÒ¥À¢Ðµ Æ9Hã Ö-À¥Wt¿àìŽ)0e1*Š{TÚ¨„;ŒåаhL¨Ûˆó›fÝŠ@›oµÎ¨S ­^ý_˜7ùu2êå÷ÕçÏ7ȹh€Èùh×(ç¤Inà6Ežƒüþ&9-ÄÖïÛ·o£<¶AÎy‹œûZí~Æu¸êª«²kÇó¶,Ü¡C‡20Ç:iË çé°…”Ƙ¯.«FÖm®z¬;°˜ú³ÒîSèlɳx­%VBqåÉb µm÷Ø7Kìh÷©ý~ïw(@ }5ªüÚ¼ëŸ=C)#†MÍËÀiD­Ñr9`ÈËXñ õZ7ª7Aìd6î3ƒ†ÅwËq,悎`êÜÌW5ì€ÐÔð?gÚ<\œ`tp ° ÷ÇE ÷É|ìjnnîjiiéÅ<$knLÀÝXww÷˜lPF0HРä»ÔÙÆl€­\†M»E½ j›>7¼éQozg5ÌɹhÀ ‹Çå¼7Ç ˆ€k0Ö„!ç®d¼§Y@Ü:bçíÞ½{“3”£¸úꫳlF5ÖÃÒ.O€4”¨À­€ƒ¡±±±®ÆÆÆùœ™»IV’pdL@ݨ(åaiCiòذRp£¡AšÖfji`m¶qsë8ÄYwi½q f4Šni”s“ 9Ÿ¨Û$ç³YÎ'’ÖÈuÀhÚ´iS£ç&9ßkä|nxä‘G6=üðì[·n½¶:89&ÆðÚk¯Jf€Ó©ìh°”:¡R.ÅÅfÝæËÒ-6x[Lý¸®TÌIÄk†[¨¯èÉõ‘׋Ôëpà…Jy,šwÍl• ;14Ç´E¦­¦MNÜ Œ!9™Í–¶Ô.ËEj©{›‰b/–WfC—ñôÄÔŸa'3gÈvà \gS ËÝe¹@Tl XÌ¢ü <áúPÀÑGi *F¶i"Pƒ±XÐ'ë«£¹¹ùŒì˜{L0 Mæë°(ãA¹?†D!ùºá¨(À6b€Ú¨jå²i³´ÔÑsm³¸ÙX¸ÚÇÛF5šFGGe4ɹn’sÞ, nMKK ÀÛÚ 6à¶Yne 4ËuZðàÁówïÞ}‘¼n£¸Fp\O.Æ-\©0”¸–op¡"léR1p•dÝæ Þ“u é¥ÅÖËKÙÉf¾®RØ4èfEëâ¹|ÙóÏǬ-µ Ë^3[̳½åd”üÙ¬Ôkô'ÓîѪnÕÚf(c9yrò6Ú´]{Âç“®\„Ƚ é)[qÙÆÌéIÀæ¸Ø-CÀ¸ÙÂ~€ôãJlÕVómµ ܈‹‚¿æšk2V »_°m˜cdÔ ã£ž5dÌœàpZÀ^l„†ƒÖÝÝ=,cPÀÀ€ÌÝAQÄhC ¨é[‚µ1‡U›/“–$ÓñiiÞ8<{@%7˜1Y˜ñ2R°äÜ@PÕäFG·Ä¸ÙbáŠX¸ ¼å·Íp2šå\7£tˆH˺uëÖžwÞykä·ÇÆnT¹n´µµ=E@õb(›p àÔâàú§ ×™1p‹ à–Óeº¬ÛlúªR-û–Jo.„±cØ\øÔ/:%ÔVJ9>o i_½dƒÙηuj;­Hú„¼mò_®ÇŠ6‹ç<Ó–(å="'Fä2ëçÉÕõØ4#fƒ- *Ê: 5·ÁÐéV,žp¢¸á–•ä1iÜlJ9nÓ¥Øí-5€Š€mn‚ùC öåºë®ËÀ€]Ì $`~‘QC ;†p(£vjí²èFÝ4#§OŸð0µ0Ý9P#XÓC³j¡ø´H›R€©(ýÊ_Fеqã7fáÏxF¶ƒÇï”Ǧj1â5Ô5Suà 0<{öìÉîã¼=öØcÙú|ðÁg›ÃæÁ6‹´À8UÐÝì’ ÓE÷­Ô {8¾·dHèX<i¨´Wð³ö]Áv£Ë"ÓlDµ(ÀyF_H/uW#Ï/¢KCÔmQ Ï7¯ òy;7ïqîêsc Y,O.Ä5º\À)¶Ê @ bÕžþô§g÷¡81'$X’†9/ 1.s팣ã2ÏN‹áïG&€€ÎÎÎ~İå@ ¾ÁÁ|XfM³i:>ÍsyêÒåĘe ûöí«áòX…>‘øñr!Ç1#.™LÄjF’‚€kŒµ¸Ö¶¶¶®€“_ë…^xRtоóöïßÉîÝ»/•ç62S  îsü,T$1hæìÛbÇ¿-'x[IIóqVZ‡Þ;‡!X\âF û{݃l}5ØJÝ‹X{Á0צY8›ù©ãÕØ–J'êÐ&ݺª(^ܯ"v:’*tV#ÓÆ:ÚÕœ¶ )ÄjéªÇE`ÇK)ö9ï3BnIb-ªMæî€6"dãe6Ëöv[žÛ¶*­WÌ­˜`¾Àå6 îB\^°m˜wPœt¨a ƒËó¸ê“b¼{äuCІÄ0÷Éæ W6}yí`¬ÙdDÀ‘­U0P—^ziúìg?;¹é¦›R$>Ü~ûíY@r¸Z glœpkàä·È€['àmœÌrmw ¾ðÑG½ì±Ç»DŒìfc.!þ 0œ¬æ Œ,æ®Ýb¹O+Þ–ª®Û|7Ê˵Ù],·)m}°ãlUDZ6dɆ*i×£-Œ«m®­•*”om,?˾GöÕ^8vJ°ýÈÕ¹@‹<‚6½) ­€iK夶çíkjC±j¡‚{6°Ðf™°X®—:Œ êÕŠ -è`³ÇfwS`Õ°SÁ}´ bc], ÔYôy+5=JXࢃ âiO{Zϰ…‰¹ ÀÏn`Õ8€[²=%óè¨æ™×‚ý†ÚÚÚúÄ0÷È|ê…  †1´Aêi ¦]Ÿ%Ô²qýõ×§/~ñ‹“_ûµ_ËŒ?Ž Ç ƒ*bÅr¥WpÍp¢#Zà>·îÈ‘#­6l8O®ÿyÌ:°–¹²A®ÿÅÿû¿ÿûÔíÛ·_(À­¸MÁ¾¡”®9&¨€}ËëóeÆY7o¯ð¶T¬[‘N«»ŒÛ’Á&aÇmbYã­Y/;VîyªÈ¾Ùsí¹?-°‡a%«¶ÿ~·¹æÇÖ¯_\Œt·Ì'0jx2<<Ü«€švƒzîO Ôl6çÔÆw,þÝßýÝ’u=‡@œu¥Z7ž¡q½€ökÛÛÛÑ.kƒÌ¸ blÛeþì]rÁ®]»žºsçÎ˨µ€}ƒË±µˆ빇Ǒ} ðÆÚoã^Üm%tÆRºL+]š¤’`n!MÛ+ý}ø`Ö`#é…Â<€'É96ËŠá`¦X”Eq¥Ä‡³I ÀµÈœi‘ù±VÆ:™3`ß6Ê<Ù(à¬KæØ1_çuuu]úÓŸþtÛC=tb#‘¨€älɾáq6Ì;€7°oÈFÅ|¬$û¶\.Ójé ê½w)2{‹Ø5öFÛ0•æÕ‹Ùž=óbÉ-Ø›ÁÞ˜2Ö½ŠI³ œg ½ßo §r}icv#Óf”•mÐ Èx;!“èr{¢mM‹ÔõÄaТSšUs.ØY™/úýE &”Ä ?ÏÛ0ë“  ;_ºJ‘ £MWê\Ýb³p¬-LÊÁv<ó™ÏÌ % '@: $\ `<öîÝ ×º¬—çoÞ¼¹SæÊ 2?å5ÝR=9Hë3ÌšfÕ< VJÊLˆ²lzÑcáê7žÀŽŽ®=-"ú£U6h“µñ /Ä8#ú`¿L›§<ñÄÛvíÚu©€µ€7fž‚íg*_‚7¶ÎbG¥ÝtKå2­¶øàåj<`úÁ¬ÁaÓˆë†Þ $ÐÙº¢ôVÙ6ÚþyÙ£¡ŽD–ðð - ÅÄÙßnÙ6›  Ÿ—çŽ)=Ý£e2m™›Fä°œÈçÏV÷ÅR¦¶'YȪ»V49,b·àÏ*¯ §40ñÙd,7(FŸcaç«ËÌEñT‚Ò_jš~µ U°i7ÝtSƬeÛ†kx5\g”¼@Ͱ“'OöÊ5:"×ÿ¨(U¸<Å€öŠáì’ùÑ-k¤7jšYLfv,ˆ@mu±p ®1ì[½aßÞÖˆÎYÛßßß!c݉'6ˆ~p;Ó¦MÝ2ŽÊãç ÛzèС§Êãëè:pÃ\ÅF.2l*t ¸P)7ù¹ÞK–û¹ˆU«† #Ø5\÷¼&áŒâð^€˜¼LXk‡µ ²ä‰µ×ÞgZ×§~ŽmÓÿÛøxk£óòbG’™Ý["h›hâÍÇ{l¶ö!¤oº×]ÁNÒP;‰õë<§‘½G‹ƒ‚Æç¤AY²=€C¼ ¨j¯›Â|”OdË–Np=þ¬g=+k`5°»eÉ\[ÄŠ¬ ‘]o›(ТLûd^ ˆ¡ìîèèèìFø@Ö4³f] ãÅ/úêp¥ü:×æ×žŽÝÖäc­l :e® æ?sJæ#ÀÛ&=2OÉs{d~]öóŸÿüŠÇ{l6îER Xa¸Pc ö › 7‚7è$Æ;Ux[ˆ\I]gòY°Akìý‰k °æu9ÐaEú1&ði7¦µ™,Áaš¶·^Èï“Ù³îPkŸC=N-xÓÿ+Ü@î-%3c|#h›´M’Oír2aœ6ÌVÃ2cA{Ì[¬¶ŽŒÍ‚ñ˜=^ðP?4=‰ìdõŽAçXD¬åwîC‰²U ^µÓþ0NºAao¾ùæŒ]CÜ\ߨÁÂè!^hß¾}pƒ¦¢,O‰ÒÁŽ`# °FmcÄBÅâ½Ä»PÌšG¨xŠšÄ‡’H’x0 ätì¥>ºnåþ…?¨[cG„Y˜6½;D\[›¾HO¼P¡jÊ–¦ M€ÐÄôšÚez» ýzÏŸ¯3pBÇDzPx`ß°ÃÅn ÃÕʼnàu(Jf¡Î¶è#ûVy0C7Á\GP”¬íÞ½®Ðq¹vGZ[[ÛÖÄX"¹ G®!‚Å;嚬YfÍÆ«MDV-J™à­&™§Cöm(ßôçó­GtM7]d#xZt bÞ.Ñ's»]æí^Ñ=W=zô©bð›Þ°)ó¹Ž5€ûlÐSoð€ÙYhÜÛRõ$]nV‰-À® ÀÀì@4®R )ãºxnP˜ðH {^=¢Äû,¯ûAˆÑÓ]ôqÎÖI:š|Ñ Ö‚¼æ¨ZãIl_–‚ÑLÛ˜œÌã2ºäÄn ¡w¯i¬f¼4ªY,]O¦xÙZl^œ[9éÉ^2C(õÙQ¦^cauƒ»Œ €X7780tEn‰åp«•]ƒbÄùG;'6°lPŠØµ‚E¥ù]»vY—1k]tQ§÷¹™»JÒkッƒG[[[ Ös°Öx"Öz“™5ÖÖ¦Êu¼èE/JÞõ®w¥/}éK³VW¸ÖQ¢”³¹øâ¿˜|ìcË€Û×¾öµôW¿ú•vjöà­É`(/ƒ…€/€7Hÿ–-[0—Ê<ÞúË_þr›l × á†à – P@,.»z¼U"ia¡àm©ÜbÒÅ5`†Âùgë;Øxh ¯ ·°áÇóéÙ;[žö–ÿ[Û[”lPtß&ÿ‘I³áJ#çÙ[Ë é÷uAÈë¥îÍõîYäÚŠA[ÉÐ÷#ÚöÈ„»Ù˱¨Ú[€¶ãçÿÖ Ï2b–…+¢ník¼Ý…ýl=QíDó*Mc‡„ßeÇÝ,åŽ;2Ö©ùP’Ìè*GATº«Âjk8'8·(Š‹þ›ÊعB9‚M€`MÆ„€² ¬!+/Öº XÓ1k3’ ^ýêW'wÞygzÛm·eÇÁ¸”(QÊ]‹Ÿ€Îxó›ßœÜ~ûíé¿ýÛ¿¥_ýêWk~ö³ŸÙ ó°aßzQfFæºntɆp“² d2(@ Kæ~ÀÛ}÷Ý·mß¾}xƒ.Xce}ľA/aS‰ %ÁËK,d>W¢-Vh½WZßUR/âøèeÜþ‡`5¸¬1Àn°ńë¦ë´;šèðܧ|Ÿ—€ç…… Ú{@K»4½ø9Û*Ò– ñιÆ¥IÙ—Ï Úª*s´Ú™6Òöcˆk“²FÓ·p¥ë ­'€E³ Äf¤xßïôµ(ß+ù¡'•M°T2„}KɺA)‚áA’” b«à–ÀN‹”™¦å‚·ù*³Õ^Æçó†nHž÷¼çe=B¡1ŸX· 1kÖàWB÷‚ƒbÔ:r°Ö#¯9#;[ Ö˜dÐkøÒ;î¸#}ãߘ}§U:Q¢ÌW [^ÿú×c¤?ÿùÏÓ{î¹§æ{ßûž+¦ët@±o}2{D×t¡ž ¬‰ sð†d†ÃòØ6€7ÙL6!T@ƒ7¶çÃ-Úe±˜4t’©ÞÒçt1\ŸÕªÓpýtÌÎ/Ø4/6tfx #M8·q¡³P,X(Á«º`íØ>  ìgÛ~¡ñá]Û"Pf3M½ö’êµí2N$~6~UIµ3mâ•“yÀM&àÓàôÜ¡,ð§ËqX0§›¾‡ÈzÀͺ>½ÊÍEŸg'Ÿu{ÚŠÌ!°ç¹Q±8à°±ƒÆ.‹¬îÃUx+Ü'° x«T*þ¹ ÆOúÓ3f …qÁnâ÷ #¶ðÉ'ŸL;::NŠX;ƒƒcÇŽõ(f­K5Æ­¹Ìš¾âÞóž÷dn×(QSÀÞÊxK¼•xÓºx8™÷Ö+z§7g7 0#xë•Ê0o÷ßÿÖƒ6¢ô \sLX xcË,€6‚72o )²šãÖØÈ]3køŸ^Æ>3v ˜:ßóR…6áÚ>yv¯5£¶Ÿ^õOf¿×sj²DÛB_îÅ[pfcë ±³7×Éž—#2me²mcŠ¢`ò$@›FÕ*M×mBö^F‹þë> &ͳ»Í†è‰WÁÙxú¸ìΆ  »TÄ'°s-\uÈ hëÅ ·3M±YR$Š/PˆèÉ– µÖàzƵ€› ±9è €,÷O‹=(`î4Jw ÕXk9³Ö•ƒµÖ†"X‹Ràíg?ûÀ[rï½÷Ž'g{?\ðvôèÑÑ7›ræmè²Ë.ë‘Ç‚yð¶E6Žõô¼´¼d´A/iðÐ1_Vy%/Ö P#XcžcÜ€tôìÎ!ë{Z[Vm,¹ íŸSÖmjmª¶ƒshËzÙs`o½ãòZDê×[û ¿¨¼fW¾9Ñ:¹êâÙª´Ù¬&¸H I¶œô^‹¼5°ñZ^X ¤/¤¾àžûÒ2ož+3”!SN’‚-hÓš½l J±Ë€ÃeÑK9 5(L¸$XÝÊÀÏaÁë–%çº`ç ×  à ¥ #‚óµÿþä‰'ž@üZ—¼ö tïðÖ°&¯ëPÌZ—k6Ø5‚µ(U%/|á 1,x+%~Æé”ë4gÞÞPã Ù¦C[¶lA˜·Ëe}\*€¢ë À` à·ðhð†Í¨fÞV"x[³FV àŒ-§ØØÉiØ@˜áµÐë8Ðûqìl@Ñ™¢ÖöxY›ÞïÐ1Ö^½5 šDbؤÛäÝ‚JëõŽ«¨ü‡¼gWrv—™ªÌ­vЦ³˜²¸™œOȉ¾Ñ«‹¦Y7 fëOf!í$¶›M·¬âwÙX5‹ô½‘^öªmŸ5[M8²noXÔØqaAc`— … ðÆx<ÎzJÌ8=—\§´È½å–[²RŒX”¹AwïÞ="çµMÎéQQ¬ý¢4ÑÁ@n;PO0k:v­/™Y¾cª(î«^õª,†1J”•Þ>ð”î¿ÿ~[ ݺMûEõ ô‹êxC7‘‘­[·v ¨¸PÖÔÇ¿‰ ØHÂ3]eÁtØ7ê.– ©x«!PcÉ‚4º@ñ8Ž:¿ç¿ç‡=Càè Õ.Ak{4ãæ5v·€ÇÖD³í-² Ζáðˆ /ÆÛº]=òÅ‚9MÓ¿Á±Ëcò;óùK=MÐV•ÌE}•ê Ú2†B&Ù!ír²/²1^¡V¡^¤–‰›­®Í0õ¢—QêËPÑ@ݪ· ^,=¾ éö úÅ¢F 1¸ù֘ݗþÇâ'xÃ-Ájeßp^®¿þú ¬!3ç`•‰(ßñä“ONôöö¢|Ça¨[5$Ï£j|‡¼Vƒ5ºBYƒ;7Æ­¥Ï{ÞóÒ¿ú«¿JQo-J”•Þ~ñ‹_d¥B¾ð…/¤=ôfÞ´w„§o¢‡f€7Yc#²Ž:|l>pàÀå²1Ú€M$tt;¿°¼aâ7¸Mɼ-$æm¹švr°ñ>7÷пH:c1\œèk¼—Œ6è::Ô/T–`œ¸%1èEâ{˜èÂ'É2\ö¸´ý ¹4½X;ýÓ6ß&j‘ßqPž?©qFRÅñlÕ Ú¼dœÐ¹ HH¸H_ËpyEù8élGobè݇¥u-èÒ”¬­Ers†Ê‰XfÐîd¼‰ÚEi‰Æ*äP|P€pI`‘ÃÝp†X*L°px1]:î Ê b¡mhªE øà’XC\$ipNJߌX@¸BåœEzH M—àá¶¶¶n1b,: Xó\¡SI×^{múñ<ýýßÿý³*xG‰²Rs÷ oxCòš×¼&ýò—¿Œ:oé‘#GB¥Bè6ÝÖ/Ÿ~ÑC}oycúQÑIgD.ݽ{÷Vo-oÐG¬í6xæ’Õþ«¼Q÷“QÓ`ŒY5Ú€5 Êð:œö2†€-¨ìßóÙ˜lm·<²C5 Èl9 ¯¨n¨÷§®âPÔ—Ô’'–ô(j}êâàØÍÇÕƒÝg"h[Û6¦hKœÔQ ;eRß"÷›mÚoÙ€G”©Á–eѬûÑ+0hýé^òƒuq†šízÕ+lÙ¹¢ÔxžPëa,° …—Àܾ}û2 ÁÝØÑA9⽺š9”ÈJtŸBYâ7!É®(J(?€SÙùgñˆÉ‘ÇmÚ´©]”â°œŸ>´œB­5Ô:ß:!  é;ÞñŽÌàD‰²ÀáCúPòÖ·¾5ýä'?™~ó›ßLE—„Šô2Þ­_to}¢‡Þq:"ú¦]tË–;vl‘µÖÀBáÐCÐU4`¢h†õÄdè5è²…¸M+ ÒØÚÉj,ÛÁߟj0èV ÖðZèfv\&PÕöA{i<{c«"xå2f‹÷³¡9áÅÉi›FðfÝ©6{ÕºM½r ¨i{[äeËmærŒa½"U™„PíLwnº¸ã Šà PØ%ç&Ë¥š2ÖØkIåµ³òº.„:„2of«SÇcã®@  ™¦Po¾‡›”J“éø`çà:…‚dv—pP(ÕæBøDQ\ÝÉJǸµ;w"Ñ`Bæ11Gd~Á˜ ËóÝò›:U’A§a׬+4ëú›¿ù›‰€µôÅ/~q´êQÎ A\è½÷Þ›þà?Hîºë®ÒÃ?JV˜á6E]Cg²ÎúE¿ ·é˜lrÀÄ”õ·UôÊ`ܰáb²Ë_hðý°ƒûÐCÐkìmj ªWŠE#H#“¦5Ͱ‘Q£þ‡§ú:—¥;p¼kØ$ã·±'3BCIÖSc» x¯'à)Úä—SD^Û4ÝŽÑcú¬m²1ÛÚ–†¾W'n5s畱€3g|™€Ð¯<$Uí]  »5 ÚÀ‚“~@&ÛÕ^¶¨ZúB[ÿ{9k-¬'‡®yc zqjüës×ÎÖÀ±¿Q7îµECÁ™öØôyx£Ò óF¬@ @Þñâ5P¢x ]¨:E¿ ¡"Päè °†ÌP?;ÀÅp víäÉ“§Å´‰Ñè–s1‚â¸òš.1(¬ivM§ˆg`Mmz÷Ýw§·ß~ûŠ/è%Ê|äå/yò’—¼$ýë¿þëôsŸû\*z%”¬0¨ÀÛ Ú½‰¾ët£ètXß¶mÖ!2M·‰nY„ØSVû¸® ÀÁæz : : :ú € ©¨€k`PÇ“E#“f5€6 Ôä,Pñ¬áØ.Yäǎ߇ߣÃYpŸõÖŠBhÈP‘iòâ¿lÜ´í3ê5a÷:•O±ž©7Ë$^¡\sç•ßò’ó4ÛfÁ¶œË's}>èl¼«Ö5Zí -Q ‹œ¸×Ë{X.Ê•rQjmܘö«ÛIe3:-Ëew"ÞâUyÖ; äi0æ¥TëIUä:µµß¼²%^M;‰-µMæ `‹à ;[îôÀJAQB©`ÈáuPšx;C¼Ÿ)éoÀ‘Ö ·Ø »p”2yÎsž“Ü|óÍ™{ÊdžcjkkË’ <ˆzkmˆ§‘…^DzL¸×@ײ&µmž»Ï+‡a_gÃt¬Ý±ÉQ64Çûl¯(| è•Åòº éÆïLÅÜñµ:+Ö{<>$¯{<'ƒú”>§k´TÍk«ÚA›v‘jЖÅm“‹p•Eòv·`ѹ-‚ê¡f'¢ü¶Î ?ÏfÅXðêº`ƒ(uÖ«ÝUx Å۩؆ó^Ÿ7ý>;Á€"” ]â9(ôÙZeQ<"»›+äBÔZš8ÔgÔöJ Õ‹ÑõjlFKQ‘¢×{,›íñÚv#¡ S¯q¯‘Euå¼ÅBz¬Á]A(Ç 8ÿF‡Çð°NØãh ÀÆÏfQH(Ub ¹1pÊplp ¹1kˆ¹Ã1@9²l 2dóírlmDQ?jT~G¯C·|W·q…2vͲkYV¨üÞôóŸÿ|zÇwDWh”(òŠW¼"s™~æ3ŸÉܦ*ËÔ+Î;5DÇ£ÛÈʼÉz=Oô Bådšnýqô ]¦Ð;oØl¼A§@·@¯ÐÕ¨õ»ÕÃ6fͺG½D5‚4|¾ß 0ÆbÀx/Ž :Lj׳ޜNæ •¯²›¯Ÿ¨­ êy•ôqÏöÙE• <Æ/æô뽘l ClŸ÷ý–}´$ˆq'¢H¿bÙ4h«Êñ+ ´%ÉÌ,R‚6ÑrËÛ+ áZ/K$4Á4 îQ³–Òõ&ólÉKMö²`ì·Œ›^4TZÙ¥MźYV.ô[ PFto2nD³oPFp7"û’.U <ÏVZx]wø.*8­ØÜôŽ –JPÓäü,|v«L˜À÷ı6Ž Ý :4(çõÖNËçŽ!~¦³³³[>›IjÉÌ~¡–]+½ímo˲BÁêE‰evÁº¼û׿þõY–é~ðHͺ '3“2NtÀЉ'†dsà¶AÖðÄÖ­[ûPœWÖñVvÐXÿdýñ}pY2ã”›8né y*¬Þ× .O|t{>kV è,|?³@3ä ÏÃãÀ²º?¨‘^qu †ôBdDÈ•êé|?¦”Æôwi×§v [{êÙm¿t·PÖ«Í^µÞ+¯*—óŒŒÑ39Pë¥ç.©ò.+´a—£êÔ©‰d¦‹´77¨ëä"?$ãr¹ßhicP×úâyì—×Å€,›] ¶›WÆóÓ‡X˜Pgê¶“8TÞÄ2¶Y¯G_{Ôs(6I qT„dÕp ÌÝ“` nX$PìÞ½%8K‡&¤-àëMd/ðÑcÀôdµÁ÷¡f÷vñ„ÞS´›²ŸçQßši´©Ú¡êÚlµeGw@î㽺Ñ1Zg˜ÑÕ Æ. ÛÒEgmé]Ý«P†d×ÐÕ ;¯ut\vÜmÈDð8ÜÙÙÙ+÷äó¦Kµ‡]KfÆ8¤?ùÉO’ýèG«¶k”(K-/øú׿ž¼êU¯Jßÿþ÷—ÀŠ+ð¦ëtjð– d{Ÿ9sfD6cëe·Ê8rÉ%—ôÈ¿\ôÁÔ3ì¨Ý¢“,hÓnS2jܤ2Ž`Ÿ‰ (=ÜÐÂõI÷¨—h²$ôæ?”Tç%¬yñg¡þ£!ö̲fž- ‘ ÖCe+Ø$9Wèõê¶RT^˦È5<*ïÙ“Ï!²lÚ5:ÏŒÝÚæ)X(#qçw¢­ÙÖ›Úõ2šå¢l€ð’üÍ@굪©i½´ Ž;ýZK•ñÀ]¨…ˆeå¼Åm'°žÜ–U´µæ¼Þlº0a(óÈ;ý~} ÜbÒDxAa Q±11¥D¨xtaJ€7 Ú˜¤ÀÄî„ù[e Éw°Ö~üøñù޹ߗ/VÍ®…b×H•Ï Ë«}1G‰R$X¿d€ªM^ùÊW&¿õ[¿&;ýû¿ÿ{Ôv³í°,x#€}€s`ßÞ&6mÚ4¸eË–‹E_lýЈzŒØÌA?½×,>õ™fÛtI&<éÌTê%n©ó˜¡Jäé` ~<öÌV °d„ÕËÚ-Éã²á4¡Bìž±¶Ó²“EŸg+„@^ˆlÐ œWïÍ6«÷ìÌí˜\Ó_Ü ]£Ùæüƒü`úÙÏ~6‚¶J°mh°-»°´¿¿ßs‘fl›\˜ýØa‰Á¾‚ÀÍë< '‚e¼RzaÛX5‹ò-¨Ó­Eìó^xÔª·æ1gÀÒ#ÄÒY:TÛRó^¬… аÂç²12cáè¶Ð±tMà¼Ñý Þ«3Y âð=pvtt…Pî÷ɑ؟ÓáÝe°kS‰d×¢©²Z:ñþûïÏÖO5 6loûÛÑà­$ë×cÝty©!ºcDlŨèŒOk¸Êèðvå ^ð‚ó¡7K†˜7ö*e¶:]–sdäÒtYêjœG]®ˆµ'1´¾Õå:B:ÔÏU©7È^=Q}ß+Nk]®EÝ~<×iQ¬µf¾<Ûh½^úÜxBàÎ#+ìÿÖfòXåº Žíx®ç»ÓFJé…/|aæÕûË¿ü˪_ÇUÚ°(@?#[ïK_úÙ6&$ÐÍÕ*£E^»]þfQJ-4ävb„R¨mÑ@Ûm ÔrÃ+T«'×;T/`=‹v2 Õʱ“:²ôó¡’&vÑ{eUx<¶-ŠÝq1K Ê44[»@I’‘cì]¤dßÀÔ±|n¡ ‘h€2¸Ef¨(ä½òÙ'E‰ŽÊùN¦ëúuÍ—]‹eµÀ ŒSµ Ö½è‰TmœBµÝÎbÝDOÁ]:" jÝéÓ§G9Ò·gÏžKo¾ùæ+o¹å–$AW´}CÌ-nZ†Å²mÐYìê‚çù˜W:ŠzOƒ€z Ç‹Yöj†zöÁ`6Ðß#B ϳ^âç…ÑÇ­“¿Û«Sjíf¨S‚WíÁ~†.B,·§e<žÏnÚf$  å ìÐJ}©_) ç}ï{_Ú\Œ2w\ƒŠêhíÒ!{»øè±H!Y7Ëé n‹êEhÎ.Õ“DOžPŒöB}áfËî µ«òœ÷˜]x<–móÀW>Å‚[}¾taJívæ.—1#t©°@â@Ø5¼Ù©yVhVjääÉ“Gä:ïÍ"A}_23v­#²kQ¢T¿@hµ£Ö¦Çº Ö ÿˆýß*cL6sû¸¹ï¾û®½í¶Û.¼é¦›2"€KXPœ-øÞBeA,H(ÒÁ8…ÊhXp¤É{ –½Óžˆˆ²v ä)±Ï{ßêdÏý­E½PíoðŽ=TùÁ;¯¹ ûò@®ï{“éD³±lÏyÎsJ¿ýÛ¿%®­Y1  ±mïyÏ{àsf±]æî°a´È…Û';­‹ÅÀ_T6,J.7sÆ.¯}T(!Á£·½ªÍ|½§$ô..æô$/*Ähid TõoÔ‹U» ¼sGvM9‚5¯-ŒvA0–îR°kÈÔdË,< †^¡èÈ »h¤þï’¯;‘Lgë¸Í®uص‰Ö¢DI²LË¿ù›¿É6HU&éöíÛáiAéu€·Ñ|C¿VôW—åíÇߺoß¾«¼5 µ€t~3ô ôº¦À` ݆ô¬W0ÝËlô\›ž{2ÔßÓc˜¬g¤YH[ÀЦjÛJâšaã}ÝöE÷ëÓ÷q½¸‘ÍÀ†]1® ä¢ÛÉ“'ËŽ|w¾'’éÆ¿ºîÚ™dºîZOd×¢D ÖÝ›Þô¦ª<6Ľò•¯LÿüÏÿܶÂÒMè-pÓà öa؆¿üå/;ņ<í/xÁÏ|æ3§²K¡oP®L¾l³.*ðÖxí=ðaCelÖ¥WyÀ‹Ó6È ¯±¬’N®³ vü-¶ø­eß,ÀóHË€ñL™ «hWÈ}ëÙçPèkxŽŽŽ‘ï~2Ÿºt¯aÙ²$˜•$+ ´a'ôá8}×»ÞÅ]Ö°2Ô-j4H»¯££ãÿ]vÙeMX”Œ‘ÂбU–ñÒMsËmàn'm¨Q®žàvXpgã¼Åâæõèoۢݻv¤™¶P.»S õí³ @ǵÐ` ;\Ü"ž »_*P¼1'=öXæ•]ðpww÷n9¾cÊM¢Ù5í ÕtxŒ]‹¥ˆÎ’µ ýˆ5XrÛm·%?ÿùϳºn÷ÜsOšÇ½…bÝ4hÎ_ŸÛ‡®Ã‡ooooßzðàÁ«n½õÖô(Æl#u»¼ P»lmi ¯§Ý¬{)ä±6Æ+ÉäU(êè*'bm Š †æM(QMÛÓ*kj[å¡÷ɼ5X¯\/f‹êM¼Že—÷—¾üå/§!—lm’w¾óÉ?þã?&Û·o·lÛšœiâ¿RåC²{¼48k€±]cÝBÙ¤ET®­?ã5Ôµ“˶§²»4»­ËÖféxiÙ¡Ö!ž+ÔfÙ^«Ü5ñý:ÐÖ* ‚4¿FVÏÑ ªY6Ä®Qc÷ÜâûÑ+ôÑGÍâ äz—²f×B±kjWÕÙµ(QV‡@îsŸK^þò—[Ö­`ÝxÃãrÖ ™ý÷Ýw_‡³k_ð‚\xóÍ7g‰NÛ¶mËâhâð?˜}¸Lá­Í ÛVP{Atp¼­f uª K¡gHoª-ô\Œò<;öø‹ Ýzî]¯{Žw,xN%ˆ õö."%ô±å-ÂÆäºÞŸëÿ>eø?3F'^ûÚצÏþóWÜXq  “ ‡e×¥ë¶Á07åÀmMÚšäBî—Ŷ^€Úõ_|qFƒÓUŠ%û[raxY˜^‡PoÒPüXˆý²€Ï£uV©fâ< ¹gC4¾·Ë±¿‹ç<”ÄÁçô­u‡êA°Æ¢¹,ÿA Æ¦Ï …œ<ùä“Èð’Ýîî<>Ác×B±k‘]‹eõ Y·O}êSé¿øE²nÉÙ±nCðÖšoò»Ž?þà½÷ÞûTgW xk¼úê«3І$l˜7Ô|³Ý=FLoîm–?7À:TÇëm™3k,8òêªYpdm›%¼X²rb±½nA³… yµêŠì¤=çú½lxØô‡T›‘a,[Öý@^y³"ç~ýJÿùÏ'¯xÅ+Òw¿ûÝ¥Gy¤(ÖÍs™2Ö­Yôÿ_ýêWG޹æùÏþSÀºÁEŠÞ¡ÖeŠ2!ØT2ËTÛ .¼x-½á •‰²É`åÕá,jì ð÷B]tïX4£hí”<=2Äs§zmuX„ÇÆsÆnÝÝÝ;ä¹}Ét[‡aÙ¦J|ì£GmK(Ÿþô§“ï~÷»igg§ÎlÌ·¦´áÿú÷ïßß$3€ë‚!vEá.Å-cìBѱnd”4å]T °xñ¾Œº°^Ú…©w*¡ÀUá³.M½s²ŠÀö®ãyÐY¡hº”šN.Ð}Eá¢f3y ìfáEqÜ|0s‡;vl «« ìÚÉ\ ó÷Ø5/vm"²kQ¢œ¬ÛÇ?þñŒuË×»íaê嵬[÷É“'þþ÷¿Ù¡C‡aÚtÕUWeº .SÆÚÂm ð†ú¨ï¦m†eÍô¦9ªbÙ6¯AQ¨f›ý.ÇlíŠNNÓ¶Fƒ³aÁ[ òBÅã= ²µÚ6êcÀs,Ø.¶cÿøøø °1,Û`>&žýìg—ÞûÞ÷®Øù¾bAv@H¿ãŽ;´›F»A·Æ|Ôõöö>pàÀÈD8 ,ÃUŠûŒw³%B¼µ6È Ì÷he Ì,ð³ _OÒPcz[zÃÛµèx¯ü‡›`ƒIµ”ßÉx5/#”¥=»†Av Ÿ‡$Ùé&{öìIÛÛÛ‹"ÜŸƒ4Æ®Yv­Sí¢lìZÆ®Ýzë­%d›¢f”(QV¯@¯ÜsÏ=(œõ0•Mºo¡ ÓAu;ôÐCu»VtÈf°n¯¡½ÀƬ’0Þ°á´íË à·±m^œ±%BåGŠØ6û¸­Ÿf?'·ç}§F-óæÅx‡ÎI¨æ§=~¶Ü[vdttô‘üšöävát2í}™J>Ï*}å+_IVZòÁªmÛo¿=ùñœ~ç;ßÑI õ ¬¸á±Z1Þ÷Ëb¾U.ØF.t"u Þ0à6Eì«_‡&£e´láÝ"¶K¿GÓãv±Y=4ñíâ°‹Þ‚;ýžPV‘®»f“ ¬k”®O²l8¯ºŒÎ/56€5(A(;€5°k¢$å´÷"Ñ ]í’CìšÍ %õ=!ÇQúüç?ŸþéŸþiríµ×FÐ%Ê9"¯~õ«Á¼¥úЇÒø‡ÐI ^¬Û`€uCD{zúô釸Ã^"6ãjo-Ð%Ð[Øô#î·p(‚x7xk«F½hãÆl餢öƒ6KÕ2h¡>×ìÑŠk¶¶¡‘ý?” kÁ›íIʂš¤…"w©&+`kÀ€ÊùFøÌƒÉt#ø39`#˦ÛUM úÄJL>X5  ÔüÓŸþ4mkkÓF¾> ê>ÐGmGGÇ}r{‹\ø¸øl …PAÐÖ ‹]ó¦Y7»uL—7éC­9B…p5Û¦AU¨2´—:mc<¥ ²m.O壓 ,Û`†ÿuéë `Ó®P|2CÑ Q”â„\—²[jK¦‹±k:vm»vÓM7¥2'R´ëaÛ™(Q¢Ì.XÃÕZîc.ÿßøFòGôGéwÞ‰ Ó1ÑuE¥Af´ÂJ&KƒduÝDÙ±cêº]yóÍ7oyîsŸ[³uëÖŒá¹ôÒK³'X8Üg¼À¼5t9êLR«ƒ)E ÎÖæô˜3Êâ±h³¾P)§›×v ².T4â|Ør ^Qᢾ¸¶º³³ó8: %ÓIidØN'Ž[nô»ï¾{ÅÏïÚ¾ó錄þë¿.sªÄø¶~Úx#p»_.þsåõçk €ƒ…±Ú4ˆ£ÛÔ+¢'±Bv'ãì ±yzQèÅë5Ô;5/nAÖ®Pý¼ÎÕ5ØlW°–ú>Ù5$൷·gìÚ#<‚l§å¼îÉXI]?Í®uÎÆ® ,½ï}ïK?ö±M5Ä&ÈŽ%ÊìÏ—¾ô¥jìˆ0/ ]óš×¼&=pà@ªšÏkðæ¹Ky_Ǻ¥²yâ'?ùÉ©ƒ^#Àmà 7ܹH˜ýŽÿàÀºÁe =Gðæm ½RÞfßöãÔåA4è³ïõ2V½ìS› `Ù;MXWÔ Õ֗󘹢~¨Hâøq¾a[Μ9ƒÖ…ÀÖž3É´[4Ë»ž¢ fÈUAÛ X•Ï}îs Äu6i]>êÕ} \µAé÷Ë.êæÑÑÑ,9iø…ápƒ"xƒ nSôÌİM|½ Ó®S;iuýª¶îJý:ÒΡ2%š!ó öêîšmãwé÷ë®¶8.ÿ'»FW(Ù5Þûî»/l‡F}ªHîX»ª»–±kÏ|æ33víE/zQ´¼Q¢ÌS ÛÐãy• AÛ˜n¼ &~yŒuýxêСCHVxê¾}û.ÎsžÓ—)ôlì¼ o¨ëÖ à ýLa;B}E½¸2¯š€ÎìôbCuÎB}°=OfÁì÷Øî:^y(›Dç…ìh¢Â‹-ÓÉ <&5œ[ØÙèÀöX2]5Â6-šÅ±}õ«_MŸþô§¯Š‰\¿ZVä>ðä¿øEzï½÷r1æ`mhÃ%µ]ß###[áFC )À,‹ñbAba´±¾›®óféoõ£'§u[jÀæe–jpVÌI—¥uz4ºÞ9Ùb»¶ì‡fÕÜt¿PJv »!í Åk÷ìÙ“¹Bå¶„D9×óP)_\Ü1õص~]{ï{ß‹¬±)v-J”(Q €[ªÁ›Í. °nY¬›l>÷=üðÃímmmW>ëYϺ èQ>zx@ YÀ ]][ ¢C6ŠX+[ŠIÛ˶…€™×!ԹǾP?R}Ü0óÂ}4Aá……ܳ´¿°Ë°µr.wæí G Ãv*¿íHLâÿàþ`ÕLâUÚp¿ùÍo&/{ÙËJÛ·oWàÌ‚67º=pà€Ü >íâ‹/®ØÀ¢ãâÀ¤H!ó  åB˜´€iieÆÖµpìBðn½89o'f)t¯Ô¹MçÖîO=l¿P‚6»FÆD¼ÊŠe.6óp~˜t°v2¿= °½êU¯J?ûÙÏ®ªÉ[¿š~ Õ·¿ýíD y* ƒÛ™5 Ø(²xvËŽ¨_ÅCCCÍØ-aA1Ó…,€ Ø7€7458&.à1$.ÀuÊ÷뉩©c§Ÿ·õtô¤Ö‹Ó닪BÔ´¥Áµ;”‹‹HlºX.Ëxà|`äÒ E…ÇЯróšký¨£#¿ëd®u¢AŸÖè =«îš|ïTìYÑ(Q¢DY 릻)XÖm@m7$Ó±np™žlkkë@qÙÞ½{/ö³ŸÝŒŽ °!ÐOoo(È àFð†oÜð{l™Îl¡s‹"4¼ ¾u!—©½oãßBql^Q/Oÿ6vÈaýTØ\ØR±½]]]ÉkN+ÀÖá¶e/ÆŸ÷¼ç•¾õ­o•=!VJúÕ¶á·þá¦4<<ÌÄ=›y¿¤Æ™Çd È{nEtÒ¹1aˆöé.%ppÃsgxl¬ñ÷Ã…ÏÀódàØƒ€È[(ºƒl¡6Uv§¢™4¯ ®eÕ,æÁš.çA÷(“ X —` ŠÌ’ :4"`íüÞ£ùv±ºgh—l=9`cm™¡haöâ¿8šœ(Q¢T’uK¬ÛaÝ —P2j}2í2-¡£ÂŽ;N>|x›Ø -7Þxc ó¼1̤ ó"ÓT@^6°¹Å€ÇF·T$Øa¼²·±e[ÚrE]yìë½²SÚîØØ»ƒbm×!V =ÁÀÿ°™p' ¸=*6õÉd:© [6޳$#ñ ³Ó°Ñå‹$Gж òÜç>7ùÚ×¾–¾å-o!n›]¨¥|Õ-äWG޹RЕ²àê°àòcë+ ,@ÖŠaÏ3N52pÈáqL ‚<›þì-(/»4Ø,5®¿Þå„Àšíjû‡ÒM¬û„æôuòÐC%?þxrðàÁqÙU‘ßy8™Ž[UJ¯G6ë e¢ÁTÏP9Ç¥O|âé{ÞóžìœG‰%Ê"±nEyÔØ˜?¶ž¬Þ+ö<ðÀq°n×]wÝæg<ã5즻æ öà nRlrq æ …qo6ÑÍ2A¡d7mGl6[åÀ²{Ôÿ|í j¿ÛVF•0ñ˜>VHƒMaV(l#¼V§NEGùœ¶d:ŒF×a 6|ÅÐÐPúú׿~N@ €y%T¨_­«ðÿø1qÒ·¾õ­ºcB’ø¨n©,–Ý'Nœèx­€“M,ý @f™7‘eìÜ„˜˜0`ÚHÓ•Êø7ÆÀqx}àŠjàXZ7ÆÄÌQ Òtö(“ð[X¤÷±˜XÃŽ` ¿ÊÝ vî܉ŒÐ’€·ò›å ,M¦³BìÁš.ã1Êk‚˜5°kÏzÖ³¢i‰%Êr±nÆmãL¦cÝÞP/EðFWï/~ñ‹Ã{öìÙvýõ×?EÀ[ïÛ»=ŠÍ/À*¼qà0oº/¶v…zÅiÏú!Ò€y%<,øÓ$€Ç¼éÿ½"½0Ò^²v'ìì ìâyØ8ü.üN9WƒrXŠç»?™.ÿt:mºxn¿²çDŸéúÕþßúÖ·fsJ€]¥©³“3ƒÀ-•IµOP»•+dA]*‹­ Ž“€† 虨 ë–± Vbb³¼A™9,LUÀÛ…×]w]Í–-[¦˜7è_7lŽaØÀŒ›Nv£·¯¥§†ì˜Ç²áy»Á×̺0µ{S^÷ÈmW4HÓ-"ׇçq,°k¬*ve\nQêP~þ˜¨FÛA—¨nOÕ—L»D'ÎÀvN€6 ÜÞùÎw–dÒUê7Ÿr ^¦`Ü—q¬¯¯o›L°§Ø¼aaÜðè]€tŒþÇ$ÖŒ‰ i¼e,†fâäôgè]“u}’$“ÆR&ßÁªÒº‹vü\ Ʋ²Àä¹ãò½'rÐ¥‹S2ËŠ`­G±jdÖ¸;bÜZ–h ç§ôgögé'>ñ‰XÆ#J”(ÕÞBšźyàö›ÿ漑Íp—ŒÖ]»v]rÙe—m¾òÊ+›áY`rl ³*a Ÿà8è.¥gFÇJ[/ í>ƒ`N³fºjו6ƒÞͨÙN8$)˜õŠÁc$³&cB@<4GrA/po2]\`­KmøuÜsz.¶s ´AP*å@Þð†7”Ð. §yë~tº• ^ڙȢè±Q@Ì¥²°.jmmmPÓI Xpl¸ÏÚføŸ“^÷ðÔlc æl!\[òšïÚÝioÞj%€Ïx 6ÄÊý òš²;K9‘œãÑ«Ø5¬ÑÊØÁÒ«_ýj4ñMQ˜2J”(QªUпR6þ¥x@Ǻ&3]¦¸õ*ÖY¦¼u‹ÞíݳgÏ!‘‹}ôÑKD6lݺµyÙ]A{l`W„lˆfÛôÐá5:ÌF61©ã¡µm¡·H'­1.MwÑá÷ðx&óø¼aùÿ”Ó±üÜè$A]Š€m »’™îÐñs°s  ‚r ÿ÷ÿ—þáþaòßÿýßI8SH×ça¼c°èš°…Ñ)c€·§ {бõŒwPc¼‚öñsêëú–t³.ÁA—¥mÿ¡[QÙ¦Á\\ \à¤ÑY’„”;;<`ÉmŸ,ºÓòúSù‚á¹7`Mg…²«AO¬MÑÙ×]w]ú©O}*ºB£D‰²"á0?ùÉOÒú§Jïºë®ôÔ©SÚnØÒ }j«[«oMù(‰žm;>)ëŸ|òÉ‹6oÞ|Ñ¥—^Ú‚ìR€7ľÀ1|…  öF22kl|Ž%-¬÷ƶÇÒI Œ{¶É ušÉ#£Æ˜¼<ƒ3•û§ØôŸÎÏ §)*²®Ë@ÀvNJý¹ø£ðù_ÿõ_éG>ò4š·ÀM»Imz÷†d:VAï˜údÒÊÜì?,;‰ ~.@¶IÛ:v à p£‹R»,m{(]'Mïht¦¾o!”MzÐÝp«ú©Èo8#¯=-ŸÑ›ŸÝòeÔk½ °¬õ'3“ ¦Jx èá;ÞñŽôÎ;ïÌ”P”(Q¢¬…¾}ÛÛÞ–¼ò•¯L¿ð…/¤hD.ú4M‰ Ô‘ÔàæŸa7´#øœNÑÃû¶Q6þ ì”èÍ5`ßÙœžqÓ¶ 7ÿ tA›Ž†ð~($‡›¾Ÿ¶…˜TÀÚ¤jr¿O~GfKòßÏ$í¡¡K™›ý.Öt¨±äŒ_[‘ m± ;&çg?ûÙôe/{Yòö·¿½´{÷n›âí-¾ù$[ŸÌ,ªÈEW’ ~F&q‡Œ™Àëem¶QQ«€¸z˲´ÑuJw(㸫²ý@ù(\`X@xœ ‹LSåºvœÜŽËÀâê’ÉŒœQE;{&ûÕΨG¶¾³–¹Aåw–ÞøÆ7¦wß}wV›(J”(QVšÐ•öÅ/~õ@Ó~ô£¥ï}ï{%³ñ×ÀDon×+Ö6ÄÚŒ!ÑéÃbCNÊhjkk[/ ìüõë×oжvÓ¦MuèB§«Юèͽ¯±Þ Øèt ëÂvà>ÃiðAZNŒ¨Áó”Û’\ÿ'M¿¶!lºf'c×è-%ç¨;tE6Lš¯ýë3¶X‚ÝÈk_ûÚôK_úRVE99;ÐÔ–¯Ð»&™rÑ5å ®N&p‡Œ:ùì5}}}­ÂäÖËâj‘EÖ$€¬F3kzÀ¼A¸uD]ÏM/6,B.0€8¹•V]½ò\¯¼Ž;PÔ<™‹©W >ÆîŠØŒ¹ô¦7½)ýà?˜Ä¸µ(Q¢¬&Nûîw¿›þèG?Jî¹çžÒüãý0 e½dÞZxkÊíHäjOàP;´áøñãk`C¬mhmm]ßÒÒ²1ÕLˆcÆ&=7r^=O‚PQze¸Ñ§§FW0È R¹‘Ñ/¯éÅãëK¦ËoØMÿ¨9ý Ĩi°¦Ë@Evm¥¶»îºk)¿R»í®É.<½cÒq o\tõdïä÷ô£iºLò:™ð ²pše´È‚j‘ŵFn›¬5Ém½üQ«S¬m†j ˜”1yl\n‡äfC^‡1dV’„Ëž ™E¦Ak¿bÕ XËb —ÀbÞyçé-·Ü²,ó€|¥4Ž%Ju t \’ž¼ô¥/ÅHï»ï¾D6¨%¹MEÏ{%B´ i5co-xk }¦{``à˜Œúü5ͲÉ_+mÜ®À&w›än¼;u:6šÚXíþdE¹…—Ûa ¹ öoPÆÒ÷š#P³2Ž–uÔzh´‰ìÚJmË$^z7Á “´¾ÕÙ-±I³bÞàê’¢dtçÌVQmþ|=‡,®:Œü>ý¡õò¾’ü;‘NJ)göFÕ‚™ìRRõÜx23Ê6Hî7C5‚ºQ Öð}P P`¿ó;¿“uL@?R[h)„±Q¢D‰²PAÜïßþíßûCïåzÝë^‡Vˆéý÷ßo=76Û¾/·ëƒ$€õâ4äv¢N‘ `½:ºòÇk•AÙ¹­Å©Ë7ý9xƒý˜Èÿ×ݬI ÙÌ7`6ý}ÉÌŽg…Ó`´¶¶¦ì%‚¶¹°n¡º<œ„ŒIЋMÇ)Xæ­A-¦:µÀ0jÔâ®!“V&àIùxêzt¡cÉÙÔµ]d¼4;¡aÖøùÙw„þû¿ÿ{6¢D‰e5²êßýîw/„ÐÀ†à­92-jÿNݶ$3cÞʱ%ùíhnÒ܆ÔЖ”Ù=ul¡í×­m‰fÖBÿeKl7œ$@r”ÚæÜ3Ymvi¿g\`úVÇ)è@S½cª7àŽ·º;os|za…Ú¯L 6’Ìtƒ&3Kœ *FÍ5kã ¢D‰evðV“øÉ ¹ÎmÊmmF‘-i2ì›ouƆÔ*ÛQ°sÖŽ¤ 6^Ö†Œ Ñ m0°éŸÐ›þ8]"h[,ð¦én½à8Ö$3éíf³àÍ‚k0»¥:ÚjœÅæíæì1ZÚzÔ,0˲i6¢vBžË5.°(Q¢D™›™HüÚ ÜÈ7){²¦`”cKê ;’ªãwÀšµ%ÚŽØA[Â÷LW›þÚ–kÑéX…F5ôâón-ëæ1ouÎb«IÎŽ-°;" Ö¼]ÃÎ}½°ÆœPÜ E‰%Jel‰Wfª>×ÇõÆŽ4ûamISÀ–x!8s±#E¶dÔØ‘Ç–h÷çxÜôGж܋ް&™Y&£NíxÔbj4@­Ñ¼¦>ñc껤¢…6–ÌÌõœ~Ì‚4Ž4.°(Q¢DYTð–$3]§µ ¼Y[bíI“cO¬Ë´6Ü<;âyj<–m,`GF“³“â¦?‚¶ª^t:T3gzÖ™…Uo^kš“Zl΢3·:Ë4”%W”(Q¢,­-ÑDÀ˜ÒÿÖŽÔ'3]¢õΨ lþiG´í*Ї/v³o]ŸÑ–DжbܸpzÑÔPWWÔŠâÚf[pE£iqqE‰%Ju¸šÕ V_`GBÉmIâ3mé,¶¤4‹±1jÑ–Dжâ]bž^t5æ~(Û§Æ,6OJI84uTÉ™Q¢D‰¥ºÉ®qdžÔ&ÅŠìHêŒRý°Y¦¤EжêAœÞíè[ͦy»¢¢’‰³Ó‰‹*J”(QV7ˆ«„)²iÜèGЖÉ9^í¸\0U3‡ÏŠ%J”(ÑŽD;RaZöc¨YŽöBZÐæýÚ¢D‰%J”(QªU.¿üòäùÏþ¹ Ú¢D‰%J”(Q¢Ì.µñD‰%J”(Q¢DÐ%J”(Q¢D‰%‚¶(Q¢D‰%J”Ú¢D‰%J”(Q¢DÐ%J”(Q¢D‰%‚¶(Q¢D‰%J”Ú¢D‰%J”(Q¢DÐ%J”(Q¢D‰%‚¶(Q¢D‰%J”Ú¢D‰%J”(Q¢DÐ%J”(Q¢D‰A[”(Q¢D‰%J”Ú¢D‰%J”(Q¢DÐ%J”(Q¢D‰A[”(Q¢D‰%J”Ú¢D‰%J”(Q¢DÐ%J”(Q¢D‰A[”(Q¢D‰%J”Ú¢D‰%J”(Q¢DÐ%J”(Q¢D‰A[”(Q¢D‰%J”Ú¢D‰%J”(Q"h‹%J”(Q¢D‰A[”(Q¢D‰%J”Ú¢D‰%J”(QV“üÓ±¬ÁiOIEND®B`‚yabause-0.9.15/src/cocoa/CMakeLists.txt000644 001750 001750 00000005031 12755623101 021665 0ustar00guillaumeguillaume000000 000000 project(yabause-cocoa) yab_port_start() find_library(AUDIO_LIBRARY AudioUnit) if (NOT AUDIO_LIBRARY) return() endif() set(yabause_cocoa_SOURCES main.m PerCocoa.m YabauseButtonFormatter.m YabauseController.m YabauseGLView.m YabausePrefsController.m vidgcd.c vidgcd.h ) set(yabause_cocoa_XIBS English.lproj/MainMenu) include_directories("${CMAKE_CURRENT_SOURCE_DIR}/..") add_executable(yabause-cocoa MACOSX_BUNDLE ${yabause_cocoa_SOURCES}) target_link_libraries(yabause-cocoa yabause ${YABAUSE_LIBRARIES} ${AUDIO_LIBRARY}) yab_port_stop() set_target_properties(yabause-cocoa PROPERTIES OUTPUT_NAME Yabause) set_target_properties(yabause-cocoa PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/CMake-Info.plist) find_program(IBTOOL ibtool HINTS "/usr/bin" "${OSX_DEVELOPER_ROOT}/usr/bin") if (${IBTOOL} STREQUAL "IBTOOL-NOTFOUND") message(SEND_ERROR "ibtool can not be found and is needed to compile the .xib files. It should have been installed with the Apple developer tools. The default system paths were searched in addition to ${OSX_DEVELOPER_ROOT}/usr/bin") endif() add_custom_command( TARGET yabause-cocoa PRE_BUILD COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/Yabause.app/Contents/MacOS) add_custom_command( TARGET yabause-cocoa PRE_BUILD COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/Yabause.app/Contents/Resources/English.lproj) foreach(xib ${yabause_cocoa_XIBS}) add_custom_command( TARGET yabause-cocoa POST_BUILD COMMAND ${IBTOOL} --errors --warnings --notices --output-format human-readable-text --compile ${CMAKE_CURRENT_BINARY_DIR}/Yabause.app/Contents/Resources/${xib}.nib ${CMAKE_CURRENT_SOURCE_DIR}/${xib}.xib COMMENT "Compiling ${CMAKE_CURRENT_SOURCE_DIR}/${xib}.xib") endforeach() add_custom_command( TARGET yabause-cocoa POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/Yabause.icns ${CMAKE_CURRENT_BINARY_DIR}/Yabause.app/Contents/Resources) add_custom_command( TARGET yabause-cocoa POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/resources/controller.png ${CMAKE_CURRENT_BINARY_DIR}/Yabause.app/Contents/Resources) install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/Yabause.app/" DESTINATION "Yabause.app" USE_SOURCE_PERMISSIONS) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../../AUTHORS DESTINATION ".") install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../../ChangeLog DESTINATION ".") install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../../COPYING DESTINATION ".") install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../../README DESTINATION ".") yabause-0.9.15/src/cocoa/vidgcd.c000644 001750 001750 00000271227 12755623101 020545 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2004 Guillaume Duhamel Copyright 2004-2008 Theo Berkau Copyright 2006 Fabien Coulon Copyright 2010 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "vidgcd.h" #include "vidshared.h" #include "debug.h" #include "vdp2.h" #ifdef HAVE_LIBGL #define USE_OPENGL #endif #ifdef USE_OPENGL #include "ygl.h" #endif #include "yui.h" #include #include #if defined WORDS_BIGENDIAN static INLINE u32 COLSAT2YAB16(int priority,u32 temp) { return (priority | (temp & 0x7C00) << 1 | (temp & 0x3E0) << 14 | (temp & 0x1F) << 27); } static INLINE u32 COLSAT2YAB32(int priority,u32 temp) { return (((temp & 0xFF) << 24) | ((temp & 0xFF00) << 8) | ((temp & 0xFF0000) >> 8) | priority); } static INLINE u32 COLSAT2YAB32_2(int priority,u32 temp1,u32 temp2) { return (((temp2 & 0xFF) << 24) | ((temp2 & 0xFF00) << 8) | ((temp1 & 0xFF) << 8) | priority); } static INLINE u32 COLSATSTRIPPRIORITY(u32 pixel) { return (pixel | 0xFF); } #else static INLINE u32 COLSAT2YAB16(int priority,u32 temp) { return (priority << 24 | (temp & 0x1F) << 3 | (temp & 0x3E0) << 6 | (temp & 0x7C00) << 9); } static INLINE u32 COLSAT2YAB32(int priority, u32 temp) { return (priority << 24 | (temp & 0xFF0000) | (temp & 0xFF00) | (temp & 0xFF)); } static INLINE u32 COLSAT2YAB32_2(int priority,u32 temp1,u32 temp2) { return (priority << 24 | ((temp1 & 0xFF) << 16) | (temp2 & 0xFF00) | (temp2 & 0xFF)); } static INLINE u32 COLSATSTRIPPRIORITY(u32 pixel) { return (0xFF000000 | pixel); } #endif #define COLOR_ADDt(b) (b>0xFF?0xFF:(b<0?0:b)) #define COLOR_ADDb(b1,b2) COLOR_ADDt((signed) (b1) + (b2)) #ifdef WORDS_BIGENDIAN #define COLOR_ADD(l,r,g,b) (COLOR_ADDb(l & 0xFF, r) << 24) | \ (COLOR_ADDb((l >> 8) & 0xFF, g) << 16) | \ (COLOR_ADDb((l >> 16) & 0xFF, b) << 8) | \ ((l >> 24) & 0xFF) #else #define COLOR_ADD(l,r,g,b) COLOR_ADDb((l & 0xFF), r) | \ (COLOR_ADDb((l >> 8) & 0xFF, g) << 8) | \ (COLOR_ADDb((l >> 16) & 0xFF, b) << 16) | \ (l & 0xFF000000) #endif static void PushUserClipping(int mode); static void PopUserClipping(void); int VIDGCDInit(void); void VIDGCDDeInit(void); void VIDGCDResize(unsigned int, unsigned int, int); int VIDGCDIsFullscreen(void); int VIDGCDVdp1Reset(void); void VIDGCDVdp1DrawStart(void); void VIDGCDVdp1DrawEnd(void); void VIDGCDVdp1NormalSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDGCDVdp1ScaledSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDGCDVdp1DistortedSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDGCDVdp1PolygonDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDGCDVdp1PolylineDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDGCDVdp1LineDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDGCDVdp1UserClipping(u8 * ram, Vdp1 * regs); void VIDGCDVdp1SystemClipping(u8 * ram, Vdp1 * regs); void VIDGCDVdp1LocalCoordinate(u8 * ram, Vdp1 * regs); int VIDGCDVdp2Reset(void); void VIDGCDVdp2DrawStart(void); void VIDGCDVdp2DrawEnd(void); void VIDGCDVdp2DrawScreens(void); void VIDGCDVdp2SetResolution(u16 TVMD); void FASTCALL VIDGCDVdp2SetPriorityNBG0(int priority); void FASTCALL VIDGCDVdp2SetPriorityNBG1(int priority); void FASTCALL VIDGCDVdp2SetPriorityNBG2(int priority); void FASTCALL VIDGCDVdp2SetPriorityNBG3(int priority); void FASTCALL VIDGCDVdp2SetPriorityRBG0(int priority); void VIDGCDGetGlSize(int *width, int *height); void VIDGCDVdp1SwapFrameBuffer(void); void VIDGCDVdp1EraseFrameBuffer(void); VideoInterface_struct VIDGCD = { VIDCORE_GCD, "Grand Central Dispatch Software Video Interface", VIDGCDInit, VIDGCDDeInit, VIDGCDResize, VIDGCDIsFullscreen, VIDGCDVdp1Reset, VIDGCDVdp1DrawStart, VIDGCDVdp1DrawEnd, VIDGCDVdp1NormalSpriteDraw, VIDGCDVdp1ScaledSpriteDraw, VIDGCDVdp1DistortedSpriteDraw, //for the actual hardware, polygons are essentially identical to distorted sprites //the actual hardware draws using diagonal lines, which is why using half-transparent processing //on distorted sprites and polygons is not recommended since the hardware overdraws to prevent gaps //thus, with half-transparent processing some pixels will be processed more than once, producing moire patterns in the drawn shapes VIDGCDVdp1DistortedSpriteDraw, VIDGCDVdp1PolylineDraw, VIDGCDVdp1LineDraw, VIDGCDVdp1UserClipping, VIDGCDVdp1SystemClipping, VIDGCDVdp1LocalCoordinate, NULL, NULL, VIDGCDVdp2Reset, VIDGCDVdp2DrawStart, VIDGCDVdp2DrawEnd, VIDGCDVdp2DrawScreens, VIDGCDGetGlSize, }; static u32 *dispbuffer=NULL; static u8 *vdp1framebuffer[2]= { NULL, NULL }; static u8 *vdp1frontframebuffer; static u8 *vdp1backframebuffer; static u32 *vdp2framebuffer=NULL; static int vdp1width; static int vdp1height; static int vdp1clipxstart; static int vdp1clipxend; static int vdp1clipystart; static int vdp1clipyend; static int vdp1pixelsize; static int vdp1spritetype; int vdp2width; int vdp2height; static int nbg0priority=0; static int nbg1priority=0; static int nbg2priority=0; static int nbg3priority=0; static int rbg0priority=0; #ifdef USE_OPENGL static int outputwidth; static int outputheight; #endif static int resxratio; static int resyratio; typedef struct { s16 x; s16 y; } vdp1vertex; typedef struct { int pagepixelwh, pagepixelwh_bits, pagepixelwh_mask; int planepixelwidth, planepixelwidth_bits, planepixelwidth_mask; int planepixelheight, planepixelheight_bits, planepixelheight_mask; int screenwidth; int screenheight; int oldcellx, oldcelly, oldcellcheck; int xmask, ymask; u32 planetbl[16]; } screeninfo_struct; struct { vdp2draw_struct info; u8 prioritytable[8]; u32 coloroffset; int islinewindow; clipping_struct clip[2]; u32 linewnd0addr, linewnd1addr; int priosused[8]; } vdp1draw_info; ////////////////////////////////////////////////////////////////////////////// static INLINE void vdp2putpixel32(s32 x, s32 y, u32 color, int priority) { vdp2framebuffer[(y * vdp2width) + x] = COLSAT2YAB32(priority, color); } ////////////////////////////////////////////////////////////////////////////// static INLINE u8 Vdp2GetPixelPriority(u32 pixel) { #if defined WORDS_BIGENDIAN return pixel; #else return pixel >> 24; #endif } ////////////////////////////////////////////////////////////////////////////// static INLINE void puthline16(s32 x, s32 y, s32 width, u16 color, int priority) { u32 *buffer = vdp2framebuffer + (y * vdp2width) + x; u32 dot=COLSAT2YAB16(priority, color); int i; for (i = 0; i < width; i++) buffer[i] = dot; } ////////////////////////////////////////////////////////////////////////////// static INLINE u32 FASTCALL Vdp2ColorRamGetColor(u32 addr) { switch(Vdp2Internal.ColorMode) { case 0: { u32 tmp; addr <<= 1; tmp = T2ReadWord(Vdp2ColorRam, addr & 0xFFF); return (((tmp & 0x1F) << 3) | ((tmp & 0x03E0) << 6) | ((tmp & 0x7C00) << 9)); } case 1: { u32 tmp; addr <<= 1; tmp = T2ReadWord(Vdp2ColorRam, addr & 0xFFF); return (((tmp & 0x1F) << 3) | ((tmp & 0x03E0) << 6) | ((tmp & 0x7C00) << 9)); } case 2: { addr <<= 2; return T2ReadLong(Vdp2ColorRam, addr & 0xFFF); } default: break; } return 0; } ////////////////////////////////////////////////////////////////////////////// static INLINE void Vdp2PatternAddr(vdp2draw_struct *info) { switch(info->patterndatasize) { case 1: { u16 tmp = T1ReadWord(Vdp2Ram, info->addr); info->addr += 2; info->specialfunction = (info->supplementdata >> 9) & 0x1; switch(info->colornumber) { case 0: // in 16 colors info->paladdr = ((tmp & 0xF000) >> 8) | ((info->supplementdata & 0xE0) << 3); break; default: // not in 16 colors info->paladdr = (tmp & 0x7000) >> 4; break; } switch(info->auxmode) { case 0: info->flipfunction = (tmp & 0xC00) >> 10; switch(info->patternwh) { case 1: info->charaddr = (tmp & 0x3FF) | ((info->supplementdata & 0x1F) << 10); break; case 2: info->charaddr = ((tmp & 0x3FF) << 2) | (info->supplementdata & 0x3) | ((info->supplementdata & 0x1C) << 10); break; } break; case 1: info->flipfunction = 0; switch(info->patternwh) { case 1: info->charaddr = (tmp & 0xFFF) | ((info->supplementdata & 0x1C) << 10); break; case 2: info->charaddr = ((tmp & 0xFFF) << 2) | (info->supplementdata & 0x3) | ((info->supplementdata & 0x10) << 10); break; } break; } break; } case 2: { u16 tmp1 = T1ReadWord(Vdp2Ram, info->addr); u16 tmp2 = T1ReadWord(Vdp2Ram, info->addr+2); info->addr += 4; info->charaddr = tmp2 & 0x7FFF; info->flipfunction = (tmp1 & 0xC000) >> 14; info->paladdr = (tmp1 & 0x7F) << 4; info->specialfunction = (tmp1 & 0x2000) >> 13; break; } } if (!(Vdp2Regs->VRSIZE & 0x8000)) info->charaddr &= 0x3FFF; info->charaddr *= 0x20; // selon Runik if (info->specialprimode == 1) { info->priority = (info->priority & 0xE) | (info->specialfunction & 1); } } ////////////////////////////////////////////////////////////////////////////// static INLINE u32 FASTCALL DoNothing(UNUSED void *info, u32 pixel) { return pixel; } ////////////////////////////////////////////////////////////////////////////// static INLINE u32 FASTCALL DoColorOffset(void *info, u32 pixel) { return COLOR_ADD(pixel, ((vdp2draw_struct *)info)->cor, ((vdp2draw_struct *)info)->cog, ((vdp2draw_struct *)info)->cob); } ////////////////////////////////////////////////////////////////////////////// static INLINE u32 FASTCALL DoColorCalc(void *info, u32 pixel) { #if 0 u8 oldr, oldg, oldb; u8 r, g, b; u32 oldpixel = 0x00FFFFFF; // fix me static int topratio[32] = { 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; static int bottomratio[32] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 }; // separate color components for top and second pixel r = (pixel & 0xFF) * topratio[((vdp2draw_struct *)info)->alpha] >> 5; g = ((pixel >> 8) & 0xFF) * topratio[((vdp2draw_struct *)info)->alpha] >> 5; b = ((pixel >> 16) & 0xFF) * topratio[((vdp2draw_struct *)info)->alpha] >> 5; #ifdef WORDS_BIGENDIAN oldr = ((oldpixel >> 24) & 0xFF) * bottomratio[((vdp2draw_struct *)info)->alpha] >> 5; oldg = ((oldpixel >> 16) & 0xFF) * bottomratio[((vdp2draw_struct *)info)->alpha] >> 5; oldb = ((oldpixel >> 8) & 0xFF) * bottomratio[((vdp2draw_struct *)info)->alpha] >> 5; #else oldr = (oldpixel & 0xFF) * bottomratio[((vdp2draw_struct *)info)->alpha] >> 5; oldg = ((oldpixel >> 8) & 0xFF) * bottomratio[((vdp2draw_struct *)info)->alpha] >> 5; oldb = ((oldpixel >> 16) & 0xFF) * bottomratio[((vdp2draw_struct *)info)->alpha] >> 5; #endif // add color components and reform the pixel pixel = ((b + oldb) << 16) | ((g + oldg) << 8) | (r + oldr); #endif return pixel; } ////////////////////////////////////////////////////////////////////////////// static INLINE u32 FASTCALL DoColorCalcWithColorOffset(void *info, u32 pixel) { pixel = DoColorCalc(info, pixel); return COLOR_ADD(pixel, ((vdp2draw_struct *)info)->cor, ((vdp2draw_struct *)info)->cog, ((vdp2draw_struct *)info)->cob); } ////////////////////////////////////////////////////////////////////////////// static INLINE void ReadVdp2ColorOffset(vdp2draw_struct *info, int clofmask, int ccmask) { if (Vdp2Regs->CLOFEN & clofmask) { // color offset enable if (Vdp2Regs->CLOFSL & clofmask) { // color offset B info->cor = Vdp2Regs->COBR & 0xFF; if (Vdp2Regs->COBR & 0x100) info->cor |= 0xFFFFFF00; info->cog = Vdp2Regs->COBG & 0xFF; if (Vdp2Regs->COBG & 0x100) info->cog |= 0xFFFFFF00; info->cob = Vdp2Regs->COBB & 0xFF; if (Vdp2Regs->COBB & 0x100) info->cob |= 0xFFFFFF00; } else { // color offset A info->cor = Vdp2Regs->COAR & 0xFF; if (Vdp2Regs->COAR & 0x100) info->cor |= 0xFFFFFF00; info->cog = Vdp2Regs->COAG & 0xFF; if (Vdp2Regs->COAG & 0x100) info->cog |= 0xFFFFFF00; info->cob = Vdp2Regs->COAB & 0xFF; if (Vdp2Regs->COAB & 0x100) info->cob |= 0xFFFFFF00; } if (info->cor == 0 && info->cog == 0 && info->cob == 0) { if (Vdp2Regs->CCCTL & ccmask) info->PostPixelFetchCalc = &DoColorCalc; else info->PostPixelFetchCalc = &DoNothing; } else { if (Vdp2Regs->CCCTL & ccmask) info->PostPixelFetchCalc = &DoColorCalcWithColorOffset; else info->PostPixelFetchCalc = &DoColorOffset; } } else // color offset disable { if (Vdp2Regs->CCCTL & ccmask) info->PostPixelFetchCalc = &DoColorCalc; else info->PostPixelFetchCalc = &DoNothing; } } ////////////////////////////////////////////////////////////////////////////// static INLINE int Vdp2FetchPixel(vdp2draw_struct *info, int x, int y, u32 *color) { u32 dot; switch(info->colornumber) { case 0: // 4 BPP dot = T1ReadByte(Vdp2Ram, ((info->charaddr + ((y * info->cellw) + x) / 2) & 0x7FFFF)); if (!(x & 0x1)) dot >>= 4; if (!(dot & 0xF) && info->transparencyenable) return 0; else { *color = Vdp2ColorRamGetColor(info->coloroffset + (info->paladdr | (dot & 0xF))); return 1; } case 1: // 8 BPP dot = T1ReadByte(Vdp2Ram, ((info->charaddr + (y * info->cellw) + x) & 0x7FFFF)); if (!(dot & 0xFF) && info->transparencyenable) return 0; else { *color = Vdp2ColorRamGetColor(info->coloroffset + (info->paladdr | (dot & 0xFF))); return 1; } case 2: // 16 BPP(palette) dot = T1ReadWord(Vdp2Ram, ((info->charaddr + ((y * info->cellw) + x) * 2) & 0x7FFFF)); if ((dot == 0) && info->transparencyenable) return 0; else { *color = Vdp2ColorRamGetColor(info->coloroffset + dot); return 1; } case 3: // 16 BPP(RGB) dot = T1ReadWord(Vdp2Ram, ((info->charaddr + ((y * info->cellw) + x) * 2) & 0x7FFFF)); if (!(dot & 0x8000) && info->transparencyenable) return 0; else { *color = COLSAT2YAB16(0, dot); return 1; } case 4: // 32 BPP dot = T1ReadLong(Vdp2Ram, ((info->charaddr + ((y * info->cellw) + x) * 4) & 0x7FFFF)); if (!(dot & 0x80000000) && info->transparencyenable) return 0; else { *color = COLSAT2YAB32(0, dot); return 1; } default: return 0; } } ////////////////////////////////////////////////////////////////////////////// static INLINE int TestWindow(int wctl, int enablemask, int inoutmask, clipping_struct *clip, int x, int y) { if (wctl & enablemask) { if (wctl & inoutmask) { // Draw inside of window if (x < clip->xstart || x > clip->xend || y < clip->ystart || y > clip->yend) return 0; } else { // Draw outside of window if (x >= clip->xstart && x <= clip->xend && y >= clip->ystart && y <= clip->yend) return 0; //it seems to overflow vertically on hardware if(clip->yend > vdp2height && (x >= clip->xstart && x <= clip->xend )) return 0; } } return 1; } ////////////////////////////////////////////////////////////////////////////// static INLINE void GeneratePlaneAddrTable(vdp2draw_struct *info, u32 *planetbl) { int i; for (i = 0; i < (info->mapwh*info->mapwh); i++) { info->PlaneAddr(info, i, Vdp2Regs); planetbl[i] = info->addr; } } ////////////////////////////////////////////////////////////////////////////// static INLINE void FASTCALL Vdp2MapCalcXY(vdp2draw_struct *info, int *x, int *y, screeninfo_struct *sinfo) { int planenum; const int pagesize_bits=info->pagewh_bits*2; const int cellwh=(2 + info->patternwh); const int check = ((y[0] >> cellwh) << 16) | (x[0] >> cellwh); //if ((x[0] >> cellwh) != sinfo->oldcellx || (y[0] >> cellwh) != sinfo->oldcelly) if(check != sinfo->oldcellcheck) { sinfo->oldcellx = x[0] >> cellwh; sinfo->oldcelly = y[0] >> cellwh; sinfo->oldcellcheck = (sinfo->oldcelly << 16) | sinfo->oldcellx; // Calculate which plane we're dealing with planenum = ((y[0] >> sinfo->planepixelheight_bits) * info->mapwh) + (x[0] >> sinfo->planepixelwidth_bits); x[0] = (x[0] & sinfo->planepixelwidth_mask); y[0] = (y[0] & sinfo->planepixelheight_mask); // Fetch and decode pattern name data info->addr = sinfo->planetbl[planenum]; // Figure out which page it's on(if plane size is not 1x1) info->addr += (( ((y[0] >> sinfo->pagepixelwh_bits) << pagesize_bits) << info->planew_bits) + ( (x[0] >> sinfo->pagepixelwh_bits) << pagesize_bits) + (((y[0] & sinfo->pagepixelwh_mask) >> cellwh) << info->pagewh_bits) + ((x[0] & sinfo->pagepixelwh_mask) >> cellwh)) << (info->patterndatasize_bits+1); Vdp2PatternAddr(info); // Heh, this could be optimized } // Figure out which pixel in the tile we want if (info->patternwh == 1) { x[0] &= 8-1; y[0] &= 8-1; switch(info->flipfunction & 0x3) { case 0: //none break; case 1: //horizontal flip x[0] = 8 - 1 - x[0]; break; case 2: // vertical flip y[0] = 8 - 1 - y[0]; break; case 3: //flip both x[0] = 8 - 1 - x[0]; y[0] = 8 - 1 - y[0]; break; } } else { if (info->flipfunction) { y[0] &= 16 - 1; if (info->flipfunction & 0x2) { if (!(y[0] & 8)) y[0] = 8 - 1 - y[0] + 16; else y[0] = 16 - 1 - y[0]; } else if (y[0] & 8) y[0] += 8; if (info->flipfunction & 0x1) { if (!(x[0] & 8)) y[0] += 8; x[0] &= 8-1; x[0] = 8 - 1 - x[0]; } else if (x[0] & 8) { y[0] += 8; x[0] &= 8-1; } else x[0] &= 8-1; } else { y[0] &= 16 - 1; if (y[0] & 8) y[0] += 8; if (x[0] & 8) y[0] += 8; x[0] &= 8-1; } } } ////////////////////////////////////////////////////////////////////////////// static INLINE void SetupScreenVars(vdp2draw_struct *info, screeninfo_struct *sinfo) { if (!info->isbitmap) { sinfo->pagepixelwh=64*8; sinfo->pagepixelwh_bits = 9; sinfo->pagepixelwh_mask = 511; sinfo->planepixelwidth=info->planew*sinfo->pagepixelwh; sinfo->planepixelwidth_bits = 8+info->planew; sinfo->planepixelwidth_mask = (1<<(sinfo->planepixelwidth_bits))-1; sinfo->planepixelheight=info->planeh*sinfo->pagepixelwh; sinfo->planepixelheight_bits = 8+info->planeh; sinfo->planepixelheight_mask = (1<<(sinfo->planepixelheight_bits))-1; sinfo->screenwidth=info->mapwh*sinfo->planepixelwidth; sinfo->screenheight=info->mapwh*sinfo->planepixelheight; sinfo->oldcellx=-1; sinfo->oldcelly=-1; sinfo->xmask = sinfo->screenwidth-1; sinfo->ymask = sinfo->screenheight-1; GeneratePlaneAddrTable(info, sinfo->planetbl); } else { sinfo->pagepixelwh = 0; sinfo->pagepixelwh_bits = 0; sinfo->pagepixelwh_mask = 0; sinfo->planepixelwidth=0; sinfo->planepixelwidth_bits=0; sinfo->planepixelwidth_mask=0; sinfo->planepixelheight=0; sinfo->planepixelheight_bits=0; sinfo->planepixelheight_mask=0; sinfo->screenwidth=0; sinfo->screenheight=0; sinfo->oldcellx=0; sinfo->oldcelly=0; sinfo->oldcellcheck=0; sinfo->xmask = info->cellw-1; sinfo->ymask = info->cellh-1; } } ////////////////////////////////////////////////////////////////////////////// /* FIXME: This function will not work on Big Endian systems. Since its only here in vidgcd, and the only thing that this vidcore will work on right now is Mac OS X 10.6 (which is only available for Little Endian systems), its ok for the time being... */ static INLINE u32 FASTCALL Vdp2Blend(vdp2draw_struct *info, u32 src, u32 dst) { u32 alpha, s1, s2, d1, d2, o1, o2, pri; pri = Vdp2GetPixelPriority(dst); /* If we're not doing color calculation on this plane, then there's no need to do any blending... */ if(info->PostPixelFetchCalc != &DoColorCalc && info->PostPixelFetchCalc != &DoColorCalcWithColorOffset) { /* If the old pixel is of higher priority, use it. */ if(pri > info->priority) { return dst; } return src; } if(pri < info->priority) { pri = info->priority; } alpha = 255 - (((info->alpha) << 3) + 0x07); /* Magic alpha blending! */ s1 = src & 0x00FF00FF; s2 = src & 0x0000FF00; d1 = dst & 0x00FF00FF; d2 = dst & 0x0000FF00; o1 = (d1 + (((s1 - d1) * alpha) >> 8)) & 0x00FF00FF; o2 = (d2 + (((s2 - d2) * alpha) >> 8)) & 0x0000FF00; return o1 | o2 | (pri << 24); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL GCDVdp2DrawScroll(vdp2draw_struct *_info, u32 *_textdata, int width, int height) { int i, j; clipping_struct _clip[2], _clip1, _clip2; u32 _linewnd0addr, _linewnd1addr; screeninfo_struct _sinfo; int scrollx, scrolly; int *mosaic_y, *mosaic_x; int linescrollmult = (_info->islinescroll & 1) + ((_info->islinescroll & 2) >> 1) + ((_info->islinescroll & 4) >> 2); _info->coordincx *= (float)resxratio; _info->coordincy *= (float)resyratio; SetupScreenVars(_info, &_sinfo); scrollx = _info->x; scrolly = _info->y; _clip[0].xstart = _clip[0].ystart = _clip[0].xend = _clip[0].yend = 0; _clip[1].xstart = _clip[1].ystart = _clip[1].xend = _clip[1].yend = 0; ReadWindowData(_info->wctl, _clip, Vdp2Regs); _clip1 = _clip[0]; _clip2 = _clip[1]; _linewnd0addr = _linewnd1addr = 0; ReadLineWindowData(&_info->islinewindow, _info->wctl, &_linewnd0addr, &_linewnd1addr, Vdp2Regs); { static int tables_initialized = 0; static int mosaic_table[16][1024]; if(!tables_initialized) { tables_initialized = 1; for(i=0;i<16;i++) { int m = i+1; for(j=0;j<1024;j++) mosaic_table[i][j] = j/m*m; } } mosaic_x = mosaic_table[_info->mosaicxmask-1]; mosaic_y = mosaic_table[_info->mosaicymask-1]; } dispatch_apply(height, dispatch_get_global_queue(2, 0), ^(size_t j) { int x, y, i; u32 *textdata = _textdata + (j * width); u32 linewnd0addr = _linewnd0addr, linewnd1addr = _linewnd1addr; screeninfo_struct sinfo = _sinfo; clipping_struct clip[2] = { _clip1, _clip2 }; vdp2draw_struct inf = *_info; vdp2draw_struct *info = &inf; int Y; int linescrollx = 0; // if line window is enabled, adjust clipping values if(info->islinewindow) { // Fetch new xstart and xend values from table if (info->islinewindow & 0x1) { // Window 0 linewnd0addr = _linewnd0addr + j * 4; clip[0].xstart = (T1ReadWord(Vdp2Ram, linewnd0addr) & 0x3FF) >> 1; // fix me linewnd0addr += 2; clip[0].xend = (T1ReadWord(Vdp2Ram, linewnd0addr) & 0x3FF) >> 1; // fix me } if (info->islinewindow & 0x2) { // Window 1 linewnd1addr = _linewnd1addr + j * 4; clip[1].xstart = (T1ReadWord(Vdp2Ram, linewnd1addr) & 0x3FF) >> 1; // fix me linewnd1addr += 2; clip[1].xend = (T1ReadWord(Vdp2Ram, linewnd1addr) & 0x3FF) >> 1; // fix me } } // precalculate the coordinate for the line(it's faster) and do line // scroll if (info->islinescroll) { /* Figure out where we actually are in the line scroll table. */ info->linescrolltbl += linescrollmult * (j << 2); if (info->islinescroll & 0x1) { linescrollx = (T1ReadLong(Vdp2Ram, info->linescrolltbl) >> 16) & 0x7FF; info->linescrolltbl += 4; } if (info->islinescroll & 0x2) { info->y = (T1ReadWord(Vdp2Ram, info->linescrolltbl) & 0x7FF) + scrolly; info->linescrolltbl += 4; y = info->y; } else //y = info->y+((int)(info->coordincy *(float)(info->mosaicymask > 1 ? (j / info->mosaicymask * info->mosaicymask) : j))); y = info->y + info->coordincy*mosaic_y[j]; if (info->islinescroll & 0x4) { info->coordincx = (T1ReadLong(Vdp2Ram, info->linescrolltbl) & 0x7FF00) / (float)65536.0; info->linescrolltbl += 4; } } else //y = info->y+((int)(info->coordincy *(float)(info->mosaicymask > 1 ? (j / info->mosaicymask * info->mosaicymask) : j))); y = info->y + info->coordincy * mosaic_y[j]; y &= sinfo.ymask; if (info->isverticalscroll) { // this is *wrong*, vertical scroll use a different value per cell // info->verticalscrolltbl should be incremented by info->verticalscrollinc // each time there's a cell change and reseted at the end of the line... // or something like that :) y += T1ReadLong(Vdp2Ram, info->verticalscrolltbl) >> 16; y &= 0x1FF; } Y=y; for (i = 0; i < width; i++) { u32 color; // See if screen position is clipped, if it isn't, continue // AND window logic if(!TestWindow(info->wctl, 0x2, 0x1, &clip[0], i, j) && !TestWindow(info->wctl, 0x8, 0x4, &clip[1], i, j) && (info->wctl & 0x80) == 0x80) { textdata++; continue; } //OR window logic else if ((info->wctl & 0x80) == 0) { if (!TestWindow(info->wctl, 0x2, 0x1, &clip[0], i, j)) { textdata++; continue; } // Window 1 if (!TestWindow(info->wctl, 0x8, 0x4, &clip[1], i,j)) { textdata++; continue; } } //x = info->x+((int)(info->coordincx*(float)((info->mosaicxmask > 1) ? (i / info->mosaicxmask * info->mosaicxmask) : i))); x = info->x + mosaic_x[i]*info->coordincx; x &= sinfo.xmask; if (linescrollx) { x += linescrollx; x &= 0x3FF; } if (!info->isbitmap) { // Tile y=Y; // need to calculate this without history! Vdp2MapCalcXY(info, &x, &y, &sinfo); } // If priority of screen is less than current top pixel and per // pixel priority isn't used, skip it #ifndef CRAB_REWRITE if (Vdp2GetPixelPriority(textdata[0]) > info->priority) { textdata++; continue; } #endif // Fetch Pixel, if it isn't transparent, continue if (!Vdp2FetchPixel(info, x, y, &color)) { textdata++; continue; } // check special priority somewhere here // Apply color offset and color calculation/special color calculation // and then continue. // We almost need to know well ahead of time what the top // and second pixel is in order to work this. #ifndef CRAB_REWRITE textdata[0] = COLSAT2YAB32(info->priority, info->PostPixelFetchCalc(info, color)); textdata++; #else color = COLSAT2YAB32(info->priority, info->PostPixelFetchCalc(info, color)); *textdata++ = Vdp2Blend(info, color, *textdata); #endif } }); } ////////////////////////////////////////////////////////////////////////////// static void SetupRotationInfo(vdp2draw_struct *info, vdp2rotationparameterfp_struct *p) { if (info->rotatenum == 0) { Vdp2ReadRotationTableFP(0, p, Vdp2Regs, Vdp2Ram); info->PlaneAddr = (void FASTCALL (*)(void *, int, Vdp2*))&Vdp2ParameterAPlaneAddr; } else { Vdp2ReadRotationTableFP(1, &p[1], Vdp2Regs, Vdp2Ram); info->PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2ParameterBPlaneAddr; } } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL Vdp2DrawRotationFP(vdp2draw_struct *info, vdp2rotationparameterfp_struct *parameter) { int i, j; int x, y; screeninfo_struct sinfo; vdp2rotationparameterfp_struct *p=¶meter[info->rotatenum]; SetupRotationInfo(info, parameter); if (!p->coefenab) { fixed32 xmul, ymul, C, F; // Since coefficients aren't being used, we can simplify the drawing process if (IsScreenRotatedFP(p)) { // No rotation info->x = touint(mulfixed(p->kx, (p->Xst - p->Px)) + p->Px + p->Mx); info->y = touint(mulfixed(p->ky, (p->Yst - p->Py)) + p->Py + p->My); info->coordincx = tofloat(p->kx); info->coordincy = tofloat(p->ky); } else { u32 *textdata=vdp2framebuffer; GenerateRotatedVarFP(p, &xmul, &ymul, &C, &F); // Do simple rotation CalculateRotationValuesFP(p); SetupScreenVars(info, &sinfo); for (j = 0; j < vdp2height; j++) { for (i = 0; i < vdp2width; i++) { u32 color; x = GenerateRotatedXPosFP(p, i, xmul, ymul, C) & sinfo.xmask; y = GenerateRotatedYPosFP(p, i, xmul, ymul, F) & sinfo.ymask; xmul += p->deltaXst; // Convert coordinates into graphics if (!info->isbitmap) { // Tile Vdp2MapCalcXY(info, &x, &y, &sinfo); } // If priority of screen is less than current top pixel and per // pixel priority isn't used, skip it if (Vdp2GetPixelPriority(textdata[0]) > info->priority) { textdata++; continue; } // Fetch pixel if (!Vdp2FetchPixel(info, x, y, &color)) { textdata++; continue; } textdata[0] = COLSAT2YAB32(info->priority, info->PostPixelFetchCalc(info, color)); textdata++; } ymul += p->deltaYst; } return; } } else { fixed32 xmul, ymul, C, F; fixed32 coefx, coefy; u32 *textdata=vdp2framebuffer; GenerateRotatedVarFP(p, &xmul, &ymul, &C, &F); // Rotation using Coefficient Tables(now this stuff just gets wacky. It // has to be done in software, no exceptions) CalculateRotationValuesFP(p); SetupScreenVars(info, &sinfo); coefx = coefy = 0; for (j = 0; j < vdp2height; j++) { if (p->deltaKAx == 0) { Vdp2ReadCoefficientFP(p, p->coeftbladdr + touint(coefy) * p->coefdatasize, Vdp2Ram); } for (i = 0; i < vdp2width; i++) { u32 color; if (p->deltaKAx != 0) { Vdp2ReadCoefficientFP(p, p->coeftbladdr + toint(coefy + coefx) * p->coefdatasize, Vdp2Ram); coefx += p->deltaKAx; } if (p->msb) { textdata++; continue; } x = GenerateRotatedXPosFP(p, i, xmul, ymul, C) & sinfo.xmask; y = GenerateRotatedYPosFP(p, i, xmul, ymul, F) & sinfo.ymask; xmul += p->deltaXst; // Convert coordinates into graphics if (!info->isbitmap) { // Tile Vdp2MapCalcXY(info, &x, &y, &sinfo); } // If priority of screen is less than current top pixel and per // pixel priority isn't used, skip it if (Vdp2GetPixelPriority(textdata[0]) > info->priority) { textdata++; continue; } // Fetch pixel if (!Vdp2FetchPixel(info, x, y, &color)) { textdata++; continue; } textdata[0] = COLSAT2YAB32(info->priority, info->PostPixelFetchCalc(info, color)); textdata++; } ymul += p->deltaYst; coefx = 0; coefy += p->deltaKAst; } return; } GCDVdp2DrawScroll(info, vdp2framebuffer, vdp2width, vdp2height); } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawBackScreen(void) { int i; // Only draw black if TVMD's DISP and BDCLMD bits are cleared if ((Vdp2Regs->TVMD & 0x8000) == 0 && (Vdp2Regs->TVMD & 0x100) == 0) { // Draw Black for (i = 0; i < (vdp2width * vdp2height); i++) vdp2framebuffer[i] = 0; } else { // Draw Back Screen u32 scrAddr; u16 dot; if (Vdp2Regs->VRSIZE & 0x8000) scrAddr = (((Vdp2Regs->BKTAU & 0x7) << 16) | Vdp2Regs->BKTAL) * 2; else scrAddr = (((Vdp2Regs->BKTAU & 0x3) << 16) | Vdp2Regs->BKTAL) * 2; if (Vdp2Regs->BKTAU & 0x8000) { // Per Line for (i = 0; i < vdp2height; i++) { dot = T1ReadWord(Vdp2Ram, scrAddr); scrAddr += 2; puthline16(0, i, vdp2width, dot, 0); } } else { // Single Color dot = T1ReadWord(Vdp2Ram, scrAddr); for (i = 0; i < (vdp2width * vdp2height); i++) vdp2framebuffer[i] = COLSAT2YAB16(0, dot); } } } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawNBG0(void) { vdp2draw_struct info; vdp2rotationparameterfp_struct parameter[2]; if (Vdp2Regs->BGON & 0x20) { // RBG1 mode info.enable = Vdp2Regs->BGON & 0x20; // Read in Parameter B Vdp2ReadRotationTableFP(1, ¶meter[1], Vdp2Regs, Vdp2Ram); if((info.isbitmap = Vdp2Regs->CHCTLA & 0x2) != 0) { // Bitmap Mode ReadBitmapSize(&info, Vdp2Regs->CHCTLA >> 2, 0x3); info.charaddr = (Vdp2Regs->MPOFR & 0x70) * 0x2000; info.paladdr = (Vdp2Regs->BMPNA & 0x7) << 8; info.flipfunction = 0; info.specialfunction = 0; } else { // Tile Mode info.mapwh = 4; ReadPlaneSize(&info, Vdp2Regs->PLSZ >> 12); ReadPatternData(&info, Vdp2Regs->PNCN0, Vdp2Regs->CHCTLA & 0x1); } info.rotatenum = 1; info.rotatemode = 0; info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2ParameterBPlaneAddr; } else if (Vdp2Regs->BGON & 0x1) { // NBG0 mode info.enable = Vdp2Regs->BGON & 0x1; if((info.isbitmap = Vdp2Regs->CHCTLA & 0x2) != 0) { // Bitmap Mode ReadBitmapSize(&info, Vdp2Regs->CHCTLA >> 2, 0x3); info.x = Vdp2Regs->SCXIN0 & 0x7FF; info.y = Vdp2Regs->SCYIN0 & 0x7FF; info.charaddr = (Vdp2Regs->MPOFN & 0x7) * 0x20000; info.paladdr = (Vdp2Regs->BMPNA & 0x7) << 8; info.flipfunction = 0; info.specialfunction = 0; } else { // Tile Mode info.mapwh = 2; ReadPlaneSize(&info, Vdp2Regs->PLSZ); info.x = Vdp2Regs->SCXIN0 & 0x7FF; info.y = Vdp2Regs->SCYIN0 & 0x7FF; ReadPatternData(&info, Vdp2Regs->PNCN0, Vdp2Regs->CHCTLA & 0x1); } info.coordincx = (Vdp2Regs->ZMXN0.all & 0x7FF00) / (float) 65536; info.coordincy = (Vdp2Regs->ZMYN0.all & 0x7FF00) / (float) 65536; info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2NBG0PlaneAddr; } else // Not enabled return; info.transparencyenable = !(Vdp2Regs->BGON & 0x100); info.specialprimode = Vdp2Regs->SFPRMD & 0x3; info.colornumber = (Vdp2Regs->CHCTLA & 0x70) >> 4; if (Vdp2Regs->CCCTL & 0x1) info.alpha = Vdp2Regs->CCRNA & 0x1F; info.coloroffset = (Vdp2Regs->CRAOFA & 0x7) << 8; ReadVdp2ColorOffset(&info, 0x1, 0x1); info.priority = nbg0priority; if (!(info.enable & Vdp2External.disptoggle)) return; ReadMosaicData(&info, 0x1, Vdp2Regs); ReadLineScrollData(&info, Vdp2Regs->SCRCTL & 0xFF, Vdp2Regs->LSTA0.all); if (Vdp2Regs->SCRCTL & 1) { info.isverticalscroll = 1; info.verticalscrolltbl = (Vdp2Regs->VCSTA.all & 0x7FFFE) << 1; if (Vdp2Regs->SCRCTL & 0x100) info.verticalscrollinc = 8; else info.verticalscrollinc = 4; } else info.isverticalscroll = 0; info.wctl = Vdp2Regs->WCTLA; if (info.enable == 1) { // NBG0 draw GCDVdp2DrawScroll(&info, vdp2framebuffer, vdp2width, vdp2height); } else { // RBG1 draw Vdp2DrawRotationFP(&info, parameter); } } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawNBG1(void) { vdp2draw_struct info; info.enable = Vdp2Regs->BGON & 0x2; info.transparencyenable = !(Vdp2Regs->BGON & 0x200); info.specialprimode = (Vdp2Regs->SFPRMD >> 2) & 0x3; info.colornumber = (Vdp2Regs->CHCTLA & 0x3000) >> 12; if((info.isbitmap = Vdp2Regs->CHCTLA & 0x200) != 0) { ReadBitmapSize(&info, Vdp2Regs->CHCTLA >> 10, 0x3); info.x = Vdp2Regs->SCXIN1 & 0x7FF; info.y = Vdp2Regs->SCYIN1 & 0x7FF; info.charaddr = ((Vdp2Regs->MPOFN & 0x70) >> 4) * 0x20000; info.paladdr = Vdp2Regs->BMPNA & 0x700; info.flipfunction = 0; info.specialfunction = 0; } else { info.mapwh = 2; ReadPlaneSize(&info, Vdp2Regs->PLSZ >> 2); info.x = Vdp2Regs->SCXIN1 & 0x7FF; info.y = Vdp2Regs->SCYIN1 & 0x7FF; ReadPatternData(&info, Vdp2Regs->PNCN1, Vdp2Regs->CHCTLA & 0x100); } if (Vdp2Regs->CCCTL & 0x2) info.alpha = (Vdp2Regs->CCRNA >> 8) & 0x1F; info.coloroffset = (Vdp2Regs->CRAOFA & 0x70) << 4; ReadVdp2ColorOffset(&info, 0x2, 0x2); info.coordincx = (Vdp2Regs->ZMXN1.all & 0x7FF00) / (float) 65536; info.coordincy = (Vdp2Regs->ZMYN1.all & 0x7FF00) / (float) 65536; info.priority = nbg1priority; info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2NBG1PlaneAddr; if (!(info.enable & Vdp2External.disptoggle)) return; ReadMosaicData(&info, 0x2, Vdp2Regs); ReadLineScrollData(&info, Vdp2Regs->SCRCTL >> 8, Vdp2Regs->LSTA1.all); if (Vdp2Regs->SCRCTL & 0x100) { info.isverticalscroll = 1; if (Vdp2Regs->SCRCTL & 0x1) { info.verticalscrolltbl = 4 + ((Vdp2Regs->VCSTA.all & 0x7FFFE) << 1); info.verticalscrollinc = 8; } else { info.verticalscrolltbl = (Vdp2Regs->VCSTA.all & 0x7FFFE) << 1; info.verticalscrollinc = 4; } } else info.isverticalscroll = 0; info.wctl = Vdp2Regs->WCTLA >> 8; GCDVdp2DrawScroll(&info, vdp2framebuffer, vdp2width, vdp2height); } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawNBG2(void) { vdp2draw_struct info; info.enable = Vdp2Regs->BGON & 0x4; info.transparencyenable = !(Vdp2Regs->BGON & 0x400); info.specialprimode = (Vdp2Regs->SFPRMD >> 4) & 0x3; info.colornumber = (Vdp2Regs->CHCTLB & 0x2) >> 1; info.mapwh = 2; ReadPlaneSize(&info, Vdp2Regs->PLSZ >> 4); info.x = Vdp2Regs->SCXN2 & 0x7FF; info.y = Vdp2Regs->SCYN2 & 0x7FF; ReadPatternData(&info, Vdp2Regs->PNCN2, Vdp2Regs->CHCTLB & 0x1); if (Vdp2Regs->CCCTL & 0x4) info.alpha = Vdp2Regs->CCRNB & 0x1F; info.coloroffset = Vdp2Regs->CRAOFA & 0x700; ReadVdp2ColorOffset(&info, 0x4, 0x4); info.coordincx = info.coordincy = 1; info.priority = nbg2priority; info.PlaneAddr = (void FASTCALL (*)(void *, int, Vdp2*))&Vdp2NBG2PlaneAddr; if (!(info.enable & Vdp2External.disptoggle)) return; ReadMosaicData(&info, 0x4, Vdp2Regs); info.islinescroll = 0; info.isverticalscroll = 0; info.wctl = Vdp2Regs->WCTLB; info.isbitmap = 0; GCDVdp2DrawScroll(&info, vdp2framebuffer, vdp2width, vdp2height); } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawNBG3(void) { vdp2draw_struct info; info.enable = Vdp2Regs->BGON & 0x8; info.transparencyenable = !(Vdp2Regs->BGON & 0x800); info.specialprimode = (Vdp2Regs->SFPRMD >> 6) & 0x3; info.colornumber = (Vdp2Regs->CHCTLB & 0x20) >> 5; info.mapwh = 2; ReadPlaneSize(&info, Vdp2Regs->PLSZ >> 6); info.x = Vdp2Regs->SCXN3 & 0x7FF; info.y = Vdp2Regs->SCYN3 & 0x7FF; ReadPatternData(&info, Vdp2Regs->PNCN3, Vdp2Regs->CHCTLB & 0x10); if (Vdp2Regs->CCCTL & 0x8) info.alpha = (Vdp2Regs->CCRNB >> 8) & 0x1F; info.coloroffset = (Vdp2Regs->CRAOFA & 0x7000) >> 4; ReadVdp2ColorOffset(&info, 0x8, 0x8); info.coordincx = info.coordincy = 1; info.priority = nbg3priority; info.PlaneAddr = (void FASTCALL (*)(void *, int, Vdp2*))&Vdp2NBG3PlaneAddr; if (!(info.enable & Vdp2External.disptoggle)) return; ReadMosaicData(&info, 0x8, Vdp2Regs); info.islinescroll = 0; info.isverticalscroll = 0; info.wctl = Vdp2Regs->WCTLB >> 8; info.isbitmap = 0; GCDVdp2DrawScroll(&info, vdp2framebuffer, vdp2width, vdp2height); } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawRBG0(void) { vdp2draw_struct info; vdp2rotationparameterfp_struct parameter[2]; info.enable = Vdp2Regs->BGON & 0x10; info.priority = rbg0priority; if (!(info.enable & Vdp2External.disptoggle)) return; info.transparencyenable = !(Vdp2Regs->BGON & 0x1000); info.specialprimode = (Vdp2Regs->SFPRMD >> 8) & 0x3; info.colornumber = (Vdp2Regs->CHCTLB & 0x7000) >> 12; // Figure out which Rotation Parameter we're using switch (Vdp2Regs->RPMD & 0x3) { case 0: // Parameter A info.rotatenum = 0; info.rotatemode = 0; info.PlaneAddr = (void FASTCALL (*)(void *, int, Vdp2*))&Vdp2ParameterAPlaneAddr; break; case 1: // Parameter B info.rotatenum = 1; info.rotatemode = 0; info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2ParameterBPlaneAddr; break; case 2: // Parameter A+B switched via coefficients case 3: // Parameter A+B switched via rotation parameter window default: info.rotatenum = 0; info.rotatemode = 1 + (Vdp2Regs->RPMD & 0x1); info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2ParameterAPlaneAddr; break; } Vdp2ReadRotationTableFP(info.rotatenum, ¶meter[info.rotatenum], Vdp2Regs, Vdp2Ram); if((info.isbitmap = Vdp2Regs->CHCTLB & 0x200) != 0) { // Bitmap Mode ReadBitmapSize(&info, Vdp2Regs->CHCTLB >> 10, 0x1); if (info.rotatenum == 0) // Parameter A info.charaddr = (Vdp2Regs->MPOFR & 0x7) * 0x20000; else // Parameter B info.charaddr = (Vdp2Regs->MPOFR & 0x70) * 0x2000; info.paladdr = (Vdp2Regs->BMPNB & 0x7) << 8; info.flipfunction = 0; info.specialfunction = 0; } else { // Tile Mode info.mapwh = 4; if (info.rotatenum == 0) // Parameter A ReadPlaneSize(&info, Vdp2Regs->PLSZ >> 8); else // Parameter B ReadPlaneSize(&info, Vdp2Regs->PLSZ >> 12); ReadPatternData(&info, Vdp2Regs->PNCR, Vdp2Regs->CHCTLB & 0x100); } if (Vdp2Regs->CCCTL & 0x10) info.alpha = Vdp2Regs->CCRR & 0x1F; info.coloroffset = (Vdp2Regs->CRAOFB & 0x7) << 8; ReadVdp2ColorOffset(&info, 0x10, 0x10); info.coordincx = info.coordincy = 1; ReadMosaicData(&info, 0x10, Vdp2Regs); info.islinescroll = 0; info.isverticalscroll = 0; info.wctl = Vdp2Regs->WCTLC; Vdp2DrawRotationFP(&info, parameter); } ////////////////////////////////////////////////////////////////////////////// int VIDGCDInit(void) { // Initialize output buffer if ((dispbuffer = (u32 *)calloc(sizeof(u32), 704 * 512)) == NULL) return -1; // Initialize VDP1 framebuffer 1 if ((vdp1framebuffer[0] = (u8 *)calloc(sizeof(u8), 0x40000)) == NULL) return -1; // Initialize VDP1 framebuffer 2 if ((vdp1framebuffer[1] = (u8 *)calloc(sizeof(u8), 0x40000)) == NULL) return -1; // Initialize VDP2 framebuffer if ((vdp2framebuffer = (u32 *)calloc(sizeof(u32), 704 * 512)) == NULL) return -1; vdp1backframebuffer = vdp1framebuffer[0]; vdp1frontframebuffer = vdp1framebuffer[1]; vdp2width = 320; vdp2height = 224; #ifdef USE_OPENGL glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, 320, 224, 0, 1, 0); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glOrtho(-320, 320, -224, 224, 1, 0); outputwidth = 320; outputheight = 224; #endif return 0; } ////////////////////////////////////////////////////////////////////////////// void VIDGCDDeInit(void) { if (dispbuffer) { free(dispbuffer); dispbuffer = NULL; } if (vdp1framebuffer[0]) free(vdp1framebuffer[0]); if (vdp1framebuffer[1]) free(vdp1framebuffer[1]); if (vdp2framebuffer) free(vdp2framebuffer); } ////////////////////////////////////////////////////////////////////////////// static int IsFullscreen = 0; void VIDGCDResize(unsigned int w, unsigned int h, int on) { #ifdef USE_OPENGL IsFullscreen = on; glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, w, h, 0, 1, 0); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glOrtho(-w, w, -h, h, 1, 0); glViewport(0, 0, w, h); outputwidth = w; outputheight = h; #endif } ////////////////////////////////////////////////////////////////////////////// int VIDGCDIsFullscreen(void) { return IsFullscreen; } ////////////////////////////////////////////////////////////////////////////// int VIDGCDVdp1Reset(void) { vdp1clipxstart = 0; vdp1clipxend = 512; vdp1clipystart = 0; vdp1clipyend = 256; return 0; } ////////////////////////////////////////////////////////////////////////////// void VIDGCDVdp1DrawStart(void) { if (Vdp1Regs->TVMR & 0x1) { if (Vdp1Regs->TVMR & 0x2) { // Rotation 8-bit vdp1width = 512; vdp1height = 512; } else { // Normal 8-bit vdp1width = 1024; vdp1width = 256; } vdp1pixelsize = 1; } else { // Rotation/Normal 16-bit vdp1width = 512; vdp1height = 256; vdp1pixelsize = 2; } VIDGCDVdp1EraseFrameBuffer(); } ////////////////////////////////////////////////////////////////////////////// void VIDGCDVdp1DrawEnd(void) { } ////////////////////////////////////////////////////////////////////////////// static INLINE u16 Vdp1ReadPattern16( u32 base, u32 offset ) { u16 dot = T1ReadByte(Vdp1Ram, ( base + (offset>>1)) & 0x7FFFF); if ((offset & 0x1) == 0) dot >>= 4; // Even pixel else dot &= 0xF; // Odd pixel return dot; } static INLINE u16 Vdp1ReadPattern64( u32 base, u32 offset ) { return T1ReadByte(Vdp1Ram, ( base + offset ) & 0x7FFFF) & 0x3F; } static INLINE u16 Vdp1ReadPattern128( u32 base, u32 offset ) { return T1ReadByte(Vdp1Ram, ( base + offset ) & 0x7FFFF) & 0x7F; } static INLINE u16 Vdp1ReadPattern256( u32 base, u32 offset ) { return T1ReadByte(Vdp1Ram, ( base + offset ) & 0x7FFFF) & 0xFF; } static INLINE u16 Vdp1ReadPattern64k( u32 base, u32 offset ) { return T1ReadWord(Vdp1Ram, ( base + 2*offset) & 0x7FFFF); } //////////////////////////////////////////////////////////////////////////////// static INLINE u32 alphablend16(u32 d, u32 s, u32 level) { int r,g,b,sr,sg,sb,dr,dg,db; int invlevel = 256-level; sr = s & 0x001f; dr = d & 0x001f; r = (sr*level + dr*invlevel)>>8; r&= 0x1f; sg = s & 0x03e0; dg = d & 0x03e0; g = (sg*level + dg*invlevel)>>8; g&= 0x03e0; sb = s & 0x7c00; db = d & 0x7c00; b = (sb*level + db*invlevel)>>8; b&= 0x7c00; return r|g|b; } typedef struct _COLOR_PARAMS { double r,g,b; } COLOR_PARAMS; COLOR_PARAMS leftColumnColor; vdp1cmd_struct cmd; int currentPixel; int currentPixelIsVisible; int characterWidth; int characterHeight; static int getpixel(int linenumber, int currentlineindex) { u32 characterAddress; u32 colorlut; u16 colorbank; u8 SPD; int endcode; int endcodesEnabled; int untexturedColor = 0; int isTextured = 1; int currentShape = cmd.CMDCTRL & 0x7; int flip; characterAddress = cmd.CMDSRCA << 3; colorbank = cmd.CMDCOLR; colorlut = (u32)colorbank << 3; SPD = ((cmd.CMDPMOD & 0x40) != 0);//show the actual color of transparent pixels if 1 (they won't be drawn transparent) endcodesEnabled = (( cmd.CMDPMOD & 0x80) == 0 )?1:0; flip = (cmd.CMDCTRL & 0x30) >> 4; //4 polygon, 5 polyline or 6 line if(currentShape == 4 || currentShape == 5 || currentShape == 6) { isTextured = 0; untexturedColor = cmd.CMDCOLR; } switch( flip ) { case 1: // Horizontal flipping currentlineindex = characterWidth - currentlineindex-1; break; case 2: // Vertical flipping linenumber = characterHeight - linenumber-1; break; case 3: // Horizontal/Vertical flipping linenumber = characterHeight - linenumber-1; currentlineindex = characterWidth - currentlineindex-1; break; } switch ((cmd.CMDPMOD >> 3) & 0x7) { case 0x0: //4bpp bank endcode = 0xf; currentPixel = Vdp1ReadPattern16( characterAddress + (linenumber*(characterWidth>>1)), currentlineindex ); if(isTextured && endcodesEnabled && currentPixel == endcode) return 1; if (!((currentPixel == 0) && !SPD)) currentPixel = colorbank | currentPixel; currentPixelIsVisible = 0xf; break; case 0x1://4bpp lut endcode = 0xf; currentPixel = Vdp1ReadPattern16( characterAddress + (linenumber*(characterWidth>>1)), currentlineindex ); if(isTextured && endcodesEnabled && currentPixel == endcode) return 1; if (!(currentPixel == 0 && !SPD)) currentPixel = T1ReadWord(Vdp1Ram, (currentPixel * 2 + colorlut) & 0x7FFFF); currentPixelIsVisible = 0xffff; break; case 0x2://8pp bank (64 color) //is there a hardware bug with endcodes in this color mode? //there are white lines around some characters in scud //using an endcode of 63 eliminates the white lines //but also causes some dropout due to endcodes being triggered that aren't triggered on hardware //the closest thing i can do to match the hardware is make all pixels with color index 63 transparent //this needs more hardware testing endcode = 63; currentPixel = Vdp1ReadPattern64( characterAddress + (linenumber*(characterWidth)), currentlineindex ); if(isTextured && endcodesEnabled && currentPixel == endcode) currentPixel = 0; // return 1; if (!((currentPixel == 0) && !SPD)) currentPixel = colorbank | currentPixel; currentPixelIsVisible = 0x3f; break; case 0x3://128 color endcode = 0xff; currentPixel = Vdp1ReadPattern128( characterAddress + (linenumber*characterWidth), currentlineindex ); if(isTextured && endcodesEnabled && currentPixel == endcode) return 1; if (!((currentPixel == 0) && !SPD)) currentPixel = colorbank | currentPixel; currentPixelIsVisible = 0x7f; break; case 0x4://256 color endcode = 0xff; currentPixel = Vdp1ReadPattern256( characterAddress + (linenumber*characterWidth), currentlineindex ); if(isTextured && endcodesEnabled && currentPixel == endcode) return 1; currentPixelIsVisible = 0xff; if (!((currentPixel == 0) && !SPD)) currentPixel = colorbank | currentPixel; break; case 0x5://16bpp bank endcode = 0x7fff; currentPixel = Vdp1ReadPattern64k( characterAddress + (linenumber*characterWidth*2), currentlineindex ); if(isTextured && endcodesEnabled && currentPixel == endcode) return 1; currentPixelIsVisible = 0xffff; break; } if(!isTextured) currentPixel = untexturedColor; //force the MSB to be on if MSBON is set currentPixel |= cmd.CMDPMOD & (1 << 15); return 0; } static int gouraudAdjust( int color, int tableValue ) { color += (tableValue - 0x10); if ( color < 0 ) color = 0; if ( color > 0x1f ) color = 0x1f; return color; } static void putpixel(int x, int y) { u16* iPix = &((u16 *)vdp1backframebuffer)[(y * vdp1width) + x]; int mesh = cmd.CMDPMOD & 0x0100; int SPD = ((cmd.CMDPMOD & 0x40) != 0);//show the actual color of transparent pixels if 1 (they won't be drawn transparent) int currentShape = cmd.CMDCTRL & 0x7; int isTextured=1; if(mesh && (x^y)&1) return; if(currentShape == 4 || currentShape == 5 || currentShape == 6) isTextured = 0; if (cmd.CMDPMOD & 0x0400) PushUserClipping((cmd.CMDPMOD >> 9) & 0x1); if (x >= vdp1clipxstart && x < vdp1clipxend && y >= vdp1clipystart && y < vdp1clipyend) {} else return; if (cmd.CMDPMOD & 0x0400) PopUserClipping(); if ( SPD || (currentPixel & currentPixelIsVisible)) { switch( cmd.CMDPMOD & 0x7 )//we want bits 0,1,2 { case 0: // replace if (!((currentPixel == 0) && !SPD)) *(iPix) = currentPixel; break; case 1: // shadow, TODO *(iPix) = currentPixel; break; case 2: // half luminance *(iPix) = ((currentPixel & ~0x8421) >> 1) | (1 << 15); break; case 3: // half transparent if ( *(iPix) & (1 << 15) )//only if MSB of framebuffer data is set *(iPix) = alphablend16( *(iPix), currentPixel, (1 << 7) ) | (1 << 15); else *(iPix) = currentPixel; break; case 4: //gouraud #define COLOR(r,g,b) (((r)&0x1F)|(((g)&0x1F)<<5)|(((b)&0x1F)<<10) |0x8000 ) //handle the special case demonstrated in the sgl chrome demo //if we are in a paletted bank mode and the other two colors are unused, adjust the index value instead of rgb if( (((cmd.CMDPMOD >> 3) & 0x7) != 5) && (((cmd.CMDPMOD >> 3) & 0x7) != 1) && (int)leftColumnColor.g == 16 && (int)leftColumnColor.b == 16) { int c = (int)(leftColumnColor.r-0x10); if(c < 0) c = 0; currentPixel = currentPixel+c; *(iPix) = currentPixel; break; } *(iPix) = COLOR( gouraudAdjust( currentPixel&0x001F, (int)leftColumnColor.r), gouraudAdjust( (currentPixel&0x03e0) >> 5, (int)leftColumnColor.g), gouraudAdjust( (currentPixel&0x7c00) >> 10, (int)leftColumnColor.b) ); break; default: *(iPix) = alphablend16( COLOR((int)leftColumnColor.r,(int)leftColumnColor.g, (int)leftColumnColor.b), currentPixel, (1 << 7) ) | (1 << 15); break; } if(*iPix & 0x8000) { vdp1draw_info.priosused[vdp1draw_info.prioritytable[0]] = 1; } else if(*iPix) { u16 p = *iPix; int s, prio, c; Vdp1ProcessSpritePixel(vdp1spritetype, &p, &s, &prio, &c); vdp1draw_info.priosused[prio] = 1; } } } //TODO consolidate the following 3 functions static int bresenham( int x1, int y1, int x2, int y2, int x[], int y[]) { int dx, dy, xf, yf, a, b, c, i; if (x2>x1) { dx = x2-x1; xf = 1; } else { dx = x1-x2; xf = -1; } if (y2>y1) { dy = y2-y1; yf = 1; } else { dy = y1-y2; yf = -1; } //burning rangers tries to draw huge shapes //this will at least let it run if(dx > 999 || dy > 999) return INT_MAX; if (dx>dy) { a = dy+dy; c = a-dx; b = c-dx; for (i=0;i<=dx;i++) { x[i] = x1; y[i] = y1; x1 += xf; if (c<0) { c += a; } else { c += b; y1 += yf; } } return dx+1; } else { a = dx+dx; c = a-dy; b = c-dy; for (i=0;i<=dy;i++) { x[i] = x1; y[i] = y1; y1 += yf; if (c<0) { c += a; } else { c += b; x1 += xf; } } return dy+1; } } static int DrawLine( int x1, int y1, int x2, int y2, double linenumber, double texturestep, double xredstep, double xgreenstep, double xbluestep) { int dx, dy, xf, yf, a, b, c, i; int endcodesdetected=0; int previousStep = 123456789; if (x2>x1) { dx = x2-x1; xf = 1; } else { dx = x1-x2; xf = -1; } if (y2>y1) { dy = y2-y1; yf = 1; } else { dy = y1-y2; yf = -1; } if (dx>dy) { a = dy+dy; c = a-dx; b = c-dx; for (i=0;i<=dx;i++) { leftColumnColor.r+=xredstep; leftColumnColor.g+=xgreenstep; leftColumnColor.b+=xbluestep; if(getpixel(linenumber,(int)i*texturestep)) { if(currentPixel != previousStep) { previousStep = (int)i*texturestep; endcodesdetected++; } } else putpixel(x1,y1); previousStep = currentPixel; if(endcodesdetected==2) break; x1 += xf; if (c<0) { c += a; } else { getpixel(linenumber,(int)i*texturestep); putpixel(x1,y1); c += b; y1 += yf; /* //same as sega's way, but just move the code down here instead //and use the pixel we already have instead of the next one if(xf>1&&yf>1) putpixel(x1,y1-1); //case 1 if(xf<1&&yf<1) putpixel(x1,y1+1); //case 2 if(xf<1&&yf>1) putpixel(x1+1,y1); //case 7 if(xf>1&&yf<1) putpixel(x1-1,y1); //case 8*/ } } return dx+1; } else { a = dx+dx; c = a-dy; b = c-dy; for (i=0;i<=dy;i++) { leftColumnColor.r+=xredstep; leftColumnColor.g+=xgreenstep; leftColumnColor.b+=xbluestep; if(getpixel(linenumber,(int)i*texturestep)) { if(currentPixel != previousStep) { previousStep = (int)i*texturestep; endcodesdetected++; } } else putpixel(x1,y1); previousStep = currentPixel; if(endcodesdetected==2) break; y1 += yf; if (c<0) { c += a; } else { getpixel(linenumber,(int)i*texturestep); putpixel(x1,y1); c += b; x1 += xf; /* if(xf>1&&yf>1) putpixel(x1,y1-1); //case 3 if(xf<1&&yf<1) putpixel(x1,y1+1); //case 4 if(xf<1&&yf>1) putpixel(x1+1,y1); //case 5 if(xf>1&&yf<1) putpixel(x1-1,y1); //case 6*/ } } return dy+1; } } static int getlinelength(int x1, int y1, int x2, int y2) { int dx, dy, xf, yf, a, b, c, i; if (x2>x1) { dx = x2-x1; xf = 1; } else { dx = x1-x2; xf = -1; } if (y2>y1) { dy = y2-y1; yf = 1; } else { dy = y1-y2; yf = -1; } if (dx>dy) { a = dy+dy; c = a-dx; b = c-dx; for (i=0;i<=dx;i++) { x1 += xf; if (c<0) { c += a; } else { c += b; y1 += yf; } } return dx+1; } else { a = dx+dx; c = a-dy; b = c-dy; for (i=0;i<=dy;i++) { y1 += yf; if (c<0) { c += a; } else { c += b; x1 += xf; } } return dy+1; } } static INLINE double interpolate(double start, double end, int numberofsteps) { double stepvalue = 0; if(numberofsteps == 0) return 1; stepvalue = (end - start) / numberofsteps; return stepvalue; } typedef union _COLOR { // xbgr x555 struct { #ifdef WORDS_BIGENDIAN u16 x:1; u16 b:5; u16 g:5; u16 r:5; #else u16 r:5; u16 g:5; u16 b:5; u16 x:1; #endif }; u16 value; } COLOR; COLOR gouraudA; COLOR gouraudB; COLOR gouraudC; COLOR gouraudD; static void gouraudTable(void) { int gouraudTableAddress; Vdp1ReadCommand(&cmd, Vdp1Regs->addr, Vdp1Ram); gouraudTableAddress = (((unsigned int)cmd.CMDGRDA) << 3); gouraudA.value = T1ReadWord(Vdp1Ram,gouraudTableAddress); gouraudB.value = T1ReadWord(Vdp1Ram,gouraudTableAddress+2); gouraudC.value = T1ReadWord(Vdp1Ram,gouraudTableAddress+4); gouraudD.value = T1ReadWord(Vdp1Ram,gouraudTableAddress+6); } int xleft[1000]; int yleft[1000]; int xright[1000]; int yright[1000]; //a real vdp1 draws with arbitrary lines //this is why endcodes are possible //this is also the reason why half-transparent shading causes moire patterns //and the reason why gouraud shading can be applied to a single line draw command static void drawQuad(s32 tl_x, s32 tl_y, s32 bl_x, s32 bl_y, s32 tr_x, s32 tr_y, s32 br_x, s32 br_y){ int totalleft; int totalright; int total; int i; COLOR_PARAMS topLeftToBottomLeftColorStep = {0,0,0}, topRightToBottomRightColorStep = {0,0,0}; //how quickly we step through the line arrays double leftLineStep = 1; double rightLineStep = 1; //a lookup table for the gouraud colors COLOR colors[4]; Vdp1ReadCommand(&cmd, Vdp1Regs->addr, Vdp1Ram); characterWidth = ((cmd.CMDSIZE >> 8) & 0x3F) * 8; characterHeight = cmd.CMDSIZE & 0xFF; totalleft = bresenham(tl_x,tl_y,bl_x,bl_y,xleft,yleft); totalright = bresenham(tr_x,tr_y,br_x,br_y,xright,yright); //just for now since burning rangers will freeze up trying to draw huge shapes if(totalleft == INT_MAX || totalright == INT_MAX) return; total = totalleft > totalright ? totalleft : totalright; if(cmd.CMDPMOD & (1 << 2)) { gouraudTable(); { colors[0] = gouraudA; colors[1] = gouraudD; colors[2] = gouraudB; colors[3] = gouraudC; } topLeftToBottomLeftColorStep.r = interpolate(colors[0].r,colors[1].r,total); topLeftToBottomLeftColorStep.g = interpolate(colors[0].g,colors[1].g,total); topLeftToBottomLeftColorStep.b = interpolate(colors[0].b,colors[1].b,total); topRightToBottomRightColorStep.r = interpolate(colors[2].r,colors[3].r,total); topRightToBottomRightColorStep.g = interpolate(colors[2].g,colors[3].g,total); topRightToBottomRightColorStep.b = interpolate(colors[2].b,colors[3].b,total); } //we have to step the equivalent of less than one pixel on the shorter side //to make sure textures stretch properly and the shape is correct if(total == totalleft && totalleft != totalright) { //left side is larger leftLineStep = 1; rightLineStep = (double)totalright / totalleft; } else if(totalleft != totalright){ //right side is larger rightLineStep = 1; leftLineStep = (double)totalleft / totalright; } for(i = 0; i < total; i++) { int xlinelength; double xtexturestep; double ytexturestep; COLOR_PARAMS rightColumnColor; COLOR_PARAMS leftToRightStep = {0,0,0}; //get the length of the line we are about to draw xlinelength = getlinelength( xleft[(int)(i*leftLineStep)], yleft[(int)(i*leftLineStep)], xright[(int)(i*rightLineStep)], yright[(int)(i*rightLineStep)]); //so from 0 to the width of the texture / the length of the line is how far we need to step xtexturestep=interpolate(0,characterWidth,xlinelength); //now we need to interpolate the y texture coordinate across multiple lines ytexturestep=interpolate(0,characterHeight,total); //gouraud interpolation if(cmd.CMDPMOD & (1 << 2)) { //for each new line we need to step once more through each column //and add the orignal color + the number of steps taken times the step value to the bottom of the shape //to get the current colors to use to interpolate across the line leftColumnColor.r = colors[0].r +(topLeftToBottomLeftColorStep.r*i); leftColumnColor.g = colors[0].g +(topLeftToBottomLeftColorStep.g*i); leftColumnColor.b = colors[0].b +(topLeftToBottomLeftColorStep.b*i); rightColumnColor.r = colors[2].r +(topRightToBottomRightColorStep.r*i); rightColumnColor.g = colors[2].g +(topRightToBottomRightColorStep.g*i); rightColumnColor.b = colors[2].b +(topRightToBottomRightColorStep.b*i); //interpolate colors across to get the right step values leftToRightStep.r = interpolate(leftColumnColor.r,rightColumnColor.r,xlinelength); leftToRightStep.g = interpolate(leftColumnColor.g,rightColumnColor.g,xlinelength); leftToRightStep.b = interpolate(leftColumnColor.b,rightColumnColor.b,xlinelength); } DrawLine( xleft[(int)(i*leftLineStep)], yleft[(int)(i*leftLineStep)], xright[(int)(i*rightLineStep)], yright[(int)(i*rightLineStep)], ytexturestep*i, xtexturestep, leftToRightStep.r, leftToRightStep.g, leftToRightStep.b ); } } void VIDGCDVdp1NormalSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer) { s16 topLeftx,topLefty,topRightx,topRighty,bottomRightx,bottomRighty,bottomLeftx,bottomLefty; int spriteWidth; int spriteHeight; Vdp1ReadCommand(&cmd, Vdp1Regs->addr, Vdp1Ram); topLeftx = cmd.CMDXA + Vdp1Regs->localX; topLefty = cmd.CMDYA + Vdp1Regs->localY; spriteWidth = ((cmd.CMDSIZE >> 8) & 0x3F) * 8; spriteHeight = cmd.CMDSIZE & 0xFF; topRightx = topLeftx + (spriteWidth - 1); topRighty = topLefty; bottomRightx = topLeftx + (spriteWidth - 1); bottomRighty = topLefty + (spriteHeight - 1); bottomLeftx = topLeftx; bottomLefty = topLefty + (spriteHeight - 1); drawQuad(topLeftx,topLefty,bottomLeftx,bottomLefty,topRightx,topRighty,bottomRightx,bottomRighty); } void VIDGCDVdp1ScaledSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer){ s32 topLeftx,topLefty,topRightx,topRighty,bottomRightx,bottomRighty,bottomLeftx,bottomLefty; int spriteWidth; int spriteHeight; int x0,y0,x1,y1; Vdp1ReadCommand(&cmd, Vdp1Regs->addr, Vdp1Ram); x0 = cmd.CMDXA + Vdp1Regs->localX; y0 = cmd.CMDYA + Vdp1Regs->localY; switch ((cmd.CMDCTRL >> 8) & 0xF) { case 0x0: // Only two coordinates default: x1 = ((int)cmd.CMDXC) - x0 + Vdp1Regs->localX + 1; y1 = ((int)cmd.CMDYC) - y0 + Vdp1Regs->localY + 1; break; case 0x5: // Upper-left x1 = ((int)cmd.CMDXB) + 1; y1 = ((int)cmd.CMDYB) + 1; break; case 0x6: // Upper-Center x1 = ((int)cmd.CMDXB); y1 = ((int)cmd.CMDYB); x0 = x0 - x1/2; x1++; y1++; break; case 0x7: // Upper-Right x1 = ((int)cmd.CMDXB); y1 = ((int)cmd.CMDYB); x0 = x0 - x1; x1++; y1++; break; case 0x9: // Center-left x1 = ((int)cmd.CMDXB); y1 = ((int)cmd.CMDYB); y0 = y0 - y1/2; x1++; y1++; break; case 0xA: // Center-center x1 = ((int)cmd.CMDXB); y1 = ((int)cmd.CMDYB); x0 = x0 - x1/2; y0 = y0 - y1/2; x1++; y1++; break; case 0xB: // Center-right x1 = ((int)cmd.CMDXB); y1 = ((int)cmd.CMDYB); x0 = x0 - x1; y0 = y0 - y1/2; x1++; y1++; break; case 0xD: // Lower-left x1 = ((int)cmd.CMDXB); y1 = ((int)cmd.CMDYB); y0 = y0 - y1; x1++; y1++; break; case 0xE: // Lower-center x1 = ((int)cmd.CMDXB); y1 = ((int)cmd.CMDYB); x0 = x0 - x1/2; y0 = y0 - y1; x1++; y1++; break; case 0xF: // Lower-right x1 = ((int)cmd.CMDXB); y1 = ((int)cmd.CMDYB); x0 = x0 - x1; y0 = y0 - y1; x1++; y1++; break; } spriteWidth = ((cmd.CMDSIZE >> 8) & 0x3F) * 8; spriteHeight = cmd.CMDSIZE & 0xFF; topLeftx = x0; topLefty = y0; topRightx = x1 + x0 - 1; topRighty = topLefty; bottomRightx = x1 + x0 - 1; bottomRighty = y1 + y0 - 1; bottomLeftx = topLeftx; bottomLefty = y1 + y0 - 1; drawQuad(topLeftx,topLefty,bottomLeftx,bottomLefty,topRightx,topRighty,bottomRightx,bottomRighty); } void VIDGCDVdp1DistortedSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer) { s32 xa,ya,xb,yb,xc,yc,xd,yd; Vdp1ReadCommand(&cmd, Vdp1Regs->addr, Vdp1Ram); xa = (s32)(cmd.CMDXA + Vdp1Regs->localX); ya = (s32)(cmd.CMDYA + Vdp1Regs->localY); xb = (s32)(cmd.CMDXB + Vdp1Regs->localX); yb = (s32)(cmd.CMDYB + Vdp1Regs->localY); xc = (s32)(cmd.CMDXC + Vdp1Regs->localX); yc = (s32)(cmd.CMDYC + Vdp1Regs->localY); xd = (s32)(cmd.CMDXD + Vdp1Regs->localX); yd = (s32)(cmd.CMDYD + Vdp1Regs->localY); drawQuad(xa,ya,xd,yd,xb,yb,xc,yc); } static void gouraudLineSetup(double * redstep, double * greenstep, double * bluestep, int length, COLOR table1, COLOR table2) { gouraudTable(); *redstep =interpolate(table1.r,table2.r,length); *greenstep =interpolate(table1.g,table2.g,length); *bluestep =interpolate(table1.b,table2.b,length); leftColumnColor.r = table1.r; leftColumnColor.g = table1.g; leftColumnColor.b = table1.b; } void VIDGCDVdp1PolylineDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer) { int X[4]; int Y[4]; double redstep = 0, greenstep = 0, bluestep = 0; int length; Vdp1ReadCommand(&cmd, Vdp1Regs->addr, Vdp1Ram); X[0] = (int)Vdp1Regs->localX + (int)((s16)T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x0C)); Y[0] = (int)Vdp1Regs->localY + (int)((s16)T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x0E)); X[1] = (int)Vdp1Regs->localX + (int)((s16)T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x10)); Y[1] = (int)Vdp1Regs->localY + (int)((s16)T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x12)); X[2] = (int)Vdp1Regs->localX + (int)((s16)T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x14)); Y[2] = (int)Vdp1Regs->localY + (int)((s16)T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x16)); X[3] = (int)Vdp1Regs->localX + (int)((s16)T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x18)); Y[3] = (int)Vdp1Regs->localY + (int)((s16)T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x1A)); length = getlinelength(X[0], Y[0], X[1], Y[1]); gouraudLineSetup(&redstep,&greenstep,&bluestep,length, gouraudA, gouraudB); DrawLine(X[0], Y[0], X[1], Y[1], 0,0,redstep,greenstep,bluestep); length = getlinelength(X[1], Y[1], X[2], Y[2]); gouraudLineSetup(&redstep,&greenstep,&bluestep,length, gouraudB, gouraudC); DrawLine(X[1], Y[1], X[2], Y[2], 0,0,redstep,greenstep,bluestep); length = getlinelength(X[2], Y[2], X[3], Y[3]); gouraudLineSetup(&redstep,&greenstep,&bluestep,length, gouraudD, gouraudC); DrawLine(X[3], Y[3], X[2], Y[2], 0,0,redstep,greenstep,bluestep); length = getlinelength(X[3], Y[3], X[0], Y[0]); gouraudLineSetup(&redstep,&greenstep,&bluestep,length, gouraudA,gouraudD); DrawLine(X[0], Y[0], X[3], Y[3], 0,0,redstep,greenstep,bluestep); } void VIDGCDVdp1LineDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer) { int x1, y1, x2, y2; double redstep = 0, greenstep = 0, bluestep = 0; int length; Vdp1ReadCommand(&cmd, Vdp1Regs->addr, Vdp1Ram); x1 = (int)Vdp1Regs->localX + (int)((s16)T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x0C)); y1 = (int)Vdp1Regs->localY + (int)((s16)T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x0E)); x2 = (int)Vdp1Regs->localX + (int)((s16)T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x10)); y2 = (int)Vdp1Regs->localY + (int)((s16)T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x12)); length = getlinelength(x1, y1, x2, y2); gouraudLineSetup(&redstep,&bluestep,&greenstep,length, gouraudA, gouraudB); DrawLine(x1, y1, x2, y2, 0,0,redstep,greenstep,bluestep); } ////////////////////////////////////////////////////////////////////////////// void VIDGCDVdp1UserClipping(u8 * ram, Vdp1 * regs) { Vdp1Regs->userclipX1 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0xC); Vdp1Regs->userclipY1 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0xE); Vdp1Regs->userclipX2 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x14); Vdp1Regs->userclipY2 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x16); #if 0 vdp1clipxstart = Vdp1Regs->userclipX1; vdp1clipxend = Vdp1Regs->userclipX2; vdp1clipystart = Vdp1Regs->userclipY1; vdp1clipyend = Vdp1Regs->userclipY2; // This needs work if (vdp1clipxstart > Vdp1Regs->systemclipX1) vdp1clipxstart = Vdp1Regs->userclipX1; else vdp1clipxstart = Vdp1Regs->systemclipX1; if (vdp1clipxend < Vdp1Regs->systemclipX2) vdp1clipxend = Vdp1Regs->userclipX2; else vdp1clipxend = Vdp1Regs->systemclipX2; if (vdp1clipystart > Vdp1Regs->systemclipY1) vdp1clipystart = Vdp1Regs->userclipY1; else vdp1clipystart = Vdp1Regs->systemclipY1; if (vdp1clipyend < Vdp1Regs->systemclipY2) vdp1clipyend = Vdp1Regs->userclipY2; else vdp1clipyend = Vdp1Regs->systemclipY2; #endif } ////////////////////////////////////////////////////////////////////////////// static void PushUserClipping(int mode) { if (mode == 1) { VDP1LOG("User clipping mode 1 not implemented\n"); return; } vdp1clipxstart = Vdp1Regs->userclipX1; vdp1clipxend = Vdp1Regs->userclipX2; vdp1clipystart = Vdp1Regs->userclipY1; vdp1clipyend = Vdp1Regs->userclipY2; // This needs work if (vdp1clipxstart > Vdp1Regs->systemclipX1) vdp1clipxstart = Vdp1Regs->userclipX1; else vdp1clipxstart = Vdp1Regs->systemclipX1; if (vdp1clipxend < Vdp1Regs->systemclipX2) vdp1clipxend = Vdp1Regs->userclipX2; else vdp1clipxend = Vdp1Regs->systemclipX2; if (vdp1clipystart > Vdp1Regs->systemclipY1) vdp1clipystart = Vdp1Regs->userclipY1; else vdp1clipystart = Vdp1Regs->systemclipY1; if (vdp1clipyend < Vdp1Regs->systemclipY2) vdp1clipyend = Vdp1Regs->userclipY2; else vdp1clipyend = Vdp1Regs->systemclipY2; } ////////////////////////////////////////////////////////////////////////////// static void PopUserClipping(void) { vdp1clipxstart = Vdp1Regs->systemclipX1; vdp1clipxend = Vdp1Regs->systemclipX2; vdp1clipystart = Vdp1Regs->systemclipY1; vdp1clipyend = Vdp1Regs->systemclipY2; } ////////////////////////////////////////////////////////////////////////////// void VIDGCDVdp1SystemClipping(u8 * ram, Vdp1 * regs) { Vdp1Regs->systemclipX1 = 0; Vdp1Regs->systemclipY1 = 0; Vdp1Regs->systemclipX2 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x14); Vdp1Regs->systemclipY2 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x16); vdp1clipxstart = Vdp1Regs->systemclipX1; vdp1clipxend = Vdp1Regs->systemclipX2; vdp1clipystart = Vdp1Regs->systemclipY1; vdp1clipyend = Vdp1Regs->systemclipY2; } ////////////////////////////////////////////////////////////////////////////// void VIDGCDVdp1LocalCoordinate(u8 * ram, Vdp1 * regs) { Vdp1Regs->localX = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0xC); Vdp1Regs->localY = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0xE); } ////////////////////////////////////////////////////////////////////////////// int VIDGCDVdp2Reset(void) { return 0; } ////////////////////////////////////////////////////////////////////////////// void VIDGCDVdp2DrawStart(void) { int wctl; Vdp2DrawBackScreen(); vdp1draw_info.prioritytable[0] = Vdp2Regs->PRISA & 0x7; vdp1draw_info.prioritytable[1] = (Vdp2Regs->PRISA >> 8) & 0x7; vdp1draw_info.prioritytable[2] = Vdp2Regs->PRISB & 0x7; vdp1draw_info.prioritytable[3] = (Vdp2Regs->PRISB >> 8) & 0x7; vdp1draw_info.prioritytable[4] = Vdp2Regs->PRISC & 0x7; vdp1draw_info.prioritytable[5] = (Vdp2Regs->PRISC >> 8) & 0x7; vdp1draw_info.prioritytable[6] = Vdp2Regs->PRISD & 0x7; vdp1draw_info.prioritytable[7] = (Vdp2Regs->PRISD >> 8) & 0x7; vdp1draw_info.coloroffset = (Vdp2Regs->CRAOFB & 0x70) << 4; vdp1spritetype = Vdp2Regs->SPCTL & 0xF; if(Vdp2Regs->CLOFEN & 0x40) { // color offset enable if(Vdp2Regs->CLOFSL & 0x40) { // color offset B vdp1draw_info.info.cor = Vdp2Regs->COBR & 0xFF; if(Vdp2Regs->COBR & 0x100) vdp1draw_info.info.cor |= 0xFFFFFF00; vdp1draw_info.info.cog = Vdp2Regs->COBG & 0xFF; if(Vdp2Regs->COBG & 0x100) vdp1draw_info.info.cog |= 0xFFFFFF00; vdp1draw_info.info.cob = Vdp2Regs->COBB & 0xFF; if(Vdp2Regs->COBB & 0x100) vdp1draw_info.info.cob |= 0xFFFFFF00; } else { // color offset A vdp1draw_info.info.cor = Vdp2Regs->COAR & 0xFF; if(Vdp2Regs->COAR & 0x100) vdp1draw_info.info.cor |= 0xFFFFFF00; vdp1draw_info.info.cog = Vdp2Regs->COAG & 0xFF; if(Vdp2Regs->COAG & 0x100) vdp1draw_info.info.cog |= 0xFFFFFF00; vdp1draw_info.info.cob = Vdp2Regs->COAB & 0xFF; if(Vdp2Regs->COAB & 0x100) vdp1draw_info.info.cob |= 0xFFFFFF00; } if(vdp1draw_info.info.cor == 0 && vdp1draw_info.info.cog == 0 && vdp1draw_info.info.cob == 0) { if(Vdp2Regs->CCCTL & 0x40) vdp1draw_info.info.PostPixelFetchCalc = &DoColorCalc; else vdp1draw_info.info.PostPixelFetchCalc = &DoNothing; } else { if(Vdp2Regs->CCCTL & 0x40) vdp1draw_info.info.PostPixelFetchCalc = &DoColorCalcWithColorOffset; else vdp1draw_info.info.PostPixelFetchCalc = &DoColorOffset; } } else { // color offset disable if(Vdp2Regs->CCCTL & 0x40) vdp1draw_info.info.PostPixelFetchCalc = &DoColorCalc; else vdp1draw_info.info.PostPixelFetchCalc = &DoNothing; } wctl = Vdp2Regs->WCTLC >> 8; vdp1draw_info.clip[0].xstart = vdp1draw_info.clip[0].ystart = 0; vdp1draw_info.clip[0].xend = vdp1draw_info.clip[0].yend = 0; vdp1draw_info.clip[1].xstart = vdp1draw_info.clip[1].ystart = 0; vdp1draw_info.clip[1].xend = vdp1draw_info.clip[1].yend = 0; ReadWindowData(wctl, vdp1draw_info.clip, Vdp2Regs); vdp1draw_info.linewnd0addr = vdp1draw_info.linewnd1addr = 0; ReadLineWindowData(&vdp1draw_info.islinewindow, wctl, &vdp1draw_info.linewnd0addr, &vdp1draw_info.linewnd1addr, Vdp2Regs); } ////////////////////////////////////////////////////////////////////////////// void VIDGCDVdp2DrawEnd(void) { #ifndef CRAB_REWRITE int i, i2; u16 pixel; u8 prioritytable[8]; u32 vdp1coloroffset; int colormode = Vdp2Regs->SPCTL & 0x20; vdp2draw_struct info; u32 *dst=dispbuffer; u32 *vdp2src=vdp2framebuffer; int islinewindow; clipping_struct clip[2]; u32 linewnd0addr, linewnd1addr; int wctl; // Figure out whether to draw vdp1 framebuffer or vdp2 framebuffer pixels // based on priority if (Vdp1External.disptoggle) { prioritytable[0] = Vdp2Regs->PRISA & 0x7; prioritytable[1] = (Vdp2Regs->PRISA >> 8) & 0x7; prioritytable[2] = Vdp2Regs->PRISB & 0x7; prioritytable[3] = (Vdp2Regs->PRISB >> 8) & 0x7; prioritytable[4] = Vdp2Regs->PRISC & 0x7; prioritytable[5] = (Vdp2Regs->PRISC >> 8) & 0x7; prioritytable[6] = Vdp2Regs->PRISD & 0x7; prioritytable[7] = (Vdp2Regs->PRISD >> 8) & 0x7; vdp1coloroffset = (Vdp2Regs->CRAOFB & 0x70) << 4; vdp1spritetype = Vdp2Regs->SPCTL & 0xF; if (Vdp2Regs->CLOFEN & 0x40) { // color offset enable if (Vdp2Regs->CLOFSL & 0x40) { // color offset B info.cor = Vdp2Regs->COBR & 0xFF; if (Vdp2Regs->COBR & 0x100) info.cor |= 0xFFFFFF00; info.cog = Vdp2Regs->COBG & 0xFF; if (Vdp2Regs->COBG & 0x100) info.cog |= 0xFFFFFF00; info.cob = Vdp2Regs->COBB & 0xFF; if (Vdp2Regs->COBB & 0x100) info.cob |= 0xFFFFFF00; } else { // color offset A info.cor = Vdp2Regs->COAR & 0xFF; if (Vdp2Regs->COAR & 0x100) info.cor |= 0xFFFFFF00; info.cog = Vdp2Regs->COAG & 0xFF; if (Vdp2Regs->COAG & 0x100) info.cog |= 0xFFFFFF00; info.cob = Vdp2Regs->COAB & 0xFF; if (Vdp2Regs->COAB & 0x100) info.cob |= 0xFFFFFF00; } if (info.cor == 0 && info.cog == 0 && info.cob == 0) { if (Vdp2Regs->CCCTL & 0x40) info.PostPixelFetchCalc = &DoColorCalc; else info.PostPixelFetchCalc = &DoNothing; } else { if (Vdp2Regs->CCCTL & 0x40) info.PostPixelFetchCalc = &DoColorCalcWithColorOffset; else info.PostPixelFetchCalc = &DoColorOffset; } } else // color offset disable { if (Vdp2Regs->CCCTL & 0x40) info.PostPixelFetchCalc = &DoColorCalc; else info.PostPixelFetchCalc = &DoNothing; } wctl = Vdp2Regs->WCTLC >> 8; clip[0].xstart = clip[0].ystart = clip[0].xend = clip[0].yend = 0; clip[1].xstart = clip[1].ystart = clip[1].xend = clip[1].yend = 0; ReadWindowData(wctl, clip, Vdp2Regs); linewnd0addr = linewnd1addr = 0; ReadLineWindowData(&islinewindow, wctl, &linewnd0addr, &linewnd1addr, Vdp2Regs); for (i2 = 0; i2 < vdp2height; i2++) { ReadLineWindowClip(islinewindow, clip, &linewnd0addr, &linewnd1addr, Vdp2Ram, Vdp2Regs); for (i = 0; i < vdp2width; i++) { // See if screen position is clipped, if it isn't, continue // Window 0 if (!TestWindow(wctl, 0x2, 0x1, &clip[0], i, i2)) { dst[0] = COLSATSTRIPPRIORITY(vdp2src[0]); vdp2src++; dst++; continue; } // Window 1 if (!TestWindow(wctl, 0x8, 0x4, &clip[1], i, i2)) { vdp2src++; dst[0] = COLSATSTRIPPRIORITY(vdp2src[0]); dst++; continue; } if (vdp1pixelsize == 2) { // 16-bit pixel size pixel = ((u16 *)vdp1frontframebuffer)[(i2 * vdp1width) + i]; if (pixel == 0) dst[0] = COLSATSTRIPPRIORITY(vdp2src[0]); else if (pixel & 0x8000 && colormode) { // 16 BPP if (prioritytable[0] >= Vdp2GetPixelPriority(vdp2src[0])) { // if pixel is 0x8000, only draw pixel if sprite window // is disabled/sprite type 2-7. sprite types 0 and 1 are // -always- drawn and sprite types 8-F are always // transparent. if (pixel != 0x8000 || vdp1spritetype < 2 || (vdp1spritetype < 8 && !(Vdp2Regs->SPCTL & 0x10))) dst[0] = info.PostPixelFetchCalc(&info, COLSAT2YAB16(0xFF, pixel)); else dst[0] = COLSATSTRIPPRIORITY(vdp2src[0]); } else dst[0] = COLSATSTRIPPRIORITY(vdp2src[0]); } else { // Color bank int priority; int shadow; int colorcalc; priority = 0; // Avoid compiler warning Vdp1ProcessSpritePixel(vdp1spritetype, &pixel, &shadow, &priority, &colorcalc); if (prioritytable[priority] >= Vdp2GetPixelPriority(vdp2src[0])) dst[0] = info.PostPixelFetchCalc(&info, COLSAT2YAB32(0xFF, Vdp2ColorRamGetColor(vdp1coloroffset + pixel))); else dst[0] = COLSATSTRIPPRIORITY(vdp2src[0]); } } else { // 8-bit pixel size pixel = vdp1frontframebuffer[(i2 * vdp1width) + i]; if (pixel == 0) dst[0] = COLSATSTRIPPRIORITY(vdp2src[0]); else { // Color bank(fix me) LOG("8-bit Color Bank draw - %02X\n", pixel); dst[0] = COLSATSTRIPPRIORITY(vdp2src[0]); } } vdp2src++; dst++; } } } else { // Render VDP2 only for (i = 0; i < (vdp2width*vdp2height); i++) dispbuffer[i] = COLSATSTRIPPRIORITY(vdp2framebuffer[i]); } #endif VIDGCDVdp1SwapFrameBuffer(); if (OSDUseBuffer()) OSDDisplayMessages(dispbuffer, vdp2width, vdp2height); #ifdef USE_OPENGL glRasterPos2i(0, 0); glPixelZoom((float)outputwidth / (float)vdp2width, 0 - ((float)outputheight / (float)vdp2height)); #ifndef CRAB_REWRITE glDrawPixels(vdp2width, vdp2height, GL_RGBA, GL_UNSIGNED_BYTE, dispbuffer); #else glDisable(GL_BLEND); glDrawPixels(vdp2width, vdp2height, GL_RGBA, GL_UNSIGNED_BYTE, vdp2framebuffer); #endif if (! OSDUseBuffer()) OSDDisplayMessages(NULL, -1, -1); #endif YuiSwapBuffers(); } /* FIXME: Support Vdp1 8-bit mode sometime... */ static void Vdp1DrawPriority(int prio) { int colormode = Vdp2Regs->SPCTL & 0x20; vdp2draw_struct *info = &vdp1draw_info.info; int islinewindow = vdp1draw_info.islinewindow; int wctl= Vdp2Regs->WCTLC >> 8; // Figure out whether to draw vdp1 framebuffer or vdp2 framebuffer pixels // based on priority if(Vdp1External.disptoggle) { dispatch_apply(vdp2height, dispatch_get_global_queue(2, 0), ^(size_t i2) { u16 *fb16 = (u16 *)(vdp1frontframebuffer) + (i2 * vdp1width); u32 *fb = vdp2framebuffer + (i2 * vdp2width); int i; u16 pixel; u32 linewnd0addr = vdp1draw_info.linewnd0addr; u32 linewnd1addr = vdp1draw_info.linewnd1addr; ReadLineWindowClip(islinewindow, vdp1draw_info.clip, &linewnd0addr, &linewnd1addr, Vdp2Ram, Vdp2Regs); for(i = 0; i < vdp2width; ++i, ++fb16, ++fb) { // See if screen position is clipped, if it isn't, continue // Window 0 if(!TestWindow(wctl, 0x2, 0x1, &vdp1draw_info.clip[0], i, i2)) { continue; } // Window 1 if(!TestWindow(wctl, 0x8, 0x4, &vdp1draw_info.clip[1], i, i2)) { continue; } if (vdp1pixelsize == 2) { // 16-bit pixel size pixel = *fb16; if(pixel & 0x8000 && colormode && vdp1draw_info.prioritytable[0] == prio && prio >= Vdp2GetPixelPriority(*fb)) { // 16 BPP // if pixel is 0x8000, only draw pixel if sprite window // is disabled/sprite type 2-7. sprite types 0 and 1 are // -always- drawn and sprite types 8-F are always // transparent. if(pixel != 0x8000 || vdp1spritetype < 2 || (vdp1spritetype < 8 && !(Vdp2Regs->SPCTL & 0x10))) *fb = info->PostPixelFetchCalc(info, COLSAT2YAB16(0xFF, pixel)); } else if(pixel) { // Color bank int priority; int shadow; int colorcalc; priority = 0; // Avoid compiler warning Vdp1ProcessSpritePixel(vdp1spritetype, &pixel, &shadow, &priority, &colorcalc); priority = vdp1draw_info.prioritytable[priority]; if(priority == prio && priority >= Vdp2GetPixelPriority(*fb)) *fb = info->PostPixelFetchCalc(info, COLSAT2YAB32(0xFF, Vdp2ColorRamGetColor(vdp1draw_info.coloroffset + pixel))); } } //else //{ // // 8-bit pixel size // pixel = vdp1frontframebuffer[(i2 * vdp1width) + i]; // // if (pixel == 0) // dst[0] = COLSATSTRIPPRIORITY(vdp2src[0]); // else // { // // Color bank(fix me) // LOG("8-bit Color Bank draw - %02X\n", pixel); // dst[0] = COLSATSTRIPPRIORITY(vdp2src[0]); // } //} } }); } } ////////////////////////////////////////////////////////////////////////////// void VIDGCDVdp2DrawScreens(void) { int i; VIDGCDVdp2SetResolution(Vdp2Regs->TVMD); VIDGCDVdp2SetPriorityNBG0(Vdp2Regs->PRINA & 0x7); VIDGCDVdp2SetPriorityNBG1((Vdp2Regs->PRINA >> 8) & 0x7); VIDGCDVdp2SetPriorityNBG2(Vdp2Regs->PRINB & 0x7); VIDGCDVdp2SetPriorityNBG3((Vdp2Regs->PRINB >> 8) & 0x7); VIDGCDVdp2SetPriorityRBG0(Vdp2Regs->PRIR & 0x7); /* Draw all the screens, from the lowest priority one forward. */ for(i = 1; i < 8; ++i) { if (nbg3priority == i) Vdp2DrawNBG3(); if (nbg2priority == i) Vdp2DrawNBG2(); if (nbg1priority == i) Vdp2DrawNBG1(); if (nbg0priority == i) Vdp2DrawNBG0(); if (rbg0priority == i) Vdp2DrawRBG0(); /* Draw anything in VDP1 that should be shown at this priority level. */ if(vdp1draw_info.priosused[i]) Vdp1DrawPriority(i); vdp1draw_info.priosused[i] = 0; } } ////////////////////////////////////////////////////////////////////////////// void VIDGCDVdp2SetResolution(u16 TVMD) { // This needs some work // Horizontal Resolution switch (TVMD & 0x7) { case 0: vdp2width = 320; resxratio=1; break; case 1: vdp2width = 352; resxratio=1; break; case 2: // 640 vdp2width = 320; resxratio=2; break; case 3: // 704 vdp2width = 352; resxratio=2; break; case 4: vdp2width = 320; resxratio=1; break; case 5: vdp2width = 352; resxratio=1; break; case 6: // 640 vdp2width = 320; resxratio=2; break; case 7: // 704 vdp2width = 352; resxratio=2; break; } // Vertical Resolution switch ((TVMD >> 4) & 0x3) { case 0: vdp2height = 224; break; case 1: vdp2height = 240; break; case 2: vdp2height = 256; break; default: break; } resyratio=1; // Check for interlace switch ((TVMD >> 6) & 0x3) { case 3: // Double-density Interlace // vdp2height *= 2; resyratio=2; break; case 2: // Single-density Interlace case 0: // Non-interlace default: break; } } ////////////////////////////////////////////////////////////////////////////// void FASTCALL VIDGCDVdp2SetPriorityNBG0(int priority) { nbg0priority = priority; } ////////////////////////////////////////////////////////////////////////////// void FASTCALL VIDGCDVdp2SetPriorityNBG1(int priority) { nbg1priority = priority; } ////////////////////////////////////////////////////////////////////////////// void FASTCALL VIDGCDVdp2SetPriorityNBG2(int priority) { nbg2priority = priority; } ////////////////////////////////////////////////////////////////////////////// void FASTCALL VIDGCDVdp2SetPriorityNBG3(int priority) { nbg3priority = priority; } ////////////////////////////////////////////////////////////////////////////// void FASTCALL VIDGCDVdp2SetPriorityRBG0(int priority) { rbg0priority = priority; } ////////////////////////////////////////////////////////////////////////////// void VIDGCDGetScreenSize(int *width, int *height) { *width = vdp2width; *height = vdp2height; } ////////////////////////////////////////////////////////////////////////////// void VIDGCDVdp1SwapFrameBuffer(void) { u8 *temp = vdp1frontframebuffer; vdp1frontframebuffer = vdp1backframebuffer; vdp1backframebuffer = temp; } ////////////////////////////////////////////////////////////////////////////// void VIDGCDVdp1EraseFrameBuffer(void) { int s, s2; int w,h; h = (Vdp1Regs->EWRR & 0x1FF) + 1; if (h > vdp1height) h = vdp1height; w = ((Vdp1Regs->EWRR >> 6) & 0x3F8) + 8; if (w > vdp1width) w = vdp1width; s = Vdp1Regs->EWLR & 0x1FF; s2 = (Vdp1Regs->EWLR >> 6) & 0x1F8; dispatch_apply(h - s, dispatch_get_global_queue(2, 0), ^(size_t i2) { int i; i2 += s; for (i = s2; i < w; i++) { ((u16 *)vdp1backframebuffer)[(i2 * vdp1width) + i] = Vdp1Regs->EWDR; } }); } ////////////////////////////////////////////////////////////////////////////// void VIDGCDGetGlSize(int *width, int *height) { #ifdef USE_OPENGL *width = outputwidth; *height = outputheight; #else *width = vdp2width; *height = vdp2height; #endif } yabause-0.9.15/src/cocoa/Yabause.icns000644 001750 001750 00000527464 12755623101 021417 0ustar00guillaumeguillaume000000 000000 icns¯4TOC His32ss8mkil32 .l8mkit32Vpt8mk@ic08Žic09yŸis32sÿ€ƒ€ BÐÑ× € *$ËÖ# N/C0 H7 ÐÍc Vi T^>€ ÏÇÊÿ J{zg…hËÀÛq˜¡‰%’‰‰ÄÅ )ƒ‡b àШˆÀÿ€5ikI’ØÅ§ŒÆ§ËÕMU\š§¨š‰Ëº¡ºÊά´¸¯¯×†‰ˆˆÏÇÀ´°±´º³ªë„ÝÝÊ;. ‰€ƒÿÿ€‚ /• €  #1œ* 88M6 R@€ މB$`t]iG€ Ÿ€…€ S‡…p’t‡u’}¦¯–)751.{{ -”k:²‚?0uy€€5tvR 7”i>2~K‡ŸV]\uK>?91‰jBpŠ–‚Љk^¬1003‘ud^cm™•Ö„™¬¢3. ˆ‚ÿÿ ((%‚((]yy.-y~…kyv€ qŠ$zŒI/€ .+™ªh« ] € {w?U¹Ç%šÀ—€ lr€•×áßÄ!u_ƒÃîõâF fg KÝà«"¦l"af€€&8ÈÊ’ P"k2uŠ3²´‘t7""vT(Zx‡|‡]H¡€ {kaOHM\¡’Ì„ˆ˜I‡{[ ˆ  ‚ÿs8mk³þüüüÛ#ûüüýùèÿÿÿýwrŒëÿÿÿû7ùÿÿÿþkþÿÿý†iÿÿÿþ¬ûÿÿþÔ6ìèýÿÿüèÿÿÿõ ÜÀåÿÿÿÿÿÿü5™ë#÷ÿÿÿÿý{¢Ç·ÑÉKýÿÿÿàŸýÿÿÉÝÓüÿÿÿ»ÇÿÿÿßÉø· ãÿÿÿµÉþÿÿÇNåÿãÒÊùÿÿÿÿۥκ:ÃâôÿÿÿÿÿÇ4Méÿÿÿ{ Þ××Ýgil32 .ÿ‡€„„…€†€ ‚  ‚cq ‚ € lldffÛÿ „   íê€ÿ ìo  † (&_êefgj%& … )2;l :0'… 1)1_—ˆ{t;¨‹]—Mkƒ‘ž®®­šŽ]$L“aƒ§*‡’¡®¸ª{9,00«I˜LL’œ§ª¤™Œ5*EO;552’n_“„v“šœ˜a3d¥‘]C7.0’Ri–…Z‡ŒŽŒ…;2:¾Ø£kC>3.—Fe”„Ty~~x80O¬¸•aC=8.—GM˜L€€Lmprqn9)Cs|hKA:8-–S;€®L€ Gbc`ZRdE0KOF?<96-„{3I~³QSR!>I[n‹ó¯35>><:8/1è“Y/JkžºÌhhkl‘§±²³±°£q|‹6354313‹¥‹W2/Kcu˜ ¦¢¥¡ŒsT.!Kî13531K®¢lP7%"$,-' 1]ºàÿePL²olf^bn uƒ•«»·ª‡tj‚KMTÅÅÆÆÂ—•zP€‚€QSX^V%& €†€ ƒ  ‰ÿÿ€x‚wy‚€ƒƒƒ€z‚wz€‹€€1xs€tn‚EG j€t!srS{|{\DC=?@¥R{|z:ƒ hyx{ƒŒ'•’ž¤¦”E%Š{w{T„#w|…“€?”=@AC~‘‹„{k„ ;ŠŒ”œ§KD‚Q¦š“‰‚$… !d˜œ¤ª¥€ ª©£š—Gƒ Bs#‰£¬³¾v€ Š»²©£sƒBštk2«°»ÂÈ%DÌÁº¯œ†E›am›b¿ÀÊÓ  ¼ÐȾºB€€H™ee›C“ÊÏÙåmY‹æØÍËr€˜yG‡C;"¹ÓÞç÷ó÷äÛÓ¡ B‚Ip•GØßêôüðçÝÉ+ —}0ˆEzáæîñíäÜW57!‚XG‚„ »ßåæäÝ› R”|@$:T„…•ÖÛÛÚÕb%±Ï’S% …,P‚„’ÌÏÐÐËc:ž«‚F% ….5‡D€ ŒÂÄÆÅÂf *\eN-#„< l›A€€ ˆ¹»º·²P]1.1(" qf0k IKKKn£¨¯¹À–‹è¥ !!á‚A1WŠ©Àcdgk³ÔÚÒIJ¢“^j~ “xA3Nb„Ž•“Œˆ†x\<3næ€ D›W9 €'E{¬Øÿa HCŸŠy\WQIMY_n‘§»¼‰rg‚BFM´·¸º·‰ŸµÁÄ´›I€‚€GLQYR$nˆusx<† ƒ@YZ€]2 ˆŠ~‚}~‰ÿl8mkHyl~‰HÿÿÿÿÿÿÿÿÿÿD+ÿÿÿÿÿÿÿÿÿêXÿöùùùùùùúÝÅýùùùùùùõò,‘ÿþÿÿÿÿÿÿÿv3]Œ™’jÿþÿÿÿÿÿüÿbËÿÿÿÿÿÿÿýú·ð÷àǹªöüÿÿÿÿÿþÿš0úýÿÿÿÿÿÿÿÿ‚c/ÿÿÿÿÿÿÿÿÔhÿÿÿÿÿÿÿþõHÿþÿÿÿÿÿüÿ9¨ÿþÿÿÿÿÿÿÔâýÿÿÿÿÿýÿp&ªüýÿÿÿÿÿÿÿ^…ÿÿÿÿÿÿþÿª(¸ÿÿÿûÿÿÿÿÿüîDÿýÿÿÿÿÿýç ¿ÿÿ{ÿýÿÿÿÿÿÿàþÿÿÿÿÿûÿLœÿü¯°ÿþÿÿÿÿýÿþÿÿÿÿýÿ‰Hÿùèáþÿÿÿÿÿýÿÿÿÿþÿ» ÔùúxEÿüÿÿÿÿÿÿÿÿÿýï$y¢T=þÿò zÿÿÿÿÿÿÿÿÿÿÿQ+ºÿÿÿÿë¡öÿÅ»ÿÿÿÿÿÿÿÿÿ‘ÎÿûúûùÿÿPáÿÿ—=ÿÿÿÿÿÿÿÿýYÿüÿÿÿÿþù×öÿÿ«(ÿÿÿÿÿÿÿÿûøÿÿÿÿÿÿÿÿöÿÿæ,ÿÿÿÿÿÿÿÿû þÿÿÿÿÿÿÿÿÝþÿÿ’#ÿÿÿÿÿÿÿÿé túþÿÿÿÿÿùí‰úÿýÿœLÿÿÿÿÿÿÿÿðŸ¶òþûýýüûÿvôúþúÿæ©‹|tÿÿÿÿÿÿÿÿÿÿÿÿéÿÿÿÿÿ¥ küÿûùÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿÌSœÃ̱} sÖÿÿû÷ö÷ùúÿÿÿÿÿÿÿÿÿå•1-4A–ÐÿÿÿÿÿÿÿÿÿÿÿÿÿÿðM:nŸ±ÂÇÿÿÿÿÿÿÿÿÞ .@ýýýýýýýýàÿÿÿÿÿÿÿÿæççççççççÊLLLLLLLL@it32Vpÿÿÿÿÿÿ÷ÿýùýÿýýýÿÿ…—³•’—²•“•±••–¯”––—Ї”—•„Š…•™’ Š‚„enmllkk€l€k† ’› †‚mklkèñ€ðîï€ðïîïi„ œ  „nl€k ðïðïïîïÓÑцÒÐùƒ Œ  „j€kñð€ïу҆׀Ò܆ƒ ŒŸŠ  ‚]ìïîïÑÒ†×Ò€Ñïïî‚  Š¡ˆ   ‡×€Ò†×ÒÐîïïîðñô€k?‚  ˆ¡† !"$‚ ÂÕ„×Òðïîîökmmp #  ‡£… !#%&)‚TÜÖ€×ÒÒÑïððîl€ks„€ &%$" …¥ƒ "#%')+'©Ö€Òïðñkllj‚„„$)(&$#  ƒ§ !#%&(+,.2‚1Ýïïìklm‹/,*(&%#! § !#%'*,-/122€fkki€ 11/-,*'%#! €© !#%'*,.13568'€‘*6531.,*(%#! « !#&(*,.13579:=€•<97532/,*(&#! ¬ !#%(*,024579;=?6š:><:75420-*(&#! ­ #%(*-02469;<>@BF›+DA?=;9642/.+(&#!¯ #%(*-/2469;=@BDFFD˜GECA?=;97420-*(%#  «"$'*,/2469;=?BDFHJM/—?JHFDBA=;9742/-*(%#«€!$&*,/2469;=ABDFIKMOO—)QMLJGDCA?;9742/,*'%!ªl‚ #&),.1369;>ACDHJLNPRTA”PQPNLJHECA>;9642.,)&#! ªkð˜ &(+.0358;=ACEHJLNPRTVZ“AWTRPNLJHECA>;9640.+(&© kîÒâv,,0258;=@CEGJLNQSUWY[R’#]YWUSQOLJHEB@=;8520-+¨ kïÒ×ÔÖM€%.247:=?BDGJLOQSUX[]_b4‘ V^][YUSQOLJGDB?=:742.)¨„kïÒ€×Ú«‚ .369ea_][YWTQOLJGDB?<9631¨„ÿïÒ×֨׶½™77;=ACFILNQSVX[]_acehJgeda_][YVSQNLIFDA>;86¨]ÿÌÒ×ÖÙÓ±²Ôàqƒ$;ADGJMPRUX[]_bdfjlnn^Œ8smljhdb`][XUSPMJGDA>8 ¨ „ÿÕØ×ÖÚͦ®×ÒÓƒ>BFHLNQTWZ]_bdgjlnprw5Œorqnljhdb_]ZWUQOLIFBB¨ ÿÌÖ×ÖÚÌ¥©Ô€×Òïq„EGJMPSVY\_adfilnpruvp ˆYxuspnljgdb_\YVSPNJGF*¦kÌØ×ÖÙÌ¥¤ÒØ××Òðl„1JLORUW[^`cfilnpsuwy}MŠ.ywusqnlifd`^[XURPLI=§mîØ××ØÎ§žÍØ××Òîl… BMQSWY]`behknpsuw{}~‡ r~|{yuspnkhfb_]YWSPMI©nðÒ××ØÑª™ÄÙÖ××îk‡OQUW[_`dgjmosuw{}‚„e„P‡€}{xuspmjhda_[YUQR&¨eñÑ€× Ô­—¹ÙÖ××Ók‡)UUY]_bfhlnquwz}„†‹1„#ˆ…„‚}zwuqolhfb_]YVU7¦èÑ€× Ø³—¬ÖÖ××Òè‰=YZ]`dfjnpsvy|~„†ˆŠ} „tŒˆ†„‚|yvsqnjhd`]ZWJ ©mӀר»š Í€×ÒðeŒ Q[_aehlnquw{~€„†ˆŒŽ“R‚ K“ŽŒ‰†„~{xuqnlhfb_[X¨jð€×ØÆœš¼Ù€×îl]_bfjloswy}€‚…ˆ‹Ž‘’|}€~}|‘‘Ž‹ˆ†‚€}ywsomifc_`.¦îÑ€× Ò¤›¨ÖÖ××Òk3dcgkmptw{}€„‡Š’•—  €¡  ˜•“Šˆ„€{wuqnjgdcE¨lÒ×°™œÊ€×ÒðJfgkorux{~‚†‰Œ‘•—™šœ€œš™—•‘Œˆ†‚|xvrokieW¨„î€×Ø¿™›±Ø€×ðk’\hkorvz}ƒ‡‰Œ“—™œž €£ žœ™—“‰‡ƒ|zvromhe ‡ ÿÑ××ÖÑ œÏ€×Òl•,$ilorvz}ƒ‡‹Ž”˜›ž ¤¥¦¥¤¡ž›—•‘‹‡ƒ~zvsplm7‰€‡€‹jÌ€×Ù²š›³Ø€×ð“,A-€‘1?=;96420.,(&$! « #%)+-02469;=?ACF€•EA?=;97420.,(&# ¬ #%(+-02479=>@BDFH=™AGECA>=;7520.,(%# ­"%'*-0257;=?BDEGILP"›1NJHFCB?=;7630.+(%# ¯ "%'*-0257;=?ADFHJLOPL˜QNLJHFDA?=;8520-*'%" «"$'),/247;=?ADFHKMOQSW5—GTRPNKIFDA?=:7520-)'$"ª€&)+.247:=?BEFIKOQRUWYY—.\XUSPOMIHEA?=:742/,)& ªO‚&+.1469ADFIMOQSUXZ\^`d#“Hb_\ZXWSQOLIGDA?<9630/© M«•¡U448;=ADFILOQSWX\^_bdf[’'hdc`^\YWSQOLIFDA>;853%¨ L«•™—˜;€,7:=?CFHKNQSVY\^`cegim:‘ `hgeb`^[YWSQNKHFC@=:71 ¨ =Lª•™˜™žd‚ 7;?AEHJMPSUX[^`begikllŽEpligeb`^[YVSQNJHEB?<:¨Wšª•™˜›™ejj?@DFJLOSUX[^`bfgjloqtRŽsqpmjiec`^[XUSPMJGDA?#¦=µ˜•™˜œ“\^– Q*DEHLOQUWZ]`bfhjnprtvz#dvtrpnkieb`^ZWUROLHFC3©=›”™™˜ŒU\™š—™)‚:GJMQSWZ\_behjnprtvxzhŒ?yvtrpmkheb`]ZWTQMJGA¨‹›€™˜ŠLX™•—ƒGKORUX\^begjmprtxy{~„:Œ{}}ywurpmjgeb_\YUSOKK¨ 陘™˜‡JQ•€™•©R‚#PPTWZ]`cgilortxz}ƒ|ˆb…}{wurpmigd`^ZXUQQ/¦Mˆ˜™˜œˆJHš™™•©L„8UUY\_beiknrtwz|ƒ†ŠUŠ2‹…ƒ}zwtrokieb_\ZUSE§M«›™˜›‹M>‡›˜™•«L… KWZ]`dgknptvy|ƒ†ˆŠŠ‡ }‹‰†…|yvtqmjgea^ZVR©N«•™™šQ4zœ˜™™ªM‡Y[_beikpruy{ƒ‡Š‹‘o„X”ŽŒŠ‡„|xvrpliec`[]*¦L«•€™ ”W1hœ˜™™•L‡/``cgkmptw{}ƒ†‰Œ‘’˜6„'”’‘ŽŒ‰†ƒ}{wtrnkge``>¦ª•™™˜›`3S˜˜™™”ª‰Dceikprvy|‚†ˆ‹Ž‘“•—‰ „€™•“‘ŽŒˆ†‚}yvrpkieaS © K•™™˜m8@Š€™•«LŒZfilptv{}„ˆŠ‘“•™œ¡Z"ƒ#R¢›˜–“‘ŽŠ‡„}{xtpmifc¨J©€™›:7oœ€™«N#hinqtx{ƒ†ˆŒ’•˜›žŸŸ‡ˆ€‰ˆˆŸŸžœ˜•“Œ‰†‚{xuqojk4¦¨–€™ G8M—˜™™–M28onsuz|€ƒ†Š‘”—š ¢¥®¯±°±¯®¦¢ žš—•‘‹ˆ„}yvronL¨ L–™™˜™[6;…€™•§Rrswz~„ˆŒ“–˜œŸ¢¥§©ª€¬ª©§¥¢ œ™•“‹‰…‚~zwtpa¨‹ª€™›s79\œ€™©I’gswz~‚†‰”–šž¡¤§ª­°€±°­«§¤ ž›–”‰…‚~|wsq$‡é•™™˜@:<Œ˜™™•L“(uv|~‚†‰”˜›Ÿ¡¦©«¯²€µ²°­©¦¢Ÿœ˜”‰‡‚|wx=‰€‡€‹Wˆ€™š]79_›€™©“,C|{‚†‰‘”˜›Ÿ£¦ª­±´·¹·´±­ª§£Ÿœ˜”’Їƒ|zZˆ€€€Š´›€™ ‚9:<˜™™•L•)^~‚‡Š‘”˜œŸ£¦ª®±µ¸»¸µ±®ª§£Ÿœ˜•’Їƒ€{nˆ 933443:ˆW’€™˜M99W›€™«™(t~‚‡‰‘”˜›Ÿ£¦ª¬°´¶¸¶´±­ª¦£Ÿ›˜”‘Ї‚~~,†343,…-+€3…µš€™ ~798‚˜™™˜M—(0…‰‘”˜›Ÿ¢¥©«®²³´³²¯¬©¦¡Ÿ›˜”‰‡„H†54€-‚/‚.€-33…”™N:9I˜™š&K†„‰Œ“—šž £§©«®¯°¯®­ª§¤¡žš—“‰…„g†:3,-./0-,+*+€,-.--3‚L™899h™›šg†‡‹Ž‘•˜œž¢¤§©«¬©§¤¢Ÿœ˜•’Œˆ„y‡4+-.//+'19=>;8752.,-€.-37‚©€™šR998†™="}†ŠŒ‘“—™œ ¢¥§¨¨©¨¨§¥¢Ÿ™—“‘Š…†4…2-..0,(=R^aa\RIEB>:50-€.--3‚=•€™:99D™—6‰‡Œ’•—šœ ¡£¤€¥¤£¡ ›—•’ŒˆŠQ‡3-..0'8`xŠ…{peZOFDCC@;5/-€.-4€›™k€9\™¦ S‹ŠŒ’•—™œžŸ‚¡ ŸŸœš—•“Šˆo ‡4-..0&L ’Š‚yodXLDCB@@>70-€.-3‚™F€9n™HŸ  n‰Š“•—š›€ž ›š—•“‘Šˆ€ ‰6-../(W𲩥Ÿ—ƒxl`SGDBA?>>80.-€˜€™‰8€9™¢ ƒˆ‹Ž“”–—™‚š ™—–•“‘‹ˆ†=†,€.+S¨º·¸²¬¢˜‹€sfYLDCA@>=<80.3K™o9‘™  {†ˆŠŒ‘’”•‚– •”’’Šˆ†ƒˆ3.<£¾ÂÇÆ¿¶«Ÿ’†xk]PECB@?=;;7.-1¨™V€9:˜€™š¢x„†ˆŠŒŽ’’“”“’’ŽŒŠˆ†„ˆ-.ƒ½ÅÐÓÓÊ¿²¥˜Š|oaSEDBA?=<::3.-•€™˜?€9@™š£ v€ƒ†‡‰Š‹Ž‚ ދЉˆ†„€‡6.N±¼Ë€ÖÒÄ·©›qcUFDBA?><:99/‚.š€™Ž8€9G‚™£t}‚ƒ…‡‰‰„‹ ‰‰ˆ…„‚€}{ˆ-€.-ˆ¯¾Ë×ÖÖÔÆ¸ªœŽqcUHDCA?><:995./š€™~9F™›£p{}‚ƒ…€‡ˆ‰ˆ€‡…„‚€}{x‡.<ž¬¹ÆÑÕÔ娛qcUGDBA?><:998/.™n9>™š£ nyz|}€€ƒƒ‚„ ƒƒ€€}|{yv‡7.Z™¦²½ÅËÉĺ¯£—‰|naSEDBA?=<:€92.™d‚9˜€™˜£kuvx{|~~„€ ~~|{xwus‡-.l’ž©²¹¼»¸°§œ‘„xj]PECB@?=<:€94.™a‚9™¢ hrtuwxzz||}€~ }||zzxwusrp‡/.tŠ”¦¬®®ª¥”‰}reYLDCA@>=;:€96.™]‚9z™£fopssuvwx„y xwvusspon‡-.s€Š’˜ž  ž˜’Š€uj_SGDBA?><;96.™\‚9e™L¡bknoqqss†ussqqonkj‡-.lv~…‹’’Œ†vlbWKDDB@?=<:98.™`‚9Kš€™ª¢`hjkmno€qr€sr€qonmkjhf‡‚._jry‚„„‚yslbYNFDBB@?=;:97.š€™j‚9:‰˜™™–L \ffhijlmm„n mmljihffc‡-.P^flqtvvuqmg`XOGDDA@@==;:95.š€™tƒ9cš€™ªŸZbcdfhhi†jihhfdcbaˆ,.ARY_cfhhgda[ULGDDC@?>=;;‚94.˜€™ƒ8‚9B”˜™™•M›  W^_abdd€fg€hg€f ddbaa^] …2.8HKQUXZZYVSMIEDDCA?>==;ƒ91.•€™•>‚9 8d›˜™™«Lš  S\\]_`abb„c bba`__]\Z „.2CDGIJKKJIGEDCBBA?>=<;„9‚.¬€™šPƒ9 ;‡š™™•©N›PXZ[[]]^†_^]][[YXW-/€.=CDCDCCD CCB@??=<;;ƒ94.,N™k„9P•€™•«L™NTVWXYZ€[\][ YXWVTT‚^b4*€.3BB„C BAA@@?=<;;„9/.6•€™<ƒ9 5_™˜˜™•ªLJ—KRRSTVVWXYXWVVUR‚ +hggfÛÜ‘?/€.:…A@@?>>==<;„93.-«€™›Tƒ9 :6h›š˜™•©¨M‹€”GNPP€R‚T"UTUUVVUUQKGAB 'C^z¬èçæåÉÇ×*/../<@?@??€><;;:ƒ9:5.,.N€™˜‚8ƒ9 :8g•œ—™•–ªéOV€€ DJLLNNPPQR€TUTOKGBBQat†™“­ÈãëÞÏÎËÉÍËÈÉO-€.2=?‚>==<<;;„9:7/.2”€™šW8„9 5\ ™˜™–Н¸QRU†ƒ0BIKLMOONLIGDA>FSevˆ™ª»ÎàìíæÞÖÒÒ×ÙÛÝÝÛ×Ì©3/..-2:==‚<;:…9:60.-€µ•€™‹<:ƒ9:3Ry›—™Ÿ››´¶»TTU^27<;:97;DMZhv„‘Ÿ®ÀÓäñïëæßÛÙÚßäèëÞÌ»ª£ž¬ÔÓ†*0..-17;<;€:…9:95/.-1€Wª€™›l5:ƒ9W;3?cˆ¡  ž ¢»½¾ÈXYZ\]\^``baac($Wcmw‹•ž§¶ÄÓáïóñíéåáàßäéïóï×À¨‘|k[KEAOÐÐu'0..-/37::„9::962‚.,7‚L–™™˜™]4:ƒ9N:83Mk‡¢¦¤¢¤¦¥§ªªÅÆÈËÍÎÑÔÖØÙÚÝ£Œ˜›¥´¾ÈÓÜèîííëéçäááâãéïôùûéÏ· ‰qZC.*.15675;ÅÏÌs&.-0357898752/-€.-,6ƒ¨•€™“R4:ƒ9O::43Jf—«®¬«ª¬®¬®°³µ·¹»½¾ÀÂÄÓÛÜÜÝÝÜÛÛÚÙÙÚÚÝÞäéîóøýûèÓ¾©”~eN6(,27;<<;:;=8<ÇÐÐÌb*-.-.0ƒ20/-.-49ƒ J©•™™šŒU4:„9::50BWk–§¶¹¸¶··¸·¹»½¿ÁÂÄ€Æ!ÈËÍÐÓØÛàåéîòõ÷ëÛο±¡{fP<)*/4:=<;:€9:<9-F’ÖÒÐÏÝ>3,-.„-‚.-.3† Lª•™˜œ[49:„97:;72/>Sbq€‘ž§²ºÆÊÌÎÏÒÔÕØÛÝàÞßÜÜ×ÏÆ¾µ­£™€pbRC2'*/48==<;:‚9:<9.7m§ÛÕÔÑÊk"53€-†.€-+3/† L©•™˜›“b;5;:„9:;;830-8GT\emw‚ƒ‰Š€Œ‰‡…€}|ulbYOE;0')-037:=<<;:„9:;=6-:k›ÑäÖ×ÔÍæ€€4,…-343:ˆLª•™˜š™tL18;:…9(:;;<9631/-+/0/54553/+())**,.02469;==<;;::†9:;<:1)Ep¢ÒìߨØÒÑëg€633434‹L©•™˜™ †^>18;:ˆ9:€;<<€;‚:;<€=<€;::‹9:;=;3+3\†°ÚñäÜÜÖÓïéi€L©–•™—˜x[>16;;:«9:;<=91*1SvŸÉðóèààÙØóòkg‚€†L©ª•™˜™ –y\E238;;::£9:;<=:4-'8[~¢ÃåüòçääÞÛøömn††•KLª••™—š —€jT>/259€;::˜9 :;;<=<83-'5QnŠªÍïÿúïåãæáßüûon©L¬ª••˜—™Ÿ¢‘{iZJ:.1368;<‚;ˆ:;#<<==:741-))}xˆy {|~€ƒ„†ˆ‰R‚;–€—‚…†ˆƒ…†—˜—{ ‚ 5Œ‡†„ƒ€~}{ˆyx~KY|‡y {}~€‚ƒ…‡ˆŠ‹ŒŒVˆ€…†ˆ€…„„€—˜——’DED( ‹Š‰‡†ƒ‚€}{‡yze  n†y{}€‚„†ˆ‰‹ŒŽ‘m€z‡„ˆ…˜—˜˜›€DEDC?Z’ŽŒ‹‰ˆ†„‚}{…yxt¡*yxƒy{}‚„†ˆŠ‹Ž’’˜2‚5‹ˆ€…——˜—EDEEH„€'’‘Ž‹Šˆ†„ƒ}{ƒyx|5¡B}xy{}‚„‡ˆŠŒ‘’”•–ƒl‡€…€—DDED‚„ƒ}•”“‘ŒŠˆ‡…ƒ}{yx}O£\{€y{}‚„‡‰ŠŒŽ’“•–˜™žP‚‹—˜•DDC‚‹Nž˜–•“’ŽŒŠ‰‡…ƒ}{€yzh §oyyz}~€‚„‡‰‹Œ’”•—˜šœœ˜@DEB€—›š˜—•”’ŽŒ‹‰‡…ƒ}{yxv!§+zx|~€‚„‡‰ŠŒ‘’”–—™šœžŸ¢n€‘v¡ž›™—–”’‘ŽŒ‹‰‡…‚€~|y|9§F}€‚„‡ˆŠŒ‘’”–˜™›Ÿ ¢¢¦,€•?¦¡ Ÿœ™˜–”’‘ŽŒŠˆ†„‚€}V©d„†ˆŠŒŽ‘’”–˜šœžŸ¡¢¤¥¦Š™—¤¤¢¡Ÿžœš˜–”’‘ŽŒŠˆ†„€o­y‚…ˆŠŒŽ’”–˜šœž ¡£¤¦¨©°K™j­¨§¥£¡ žœš˜–”’‘ŽŒŠˆ†‚€'­3ˆ†‰‹’”–˜šœž ¢£¥§©ª¬«¢˜.¬«ª©§¥£¢ žœš˜–”’‹‰†ŠD©PŠ‘”–˜šœž ¢£¥§©«¬®¯´l—’¯®¬«©¨¥¤¢ žœš˜–”’‹Œd©pŽ‘“•—šœž ¢¤¥¨©«­®°²²³%•[¹²°¯­«ª¨¦¤¢ žœš—•“’Œ~ªE‚‡’•—™›Ÿ¡£¦¨ª«­¯±³´¶·Œ”°´´³±¯­¬ª¨¦¤¢ žœ™—•“0¨"E˜`=–’—™›Ÿ¡£¥¨ª«­¯±³µ¶¸¸¾B“‰»¸¶µ³²¯­¬ª¨¦£¡Ÿ›™–”—P§&C˜…K^š—šœž¡£¥¨©«­°²³µ·¸º»¼§ ’GÁ»º¸·µ³²¯­«©§¥£¡Ÿœš˜—s§ C—…ˆ†‡6€ ~šœž ¢¥§©«­¯²³µ·¹º½¾ÀÆg‘®¿¾½»¹·µ³²¯­«©§¥£ žœ™¨ ?D—…ˆ‡ˆQ ‚%•œ ¡¤¦¨ª­¯±³µ·¹»½¿ÀÂÁ½ŽzÈÂÀ¿½»¹·µ³²¯­«©¦¤¢Ÿœž;¦+Y’—…ˆ‡ŠˆNS]F¤Ÿ£¥¨ª¬®±³µ·¹»½¿ÁÂÄÅÉŽ4ÇÅÄÂÁ¿½»¹·µ³±®¬«¨¦£ ¤]¦?¬……ˆ‡ŒEG„Hj§¤§ª«®°²´¶¹»½¿ÁÃÄÆÈÉÎ:¨ÊÈÆÅÃÁ¿½»¹·µ²°®«ª¨¥¤‚ ¨?’€ˆˆ‡Œz=E‡‰†‡%‚§¨ª­¯²´¶¸»½¿ÁÃÅÆÉÊÌ̬ŠgÔËÊÉÇÅÃÁ¿½»¸¶´²¯­ª¨¥œ$¨’†‰ˆ‡w2Aˆ‰‡ˆ……-£¨¬®±´¶·º¼¾ÀÂÄÇÉËÌÎÏØ_Œ#ÉÎÎÌËÉÇÅÃÁ¾¼º¸µ´±®¬¨¬F¦à†ˆˆ‡Œt19„ˆ‡ˆ…–G‚P¯¬°³´¶¹»¾ÀÂÄÆÉËÌÎÐÒÒÆˆœÖÒÐÎÍËÉÇÄÂÀ¾¼¹·´³°­°k¦Etˆˆ‡Œu0/‰‡ˆ…—C„z³±³¶¸º½ÀÁÄÆÉÊÌÎÐÒÔÖÚ…ˆNÜÕÔÒÐÎÌÊÈÆÄÁÀ¾»¹¶³±¯”§C˜‹ˆ‡Šx4$uЇˆ…˜C…²´¶º¼¿ÀÃÅÈÊÌÎÐÒÔÖØØ×,‡ÂÙØÖÕÓÐÎÌÊÈÅÃÀ¾½¹¸´°­0©E—…ˆˆ‰~8gŒ‡ˆ‰˜E…:´´¸º¾¿ÁÅÇÊÌÍÐÒÔÖØÚÜÞ¨„…ãÜÚØÖÕÒÐÎËÊÇÅ¿½»¸´»X¦N˜…ˆˆ‡ƒ?RŒ‡ˆˆ‚E‡^½¸»¾ÀÃÅÉÊÌÏÑÔÖØÚÜÞßåQ„:àÞÞÜÚØÖÔÒÐÍÊÉÅÄÀ¾½¹¼|¦¢…ˆˆ‡ŠI;‡‡ˆˆ„¡‰†½¼¿ÁÅÆÉËÎÐÓÖ×ÙÜÞàââÌ„½äâàÞÜÚ×ÖÔÐÏËÉÇÄÁ¿½º¡© E‚ˆˆ‡ŒW&w€ˆ…™OŒ«½ÀÂÅÇÊÌÐÒÕÖÙÛÞàâäæí‚ƒ23xîåäâàÞÛÙÖÔÒÏÌÊÉÆÂÁ¼»8¦?˜€ˆŠk Z‹€ˆ—FA¿¿ÄÅÈÌÍÑÔÕ×ÛÝàâãåèèæÃÄ€ÅÄÄæèèæãáàÝÛØÕÔÐÍËÉÆÃ¿Åa¦“…€ˆ ~-5†‡ˆˆ„DhÈÂÆÊÌÎÑÔÖØÛßàâåçêìîøù€úùøïìêèåãàßÛÚÖÕÑÎÍÉÇÄÆŒ¨ D†ˆˆ‡ˆC q€ˆ…•“ÈÇÊÌÐÒÔØÙÜàáãçéìíîîð€ñðîîíìêçåáàÜÚØÕÓÐÍËÈÅ­¨—€ˆŠ^D‹€ˆ—C’!´ÈÊÍÐÓÖØÛÞàãäçëìïñóõ€÷õôñïìêçåãàÞÚØÕÓÐÍËÆÆ?Œ†ß…ˆˆ‡}&!y‡ˆˆ…D“EÉÉÍÐÓÖØÛÞàãæéëîðóõ÷€ù÷öóñíìéåãàÞÛØÖÓÐÎÉÏl‰€‡€‹?t€ˆŠFHŠ€ˆ˜“,sÒÍÐÓÖØÛÞáãæéëîðô÷ùûýûùöôñïìéæãáßÛÙÖÔÐÍÏšˆ€  €Š“‹€ˆ o!{‡ˆˆ…E•) ŸÑÏÓÖÙÛÞáãæéìîñô÷ùüþüù÷ôñïìéæäáßÛÙÖÔÑͺ$ˆ  € ˆY†ˆ4?Š€ˆ—™('ÀÏÓÖØÛÞáãæéìîñôõùúüúù÷ôñîëéæãáÞÛÙÖÓÎÑK†  €  …­ˆkn‡€ˆD—PÔÑÕØÛÞáãæéêîïòõ÷€ø÷õóïîëéæãáÞÛØÖÑ×y†  ‚€ …ˆ4/‡€ˆ…š|ÚÔ×ÛÝßãäèêíïðóô€öõóñïíëèäãßÞÛØÕÖ¨ † ‚C‰€ˆmRˆ’š# ©××ÙÛÞâãæèëíïðòòôòóðïíëéæãáßÜÙØÓÅ,‡ "%&! ‚–€ˆ‰9tˆ?-ÉÕØÚÞàãäæéëíîï€ðïîíëéçäãáÞÜØÔØU… ';GIF@4*&$"€ ‚?…€ˆ|*ˆƒ"YÛÕÙÜÞáãåçéêìíîíîíìëéçåãáßÜÚÖÜ„‡€"KdtocXK?2'&%$"ƒ€“ˆV€Eˆ …ÞØÚÝßáãåæèêëêëêëêéæåãáàÝÛØÙ³† €7l‹€xnbWJ<.&%$##!†ˆ-€XˆJŸ±ØÙÛÝßáãäåæççèççæåäãáàÞÛÙ×Ì4‡CŠ£š•†znaRE6'%$#"!! €ˆv€lˆ  4Ñ×ÙÛÝßàâãää€å ääãâáßÝÛÙ×Õb† €>™­««¥’…xj[L=-&%$"! DˆY€€ˆ† ÇÖ×ÙÛÜÞàááâãâãâááàßÜÛÙØÖÔˆ'”³·½»´©œŽ€qbRC2&%$#"! ‚•ˆ>€ˆ‰¢ÄÔÖ×ÙÚÛÜÝßàßàßàßÝÜÛÚÙ×ÖÔÒˆ r°ºÇËÊÁ´¥•†vfVG6&%$#"! ƒ€ˆ‡%€%ˆ‰£ÂÑÓÕÖØÙÚÛ€Ü ÝÜÜÝÛÚÙØ×ÕÔÑЇ9¤°ÁÎÎÏʺªš‰yiYI8'%$#"! "ˆ{€-ˆ‰£ ÀÏÑÒÔÕÖרÙÙ€Ú ÙÙØØ×ÕÕÒÑÏΈ€v¡±ÁÏÎÎÌ»«›ŠzjYI9)&$#"! ‰€ˆi,ˆŠ£ ¾ÍÏÐÑÓÔÕÖÖ×€Ø×€ÖÕÓÑÐÏÍ̇ 'ެ¼ÉÌÌÅ·¨˜‰yiXI8(%$#"! €‚ˆY$ˆ‰£ ½ËÌÎÏÐÑÓÔÔÕ€Ô ÕÔÔÒÑÐÏÎÍËʇE‡–¤±ºÁ¿¹®¢“„ufVG6&%$#"! €ˆM‡ˆ£ »ÉÊËÍÎÏÏÐÒ‚Ñ ÒÐÏÏÎÍÌËÉLJW€™¤«°¯«¢—‹}o`QB3&%$#"! €ˆI‚{ˆ¢ ¸ÆÈÉËËÌÍÍÎÎ€Ï ÎÎÍÍÌËËÊÇÆÅ‡‚^v‚–ŸŸœ•ŒuhYK<-&%$#" ˆF‚f€ˆ‡£¶ÄÅÆÇÉÊ€ËÌ€ÍÌ€ËÊÉÇÆÅÄÇ\jv†ŒŒ†uj^PD6'%$#"! ˆD‚N€ˆ‡C¡³ÂÃÄÅ€ÇÉÉÊ€É ÊÉÉÇÈÇÅÄÃÂÀ‡‚R^hqw|€€|xqi_TH;-&%$#"! ‰€ˆJ‚2‰€ˆ–¢ ±¿ÀÁÂÃÄÅÅÇÆ€Ç ÆÇÅÅÄÃÂÁÀ¿¾‡DQZcimoomib[SH=1'&$#"! ‚‰€ˆU‚v‡ˆˆ…D€¯½¾¿ÀÁˆà ÁÁÀ¿¾½»…5CLSY\__]YTMF<1(%$$#"! ‚ˆ^ƒL‰€ˆ—Ÿ­»¼½¾€¿ÁÀ‚ÁÀÁ€¿¾¼»º¹ˆ%5>DIMNNMJF?8.(%%$$#! ‚ˆo‚)‚‡ˆˆ…D›ª·¸¹º»€½¾‚¿¾€½»ºº¹¸·… )-39=>>=:6/*&€%$"!! ƒ„€ˆ„#‚ MЇˆˆ—E𠍵¶·¸¹¹»º¼‚» ¼º»¹¹¸¸¶µ´„€%%(*,--,+)&%&%$#"€! ƒ•€ˆ‰7‚ t‰ˆˆ…˜C›¦³´´µ€·¸¸¹ƒ¸€·µ´´³²€"€%$ %%&%%#$""!!„BˆV„8ƒ€ˆ…—E–€ £±²²³³µ´¶µµ¶µ¶µµ³³²²±°‚_b€$$…%##""! !… …€ˆz!ƒ Hˆˆ‡ˆ…˜D?— ¡­®°±°±²²³³´ ³²³±°±°¯®­‚ *ddcbÖØ€+€$…#""!! …‚˜€ˆ‰<ƒ RЉ‡ˆ…—’CŒ€” Ÿ«¬¬­®®°¯°±€°±€°¯¯­«©§¦&@[v§ààÝÜÀ¾Ï‚ #ƒ"€! …ƒ E‰ˆˆ‡n‚ P„‹†ˆ…†–áFG€ ©©ª««¬¬­­€®¯®¬«©§§¬°¶¼Á¨ÂÜä×ÈÆÄÂÄÿÀ<€!"!"! † €€ˆ?„ F{‡‡ˆ…xœŸIKW†)𦍩ªª«ªª©¨¨¦¥§¬²¸¿ÄÊÎÔÙÝçàØÐÌËÏÒÕÖ×ÖÐÄž€!„ †‚ €¬…€ˆx"ƒ:e‹Œ†ˆ‹£¦´MNNQ•‚¡,¢¥¨­²¸½ÂÆËÑØßãâáÞÛØÓÔÚßäèØÄ±ž—ŸÍËx Š‚Y—€ˆ‹Wƒ1 %Mv‘’’¬®¯´RSTVVXXZ\]\_^%#ž«¯³·»¿ÃÆÌÑØÞã€åâàÞÝÝàæìðëѶœjWD3,'7€ÈÈfˆƒ ‚D„ˆˆ‡‡F ƒ* 5Vt’—•“”˜–šœž·¹»¾ÁÃÅÈËÍÎÓÓ›†Š“–ŸÁÈÌÑÕÚÝßàßáçìò÷ùåÈ­’w]C*  ½ÇÃb€€ ƒ˜…€ˆ: ƒ$ 1On†¡žœœž Ÿ¢¥§ª«®°²´·¹»ÊÑÓÔÖÖÑÑÒ€ÔÖ×ÙÛàæìñöüúå̵„lP5 !"!€ ""¿ÉÈÄT‚„ ƒ E–…ˆˆŠy<ƒ (?Un†˜ª­¬€«¬¬­°²´·¹»€½!ÀÃÆÉÎÒ×ÜàåêîóõçÖǵ¥”€iP9! "! €!-ƒÏÊÈÇÒ ƒƒ ˆ C˜…ˆ‡‹|B„7 #:K\n€™¥°»ÁÃÆÇÉËÎÑÔ×ÜÙÙÖÖÐȽµ« –‹n]L:) ""! ‚!Z›ÕÎÌÊÂd €… ‰ E—…ˆ‡‹‚L „0 .ºÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿSsøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿý×YÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿŠœÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿiíüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÁ2²ÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüö':Îÿûþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ˜=ÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿ]IÖÿûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿ0Öýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿ”NãÿüÿÿÿÿÿÿÿÿûþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÈzÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿËHèÿüÿÿÿÿÿÿÿÿûÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿW&üýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüû0?áÿýÿÿÿÿÿÿÿÿüÿ¯ÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýé½ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿg4Úÿýÿÿÿÿÿÿÿÿüÿ¨xÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ„[ÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿŸÏÿýÿÿÿÿÿÿÿÿüÿ§³ÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýþîüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÜ ³ÿüÿÿÿÿÿÿÿÿüÿ³èýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûÿA‘ÿüÿÿÿÿÿÿÿÿþÿËNÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþùýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿxpÿüÿÿÿÿÿÿÿÿÿÿÙ0~ÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿ¬2÷ýÿÿÿÿÿÿÿÿÿýõAµÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýâ ÆÿþÿÿÿÿÿÿÿÿýÿqîýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿFŠÿþÿÿÿÿÿÿÿÿþÿ¬Tÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿ~Aþüÿÿÿÿÿÿÿÿÿþà„ÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿ´ÑÿÿÿÿÿÿÿÿÿÿýÿR¹ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýëvÿþÿÿÿÿÿÿÿÿÿÿ« ðüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿP#ñýÿÿÿÿÿÿÿÿÿýëWÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿ…¨ÿÿÿÿÿÿÿÿÿÿÿÿvŽÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¾ -76,)üþÿÿÿÿÿÿÿÿÿýã Áÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüò&-`†¥ºÉÓÒÈ·¡Z$¥ÿÿÿÿÿÿÿÿÿÿÿÿh'öüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿZHŽÉüÿÿÿÿÿÿÿÿÿÿõÀ„=%øþÿÿÿÿÿÿÿÿÿþæ ]ÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿ8–äÿÿÿùúûüüüüûúúÿÿÿÙ‰)•ÿÿÿÿÿÿÿÿÿÿÿÿˆ”ÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÊiÔÿÿúüþÿÿÿÿÿÿÿÿÿÿýûûÿÿÅU íþÿÿÿÿÿÿÿÿÿÿú"Ëÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüù0ŒþÿúýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüûÿðvWÿÿÿÿÿÿÿÿÿÿÿÿ¿0úüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿc ÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿ„Âþÿÿÿÿÿÿÿÿÿÿÿjdÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿ™—ÿüþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýþÿ{úÿÿÿÿÿÿÿÿÿÿÿý"™ÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÔ{ÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþýÿZcÿÿÿÿÿÿÿÿÿÿÿÿÜÎÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüþ9Bûýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿé$©þÿÿÿÿÿÿÿÿÿÿÿ¨3ÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿq Óÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿ±êÿÿÿÿÿÿÿÿÿÿÿÿyrÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬fÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿ?,ÿÿÿÿÿÿÿÿÿÿÿÿÿVÇÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿãÞýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÀ`þÿÿÿÿÿÿÿÿÿÿÿÿDÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ²Jÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ(ƒÿÿÿÿÿÿÿÿÿÿÿÿÿ4˜ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®ªýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþ€«ÿÿÿÿÿÿÿÿÿÿÿÿÿ4–ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯ìÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÍÑÿÿÿÿÿÿÿÿÿÿÿÿÿF–ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯,ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùäÿÿÿÿÿÿÿÿÿÿÿÿÿ[–ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯]þÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëÿÿÿÿÿÿÿÿÿÿÿÿÿ‡–ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþòÿÿÿÿÿÿÿÿÿÿÿÿÿÆ–ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯Žÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùÿÿÿÿÿÿÿÿÿÿÿÿÿô–ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯“ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿïÿÿÿÿÿÿÿÿÿÿÿÿÿÿg–ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¯ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÕÿÿÿÿÿÿÿÿÿÿÿÿÿþÑ•ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®zÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþ¼ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿašÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ³Zþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ£ÿÿÿÿÿÿÿÿÿÿÿÿÿÿþæ„ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿœ)ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷uþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ²`ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿvêÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÉ2ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿœZÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿp§ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿwðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿ˜[ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿn(þÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþý ¸þÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿ¯9[ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ}4Pm„Š…îÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþ¸YÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþûÿÔv[ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÔÐìÿÿÿÿÿóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿ8 çþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûÿÿ³g"[ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýùùùúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿ§Œÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüýÿÿ¾x?\ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýüýþÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿã#÷ýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþûþÿÿÛªzL)YÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþûP‡ÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþûüÿÿÿ獄dPA1" dÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿÿrßýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþüúûÿÿÿÿÿìÜ;¯©© ŸŸŸ£ÈÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþûÿýyUÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýüúùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþµöÿûüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüÿçl”ÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþýüüûûúúúúúúúüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿ4]ÉÿÿúûýÿÿÿÿÿÿÿÿÿÿýûûÿÿºL µÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÝ.ÛÿÿÿúúûûüüûûúûÿÿÿÏÑÿûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüýÿV?„¾ñÿÿÿÿÿÿÿÿÿÿê¶z36Éÿûþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýúÿÿ#U|š°¾ÈȽ¬—vO-¸ÿüýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýúÿÿÙy#,,!§ÿÿûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüúÿÿñœ=êÿûüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþûûÿÿë UOºÿÿúüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÜšO†Ùÿÿúüþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿú¸|@=ŒÛÿÿýúýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¢?ŽÐÿÿÿûúüþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿe4m¦ßÿÿÿÿúûüýþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿs D|ªÑùÿÿÿÿþùúûüüýýþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿp5]…­Ñëÿÿÿÿÿÿÿÿÿþûùùùùùûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿp6Oi‚µÎÙäïúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿp2=HS^hs~ƒŠŠ´ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿpOÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿp]ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿp[ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿp[ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿp[ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿp[ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿp[ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿp[ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿp[ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿp[þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþpZýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýo^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿs&kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk/ic08މPNG  IHDR\r¨f$iCCPICC Profile8…UßoÛT>‰oR¤? XG‡ŠÅ¯US[¹­ÆI“¥íJ¥éØ*$ä:7‰©Û鶪O{7ü@ÙH§kk?ì<Ê»øÎí¾kktüqóÝ‹mÇ6°nÆ¶ÂøØ¯±-ümR;`zŠ–¡Êðv x#=\Ó% ëoàYÐÚRÚ±£¥êùÐ#&Á?È>ÌÒ¹áЪþ¢þ©n¨_¨Ôß;j„;¦$}*}+ý(}'}/ýLŠtYº"ý$]•¾‘.9»ï½Ÿ%Ø{¯_aÝŠ]hÕkŸ5'SNÊ{äå”ü¼ü²<°¹_“§ä½ðì öÍ ý½t ³jMµ{-ñ4%ׯTÅ„«tYÛŸ“¦R6ÈÆØô#§v\œå–Šx:žŠ'H‰ï‹OÄÇâ3·ž¼ø^ø&°¦õþ“0::àm,L%È3â:qVEô t›ÐÍ]~ߢI«vÖ6ÊWÙ¯ª¯) |ʸ2]ÕG‡Í4Ïå(6w¸½Â‹£$¾ƒ"ŽèAÞû¾EvÝ mî[D‡ÿÂ;ëVh[¨}íõ¿Ú†ðN|æ3¢‹õº½âç£Hä‘S:°ßûéKâÝt·Ñx€÷UÏ'D;7ÿ®7;_"ÿÑeó?Yqxl+@IDATxì} \Uµöž™[Ó+é’F“®ô*¢øÄŽ•ªïé¯>•f‰€êõéCPŸ>û 6ŠTé=@BBBB’Þn™ÿûÖÞkŸ3sgæœssoro2ûÞsöÞk¯µv9û[»œ2©|>oª®ÚÕØ;[ ½wV»Zëj T[€-P5Õ~Pm½¸ª`/¾øÕªW[ jª} Ú{q T À^|ñ«U¯¶@ÕTû@µö⨀½øâW«^mª¨öj ìÅ-P5{ñůV½ÚUPíÕØ‹[ jöâ‹_­zµª Úª-Pmß÷#Ä·ƒªGçÛà¾5«ÝÑG ÓŽjŽÑ©¢+TƒøjC‹èÕhü`Ç›…c^|‘*g¶À›Ð5¬ õíÑªŠ—í¨í)8hA«®s-@£Zt®ívVê(¨‚?A+fJðr°Çé%Òª¤x-°Ø–áx>{•« Z`tÜŒ£xVÛª÷\•ëqT›ë©ªë\ ЈÆÁ%AÕu <‹,îþlö¨V/µ;‘­aB5œ¨‚ûúDUæÎ¶ÀG X²Öãrÿ­Q"‡‚!‹£º£Ú¹6`ÛŽjäjúNµ@H7á¨öÑdmpnÜVÿjµqwªs=·¡«|j¿Vûgâþy[Ò–æfVÕÂv¾ ŽMÚàUþX-P½çŸ¼O®CËòv¿¸J›€ÊC¿Çý©ºÄ-À{Ó¼3Pu]ÛÕ{þÉÚ“ëþýq,U1o ”PÆçë_pÜ#®ÑpªjL*ÝÏ…÷/oò9nòÇvÃÁy ŽëbKT£ZàZ0$ºçŸJ¡¦âvù¨ìw_z>8æ[:S€Ë äÁO Ál¾*IàÒ¦¶ñ\“ÊŒI ÓóYÛ›o1¹öÅI Úæ!8¶%ªò–l‰ ¾Š£Ò]¬ÁTzSÛçID ä{J$ŸßnÚwüÜÐOèîÿIÅ2±Ð ^ÿ¥b%•ã9ÓÞòçÎZ¬Êªwcj¦îdä^ê9ª²…ªEÊʦV’´:T|ðsœ«©?#™H’Òì2Þ¼É6ÿ¥3à߀"žVª˜I uƒcG)eåhùÜF¿•Kî•ôTz°ÉÔ–´ìo‡ÀAI…ªü-p!b3 (‘tí˜öþ»±ÙÖ'L.»$¢¶’ùXÿq8¸þïà:c¶@Ë;qð®@l—k_`rm{Ö“±™ÚcŒ¬+c·‚,¹n‰Ï^å,jÞóÿA­b”×§¦îÄŠ<½!1Ÿ]a²­v¦¨_ƒPÙY{¢9l(wn$ ÆqdˆÌe_3éšÉIA©w·1¤2Øà싽€EIŠÀ}€Õ8žI"T啸璴EMÃéýG%éy¼Øôkoâê±9iÙž„ÀG+ %Ý,ÖÅž?¥˜X)žJÁ¦ 6cRu•ØzUZ[ÓoL>ûz’2s ÅG…KNË’(Ú‹x9} I}9ØÔ4¼7‰HäíĆ3ëÁÇøyë¹¢ÕèÌ€ÊÕ…@Å ”Qý|nƒio½G£{„_SÏ ÁD¶”SÙ›öˆÊïºJü1QV©ZìÑœšH¤'2gÛžIz·‰Õàòœ¯õGbsg Àzdò‰\®íTêÅD2=™9•i2ØhJè>þñ eöVöï£â‰îùgjÆòŒ“¬Þëò¹5&Ûrog*ðz"ŽàÎæñ'¿Š“Y˜§½å.gu ‡ã.÷]¹_&âÞ»˜/BuÝó¯©?ØÔÔŽ•k£Fº·5—ÇX"sÝÿ.‰žQïjy ø>wMÃ;œ=þ:Ɉ‚#ð1¼È¶/BJ™lÛR³}sâ¿ewyo€\ú‹9 [›êSùl¿úT¦¶=“”JgKö³T[zÛÔµM¯¤æÌÉ•PÍR®c¯«Réþ¦ÏÀOÛ;L€C.ë3HŒôlÇeq[Ó/PX>9žÈý Ü$’sÉ “TI?wkßSD«MÕcúüILÛUæÛ©:ê[ìò4r Pð­Q`0ðÓÖür’ÒòjÇ‘Èz'É 3¼ó~<뚆 x}f|6—JåQÆ6ãrðÏ<l(z*7çàË+¦:‘Ïfèúê´ÕÍ?.2|t”ÏïÆv}¼ýÌ [ìã¥-û|Ž>þà÷\×nÚvüRfÆ Ë¸ü“Ê{w¼ÅYÀJ£co6µ7ߎ—5>‘Î>›;·DŒ4ͤŽúè÷eôG2}hf¸ß€3̦–WÐùbïoÔB”3§]zßjÞÍsê2ë÷Í¥³“°1ИŒLD=Æ!Ì;CˆÏ?Îtôm›Ø°wæ4ê~¸`d É×¢ãá'mýþ¦®q¶å¥À(%ËŽC|,vÕgzâl€Ëa.‹:.»¹üî”cŸí7JãHd`2µ‡›LýIÝQžNé´#<ÁÎC€û#wF€LÞ8 ¼cë½fÇ–û“æË­ëX·o’(æ´¼¥¥qf.•;u˜ ÙiÁdøyO±¸mùLÍ”éçqÊDÐ Är)¿ Sÿ¿v&nü¢3‚¥dbÊ¥„и³}<މ8b»<¾~’®‰¶.¶LRFñ f~‚Þ/@ §Kûõ†!dÒ›Nòˆ0ü†>ûšm›Ÿ@ç‹÷p:iª¶¦æ˜cgM›€ú ëöz׌Öyµà`ðšäa`ñoé|þ÷™Lú˳>}Åـܴ$µ:âSß0NDØî6  ­%òvÉ!¾PÆ[¢8©W7ºuŽØÓɨ \3D±uI:gkpðƒ±ï Ô6~ü]_T=[zææg.Æ€ðét­/>H:ê[?ˆ“;£°eÃÃfÝjnÚÆs˜˜?^ñ3mì¨x»—k깘yM´ áå9“_žÎ¥_ÏfS+füë—WW(ÞñH»¿Bz‡¤>ý¦›}Æž/C}ø)¿âõ|A<¼îçâ*K_– ²€0|¥uȼ ÙÖG0õ(©&‚~ŽùI+ñ³îJ7™ÍÅ‘hTËÔ‹ý€Dï8DÖI^0š{Ð[“GA_À‡V“x89z~M‡aQ9í×_ý.6ùŒTòæm¥gÐAWª6Ÿ~jÊE_~µ\™ºˆ>z˜áËqCu”/cD·ÝÖOÛ!º ÓÂÑŸ£>h8é‘s`&_·,ÝñMü€é]5hoº_õMܬ[P-Þêåíá.w»z 8î PB”ŸÏo…õü³©i|_kÙôHð  -` ~òÓüˆ-°™b †ë¨¯{`¨käØs°!8£QÉÛüd)p«7n6?»ûAó™³N) ïdD2>€}ñó™ÔÃÓλdëNêL*þÄ?ZÑŒ÷!\‹Œ­H¯vÔÇõê0(|êOFuŽè´ð±G!3^Kü–fÃ,˜Î4¼33lÛS?Kz2Žn?ôî’ۀ̧رB§âàLÀ¢¬˜£DœÖ“÷M;óµ—8àWð*ø-ˆ€‹f ,µÌ fÁ¨ž1°*j2õƒÍðQ§˜5+Ùÿã¹ÿ¾ë!óî£5c‡%Ú?-V¾C$n!¥î¬KåïtÑ¥›‹vaübä5#I~ƒ‡cúôÛWÀ϶äHÎY—Lëy-€`‡ë>¬K‹t—³3|zP–$ -ÐÕF@žki¹/Iu•÷JžÒHwø±Á×™Cç7p|-™nþÔØ‡eO ®\ø°´Øî¥ÁÏ‘Çñ2€Þš·ýP™ ¨nÊø°Óáâ¶Ìífá sLkKüÛ@§2Óüà"y6(nµ9¨=Ž®|+¦°Ÿqñå]º{·%øú‚ÆŠ7”H+Iª­h¦ÌšƒÑ¿Áþ:¥çh„Ý´, À¤<œÎÓBЀ(Íûn ñPº.H×pÉ‚–"âMW¾ß߉¯ûp³ü R*»’ƾ»»Ýs(@¢Š¦R°ðI ,z?ÀQO j8~0 rx³Ïëqòôøâ´át;úc0~& å¼lÊlÞð¬Yºè†DmÿÓÏ~Ò¼uÆþ•d²ÈîŸxôíÿÒ¹¶Û¦~ê+ño9TÒÚµi‡ºÓ“¨?ù|3hÈaXÊÙu<À–ŠÛõ½XXÀÝîˆ1°F#ް#~R#ÀM¿\ûËRΧàåý_®ÿ»Õ±‡în×Xƒ#Clç›ï” xÀ8#ðÓXð/¬Ëéc¡Éïó°Hpƒšpã|þõf˦yå&ÚÇÜþÕÿgj2ÏoqL{ þP—ËÜ2ùS_ZKÙîa:ÙÞŸ$ëƒg™IÓ> ð´Ü´³àõ£v¹xÑNA½!âA\# ›‹a³ •\®m.žöû[%–RiTÊu§Ö ¥V¢í®MÀp™¶!rŽ{qÄ6Hò5¾™ž©=4¬Ë‡=Àհ«ŽÞ…k~€ÔƒÙØÉ)€ýH.@Wàw|¸ „¼e|ã&}ÐÌöëèHY_îJWßXk~ÿàãæ#'â'Éx?Þä‡!ÿg\téòJr=(í–$eá=ÿñ“>$†Uz†[ÌËz ¶/L㪷ø¼~¬åe3|¤o×ôÀ®©n –’-Þ(Þ Ð½„rF §üÚ[îñÅIà}â]~–©'–ã~¼ÏùyFâ:~3=Ÿçwù;8\ß‚ÑÚƒt0³Ó0ü̽7üvªogTZh@øh°ÍP ŽêêÛwŒ1æD³zEüŽò½Ûî4Ùlöìëþø·?u¨sÏ&°c'ºç?jü;LCãi ú<ÌAGÛÙ¶`„FŸ@Vc ¾ tMP#ÞTÙ‚æcç€~ñº­@eŒÈ+àI„:+²°kö$ÇÅÒ´$â¯ôÚŸ«÷b¥€/ sF@œüE›}ôÅ`·AóB,õi4BqvH„öìv3÷ñKL[[¢»pÜЛá+ÜóQÄD÷üagú ´nûAX¦àºŽ/޻鏶StâS‰]Ø{ÿvm¯´B^Y^`fQî9Ùc€µ!Ÿ.+P$ïÚ[þÞ™Âå}áñ8v鎱'¹£P˜¦$²?=Î}%ëº üûnŒô€6ÀÌCh!C–SÃ#e¤uuýÌøÉ‰¿ë0µý°Ö¹ø|í-A_K™IS?a2™Z?ÛҶ֬׶ Ò‚ëPp=xm’ý¶Ê.ŽôTÀfà~¿yÛñÖKkóÝp”â…£''úî‚9 z#¾¨FÇPyİ”×°ú^;)eÝ¡Ñû.O•+ÕÁ'ða¼æÚÀœã:Îàn˼‹ùNB~§%ÉsȰÙf䘷…ÀHmWio¶¥¶·¶kQ»{þÐ5³4×¼|G# ×Œüz½DVe˜óEåÄ׬Á<ž¤ªÊ{¯kdwøì@=ÕmGÁ¸Ûýþ$ÌeWc0¿3ÒÒw\h.¸°EÕƒXåJɰ¸N üêwLÍ3¼ëp^ÐÉkëûJ§Ú°î¥$UæÎñ£8Θ’d‘˜—Øx Gô£šNuSþƒ¿TF¶-ó¤­m¼Xia‡€õÅÃIå­¬ãqïÈ5 %ªœüÉ Ðƒ îX=ä0åoÚÂ%<óDî/à¾4‘D70÷ä«ËÑ «d®eÛ_ñæ_g§•À*4oÕ»ü rõ°Û¼5¿rt1Î Lœò.ìŒNVáNü<{Ò òó™ŽDo.í·ÿ{Lßþ£¼‘îØfņӵ-¯15ÔjXAãõW=ä)KȆÓÃý%Ö~#׉o‰‚׿—7Í[oÃíÀD7®˜íjïb`w»ž<жá:ò8)!ÚÏbZ¶ ßâ; ÕØ î¾î.»‹ÁKw–P¢<å´#ÐÈtNøP@Úm¡IÈù×8ˆ«X®ß€qfÖ¡ŸEÚv±ˆ´¢l7:çY¢; 'ÍH}%0.µO(ÔãuºtñJ…­à©?(nÚö–œÏ”)F„×éoÆàív–ž>Ðà.i¢9V¶} ~žë.ôüáJ+ =ਖ@®/;Rè Uã w'¯‚[Áîhžñ8£¾òHÙ‚c7ÃG¢uëŒ4»Ûý HЯRfæÁŸ255¸çÏöbª¯íòÅp;C¡×G¯)½¼^ê#Ýó’G¯[8¬ya騢6 ?,×Þ¶Ä4ÃtÂñI¿ë‘ª[ò«t9Ïˬ|ÍÛŸÀ+·óåâó*J'PY;G —êE$)êT®ãv´ÒÓVí°Å>;˜ÕŸ(ÎG‡K4Aã}3~lnw:Þ󟑤ã÷;Å >]@§×@€Æ¶ ÐCפRÛ·¥ð:YÕ«ò¾/8t+>ȮeÂaòäsÛÍÖ ·€Ëíįðƒ`ýÏøìÝÏ™¨‡uq*æ0©oÁ±E®¢ÄÖæWLcß1Âô±ÀƒÌZz¹¸¸¨éL0-[z.’c7ÑÎî ÊïGuv(=Ø!]§T_ùmÜvxÒêšö¶fúDƒÛ†#0ט»Úqöq/ŽØ÷üë™Ãßz® ïÚvb¡ @:P¬OϤB íJç<Ëã6ç{ 'ŒÂð‡e]ºÈ©^Ëna7›×ÿ×&ñ-?~P•_õÍ9µ=Âë-3m,nœ$êÜù\3~Ÿïw¸ˆxoW—XYhf é®çtSD‘Eؘ4jsüJ#76‘©¬“%]ãâ;}Ìþ0^†I´—ÆÒÿ/ë²÷jˆäØŽ³œú†þÒ~jD£|¶¿oS¶Ÿ;ä-ºVa}Rp^fH×ë­ebÂŽ­›–¦…±ëè z~Ó-Ñ26i&áïm€ É_ÊIÔm-+̶ØðÀ^d½ÀáNP:ìFf×Ù|'òú¢;¥v"õƒ²„¦¹®sjjëú˜,éuå,àI…v’ÿ$È'ºç¿Ï¨ƒÍøýN°×íXøÃ*%Úmn;x½&Ô¡íçxýõrÙ¦—°­­#I„á°¼\I'ðéµ·,7[7vêQß9Gs½i  · 8Þ®„8~kórŒ6cðòÍ{¡+¬ûµ#X?øY†Š#¨s+ôd›K×¼ÕÈ ²ŸY³êÓ´c]œj*ÏÉ\‡ÃO\5¡|bã)±ïùó1ßcN¼ÒÔqôWA@'aë#(qú6àÐÈ(C~A8`ó „ÝT¶@†‘ÓÆ£H.·Ã¬]yüÄ·üüsCj{T°·Í´ñ~á;MYðkG‚_БCœ,œ§ï|!úÐaû›}§œš¨®`þ$ŽqI…òOÿ¿&‘8x¢™6ë}¾ý¥Ù8Äð\zá,LÚ2ܶ ƒ˜å ·©ð“¨×ŽAw1 ÚŸ:A—4ò¸²lÛôÖþ/PCÇ ÄY8v$ÚÕ¼½Êäo¾9³à¦ë®Å5ú3>æ1èÛç½ß Ø?Q›5ïXb6¯sû¶µÃP™tö´(€‹;LEð‹Šü|mÕë“_~Í£ƒÂA‡_€Çd9°Çv¼¶Ü˜ëNw”'èC)sø1ŸÃ[›ubýLí,uf{3\dlZȰío¸=Åxм-‚r-åR–’¡Ðé”7ÐaËÒÚ² 3ÇÛ…'áé{à0¡Ì.gï5{ ~~]ÿu;6p‡û<rÕúà×r¦cþüÄóòu–¸­×#ÐØw_ì ìã;›v<ÛùBÍuI‡Ù¡ÜÔ]eé³d àB™Žë}¦ë¡:èü,§©¶,uµ}Îà ÁD{IcÐ&OàX·mðqäO´C9yÚ™fê̳!Æv²m%ù!h} ¸8<²ñdSpf€c«§1Œƒžóm8ˆx:HBu‹{ñpòé¢Åžø®¼eåÒaÙ˜èkMTð2Žñ¨¯­Mùs¯0ón¼v|*—ÿ.U‡õ,£µ½Ý<³øµòµ,‘²cÛ3ŸšÎdÄx0J/5xw §ãhŽ+°;ùz¼xù†kŽîÃ¥X®¡Û?óÄÂWÍâoÒäs­¦¹i…<ì >2ÿuN¤‚P ‚ÆéËA3ÜA®<ø•¿ìõžb?“®17¯.¼»\S”¢÷‘sâJ%v’Æ©ÿÔ$²GÿE3läÒVÜ‚@Ú¶!õ9lZ_#’ù4=v¥Pƒ `wdzPoÊÃ"„Ù$§ð³þ›7<‰Ÿsç—Ì»÷@"ñ†Aâ\ºH Áú­‹rL fþO®y?ÐÀ/Þ ©$–h¾{þÍà~‰ÖÈbÝ×­¹ÇX:¡n  ÑÛØôuäf9„.½*àQ° /u‰!¨ ~öL¿ðs y©oõ{£c'nÆïËG!¹ËÀ= ‘DyfÞbLtÏ̸ÃðmÿSmÝØ6¡zkýÃí§í[Hsí®†Öí§¨<Û¯¿øš9C@# ¼®,¼üÓkÜÒ¼Ö¬~ýå[ |Ê/‘ôçòÉ=/¥Çθهæú>ŽÚ8ÍÖ¯±ÁL<ÀÜùܼ8ìžgǶWLßSM}ã°0*èŠD騶3[°vÀb9íÔáÎסó*0´ƒ†|ŸhûŒœn¼ø'ŒX|.*–ãu>Çξ+ÀÁò)±ïùó1ßSßõm<Ñhímh áYð…ã$ÂI¢òX’=[A›2Ê­SæYàt¶ DÇÈYA>×f^{妭•Oî&rKÁ}b"‰ÀÜã @~Μô>xÚÑ6_HÒ>›V½n¶<÷ˆiÅ4ù•ü–H\—7Û¶¼l† ?ZÖ§ \õ-ð0’x¶ó#…G/à爢ô\üªËÓÀÖ¡òêkþäilÄ{íÍø†`¢™æ$´G§7â¶L >^—ãKÐË’=ò<3qŠÝºa]ÂÎSÉÏ‚z!9z8¬ò~ ³UÎù᩽ȃ.Iºp|\¬Z~ ~¾=Q»Re+Ž™8’t<Êív×£–¼Í·pTã¸<ÿ–¤eÞxùE3ï5}5ßúìEæ ýÆ'k¿üÕÿ‘3ÁËÃùxVé DËc;ÙuD ƒ8ÌëîôJ>e@/:Âù“Ëñ­q9ôÈOâÃ!Óԓ¥¼%‰@/ wþc»!C÷ÃíËs½aÓ¶ñí¢õg»j»8Û_ù¥Ý™Ž4i7¦i8¤#ÜÆ~Z{^ÉC.­½^ªÌÔ»eÓóX÷ß»~!Æó^Š÷š`™Ì»yNÝú[¹ðŠýØ$vñ£˜×_xÆ 9ÆL?åLÜ+¯7GL›dnì¹;÷JpÝ—©i4ýN–ާ€“ÎÇNæÖç÷¾ëDAg 6ñ2Ä,yå¸U$ß`ëppŸÔ=  M™ÓϾΠ4b`ÌEg}Dìà “De£NØUÆ¥Y .;ðãlÿ­þ¯.TÎÇ­ Äòxm|=~«ñû²P¾˜þmà»"&ocë`ÞçôK·Öÿ—”·¬b¹¶æ&óÒÝ6^Í ;ÁÌ8éL¼Pb«3°O£¿ÏPsç3/ÆÒ¥L[7ãÖààX¯•AGA¼ð­‘(`‚ðèäÃ!DFIYÇc Eh“ôáûL1+–?m¶nIô‚ä ¨/o ÆÞ@/gdÃÛÍ8ðl|åç½ÒŽ@îX§tMRÁ¨*ø\˜ d+c…% ž›Ë0wD5Bþ^~›qÑK×ãöêZWØ—SG²(±%zãn7þš†¿âÒ·mvlÞdæÝu‡Ù¾q½` >É<`AÚ£`§µ P}~@g FO F}w‹ÏÑDw(ð9£À)Ȩ^áC9úõn¶m]kÖ®æÃg±Ý,pþŽÍ1$îO¢{þ'y…9z¦E,ëF4*"]ÄFÅiZ$*»·Ž Na`«˜çÅPï0è“ΔŸñM^4KýRIIüOƒ™†±W»Ý¶ ¸ôsú™†;p¥N‰Û‚W.7/Ýù'üK“é?|„™qÊY©9 •võµ5æú ?dú6Ô—f(CÝðæSfÍÊû$U§˜t>¡!@Ÿ½[À/>»§¥3MŒé:p@ŒFÇ‘_e¬ï6þ t„ôº<ßvÒgäÃRàx'^wÞ(—øžÿ„ýŽ4ÓgŸ)mCÃ¥u-ö Þ‹põómmYt õ\³]Q\Fá©>/CÊ‹öz(ΊRÞÔ`°ù»É,~{ÎÞ\9ΉÀ§`¯w»e@ð7·6ð–;X,·zá<³è¡{ñ|v~£ÍÌSßi2µåÁ¯Jõíc† ì¿ã¾¹ó£™Uþæ /™!ûlêëˬ#»ø®ƒ±Êè¬q]GkvHÆé“Ï}r,ÜqÃá0/Ø!?å©Gô«og$,O]}Ù|mq¢7¤G¡šÜ$)7u J’Ýó¯­7ïùð°‡2P€&PµX³AV NÎ8©¦)ƒå´ÌAuwÌ2Âë0/B–7XÅðŠ—ç^‡ÁV¨t\=9õO²‡W÷.çÛå3Þêkimü%jü+çÍ5‹H|é3hˆ™~"Öü55qkíÙGr˜Ç _.×nÌý!v…›]gF‡Ø‘?È‚¸ëàì¥ *ø)Çþ'ÉL ‡ÒT®ü"Oä-szä‡ÍðS¨%‰ûYfÞóR!½CÒQÇ^h e,0„®ÌjÄÄ ‚Æ)¦I]Éú´Ÿk7Êð/,Ç‚8u’·ð8~òÚ8B”µQ³rÙ_aäù»3‰A<ŽöDR=˜y—l¾¤^Þ¸ä&¬ÐÞ·M^Ÿû´YúÔ#²€«mÄ'²N>Ódp«/¦{3ŸËž4ãâËy¥ÁÑSNØšv¬1 _ú™ë8Ò•¤Ù>ŸëPEàÔŽëúž•w<áŽë;$r :|áÈoÁ>̼ÐñU÷ížB âÉï¸,IõÈËۂוš ׸±Ý°}&›#ý¤›-Ù2±¬zHùg=´ì¾Y?¦¤âX-–—¶ºm;¦#dÛˆ:\ãûö£BÑ—2›7.ÂÓ~z$‚Ÿ^Oô³M̶'»]ºøàèÆëÑŸŠÛ þë/<+ì5uufög›ÆƒâŠ¿‘ʦŽ;àÓ—é—Oiñâ} ®òmßö:~`d¸é?h_t\»¦J'Å¥ã²Ã¸ÒÔ_Á\ üjL*_ó؜ʥN;à‚Ë*]enäp—/pÄv[7/Åèñsß™ èˆì^ b¡‘"vÊàv{·üÁ—NÊœÙ9yðéÐ'@öÜñ2M䂵µò«¯Kê8î´Ãt| sHâØx°Ø±Ýégï$ )({A\]¼qz¸,´þô•ϵƒÔ ¥@TãŒXºõ%ŽâZãGfËËù„N"Â[pýàúuÂñ­Ôû;!×+Db²³5Ág¼Fü÷A>ÖÜ}õ¢ùfÉ“ûìø”ßþÇž$ÓËšÑ{Ϙzñ¥•gñ)\òùÙwzJŒÀ–MKðlûDÓàxé\:ÂÙάý…®£:¶ƒÀѬ| '»€ßuxvfè£óy†ù®ÓóÙˆ~ý‡˜ù/Ü£VgÙwòæ´w^æhѧŸØÚ¾kóRÅ~«50z¿ŸsŸü>6FoÞsSt*ŽDwŽ:Ô­‡ì°Ò …l¯ÛŽùVþ¨8ª×¿¾Ô,|èrŸŸü|À‡ørç?–K™/O¿ðÒ?Äâ-dz¢Éöðþseå~€SFvnÒ¤“KÀvh¥)ÝNw™ædð¢B¬žÀh0®Ä46«oïÐ(Á˜ ýï½áX´°UbÄN8ýß̰á]¹C¨eQ_g?®‰D³ÖÏûÞ ±å߸ îy¥Õݵ5Û—rl|þÑ‘ÆcÅk÷›U¯³JIŒ>Ñþœ…ƒ›{´ë°à'×\ŒÖÿpœ–ã =‹Bà§Ì~‡¿-Éí¾_pá¥ß“W ƒ`±Ýæ‹ñEžß ŠÀÚí|'Ôh{!ùèè…×¥ é´ªK|Ëkeb‚_ŒHÀkgSÍ[ŽzŸäÝ•§á#&™cO¾È¿0OÖUg'Z?o˜æÊiÛ.¨'q+ülKð±±ä(gš8åcºü [Q«cûÖ7ÌKÏÝÔ™ªÿB÷vF°·Ét¹xù§×šO¥¾§!øBϼ{þb²mmž}Ä”i†G‡¾pïv3ø¢8¼xx·à‚ é%“¿|Fl7ؾ*V:¤í¾s†;$;ªç÷Wúoò0 ¾ŽäÒÁç_8lAT *+«igþËå²IW² Rï{?òS‹Ç~µ|aPKØè(‹&–Ÿ ¦_î` …‡- ¬d—ˆ;YÛžÉê#¿ÕOál¶Õ<ùOÜïÇ/,'t¯‚ÿc ez-{—€Wo¼v`>—ú_´F}T‹ô/ÝógÓº#x ƒëþýŽx[”¨¦Ïoª«?ç-]XMIîÿ" wÌòæÙǯÇóx‡\:žõ˜µvZø§4éÄŒ“î€!®Ó+ŸÊÇÉïd:Œ®ªé*GŸà¤ß·ß sÚYÿ.eèŠÓoýÙoÊáy±l𷣫#ËÌ?øÚáÙ€òªïšÆC‘á;NÕˆ£OÝr èÈ"Ï$ü½ôìϱó¿LSâú\ï—yOàëRК2?ÃŘÙ0ءᴿiS°+˧ìö?öäŠo÷…ô®K¥3ï8øŸß¢ílðL(X—DI[ëvóÄ?¯‘çDŽ‚ ‚€ï°–Ì …øA':à+¨>Q+/5…i¤ÓÐ}üGÍèq‰ží‘2ŸúnÎ:ç+¢SGɃù„Ê[vJ/u‘úÙ:2ˆºƒí¢ÖFé ØHŸ#y~' ¶Ë4Ký¡ÄŽO‰Â¢ï=®Ë Àü›®û46\ωÓtËñ|?7þÂnÂA‡™þÃö “Ê…³ùTþƒÓ.øR¡‚rÜñé|ÁƒÓl|üLñº…fÞó¿F7ÄŸïÉAç²ÿÊIÀ‚ }DÆæhÅá·aá$¿“ƒ  ‡Á/aÇÏ;)çœ{-ŸÍªSç³?0Gfšg8¿R4I—zàĪÂÓ ëM5$Zá^›N>áE女1 8òã‡ø¶¯ÁÌìG“ðt3øoO(ÓëÙ»ä6àË7^; mÿhÈ-ç7q»/|¯Ÿ-8pÄ(3ù˜pÝխЬ¸ÑóÅé]ö» ,;“ħ&Q²ní|3dØ<#0.¡Û‰·<èèøMC d€SGEJ§ï*òq:¶ â ‡vÞ‘¦²šŸð’.ii3tèX³æWÌ+Ë= Y¹ÆÓfgÎ~ß×Á ½tΓ0OÁí7›pæ-‹ó<#ùý->Õ"Lîþ>Ã.Îd‰ºL„Lš(ếÍË%i'3Æ)˜ö[bUX ÛQß–tÕ'rwà÷†„zy8ƒÃ°Î6¨KzèC&ᙈêÔòÙ²8ýZ–Aò„ïÃ6QèB³<гüÔCºKsPÇ+1„Á·rùã?gñ‰ï-K,µ‡ì”à-?\’/Çi‹¥O?jvl*Äßî3ƒåG:,ûóuñ¦_¥L9*Ðð9ØnísñÒЯ…ßvÕ ÛΫ½ÚÑ١ٹáœçà N Yä°üNÞƒOg `(¿€Û.=,Èí¬AÁ€ÎêW}¾Ó-ÆÃ@Ê.¥wåsdW'-«õYA©+x]U\\4HXå¥=„ËÕ[¼€éÞA¨iûzóøƒ|×,ñØðwýÒëÚ 6œú›\ê§h³Ú¨v[· ?ܹà¥B6\¸ÉGk¸ˆvùO»ø²;£ùº”ãyhûzR/>û+¬³Ÿ³½œÂìÕ§ÝÚÓ5- B‘˜€Ã?D¬ª ¬éÌLÒáËÈùÕ(ùäNƒšFš†Ã¾Òhhül@ hËbuKÕ}ÙÙH•¸¤°Ž¤Q;,E™`ù…G¢6Yò±<œq=|ßÕxÎ?ñ ¡5Ðð{µ‹ƒ¾’ 4jTã%Hˆ¾[¶m5‹ùŒ‘ãÃ>FŒ.¢–ŒÎ¯iéûÅ’)ÝO¼Y<™$®¾÷*Ó´cCAG§Ž ß²Û“`= …ä€! ëS&ˆ3ÿ93±¼Ž†8ÁHž4(È­ NM³a›O±1É“ùÊ!EüX(K³>ùláL^‰„ù­eèœ':Â[?ËóÒ³¿5kVÍ•ä'Þé9G¢^ý½†µS`Ñ]³¶o.¬%ÀðÊ£tX÷×à“^92R ÜÛùÔ”Ï~vw¾qʱ5Na•§iÇFk ö´7—êÜÚÑ)ϰ€FááâVÞÉñÙü,ÍÊ8Yí¡Lu+ø…ϧ¦)øånå/õˆ,i KaIÓÇ›Y(ü‹±Ñ2Ùt-§ˆPΞ™®!!‹>IW>MÖ¸—Ä뜘i=ÿÔ/¬`²óÀÞ¹Û!ÉòéñÜ2ÙLêÔ¬OTí8íçv»q³1µ ÅäñüM¿øÒ‡J$ìJR32;G>I¦+—?ý€ß‹à`Eµû¨öîŠyœ¬#[} ƒ‘,$0Q#Ï>Z1øõV$é|:?|Fà3]o[R·äãòfºäç‰>æciè<-T>Òl.!X^‘q²gu1›®ÿüÇ7ÅÈ2žÀñÍ D=I »×±&6 ~rí»PËÈûäM[6™¥ÏàYù"Wß·Ÿ9}Vµdôš––+J¦ìzâÈòª¤Ù>ûøO1=å—·ÙÏ]çõž ¸>oy4¢< I €aQÄU·‚žYQ…Ÿ1«zí^óлåâ~.„×ÎDÓB‡äÅüHóåÔ%0Ný£¥ËÙž<ÒTVãðIzèžoâ{o†¨±‚|ôô„Xœ{ S"Àïùã^üõ‘méÿ#Þú+v9¢ì/ù„y‘Ϧ|vNOzóë(ß á2F…ù÷ÝùuӌѪÀ¹N­´p§÷ÐQGPúš¤ÀBY™&¼ŽÉÆ-M *鈻\gV¯ r5’íÊäè•bJf® åÊ+eb…=DŸ„5Mi¢TØü‰,/=w‹yýµŽƒ‹g*àzÿ4;eiþ½‚šÈ´´Ö­²oTˬ}u¡Ù²fU¶ÆƒÌðý¦t w ¤RàŸÄOttÐÓõ>*Ì'c»íøÙ®îâä!¯ÝºHÖörpªÀ#ÌãÃÅ<.%Ä…|ôåOÁÏ¸Ì |w„hTE=r Ý©F ­N¡kyaŠ÷ Ö­ÇÒ\ŠM “|˜e¦£êµoÌÃûüˆqbw%$žJ,µ‡ Ä6‹oøÎ>èÂ_‰jþjï|Ñ·”7_ŽÅš2ÂåS9ó9t¤Dkî]•Ì ?#–¨lË—<Šý€[ ËP¢Ã;ì^…¼ @Pœ¨ „ Q¥ð.":–‘Ÿ9 3ˆpK]6¨a°r.o§Ù—Ól‰|9B,EÓäp9•¦~)¹V¼|uïßçȶ(_LŸ·t¿“w¯b‹|v_[£-½á/ç¿öÌ㦽…ûf…®±ÿÀx£¿1¿Ÿvñ%OJ÷¨Ø½(Íp|.I©è?ñFÞfĨéIĨŠÅ_AºC•ò0MÃf!X#Á8ÓxpºO‡¥—ǰgÜù^Þê$;<*w„£^ËÛ!©»Š•ôE½Kyà®o™-›V–ä«@܆´c*¤wkÒœ‰êûçdÇ{Ò´å[ÞwK²—ͺµpPËÈÇ=ÛóGfÛú7ÍÚťﮌ}.~äèß‚=eã¯Ru?Ä·ãØ¿S8/ªÜ}Çæýÿµ©oìN*&è’8yX†à)ë\"Yäˆ/àø2Z4ÏaüÖ·öLbÂÄ a5X ’^~ñóêBÚÞDŽ5àŒ-Ѳ-IÈ uÕ¬3ñ=åÃP'ô‡üT| ršcôàB7×è¦ÃÂ…#ÍU³åóâ4J¯AtìëËYˆßº{ô+sW$¶nIÊZŠ7–È·ç.Ca#ïÛ-yòé Åñ'½†OŠÆ :ÐO¦ê24L¯pG ”«pD¶‹Öfó¦Øü¦9ãÝ×*©¬/ƒkÙÔx ¤ÃyG—¨ùØt¹]Àú%ÎÊ[")6ÉçCbý›¯˜‡þÁG};ÎÔîO,!põcÇäMÛ¿à!Ä®N¥Ž؇j³¡ÅñWÑ5 •Ç0´ö[d–Ev|còªÙ£^샘‚ý£OŸÚ;¾ðØŠ&&u§‹4/þøêq¨ÔQ…àã¾¥6þ(7z d:¥¢9]›úvSJç³§Äq{’2-^ðóÒó·šÙ‡¼'‰X¯ŽÂa¢§)¢C‰š&ÓrvOÇ# DÙNý™Ä7í kÓBØz%»&*¸S)Z8=N¸­µÙÜuÇWL¶=xƒ4ŽxáàL­KÜ÷ŽÛ¸m[Û»±Tú(>{20‘)k\;c~ šz .ÆùÛ·µo¹zö¨›aÁÿ犹«qW­ÓšË FÎÉñ£“—@¸¾œÒóxÍsÙÓ—dIã ¿£ˆußÿ†iç]µ7¹?¡°ÿ“´ÀÝó]üB ûg¡+˜`´u( ‰(¿çQx”¦$;Ë?>bÉ4òÙ0_ËuayÝiÌ‹''#’Ý«¢@IDAT^ÎÊ’Å2qò•s̳ØiYÃt¥ýóßÃGW–„“ℹ ÅÚN;ŽöWÎõƒíÛÛ×` ô[Ÿ·#G³Î8e ÏÇ»ÿ¼zöÈW®œ5êÂ9ÇÇ[²'É»¢˜÷³ï ²E)|sÉ"y׿ß° “ðyïŠöƒbm5éÔ÷JÉ÷ÚÇQÆ¥IÊÉÑìo·^j¸«íÑRàT,–Qâ±æ% ¥VÈZ§ÄÅ-ÝfËôàý|¾·÷ëASƒ ï㓇*ô°Ù;Ý¡Ò “æIß2úrJÔ•æXœÆŽÞÂywÊl©cJ$åàà ­ÓîšYã_9kä`´_€ÏBQôÆM§s‹œ„›b7f6Œ|þêY#ßÉ€¡¢Hg[Xñ~•ôña—eÏ=Y–eäþÑ»Þhà?L¹à’e•ôü~M&Ñuã†eæÁ»‚umP(‚X÷2àòðS°¹vR]*ʸ@±ø¡‘ž`—ypÔ']÷¡ Ê‘Ž¿Ö ªGóe±T¯dM‚dê<W²M+âËâ«hAcûÜû·oºx"ï7àæÌ¬Sn ¼jöˆÿמjY‚)þ ¤bÿïT&š=ƒ›¯š=ò©«ùž8Ù”5|ê뜋£”¼¹x‘áç½K9>ø3`øˆRI´¬ÉwêÉŽ%»7²Ùs? ‘›7÷ü|×_D$˜Ä©Ç¸ý÷ižÇrzRÄ” ºÐ¡éÈ t¤sä·À/OåøéS–dk0Ã{–EÈdæáҨ˖(g›Hµ!Þ1¹ó¶+L[kâÍû× ê#N]bïêƒGMÈÌyúý÷q J¬`× ¼Íù0 Á·8yräôºR±Ê€––FvèŠèåE]ñÞ}/ãFLšŠvÄöEe÷ÄŒ‹.¢2K¯H½¥ücÒ’Þû×oa»T"²hS:çA\i„ŒTˆ‰î Œ¤¸N—M"O`dôÏ‚|ÖØe@4]¨A >™)P‘ê¤O… Ùò0ư-Š02|Ös1Æ §ÿð½ÿ‰ïηâñÏœŸ½óÊÙ#>ÏæùâÆ‰…)=6V‹’}isŸmÏ]yàÈ-eY€@8ý¯èÖ¿öªáK?%€?l¿è[©|êÆ’ò½“ÈõY¢Ì¶¶&óç[¾„°hñ5ö`p6hP–š¡ )»~G‰#|<ÀxNé]šŒþL/Á£†ÀËñ *ùHY˜!œ4O¦[GRpâOs¦-^ø€yæqÎâ»ó!Á™X"7kWÎùܼûwç:?Q¹CÌàkY_5kôÙ!Zì`M)Îy7~ë\¢ƒJ¥y.Öë/<ã£Å¾ƒ‡š†~‘í¹¥¥OúæbÙ^?å_Œ£dÛ–ªÛºµ‹Íwלòޝ˜1É=oêð]ÌÚÜø¯¯1í0›Û²fss›iãµLè ósØÈ’aõÇQŠH @]S–ü¨x룭©ÉðÉ¿r®þr áÖoÍþGOoN> …_‰cdÜJ´4o3wüï͹þÆÔÔÖ 0ÔP€½?¢0:  n|[¦ú„CÈÐ>ðQ|ZY^úaœý“Ž´Î” z%'¦ ÐÙáø)̼åÏ2J<¾Õ/qj%ôŒ šeKž0=x9’ºÏA`i¡9‡Žîƒý–?wüC‡7ÓfÍ6ÃGŒ°£9€ŸÇ7/rÙ Þ¥àÁ§Ø¨ðú„\#î»ð71˜„‹@ãÁ 5<ðq}j` ãb ªË˜-˜lli7mÉ—Å‚µæ…Õ_ —¡TݤС\¹*:¾ïŸ¯P¨A£ÇJÅ**I™¿vÑ{VÌf7&†'àÈ&)ÃêUó̃wã›+‰7.®ôdÊgÑå©£²“Ói»ÊÑÏáŠÏpñ4?²C‡Ü% .òéô|H“ŽN“àxøÕ^-3¨N-"ÅÍ›m[ß4ùã%`as%r€ûÇI$xË,Ó–#ø½Ø{Yo=õtsÂ;ßmFMÜÏdêL·ex œ©c¼Nhiþj2Œ7ŒóÓ5Œ×â}øX6ˆiÀI' ŒwƒÐF`l¿:3¤2"¿¶`ÿâÕޏ4J¢À<÷‹ëÁ%´fñËYŽ„ˆr¹üQ,{@úÔáóIëñÔc¿6‹æßg1³S@ d è‚°¢ÓoÒ9ðÊÎ~8ÒoõÀ08Ý|ês:õ®€ÆÕ/YÑk±.Õ€©‹+;eÿvÛWñi¯ò{IeÚnè§”I+KÞÒwÛw‘xbY† ã'ïoNÿйf,¾b-`¯'ð-è-ðØI ƒ^ÀOÐãð3\#q™% /Îäß¡ÛÇ­‰tÎ$Öãqú¾u¦–Ó¸KÃo~cÖÈ3*‰€ú–î†V|°`û†uø•tâsß‘³Þ\M]~Ožþ‡Ûç?¹?Lˆ 8»í+fóÆ•ÁˆK!5‰¡2ÀÑ= 2 f jÊxØ"ãîÿc ¡·3‚ò³ÕSXÁ·Tj¥œa>)~¨O<òK³ô•‡…?Á‰S…ãp´'Á›v#ÏA™þ-®L¦&c?éTó¶wý‹iÀ·,,øð9êÓˆ1àˆŒú»ù |Žø!àKØÆ eâ^|†Cq–‘qžÄG°K‹‘}ëMŸÚÈ’«’ã~ï¯æÌSvD.Övf%mL[»ô•Š,|îŸÿˆps§|òò7#xö¤äSQŽZ±]sÓ<pnaA09 sMPÉH ŸA:x4ìAL>zvácØòûlÏã xÐEyXZx›`< UPf¤ËçâÞ߷…Ovþ:Ø_J"rÕÌQ€ÿqe걇uê‡?n¦~”Ùëà§ÿ˜öøvôç ÀNûíôŸ w BJ@Sù ö à§áÓùQ?4 (¿#0´¡3‚[w•ª6,“ÏÞ:gÆŒºRLÞ<}ãµ(Ãi¥˜< nÝ’Ê ?ýu•ñrElzF~Y&8ßÎCaó É“OdCzþ0ø™æ)ü.Þ¼c“lvò=’„î)ð_D-ƒÏå~ ™ŠÛª³_­&øGL°kýLƒŽöáÑ_inôÇ 'k~1!àèÎô)YüÎ S0ÿ0ÐÅ0 TùW žVÂÞÀ $F eËdÖý;ó(vÞô3›ÞŠÄŠC÷¶ o–}î_÷2Tƒeý|*ýdÙÄ=7£Ö“Vïñ‡~f–¼‚­8àvTÈ„AI v˜æë#¾"cÓíÌ p`iäÖǃ­^ l58…>‰52´Yb·èi¿ßþ Ç~º­à?6¡Œ¹êÀQA±6ýêñ Ï;Ï ?#záZŸK€14LÃáfvÔ×é>gÁ @G{‚ž£~*íÀOÓz:BÛƒßUñbšðºÁµ/6JdLêëWÍ=Õ©÷ž7Èí4O-Øðú²2)¹^Šr¹|––|ot×£ÒÏ$©8Gø¿þßWLK ž—ˆ$Á’‚˜£ª„`W@1’ŽÑ³Õ­û‹}IƒáFñz g6ÏBðKþ¾|Ö(¼ðÌmfá¼»“4yYå÷àhf$®ûÖ´1C1ÛŒ5cÈ`t>éý1CF³£¹¬ó9ÒøÁ@wÿônÚŸQÀ‹O€ÛÃnú¹8ô[º»e(ÆaW;°1?Ö#êÓÁ§k¥5Ö¤M_Ìbºz\ïóz€ ~\qbq|Ã믓:Äû ä'*º¶µ«[U䨳Gõ€æøn>-¾cÛFw ÍâøX̬jß.tFÐi€" 2 xÕUœW~¯§ü,ã½ÿvüŠœ?Aðž /”­Ï~œÑSR0yæ»Ì¨ÉSøÝ_~¿ûï7ÿܺ_nïa­ŸÑ‘_§ù=Ÿ°»gVðë @rø jÔg­}:ÈôçcÇ5a*¹J;puÕ£¹åì&¼þ½ï5nKµì©%|ø‡w¢\CÿQ,KN˜3'Ñn”Â^–Îw§ÏÄq?ŽxWŒ*ŽØ0Ùbµ¹›@iú ûì0º2€C?z0L§O†(²)öÌü蔟ƒ0Ã]ã4 ®|h9)]l ˜Ö‰O{qÓéÓ,K'ßíË·ŸGfê!‡™i‡e×ëþöÀí€ËÆ“záqå”<õÇ+à.ëŒFOó™yî¿Ýôðpþúµ}HÈü¤Éëã¢<5J«#€K(áBš­‡Á«g¸œÛŒúЋ_އ•­…Õ¬èòy^нÝ=ˆH´ΑXÁ¥›kê+Ðì,ÀÄ4 àíUŽü…< ó*äqàvt• ç­å ûRFä+4È&t|E’{S‰]Þ´Bû4•ö4Ø~úYZ™²c/÷óyo?¼ аÛðãÀï÷~t/é­1 VÚç;#íGy‚¿¸¶Eá Ѩb`ü¥ÀW8Ú·©|:r“dËš7Š‹Õ!^ÛÐ¥•¬©ôªR佯¯ÍlNRo¯]F€”>Aé| +àðL·Æ# hå³F!~wzá±t5(ÖÈh¾Z.¯?\&-‹£%©/x?„cmBsí¡ƒbfô©8rGœövSÛØhA)unç^f:ÅÇÔqnüÙ ?NõÉçÖõ~šåeäïv?§jr+À‹G £Ă\¢ç)ª”Òk‘_cÌgÐ.S5bСRB9ŸoÿE9Þ?tù<ßÞª:Û­q‚§S°…G^e%ÍŽa¤ yì×؂ߦ‡ß1¬†C£ ú h†ÝáËàèg^zP¿›äJ]"N\&ÞÁS2¹µ½áƒ@OäZtìäýÍ8|²ÎŽÈ¼~kz·F×L¾1ØçhïNÐáðÁçû‹]Žß ¿,œ,u¸Ã6 ¤h$‚ˆû6ôŠ]›taÓð¡h€k”JÆ!{¢/K™ÀŽÍ›Ê¤’síQV‡ÒþRj¡d5ÕªÊWœG;Ÿ #‘Ìì|¤Ùˆíq6%èª^§ï¼"(äR gBøf™‚0âbDU·œäÛÛˆR>a2~}K€Ïïõñþ=Í0¿ìÓ†‘ëh¶wú%Œ O>ó½ço ‡3Ô#z铟õvaÆ¥¤aØ8îˆ*mòtüÈŽ©Í¤ð!äQÁ¡h'Ô CÈn`>ÓºaG;~×-Ê!¿Æ(žjzÇ`çáºZ~Æ› 6ö?úÛWÀÍ$ðaêRc`Ó´s«Q G)WÐ} “}–N:²ó Ã6ÍÓþ 9QÒ §íMþÈ{ÿ£Æ0[ð;àó«>íöN@Ž«TVV ƒ3R€™F‚ßûÃ7þØß·ÆÃÊÈt!¦á£¾ÐÁ6ÒC›Â5¯F½_ŽîJêq[°-°qoå `| ù€„‚6—ùá€É†â<åuûËUãÑ-à7ùþì¬Ü] ‰±oÉàîæý\Ž©PŸ<ÖÙ4ºÁN¥ŸjDÁއi¶³oÛM> K~8ÉÔ™uû ‹ß´··ƒ_W_gà} Ü™êë“z9N£Ð¶ü;–©t›mlÖK og bp‡Œ³;#ÀÒÁ-#„Ÿ2œÐ×Cˆí¦¥ô•¢‘M¢ŽæyT>äÓl‹þÕ@š·aNmH<¶µ4K#”ò¡Öí1qO™±å5TSʶ€Œ¢¸òT¤“;_¿÷§Ÿ}J­avh5ÔÏ0iAX‚NÊ£¾20nÅ­¯éⳈLt<–—|*£ZºÅŸ¥uè°} ¼µMps£ÀÇÃp¶]]ÙÁdòiû8/¡åç5pôœ `@ð«ÙèyíìÀÎ üL£œ19øXª„PÏ^à3Av†W@îÈW|¸½%øÁŠÒE„¶æ&4P…ÝSË_yÆQ¤³µ-ÀQ„À²]avZø9žjõqÙuiÀnC°Ó °_ÓÙp`¼6µãYÓUž:V:%$Lÿtº0ÿÕ¨ß1‡.¤¤Ì´(mÀæñÈnN¦üD [Õ: r€?ëžò Mµ¤žèßn_Œ?ý-‡ pLf0 3õf;Ò§%·mçl6ï$& …í¬LEI^•Â>@:ò7¸¨øþn;¬\\ÇjÙ±½ò‚äÍ̸úª|A  ¿H§!Øí'ŒÛ‡?Ø hhòå‹¿sq 2 ‚ùÁ&AˆL€ãXvá4HºhYÐ3Lb\ç$¯=˜3þØá]Z8§.說O¿>2jË->1ެ{Pÿt*ÀšÂ €¥³'©?Gq1ðyÝÀL€?¢³Y*p¹ Ë·W F€3»gæÛW ö _m7ñO8]ÅŠ}ìF:€Š3€,¾ežÄ5mÞXÙ3lá W™ú©¯ð“ÙU³8‚  À;)FÎ`Ù)¼!`L:/€ï:8gtÚ¡%"§èî$ß±±#j§e€aÒä_Ëéi»fÀ~òj}ä«¿}ðRÝéçÈ?ëaÁŸÎœœþÛ»Ú^¶ ÀƒÑ\@Í©¾Ìœ™€Î à»%.³"ð‹pAÛ“MìÛ’ Zä•)bñÑ ÷4">BEÐñf§WoZê%qÛ׿i©<ËÏe2GBçÿ%Ñ»·órå]éŒ;â¼# ðF¯ðËRرù:;Œ>ēؑÕ(Dµ«tF0ùÎæô|GE„ù) »°Ðl:ËÜ]®.»©?6ò#§Å±ÔV€eE{rtXó€ŸïȾŸ¬C£ÁyÀÙŒŒì4ðœ¸_’gn™ KÙ'p³æ‘ãfaáô_ôÛ¹ödŸmK§4+Î8ƒ_žÃþ~]\}•ôø´J?¦Lhê“®m>;ª¡QçãµåÓ~Ò7QC@àËÅIÌlÜ‚ža1–jsvÜC{š#hÔÂD(ÑΪºÉ#éhØNûÉoËîõwC טë½é%FyŽÚl'ïXf‚?‡·ü8úË+½º¨ n©˜òüÙu)`}»1h7í3~6æO•â[ϵ]ˆ&íêáí!5\BÎ*º8J 6¯~ÙX§…eªá-ÀQG€¤ Gg€˜lÀ0ÕË8ÉOcÀ&qòƒaítžPTŽP :x?=êd<3*Ô€.éÂ\”A×Eaû…1]V3¦á©8):Ê ðÛzÀpô×7üd°„àRAFq·ÑÝÝÏ`dV@ºÞ) ‘à^  Á–Ò¶Ó¸4©¤Út3Žüâ[¯ì9N{Ð¨Þ’Š’€V<3Є'+pß…7]sØÔ /Û[¿ X²­+sìt¶§ø]~ v{e¶GÀC ÃìX6ÄÀ8(%±â•w¥ÑÞ†¨©›‘Â8I’âÓ$N&Wå¯TÏΦáéWb2Òqš.}ZÊ…)8Ë,£?¿öãF÷Q¶‘n¸zÅž_÷¨9åWÐÓçmBñi8+P>øP¨íÁ°kRÉÆÇ%&Iîä=/ëXJ{¢¨t’Rivà(ûôT¬W|U›ó7½±"ÊàöPêƒ`¯€¢¶+å& —µXv\ÜŽ·û@d§Eo’‘žÊ g)VVôS‰ë}2S(‘©ƒ²MÑžjÕA»ëY,Ò$æxè•>äV`‰¼º‚ÔÚšÞ–ÉØ5u%}­x®¥.TF;ú׊õH×èôŸOr“Эÿ¥ÁYyjVƒ@ÃÁ©=g2 @XÖýjt)@ÀÑß‘³šä2°©Z|–ÍÅIôt¦k „Ç;BQŽÛ„ôçç‘’º +–Åù¿E‡±ÊËÀ¿Ò ‚Í- ¦u·„1=uq‘qéÖ0Øêc¸ø(HSYÇoÓ\YăòIy\š/âÝåêÓ5±žWooj±#3înåÚZL?ÖÉ;]rÀ8d;M­µÙ´7;„…—²xV†ò¢£~Ö: pÀ§ Á`#ðzò`Ð…Ù¦ ¯1©–Oü¢¸$–9Å1¸œð]ß}ËèˆþÆ_ ÁM+_7üˆ(?µTÁ ÛÖ·í<¤ÿ¨O5ɵÁÌ J£Ž Ìó9ÊË}·Ì (hgvÀ‡HGº—„£NžËõFß)}މ:…Œ“t@I hQyu6}HÝòmkÛFFŠ7±_r½€F”ÑßÝ÷ç=ÿ<¿ô#Oê €íÊ™€Sëê Ê(šȆ ŸâsÄw£¾_XÃÀfbû@ƒ4#ÄCt&ÚËß!.R•OÒO*³Èƒe+ñÔð{iì8 ï§®[¾$†Dþÿñ‰b0VYÜ(-£-; tB ²â°ŽîBŸ¹­#¿¥+O±ïe(N–:V‰qG³rnöáèžuè.wÑ3[û&rzGÓ““Q#¸Œüv$ÏÉHÎ0Gs7ºc6ÐÞR8è0CÍüLúeý/³æF ˆ&Ï6t¾§1Έõ;ðÉ5ÊÅùJ0fy wØÐœO…f¶b¬ŸA@f4t¸ƒÀ§ûàëí>_o×¶MBíáÛ‰4¶ í$îÚŽíFž¸® eŠÃ^“O›%Qœýð ¥Y4?nÞžoÃŠ× Ÿ ì;8òíO,¸éºÛ§]xÉ^xïpÿ…_¦ô®¶®Ÿé×lAŸ“D\MŽ\t|ì׉…ÆÀv(Q9k'l· a ³1 –<±CªóИ† ãRD;?{-ÙEüACñ5Ü6SGMÛךæ¦ßlRž¸>^ë},…J%Ç6ÜÖ–3ýja*±V—Í?ù¸ýˆÝäÆZH¢BÛxHeP'†éü¾ >­7ëH1R- Q Âdñ´PšÐ)οø®5âk@NÓ†š\[ó éš^‘²OR÷§è„c…–<ñ°™uú»"¥Áû›E?½îˆý/¸äåHæ=‡áUTeÿpuÚZ·™ë„I–)=;pËŽ@C³{Ø5«ŽúŒ“‡6ŽŽä$Ýɉ‰,¯© HfXty²Ó >²jšÊm\ÿ €âžÄ³šÊ£¿C_$™´ê‰Ìú‘[PÁŠ¿ °±©ÍôŇ3¥ýÖ A;¯£¿¬ÿ9´ ¦yI=Q+\ ¬w¬ Ï:;>­»õy lZ):M–O§¼´›¥Ù0órŠczMí• ¡Ss_zÆ¿ÎÙÝÜ<)ëú b¿V–£|ÂæÕ+ÍÆ•ËË3)ý1ÍýÝÓ7Ήñë"ÐÞbÑe€]ç‡×Úì Hó„²Ö÷w(:T®”ïø8¢ÞA°yÛ2š·¥[ýv ¸¬Ýy½æ<`°“gŽÊcS nÑñuÆ?B8XÜ£—{øò,@“_ûgõÞ¿ó힀»;ÀÛ|ý¥ýZ§‹¦aü˵±>ã…ôð“ŸzÂ2¶zŒåÚp=²Ì<Âã~Ìud¨øD§BƒFF®åËfÇY@åP ƒú˜†?Vo vl)ÛYÙy,ë3lG"KÓY‚S:%y P7BY#‚8õˆ.‚¶ÌáòÒü¾@VË#i,PùTVù:Ö¬‹))s_”FnŽmnÁTNÛÕ¶ãlÚ6ì·ö…ëKœíÅz"#òÛƒqÛ.Ô«ºEø„~Ñ@^«ÛËDU¨(½)ÆÇy)‚ݤ{Å`áXÑyИ ô:åš¶l2ËŸ}2–,&]gô5™¿ùæ²K’XŠö0& \t<¬í, }žOCïaØ‚ÊŨޠ÷ Há+oAZHNA¬Å‚$ÈÇÓE§›‹| »»/K6Ýþ{äl2”ÉpívŒÜ(›‚AG}Xf¦y +ȯ•xiðÈ#lu€)L·>ã%€Ny§Ãú¶ eªP’Ì[;ÚXŠH÷ôW_XµP @.Ÿ´šC"ÞñÊnÕü¹fKŒ7ž-ذ䖥¿˜Ó¥woI×M'Û1@ ðÑ[ø t‚Q©À`{^k>ê°2ÍÍ (#rì6/å òwt¤ûüŠŒ•¬™"ÝwÕæ<·Ž?c}oT%·¶bT×òÒ‡€ÔQêÌú–8@ x)i©·ÓcÓ!+ôÀn›Ÿ„C<ž_iQ)Jß.kÖ¤²Ãè¯É!`ÆÅ—s‹y%‘ü˜Bß!ø~h'gÁƒw~70–K™w7·6Üõò¾y !–¾^΀9<]· ³³‚x€äSš•!ÝiÖh„õ†Ã¼†¼Ì*ÄgXuh>ˆ‡A¯ùa³L€Ftí‡;!¿“ÍZl¢ˆd–L®@&õôP\êÃú±-ÄwzDŸ•£n¢ƒ|ÈCh nI§Ž€¯ =N%B<ý›"HÚÛ³¹›²K†òæ.z•Ü>“"?ºZI¿/°Í,|èT˜MËkjÓOÏ¿ñÛîwœbÉì‘LìÒAq‘Å€àg²†GÓ)¿€ÐÆ-H]Gõ|L+<Ä8@g1=ˆ«q°<Òñ©yIyT7ËÅ2ôB£OëwåÅyýÑG×?ùีO=xð›ßw(UOß3~ÌÄ·!ŸÈŸ³"X64sCåcÝ¥M-=Xœ. ž–騖¤‰¬ÓðØv׸´™ð€_ó=Èqáó~ò–ÚÒŠ}xb·Ï™÷¦<6Í—Äá×BÿžÊ§.Ðx)ø¾“ÍkO?&·TzÚ¦U+DǾ‡‡<ñ£WÌ¿éº?à‚/߀[]1ëW}ïà³Uç¿Üdz·ö‚l’ûûrëO6wq­ô¶ êI¹P)|ĵc;P¶À¹(r²OvÒ%ˆ“JŠD‚´±"Ÿ{lb{ÚÌJåò3¡ï@ e&îƒN€¥é‡Oy@9´ËïRæM&›6ï¸â'-ßü›µ/Üó×Hýoîh5ýê2&ƒ6“fuÝ‹žÖ¡’áqŒô¤æ8’øl‰;:cl'Ò4ÍÆz¥Î8nö¡KSðå›ãa¡sý×5çïÿéË–”fÛs©:‚zÀKoE*0á8;1O ÀÈÇ €Ó+ž©Ç; ú4”Mô"BФ»´¨üh&Mo=Ó}èÁCÏ=û¼¥7Ýz ¿|ć¤þضºlŽÖèÙ¼Œë}ç9ã>ò€|¥Ú—½D€·ËVmm1cû×»¶Ô6 ˜]s Aë¤Úz²òš&¾Ä]›¸4ßfu$;¾°î8aÖaSKô]6Ñ•ÊÿéksW=§z½Ø÷sš_¾ñ:¬ òjb)ìŒÙ;m¨wÙ³O˜|k`Ô³JeSŽvB6“zaþ×]×{íwÇ}á 17Ê©ë=t™VsjÞÈ)x`—ãÈ%v(8‚›n;™0Àdðº Ä…&}T:f³¡±©!ñ<Ä£éÅ`èàAû,s謙úCàÐ_ ØŠ¡>þÛ:²ò @wzfl3g3°*̺®±™yâi晿Üj+Pἂ Aõx4|’§U%RV{Gaº„qRÙ îh’Æ0ÐúAZ¬±»c„²ÅÝÒ,“&£û¤® ¼ 1•Ëþ*ŸNW4|¶ŸOn]·6¬§SáWŸ|³¸œ=ãÀ$ò}ѽ¯ÜÖ·å¼ù7]{髚oNÍùÿí] tµ•Öó¾'vbÇÎæ¬$¡ !!¤-˜8LO{ºÑmÚ¡´Óöt:sºÏ -ki‡i™z¦…žnpZ´ -¥C-[³ÛIœ=!qì8vü¼;~ó}WÒÿþÿùÙo±;y’ý?IWWWÒ•îÕòKú׌„©¤=n¸l4ˆp£ùˆMy@ŽØà¥gé†[zJèüÂOcƒê¸tÛFkáÖÖ±¬O7\Ïg—é‹1 ›nvÀņŸïæL/T‹>vZ¾ô\µ‚?¯v×é ñ c†&Ë!Ä™ŠMÒŽ ¿)ƒ(<`|ò†®ZqÍûTÃ+/©¶Æ#Œ6¬iÆT€÷è—ä"£0LC²Ädch sf¸ðc!fü„Y^h7ñðgÂ-TmîgHrèÏ Z“Œ!k¦åêC "0ëÖèô´OàÌ"¼¦TR$?¾—ª}˜:q¢1iŠJ3NÔ(ÈkéžMʈ…T lبüF\â5ž;(ô$ë)Šž¡q¤~›Z÷-XGI®×d)˰(X†W„4Ò¦`[a ùa®¬‘,Âcñ¢~‹‘¾Í}mX¬LzΤPŽ}ýYË×lÜ÷ò߸µ¹ùþÛËs³C ˆ_1\vyÚk¿ú©êÅAGÛTbÓÑüU—È븴¥¡s®†"ˆ[ÛQ·Q &ÓÏ|WçyŒñ~›ƒCµüT=„Å_wq“c`Ò `ù[ïñ€T+2¦‹­B«¬móî÷3Ž5Å…9jZe>æëxªðZ¶„|Vu¡*(ð)U‰à‹èsZZžíqÔsÁ5Æ$C; žHŠX¢Ò/ÿü1Å nÎéÀÂ^DZ#ªëD‹êļ‰'„K=K«ªUͲU*¯™%ž‰C÷ëO>¦^~ì'^V“qäcØS>åø'ù“ìHŒ…ÐÛz°áŠÂÏý )Œ†Õe7n:XøóDz*ëÖÝþ%4±{üÈñÜܰý¹ßÆ 1,¯ræA TÎY [»¥(•lÎkË . Ü»ÄAÜ(žÏö‡C(pÞ<ëEØÿåž¼Ü-‹®ýðé^;HZ,{ËÝz £+ØÓÃ+Æ {xS^𣦢'¯(ËU•SòÔÔÉyªº*_UOÁ/-ÎÕ‘|4 $`‚lX`†µ­0)7Ò¢¯îÉ]¼Z¸µ“¿ÚO‹½uûÕI\3ßzx?ÜûUÛ¡*ÜxXnÝ*œBžÝ jƃœ¦iGzôaµõw‰7i‡°Y(K•ñ ǃÁìúýn8m'ßñó5_*½¾I 7DÞ‹UÿõÃ%[W¯äãfŠP­ÂÑðÒÕÑÛ†9˜kóV­V´Å°µã±Â.Þƒé0Ö”U Ú¶q‚¶ŸÜMˆµ£„:k€{/vGî-PÅ{+ßýîö‘—d…¤Ày«îR¥¥UjRI.žU1)GM*ÍUeÅÚ./ÓvŤ\}Âóð;;Bºä3ùF7½ÚÖ~òE€Ͷt‹ëç3¡ñ÷TÆ-JA$?ÆŽ*ÌÕO¶©æ]ÛU žã uªyw½êÇ-¾iä{å'¿ f¯ºT¶&3A;zxæ¾;ÕþM¯¥L–o1¸k°€‹!clÈ«ÎÞÕ= ú§jÀò/ܼåhÂ+÷MKˆO¾nííס‘$3ñB„Í¿y\…›“[d‰ŸZ(*”#Yç_¨Š&WèFÌÆ‰'¨ô´ Óx—áŒf¦ðDGd‡¥i£ôÛ§Á͈ьýMYY‘f<é ©ì0Òæ¤P7vZœÌ á “42}4 düÜT(‚úfM’°¬ìÒµþì†pg×¢‚ü|,S ‡)-‘§´¸X•ð))F/]¢&••AøËä>{]SæÝð€p 3ùËsÛ2Á¦±e2n]fþZº‡Á5Ñ´Ÿ X€9 ¶Ví50›çê[÷6¨ã;·Aè·‰À·ã‹R£i8¸êÛkUV^¾É—Vý¸ðã©ïü»:²³.­ä²¡Š1 "€sT ï*è†ÐwâT_:‚o2sËM›®I&c ³_·îŽ'AèšDĺÛOªOþ÷¨w'BQ8üÔ9 ÕìTS¼^^7êAB 0Š(OpM §éxÒ®=·‰G±Z¦ <#$Áø×ÒÑ(ƒó"ÂdiòE²¤açÝ–žÉ¼ôüùñh|“7m™¸Ä·xÀ¤bÂX#L<âÕ?ôÓ0Žu‡ö~¥—'Äôð6°oš(ì;¶¨Ø-»w¨~ÌÛÇÚ¬þâͪjÉyÒûû§¼ïÿÙûïMk$`óL–qÀ>é* =çøæ÷&·Ÿßf!ÖFúò›ŽÜ0”èš41¶üà¶Y999[áöž5¢ó¼ÿ¶gžHêöC>m‹˜o jP¹µs!;ìaQ>lô"¬pY¡Eíðáž8ϵm•‚¡ˆ¥á ½¤©Óö§¥Å¤+ 2_, Ó2ñ˜†ä5HKp m™<{ø¾rûñ<·Î7I“–6ŒÃm‹Ç„Dq,Àg£wç•Y'öî„°oUMõ[TóÎ­Š `<Ìe_ºUMÅ*$»€9¸p‹ïó}ÿÔΗ^0ô‘å/HrÑÞ8Uàc‚®c=¡‚伞rÞ»=ýÈ’µ±ûQÄëoÞ|ôGŒ,'6|Xkc*u|ÿUÿü3šÙÉDœü’RU³x©š†‘à s-$l¸V`¬›‚D°O ¤–€glŒÅM£·q‚6ãÒ×iZúŒ£ÓðòBª6-bÄàêÀçˡˢék·/ ‡h>8Ýfᆎ‡¯Ã5ÝD÷¥iüQ¸¸ˆdª§í„jÙS}§:±gÜ;ÔI,ÜùoþõO³£`R¹z×í˜àí€ôþ¢ n<>¢v®û‡÷ÿ7¦n·!{vUô4çtÄÉáhoä#7mn|.UJÑš&&ª_wçc¨÷÷ ƒæqoÀî—þ¨ìAOƒwÒ´Uµð\U¹`‰ÊÇ<š Z Œ8íÖ0?œhƒÑ >h$Îô”B@9H>­RðçÏæ?f„ØSflqüS ßÂ} ˜V4,·×~ƒËê"ޱ)0a|èå8¼Ã÷ãX ;±g§ê<>>=;³5¬AÞ/úì×Õ n1·ÂNÁG̃UbÓX_yÁê¿»uYõ›ðRø§xó°t'X ŠðTN_ößÿkýa¼ÕJÝHý&_ïÁŒí5D˜Ÿ ~ã®zÅB)\þ‘ Ù¤q(eÕ5˜,PSæÌÇûá-Ķá‹=X)D…%¾P‹P ®¶cVYŠÇŽ$½¾:¯Ç'jF4}#¬f cáÖöç#àf$¤Ëlê¼ Ž…{øÌ·R}˜‡qgÃÉÃÔÉ#|·¯ßà†Í ]Γ“«–}èz5ïò«t'äWžÛŒ"ŸŸºò’ûY®;.(ŸÔ×—w7ô)x5C&n;¡Ën]´øè=øEâ;‡*FJ…Üö_·/ÇûåA »,›¦½»ÔÎ~%;J³œÄI‰Áã¡“gÎQ“§ÏTeÓgË‹dhè ³”h’¨ÅW AKB©PèŒb#”A4­xé[˜Ql£‘ˆ ·eѶ¤A\S־ΰ ãG;¾ön<§û0`‡&n>dͦ.ÂÑâ^•ÖÌDïn†ù\@äü›0ÁÉ‘¾ìYU«Va5ß:Æù؃° &œAÔ#§Núª½Õg$9D«HÍÔ¯½ã£˜/ý±’ŠÛzä°¬ ŒõÛÔJ¹Ák9Ž J*«Uqe•*™Z-»ÈòK°Ö9H)PxŒÐÅ„‰p™0íÖ‚T ÃÄeÚb“¥xBU ñ”ƒ?Mæ‘÷ÚwáulwÛqÕ›Cô.ì”ë<Þÿ1YŒë ŸL•]¿hJ¥:ïƒ×«Yxï ÷z~Ÿ°† Džºâ¢ëãnÝ*·©oÚg!m_ˇsÚa¡Ð‹x徿›[=;Zi³Å¥l°(øuD \,0‘nlðØþÜÓª³5pq¸(ãÆ›Š ±xĤ¢rØepORù¥xŠKqP Oi)Åí‚OT@ý˜x$"¡T°JÍWöuvêRâuhw§ÀºÛÛTo¸]õˆ}öIÕ«×{ÂmбÈ$“‡ý‹¯y¿Zpå»qÁLî`!7 ÐkÝY§ú—¯¸dÿpüºoÁ‚üÖâŽOfE"_ƒ2˜3îX…¡•ý*í¶tùå ´Ó3PÜeôùdc÷ã;l þ š÷ïN6ʄŠáÝo^Q)Î)äËY*ìÜ|ì?Ï3y6l¥‚€Ñ–v÷Aˆ9eO=À/ÇbhÚg„–ÂÛ׃ï×÷õ:ΊTÄ‹®~Ÿ:çª÷¨œ¼oxûª#€Á£™’~zÊy«Š~<ø­Kk.€Þÿ8¶Ø~áf[j<ÌQ½ŽŒÿ(4ýø[ñZeŒLÚ €î¨oÙý?hÝI%oGê·ª½¯lÀ½Y.•¸×q °|ªZ„›~\qmôÀy¯+ìZð¹ØG ýDA¨‡¦,]5ì¸ÃqzÍœ99e]Wâ娕PWwØ t†£å £Ö ô~¡|f¸<¾8#v¦­˜rdÍš¬úꂵÈtJÌìhi–ÅA~9ØÇd8P†Ó,¾ö:5ç²+°~Ã÷úˆ5„à[aÛóG)¯Ûû‰Ñ¼=ê¶e3g`L· ¯ÏA®A–@°ªEnžÃ»hUˆ‡yæâK:MlWû0¬ß‰]@ØÙqj`àÏXÔ;í¯YF¤¤L¼FlÝßE¾H²†•ôÆ¶ÍØŠùŠò&Ë´ ÃãîÎ+WË0¿úÍ+ô­½ö¾gs8QƒŸQ[ýwþ:Ò«Æm>œ}æs °¢RÍ{ÇÕjá»Þ£Š*ªP ¶yg?0·÷ ï´00°ç°>=ùMËž;ó¹3º%HIX%[z?„ÝT?^RûüôÚðNzï+/ªðDÝYæÏ¬s:²qEüÌ·¾]Í»ü5}ù…ú I@È)ØZÐãí£‚ïS] qOW¸÷Žé+WbõÕ™XŒª q\*z1ö¯à¬ŒM,¡µulÏ.u`ãËŠ§ 9»9ÀíÕUç.Wspdíê+UÎt°§go‡îAaOZPül ;ôµŠùo:pvsqd¥uÀìl[wÇììHäœM䮌” 5}ó¾ÝêЖ¿*.:sq‹EUK–©9o£Ð_¡¸ª¯{vˆ}lïW±S;0 Ã( ¾ZÀ-“ž‹×hÎ$âÀ˜(&Êׄ;Zö|»¿ /–mÓ3­xÊO‰ÑÖ¯pÒ£ãb²q!Gõy+Õ ìÒ«½øoT!>,#óúÀ|=:„׬{ûèp>n†÷@GxbàÔÀ­NðS«ç1S6Û¼ó"|ÔñÇð/°°tìnl_=Š\wÕ©¾t¯‰J'a'-”`/þÌ /¡¯Æ%Ü4%Æ'ôÑ_ýÑá?p(ÓZ®ýîAJ¡ â'8WqwiíÂíie4Ã#¹ Þ{oa¸¨÷V¼øgxÓ ÛE N¦5á8jËÁýnC™2 wæÕ,‹ªYñV5O.kñFlV ‘Ï@Žñº÷ÚÎâÀ¶Š öò¬tþé;²iÃïƒ9¡Sß+šµèð(þ›…Ó¢,wê×Þ¹2Š<ÿ2 KÙÆÒî³?…-³Çq+qΨŸ8tmřӜ‚U¹xþ"ø)¼u‡g¬é5j‘f-Ì “Ûó‹p#l3Ç·aF)lE¿#¿ã‘êêe6)g§ÏÓª˜ÍW×­Ë- øêüFx§¦œu(n®·JÀž£2hÅùõ¼BÊ ³µ%eÒ.¿ËfÔBà—ª©xª–œ¯&Ï[¨wäÅ‹B†ñF"äð üÐÂO¡÷záyûx~P:kîó¤ëÌèqà´+›õ]÷­)ë+(ø ö ü `Ü.™œ¡À\ž§·wÿÅ^ÀÁ F­Pm¸C¾ G’ùñ6,g†ç·Ù–bÛmʤʚ ‡IDAT9n`žŒËW+,VœR4¥JåÇ–‰|’Ã3.~²ÑòS»=|Oü,‘ŧ›&ÖËϯž#ƒƒ‡©ßüïïÔãèí7üåe¿Ðkšúw¬¹~€s>(AÒp#Q]KÃ;ÑSsjp-ŒK}&…i€×¸¥‘…]°À) 90 ü@Ø r=ýv*áW&¸Ô£¿lìÃí=]]ªŸ—|àá‚$£²—ãÍ>†(.þàvtI@`tea|v>ã…“oü" ›'á§ ç•è§3$É òsÙ¨ÀYÒ'ŽXÆM¨À´_ÜLÈÀ¼8&øôÀ‡Äh]ÿh¿ú|¦¿÷Yàî¾uãQõì¨'Ö߬¶n߈1„gàs‡sàQ
ÙQ¢6FddzÉþ:#‰å’Œm¼CNØè°#‚  ¸¾ûö¢BÊ08\.%A?">šZ‰øÂ-ž?ŽuSœÄmG'š>i \„Íâ˜ôÅ †K\O[ˆçùýtY†1Xãü6 q=§‡+±Ì¡áÐÓÃ>V/¼tXýáOÔ³ÿw@hÅUeêi¿ ¡ý‚“àgÂç&ÀqÁ#ä@líÜØGç—ŠrssÞ‹ÃÝïG˽=!ÊÀÿ¨ x‚€i—â(@’ðÓ·´¬â@¹}#-ÔÀ”/ÆcÚø74½x1¸^y·½=aœn† ŒNãŽGG`‡q‚¸ô’ÓèfìmñÄRâªohQyí¨z~ÃAµáÕ#ª©I¾óý ~oøn¸œ0ìwËÖü¸g$ lèn|Ä!r5>Ñø·hÅ— !°q{ nO áG>\‰¤£ijᥠx´|¸Átu|F©²Ó É#³£ˆ„.ðD}éTia'Æ1ôi a-Ád¢B^~àö„ŸpR3¶ˆqêpBNa“NþÕÇÔ+Õ+¯7ª†}­zaç†aÎ8EkuÍ$_]·¦¨$»ì2È•Á; \o†ÍêFí³5Ì ½qS\ìÜÚØAÜ(- §0é!éE0ž/ æÃÊ8ô|yðh3 ' ìñè0¾ä‰Ü5yóÅχ#N¦#ø´´ÿè±õúÖf-𛎩[›TG'Ö9Ò0N¤Á´1Œbj| S'Òo¬[WÔ^ؽ3„KpkÙjôØ— +å‰zn6~«´Ühå Bk•OÛÑ8Hp z{xàõãøÜ‚<† ¢¯q£p_Z6 Â<·ISУ4$ ý#¸tvuã3ïõ-jó¶ãjS]³ªohU {ÛT8Mag.bS±_?[DF˜m?_“—ÓS±`–B,—b1çBtO÷/ bWhƒ‚L¥@¶Y7JB‘` b…šDb”ЇÃ0Á'=&fÓ²p “0âÃs|J˜ŽCâ4·ö¨ý‡:ð´«}‡ÂxÚÕŽ=m"ð]ÝIÍÏ…T:?N¤Ãµ±‹#ífìÈO|ÊuJNá9Ù‘ù‘¬¬ôùœùàør¨’c…ßÚQgùnz{?nÀ-8QÒ¡àáô¥ãÅ5aÒÂMlz4@lí†ó³ÓM-ÝêPc—:ÖÜ­ŽëRo4u©ƒot¨}‡!ìê½#½á;K;RãÀH98ºñÙ´œ‚»ž¾/?Ô[R•ɮɅ¦E²²« í5¡H¨Je«IDzHVHl¸Ë!˜“ð”A(sEHýBMá ¬+øßS”騀ó"Û“áÕÚV'; áVª-ܯZÃ}êd{Ÿ¸Û`7èQö¦nþ9I7D¡ÆìÀ8W@LòNÄ0d4½»ž~:?¯t@v÷duä„òrúq¢ÆÜñöO|ááήî·uc³P7Î*@üU¾˜ ùr‹> ¢£ûágšÛ)€‰Uc#ºœcbeâåfáÕWc âcMìeý²Ü†:Ûqà4s€KÕÎ88d(œÈЊwÅv œpíÀq ƒ9à@W¾+ºã€S® 8d0œÈàÊwEwp ÀµÇ æ€S\ù®èŽN¸6à8Áp ƒ+ßÝqÀ)×2˜Ndp廢;¸Ã@gLÀ™¢ÈàS‚gLö½Œê[ƒ=¯sŒ+œWö'Ÿx_çÃÉ#;LÇ$9à¦I2Ê¡9œp àl¬UW&Ç$9à@’ŒrhŽg#œ8kÕ•Éq I8$£šãÀÙÈ§ÎÆZuerH’N$É(‡æ8p6rÀ)€³±V]™’ä€SI2Ê¡9œp;Ç·Vükã›… ›ú‘ ›3—1ÇÇÇÇÇÇÇ3š¡>@éŒã€ã@frÀ-ff½»R;œp Áq ƒ9à@W¾+ºã€S® 8d0œÈàÊwEwp ÀµÇ æ€S\ù®èŽN¸6à8Áp ƒ+ßÝqÀ)×2˜Ndp廢;8àÚ€ã@sàÿóMdÈ>?æIEND®B`‚ic09yŸ‰PNG  IHDRôxÔú$iCCPICC Profile8…UßoÛT>‰oR¤? XG‡ŠÅ¯US[¹­ÆI“¥íJ¥éØ*$ä:7‰©Û鶪O{7ü@ÙH§kk?ì<Ê»øÎí¾kktüqóÝ‹mÇ6°nÆ¶ÂøØ¯±-ümR;`zŠ–¡Êðv x#=\Ó% ëoàYÐÚRÚ±£¥êùÐ#&Á?È>ÌÒ¹áЪþ¢þ©n¨_¨Ôß;j„;¦$}*}+ý(}'}/ýLŠtYº"ý$]•¾‘.9»ï½Ÿ%Ø{¯_aÝŠ]hÕkŸ5'SNÊ{äå”ü¼ü²<°¹_“§ä½ðì öÍ ý½t ³jMµ{-ñ4%ׯTÅ„«tYÛŸ“¦R6ÈÆØô#§v\œå–Šx:žŠ'H‰ï‹OÄÇâ3·ž¼ø^ø&°¦õþ“0::àm,L%È3â:qVEô t›ÐÍ]~ߢI«vÖ6ÊWÙ¯ª¯) |ʸ2]ÕG‡Í4Ïå(6w¸½Â‹£$¾ƒ"ŽèAÞû¾EvÝ mî[D‡ÿÂ;ëVh[¨}íõ¿Ú†ðN|æ3¢‹õº½âç£Hä‘S:°ßûéKâÝt·Ñx€÷UÏ'D;7ÿ®7;_"ÿÑeó?Yqxl+@IDATxì}¼eUu÷¾¯Oo0Ô¡Ì]Š ŠÒ,ˆÆIĉ½ÅDcüRÈ—/*š¨‰¿ˆ5&jÔ F£DTPÄB¬t†> Ó^¿ßúÿ×ÚçìsÞ}^Ûû½sÎÞ«ü×Úëìrú­Õëu—RŠ@Š@Š@Š@Š@ŠÀŠ@ǪnªmŠ@Š@Š@Š@Š@Š"R;HHHHHX€H p§§*§¤¤¤¤¤€ÔRRRRR`ÒÀÜé©Ê)))))é µt°wzªrŠ@Š@Š@Š@Š@:Hm E E E E E`F ,Àžªœ"""""RHHHHHX€H p§§*§¤¤¤¤¤€ÔRRRRR`ÒÀÜé©Ê)))))é µt°wzªrŠ@Š@Š@Š@Š@:Hm E E E E E`F ,Àžªœ"""""RHHHHHX€H p§§*§¤¤¤¤¤€ÔRRRRR`ÒÀÜé©Ê)))))é µt°wzªrŠ@Š@Š@Š@Š@:Hm E E E E E`F ,Àžªœ"""""P#ÞÇà'VŠ@¸ZŒ<¡ CÉFŠÀ,@¯øµM–%³Ô¿äÖÀXWÞ$uºyŽÖ+¹="ðx©Ê æOuRMR&¯‰Fšü'¶¤0^ƺÝÕ²Ü#K )¥ÌP»h‹)¥,´ß. „“"0K#€×¯Óä?KwÎ|rk¼‡Ëu½A'Ȳ±ÌHåŠ"°Bì< ËÏ*²—̤T¼ó¹,ÝUM¶dœÌ-!èl–e'¤mŠ@Å{+e靨n2—";—ŠsbIø >#“¹à#V—ÌÙ² ¥™ˆÎ’>9†“͈8E°Ÿ?A§ø¼S2·Må €8_2ÿá i›"Pqp Š[Q›*¶›Ì¥ĈÆâeI¯ýňn #ð])àSÓzÅc]”Rf 0ÿkì&“)1"ðAM“ŒÈ&Ì08ÈÌ®2Mç @q á^YðŠ`J)3\‰úÂLN6SÚõ‚“ÞùoS0LËŒ çDY~í%¦ò €×Å€O–%=€h¤4ø˜n;ž ¿“ͯK&µa´w p6ùÃÈd_læØCBÄkYÏnÆL´ÈÀ¸tЧ§SJ˜kx£8üsÍéäÀOÅãW–½žî-€ïRÀÕ€”RªŽÀ°Äm(Œ¦”"0W"€ƒW´ÙÅsÅáä県Ànñz_Yv”½oçe§3¤”"PuºÄàWm4ÙK˜f¾&úiòŸf“ú˜ÀÛRO—¥aò‡V;ð¾€çRJ¨:§‰A„¦”"0"€±2}ðg.쩹íã{Åý·ªB;oxo—Ìû|!mS*ŒÀ}bkÿ í%S)S‰Æ]\-M¯ýM%zIg¢ÀJ;–p;,ã_%\rXWf¤rŠ@ä,|\‰Âó()¥ÌÖ|HKW«fëÞ™~á¾ÿ‘² ŽUW`o‰,÷˲…Ø©V“q¿“)Íú(^‰šðûøü^@J)³-¸Bu§,1N¾²ºÖjËeLLd™ñL%c_XËçKϘŒ™ððTŒ´K@Ÿ"ËÏdiçs-|­¹îE¿/ ~Q ~"Ï– ÷ÉßÓ>ÿOYžÓHÂN˜b¾#zQ'ŒƒÝ‹ÿ0‡SÜA1ÔF.s#ñO~¼ëø6ʸ“?„c6D\ÀOZâ@ rpõúƒ®£+ý„vä@O¾Ö±¿ú¥ààáÔhé1‚Œ°%š…œ"0ù¼QT¢¿óßÕûtWë(Ï|U‡' œDf"‡È«›GÄ6OSã0=¥X8[€+xçÿ éÿX{p’¸#C?‹ýû&¡G?–Â?†„éägê€÷G1‡ËýQp^^–utmð¶Óv–E@'àWâÕhLÏp¼£sL# {AF ÂwþŸ'žÉó·¹*/ÏòãsU<×îÜ#âÀ1²à@[ÒlhA/•šÜÙ–ÚŒ22ôs9R»e©Äž©Ô:VÊx`?j ý卸B@zç!íy9¡ÔÉ¿móñXÑÃYÑ™² Ž%4YÞl8€Ï§ÊRÉûzÃß”ç¶O6NI¾‚Ôj5ùš™üN@GôÛôë¥:¯­ JÉĉ.-¾1vuÓ;ÿ±#ž H)E Hïü·#ŠsctèZ¹š|SUÞâ¾è_Æ06ÓÏ„uº^ ÇËrdHŒ’—O5ºú°<phø:±&~àO:ºäw†7ËÑ5nyEK˜üñù´¯E³€Jpæý¦«ïéÒ7Ö-”˜ÎÚzâ²á¯ˆQŸUòõÇé%K”+ä³å €¯,¾x/ÄÜŽ ýT&™[cšHØcDÀŸñëY¿Nü˜üq€MÏ"€7Â*¹”¿>³Ü‚?ëçA&9Õ¯u`¥gýØ’RÍõ,>K¶‹c×êD1ðÜØFþ¼ŒÀÙR«èïüw÷*?ö³—ötûã±€ï3ó2¼³«R£Ã7ʯ̶ý9¼V•Ä+òojÅl}6=ÖéRÀ›xg;n²ß£Çg5SŠNøœèmðÒ9_41)Ålâç †Ž2Ýr€Ðㆣߪyº¸ð¾8µO¨ó4h¶×ÈõCük\ßÒJ°s5›ðaœ=‡9¥œVmÞîÇÅžJ^ùëCG˲§í)ÎÆ+ÞÅgIf«/ÄÜŽ ^%¿àt{L ›?gr xæÂKVÈ$*僽 @y=}'Ëí€}cÇoµxol# ^E ’wþ{Ë0X“ó4vë3#ä)ö#0A¾,)µ;#ú昼÷_QÂr·Uak¶·|öFY¢_©À¥æ®Å¯’„gzRšn8YëÊ&~€rÀÒÁŠ60pñP€,[†¬ ßév=üi¡Ô©i…çNp¤QIÇ‹T‡yûëϼIÏ£C}µC]µEµz_½îVÉS"}µúÈ"¹y·BZÉNd:FkõŸuoÿMµ .˜ì=À h\¢‚݉ï¢îÞcåìÿùT:Kë·ö¼²Þ€|ÆSù·”$ÇŠÀÈÀ÷¯(}NìàáäJ’ް•˜š²‘7‹æ?MY{Џ еèÅ¢1Â2‰ŠU,ê'ÿòÄî£êùpk¼ƒÊÈÀîG¾äûñ¦hÔô]A¯äW‰¢Öbßpñ=µ‡»×Èc6kj®c/¹”½—«Õ÷–Ij̺’½&7¸ëøeÐ>Y–ȲÌòØFMÒ&·Ë‘æUndäÝ_÷®OÐâÑ”’X­c±[ºò rˆaÏÀ4™äœØ6<4ðþÈ`J^$%¼)6Ü_ÙsÂwJÄ®2ê~L®ÒæTl])JO™Šâdu:{N—ÏÑ>q²jI^"Ðtb·³x44Fã«f?‚XÀ°« Žîp>øÏ2àµõK˜€.§' áª21•‹¸ýÓôõõ$ûëÀúhÇ:™o’Ýz ì²eRZ#彤¼·h-/jÎÚ®\4ºªÿmGŸwÁXì"÷áØµX´ìw\OßI4Ór’WñYNW´6¬ðë~C»ÿUõgʽ§x¯ðPY*y Þíò™Y¾}šø·E–•±ýü¡Ey%\ÎCÇö¾eRÿWH{¶šj€ûƒÿP D(tõêzŸd±E,¥ ÐÒà×uíuq“ÓBç€È¨’3>Ü?¥‰F .gþÿ-A«dò‡S K¥“?Œj+Bnö§ÇŠ‹?—%ê}7„¡V[æºåyW‹ú€/LÍùĉµ–ÄÈ·(Dˆ¥Zð© ü›,5|Þô W—a=òÀ‡åjíÃ(ÆLoðJn;ŬÄxØ·]ôþµ##GÈ$q„Ìù‡‹<¼yƒmô÷/ÅÆ¬L2m¾cãkþâýMœ»Thq_û«u¹åk^ï:åé?]sâ¶'yï˜Lè˜ÓyÉ4äA‡ïÙiÛ:#ƒ?r8¬(}Cì<§"[3k ”Ù]x§¸‡Eˆž::7ÈóçE·3— pÂ&hÎÙ²òªu†Œç³è ÿLDóy!î¹Ñ=úÐç•o×pVÉ‚íœNw}à‹v-:Z›S­!.³„ŸìWÌéÊÅsþáÑáþƒŽ~Ã;gJ>úå§EKOw‹–͉¶ƒ Ýp+LNô8@“?XÌšð½¾J¦u9£#›Ýð\Ì¥Ê"í,? `ûÉ"ÛªOså€ ^Õz¾,÷„XÛÑ‘ßÈ“ŸW»Îîè¦bU!*®Ÿ¼§rÖO]x'»ÏsŽ·Y›òÄϲ¨ô.>Úõì>\Œúm<ŒöiYðDèœI7~ìï÷ë¨w/#Éñ×ÇÊðuüN7ˆ7i:9–!È6!Ì™JÍŒ£«::û^)¦ý½~DîâØ®tví%“ÿÖöuòá~¿Ï¤c`’gŸ[èußg°ƒí’?üdiÁ÷})4Ù£õ=n¤'äÿ&í$ᣧÉ2#“?*2×àó²ày€èO \á::çs)!~ÂæäaCc64Çã‹E½¾üà†·EšÇÙ¥+ŸåÚ"csý'Zú=AþYðº×¬Jx5®oÏÈ 2ÞãFñI2%%b¢_†[êl;«œŸ#ÎH3;K\õxç_ÞTˆ™jnÙÊçÉxÓͳw¶yÌArH5X_QªÐíà¼÷ )»÷ߌ5¢Š†ñ©”Vrßÿ“UE”F=“¯"sñ_GÂ}¸É¢­}¼ZN™?Ê@t/þC±”žà„,÷“4Ç"<àoã,ì$?™cùƒæ€I]ô²ƒÈ{¾h1üt !Á_\ù­(}_ì|´"[-ÍÌÅT#?nü 1S]><<ð-×Õ‡; 7;¹cà‘$CB‰PÆX%kÏÇ EA%(Ë3UÖ$¨ãT%×Yºòi®÷¯¥ÃFû¡,˜xÜѱÄ-[õlöNêvŽ‚2R 4¼˜ óû„¯û”¸ÁAh ù@ >rÃߊÒv±óŒŠlif® Rï’åY²‡BÌ4:|³üÄ/\G7~7fa¥lÆøƒ?Ùê edÉ ‘ñ|ð2>ª!+ª 2¾âeºDQ¾×Jgç"¹dú ÷ȶÿ2‰h›‹ù‹²ÈˆÙÞ$ní–‹ÞwD½Ó"cñ)2¨cÒ?Fýè_¾loMæ%Úo¥V¯•%ê¹¥ÒŽ;;—röý“1&}”q€?@Án 4\ `þgûY– 3ág »åY€ZÇ>1ÍÌ*l?Á) œ€9p¨›žŸñ(ˆ’NØÌX4?ë‡R$ª¬jAFËG‚ ÚÕR–}ÉŠÇ»Ý;¯vCw“i…'å?( ^ œvºá“ï9¬cÄ%_Å;ëæ_x†<žÇ…“»”fOö ß&Þ`¿GM=}Üâe'›|FûƤ¤gÿ8 Ë’‡ 6\±Sqg_²ƒêCÏŸí£3Æø°’¿e°Ð†¾)?ñ‹“òJÒÿ+¿ªÄҌ螟€à,9]|»B–èu©u¬rÝ‹^)–zgq8ÚãZ8¹ãVº±PËÏ£ÅȺÊq ]-R@9…¼L¯K®¨ïu(/«ÁþÍn뽌jÑž6Ü_¼²3©të'.’¿`KžˆþèAUi°N²œ¸¸Âà 32JŒ b@`°aak-Œè¡\özºå:×…N€ã1!òÈð#î¾;ß/—ñ 3áÕ°+Bõ‹/î¼eÛm§Ô;:ž-#ë¹â(Þ0oCÉ”Ÿ#xøqo½ÀíÜÓAEK8ë_{àŸHîj8ëÆ™8ÎŹ–M83¯,ê5–¡ê§Ó5 SS>h°aDà0‹m™W«!ùÎÿ¿É˜ñ`µBhŸ,Ë«06óá €¯ï%s,}žk;<øy`y ò«Á±*зÙäïg²f<À€Ÿñ²ÉDNà:E« äÊeá0‘GcjPÄyZ e“a¶&—PWº«ÏrÛŒ~)ïsbò€_~úƒ+{úŸ!~<ûæ‡{޼¼m Aý™”æfú_ñ¿B&ÿÄu¿æV­}¡4~ýY7ÚµÎÂ2 [çÃ!šÇ$>á§÷VÏàj@Ó1³KÊ®˜]ÐØ¿0ù ~x%Àóx ÂLP"\Y ¡Ø¡LYËm¿$¿|Õ™r9?>5íÿÁW¿äî¾Ám“/Š/kóë(0jøf1xÝ}û£—\þ´Ÿnúmôû{Kä–Uߢ ¾¡kÛfoAûY•¶Ž6¶º@~±O}ÁË}%“%¦ÈÖp! mŒÍ›Å{oR®_/ouýzR:Ó¾Qtß9 ý¨ªÚ¢¢š¨ü“bñUUXíè~¬ëê}f¦¢Ùðƒ p(@‹ÑF7ÔtSž*é€Ä¼Hò~PQ1Å¢=…´Ì@drÔ••ÇCÆ ©ç ™_¢¿{×î»?eèq6‡í¿ûÚ_½Åuv̧cç8±šå¨8aY v¥üÖô•_ûÎ+¥m^'´¨¯ýut.qûò™àõÅ¥ìÒ;‚…3pùeì¬=»2FH§‚Òpm@‚2…õ‚׃ lA*À'e<¨ÍÕTÝæ†öü›Ô»’·ðú%NxxøáÙ/?¦ÎVÿ¦ê×oDqýT•'£×Õ÷×Ñu̘Œ;“’õ“¿ŸZ9ÙÚD;ŒAŽ[ÎñÖ¤'DúELÓQ]®©§e•-û£RŠ×lâ€Yu[îþ„¼xT¢¥¿zñsÝùgà•ý”fQ0ØÞ+³ÚÒ¶Ê<¶UÚÄýr9|«œøn•¯(n­utÝï:FÜ9¼rëɯyMùòÞù¿(v}Öìû"·tù)˜ªÕ”M¸(ÒdB&¶ PypàùnFÏʧ2møƒ„ì @(B¿ [5T—öÔ@޽9•Fä¾ÿgäÒÿýUxð=K–è÷%§S?nNc6êî'NÝ!KOtçj=òjà+äòôšè¦Úi œà1q3ÙD:!^0ér NÆNþ~⇠ҽ=h@Ï;`¾H\ÓQÿÌi~ZŽ14ø€»û·ï“Aj„*1VË/rßú»?s«–êY\  ³|íyç¦ÿ熇%/Æ Ï|ù]ot×á_J“ˆ€Ü{¯É$_—IÞm’¯ÏÝÒUë¸yhÅžß}Þ•ܘ-ùz¦”¿W¢µ½¸r¯§¹ÕkåŠ0'QN§:¿bF•”M¬,èä¬e6åçªoXŠ'Lþç ­“8ý ´@VôYÂÖt¡Cœf<Ó¡Ì,^ÕëÈ¥ÿ•zà.Qô„6¼N–¢[jƒ™Û4K!P¿Í²`‡DO]}òjO×ÑíLÕ@6‰ËtÉ ×&[àµâ&b/­DÖ8ûBŽeÐÁ´D:‹J£ž*S‚Z`™Žfe­âÄ$«Ì‡¶ÐLLmz¡?úðOäy€ÏÓF¬Õ‰vŸ{ûk õekâÊ=öúM2y\'¯–]+»ä×µÎÚu_õç÷΢º Å` Žú&GwÏ^î  ï”öŠwþ-q’Õ×6é‚Ëi8˜\Çå«Àø N|Lðþ €dð?”0OFå¡¿ÏÊ/‡WÖì~_ÂWÉ•gì¦é¦ùô€f±@[~¢,¸$ÓÝL ´áÿqÝò[µŽí„m 'eî ·rËе .a¿Úaþz9º@­0:;»Có—®³k™N¬&è'Y9qk†ÜÆr>ñ6—ÏùÄ%&%1§7µ‹‰Üû Ó>äTQ7PT]”•©›¹rP¯ïtû?%®ïF b'ô“Ãe¹#¶¡vãÏ÷[a¼ž+Üò¿¾òÚšü‰Ü8Pž@›˜¹4æäßbBÎtüÍÙ˜ó1¦TÉØDkyÔŽ:¶UqG>ö’A„v¦§PÆ7¡Œ_.Ó` [°«Lo¶×ð<·ã‘_»Ñ‘=`FIŸúÎÜsO=Ѽ6úÕä(þ »e_üX._9Z¯ÿphqçÏùÛwüù’}­T$êä@íµßså©ÿå’Ã4š_&G»ô/{‚̾¸äŽÄ5fcÊPKÔõ’¿òE¢ ™ZùÚ« %xÁ-`à톟fžÀðH2Û,mËü@mB¼=ÀÎLª»‘þKªšüQÅ×Ër2s-i«›k^OÝß#DŸfŒ}¾¶X^ |•ôã¥S÷vš ¯ (ØÙžhP8î”xaà “ceAT2š÷.’®JŠØ í¨]Ó% • ~P¶½!–ù”ÉÇVÄaYR;Û¶\æ¶ÜóU£ÄÙ<õ„£Ý‡_û²8àñPwÉ~¼ ¾!}gÇš«çÀ}ûéFc‰DçñÒ î ÃÞ*¦dzÄüIkÌ•J°2̒άñ!W,CTå=†ç7R ƒƒ9ê<ÏTlej&ge¢ oºtÅóšÐ)?+œ€ ^Q•ågTe¬ÝvÒÄn“,o”%ú¿œ\zîÿoyà|1§“œd*Iœmrå|i©§Ã‰pR†wž‡-½ÅÖÜ&xä!còVÒ)«:ÄR# vH0ÿs0ˆ\·\x&çý!sB†Òš}䇂¶]åú·À|”tù/op?¼a“{òÑ8Æœµ gó?–åÊš|þ–þ«¾ˆ7ko“c_œ¨üÁ;ÿû®{±´Aÿx&M´n´aL­šÇ‹ö®Ó-[1f݆«ùÕ̼¥³}“÷gá°‘=°äìJ88ÉmfW„—´ o¤?‘¦¾±'¢,)|80³#¼fôìà‚šÕ¬ê#wËäe5Æäk“bèܪŒÅ°£-1òìÆü®¸wV.vöœ&Ï<¹ S´Á Ø»²Ò ‰*Ó‚]ÈR‡â,Œ¹–W1åÓŽa†ö ªè‰€”?¨«2LÐÊŠê˶…ž$âsË’WÏè^Æ`!I™ÞäîØôÏ`GKö[Ëß èêŒi‚•À½ÉïË@|y­Ó]¾qņ_ÕÎ;od‚ºóQìL©Ô÷bWlï}Ï‘'ÿŸC3á$ˆ¼Î£6™b>·‰ÂÌ+‹yf©cò*d"/ü‡Œñü¦ÀSuX ®·éí™vfeºe¸™‰4)+â(J:|ª$Õ÷ð}ÿz½’gRñ ~úW”çlZhWüŽÂ[÷Ëý¦íÈàå u®£óo;Ú6œ|ýäšM¬f5œx3žd¦2ù—'Ùû°iºç‘Lþð4€…²$ª_*a>RAµTÅ#„|UŸ9É,[q”[¶òX·c;~ï%NúÍ}¸ÏÿÝËÏ>-މ¡>$cðå®ö-yñõÛ³ì½û‰Õ ŽZÃÅq sÔžÞ½åÞÿ¹<èTªžu#Ï>À©4”13k#Å ¾M£è!:É zP%;Ó`x5Àx ¥À£M¨Km†öòçDFþƺ@=š†‡%;¡oЩ" à¾%“?ª#v˜Û“?*aC$² .'5þ¥,þ:]´ÔjK\ŸÀíÇ8ÉO°è–œø0p˜©V¼Œîe9Ø Qˆ¦)CÆ—)/˜¤‘¯B"¢ƒ¶ø™+”›ðàq=REY–=F¶U)+ªMè•øª›Ó=ÖàÀVwËuÈàÄ8NZÚ×ë.•ß Økù²8Qq&rŒÅß–Ïç~kãêî^àgùRÊ?ÉæÍ­˜í¢zěݒåGNç=™Rmþ 'Bä=ÂÈ—ùœ_M™ÔÁm‰e´›Ëæ<µ‘Û íeváþÈôyu63:ø(s¥˜Ðã?|jA9Vú¹ÀíøJÒÿŠ•'Vb)²y#™Åðïß.¬Â¿ŽÎõ®kÑybªý!ç(°š|e²„™Ž•9!†w‘= øÏ&Y›à…h¤ËÓŸX•˜—‰ÞBÖxðJrŸŠþx›”¡¯V]ú'+Øó>˜Hà™,uL¶]Ú»®n‘Kÿÿ. •ÜÝzD ­•e°½µ˜4gÆø,±z•øqj¾àÛøF@;“Ÿ˜9q“,v,y’ÁËITVº•ÁŸ\˜®/{ùDªò^ ±Lüf<’iDÅ…ºæó­‚d"-øŠ™ë{^OýªÉÃîî¦_ÿ¥Ü‘(©CŒ~á¯wDz®øÈ%ׯËeÜ/-ÝÝsùº·½-Þ{íôzv`É· ÜQ1]éìZì6÷·òÎÿr$͘ŸX1ArFÅ“¥(ÅÉ´?“3ãš¾ìá8M—d›òT±©/ùÄ üëa¨Ñ'Эl•P,UÈy1 ²Phg’ßýÚói¹ªWÉ10œÇ~u;«0“X6òΤ 3n»G;ëÖ¿L~ìGöµ Ž“^0Ùq²Ìæ>›'É÷hYP9Ælž±‹ž €BÆð|@nGîÿš¾©PÁø{úˉΦ犻ÑüC¿7YŸg«<ºÙ&KoL—.;Ì~Ì;d’Ãcq6‘Ú¤»~rÍ·¤Ò%NŒXI*óÐ9‹f²Ô¢ÌjÓÉÖË© á,¬öÔ†MÐÞ ÷…æÀS»Ð£ˆ¬€™Ñ­ &øäbëéf¸Ìy:itø:yÕú’é@LF÷Z>~2 sAVGÙ¹ài|ÿFL\ߌetæºú^4-SáDë'¼Â¤êÏx1!Š¥LÞʘ%¡G®µNžÆ?˜¦§Y“W%åAb²Ò ñotx*§d“UðÀ¹Äõ>xy•¢â·äÓxD×l-d•¾{×îæ_ÿ Rñ¾j»fùR÷­¿{»Ãƒã$ôkî3G®ÜpEzˆoœhMœ‡=¢~¤ïüyü_»ÞÅûcÆ£gùD”NŒÊB‰jœL©òõ39ae¬`{:5X&2V¹œW{dO•”^òSÅ XøƒÍuvŸ<UÄdÏe-'<›ÜÆ¢›fW̃œŽ­`bôe?I’F¾É«’ʉç(‹|BåT<¢Ëeø|nG4ãå ]ª©nK¾éÀ’e3»D¦"rð«æ6ßöïnëýW*!ÒúžqºûÓ<³ún9_ü îé÷õö_vè+/èo&”hSŽÀ™¢ýÿ}|–;ààä ÜŤ‡ÙYó²1² ›r|À÷DÁ¤š4o4…àšt_†¸ÚÏu[ñZýhjH HLÊË xÝÊBÀÁv+» Ò¤WÃòÐß¿É}|‡'z‚ëO•%z[Š^“&tDmÂX $\2Ü"K¼÷õ²ÀvÊ­€—Ëoì›Q&’á¤){-›ädRÃN—nr˜1"QXäTqÀËäT¾ŸcÛV(ø˜ÑKv ²àƒ§Ñ[ó4¤ÜG´>š“6½œ/ø:ƒ>2¼Ó]{Í;eïÖzwW§ûú_ÿ‰;dŸì“WI5>Ws]_zÌkþ Ÿ¤M©ýó+mkÚ#öö­uGŸø¥wc¶Ó‰PØ~²ƒd>’ªe-aòÔâø|b•t½Ý ‘x:1˜:jô¯ÌCÞ“®z™Mðä‰ÿÍo‘ƒZ&cåf¶¾¹O44ÁÕðÀ·ÝèÐ/&(=m18rvµ •D%載™3([^ÅlBJ€QæyH?A{ûYÙP& ¶0«%d8Y7ð<]ªcŽxlêI‘£VPËèV&¸àâ :Ü+ÕG·Û}ÿJî– ˆ/È‚‡HçmŠþÔûÜ;ÅïJÎÔF‡o–ËY¿7Lsjò×#N´™ßÁäol©³LÍáÄ,…òä¯eNÙPõúÉìe6ÉO€‚F¥Câ:äð—€;½] ¬Žm$á;<u\ëêZâÚp¾¶G1Æ6Ê6ˆö…†¢ÑÆÆ6 üH/ƒh©±í+Ø!OJŠeºY{'&=0ü0O-µø–ùA‡‹vOl³¯ÊÁ|ó…8^n<|@ÐWÕ‡éñÓˆœùMŽ *™üáÎïË2¯'T2jG9œž(¾Wò±•áËä+¨äåK÷eÛ&ãëD/ ƒº "÷kµžªùÄê£Ýê½O‚DÌ„ßÝøbL ›ïüGýàb|Ðúó\Oïri‡R7Ìj{ÒöäM†² “¥æÁGÆ04‹²µÕÏó± õ¼#…ö.BDÆòZB†º 0„Ž«x˜+nzšÀ?!®‰‹Žw?»öËVáÖpº´kIÚÀÐØÐ¤”ŽÅÝfm Α§mŽÐó¥àQÄø,ú|ÈSŒ(\‘W¶§¾ªmÊCI6MyžN±FÔ“UØç躬 ’Ñ­ 'Á'×cÓ~#är¾U~â÷'er¬ò]|~,ðÙ†;k~·t¶ÆüÁ½D¼ÿ9µ÷õ&S)ù)˺Û%ß(>sÂÁMÀʬ}ÌŽÇž¨”Ú Ù=­s¢³³ªÉ ÚU (ÚÛ[Ú@X8H4µßÈC ´îæ+ñs{ô—uÎëF?ÔTuÑŠIAmx:Ý=Kä cØ=ºýfhÅL8øPL ûëRï1ë^ëÀ;ÿo“¶²"o¿Òvü„‡v$M‹ òa»TNƇ¬ê Ašž—(òÈø²ä&ÀSo –傼aÉ&ãfr$ætä(®:Þ6õ”¤²&£“S+ìVtÕ’gvÊÉÑÅRªä}9V–f~ÞoÒ€ñwñkEÑÓèеòYËë2;¾£e„ ƒÎÇNiˆ²Ò×°õ|ßI•NeEš ‹¡ ðÊøMíªÍLf`œêæ§é©ÍIðhø†cþà{û´[ò‡nŒ¯<ÕßË€Þag\Ô$Žäd»nýs\o_öºý°:X0ßw!Cž!•?'v8ø\·xÉè¶í- Åì`UÛT¹êÙ>[#A2,m¼.õ¤BØBFrâùdv¡Ouè‡y"ª8ünÆóô’}…S12[æ#…JF ;óM±ˆ)òšêúÄ=ÞkºfÈoþH2÷øÂBئ€‰íeüXž žðŽ+¾r•užj"ް¢“²²·*îXÊÃ`!BÖqÇö¥ØÙÃL»À±:ÇlOˆg~×fþЖ®X/bÒœúO=Ïç¤oõMÅÅ–NºÎÎ^wè/6£nÞ+è½Q-,pì¼/Å®nߢ}äÞÿó²6ãÛL¢’‚VE¬àmˆÊÿÆ7@Ý(Ó(ƒz5ö¥5çåí™íºd+´«nÁCMMy^ŸbZ7âŠJ†š…u„¬Õ/£õÍìzl³_ÞŒ ^åê#w–ɱÊÿ#ÀŸ‰>[qÓÀÄö >Ø‚§Bã'ù´åpÿW¥ £[¡5v¦VôR'ËYtLbVÖQ[a7¥ÃÃ| €=âØ¶?£7±]æ±.yýøëÁ ¢uPrá€çs+F %ùlà.Ø­¹µûêV®ŽþYŸ˜ýWx“Ò´#€Û)Ñ/ÛvÔ+¥Íô°}‡}Ç·'ß´IZ,] Ïó¹e'IVy»eõe4V¨YY¥M¶ ÏH”÷z¡-µ#úÊTSê(y2{”áÐ>l°¾"íë ¹bžLÚÉèÞ¹ÜJž+Ù«n–ûþ?Ìùqsø1¸çÆ51;ÑÓ3ß/¸9Œô¸G7á’—¼îÒÕ}zX±±£‰ù2Ýʤ£ƒBËwÜ ÇÑ!å9n³jeb˜œªš|Á&- 2Hım~@—G;%›ŸÕâ*¨™VÖ*ç+««æ½Ÿ¢EŸ5Z ä—­Øàî» _þŒúüç1bà?dyH–”¦CEís²èΛƸZk÷{’[wèïPη| rØ®¬·XdNû‡6ƌǶ§BhŒ–Ëu=­x]iÛ—û¢~…<žÛn`Æ3(–’¯³·-RN/)´*¶²iôº<5´û‹¢]ÉE×1„g¼äW9Ó€V´9/ŒWrMjdðçndè†Ü 뜬£°ãî;¶¾gt²NJY!ùNœa ëƒnXcÓu˜ð2D£²ùRÆ'¬áCØlQ?äÑy`›là‹·ÿ…Çç§òÔ øW°W´ =: æQ\ºì@·ÿº³I‹¸‚á¯DÄ_ÐßJFúº—¸ G¾Œ±D[ñ >¯M»ÓÚ!ZEä( %Ÿ@5¤î¹Ô¹Ñ‡µS5 &ú”u0v4ö±°£åy¨78LG`;kÓNthó©Ù¼ft¡ÂÕFëÁaƒ|¬Ô%«<)Y^ý¥ET.“•¢Ú*Ú#ضørùÁÀõù=yÚ{Ø1Óqþ¢˜æ1öë¤nòÞ¸iýcÎw½½ùSÿ°æÛN¹}K“M2¿ÅÄféÛ • íšíUWŠK(™y^Ÿ a>0G{e_à‡Ê©¬æéLÁëb‚ð[,QuL:¡‹>ѾéóŽºp3>öðÀÕòÛ¿GU¤ˆ|6zÁ¦t `ò»‡¦x+à…“W¬Æˆ¼p·ëî;^:P';ú¸‰:\ÞÙ`•½°´·SÙ\“+Òµ#ÅëS¹>aÕ^n×l‡<Áàýjî‹‚~#K¿Lž^¯8‘›|àcG‡|D((‡q°@ëììq]½nÛ¿„µ˜éé~aLóïüã >®-­XµÑ=æ˜W ~Þ.GÒv£ùÆ2誓ɣ ]ª0âPßxÆ1± äU••L Ú¤ ^ «×Xe< EÕ"Óòj,ãd2%z »Ô3Ððrlóδ S7䱪‡J@“‹VHòRÂÀ£ÉÆ+½ÞGUÓñ~ŒuÖïý÷¾yÚ•«ëÁ7½Ià£?É· •¡Ÿ!–Ήmí õ¿ã–.?ˆfÐ6¯,i»„€¶!´cm'y™\4Y[Á?d©H†fs›Š"„‰’Ï_Ù†g¸E?(A}ä|¢LƒföZùatuPýƒ“’¼}o+ÛÂwÏ/ÙØõ 7*·;+Jˆ_UdkV›ISß=¸Nõ$Y†§1qÍþ_“¢g¢ÍßQѳòNHYôºpp ˆ åNirh …N]–ÍxšU,ßñ›Ú¤†âQ‡˜>¨=z‹íÓ” ƒ ÆS2¼Qe¨¡ºP(ÙV?[ѳŒ@IDATÈóÕ-ÅÆC†«Votûpª‡ˆµÅ¥ì/ÇŸG¸Ø™Ñßù_´dù„ÜácÛšdûihˆ>0òöF\YéǬÀb‹f{õ= .Q(OTãk^ñ vÝœ¦ê }OÒ¾…ÐEh¾6ݰ?‹ªêsCâ÷ÿ VòÛkðõç²ü2)E~‚vøv©ãª¨g]^ ܳCæˆZ“[VèKDòNŸHC§C76™l€:*ך®BÖ‘Ù‹[`·² $eþ˜¯„*ùàýàÖxô“þ † äX(ƒêë—Ù åÔÅREˆ¡ü#»d‡|‚{€c¾¬[¢‹ú9˜®f!¤v…×-¯‚Õݨ{èA<ú5=UÐ?ÕÂÜ—Fÿÿý|²ü0Ôótÿ#Va[aCцí G››¶)U+æ½|(ëihÙ Í\£M² þÐÓ Ët×äJ>y[¡ýÐOÊúŸ`[2êCFoa“|s y\:EªË³M»ù¬|ùTžsŠŸ`ölY*{Å ~•¦o!ݘ~ p®,[Û56Jÿ®º¡Áßèä„î‰y¾)ÙÒýdë;9…–tíÖ™ Í0¬³û…>tJ”uÌÏ–>êc~š`eu ì¨]4fÓÛ×¢Öù¢¿ (8ª”ÿ:›0)/2ëx¾Ã¥áÈé@Á{dsþâxÔñª»{©Ûxì+Ð=¸`%Y]H”¼=s‚ ú¶¤°-?Hêerù\–×ô›Ú„øY5¥¶¬m³­Â+C‰ðXCoÄ7tM>xßÔ¹›4¬èެúw\*o9U2lÂ:¬¸‘²¨jE×åÏ¥ÉõùvG¡îv?òùF¶5ûŽtNXk54óÝÜwHô_"èôYÞhcàæör Ä uˆÙ̪Š@Xm! §à—ç© ÓÕd!Šäù>ßøÐtˆ¬[d ƒYT\Z3ÇíììvGÊäPAÂýÉÅØ™K&ðÎôï3qÌK]OßJmK¾•>çË6díÂPÛJlIÚ†‚¶Vn›Ê*ÉÓlÀ£±]*ðÄ¢)ë´ xÊ×¼ò©9Az#> i™†Èyyk£Zd<Ï'ŠÉÝätÀçÈ×Ú£y ƒ PÎXšÇºþ8t˜c¬`§¡uŠ™rR~ÄmßúoÒ’«ù5ñòXY*y¿PìÌÙ”âí:¼rò,YˆgB‘G†·ÉÄÕ+g¥v“œu<ßq9XÇdŸ— ¥‡y¥N9ÃñȸtâšnÁF0(ÀãÑ?ó µÂGM•¯}ž9@Ø’ór,­(‡úiÀRÀ_åó«"ǃ¥¯Xu˜üÌõï‰z{÷¾÷–e¡]Æ\/uþ¬,ºC%#pðSÜáGþ.¡µU !¡ˆ} ³ºÊÊæE¹RùLTù¦­8hxLÀEÆ—%—ñÂ|Q.ÇR]…P ò$ëe`ÀsÉò°šÙ2Œ;Ý#zìòÑh™O«´­ø8~ݾõ3|ø5¨ ½Tlü¤;sÞDºwž.ð;âšPôKžØtr¥£ ²ã[‡d_—UNóá 1–×¢<8°e[ü)xsÓƒ! þ[™“ó jƒZ¢c6ÌV™—aÁD;!Ÿ>® ÐpÁ¯L^YDÅk†ÇüoVb%Ù7ø,ÅÿÎÏRw쉯ÖýŒö$û“ûYVl“h8 7”A†LQÞ+©šñ¼¡F¨Š•¥ ¯•áTžjÀ5YdXÂÖè09¥[„VøãЩ¬ˆT°Ñʶ*íÜþ]ùA­;„¨Ù¯ ú£Z˜Gàé îÎÄ«'xˆ©|ÐÁê¨eÁÖw³ã³¿[§/CÇ‚`aÞhÆSÕVƒG±e!·ã£Ö…‚€jf´±0jBÿVG ã|UU¤Jᬲ\¼o†'´5{éÖr1®Ò}%¦Y†]É;ÿG?ö\ߢ•Ru¿?µmh3@kP:_µ-”Á 䥤 ’Xà¡0VÛ-ò€ªòb9˜W}l‰ º$øÅ Ê3YÐÉ'‹ÄÇtð=tË©×<™ õSŠ…4Ø›ÛùÞâ¬$Ý'VðÔJŒ@º0Á@MCì.ÑÅ¥Ü'OcBªõÑ~ù>À6·x™<Ðd€`§è:±±‹¸v]¥Áœuî‰Ò‰«:Ílc´"6¡› 4ßhSÅ'â 4±Ar‘ǺÂߌGÅ Ìê«¿dÉ*ˆG«Õ{mtwÜú-y3êoB­pKévYæsZ"•‹þÎÿš½’Ÿú}=÷¯3ß¿ºŸQf+¶ +5)«,åtå5©˜µðÀ±þD<¯j´œ×LÎô3„ËW–•nÕŠ’<Ýò¤µÒ¾A=h{ÿ Q\2OoŒ?"+Ûvÿ'«zåðY–%¥ F ]˜` ¦)ö.Ñ¿všRß³ëz9⾊”×öaë˜JϺp† :åDÛ¬ãGßtüàÚ†3Ć%Â|F§+6UœLÕC.Ã*Ù(Ø y4•· wH4[J'UÅH’¯ß¢%käó±òyü„/§Ì÷ýÿŽŽ.wÂÞ$ŸìÕ¡û±ñ«‘ùþE›àŸ´¶•†²ÊúöP”Õòv…Ⱦ°ÀâB‚ñÂ|(AjQ+HÒ6Ä&‘}æàfõ3›¡)ú¯ŽQŽH²Ú¾õ?Ý(¾XZMz£˜™ïÈmd:h{H[ž&üUôôȶKäžÛ=™tÐÂ`Âkw  –dE‚Û0(Ø€Òm´à BGs¼_cù(ÂYèêd6Zñ”ŸûC[‹Üã;ð-¼_ŒK¿GýBy<ú³žûHMÿ2Û©ó/s†T ·Ë¢¦Ãz¡[¾êà¬Íxc¾é~ö{éÙ´/mç*£yÂi±¶ÇæâÛŒ Ûlz{ª‰²Éd|¥ëß½)œ¹\ð?ÙÆ¼„OÕíV< ø\Y¢?€¯mm»ÿsò<@¿t{H²j¢ãJ!0ü Å )ØÈÏ”Šv|!>!ʸ°‚£cä­{ºl[Ùóö3[Ð4=j)˜â[‰ 6ô~>Ì„ö Ô ÛhKý÷öèTýŒ n‡üNÀq'ÿ1Äb§¿Kc™|D2ú;ÿK—í'Ÿû=_ï×£ÅàŸ€Â0¨¬0¯ ýw¸í]ZÒŽVÄk8ÏŒ†>ÏÓ@µ;ø»bî#U˜zÐ=´åËìÔX¡Ã²71ÎN¬=šò^®½ DŽ/8´†mip(Ð{!žÚ$Sõ¹Ð/ôø*"è ‘‘ó”ò,_–%<ñ|l‰¬[dM‡vxf(2BƤpÀA§ºý|b¦ÿ|L3„OhïÛö‰§¼ÑuÊ7Ð&¸±¯u§fû>hd%•U…BƒhlD£¾Âz]‚‚”ó¨ eÍ‚«8a»+æ)A[¤Ã.þZئÂ$2¶& óXѦnY°UƒYà#T°|}d{ð¾ÏÉiNßAÓ­=ELãþJSˆ@:˜BЦ£ò³}ìO»þàj>¼ãWò<ÀÕì¨:`h§Í|}Ê]Ùƒé²âFô0“ÞÒÂÀ–+ØjV·!"ß[2YøSày:ÉT"&äˆçqd Eo3´•É ¿xöGSìžø„7ðj€w+ÒöÙ‚ûØHØ3»^Œ¾!¶áƒÖŸéö=àd;ûk mCH¥«Ïí†íÅp/”Æ…ÿ1x!„È0«eOóÛb{$•òPE¸‘5ÿmktò=0Aòö±Ó^ Ã,°üm\,ïûW2¼Á<ž­º~¤Õ”"¦¶©)ÝøÉ8x‰{ø'ÿúÖW­Ü°ßÚ©LRkÛ–¯ÈóúíméÛÚ¹[tòFh˜vx´¬ó‡ƒŸ`P,‡ÁŒG@iðƒ PZÈd„ €â¡õSUóO-Ñ(g´Ð—°®€Tؼ®Ä™º°OmÙà×÷wG…»øê—¸¾îîÉ@LIÏl½÷sò*Nã'8˃;¶XÉé¹ÉŒ†ÎŽ?ŒÌ«¼HçÖè:0”èoš >ãDelx?àO™çéÊ3{¡Th²è‹bžÈuÖϘˆ mÙ-cN|¹[´x5`b¦ÃüU1 T„]É;ÿÇü*Ù'«°§ø'+ÙgØo(Kb^Û)_ÙeÂÌC—8YÙp¬LL’¨X-ðÌÑÍ‚ 0¦‘ õޝ+êBVXϲÑFY… 7ÐÜrüZY)VÏS |!á¦ïT°·oüè{þ\ú¹Üs+½¹5Ë–º•K—¸+¯»Ù“¢mñ>îèð·t¹|»É€ãC8 yæ0V°\ cÁ.—š<1u¥úª ú! RnÄ%Cu[Ȇ¶i@øF$¾*P(/k}P†XÈS‚Ù:ÿ•g*-r᪠ÈêÒ%öö-wwoŽþ£'g‹å÷ÉRÉÍV±ÓîTÉ;ÿ{ïs´;ù‰oÎ÷k¡ûÊïgtBú|Êd|jù’èi»Aã!†­tcöDºQŽ^Kýð¨9P@7_›ÉÀ²éè†ë̦y3y/EH[¡mX`õÈé&*ßÀp÷Ýy‘Ã8SAÂCÔ§ËrG¶æ½‰tqÿú3ï_ò–g>õߥÏü‰˜i¸ÚrÌÁºÍ<è6ÝsD/z ÿn×Ý»·|ýL_WÓ <íÔ~pÃ}Ï2-“åÀaƒóKDžÿB·ƒ0F#²€-ÙR\2ˆÓJ&Ã’á ªÚF¹®6YSAúCV„¤ ú eÅMÈ'ZÀoø ùš[½×wß]׸ݻt¬„”åë± DÆ…ßcÚÀ;ÿgœón·_üþôûZŒjÖö9÷7ö´2l×£`ÿÆ#Ûç­ °…xQ•‡¥l•idöËr*aZ™ŸÄ1 ±ÐÃ|Ñb˜ŽnlÉz @“÷‘|ŒÆ² _¼ìÖ{ÿÓíÙu«ã¯ß+&>ß̰Ð0)-Œjǯ孟¸ðÀîþ‘ïɵ÷eío_úwÈ>Ñ€¦ [ï½XžØÂŽë@l}GöÛÐ_Ð(‹-þ0ž0oz~P½IÊôM×ÛPº*%#j™„‡íÀ&uÁ(Ðsøì1 ‡õ)O‚â¦ò ÈF¦k|`Ñ—é†Ð:ÜãO{‹ê +bz…`ã+s-!ŸÛ风;Ï­\}ˆµ ÛW~cßÙ>÷;1lK`†|m£ØÛ€S^C[2<èQßÚ‹æ©J]؃7¹œb’N¢–5k~è­ý [=È×€„ô›æ¸¹rEvl¿Fîý_]‰Wº^ ñà_JmŠ@:hS C˜[.ºðñãõkju÷øÞ,¿Xžø‡W½Øõtu5c·•†Ku÷ßùiyC'€“›Xi6¨•s ’† êaÐàbúP? —1š•‰kK3>hšJØô™ÌÐf7űêÖƒ~ÐyÖ*¯#ìzÿÎúµ²B³:{¼5kãÖñ x3¡ÿ뵧 À®ŒþÎÿ²åû»cOzY¶ß°°“°Ñç:°Ãt¿± I*9Ï'ã+KuAä¾÷\0O „Bæ—yB:8eõ±ìÂN"î¹ý#nxh;q#¯àÞ¹²ÜÙ΂ƒOmÜåö°ß‡rÒ÷wè:wóÝ÷»ÛïßÚFšCõïÞìúï/ÏìGx~°­–m@ãà敯ã„‹òX2àU×(›`‹l3™ W)WÀn ›u \«sªïAla—ó¾d:Ê…*”G^e L7 ¢Xƒ&k®»g‘|g¾ËÝ{×Ï@‰™ž.àïi M؇ †E¨£¥C?Ûs‹Õö öŸ$î=ìZó}™ó½„Lž$•õz!ÏëBŒ†m%âdH%»Ti²ò˜æ!ýo:Á7èŠÆ˜öÉÌâPœõ…§ÿ‚jr7_Ím¹÷+n×£¸"_Iú¨XÁ¸šR›#Úл>ðE¯~ÁYŸ—þòÓÞ3I\túÓŽ>Â]ú³kÝŽ=ý“Ôž¼øî7É7ÑOr]]K²Aý=|¤€2V¸DŠ­‘Ç¿mN¾Ñyu@ò” ú(A¶'ª:¡!«JÊÈa2¹­1ðE–0b¶è›ùRà _/›¬È4\66 báêpäo¯}ä×oû¾¼&õœ‰• 0 ü^,mÂÅk°Q?€ÑÓ»Ì}î{xð¥{kIØ!ÜpÏz¢Q&kæU”;Pʪ§;Ô—Š¼¼M+B¦O<•2‘l¥®•ÒÓ4 †Éííó%X °Ã3}_€RÄd³|àChwç#¿vÜ‹‹œ•¤ßˆ•è÷Ò*©É,4’ž˜æN¹í¢÷¯Ý¹xPÞú‹¦ å–/^ä>ðÇç»®ÎøÇe#òÉÎ{nÿ”<£¨_ÑD÷ EŒt8Èê9?PøÛ€žÉÅT¬ HÐÃJ·V&¥„K= ì5Ú?³K£¨Mn»ÌƒfFá*)TR½\?ç{™Ny-ð”Óß „Øéíb`·b;Ó¿’wþO:õÕnñ’ÕÜGÜWr0Æý&i»àÌùºó¸µý™<ÅLÖÚDËm€:†ml”´hcÉl©ÊÓ¼úãh/o “¨rš °ÍnèC3øå“ÖQíÑ®(„õòr~ ùsxè!yåq*Ib剕XZ FâÏ4ó8°›>qá‘Ãnô{Òƒäûö¤}V­p]òÙOnÆoÜ4<$g¥r°tùQìä~ á«€Z J9ô,˜– `Ù€¢#JS2„\Åö6¹íJ½=ßl5§†É Z”ka_Åò:цé4å•}fKí°”ûòy€Ž¸å+pÛ¶nrl¿ .ÆJèË'ÈRÙè<‰ŠàüFÔ']×îw¬;U¶j5=¯ÁÞñûËöö÷7MøÚît¿ekÉIÚ“o@3ñØfMÌj¹ìô¼O& â5¥CÚÛ/cgt`6¦1qáGxYÀ|ð^ vyß_ÆŠ;oûˆ¼IõõÖ°8©Âó-)EŠ@º0ÅÀÞ|Ñ»Ÿ42Zÿ¨¯Ÿ"DKµ?:ç Þh)ÐFƃ[.—ß ¸6\òAÆŒHçÇ`@:Ç'®2ùÌ! a <–ÒÉd2ÍBFÕÇ\Ô'lHW¼Py,û:®™¾N¢L ¶è;ë€<( |Éxª«zäÿRψ#´'<åM®³Wé£&\*}BT Sÿ²¨õMMubZxÖâIg½]ž¹ÐsÝ7¢Ë]bû¨|5€åÒ¾W݇l Êgc°}+ìdü ™«Â>76‘(£‚”E–º(ey §Â*§YÓ‡± ùöFÏÙ7P¡ \C*NÅP„ôîýyßÿŽ=bá?ûkñ´D L¡Üøñ÷<¿ÞÑq¹¨Fy÷—/|åï9¼?ÕÝ=w|Ö n×#?€ÆòMŽ$(!逤ü¦ƒ“ÉxÜ"ÊØ¥|°òv oƒ˜(©¨¨0ÅÔ”g|Ê /j`kgõ^ȧ<¹´›ÕWèËW(¦g–£n¾}òàgŠJôwþ=éÅnõšCua§IÒøséþ/µH•Ûö1@r^Þ²v`|Êž+Åò˜ÜÊÊl–í¨ Å.Ú£H%?P±˜< Ûbræ;ôJª”%YyÔ/BÓ¹ëћ܃÷§$­x· ÿ~4ôœE ÝÈB1±ÌMïŸÕêµOŠô¤ŸôŸ˜•ÂïìëÜe7ý¶x…n2 ”t{äÍ€U{ÂA—P›@EðoƒŽ+! ƒA¥LÖ»&ü “ê¦O¢é7ЛȈÍl+ŒÙ†/2ŸxÆgå)CD¬T‡ " ¢ñ…äø¢L&8¨ãk7]*[»½hŒ-žÀo¤_|’˜7üÀCŠÑÒò¸³žù·òKŒr‡ÁïCìÉ#ù-÷£®@Íe½t>µ3ÅMÚŠÚSÕ’M8 IaŒ×`ƒŠhö¨Ôb•ÕG4 ¸.dÊo´ª[ÁŒèy/½›Cƒ¸Û7ý3?ù[SÀCI•%êS³q\Ÿ{¨é`‚û¬^¯×~ÿ¾’®üW¢b½‚Ê“v·þø 7¼y;ñ¦Gñ,LÜ44øÊ¥+6bXÑEL\:ØÖØ’$[žÃ?£eÂ<©r™6§rªa¶¦çv3UVÝÀ6ù²"Éldƒ§èÀjÆ3> qQÉC’"£ÀcÝÉ¥\ö²¦mJ⇂î¸íJ ÅLg8^ ‰idØxuëŒ ÈMKä¬gý_·jõÁg !ö~ŸéžÓ2vØÙ~ÍJÔ1fÆ7Éœ]BÈŠÿŠG{¹²êSÖøždò>–}°–Èú($êŠ\+E~ˆë]ò4n ¥9<P¯ºÍ·~Äõï¹Ï‹ÇÞþ‘ø~l# _#&Ю¸à‚®þ[úiéd¯ž€ø´Dúwîp7^v‰Û~ÏÄ9r¯eîÞŽ%îÞíN w"Ê»vÜê–.;L¾°·TU?y¡Ä‰@àÉxC l­ J8¹S—â*O “W‚䯖1lµ¶K°’Tð$øçé '¬yÆ×¼ñ ÿ2äœ8¤,ð!°§W¥SköÞ ßø…Ûùèýªg«S‡ÊRÙ»ZMªûŸ•E/¶ñiî±'¿T­ ôfŽFý¾ûER¸¥¬ ªä½(%ž(ÙøÞž(6¥{nÍò¥îݯxQ¡£R(ÂjX&ÿ;ný/ýžC ,$S°ªÅÖ†œh¸-a’ÏÑÔk·!Ÿ¾ÐF» ¡tøZð6ñ"xžÏ¼ò¨?¯tÉ_DyeÄÛ"&nq¶ £|Zw{ïs„;òØç+ØþúöWÚ;!ÄJÞù?åɯw‹¯alu"ìº_³ý(îj{ÝòV¥{ Bª¦SäetèCx4¤òà7£+Yå©=U¦>²ÔC)Ëç2Ð/$¯/D¶7è˜.q „.ò¡/…äiØŠ#C;Ý›>žÙöp«êtYfú–Uûk6ËÓ-€;èºOüý>#µË„ý¤"m!×GFÝmÿû}w×µ?Ç 7bv/Z,gþÏsKVÉàféàµkÜžA÷Ëßlö¤h[¼ç‹ûÕKW¡… ~°) z •!±åà¤Ï Ø$ƒ ½&!Cz˜×Š%´Ì7U!±È—<á h62ºñ%±¥ÊTlÊó¶( }ˆRø·?% †ó„ÜÿÞ|›»ÿáøÈî|ôyuí(×Ó·†ˆ$8‰aèá™0<“¼0ý ƒm¾4çs<ƒÙÁƒ†˜*¨øÌ«ðšÙUõJ£_ðJ M!”FIÈxó ò!OÉÐQ=*¤ÒP…zÊhR†Œ|··g±ëìîuwÞþ¿€™ž&àï‹i „kÆK´¶ñÎÿ³÷ƒrö¿;M÷-p(­PÖý¢$ì!Š`m$ÛêÞ2²ÊqgRÒ°)“˜>6Ê7-ð¨Ê²üÎŽù–±$3Aû…£Å´ 0.E`ºElÐiî =pßå²|"U¤‰‘×Ta(ÙhŒ@ºPŠÉ Ÿ|ÏaòS¾xê别­Å=Ûv¿’ûýÜO†Û·t¹;þܸÅ+šѵS¾ˆO¯\õ­*úƒ§{ËGå×¾vbüâÈÁ‰ %ÔmÒlPó¿rò5'aB¨®Ÿh1šj(LšNÊ×<\ðòFìª[Ƈ\hOJ¥¾ò@%lQ†$6ò”et/Ø@PÇ*<ëÏ0ÉžÝ"8îÄóÜš½tÌ„#ɪÎ[Ñßù?áñ/u«÷^/aEÄw¬4öùo4”ËQùlˆ"hªŽ³Ø‹Á $ÊÝŒnJª:éusìfvà^£­Ð­Šé–<\È÷z ê¹kçoÝÝ·_\ÒŽVÄ™ÌÙÑÐð¸HW‚ÝøÑ÷ÞQwWi]@n{öayÂÿú˾á†öèý~X´l…;ö™Ïs½K—ioé¢>wØ~kÝ7åGƒb§‘‘~ù>À=n¯µ§`ä¢IóÁ¤CPZ 6¤ãÊ )Jø·ADù‰ùkˆF'Çä½-…0Ÿ x tãmm›kf_yÞ Õ9­ChƒñÁ¥ù¬l©…>‰ âµj¯CÜÍ×ýLÄLðÈ’7¸ö[Cm¯–%êÑé ù Ò9Ï{·Äïüû}Ó’,èZSiaY÷œ²ØTQ×ÜÁÐÁ¿ékN¥Êó6 ød†·l’ŒÞ`Ó0±ñÉäuè í1÷ßx™­2_Ãzâ÷A6]÷nxx§·s‹ëO–官FöØHŸ>þÞ£;\ýûRÜìM‹‡ý6ýð»nt$Þ¥où wÜ9Ïu½K–Nü}övïÜí®»#~ßسÅuv-vËV¦C¡Œ+œ¬e`ÁØÂIP¼ö4TÀçË|ŽoÐS¡âän4ꨠâ3ï1ý6Üàþ@2lúT¦vs†g¶ý†BŸ &âÓ l«ýÜ—²?ZåûgV¬:À=øÀmîám·Ã|¬„#³ÇÉòï± n%ïücò_µæ„RöT¾”2©%¾q!N¾"„²”ÏïwÃV;Š«(j³‘Ø€.‹¹/ §toƒ$ÝÛ,\– ±| dͨ‰›J Ö¨#в t{ó'äõÔM\Ôìß ú¢ZHàãF Hˆn¼èïé¨uà§T÷7bS ¹;®ù±ÛüKœ$当ÿ±Ï˜øäïÍŸ"Ïüàú[ÜÖGvxR´í£Ûor+W+Ïȯ¬q€„)D´ š-ø×À£ªé’ˆ±MõeT8@iÞó‹6&×£¼Râ «XDjŽ ¤&6•¬¾„øMm¨Eˆ)–lôª+Ená*V“ôýÖç®ûåÉ—Öð´héPAÆÝ;#Xöge‘ZÅKGõ ÷¸S_aVtŸ2Þ0‹ìCïó ÁãÓ5“!‰L iÎÊÐPEÅ#ÙÇ¥‡öšà ÉûèmÐ?ú®¼=ÅSœ|QFÌ+·“×+çª?[ïÿ¡»÷ÎÊžÃû¥Ø??ô!åg& þ€[>öÎoKø×ÆÚ8Û¿å—¹{n,^¶ï‘3þcžþœ Ÿù‡þõtu¹ÊóKûzCr”|½>ân½é"72ì¯ ËpƒÌCoe%µàCÐd8`†kåÿ³÷€r×ùøì{ê$zGtL³ ¶é¶q ˜¸Ç—ÄÉÏŽØNxSŒ{b°;ÿØÇcŠé½7u’E õþÊÿ|ß™3wîÝ»ûö½½w%ÁÎ{»3sÎw¾sîìîœÛ/!aâ­ÅIßYÄB[ôEOU~SМ˜ ¾¡÷}Ú!nü©0´“¾ÚªQ/?Y…cì¸Éîð×}„Ô%¿ýOIü-¸æ¬;öÍÿŒÁLÆÛ_Qqçç¡JýÜdAõ;¢Ÿ“޵o{<áþ³ Ÿ ?D%ûŽ‘[lˆ ¼IiyìOc€ià÷1B.ƒ.ˆ.Kð§|° »ò¦0yÇ ããð²´L‰‡ùæ=…õ·–”ÕâåM-ñÔvÒJ÷̼ì’#ú*•[e”JKþ¸®Ú tËž_ú0p¬'üèç˜Ê(Ó''î¼Ý¶îú‡ŸÈhŠïöt¯që×½è&L|­'“&›\´ ßé;ÚäÄ)Œx¬ˆ'Üó)sH@ãï,˜øS¸ê€áüNxE‡ÿ‘ÜëTµÇÔ‘›àiqWñG1d±ˆŠÆ×tÏ7%”rÜiçCx.Àúõ¥'®°Ëèø,¨àšÿÄU“æØ“¿ìvÞí?/[|øÐQ©JZü™ÇBA˜*Œû¦MáâH<Ÿ’xtG¾\ãR—l±#^oƒeQÃxg¡wc‘3("a—°Üj«ØNôNEnpÓû¦Û¸~Y®v\à$Ñ–g(a^Q”¯Ú€i—]¸¿ünOsBYŸè†µkÜ4¹­¯ÝÙÏüà¸ÉÏHÙýßlÙ{‡‰îÅeËÝôgžo–ª_ûµ«ŸwC‡o-çì&WL&É :‘Ù$C]?'þñ’BNxÞ–mÌÓÚ9Éë'dN˜ÀÀ+:Y¹×‰ÿ¢ö˜:r.ÇÓ.Ë ¡Q]ܦ{{gÇúU ||¡@Ö)²½ÕÙÓòW–÷~œP[^EohÉ5ÿ;ì|¨<ìç,§ø$S|éÏÔ÷(ÅG­·âĘ" iõù‘äãøyï >¾àG;ø¤•6»_ÞŒ¬Žcˆ|&>ðýœŸâñqfýFUñ]c1ˆÔÛA”ø1@Eòó ·lIzϤiK¨¿'œ——ÀÛ¦ä¼*Wfÿä’ýäçp›ŒYi[þ«_^ìžøËïܺ•éköy{_9áoÔÖãù‘U›³ÿ>îÖÇåq+JÝz¤ãå/Osã'ê†ÉŠ&›T´­“L,ãÜhŸÔ8ž•©òŒÞO^ÔãM ¹I!¾ýŠEJ˜` «#jèjÈU [ÏÁŠÆj¯bå‡$ƒËƒð´j,ááA‚Ønâ^îÙùºËJ]™“Óçy‰ëÕR7[þ(¥_óÿžÓàFÁý(.ß7Ç›|¦ú9A¯ˆDfTë<'ÍU㨵ÏË[Óyî›çø~¸cŸ)¾$Ju©¼QÎ'šRB«õ66Á¤W*ô»÷Ò»Ý3sŠø¤‚¯ÕÁVÿ;k)ÛòM3¯ºsfüø¢Ýzzû°å¿]YC¾bÑB÷ÄupØ—!Æ»åÞþE&ð:Ä]úÉºÆÆîJi÷önt³žø9`]àgRõQ¢!2êØ–IŠE(\e:‘¥õ†‚Mf¬ÑÇ_Ä¥Xà¤%oYŸÀçÅËÁA;ãð}5UßüÃWŒc_±Üꀶ)_Ê8õ'¾í«rØ£ôõò÷K û"Ž&Êñb[ú5ÿGýQ®éØéØêç„‘÷cŠ&ÆlNeÔùÏ kÓù¾ð3 sÀ±G¹B"‘‘’o‚¼G7bKøîy.¯º0Äæ*6̆uZ%fJ†¯µkº93®Ì Jëb²8º4ö6ñ G ô™fБ•`8ýòoL–݈·õn%Г×øO¿éÏr/í)C‡r·ÿ˜mËYï¿Õ·|Íš™>ýLi‡4lps  –ÊÄŒ+Ë0'éäg“‹É8ïA ·Ö¥…/“þå%·Ê¥*ÒK`Õ£ö:/ƒ\¹éêùd ÞÞóÀE¯H!ö:)LÀ¡í}°¢z=?B»Ê…6—C\Œ=^nÁºÄ-|nÜ–U°4ÇËëGƒtûÒ¯ùßzüÎîï¿”‡Gl|8ª2`6~ˆ:Ó‡1×AÇ;þ_{Þ8áPu..ØC«N…Í Ø‚NêÈUK3 ¥ò=ÏÃ`.ë+Í•‹ßU`ñ22¡±½}rµÉ´G.•szÇ!•ÙÆ 'Îüo—Íl^5{žüA×X9ÒŠ]–¥Ýzmñü9nÆMq½Ýéë•Î7帷¸­¶+í*Cœ,ô“+9éY¾9­øŽ-zþyTèíœuÞÒI,øÆ¼% JÃÄ––Aì‰lÔˆu2‰HÈKç  m«}F–Ê©³®´éˆu°°ñš]¢ó±ÁO„CÏSil>&ºÖ+Qk“Öl«,‰7zã‰_t#Gá~¥|Wþv~ v¥¯hžüޝ¹¡ÃF„mül QgÇO?Zgâä8U(Œjéjãš|F±ðÓT'ÒV‡È}ÃâõþÕB]Ž|Rí9#€ˆÅ…·ei%u†ñ*“Í{êåzÿ¹‘A©Íÿö?”ê¡M>èxU¬à‘¾ÝÃGüIFéˆAT?† gMs³n½Q®åNnðCù‘îs̉n›wé‡aðêJ_ߦœqæ•®®^aÁ®¶õƒgkÜò©éWº5«ôVÆaÂs›hÈ$ §t²ŠÙ1YB™§§ oRâ‰Î‹ 8(“7àhÁ¶Ø‘_íM hÀ>p§Ú91˜ãn—×Iœ O–Ï0À9VV¾€fÙå2q0Ð9`w±ù|ÙíwÐ)n÷½ŽáØa¥ˆßqjã„ñ«5–ú±óÓãXãã­ åˆ ÑÕÀ™=€ðªø$É‹7ÕD¤ÀlmÞ´…-¤ž;ÐO¾O†æã°±2Sê<ß’E¹gçýÅTe×óÄAK®o-{A^©üýñoqã0÷Ê®«Fm¸F/íÚÓ=(Oô»Mv±!ÿ¦Ëž¯{“Ûn½ÓÂ{rÑùS>{öäGïwü¹EBÿÁ]Ô¤êéY/—}¿ú‰v2óq¢ÎX&ªhÆ”gKê)”à :=ñ y\ØõÜ)N€rä*Îç…=c„]ª *õ’CD±×ÑX±”‹XzŠ9–¶ã>N |Í‘§ºí'7{˜>ëÜwúûuÕJü–J7°tÒÛqÖ? m/´ÍzÒW™éD14ÔáJ`øŽ±õp´ð4ŠÞÀ©ô‘Oðª!]y¯ÁJM¼ç&Þ#ò8ƒqàÖØ½¹ªA™á[·v±›5ë|6UÄL…·q ´Ô'©ñ«°Ôò¦Ͼ«®ê\·aä/äGyBY±Í>èž¾ÿ®äìšÈÑĽ§¸=Ž,ïÄW¹µðYûŸqæ¿D.³ÍÓE° +,£ÿü3•“ÖîTêxr‹œaBÂĤ3W¢ Ôlˆt˜åøŸLx‰ÖS7âV“ Ü*Q˜i˜·å„™ñðÕÅxÆ…6 ´Ö¦r ÖAòË®¼AŠË%wÞíp·ÿA¥ŸhÿqôSF‹þ;ý`šVï´ëaî5GÊ1À¸ã¥•Ž`ÜÒc§ÑäbA&êðF>J’Fò~0   ‰ÓÜ‘œ ÿÆxs|džqû¦B2ËÛ)w´Œ¦„'™÷ÔoÝò¥3MSvs­~Y¶“6ó#ðŠ]˜qù%çÈ÷ÿ|†yÞ#[þ8ººàxÿ^¯?¿¾je’ŠûÊþŸ=û’¨^/˜ôå  2kêOxiQ°•eÇâsz†!‘©Þð:TÞF;¦ÒZd ‰'»úÈptëå),yô-Ë ñ/´Ó~FôÞ ÍE [h½Ü&bÆ¥Jâµï}ŠfIJ!ÏJ}ۿȉp#AVfÁ®Ú“ûq€•„䌼~ÀƒQwÈÍÞö7]rňó÷C€á86²7 Ö˜óóñŸ‡ñq´íóAÀÞÊÕgMLôwv™aKxIOg)äi¿)5”äß ¯Îr§¬b¢Xºxª›ÿT#ëx)–ÁvŠáß Ö¸m×ÚxE®Ì¸üb9»¹ïœ²†òÙÇåDš©ùWµŒ?Áí{ì›9‰•â¿âÎÙï3g}«Anœ¡‡]q¥Ü`êÃß—ó º9ÙÅ™ä ð“¦é8-ú ØdVÛ„&º à”˜L¬~²35êØ\fý;6€ŸhAœn+ŸÓrã¥C1ߢ#˜h™—ïkz^ㆀÿǸ­'¹£û4Ë.¿¨ãàxѽ¥Ž¾ÕëÞø ·ý¤½9Î\Æ)ã±á@¡±ÁE^ŸêSCœaB [üÁ\ÞP£ÏôÉûÁFZØõ<ŒÑó›<ÆUù5¥Ôéå‹Ðáò-ÑÅþ©“Ëu—¹iþ@~—-9î3 q®UõÉPqPíöf3Øý÷Š*3/¿äxY ßÈ w<+¼<#ÉþÃ÷åò5ÚôÖ÷ÈSóJÚbësßÚäÀð€Êã‚>L^¥ŸQ¶aýRÞ hÂö‡æ^÷ŸÜ =±bËŽS&L?±Ù„¦wät©:`ü$È-E …ØÀŒ(Ï!åñU¤XÚBÃÀ©ò0)n‹/Z,O¼lT1hF­:íy©Â¸Hc§]vS½Æ­[»nÊ*x5öÝ‘q€¨°«kTF^hw›mwqïûÐw]GçP Œ CkJð¦ãÅLŠkº-8% zïú éŒ9åCC€þç?W“Dy—áø Ø§•x¹Db¡Þ–%‹œ=ÿ†*¸ ²>÷øƒß‘Kþæ›—²ëוí¤Í_ܼ¢öà±¾ò3ø­ ϰâ†(aÂ1ÿgj$ÜË}¿Þê†ËJ@EZt™\êWï˜=·ïåâz€¢tÏ<}­<ßþÑ@‡ÉQç#¾'rHñï'Ä eT'6±Œ&;zñ|´‚ßÄœôŒ2è2~ˆ¥ÜÛÕÈqìäèIhrÈàÑúlh ^†8±ÂB(jèä5tè9ðei•^Î/g^xJLé×ü¿åg»ar¨ƒ£„eçÖ¿Ž „Ú×1ÁaŒtÌi‘ÓÆX)Ž-@BCjÈ7PõDz9¢7úT"µƒ±”˜—{#­œ&·z“{.S¡¦.cB3øl Ï<ý·$ú-Ƽ%´åd(÷%ð¶)KWÌ ÀôŸ~kWy¬ï ²¼uã…KýjóǯqŸ7ä¶šÐèÉÔ°rÅ~Ÿþ—ÏË<¬ä»æŽ’WúE$i Þç¦>ô=·nÍK2{¥-8ýÉXÅó–¶UÆ Ì›KðiÌŠòïål'b½Œ º”ð Âsçb¼ ‚2^Ô´ó\i9µ\ÄÄF®(ŽØ¿é<äínÏ}ßhTeÕ˜p¢ø5¶,gÆ{à¡owûp‚Žƒ ”~\ùé qÌ9¢¦«út¼ÃXÛ¸š³ÖðÇ¡]J¹ÄvŸù]H«½Lô &abËì{¤ZW@0€=DúÄrÂßl7{Ú/A¹-¬4W®‹6{#€ü_¦ýô;ãeß3în1¹Œ…yvê£nþ#ù'üÁß.‡á¶Ýu2\ã‡ý«)/¬ýœLƒMþ×\i|Á:eÖåR£ÇøŽë“›"q“”wŠI‹ÿ±ÐtÑ(‰Ð&Ñ0Ù%*òÖä•÷šMÔ‘=›”¥õU>½}ÖWàVð§ý©'ÅÔá÷¶ €_$C[ÿ |뻿ÆÛâfÃß’û#GŽãrqŒ°øçXëXpL(Ó±z,´¸¯D‘ØAÚlUaÔ°ª>ö¯‘\±ŒŠñ¨À¬Ð/tøó¼AÉT•¶×å´ÝìPëxÄ’Z>»QnÕý8~}Xï/½àxÿ‰òjÁÆEéËòªs°Å¯ÜÒÕ5¤£wïåç´_ŸÞKsf¹ùÝS“zÛ]vw;Ë @Iå†!ëF~Âßá¯rY¤»±¢þ8–/}Ò=53s+™Üªç7•Ù¤m¼6¦§IÑ’S¬¶|"ƒ­ï™Zý–fC?¥¼‰i’/"‚§Ø'áÔLœ¯'bã´:¢¯jc>jù6y†ýx«<ÉMp*î¨7|ÈaëyK.o8áÓnòNpYSc…q“‹Ç„?.Ða`1&&W‘Ú„·)U{/'0z‹¹M"Ÿ†E &;jucZÆG™a‚F^f±™*ð™€Ð$~ÓþÕ»ëî^ë¾ûB^†k˜kü˜ß,¯•%úhS·`¶È€é—c²œaö?2>…o~¯Z²ÈͺM¶ük$|&»rdYö].W2¼{Ê'ÏlÅ=´¿'‹’½æ‹WxYòÒ4÷ÔŒ«t²ÊN’ÙYÞó&Gȼ<0Èrx¨ƒ¿ŒŽ]rùI›í˜ÕÇ`,jÏ8±4Ur8S,áž—¶ž+OŽ9œ¹ç#‹’G> UŸØz~ÇûÎ 1Ñéô6~®î„Sþ1µl6®‘^Xz;>ö8Nöù`ÔÈý|Ä4þL"8>`Ýû޹­mœ±ÉÈ›V$|&}˜Lj,"‹ dÓý©[½ê…X\fûÛBŽËþÚe -nàÁË»Fu¸ÎkeÜw(zì×®Xæ¦ÞpëÙˆû¡ä—ívßËítðáùÊæ¤«;z+ožòé¯àÆ=­*'‰£–œðäô_»Å/âa2‰édFç4LŒýʼ='Ñh„Él&³(«;ùfô©LçkÕiœæuºMp•_Úkœ>fJÐö: °ú":Ó—•Ð=w‡ñaÚòÊ»O=Ÿ÷6°qÃròÓãrë²s õ2 ZÍqR%±ý†ò™?ågƒ­>ß6 Ñ.ôGI¤ô‘-b6¾Ø"OF2…ï±{™uQÃ8”gçßâȱÿ•éâç+-òÕvSòlq+£û†_!ûŸ-z\6®]ë¦Ýxë^¿®&õÈ­·q{s|M} ¹nÇ÷ýÜ™µ¯5l‚¼Ž)ÎÀåë¨c8PnEúð}ß–óª×7l"3NLkU2™ì8ÝùIØ0QF²À< L"øÔdœÑ 6¥÷}ušp'g ©6£1Y^ª)¤?2{>©@̸Þl_}ÃåÛþæ«nøˆ1¤ØRÞ9ü]nŸý߯O9YF_ís,0$xaùïkŒ“ëx©’¸”vÞž¡M©ÚFH­¨ËŒ?SJÕG*6-æXn2}„óËœÓGZ”Æá¸ÿÔ‡ðˆß–”µâåè–xj;iÉt¶ÄKANf\vñ?È/âÌ‚èMOO·›þ×?»ÕK—Y¶Ñ1dˆ;ð¤w¸á£·ÊªšîËc}¿,OöûEÓDƒ#ÀÃ;pLïøÁ™7n…ç¬\þŒÛi×c£cÚ:¹cbä<ŒZ(µÉLŽÂr&ûÜ[þ«\j’ð)žLôëyÒYäKâ9âäD.òypMJoq$8‡‘-ìQ๕$âVeì+5&Â0|øhÆñÔ¬-coìÈQãÜÇ?¥ÜñqÛb9ý@È¢clm;‰ÐÆNGkÔëaËÙ5~¨¬m5 ´ÂabNC“œÝ"XŸÃçEZ‘VcO8”Ò¬,À‘ëíÝàî½õßÜÚµµç­”¿æ:ç]òšÖMÛzs-fÀ´Ÿ|óòDZ§B ¶LgßþW·bò`í²÷ëuxÐOá¥ÏýD’ÿ÷ çáùoÉ¡‡E/<äæÎ¾&Dlj˜aé䜕A&mÅêü)Se‹I8+“/eÐÉŸóO)ÄYCм­ç°äaµq¡V yç¿·£OP'r³ 6ðK5Þ¼ŸäÄ?µU=ÁÄBÿ†>éÆo»3„›}9ù_r[ñš„š,g<ŽŽ‡ƒp§Ô ®jütà«åž(öe¦ãJ§´S í†2jhi¥"Êç†"°°iËH½mXXÕÐ,’¿Õ3ÿo·bùü˜¦Ì6ιjßç¿ÌÞÜ[Ä À“ÿyáv½½¿’ñ)ü¤¿yÜå–̺îÐOžr ÛnÏRž¥s{ïøu_×y딯W-9«wê#?s//žQ½d6Áz ç>ÈâI3qz²­5cÍN¶ÀÞlô…ùZ,ñù]“¡N·= ËY«ï¹¤"q­ñ·ª}ÌŒ=­ÇsÞuê¹µ¼l6òÝö<ÒsÜÇ–MWnÐM–Ç–5ÆCu¦GWÚ¬äÿ¾örêkÈÁf%ßèÅ8*ì‚;â4u"³XUCocXÔˆ6ú¦š\™ùR߃¯H¶ðÙ{äF[¿‹$¥61A~¸TmòM2›ý @ßUWuvo¬\-£³cÑ#´@žì÷Üôú¾Øêßý¨cŠv ¾'7öô½ç€S»p~s(8¾wм’=%E…[”>pç7å|]ß¡ùË™1qr5 êYH8ðG25§£drޏ->dœ¨Té‹è)÷ñÓ]Ž@ò‚zß—NÔö¯u±o$Ò9ÙM9ð„(ºÍ«‰e½ïCñp‰Å®‹®Ë›,›.sµ#ëKƒãip«“1Nƺ8žËŸ?“žÑ€0*Àò?’·Õ‡e¿2ÐE\´õ²5«_”óiZ¶ÓóÓë-övýÊÍ~`ÖÒ¹gÉOáØ¢‡}ñ¼9î™:÷÷‡?\nµÏOd]°ÿUÂ÷¾ƒ?öÒ‚y›¥ÃÁäKš%iÄ~­<,è¡{¾#m²¾‘;1Ê$y(~Ì“Œ4W ˆIÊ ' !Mä¡)tÚ µ"¤´$ ¡ò–•CÈA œòÆm¡ŽÀ‡~¢—zî=§ç† FÝæövìÉg¸É;Naœ¶¼ñXš Ë‘´ÓËÈ1ã 5¶ta?¶4â,·1Ažõm:Öf‹±&Vµä£,’ oêO‘*DLêËKI—¶ÍÚQõöv»ûï¸Ømܰ:P—Üø[á_T²6ý&Íú$À—_ôfÜÚ*ó+in´V¾ô¢›q“Üè§Æ]þŒ}÷£Þà¶Ýy7ëUã 9ïÙî.а`\Oô~ym_0oݪ•ϹaÃǺm·“ä€ SL Ò'é™<ç俼“õ°E\“Ë&`á ' F2̳šh‰µÙeÐe“Wì/$*‹›†b‹¥3%œÔz]Öož®z÷¹Þ!pݺ•nÞœA±Ù”m·ÛÕ}ôŒËäŽvôIС,´”xÌmyQ›Ž Œ Š`¡Z/`ã§RiX‹Â”`ÐGIËÕN„©qgÏ|¨ ‚Q‘+Ë[_ovôW‹O.‚z¯>~(¸,iWU2¨m™ŒËî;/>ÿ°<âGC[Rž/§¶ÄSÛÉ&B“kQKãþ;º¯¾Šâ’>¶üׯÆøÚeèÈ‘nßcO®ú1Ö¶hL#öürÊg~£1ô&Eáæý¸ä'l¤”MoÏFwïmºîkªÆ;;ê<›Ì¢6é§bó‰¡Z–ØQ']ØGs4!†Ø·µ9§ h¢61_^ â”@üÄmõ­ôDF¸´NíUƘ±ò7|ä÷ö÷ZôMÙyÍQï‘sŽãø >þsùu¹!HÆB#Õ1F;­K˽=¸€$ -ð¦}¥Ów/Ï–˜?¥ƒ­%Èc¾ $5±‘ˆ¾ŸVq‰¼J–ã:¹¥öwÉ-µåª¥”nñŸZâ¬ËÓvQc6Ë€YKçœ#?‹ckÄí“<áÇ!1:êèSå.‡ý&«GçÞ{úy~¬’X¹L~ÙtHtŒÃ2¥Æ"ÑaAÃVÒ¡«*”AG×|£‡tb¿‰.{“±ŽùL‘+Ë·7ŸË8¬—µ¥fO8Tyßí»õëªo¢Á‹l~FÈæIØæÚ4Un¾Ô/‰§œŽ…Düˉ>ð‘‹»iÚïxß×ÜVã¶—8%k°LÜKÂZZ¾‘»Ü@‚ÏÛÀÒ íDž“@ìjªæ+æÈr§x ˆ¾|¬AbS‰ù z4,F/4þ“å5õ*÷ÒÂúW+ÅöM¶oû+›äh›o!#°ig‰Ì =ùƒ®±}ÿ-âBON\¾ð97çžÛ3Þª»ÃGq{¾öÕŠæ$òÐB÷¡ý?÷µ©ÍÑl2ë£ÅóºVxäÞÉùzO†ì$˜pm¢OÅ•™Ù­’qfPg¹ÔD“DúâÊPÒž2è—2£º¸­2Úƒ)`jÈ¡'Ž òI `¾À¿Ën‡¸×s¤›¤ì±÷QrÍÿG46‹K"ѱóqc¤².3:€ÆEñ±$Ýz1„)úJ›&R±×ex;ÚFô´É`Ù•·XLO±|D`ƒ:?¼MŠF:è/^4ÍM}ô—1´ÌöKBþ¶2´¹7¯جV6ñ]žÝŠ¢u«V¸·ÈÓýú9ã¿¶}Þp‚ëjg+EŸûö”Ïžõ‡‚Ø6 î3úáV8îéÙàî¹í"‡:.:½'’ÔD)â ‚ “p\0¡F}rd‰DŸ¨a¢ü‘µç"6Žè u•ÑDrå¦eÿòˆ×|‰NèW6Xÿ]§ý«9r,´--8Ûÿƒÿ–<Ú¢“± '-é§ÇH‡)=6IàiyzÌTÇ1H @N¿6ʯ€X–ý|î„LãOúhqiH¤rðSÁÈõÑLù³Ï+ÆD®_¿Bnõ{¡<ø´þ ˱ym<k‰³&âl›8C äjŠjÖŸÒÛç>ÑIƸ¯·Wí{cÝü˜Év{ìãpæÁåîÕ•m¾Z0禠û?qŠÍ”í|Ųùr€ÿp¯}Ó?c¶Ä(lF‚Ôd*(è«ei&"- Óvj“–)w䞘ô)“·(ÔÀi1S›/í8rznÚÁ"i‚”¼Öö"7Vn¹{éesªñ@-Eýh;~‡Ï¼ÎRç ùŽ)ð"èÃùcä 8´½ƒ¤/ûúD.»È¸l°’~…÷†Pÿ:fõåñ¹jŒ[xŒ78Ųʟù ±ZL~ y:À£Äã-–Kc K ða .«Eìuüî»ýR·fõb—]Ë®5·/{AÚüÀf±`ÚO¿3^’ÿO%lÎc‡_9ï¡{:éoØÈQnÏâïö·´»»ûƒGœqFíg ×sÓ~TšÛŠ žž}›÷Ô)Wš"Qö›â'pC°ÉÏr@ÍIÝA™Pª²´³À‰cYÌ ú!±ògãPŒ’%1DXQ‘5b§'¶>œ¨ŸëO Œñ1Nï'»ê—Å”ÕÙ=èËî¹{ÄäyЄª€(Ò'x(ØCM{z–¶ö“8ªå »(Õx‚Èä9² ƒóLPà'êRžØ2™ Ô1ô)è1¾<9ýîù÷Y·ì÷$ÁÞ×vy•Àf±PéÝðŸ2î;9ö‹åþþÏMÓçÏ÷Ç»·ìú2\®U.°È†Â'úÂ×H¹9Pá– éýó%EõÀßw+–=’ƒ¹áDM”aò€ôDJqj¦ÅD,ÒHOÌ&ÒCüDò0‰G2ÚûÉžÓyFg¾–0™÷Í=eÄ‚ Ë‹(ÚÖg[qÁÆëˆG›+¸»¥·™ò#ÑåÉòñˆK4fϦúÓ°Áéõ¨¼žøÐÖØÃ224µãòNê¸hŒhܱÎ|Óa¤$ƒ0^Z3À$M1DAÓDf\€ e& O‚ÄI3ãÝ—?é¹ÿòSnk…ПX®‹6ûæ:›|`úeT’廋 ÷ê®›¢ÄYÿÛì¸KCØ€.ßÂû×ZT\C‰=¥—nytð7çzº×'¾2“e¢ÐV<©C‚É8e’™ ³¸gIÙd9É Ò̼N\†_±H&§cѸTf>P›\c©ñN£9m؃ÿ¬Î'~“£õS[ô´'¥rfúñÊìQŒ]Šàr¯CÓ¡‘èâ¶âˆ LQ™êÌ ¡¶"ŒõŒÀ )]D2[–,gÌ•CC_©pC$Èóà ½£*·ø]ãîºù‡ûc´ à@ÄÉòjÉI¾-Xž¶‹ŽÀ&]˜ù³KvJ¡»žÂqÿ ýo¨•kýw?µÅùEÍ© ©|¥8ÆÍŽé%¢ß¶"ªe/ÏuÝ{]Å“$U“r6 xÎÃguòO“d}`VÍè"# TQ hŸÕ±·Ä”à`CBµ¥oø3ŸlWcœ·ƒs†£¶IÒ‡·Â©Tfá¼ ƒÆdT’çÕI¥66^ñ&–Ît †_:ðB ÇQ¡†‘•EñÛ#F°K•Œ€¾#@F­±y=c¾ûnÿ¶[¹â¹ÈªÔæyÂ~©Úä›õlÒ€¾½ØÏ5¾Èjô¸?|îvØëV ,Ý}®÷CS>yfK«[`Ü¥z¿àV¡¥—ÙÓÿàæÏÉì͉&^NªÑÌŠI7ê†dcVáS`ÂÅ>r †I’ñ,¢ÎNî"¨’F¹²|àÑ8«}yãódBÆBso¯ŽSréàŸ2±ê)S߉àÒ‡ty½/Qb…!Yiˆí?¶j«œ FÜÔÁ·_f‹©ªö.laìmŒßl 3™ÕDÃÆû5¬Ê5– óöt„ g"Ê ªºiÆœXcYâÇ yŒŸ3ë:7ÿé[cx™mí*ÓA›{óM¶0óŠK>$ßþw9D9î?nÒŽnâÞxBYqEÎ þúg|µegîù€™°ë· Å-CK/÷Ýñ=‡»rÒfÔìd©S<¹BIdJZ凶?ôd‰œ3nßí­M5JÇ#²˜/ÝöËS…M'l,yÓBúЫ m}¥ç÷ k|àQÎjŸŠ…ZÇ} z´KÉ«1ĘŽ%ð…feê3‚i2¢¿\Ž´PMªýÉ—‘.èWLÈÄÑpPýXN=%ªS% Õ.Ò«äþ…óò^¦—ÚJ°ÚyüŠJxYL$cIËÓ˜ÄZˆ4`IJ¾L±ê@±dN›‚‘±[-.ÓçÖÙx2 XM÷‘ ^œïrû]u VÞñœU-ðÕv±™À&Y¾aý·e\&56¸vwöí]§äÆLØ®(÷àY+×/¬rꩯ¶›hü\–ý/€²ËâE3ÝÃ÷âJÑœDuO´Y|¤Ëš¡OÌÖO™0o$Ù„ø¤«”bÛ§Õ 2hk ’5x4ˆØDd ‚±šþb~´5­m‹ßˆ¨—dOÞ¼¹$Kà°‚@né@äÛ±/ÂUàõª+*AžŒ„¾@Ïy*S%œAbqDi*½Æ cMC(ˈR2õæˆñÙØÄ8Vc)Óý¸ëÛÞ…;`ÎKáJì`7Cæ˜Z‰ÞÚÔ›õ´|`Úe—œ(ßûO9*/LÜ-ñ…†(qÍÿ®‡½¶!làŠû·ý?û/O6Œeß)‹³¨‹4íÑ«Ü3óîL»ÊN¸© 6î dMÓ‚¬>ÖËÒÖy ¦:y Šq %%O¤Á…ÄÅvbU«¥I™ÆU¾¨ó‰_˜ù×!Ï PïË|F51ÏÀ$8³¡§¢êS:` ¥’(¨“’Ñ' ´Òœª«%ƒ—¨ zö2ø‰ lÆ1Ƙ"ƒ*æ‹Û0ÉP\³Ì}òf7[®ùoQÁ…ç{´K{8-]˜{e׈ŽJßÅsŸÄÀ>™ÕK—¸yÝÛ°Ñn‡¿®ØÛýV*wMy~Ýwà•Ä^7Ê«{?úäÒÀ‹å|€…ÅìDOÄõtjÌ÷è-ùJƉÍ%Z?ÁGè7ˆQuT¦J¦Ù¥ÊÆÀš/ƈàLî‰4v*Ÿ’“€à ˉ¸üËdqt~ëßV‚<åƒ!‘bð0©}“}{£ :(8̵ñÖ’o¬§“H ^Aä:F­¬Ï^3 «¹€ñ¬Zñ‚< ;C[Rp=-ÎÛi—ö„hé Àúõ#p»É½ƒ÷&¸¿?Žû÷6x¯ì­&lï¶Ûsß&½¦Ì7vôö}¡ÒÕÕ›’¾ú:³e‘ÿ_+{Ãú•r¼ô¹³jfÈ“ùµ:ŒŒ®zr®61Ij’aÖ6›Tåb›ìc¾š²(N6É•ñ( Ø'ú$R® Æ`~X;Ä'/Û @.9QPj>K€8p&/}Æ|BÈAð1$²”/[ؼšþ|̤pF….@"TLk²¥1k* \ÄeOøX"}J .V¢ém $ÒŽ×ùßz}—Û°¡eý ¸ÇÃ~Ú¥=aZ¶0í² ÷—Û|ÿkð\@ã™ÇlèV¿t%?Æ=äIU?Ò&â·ïgÏjìvƒMøÙBLÿ]â¼µ±¾øüãîÑû¯ ®²Ÿ)•×Vé²É&𤫱YppÉF>­ŽsƒE“B¨ëÄã–n–DÀÆË"Ê”„6ÚôØH®yr}…>é/iUî$%Hΰ~äS›Æ¯Ë¨þÕ$©å$oFŒç–f();‘ÂWµL}&F¡¥ «I3h³Î@«|Åà,OÖÖ°ÝûyÒßLë–]ÿ8ø}ÙNÚü[Þ´l ££ã{2<Ê¢UK^rÏ>þpÃtãwÚÕmµÝĆñ §õŒ_÷Íp¯&î*ör+ø±éž{椇t©5ãUGWGEþª{• b½¶“ÈÐÏòWá¸2Ó†é/ñäýš!ÔnuÂÕü 9Œ…Š•Çq/€´¹k_‡ÇöXM3ØÐVJ%vJF“e Í@ r6ì :ü©Z¥ÒA7;F)LFotq]…'k‚Èêã bßj(’¨['ñæ[~fînê#¸ŸVKÊ|ñò¡–xj;ÙâF %+3/»øÝòô+$‡B vùϾã&yLff7p öŠœä´Ûá…Þñ|þ€S»6Ôpùjã¾ÇÊ«±¦‰QÂ!€Û®?_ž–¶$°d'âhŽŽçvâ«'ø@“J<Æ<Þ8€5U…n•ŸD£­¬ßª˜EõLVJ™7ÎrÂeÞ.ÕÈ›r(7ø LjQêDh‡²¶ÀÃÖ¶è ¨PF|$D3WÊØ^zQWÛ‰€q$]r¦¼Ä:¸Lq§áÈ8ö‰Ù¬ËùX³ê%9å±ÁÕx¥—â¡}Ü¿ôaÞr”¾€ÿdס·û}æ‘ÜšeohNÚw7jëmŠü”~¾ÿgϺ½HÂW×TY–¯¶byÖ®]ên¹®«ú|8¯?[gÂK²BvÒÏò¤h3åK)Bwµè™@’.ùØŒ˜Ü ÉÊHqµOQòŸ 5{PÀ'ñhs/€öé‡ßçžø5ŃÄx¨C_AÊË¥Ð7âð&%Ž1ø‡/*Kúg»ž+±±–Õ‰AÒR]쟒,À(rêØ–Ëcêñˆ+­·\w®[·vYlUfûSBþ\™ÚÜ[ö”¾°nãHœ¶{QôúåÅ6L×9t¨ÛåÐ#Æ7\â6ö~¥Ü«‚MœÆ/Íhb¤^xö÷è¿ÔÄSƒ§j¢Žp™<i¨RÝ~|d°‘­ò$‚8‰Ð*Q)‰ÄKª±‡Xor“±Îìr3r{0ÞBàËúVgä—jÀq¢/èÄ..ÊIVQ}´1_Üc¶dõq?nÃ.í¹¾Ÿ¬mì7³±Šc ¹ÿçnásÏ]±í Ú׈Í/a×6y@©+xجö¶5hgýW^çÛéÀ×z¿ÙqwÎ~ÿÕd¿s߯rÕñ²ü+Z1ßû3™X“s12)7_&cÄI!n+_\ÇIÖ6kYµ,"ˆeÚNËÝ4A³áÛ„·“5üÑ'tѹàå‹[ÿà§k50Õ óÇZ夷 ¦(¢’î‰"(4dÇ/¢a3E˜),¥ÌZ®_+žçžyÐ=rßÏG:p+\'[èVBÛbKRWäNñçÊ Œ)j ^œ=í\Üø=gð Ÿ8¤(÷àyâÅÖáFíÒÿྦ8ï£ôƒ8'ä¦kÏÉßµšô£¸kMÖ€ÔÕEÙfÖ.îÇmõ‘¶Žõ ;JPÐe%ÆSV+ÒÀ^È‚ÚøP[⧈ÌñâÁÛÐG än‹5}Åx/‹1â2Uò–#ˆ:ð—¬mJ—u)34‘†‹žê§:Ùb¥è°Ëÿ¶ës.]qŵq?Ž–œ‡S\Èm¦M5¥­Ìúñ%Gõ¹¾Oµ`¸×ÿÜï¶þ;‡ Mp¯ÜÄè“ÇwuáD·vilð¨Ñóƒ6‡Z½j‘»ùºóëLïõ'ñºI£î?ظ3é&êVÅéà-«Gx±Œé›Â$6í¨XRŠÐä°áà¡Â %xŶôG“H…/DA¡x¬a ŠôÊÀ)¥Udfl‘a¦Y €:ªLìÁ„ôr¥ué^Ÿ÷?ß­–“ÿZT¾$~p_Žvi@¿#PÚ @oG/.‘‹~²ýÆR0÷»\ÏFœÔÚX2|„›´ï@Éätõ¾Ÿ9û mHzº¤Û’Ÿ æÞã{ðWiïE÷êdŒ:ª8ÏUET•ø"DVWí#ù‰YRŽÌÕoƈ"ƒ˜ü¨¹ÀŸé/ÀðEÄ’ 2è• vG •)iº“Mžà²B~ëHë"1›YžXŸå‰uý¦ éN½hdŒz\¾ æÝ“(ËmÝ&ô¸×»´G ¡(e`úýüt±ªòò‚ynñ¼9âÚqÿƒ‹¼åïúŽžÞÂÎeЂ¼2Ào”ÅhÉ-Ïî»ãGîÅçŸà¨ÕKk<™gm²É9Ö×ó]?9Õñ˜1Ìtc÷Ìœq|!ÑgÄb…Wz†>zeÀÈÁDÓgEd—?Û ÕM:¨CR§Ž™.[>%—©†ªaqžo|ï»w>oIY*^Nj‰§¶“W̾Ð×Õ%{Ê+ç5B½==îéûîÝaÃÝûzìÿGû|þì§D=úyµà|€nwÃ5ÿêÖ¯küüüÉ;¾¡v]’$YVqÕSÕÕÕVf“dUh"€ ‰;U¼<{ €¬âÍʼ½qfùá³VÉrǸzºWݮ㰜+¬o<Âú¦k»ä6å-9bˆûnœ ¯–8˨¶p‹!EG=s‡á•i¾°}ïÏ>ñ°[·jå€ÂÜñÀC‹Üú_¼nØðó@œ7·Šð{òÂe¡¥–U+º[¯¿Ðò\èK½ìc˜~ê(ª’hì²^ºª«‹Ë&]fúÈIŠG:Hp”¡F= ¤’x°È=¯åÆW¾­r‘xT€EÝDQ_߸£V^©K)ÊfyT¹²z¾s ò„u‚Ä÷oÅò–]‚ß%áµä0[Þ0l Ù击¡/lœ¸|ïÆtV:‡Ê÷(œlÞÙ'‹+•UCú:7v÷m\Ú5í%l€´Kκ0íª®an©ëÊñ3(Nü{î‰Gd‹cÿ;ìwð€lêeŽºà5ŸøËêaÚº†G'("¯) [ øôì[äv«¿qöþA2 Þ ‰´éRI:Šxk6»¢w–ü Ç$où€(ëfº)GàI­ d´5×ê$ÔEN!‰½#ªéýÞÍ™}s#Ð"0 Ia{\‹¨Ž‹Úe›·ñ ÞJï>rfÊòÝÛS¾V{ ÷öòÚfÑFIüpÄßZoj=·Wîü ]_¥WêNwþÁ“pò‘,ø<©çȺíÓ®·cNOïÆ©nÚKOwµàî¥âw³+…®T^ùÙlص¨¥|æÑû]OÏÀöjáÄ?Üü§ 2·sÝ¨Ë âjÓèàžÌÏËkdÙrçÍßsw<Èm?±ñõ K~eÇÖ þÁ®CÄco¡×ËÏõ“~+–¶8õVnúó²xѓ[öˆ_ì}S1mîz$ûÞÎ G÷ôVŽ®ôõ!ÙüÀn·aÄ­+ª²ÊD?è%ABÀŠÃö¤ƒÅŠ-V:eUáàIkÎwnº“•†»+=÷|}ê 3Å%P¯èÒܰFCƒ­ÿŽ¥Ãåò“Ê®‘xÐMÜñïÑ?]]saq¥£Ãñþ¸á£Fç©,ë«T>ºÿgÎüå€ ÛýöüY^…}ÿj9·ÍÎî´ýÒ 9&µ‹IN_„oƒÃÚU:‰ÇÆA‚  ‡ŽµUM­ë³êÓ|iœô@¥gß“$â783¿JWÍSí ÄôàÏîÚ”ú†Ÿ_¡0ùˈ­ylü£Ÿ’õêv¾É¹ƒ€˜K[Á_ŠG„½ÐÁþÈèô¹^§tèÄþâ¶h”æÊƒ›†¥ù€‰ø6þ˜Óâ QìËøP‹Að¡r8Ù°a­»ú¿>æ^^2—ú’ß’ÿ%û)œ¾k·ÝFtŽÛ𦾾žSäx²8Ø_^ú¥+ÜÛ  _îs•;ä§ð—JOåÚ¯O}~Á ™6cÃÂöt.ñ9ùFîZȲÊé©{n ?´F9·ÛcŸÂ’¿øœ¹ßÖ»ã1šíRüüE(ÿS^Ÿ,ž:͸|éwËõßpo}ÏEiÅ&ê!yX‚-#$7®4äWùF ñÓ.sšëÇqp°H…6u|KH3ÝD!­`Ÿ’ZÇs[wu=߃ +Ìäö¿~«UÉ1W^[LòÇVþF·áÝò}{¯ÜéDù’Œªõ=-ìiŽh¼üð»w÷uôá0Â}•¾?¸î¾ßüÛ´EÉmG›ó±É­ Y˜öî1ò£üZQKƒKþV¾ôâ€épé_QE¶þ/¬œz*îªÕ.åŒÀ§„öxyíQ}ÂúäŒÝ®»¿Þíè»á ZH<~ã¸Úº®²ž'Aj¬µTW'¾k®TdâÊòpkVª"8¬:Hƒ[Ç̱ •êâO{(}!Þ:¨#],¦ª œ ê˜% ~[µYw¿öý"úYÓþâf<þÇ~ SϦ/ÆVÑöÚkø²‘+ß'_ÎË.ýåÛUØãàK ¹íA²r|ë¬|ýüƒ'?)ýÕ½=ÝWÊ †OÕ3ÚÜu…¬T† ÿ´,èvE,l_O¯›ÿð}¦»ý$7zü„ÛÕ0˜·¦oë_×еÅÅÎÀ®µÒ'†Ûn¼ÔMÚé@·í„=«¢Gª•Ø1Ç×JÊUD5uXê©êÅ%A×JúÜÒg2×€˜g±uoK"Köa‹?^ ˆ—ƒØXàÛyr:J°ñФu¤‘_ IÖùÔ”f㌡ø^ºd¾ìeº86+³½VÈ.ÓA³ÜçøAØ(8)—šZô3…¾2òxY5†´Q¬‡Sõl˜4c0U¦ÎêR<eš5M”º•Ë_p7^s®€êY¥9šèáØ2ΗÙ,ÊyO|íù‡L¾KN)ù³tÄfÔæÄV2>ÿÚÙ»îéó™ôå®(ý<§Á AS+}•¯ ÆižÍsÓw=Öç©êʶÙi77lÄȺ˜F•29\¾ó—¾4ð]:hãêÀ3¢,ý²@€ãµþ¿3]·¿­WR“~fžO%¨*’48Å#ØØ6nƒ&m ,d‘TY>"€‹°aßÛSåmÉçñÀ€]±êõø¸&ß_£‡ÄœÆT“hRÁÊŠpTÉ3€ÖÞ— ãe‚Œ>MÉ~ì#RäéjCuùÓæ¡—÷÷¿VÎ'Èó&Ùà³_58_5­ºš¸‡çþ“ìõ½Wl³>±æB´^ÛKΘsÞÁ“>*_ÁJëC¨íqÐ+3®¸øhùr¼gãÚµî¹éƒ»´râ^zc§Ú‹Ø°F²AïF·eŒÀ/„´%Ç8qÜöΛ¾?°„Â4-v”P¢&ÙD•Mu)½kŠõÜH‚)€È‰dÖ¶:ŠJqž“úÐOÄð>Ï‹¶4s_á|®£ÆûfÛs¢M^G%Èâå1εÑd¼YÜMëÓNÓ:]ÎØ6ng±Yݽ·_î>75—ÙnÙ92µâª¸Î žüO•Êã‚ÁC½Úeà#°“dþÿ’C&×â*‰›—c1è9ý±°­ÿ²ë¿WNh6r”¿ó®5ËÇWܯ÷?ãk/ä+ÛÒŽÀ{Ä×ÂVø{ô_¹§fÞ,®ê$‹(I!¦L—É0ÄšQfIF]åaÄ6Œ*cd²X¬mMÊfÏ|ø ´u!(ò2è¨ÇV¿(R/Ÿôƒ½4è8]r‘¨=dhWµaÅ‹U–ð¿aà?Í¥ü±ÞÚ¨&•¦mÓ.›Ârߟyú^÷À]WæêJb>jýÃ,¢9ïÐIGΚ5éaaÜx¨˜[¬Fü¯Âæ[e'À,9,p1î“°©—P+Ó~zÑ^ò£zgÁ㤿…³§ Š wþ«ÈƒŠ(•ÞÊ¿ÁÓæhzz…»[r>À êrË—=§I­FèÙRŽÕÉ)¬²É'8¢LDŒO²qˆÆ…ZáQ  ”XQkÛó{»ÔqÊO^µ'Úaø#—¼óvQ’`‚ŒøXN0„b11>2ÚjAíF[úà«V.v×ýáëâ_ÑÒ ¾ÿØÃÚgÙ¥áVÿ!Ï’ÛåËe}îାÝoj†ÊýÌå#WÝÑuÀv{5ÅÔ¤ñ ²gGOåóâ·³Iß4~æ®·{psýĽ‹9ùO¦€;§|öÌ‹Xž6G!#0WXþ¾¦~HÖ¯[)çœ%Ú¨I²>› ¢´A‹¬žY1âÊä–êä(„L )/‰Œá‡¾QÃ&ÒÁ4–Qç…•õÑŽÏê‡ïÃO>ãHמØ*xÛk€¨h/oŒþØò6*§zQ³´‰ˆŒÏ_•èÐʪ³¬±>Ë”å–ûÖË}$¾êÖ¬~9í¤¼¾ÿsË£¯Í|á!;î3kæ¤{ä"¯‹µYž¼V;ú-HSqGÊÍ„žCÿ(ß¿MrnÀ€W|ç;8ãîcE 3ÿ™ƒÛú³ívnÔÖã‹ÃÉ­ž//„¨MRäà3ùk‘„µ¸p<÷î[ªOÿ¨J:™,Q•$2`Ò˜ê$†T'"&Dd\Ci§:MbU>óËd°ÃƒJú¶"@1w÷Óç‹ žI>ºBÀsЧ²*?ä –Z›Õ±Pîq¯o°f|AZÄaè35MÛÁ*òÁv̺¬>qQÕô»ÿË-˜÷@•®$¾÷›dN’cýïëéë¹_ÒÑ‘%-[›6=#$÷ï‚C&þòÒƒ'¶üË€WVYºÄ_Hæ}aöôA]÷ñ›°ûÞéa|oqÏøuW Þ¼mYâœ"ÜKJäÔ˜àç̾ý8yxAÀ!!E¹ƒÉ‰IÊ¢LéMÕUü¢Ë&)ÂÉåÙ3¤ÌgÞ—ñ¡V˜Öi92'þ±õ'äiŸ2Øù?¬Ä/“£Æ?+à½M,CÌõc @MÄž\ìÁÒò*‰PNT¾de‰oCd-ªy«ÝÓQ çó Í]A  bø¾ã{ßÒrùán¨$¡Ëå“ý8×RçmgòŬ|h­«<|Þ!“ ¹¬¾Ñ!ð @¯«œÑ(y=\_o¯{nÚ£õ µurû¡ »UßÓ½¶A=M߯8µ«þõ`õÌÛº2GdžÞ$¯ís×ÿ¡Ë­Z±ˆËƒ‰?.éžh2úüD’X%É©™fEŸ`ãÔ¥%bòA-q ‹7öË lðŸ¬ÐÖËMŸ­Ã®~øÃÉÕo#¾á…nÌ–<‚Q¹€añ1Baü[ÛêXF;ÿàµBI—*õšDðàgíÚeMÅëÞÛË%["VMŽÂ 8™ÔÙq¤Ã"(?|iLZ›œBÿ–N”*ÌKÀ¶\¨³zêSs0à™xчv„R3,K$d³–,*oÆ.C” bÜu¿ÿ7·rÅ Aiݳ…ypÇDRס“vëîÝ ·Æ¬ì7HŠ˜U܈aCÜÈaC݈¡CÜ0ùm‘¯o‡|wåÒDW‘I\NF‘ÝNàwH¢ê–CW="ïñÆž>·^4·Q^ëä…½\›iÙF湋à?þë «Kô€V*®·˜5Düg§>2èE™°{Q[ÿî‘>wöàô´ 8¸é½òzÃí vþCî¹Îû˜ãqž«ÌH V¦R‰RôÕIšƒ'±Œ¹‚ R¬€µ:ÖGõB-¶‚§÷44Èͧ&1ø¯HeE:”d%AE¶‚}¢‘SBbŒtq(ÓvŒ zÆ8$þÇv a¬'.!W[ÎĬZæýEŤ>žXµyà×îéÙ·G’R›÷ û7Kõ!Ç%~r–ÿE<)£Ú¤Ý‘#†»±£G»±cF¹1#‡Kâ&çiáKƒ$ßãðÄXÖ’ð呼Lü}="‡.^ Я;¿Ólò{‡¯_ŸÛ këd¥`Mw[³¡Û­§ÇoÒ…Wç2üÇyOÞgʾ/|éÔ«]i»Ÿ^˜öî1Žÿ7]–¿ø‚[ýòâAól[Ѓd"ýÅ ƒh¶zN‡/Ê«ô{kßsÛnÇ]^ãvÛóõL–\P$$`¿Ô˜,dÛšIÙ‹0³pr‰*%’|ã¤o2Ô1V' ¦w]¡ð[ù1Æ|a³½A¡ò2™úˆmo€ÚëLgvŠ3æþkÃk¼À‹_¥d’¥Ä XÉÔ´ócT-W l­O\Äo:ói±˜<±1 ‘x œYo”©3â½0ÓÝz}é;,¦Ò8Þ:­¨Ï?hâIr`í÷â«å'že—¯sH§ÛvëmܶãÇI½µ6dˆ|î’%©KFORýÕê'N¹H† é= Îm%o}#‡·JNJ_½¡Ç­ÜØÍ=Ù8[Ý—ù勳fOš|ùá ?tÆCnà7Êi à†W:†Ž8]~5càìòÂŒÇûÅÔŒÞf[7r\!9 §§£ûWµü´å›Ýà<“åuŸ¼|îÊ@–“ÏŸûU÷ñÏ]íÆlµ]Ê †ŠÎ$šWrdÙ-uÚÉZ€&¬ô A"C±&psŒÜ•·@„a%ÀÖ0̯q(7˜ŒW'Eô5&ó"’ôZJP$*Jò¤fUôc Úƒ¶˜QþTÉ«1Tú€7þwÐ{ÎÈ(öéaª ©¸$Xõ³~Ý*÷Ç«¿"—†¶äÔ „ðfy÷œj,Srþ!ß!YójÈ蛦tÈ3\&n¿½›4i¢›0~<¿¾HÜÜ‚·-}ü^¸E/ ßMÙJ“?¿Òþ;‹ Aèò¨šá#×߬}O´¯ß:ÅÀjÌÐN¾¶ïæÖÉ‚•rsº•ë{Ý¿WA™[üÞç>°¨{âЮ&œÖ5mZá_ÈÆ'Ò^÷wE,ú†µkÜ’óM5~×Ým›6ì»ó O [”í²åŒÀƒê¹­wͪ%rÝ·Þô%7éH:ÉäHáREW5ÀlbKA>ú‡R Òí ú€\ñ*ò¶QA ô•õÊ1Ó¼ðÉ Æ‰ðºŒðúlÐH›  UÐ%rÁ{;ð6jÁ¬…Ü"Cû…6åÛãYå`͇Áb®þt®[öò3¦*»>_`¥¶%傃&}@’ÿoÅÙ&Iþ[ë8è@wâÉ'¹C?ÌMš<ÙuÊ.þJç×![þr|çß ÏW‡ïgkÃÈŠñ¢¶ÉŠVyQü:Bh'òpèI{„ì!˜ ‡vÛz„Ûi«á²§@â1C2µð­¯òžŽŽ%¿-ãβ¤ÿ2㊠÷‘Ṥdÿœù¿ü…çúÖ@ì~øëÝðÑ8Ñ\é«t\úÃ?ýõæXÚÖ›`nŸ¸ åeû^öò7dÈp·Ó®‡%ŠŸt‚ñSFFƸD¦ó…ÔÔûžÇrºy22èPÈŒïcR ”Ö& ÁÐÐëY dH–xl ë·¨Ââ„ IH¾ÚaÚ$`Ÿ´á®©Kµe•Nô>|‰±&C­üžÓðçc1Y™úèݽ·ÿĺe×OˆƒÓÊvbü<ñt9ŒõÿI¿á=¿fÛL»µî´Ë.îÃpSößßm-[üHð¸‹+¾xø.ó (íÿE´>ºÄø¬M½|p©˜èÃŒÛpcßw¶ò¤LPWÜP‰iŒ*;|ˆÜý®ÂÃñކĺ¼–,æ>†m|í›FN¸úÖeË »J¤¡=}}…|I±kõÅ'g z”† îÆLHï’$YOO¥ûÿiÛ6Ûô#ð& ae+¸óæÿpÏ=óˆ&”Øa6‘@g²x‚˜&ÌŒŠ Ég 8™yÄI=ý€K^¡­‰Žà½.¥7¹÷¥¦žGdº%Ûê—íÐøÔ&¶7[3†_` +ØP¨"s’~ y£¾V.“›yÐ 7\…ÿY™(ód‹Íqýó7‚iɵÂ_úI­¶ ç4é9`ôsé7´ÑgvÍÖ“vØÑûæ·¸Ã>Úßn;nÕwø­}l¹ëV¿ßÚÇV=¶ä¹'@÷`«>y%2<^÷D5dØSÀ½hkzã:„_$xKø*·ž_—°qÐøÆÉÂÛŒêv7œµx0tKjùΞÜ9nÝ/p›æ¢6´&(Gbþ¶‡/?;ß­ä¥ð?nò²Â×Ð:KáÞÕÞýßßmÖú5Ž›Þ-¯R…¸þûW}Å}üó¿q£Fo#Î$ÁÈD`N‘ËL†,§[2š`°ubÇ䥙*H@°LNÎSÛ\9às^¶¥;p¨3ÁJÐzKaȰ°ø‡BÐ Ø <„> Ë8(ƒ-;Ä©º¤$Xo—‰yj|¼ižì–ë/u‹=•—Ûú±ÐßT® eÇÃf$Éâlÿ‘­ð7f«±îu'œäNxû»Ü„É;ÊÖ»Ûç1~;®Ú²¥orlõsË]®Ð-x©‰ûQÛŽùg·ú;£½A—¤9®OØZ’½ Šo‡¾—‡~޾SdÛÊÆ w£†&>Œ²¬Z¾æÿÆA“eBj¾ôuoÅÚ¼Ç-ÿ¥Ï=ÛÕÖ“wjÊ>wt´ä™óÁ_»QÖàASË"yçÈõàÞóßš 2‰†]ycbËê@OF–Übna²ÒvN"Ô\ˆÔ b)"·Þ¾7éÓeÀ<°/ ˆÀø~ÿ‘ØÇì¹â„ñä%~•ÑIˆÓü™oí#‘àœPBâûìÕ‘C pÒIñ%ädÆ[ª?ã‰kÝ#÷ÿoJ^bgŽp¡Dþ@ý·Ÿ8¤³óFl„%5pVÿÁG½ÎrÚénç½öfrgR÷IŸmìÚ÷/îþ·¿ëŸ+X)@ò÷/îÎ÷2¶Ó+é]þ^ÇÄ/+Æ!{±•’¹ŒzÙ~&{¯÷ :£*þ¶5ÌM”´¢ÈÁóÏ;hògšõUw@~Xš6ëö8öÏÝ=ƒ$Ãÿ ºüïÉ)ŸþÊÜA†Ñ6ÛüFà ©%ûmo¹áÛr_øÇ8õ’ š¾1!1ç E…‰Jú¨UÕ@â£Ó$‘Ñœ Oœ•ÉXb¡?ÀüYûè«|þeyµaèNùt/€*à™$óñDXÆçûæxþÓŸ(Á@SH¯!¹ÚÐÀ¿¥x•(¨ã1ƒ¯åKŸs7üé‚ /¹±^ø.Ù黎sCú::~%‹¸[Ùþ¶’˲O|ïÜ~Gå:ä<-ÝêGGÂÇ1üdK_·îm¯€Oò‘¾úx?öÔHúX!@²ÏÛêQJâ7½¦:$´8Gë?B¢¤>3`±øFèGb¬ Œ”½“eoÀh¹œ°E~ÿ‚C&ÕŒ¯º+Ó¯¸ä{4ãÀl_šû¤5U´ã ì²FrìkÄíòÊGÅñTÍ%.î:ö§ßœåÖ­•[X#9E¾LL’m A5“Bž8šYë_žâötX“½|_eÞ7üÒ7 —ÿh… ØG¶–{¼­²ùÝÿÊEªf,èÛp«ôO ÖCLæÖ\î*¹Çëul€@Šš{{:S¹½wwoàq<ºESú°‰’v¼<ùÛ²üÇ—ìÆí¶ï~î­§ØM“ý¸uï“y²k¨ß +ØÊ÷ èžœø%yrDý°»ß¾éÜ}Û¶úm/?Ûº +Qê–fj«^*Õ÷zZx3è}S×h“a˜0r¨› {:â54¬¨ÞùêÿæÂ×Lô™ñuWäc)dëÕâ—ÜÚåËšZè­Š9û_b¨ÜÐT mãÍqp<õ­ —^÷‡s‚+&&™i‘‚˜°4k=óŽOP@­É,n7šð€óöÞ'ù-‰Ã«è#lᛌ8шõ]ô¶àË{AÿÙn~PŸf ,nžB›ôùà0~rÂÌ“Lkß„2·[¤V~ã Æž_*8 ¿;núw÷‚< ºEÇp,¾ôrÁÁ“>&§Ó}±LG¸{ßkO~«;ú”wº¡#Gqk_Ù#Áå+>ÆoÇó¹7À'iÝÚ×½•Z»þ¹…%y¬ÔÙê§.lõKÂfÛ¯8ˆ_$ñÈÑ–NèûvèÃ@Jèûª°:dÒðíQrI£‡ÉÝë¦Xr7ù¶³œ§ü¿]²Çg0—`¾{¦|òÌ–íïXlmt#ðáÀqÖÒËM×^â^”ûŇ‚Äã“(,ùʼn)àk4úKŒš}bÓìÇôšm‘W­Hb·É •¾Æ‚Æ^ŒOÝ$I?²õ!×踀n¢Øµ—a8L‡6Àù:ÈUý¨VáÝcˆ0¿¤ís«V.âSþè ”ÖkÄøHëÒñw^¿ÓH¹6NÖLË»Ëߤ]vuoûا¸ËŸ[õ27sK?®‘üÑ÷ +ì#ñ[¢Oêêãþ¢ãV¾%ôÏ&/gb÷6r)!·ú-Ùû|mÙ#€‚¤'öì^àf°ÚÄVùU†H¬8±ò Ü;`k¹‰P™EöøœÅç; ÐIÍ9~qʹrá+^\èpûßfʘñÂ× |·7cß¶ÝìGÇWOkE”ÝÝëÝïýe·Aî'!$ä£ZÉ*&.Ÿ”²‰NÕž#7 ¦uv‚ÐäŒ|h?NøŒ ‰Ñ¯ h"ͬ¨©Q„<äbbUŽÀ™Ø=÷ ýƒÒ| ”P닯W-½ %àv¾ ˜HB ¼)Œ2EÍeä~ò¼ê_ÜšÕK3ˆÒºŸæù¥±GÄ«WwŸ+‰ n¥”]åxÿ‰§~˜wbåV½$uÝê×]þl‡ä•‘Û–¾$p¶ÃŠ€·Mmý[¢Ö'tÖÒ¶:$tÙ_·m+ZsÏ hl/rw\R}ßIÉ<˜«º¸“àøáC¥•QÆNškcíæg]‡î¶õ@hj®H ïQ-좧gÕR5,ßj»I cëe‚µãíòÊ?Èâýw+qé’ùîÆk.BÖa2Êú¬› `ãÓWh+‹&L´c\µ.Ö‡dÈx@HsMŠ"c‚Ve>Á‰¬Ôy¥°äWúôEü!ftðÏC ¶ ˆßÚ¨ HÀǦéTV­ó8ེ#Ï£F®*ƒ¨î¹ý ·`)Ñ’r­xù¯VxÂÍ~ÄÏ—ËòµÇ»cßwª2bDØíÏ=Høö’„Ÿ’!Ùc%Á¿Ø& {l/ïs+ }ÿ²6j&|«‘È­-i7¬ h‚ç?¾¬%{$ùWc/rsUz¦ÌK#eh†FŽ­|~ÿ?\%0~„Ä\Ö‡äÜ.=kÿ} ô¹+s.¿xœ¼~ DyXL(KæÏÍS HVÐíݰ¾¡-ûåhÛà¢Gà#B8¯hÒ<¾'ù½›úÈ© XZ£‰JÁš´`Ã~^bLëìÆ<È~–DµŽ¢·óaHÈ™UR÷'|[^òrY_ù‰z].|qyÑS[¹Ëïõôã9¸˜|S5V Êó{ù¼9÷¹;oþz­(/Š\RzÁCbzûz"ŽrçófØûÃÜÞý~Iôrf»%ny_²«_›$mMö8ó}]9°dŸìþ¿âBÒ~Àûäoñ'É_9Jþ–àãÓËZWä+ ñ¸ Q§³tÐOÉ|?ƒ¤%q8ØF2ø)ã2^Î àÝ!(ºT*ÆmŸ¥ÍýÂl¬¸·öW4U–¿ø‚ë^¿®)ÞfBÓB0w¯Ï}»ˆÛåÕ1¯“ÅÜЊE½þOç»%ry&Of8¦3&"¼eåÌM^N=rìDÁ -ßH'HÕ›Ëfz…›Þä &­âÀO‘+ÑJò'óò8ãCMŒ2¦ýÐzFÈÐ6NJE^©Ö›½ÚÑ+ŽþÙ[RèG•>>щ»ü¯ù¿³¥©7M,Jiõëqòj‰³å£W+y¦»µfGcßÃŽtǼó½®[÷Lê>ÉcE€gû'[øaKß'þxå@Û¶Õo{ tW’èu%‚É;µË_äLò¨µ‡%IÞ˘àu@Hò™¤ld%ÀJÔ4“zÔa3±®ï¤dÞ »‚`<†.× n;\bÎslà&jIê  È]ßz!k®//˜×Äb¨)>°‘c±C¢ÉR©´wÿ79„[˜9¶À>ÖŠ˜qÿxœнa]U‚bËK\– ô¾/ßö‰ŽêD–è!C:Tœ%I•©j;G€rÀý‹xø²?Æ`v9µá¬fÀÊg+–Ð5,ãHbÈÆjÁJ¸L¶,º¬àáBŠg]Vð„"B]‘xŽ ³†È¯ùÍÙnÕŠ–­ÿI\GgˆZ Å×ç8y?ø+¼ì¶ßîuo·« Õ-ö°õÏ­tMü¶u•k‡½XÀî¬,ø-{=\ ÉÏvñS×!/ ‰^yHØLüšè™¤/$xØX-mÛ `+A„+/&^_[R¶Á#Ä:Q—Ôƒmh„õ‚¨¦·ŽpC儯mäÄÀHyk²Yq“;zמÓKÕ @_W—¬[q@#öu1Ëž›_W߈rʱü€ÁÖÃÈšûÑ¿õè•©ûµ,ž}^zyéÅ'® @B¢ŠKUCÒ ÿ†GíûTúç1Ð[’ÔZ€R¬­v”@êy’Dp²¦òb²öd“¾ú3Ÿ'"AIbf/Äy¾^yd˜‡%¨½Ž˜òûïþ¥{úÉ;é£owˆ´À]T:ú~(¦÷ÖfãÝa÷=Ýq8[þ!ñû„nÇõ¹‹ŸÇ÷õd?½þ?½•ŸZ)@²g¢÷µßš'†‰ÉI^½îº×¾¶%‘F >¬ k{{Kð)’=²“~²Ò€~\|šND0‘^ d))mª% U¶ר0®¤«dYþAn}pÖo¶_µ0kÇÑ hÐw2kW.wkš¼ù¸Fm½Q6U˃§iŠ m¼¥ŽÀ$ð—Zü#^í>?®˜Ô,!eœ§tyI IÉN “œO~ÚFâ©é}"La’]ìÆ¥øØFW â½æ+¯Ž“=\ÕæµøuÁ3[Ä q¨½rX[—Iõ';,è¦Jþ/>?ÓÝ~ã÷AÜŠ"·ˆtom…#ø¸àà‰ï”Ñ<¾h[m³­;ö+[ïÃ4aKBƺmÉÛ nµ' ?${`eÅ œ€6“¿OüX @’·•&o/£<^€Üoå[í·öEAkŸÜ k+ªóI_ði›$ýeÖ8¤U+"M%ù¨°)™ÇG2¬´GÈ ƒJºu°<´°ã›ðW¯$#àQrâÞ›ê4ª[ZÀîø9®˜€î!½3½{EŽÃ¾Q^8.[n‘$µní d+Ms>i¡‡¦É„%4"}2„na{Œ·%ITûDfíD*Å% 8¶-|.©[“µÊ€©Þ³ç×lc|Œƒ<áÕå9£ƒ’z"ئ%` Dæmh+}÷Ç%›-(ˆ'_5wÍsƒ^~¸Úç:¾Ý ¼aØÐaÃÜI§Ä”g¯„ÍD­ ÛŽåk‚×ÝûÜÍÏ=Øås4á§w÷kò·•ˆp •ü%¡ãZî°Ä/ÙÓvï3KúÝͯíºI[þð[úŸØ!ã³§c?LªJeò–Sò¤9¬´ÌÃn%——å.ºÈò-ß8tÒÛëñVy•q9IÓåågç7Í‚‘ctYc-ŸKúô×pL¸]^#€kQ?ÝŠEg®B*È$/$(肜Mðß×fƒ@цX }•©Ž /ÂY?ÞªŠêÀ£+¶U®~ _æ/–i;æ—•˜ß¸ÄžÉmvi<8 ã}òЄ´aI"2€ Ê ©ªkÈE¹bù æ®ìú\qв㠋6Nú” ÀÞ….”$Å7½÷4·Í¤˜dmW|²µîWü–;“¹%ûh+Ÿ‰ßúRÛŠ÷„½ HðÑ ‰ßö „•ÿ \RVðŽÉÜËØ‡N²娥AR‡KO¾ÃJ€ÚÇcˆÄM¼ }'OH‡F¾,`#œ¹@•ñ$A¹ï’.Yõ‰}ÅíŠ6æÜ—“uy×g391MibBÓ'($*KjlÖÒeÙÈK*ò’é”|i‚Ä[’Ö:Ñ› ê´Î0ZW'÷´žËý+æÒ_K^â2.›ØøØš[6ï ûÿ³÷&€¶]U•è>·y}Ÿ÷’¼4/éHoè,°¡ñ[êÿR–~üýZ–U-K,Q? Ÿ‚@ý6°ùßúV‰ * J/ „„$/„„—¾y}ÿî½§Æsε×Þgß{ϽgŸ÷ÞMκ÷œ5לcÎ5×Ú묹öÚûì£ö”É‚XJæg*ƒ Ëߋמao²©‰¼Ûiõ‰c²ú®ÿ$®ßƒV0FðLÁ7mÏ“g‹uúõ3þ¸OÀnüã‚" N£Žô\ÿ¼lÊôb€Mžr Øå™½—c¸ä]ÎÐl<.®“.˵DhŒ ¿Rp…ŒGRÅŒ—Ì6ðVaÑÔþýÝ‹Çwom|²/z·Lø`µràÞG,@M._¡2€ S™Ù9°‘§JÜ‚†üô0c‘±Ó–”—-v1¼õÊø5»+× Dš­thv; Œªvóú­×pá›,Óú¼¯hW©ß»›#JulØÏùlKÞ/ò™,µG„ÚAÏÖåtW¶\æÍÏXe°<¤ô6ØýÀl7šÛ½õÿ€à¼Fá"™W=ÿ[ŠÍgŸcÁAQ‹€ˆó Í@nÁÜ®ëg7ûñ¡@<ÃÇ¢ÀõÚ\ÿWpký ì àS}YПå̽<óÅs.Q#¯{ý$#ŒÑ·Ô©w]Clu¨óÙ³2g³Cª/\Ðí¾¦I©²ÀGjà€™©©âÀ“í|ëjrÅÊ&ŸÌÃ*ò‘+žÊ=Àïiß6ÌF cF‹°0«ÀÇ2ÿ¨2™ã“Ì·A´a©D½X”—Œ¯*„aYZÔ,íd2ÚÈ_¦K¬ÙY´)Ïe´f×|²ºØB¾¨“øZä€'‰ã¼ .èT+¯ð…9µBžÉo, è¼ – áý^Ø|åìÎi²Óíþ×9 ®ÃWþ®~Á·”SgÛ< GˆÊƒ²¶ì}1à‹€Øú·-~ ævOïàB ð ÃyÙÙºÎò]Æ ] âyY‹lq %^qÙƒ:í$[è±³`¯úÙO¶èé±Ù‚ssè73=Fd¾Y£™[ZG[×L¶~)àYo¸òôžûûÒàößÙ΋헕n,Ž:ðäcúQ‘ÅiWµ&W¶°ý“ÓÝéÑ7ª];*ÅW‡Ñ Pn¸7(A  V8‹g X&«Èk»øâG}¤D{ ˆ™Mñ²úUe¶P>1Í)üNA´Ëå¤S`—VwY)G‚¾gmT}n#0ÔQû¬£hÖÚEŸBF€§ðEÙ A»9/%õL¦íVÑkí Wmåíõ½’Åsžó¯¿«ŸÄ÷ý³ lÁÓÏ®œ)‹®œ‹„>z09pÜ V‹^[VBbO°àî:ð!eà6=†`󟹹¢\6é#q–I*ÚíKו(ÌHa×Ãîa$´ˆ$NDU>_i5~8h‚‹žÓÌØXÏ‚5Áñ±e× ®T^l½{yh±ª=zËÛZÌtZº)¡ÇÅcÔ•P°š# I„·p)èc?´sMrñý(·à ³aÁ”ö- 3pòÅÛLÉÊÔµqUlèÌžWƒ½ùö™[a×ê‰ Í Ó©~5Èùj§÷ü“¯³ÉÕZµu³muQÛøsÂO*ºîn³!ç^rYqöE[`…áp´¸¿ÐfBµ/}Ã5çœÛLGO âNûko·½¥€£Wýø«OØM:wàÈÀ’ï °s& €ph-ƒ•Ì,èU‚&ƒ¢cØ–¢éÏXI/‚'pÕ _.ˆô½UCóéeu&t˜sq|æùâ HŽ6Úâ:ù¿·ƒ¼À1§®2ÖòØW!'HEâíU–Eñí)‘¶_qÎ&4ä¥m5†Áùú¾ÄÌ1 ¥(ª‚ÌœÌcà €~ý0½X8Àvn“uªÁž9ëGòLDœý+€›ÌĦo:¤)k ö4ˆ¶{ì¸Ø²¾ß͇¾á .C_/Ç“[LÝ™©Ìí%븶4ïsƒsÅFÂ}··0çÊqÀ„áðV6S hk¤>êùzÀbƒãT=(Õ¬£Ì±ÔÃ_e7  #^¦ãA4í ÐQ`â•‘ ÔÕEÙ1ÔóW.+é<ØË¶»Õ';¨>}èµ VŒÎ¿û›ütŒ20¡¡¶Øb¤8Ê{ûY`5ÔS!Mÿ0Ú±¢­¶\|õuźM§¹9š žŒ¢HËÀ*øÜ H!£W"(§Ü´§ÊòHÊê¨Ã'sÇpškϰ,VR²v‚á6T‡k„¨b ,¨OÊâ¼Ôlæj‡­mû^€NqÃöl§?MìðÀ@éÈþ}Åô±£Ù¨(ãF’A¦ŽƒƒÚéz ï`°²h¥œt=X…- \(IÇ‚œ°Ô§ÿ¤ß‹éÁ™‚é5,¬.7æFL…• ©®¨³1'¯,ÛærsЇ!k‹%ý\Gí? ií€^,h„Qµìê’’.Ë¢Ü=ѳäS§ûò¶Ú0ŽyõÊçÚ- l3ËŠ^Õ¬«­6\ôÌ«ŠUëÖõg.ÂýiÌŠŠ Ýl³:t–\‰ˆ(drí^ý²JÉ*xÈjåZ‘€Ò@N±ê¼|’èÖ¿ÐçWI•´¸û÷Þ|Jk·è¬í€¾#ºhoLK›Ñ`À>©÷ß¶<(Y<­¥2`Y*˨Ç"Z˜Ci9‚›á¤GREÊ@©@3Ž—Nɧ<]swûeývÆÍ ž¿ry¢¤g øÄ$?<˜§…‡d¦k0ó3áÁô&°ꎸ\fZ»Ä'*Ê‚²$¼êw1K>ÍL¼¬­60@^vý³“9ë+ëK1Eæe;:(Ik0"ŽÏ`VNMíÅlóÏ×îð§ƒÛJ8ÛÙv¿  ÀÔøØÀgÿt®í1h›éŽƒvâH¿ÿÀÜs{Q½ N½r›p 5E4e"¡ëÁV˜dËpŒzÆ/wTž-@Kßt4±§Šä&]õe>B7ÿ£Ã™N`RЇ9úh~:éú¡GÀ §…±4l)ìÏÊ”YåV…á…a•®»´³î÷¶åÿçn+Önô_XÍ:ÇúËŽªu';€2ÌB}‘ìDžô£þìKüÖåÁ?Uòöbó¬-ZÕî½gN\yúóX™.²cQxyŸ”C»wÍÚ€ÅøˆÊAS·Ó-íÄ‘~ß=À)Ôþ»i«Ò&>n]rŒÙÂä&3ó<;+ËÀaâãv%ư|"äY†ê17E%'—Iï®C{®-A}ûTv¤…· †çõ 9—þ³u=3Ÿ sPè& 2Áß!36û&“ðäEEd.Ñô†ë¶ž×î^×–û—^s­ú 7}«”c±Õcߪ#•³?%‹Ü1êgòbLöãëÒb”ÇÊê°ãåezüü˜‘——UWèd–'é匥OóñÀ|@Ð4û±…Ôûn˜ù´EØnqþ 6ù €GöïÔLU¿…f5>´c”F=pBz@ó˜&R J6ÑMlR³ù®ü0/¡R1y†¶ËÜ2ûÓ4LÒ¶ÞH„×%Æpe}Q/ëi|…,OvÂ'Ué•G[Qtÿ’¿aÇuHülÛýõ~$sUÈ@™•J"™˜Kø ?çúm¹¿jÍÚâÌm竬“ØoþB¿YßÙ±c祲úß 3|á õímHÇ¿Y‚‚Õ)›QwfŽ,À¨¿æn@©/߃ÁÜu*,à„-™µ¢ôJé"(ù¼½ª¬Â" µÔ-¾“¶ì6ûn÷¼YWÿ}ÖxpÏ.0}âûu§ÚøEÁ™•ýÔ5ÂŒz •ˆùgû?ÛÇ´¤3&M†óì)vÈãÉTõìß<©òr¬æ(I—P·)Ò¿ñÊI.vdÍuE›Š‘ 9“£ ×RÅö¦ä$}”(ç1Ëåıœó‚6ÊÌZÉ»Ã劊—`Þ)f¾G²tÞ%—jœ1w»ø*û 5žý³+güÀtˆc°ï çyDOcGʼ™ï-ÚìâWaíe [`‚¦ /ËYöº2¾ÕbUbõŠñ¥"Þt¼™gIÅŒG»g,hs¶ÑÒF-¯¥Q6(sž¸ÿx1Qž\¹ýºÍgÙ Sœ?¨s‡÷µÿ¬©©ãƒºýN;ÏnÁ“‘‰§Ih²Á,éÁ˜ N ±mjAËì»,`SM5è[Uy6û¦í~àšÀe ÕÓ—OÖV‹#˜V ôœ¨esÏ‘µ)2+Z;ÍXb»±°™cˆd¹™NQn¸ÄÃJìgÙ–@,Í|;ÂuWçÅmy¿í‹Øqêßj°÷àßãâ€Áz 9^âMsp ø ‹KRìk>@_ó«9©Ýõiv.Ü.yòÁ±»¥ƒæÇ•rŽ]÷„t,GE©>×1“'6ŽB7عNð íõ—œSÇtbÇØgƒ§ÎØÔÄÿ2††óÈnÔÞÑû5Ñ£ßnc÷¾3ÚèéÙcX= ©Kó¨Ø÷Ë&>û𒎇épòâüc¯r |äô9èÐe¡¬j©lñKNE{…¾üd½Ù_lë×óS¡åpf[í‚mÃ+üa™>¦þPÑpÐV’Ž‚µ,8– o¦ªV©·›PÓ!o)§‰'¶^ ÿþvû`݆Åz<ø'?8 (3[®@ñàųýTž.Ïâ» g0/Ïç|–E;?ǹ»Ë|†4mo¶Ó‚ ê°ƒê¾ØqFÿ<°È}Œ[Ùü“"%å>’^û|„´JÜŽe=ï§Ò8ZŸ n+!ðóÄ=oËüÀÀAòÈÓ-,pðn[[>²ó4è4q]Í&N ¹€ž‹g隉ˆåÙ'&Ó‹Y©zö/“å~šÐ\å8‹×œ–ÕVÍ‚ª»‰ß¡‰¸†S}ÁK~±=Á$ÀŽräd¹„šË9N´›c ïJ²³]v—Z>Óé>¯ç¸-²gm;Oý§m}OËqM9¾ÎôqÖrÚð³~ IŽ¥N¶ý¬N&žOĘŽGÿ ³ã“üXÀ~ԙჾ !.ìè@fÇ“ÇUÇ–¼(d´|³2ÇFnÇÆu˜2c,è=¬Ô•fã×qQ^^>šƒå8®ß81Õ™Ù6˜Ó>z¿ÑnâJrЄa;º0h'ŽôûîLøáÓÁ§,-È?. ¨ÈÉS“˜J˜LMo®…ñ¸ë š '¾˜—Ó$ V‡TÖÍÅIsJºÍbŸ„M˜šâØÜ~¨/òœ_êG?T}L:kr‡²tðº6éWõ¢Ž¥”ãP=¿-Ï8¿ófl]ó·@Ì-üô¤9`˜¹ÝÏÄ2ÇLv2î(ºã®}Žþ+9q"ˆÇ%zî xÀ0 g‹Ñ¡Ë<°¶ `¸À‹¯úBŽ<ÊÌóïEzF6ßl,ENž‹Œlý5 l“às¦¸+2`‚©KyÀùÚ‘ú0.Ì´r`±¥ûîww^ö²lùÚF‹G6F=ÐÛšg0ùĵv-|@´M–@á?–äÇäÉy‹ô\ ÙÑGªLøS„(ì%}Ã'¿)Ñ÷…¤º y½u;!‹<äQ.m™Q9ñ¢ÝIN¦!A:M°¤É‹J–hŽÃôœ6Ú099Yœ¶e â&‚)¯ñ3çµ{ÝÜzƃ>¯ù㬿›~íØ@Ç"ð£oyAZýOd–£>•#'.ù`žpú•ô$7?IVR½L¡C›pª+Mº!ó¼HM£·È¯N¡ÿZH‰™Î̹1Y-Ú zøèÁöï˜:zdÑ.eŠwî¾ût”G? œuʈVØ” IU(È㬞“iN¯6QRȉԢ±¸™©+¼Êœh9ÿN³‘»‹†h‰êt± L_€T¶BŽÉÄó’u{M 9&§<¶Ó’Q9e¢Ç~2žê'•}–=¡Â˜4–ÖÛöçnZ×=\\Іק~†Ì°o: ÀqcÇÎú5Žd=ðÛ?d~ÖO 7¦ôi‹mããkÚÒÕ˜‹ñɪÎŽr} ü(d÷€ç÷¤AÂÏÀ\¶|À3ߊíZ2“»nf£¢Gü éu¤cQŽœý¦„MD¦ÙÄËÄó‘˰ p°ûãQÑŽà&ÿLÍWï¬òãGë Î X¤ ­E†ì6¸0Z,ò8ŒÔÐüpkrAf‘[aŸb7€r‰b9À¹“±&#ÒšPi&f N®®#VL¶!ïÕ¡nØaÝLõrißä‹}¯Û©—ÃnðS³|â‰rÈëxÂbRÖ˜_0RN…°¸tò±CW¤3 Û›6ãæ?B]ÛÇÙ¾íà ’ãŒ»äéäÜ `à'+Oêl~åè[î 08Ãÿd+ðì{; °ÍƒÄ ŽïPîgÿq9@÷ `gÁ?ѬO|Xdî¶èG¹@ðÅAøÆ:™òãO™ûDÝDW@T²”«o¶|6¬ú`6¥ø“->x‡ný¾HõØáCƒšhÔ?v¨òëŽãØ(z`ø= ©Ågí+ÒCçÿ~3'¦Mã#Tcu̼ ε®§,fjã±…èg ¨!´7êöëör¹æÜÈýÇT\–eÀbMAKFŒ3d5èL7U»„ˆN1~¥‚T >o8Í ˜ Ø ¤üøÓ?ÎÆ™¸1€QÄ7KìSžõ#×ótï€-Ø‘¾¡£ƒbÇE:(GðV0G:ó‡ér¾0p,ø· ´åð|ÑÀȯ¼¬@Ÿë5ø~yD5Q¥Êƒc®‡\¯®å…`C'ϱôjí>€ lëlДװ@zªÍŸÎê>Š?܃NX¸éåÜÌìˆõÀðz@ &%~ òúÀ«ÌOšM’i7žh¡@&e›ò:«‰¶™˜Åg¢i1`ŸAÓ[àMßì$aKDb«#7ZÖçM°àC@Kß¡1ÍžZ²À‘v“8¡ò¥”wº—¶â.†Û†õ8ÇS0µ³~û~?¼À®ëɼÌHól}dêWp±àeíðABÔ%9‡.‚IرRp&mÜ|ð ÎÀ΀Ÿ.x9-ò²ëävHÓú¦à<+ÏúÕAúGbA[.—Ýs£ãˆ ›óLœ°ž«e ùГš˜ “•s¯–ö]8ß1é§=«W­.Æñ£j ’Wœ¼ÙO4°ÆßðyO8ž=;‚vÝß¿:gþÜþg‡ ùˆÜ_Å%ÕIŽn–¹ÀäOyö~\ &{¥Kàå—*|ø%»ÌÓ=¬K¥Ì“Ìù^NNÇøI #ÛVÃDq!ØÆN Có䓸ððúdÀ„#ÞÙ0 âøÑ–¾˜ØàÈ|½pÐ.~µöc .ŽX£H=ÀÄ?άœm‚…ØËjË”“Ò| Úâ\M“ÂRÏyˆ†´'±Tª}¯7@ˆ§ÜFðúË­-ë0N“ÝÄËTÕgPIú ‚™ºÕ™R …Ó Î-¡Çöü6Ü]³vN}žµ#0¦kü~Ÿ‚¿]Ð`cåì_ßúœÁ™Oþ‹àoÛÿ\”ÞÆqcà—o0c'@ . tí?Ûúçn@ì¤K\”Ú ;FÃnØWN9ý6~¹ žça^KŽšy7#kæT„7=ì^NdVŸ ØFâ’oà€©ãÃ[;ˆû6ØÔn÷J |¦âì€öF꣘­4±`þáPcôG™ŸU'ĵ0 ¾6 ̶ ˜ïX_Uh¢Ëæùf†e.Ó I?yÜ)µØŒ$™Umx÷#Ùs"ÊiÒ„Nè'u€*¸LWz ØàÌÒ`߆›«V­´©€Ÿñë¸ó OõûýÄLüË­ù ¾Æ(ŒmÝ`‹9Œãžî¦¹HŸÜÈÄ=È+ƒÖÓì ÷ ¤³}ÚýM™Æ sÊb±€<螜ٛ»qR{*Ì]È“½D˜’ŠM¼šÍ~Šm݈@;‹œ ÜÓa] ùƒ»Ÿ(N;ï‚~úd.Ìú¯¾ã×.àž¹@#Ù¨í~¾9 ) Çz³röO€}Þ´ˆ•áÆÎ€Ìr–÷¤‰·,Š“t`"@å~óF=k‚Lä¡7ÍL{!x çºa7™Êð%TàÙø Á¬ëõÛžSwèP±©-?V®XŽ hÁßF_øUÆÂ¥†Ç&׬ùuÿΘÝý#‚¶`ÐWðçXMKÔΓ ~å ¸e/pò ð Ø¾åŸ¾—µ °€žßGï$:«#êט¢’ѧ«m ëhRÕ[f«aÍŸ™ˆ°—1LkQïãXLs‘3@âM€¼ 0Pšâ%€--pWõsÐÈ÷ ÔБò¨æéÍ)œd"8ƒæY¼&ã,§3¯|!@ûÔõɉºL¡OvðbÊÔë#.ªvÅ„—·+™™¹à·†yG>f†òª¢=¿‚w{1)'óf–ð<Ú5-½ƒöbæÑÒ g¦Žmî´ôÛïË&',ài!æÇ¿/:€KõMÝó— Î oÖäBX/!‰W²‚ÊPÁ²|VA6W‰—nj˹¹à²ƒ£Õ™Göï+¸Ã0ŽÇY˜¾ ú¯ÐÆH}Ôóô'žò|H 2´È. Èy3MÊNørA N”1OGà]«Ç¥n‹õŸ¯b²ªÏÑù¶©?[ ;MrÕ™ 2FF¢Êlæs²¸iÃB/édü’G¸Ò{Ð(?wk)Ð݉±M1LõWß@`TÂPaØÓ5ÿ ÖiàæÁßÏú±Ñ÷þ¹ý³ÑгÞH«9ž³T&¡° BÇ‚y`o. X&A#˜GÀÏw|A`vJÒw{Z4ШD~HÎz#q¬äãüJÙåjNèC\5¥r"j¶Nq©é³d»yƒYá`0 }:»hÍAì¬;ýÌE›pÅëîºù-›/½ágŸÔÐHÔsõ';üëL)æb:?‚¸fQ€9‰jÒ¡S«}4c7v%qôÁtÌÕË·™ûIy¾0¨È; Èhn >™ÛbV&Rr\–çwÅÐOº¿äYêk#UqÒ "dK(ïvה˾Á_¦¯ò€)Z³ñ„¯ýñÿ<©ÏŒÇñ©Køíþø}õ9>¶žé_¹à¶£Šò€ú1!GN×ä‘#++ð“oA_<ûX ÷à_Þ gþ\ Ä"øXHF}²9 ŸõË#eé­2d`¼NbäU µ¬ÂKcԡ̤—”3Ád7¶³È×í™Uõà®'ÚX`ëø QÉŸÍZÑH0ê{ Ø4£Ø¬¨…@|NÈÇ¿m¥ú¬P9û—Ð èÀ'U'Òb€þº-#Y°FÄ„V9»wfØ3äÂßÃv]³2ùyÓ}Sa»¡°—ôg囵zà'—*Q‡•+5™âxÇÑ^Þ–› ŽñU?x}ÏÁ_;^‘ÆfHâ; üªŸ¿oýë1¼úõíL´×c;:(v\p€ÄÓÙ9hm•3ÐãEA]<ðžàž{¶àÎp¹ÌäÉv^èr\ĸ ï)IcLºÏ7§-+õk"ÃáÝì8á\ãeº ½8Â?æ‹Sv­Vm82W+ö=þh±õ2<sÀ4Ó{LŒöãH}ŽÀç[g øPh²L3  x㌞eγ-XK\ TÜmHÆ·ˆäDr›eQÊQTžÃ+ „ ªZHa•m¥¬z2ò@¬²¡ìÝ+Ï}H¶k²’ª‰ÃJÄd–×—èšO¹ §2 ÿ—ÍTê·žxÈŽnõâ÷ÿ™¼ßx¬›þ0ùË~vÆûxÖWu!€ ‹ñ¦ñÊ¥‚h@¦é”¼Jõy`nÊÊøÔµ(ˆ Î<ÎîÌ- Ç‚ åµÀN\:ó{±°ÈëùÐ`)/³P)£QMå&^j¿5ËÆ­+Ö•ú-Çg¿_|Ž¿Uƒü”`í}øórÀcKë;11~ÛºÂvJtÏȉS¨øÙæ‡^òõiCfú”ͳ Ž({>øL4A›¼x|Ë>œl.¹Ã4y£|oœ¤Jñœ”&õÂ<ʘ©íÕÉ&Õëò wÝJd&»¾^¿Ê¡SjdΜúäX§3™Ú:€»°£ïÖ3´Ç/ûÙlÏó>$U‚7^ãÇ¥%Þè‡þåúêÏüùðŸôÕ?î7 þåx4#4M»,1§M’ ôQŽÀYr.ÒËÜ >5>åÁËu}W@u&¾ÙO>Ê?/Ñ­”¬’ãò²]&R™¤+×åI”'™ YTª|¾e¡…o¨ÞlâY¤sªñGîÙU¬ÞxÚœ¸>„Ûv¼ýÍßÜÇûÀŽ £Xpøü†Ñ4“D_ à#¸Wî!ØŒE@ä˜IÏY6äV/U§‰˜U.Ñ K³N`šéK[y1úAÒLd’»ñð5ÕåÀ„-°X½´“‰Jg–ÅñA›Ê~ÓÙsS§0øç×ÿBÐgâ™:¿} ÝîèR€?ù»Ki@ã #ÏÇ—,ÄXË:ߎ!¤üǀƎƒ1™ôÉÏÏàSÐö³í4ÿ´;àv '›a—åÌ–Ú©ÖÚ›ÆJ^¦Q–ÛYÙù¹œ¬TÎäâe‚ŒtÔ©‘ñk€ûƒ`˜MÚóðƒm,pßËØ÷ÃÏÓבí§sðÅIC›¯Š¿Ü `7&L`,Ašlq@p‚”št)19á:aWX‡›ÍÄÄÜLšÉaV¨ ÛûÆ{%©Þ\T™:3ÝŒTŸH'sÈ‚Fæ£+0 YÔ“Ê”y«.©¼‹G«Æ_¼ãì›™)nÿÃúG;µàßå5~œý뺿oý<ÛWÀ÷K\èÂUM7ÎæªŽ©š-x ³àÏãÄlÒ±u_9»çu™ûb@ €­]ÇŹ öÉ/tÿ•4kÙóÉi,ÙwË*×+µžøÇÄÀ¿¹;¾¼µ{Vfí=Þ?«l!\øþ»ë·†ïðBœaŸ2=ÀIFŸqÍ0 Q G\Ò˜L«‘•ABˎ챬³%Š(³¿ÒwyÈǘý[Á—Pó‰~Í÷Êu2Zv³ºT/êç¬ÍV¬`å<½lÑg÷‘,oXèÎÌÒoI—õÓŽú‰Èì’W8oíÙêº{Þƒ%éò5U>z7‚é”Òþ0ü. ”“§20Ì3Y`ɯ¿¨öf`_4ëseNž½ÌG·•û†à¯öé º)Ïn$ô³ '‘ª´É8–ô‡’ã3©Cœ“É3Óa&é“Ay#à"Þø 4q?h7^ç bhrrøñtßcë릔Aœ-ŠS+Žð™ïÌÌH{Ô =€Ï¤ižu㌠3Œ&žeû­'}ýÔ/”¨¢xœ¡Çlfìºi ò30ŠÓ™?]s¹—i ›¹p¡tø“éÕY©¾À¨AÖG5–üM¼eZˆí`ª„«. atÉä3­ì°¹ü–±xl,;*}õ´—•㬟×úyæÏoè^>ô‡—È‹í”iãÇv§ŒæÈ«&¡¬bAÇ:Fø"-5°Ë. ˆ\‹ÏA§à¯ ø‘ËFuA º2Ë‘Óô/+gÐRÂî6Þ å-M**gÌŒL˜6¶AÓ&¨=é®äEZ_6ü´÷ч‹ [Ï^¤—™ÚÌô (Y—ŒÈvz@‰0E{ m!ÀZcòIA=}²mRåÅÃáÝíqBKS.ÄI—Ø$€m÷¥²01”&É7…½&`´#ÉÊ*ÄÒÄïÂ$Ê ™ãOeWŠz¯vƒ là\´d2l¿ïc>¨ÓÇ/&'pžÇ~©nï۴ݯ O^|}Þ ¨E€|ü‡kilùØ”Ï~t tÜ@qw†ã2{æÚÙÉZ0ÈÇ+¹þä¯2 ,×òÀº/ô+#­K䬻U¡å¹Ü%ÛK(Ëj›ËžŸÉ“¡uçúT˜ëìôžø Þí¿C’kX!/'='1+>Yh‡hcGW÷ äщ¸@y`Ï÷äkRî`o_<@IDAT?tÛ;åŒT£h©0`ÖàD…—æN 6IO%›pb¤8ÃÚÄžlЄžHÇËnŽs]êsVp›Ì…£;Ù+n´›K[as®¼¢›Ù”}¯¯Rôq#_Ø÷æ˜Ô•ïf%ûóæ„ÍÔŽT›Û‹5^Ô°´òÍËÛe½0¸ßGŽÍ‚$o¬ómr¿aÏnÒ+y馽ž›ôª7ÆÍaOz¼á/{I72:êv_’-Ý$È^ÞL˜n6LÛûµ6$¾}_ðþ&Ž%Ž£(‰Îù9í IJ±+YæìÄ˱dbˆ¶šhnº£Xì‰~Y¬‡ËV¬Z¬ê‚õßùÕâ´ó.\°^ƒÂòÉéñÿþd#Ö¨Õ:ûàÓÏÄó-œ~Éf¾#@ŽÎÈ¡Ãs(}¦ã´>®ÍÑþÔrÏâL^|ç1³ê³32M.eHNŠƒ'7_1T÷)Vd™1A'{‰(ý”®ë4áÃ\¥Ž¼ò%@ßðùâøë¯.…«ÿÊQÜÀ³bõ`:ëKs|û™g÷8û×3ÒxöÍí.Þ¸ýßç €1lÙÅå¡sûâ9 ¡Žs_°Ú= âö¢òL4}bP×Î,(;/á<ø³,ôn¾¨>ùàLÒÙè‡g)Ué E÷CG´—]Y>îT1YLO¼eóXØõõmý: 'ÓŸÁ½}ôAótúHÜwèC® ÎUæY•&• +>ŬZ[ ˜€,ÎÇ‚ ÉHd n)å¸L¼`2ŸìæR®àÜâS»Igü(+é;#ô’NÖß%¨00—s§®ì>¸6ðà0 œè þ£Sì2¶ñ¹Ý-þ.‚¿îþ­…ŸøÇö@–§m±Jžþù†RcwëØXÝî€|0_x¯åµÀå¸à ƒöéÛõác„ȼ|“î 3!Ü-±E»^â;Qkñ|EÊiòTΘl^Û ›%­¤‰îX÷¸ i‹+Ö­/ø£=ÃNÜ.â½g\|ÙÀUá¸lÀÝC?5°±‘Q 8…è7΋é³ï“d¾#@¬ØågøÔ‰ M<“²4Ѻž¦k"YIa+˜)H£¥¼Ñ®¹Ÿjð)Veoš7Î ¯Ørfèæz=ø¬¿Ÿ*_RDç^tÌsuù ïÀ–»î@ßèñ¾ºîïßÀÂRc 2ík€AÁ_‹ŒLŒ;[ À#^ÿG²1E~x˜ˆ` ONt:¦ î)ÁºyÖÎ<¿óŒo‹ƒòú~­<Ç™?á8HãÄËdÏh/õðiI|·“ %˜¬Ô>ƒCÅ^FÖZšB?µ‘Æü¿Ú†¡k×µa¦/Þ~ {»/ìü ÎOðóãFˆQôÑšlÊá-·8Á㤹’gCÙ5LèzÄÛƒsœÀ@ç×ÖÁO¤…óŠÂ–ð&“ŽkÖVnY')Û¥gÕùÖ/;P½ò{‚6LœëßëP{U¡úÓúŒe^ºig®O!°Ó.@~íÜÈ“®½óz¿®Ïck¹¾_<–%ó<£í¡>åõúúC€¢œ®ãóÚƒ½dßåܱƒ>ý±ºâ^…<‡Mîp‡œCÂÊ6¾(YNk踄òÀP«¤ÉR‰1û^v±²ªñ(GZ~›šÎ*Àöı•ã÷.;,kMK¸¾MŸÈÀ!ü.À^l<{[ßþÍÇJ÷ÿ›90#Ѩúë|.¤ì¬É?¤ H}åÛý¼À¯ÿ3xêá?8û×Ýþʹý3m "eîЄöýGFy˜¸8(áºêŽܰ@¼Îþ='žA¯ØH»<ã'6îX@ð瘟Ye$‘^"Ñ@4Ò`:Ÿ6J«Æ®—£ž¶òã\·Æ®ù¡Ÿã£€ÔÖŠ5k5± ý‡ï¼uAø¹Àø°}÷o¿‰O¥Q ÔüXê¥ ”þ9à´ Eh2"Îu¸8“ÂAvæO[µÝÚEÏ…ÅDQcëLœ¶sû¬£Ÿ¿Ð“®·§bßÏУҘp£¦GŸðÖo8÷ÉíÖm$]Nø®¯ºÝóèHÚ¦—jêt§okË÷ý~ zmgôâé,;Îôýì;?SgÀÅý]å£|ÕyÙ0ºÓŸ9Ïæ…ÉêI<žÁÓ†åú¶€c?v„!Î^¬ÏôP®ùkŒqì¤?ô ÊÖ“1Y"–ɰ"ÄcÙÿU6Z܌ߋ1[f‡4Çæ0O×Û» Pvî»§â습ëQ_°î®¿^Þ³»X¹aã‚u°ÈyçŽß¿éªË~ôUûä#Ö¨úêN2 Nq6dÊ΢8›ètßÎÀãüI:~6•ï °BÛ`žÑËŒÙ0ÝÒ5ˆTWÉ¡‘°RáªÐÖ$ÅzëI¾åÌ äSª¤¼Aá¾—BEö'Sd;©6ç2ÑKèíxwËŽñâIÞU=9¨Ûs›ÜM›~}?õ{·ýCÌ3}^Û÷\?ÌŽ+\ÿGžvè˜[ ʼnãF9i'ÏiÍhÔ­Åj¹¸C~Ówžñ§ÿœ/s^§WAkâ”e¤1„¢t#ТÃËSÑì±XRu:j5~YªâÜäÀÙqßñØ èŽüjôÀ÷¬Ù´¥ ú·#üÀí_ì?/²s–U¿1/lõÀ= I…ŠŸ sÒÐ ãÕ&:”Iã/?‹““!3XÓq™&HÁªgïÒŠ 'Nت=ÚLvK¸ù·Èr²™ù®ö©ý¥Ñhs½ÝÑO©í¡öjgû濵‹ŽG;£]e?"^°_–hÚ~ûíüA m¸ðø´Îy töÌ3ç8£NgávVo×è)÷r-Ogü:†¹Ÿ­S'Íh×Àì#¬Ý”öK~è–×ÿ“].@ìVh1ƒŽ‰£‡™c‹©,«hŸ)òý¥qÚ`&; J:À.w‰.1 R½ušå6ÓQþ6BKI €n·óµAíMâ«€ËW¯ÔÌ‚ô¿÷îâèÁ Ò™ ŒóïwÜ|Ó çÂŒd£˜³09p’ÐiB”0¸8o(ç ¥B‰UËðœMÁ-ô)“\A^¤‚áT³×O+­¾4©+ý²ž¨oÞÃ?ùc†¢ŽÔÉÌßDšVj`èÀ‚ùFàNÛo{ô^¸ÿPMà™ã]`Zß³wâÅ:Ô~y@×è}Û¿²]Ïí{ç†åØöïÉÏíýÀQåЋûì2@ïV¿ùf>‹öã.ßù†äYCe9äaf#ÉȱÓmR¾Ç𑦱ŽVÅJ|'‚OÀÒ‘¯ÿcççSv ÎtáþÀ»kNÛÒ³"Bô˜ÜûÈCÅîïïáÈxÍŽ›ßô¿hc¤þ4ë d¼aÙš·?'Îx ÇwÒ|õ»8ÿS€Ìl„0¬…A\;¥nöŠ`½Ð<·‘hÖQ ôô!ö(¦ëójøçËpæß\Aßd†«ë±«“?´IÛK=u‹¿o« »øî” õŸ÷»*^¬Oý˜vM>Ý”W ä àq€è¸–Ÿ½}]P ‰Ä³E@=è«n÷Åü(£ÆŒ|w}wlŒ§²l˜\Gí¥Q$ò£L£E‘TÙ²fœ! &[T1(Õ†’øÝ.äZJÇ'&|X ìŸÔðIJeÅÊõq­tPk ÓßùùÏhÐ.LkN47¼Þq×Íoü™ÃsV3>¥z@ŸO¾aZ@ N¨L)@)à{™XÇkiX (ðAh3lYÊÅ È KÛÙ 6닃* ÷O+pÓvM…>¤`¾ ¤®iøÞ?a,l&;¹>èèÓJ¿Ê¼±Nâ—xÂûûÛj/0€D·€Òí«kÙw¤ë/öµ/ðxß•íÄÍvW¿Îü¹0È_<ËÅ€r_Hð›´G»|ÕëËü)ÃSúI…БœLç>0D¶*/ñB¨Ø‹•gU}fËp¢K2õ)ùÃJ‡ñm޶‚Û?¾úó»÷¦ÀØXçŸÛ0¾á¬mm˜Y° þÁ#w}yÁzs)àøâ·Æ?xÇ»ÞrÞ\¸‘lÔÑ6©aÒÑäÀ7NrVŽ ¯Š¥P0Ÿ mªK:¾ ‘|²´ ï<Ê„3;šìÞíÑüE`6ýðkayņۭÔ"ç3_txC¦ºC,¬uaÌØUT¡>ŠþcÎåò'‘ XštE¡—æÛÔÊ£‚ç­üÊûtÏœy«ïü˜“Îþ(Lýç]½9ÙÑ÷Ê}q‹„ž/]êg/ñ²zåCæ“°®zfÇíº­°ú†1!õ˜ØVÿgæ´I˲ãLL”ÛÀÄw'A£dìÈ„iûUžòŠZ0K ™´˜›ùl v‹Mçœ×†™EÙøÚ¿üSqx_»÷çàŸ;6=ýÉÛo~óÉYÙ,ª'FJ'­ðÉŠ`ט8aͱ+@!þ5§€Ž?CŠøšeA@5ñŽìåÁ7ìæy—ëÌCç6rZíÎ=í[ OÍ’oÖk eÆô'¦÷Cf/Žié·é†õÒ–µŸ¾±_–rÚþÙ]ûx¶ÖVv±oD°_Ô7ì#¾¼?(³ìSÃFì /Ù ùìevËÚ­ìuçu&œ;M¾ñÜöW×unnK´YÐ{’9Ï2«›õ!é=ñKž³„Æoþc ZK3÷ÑVZ<óG_}Ê»­`ýgé§µ³}n?ÝýÅÀj±£à:þ\tÔ‡n{篜„»Ó#“Õ6Í`üq2ÃX´izeÒö ¹„|ûÌG"þf[Ð`ª/Õd5R§që,’N¶kuês›ÞP_¥¢/¬M†ÍÚê¾€£íšwQå}&¼ú:,,Ý|¦Ûùmy„f¯3ñ]Ty˜\B~õOø7mu7ا?n—Žà_¯„—°äKî ¼M¹®ø´ÅWØÍ’ÛO2çYfu×hS](¸X¶†õƇ9µ–:/Ýøå‡ï¤½´Àµ&¶ã ƒVÒ+Ö±uP3‹Öß÷Ø#Å£w«m‹¶1‹â%Óã…gœœ›fqjÄ>µz &/[N üT1ƒÀ^¤­LA¸hU”™‡­dúøKXvݾaÎ0:·M-î•ÚÓPÏÚùÊDÑæ1ezßk<ñ½ñák=èS±´]³EY&wSK:›éÌüÐZxâð”ú>ú×z,—!‹ãÇ#ú¶¥œf5¢žÁWnÇ7Æ‹C’ ?â5­›Ì0QS:&²cYd%Ìý-ú'x,‹vœ C|ã“ÿZ¼ù_ëìþe¸›btÚ¹ãtÓ¹ç…ý“’ßû¹,ïßÛ~ÝâyËýôm¿ó†sÛ7>²øÔèÌ >s2KO<ˆ*Á.&Î$1Ñ…z”)³”&lØ [š‹LÝx´ã ªÄ‹¾4¼J@³¼ÜÃ^ª/y}÷,ùšê‹6PÙS`™ÏôMf¾Ñ®ô@¨¯YV¿°î¿3Nž„|û­>†Ëo«êøm€CÚRÖ!±ãÇCÇÎø~È\ŽL}åpˆ˜ùRØéÑwA’ÃÑ8vü“Bð²<éŽõ“Å7Q»¢_Å-,ßLÇy–e2Z²Dw"±BÔz~àXkk?ùÖîüY8YYt:ã Á ù†³Oîår^ ¸çŸ>a`†4èâƒxùøÄÄǾò»oº°A°~À;Ôò>HöÃ7Èešox¥¿juYÍKÄàwµéõc‡Ž©i“Ý/é¸8"dõ<”¼Ûu šèÀÕë {ÆÇQ㱓s¨*ס•£q|“=C-l©fƪ¦Ô”mò„1‚6˜”‰E¼¥RFç²af<ûoë§ÝëOÅö?Ë•Àeÿñçø»÷pñï+ñË€k7ôã‚‹¯Ü5÷<ôõâ¾/~n`;M°¸hz¼óÏw¼ó¦ç5ÉG¼§q`vˆ3ä@y&ÚÄçôÂÉ„Y%X n“¡lr4~ Ó¤™uyðzrÖᯨw±yØ©úÍɱ|e.UøÄÌð©ßÛÎðSöQ¨ŸíS)ýyÊPîĦgö­äe€'Ûj tò¾F¦Ä<^$òã™úWˆø~rV’ìð˜ùKueu'[òÁ¡g6è[ðÉq»jùf< Tg¥L]$ÚŒº­,¦ø±z«: BøÐÓþ¶Ïþ;ÅäNW Ñ΋¥·\xñbU[Ó{ð¶/»¾¾³5{5C›:3Ý¿½óoþöT|÷' Mšˆ8Á¡ÌWL)ÁWÀÏ.P‹ŠÌ²Å@?’&‰kZp‚mJ1ñ.6_ˆÍjÐ>ùdµúÉ‹û /´'õËøKA_ª¦`’L&=rM½ÉÏ¥ÈÛ¾sç´éÛôýQíX²ÃÒ1ð¾‹>Ly"ˆ…Þ"_qp2sb±mâá¾È'¼•¥Üd^vD•Wµ¶ceVd6B®6É9nƒy¤k'"ñ2M›×þáóî5«&ÿ{î{Ï ÓmçÁ[.¼Ï’î1Ÿ×=tšó®øPqhÏÀ_n˜ÍרñŽ›ÞŒßŸ 4â?}z€ÇýÍÙÌ‚z=à Ü(£ Î9šwæX@ä,KÕL‹žkq`øÐ[\^Úg{ó—ÙK ©ù׳`Ƀ>±øk úü=øÙdÖeÞìÀ§Nêc¼ ÐZ£øÕ²=Gý¹êQëó{éXf•²òÖ_0uѸ{¡œGOõy¥ÂÏ‘Tù(í”öÍL´Óm‡=qZ¹ÍÖ‘É(fâoûÚ?~¶áÿå?=p8÷[?”3Ž,_öÑÇ0*Š¢G–ãæ£'W¬,6žuN±ë¯(ÌWÕœòiü&õŽÿ}qÍw}_1>‰_Ãj?uðyÕŽÝ÷\~ÏÍoþ¡‹nxõî>lßé‘Åaõ€Ï0ÏiFÉ0EEÿ@Éã·TÒâLꇜ¦Ò/­Ñ®CER1ɵz*,ríj™ç,,«ëQ­Öźkøžbɨ@½ú5%y’Yõ©7•ëô8x 0þÂ'¶Lv»›g¦º›áòf‘ž9K }8Úyà@ç¾ ^øÂ»~ùê­ƒ»¸_Ú–û¼`ÍÄx1>†Ú}H0«ôœãØ+×îø¾}é1`š•ºÜ˜ >#KßÀ¬ò¡,^É%^µ®CŒ±S–3¼ë‡Ì]jv¿ÞÈÅo‹ijªSüzÝ^Ï€ãÏàÞùŽ›>‹OÙóëà…–·\xéI_ÐçC{v_ùÇ—ë¿ÆH^è¨í·ÕïÆ#6þùΛßü½—ßðêÛúÕážZ=ÀÏ,?¸f 5q’‰adz~=rovPœchÆb€]bh,’y¤#‘ÅTÿÅ6ãºÐ zú3–ȰSç7•c"­ÈjUÕ'üŠý¬¸Œ…1c¹ÉT§3õ*˜Â·|úlüÚîe— ÆËgƺ—á¸mÅñÝ‚†l†l\Ç¥ ¯ò?k™Ú:†Çév‹U+‹âÑÏ|ìá¯ÝòÏ_ÿÐï¾µµð§ey)`ëþR ýPfö}/ó+jwV>CTÏã˜ÔùQNÖ‘ùPÒwy£Û'ŒGaU?tëze¹Ô‰±:&îû1ÜøÇíÿ–Ó_l¿å‘u›= :Ý™¿ÆÀxpÚ¶ tÖ=}¼•'YÖ}_P™?S̯^øÜoZÞÁ¼ñás¸/àÆË6\ø£Ÿ^`ï=%à˜*0k¤ÀíÑ—ÖÔº˜¤8¡ô,Œ©É.cØÊ'XMH.T->I»qe9žŒ s¬Õ·˜ìªÜ>JsÌŽÑÞ°ÒSGÆÈ±[ýIý¼šÔ&g†nÒKDÔ<¼|÷¿¸aª{øš±ñ±kquâZ,¯Äѽ¯£×]ž]#¥…]ùŽã«rv†í| ªÐîÖ ®}öÖÍçž_<ñõ²ÙÆÛ>Ü ¸öøx±fr¢ÒÇ,°~ïb«*B)Èèûù|©Ø!¸Æ¨!vN5S5 "ár“â šä1$êºÕri¯oæ†þ¾gÿm'|%ö7›l6^¤ïÌLÿ À{161Qœ~Ñ¥MõžÞCwÞVÜK+?y0—ÿ+0â~ ?'ü‰;Þþ«'ÿNȹ<ÉZïN&šP8{àÕsí_|1ˆñ•î 7’—z,šœÓœÿù· ’}Ý#T{ñIú^§œ g‘‡åa?Ëé³ü¶n°féÉà÷ô£Ml†3ûÖ§©NÉÙÞÐf»¬ýAD“Ø¥m¦Í›6ßÿ¿~çiOÞú¹×áõ—O~és÷ÎŒß=6>þñn·ó6퇛Ÿž…ðˆàÉ î\ >‹öpÉd”‹æ»X½üdÃų^ú}m6I¶9p´à™gÞ§D?¦<ÖßÑïýä¹1ákö­>?¦Èq¹?´¾öòÃo³eX¢ŒŸë²9Le=ÆaY|ËNØû^\}ŸŠÊ[ªMùÀën{쟚Ì5î\úã¯}ðŽ›ßüA ÅïhRZïì+®ÅôÜn}Kc!n$,\˜œsåu‰7$â_u:3·ßyó›ÞxÙÆ‹^?Ú R/ŸbfÓüð+¶Þë×þÓ© >™qŽÇ©Š‰ï¡ÇY‰áIsB ÄÅ™£É hÇS”é8RYÔ—ófÞÜËáÍtÃäÕTW–òj8Á§T!­ÄN$é‘Ìd¨býÚµÅ7^]qÍ3//®}æeŵW<³8}ói4Š3üâJ;X^vx¬ÿX޳y£ gõÆ’–ü§Ê”,&zøp,m»úúbó6ìܿӌ¶ðÎ߃ôàÑâìµ+Ôgt)·ð<ŽWùÞBÉ>meF3Rµ¤²¹^. :ÉÁ(yî°xÆM2'B/ÆUÈ]sèÙQlûóQÍ­§îÌëg³Ù¸ x¬[ü ÆàÀ €k×±eµëþ{góá„óùÓÁËV®:»¸ë°ó‹wíºçE·ÿÞ›~êŠÍOxcGžØà¬QŸPÀRPÇÌ¢‰•òˆ¶±/ ^Z pòI× Q(l”&ª°Ã2þ²"!22ì[©÷=&¾^Éüœ˜<ëÈ›5Û—§¼Étan;©'"ÁÐIA&S9¯`úì3Ï,ž}íÕų¯¹ª¸þê+‹k.¿¼X¾|Y¥Ͱ×Q‰~©'Žƒ\Ò1Xîá Â\Õ$ønH!’|·KEŽ¥çüÛ—û¶7ÎÑš…‹xÝù‰ÃÇ‹Í+'£ë͈¹"Ÿóc‘±ªÜV¨ÔŠÁ.ëw@^oE…('LÆ£AÉÅ3¤½› hé c.ßJÃç×ýøŒ¶ÚñÞÙÎþY׬ €£«Æß³ìðô~`ÖêÔ9W^{J-ø»û?VŒ/[Vœvîƒ6o^ýn§óM¸ ø/¸AðÿíÓ¿ðÌ~ááy•F€%Û)ðàÓgóirÊ"ƒ€Rœ¨²N]ŸaeÏ šÌ¦)5, (ˆz²·äC³8CöGF¼mD7ë“jê§0r_“©Dd“~ð\·ÇfØ®å+W¬Ðý³¯½ AÿšâYW_Uœy:ïÍ <Úû^2#€ €3bÉ  héâÆq«‰;Ð\o4"-$LÑDÁïç^yM±õâËŠ‡ïÞ!·ÚzÛ}äx±rb¬X…o¤æÐ%¼Ì‡¬¦F&[Y1“ò1@sI"Ñâ{©‡oNäc"ôâØFeÙtNä;}Нc¶\ï4.Gýâ\6cÄ6b°}ýG8ô?Ü(\ óKïÿ‹bÿã.Pk¸p>§à’ozq±å‚z©þ>ß7­>´ì×Ï}å++ßÉnkGÖk=ðS(¿­Æ¸xís_[l<íÊøsƒ)pû§.•ª|=jDð± P¹¢`ˆÜ^©Ô\6§%jã嬵ˋIÿC“ÙžÅA¨ÆK}\ãGQͬr^E‚ªÌÅ7I’‹gò°‘wqÂEÝ'(ß‹;þOµ»€sן˜è.»ä5·Ý¿{®¦Ìz €J—>xôã;¶.¿³ÐyséGvÚ¶ó‹U6 ó©|ý¸Ñƒá¤qÏg>QL9Rœ{-nÞ=A ƒð\¬µugÏëvÜü«7]ñ¿âGOPõ£j†Ôir†}]¿U=åô *DøÓÄAðmò%€ìgÁœ:Y1͈õɹRgnPN,ò­lVhK.°¾É9 3fn®âo&¨ð¡>9Ñ).8{…þ%ç­,.9ouqæf\·W¢â• áSŽÎðþÈ»Åü'êæ¶¼RÙ³Éõ\Ñ,z»âò˜ª o2®cÇ“|g s‚ÌÀÄñ¶›ñ®éËŠ{þùÓÅÑC‡Ì½–Þy'ú#¸)ð¬Õ+ЦºÒǦcÜoõj[ì̺¬R»¡¦—Ê’Y)ñè§r;%¯fìZðgýâ|ÁŸM±6k³qàg{ˬ€v?p_qû‡ß¿ =ëò«Š žó‚ròvõšì)á!ü4Ó¯˜:øŽgݰ½ÝOó°Û±4íeàêgý|±!»}|ÔÊ28yÁû°ÂË>>°™È4lQ0 Ût²÷2¬eÌŒÌ'ÏŒÝHÆäZÖ˜ùM\%°g ¸­îŸ¿Zg÷ öž»[ùYo$ÝDdÃxIRó)E 9î(d©íb%m·ke3•Ëœ† ä‚R!rUÄÖ{ÕÁlËõž|­bȾûŸþ¡øè»~;Œµš/ÃÀÖ5Xxg=mõô0æ¨ÞšS4°$Ï{}VÇ¥²d©TÁ¥.ƒÅ°¼R£âÎ +ð†Ë}C¸é À!ùÈ/ÜúÈ·!Ÿ·™sîÐØÄÑ£ïœZ¾âFëY$m<ç¼bý™g{yp3CÓåsŽc'à⼨À÷z‡V ÷ÎÌgá,à7ÖL¬yÍ]ðÖßév¿ë²}ÕCÃubd}X=P®˜!íÌÍ& ’õG€/õ ÁÇ·Â5%™løÌ–Arö¼+˜ ¥´˜·˜YkºM3P¥Äg \¶~ÍDqá6žÕ¯Ò™ýÅç¯*¸½_Q¨ëggê5¥:DÕÓÿü3>¡CÕ§,ƒ0¬[•!c†ªuCՖ鳇A©^'ƒÜ€œ»!'ßi~õ7ëLÖ«S?»>ý‰âÁ;øc®í¦c¸;;g¬ž,Æ;cù¡²Šäÿ`uöŒ=·Y7])£ëå2;ážK„Þ`þª}ø8‚?¾4¤ttl¼xGK?öc¸Í‰ÅÝëoàÕs‚úÜõDqË{ÿ c¹/ÿú´Ú.lÕú Åe/ü\²ØØ®áÜšf t¿þ-/?ñœ:üBèG»î;¾oÿ{^¸}ûÐFLîÖÓˆÊÀ•׿F7²#xGŸæåé˜ È^Ýä6‚"•A4âÐׇ>76 =ß'¸ñ3^S Ì8³æ…kŠ‹¶­*.:wU±í¬Åꕳ-Â3#Y™óœŸ‰ÔŒ¤"§P1Ÿ›r:ÀRsES0Ó΢SK °¡œÄU:éJî 0KxPÈEv‹ýOö‡¿ë6ÚÏxCàé«–q=À«ègˆ© ó¸ÔƒqF æ®_Á¡—6ãçòy\ª˜¿îw×ý‡˜>;½é‘lÿxÑ÷Éb?ÇNþÞùö7ý7œVü@Î9°¿øÂ_þIë__i÷Ü'Ås¯{N±íªoà)U.Œ[È-øÓœÛ'/äbgü¢s¿ÇëOgŽz/.ð9 £´¸ÊàŠoxuÁ@å¿(G^w9øù¡7L9îê²Ð©Ûj*/Û¤?/ðåµù³Ï\QœÖÊâ<¾Î^‰3û•Åé›â&½@.0OÁ¯:ùWtØôé?Ej9 ÂsLF—dè&Ž)¡˜ìH¸Ò‡ÌUOÈ“V²#'\,«a/r×·b‘»ü#ïø­âîÏ|2*n=gìß‚EÀòq{Š|9:û«*Lc}'ˆI_÷™ÂWý†ð”¿hC·Ø‡E¯½ñÖG¿¬~òyï#¸ôë8ø­,V¬Y[œsõ7œˆçò‡û‹Ê9©Ýÿ…Ïðü‚Kñ¼€ñeÍg) 2žfñü£ãt’¹Å(G^tà»1ü¿{lrÕá¯üÿÏßBóOW^öþ³n¸atãà‚ÄÀœœ4;é-þÌó`t)/ ô׆#™Ýrܘ­–yØ,9ô©´“óÛ¢ÔÜäÏ?k•>ƒ¿nÐ+]^xuMngö2²b;©ÑäUyƒËmn#À,!6ÂLù94œúXû—³á6îקküÔ óAÂŽÝ€Šts&=Úòëþ0ŸÜŸäƒÉŸÿò)¾ëöâÀî]4ÐzâÏ0ð'„OÃWMú=Y{æ¬Pm*yà.¹ÞôœAšÍËxu]uƒËs\¦rRHöòÃßYjêt_¹ÐàOú=tò}ÇÍoþ0Úóâ6ÒE‡|ñ½ï>å¾8[Û–¯^S\üüη÷Iiᤀî×ðÃÀv’£’ É'0°ž'l§s7½·3Ö}_19ýÁ‹_öŠÇqñi¢;œ€ë^U¬÷Kññ*£笃Ó1Ôác¬Ì÷zêÕzëÈz¹n¿.2OúÎØ¼¼8÷Ì•:³?ù6ùs¶®(V®˜íz}¯ÿa¯Ÿ|Þ…Ke¶¯̼G†$É#E„ ¬\JE@ÆÐ{ØŠ\5Ê€ÙÈu)3¥Ê1íZÀF‚“rlÉ„¼Âstè%ðó¾÷Ü]üõM73ÇûÞ ¶¾ZàûšÉñbÃò‰4M-P]poE¯*uYÞCTHMví:¾×è‰åÃÃ}üùCWÃMß¿ñÖ‡ÿÃbêè5æ°r×ïÝôü¦õgYÞl&uCàûþ¿˜6äÕÑl,‚¿ùü‹Šg|ã·¼G`QI³2ºOÿ–[Áº4MÆ1{{ž¡Ê›°²ÒéÜ á‡1îÞ7qtù‡.ø‘9²(_ŸÚJCY\~í«t €]‡PÇ×û2xéØÕú8ççt VûL¶3VFÚøÊ³’ ò[qM~ÛVxw–yv¿i=¶îÌÌå§UÒ 4kíuÁÜ“gã!©$ÂŒúDœ¸•‰Ù¹Êð–ŠNÐBEf|c9¦nl-¹ÉPÐÅ*m%e«ÔE²&:“¹®±ˆGú“ÅGÞÙø °Ôh-ñ~€M+&õÔÀEu—Ãóº¥ôé?Û²wùÂÝþ' }âôÉG^rÃç‹E=LnÁŸLì¼ ü7m5ìÞÏ}ªxèŽ/µeî„ØYôn@š¡ÑíüWÙËÒdXä)øÛªm'“§FüÀv:{ÀÃb ó!è}ú¢ÜÑÙ¾ý„ŒÌäשI gp wž™ZÇ#O%/ÆBHÊ<ôƒS/?ÏçÂD×M*°óæ;>8çLù37¯oY±y#¯ÑǸÌ-ÏægÙ&¡kÅd«jªÏRCh¨°*ÙìY$H"0K8 ÁÛ¦r˜¨ˆ¤$¦ ã=lDnŠòizêxq—>öP±ÿчŠCO>^Ý··8²owqdïžâèþ½z…_TšX¾²XuÚ–b3žùþ¿zq±á¼‹T“™¯ÖO=sKïÂ}ânÆSñ±râ˜Z·l¢àŽÀ ©ÒÇa(šeäÑÂŒuÊñ£>ÌO@zdºöö[|`±uõ|Tç3t×Ío¼l¦» ¸¾ï˜ËæÌñãÅþú¼1pI%Œú3/¾¼¸àÙÏ/Æ'ûür„f_t¹þ-·‚†ÊÄM¬ðDÌu ±²’•½"ÓgçRÖéîÃ?‹º>ÓíŒ}fâèá:ïþóî%Õ÷í8;¤Àÿ]¬ÛøÌ¬ÏKgãøÆ!2‰ŽšÈœØR»¤ê²z™Èå¸>ËÀ~ÆœÁŸ¶Lgô ò<›?óô’WƋ̻/¥KÙ‚²¬_ãŠÅ W)Tø”Ô¹©yèÙ‚B©æme¾­³r"ˆb´ÞslÀ}N®G/P6Ee3ÓSÅþ‡¾^ì¹ïžb÷Î{Š}x^ÿüÇÞéÜzõ³Š«_ö#Åêͧ»ËeÝêÚ" Û.þþ·~­Ø‰Ÿ@?i Ü´b¢çñÁ•>›Ç‘J÷;6ëñy´Ož˜~ïÇ%—tÖφîÅ-!ÏÝ—¹}V/꓉缕Þ0HŹî|`¾ü¡÷¥b.;Õéå«Vç_ÿ¼bË…—`¦›£;“ ýóÍñž§‰¼‘ozRF§8vè¤oéÿy]—X»Ëì.?;VŒÝ:Ý)níLLÞváK_~jýrÝn7 epÙÕ¶ «qxRôÃm²²8¬¬%Ÿ¶JüòecÅé8Kß´q²Ø²ÁÎØO#½q9ÎÞ'u¿n ¥R)õèP*eöL‚j]æŽ ¦^¦…$ÌZàd¥®^ñœœ¦ˆ)¤àR‰^H¼DôµºR/8ɄѬ—?³÷¾¯»ï½«ØußW‹=ø{¿þµbúø±ÌÃvɉ•+‹gýðOg]ûoKøæÂoQîÿ±ÃŠ÷¼áŠÝ-ú$qA à¡^€µ£c"Üê·dÄ©%:2…ç0`˺2f†êã4nýÞ×Þöè_ZËŸÚÙMßqó¯líãw±zvÔÂ$;ÿåÓÅ_¾eaJ§zí–3ð£B/(Ön>£Ù«4 âcAZ=ïÝr>Ás¢V"ŸÀÀzž°4¢,Ó“>QúQNy†u ðc*¹u|¬s[;>cÅÌ­‡Šãw]öÒ]b[5ldcÊàÒ«®X¿Á/øñH‡n¤ãA—Ô×<4F¬X>VlX;Ql\7Q¬G_·v܃:~¶zýdq:Îä7oX^¬YÍ­V;f4ÃÔ4NLBaVkr&*O¨ä‡qrûUlf-W.é:•ê¬ ú(Ï5©6Èz£®2¼ôî ”2žb§’×sh×ãÅ®¯î(ž¸ûväú;¿RL=ñ?ß1†G½=÷†Ÿ-¶^ól4 ~Ò?9ë‡ïî÷þ'-þêW^[Ü3œoDÏæ9¿.¸ úÏ ç˜Ô¿9s ÑDZͿ?æsìDßÃÖ-þË·=ò;mt•²nêη¿ù—0ë¼nášÍÝîLqÛþªØ÷Ø#Í€¥ÀÅDw:v¸#° ;•¤IÐ&Õêdm‡ ‚€tˆõI3aC€„uLšà#“y]V‡Ÿ¾‰ }&f7°–7Ôõ$$÷_·;vTwâ ¡;ñhë©å÷]ð=ß³§ÒîS·0”À%Wýl±~ãjõ<ðf‚ù†5ãÏÈ×1¸ãµaí$<ƒ<åËŠõà±¼ gM8(ÖcéØåÇÌ“0ËyÔ?„¡g6(ÎuUÊëIu;®’¹Mò˜*z eâ­¦ì¾ò9„¸Š™/…ñJ€ ³Ý»(Š©cGŠ=_»ÁþŽâI¾¾z§®Û‡æÉÎ'V¬(^ôš_-Öœq\™°»¬ý¦Oø¥Vœ@k&Æ‹¸$5È(8Ùý×ÏÀχú õ{ýy…Ýévn|ím¿!c D.ú˜ìøý›Öv§º_Eí§äA¦|ôÐÁâ–¿y÷Ðg™U5Tr|b²8Ï9ØzÅ5Åø8n•H“%º[ÿ|ó®÷¼!ÐÊG㛕{p@‰ö¬ÙOÓȫ֬L›ö_ÖịÒ=2¬”aÝVéWqà‡| ¢ÇñÇ1Á>ÖíŒ?ޝ2?<3Q<615þøÔôøc«6LOmyÁKOÖŽBÏ`ýÚ5êK<õ²X³jóåkV¯ÆY÷*½Ö¯][¬Uy5ròV#¸¯Ap_S¬†Î†g"ÇY:¿Wëg+Fß±—V¯ªcõVÑ3Žá¯ã#í:¿ª¯Røàu%ÝÄ''ìTé8ÚÒ©à©âuIoÆkdÀ¼ßUbc‰™}1€ ¿OÂ`¯€ÿ•;p ÿ«ÅÌôPŸÚ6`O`â}æ5Å ^q£Û™ð8.Q¼÷W©8vøàÀu/ÔÀ8ŸÀaŽ…úµ<¿ËwöŸŒÀO?1’ßòº[ù¹…ø<¶éS<ŸN’ïxû›7"üqb´@ð~€Ûq?@eUÞ‚Ý“ab×ëξâºbëåW\p¢µ`Mo¼ëñiHÁS쌟&fðüS“°ñ)¢~MO¶©’Õá úä6xž[F!^^‡(•¥®ÉÛå:^a¥–éJ½sÙÔƒ§Yuøu–½Ð9Šjðp£ÎçáÞEôQ.x8ËÈßg:<ƒ®»Ž ¸Åa%€+ ÛYš§"ǦŽo>|äèªU¸ÓzÙò86fß±,^ë_ É3¿# ø–[¦wa)Hxg ZÖMÁm•zF Yä5‡K®êü5·d?+¹šQÉ d³Ð¡‹<‡ˆo³ °È< èa¡Ê*~ü…uàqœhpÿ ú]8³'Í;ò—bzÉ/¾µX·u›7mÇK]àý€6[ÑÊâÒÅÞöÆâÈA¬ÓOBâˆZ11V¬ÄåþÒਫ਼øþÃØÞä¯÷MŸ˜;û»GñmxÐÏ+Ñc~`a f|v¼ã¦÷#Xç‚kžCá¾[>W|ý–™±´D|fÀÙX­o½âêbrž ^Ç›O’•I™¼àǤ¯²* ´F« S)0VP\ëüT—×A Ù¤µÀ’W-«ÔPGÒOp(gên%êêßyÊȨaUÙPž ¶VžÝ/Ókl›)á½´ïÕVx=¾Uðr¤ôÏý²,d–WÛb~™)ÈMLµ/r×,åÆ<Ó©é:¤´“°d%)+j¶«Ê3?X®ëÕY=2˜òúz‹‚ôóÖ3Ýõ00%Vye7êá®|Þ˜÷~éóÉ{ì¿r{±ïÁû{túqåTÄ\ño°¸ôÛñ­luwè%Þ"W1_t‹]Ü_¼ï-¯/íÝ}R›Ä]•,Æ{~_àd:Æ><‚³}~>ÌÇ;ódº´ýÆ[ù¥a8Pû”.¼ ÿ¡ /Cg\í$ÞpÇG>Pì~à¾v ž"VÆ—-+κìªâ,ü¶À²<1µîO“sL¶>0‚1(>ôØ,ñ‚;ÊVSÔ13¹ Ðú·Ü &7“ä[9éK!Çæ ߥ#-éfX‘Õ2ëLب‹Àmü›b?žñTKc¸Æ|ú3.Ç¥«Š5xÐGš câEÞ4Ù7ãÐ;™^LòL擾ex¼ ³ëCÁeÍuQ—G£ÌKœóåå–X”KŸ+3¶R·„¦/8´eRoÉ~ò=dIL¯à'ÈdÉnë:¹„•ÌßÀ4U·m 3ŸÃ6r¡£œê Üíd¾™ášNM׊zWI'ó#x´dÿŽO«ŸîX ߣöYÝ„tP)J˜RÒUû©Ã‡usžþ]·)ðÆÏ?ÒßômÅuÿ×!NÄ€­oX@nëƒè?lmïÝ[üÝo½¹xô^~¡ëÔJ—Ëðìiþ–Ÿ68Éa›ÕÜåVþqôǃ=Bìqþ´6Àn˪GpÏÔ½ö¶Gþ¬e»sù§º"XH—:;ÞyÓG1¾u!zóaùÛÖ·~à=¨KåÆòùZÔ+_wúÖâL,ø=PÈy *ÛaJ€ø —$0V('ø„c½œÐýpG¼Ð,&þ ¼•ðX·QÚ´:R‹:”›^X!&ì˜9–E¹Ÿ¥-R kà Órý0®™s¾l86êQ8¯Dú¦c¤ÞͱYvž22M×2–E Wú@ ë#Æhc9|£2yˆ(å2QkSÂÑ WN<ÓZêu«l̲ ^G.3?ÔcG5!(Át"/ DÏLa+ÿ¯»îÆ6þ]_ÖkÏý÷âá:§öz5ºe>è/ùßlÀñ„5òœ‰\T”QâîÈï­ÇïÿÒú|šYN 2†ñÄÅwx#sŽsŽ2Ò‘ÎÑæNØŽ¦ã2Š3ØUæn>võÉ è©š?Ù{éënyèSÃv0ë¶Áªºý]ozÆØtçK°²j0KUí#ö_zÿ_Ç?µìŽ÷ œ' nŽ«6n ÖèæL‹d‡É‚GvÈ8øÓ$K<¡ÔtLÈÄ3­ÙÄlx«GLçGFyiÇ(ç©àb²²Õ_­CÁ2¬ë$ÿ£.zßc“®PAJ,Ðá’ç¶J±cƒجŽðÙXfXÚO~Qà²lð;»oÔWÁuKÚú[BÇšŽqð^Ó3|è—zórò‘&3ž«É(ز%žcÖ€©˜ˆdÀM„^Æ'ÉTÑ1VÎ ¯\2gÆ`¿wáïÆwîyÝþIܸ¶çkøÎý°3§C§¨°ƒ'ï}û¯ü.Ì/b1èÑÑÈÖÍÔÁ+_¶;}üóoÿOÿçGpÆÉ;Ìr¨hq”Úí/OOOÏöÛç7솞Z=ØwÞü¦ŸÁøyKÛ^Às³oû»¿ÂÀÄŸúiýÖsŠ3.¹¼ØrÁ%ŸüÅÏdšØc¢E®ƒe–Hë_’T–>»Mr—ïTÈð‚UË”NFhŽ(°ç|r{êFÿVz²H*{N›*HÇ),ùÐ4ñN"ìäØà6+—6£>³F;¢ËyÆ$Øê ¾Ê¥®äòzV¡b𘻶ËeÉJ¥.ƒ5ùçø°)ßÈ3›QCèWr`’šTܯdƒVÂ7¤^µ’ me¥Œ,  ê»wÞmÁg÷¼f¿{'¾‚÷4ù¬ç}±PúÜç~sñœÿðÓˆùÔSðE@¾ @ëZ è¬8í H§óß·<ëù/ýUg~'õpãB}áï,Àþ`jÿŠŸØ¾sç »ie–åâÓݾ}ìέ+ޣ߱8 ³kíÁ£,ïøÈûOùïæÎÞ‚…K¸ÂßxÎy¸_à²b3Ë—§‰–®^ÌÞÊÁÑ?ß$U™o*‘|òT¦_%¯Z&äÔu™ÛèYÖåfÌôd%é›+R.J~ˆ´7‚cw{‡4òIDATRe]ަ×&MQN›I™Lç;Ïe‚.6d’õ‰¡º{ìRÜP©RO€,¯áešYQNÝR,2žÙtR'ÇÔ!³fÝl$†˜+•KŽS%ƒ–PÑ¡'+vãá:|í¹‡OÒ»»Ø;òy§þ(-¬–¯]W¼øuo-Vn8Í+‹€XPÔ°,r¥™™_ÚòìoÚNú—¯9ó ¢?iO³"s”†ÝÇñ‘ùù_¸õ‘_GîeØUšý¦ê@5ßùÛo< ¿ñÙ6¡e->ú··Ÿn‰ÿÜ´íÂâôK.+N;ÿÅø²å >ƒƒ²‚r 6~h%â[”˼”\nY‰IAGAŠvT©º_A'+'¬Œ”Øœ+ßÄHùìÁ»¬S:Ð3Mb'$¿’ÿïØJ]àIîv£0'Ö˜ ?—]ÖKÛLF§¶‰åÂJ}¥Ž, <Ã[vÍ\gzî¡ûKWJ\IO–ܬé«@6SR0ºÔ ¬Pzãç“×çùŒ|žÍïÆö=ƒþÑ“üµ³ÒÃ¥MñÄà_ýäÅ™W]g ‰@®ÀÁ?rB¸ˆ²Ça)Â5òNñ}g|ÃóÿÂŒÅöoŽw»Î|-Ê| öat”ÏÒÝ[ÆÇ;?ðó_|äŽYCe—Ÿã«¹ýæ7>?,ó ˜äšöá—µnÿðûŸ6—š:oß"Xö¶bÓy§aQ°jãf›«PüÆ„-¬de5oÇäÍÜô,+ËäK"ùôHo5•Mu˜¾ó˜¹qDgEûÔ²–ñ˜aä$À؇Å÷~¥,ôÉ]g\“]°.ØÇm‹°T% ¯Îz­‹Îª ¯¬` ¿B£ØÆvùA×}üˆ$yIðÇ)Ù9äº)៥d?D÷ÜÀR} L¥…Ýð‘ÿìÝðfIèt?Jb—LÏIݦ’à Ïc+: ÐÍ5-ž½n]ÇùŒ|ýÜ>»zÁGè]öáÛÎÇa€7Ìßf2üÉ­U'¶Ç¿.mßôÀª†¼{†à©ë˜/ôP ¾& »ýÔ˜û®W‡ü¨bžÌ G‰NÛæ¦Ïk£«‰g9>{ ™$I$Z£µ$"fÄ4%e³Ól$6IRbSn7Oj^'¦´ z¥b¬g{–µ]K6cE¬/ˆ#m¤»Ø–m °æK±±Oë“jÇUŽ«&Þ¹ÚˆWQEØT,Å™é¾9¯é~EXí˜Äåa ÓÍúé¾›nƒÛKŸ~n=_qßÛ~Òõž8áºNq½¤ËWú¹å: ¬/€FºUøÊ÷ÜçV¼ë½A˜øàÎIYIŽøE­ú óX+ Î|vî oá ýÊZ6¬]4·qhøSäëcd8æ×y•Õ™jçÝ/è‹“?úï/}ª»J»ñ_v~éþõt«¦ïS$úÛØ/¹¡A·ûéºSt!– c€“ÿÔÙóÜ4žÌos-sç»–y ÜÔVº)Eˆ“krôɱ81$PÓIÁ+1N*V¨5F ÔãÙ-×½¬eЉH++5'&rºO‰>Él(Æ(é×DÍIÝ·k¿µ‰Û½^ËtŸ+:iް>N#ñ™Ä–Ì{8‘·Ÿ–ÄÞGg½DöÉžî‘Ñ×ÙŽäÎôÕÁ’¡_û,}Û]îºßøM7™&å|4/‹”T——–&P³ÙKc‚×c=ž=…³§²¹Æ«Î÷è_úP°úÜ æÑÜó¿’K~´6=å KÄÀÓ™LöŸÜzø™HWuUÛ;¿v•¾BhfݱpÒÔi ”Ø’Io-yii7F‰Õ¿ýL'¢é8ȬÐVZsEæÓËŠXÁ^bަXMÖZ÷m!©\cY|×|«ù”j,›oæú{éûö×6ú§[]÷±LÛõwuýgNi;}÷Γ[,— V¿É­ùÀp3/_*¹]“u’Е…±9 @^þpÞoþüX0»aÕ¼å Ù?¢ÏÎGÉ߸äE?+âƒø3î¡Ü¯Ž~kœ«HÌ‹b{¦‹ðP†éÎGø"gLÞt#…=¶{§Ûó³-8"‰ 1Ö7ÒýširÀg šè«…ÉӦˤ`•"Ó•Ë“§M£útºwßnÜ’=÷ÃiH¶òn¤••!±z,)ô Ë“F½¬nW¿ÚΆ…²ò>Ù^ \²­¢äáÁ!ù®œþ6ÐÓ#É|¨¿Ÿ.Dí•[Uѵ(|ou>jêcL—&|Jî}”Ìùb:ÜÎV)Å:a mÕ îº÷ÔÍYq­*9çÛ¿¤©':9Ð×+£É›³,VR&öÇêüž³3{®_ºôŽ1½ãMd³ÿ%“¦§eÆå+_a.Ìø÷éñþ©­GŸ¬ÂþØ%ÛëØ>æ ;7>ð09ýý1w9ì «™_Þò8í”qaSDË„Wy²0©…'-ŽëYúußÐhÝî˜ËºÓaã¤fÇß²Ü8yýÓ£%Br–”MãÐ$m³$±[ÒæÄä(1³?C‚ÏñÍirCt.}ÎO‘ã6NÖùœ– ™0u~xJ×ÔoÓá]ãM%ß4h×Ó?p½t‘0À@¥à_×,¹y½[ùkt³èIÂŽ;'lî‘–¥»’”)œ˜“Æû1™j‘v¸©ÿ]óVßò—¡•^6¬n›Ÿu™»3ùü;éÚœ[¨Ë*݇QâÑm‘3ÏÑé’§3¹ÌcŸØvä—”(øQ¬j°iÂ&ÌU~óæ†í¯~:ñ‘ñ掿ë}í—ÏÊñŽÿ` \Ú 4ѯcÞðî{ÝÕw½~1ÓJyØò‡Z×Kò'½¼´]²¹T-‰36…g‘_(+ž ?îpï]´n]Oµn•Ï®»0?ØÄµ4ÚëèÔÀ*ª/¥þŽwŽê Ö¶…Û躠­t¦ø§+¯=¾í¾ÿërÕÊÕXök¼É=g_Ÿß¸±©Åù;Ú÷ž<€Sô°’½Ïý„®Ðž°ç/ŒÁ(à €jd ™~»¿üÎ÷º«ÿí¿sÍ3fZnÖ­ Ÿ{­2'ó01ÐÌOMœì}»aEÇf^Ï%ýË‹W,«Š•Á'ë3îÙü¤Á»ç\}s§‚jgM¿*˜–mlº:›Ï/£A]å²ù«hDó]>3‹FáÿéwÈr‘!—~áßÎvÑÿýÓwö®ìÚé·=\îϸáWé;ü½™¡ìÞOn;|€Ú/ÙeÂ'Ìü“64.X0ùk4ûp%¶DnpÐí§³GwmO>,•Œ` Ô%ó¯Yã–ßýëîò›éâw:í/Iœ²fi©$ûš°-Õ‹L˜€—4^BV?äÈüãDüä’Ÿ<øžZLþuù&©ÂAUÅ€yá_ìZÔ¼‰ÞÛ¿U)žø©‚{~ún#\) ÔMS¦º+×ßM§ùݵ^qíÄ’žð ã#s•¯¹:IèŒÓ—–^NÛ‹©Ø¾Î ÒY€g÷ :³nî$UGï¹±JÕLä#‘Ïgvn|ð tÅ%ßZ²" ßýÐöÝŸw¹Ÿ1ÂÀ™VzôöŠ»ïqWÞþ.Ç“Íûœˆ“ÄÌÖz*>IÐÉ©yiµ.@V˜½âK'ö´2ТmÏÓ÷Ø¿5ûúµôu,``tªj໺cÓƒ¿CW‡~‘äF¯ï²—îÖ¶ÿç?u§èñ§XÀ1|óª+n½Ó-}û»ŸîçäëþOØ û‰ƒ÷É*®ó"íRQM^í¥½—¾ãþÓ™+wÑÔ}—ÄltÕ þuòš ÜÅØœ9|Ðí£‡ uÓÓ×°€0pé00窕îêóîò[ît“¦ÏУp>%çQ'†ñGôã?~1?œýýY×\ÿ‡ÆÊe ª'<˜]ÿbnÎ }›:z[¹ƒ»X<_pt÷÷úÖ_à¹K&ìÁ@3ÀϨ¸â¶wº«Þñ^7ÏNñ'ßÙÛú¹&vä_ ÀiºNjÃŒÎþGq‘_¿©j kU?`ùÖÁCÍ=›húÍ›¬øÂd=¼m«;´óWò€˜ŠwÁsšš§ºËÞü6wåÛîr ×Ýâí™5r–žWIâ×Óó¼–FêKÒ®°Döv:HðÉ„‚‡Bz^³±ã}Љ¶K›T%2]Ý?ühv0»aæªUüûv,`ࢨ‰ €áËü=úôD‰YøƒÝ~ð5÷:ýt°ëÔñ‰é¢‚0p^ ðü—ßòvwéßp³k ¤¯ÉZ“sjà“5{æ%r(´%Gö‰>=QgåOòŽžií6Òt>?ûªU¯³,``,¨¹ þùèNÛS¾H²ÿ8–d”ë‹?ø§^Õ|éÇÂÀ@u0ÐØÜìÞx«»ò­ïtKn¹Ã55OIpÉ£rŸ¼¹ÿ´gñ‰ß—^'0eœâeÔ,>=P|‘Oª9¯ÙÖ|åÝ0µlÎæ>=}ÅŠâ+00 ÔäÀóðòÆûéù™Mô¹iõº‰*ùWGvms§ìw|ñ 0*Ë@Ëü…ôþíî²›ow ×¼É5L²o }R–2•h9­k'¹MªqR¦¦ÈFZ }ôì,òÉAdàñªP×ïrã›ÙááÏL_~í6QcÆ‘šž0//}ù³mÃ_£ÐÝãÈÓy»Î ô»û÷º#;_Â-†Ï›5Á@ù d›šÜâu·Ñãvow‹n|‹kY°XHÒ6VGßšh%9§’?Ã-9lðÃÉœM $@–ô鉂:Np*Ëš}¨Ÿ3dóÅ7ôè´¥«ŽŠc¬À@¨ù s$ZÔü'ôÉû'äÁÂmÅø3G¸#/ïpí|V ³…Aå2Ð4uª[¼öV9Ê_LGûSZg‹‹$ÁZ‚f­&W*¼Ž®4H©‰ÚÚL¯…×qIÿòÒRÖSM ­‹àã™Mëqb)Ƥ9M}x$;”ý«éË—ãb"a«J2POØî/?xÍÐp~ ªâ÷ ð}H•ôc]^zzܱ=;ÝñÝ;ßr çÇ@¶¡ÑÍY±Ê- Sú|_Ý™¯Žüý’{HòÖâ“qÐSº•¬¥$†r»éµµêÅ!#ŒªS;“0êÐL"9ã^Ïäò_èiøÊüù«ø±µXÀÀ„0PWfPž*¸°ù?ÑÇí~+zá¢-h~(·¼Hæ‹OîÛãNîÅõvb2PÄ—4|ûÝÙt'¾o¼‰’>ý¯~“ã«ø-› 7!ñ²¼49…I‘³'ÉÌŠµ$­E¤×H V¼á|< á}òWî˜ú—.*.“w?wnø¯ZNt|7ð±í…bB¨» €gsûWžÍ Ò$ ÿ1¯›R&6ÐY€vƒô}g;é¢Á}îä«»]ÇÑÃÒ=É@¶±Q’üüëntó¯»ÁÍ¿ö®‘®Ø/\Ò ZGHül—`9 ‹FÊTâ757(D“tâWm¥ÕûPç)Àû €”jkÁÛ©Ü4<˜ùêŒeËv± ,` Z¨Û €'xǦûïÉä3ÿƒäE^WѲhÀÑyB Ôg¬ìn?åNÐDà䫯¸ž3¸ÉWE·‚UŒL¶Áµ^¹Üµ­º‘Žò×¹6:µßÿñ«ÔÀO¸ì£¯øÂA¾ÙÐéC¯¹áÁÁ v¡ÀÀØ10uö<7gåj7ïZú_y½›»âº’GøeEô‰—Œ’¤Ï|B¶z}Å—Ú.’÷åËóMþâ‚<˜%z oþ{äâ‘–Ë®|‚&÷¸ò—yÂRµ \ÏþîGî_–kÈ|†äÒÖëǵôNÿ\÷Ê“‚Ю2ë¤É& ÃôëÎÇÜ)úª ýµ}ôÓBýMcCþ¯§,\ºß÷%¨v.© €ßÛ¿tÿ ÙLæ~ʱïòºq+ÃNN“¿ž0Ú}²÷˜¨LŸ-àÞéd¡Ÿ®8uÎЂŽ#Ý@7."·mÇ#2À§òg,¾œ.Ø{%|>²¿Þñct³“ø }ÿþöæ¥w3#N ̬8Ñ{–|YL%e㶸®`…Çz_§R^Zšc*´] ­›®~ÚûmëW[]þ# ŽöýæAY3 ”þdÖL÷/®£Û7~îÍY—y>Ä·_œ§sXKb'ªå¥¥ JØFö¨ú_„#Ì`oë»6³tiŸFÇ Ô&çúÖæ¨Êè5}¨3»¾üà½ôÙþ,™-/Ãôü¡~çHeêÈž=°Î·›Ì:©ò’ë"šNd­+(¶Ï¸Üà€ü¢€'|† ãè!Çw'ÄÎÅÕO_¸ØÍZºÂÍ¢ õZ—^Må ×BÉÞ¿'Ž“w ÕACØû×Ç èB\‘¡·ðe*㇃rnM%|QDØPPE‰_½ŒvÔïÝ;~ÜýÃ7¿åþ÷?|ý¼ûVo¡ÿõ\Áj™¢d-æbúÎwl[4åC™|þ¿‘ŸUã«È6ì‰n~‰lÔóÎ4´“¥¯³^ÀìMŒÄmÀ¦pÞNý+ž×t-2ýõži§û£ÿã®›îCÐuò¨ÞƒÀïÅ3V— |s–ù ÜôE—Óiü+\ëeWR²_îf^¾Ìñãrã÷p"oU{¿²"zï‰( «E0Q{lÀ$y'bÉZ”ÂÓí¥Þ»’ø5ûk5Ì’#ñBzyY»¾®egçY÷½üÀýã?}Ç=ñã'ÝÐPê¬Úr³>Ý!H` ö(ü¸ÖÞƸÇ|F`禇ÞGÏßþcºqÇMcæ^v„D·¼´TA7A©ÄαÃdA`´Ëô;T_zLÙ·ú;X“9žºÑ3]'޹³2) ÉÔ¹\?ÎŒÙ6Ÿ@G|C)³æP¢_ä¦Ó=ò§/^âf,¼Âͤïí§-¼LOßG*ïëyáûˆÕQ{0bµê“V«% ó±}¤NUK%z°œíO $b¨•Lül. –âtž¥¤ÿÄù¿ûá“O¹¾‘? [ÈÅzöƒ Ô2£}xgMhqçE;ô;;*% ó´ò;Nßθîõ¼ÃY¤2 (À«;^3^±E“i╬¥ö‰v‹ý]gé>í®—îKÐK÷#è¡’ïQÐÛqš¾JøXUÍt|þ™ÝÔ9óÜ4ºÚ¾¥m‘&ü6®/t vAžlîx;SÿSï?zgÚ[#©p›Új-©‹>˜zCS˜£´6-éûÔ;¡Œr¹"E¨NR²¡¨gD¥zNúßýþ’ôôÔ–Ñ’~ÜÁ-$¬¨ƒZd àY‹Cÿ>ïúÒƒ7å³2ø5Š–½ ˆÉžU÷§"ýTÉš{,ëÃΗ°¦Ø.m§AxØqÕ4êËÛ[ õ÷Iñ¼æØý]2)èm?-“žôÓ³ xÒÀmÃéÓ¤b†Uù ðÏé&Ïl¥ÝÌqÍ3f¹)s温³(ÑÏåd?_~3%~Ið´]t³Úv³mÉQÃû$èü¶ ï}(8ê(ù î|E@Š!•EåŠ-¡b˜™µÁ©™°*©–¬YúNÚRÉ=Q'õyd|’£}éHŸNï÷ JúÿOôûËŸØn!GëÙ0PË œëóWËcó¾óÆrùüÇiòr>«ì²$Ê奥 ºÂÛï(­ ‰Y`Öã¨#‚ ²ù&9ÙQ«ï„ÕM"[‡«ìP†§ÕMö2Ö3L±¹>štºþžn¹™ÿD±¿«Ã tuÑmi¢Ð}V~¶8Ôßçò9ºgÊ%°ð©øI-ÓéÝÓ~š›4þIæúäiªŸ<’ü¬Ù”ô©¤£ú&Â*£¿RMËž÷°Mü6’m“ÞWA¯~Â{ƒ¡ÞÖ—bN‚†%-¨Ú÷‹¥€ •`*•”}ºé¼¥‘&ô¡”%¡Bê¼;|ä¨{ì?tß}ü ÷äÓ?qôã.n!a}¬@ Ô"#|Rkq(•ëó‡žrvêÀ½´Ãûm"ðüŸ<èw€TÊÎWØ·MÀ:ßÎCáºÉ+²âÖÛP©îxͶâĪ,‹"è‹ì¹GŒñvÖ5ó¶Zªm„5›Ä§÷)ÑqŒüPÎ ÒD 7ÐëûúÝP/]ÐG%×û©e*égŽCô+†üpŽÎ0ääWìi°¯‡ ‘‡ù­¼`E)+í+W“ZÒקнç3ɉlCÝ­Ž/†s®iJ‹ðÒ0i²|oÎ?}k˜DmDÌdzHM#ý75O•Öð£j›¦P‚—’ôdÛHu]˜_ª)¡\±—–"0зS©ýŽÚUAúBo(Å7;e·†1¯Z¨É€R„~¨2-².øAP‰k‹qÚ”Ī ª[rgÛçCE<òã··n;á¾÷ø×Ý??þ˜ÛúÒ6:IÙ]PÜ`´…j냄 ¨QRÏÄvû•/?xÙ`nøÃÙLöwéTã’Q;všD;¿D¶M`maGí±T–Úá—ÆQto§4Žß s›„+Hb£méXÚ7uÉí*si-ªÁ4Œ‰ä€Û¨Mªi™ Õ”õRãiÕÛ3Á 2H„%ŒZ™N…Ä·z¿ëek ¢È!™E¶Q›â¹Í°Vj!ë$&‚P»¼´4' žpê!jW{2xTJÌ&Ž‘ CÇÁr°Oê>š6[ iŽê9‹ÚÍŸ8¡U„Mù/ÑîU©²DÎßå30jïììwýxŸûþ÷»-?¥{btôÓ™§¿ ̘_غ…"¯çðXÀ@-3}½>îS¢ÓÄGÖú[KÜ”Ó/+~|½+e a ¬ä…Ï<ˆJÖ©¶ÀOÀªm oca‡Rd ChoÇ!œ¨ÅO‰MlköªRkú*{)ˆÏ&ã#ª*e$ªdecIZ ¾‹ Öÿbµh¢äžF$ »ö¶»ïÿhŸ{üÉ×Ü/þõ˜Š¿Z"X×ç1H“ ¢OwСr‘ ð3†²î^ÚÉÞG®nL¹ ;GÞyý²l3œì˜ÉÊcY_”"l —¶+Ú©3ÖbjÁ²ÔØÐ^‘ÎÚ´HëÕÊt"˜&Š!c'Y›yMÿ*D±•èµ™e©I[¿«`V*ÞÇŠüùxE>Ì&áœcŠ2 -~¬Þ·:â€ÞcÔ>ø±\$NyÛ‰"Ø««Ä_ ïãFñ´]Ö¤ì¼_q󮨤Ïf[41´~q!=Ø;¡†H/ÚD.jòV#6xÀ¹ËÓí}î_ž;äžyî°ûÉsÝË{Ú“Sûɼ èºÆàÜ´q‰2|j/QÆ{Øü]8ø~z@è½´Wº…âÙÞŸ¨——–*èæ Éï0­Ô}„ggÜæq<ª{ `!ÕwÀŠ›È6ø0{'6ڜȊeúuR†ø^/ÝâvQ¤lаâ&ÂF6RÕ‡q’¶ÑHâ,7ÁšRVÔ©*¬»æCQâkd¼´„~y^Rø(Nº/¾?l^“[¹C!jWEÚÆtÖ‘Ä.ÄNb‰_qí‚CÖjs(XP،ݿL ÿ…_§SúÇÜÏé'yûœM@TÃ`‚ˆGØš`À>Ñ5ÑWt’àû ìé9¸2ïnÍg2·Ñ¾w-íÚ¯er$ñÅ;mª';rª© ¥´x¬éÖëÙ@^Zª (K†ZÁÇ2›4Ö㤗¼*èkìŸ-Ó²iØHÿÕCÒq/+i×î'²d¯´Ðš+Ñ^ŠâvM6»0¹ð~¥qÅ}ÏÁ‚ /PçjíûâKÆÅvÞ%£å¥¥ÀÔé d¥J8ƒ˜wñ|„¶P >ƒ†|÷äÜÎWÚÝ®½|t’~†wFêGw««*[cPeÝ©*Âg»ªz…ΔÅÀŽÿó……Mù†ut;Û[Éð6Ê o¢½÷$v’žÐææ-N;rKoRgëEWHDË:¶Ó"¨oQ«¬~ W`gä_]š­v@|'}ó¾´,òÁ=V'IÿLúûG ¾/¥ü˜]É>¼÷ac £ã '¾m¥i»ûÅ6¼‘¼´´Á[“8 cSÉã[³¥Ç[[T;Ñç¶î<é^Ü~’’|‡$ú½û;Ü`…Oãû¾^H‰ À…°›K…ûô_*ý4ƹï«_hšA$0IDVÞ-²’£y*‘…]I‚j#‰)²ÑÉ£mNdo“ôÍðO޾d­:1·”A/.’ZcœÇjŒ€€¢£¢É,©Ââ&ý³ñ;ºù2?Á_A?YÔ¥pŒ‰^»C޼¯Ðd1XöcPPK°žÞ!·g§ÛûZ§Ñï #|þýP—÷V³%&5»éÐñ 0í%* !&Œ'ŸÜиäXÛJºUñê|ÆÑä sC&“_M©¥-d2K"ZÐZ3"õ™ëüÒRªs‹Z!N6¾ÍÊä^,Åžm´™×ôoX­Š : cCp± ýÐJðô-´™ÏëIxß³SÑúãí^@!&Kéq¥ÛC S›a°OÅŠúfnÙy0 Qy½x`85k=—Ë»£'zݾ×ϺW^ëp»÷u{¨äÄøhOY¿­Wǵ±Æ 6¶z91 D{Љé¢N,û6ÿÏÃù¦ëèz‚et¦`™Ëä—e]fY>“]FWÌò Ä'Mâö¶±äšOVT*‚ÖRáÒ4ÃãŽt^’ÛðK1b/UÓx¼/ÉíºRR=ÞJQz<•¢æµo·R!‘ž =ÞÛGvAé|,u)kvb±Ä¡vUƒ÷A°‰Ùú’ð¡ù¦‹ëOœês¯évw»×é_Ê#]t$ßíë©©S÷~ø[bp± ¾žð{¦z#Æv ¼öwÌljZ–Í4Ò„À]Eo–e.Ë*3™EäV¾RЄT¨H©Z3@Óø æuëõ!±©x XŒùöx_²žqºb`ˆ«qbíÜ÷ÑÀaÃs~eõSý‡€!.kBœ¢ Çú«‚@½Þ— ˸3gÜÑã}î %òCôøX¯;|¼Ç<¢2Ý Vö'vÚáê^cPÝÛ½›XÂînb»èµÈÀÁoýÍœ\c~Ë5.pnxEh£q,¢IBS^L%¶QŠ[DÉl†dŸm¥³ 3é9î33.?#Û™IJšá†IÎr=ßJ7@šI=¤Ò3Öe¦$î;½m5›Zaoã}ÇwÐÝÛëé±³¹¡!×ÙÝãÎvw»ŽÎ.w¶§Çuõ¶¹îÞfªRÛëêÎQ’ÔdO‰žä9ñ÷àh½ïBL*Á2bÔ*¥ŸY_«£A¿«’%÷Ý×KÛ{±Û÷ä·[³ÝM™á–žÉÙ\ÃTöטo¤‰C.;<Ü8)“ϵ¸}KËócò¼¶'Éä}#Uÿ쑯ܳ핽¿Ã>zúúèôùWÃÒEÉœïI?08Híýä&ï:ºÎ}U|㔹lÕÁ*` €je€jÝ2èWKï¸çL‘ò«.Ü–` €Úg [ûCÀÀ` €rÀ \Æ€` €0P `PC` €0P.˜”Ëð` €0ê€Lê`#b` €0Êe€r €0À@0€ @lD  €0À@¹ `P.cÀƒ0À¨0¨ƒˆ!€0À(—LÊe x0ÀuÀ&u°10Àå2€ @¹ŒÀ` À 6"†À` \0(—1àÁ` Ô˜ÔÁFÄÀ` ”Ë&å2<` €:`€:؈` €rÀ \Æ€` €0P `PC` €0P.˜”Ëð` €0ê€Lê`#b` €0Êe€r €0À@0€ @lD  €0À@¹ `P.cÀƒ0À¨0¨ƒˆ!€0À(—LÊe x0ÀuÀ&u°10Àå2ÐX®ð` ŒÂ@~й|ß(40ªƒLªc; uÂÀPß?ÖÉH0 0ê|Pï[ã` €0P‚LJ` €zg€zßÂ` € `P‚¨À` Ô;˜ÔûÆøÀ` ”`€¤@À` ÞÀ Þ·0ÆÀ` ˜” *0ÀõÎ&õ¾…1>0À%À )P0À¨w0¨÷-Œñ0À(Á&%H €0À@½3€ @½oaŒ €0À@ 0(A T` €0êLê} c|` €0J0€ @ R ` €0Pï `Pï[ã` €0P‚LJ` €zg€zßÂ` € `P‚¨À` Ô;õ>@Œ ŒÀÀK¤ß4BÔ``4vÖˆ60À` €0À` €0À` €0À` €0PI2ù|¾’ñ €0À¨ð3À*Øè` €J3€ @¥G<0ÀUÀ&U°Ð0À•f€J3Žx` €0ª€Lª`#  ` €0*Í&•fñÀ` T˜TÁF@À` TšL*Í8â0À¨0¨‚€.€0À¨4˜TšqÄ` €0P `P]` €0Pi0¨4ãˆÀ`  À  6ºÀ` Ò `PiÆ €0À@0€ @lt €0À@¥À ÒŒ#` €*`€*Øè` €J3€ @¥G<0ÀUÀ&U°Ð0À•f€J3Žx` €0ª€Lª`#  ` €0*Í&•fñÀ` T˜TÁF@À` TšL*Í8â0À¨0¨‚€.€0À¨4ÿ@«í1¿4IEND®B`‚icnV ¿€yabause-0.9.15/src/cocoa/YabauseGLView.m000644 001750 001750 00000011217 12755623101 021755 0ustar00guillaumeguillaume000000 000000 /* Copyright 2010, 2014 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "YabauseGLView.h" #include "peripheral.h" #include "vdp1.h" @interface YabauseGLView (InternalFunctions) /* These are nice to have, but not really necessary to things... */ - (float)width; - (float)height; @end @implementation YabauseGLView - (id)initWithFrame:(NSRect)frameRect { NSOpenGLPixelFormatAttribute attrs[] = { NSOpenGLPFAOpenGLProfile, (NSOpenGLPixelFormatAttribute)NSOpenGLProfileVersion3_2Core, NSOpenGLPFANoRecovery, NSOpenGLPFAColorSize, 32, NSOpenGLPFADepthSize, 32, NSOpenGLPFADoubleBuffer, 0 }; NSOpenGLPixelFormat *fmt; fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; if(fmt == nil) { [fmt release]; return nil; } if(!(self = [super initWithFrame:frameRect pixelFormat:fmt])) { [fmt release]; return nil; } _isFullscreen = NO; [fmt release]; return self; } - (void)toggleFullscreen { CGError err; CGDisplayFadeReservationToken token; err = CGAcquireDisplayFadeReservation(kCGMaxDisplayReservationInterval, &token); if(err == kCGErrorSuccess) { CGDisplayFade(token, 0.5, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, 1); } if(!_isFullscreen) { NSScreen *s = [NSScreen mainScreen]; NSRect dispRect = [s frame]; fsWindow = [[NSWindow alloc] initWithContentRect:dispRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES]; [fsWindow setLevel:NSMainMenuWindowLevel + 1]; [fsWindow setOpaque:YES]; [fsWindow setHidesOnDeactivate:YES]; oldFrame = [self frame]; dispRect.origin.x = dispRect.origin.y = 0; [self setFrame:dispRect]; [fsWindow setContentView:self]; [fsWindow makeKeyAndOrderFront:self]; } else { [self setFrame:oldFrame]; [window setContentView:self]; [fsWindow release]; fsWindow = nil; } if(err == kCGErrorSuccess) { CGDisplayFade(token, 0.5, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0, 0, 0, 0); CGReleaseDisplayFadeReservation(token); } if(VIDCore) VIDCore->Resize([self width], [self height], !_isFullscreen); _isFullscreen = !_isFullscreen; } - (BOOL)acceptsFirstResponder { return YES; } - (void)keyDown:(NSEvent *)event { if([[event charactersIgnoringModifiers] length] >= 1) { PerKeyDown([[event charactersIgnoringModifiers] characterAtIndex:0]); } } - (void)keyUp:(NSEvent *)event { if([[event charactersIgnoringModifiers] length] >= 1) { PerKeyUp([[event charactersIgnoringModifiers] characterAtIndex:0]); } } - (void)showWindow { [window makeKeyAndOrderFront:self]; } - (void)reshape { CGLContextObj cxt = CGLGetCurrentContext(); /* Make sure that the emulation thread doesn't attempt to do any OpenGL calls during the resize event, otherwise one of the two will crash. */ CGLLockContext(cxt); if(VIDCore) VIDCore->Resize([self width], [self height], !!_isFullscreen); CGLUnlockContext(cxt); [super reshape]; } - (void)drawRect:(NSRect)rect { CGLContextObj cxt = CGLGetCurrentContext(); /* Make sure that the emulation thread doesn't attempt to do any OpenGL calls during the flush to the screen. */ CGLLockContext(cxt); [[self openGLContext] flushBuffer]; CGLUnlockContext(cxt); } @end /* @implementation YabauseGLView */ @implementation YabauseGLView (InternalFunctions) - (float)width { return [self bounds].size.width; } - (float)height { return [self bounds].size.height; } @end /* @implementation YabauseGLView (InternalFunctions) */ yabause-0.9.15/src/cocoa/Yabause-Info.plist000644 001750 001750 00000002061 12755623101 022464 0ustar00guillaumeguillaume000000 000000 CFBundleDevelopmentRegion English CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile Yabause.icns CFBundleIdentifier org.yabause.yabause.cocoa CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType APPL CFBundleSignature ???? CFBundleShortVersionString 0.9.15 LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} CFBundleVersion NSMainNibFile MainMenu NSPrincipalClass NSApplication NSHumanReadableCopyright Copyright © Yabause Team yabause-0.9.15/src/cocoa/YabauseButtonFormatter.h000644 001750 001750 00000002431 12755623101 023750 0ustar00guillaumeguillaume000000 000000 /* Copyright 2011 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef YabauseButtonFormatter_h #define YabauseButtonFormatter_h #import @interface YabauseButtonFormatter : NSFormatter { } - (NSString *)stringForObjectValue:(id)obj; - (BOOL)getObjectValue:(id *)obj forString:(NSString *)str errorDescription:(NSString **)err; - (BOOL)control:(NSControl*)control textView:(NSTextView*)textView doCommandBySelector:(SEL)commandSelector; @end /* @interface YabauseButtonFormatter */ #endif /* !YabauseButtonFormatter_h */ yabause-0.9.15/src/cocoa/vidgcd.h000644 001750 001750 00000001615 12755623101 020542 0ustar00guillaumeguillaume000000 000000 /* Copyright 2010 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef VIDGCD_H #define VIDGCD_H #include "vdp1.h" #define VIDCORE_GCD 10 extern VideoInterface_struct VIDGCD; #endif yabause-0.9.15/src/cocoa/YabauseButtonFormatter.m000644 001750 001750 00000006207 12755623101 023762 0ustar00guillaumeguillaume000000 000000 /* Copyright 2011 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "YabauseButtonFormatter.h" #include @implementation YabauseButtonFormatter - (NSString *)stringForObjectValue:(id)obj { if(![obj isKindOfClass:[NSString class]]) { return nil; } if([obj length] >= 1) { return [obj substringToIndex:1]; } else { return [NSString string]; } } - (BOOL)getObjectValue:(id *)obj forString:(NSString *)str errorDescription:(NSString **)err { if(obj) { if([str length] >= 1) { *obj = [NSString stringWithString:[str substringToIndex:1]]; } else { *obj = [NSString string]; } } return YES; } - (BOOL)isPartialStringValid:(NSString **)partialStringPtr proposedSelectedRange:(NSRangePointer)proposedSelRangePtr originalString:(NSString *)origString originalSelectedRange:(NSRange)origSelRange errorDescription:(NSString **)error { NSString *rs = [[*partialStringPtr substringToIndex:1] uppercaseString]; *partialStringPtr = rs; *proposedSelRangePtr = NSMakeRange(0, [rs length]); return NO; } - (BOOL)control:(NSControl*)control textView:(NSTextView*)textView doCommandBySelector:(SEL)commandSelector { BOOL result = NO; /* handle all the fun special cases... */ if(commandSelector == @selector(insertNewline:)) { [textView insertText:@"\u23CE"]; result = YES; } else if(commandSelector == @selector(insertTab:)) { [textView insertText:@"\u21E5"]; result = YES; } else if(commandSelector == @selector(cancelOperation:)) { [textView insertText:@"\u241B"]; result = YES; } else if(commandSelector == @selector(deleteBackward:)) { [textView insertText:@"\u232B"]; result = YES; } else if(commandSelector == @selector(moveLeft:)) { [textView insertText:@"\u2190"]; result = YES; } else if(commandSelector == @selector(moveUp:)) { [textView insertText:@"\u2191"]; result = YES; } else if(commandSelector == @selector(moveRight:)) { [textView insertText:@"\u2192"]; result = YES; } else if(commandSelector == @selector(moveDown:)) { [textView insertText:@"\u2193"]; result = YES; } return result; } @end /* @implementation YabauseButtonFormatter */ yabause-0.9.15/src/cocoa/English.lproj/000755 001750 001750 00000000000 12757373644 021664 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/cocoa/English.lproj/InfoPlist.strings000644 001750 001750 00000000054 12755623101 025165 0ustar00guillaumeguillaume000000 000000 /* Localized versions of Info.plist keys */ yabause-0.9.15/src/cocoa/English.lproj/MainMenu.xib000644 001750 001750 00000773644 12755623101 024106 0ustar00guillaumeguillaume000000 000000 1060 14F27 7706 1348.17 758.70 com.apple.InterfaceBuilder.CocoaPlugin 7706 NSBox NSButton NSButtonCell NSCustomObject NSCustomView NSImageCell NSImageView NSMenu NSMenuItem NSPopUpButton NSPopUpButtonCell NSTabView NSTabViewItem NSTextField NSTextFieldCell NSView NSWindowTemplate com.apple.InterfaceBuilder.CocoaPlugin PluginDependencyRecalculationVersion NSApplication FirstResponder NSApplication NSFontManager Main Menu Yabause 2147483647 NSImage NSMenuCheckmark NSImage NSMenuMixedState submenuAction: Yabause About Yabause 2147483647 YES YES 2147483647 Preferences… , 1048576 2147483647 YES YES 2147483647 Services 2147483647 submenuAction: Services _NSServicesMenu YES YES 2147483647 Hide Yabause h 1048576 2147483647 Hide Others h 1572864 2147483647 Show All 2147483647 YES YES 2147483647 Quit Yabause q 1048576 2147483647 _NSAppleMenu File 2147483647 submenuAction: File Run CD-ROM o 1048576 2147483647 Run Image O 1048576 2147483647 Run BIOS o 1572864 2147483647 Emulation 2147483647 submenuAction: Emulation Pause p 1048576 2147483647 Reset r 1048576 2147483647 YES YES 2147483647 Enable Frameskip 2147483647 1 View 2147483647 submenuAction: View Show Framerate 2147483647 7 Fullscreen f 1048576 2147483647 YES YES 2147483647 Layers 2147483647 submenuAction: Layers VDP1 2147483647 1 1 NBG0 2147483647 1 2 NBG1 2147483647 1 3 NBG2 2147483647 1 4 NBG3 2147483647 1 5 RBG0 2147483647 1 6 Window 2147483647 submenuAction: Window Minimize m 1048576 2147483647 Zoom 2147483647 YES YES 2147483647 Bring All to Front 2147483647 _NSWindowsMenu Help 2147483647 submenuAction: Help Yabause Help ? 1048576 2147483647 _NSHelpMenu _NSMainMenu 271 2 {{168, 237}, {320, 224}} 1685585920 Yabause NSWindow {320, 224} 274 274 {320, 224} YabauseGLView {320, 224} {{0, 0}, {1280, 777}} {320, 246} {10000000000000, 10000000000000} YES YabauseController 7 2 {{162, 79}, {484, 400}} -193462272 Preferences NSPanel 256 268 public.item {{13, 10}, {458, 384}} 1 274 12 274 268 {{18, 36}, {296, 22}} YES -1804599231 272630784 YES 13 1044 Not Set YES 6 System textBackgroundColor 3 MQA 6 System textColor 3 MAA NO 1 268 {{316, 30}, {96, 32}} YES 67108864 134217728 Browse -2038284288 129 200 25 NO 268 {{16, 12}, {163, 18}} YES -2080374784 0 Enable BIOS Emulation 1211912448 2 NSImage NSSwitch NSSwitch 200 25 NO {{1, 1}, {424, 68}} {{6, 254}, {426, 84}} {0, 0} 67108864 0 BIOS YES 11 3100 6 System labelColor 1 0 2 NO 12 274 268 {{10, 10}, {262, 26}} YES -2076180416 2048 109199360 129 400 75 Auto-detect 2147483647 1 _popUpItemAction: YES OtherViews Japan (NTSC) 2147483647 _popUpItemAction: 1 Asia (NTSC) 2147483647 _popUpItemAction: 2 North America (NTSC) 2147483647 _popUpItemAction: 4 Central/South America (NTSC) 2147483647 _popUpItemAction: 5 Korea (NTSC) 2147483647 _popUpItemAction: 6 Asia (PAL) 2147483647 _popUpItemAction: 10 Europe/Australia (PAL) 2147483647 _popUpItemAction: 12 Central/South America (PAL) 2147483647 _popUpItemAction: 13 1 YES YES 2 NO {{1, 1}, {424, 44}} {{6, 124}, {426, 60}} {0, 0} 67108864 0 Region 1 0 2 NO 12 274 268 {{18, 14}, {296, 22}} YES -1804599231 272630784 Not Set YES NO 1 268 {{316, 8}, {96, 32}} YES 67108864 134217728 Browse -2038284288 129 200 25 NO {{1, 1}, {424, 46}} {{6, 188}, {426, 62}} {0, 0} 67108864 0 MPEG ROM 1 0 2 NO 12 274 268 {{18, 36}, {296, 22}} YES -1804599231 272630784 Not Set YES NO 1 268 {{316, 30}, {96, 32}} YES 67108864 134217728 Browse -2038284288 129 200 25 NO 268 {{16, 12}, {296, 18}} YES 67108864 0 Enable CD Block Low-level Emulation (Slow) 1211912448 2 200 25 NO {{1, 1}, {424, 68}} {{6, 36}, {426, 84}} {0, 0} 67108864 0 SH1 Rom 1 0 2 NO {{10, 33}, {438, 338}} General 6 System controlColor 3 MC42NjY2NjY2NjY3AA 2 274 12 274 268 {{15, 10}, {262, 26}} YES -2076180416 2048 109199360 129 400 75 Software Video Core 1048576 2147483647 1 _popUpItemAction: 2 YES OtherViews Disable Video 2147483647 _popUpItemAction: 1 YES YES 2 NO {{1, 1}, {424, 44}} {{6, 278}, {426, 60}} {0, 0} 67108864 0 Video Core 1 0 2 NO 12 274 268 {{15, 10}, {262, 26}} YES -2076180416 2048 109199360 129 400 75 Core Audio Sound Core 1048576 2147483647 1 _popUpItemAction: 3 YES OtherViews Disable Sound 1048576 2147483647 _popUpItemAction: 1 YES YES 2 NO {{1, 1}, {424, 44}} {{6, 214}, {426, 60}} {0, 0} 67108864 0 Sound Core 1 0 2 NO 268 {{7, 194}, {157, 18}} _NS:9 YES -2080374784 268435456 Enable Multithreading _NS:9 1211912448 2 200 25 NO 268 {{7, 174}, {253, 18}} _NS:9 YES -2080374784 268435456 Enable Higher Quality Sound (Slower) _NS:9 1211912448 2 200 25 NO {{10, 33}, {438, 338}} Video/Sound Item 2 256 12 274 268 {{18, 14}, {296, 22}} YES -1804599231 272630784 Not Set YES NO 1 268 {{316, 8}, {96, 32}} YES 67108864 134217728 Browse -2038284288 129 200 25 NO {{1, 1}, {424, 46}} {{6, 276}, {426, 62}} {0, 0} 67108864 0 Internal Memory (BRAM) 1 0 2 NO 12 274 268 {{15, 52}, {262, 26}} YES -2076180416 2048 109199360 129 400 75 None 1048576 2147483647 1 _popUpItemAction: YES OtherViews Pro Action Replay 1048576 2147483647 _popUpItemAction: 1 Backup RAM (4 Mbit) 1048576 2147483647 _popUpItemAction: 2 Backup RAM (8 Mbit) 2147483647 _popUpItemAction: 3 Backup RAM (16 Mbit) 2147483647 _popUpItemAction: 4 Backup RAM (32 Mbit) 2147483647 _popUpItemAction: 5 DRAM (8 Mbit) 2147483647 _popUpItemAction: 6 DRAM (32 Mbit) 2147483647 _popUpItemAction: 7 Netlink 2147483647 _popUpItemAction: 8 ROM (16 Mbit) 2147483647 _popUpItemAction: 9 1 YES YES 2 NO 268 {{18, 14}, {296, 22}} YES -1267728319 272630784 No file required for the selected cartridge YES NO 1 268 {{316, 8}, {96, 32}} YES 603979776 134217728 Browse -2038284288 129 200 25 NO {{1, 1}, {424, 86}} {{6, 170}, {426, 102}} {0, 0} 67108864 0 Cartridge 1 0 2 NO {{10, 33}, {438, 338}} Memory Item 3 256 12 {{10, 7}, {418, 324}} 1 256 268 Apple PDF pasteboard type Apple PICT pasteboard type Apple PNG pasteboard type NSFilenamesPboardType NeXT Encapsulated PostScript v1.2 pasteboard type NeXT TIFF v4.0 pasteboard type {{14, 14}, {370, 264}} YES 134217728 33554432 NSImage controller 0 0 3 NO NO YES 268 {{292, 177}, {17, 18}} 12 YES -2080374784 134217728 Z -2033434624 160 400 75 NO 268 {{263, 164}, {17, 18}} 11 YES -2080374784 134217728 Y -2033434624 160 400 75 NO 268 {{237, 145}, {17, 18}} 10 YES -2080374784 134217728 X -2033434624 160 400 75 NO 268 {{278, 130}, {17, 18}} 8 YES -2080374784 134217728 B -2033434624 160 400 75 NO 268 {{314, 145}, {17, 18}} 9 YES -2080374784 134217728 C -2033434624 160 400 75 NO 268 {{248, 210}, {67, 18}} 4 YES -2080374784 134217728 R Trigger -2033434624 160 400 75 NO 268 {{102, 162}, {21, 18}} YES -2080374784 134217728 ↑ -2033434624 160 400 75 NO 268 {{103, 117}, {21, 18}} 2 YES -2080374784 134217728 ↓ -2033434624 160 400 75 NO 268 {{125, 139}, {21, 18}} 1 YES -2080374784 134217728 → -2033434624 160 400 75 NO 268 {{81, 139}, {21, 18}} 3 YES -2080374784 134217728 ↠-2033434624 160 400 75 NO 268 {{81, 210}, {65, 18}} 5 YES -2080374784 134217728 L Trigger -2033434624 160 400 75 NO 268 {{180, 111}, {38, 18}} 6 YES -2080374784 134217728 Start -2033434624 160 400 75 NO 268 {{248, 111}, {17, 18}} 7 YES -2080374784 134217728 A -2033434624 160 400 75 NO {{10, 33}, {398, 278}} Controller 1 2 256 268 Apple PDF pasteboard type Apple PICT pasteboard type Apple PNG pasteboard type NSFilenamesPboardType NeXT Encapsulated PostScript v1.2 pasteboard type NeXT TIFF v4.0 pasteboard type {{14, 14}, {370, 264}} YES 134217728 33554432 0 0 3 NO NO YES 268 {{292, 177}, {17, 18}} 25 YES -2080374784 134217728 Z -2033434624 160 400 75 NO 268 {{263, 164}, {17, 18}} 24 YES -2080374784 134217728 Y -2033434624 160 400 75 NO 268 {{237, 145}, {17, 18}} 23 YES -2080374784 134217728 X -2033434624 160 400 75 NO 268 {{278, 130}, {17, 18}} 21 YES -2080374784 134217728 B -2033434624 160 400 75 NO 268 {{314, 145}, {17, 18}} 22 YES -2080374784 134217728 C -2033434624 160 400 75 NO 268 {{248, 210}, {67, 18}} 17 YES -2080374784 134217728 R Trigger -2033434624 160 400 75 NO 268 {{102, 162}, {21, 18}} 13 YES -2080374784 134217728 ↑ -2033434624 160 400 75 NO 268 {{103, 117}, {21, 18}} 15 YES -2080374784 134217728 ↓ -2033434624 160 400 75 NO 268 {{125, 139}, {21, 18}} 14 YES -2080374784 134217728 → -2033434624 160 400 75 NO 268 {{81, 139}, {21, 18}} 16 YES -2080374784 134217728 ↠-2033434624 160 400 75 NO 268 {{81, 210}, {65, 18}} 18 YES -2080374784 134217728 L Trigger -2033434624 160 400 75 NO 268 {{180, 111}, {38, 18}} 19 YES -2080374784 134217728 Start -2033434624 160 400 75 NO 268 {{248, 111}, {17, 18}} 20 YES -2080374784 134217728 A -2033434624 160 400 75 NO {{10, 33}, {398, 278}} Controller 2 0 YES YES {{10, 33}, {438, 338}} Input 0 YES YES {484, 400} {{0, 0}, {1280, 777}} {10000000000000, 10000000000000} YES YabausePrefsController 17 2 {{162, 364}, {220, 115}} -461897728 Button Assignment NSPanel 256 268 {{17, 78}, {186, 17}} YES 68157504 138413056 Current Assignment: 6 System controlTextColor NO 1 268 {{110, 12}, {96, 32}} YES 67108864 134217728 Cancel -2038284288 129 Gw 200 25 NO 268 {{14, 12}, {96, 32}} YES 67108864 134217728 OK -2038284288 129 DQ 200 25 NO 268 {{62, 48}, {96, 22}} YES -1805647807 138414080 YES NO 1 {220, 115} {{0, 0}, {1280, 777}} {10000000000000, 10000000000000} YES YabauseButtonFormatter delegate 1070 orderFrontStandardAboutPanel: 142 performMiniaturize: 37 arrangeInFront: 39 performZoom: 240 showHelp: 360 hide: 367 hideOtherApplications: 368 terminate: 369 unhideAllApplications: 370 delegate 897 window 853 view 855 toggleFullscreen: 858 toggle: 875 toggle: 876 toggle: 877 toggle: 878 toggle: 879 toggle: 880 toggle: 881 toggleFrameskip: 883 runCD: 884 runBIOS: 885 pause: 893 reset: 894 prefsPane 1048 showPreferences: 1049 prefs 1065 frameskip 1073 runISO: 1254 delegate 1078 delegate 1079 delegate 1076 delegate 1077 region 1051 mpegPath 1052 biosPath 1053 emulateBios 1054 videoCore 1055 soundCore 1056 cartType 1058 cartPath 1059 cartBrowse 1060 regionSelected: 1061 videoCoreSelected: 1062 soundCoreSelected: 1063 cartSelected: 1064 bramBrowse: 1066 cartBrowse: 1067 biosBrowse: 1068 mpegBrowse: 1069 bramPath 1072 biosToggle: 1074 buttonAssignment 1115 buttonSelect: 1120 prefsPane 1121 buttonSetOk: 1128 buttonSetCancel: 1129 buttonBox 1134 buttonSelect: 1227 buttonSelect: 1228 buttonSelect: 1229 buttonSelect: 1230 buttonSelect: 1231 buttonSelect: 1232 buttonSelect: 1233 buttonSelect: 1234 buttonSelect: 1235 buttonSelect: 1236 buttonSelect: 1237 buttonSelect: 1238 buttonSelect: 1239 buttonSelect: 1240 buttonSelect: 1241 buttonSelect: 1242 buttonSelect: 1244 buttonSelect: 1245 buttonSelect: 1246 buttonSelect: 1247 buttonSelect: 1248 buttonSelect: 1249 buttonSelect: 1250 buttonSelect: 1251 buttonSelect: 1252 threadsToggle: 1257 enableThreads 1258 newScsp 1261 scspToggle: 1262 cdbLLE 1273 cdbToggle: 1274 sh1Browse: 1275 sh1Path 1276 delegate 1137 formatter 1136 delegate 1272 0 -2 File's Owner -1 First Responder -3 Application 29 19 56 103 83 81 72 106 111 57 58 134 150 136 144 129 143 236 131 149 145 130 24 92 5 239 23 371 843 844 846 847 848 854 882 856 886 887 864 865 866 869 870 871 872 873 859 849 889 890 891 892 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 917 916 915 918 919 920 921 922 923 924 925 926 927 928 929 931 933 934 935 936 937 938 940 941 942 945 943 944 946 947 948 949 952 950 951 953 954 965 966 967 968 969 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1044 1045 1046 1047 1050 1109 1110 1111 1112 1124 1125 1126 1127 1132 1133 1135 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1253 1255 1256 1259 1260 1263 1264 1265 1266 1267 1268 1269 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{477, 639}, {220, 115}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{257, 623}, {320, 224}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{329, 203}, {484, 400}} com.apple.InterfaceBuilder.CocoaPlugin InitialTabViewItem InitialTabViewItem com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin InitialTabViewItem InitialTabViewItem com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin 1276 YabauseButtonFormatter NSFormatter IBProjectSource ../YabauseButtonFormatter.h YabauseController NSObject id id id id id id id id id pause: id reset: id runBIOS: id runCD: id runISO: id showPreferences: id toggle: id toggleFrameskip: id toggleFullscreen: id NSMenuItem NSTextView NSWindow YabausePrefsController NSPanel YabauseGLView frameskip NSMenuItem logView NSTextView logWindow NSWindow prefs YabausePrefsController prefsPane NSPanel view YabauseGLView IBProjectSource ../YabauseController.h YabauseController id id id id id id id id id pause: id reset: id runBIOS: id runCD: id runISO: id showPreferences: id toggle: id toggleFrameskip: id toggleFullscreen: id IBProjectSource ../YabauseController.m YabauseGLView NSOpenGLView window NSWindow window window NSWindow IBProjectSource ../YabauseGLView.h YabausePrefsController NSObject id id id id id id id id id id id id id id id id biosBrowse: id biosToggle: id bramBrowse: id buttonSelect: id buttonSetCancel: id buttonSetOk: id cartBrowse: id cartSelected: id cdbToggle: id mpegBrowse: id regionSelected: id scspToggle: id sh1Browse: id soundCoreSelected: id threadsToggle: id videoCoreSelected: id NSTextField NSTextField NSPanel NSTextField NSButton NSTextField NSPopUpButton NSButton NSButton NSButton NSTextField NSButton NSPanel NSPopUpButton NSTextField NSPopUpButton NSPopUpButton biosPath NSTextField bramPath NSTextField buttonAssignment NSPanel buttonBox NSTextField cartBrowse NSButton cartPath NSTextField cartType NSPopUpButton cdbLLE NSButton emulateBios NSButton enableThreads NSButton mpegPath NSTextField newScsp NSButton prefsPane NSPanel region NSPopUpButton sh1Path NSTextField soundCore NSPopUpButton videoCore NSPopUpButton IBProjectSource ../YabausePrefsController.h YabausePrefsController id id id id id id id id id id id id id id id id biosBrowse: id biosToggle: id bramBrowse: id buttonSelect: id buttonSetCancel: id buttonSetOk: id cartBrowse: id cartSelected: id cdbToggle: id mpegBrowse: id regionSelected: id scspToggle: id sh1Browse: id soundCoreSelected: id threadsToggle: id videoCoreSelected: id IBProjectSource ../YabausePrefsController.m NSActionCell NSCell IBFrameworkSource AppKit.framework/Headers/NSActionCell.h NSApplication NSResponder IBFrameworkSource AppKit.framework/Headers/NSApplication.h NSBox NSView IBFrameworkSource AppKit.framework/Headers/NSBox.h NSButton NSControl IBFrameworkSource AppKit.framework/Headers/NSButton.h NSButtonCell NSActionCell IBFrameworkSource AppKit.framework/Headers/NSButtonCell.h NSCell NSObject IBFrameworkSource AppKit.framework/Headers/NSCell.h NSControl NSView IBFrameworkSource AppKit.framework/Headers/NSControl.h NSFontManager NSObject IBFrameworkSource AppKit.framework/Headers/NSFontManager.h NSFormatter NSObject IBFrameworkSource Foundation.framework/Headers/NSFormatter.h NSImageCell NSCell IBFrameworkSource AppKit.framework/Headers/NSImageCell.h NSImageView NSControl IBFrameworkSource AppKit.framework/Headers/NSImageView.h NSMenu NSObject IBFrameworkSource AppKit.framework/Headers/NSMenu.h NSMenuItem NSObject IBFrameworkSource AppKit.framework/Headers/NSMenuItem.h NSMenuItemCell NSButtonCell IBFrameworkSource AppKit.framework/Headers/NSMenuItemCell.h NSOpenGLView NSView IBFrameworkSource AppKit.framework/Headers/NSOpenGLView.h NSPanel NSWindow IBFrameworkSource AppKit.framework/Headers/NSPanel.h NSPopUpButton NSButton IBFrameworkSource AppKit.framework/Headers/NSPopUpButton.h NSPopUpButtonCell NSMenuItemCell IBFrameworkSource AppKit.framework/Headers/NSPopUpButtonCell.h NSResponder NSObject IBFrameworkSource AppKit.framework/Headers/NSResponder.h NSTabView NSView IBFrameworkSource AppKit.framework/Headers/NSTabView.h NSTabViewItem NSObject IBFrameworkSource AppKit.framework/Headers/NSTabViewItem.h NSText NSView IBFrameworkSource AppKit.framework/Headers/NSText.h NSTextField NSControl IBFrameworkSource AppKit.framework/Headers/NSTextField.h NSTextFieldCell NSActionCell IBFrameworkSource AppKit.framework/Headers/NSTextFieldCell.h NSTextView NSText IBFrameworkSource AppKit.framework/Headers/NSTextView.h NSView NSResponder IBFrameworkSource AppKit.framework/Headers/NSView.h NSWindow NSResponder IBFrameworkSource AppKit.framework/Headers/NSWindow.h 0 IBCocoaFramework NO com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 YES 3 {12, 12} {10, 2} {15, 15} {621, 376} yabause-0.9.15/src/cocoa/YabausePrefsController.m000644 001750 001750 00000031732 12755623101 023747 0ustar00guillaumeguillaume000000 000000 /* Copyright 2010 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "YabausePrefsController.h" #include "cs0.h" #include "vidogl.h" #include "vidsoft.h" #include "scsp.h" #include "smpc.h" #include "sndmac.h" #include "PerCocoa.h" @implementation YabausePrefsController - (void)awakeFromNib { _cartType = CART_NONE; _region = REGION_AUTODETECT; _soundCore = SNDCORE_MAC; _videoCore = VIDCORE_SOFT; _prefs = [[NSUserDefaults standardUserDefaults] retain]; /* Fill in all the settings. */ if([_prefs objectForKey:@"BIOS Path"]) { [biosPath setStringValue:[_prefs stringForKey:@"BIOS Path"]]; } else { [_prefs setObject:@"" forKey:@"BIOS Path"]; } if([_prefs objectForKey:@"Emulate BIOS"]) { [emulateBios setState:[_prefs boolForKey:@"Emulate BIOS"] ? NSOnState : NSOffState]; } else { [_prefs setBool:YES forKey:@"Emulate BIOS"]; } if([_prefs objectForKey:@"SH1 Rom Path"]) { [sh1Path setStringValue:[_prefs stringForKey:@"SH1 Rom Path"]]; } else { [_prefs setObject:@"" forKey:@"SH1 Rom Path"]; } if([_prefs objectForKey:@"Enable CD Block LLE"]) { [cdbLLE setState:[_prefs boolForKey:@"Enable CD Block LLE"] ? NSOnState : NSOffState]; } else { [_prefs setBool:NO forKey:@"Enable CD Block LLE"]; } if([_prefs objectForKey:@"Enable Higher Quality Sound"]) { [newScsp setState:[_prefs boolForKey:@"Enable Higher Quality Sound"] ? NSOnState : NSOffState]; } else { [_prefs setBool:YES forKey:@"Enable Higher Quality Sound"]; } if([_prefs objectForKey:@"Enable Multithreading"]) { [enableThreads setState:[_prefs boolForKey:@"Enable Multithreading"] ? NSOnState : NSOffState]; } else { [_prefs setBool:YES forKey:@"Enable Multithreading"]; } if([_prefs objectForKey:@"MPEG ROM Path"]) { [mpegPath setStringValue:[_prefs objectForKey:@"MPEG ROM Path"]]; } else { [_prefs setObject:@"" forKey:@"MPEG ROM Path"]; } if([_prefs objectForKey:@"BRAM Path"]) { [bramPath setStringValue:[_prefs objectForKey:@"BRAM Path"]]; } else { [_prefs setObject:@"" forKey:@"BRAM Path"]; } if([_prefs objectForKey:@"Cartridge Path"]) { [cartPath setStringValue:[_prefs objectForKey:@"Cartridge Path"]]; } else { [_prefs setObject:@"" forKey:@"Cartridge Path"]; } if([_prefs objectForKey:@"Cartridge Type"]) { _cartType = [_prefs integerForKey:@"Cartridge Type"]; if(_cartType != CART_NONE && _cartType != CART_DRAM8MBIT && _cartType != CART_DRAM32MBIT) { [cartPath setEnabled:YES]; [cartBrowse setEnabled:YES]; [[cartPath cell] setPlaceholderString:@"Not Set"]; } [cartType selectItemWithTag:_cartType]; } else { [_prefs setInteger:CART_NONE forKey:@"Cartridge Type"]; } if([_prefs objectForKey:@"Region"]) { _region = [_prefs integerForKey:@"Region"]; [region selectItemWithTag:_region]; } else { [_prefs setInteger:REGION_AUTODETECT forKey:@"Region"]; } if([_prefs objectForKey:@"Sound Core"]) { _soundCore = [_prefs integerForKey:@"Sound Core"]; [soundCore selectItemWithTag:_soundCore]; } else { [_prefs setInteger:SNDCORE_MAC forKey:@"Sound Core"]; } if([_prefs objectForKey:@"Video Core"]) { _videoCore = [_prefs integerForKey:@"Video Core"]; [videoCore selectItemWithTag:_videoCore]; } else { [_prefs setInteger:VIDCORE_OGL forKey:@"Video Core"]; } [_prefs synchronize]; } - (void)dealloc { [_prefs release]; [super dealloc]; } - (void)controlTextDidEndEditing:(NSNotification *)notification { id obj = [notification object]; if(obj == sh1Path) { [_prefs setObject:[sh1Path stringValue] forKey:@"SH1 Rom Path"]; } if(obj == biosPath) { [_prefs setObject:[biosPath stringValue] forKey:@"BIOS Path"]; } else if(obj == bramPath) { [_prefs setObject:[bramPath stringValue] forKey:@"BRAM Path"]; } else if(obj == mpegPath) { [_prefs setObject:[mpegPath stringValue] forKey:@"MPEG ROM Path"]; } else if(obj == cartPath) { [_prefs setObject:[cartPath stringValue] forKey:@"Cartridge Path"]; } [_prefs synchronize]; } - (IBAction)cartSelected:(id)sender { _cartType = [[sender selectedItem] tag]; switch(_cartType) { case CART_NONE: case CART_DRAM8MBIT: case CART_DRAM32MBIT: [cartPath setEnabled:NO]; [cartPath setStringValue:@""]; [cartBrowse setEnabled:NO]; [[cartPath cell] setPlaceholderString: @"No file required for the selected cartridge"]; break; default: [cartPath setEnabled:YES]; [cartBrowse setEnabled:YES]; [[cartPath cell] setPlaceholderString:@"Not Set"]; break; } /* Update the preferences file. */ [_prefs setObject:[cartPath stringValue] forKey:@"Cartridge Path"]; [_prefs setInteger:_cartType forKey:@"Cartridge Type"]; [_prefs synchronize]; } - (IBAction)regionSelected:(id)sender { _region = [[sender selectedItem] tag]; /* Update the preferences file. */ [_prefs setInteger:_region forKey:@"Region"]; [_prefs synchronize]; } - (IBAction)soundCoreSelected:(id)sender { _soundCore = [[sender selectedItem] tag]; /* Update the preferences file. */ [_prefs setInteger:_soundCore forKey:@"Sound Core"]; [_prefs synchronize]; } - (IBAction)videoCoreSelected:(id)sender { _videoCore = [[sender selectedItem] tag]; /* Update the preferences file. */ [_prefs setInteger:_videoCore forKey:@"Video Core"]; [_prefs synchronize]; } - (IBAction)biosBrowse:(id)sender { NSOpenPanel *p = [NSOpenPanel openPanel]; [p setTitle:@"Select a Saturn BIOS ROM"]; if([p runModal] == NSFileHandlingPanelOKButton) { [biosPath setStringValue:[[[p URLs] objectAtIndex:0] path]]; /* Update the preferences file. */ [_prefs setObject:[biosPath stringValue] forKey:@"BIOS Path"]; [_prefs synchronize]; } } - (IBAction)sh1Browse:(id)sender { NSOpenPanel *p = [NSOpenPanel openPanel]; [p setTitle:@"Select a Saturn SH1 Rom"]; if([p runModal] == NSFileHandlingPanelOKButton) { [sh1Path setStringValue:[[[p URLs] objectAtIndex:0] path]]; /* Update the preferences file. */ [_prefs setObject:[sh1Path stringValue] forKey:@"SH1 Rom Path"]; [_prefs synchronize]; } } - (IBAction)mpegBrowse:(id)sender { NSOpenPanel *p = [NSOpenPanel openPanel]; [p setTitle:@"Select a MPEG ROM"]; if([p runModal] == NSFileHandlingPanelOKButton) { [mpegPath setStringValue:[[[p URLs] objectAtIndex:0] path]]; /* Update the preferences file. */ [_prefs setObject:[mpegPath stringValue] forKey:@"MPEG ROM Path"]; [_prefs synchronize]; } } - (IBAction)bramBrowse:(id)sender { NSOpenPanel *p = [NSOpenPanel openPanel]; [p setTitle:@"Select a BRAM File"]; if([p runModal] == NSFileHandlingPanelOKButton) { [bramPath setStringValue:[[[p URLs] objectAtIndex:0] path]]; /* Update the preferences file. */ [_prefs setObject:[bramPath stringValue] forKey:@"BRAM Path"]; [_prefs synchronize]; } } - (IBAction)cartBrowse:(id)sender { NSOpenPanel *p = [NSOpenPanel openPanel]; [p setTitle:@"Select the Cartridge File"]; if([p runModal] == NSFileHandlingPanelOKButton) { [cartPath setStringValue:[[[p URLs] objectAtIndex:0] path]]; /* Update the preferences file. */ [_prefs setObject:[cartPath stringValue] forKey:@"Cartridge Path"]; [_prefs synchronize]; } } - (IBAction)biosToggle:(id)sender { /* Update the preferences file. */ [_prefs setBool:([sender state] == NSOnState) forKey:@"Emulate BIOS"]; [_prefs synchronize]; } - (IBAction)cdbToggle:(id)sender { /* Update the preferences file. */ [_prefs setBool:([sender state] == NSOnState) forKey:@"Enable CD Block LLE"]; [_prefs synchronize]; } - (IBAction)scspToggle:(id)sender { /* Update the preferences file. */ [_prefs setBool:([sender state] == NSOnState) forKey:@"Enable Higher Quality Sound"]; [_prefs synchronize]; } - (IBAction)threadsToggle:(id)sender { /* Update the preferences file. */ [_prefs setBool:([sender state] == NSOnState) forKey:@"Enable Multithreading"]; [_prefs synchronize]; } - (IBAction)buttonSelect:(id)sender { NSInteger rv; NSInteger tag = [sender tag]; int port = tag > 12 ? 1 : 0; u8 num = tag > 12 ? tag - 13 : tag; u32 value = PERCocoaGetKey(num, port); unichar ch; /* Fill in current setting from prefs */ if(value != (u32)-1) { switch(value) { case '\r': ch = 0x23CE; break; case '\t': ch = 0x21E5; break; case 27: ch = 0x241B; break; case 127: ch = 0x232B; break; case NSLeftArrowFunctionKey: ch = 0x2190; break; case NSUpArrowFunctionKey: ch = 0x2191; break; case NSRightArrowFunctionKey: ch = 0x2192; break; case NSDownArrowFunctionKey: ch = 0x2193; break; default: ch = toupper(((int)value)); } [buttonBox setStringValue:[NSString stringWithCharacters:&ch length:1]]; } else { [buttonBox setStringValue:@""]; } /* Open up the sheet and ask for the user's input */ [NSApp beginSheet:buttonAssignment modalForWindow:prefsPane modalDelegate:self didEndSelector:nil contextInfo:NULL]; rv = [NSApp runModalForWindow:buttonAssignment]; [NSApp endSheet:buttonAssignment]; [buttonAssignment orderOut:nil]; /* Did the user accept what they put in? */ if(rv == NSOKButton) { NSString *s = [buttonBox stringValue]; u32 val; /* This shouldn't happen... */ if([s length] < 1) { return; } switch([s characterAtIndex:0]) { case 0x23CE: /* Return */ val = '\r'; break; case 0x21E5: /* Tab */ val = '\t'; break; case 0x241B: /* Escape */ val = 27; break; case 0x232B: /* Backspace */ val = 127; break; case 0x2190: /* Left */ val = NSLeftArrowFunctionKey; break; case 0x2191: /* Up */ val = NSUpArrowFunctionKey; break; case 0x2192: /* Right */ val = NSRightArrowFunctionKey; break; case 0x2193: /* Down */ val = NSDownArrowFunctionKey; break; default: val = tolower([s characterAtIndex:0]); } /* Update the key mapping, if we're already running. This will also save the key to the preferences. */ if(tag > 12) { PERCocoaSetKey(val, tag - 13, 1); } else { PERCocoaSetKey(val, tag, 0); } } } - (IBAction)buttonSetOk:(id)sender { [NSApp stopModalWithCode:NSOKButton]; } - (IBAction)buttonSetCancel:(id)sender { [NSApp stopModalWithCode:NSCancelButton]; } - (int)cartType { return _cartType; } - (int)region { return _region; } - (int)soundCore { return _soundCore; } - (int)videoCore { return _videoCore; } - (NSString *)biosPath { return [biosPath stringValue]; } - (NSString *)sh1Path { return [sh1Path stringValue]; } - (BOOL)emulateBios { return [emulateBios state] == NSOnState; } - (BOOL)cdbLLE { return [cdbLLE state] == NSOnState; } - (BOOL)newScsp { return [newScsp state] == NSOnState; } - (BOOL)enableThreads { return [enableThreads state] == NSOnState; } - (NSString *)mpegPath { return [mpegPath stringValue]; } - (NSString *)bramPath { return [bramPath stringValue]; } - (NSString *)cartPath { return [cartPath stringValue]; } @end /* @implementation YabausePrefsController */ yabause-0.9.15/src/cocoa/main.m000644 001750 001750 00000004127 12757373537 020255 0ustar00guillaumeguillaume000000 000000 /* Copyright 2010, 2012 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #import #include #include "yui.h" #include "peripheral.h" #include "m68kcore.h" #include "m68kc68k.h" #include "permacjoy.h" #include "sndmac.h" #include "vidogl.h" #include "vidsoft.h" #include "vidgcd.h" #include "cs0.h" #include "vdp2.h" #include "PerCocoa.h" #include "YabauseController.h" #include "YabauseGLView.h" M68K_struct *M68KCoreList[] = { &M68KDummy, &M68KMusashi, #ifdef HAVE_C68K &M68KC68K, #endif NULL }; SH2Interface_struct *SH2CoreList[] = { &SH2Interpreter, &SH2DebugInterpreter, NULL }; PerInterface_struct *PERCoreList[] = { &PERDummy, &PERCocoa, &PERMacJoy, NULL }; CDInterface *CDCoreList[] = { &DummyCD, &ISOCD, &ArchCD, NULL }; SoundInterface_struct *SNDCoreList[] = { &SNDDummy, &SNDMac, NULL }; VideoInterface_struct *VIDCoreList[] = { &VIDDummy, &VIDOGL, &VIDSoft, &VIDGCD, NULL }; void YuiErrorMsg(const char *string) { NSString *str = [NSString stringWithUTF8String:string]; dispatch_async(dispatch_get_main_queue(), ^{ NSRunAlertPanel(@"Yabause Error", str, @"OK", NULL, NULL); }); } void YuiSwapBuffers(void) { [[controller view] setNeedsDisplay:YES]; } int main(int argc, char *argv[]) { return NSApplicationMain(argc, (const char **) argv); } yabause-0.9.15/src/cocoa/YabauseController.h000644 001750 001750 00000003666 12755623101 022747 0ustar00guillaumeguillaume000000 000000 /* Copyright 2010, 2012 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef YabauseController_h #define YabauseController_h #import @class YabauseGLView; @class YabausePrefsController; @interface YabauseController : NSObject { IBOutlet YabauseGLView *view; IBOutlet NSPanel *prefsPane; IBOutlet YabausePrefsController *prefs; IBOutlet NSMenuItem *frameskip; IBOutlet NSWindow *logWindow; IBOutlet NSTextView *logView; BOOL _running; BOOL _paused; NSLock *_runLock; NSThread *_emuThd; char *_bramFile; char *_isoFile; BOOL _doneExecuting; } - (void)awakeFromNib; - (void)dealloc; /* NSWindow delegate methods */ - (BOOL)windowShouldClose:(id)sender; /* NSApplication delegate methods */ - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)app; - (IBAction)showPreferences:(id)sender; - (IBAction)runBIOS:(id)sender; - (IBAction)runCD:(id)sender; - (IBAction)runISO:(id)sender; - (IBAction)toggleFullscreen:(id)sender; - (IBAction)toggle:(id)sender; - (IBAction)toggleFrameskip:(id)sender; - (IBAction)pause:(id)sender; - (IBAction)reset:(id)sender; - (YabauseGLView *)view; @end extern YabauseController *controller; #endif /* !YabauseController_h */ yabause-0.9.15/src/cocoa/CMake-Info.plist000644 001750 001750 00000001725 12755623101 022061 0ustar00guillaumeguillaume000000 000000 CFBundleDevelopmentRegion English CFBundleExecutable Yabause CFBundleIconFile Yabause.icns CFBundleIdentifier org.yabause.yabause.cocoa CFBundleInfoDictionaryVersion 6.0 CFBundleName Yabause CFBundlePackageType APPL CFBundleSignature ???? CFBundleShortVersionString ${YAB_VERSION} CFBundleVersion NSMainNibFile MainMenu NSPrincipalClass NSApplication NSHumanReadableCopyright Copyright © Yabause Team yabause-0.9.15/src/cocoa/PerCocoa.m000644 001750 001750 00000012213 12755623101 020776 0ustar00guillaumeguillaume000000 000000 /* Copyright 2010, 2011 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "PerCocoa.h" #include "yabause.h" #include #include #include /* Forward Declarations. */ static int PERCocoaInit(void); static void PERCocoaDeInit(void); static int PERCocoaHandleEvents(void); static u32 PERCocoaScan(u32 flags); static void PERCocoaFlush(void); static void PERCocoaKeyName(u32 key, char *name, int size); static PerPad_struct *c1 = NULL, *c2 = NULL; PerInterface_struct PERCocoa = { PERCORE_COCOA, "Cocoa Keyboard Input Interface", &PERCocoaInit, &PERCocoaDeInit, &PERCocoaHandleEvents, &PERCocoaScan, 0, &PERCocoaFlush, &PERCocoaKeyName }; /* Utility function to check if everything's set up right for a port */ static BOOL AllSetForPort(int p) { int i; NSString *str; NSUserDefaults *d = [NSUserDefaults standardUserDefaults]; id val; Class c = [NSNumber class]; for(i = 0; i < 13; ++i) { str = [NSString stringWithFormat:@"Keyboard %d %s", p, PerPadNames[i]]; val = [d objectForKey:str]; if(!val || ![val isKindOfClass:c]) { return NO; } } return YES; } void PERCocoaSetKey(u32 key, u8 n, int p) { PerPad_struct *c; NSString *str; NSUserDefaults *d = [NSUserDefaults standardUserDefaults]; NSNumber *val = [NSNumber numberWithUnsignedInt:(unsigned int)key]; assert(n <= PERPAD_Z); /* Build the string we'll look for, and set the value for that key */ str = [NSString stringWithFormat:@"Pad %d %s", p, PerPadNames[n]]; [d setObject:val forKey:str]; [d synchronize]; /* Update the mapping if we're running */ if(p == 0) { c = c1; } else { c = c2; } /* This will effectively make sure we don't update until we've started. */ if(c) { PerSetKey(key, n, c); } } u32 PERCocoaGetKey(u8 n, int p) { NSString *str; id result; NSUserDefaults *d = [NSUserDefaults standardUserDefaults]; assert(n <= PERPAD_Z); /* Fetch the key data */ str = [NSString stringWithFormat:@"Pad %d %s", p, PerPadNames[n]]; result = [d objectForKey:str]; if(result && [result isKindOfClass:[NSNumber class]]) { return (u32)[result unsignedIntValue]; } else { return (u32)-1; } } static int PERCocoaInit(void) { /* Fill in pad 1 */ c1 = PerPadAdd(&PORTDATA1); PerSetKey(PERCocoaGetKey(PERPAD_UP, 0), PERPAD_UP, c1); PerSetKey(PERCocoaGetKey(PERPAD_DOWN, 0), PERPAD_DOWN, c1); PerSetKey(PERCocoaGetKey(PERPAD_LEFT, 0), PERPAD_LEFT, c1); PerSetKey(PERCocoaGetKey(PERPAD_RIGHT, 0), PERPAD_RIGHT, c1); PerSetKey(PERCocoaGetKey(PERPAD_LEFT_TRIGGER, 0), PERPAD_LEFT_TRIGGER, c1); PerSetKey(PERCocoaGetKey(PERPAD_RIGHT_TRIGGER, 0), PERPAD_RIGHT_TRIGGER, c1); PerSetKey(PERCocoaGetKey(PERPAD_START, 0), PERPAD_START, c1); PerSetKey(PERCocoaGetKey(PERPAD_A, 0), PERPAD_A, c1); PerSetKey(PERCocoaGetKey(PERPAD_B, 0), PERPAD_B, c1); PerSetKey(PERCocoaGetKey(PERPAD_C, 0), PERPAD_C, c1); PerSetKey(PERCocoaGetKey(PERPAD_X, 0), PERPAD_X, c1); PerSetKey(PERCocoaGetKey(PERPAD_Y, 0), PERPAD_Y, c1); PerSetKey(PERCocoaGetKey(PERPAD_Z, 0), PERPAD_Z, c1); /* Fill in pad 2 */ c2 = PerPadAdd(&PORTDATA2); PerSetKey(PERCocoaGetKey(PERPAD_UP, 1), PERPAD_UP, c2); PerSetKey(PERCocoaGetKey(PERPAD_DOWN, 1), PERPAD_DOWN, c2); PerSetKey(PERCocoaGetKey(PERPAD_LEFT, 1), PERPAD_LEFT, c2); PerSetKey(PERCocoaGetKey(PERPAD_RIGHT, 1), PERPAD_RIGHT, c2); PerSetKey(PERCocoaGetKey(PERPAD_LEFT_TRIGGER, 1), PERPAD_LEFT_TRIGGER, c2); PerSetKey(PERCocoaGetKey(PERPAD_RIGHT_TRIGGER, 1), PERPAD_RIGHT_TRIGGER, c2); PerSetKey(PERCocoaGetKey(PERPAD_START, 1), PERPAD_START, c2); PerSetKey(PERCocoaGetKey(PERPAD_A, 1), PERPAD_A, c2); PerSetKey(PERCocoaGetKey(PERPAD_B, 1), PERPAD_B, c2); PerSetKey(PERCocoaGetKey(PERPAD_C, 1), PERPAD_C, c2); PerSetKey(PERCocoaGetKey(PERPAD_X, 1), PERPAD_X, c2); PerSetKey(PERCocoaGetKey(PERPAD_Y, 1), PERPAD_Y, c2); PerSetKey(PERCocoaGetKey(PERPAD_Z, 1), PERPAD_Z, c2); return 0; } static void PERCocoaDeInit(void) { } static int PERCocoaHandleEvents(void) { return YabauseExec(); } static u32 PERCocoaScan(u32 flags) { return 0; } static void PERCocoaFlush(void) { } static void PERCocoaKeyName(u32 key, char *name, int size) { snprintf(name, size, "%x", (unsigned int)key); } yabause-0.9.15/src/cocoa/Yabause.xcodeproj/000755 001750 001750 00000000000 12757373644 022533 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/cocoa/Yabause.xcodeproj/project.pbxproj000644 001750 001750 00000154232 12755623101 025576 0ustar00guillaumeguillaume000000 000000 // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 42; objects = { /* Begin PBXBuildFile section */ 2A1145191385E5010087C872 /* YabauseButtonFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A1145181385E5010087C872 /* YabauseButtonFormatter.m */; }; 2A3392711162E100000DA0E9 /* GLUT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A3392701162E100000DA0E9 /* GLUT.framework */; }; 2A474DF01163A013006993EA /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A474DEF1163A013006993EA /* AudioUnit.framework */; }; 2A474DF21163A013006993EA /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A474DF11163A013006993EA /* CoreAudio.framework */; }; 2A6C5D31186244AE008FE119 /* japmodem.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A6C5D2F186244AE008FE119 /* japmodem.c */; }; 2A7AB7CC117D1C1B00E47298 /* vidsoft.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7AB7CB117D1C1B00E47298 /* vidsoft.c */; }; 2A7D39D3115BA16100DE3BD1 /* bios.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D3987115BA16100DE3BD1 /* bios.c */; }; 2A7D39D4115BA16100DE3BD1 /* cd-macosx.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D3989115BA16100DE3BD1 /* cd-macosx.c */; }; 2A7D39D5115BA16100DE3BD1 /* cdbase.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D398A115BA16100DE3BD1 /* cdbase.c */; }; 2A7D39D6115BA16100DE3BD1 /* cheat.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D398C115BA16100DE3BD1 /* cheat.c */; }; 2A7D39D7115BA16100DE3BD1 /* coffelf.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D398E115BA16100DE3BD1 /* coffelf.c */; }; 2A7D39D8115BA16100DE3BD1 /* cs0.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D3991115BA16100DE3BD1 /* cs0.c */; }; 2A7D39D9115BA16100DE3BD1 /* cs1.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D3993115BA16100DE3BD1 /* cs1.c */; }; 2A7D39DA115BA16100DE3BD1 /* cs2.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D3995115BA16100DE3BD1 /* cs2.c */; }; 2A7D39DB115BA16100DE3BD1 /* debug.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D3997115BA16100DE3BD1 /* debug.c */; }; 2A7D39DC115BA16100DE3BD1 /* error.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D3999115BA16100DE3BD1 /* error.c */; }; 2A7D39DD115BA16100DE3BD1 /* m68kc68k.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D399B115BA16100DE3BD1 /* m68kc68k.c */; }; 2A7D39DE115BA16100DE3BD1 /* m68kcore.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D399D115BA16100DE3BD1 /* m68kcore.c */; }; 2A7D39DF115BA16100DE3BD1 /* m68kd.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D399F115BA16100DE3BD1 /* m68kd.c */; }; 2A7D39E1115BA16100DE3BD1 /* macjoy.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D39A2115BA16100DE3BD1 /* macjoy.c */; }; 2A7D39E2115BA16100DE3BD1 /* memory.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D39A4115BA16100DE3BD1 /* memory.c */; }; 2A7D39E3115BA16100DE3BD1 /* movie.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D39A6115BA16100DE3BD1 /* movie.c */; }; 2A7D39E4115BA16100DE3BD1 /* netlink.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D39A8115BA16100DE3BD1 /* netlink.c */; }; 2A7D39E5115BA16100DE3BD1 /* peripheral.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D39AA115BA16100DE3BD1 /* peripheral.c */; }; 2A7D39E6115BA16100DE3BD1 /* permacjoy.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D39AC115BA16100DE3BD1 /* permacjoy.c */; }; 2A7D39E7115BA16100DE3BD1 /* profile.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D39AE115BA16100DE3BD1 /* profile.c */; }; 2A7D39E9115BA16100DE3BD1 /* scu.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D39B2115BA16100DE3BD1 /* scu.c */; }; 2A7D39EA115BA16100DE3BD1 /* sh2core.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D39B4115BA16100DE3BD1 /* sh2core.c */; }; 2A7D39EB115BA16100DE3BD1 /* sh2d.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D39B6115BA16100DE3BD1 /* sh2d.c */; }; 2A7D39EC115BA16100DE3BD1 /* sh2idle.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D39B8115BA16100DE3BD1 /* sh2idle.c */; }; 2A7D39ED115BA16100DE3BD1 /* sh2int.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D39BA115BA16100DE3BD1 /* sh2int.c */; }; 2A7D39EE115BA16100DE3BD1 /* sh2trace.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D39BC115BA16100DE3BD1 /* sh2trace.c */; }; 2A7D39EF115BA16100DE3BD1 /* smpc.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D39BE115BA16100DE3BD1 /* smpc.c */; }; 2A7D39F1115BA16100DE3BD1 /* vdp1.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D39C2115BA16100DE3BD1 /* vdp1.c */; }; 2A7D39F2115BA16100DE3BD1 /* vdp2.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D39C4115BA16100DE3BD1 /* vdp2.c */; }; 2A7D39F3115BA16100DE3BD1 /* vdp2debug.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D39C6115BA16100DE3BD1 /* vdp2debug.c */; }; 2A7D39F4115BA16100DE3BD1 /* vidogl.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D39C8115BA16100DE3BD1 /* vidogl.c */; }; 2A7D39F5115BA16100DE3BD1 /* vidshared.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D39CA115BA16100DE3BD1 /* vidshared.c */; }; 2A7D39F6115BA16100DE3BD1 /* vidgcd.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D39CC115BA16100DE3BD1 /* vidgcd.c */; }; 2A7D39F7115BA16100DE3BD1 /* yabause.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D39CE115BA16100DE3BD1 /* yabause.c */; }; 2A7D39F8115BA16100DE3BD1 /* ygl.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D39D0115BA16100DE3BD1 /* ygl.c */; }; 2A7D3A1E115BA29F00DE3BD1 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A7D3A1D115BA29F00DE3BD1 /* OpenGL.framework */; }; 2A7D3A31115BA35200DE3BD1 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A7D3A30115BA35200DE3BD1 /* CoreFoundation.framework */; }; 2A7D3A33115BA35200DE3BD1 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A7D3A32115BA35200DE3BD1 /* IOKit.framework */; }; 2A7D3A48115BA3AF00DE3BD1 /* c68k.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D3A41115BA3AF00DE3BD1 /* c68k.c */; }; 2A7D3A49115BA3AF00DE3BD1 /* c68kexec.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D3A43115BA3AF00DE3BD1 /* c68kexec.c */; settings = {COMPILER_FLAGS = "-O0"; }; }; 2A7D3A4B115BA3AF00DE3BD1 /* gen68k.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D3A45115BA3AF00DE3BD1 /* gen68k.c */; }; 2A7D3A5A115BA41200DE3BD1 /* gen68k.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A7D3A45115BA3AF00DE3BD1 /* gen68k.c */; }; 2A7D3A9B115BAB9E00DE3BD1 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2A7D3A99115BAB9E00DE3BD1 /* MainMenu.xib */; }; 2A7D3AD5115BB01500DE3BD1 /* Yabause.icns in Resources */ = {isa = PBXBuildFile; fileRef = 2A7D3AD4115BB01500DE3BD1 /* Yabause.icns */; }; 2A82CCA1116171DB00F15B02 /* PerCocoa.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A82CCA0116171DB00F15B02 /* PerCocoa.m */; }; 2A9D7600116645D700A580EB /* sndmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 2A9D75FE116645D700A580EB /* sndmac.c */; }; 2A9D760E11665F2800A580EB /* controller.png in Resources */ = {isa = PBXBuildFile; fileRef = 2A9D760D11665F2800A580EB /* controller.png */; }; 2A9D7621116667C300A580EB /* YabausePrefsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A9D761F116667C300A580EB /* YabausePrefsController.m */; }; 2AD10F9E118BBC850088FB2C /* scsp2.c in Sources */ = {isa = PBXBuildFile; fileRef = 2AD10F97118BBC850088FB2C /* scsp2.c */; }; 2AD10F9F118BBC850088FB2C /* snddummy.c in Sources */ = {isa = PBXBuildFile; fileRef = 2AD10F99118BBC850088FB2C /* snddummy.c */; }; 2AD10FA0118BBC850088FB2C /* sndwav.c in Sources */ = {isa = PBXBuildFile; fileRef = 2AD10F9A118BBC850088FB2C /* sndwav.c */; }; 2AD10FDB118BCFA00088FB2C /* thr-dummy.c in Sources */ = {isa = PBXBuildFile; fileRef = 2AD10F9B118BBC850088FB2C /* thr-dummy.c */; }; 2AF0CA51116146A400196BED /* YabauseGLView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AF0CA4F116146A400196BED /* YabauseGLView.m */; }; 2AF0CA9911614DD500196BED /* YabauseController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AF0CA9811614DD500196BED /* YabauseController.m */; }; 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; F07BF9E414A1C2C500775818 /* yglshader.c in Sources */ = {isa = PBXBuildFile; fileRef = F07BF9E314A1C2C500775818 /* yglshader.c */; }; F07E62CB15054DCC00DF8A4E /* titan.c in Sources */ = {isa = PBXBuildFile; fileRef = F07E62CA15054DCC00DF8A4E /* titan.c */; }; F0E47FAD156C34EC001A1B51 /* osdcore.c in Sources */ = {isa = PBXBuildFile; fileRef = F0E47FAC156C34EC001A1B51 /* osdcore.c */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 2A7D3A7A115BA63900DE3BD1 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; proxyType = 1; remoteGlobalIDString = 2A7D3A54115BA3E700DE3BD1; remoteInfo = gen68k; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 2A1145171385E5010087C872 /* YabauseButtonFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YabauseButtonFormatter.h; sourceTree = ""; }; 2A1145181385E5010087C872 /* YabauseButtonFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YabauseButtonFormatter.m; sourceTree = ""; }; 2A3392701162E100000DA0E9 /* GLUT.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLUT.framework; path = System/Library/Frameworks/GLUT.framework; sourceTree = SDKROOT; }; 2A474DEF1163A013006993EA /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; }; 2A474DF11163A013006993EA /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; }; 2A6C5D2F186244AE008FE119 /* japmodem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = japmodem.c; path = ../japmodem.c; sourceTree = SOURCE_ROOT; }; 2A6C5D30186244AE008FE119 /* japmodem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = japmodem.h; path = ../japmodem.h; sourceTree = SOURCE_ROOT; }; 2A7AB7CB117D1C1B00E47298 /* vidsoft.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vidsoft.c; path = ../vidsoft.c; sourceTree = SOURCE_ROOT; }; 2A7AB7CE117D1CBE00E47298 /* vidsoft.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vidsoft.h; path = ../vidsoft.h; sourceTree = SOURCE_ROOT; }; 2A7D3987115BA16100DE3BD1 /* bios.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bios.c; path = ../bios.c; sourceTree = SOURCE_ROOT; }; 2A7D3988115BA16100DE3BD1 /* bios.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bios.h; path = ../bios.h; sourceTree = SOURCE_ROOT; }; 2A7D3989115BA16100DE3BD1 /* cd-macosx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "cd-macosx.c"; path = "../cd-macosx.c"; sourceTree = SOURCE_ROOT; }; 2A7D398A115BA16100DE3BD1 /* cdbase.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cdbase.c; path = ../cdbase.c; sourceTree = SOURCE_ROOT; }; 2A7D398B115BA16100DE3BD1 /* cdbase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cdbase.h; path = ../cdbase.h; sourceTree = SOURCE_ROOT; }; 2A7D398C115BA16100DE3BD1 /* cheat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cheat.c; path = ../cheat.c; sourceTree = SOURCE_ROOT; }; 2A7D398D115BA16100DE3BD1 /* cheat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cheat.h; path = ../cheat.h; sourceTree = SOURCE_ROOT; }; 2A7D398E115BA16100DE3BD1 /* coffelf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = coffelf.c; path = ../coffelf.c; sourceTree = SOURCE_ROOT; }; 2A7D398F115BA16100DE3BD1 /* coffelf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = coffelf.h; path = ../coffelf.h; sourceTree = SOURCE_ROOT; }; 2A7D3990115BA16100DE3BD1 /* core.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = core.h; path = ../core.h; sourceTree = SOURCE_ROOT; }; 2A7D3991115BA16100DE3BD1 /* cs0.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cs0.c; path = ../cs0.c; sourceTree = SOURCE_ROOT; }; 2A7D3992115BA16100DE3BD1 /* cs0.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cs0.h; path = ../cs0.h; sourceTree = SOURCE_ROOT; }; 2A7D3993115BA16100DE3BD1 /* cs1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cs1.c; path = ../cs1.c; sourceTree = SOURCE_ROOT; }; 2A7D3994115BA16100DE3BD1 /* cs1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cs1.h; path = ../cs1.h; sourceTree = SOURCE_ROOT; }; 2A7D3995115BA16100DE3BD1 /* cs2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cs2.c; path = ../cs2.c; sourceTree = SOURCE_ROOT; }; 2A7D3996115BA16100DE3BD1 /* cs2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cs2.h; path = ../cs2.h; sourceTree = SOURCE_ROOT; }; 2A7D3997115BA16100DE3BD1 /* debug.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = debug.c; path = ../debug.c; sourceTree = SOURCE_ROOT; }; 2A7D3998115BA16100DE3BD1 /* debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = debug.h; path = ../debug.h; sourceTree = SOURCE_ROOT; }; 2A7D3999115BA16100DE3BD1 /* error.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = error.c; path = ../error.c; sourceTree = SOURCE_ROOT; }; 2A7D399A115BA16100DE3BD1 /* error.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = error.h; path = ../error.h; sourceTree = SOURCE_ROOT; }; 2A7D399B115BA16100DE3BD1 /* m68kc68k.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = m68kc68k.c; path = ../m68kc68k.c; sourceTree = SOURCE_ROOT; }; 2A7D399C115BA16100DE3BD1 /* m68kc68k.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m68kc68k.h; path = ../m68kc68k.h; sourceTree = SOURCE_ROOT; }; 2A7D399D115BA16100DE3BD1 /* m68kcore.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = m68kcore.c; path = ../m68kcore.c; sourceTree = SOURCE_ROOT; }; 2A7D399E115BA16100DE3BD1 /* m68kcore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m68kcore.h; path = ../m68kcore.h; sourceTree = SOURCE_ROOT; }; 2A7D399F115BA16100DE3BD1 /* m68kd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = m68kd.c; path = ../m68kd.c; sourceTree = SOURCE_ROOT; }; 2A7D39A0115BA16100DE3BD1 /* m68kd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m68kd.h; path = ../m68kd.h; sourceTree = SOURCE_ROOT; }; 2A7D39A1115BA16100DE3BD1 /* m68kq68.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = m68kq68.c; path = ../m68kq68.c; sourceTree = SOURCE_ROOT; }; 2A7D39A2115BA16100DE3BD1 /* macjoy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = macjoy.c; path = ../macjoy.c; sourceTree = SOURCE_ROOT; }; 2A7D39A3115BA16100DE3BD1 /* macjoy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macjoy.h; path = ../macjoy.h; sourceTree = SOURCE_ROOT; }; 2A7D39A4115BA16100DE3BD1 /* memory.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = memory.c; path = ../memory.c; sourceTree = SOURCE_ROOT; }; 2A7D39A5115BA16100DE3BD1 /* memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = memory.h; path = ../memory.h; sourceTree = SOURCE_ROOT; }; 2A7D39A6115BA16100DE3BD1 /* movie.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = movie.c; path = ../movie.c; sourceTree = SOURCE_ROOT; }; 2A7D39A7115BA16100DE3BD1 /* movie.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = movie.h; path = ../movie.h; sourceTree = SOURCE_ROOT; }; 2A7D39A8115BA16100DE3BD1 /* netlink.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = netlink.c; path = ../netlink.c; sourceTree = SOURCE_ROOT; }; 2A7D39A9115BA16100DE3BD1 /* netlink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = netlink.h; path = ../netlink.h; sourceTree = SOURCE_ROOT; }; 2A7D39AA115BA16100DE3BD1 /* peripheral.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = peripheral.c; path = ../peripheral.c; sourceTree = SOURCE_ROOT; }; 2A7D39AB115BA16100DE3BD1 /* peripheral.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = peripheral.h; path = ../peripheral.h; sourceTree = SOURCE_ROOT; }; 2A7D39AC115BA16100DE3BD1 /* permacjoy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = permacjoy.c; path = ../permacjoy.c; sourceTree = SOURCE_ROOT; }; 2A7D39AD115BA16100DE3BD1 /* permacjoy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = permacjoy.h; path = ../permacjoy.h; sourceTree = SOURCE_ROOT; }; 2A7D39AE115BA16100DE3BD1 /* profile.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = profile.c; path = ../profile.c; sourceTree = SOURCE_ROOT; }; 2A7D39AF115BA16100DE3BD1 /* profile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = profile.h; path = ../profile.h; sourceTree = SOURCE_ROOT; }; 2A7D39B0115BA16100DE3BD1 /* scsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = scsp.c; path = ../scsp.c; sourceTree = SOURCE_ROOT; }; 2A7D39B1115BA16100DE3BD1 /* scsp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = scsp.h; path = ../scsp.h; sourceTree = SOURCE_ROOT; }; 2A7D39B2115BA16100DE3BD1 /* scu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = scu.c; path = ../scu.c; sourceTree = SOURCE_ROOT; }; 2A7D39B3115BA16100DE3BD1 /* scu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = scu.h; path = ../scu.h; sourceTree = SOURCE_ROOT; }; 2A7D39B4115BA16100DE3BD1 /* sh2core.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sh2core.c; path = ../sh2core.c; sourceTree = SOURCE_ROOT; }; 2A7D39B5115BA16100DE3BD1 /* sh2core.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sh2core.h; path = ../sh2core.h; sourceTree = SOURCE_ROOT; }; 2A7D39B6115BA16100DE3BD1 /* sh2d.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sh2d.c; path = ../sh2d.c; sourceTree = SOURCE_ROOT; }; 2A7D39B7115BA16100DE3BD1 /* sh2d.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sh2d.h; path = ../sh2d.h; sourceTree = SOURCE_ROOT; }; 2A7D39B8115BA16100DE3BD1 /* sh2idle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sh2idle.c; path = ../sh2idle.c; sourceTree = SOURCE_ROOT; }; 2A7D39B9115BA16100DE3BD1 /* sh2idle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sh2idle.h; path = ../sh2idle.h; sourceTree = SOURCE_ROOT; }; 2A7D39BA115BA16100DE3BD1 /* sh2int.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sh2int.c; path = ../sh2int.c; sourceTree = SOURCE_ROOT; }; 2A7D39BB115BA16100DE3BD1 /* sh2int.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sh2int.h; path = ../sh2int.h; sourceTree = SOURCE_ROOT; }; 2A7D39BC115BA16100DE3BD1 /* sh2trace.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sh2trace.c; path = ../sh2trace.c; sourceTree = SOURCE_ROOT; }; 2A7D39BD115BA16100DE3BD1 /* sh2trace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sh2trace.h; path = ../sh2trace.h; sourceTree = SOURCE_ROOT; }; 2A7D39BE115BA16100DE3BD1 /* smpc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = smpc.c; path = ../smpc.c; sourceTree = SOURCE_ROOT; }; 2A7D39BF115BA16100DE3BD1 /* smpc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = smpc.h; path = ../smpc.h; sourceTree = SOURCE_ROOT; }; 2A7D39C2115BA16100DE3BD1 /* vdp1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdp1.c; path = ../vdp1.c; sourceTree = SOURCE_ROOT; }; 2A7D39C3115BA16100DE3BD1 /* vdp1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vdp1.h; path = ../vdp1.h; sourceTree = SOURCE_ROOT; }; 2A7D39C4115BA16100DE3BD1 /* vdp2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdp2.c; path = ../vdp2.c; sourceTree = SOURCE_ROOT; }; 2A7D39C5115BA16100DE3BD1 /* vdp2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vdp2.h; path = ../vdp2.h; sourceTree = SOURCE_ROOT; }; 2A7D39C6115BA16100DE3BD1 /* vdp2debug.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vdp2debug.c; path = ../vdp2debug.c; sourceTree = SOURCE_ROOT; }; 2A7D39C7115BA16100DE3BD1 /* vdp2debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vdp2debug.h; path = ../vdp2debug.h; sourceTree = SOURCE_ROOT; }; 2A7D39C8115BA16100DE3BD1 /* vidogl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vidogl.c; path = ../vidogl.c; sourceTree = SOURCE_ROOT; }; 2A7D39C9115BA16100DE3BD1 /* vidogl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vidogl.h; path = ../vidogl.h; sourceTree = SOURCE_ROOT; }; 2A7D39CA115BA16100DE3BD1 /* vidshared.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vidshared.c; path = ../vidshared.c; sourceTree = SOURCE_ROOT; }; 2A7D39CB115BA16100DE3BD1 /* vidshared.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vidshared.h; path = ../vidshared.h; sourceTree = SOURCE_ROOT; }; 2A7D39CC115BA16100DE3BD1 /* vidgcd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vidgcd.c; sourceTree = ""; }; 2A7D39CD115BA16100DE3BD1 /* vidgcd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vidgcd.h; sourceTree = ""; }; 2A7D39CE115BA16100DE3BD1 /* yabause.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = yabause.c; path = ../yabause.c; sourceTree = SOURCE_ROOT; }; 2A7D39CF115BA16100DE3BD1 /* yabause.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = yabause.h; path = ../yabause.h; sourceTree = SOURCE_ROOT; }; 2A7D39D0115BA16100DE3BD1 /* ygl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ygl.c; path = ../ygl.c; sourceTree = SOURCE_ROOT; }; 2A7D39D1115BA16100DE3BD1 /* ygl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ygl.h; path = ../ygl.h; sourceTree = SOURCE_ROOT; }; 2A7D39D2115BA16100DE3BD1 /* yui.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = yui.h; path = ../yui.h; sourceTree = SOURCE_ROOT; }; 2A7D3A1D115BA29F00DE3BD1 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; 2A7D3A30115BA35200DE3BD1 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; 2A7D3A32115BA35200DE3BD1 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; 2A7D3A41115BA3AF00DE3BD1 /* c68k.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = c68k.c; path = ../c68k/c68k.c; sourceTree = SOURCE_ROOT; }; 2A7D3A42115BA3AF00DE3BD1 /* c68k.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = c68k.h; path = ../c68k/c68k.h; sourceTree = SOURCE_ROOT; }; 2A7D3A43115BA3AF00DE3BD1 /* c68kexec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = c68kexec.c; path = ../c68k/c68kexec.c; sourceTree = SOURCE_ROOT; }; 2A7D3A44115BA3AF00DE3BD1 /* c68kmac.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = c68kmac.inc; path = ../c68k/c68kmac.inc; sourceTree = SOURCE_ROOT; }; 2A7D3A45115BA3AF00DE3BD1 /* gen68k.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gen68k.c; path = ../c68k/gen68k.c; sourceTree = SOURCE_ROOT; }; 2A7D3A46115BA3AF00DE3BD1 /* gen68k.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gen68k.h; path = ../c68k/gen68k.h; sourceTree = SOURCE_ROOT; }; 2A7D3A47115BA3AF00DE3BD1 /* gen68k.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = gen68k.inc; path = ../c68k/gen68k.inc; sourceTree = SOURCE_ROOT; }; 2A7D3A55115BA3E700DE3BD1 /* gen68k */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = gen68k; sourceTree = BUILT_PRODUCTS_DIR; }; 2A7D3A9A115BAB9E00DE3BD1 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = ""; }; 2A7D3AD4115BB01500DE3BD1 /* Yabause.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Yabause.icns; sourceTree = ""; }; 2A82CC9F116171DB00F15B02 /* PerCocoa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PerCocoa.h; sourceTree = ""; }; 2A82CCA0116171DB00F15B02 /* PerCocoa.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PerCocoa.m; sourceTree = ""; }; 2A9D75FE116645D700A580EB /* sndmac.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sndmac.c; path = ../sndmac.c; sourceTree = SOURCE_ROOT; }; 2A9D75FF116645D700A580EB /* sndmac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sndmac.h; path = ../sndmac.h; sourceTree = SOURCE_ROOT; }; 2A9D760D11665F2800A580EB /* controller.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = controller.png; path = resources/controller.png; sourceTree = ""; }; 2A9D761F116667C300A580EB /* YabausePrefsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YabausePrefsController.m; sourceTree = ""; }; 2A9D7620116667C300A580EB /* YabausePrefsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YabausePrefsController.h; sourceTree = ""; }; 2AD10F97118BBC850088FB2C /* scsp2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = scsp2.c; path = ../scsp2.c; sourceTree = SOURCE_ROOT; }; 2AD10F98118BBC850088FB2C /* scsp2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = scsp2.h; path = ../scsp2.h; sourceTree = SOURCE_ROOT; }; 2AD10F99118BBC850088FB2C /* snddummy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = snddummy.c; path = ../snddummy.c; sourceTree = SOURCE_ROOT; }; 2AD10F9A118BBC850088FB2C /* sndwav.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sndwav.c; path = ../sndwav.c; sourceTree = SOURCE_ROOT; }; 2AD10F9B118BBC850088FB2C /* thr-dummy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "thr-dummy.c"; path = "../thr-dummy.c"; sourceTree = SOURCE_ROOT; }; 2AD10F9C118BBC850088FB2C /* thr-macosx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "thr-macosx.c"; path = "../thr-macosx.c"; sourceTree = SOURCE_ROOT; }; 2AD10F9D118BBC850088FB2C /* threads.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = threads.h; path = ../threads.h; sourceTree = SOURCE_ROOT; }; 2AF0CA4F116146A400196BED /* YabauseGLView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YabauseGLView.m; sourceTree = ""; }; 2AF0CA50116146A400196BED /* YabauseGLView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YabauseGLView.h; sourceTree = ""; }; 2AF0CA9711614DD500196BED /* YabauseController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YabauseController.h; sourceTree = ""; }; 2AF0CA9811614DD500196BED /* YabauseController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YabauseController.m; sourceTree = ""; }; 8D1107310486CEB800E47090 /* Yabause-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Yabause-Info.plist"; sourceTree = ""; }; 8D1107320486CEB800E47090 /* Yabause.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Yabause.app; sourceTree = BUILT_PRODUCTS_DIR; }; F07BF9E314A1C2C500775818 /* yglshader.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = yglshader.c; path = ../yglshader.c; sourceTree = SOURCE_ROOT; }; F07E62CA15054DCC00DF8A4E /* titan.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = titan.c; path = ../titan/titan.c; sourceTree = SOURCE_ROOT; }; F07E62CC15054DF500DF8A4E /* titan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = titan.h; path = ../titan/titan.h; sourceTree = SOURCE_ROOT; }; F0E47FAC156C34EC001A1B51 /* osdcore.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = osdcore.c; path = ../osdcore.c; sourceTree = SOURCE_ROOT; }; F0E47FAE156C34FB001A1B51 /* osdcore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = osdcore.h; path = ../osdcore.h; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 2A7D3A53115BA3E700DE3BD1 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 8D11072E0486CEB800E47090 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, 2A7D3A1E115BA29F00DE3BD1 /* OpenGL.framework in Frameworks */, 2A7D3A31115BA35200DE3BD1 /* CoreFoundation.framework in Frameworks */, 2A7D3A33115BA35200DE3BD1 /* IOKit.framework in Frameworks */, 2A3392711162E100000DA0E9 /* GLUT.framework in Frameworks */, 2A474DF01163A013006993EA /* AudioUnit.framework in Frameworks */, 2A474DF21163A013006993EA /* CoreAudio.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 080E96DDFE201D6D7F000001 /* Classes */ = { isa = PBXGroup; children = ( 2A1145171385E5010087C872 /* YabauseButtonFormatter.h */, 2A1145181385E5010087C872 /* YabauseButtonFormatter.m */, 2AF0CA9711614DD500196BED /* YabauseController.h */, 2AF0CA9811614DD500196BED /* YabauseController.m */, 2AF0CA50116146A400196BED /* YabauseGLView.h */, 2AF0CA4F116146A400196BED /* YabauseGLView.m */, 2A9D7620116667C300A580EB /* YabausePrefsController.h */, 2A9D761F116667C300A580EB /* YabausePrefsController.m */, ); name = Classes; sourceTree = ""; }; 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { isa = PBXGroup; children = ( 2A3392701162E100000DA0E9 /* GLUT.framework */, 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, 2A7D3A1D115BA29F00DE3BD1 /* OpenGL.framework */, 2A7D3A30115BA35200DE3BD1 /* CoreFoundation.framework */, 2A7D3A32115BA35200DE3BD1 /* IOKit.framework */, 2A474DEF1163A013006993EA /* AudioUnit.framework */, 2A474DF11163A013006993EA /* CoreAudio.framework */, ); name = "Linked Frameworks"; sourceTree = ""; }; 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { isa = PBXGroup; children = ( 29B97324FDCFA39411CA2CEA /* AppKit.framework */, 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */, 29B97325FDCFA39411CA2CEA /* Foundation.framework */, ); name = "Other Frameworks"; sourceTree = ""; }; 19C28FACFE9D520D11CA2CBB /* Products */ = { isa = PBXGroup; children = ( 8D1107320486CEB800E47090 /* Yabause.app */, 2A7D3A55115BA3E700DE3BD1 /* gen68k */, ); name = Products; sourceTree = ""; }; 29B97314FDCFA39411CA2CEA /* Yabause */ = { isa = PBXGroup; children = ( 2A7D3972115BA0DD00DE3BD1 /* Emulation Core */, 080E96DDFE201D6D7F000001 /* Classes */, 29B97315FDCFA39411CA2CEA /* Other Sources */, 29B97317FDCFA39411CA2CEA /* Resources */, 29B97323FDCFA39411CA2CEA /* Frameworks */, 19C28FACFE9D520D11CA2CBB /* Products */, ); name = Yabause; sourceTree = ""; }; 29B97315FDCFA39411CA2CEA /* Other Sources */ = { isa = PBXGroup; children = ( 29B97316FDCFA39411CA2CEA /* main.m */, 2A82CC9F116171DB00F15B02 /* PerCocoa.h */, 2A82CCA0116171DB00F15B02 /* PerCocoa.m */, 2A7D39CD115BA16100DE3BD1 /* vidgcd.h */, 2A7D39CC115BA16100DE3BD1 /* vidgcd.c */, ); name = "Other Sources"; sourceTree = ""; }; 29B97317FDCFA39411CA2CEA /* Resources */ = { isa = PBXGroup; children = ( 2A9D760D11665F2800A580EB /* controller.png */, 2A7D3AD4115BB01500DE3BD1 /* Yabause.icns */, 8D1107310486CEB800E47090 /* Yabause-Info.plist */, 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, 2A7D3A99115BAB9E00DE3BD1 /* MainMenu.xib */, ); name = Resources; sourceTree = ""; }; 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, ); name = Frameworks; sourceTree = ""; }; 2A7D3972115BA0DD00DE3BD1 /* Emulation Core */ = { isa = PBXGroup; children = ( 2A6C5D2F186244AE008FE119 /* japmodem.c */, 2A6C5D30186244AE008FE119 /* japmodem.h */, F0E47FAE156C34FB001A1B51 /* osdcore.h */, F0E47FAC156C34EC001A1B51 /* osdcore.c */, F07E62CC15054DF500DF8A4E /* titan.h */, F07E62CA15054DCC00DF8A4E /* titan.c */, F07BF9E314A1C2C500775818 /* yglshader.c */, 2A7D3A3E115BA38900DE3BD1 /* C68K */, 2A7D3987115BA16100DE3BD1 /* bios.c */, 2A7D3988115BA16100DE3BD1 /* bios.h */, 2A7D3989115BA16100DE3BD1 /* cd-macosx.c */, 2A7D398A115BA16100DE3BD1 /* cdbase.c */, 2A7D398B115BA16100DE3BD1 /* cdbase.h */, 2A7D398C115BA16100DE3BD1 /* cheat.c */, 2A7D398D115BA16100DE3BD1 /* cheat.h */, 2A7D398E115BA16100DE3BD1 /* coffelf.c */, 2A7D398F115BA16100DE3BD1 /* coffelf.h */, 2A7D3990115BA16100DE3BD1 /* core.h */, 2A7D3991115BA16100DE3BD1 /* cs0.c */, 2A7D3992115BA16100DE3BD1 /* cs0.h */, 2A7D3993115BA16100DE3BD1 /* cs1.c */, 2A7D3994115BA16100DE3BD1 /* cs1.h */, 2A7D3995115BA16100DE3BD1 /* cs2.c */, 2A7D3996115BA16100DE3BD1 /* cs2.h */, 2A7D3997115BA16100DE3BD1 /* debug.c */, 2A7D3998115BA16100DE3BD1 /* debug.h */, 2A7D3999115BA16100DE3BD1 /* error.c */, 2A7D399A115BA16100DE3BD1 /* error.h */, 2A7D399B115BA16100DE3BD1 /* m68kc68k.c */, 2A7D399C115BA16100DE3BD1 /* m68kc68k.h */, 2A7D399D115BA16100DE3BD1 /* m68kcore.c */, 2A7D399E115BA16100DE3BD1 /* m68kcore.h */, 2A7D399F115BA16100DE3BD1 /* m68kd.c */, 2A7D39A0115BA16100DE3BD1 /* m68kd.h */, 2A7D39A1115BA16100DE3BD1 /* m68kq68.c */, 2A7D39A2115BA16100DE3BD1 /* macjoy.c */, 2A7D39A3115BA16100DE3BD1 /* macjoy.h */, 2A7D39A4115BA16100DE3BD1 /* memory.c */, 2A7D39A5115BA16100DE3BD1 /* memory.h */, 2A7D39A6115BA16100DE3BD1 /* movie.c */, 2A7D39A7115BA16100DE3BD1 /* movie.h */, 2A7D39A8115BA16100DE3BD1 /* netlink.c */, 2A7D39A9115BA16100DE3BD1 /* netlink.h */, 2A7D39AA115BA16100DE3BD1 /* peripheral.c */, 2A7D39AB115BA16100DE3BD1 /* peripheral.h */, 2A7D39AC115BA16100DE3BD1 /* permacjoy.c */, 2A7D39AD115BA16100DE3BD1 /* permacjoy.h */, 2A7D39AE115BA16100DE3BD1 /* profile.c */, 2A7D39AF115BA16100DE3BD1 /* profile.h */, 2A7D39B0115BA16100DE3BD1 /* scsp.c */, 2A7D39B1115BA16100DE3BD1 /* scsp.h */, 2AD10F97118BBC850088FB2C /* scsp2.c */, 2AD10F98118BBC850088FB2C /* scsp2.h */, 2A7D39B2115BA16100DE3BD1 /* scu.c */, 2A7D39B3115BA16100DE3BD1 /* scu.h */, 2A7D39B4115BA16100DE3BD1 /* sh2core.c */, 2A7D39B5115BA16100DE3BD1 /* sh2core.h */, 2A7D39B6115BA16100DE3BD1 /* sh2d.c */, 2A7D39B7115BA16100DE3BD1 /* sh2d.h */, 2A7D39B8115BA16100DE3BD1 /* sh2idle.c */, 2A7D39B9115BA16100DE3BD1 /* sh2idle.h */, 2A7D39BA115BA16100DE3BD1 /* sh2int.c */, 2A7D39BB115BA16100DE3BD1 /* sh2int.h */, 2A7D39BC115BA16100DE3BD1 /* sh2trace.c */, 2A7D39BD115BA16100DE3BD1 /* sh2trace.h */, 2A7D39BE115BA16100DE3BD1 /* smpc.c */, 2A7D39BF115BA16100DE3BD1 /* smpc.h */, 2AD10F99118BBC850088FB2C /* snddummy.c */, 2A9D75FE116645D700A580EB /* sndmac.c */, 2A9D75FF116645D700A580EB /* sndmac.h */, 2AD10F9A118BBC850088FB2C /* sndwav.c */, 2AD10F9B118BBC850088FB2C /* thr-dummy.c */, 2AD10F9C118BBC850088FB2C /* thr-macosx.c */, 2AD10F9D118BBC850088FB2C /* threads.h */, 2A7D39C2115BA16100DE3BD1 /* vdp1.c */, 2A7D39C3115BA16100DE3BD1 /* vdp1.h */, 2A7D39C4115BA16100DE3BD1 /* vdp2.c */, 2A7D39C5115BA16100DE3BD1 /* vdp2.h */, 2A7D39C6115BA16100DE3BD1 /* vdp2debug.c */, 2A7D39C7115BA16100DE3BD1 /* vdp2debug.h */, 2A7D39C8115BA16100DE3BD1 /* vidogl.c */, 2A7D39C9115BA16100DE3BD1 /* vidogl.h */, 2A7D39CA115BA16100DE3BD1 /* vidshared.c */, 2A7D39CB115BA16100DE3BD1 /* vidshared.h */, 2A7AB7CE117D1CBE00E47298 /* vidsoft.h */, 2A7AB7CB117D1C1B00E47298 /* vidsoft.c */, 2A7D39CE115BA16100DE3BD1 /* yabause.c */, 2A7D39CF115BA16100DE3BD1 /* yabause.h */, 2A7D39D0115BA16100DE3BD1 /* ygl.c */, 2A7D39D1115BA16100DE3BD1 /* ygl.h */, 2A7D39D2115BA16100DE3BD1 /* yui.h */, ); name = "Emulation Core"; sourceTree = ""; }; 2A7D3A3E115BA38900DE3BD1 /* C68K */ = { isa = PBXGroup; children = ( 2A7D3A41115BA3AF00DE3BD1 /* c68k.c */, 2A7D3A42115BA3AF00DE3BD1 /* c68k.h */, 2A7D3A43115BA3AF00DE3BD1 /* c68kexec.c */, 2A7D3A44115BA3AF00DE3BD1 /* c68kmac.inc */, 2A7D3A45115BA3AF00DE3BD1 /* gen68k.c */, 2A7D3A46115BA3AF00DE3BD1 /* gen68k.h */, 2A7D3A47115BA3AF00DE3BD1 /* gen68k.inc */, ); name = C68K; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 2A7D3A54115BA3E700DE3BD1 /* gen68k */ = { isa = PBXNativeTarget; buildConfigurationList = 2A7D3A59115BA40C00DE3BD1 /* Build configuration list for PBXNativeTarget "gen68k" */; buildPhases = ( 2A7D3A52115BA3E700DE3BD1 /* Sources */, 2A7D3A53115BA3E700DE3BD1 /* Frameworks */, 2A7D3A6F115BA5A200DE3BD1 /* Run gen68k */, ); buildRules = ( ); dependencies = ( ); name = gen68k; productName = gen68k; productReference = 2A7D3A55115BA3E700DE3BD1 /* gen68k */; productType = "com.apple.product-type.tool"; }; 8D1107260486CEB800E47090 /* Yabause */ = { isa = PBXNativeTarget; buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Yabause" */; buildPhases = ( 8D1107290486CEB800E47090 /* Resources */, 8D11072C0486CEB800E47090 /* Sources */, 8D11072E0486CEB800E47090 /* Frameworks */, ); buildRules = ( ); dependencies = ( 2A7D3A7B115BA63900DE3BD1 /* PBXTargetDependency */, ); name = Yabause; productInstallPath = "$(HOME)/Applications"; productName = Yabause; productReference = 8D1107320486CEB800E47090 /* Yabause.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 29B97313FDCFA39411CA2CEA /* Project object */ = { isa = PBXProject; attributes = { }; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Yabause" */; compatibilityVersion = "Xcode 2.4"; developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( English, Japanese, French, German, ); mainGroup = 29B97314FDCFA39411CA2CEA /* Yabause */; projectDirPath = ""; projectRoot = ""; targets = ( 2A7D3A54115BA3E700DE3BD1 /* gen68k */, 8D1107260486CEB800E47090 /* Yabause */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 8D1107290486CEB800E47090 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */, 2A7D3A9B115BAB9E00DE3BD1 /* MainMenu.xib in Resources */, 2A7D3AD5115BB01500DE3BD1 /* Yabause.icns in Resources */, 2A9D760E11665F2800A580EB /* controller.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 2A7D3A6F115BA5A200DE3BD1 /* Run gen68k */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "$(PROJECT_DIR)/../gen68k/gen68k.c", "$(PROJECT_DIR)/../gen68k/gen68k.h", "$(PROJECT_DIR)/../gen68k/gen68k.inc", "$(PROJECT_DIR)/../gen68k/c68kmac.inc", "$(PROJECT_DIR)/../gen68k/c68kexec.c", "$(PROJECT_DIR)/../gen68k/c68k.c", "$(PROJECT_DIR)/../gen68k/c68k.h", ); name = "Run gen68k"; outputPaths = ( "$(PROJECT_DIR)/../gen68k/c68k_op0.inc", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "cd ../c68k\n\"$BUILD_DIR/$CONFIGURATION/gen68k\""; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 2A7D3A52115BA3E700DE3BD1 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 2A7D3A5A115BA41200DE3BD1 /* gen68k.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 8D11072C0486CEB800E47090 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 8D11072D0486CEB800E47090 /* main.m in Sources */, 2A7D39D3115BA16100DE3BD1 /* bios.c in Sources */, 2A7D39D4115BA16100DE3BD1 /* cd-macosx.c in Sources */, 2A7D39D5115BA16100DE3BD1 /* cdbase.c in Sources */, 2A7D39D6115BA16100DE3BD1 /* cheat.c in Sources */, 2A7D39D7115BA16100DE3BD1 /* coffelf.c in Sources */, 2A7D39D8115BA16100DE3BD1 /* cs0.c in Sources */, 2A7D39D9115BA16100DE3BD1 /* cs1.c in Sources */, 2A7D39DA115BA16100DE3BD1 /* cs2.c in Sources */, 2A7D39DB115BA16100DE3BD1 /* debug.c in Sources */, 2A7D39DC115BA16100DE3BD1 /* error.c in Sources */, 2A7D39DD115BA16100DE3BD1 /* m68kc68k.c in Sources */, 2A7D39DE115BA16100DE3BD1 /* m68kcore.c in Sources */, 2A7D39DF115BA16100DE3BD1 /* m68kd.c in Sources */, 2A7D39E1115BA16100DE3BD1 /* macjoy.c in Sources */, 2A7D39E2115BA16100DE3BD1 /* memory.c in Sources */, 2A7D39E3115BA16100DE3BD1 /* movie.c in Sources */, 2A7D39E4115BA16100DE3BD1 /* netlink.c in Sources */, 2A7D39E5115BA16100DE3BD1 /* peripheral.c in Sources */, 2A7D39E6115BA16100DE3BD1 /* permacjoy.c in Sources */, 2A7D39E7115BA16100DE3BD1 /* profile.c in Sources */, 2A7D39E9115BA16100DE3BD1 /* scu.c in Sources */, 2A7D39EA115BA16100DE3BD1 /* sh2core.c in Sources */, 2A7D39EB115BA16100DE3BD1 /* sh2d.c in Sources */, 2A7D39EC115BA16100DE3BD1 /* sh2idle.c in Sources */, 2A7D39ED115BA16100DE3BD1 /* sh2int.c in Sources */, 2A7D39EE115BA16100DE3BD1 /* sh2trace.c in Sources */, 2A7D39EF115BA16100DE3BD1 /* smpc.c in Sources */, 2A7D39F1115BA16100DE3BD1 /* vdp1.c in Sources */, 2A7D39F2115BA16100DE3BD1 /* vdp2.c in Sources */, 2A7D39F3115BA16100DE3BD1 /* vdp2debug.c in Sources */, 2A7D39F4115BA16100DE3BD1 /* vidogl.c in Sources */, 2A7D39F5115BA16100DE3BD1 /* vidshared.c in Sources */, 2A7D39F6115BA16100DE3BD1 /* vidgcd.c in Sources */, 2A7D39F7115BA16100DE3BD1 /* yabause.c in Sources */, 2A7D39F8115BA16100DE3BD1 /* ygl.c in Sources */, 2A7D3A48115BA3AF00DE3BD1 /* c68k.c in Sources */, 2A7D3A49115BA3AF00DE3BD1 /* c68kexec.c in Sources */, 2A7D3A4B115BA3AF00DE3BD1 /* gen68k.c in Sources */, 2AF0CA51116146A400196BED /* YabauseGLView.m in Sources */, 2AF0CA9911614DD500196BED /* YabauseController.m in Sources */, 2A82CCA1116171DB00F15B02 /* PerCocoa.m in Sources */, 2A9D7600116645D700A580EB /* sndmac.c in Sources */, 2A9D7621116667C300A580EB /* YabausePrefsController.m in Sources */, 2A7AB7CC117D1C1B00E47298 /* vidsoft.c in Sources */, 2AD10F9E118BBC850088FB2C /* scsp2.c in Sources */, 2AD10F9F118BBC850088FB2C /* snddummy.c in Sources */, 2AD10FA0118BBC850088FB2C /* sndwav.c in Sources */, 2AD10FDB118BCFA00088FB2C /* thr-dummy.c in Sources */, 2A1145191385E5010087C872 /* YabauseButtonFormatter.m in Sources */, F07BF9E414A1C2C500775818 /* yglshader.c in Sources */, F07E62CB15054DCC00DF8A4E /* titan.c in Sources */, F0E47FAD156C34EC001A1B51 /* osdcore.c in Sources */, 2A6C5D31186244AE008FE119 /* japmodem.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 2A7D3A7B115BA63900DE3BD1 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 2A7D3A54115BA3E700DE3BD1 /* gen68k */; targetProxy = 2A7D3A7A115BA63900DE3BD1 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( 089C165DFE840E0CC02AAC07 /* English */, ); name = InfoPlist.strings; sourceTree = ""; }; 2A7D3A99115BAB9E00DE3BD1 /* MainMenu.xib */ = { isa = PBXVariantGroup; children = ( 2A7D3A9A115BAB9E00DE3BD1 /* English */, ); name = MainMenu.xib; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 2A7D3A57115BA3E800DE3BD1 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_MODEL_TUNING = G5; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = C68K_GEN; GCC_VERSION = ""; INSTALL_PATH = /usr/local/bin; PREBINDING = NO; PRODUCT_NAME = gen68k; SDKROOT = macosx; }; name = Debug; }; 2A7D3A58115BA3E800DE3BD1 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_MODEL_TUNING = G5; GCC_PREPROCESSOR_DEFINITIONS = C68K_GEN; GCC_VERSION = ""; INSTALL_PATH = /usr/local/bin; PREBINDING = NO; PRODUCT_NAME = gen68k; SDKROOT = macosx; ZERO_LINK = NO; }; name = Release; }; C01FCF4B08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; COPY_PHASE_STRIP = NO; ENABLE_OPENMP_SUPPORT = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_MODEL_TUNING = G5; GCC_OPTIMIZATION_LEVEL = 3; GCC_PRECOMPILE_PREFIX_HEADER = NO; GCC_PREFIX_HEADER = ""; GCC_UNROLL_LOOPS = YES; GCC_VERSION = ""; INFOPLIST_FILE = "Yabause-Info.plist"; INSTALL_PATH = "$(HOME)/Applications"; OTHER_CFLAGS = "-fnested-functions"; PRODUCT_NAME = Yabause; SDKROOT = macosx; }; name = Debug; }; C01FCF4C08A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_OPENMP_SUPPORT = NO; GCC_MODEL_TUNING = G5; GCC_PRECOMPILE_PREFIX_HEADER = NO; GCC_PREFIX_HEADER = ""; GCC_UNROLL_LOOPS = YES; GCC_VERSION = ""; INFOPLIST_FILE = "Yabause-Info.plist"; INSTALL_PATH = "$(HOME)/Applications"; ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = "-fnested-functions"; PRODUCT_NAME = Yabause; SDKROOT = macosx; }; name = Release; }; C01FCF4F08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; ENABLE_OPENMP_SUPPORT = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_OPTIMIZATION_LEVEL = 3; GCC_PREPROCESSOR_DEFINITIONS = ( "USE_SCSP2=1", CRAB_REWRITE, NO_CLI, HAVE_LIBGL, HAVE_LIBGLUT, HAVE_SYS_TIME_H, HAVE_GETTIMEOFDAY, HAVE_STRCASECMP, "$(GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_1)", ); GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_1 = "VERSION=\\\"0.9.15\\\""; GCC_VERSION = ""; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.6; ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = ""; PREBINDING = NO; SDKROOT = macosx; }; name = Debug; }; C01FCF5008A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_OPTIMIZATION_LEVEL = 3; GCC_PREPROCESSOR_DEFINITIONS = ( "USE_SCSP2=1", CRAB_REWRITE, NO_CLI, HAVE_LIBGL, HAVE_LIBGLUT, HAVE_SYS_TIME_H, HAVE_GETTIMEOFDAY, HAVE_STRCASECMP, "$(GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_1)", ); GCC_PREPROCESSOR_DEFINITIONS_QUOTED_FOR_PROJECT_1 = "VERSION=\\\"0.9.15\\\""; GCC_VERSION = ""; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.6; ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = ""; PREBINDING = NO; SDKROOT = macosx; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 2A7D3A59115BA40C00DE3BD1 /* Build configuration list for PBXNativeTarget "gen68k" */ = { isa = XCConfigurationList; buildConfigurations = ( 2A7D3A57115BA3E800DE3BD1 /* Debug */, 2A7D3A58115BA3E800DE3BD1 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Yabause" */ = { isa = XCConfigurationList; buildConfigurations = ( C01FCF4B08A954540054247B /* Debug */, C01FCF4C08A954540054247B /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Yabause" */ = { isa = XCConfigurationList; buildConfigurations = ( C01FCF4F08A954540054247B /* Debug */, C01FCF5008A954540054247B /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; } yabause-0.9.15/src/cocoa/YabauseGLView.h000644 001750 001750 00000002462 12755623101 021752 0ustar00guillaumeguillaume000000 000000 /* Copyright 2010, 2014 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef YabauseGLView_h #define YabauseGLView_h #import #include #include @interface YabauseGLView : NSOpenGLView { IBOutlet NSWindow *window; NSRect oldFrame; NSWindow *fsWindow; BOOL _isFullscreen; } - (id)initWithFrame:(NSRect)frameRect; - (void)toggleFullscreen; - (BOOL)acceptsFirstResponder; - (void)keyDown:(NSEvent *)event; - (void)keyUp:(NSEvent *)event; - (void)showWindow; - (void)reshape; - (void)drawRect:(NSRect)rect; @end #endif /* !YabauseGLView_h */ yabause-0.9.15/src/cocoa/YabausePrefsController.h000644 001750 001750 00000005170 12755623101 023737 0ustar00guillaumeguillaume000000 000000 /* Copyright 2010-2011 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef YabausePrefsController_h #define YabausePrefsController_h #import @interface YabausePrefsController : NSObject { IBOutlet NSTextField *biosPath; IBOutlet NSTextField *sh1Path; IBOutlet NSTextField *bramPath; IBOutlet NSButton *cartBrowse; IBOutlet NSTextField *cartPath; IBOutlet NSPopUpButton *cartType; IBOutlet NSButton *emulateBios; IBOutlet NSButton *cdbLLE; IBOutlet NSButton *newScsp; IBOutlet NSButton *enableThreads; IBOutlet NSTextField *mpegPath; IBOutlet NSPopUpButton *region; IBOutlet NSPopUpButton *soundCore; IBOutlet NSPopUpButton *videoCore; IBOutlet NSPanel *prefsPane; IBOutlet NSPanel *buttonAssignment; IBOutlet NSTextField *buttonBox; int _cartType; int _region; int _soundCore; int _videoCore; NSUserDefaults *_prefs; } - (void)awakeFromNib; - (void)dealloc; /* NSTextField delegate methods */ - (void)controlTextDidEndEditing:(NSNotification *)notification; - (IBAction)cartSelected:(id)sender; - (IBAction)regionSelected:(id)sender; - (IBAction)soundCoreSelected:(id)sender; - (IBAction)videoCoreSelected:(id)sender; - (IBAction)biosBrowse:(id)sender; - (IBAction)sh1Browse:(id)sender; - (IBAction)mpegBrowse:(id)sender; - (IBAction)bramBrowse:(id)sender; - (IBAction)cartBrowse:(id)sender; - (IBAction)biosToggle:(id)sender; - (IBAction)scspToggle:(id)sender; - (IBAction)cdbToggle:(id)sender; - (IBAction)threadsToggle:(id)sender; - (IBAction)buttonSelect:(id)sender; - (IBAction)buttonSetOk:(id)sender; - (IBAction)buttonSetCancel:(id)sender; - (int)cartType; - (int)region; - (int)soundCore; - (int)videoCore; - (NSString *)biosPath; - (NSString *)sh1Path; - (BOOL)cdbLLE; - (BOOL)emulateBios; - (BOOL)newScsp; - (BOOL)enableThreads; - (NSString *)mpegPath; - (NSString *)bramPath; - (NSString *)cartPath; @end #endif /* !YabausePrefsController_h */ yabause-0.9.15/src/cocoa/PerCocoa.h000644 001750 001750 00000002034 12755623101 020771 0ustar00guillaumeguillaume000000 000000 /* Copyright 2010, 2011 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef PerCocoa_h #define PerCocoa_h #include "peripheral.h" #define PERCORE_COCOA 42 extern PerInterface_struct PERCocoa; /* Update a key mapping */ void PERCocoaSetKey(u32 key, u8 name, int port); u32 PERCocoaGetKey(u8 n, int p); #endif /* !PerCocoa_h */ yabause-0.9.15/src/cdbase.h000644 001750 001750 00000003271 12755623101 017437 0ustar00guillaumeguillaume000000 000000 /* Copyright 2004-2005 Theo Berkau Copyright 2005 Joost Peters Copyright 2006 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file cdbase.c \brief Header for Dummy and ISO, BIN/CUE, MDS CD Interfaces */ #ifndef CDBASE_H #define CDBASE_H #include #include "core.h" #define CDCORE_DEFAULT -1 #define CDCORE_DUMMY 0 #define CDCORE_ISO 1 #define CDCORE_ARCH 2 typedef struct { u8 ctrladr; u8 tno; u8 point; u8 min; u8 sec; u8 frame; u8 zero; u8 pmin; u8 psec; u8 pframe; } CDInterfaceToc10; typedef struct { int id; const char *Name; int (*Init)(const char *); void (*DeInit)(void); int (*GetStatus)(void); s32 (*ReadTOC)(u32 *TOC); s32 (*ReadTOC10)(CDInterfaceToc10 *TOC); int (*ReadSectorFAD)(u32 FAD, void *buffer); void (*ReadAheadFAD)(u32 FAD); } CDInterface; extern CDInterface DummyCD; extern CDInterface ISOCD; extern CDInterface ArchCD; #endif yabause-0.9.15/src/sndmac.c000644 001750 001750 00000022440 12755623101 017455 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005-2010 Lawrence Sebald Copyright 2005-2006 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* This file is adapted from CrabEmu's sound.c for Mac OS X as well as the sndsdl.c file in Yabause. */ #include #include #include #include #include #include "scsp.h" #include "sndmac.h" #define BUFFER_LEN 65536 /* Workarounds for APIs changed in Mac OS X 10.6. */ #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 typedef AudioComponent Component; typedef AudioComponentDescription ComponentDescription; #define FindNextComponent AudioComponentFindNext #define OpenAComponent AudioComponentInstanceNew #define CloseComponent AudioComponentInstanceDispose #endif static int SNDMacInit(void); static void SNDMacDeInit(void); static int SNDMacReset(void); static int SNDMacChangeVideoFormat(int vfreq); static void SNDMacUpdateAudio(u32 *left, u32 *right, u32 cnt); static u32 SNDMacGetAudioSpace(void); static void SNDMacMuteAudio(void); static void SNDMacUnMuteAudio(void); static void SNDMacSetVolume(int volume); #ifdef USE_SCSPMIDI int SNDMacMidiChangePorts(int inport, int outport); u8 SNDMacMidiIn(int *isdata); int SNDMacMidiOut(u8 data); #endif SoundInterface_struct SNDMac = { SNDCORE_MAC, "Mac OS X Core Audio Sound Interface", &SNDMacInit, &SNDMacDeInit, &SNDMacReset, &SNDMacChangeVideoFormat, &SNDMacUpdateAudio, &SNDMacGetAudioSpace, &SNDMacMuteAudio, &SNDMacUnMuteAudio, &SNDMacSetVolume, #ifdef USE_SCSPMIDI &SNDMacMidiChangePorts, &SNDMacMidiIn, &SNDMacMidiOut #endif }; static AudioUnit outputAU; static unsigned char buffer[BUFFER_LEN]; static int muted = 1; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static UInt32 read_pos = 0, write_pos = 0; static int soundvolume = 100; static OSStatus SNDMacMixAudio(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumFrames, AudioBufferList *ioData) { UInt32 len = ioData->mBuffers[0].mDataByteSize; void *ptr = ioData->mBuffers[0].mData; pthread_mutex_lock(&mutex); if(muted || (read_pos + len > write_pos && write_pos > read_pos)) { memset(ptr, 0, len); } else { memcpy(ptr, buffer + read_pos, len); read_pos += len; read_pos &= (BUFFER_LEN - 1); } pthread_mutex_unlock(&mutex); return noErr; } int SNDMacInit(void) { OSStatus error = noErr; ComponentDescription desc; AudioStreamBasicDescription basic_desc; Component comp; AURenderCallbackStruct callback; UInt32 bufsz; int rv = 0; /* Clear the sound to silence. */ memset(buffer, 0, BUFFER_LEN); /* Find the default audio output unit */ desc.componentType = kAudioUnitType_Output; desc.componentSubType = kAudioUnitSubType_DefaultOutput; desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; comp = FindNextComponent(NULL, &desc); if(comp == NULL) { rv = -1; goto err1; } /* We got the component, make sure we can actually open it up. */ error = OpenAComponent(comp, &outputAU); if(error != noErr) { rv = -2; goto err1; } /* Set up the AudioStreamBasicDescription - 32-bit Stereo PCM @ 44100Hz */ basic_desc.mFormatID = kAudioFormatLinearPCM; basic_desc.mFormatFlags = kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger; basic_desc.mChannelsPerFrame = 2; basic_desc.mSampleRate = 44100; basic_desc.mBitsPerChannel = 16; basic_desc.mFramesPerPacket = 1; basic_desc.mBytesPerFrame = 4; basic_desc.mBytesPerPacket = 4; /* Set the stream format that we set up above */ error = AudioUnitSetProperty(outputAU, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &basic_desc, sizeof(basic_desc)); if(error != noErr) { rv = -3; goto err2; } /* Set the callback for getting sound data. */ callback.inputProc = &SNDMacMixAudio; callback.inputProcRefCon = NULL; error = AudioUnitSetProperty(outputAU, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)); if(error != noErr) { rv = -4; goto err2; } bufsz = 2048; error = AudioUnitSetProperty(outputAU, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &bufsz, sizeof(UInt32)); if(error != noErr) { rv = -7; goto err3; } /* Initialize the Audio Unit for our use now that its set up. */ error = AudioUnitInitialize(outputAU); if(error != noErr) { rv = -8; goto err3; } /* We're ready to output now */ error = AudioOutputUnitStart(outputAU); if(error != noErr) { rv = -9; goto err4; } muted = 0; soundvolume = 100; return 0; /* Error conditions. Errors cause cascading deinitialization, so hence this chain of labels. */ err4: AudioUnitUninitialize(outputAU); err3: callback.inputProc = NULL; callback.inputProcRefCon = NULL; AudioUnitSetProperty(outputAU, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)); err2: CloseComponent(outputAU); err1: return rv; } static void SNDMacDeInit(void) { OSStatus error; AURenderCallbackStruct callback; /* Stop the Audio Unit from playing any further */ error = AudioOutputUnitStop(outputAU); if(error != noErr) return; /* Clear the callback */ callback.inputProc = NULL; callback.inputProcRefCon = NULL; error = AudioUnitSetProperty(outputAU, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)); if(error != noErr) return; /* Uninitialize the Audio Unit, now that we're done with it */ error = AudioUnitUninitialize(outputAU); if(error != noErr) return; /* Close it, we're done */ CloseComponent(outputAU); } static int SNDMacReset(void) { /* NOP */ return 0; } static int SNDMacChangeVideoFormat(int vfreq) { /* NOP */ return 0; } static void macConvert32uto16s(s32 *srcL, s32 *srcR, s16 *dst, u32 len) { u32 i; for(i = 0; i < len; i++) { // Left Channel *srcL = (*srcL * soundvolume) / 100; if (*srcL > 0x7FFF) *dst = 0x7FFF; else if (*srcL < -0x8000) *dst = -0x8000; else *dst = *srcL; srcL++; dst++; // Right Channel *srcR = (*srcR * soundvolume) / 100; if (*srcR > 0x7FFF) *dst = 0x7FFF; else if (*srcR < -0x8000) *dst = -0x8000; else *dst = *srcR; srcR++; dst++; } } static void SNDMacUpdateAudio(u32 *left, u32 *right, u32 cnt) { u32 copy1size=0, copy2size=0; pthread_mutex_lock(&mutex); if((BUFFER_LEN - write_pos) < (cnt << 2)) { copy1size = (BUFFER_LEN - write_pos); copy2size = (cnt << 2) - copy1size; } else { copy1size = (cnt << 2); copy2size = 0; } macConvert32uto16s((s32 *)left, (s32 *)right, (s16 *)(((u8 *)buffer) + write_pos), copy1size >> 2); if(copy2size) { macConvert32uto16s((s32 *)left + (copy1size >> 2), (s32 *)right + (copy1size >> 2), (s16 *)buffer, copy2size >> 2); } write_pos += copy1size + copy2size; write_pos %= (BUFFER_LEN); pthread_mutex_unlock(&mutex); } static u32 SNDMacGetAudioSpace(void) { u32 fs = 0; if(write_pos > read_pos) { fs = BUFFER_LEN - write_pos + read_pos; } else { fs = read_pos - write_pos; } return (fs >> 2); } static void SNDMacMuteAudio(void) { muted = 1; } static void SNDMacUnMuteAudio(void) { muted = 0; } static void SNDMacSetVolume(int volume) { soundvolume = volume; } #ifdef USE_SCSPMIDI int SNDMacMidiChangePorts(int inport, int outport) { return 0; } u8 SNDMacMidiIn(int *isdata) { *isdata = 0; return 0; } int SNDMacMidiOut(u8 data) { return 1; } #endif yabause-0.9.15/src/sh7034.h000644 001750 001750 00000013232 12755623101 017144 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2005 Guillaume Duhamel Copyright 2004-2006, 2013 Theo Berkau Copyright 2016 James Laird-Wah This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SH7034_H #define SH7034_H #include "core.h" #include "sh2core.h" void cd_trace_log(const char * format, ...); void sh1_dreq_asserted(int which); //#define WANT_CDTRACE #ifdef WANT_CDTRACE #define CDTRACE(...) cd_trace_log(__VA_ARGS__) #else #define CDTRACE(...) #endif u8 FASTCALL Sh1MemoryReadByte(SH2_struct *sh, u32 addr); u16 FASTCALL Sh1MemoryReadWord(SH2_struct *sh, u32 addr); u32 FASTCALL Sh1MemoryReadLong(SH2_struct *sh, u32 addr); void FASTCALL Sh1MemoryWriteByte(SH2_struct *sh, u32 addr, u8 val); void FASTCALL Sh1MemoryWriteWord(SH2_struct *sh, u32 addr, u16 val); void FASTCALL Sh1MemoryWriteLong(SH2_struct *sh, u32 addr, u32 val); void sh1_init_func(); void sh1_serial_recieve_bit(int bit, int channel); void sh1_set_start(int state); void sh1_serial_transmit_bit(int channel, int* output_bit); void sh1_assert_tioca(int which); void sh1_assert_tiocb(int which); struct Onchip { //sci0/1 struct Sci { u8 smr; u8 brr; u8 scr; u8 tdr; u8 ssr; u8 rdr; //not visible to cpu u8 rsr; u8 rsr_counter; u8 rsr_written; //not visible to cpu u8 tsr; u8 tsr_counter; u8 tdr_written; //implementation specific int serial_clock_counter; }sci[2]; //a/d u16 addra; u16 addrb; u16 addrc; u16 addrd; u8 adcsr; u8 adcr; //itu shared u8 tstr; u8 tsnc; u8 tmdr; u8 tfcr; //itu channels struct Itu01 { u8 tcr; u8 tiorl; u8 tier; u8 tsr; u16 tcnt; u16 gra; u16 grb; }itu01[2]; //2/3 have bra and brb struct Itu23 { u8 tcr; u8 tiorl; u8 tier; u8 tsr; u16 tcnt; u16 gra; u16 grb; u16 bra; u16 brb; }itu23[2]; struct Itu { //shared regs u8 tstr; u8 tsnc; u8 tmdr; u8 tfcr; u8 tocr; struct Channel { u8 tcr; u8 tior; u8 tier; u8 tsr; u16 tcnt; u16 gra; u16 grb; //buffer regs unused for channels 0-2 u16 bra; u16 brb; //not registers, implementation specific u8 tcnt_fraction; }channel[5]; }itu; u8 tocr; //dmac struct Dmac { struct channel { u32 sar; u32 dar; u16 tcr; u16 chcr; //implementation int is_active; }channel[4]; u16 dmaor; }dmac; //intc struct Intc { u16 ipra; u16 iprb; u16 iprc; u16 iprd; u16 ipre; u16 icr; }intc; //ubc struct Ubc { u32 bar; u32 bamr; u16 bbr; }ubc; //bsc struct Bsc { u16 bcr; u16 wcr1; u16 wcr2; u16 wcr3; u16 dcr; u16 pcr; u16 rcr; u16 rtcsr; u16 rtcnt; u16 rtcor; u8 tcsr; u8 tcnt; u8 rstcsr; }bsc; struct Wdt { u8 tcsr; u8 tcnt; u8 rstcsr; }wdt; u8 sbycr; //address space //port a u16 padr; //port b u16 pbdr; //pfc struct Pfc { u16 paior; u16 pbior; u16 pacr1; u16 pacr2; u16 pbcr1; u16 pbcr2; }pfc; //port c u16 pcdr; //pfc u16 cascr; //tpc struct Tpc { u8 tpmr; u8 tpcr; u8 nderb; u8 ndera; u8 ndrb; u8 ndra; }tpc; }; struct Sh1 { //u16 rom[0x8000];//64kb u8 ram[0x2000]; struct Onchip onchip; s32 cycles_remainder; }; extern struct Sh1 sh1_cxt; void sh1_exec(struct Sh1 * sh1, s32 cycles); void sh1_onchip_run_cycles(s32 cycles); void sh1_set_output_enable_rising_edge(); void sh1_set_output_enable_falling_edge(); void sh1_dma_exec(s32 cycles); // SCI SCR bits #define SCI_TIE 0x80 /* Transmit interrupt enable */ #define SCI_RIE 0x40 /* Receive interrupt enable */ #define SCI_TE 0x20 /* Transmit enable */ #define SCI_RE 0x10 /* Receive enable */ #define SCI_MPIE 0x08 /* Multiprocessor interrupt enable */ #define SCI_TEIE 0x04 /* Transmit end interrupt enable */ #define SCI_CKE1 0x02 /* Clock enable 1 */ #define SCI_CKE0 0x01 /* Clock enable 0 */ // SCI SSR bits #define SCI_TDRE 0x80 /* Transmit data register empty */ #define SCI_RDRF 0x40 /* Receive data register full */ #define SCI_ORER 0x20 /* Overrun error */ #define SCI_FER 0x10 /* Framing error */ #define SCI_PER 0x08 /* Parity error */ #define SCI_TEND 0x04 /* Transmit end */ #define SCI_MPB 0x02 /* Multiprocessor bit */ #define SCI_MPBT 0x01 /* Multiprocessor bit transfer */ #endif yabause-0.9.15/src/cdbase.c000644 001750 001750 00000114432 12755623101 017434 0ustar00guillaumeguillaume000000 000000 /* Copyright 2004-2008, 2013 Theo Berkau Copyright 2005 Joost Peters Copyright 2005-2006 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file cdbase.c \brief Dummy and ISO, BIN/CUE, MDS, CCD CD Interfaces */ #include #include #include #include #include #include "cdbase.h" #include "cs2.h" #include "error.h" #include "debug.h" #ifndef HAVE_STRICMP #ifdef HAVE_STRCASECMP #define stricmp strcasecmp #endif #endif #ifndef HAVE_WFOPEN static char * wcsdupstr(const wchar_t * path) { char * mbs; size_t len = wcstombs(NULL, path, 0); if (len == (size_t) -1) return NULL; mbs = malloc(len); len = wcstombs(mbs, path, len); if (len == (size_t) -1) { free(mbs); return NULL; } return mbs; } static FILE * _wfopen(const wchar_t *wpath, const wchar_t *wmode) { FILE * fd; char * path; char * mode; path = wcsdupstr(wpath); if (path == NULL) return NULL; mode = wcsdupstr(wmode); if (mode == NULL) { free(path); return NULL; } fd = fopen(path, mode); free(path); free(mode); return fd; } #endif ////////////////////////////////////////////////////////////////////////////// // Contains the Dummy and ISO CD Interfaces static int DummyCDInit(const char *); static void DummyCDDeInit(void); static int DummyCDGetStatus(void); static s32 DummyCDReadTOC(u32 *); static s32 DummyCDReadTOC10(CDInterfaceToc10 *); static int DummyCDReadSectorFAD(u32, void *); static void DummyCDReadAheadFAD(u32); CDInterface DummyCD = { CDCORE_DUMMY, "Dummy CD Drive", DummyCDInit, DummyCDDeInit, DummyCDGetStatus, DummyCDReadTOC, DummyCDReadTOC10, DummyCDReadSectorFAD, DummyCDReadAheadFAD, }; static int ISOCDInit(const char *); static void ISOCDDeInit(void); static int ISOCDGetStatus(void); static s32 ISOCDReadTOC(u32 *); static s32 ISOCDReadTOC10(CDInterfaceToc10 *); static int ISOCDReadSectorFAD(u32, void *); static void ISOCDReadAheadFAD(u32); CDInterface ISOCD = { CDCORE_ISO, "ISO-File Virtual Drive", ISOCDInit, ISOCDDeInit, ISOCDGetStatus, ISOCDReadTOC, ISOCDReadTOC10, ISOCDReadSectorFAD, ISOCDReadAheadFAD, }; ////////////////////////////////////////////////////////////////////////////// // Dummy Interface ////////////////////////////////////////////////////////////////////////////// static int DummyCDInit(UNUSED const char *cdrom_name) { // Initialization function. cdrom_name can be whatever you want it to // be. Obviously with some ports(e.g. the dreamcast port) you probably // won't even use it. return 0; } ////////////////////////////////////////////////////////////////////////////// static void DummyCDDeInit(void) { // Cleanup function. Enough said. } ////////////////////////////////////////////////////////////////////////////// static int DummyCDGetStatus(void) { // This function is called periodically to see what the status of the // drive is. // // Should return one of the following values: // 0 - CD Present, disc spinning // 1 - CD Present, disc not spinning // 2 - CD not present // 3 - Tray open // // If you really don't want to bother too much with this function, just // return status 0. Though it is kind of nice when the bios's cd // player, etc. recognizes when you've ejected the tray and popped in // another disc. return 0; } ////////////////////////////////////////////////////////////////////////////// static s32 DummyCDReadTOC(UNUSED u32 *TOC) { // The format of TOC is as follows: // TOC[0] - TOC[98] are meant for tracks 1-99. Each entry has the // following format: // bits 0 - 23: track FAD address // bits 24 - 27: track addr // bits 28 - 31: track ctrl // // Any Unused tracks should be set to 0xFFFFFFFF // // TOC[99] - Point A0 information // Uses the following format: // bits 0 - 7: PFRAME(should always be 0) // bits 7 - 15: PSEC(Program area format: 0x00 - CDDA or CDROM, // 0x10 - CDI, 0x20 - CDROM-XA) // bits 16 - 23: PMIN(first track's number) // bits 24 - 27: first track's addr // bits 28 - 31: first track's ctrl // // TOC[100] - Point A1 information // Uses the following format: // bits 0 - 7: PFRAME(should always be 0) // bits 7 - 15: PSEC(should always be 0) // bits 16 - 23: PMIN(last track's number) // bits 24 - 27: last track's addr // bits 28 - 31: last track's ctrl // // TOC[101] - Point A2 information // Uses the following format: // bits 0 - 23: leadout FAD address // bits 24 - 27: leadout's addr // bits 28 - 31: leadout's ctrl // // Special Note: To convert from LBA/LSN to FAD, add 150. return 0; } ////////////////////////////////////////////////////////////////////////////// static s32 DummyCDReadTOC10(UNUSED CDInterfaceToc10 *TOC) { return 0; } ////////////////////////////////////////////////////////////////////////////// static int DummyCDReadSectorFAD(UNUSED u32 FAD, void * buffer) { // This function is supposed to read exactly 1 -RAW- 2352-byte sector // at the specified FAD address to buffer. Should return true if // successful, false if there was an error. // // Special Note: To convert from FAD to LBA/LSN, minus 150. // // The whole process needed to be changed since I need more control // over sector detection, etc. Not to mention it means less work for // the porter since they only have to implement raw sector reading as // opposed to implementing mode 1, mode 2 form1/form2, -and- raw // sector reading. memset(buffer, 0, 2352); return 1; } ////////////////////////////////////////////////////////////////////////////// static void DummyCDReadAheadFAD(UNUSED u32 FAD) { // This function is called to tell the driver which sector (FAD // address) is expected to be read next. If the driver supports // read-ahead, it should start reading the given sector in the // background while the emulation continues, so that when the // sector is actually read with ReadSectorFAD() it'll be available // immediately. (Note that there's no guarantee this sector will // actually be requested--the emulated CD might be stopped before // the sector is read, for example.) // // This function should NOT block. If the driver can't perform // asynchronous reads (or you just don't want to bother handling // them), make this function a no-op and just read sectors // normally. } ////////////////////////////////////////////////////////////////////////////// // ISO Interface ////////////////////////////////////////////////////////////////////////////// typedef struct { u8 ctl_addr; u32 fad_start; u32 fad_end; u32 file_offset; u32 sector_size; FILE *fp; FILE *sub_fp; int file_size; int file_id; int interleaved_sub; } track_info_struct; typedef struct { u32 fad_start; u32 fad_end; track_info_struct *track; int track_num; } session_info_struct; typedef struct { int session_num; session_info_struct *session; } disc_info_struct; #pragma pack(push, 1) typedef struct { u8 signature[16]; u8 version[2]; u16 medium_type; u16 session_count; u16 unused1[2]; u16 bca_length; u32 unused2[2]; u32 bca_offset; u32 unused3[6]; u32 disk_struct_offset; u32 unused4[3]; u32 sessions_blocks_offset; u32 dpm_blocks_offset; u32 enc_key_offset; } mds_header_struct; typedef struct { s32 session_start; s32 session_end; u16 session_number; u8 total_blocks; u8 leadin_blocks; u16 first_track; u16 last_track; u32 unused; u32 track_blocks_offset; } mds_session_struct; typedef struct { u8 mode; u8 subchannel_mode; u8 addr_ctl; u8 unused1; u8 track_num; u32 unused2; u8 m; u8 s; u8 f; u32 extra_offset; u16 sector_size; u8 unused3[18]; u32 start_sector; u64 start_offset; u8 session; u8 unused4[3]; u32 footer_offset; u8 unused5[24]; } mds_track_struct; typedef struct { u32 filename_offset; u32 is_widechar; u32 unused1; u32 unused2; } mds_footer_struct; #pragma pack(pop) #define CCD_MAX_SECTION 20 #define CCD_MAX_NAME 30 #define CCD_MAX_VALUE 20 typedef struct { char section[CCD_MAX_SECTION]; char name[CCD_MAX_NAME]; char value[CCD_MAX_VALUE]; } ccd_dict_struct; typedef struct { ccd_dict_struct *dict; int num_dict; } ccd_struct; static const s8 syncHdr[12] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 }; enum IMG_TYPE { IMG_NONE, IMG_ISO, IMG_BINCUE, IMG_MDS, IMG_CCD, IMG_NRG }; enum IMG_TYPE imgtype = IMG_ISO; static u32 isoTOC[102]; static CDInterfaceToc10 isoTOC10[102]; int isoTOCnum=0; static disc_info_struct disc; #define MSF_TO_FAD(m,s,f) ((m * 4500) + (s * 75) + f) ////////////////////////////////////////////////////////////////////////////// static int LoadBinCue(const char *cuefilename, FILE *iso_file) { long size; char *temp_buffer, *temp_buffer2; unsigned int track_num; unsigned int indexnum, min, sec, frame; unsigned int pregap=0; char *p, *p2; track_info_struct trk[100]; int file_size; int i; FILE * bin_file; int matched = 0; memset(trk, 0, sizeof(trk)); disc.session_num = 1; disc.session = malloc(sizeof(session_info_struct) * disc.session_num); if (disc.session == NULL) { YabSetError(YAB_ERR_MEMORYALLOC, NULL); return -1; } fseek(iso_file, 0, SEEK_END); size = ftell(iso_file); if(size <= 0) { YabSetError(YAB_ERR_FILEREAD, cuefilename); return -1; } fseek(iso_file, 0, SEEK_SET); // Allocate buffer with enough space for reading cue if ((temp_buffer = (char *)calloc(size, 1)) == NULL) return -1; // Skip image filename if (fscanf(iso_file, "FILE \"%*[^\"]\" %*s\r\n") == EOF) { free(temp_buffer); return -1; } // Time to generate TOC for (;;) { // Retrieve a line in cue if (fscanf(iso_file, "%s", temp_buffer) == EOF) break; // Figure out what it is if (strncmp(temp_buffer, "TRACK", 5) == 0) { // Handle accordingly if (fscanf(iso_file, "%d %[^\r\n]\r\n", &track_num, temp_buffer) == EOF) break; if (strncmp(temp_buffer, "MODE1", 5) == 0 || strncmp(temp_buffer, "MODE2", 5) == 0) { // Figure out the track sector size trk[track_num-1].sector_size = atoi(temp_buffer + 6); trk[track_num-1].ctl_addr = 0x41; } else if (strncmp(temp_buffer, "AUDIO", 5) == 0) { // Update toc entry trk[track_num-1].sector_size = 2352; trk[track_num-1].ctl_addr = 0x01; } } else if (strncmp(temp_buffer, "INDEX", 5) == 0) { // Handle accordingly if (fscanf(iso_file, "%d %d:%d:%d\r\n", &indexnum, &min, &sec, &frame) == EOF) break; if (indexnum == 1) { // Update toc entry trk[track_num-1].fad_start = (MSF_TO_FAD(min, sec, frame) + pregap + 150); trk[track_num-1].file_offset = MSF_TO_FAD(min, sec, frame) * trk[track_num-1].sector_size; } } else if (strncmp(temp_buffer, "PREGAP", 6) == 0) { if (fscanf(iso_file, "%d:%d:%d\r\n", &min, &sec, &frame) == EOF) break; pregap += MSF_TO_FAD(min, sec, frame); } else if (strncmp(temp_buffer, "POSTGAP", 7) == 0) { if (fscanf(iso_file, "%d:%d:%d\r\n", &min, &sec, &frame) == EOF) break; } else if (strncmp(temp_buffer, "FILE", 4) == 0) { YabSetError(YAB_ERR_OTHER, "Unsupported cue format"); free(temp_buffer); return -1; } } trk[track_num].file_offset = 0; trk[track_num].fad_start = 0xFFFFFFFF; // Go back, retrieve image filename fseek(iso_file, 0, SEEK_SET); matched = fscanf(iso_file, "FILE \"%[^\"]\" %*s\r\n", temp_buffer); // Now go and open up the image file, figure out its size, etc. if ((bin_file = fopen(temp_buffer, "rb")) == NULL) { // Ok, exact path didn't work. Let's trim the path and try opening the // file from the same directory as the cue. // find the start of filename p = temp_buffer; for (;;) { if (strcspn(p, "/\\") == strlen(p)) break; p += strcspn(p, "/\\") + 1; } // append directory of cue file with bin filename if ((temp_buffer2 = (char *)calloc(strlen(cuefilename) + strlen(p) + 1, 1)) == NULL) { free(temp_buffer); return -1; } // find end of path p2 = (char *)cuefilename; for (;;) { if (strcspn(p2, "/\\") == strlen(p2)) break; p2 += strcspn(p2, "/\\") + 1; } // Make sure there was at least some kind of path, otherwise our // second check is pretty useless if (cuefilename == p2 && temp_buffer == p) { free(temp_buffer); free(temp_buffer2); return -1; } strncpy(temp_buffer2, cuefilename, p2 - cuefilename); strcat(temp_buffer2, p); // Let's give it another try bin_file = fopen(temp_buffer2, "rb"); free(temp_buffer2); if (bin_file == NULL) { YabSetError(YAB_ERR_FILENOTFOUND, temp_buffer); free(temp_buffer); return -1; } } fseek(bin_file, 0, SEEK_END); file_size = ftell(bin_file); fseek(bin_file, 0, SEEK_SET); for (i = 0; i < track_num; i++) { trk[i].fad_end = trk[i+1].fad_start-1; trk[i].file_id = 0; trk[i].fp = bin_file; trk[i].file_size = file_size; } trk[track_num-1].fad_end = trk[track_num-1].fad_start+(file_size-trk[track_num-1].file_offset)/trk[track_num-1].sector_size; disc.session[0].fad_start = 150; disc.session[0].fad_end = trk[track_num-1].fad_end; disc.session[0].track_num = track_num; disc.session[0].track = malloc(sizeof(track_info_struct) * disc.session[0].track_num); if (disc.session[0].track == NULL) { YabSetError(YAB_ERR_MEMORYALLOC, NULL); free(disc.session); disc.session = NULL; return -1; } memcpy(disc.session[0].track, trk, track_num * sizeof(track_info_struct)); // buffer is no longer needed free(temp_buffer); fclose(iso_file); return 0; } ////////////////////////////////////////////////////////////////////////////// int LoadMDSTracks(const char *mds_filename, FILE *iso_file, mds_session_struct *mds_session, session_info_struct *session) { int i; int track_num=0; u32 fad_end = 0; session->track = malloc(sizeof(track_info_struct) * mds_session->last_track); if (session->track == NULL) { YabSetError(YAB_ERR_MEMORYALLOC, NULL); return -1; } memset(session->track, 0, sizeof(track_info_struct) * mds_session->last_track); for (i = 0; i < mds_session->total_blocks; i++) { mds_track_struct track; FILE *fp=NULL; int file_size = 0; fseek(iso_file, mds_session->track_blocks_offset + i * sizeof(mds_track_struct), SEEK_SET); if (fread(&track, 1, sizeof(mds_track_struct), iso_file) != sizeof(mds_track_struct)) { YabSetError(YAB_ERR_FILEREAD, mds_filename); free(session->track); return -1; } if (track.track_num == 0xA2) fad_end = MSF_TO_FAD(track.m, track.s, track.f); if (!track.extra_offset) continue; if (track.footer_offset) { mds_footer_struct footer; int found_dupe=0; int j; // Make sure we haven't already opened file already for (j = 0; j < track_num; j++) { if (track.footer_offset == session->track[j].file_id) { found_dupe = 1; break; } } if (found_dupe) { fp = session->track[j].fp; file_size = session->track[j].file_size; } else { fseek(iso_file, track.footer_offset, SEEK_SET); if (fread(&footer, 1, sizeof(mds_footer_struct), iso_file) != sizeof(mds_footer_struct)) { YabSetError(YAB_ERR_FILEREAD, mds_filename); free(session->track); return -1; } fseek(iso_file, footer.filename_offset, SEEK_SET); if (footer.is_widechar) { wchar_t filename[512]; wchar_t img_filename[512]; memset(img_filename, 0, 512 * sizeof(wchar_t)); if (fwscanf(iso_file, L"%512c", img_filename) != 1) { YabSetError(YAB_ERR_FILEREAD, mds_filename); free(session->track); return -1; } if (wcsncmp(img_filename, L"*.", 2) == 0) { wchar_t *ext; swprintf(filename, sizeof(filename)/sizeof(wchar_t), L"%S", mds_filename); ext = wcsrchr(filename, '.'); wcscpy(ext, img_filename+1); } else wcscpy(filename, img_filename); fp = _wfopen(filename, L"rb"); } else { char filename[512]; char img_filename[512]; memset(img_filename, 0, 512); if (fscanf(iso_file, "%512c", img_filename) != 1) { YabSetError(YAB_ERR_FILEREAD, mds_filename); free(session->track); return -1; } if (strncmp(img_filename, "*.", 2) == 0) { char *ext; size_t mds_filename_len = strlen(mds_filename); if (mds_filename_len >= 512) { YabSetError(YAB_ERR_FILEREAD, mds_filename); free(session->track); return -1; } strcpy(filename, mds_filename); ext = strrchr(filename, '.'); strcpy(ext, img_filename+1); } else strcpy(filename, img_filename); fp = fopen(filename, "rb"); } if (fp == NULL) { YabSetError(YAB_ERR_FILEREAD, mds_filename); free(session->track); return -1; } fseek(fp, 0, SEEK_END); file_size = ftell(fp); fseek(fp, 0, SEEK_SET); } } session->track[track_num].ctl_addr = (((track.addr_ctl << 4) | (track.addr_ctl >> 4)) & 0xFF); session->track[track_num].fad_start = track.start_sector+150; if (track_num > 0) session->track[track_num-1].fad_end = session->track[track_num].fad_start; session->track[track_num].file_offset = track.start_offset; session->track[track_num].sector_size = track.sector_size; session->track[track_num].fp = fp; session->track[track_num].file_size = file_size; session->track[track_num].file_id = track.footer_offset; session->track[track_num].interleaved_sub = track.subchannel_mode != 0 ? 1 : 0; track_num++; } session->track[track_num-1].fad_end = fad_end; session->fad_start = session->track[0].fad_start; session->fad_end = fad_end; session->track_num = track_num; return 0; } ////////////////////////////////////////////////////////////////////////////// static int LoadMDS(const char *mds_filename, FILE *iso_file) { s32 i; mds_header_struct header; fseek(iso_file, 0, SEEK_SET); if (fread((void *)&header, 1, sizeof(mds_header_struct), iso_file) != sizeof(mds_header_struct)) { YabSetError(YAB_ERR_FILEREAD, mds_filename); return -1; } else if (memcmp(&header.signature, "MEDIA DESCRIPTOR", sizeof(header.signature))) { YabSetError(YAB_ERR_OTHER, "Bad MDS header"); return -1; } else if (header.version[0] > 1) { YabSetError(YAB_ERR_OTHER, "Unsupported MDS version"); return -1; } if (header.medium_type & 0x10) { // DVD's aren't supported, not will they ever be YabSetError(YAB_ERR_OTHER, "DVD's aren't supported"); return -1; } disc.session_num = header.session_count; disc.session = malloc(sizeof(session_info_struct) * disc.session_num); if (disc.session == NULL) { YabSetError(YAB_ERR_MEMORYALLOC, NULL); return -1; } for (i = 0; i < header.session_count; i++) { mds_session_struct session; fseek(iso_file, header.sessions_blocks_offset + i * sizeof(mds_session_struct), SEEK_SET); if (fread(&session, 1, sizeof(mds_session_struct), iso_file) != sizeof(mds_session_struct)) { free(disc.session); YabSetError(YAB_ERR_FILEREAD, mds_filename); return -1; } if (LoadMDSTracks(mds_filename, iso_file, &session, &disc.session[i]) != 0) return -1; } fclose(iso_file); return 0; } ////////////////////////////////////////////////////////////////////////////// static int LoadISO(FILE *iso_file) { track_info_struct *track; disc.session_num = 1; disc.session = malloc(sizeof(session_info_struct) * disc.session_num); if (disc.session == NULL) { YabSetError(YAB_ERR_MEMORYALLOC, NULL); return -1; } disc.session[0].fad_start = 150; disc.session[0].track_num = 1; disc.session[0].track = malloc(sizeof(track_info_struct) * disc.session[0].track_num); if (disc.session[0].track == NULL) { YabSetError(YAB_ERR_MEMORYALLOC, NULL); free(disc.session); disc.session = NULL; return -1; } memset(disc.session[0].track, 0, sizeof(track_info_struct) * disc.session[0].track_num); track = disc.session[0].track; track->ctl_addr = 0x41; track->fad_start = 150; track->file_offset = 0; track->fp = iso_file; fseek(iso_file, 0, SEEK_END); track->file_size = ftell(iso_file); track->file_id = 0; if (0 == (track->file_size % 2048)) track->sector_size = 2048; else if (0 == (track->file_size % 2352)) track->sector_size = 2352; else { YabSetError(YAB_ERR_OTHER, "Unsupported CD image!\n"); return -1; } disc.session[0].fad_end = track->fad_end = disc.session[0].fad_start + (track->file_size / track->sector_size); return 0; } ////////////////////////////////////////////////////////////////////////////// char* StripPreSuffixWhitespace(char* string) { char* p; for (;;) { if (string[0] == 0 || !isspace(string[0])) break; string++; } if (strlen(string) == 0) return string; p = string+strlen(string)-1; for (;;) { if (p <= string || !isspace(p[0])) { p[1] = '\0'; break; } p--; } return string; } ////////////////////////////////////////////////////////////////////////////// int LoadParseCCD(FILE *ccd_fp, ccd_struct *ccd) { char text[60], section[CCD_MAX_SECTION], old_name[CCD_MAX_NAME] = ""; char * start, *end, *name, *value; int lineno = 0, error = 0, max_size = 100; ccd->dict = (ccd_dict_struct *)malloc(sizeof(ccd_dict_struct)*max_size); if (ccd->dict == NULL) return -1; ccd->num_dict = 0; // Read CCD file while (fgets(text, sizeof(text), ccd_fp) != NULL) { lineno++; start = StripPreSuffixWhitespace(text); if (start[0] == '[') { // Section end = strchr(start+1, ']'); if (end == NULL) { // ] missing from section error = lineno; } else { end[0] = '\0'; memset(section, 0, sizeof(section)); strncpy(section, start + 1, sizeof(section)); old_name[0] = '\0'; } } else if (start[0]) { // Name/Value pair end = strchr(start, '='); if (end) { end[0] = '\0'; name = StripPreSuffixWhitespace(start); value = StripPreSuffixWhitespace(end + 1); memset(old_name, 0, sizeof(old_name)); strncpy(old_name, name, sizeof(old_name)); if (ccd->num_dict+1 > max_size) { max_size *= 2; ccd->dict = realloc(ccd->dict, sizeof(ccd_dict_struct)*max_size); if (ccd->dict == NULL) { free(ccd->dict); return -2; } } strcpy(ccd->dict[ccd->num_dict].section, section); strcpy(ccd->dict[ccd->num_dict].name, name); strcpy(ccd->dict[ccd->num_dict].value, value); ccd->num_dict++; } else error = lineno; } if (error) break; } if (error) { free(ccd->dict); ccd->num_dict = 0; } return error; } ////////////////////////////////////////////////////////////////////////////// static int GetIntCCD(ccd_struct *ccd, char *section, char *name) { int i; for (i = 0; i < ccd->num_dict; i++) { if (stricmp(ccd->dict[i].section, section) == 0 && stricmp(ccd->dict[i].name, name) == 0) return strtol(ccd->dict[i].value, NULL, 0); } return -1; } ////////////////////////////////////////////////////////////////////////////// static int LoadCCD(const char *ccd_filename, FILE *iso_file) { int i; ccd_struct ccd; int num_toc; char img_filename[512]; char *ext; FILE *fp; size_t ccd_filename_len = strlen(ccd_filename); if (ccd_filename_len >= 512) { YabSetError(YAB_ERR_FILEREAD, ccd_filename); return -1; } strcpy(img_filename, ccd_filename); ext = strrchr(img_filename, '.'); strcpy(ext, ".img"); fp = fopen(img_filename, "rb"); if (fp == NULL) { YabSetError(YAB_ERR_FILEREAD, img_filename); return -1; } fseek(iso_file, 0, SEEK_SET); // Load CCD file as dictionary if (LoadParseCCD(iso_file, &ccd)) { fclose(fp); YabSetError(YAB_ERR_FILEREAD, ccd_filename); return -1; } num_toc = GetIntCCD(&ccd, "DISC", "TocEntries"); disc.session_num = GetIntCCD(&ccd, "DISC", "Sessions"); if (disc.session_num != 1) { fclose(fp); YabSetError(YAB_ERR_OTHER, "Sessions more than 1 are unsupported"); return -1; } disc.session = malloc(sizeof(session_info_struct) * disc.session_num); if (disc.session == NULL) { fclose(fp); free(ccd.dict); YabSetError(YAB_ERR_MEMORYALLOC, NULL); return -1; } if (GetIntCCD(&ccd, "DISC", "DataTracksScrambled")) { fclose(fp); free(ccd.dict); free(disc.session); YabSetError(YAB_ERR_OTHER, "CCD Scrambled Tracks not supported"); return -1; } isoTOCnum = num_toc; // Find track number and allocate for (i = 0; i < num_toc; i++) { char sect_name[64]; int point; sprintf(sect_name, "Entry %d", i); isoTOC10[i].ctrladr = (GetIntCCD(&ccd, sect_name, "Control") << 4) | GetIntCCD(&ccd, sect_name, "ADR"); isoTOC10[i].tno = GetIntCCD(&ccd, sect_name, "TrackNo"); isoTOC10[i].point = GetIntCCD(&ccd, sect_name, "Point"); isoTOC10[i].min = GetIntCCD(&ccd, sect_name, "AMin"); isoTOC10[i].sec = 2; isoTOC10[i].frame = 0; isoTOC10[i].zero = GetIntCCD(&ccd, sect_name, "Zero"); isoTOC10[i].pmin = GetIntCCD(&ccd, sect_name, "PMin"); isoTOC10[i].psec = GetIntCCD(&ccd, sect_name, "PSec"); isoTOC10[i].pframe = GetIntCCD(&ccd, sect_name, "PFrame"); point = GetIntCCD(&ccd, sect_name, "Point"); if (point == 0xA1) { int ses = GetIntCCD(&ccd, sect_name, "Session"); disc.session[ses-1].fad_start = 150; disc.session[ses-1].track_num=GetIntCCD(&ccd, sect_name, "PMin");; disc.session[ses-1].track = (track_info_struct *)malloc(disc.session[ses-1].track_num * sizeof(track_info_struct)); if (disc.session[ses-1].track == NULL) { fclose(fp); free(ccd.dict); free(disc.session); YabSetError(YAB_ERR_MEMORYALLOC, NULL); return -1; } memset(disc.session[ses-1].track, 0, disc.session[ses-1].track_num * sizeof(track_info_struct)); } } // Load TOC for (i = 0; i < num_toc; i++) { char sect_name[64]; int ses, point, adr, control, trackno, amin, asec, aframe; int alba, zero, pmin, psec, pframe, plba; sprintf(sect_name, "Entry %d", i); ses = GetIntCCD(&ccd, sect_name, "Session"); point = GetIntCCD(&ccd, sect_name, "Point"); adr = GetIntCCD(&ccd, sect_name, "ADR"); control = GetIntCCD(&ccd, sect_name, "Control"); trackno = GetIntCCD(&ccd, sect_name, "TrackNo"); amin = GetIntCCD(&ccd, sect_name, "AMin"); asec = GetIntCCD(&ccd, sect_name, "ASec"); aframe = GetIntCCD(&ccd, sect_name, "AFrame"); alba = GetIntCCD(&ccd, sect_name, "ALBA"); zero = GetIntCCD(&ccd, sect_name, "Zero"); pmin = GetIntCCD(&ccd, sect_name, "PMin"); psec = GetIntCCD(&ccd, sect_name, "PSec"); pframe = GetIntCCD(&ccd, sect_name, "PFrame"); plba = GetIntCCD(&ccd, sect_name, "PLBA"); if(point >= 1 && point <= 99) { track_info_struct *track=&disc.session[ses-1].track[point-1]; track->ctl_addr = (control << 4) | adr; track->fad_start = MSF_TO_FAD(pmin, psec, pframe); if (point >= 2) disc.session[ses-1].track[point-2].fad_end = track->fad_start-1; track->file_offset = plba*2352; track->sector_size = 2352; track->fp = fp; track->file_size = (track->fad_end+1-track->fad_start)*2352; track->file_id = 0; track->interleaved_sub = 0; } else if (point == 0xA2) { disc.session[ses-1].fad_end = MSF_TO_FAD(pmin, psec, pframe); disc.session[ses-1].track[disc.session[ses-1].track_num-1].fad_end = disc.session[ses-1].fad_end; } } fclose(iso_file); return 0; } ////////////////////////////////////////////////////////////////////////////// void BuildTOC() { int i; session_info_struct *session=&disc.session[0]; for (i = 0; i < session->track_num; i++) { track_info_struct *track=&disc.session[0].track[i]; isoTOC[i] = (track->ctl_addr << 24) | track->fad_start; } isoTOC[99] = (isoTOC[0] & 0xFF000000) | 0x010000; isoTOC[100] = (isoTOC[session->track_num - 1] & 0xFF000000) | (session->track_num << 16); isoTOC[101] = (isoTOC[session->track_num - 1] & 0xFF000000) | session->fad_end; } ////////////////////////////////////////////////////////////////////////////// void BuildTOC10() { int i; session_info_struct *session=&disc.session[0]; for (i = 0; i < session->track_num; i++) { isoTOC10[3+i].ctrladr = session->track[i].ctl_addr; isoTOC10[3+i].tno = 0; isoTOC10[3+i].point = i+1; isoTOC10[3+i].min = 0; isoTOC10[3+i].sec = 2; isoTOC10[3+i].frame = 0; isoTOC10[3+i].zero = 0; Cs2FADToMSF(session->track[i].fad_start, &isoTOC10[3+i].pmin, &isoTOC10[3+i].psec, &isoTOC10[3+i].pframe); } isoTOC10[0].ctrladr = isoTOC10[3].ctrladr; isoTOC10[0].tno = 0; isoTOC10[0].point = 0xA0; isoTOC10[0].min = 0; isoTOC10[0].sec = 2; isoTOC10[0].frame = 0; isoTOC10[0].zero = 0; isoTOC10[0].pmin = 1; isoTOC10[0].psec = 0; isoTOC10[0].pframe = 0; isoTOC10[1].ctrladr = isoTOC10[3+session->track_num-1].ctrladr; isoTOC10[1].tno = 0; isoTOC10[1].point = 0xA1; isoTOC10[1].min = 0; isoTOC10[1].sec = 2; isoTOC10[1].frame = 0; isoTOC10[1].zero = 0; isoTOC10[1].pmin = session->track_num; isoTOC10[1].psec = 0; isoTOC10[1].pframe = 0; isoTOC10[2].ctrladr = isoTOC10[1].ctrladr; isoTOC10[2].tno = 0; isoTOC10[2].point = 0xA2; isoTOC10[2].min = 0; isoTOC10[2].sec = 2; isoTOC10[2].frame = 0; isoTOC10[2].zero = 0; Cs2FADToMSF(session->fad_end, &isoTOC10[2].pmin, &isoTOC10[2].psec, &isoTOC10[2].pframe); isoTOCnum = 3+session->track_num; } ////////////////////////////////////////////////////////////////////////////// static int ISOCDInit(const char * iso) { char header[6]; char *ext; int ret; FILE *iso_file; size_t num_read = 0; memset(isoTOC, 0xFF, 0xCC * 2); memset(&disc, 0, sizeof(disc)); if (!iso) return -1; if (!(iso_file = fopen(iso, "rb"))) { YabSetError(YAB_ERR_FILENOTFOUND, (char *)iso); return -1; } num_read = fread((void *)header, 1, 6, iso_file); ext = strrchr(iso, '.'); // Figure out what kind of image format we're dealing with if (stricmp(ext, ".CUE") == 0 && strncmp(header, "FILE \"", 6) == 0) { // It's a BIN/CUE imgtype = IMG_BINCUE; ret = LoadBinCue(iso, iso_file); } else if (stricmp(ext, ".MDS") == 0 && strncmp(header, "MEDIA ", sizeof(header)) == 0) { // It's a MDS imgtype = IMG_MDS; ret = LoadMDS(iso, iso_file); } else if (stricmp(ext, ".CCD") == 0) { // It's a CCD imgtype = IMG_CCD; ret = LoadCCD(iso, iso_file); } else { // Assume it's an ISO file imgtype = IMG_ISO; ret = LoadISO(iso_file); } if (ret != 0) { imgtype = IMG_NONE; if (iso_file) fclose(iso_file); iso_file = NULL; return -1; } BuildTOC(); if (imgtype != IMG_CCD) BuildTOC10(); return 0; } ////////////////////////////////////////////////////////////////////////////// static void ISOCDDeInit(void) { int i, j, k; if (disc.session) { for (i = 0; i < disc.session_num; i++) { if (disc.session[i].track) { for (j = 0; j < disc.session[i].track_num; j++) { if (disc.session[i].track[j].fp) { fclose(disc.session[i].track[j].fp); // Make sure we don't close the same file twice for (k = j+1; k < disc.session[i].track_num; k++) { if (disc.session[i].track[j].file_id == disc.session[i].track[k].file_id) disc.session[i].track[k].fp = NULL; } } } free(disc.session[i].track); } } free(disc.session); } } ////////////////////////////////////////////////////////////////////////////// static int ISOCDGetStatus(void) { return disc.session_num > 0 ? 0 : 2; } ////////////////////////////////////////////////////////////////////////////// static s32 ISOCDReadTOC(u32 * TOC) { memcpy(TOC, isoTOC, 0xCC * 2); return (0xCC * 2); } ////////////////////////////////////////////////////////////////////////////// static s32 ISOCDReadTOC10(CDInterfaceToc10 *TOC) { memcpy(TOC, isoTOC10, 102 * sizeof(CDInterfaceToc10)); return isoTOCnum; } ////////////////////////////////////////////////////////////////////////////// static int ISOCDReadSectorFAD(u32 FAD, void *buffer) { int i,j; size_t num_read = 0; track_info_struct *track=NULL; assert(disc.session); memset(buffer, 0, 2448); for (i = 0; i < disc.session_num; i++) { for (j = 0; j < disc.session[i].track_num; j++) { if (FAD >= disc.session[i].track[j].fad_start && FAD <= disc.session[i].track[j].fad_end) { track = &disc.session[i].track[j]; break; } } } if (track == NULL) { CDLOG("Warning: Sector not found in track list"); return 0; } fseek(track->fp, track->file_offset + (FAD-track->fad_start) * track->sector_size, SEEK_SET); if (track->sub_fp) fseek(track->sub_fp, track->file_offset + (FAD-track->fad_start) * 96, SEEK_SET); if (track->sector_size == 2448) { if (!track->interleaved_sub) { if (track->sub_fp) { num_read = fread(buffer, 2352, 1, track->fp); num_read = fread((char *)buffer + 2352, 96, 1, track->sub_fp); } else num_read = fread(buffer, 2448, 1, track->fp); } else { const u16 deint_offsets[] = { 0, 66, 125, 191, 100, 50, 150, 175, 8, 33, 58, 83, 108, 133, 158, 183, 16, 41, 25, 91, 116, 141, 166, 75, 24, 90, 149, 215, 124, 74, 174, 199, 32, 57, 82, 107, 132, 157, 182, 207, 40, 65, 49, 115, 140, 165, 190, 99, 48, 114, 173, 239, 148, 98, 198, 223, 56, 81, 106, 131, 156, 181, 206, 231, 64, 89, 73, 139, 164, 189, 214, 123, 72, 138, 197, 263, 172, 122, 222, 247, 80, 105, 130, 155, 180, 205, 230, 255, 88, 113, 97, 163, 188, 213, 238, 147 }; u8 subcode_buffer[96 * 3]; num_read = fread(buffer, 2352, 1, track->fp); num_read = fread(subcode_buffer, 96, 1, track->fp); fseek(track->fp, 2352, SEEK_CUR); num_read = fread(subcode_buffer + 96, 96, 1, track->fp); fseek(track->fp, 2352, SEEK_CUR); num_read = fread(subcode_buffer + 192, 96, 1, track->fp); for (i = 0; i < 96; i++) ((u8 *)buffer)[2352+i] = subcode_buffer[deint_offsets[i]]; } } else if (track->sector_size == 2352) { // Generate subcodes here num_read = fread(buffer, 2352, 1, track->fp); } else if (track->sector_size == 2048) { memcpy(buffer, syncHdr, 12); num_read = fread((char *)buffer + 0x10, 2048, 1, track->fp); } return 1; } ////////////////////////////////////////////////////////////////////////////// static void ISOCDReadAheadFAD(UNUSED u32 FAD) { // No-op } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/macjoy.c000644 001750 001750 00000036551 12755623101 017502 0ustar00guillaumeguillaume000000 000000 /* This file was imported form CrabEmu ( http://crabemu.sourceforge.net/ ) -- A Sega Master System emulator for Mac OS X (among other targets). The rest of the file is left intact from CrabEmu to make things easier if this were to be upgraded in the future. */ /* This file is part of CrabEmu. Copyright (C) 2008 Lawrence Sebald CrabEmu is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. CrabEmu 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 CrabEmu; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include "macjoy.h" static int joy_count = 0; static joydata_t *joys = NULL; static void joy_find_elements(CFMutableDictionaryRef prop, joydata_t *joy); /* Compare two buttons for sorting. */ static int joy_cmp_buttons(const void *e1, const void *e2) { const joy_elemdata_t *b1 = (const joy_elemdata_t *)e1; const joy_elemdata_t *b2 = (const joy_elemdata_t *)e2; return b1->number < b2->number ? -1 : (b1->number > b2->number ? 1 : 0); } /* Get the io_iterator_t object needed to iterate through the list of HID devices. */ static void joy_get_iterator(mach_port_t port, io_iterator_t *iter) { CFMutableDictionaryRef d; IOReturn rv; /* Create a matching dictionary that will be used to search the device tree. */ if(!(d = IOServiceMatching(kIOHIDDeviceKey))) { return; } /* Get all matching devices from IOKit. */ rv = IOServiceGetMatchingServices(port, d, iter); if(rv != kIOReturnSuccess || !(*iter)) { return; } } /* Create the interface needed to do stuff with the device. */ static int joy_create_interface(io_object_t hidDevice, joydata_t *joy) { IOCFPlugInInterface **plugin; SInt32 score = 0; /* Create the plugin that we will use to actually get the device interface that is needed. */ if(IOCreatePlugInInterfaceForService(hidDevice, kIOHIDDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &score) != kIOReturnSuccess) { return 0; } /* Grab the device interface from the plugin. */ if((*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (LPVOID)&joy->iface) != S_OK) { return 0; } /* The plugin has done all it needs to, release it. */ (*plugin)->Release(plugin); return 1; } /* Fill in a elemdata_t structure with information about the given physical element. */ static void joy_fill_elem(CFTypeRef elem, joy_elemdata_t *ptr) { CFTypeRef ref; int num; memset(ptr, 0, sizeof(joy_elemdata_t)); /* Grab the element cookie. */ if((ref = CFDictionaryGetValue(elem, CFSTR(kIOHIDElementCookieKey)))) { if(CFNumberGetValue(ref, kCFNumberIntType, &num)) { ptr->cookie = (IOHIDElementCookie)num; } } /* Grab the element's minimum value. */ if((ref = CFDictionaryGetValue(elem, CFSTR(kIOHIDElementMinKey)))) { if(CFNumberGetValue(ref, kCFNumberIntType, &num)) { ptr->min = num; } } /* Grab the element's maximum value. */ if((ref = CFDictionaryGetValue(elem, CFSTR(kIOHIDElementMaxKey)))) { if(CFNumberGetValue(ref, kCFNumberIntType, &num)) { ptr->max = num; } } } /* Callback function to handle each sub-element of the controller class. */ static void joy_elem_array_hnd(const void *value, void *parameter) { CFTypeRef elem = (CFTypeRef)value; CFTypeID t = CFGetTypeID(value); joydata_t *joy = (joydata_t *)parameter; long elemType, elemPage, elemUsage; CFTypeRef type, page, usage; void *ptr; int et; /* Make sure we're dealing with a dictionary. */ if(t == CFDictionaryGetTypeID()) { /* Grab the type of the element. */ type = CFDictionaryGetValue(elem, CFSTR(kIOHIDElementTypeKey)); if(!type) { return; } /* Grab the HID usage page. */ page = CFDictionaryGetValue(elem, CFSTR(kIOHIDElementUsagePageKey)); if(!page) { return; } /* Grab the HID usage type. */ usage = CFDictionaryGetValue(elem, CFSTR(kIOHIDElementUsageKey)); if(!usage) { return; } /* Get the integer values from the data grabbed above. */ if(!CFNumberGetValue(type, kCFNumberLongType, &elemType)) { return; } if(!CFNumberGetValue(page, kCFNumberLongType, &elemPage)) { return; } if(!CFNumberGetValue(usage, kCFNumberLongType, &elemUsage)) { return; } /* If the element is listed as a button, axis, or misc input, check what it actually is. */ if(elemType == kIOHIDElementTypeInput_Button || elemType == kIOHIDElementTypeInput_Axis || elemType == kIOHIDElementTypeInput_Misc) { switch(elemPage) { case kHIDPage_Button: ptr = realloc(joy->buttons, (joy->buttons_count + 1) * sizeof(joy_elemdata_t)); if(ptr) { joy->buttons = (joy_elemdata_t *)ptr; joy_fill_elem(elem, joy->buttons + joy->buttons_count); joy->buttons[joy->buttons_count].number = elemUsage; ++joy->buttons_count; } break; case kHIDPage_GenericDesktop: switch(elemUsage) { case kHIDUsage_GD_X: et = JOY_TYPE_X_AXIS; goto axis; case kHIDUsage_GD_Y: et = JOY_TYPE_Y_AXIS; goto axis; case kHIDUsage_GD_Z: et = JOY_TYPE_Z_AXIS; goto axis; case kHIDUsage_GD_Rx: et = JOY_TYPE_X2_AXIS; goto axis; case kHIDUsage_GD_Ry: et = JOY_TYPE_Y2_AXIS; goto axis; case kHIDUsage_GD_Rz: et = JOY_TYPE_Z2_AXIS; axis: ptr = realloc(joy->axes, (joy->axes_count + 1) * sizeof(joy_elemdata_t)); if(ptr) { joy->axes = (joy_elemdata_t *)ptr; joy_fill_elem(elem, joy->axes + joy->axes_count); joy->axes[joy->axes_count].type = et; ++joy->axes_count; } break; case kHIDUsage_GD_Hatswitch: ptr = realloc(joy->hats, (joy->hats_count + 1) * sizeof(joy_elemdata_t)); if(ptr) { joy->hats = (joy_elemdata_t *)ptr; joy_fill_elem(elem, joy->hats + joy->hats_count); ++joy->hats_count; } break; } break; } } /* If we've found another element array, effectively recurse. */ else if(elemType == kIOHIDElementTypeCollection) { joy_find_elements((CFMutableDictionaryRef)elem, joy); } } } /* Process all the sub-elements of a given property list. */ static void joy_find_elements(CFMutableDictionaryRef prop, joydata_t *joy) { CFTypeRef elem; CFTypeID type; if((elem = CFDictionaryGetValue(prop, CFSTR(kIOHIDElementKey)))) { type = CFGetTypeID(elem); if(type == CFArrayGetTypeID()) { /* Call our function on each element of the array. */ CFRange r = { 0, CFArrayGetCount(elem) }; CFArrayApplyFunction(elem, r, &joy_elem_array_hnd, (void *)joy); } } } /* Read the device passed in, and add it to our joystick list if appropriate. */ static void joy_read_device(io_object_t dev) { CFMutableDictionaryRef props = 0; /* Create a dictionary to read the device's properties. */ if(IORegistryEntryCreateCFProperties(dev, &props, kCFAllocatorDefault, kNilOptions) == KERN_SUCCESS) { CFTypeRef inf; SInt32 page, usage; void *ptr; /* Grab the primary usage page of the device. */ inf = CFDictionaryGetValue(props, CFSTR(kIOHIDPrimaryUsagePageKey)); if(!inf || !CFNumberGetValue((CFNumberRef)inf, kCFNumberSInt32Type, &page)) { goto out; } /* Ignore devices that are not in the Generic Desktop page. */ if(page != kHIDPage_GenericDesktop) { goto out; } /* Grab the primary device usage. */ inf = CFDictionaryGetValue(props, CFSTR(kIOHIDPrimaryUsageKey)); if(!inf || !CFNumberGetValue((CFNumberRef)inf, kCFNumberSInt32Type, &usage)) { goto out; } /* Ignore devices that are not either a Game Pad or Joystick. */ if(usage != kHIDUsage_GD_GamePad && usage != kHIDUsage_GD_Joystick) { goto out; } /* Allocate space for the new joystick structure. */ ptr = realloc(joys, (joy_count + 1) * sizeof(joydata_t)); if(ptr == NULL) { goto out; } joys = (joydata_t *)ptr; memset(joys + joy_count, 0, sizeof(joydata_t)); /* Grab and store the name of the device. */ inf = CFDictionaryGetValue(props, CFSTR(kIOHIDProductKey)); if(!CFStringGetCString((CFStringRef)inf, joys[joy_count].name, 256, kCFStringEncodingUTF8)) { goto out; } /* Create the device interface needed to interact with the device. */ if(!joy_create_interface(dev, joys + joy_count)) { goto out; } /* Find all elements of the device. */ joy_find_elements(props, joys + joy_count); qsort(joys[joy_count].buttons, joys[joy_count].buttons_count, sizeof(joy_elemdata_t), &joy_cmp_buttons); ++joy_count; } out: CFRelease(props); } /* Release the given joystick's interface and clean up any memory used by it. */ static void joy_release_joystick(joydata_t *joy) { (*joy->iface)->Release(joy->iface); joy->iface = NULL; if(joy->buttons) free(joy->buttons); if(joy->axes) free(joy->axes); if(joy->hats) free(joy->hats); } /* Scan the system for any joysticks connected. */ int joy_scan_joysticks(void) { io_iterator_t iter = 0; io_object_t dev; if(joys != NULL) { return -1; } /* Get the iterator needed for going through the list of devices. */ joy_get_iterator(kIOMasterPortDefault, &iter); if(iter != 0) { while((dev = IOIteratorNext(iter))) { joy_read_device(dev); IOObjectRelease(dev); } /* Release the iterator. */ IOObjectRelease(iter); } return joy_count; } /* Clean up any data allocated by the program for joysticks. */ void joy_release_joysticks(void) { int i; for(i = 0; i < joy_count; ++i) { joy_close_joystick(joys + i); joy_release_joystick(joys + i); } if(joys != NULL) { free(joys); joys = NULL; } joy_count = 0; } /* Get the joystick at a given index in our list of joysticks. */ joydata_t *joy_get_joystick(int index) { if(index < 0 || index >= joy_count) { return NULL; } return &joys[index]; } /* Grab the device for exclusive use by this program. The device must be closed properly (with the joy_close_joystick function, or you may need to unplug/replug the joystick to get it to work again). */ int joy_open_joystick(joydata_t *joy) { if((*joy->iface)->open(joy->iface, 0)) { return 0; } joy->open = 1; return 1; } /* Close the device and return its resources to the system. */ int joy_close_joystick(joydata_t *joy) { IOReturn rv; if(!joy->open) { return 1; } rv = (*joy->iface)->close(joy->iface); if(rv == kIOReturnNotOpen) { /* The device wasn't open so it can't be closed. */ return 1; } else if(rv != kIOReturnSuccess) { return 0; } joy->open = 0; return 1; } /* Read a given element from the joystick. The joystick must be open for this function to actually do anything useful. */ int joy_read_element(joydata_t *joy, joy_elemdata_t *elem) { IOHIDEventStruct ev; memset(&ev, 0, sizeof(IOHIDEventStruct)); (*joy->iface)->getElementValue(joy->iface, elem->cookie, &ev); return ev.value; } /* Read the value of a given button. Returns -1 on failure. */ int joy_read_button(joydata_t *joy, int num) { /* Subtract 1 from the number to get the index. */ --num; if(num >= joy->buttons_count) { return -1; } return joy_read_element(joy, joy->buttons + num); } /* Read the value of a given axis. Returns 0 on failure (or if the axis reports that its value is 0). */ int joy_read_axis(joydata_t *joy, int index) { float value; if(index >= joy->axes_count) { return 0; } value = joy_read_element(joy, joy->axes + index) / (float)(joy->axes[index].max + 1); return (int)(value * 32768); } /* Read the value of a given hat. Returns -1 on failure. */ int joy_read_hat(joydata_t *joy, int index) { int value; if(index >= joy->hats_count) { return -1; } value = joy_read_element(joy, joy->hats + index) - joy->hats[index].min; /* 4-position hat switch -- Make it look like an 8-position one. */ if(joy->hats[index].max - joy->hats[index].min + 1 == 4) { value <<= 1; } switch(value) { case 0: return JOY_HAT_UP; case 1: return JOY_HAT_UP | JOY_HAT_RIGHT; case 2: return JOY_HAT_RIGHT; case 3: return JOY_HAT_RIGHT | JOY_HAT_DOWN; case 4: return JOY_HAT_DOWN; case 5: return JOY_HAT_DOWN | JOY_HAT_LEFT; case 6: return JOY_HAT_LEFT; case 7: return JOY_HAT_LEFT | JOY_HAT_UP; default: return JOY_HAT_CENTER; } } yabause-0.9.15/src/c68k/000755 001750 001750 00000000000 12757373644 016635 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/c68k/CMakeLists.txt000644 001750 001750 00000001777 12755623101 021371 0ustar00guillaumeguillaume000000 000000 project(gen68k) cmake_minimum_required(VERSION 2.6) include(CheckCSourceCompiles) # variadic macros check_c_source_compiles("#define MACRO(...) puts(__VA_ARGS__) int main(int argc, char ** argv) { MACRO(\"foo\"); }" VARIADIC_MACROS_OK) if (VARIADIC_MACROS_OK) add_definitions(-DHAVE_C99_VARIADIC_MACROS=1) endif (VARIADIC_MACROS_OK) set(gen68k_SOURCES c68kexec.c c68k.c gen68k.c) add_definitions(-DC68K_GEN) if (MSVC) add_definitions(-DC68K_NO_JUMP_TABLE) add_definitions(-D_CRT_SECURE_NO_WARNINGS) endif (MSVC) add_executable(gen68k ${gen68k_SOURCES}) execute_process(COMMAND ${CMAKE_CURRENT_BINARY_DIR}/gen68k) set(GEN68K_INC c68k_ini.inc c68k_op0.inc c68k_op1.inc c68k_op2.inc c68k_op3.inc c68k_op4.inc c68k_op5.inc c68k_op6.inc c68k_op7.inc c68k_op8.inc c68k_op9.inc c68k_opA.inc c68k_opB.inc c68k_opC.inc c68k_opD.inc c68k_opE.inc c68k_opF.inc) add_custom_command(OUTPUT ${GEN68K_INC} COMMAND gen68k DEPENDS gen68k) add_custom_target(c68kinc ALL DEPENDS ${GEN68K_INC}) yabause-0.9.15/src/c68k/c68k.c000644 001750 001750 00000015607 12755623101 017545 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2004 Stephane Dallongeville This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file c68k.c \brief C68K init, interrupt and memory access functions. */ /********************************************************************************* * * C68K (68000 CPU emulator) version 0.80 * Compiled with Dev-C++ * Copyright 2003-2004 Stephane Dallongeville * ********************************************************************************/ #include #include #include "c68k.h" // shared global variable ////////////////////////// c68k_struc C68K; // include macro file ////////////////////// #include "c68kmac.inc" // prototype ///////////// u32 FASTCALL C68k_Read_Dummy(const u32 adr); void FASTCALL C68k_Write_Dummy(const u32 adr, u32 data); u32 C68k_Read_Byte(c68k_struc *cpu, u32 adr); u32 C68k_Read_Word(c68k_struc *cpu, u32 adr); u32 C68k_Read_Long(c68k_struc *cpu, u32 adr); void C68k_Write_Byte(c68k_struc *cpu, u32 adr, u32 data); void C68k_Write_Word(c68k_struc *cpu, u32 adr, u32 data); void C68k_Write_Long(c68k_struc *cpu, u32 adr, u32 data); s32 FASTCALL C68k_Interrupt_Ack_Dummy(s32 level); void FASTCALL C68k_Reset_Dummy(void); // core main functions /////////////////////// void C68k_Init(c68k_struc *cpu, C68K_INT_CALLBACK *int_cb) { memset(cpu, 0, sizeof(c68k_struc)); C68k_Set_ReadB(cpu, C68k_Read_Dummy); C68k_Set_ReadW(cpu, C68k_Read_Dummy); C68k_Set_WriteB(cpu, C68k_Write_Dummy); C68k_Set_WriteW(cpu, C68k_Write_Dummy); if (int_cb) cpu->Interrupt_CallBack = int_cb; else cpu->Interrupt_CallBack = C68k_Interrupt_Ack_Dummy; cpu->Reset_CallBack = C68k_Reset_Dummy; // used to init JumpTable cpu->Status |= C68K_DISABLE; C68k_Exec(cpu, 0); cpu->Status &= ~C68K_DISABLE; } s32 FASTCALL C68k_Reset(c68k_struc *cpu) { memset(cpu, 0, ((u8 *)&(cpu->dirty1)) - ((u8 *)&(cpu->D[0]))); cpu->flag_notZ = 1; cpu->flag_I = 7; cpu->flag_S = C68K_SR_S; cpu->A[7] = C68k_Read_Long(cpu, 0); C68k_Set_PC(cpu, C68k_Read_Long(cpu, 4)); return cpu->Status; } ///////////////////////////////// void FASTCALL C68k_Set_IRQ(c68k_struc *cpu, s32 level) { cpu->IRQLine = level; if (cpu->Status & C68K_RUNNING) { cpu->CycleSup = cpu->CycleIO; cpu->CycleIO = 0; } cpu->Status &= ~(C68K_HALTED | C68K_WAITING); } ///////////////////////////////// s32 FASTCALL C68k_Get_CycleToDo(c68k_struc *cpu) { if (!(cpu->Status & C68K_RUNNING)) return -1; return cpu->CycleToDo; } s32 FASTCALL C68k_Get_CycleRemaining(c68k_struc *cpu) { if (!(cpu->Status & C68K_RUNNING)) return -1; return (cpu->CycleIO + cpu->CycleSup); } s32 FASTCALL C68k_Get_CycleDone(c68k_struc *cpu) { if (!(cpu->Status & C68K_RUNNING)) return -1; return (cpu->CycleToDo - (cpu->CycleIO + cpu->CycleSup)); } void FASTCALL C68k_Release_Cycle(c68k_struc *cpu) { if (cpu->Status & C68K_RUNNING) cpu->CycleIO = cpu->CycleSup = 0; } void FASTCALL C68k_Add_Cycle(c68k_struc *cpu, s32 cycle) { if (cpu->Status & C68K_RUNNING) cpu->CycleIO -= cycle; } // Read / Write dummy functions //////////////////////////////// u32 FASTCALL C68k_Read_Dummy(UNUSED const u32 adr) { return 0; } void FASTCALL C68k_Write_Dummy(UNUSED const u32 adr, UNUSED u32 data) { } s32 FASTCALL C68k_Interrupt_Ack_Dummy(s32 level) { // return vector return (C68K_INTERRUPT_AUTOVECTOR_EX + level); } void FASTCALL C68k_Reset_Dummy(void) { } // Read / Write core functions /////////////////////////////// u32 C68k_Read_Byte(c68k_struc *cpu, u32 adr) { return cpu->Read_Byte(adr); } u32 C68k_Read_Word(c68k_struc *cpu, u32 adr) { return cpu->Read_Word(adr); } u32 C68k_Read_Long(c68k_struc *cpu, u32 adr) { #ifdef C68K_BIG_ENDIAN return (cpu->Read_Word(adr) << 16) | (cpu->Read_Word(adr + 2) & 0xFFFF); #else return (cpu->Read_Word(adr) << 16) | (cpu->Read_Word(adr + 2) & 0xFFFF); #endif } void C68k_Write_Byte(c68k_struc *cpu, u32 adr, u32 data) { cpu->Write_Byte(adr, data); } void C68k_Write_Word(c68k_struc *cpu, u32 adr, u32 data) { cpu->Write_Word(adr, data); } void C68k_Write_Long(c68k_struc *cpu, u32 adr, u32 data) { #ifdef C68K_BIG_ENDIAN cpu->Write_Word(adr, data >> 16); cpu->Write_Word(adr + 2, data & 0xFFFF); #else cpu->Write_Word(adr, data >> 16); cpu->Write_Word(adr + 2, data & 0xFFFF); #endif } // setting core functions ////////////////////////// void C68k_Set_Fetch(c68k_struc *cpu, u32 low_adr, u32 high_adr, pointer fetch_adr) { u32 i, j; i = (low_adr >> C68K_FETCH_SFT) & C68K_FETCH_MASK; j = (high_adr >> C68K_FETCH_SFT) & C68K_FETCH_MASK; fetch_adr -= i << C68K_FETCH_SFT; while (i <= j) cpu->Fetch[i++] = fetch_adr; } void C68k_Set_ReadB(c68k_struc *cpu, C68K_READ *Func) { cpu->Read_Byte = Func; } void C68k_Set_ReadW(c68k_struc *cpu, C68K_READ *Func) { cpu->Read_Word = Func; } void C68k_Set_WriteB(c68k_struc *cpu, C68K_WRITE *Func) { cpu->Write_Byte = Func; } void C68k_Set_WriteW(c68k_struc *cpu, C68K_WRITE *Func) { cpu->Write_Word = Func; } // externals main functions //////////////////////////// u32 C68k_Get_DReg(c68k_struc *cpu, u32 num) { return cpu->D[num]; } u32 C68k_Get_AReg(c68k_struc *cpu, u32 num) { return cpu->A[num]; } u32 C68k_Get_PC(c68k_struc *cpu) { return (u32)(cpu->PC - cpu->BasePC); } u32 C68k_Get_SR(c68k_struc *cpu) { c68k_struc *CPU = cpu; return GET_SR; } u32 C68k_Get_USP(c68k_struc *cpu) { if (cpu->flag_S) return cpu->USP; else return cpu->A[7]; } u32 C68k_Get_MSP(c68k_struc *cpu) { if (cpu->flag_S) return cpu->A[7]; else return cpu->USP; } void C68k_Set_DReg(c68k_struc *cpu, u32 num, u32 val) { cpu->D[num] = val; } void C68k_Set_AReg(c68k_struc *cpu, u32 num, u32 val) { cpu->A[num] = val; } void C68k_Set_PC(c68k_struc *cpu, u32 val) { cpu->BasePC = cpu->Fetch[(val >> C68K_FETCH_SFT) & C68K_FETCH_MASK]; cpu->PC = val + cpu->BasePC; } void C68k_Set_SR(c68k_struc *cpu, u32 val) { c68k_struc *CPU = cpu; SET_SR(val); } void C68k_Set_USP(c68k_struc *cpu, u32 val) { if (cpu->flag_S) cpu->USP = val; else cpu->A[7] = val; } void C68k_Set_MSP(c68k_struc *cpu, u32 val) { if (cpu->flag_S) cpu->A[7] = val; else cpu->USP = val; } yabause-0.9.15/src/c68k/c68kexec.c000644 001750 001750 00000020507 12755623101 020405 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2004 Stephane Dallongeville This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file c68kexec.c \brief C68K emulation execution and instruction functions. */ #include "../core.h" #include "c68k.h" // #define TRACE_WITH_Q68 // Define to use Q68 tracing code to trace insns // (requires Q68 built in, of course) #ifdef NEOCD_HLE void cdrom_load_files(void); void neogeo_cdda_control(void); void neogeo_prio_switch(void); void neogeo_upload(void); #endif // exception cycle table (taken from musashi core) static const s32 c68k_exception_cycle_table[256] = { 4, // 0: Reset - Initial Stack Pointer 4, // 1: Reset - Initial Program Counter 50, // 2: Bus Error 50, // 3: Address Error 34, // 4: Illegal Instruction 38, // 5: Divide by Zero 40, // 6: CHK 34, // 7: TRAPV 34, // 8: Privilege Violation 34, // 9: Trace 4, // 10: 4, // 11: 4, // 12: RESERVED 4, // 13: Coprocessor Protocol Violation 4, // 14: Format Error 44, // 15: Uninitialized Interrupt 4, // 16: RESERVED 4, // 17: RESERVED 4, // 18: RESERVED 4, // 19: RESERVED 4, // 20: RESERVED 4, // 21: RESERVED 4, // 22: RESERVED 4, // 23: RESERVED 44, // 24: Spurious Interrupt 44, // 25: Level 1 Interrupt Autovector 44, // 26: Level 2 Interrupt Autovector 44, // 27: Level 3 Interrupt Autovector 44, // 28: Level 4 Interrupt Autovector 44, // 29: Level 5 Interrupt Autovector 44, // 30: Level 6 Interrupt Autovector 44, // 31: Level 7 Interrupt Autovector 34, // 32: TRAP #0 34, // 33: TRAP #1 34, // 34: TRAP #2 34, // 35: TRAP #3 34, // 36: TRAP #4 34, // 37: TRAP #5 34, // 38: TRAP #6 34, // 39: TRAP #7 34, // 40: TRAP #8 34, // 41: TRAP #9 34, // 42: TRAP #10 34, // 43: TRAP #11 34, // 44: TRAP #12 34, // 45: TRAP #13 34, // 46: TRAP #14 34, // 47: TRAP #15 4, // 48: FP Branch or Set on Unknown Condition 4, // 49: FP Inexact Result 4, // 50: FP Divide by Zero 4, // 51: FP Underflow 4, // 52: FP Operand Error 4, // 53: FP Overflow 4, // 54: FP Signaling NAN 4, // 55: FP Unimplemented Data Type 4, // 56: MMU Configuration Error 4, // 57: MMU Illegal Operation Error 4, // 58: MMU Access Level Violation Error 4, // 59: RESERVED 4, // 60: RESERVED 4, // 61: RESERVED 4, // 62: RESERVED 4, // 63: RESERVED // 64-255: User Defined 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 }; // global variable /////////////////// #ifndef C68K_GEN #ifndef C68K_NO_JUMP_TABLE #ifndef C68K_CONST_JUMP_TABLE static void *JumpTable[0x10000]; #endif #endif static u32 C68k_Initialised = 0; #endif // C68K_GEN #ifdef NEOCD_HLE extern int img_display; #endif // include macro file ////////////////////// #include "c68kmac.inc" #ifndef C68K_GEN # ifdef TRACE_WITH_Q68 #include "../q68/q68.h" static c68k_struc *TRACE_CPU; static uint32_t readw(uint32_t address) { return TRACE_CPU->Read_Word(address); } /* Make our own version of the structure to avoid the overhead of dozens of * function calls every instruction */ static struct { u32 D[8], A[8], PC, SR, USP, SSP, dummy[7]; void *readb, *readw, *writeb, *writew; } state = {.readw = readw}; void TRACE(int PC,c68k_struc *CPU,int Opcode,int CCnt) { static FILE *f; if (!f) f = fopen("c68k.log", "w"); TRACE_CPU = CPU; memcpy(state.D, CPU->D, 16*4); state.PC = PC - 2 - CPU->BasePC; state.SR = GET_SR; if (f) q68_trace((Q68State *)&state, f, CPU->CycleToDo - CCnt, CPU->CycleToDo); } # endif // TRACE_WITH_Q68 #endif // !C68K_GEN // main exec function ////////////////////// s32 FASTCALL C68k_Exec(c68k_struc *cpu, s32 cycle) { #ifndef C68K_GEN #if 0 register c68k_struc *CPU asm ("ebx"); register pointer PC asm ("esi"); register s32 CCnt asm ("edi"); // register u32 Opcode asm ("edi"); // c68k_struc *CPU; // u32 PC; // s32 CCnt; u32 Opcode; #else // register c68k_struc *CPU asm ("r10"); // register u32 PC asm ("r11"); // register s32 CCnt asm ("r12"); // register u32 Opcode asm ("r13"); c68k_struc *CPU; pointer PC; s32 CCnt; u32 Opcode; #endif #endif #ifndef C68K_GEN #ifndef C68K_NO_JUMP_TABLE #ifdef C68K_CONST_JUMP_TABLE #include "c68k_ini.inc" #endif #else C68k_Initialised = 1; #endif CPU = cpu; PC = CPU->PC; if (CPU->Status & (C68K_RUNNING | C68K_DISABLE | C68K_FAULTED)) { #ifndef C68K_NO_JUMP_TABLE #ifndef C68K_CONST_JUMP_TABLE if (!C68k_Initialised) goto C68k_Init; #endif #endif return (CPU->Status | 0x80000000); } if (cycle <= 0) return -cycle; CPU->CycleToDo = CCnt = cycle; #ifndef C68K_DEBUG CHECK_INT #else { s32 line, vect; line = CPU->IRQLine; if ((line == 7) || (line > (s32)CPU->flag_I)) { PRE_IO /* get vector */ CPU->IRQLine = 0; vect = CPU->Interrupt_CallBack(line); if (vect == C68K_INT_ACK_AUTOVECTOR) vect = C68K_INTERRUPT_AUTOVECTOR_EX + (line & 7); /* adjust CCnt */ CCnt -= c68k_exception_cycle_table[vect]; /* swap A7 and USP */ if (!CPU->flag_S) { u32 tmpSP; tmpSP = CPU->USP; CPU->USP = CPU->A[7]; CPU->A[7] = tmpSP; } /* push PC and SR */ PUSH_32_F((u32)(PC - CPU->BasePC)) PUSH_16_F(GET_SR) /* adjust SR */ CPU->flag_S = C68K_SR_S; CPU->flag_I = line; /* fetch new PC */ READ_LONG_F(vect * 4, PC) SET_PC(PC) POST_IO } } #endif if (CPU->Status & (C68K_HALTED | C68K_WAITING)) return CPU->CycleToDo; CPU->CycleSup = 0; CPU->Status |= C68K_RUNNING; #ifndef C68K_DEBUG NEXT #else #ifdef C68K_NO_JUMP_TABLE NEXT #else Opcode = FETCH_WORD; PC += 2; goto *JumpTable[Opcode]; #endif #endif #ifdef C68K_NO_JUMP_TABLE SwitchTable: switch(Opcode) { #endif #include "c68k_op0.inc" #include "c68k_op1.inc" #include "c68k_op2.inc" #include "c68k_op3.inc" #include "c68k_op4.inc" #include "c68k_op5.inc" #include "c68k_op6.inc" #include "c68k_op7.inc" #include "c68k_op8.inc" #include "c68k_op9.inc" #include "c68k_opA.inc" #include "c68k_opB.inc" #include "c68k_opC.inc" #include "c68k_opD.inc" #include "c68k_opE.inc" #include "c68k_opF.inc" #ifdef C68K_NO_JUMP_TABLE } #endif C68k_Exec_End: CHECK_INT if ((CCnt += CPU->CycleSup) > 0) { CPU->CycleSup = 0; NEXT; } C68k_Exec_Really_End: CPU->Status &= ~C68K_RUNNING; CPU->PC = PC; return (CPU->CycleToDo - CCnt); #ifndef C68K_CONST_JUMP_TABLE #ifndef C68K_NO_JUMP_TABLE C68k_Init: { u32 i, j; #include "c68k_ini.inc" C68k_Initialised = 1; } return 0; #endif #endif #else return 0; #endif } yabause-0.9.15/src/c68k/gen68k.h000644 001750 001750 00000003141 12755623101 020067 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2004 Stephane Dallongeville Copyright 2004 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /********************************************************************************* * GEN68K.H : * * C68K generator include file * ********************************************************************************/ #ifndef _GEN68K_H_ #define _GEN68K_H_ #ifdef __cplusplus extern "C" { #endif // setting /////////// // structure definition //////////////////////// typedef struct { u32 name; u32 mask; u32 match; } c68k_ea_info_struc; typedef struct __c68k_op_info_struc { s8 op_name[8 + 1]; u16 op_base; u16 op_mask; s8 size_type; s8 size_sft; s8 eam_sft; s8 reg_sft; s8 eam2_sft; s8 reg2_sft; s8 ea_supported[12 + 1]; s8 ea2_supported[12 + 1]; void (*genfunc)(void); } c68k_op_info_struc; #ifdef __cplusplus } #endif #endif // _GEN68K_H_ yabause-0.9.15/src/c68k/gen68k.inc000644 001750 001750 00000154065 12755623101 020425 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2004 Stephane Dallongeville This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #define EA_DREG 0 #define EA_AREG 1 #define EA_AIND 2 #define EA_AINC 3 #define EA_ADEC 4 #define EA_D16A 5 #define EA_D8AX 6 #define EA_A16 7 #define EA_A32 8 #define EA_D16P 9 #define EA_D8PX 10 #define EA_IMM 11 #define EA_AINC7 12 #define EA_ADEC7 13 #define EA_ILLEGAL 15 #define SIZE_BYTE 0 #define SIZE_WORD 1 #define SIZE_LONG 2 #define COND_TR 0 #define COND_FA 1 #define COND_HI 2 #define COND_LS 3 #define COND_CC 4 #define COND_CS 5 #define COND_NE 6 #define COND_EQ 7 #define COND_VC 8 #define COND_VS 9 #define COND_PL 10 #define COND_MI 11 #define COND_GE 12 #define COND_LT 13 #define COND_GT 14 #define COND_LE 15 #define COND_NOT_TR COND_FA #define COND_NOT_FA COND_TR #define COND_NOT_HI COND_LS #define COND_NOT_LS COND_HI #define COND_NOT_CC COND_CS #define COND_NOT_CS COND_CC #define COND_NOT_NE COND_EQ #define COND_NOT_EQ COND_NE #define COND_NOT_VC COND_VS #define COND_NOT_VS COND_VC #define COND_NOT_PL COND_MI #define COND_NOT_MI COND_PL #define COND_NOT_GE COND_LT #define COND_NOT_LT COND_GE #define COND_NOT_GT COND_LE #define COND_NOT_LE COND_GT #define OP_ILLEGAL 0x4AFC static void GenORI(void); static void GenORICCR(void); static void GenORISR(void); static void GenANDI(void); static void GenANDICCR(void); static void GenANDISR(void); static void GenEORI(void); static void GenEORICCR(void); static void GenEORISR(void); static void GenSUBI(void); static void GenADDI(void); static void GenCMPI(void); static void GenBTSTn(void); static void GenBCHGn(void); static void GenBCLRn(void); static void GenBSETn(void); static void GenBTST(void); static void GenBCHG(void); static void GenBCLR(void); static void GenBSET(void); static void GenMOVEPWaD(void); static void GenMOVEPLaD(void); static void GenMOVEPWDa(void); static void GenMOVEPLDa(void); static void GenMOVEB(void); static void GenMOVEL(void); static void GenMOVEW(void); static void GenMOVEAL(void); static void GenMOVEAW(void); static void GenNEGX(void); static void GenCLR(void); static void GenNEG(void); static void GenNOT(void); static void GenMOVESRa(void); static void GenMOVEaSR(void); static void GenMOVEaCCR(void); static void GenNBCD(void); static void GenPEA(void); static void GenSWAP(void); static void GenMOVEMaR(void); static void GenEXT(void); static void GenTST(void); static void GenTAS(void); static void GenILLEGAL(void); static void GenMOVEMRa(void); static void GenTRAP(void); static void GenLINK(void); static void GenLINKA7(void); static void GenULNK(void); static void GenULNKA7(void); static void GenMOVEAUSP(void); static void GenMOVEUSPA(void); static void GenRESET(void); static void GenNOP(void); static void GenSTOP(void); static void GenRTE(void); static void GenRTS(void); static void GenTRAPV(void); static void GenRTR(void); static void GenJSR(void); static void GenJMP(void); static void GenCHK(void); static void GenLEA(void); static void GenSTCC(void); static void GenDBCC(void); static void GenADDQ(void); static void GenSUBQ(void); static void GenBCC(void); static void GenBCC16(void); static void GenBRA(void); static void GenBRA16(void); static void GenBSR(void); static void GenBSR16(void); static void GenMOVEQ(void); static void GenORaD(void); static void GenORDa(void); static void GenSBCD(void); static void GenSBCDM(void); static void GenSBCD7M(void); static void GenSBCDM7(void); static void GenSBCD7M7(void); static void GenDIVU(void); static void GenDIVS(void); static void GenSUBaD(void); static void GenSUBDa(void); static void GenSUBX(void); static void GenSUBXM(void); static void GenSUBX7M(void); static void GenSUBXM7(void); static void GenSUBX7M7(void); static void GenSUBA(void); static void GenCMP(void); static void GenCMPM(void); static void GenCMP7M(void); static void GenCMPM7(void); static void GenCMP7M7(void); static void GenEORDa(void); static void GenCMPA(void); static void GenANDaD(void); static void GenANDDa(void); static void GenABCD(void); static void GenABCDM(void); static void GenABCD7M(void); static void GenABCDM7(void); static void GenABCD7M7(void); static void GenMULU(void); static void GenMULS(void); static void GenEXGDD(void); static void GenEXGAA(void); static void GenEXGAD(void); static void GenADDaD(void); static void GenADDDa(void); static void GenADDX(void); static void GenADDXM(void); static void GenADDX7M(void); static void GenADDXM7(void); static void GenADDX7M7(void); static void GenADDA(void); static void GenASRk(void); static void GenLSRk(void); static void GenROXRk(void); static void GenRORk(void); static void GenASLk(void); static void GenLSLk(void); static void GenROXLk(void); static void GenROLk(void); static void GenASRD(void); static void GenLSRD(void); static void GenROXRD(void); static void GenRORD(void); static void GenASLD(void); static void GenLSLD(void); static void GenROXLD(void); static void GenROLD(void); static void GenASR(void); static void GenLSR(void); static void GenROXR(void); static void GenROR(void); static void GenASL(void); static void GenLSL(void); static void GenROXL(void); static void GenROL(void); static void Gen1010(void); static void Gen1111(void); #ifdef NEOCD_HLE static void Gen0xFABE(void); static void Gen0xFABF(void); static void Gen0xFAC0(void); static void Gen0xFAC1(void); static void Gen0xFAC2(void); static void Gen0xFAC3(void); #endif #ifdef NEOCD_HLE #define OP_INFO_TABLE_LEN (142 + 6) #else #define OP_INFO_TABLE_LEN 144 #endif static c68k_op_info_struc op_info_table[OP_INFO_TABLE_LEN] = { // DAAAAddaaddi DAAAAddaaddi // iid181318m iid181318m // siz siz eam ear eam ear nne6A626Pm nne6A626Pm // opname opbase opmask typ sft 1 1 2 2 dccAX PX dccAX PX GenFunc { "1010", 0xA000, 0xF000, 0, 0, -1, -1, -1, -1, "------------", "------------", Gen1010 }, { "1111", 0xF000, 0xF000, 0, 0, -1, -1, -1, -1, "------------", "------------", Gen1111 }, { "ORI", 0x0000, 0xFF00, 2, 6, 3, 0, -1, -1, "o-ooooooo---", "------------", GenORI }, { "ORICCR", 0x003C, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", GenORICCR }, { "ORISR", 0x007C, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", GenORISR }, { "ANDI", 0x0200, 0xFF00, 2, 6, 3, 0, -1, -1, "o-ooooooo---", "------------", GenANDI }, { "ANDICCR", 0x023C, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", GenANDICCR }, { "ANDISR", 0x027C, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", GenANDISR }, { "EORI", 0x0A00, 0xFF00, 2, 6, 3, 0, -1, -1, "o-ooooooo---", "------------", GenEORI }, { "EORICCR", 0x0A3C, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", GenEORICCR }, { "EORISR", 0x0A7C, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", GenEORISR }, { "SUBI", 0x0400, 0xFF00, 2, 6, 3, 0, -1, -1, "o-ooooooo---", "------------", GenSUBI }, { "ADDI", 0x0600, 0xFF00, 2, 6, 3, 0, -1, -1, "o-ooooooo---", "------------", GenADDI }, { "CMPI", 0x0C00, 0xFF00, 2, 6, 3, 0, -1, -1, "o-ooooooo---", "------------", GenCMPI }, { "BTSTn", 0x0800, 0xFFC0, 0, 0, 3, 0, -1, -1, "o-ooooooooo-", "------------", GenBTSTn }, { "BCHGn", 0x0840, 0xFFC0, 0, 0, 3, 0, -1, -1, "o-ooooooo---", "------------", GenBCHGn }, { "BCLRn", 0x0880, 0xFFC0, 0, 0, 3, 0, -1, -1, "o-ooooooo---", "------------", GenBCLRn }, { "BSETn", 0x08C0, 0xFFC0, 0, 0, 3, 0, -1, -1, "o-ooooooo---", "------------", GenBSETn }, { "BTST", 0x0100, 0xF1C0, 0, 0, 3, 0, -1, 9, "o-oooooooooo", "------------", GenBTST }, { "BCHG", 0x0140, 0xF1C0, 0, 0, 3, 0, -1, 9, "o-ooooooo---", "------------", GenBCHG }, { "BCLR", 0x0180, 0xF1C0, 0, 0, 3, 0, -1, 9, "o-ooooooo---", "------------", GenBCLR }, { "BSET", 0x01C0, 0xF1C0, 0, 0, 3, 0, -1, 9, "o-ooooooo---", "------------", GenBSET }, { "MOVEPWaD", 0x0108, 0xF1F8, 0, 0, -1, 0, -1, 9, "------------", "------------", GenMOVEPWaD }, { "MOVEPLaD", 0x0148, 0xF1F8, 0, 0, -1, 0, -1, 9, "------------", "------------", GenMOVEPLaD }, { "MOVEPWDa", 0x0188, 0xF1F8, 0, 0, -1, 0, -1, 9, "------------", "------------", GenMOVEPWDa }, { "MOVEPLDa", 0x01C8, 0xF1F8, 0, 0, -1, 0, -1, 9, "------------", "------------", GenMOVEPLDa }, { "MOVEB", 0x1000, 0xF000, 0, 0, 3, 0, 6, 9, "oooooooooooo", "o-ooooooo---", GenMOVEB }, { "MOVEL", 0x2000, 0xF000, 0, 0, 3, 0, 6, 9, "oooooooooooo", "o-ooooooo---", GenMOVEL }, { "MOVEW", 0x3000, 0xF000, 0, 0, 3, 0, 6, 9, "oooooooooooo", "o-ooooooo---", GenMOVEW }, { "MOVEAL", 0x2040, 0xF1C0, 0, 0, 3, 0, -1, 9, "oooooooooooo", "------------", GenMOVEAL }, { "MOVEAW", 0x3040, 0xF1C0, 0, 0, 3, 0, -1, 9, "oooooooooooo", "------------", GenMOVEAW }, { "NEGX", 0x4000, 0xFF00, 2, 6, 3, 0, -1, -1, "o-ooooooo---", "------------", GenNEGX }, { "CLR", 0x4200, 0xFF00, 2, 6, 3, 0, -1, -1, "o-ooooooo---", "------------", GenCLR }, { "NEG", 0x4400, 0xFF00, 2, 6, 3, 0, -1, -1, "o-ooooooo---", "------------", GenNEG }, { "NOT", 0x4600, 0xFF00, 2, 6, 3, 0, -1, -1, "o-ooooooo---", "------------", GenNOT }, { "MOVESRa", 0x40C0, 0xFFC0, 0, 0, 3, 0, -1, -1, "o-ooooooo---", "------------", GenMOVESRa }, { "MOVEaCCR", 0x44C0, 0xFFC0, 0, 0, 3, 0, -1, -1, "o-oooooooooo", "------------", GenMOVEaCCR }, { "MOVEaSR", 0x46C0, 0xFFC0, 0, 0, 3, 0, -1, -1, "o-oooooooooo", "------------", GenMOVEaSR }, { "NBCD", 0x4800, 0xFFC0, 0, 0, 3, 0, -1, -1, "o-ooooooo---", "------------", GenNBCD }, { "PEA", 0x4840, 0xFFC0, 0, 0, 3, 0, -1, -1, "--o--oooooo-", "------------", GenPEA }, { "SWAP", 0x4840, 0xFFF8, 0, 0, -1, 0, -1, -1, "------------", "------------", GenSWAP }, { "MOVEMRa", 0x4880, 0xFF80, 1, 6, 3, 0, -1, -1, "--o-ooooo---", "------------", GenMOVEMRa }, { "EXT", 0x4880, 0xFFB8, 1, 6, -1, 0, -1, -1, "------------", "------------", GenEXT }, { "TST", 0x4A00, 0xFF00, 2, 6, 3, 0, -1, -1, "o-ooooooo---", "------------", GenTST }, { "TAS", 0x4AC0, 0xFFC0, 0, 0, 3, 0, -1, -1, "o-ooooooo---", "------------", GenTAS }, { "ILLEGAL", 0x4AFC, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", GenILLEGAL }, { "MOVEMaR", 0x4C80, 0xFF80, 1, 6, 3, 0, -1, -1, "--oo-oooooo-", "------------", GenMOVEMaR }, { "TRAP", 0x4E40, 0xFFF0, 0, 0, -1, -1, -1, -1, "------------", "------------", GenTRAP }, { "LINK", 0x4E50, 0xFFF8, 0, 0, -1, 0, -1, -1, "------------", "------------", GenLINK }, { "LINKA7", 0x4E57, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", GenLINKA7 }, { "ULNK", 0x4E58, 0xFFF8, 0, 0, -1, 0, -1, -1, "------------", "------------", GenULNK }, { "ULNKA7", 0x4E5F, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", GenULNKA7 }, { "MOVEAUSP", 0x4E60, 0xFFF8, 0, 0, -1, 0, -1, -1, "------------", "------------", GenMOVEAUSP }, { "MOVEUSPA", 0x4E68, 0xFFF8, 0, 0, -1, 0, -1, -1, "------------", "------------", GenMOVEUSPA }, { "RESET", 0x4E70, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", GenRESET }, { "NOP", 0x4E71, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", GenNOP }, { "STOP", 0x4E72, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", GenSTOP }, { "RTE", 0x4E73, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", GenRTE }, { "RTS", 0x4E75, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", GenRTS }, { "TRAPV", 0x4E76, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", GenTRAPV }, { "RTR", 0x4E77, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", GenRTR }, { "JSR", 0x4E80, 0xFFC0, 0, 0, 3, 0, -1, -1, "--o--oooooo-", "------------", GenJSR }, { "JMP", 0x4EC0, 0xFFC0, 0, 0, 3, 0, -1, -1, "--o--oooooo-", "------------", GenJMP }, { "CHK", 0x4180, 0xF1C0, 0, 0, 3, 0, -1, 9, "o-oooooooooo", "------------", GenCHK }, { "LEA", 0x41C0, 0xF1C0, 0, 0, 3, 0, -1, 9, "--o--oooooo-", "------------", GenLEA }, { "STCC", 0x50C0, 0xF0C0, 0, 0, 3, 0, -1, -1, "o-ooooooo---", "------------", GenSTCC }, { "DBCC", 0x50C8, 0xF0F8, 0, 0, -1, 0, -1, -1, "------------", "------------", GenDBCC }, { "ADDQ", 0x5000, 0xF100, 2, 6, 3, 0, -1, -1, "ooooooooo---", "------------", GenADDQ }, { "SUBQ", 0x5100, 0xF100, 2, 6, 3, 0, -1, -1, "ooooooooo---", "------------", GenSUBQ }, { "BCC", 0x6000, 0xF000, 0, 0, -1, -1, -1, -1, "------------", "------------", GenBCC }, { "BCC16", 0x6000, 0xF0FF, 0, 0, -1, -1, -1, -1, "------------", "------------", GenBCC16 }, { "BRA", 0x6000, 0xFF00, 0, 0, -1, -1, -1, -1, "------------", "------------", GenBRA }, { "BRA16", 0x6000, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", GenBRA16 }, { "BSR", 0x6100, 0xFF00, 0, 0, -1, -1, -1, -1, "------------", "------------", GenBSR }, { "BSR16", 0x6100, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", GenBSR16 }, { "MOVEQ", 0x7000, 0xF100, 0, 0, -1, 9, -1, -1, "------------", "------------", GenMOVEQ }, { "ORaD", 0x8000, 0xF100, 2, 6, 3, 0, -1, 9, "o-oooooooooo", "------------", GenORaD }, { "ORDa", 0x8100, 0xF100, 2, 6, 3, 0, -1, 9, "--ooooooo---", "------------", GenORDa }, { "SBCD", 0x8100, 0xF1F8, 0, 0, -1, 0, -1, 9, "------------", "------------", GenSBCD }, { "SBCDM", 0x8108, 0xF1F8, 0, 0, -1, 0, -1, 9, "------------", "------------", GenSBCDM }, { "SBCD7M", 0x810F, 0xF1FF, 0, 0, -1, 0, -1, 9, "------------", "------------", GenSBCD7M }, { "SBCDM7", 0x8F08, 0xFFF8, 0, 0, -1, 0, -1, 9, "------------", "------------", GenSBCDM7 }, { "SBCD7M7", 0x8F0F, 0xFFFF, 0, 0, -1, 0, -1, 9, "------------", "------------", GenSBCD7M7 }, { "DIVU", 0x80C0, 0xF1C0, 0, 0, 3, 0, -1, 9, "o-oooooooooo", "------------", GenDIVU }, { "DIVS", 0x81C0, 0xF1C0, 0, 0, 3, 0, -1, 9, "o-oooooooooo", "------------", GenDIVS }, { "SUBaD", 0x9000, 0xF100, 2, 6, 3, 0, -1, 9, "oooooooooooo", "------------", GenSUBaD }, { "SUBDa", 0x9100, 0xF100, 2, 6, 3, 0, -1, 9, "--ooooooo---", "------------", GenSUBDa }, { "SUBX", 0x9100, 0xF138, 2, 6, -1, 0, -1, 9, "------------", "------------", GenSUBX }, { "SUBXM", 0x9108, 0xF138, 2, 6, -1, 0, -1, 9, "------------", "------------", GenSUBXM }, { "SUBX7M", 0x910F, 0xF13F, 2, 6, -1, -1, -1, 9, "------------", "------------", GenSUBX7M }, { "SUBXM7", 0x9F08, 0xFF38, 2, 6, -1, 0, -1, -1, "------------", "------------", GenSUBXM7 }, { "SUBX7M7", 0x9F0F, 0xFF3F, 2, 6, -1, -1, -1, -1, "------------", "------------", GenSUBX7M7 }, { "SUBA", 0x90C0, 0xF0C0, 1, 8, 3, 0, -1, 9, "oooooooooooo", "------------", GenSUBA }, { "CMP", 0xB000, 0xF100, 2, 6, 3, 0, -1, 9, "oooooooooooo", "------------", GenCMP }, { "CMPM", 0xB108, 0xF138, 2, 6, -1, 0, -1, 9, "------------", "------------", GenCMPM }, { "CMP7M", 0xB10F, 0xF13F, 2, 6, -1, -1, -1, 9, "------------", "------------", GenCMP7M }, { "CMPM7", 0xBF08, 0xFF38, 2, 6, -1, 0, -1, -1, "------------", "------------", GenCMPM7 }, { "CMP7M7", 0xBF0F, 0xFF3F, 2, 6, -1, -1, -1, -1, "------------", "------------", GenCMP7M7 }, { "EORDa", 0xB100, 0xF100, 2, 6, 3, 0, -1, 9, "o-ooooooo---", "------------", GenEORDa }, { "CMPA", 0xB0C0, 0xF0C0, 1, 8, 3, 0, -1, 9, "oooooooooooo", "------------", GenCMPA }, { "ANDaD", 0xC000, 0xF100, 2, 6, 3, 0, -1, 9, "o-oooooooooo", "------------", GenANDaD }, { "ANDDa", 0xC100, 0xF100, 2, 6, 3, 0, -1, 9, "--ooooooo---", "------------", GenANDDa }, { "ABCD", 0xC100, 0xF1F8, 0, 0, -1, 0, -1, 9, "------------", "------------", GenABCD }, { "ABCDM", 0xC108, 0xF1F8, 0, 0, -1, 0, -1, 9, "------------", "------------", GenABCDM }, { "ABCD7M", 0xC10F, 0xF1FF, 0, 0, -1, -1, -1, 9, "------------", "------------", GenABCD7M }, { "ABCDM7", 0xCF08, 0xFFF8, 0, 0, -1, 0, -1, -1, "------------", "------------", GenABCDM7 }, { "ABCD7M7", 0xCF0F, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", GenABCD7M7 }, { "MULU", 0xC0C0, 0xF1C0, 0, 0, 3, 0, -1, 9, "o-oooooooooo", "------------", GenMULU }, { "MULS", 0xC1C0, 0xF1C0, 0, 0, 3, 0, -1, 9, "o-oooooooooo", "------------", GenMULS }, { "EXGDD", 0xC140, 0xF1F8, 0, 0, -1, 0, -1, 9, "------------", "------------", GenEXGDD }, { "EXGAA", 0xC148, 0xF1F8, 0, 0, -1, 0, -1, 9, "------------", "------------", GenEXGAA }, { "EXGAD", 0xC188, 0xF1F8, 0, 0, -1, 0, -1, 9, "------------", "------------", GenEXGAD }, { "ADDaD", 0xD000, 0xF100, 2, 6, 3, 0, -1, 9, "oooooooooooo", "------------", GenADDaD }, { "ADDDa", 0xD100, 0xF100, 2, 6, 3, 0, -1, 9, "--ooooooo---", "------------", GenADDDa }, { "ADDX", 0xD100, 0xF138, 2, 6, -1, 0, -1, 9, "------------", "------------", GenADDX }, { "ADDXM", 0xD108, 0xF138, 2, 6, -1, 0, -1, 9, "------------", "------------", GenADDXM }, { "ADDX7M", 0xD10F, 0xF13F, 2, 6, -1, -1, -1, 9, "------------", "------------", GenADDX7M }, { "ADDXM7", 0xDF08, 0xFF38, 2, 6, -1, 0, -1, -1, "------------", "------------", GenADDXM7 }, { "ADDX7M7", 0xDF0F, 0xFF3F, 2, 6, -1, -1, -1, -1, "------------", "------------", GenADDX7M7 }, { "ADDA", 0xD0C0, 0xF0C0, 1, 8, 3, 0, -1, 9, "oooooooooooo", "------------", GenADDA }, { "ASRk", 0xE000, 0xF138, 2, 6, -1, 0, -1, -1, "o-----------", "------------", GenASRk }, { "LSRk", 0xE008, 0xF138, 2, 6, -1, 0, -1, -1, "o-----------", "------------", GenLSRk }, { "ROXRk", 0xE010, 0xF138, 2, 6, -1, 0, -1, -1, "o-----------", "------------", GenROXRk }, { "RORk", 0xE018, 0xF138, 2, 6, -1, 0, -1, -1, "o-----------", "------------", GenRORk }, { "ASLk", 0xE100, 0xF138, 2, 6, -1, 0, -1, -1, "o-----------", "------------", GenASLk }, { "LSLk", 0xE108, 0xF138, 2, 6, -1, 0, -1, -1, "o-----------", "------------", GenLSLk }, { "ROXLk", 0xE110, 0xF138, 2, 6, -1, 0, -1, -1, "o-----------", "------------", GenROXLk }, { "ROLk", 0xE118, 0xF138, 2, 6, -1, 0, -1, -1, "o-----------", "------------", GenROLk }, { "ASRD", 0xE020, 0xF138, 2, 6, -1, 0, -1, 9, "o-----------", "o-----------", GenASRD }, { "LSRD", 0xE028, 0xF138, 2, 6, -1, 0, -1, 9, "o-----------", "o-----------", GenLSRD }, { "ROXRD", 0xE030, 0xF138, 2, 6, -1, 0, -1, 9, "o-----------", "o-----------", GenROXRD }, { "RORD", 0xE038, 0xF138, 2, 6, -1, 0, -1, 9, "o-----------", "o-----------", GenRORD }, { "ASLD", 0xE120, 0xF138, 2, 6, -1, 0, -1, 9, "o-----------", "o-----------", GenASLD }, { "LSLD", 0xE128, 0xF138, 2, 6, -1, 0, -1, 9, "o-----------", "o-----------", GenLSLD }, { "ROXLD", 0xE130, 0xF138, 2, 6, -1, 0, -1, 9, "o-----------", "o-----------", GenROXLD }, { "ROLD", 0xE138, 0xF138, 2, 6, -1, 0, -1, 9, "o-----------", "o-----------", GenROLD }, { "ASR", 0xE0C0, 0xFFC0, 0, 0, 3, 0, -1, -1, "--ooooooo---", "------------", GenASR }, { "LSR", 0xE2C0, 0xFFC0, 0, 0, 3, 0, -1, -1, "--ooooooo---", "------------", GenLSR }, { "ROXR", 0xE4C0, 0xFFC0, 0, 0, 3, 0, -1, -1, "--ooooooo---", "------------", GenROXR }, { "ROR", 0xE6C0, 0xFFC0, 0, 0, 3, 0, -1, -1, "--ooooooo---", "------------", GenROR }, { "ASL", 0xE1C0, 0xFFC0, 0, 0, 3, 0, -1, -1, "--ooooooo---", "------------", GenASL }, { "LSL", 0xE3C0, 0xFFC0, 0, 0, 3, 0, -1, -1, "--ooooooo---", "------------", GenLSL }, { "ROXL", 0xE5C0, 0xFFC0, 0, 0, 3, 0, -1, -1, "--ooooooo---", "------------", GenROXL }, { "ROL", 0xE7C0, 0xFFC0, 0, 0, 3, 0, -1, -1, "--ooooooo---", "------------", GenROL } #ifdef NEOCD_HLE , { "0xFABE", 0xFABE, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", Gen0xFABE }, { "0xFABF", 0xFABF, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", Gen0xFABF }, { "0xFAC0", 0xFAC0, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", Gen0xFAC0 }, { "0xFAC1", 0xFAC1, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", Gen0xFAC1 }, { "0xFAC2", 0xFAC2, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", Gen0xFAC2 }, { "0xFAC3", 0xFAC3, 0xFFFF, 0, 0, -1, -1, -1, -1, "------------", "------------", Gen0xFAC3 } #endif }; #ifndef C68K_NO_JUMP_TABLE #ifdef C68K_CONST_JUMP_TABLE static u16 op_jump_table[0x10000]; #endif #endif // files where code is generated static FILE* ini_file = NULL; static FILE* opcode_file = NULL; // current generated instruction infos static c68k_op_info_struc *current_op; static u32 current_ea; static u32 current_eam; static u32 current_reg; static u32 current_ea2; static u32 current_eam2; static u32 current_reg2; static u32 current_size; static u32 current_cycle; static u32 current_io_sav; static char current_cond_char[128]; static char szc[20]; static char szcs[20]; static char szcf[20]; static char szcsf[20]; static u32 current_bits_mask; static u8 current_sft_mask; #define EA_DREG 0 #define EA_AREG 1 #define EA_AIND 2 #define EA_AINC 3 #define EA_ADEC 4 #define EA_D16A 5 #define EA_D8AX 6 #define EA_A16 7 #define EA_A32 8 #define EA_D16P 9 #define EA_D8PX 10 #define EA_IMM 11 #define EA_AINC7 12 #define EA_ADEC7 13 #define EA_ILLEGAL 15 static const u32 jmp_jsr_cycle_table[16] = { 0, 0, 4, 0, 0, 6, 10, 6, 8, 6, 10, 0, 0, 0, 0 }; static const u32 lea_pea_cycle_table[16] = { 0, 0, 0, 0, 0, 4, 8, 4, 8, 4, 8, 0, 0, 0, 0 }; static const u32 movem_cycle_table[16] = { 0, 0, 0, 0, 0, 4, 6, 4, 8, 4, 6, 0, 0, 0, 0 }; // general emitter function //////////////////////////// static u32 prepare_generate(void) { char filename[32]; sprintf(filename, "c68k_op%.1X.inc", (current_op->op_base >> 12) & 0xF); if (opcode_file != NULL) { fclose(opcode_file); opcode_file = NULL; } opcode_file = fopen(filename, "at"); if (opcode_file == NULL) { printf("Can't open %s\n", filename); return 1; } return 0; } static void wf_op(char* fmt, ...) { va_list args; if (opcode_file == NULL) return; va_start(args, fmt); vfprintf(opcode_file, fmt, args); va_end(args); } static void gen_jumptable(u32 base, u32 start1, u32 end1, u32 step1, u32 start2, u32 end2, u32 step2, u32 start3, u32 end3, u32 step3, u32 op) { #ifdef C68K_CONST_JUMP_TABLE u32 i, j, k; #endif #ifdef C68K_NO_JUMP_TABLE u32 i, j, k; #endif base &= 0xFFFF; start1 &= 0xFFFF; end1 &= 0xFFFF; step1 &= 0xFFFF; if (end1 < start1) end1 = start1; start2 &= 0xFFFF; end2 &= 0xFFFF; step2 &= 0xFFFF; if (end2 < start2) end2 = start2; op &= 0xFFFF; #ifndef C68K_NO_JUMP_TABLE #ifdef C68K_CONST_JUMP_TABLE if (step1 == 0) step1 = 1; if (step2 == 0) step2 = 1; if (step3 == 0) step3 = 1; for(i = start1; i <= end1; i += step1) for(j = start2; j <= end2; j += step2) for(k = start3; k <= end3; k += step3) op_jump_table[base + i + j + k] = op; #else if (ini_file == NULL) return; if (start1 != end1) { fprintf(ini_file, "\t\tfor(i = 0x%.4X; i <= 0x%.4X; i += 0x%.4X)\n", (int)start1, (int)end1, (int)step1); if (start2 != end2) { fprintf(ini_file, "\t\t\tfor(j = 0x%.4X; j <= 0x%.4X; j += 0x%.4X)\n\t", (int)start2, (int)end2, (int)step2); if (start3 != end3) { fprintf(ini_file, "\t\t\t\tfor(k = 0x%.4X; k <= 0x%.4X; k += 0x%.4X)\n\t", (int)start3, (int)end3, (int)step3); fprintf(ini_file, "\t\t\t\t\tJumpTable[0x%.4X + i + j + k] = &&OP_0x%.4X;\n", (int)base, (int)op); } else fprintf(ini_file, "\t\t\t\tJumpTable[0x%.4X + i + j] = &&OP_0x%.4X;\n", (int)base, (int)op); } else fprintf(ini_file, "\t\t\tJumpTable[0x%.4X + i] = &&OP_0x%.4X;\n", (int)base, (int)op); } else fprintf(ini_file, "\t\tJumpTable[0x%.4X] = &&OP_0x%.4X;\n", (int)base, (int)op); #endif #else if (step1 == 0) step1 = 1; if (step2 == 0) step2 = 1; if (step3 == 0) step3 = 1; for(i = start1; i <= end1; i += step1) for(j = start2; j <= end2; j += step2) for(k = start3; k <= end3; k += step3) { u32 temp=(base + i + j + k); if (temp != op && temp != 0x4E57 && temp != 0x4E5F) wf_op("case 0x%.4X:\n", base + i + j + k); } #endif } static void gen_opjumptable_ext(u32 base, u32 start3, u32 end3, u32 step3, u32 op) { u32 start1, end1, step1, start2, end2, step2; start1 = end1 = step1 = 0; start2 = end2 = step2 = 0; if ((current_op->reg_sft != -1) && (current_ea < 7)) { if ((current_ea == EA_AINC) || (current_ea == EA_ADEC)) end1 = 6 << current_op->reg_sft; else end1 = 7 << current_op->reg_sft; step1 = 1 << current_op->reg_sft; } if ((current_op->reg2_sft != -1) && (current_ea2 < 7)) { if ((current_ea2 == EA_AINC) || (current_ea2 == EA_ADEC)) end2 = 6 << current_op->reg2_sft; else end2 = 7 << current_op->reg2_sft; step2 = 1 << current_op->reg2_sft; } if (start1 != end1) { if (start2 != end2) gen_jumptable(base, start1, end1, step1, start2, end2, step2, start3, end3, step3, op); else gen_jumptable(base, start1, end1, step1, start3, end3, step3, start2, end2, step2, op); } else if (start2 != end2) gen_jumptable(base, start2, end2, step2, start3, end3, step3, start1, end1, step1, op); else gen_jumptable(base, start3, end3, step3, start2, end2, step2, start1, end1, step1, op); } static void gen_opjumptable(u32 op) { gen_opjumptable_ext(op, 0, 0, 0, op); } #define GEN_ADR 1 #define GEN_RES 2 #define GEN_SRC 4 #define GEN_DST 8 #define GEN_ALL 15 static void start_op(u32 op, int v) { current_io_sav = 0; current_cycle = 0; wf_op("\n// %s\n", current_op->op_name); #ifndef C68K_NO_JUMP_TABLE wf_op("OP_0x%.4X:\n", op & 0xFFFF); #else wf_op("case 0x%.4X:\n", op & 0xFFFF); #endif wf_op("{\n"); if (v & GEN_ADR) wf_op("\tu32 adr;\n"); if (v & GEN_RES) wf_op("\tu32 res;\n"); if (v & GEN_DST) wf_op("\tpointer dst;\n"); if (v & GEN_SRC) wf_op("\tpointer src;\n"); } static void add_CCnt(u32 cycle) { if (current_io_sav) wf_op("\tPOST_IO\n"); current_io_sav = 0; wf_op("\tCCnt -= %d;\n", cycle); } static void adds_CCnt(char *str) { if (current_io_sav) wf_op("\tPOST_IO\n"); current_io_sav = 0; wf_op("\tCCnt -= %s;\n", str); } #if 0 // FIXME: warning removal static void sub_CCnt(u32 cycle) { if (current_io_sav) wf_op("\tPOST_IO\n"); current_io_sav = 0; wf_op("\tCCnt += %d;\n", cycle); } static void subs_CCnt(char *str) { if (current_io_sav) wf_op("\tPOST_IO\n"); current_io_sav = 0; wf_op("\tCCnt += %s;\n", str); } static void quick_fterminate_op(u32 cycle) { if (current_io_sav) wf_op("\tPOST_IO\n"); current_io_sav = 0; wf_op("\tCCnt -= %d;\n", current_cycle + cycle); wf_op("\tgoto C68k_Exec_End;\n"); } #endif static void fterminate_op(u32 cycle) { wf_op("}\n"); if (current_io_sav) wf_op("POST_IO\n"); current_io_sav = 0; wf_op("CCnt -= %d;\n", current_cycle + cycle); wf_op("goto C68k_Exec_End;\n"); } static void quick_terminate_op(u32 cycle) { if (current_io_sav) wf_op("\tPOST_IO\n"); current_io_sav = 0; wf_op("\tRET(%d)\n", current_cycle + cycle); } static void terminate_op(u32 cycle) { if (current_io_sav) wf_op("\tPOST_IO\n"); wf_op("}\n"); current_io_sav = 0; wf_op("RET(%d)\n", current_cycle + cycle); } static void do_pre_io(void) { if (!current_io_sav) fprintf(opcode_file, "\tPRE_IO\n"); current_io_sav = 1; } static void mem_op(char* fmt, ...) { va_list args; if (opcode_file == NULL) return; do_pre_io(); va_start(args, fmt); vfprintf(opcode_file, fmt, args); va_end(args); } // flag emitter function ///////////////////////// static void set_logic_flag(void) { wf_op("\tCPU->flag_C = 0;\n"); wf_op("\tCPU->flag_V = 0;\n"); wf_op("\tCPU->flag_notZ = res;\n"); switch(current_size) { case SIZE_BYTE: wf_op("\tCPU->flag_N = res;\n"); break; case SIZE_WORD: wf_op("\tCPU->flag_N = res >> 8;\n"); break; case SIZE_LONG: wf_op("\tCPU->flag_N = res >> 24;\n"); break; } } static void set_logicl_flag(void) { wf_op("\tCPU->flag_C = 0;\n"); wf_op("\tCPU->flag_V = 0;\n"); switch(current_size) { case SIZE_BYTE: wf_op("\tCPU->flag_N = res;\n"); wf_op("\tCPU->flag_notZ = res & 0xFF;\n"); break; case SIZE_WORD: wf_op("\tCPU->flag_notZ = res & 0xFFFF;\n"); wf_op("\tCPU->flag_N = res >> 8;\n"); break; case SIZE_LONG: wf_op("\tCPU->flag_notZ = res;\n"); wf_op("\tCPU->flag_N = res >> 24;\n"); break; } } static void set_add_flag(void) { switch(current_size) { case SIZE_BYTE: wf_op("\tCPU->flag_N = CPU->flag_X = CPU->flag_C = res;\n"); wf_op("\tCPU->flag_V = (u32)((src ^ res) & (dst ^ res));\n"); wf_op("\tCPU->flag_notZ = res & 0xFF;\n"); break; case SIZE_WORD: wf_op("\tCPU->flag_V = (u32)((src ^ res) & (dst ^ res)) >> 8;\n"); wf_op("\tCPU->flag_N = CPU->flag_X = CPU->flag_C = res >> 8;\n"); wf_op("\tCPU->flag_notZ = res & 0xFFFF;\n"); break; case SIZE_LONG: wf_op("\tCPU->flag_notZ = res;\n"); wf_op("\tCPU->flag_X = CPU->flag_C = (((u32)src & (u32)dst & 1) + ((u32)src >> 1) + ((u32)dst >> 1)) >> 23;\n"); // wf_op("\tCPU->flag_X = CPU->flag_C = ((src & dst) | (~res & (src | dst))) >> 23;\n"); wf_op("\tCPU->flag_V = (((u32)src ^ res) & ((u32)dst ^ res)) >> 24;\n"); wf_op("\tCPU->flag_N = res >> 24;\n"); break; } } static void set_addx_flag(void) { switch(current_size) { case SIZE_BYTE: wf_op("\tCPU->flag_N = CPU->flag_X = CPU->flag_C = res;\n"); wf_op("\tCPU->flag_V = (u32)((src ^ res) & (dst ^ res));\n"); wf_op("\tCPU->flag_notZ |= res & 0xFF;\n"); break; case SIZE_WORD: wf_op("\tCPU->flag_V = (u32)((src ^ res) & (dst ^ res)) >> 8;\n"); wf_op("\tCPU->flag_N = CPU->flag_X = CPU->flag_C = res >> 8;\n"); wf_op("\tCPU->flag_notZ |= res & 0xFFFF;\n"); break; case SIZE_LONG: wf_op("\tCPU->flag_notZ |= res;\n"); wf_op("\tCPU->flag_X = CPU->flag_C = (((u32)src & dst & 1) + ((u32)src >> 1) + ((u32)dst >> 1)) >> 23;\n"); // wf_op("\tCPU->flag_X = CPU->flag_C = ((src & dst) | (~res & (src | dst))) >> 23;\n"); wf_op("\tCPU->flag_V = (((u32)src ^ res) & ((u32)dst ^ res)) >> 24;\n"); wf_op("\tCPU->flag_N = res >> 24;\n"); break; } } static void set_sub_flag(void) { switch(current_size) { case SIZE_BYTE: wf_op("\tCPU->flag_N = CPU->flag_X = CPU->flag_C = res;\n"); wf_op("\tCPU->flag_V = ((u32)src ^ (u32)dst) & (res ^ (u32)dst);\n"); wf_op("\tCPU->flag_notZ = res & 0xFF;\n"); break; case SIZE_WORD: wf_op("\tCPU->flag_V = (((u32)src ^ (u32)dst) & (res ^ (u32)dst)) >> 8;\n"); wf_op("\tCPU->flag_N = CPU->flag_X = CPU->flag_C = res >> 8;\n"); wf_op("\tCPU->flag_notZ = res & 0xFFFF;\n"); break; case SIZE_LONG: wf_op("\tCPU->flag_notZ = res;\n"); wf_op("\tCPU->flag_X = CPU->flag_C = (((u32)src & res & 1) + ((u32)src >> 1) + (res >> 1)) >> 23;\n"); // wf_op("\tCPU->flag_X = CPU->flag_C = ((src & res) | (~dst & (src | res))) >> 23;\n"); wf_op("\tCPU->flag_V = (((u32)src ^ (u32)dst) & (res ^ (u32)dst)) >> 24;\n"); wf_op("\tCPU->flag_N = res >> 24;\n"); break; } } static void set_subx_flag(void) { switch(current_size) { case SIZE_BYTE: wf_op("\tCPU->flag_N = CPU->flag_X = CPU->flag_C = res;\n"); wf_op("\tCPU->flag_V = ((u32)src ^ (u32)dst) & (res ^ (u32)dst);\n"); wf_op("\tCPU->flag_notZ |= res & 0xFF;\n"); break; case SIZE_WORD: wf_op("\tCPU->flag_V = (((u32)src ^ (u32)dst) & (res ^ (u32)dst)) >> 8;\n"); wf_op("\tCPU->flag_N = CPU->flag_X = CPU->flag_C = res >> 8;\n"); wf_op("\tCPU->flag_notZ |= res & 0xFFFF;\n"); break; case SIZE_LONG: wf_op("\tCPU->flag_notZ |= res;\n"); wf_op("\tCPU->flag_X = CPU->flag_C = (((u32)src & res & 1) + ((u32)src >> 1) + (res >> 1)) >> 23;\n"); // wf_op("\tCPU->flag_X = CPU->flag_C = ((src & res) | (~dst & (src | res))) >> 23;\n"); wf_op("\tCPU->flag_V = (((u32)src ^ (u32)dst) & (res ^ (u32)dst)) >> 24;\n"); wf_op("\tCPU->flag_N = res >> 24;\n"); break; } } static void set_cmp_flag(void) { switch(current_size) { case SIZE_BYTE: wf_op("\tCPU->flag_N = CPU->flag_C = res;\n"); wf_op("\tCPU->flag_V = ((u32)src ^ (u32)dst) & (res ^ (u32)dst);\n"); wf_op("\tCPU->flag_notZ = res & 0xFF;\n"); break; case SIZE_WORD: wf_op("\tCPU->flag_V = (((u32)src ^ (u32)dst) & (res ^ (u32)dst)) >> 8;\n"); wf_op("\tCPU->flag_N = CPU->flag_C = res >> 8;\n"); wf_op("\tCPU->flag_notZ = res & 0xFFFF;\n"); break; case SIZE_LONG: wf_op("\tCPU->flag_notZ = res;\n"); wf_op("\tCPU->flag_C = (((u32)src & res & 1) + ((u32)src >> 1) + (res >> 1)) >> 23;\n"); // wf_op("\tCPU->flag_C = ((src & res) | (~dst & (src | res))) >> 23;\n"); wf_op("\tCPU->flag_V = (((u32)src ^ (u32)dst) & (res ^ (u32)dst)) >> 24;\n"); wf_op("\tCPU->flag_N = res >> 24;\n"); break; } } static void set_negx_flag(void) { switch(current_size) { case SIZE_BYTE: wf_op("\tCPU->flag_V = res & (u32)src;\n"); wf_op("\tCPU->flag_N = CPU->flag_X = CPU->flag_C = res;\n"); wf_op("\tCPU->flag_notZ |= res & 0xFF;\n"); break; case SIZE_WORD: wf_op("\tCPU->flag_V = (res & (u32)src) >> 8;\n"); wf_op("\tCPU->flag_N = CPU->flag_X = CPU->flag_C = res >> 8;\n"); wf_op("\tCPU->flag_notZ |= res & 0xFFFF;\n"); break; case SIZE_LONG: wf_op("\tCPU->flag_notZ |= res;\n"); wf_op("\tCPU->flag_V = (res & (u32)src) >> 24;\n"); wf_op("\tCPU->flag_X = CPU->flag_C = (((u32)src & res & 1) + ((u32)src >> 1) + (res >> 1)) >> 23;\n"); // wf_op("\tCPU->flag_X = CPU->flag_C = (((u32)src & res) | (~(u32)dst & ((u32)src | res))) >> 23;\n"); wf_op("\tCPU->flag_N = res >> 24;\n"); break; } } static void set_neg_flag(void) { switch(current_size) { case SIZE_BYTE: wf_op("\tCPU->flag_V = res & (u32)src;\n"); wf_op("\tCPU->flag_N = CPU->flag_X = CPU->flag_C = res;\n"); wf_op("\tCPU->flag_notZ = res & 0xFF;\n"); break; case SIZE_WORD: wf_op("\tCPU->flag_V = (res & (u32)src) >> 8;\n"); wf_op("\tCPU->flag_N = CPU->flag_X = CPU->flag_C = res >> 8;\n"); wf_op("\tCPU->flag_notZ = res & 0xFFFF;\n"); break; case SIZE_LONG: wf_op("\tCPU->flag_notZ = res;\n"); wf_op("\tCPU->flag_V = (res & (u32)src) >> 24;\n"); wf_op("\tCPU->flag_X = CPU->flag_C = (((u32)src & res & 1) + ((u32)src >> 1) + (res >> 1)) >> 23;\n"); // wf_op("\tCPU->flag_X = CPU->flag_C = ((src & res) | (~dst & (src | res))) >> 23;\n"); wf_op("\tCPU->flag_N = res >> 24;\n"); break; } } static char* get_cond_as_cond(u32 cond, u32 notvar) { if (notvar) cond ^= 1; switch(cond) { case COND_TR: sprintf(current_cond_char, "(1)"); break; case COND_FA: sprintf(current_cond_char, "(0)"); break; case COND_HI: sprintf(current_cond_char, "(CPU->flag_notZ && (!(CPU->flag_C & 0x100)))"); break; case COND_LS: sprintf(current_cond_char, "((!CPU->flag_notZ) || (CPU->flag_C & 0x100))"); break; case COND_CC: sprintf(current_cond_char, "(!(CPU->flag_C & 0x100))"); break; case COND_CS: sprintf(current_cond_char, "(CPU->flag_C & 0x100)"); break; case COND_NE: sprintf(current_cond_char, "(CPU->flag_notZ)"); break; case COND_EQ: sprintf(current_cond_char, "(!CPU->flag_notZ)"); break; case COND_VC: sprintf(current_cond_char, "(!(CPU->flag_V & 0x80))"); break; case COND_VS: sprintf(current_cond_char, "(CPU->flag_V & 0x80)"); break; case COND_PL: sprintf(current_cond_char, "(!(CPU->flag_N & 0x80))"); break; case COND_MI: sprintf(current_cond_char, "(CPU->flag_N & 0x80)"); break; case COND_GE: sprintf(current_cond_char, "(!((CPU->flag_N ^ CPU->flag_V) & 0x80))"); break; case COND_LT: sprintf(current_cond_char, "((CPU->flag_N ^ CPU->flag_V) & 0x80)"); break; case COND_GT: sprintf(current_cond_char, "(CPU->flag_notZ && (!((CPU->flag_N ^ CPU->flag_V) & 0x80)))"); break; case COND_LE: sprintf(current_cond_char, "((!CPU->flag_notZ) || ((CPU->flag_N ^ CPU->flag_V) & 0x80))"); break; } return current_cond_char; } // effective address related function ////////////////////////////////////// static u32 has_ea(u32 ea) { if (ea == EA_AINC7) return (current_op->ea_supported[EA_AINC] == 'o'); if (ea == EA_ADEC7) return (current_op->ea_supported[EA_ADEC] == 'o'); if (ea <= EA_IMM) return (current_op->ea_supported[ea] == 'o'); return 0; } static u32 has_ea2(u32 ea) { if (ea == EA_AINC7) return (current_op->ea2_supported[EA_AINC] == 'o'); if (ea == EA_ADEC7) return (current_op->ea2_supported[EA_ADEC] == 'o'); if (ea <= EA_IMM) return (current_op->ea2_supported[ea] == 'o'); return 0; } #if 0 // FIXME: warning removal static u32 _eamreg_to_ea(u32 eam, u32 reg) { if ((eam > 7) || (reg > 7)) return EA_ILLEGAL; if ((eam == 3) && (reg == 7)) return EA_AINC7; if ((eam == 4) && (reg == 7)) return EA_ADEC7; if (eam != 7) return eam; if (reg < 5) return (eam + reg); return EA_ILLEGAL; } #endif static u32 _ea_to_eamreg(u32 ea) { if (ea < 7) return (ea << 3) | 0; if (ea == EA_AINC7) return (EA_AINC << 3) | 7; if (ea == EA_ADEC7) return (EA_ADEC << 3) | 7; if (ea <= EA_IMM) return (7 << 3) | (ea - 7); return (7 << 3) | 7; } static u32 is_ea_memory(u32 ea) { if ((ea > EA_AREG) && (ea != EA_IMM)) return 1; else return 0; } static void _ea_calc_free(u32 ea, u32 rsft) { u32 step; step = 0; switch (current_size) { case SIZE_BYTE: if ((ea == EA_AINC7) || (ea == EA_ADEC7)) step = 2; else step = 1; break; case SIZE_WORD: step = 2; break; case SIZE_LONG: step = 4; break; } switch (ea) { case EA_DREG: // wf_op("\tadr = (u32)(&CPU->D[(Opcode >> %d) & 7]);\n", rsft); break; case EA_AREG: // wf_op("\tadr = (u32)(&CPU->A[(Opcode >> %d) & 7]);\n", rsft); break; case EA_AIND: wf_op("\tadr = CPU->A[(Opcode >> %d) & 7];\n", rsft); break; case EA_AINC: wf_op("\tadr = CPU->A[(Opcode >> %d) & 7];\n", rsft); wf_op("\tCPU->A[(Opcode >> %d) & 7] += %d;\n", rsft, step); break; case EA_AINC7: wf_op("\tadr = CPU->A[7];\n"); wf_op("\tCPU->A[7] += %d;\n", step); break; case EA_ADEC: wf_op("\tadr = CPU->A[(Opcode >> %d) & 7] - %d;\n", rsft, step); wf_op("\tCPU->A[(Opcode >> %d) & 7] = adr;\n", rsft); break; case EA_ADEC7: wf_op("\tadr = CPU->A[7] - %d;\n", step); wf_op("\tCPU->A[7] = adr;\n"); break; case EA_D16A: wf_op("\tadr = CPU->A[(Opcode >> %d) & 7] + (s32)(s16)FETCH_WORD;\n", rsft); wf_op("\tPC += 2;\n"); break; case EA_D8AX: wf_op("\tadr = CPU->A[(Opcode >> %d) & 7];\n", rsft); wf_op("\tDECODE_EXT_WORD\n"); break; case EA_A16: wf_op("\tadr = (s32)(s16)FETCH_WORD;\n"); wf_op("\tPC += 2;\n"); break; case EA_A32: wf_op("\tadr = (s32)FETCH_LONG;\n"); wf_op("\tPC += 4;\n"); break; case EA_D16P: wf_op("\tadr = (u32)(PC - CPU->BasePC) + (s32)(s16)FETCH_WORD;\n"); wf_op("\tPC += 2;\n"); break; case EA_D8PX: wf_op("\tadr = (u32)(PC - CPU->BasePC);\n"); wf_op("\tDECODE_EXT_WORD\n"); break; } } static void _ea_calc(u32 ea, u32 rsft) { u32 step; u32 cycle_sft; step = 0; cycle_sft = 0; switch (current_size) { case SIZE_BYTE: if ((ea == EA_AINC7) || (ea == EA_ADEC7)) step = 2; else step = 1; break; case SIZE_WORD: step = 2; break; case SIZE_LONG: cycle_sft = 1; step = 4; break; } switch (ea) { case EA_DREG: // wf_op("\tadr = (u32)(&CPU->D[(Opcode >> %d) & 7]);\n", rsft); break; case EA_AREG: // wf_op("\tadr = (u32)(&CPU->A[(Opcode >> %d) & 7]);\n", rsft); break; case EA_IMM: current_cycle += (4 << cycle_sft) + 0; break; case EA_AIND: current_cycle += (4 << cycle_sft) + 0; wf_op("\tadr = CPU->A[(Opcode >> %d) & 7];\n", rsft); break; case EA_AINC: current_cycle += (4 << cycle_sft) + 0; wf_op("\tadr = CPU->A[(Opcode >> %d) & 7];\n", rsft); wf_op("\tCPU->A[(Opcode >> %d) & 7] += %d;\n", rsft, step); break; case EA_AINC7: current_cycle += (4 << cycle_sft) + 0; wf_op("\tadr = CPU->A[7];\n"); wf_op("\tCPU->A[7] += %d;\n", step); break; case EA_ADEC: current_cycle += (4 << cycle_sft) + 2; wf_op("\tadr = CPU->A[(Opcode >> %d) & 7] - %d;\n", rsft, step); wf_op("\tCPU->A[(Opcode >> %d) & 7] = adr;\n", rsft); break; case EA_ADEC7: current_cycle += (4 << cycle_sft) + 2; wf_op("\tadr = CPU->A[7] - %d;\n", step); wf_op("\tCPU->A[7] = adr;\n"); break; case EA_D16A: current_cycle += (4 << cycle_sft) + 4; wf_op("\tadr = CPU->A[(Opcode >> %d) & 7] + (s32)(s16)FETCH_WORD;\n", rsft); wf_op("\tPC += 2;\n"); break; case EA_D8AX: current_cycle += (4 << cycle_sft) + 6; wf_op("\tadr = CPU->A[(Opcode >> %d) & 7];\n", rsft); wf_op("\tDECODE_EXT_WORD\n"); break; case EA_A16: current_cycle += (4 << cycle_sft) + 4; wf_op("\tadr = (s32)(s16)FETCH_WORD;\n"); wf_op("\tPC += 2;\n"); break; case EA_A32: current_cycle += (4 << cycle_sft) + 8; wf_op("\tadr = (s32)FETCH_LONG;\n"); wf_op("\tPC += 4;\n"); break; case EA_D16P: current_cycle += (4 << cycle_sft) + 4; wf_op("\tadr = (u32)(PC - CPU->BasePC) + (s32)(s16)FETCH_WORD;\n"); wf_op("\tPC += 2;\n"); break; case EA_D8PX: current_cycle += (4 << cycle_sft) + 6; wf_op("\tadr = (u32)(PC - CPU->BasePC);\n"); wf_op("\tDECODE_EXT_WORD\n"); break; } } static void _ea_read_(u32 ea, u32 rsft, char dest[4]) { char sz[8]; switch (current_size) { case SIZE_BYTE: strcpy(sz, "BYTE"); break; case SIZE_WORD: strcpy(sz, "WORD"); break; case SIZE_LONG: strcpy(sz, "LONG"); break; } switch (ea) { case EA_DREG: wf_op("\t%s = (%s)CPU->D[(Opcode >> %d) & 7];\n", dest, szc, rsft); break; case EA_AREG: if (current_size == SIZE_BYTE) { wf_op("\t// can't read byte from Ax registers !\n"); wf_op("\tCPU->Status |= C68K_FAULTED;\n"); wf_op("\tCCnt = 0;\n"); wf_op("\tgoto C68k_Exec_Really_End;\n"); } else wf_op("\t%s = (%s)CPU->A[(Opcode >> %d) & 7];\n", dest, szc, rsft); break; /* case EA_DREG: case EA_AREG: wf_op("\t%s = %s(adr);\n", dest, szcf); break; */ case EA_A32: case EA_D8AX: case EA_D8PX: case EA_D16A: case EA_D16P: case EA_A16: case EA_ADEC: case EA_ADEC7: case EA_AIND: case EA_AINC: case EA_AINC7: mem_op("\tREAD_%s_F(adr, %s)\n", sz, dest); break; case EA_IMM: switch (current_size) { case SIZE_BYTE: wf_op("\t%s = FETCH_BYTE;\n", dest); wf_op("\tPC += 2;\n"); break; case SIZE_WORD: wf_op("\t%s = FETCH_WORD;\n", dest); wf_op("\tPC += 2;\n"); break; case SIZE_LONG: wf_op("\t%s = FETCH_LONG;\n", dest); wf_op("\tPC += 4;\n"); break; } break; } } static void _ea_read(u32 ea, u32 rsft) { _ea_read_(ea, rsft, "res"); } static void _ea_read_src(u32 ea, u32 rsft) { _ea_read_(ea, rsft, "src"); } static void _ea_read_dst(u32 ea, u32 rsft) { _ea_read_(ea, rsft, "dst"); } static void _ea_read_sx_(u32 ea, u32 rsft, char dest[4]) { char sz[8]; switch (current_size) { case SIZE_BYTE: strcpy(sz, "BYTE"); break; case SIZE_WORD: strcpy(sz, "WORD"); break; case SIZE_LONG: strcpy(sz, "LONG"); break; } switch (ea) { case EA_DREG: wf_op("\t%s = (s32)(%s)CPU->D[(Opcode >> %d) & 7];\n", dest, szcs, rsft); break; case EA_AREG: if (current_size == SIZE_BYTE) { wf_op("\t// can't read byte from Ax registers !\n"); wf_op("\tCPU->Status |= C68K_FAULTED;\n"); wf_op("\tCCnt = 0;\n"); wf_op("\tgoto C68k_Exec_Really_End;\n"); } else wf_op("\t%s = (s32)(%s)CPU->A[(Opcode >> %d) & 7];\n", dest, szcs, rsft); break; /* case EA_DREG: case EA_AREG: wf_op("\t%s = (s32)(%s(adr));\n", dest, szcsf); break; */ case EA_A32: case EA_D8AX: case EA_D8PX: case EA_D16A: case EA_D16P: case EA_A16: case EA_ADEC: case EA_ADEC7: case EA_AIND: case EA_AINC: case EA_AINC7: mem_op("\tREADSX_%s_F(adr, %s)\n", sz, dest); break; case EA_IMM: switch (current_size) { case SIZE_BYTE: wf_op("\t%s = (s32)(%s(PC)));\n", dest, szcsf); wf_op("\tPC += 2;\n"); break; case SIZE_WORD: wf_op("\t%s = (s32)(%s)FETCH_WORD;\n", dest, szcs); wf_op("\tPC += 2;\n"); break; case SIZE_LONG: wf_op("\t%s = (s32)(%s)FETCH_LONG;\n", dest, szcs); wf_op("\tPC += 4;\n"); break; } break; } } static void _ea_read_sx(u32 ea, u32 rsft) { _ea_read_sx_(ea, rsft, "res"); } static void _ea_read_src_sx(u32 ea, u32 rsft) { _ea_read_sx_(ea, rsft, "src"); } static void _ea_write(u32 ea, u32 rsft) { char sz[8]; switch (current_size) { case SIZE_BYTE: strcpy(sz, "BYTE"); break; case SIZE_WORD: strcpy(sz, "WORD"); break; case SIZE_LONG: strcpy(sz, "LONG"); break; } switch (ea) { case EA_DREG: wf_op("\t%s(&CPU->D[(Opcode >> %d) & 7])) = res;\n", szcf, rsft); break; case EA_AREG: // writes in Ax registers are always 32 bits sized wf_op("\tCPU->A[(Opcode >> %d) & 7] = res;\n", rsft); break; /* case EA_DREG: case EA_AREG: wf_op("\t%s(adr) = res;\n", szcf); break; */ case EA_A32: case EA_D8AX: case EA_D8PX: case EA_D16A: case EA_D16P: case EA_A16: case EA_ADEC: case EA_ADEC7: case EA_AIND: case EA_AINC: case EA_AINC7: mem_op("\tWRITE_%s_F(adr, res)\n", sz); break; } } // misc function ///////////////// static u32 get_current_opcode_base(void) { u32 base; base = current_op->op_base; if (current_op->eam_sft != -1) base += (current_eam & 7) << current_op->eam_sft; if (current_op->reg_sft != -1) base += (current_reg & 7) << current_op->reg_sft; if (current_op->eam2_sft != -1) base += (current_eam2 & 7) << current_op->eam2_sft; if (current_op->reg2_sft != -1) base += (current_reg2 & 7) << current_op->reg2_sft; if (current_op->size_type == 1) base += (current_size - 1) << current_op->size_sft; else if (current_op->size_type == 2) base += (current_size & 3) << current_op->size_sft; return base; } static void start_all(int v) { u32 base; base = get_current_opcode_base(); // generate jump table gen_opjumptable(base); // generate label & declarations start_op(base, v); } static void set_current_size(u32 sz) { current_size = sz; switch(current_size) { case SIZE_BYTE: current_bits_mask = 0xFF; current_sft_mask = 7; strcpy(szc, "u8"); strcpy(szcf, "*(BYTE_OFF + (u8*)"); strcpy(szcs, "s8"); strcpy(szcsf, "*(BYTE_OFF + (s8*)"); break; case SIZE_WORD: current_bits_mask = 0xFFFF; current_sft_mask = 15; strcpy(szc, "u16"); strcpy(szcf, "*(WORD_OFF + (u16*)"); strcpy(szcs, "s16"); strcpy(szcsf, "*(WORD_OFF + (s16*)"); break; case SIZE_LONG: current_bits_mask = 0xFFFFFFFF; current_sft_mask = 31; strcpy(szc, "u32"); strcpy(szcf, "*((u32*)"); strcpy(szcs, "s32"); strcpy(szcsf, "*((s32*)"); break; } } // gen privilege exception (happen when S flag is not set) static void gen_privilege_exception(char *pre) { // swap A7 and USP (because S not set) wf_op("%sres = CPU->USP;\n", pre); wf_op("%sCPU->USP = CPU->A[7];\n", pre); wf_op("%sCPU->A[7] = res;\n", pre); // get vector & add cycle wf_op("%sres = C68K_PRIVILEGE_VIOLATION_EX;\n", pre); adds_CCnt("c68k_exception_cycle_table[res]"); // we will do some mem/io access do_pre_io(); // push PC and SR mem_op("%sPUSH_32_F((u32)(PC - CPU->BasePC))\n", pre); mem_op("%sPUSH_16_F(GET_SR)\n", pre); // adjust SR wf_op("%sCPU->flag_S = C68K_SR_S;\n", pre); // fetch new PC mem_op("%sREAD_LONG_F(res * 4, PC)\n", pre); wf_op("%sSET_PC(PC)\n", pre); } static void gen_exception(char *pre, char* exception) { // swap A7 and USP if needed wf_op("%sif (!CPU->flag_S)\n", pre); wf_op("%s{\n", pre); wf_op("%s\tres = CPU->USP;\n", pre); wf_op("%s\tCPU->USP = CPU->A[7];\n", pre); wf_op("%s\tCPU->A[7] = res;\n", pre); wf_op("%s}\n", pre); // get vector & add cycle wf_op("%sres = %s;\n", pre, exception); adds_CCnt("c68k_exception_cycle_table[res]"); // we will do some mem/io access do_pre_io(); // push PC and SR mem_op("%sPUSH_32_F((u32)(PC - CPU->BasePC))\n", pre); mem_op("%sPUSH_16_F(GET_SR)\n", pre); // adjust SR wf_op("%sCPU->flag_S = C68K_SR_S;\n", pre); // fetch new PC mem_op("%sREAD_LONG_F(res * 4, PC)\n", pre); wf_op("%sSET_PC(PC)\n", pre); } yabause-0.9.15/src/c68k/c68kmac.inc000644 001750 001750 00000025215 12755623101 020551 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2004 Stephane Dallongeville This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ // internals core macros ///////////////////////// #define LSL(A, C) ((A) << (C)) #define LSR(A, C) ((A) >> (C)) #define LSR_32(A, C) ((C) < 32 ? (A) >> (C) : 0) #define LSL_32(A, C) ((C) < 32 ? (A) << (C) : 0) #define ROL_8(A, C) (LSL(A, C) | LSR(A, 8-(C))) #define ROL_9(A, C) (LSL(A, C) | LSR(A, 9-(C))) #define ROL_16(A, C) (LSL(A, C) | LSR(A, 16-(C))) #define ROL_17(A, C) (LSL(A, C) | LSR(A, 17-(C))) #define ROL_32(A, C) (LSL_32(A, C) | LSR_32(A, 32-(C))) #define ROL_33(A, C) (LSL_32(A, C) | LSR_32(A, 33-(C))) #define ROR_8(A, C) (LSR(A, C) | LSL(A, 8-(C))) #define ROR_9(A, C) (LSR(A, C) | LSL(A, 9-(C))) #define ROR_16(A, C) (LSR(A, C) | LSL(A, 16-(C))) #define ROR_17(A, C) (LSR(A, C) | LSL(A, 17-(C))) #define ROR_32(A, C) (LSR_32(A, C) | LSL_32(A, 32-(C))) #define ROR_33(A, C) (LSR_32(A, C) | LSL_32(A, 33-(C))) #ifdef TRACE_WITH_Q68 extern void TRACE(int,c68k_struc*,int,int); #else # define TRACE(a,b,c,d) /*nothing*/ #endif #ifndef C68K_NO_JUMP_TABLE #define NEXT \ PRE_IO \ Opcode = FETCH_WORD; \ PC += 2; \ TRACE(PC, CPU, Opcode, CCnt); \ goto *JumpTable[Opcode]; #else #define NEXT \ PRE_IO \ Opcode = FETCH_WORD; \ PC += 2; \ TRACE(PC, CPU, Opcode, CCnt); \ goto SwitchTable; #endif #define RET(A) \ CCnt -= (A); \ if (CCnt <= 0) goto C68k_Exec_End; \ NEXT #define SET_PC(A) \ CPU->BasePC = CPU->Fetch[((A) >> C68K_FETCH_SFT) & C68K_FETCH_MASK]; \ CPU->BasePC -= (A) & 0xFF000000; \ PC = (A) + CPU->BasePC; #define PRE_IO \ CPU->CycleIO = CCnt; #define POST_IO \ CCnt = CPU->CycleIO; #define READ_BYTE_F(A, D) \ D = CPU->Read_Byte(A) & 0xFF; #define READ_WORD_F(A, D) \ D = CPU->Read_Word(A) & 0xFFFF; #ifdef C68K_BIG_ENDIAN #define READ_LONG_F(A, D) \ D = CPU->Read_Word((A)) << 16; \ D |= CPU->Read_Word((A) + 2) & 0xFFFF; #define READ_LONG_DEC_F(A, D) \ D = CPU->Read_Word((A) + 2) & 0xFFFF; \ D |= CPU->Read_Word((A)) << 16; #else #define READ_LONG_F(A, D) \ D = CPU->Read_Word((A)) << 16; \ D |= CPU->Read_Word((A) + 2) & 0xFFFF; #define READ_LONG_DEC_F(A, D) \ D = CPU->Read_Word((A) + 2) & 0xFFFF; \ D |= CPU->Read_Word((A)) << 16; #endif #define READSX_BYTE_F(A, D) \ D = (s32)(s8)CPU->Read_Byte(A); #define READSX_WORD_F(A, D) \ D = (s32)(s16)CPU->Read_Word(A); #ifdef C68K_BIG_ENDIAN #define READSX_LONG_F(A, D) \ D = CPU->Read_Word((A)) << 16; \ D |= CPU->Read_Word((A) + 2) & 0xFFFF; #define READSX_LONG_DEC_F(A, D) \ D = CPU->Read_Word((A) + 2) & 0xFFFF; \ D |= CPU->Read_Word((A)) << 16; #else #define READSX_LONG_F(A, D) \ D = CPU->Read_Word((A)) << 16; \ D |= CPU->Read_Word((A) + 2) & 0xFFFF; #define READSX_LONG_DEC_F(A, D) \ D = CPU->Read_Word((A) + 2) & 0xFFFF; \ D |= CPU->Read_Word((A)) << 16; #endif #define WRITE_BYTE_F(A, D) \ CPU->Write_Byte(A, D); #define WRITE_WORD_F(A, D) \ CPU->Write_Word(A, D); #ifdef C68K_BIG_ENDIAN #define WRITE_LONG_F(A, D) \ CPU->Write_Word((A), (D) >> 16); \ CPU->Write_Word((A) + 2, (D) & 0xFFFF); #define WRITE_LONG_DEC_F(A, D) \ CPU->Write_Word((A) + 2, (D) & 0xFFFF); \ CPU->Write_Word((A), (D) >> 16); #else #define WRITE_LONG_F(A, D) \ CPU->Write_Word((A), (D) >> 16); \ CPU->Write_Word((A) + 2, (D) & 0xFFFF); #define WRITE_LONG_DEC_F(A, D) \ CPU->Write_Word((A) + 2, (D) & 0xFFFF); \ CPU->Write_Word((A), (D) >> 16); #endif #define PUSH_16_F(D) \ CPU->Write_Word(CPU->A[7] -= 2, D); \ #define POP_16_F(D) \ D = (u16)CPU->Read_Word(CPU->A[7]); \ CPU->A[7] += 2; #ifdef C68K_BIG_ENDIAN #define PUSH_32_F(D) \ CPU->A[7] -= 4; \ CPU->Write_Word(CPU->A[7] + 2, (D) & 0xFFFF); \ CPU->Write_Word(CPU->A[7], (D) >> 16); #define POP_32_F(D) \ D = CPU->Read_Word(CPU->A[7]) << 16; \ D |= CPU->Read_Word(CPU->A[7] + 2) & 0xFFFF; \ CPU->A[7] += 4; #else #define PUSH_32_F(D) \ CPU->A[7] -= 4; \ CPU->Write_Word(CPU->A[7] + 2, (D) & 0xFFFF); \ CPU->Write_Word(CPU->A[7], (D) >> 16); #define POP_32_F(D) \ D = CPU->Read_Word(CPU->A[7]) << 16; \ D |= CPU->Read_Word(CPU->A[7] + 2) & 0xFFFF; \ CPU->A[7] += 4; #endif #define FETCH_BYTE \ ((*(u16*)PC) & 0xFF) #define FETCH_WORD \ (*(u16*)PC) #define FETCH_LONG \ (*(u32*)PC) #define DECODE_EXT_WORD \ { \ u32 ext; \ \ ext = (*(u16*)PC); \ PC += 2; \ \ adr += (s32)((s8)(ext)); \ if (ext & 0x0800) adr += (s32) CPU->D[ext >> 12]; \ else adr += (s32)((s16)(CPU->D[ext >> 12])); \ } #ifndef C68K_BIG_ENDIAN #ifdef C68K_BYTE_SWAP_OPT #undef FETCH_LONG #define FETCH_LONG \ ((((u32)(*(u16*)PC)) << 16) | ((u32)(*(u16*)(PC + 2)))) // ((((u32)(*(u8*)(PC + 2))) | (((u32)(*(u8*)(PC + 3))) << 8) | (((u32)(*(u8*)PC)) << 16) | (((u32)(*(u8*)(PC + 1))) << 24))) #else #undef FETCH_BYTE #define FETCH_BYTE \ (*(u16*)PC) >> 8) #undef FETCH_WORD #define FETCH_WORD \ ((((u16)(*(u8*)PC)) << 8) | ((u16)(*(u8*)(PC + 1)))) // ((((u16)(*(u8*)(PC + 1))) | (((u16)(*(u8*)PC)) << 8))) #undef FETCH_LONG #define FETCH_LONG \ ((((u32)(*(u8*)PC)) << 24) | (((u32)(*(u8*)(PC + 1))) << 16) | (((u32)(*(u8*)(PC + 2))) << 8) | ((u32)(*(u8*)(PC + 3)))) // ((((u32)(*(u8*)(PC + 3))) | (((u32)(*(u8*)(PC + 2))) << 8) | (((u32)(*(u8*)(PC + 1))) << 16) | (((u32)(*(u8*)PC)) << 24))) #undef DECODE_EXT_WORD #define DECODE_EXT_WORD \ { \ u32 ext; \ \ ext = (*(u16*)PC); \ PC += 2; \ \ adr += (s32)((s8)(ext >> 8)); \ if (ext & 0x0008) adr += (s32) CPU->D[(ext >> 4) & 0x000F]; \ else adr += (s32)((s16)(CPU->D[(ext >> 4) & 0x000F])); \ } #endif #endif #define GET_CCR \ (((CPU->flag_C >> (C68K_SR_C_SFT - 0)) & 1) | \ ((CPU->flag_V >> (C68K_SR_V_SFT - 1)) & 2) | \ (((!CPU->flag_notZ) & 1) << 2) | \ ((CPU->flag_N >> (C68K_SR_N_SFT - 3)) & 8) | \ ((CPU->flag_X >> (C68K_SR_X_SFT - 4)) & 0x10)) #define GET_SR \ ((CPU->flag_S << 0) | \ (CPU->flag_I << 8) | \ GET_CCR) #define SET_CCR(A) \ CPU->flag_C = (A) << (C68K_SR_C_SFT - 0); \ CPU->flag_V = (A) << (C68K_SR_V_SFT - 1); \ CPU->flag_notZ = ~(A) & 4; \ CPU->flag_N = (A) << (C68K_SR_N_SFT - 3); \ CPU->flag_X = (A) << (C68K_SR_X_SFT - 4); #define SET_SR(A) \ SET_CCR(A) \ CPU->flag_I = ((A) >> 8) & 7; \ CPU->flag_S = (A) & C68K_SR_S; #define CHECK_INT \ { \ s32 line, vect; \ \ line = CPU->IRQLine; \ \ if ((line == 7) || (line > (s32)CPU->flag_I)) \ { \ /* get vector */ \ CPU->IRQLine = 0; \ vect = CPU->Interrupt_CallBack(line); \ if (vect == C68K_INT_ACK_AUTOVECTOR) \ vect = C68K_INTERRUPT_AUTOVECTOR_EX + (line & 7); \ \ /* adjust CCnt */ \ CCnt -= c68k_exception_cycle_table[vect]; \ \ /* swap A7 and USP */ \ if (!CPU->flag_S) \ { \ u32 tmpSP; \ \ tmpSP = CPU->USP; \ CPU->USP = CPU->A[7]; \ CPU->A[7] = tmpSP; \ } \ \ PRE_IO \ \ /* push PC and SR */ \ PUSH_32_F((u32)(PC - CPU->BasePC)) \ PUSH_16_F(GET_SR) \ \ /* adjust SR */ \ CPU->flag_S = C68K_SR_S; \ CPU->flag_I = line; \ \ /* fetch new PC */ \ READ_LONG_F(vect * 4, PC) \ SET_PC(PC) \ \ POST_IO \ } \ } yabause-0.9.15/src/c68k/gen68k.c000644 001750 001750 00000304340 12755623101 020067 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2004 Stephane Dallongeville This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /********************************************************************************* * GEN68K.C : * * C68K generator source file * ********************************************************************************/ #include #ifdef __WIN32__ #include #endif #include "../core.h" #include "c68k.h" #include "gen68k.h" #ifdef C68K_GEN #include "gen68k.inc" // to do : // need accurate cycles calculations in MUL and DIV instruction // some bugs to fix // opcode generation function ////////////////////////////// static void GenLogicI(char op) { // generate jump table & opcode declaration if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_all(GEN_RES | GEN_SRC); else start_all(GEN_ADR | GEN_RES | GEN_SRC); if (current_ea != EA_DREG) current_cycle += 4; switch (current_size) { case SIZE_BYTE: wf_op("\tsrc = FETCH_BYTE;\n"); wf_op("\tPC += 2;\n"); break; case SIZE_WORD: wf_op("\tsrc = FETCH_WORD;\n"); wf_op("\tPC += 2;\n"); break; case SIZE_LONG: wf_op("\tsrc = FETCH_LONG;\n"); wf_op("\tPC += 4;\n"); current_cycle += 8; break; } // read _ea_calc(current_ea, current_op->reg_sft); _ea_read(current_ea, current_op->reg_sft); // op wf_op("\tres %c= src;\n", op); // flag calculation set_logic_flag(); // write _ea_write(current_ea, current_op->reg_sft); terminate_op(8); } static void GenLogicICCR(char op) { // generate jump table & opcode declaration start_all(GEN_RES); wf_op("\tres = FETCH_BYTE & C68K_CCR_MASK;\n"); wf_op("\tPC += 2;\n"); wf_op("\tres %c= GET_CCR;\n", op); wf_op("\tSET_CCR(res)\n"); terminate_op(20); } static void GenLogicISR(char op) { // generate jump table & opcode declaration start_all(GEN_RES); wf_op("\tif (CPU->flag_S)\n"); wf_op("\t{\n"); wf_op("\t\tres = FETCH_WORD & C68K_SR_MASK;\n"); wf_op("\t\tPC += 2;\n"); wf_op("\t\tres %c= GET_SR;\n", op); wf_op("\t\tSET_SR(res)\n"); if (op != '|') { wf_op("\t\tif (!CPU->flag_S)\n"); wf_op("\t\t{\n"); wf_op("\t\t\tres = CPU->A[7];\n"); wf_op("\t\t\tCPU->A[7] = CPU->USP;\n"); wf_op("\t\t\tCPU->USP = res;\n"); wf_op("\t\t}\n"); } wf_op("\t}\n"); wf_op("\telse\n"); wf_op("\t{\n"); gen_privilege_exception("\t\t"); wf_op("\t}\n"); // check for interrupt fterminate_op(20); } static void GenORI() { GenLogicI('|'); } static void GenORICCR() { GenLogicICCR('|'); } static void GenORISR() { GenLogicISR('|'); } static void GenANDI() { GenLogicI('&'); } static void GenANDICCR() { GenLogicICCR('&'); } static void GenANDISR() { GenLogicISR('&'); } static void GenEORI() { GenLogicI('^'); } static void GenEORICCR() { GenLogicICCR('^'); } static void GenEORISR() { GenLogicISR('^'); } static void GenArithI(char op) { // generate jump table & opcode declaration if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_all(GEN_RES | GEN_SRC | GEN_DST); else start_all(GEN_ALL); if ((op != ' ') && (current_ea != EA_DREG)) current_cycle += 4; switch (current_size) { case SIZE_BYTE: wf_op("\tsrc = FETCH_BYTE;\n"); wf_op("\tPC += 2;\n"); break; case SIZE_WORD: wf_op("\tsrc = FETCH_WORD;\n"); wf_op("\tPC += 2;\n"); break; case SIZE_LONG: wf_op("\tsrc = FETCH_LONG;\n"); wf_op("\tPC += 4;\n"); if (op == ' ') { if (current_ea == EA_DREG) current_cycle += 6; else current_cycle += 4; } else current_cycle += 8; break; } // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_dst(current_ea, current_op->reg_sft); if (op == ' ') { // op wf_op("\tres = (u32)(dst - src);\n"); // flag calculation set_cmp_flag(); } else { // op wf_op("\tres = (u32)(dst %c src);\n", op); // flag calculation if (op == '+') set_add_flag(); else set_sub_flag(); // write _ea_write(current_ea, current_op->reg_sft); } terminate_op(8); } static void GenSUBI() { GenArithI('-'); } static void GenADDI() { GenArithI('+'); } static void GenCMPI() { GenArithI(' '); } static void GenBitsOp(char op, u32 dyn) { // generate jump table & opcode declaration if (dyn) current_ea2 = EA_DREG; if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_all(GEN_RES | GEN_SRC); else start_all(GEN_ADR | GEN_RES | GEN_SRC); if (current_ea == EA_DREG) { set_current_size(SIZE_LONG); if ((op == 'c') || (op == ' ')) current_cycle += 2; } else set_current_size(SIZE_BYTE); // get shift value in src if (dyn) { _ea_calc(current_ea2, current_op->reg2_sft); _ea_read_src(current_ea2, current_op->reg2_sft); } else { wf_op("\tsrc = FETCH_BYTE;\n"); wf_op("\tPC += 2;\n"); current_cycle += 4; } wf_op("\tsrc = (u32)(1 << (src & %d));\n", current_sft_mask); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read(current_ea, current_op->reg_sft); // flag calculation wf_op("\tCPU->flag_notZ = res & src;\n"); // op switch(op) { case 'c': wf_op("\tres &= ~src;\n"); break; case 'g': wf_op("\tres ^= src;\n"); break; case 's': wf_op("\tres |= src;\n"); break; } // write if (op != ' ') { _ea_write(current_ea, current_op->reg_sft); current_cycle += 4; } terminate_op(4); } static void GenBTSTn() { GenBitsOp(' ', 0); } static void GenBCHGn() { GenBitsOp('g', 0); } static void GenBCLRn() { GenBitsOp('c', 0); } static void GenBSETn() { GenBitsOp('s', 0); } static void GenBTST() { GenBitsOp(' ', 1); } static void GenBCHG() { GenBitsOp('g', 1); } static void GenBCLR() { GenBitsOp('c', 1); } static void GenBSET() { GenBitsOp('s', 1); } static void GenMOVEPWaD() { // generate jump table & opcode declaration current_ea = EA_D16A; current_ea2 = EA_DREG; start_all(GEN_ADR | GEN_RES | GEN_SRC); // read set_current_size(SIZE_BYTE); _ea_calc(current_ea, current_op->reg_sft); mem_op("\tREAD_BYTE_F(adr + 0, res)\n"); mem_op("\tREAD_BYTE_F(adr + 2, src)\n"); // write wf_op("\t*(u16*)(&CPU->D[(Opcode >> %d) & 7]) = (res << 8) | (u16)src;\n", current_op->reg2_sft); terminate_op(16); } static void GenMOVEPLaD() { // generate jump table & opcode declaration current_ea = EA_D16A; current_ea2 = EA_DREG; start_all(GEN_ADR | GEN_RES | GEN_SRC); // read set_current_size(SIZE_BYTE); _ea_calc(EA_D16A, current_op->reg_sft); mem_op("\tREAD_BYTE_F(adr, res)\n"); wf_op("\tres <<= 24;\n"); wf_op("\tadr += 2;\n"); mem_op("\tREAD_BYTE_F(adr, src)\n"); wf_op("\tres |= src << 16;\n"); wf_op("\tadr += 2;\n"); mem_op("\tREAD_BYTE_F(adr, src)\n"); wf_op("\tres |= src << 8;\n"); wf_op("\tadr += 2;\n"); mem_op("\tREAD_BYTE_F(adr, src)\n"); // write wf_op("\tCPU->D[(Opcode >> %d) & 7] = res | (u32)src;\n", current_op->reg2_sft); terminate_op(24); } static void GenMOVEPWDa() { // generate jump table & opcode declaration current_ea = EA_D16A; current_ea2 = EA_DREG; start_all(GEN_ADR | GEN_RES); // read set_current_size(SIZE_LONG); _ea_calc(current_ea2, current_op->reg2_sft); _ea_read(current_ea2, current_op->reg2_sft); // write set_current_size(SIZE_BYTE); _ea_calc(current_ea, current_op->reg_sft); mem_op("\tWRITE_BYTE_F(adr + 0, res >> 8)\n"); mem_op("\tWRITE_BYTE_F(adr + 2, res >> 0)\n"); terminate_op(16); } static void GenMOVEPLDa() { // generate jump table & opcode declaration current_ea = EA_D16A; current_ea2 = EA_DREG; start_all(GEN_ADR | GEN_RES); // read set_current_size(SIZE_LONG); _ea_calc(current_ea2, current_op->reg2_sft); _ea_read(current_ea2, current_op->reg2_sft); // write set_current_size(SIZE_BYTE); _ea_calc(current_ea, current_op->reg_sft); mem_op("\tWRITE_BYTE_F(adr, res >> 24)\n"); wf_op("\tadr += 2;\n"); mem_op("\tWRITE_BYTE_F(adr, res >> 16)\n"); wf_op("\tadr += 2;\n"); mem_op("\tWRITE_BYTE_F(adr, res >> 8)\n"); wf_op("\tadr += 2;\n"); mem_op("\tWRITE_BYTE_F(adr, res >> 0)\n"); terminate_op(24); } static void GenMOVE(u32 size) { set_current_size(size); // generate jump table & opcode declaration if (((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) && ((current_ea2 == EA_AREG) || (current_ea2 == EA_DREG) || (current_ea2 == EA_IMM))) start_all(GEN_RES); else start_all(GEN_ADR | GEN_RES); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read(current_ea, current_op->reg_sft); // flag calculation set_logic_flag(); if ((current_ea2 == EA_ADEC) || (current_ea2 == EA_ADEC7)) current_cycle -= 2; // write _ea_calc(current_ea2, current_op->reg2_sft); _ea_write(current_ea2, current_op->reg2_sft); terminate_op(4); } static void GenMOVEB() { GenMOVE(SIZE_BYTE); } static void GenMOVEW() { GenMOVE(SIZE_WORD); } static void GenMOVEL() { GenMOVE(SIZE_LONG); } static void GenMOVEA(u32 size) { set_current_size(size); // generate jump table & opcode declaration current_ea2 = EA_AREG; if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_all(GEN_RES); else start_all(GEN_ADR | GEN_RES); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_sx(current_ea, current_op->reg_sft); // write (dst = Ax) _ea_calc(current_ea2, current_op->reg2_sft); _ea_write(current_ea2, current_op->reg2_sft); terminate_op(4); } static void GenMOVEAW() { GenMOVEA(SIZE_WORD); } static void GenMOVEAL() { GenMOVEA(SIZE_LONG); } static void GenMOVEQ() { u32 base = get_current_opcode_base(); // generate jump table current_ea = EA_DREG; gen_opjumptable_ext(base, 0x00, 0xFF, 1, base); // generate label & declarations start_op(base, GEN_RES); // read set_current_size(SIZE_BYTE); wf_op("\tres = (s32)(s8)Opcode;\n"); // fast flag calculation for moveQ wf_op("\tCPU->flag_C = CPU->flag_V = 0;\n"); wf_op("\tCPU->flag_N = CPU->flag_notZ = res;\n"); // write set_current_size(SIZE_LONG); _ea_calc(current_ea, current_op->reg_sft); _ea_write(current_ea, current_op->reg_sft); terminate_op(4); } static void GenSingle(char op) { // generate jump table & opcode declaration if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) { if (op == 'c') start_all(GEN_RES); else start_all(GEN_RES | GEN_SRC); } else { if (op == 'c') start_all(GEN_ADR | GEN_RES); else start_all(GEN_ADR | GEN_RES | GEN_SRC); } if (current_size == SIZE_LONG) current_cycle = 6; else current_cycle= 4; if (is_ea_memory(current_ea)) current_cycle *= 2; // read _ea_calc(current_ea, current_op->reg_sft); if (op != 'c') _ea_read_src(current_ea, current_op->reg_sft); // op switch (op) { case 'x': // negx wf_op("\tres = -(u32)src - ((CPU->flag_X >> 8) & 1);\n"); break; case 'g': // neg wf_op("\tres = -(u32)src;\n"); break; case 'n': // not wf_op("\tres = ~(u32)src;\n"); break; case 'c': // clr wf_op("\tres = 0;\n"); break; } // flag calculation switch (op) { case 'x': // negx set_negx_flag(); break; case 'g': // neg set_neg_flag(); break; case 'n': // not set_logicl_flag(); break; case 'c': // clr wf_op("\tCPU->flag_N = CPU->flag_notZ = CPU->flag_V = CPU->flag_C = 0;\n"); break; } // write _ea_write(current_ea, current_op->reg_sft); terminate_op(0); } static void GenCLR() { GenSingle('c'); } static void GenNEGX() { GenSingle('x'); } static void GenNEG() { GenSingle('g'); } static void GenNOT() { GenSingle('n'); } static void GenMOVESRa() { // generate jump table & opcode declaration if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_all(GEN_RES); else start_all(GEN_ADR | GEN_RES); // read wf_op("\tres = GET_SR;\n"); // write set_current_size(SIZE_WORD); if (is_ea_memory(current_ea)) current_cycle += 2; _ea_calc(current_ea, current_op->reg_sft); _ea_write(current_ea, current_op->reg_sft); terminate_op(6); } static void GenMOVEaSR() { // generate jump table & opcode declaration if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_all(GEN_RES); else start_all(GEN_ADR | GEN_RES); wf_op("\tif (CPU->flag_S)\n"); wf_op("\t{\n"); // read set_current_size(SIZE_WORD); _ea_calc(current_ea, current_op->reg_sft); _ea_read(current_ea, current_op->reg_sft); wf_op("\t\tSET_SR(res)\n"); wf_op("\t\tif (!CPU->flag_S)\n"); wf_op("\t\t{\n"); wf_op("\t\t\tres = CPU->A[7];\n"); wf_op("\t\t\tCPU->A[7] = CPU->USP;\n"); wf_op("\t\t\tCPU->USP = res;\n"); wf_op("\t\t}\n"); wf_op("\t}\n"); wf_op("\telse\n"); wf_op("\t{\n"); gen_privilege_exception("\t\t"); wf_op("\t}\n"); // force terminaison to check for interrupt fterminate_op(12); } static void GenMOVEaCCR() { // generate jump table & opcode declaration if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_all(GEN_RES); else start_all(GEN_ADR | GEN_RES); // read set_current_size(SIZE_WORD); _ea_calc(current_ea, current_op->reg_sft); _ea_read(current_ea, current_op->reg_sft); // write wf_op("\tSET_CCR(res)\n"); terminate_op(12); } static void GenMOVEAUSP() { current_ea = EA_AREG; // generate jump table & opcode declaration start_all(GEN_RES); wf_op("\tif (!CPU->flag_S)\n"); wf_op("\t{\n"); gen_privilege_exception("\t\t"); quick_terminate_op(4); wf_op("\t}\n"); // read set_current_size(SIZE_LONG); _ea_calc(current_ea, current_op->reg_sft); _ea_read(current_ea, current_op->reg_sft); // write wf_op("\tCPU->USP = res;\n"); terminate_op(4); } static void GenMOVEUSPA() { current_ea = EA_AREG; // generate jump table & opcode declaration start_all(GEN_RES); wf_op("\tif (!CPU->flag_S)\n"); wf_op("\t{\n"); gen_privilege_exception("\t\t"); quick_terminate_op(4); wf_op("\t}\n"); // read wf_op("\tres = CPU->USP;\n"); // write set_current_size(SIZE_LONG); _ea_calc(current_ea, current_op->reg_sft); _ea_write(current_ea, current_op->reg_sft); terminate_op(4); } static void GenPEA() { set_current_size(SIZE_LONG); // generate jump table & opcode declaration if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_all(0); else start_all(GEN_ADR); _ea_calc_free(current_ea, current_op->reg_sft); mem_op("\tPUSH_32_F(adr)\n"); terminate_op(lea_pea_cycle_table[current_ea] + 12); } static void GenSWAP() { current_ea = EA_DREG; set_current_size(SIZE_LONG); // generate jump table & opcode declaration start_all(GEN_RES); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read(current_ea, current_op->reg_sft); // op wf_op("\tres = (res >> 16) | (res << 16);\n"); // flag calculation set_logic_flag(); // write _ea_write(current_ea, current_op->reg_sft); terminate_op(4); } static void GenMOVEMaR() { // generate jump table & opcode declaration start_all(GEN_ALL); // get register mask wf_op("\tres = FETCH_WORD;\n"); wf_op("\tPC += 2;\n"); // get adr if (current_ea == EA_AINC) wf_op("\tadr = CPU->A[(Opcode >> %d) & 7];\n", current_op->reg_sft); else if (current_ea == EA_AINC7) wf_op("\tadr = CPU->A[7];\n"); else _ea_calc(current_ea, current_op->reg_sft); wf_op("\tsrc = (pointer)(&CPU->D[0]);\n"); wf_op("\tdst = adr;\n"); do_pre_io(); wf_op("\tdo\n"); wf_op("\t{\n"); wf_op("\t\tif (res & 1)\n"); wf_op("\t\t{\n"); if (current_size == SIZE_WORD) { wf_op("\t\t\tREADSX_WORD_F(adr, *(s32*)src)\n"); wf_op("\t\t\tadr += 2;\n"); } else { wf_op("\t\t\tREAD_LONG_F(adr, *(u32*)src)\n"); wf_op("\t\t\tadr += 4;\n"); } wf_op("\t\t}\n"); wf_op("\t\tsrc += 4;\n"); wf_op("\t} while (res >>= 1);\n"); if (current_ea == EA_AINC) wf_op("\tCPU->A[(Opcode >> %d) & 7] = adr;\n", current_op->reg_sft); else if (current_ea == EA_AINC7) wf_op("\tCPU->A[7] = adr;\n"); adds_CCnt("(adr - (u32)dst) * 2"); terminate_op(movem_cycle_table[current_ea] + 12); } static void GenMOVEMRa() { // generate jump table & opcode declaration start_all(GEN_ALL); // get register mask wf_op("\tres = FETCH_WORD;\n"); wf_op("\tPC += 2;\n"); // get adr if (current_ea == EA_ADEC) wf_op("\tadr = CPU->A[(Opcode >> %d) & 7];\n", current_op->reg_sft); else if (current_ea == EA_ADEC7) wf_op("\tadr = CPU->A[7];\n"); else _ea_calc(current_ea, current_op->reg_sft); if ((current_ea == EA_ADEC) || (current_ea == EA_ADEC7)) wf_op("\tsrc = (pointer)(&CPU->A[7]);\n"); else wf_op("\tsrc = (pointer)(&CPU->D[0]);\n"); wf_op("\tdst = adr;\n"); do_pre_io(); wf_op("\tdo\n"); wf_op("\t{\n"); wf_op("\t\tif (res & 1)\n"); wf_op("\t\t{\n"); if (current_size == SIZE_WORD) { if ((current_ea == EA_ADEC) || (current_ea == EA_ADEC7)) wf_op("\t\t\tadr -= 2;\n"); wf_op("\t\t\tWRITE_WORD_F(adr, *(u16*)src)\n"); if (!((current_ea == EA_ADEC) || (current_ea == EA_ADEC7))) wf_op("\t\t\tadr += 2;\n"); } else { if ((current_ea == EA_ADEC) || (current_ea == EA_ADEC7)) { wf_op("\t\t\tadr -= 4;\n"); wf_op("\t\t\tWRITE_LONG_DEC_F(adr, *(u32*)src)\n"); } else { wf_op("\t\t\tWRITE_LONG_F(adr, *(u32*)src)\n"); wf_op("\t\t\tadr += 4;\n"); } } wf_op("\t\t}\n"); if ((current_ea == EA_ADEC) || (current_ea == EA_ADEC7)) wf_op("\t\tsrc -= 4;\n"); else wf_op("\t\tsrc += 4;\n"); wf_op("\t} while (res >>= 1);\n"); if (current_ea == EA_ADEC) wf_op("\tCPU->A[(Opcode >> %d) & 7] = adr;\n", current_op->reg_sft); else if (current_ea == EA_ADEC7) wf_op("\tCPU->A[7] = adr;\n"); if ((current_ea == EA_ADEC) || (current_ea == EA_ADEC7)) adds_CCnt("((u32)dst - adr) * 2"); else adds_CCnt("(adr - (u32)dst) * 2"); terminate_op(movem_cycle_table[current_ea] + 8); } static void GenEXT() { current_ea = EA_DREG; // generate jump table & opcode declaration start_all(GEN_RES); // read set_current_size(current_size - 1); _ea_calc(current_ea, current_op->reg_sft); _ea_read_sx(current_ea, current_op->reg_sft); // flag calculation set_logic_flag(); // write set_current_size(current_size + 1); _ea_write(current_ea, current_op->reg_sft); terminate_op(4); } static void GenTST() { // generate jump table & opcode declaration if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_all(GEN_RES); else start_all(GEN_ADR | GEN_RES); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read(current_ea, current_op->reg_sft); // flag calculation set_logic_flag(); terminate_op(4); } static void GenTAS() { set_current_size(SIZE_BYTE); if (is_ea_memory(current_ea)) current_cycle += 6; // generate jump table & opcode declaration if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_all(GEN_RES); else start_all(GEN_ADR | GEN_RES); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read(current_ea, current_op->reg_sft); // flag calculation set_logic_flag(); #ifndef C68K_TAS_CAN_SET_MEMORY if (current_ea < EA_AIND) { #endif // flag calculation wf_op("\tres |= 0x80;\n"); // write _ea_write(current_ea, current_op->reg_sft); #ifndef C68K_TAS_CAN_SET_MEMORY } #endif terminate_op(4); } static void GenTRAP() { u32 base; base = get_current_opcode_base(); // generate jump table gen_opjumptable_ext(base, (0 << 0), (15 << 0), (1 << 0), base); // generate label & declarations start_op(base, GEN_RES); gen_exception("\t", "C68K_TRAP_BASE_EX + (Opcode & 0xF)"); terminate_op(4); } static void GenTRAPV() { // generate label & declarations start_all(GEN_RES); wf_op("\tif %s\n", get_cond_as_cond(COND_VS, 0)); wf_op("\t{\n"); gen_exception("\t\t", "C68K_TRAPV_EX"); wf_op("\t}\n"); terminate_op(4); } static void GenLINK() { current_ea = EA_AREG; set_current_size(SIZE_LONG); // generate jump table & opcode declaration start_all(GEN_RES); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read(current_ea, current_op->reg_sft); // push mem_op("\tPUSH_32_F(res)\n"); wf_op("\tres = CPU->A[7];\n"); // write _ea_write(current_ea, current_op->reg_sft); // update SP wf_op("\tCPU->A[7] += (s32)(s16)FETCH_WORD;\n"); wf_op("\tPC += 2;\n"); terminate_op(16); } static void GenLINKA7() { current_ea = EA_AREG; set_current_size(SIZE_LONG); // generate jump table & opcode declaration start_all(0); // push A7 wf_op("\tCPU->A[7] -= 4;\n"); mem_op("\tWRITE_LONG_DEC_F(CPU->A[7], CPU->A[7])\n"); // update A7 wf_op("\tCPU->A[7] += (s32)(s16)FETCH_WORD;\n"); wf_op("\tPC += 2;\n"); terminate_op(16); } static void GenULNK() { current_ea = EA_AREG; set_current_size(SIZE_LONG); // generate jump table & opcode declaration start_all(GEN_RES | GEN_SRC); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // pop wf_op("\tCPU->A[7] = (u32)src + 4;\n"); mem_op("\tREAD_LONG_F((u32)src, res)\n"); // write _ea_write(current_ea, current_op->reg_sft); terminate_op(12); } static void GenULNKA7() { current_ea = EA_AREG; set_current_size(SIZE_LONG); // generate jump table & opcode declaration start_all(0); mem_op("\tREAD_LONG_F(CPU->A[7], CPU->A[7])\n"); terminate_op(12); } static void GenRESET() { // generate jump table & opcode declaration start_all(GEN_RES); wf_op("\tif (!CPU->flag_S)\n"); wf_op("\t{\n"); gen_privilege_exception("\t\t"); quick_terminate_op(4); wf_op("\t}\n"); // Reset callback function mem_op("\tCPU->Reset_CallBack();\n"); terminate_op(132); } static void GenLEA() { current_ea2 = EA_AREG; set_current_size(SIZE_LONG); // generate jump table & opcode declaration start_all(GEN_ADR | GEN_RES); _ea_calc_free(current_ea, current_op->reg_sft); wf_op("\tres = adr;\n"); current_cycle = lea_pea_cycle_table[current_ea]; _ea_calc(current_ea2, current_op->reg2_sft); _ea_write(current_ea2, current_op->reg2_sft); terminate_op(4); } static void GenNOP() { start_all(0); terminate_op(4); } static void GenILLEGAL() { start_all(GEN_RES); gen_exception("\t\t", "C68K_ILLEGAL_INSTRUCTION_EX"); terminate_op(4); } static void GenCHK() { current_ea2 = EA_DREG; set_current_size(SIZE_WORD); // generate jump table & opcode declaration if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_all(GEN_RES | GEN_SRC); else start_all(GEN_ADR | GEN_RES | GEN_SRC); // read Src _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // read Dx _ea_calc(current_ea2, current_op->reg2_sft); _ea_read(current_ea2, current_op->reg2_sft); wf_op("\tif (((s32)res < 0) || (res > src))\n"); wf_op("\t{\n"); wf_op("\t\tCPU->flag_N = res >> %d;\n", current_sft_mask - C68K_SR_N_SFT); gen_exception("\t\t", "C68K_CHK_EX"); wf_op("\t}\n"); terminate_op(10); } static void GenSTOP() { // generate jump table & opcode declaration start_all(GEN_RES); wf_op("\tif (!CPU->flag_S)\n"); wf_op("\t{\n"); wf_op("\t\tPC += 2;\n"); gen_privilege_exception("\t\t"); quick_terminate_op(4); wf_op("\t}\n"); // read & set SR wf_op("\tres = FETCH_WORD & C68K_SR_MASK;\n"); wf_op("\tPC += 2;\n"); wf_op("\tSET_SR(res)\n"); // if S flag not set --> we swap stack pointer wf_op("\tif (!CPU->flag_S)\n"); wf_op("\t{\n"); wf_op("\t\tres = CPU->A[7];\n"); wf_op("\t\tCPU->A[7] = CPU->USP;\n"); wf_op("\t\tCPU->USP = res;\n"); wf_op("\t}\n"); wf_op("\tCPU->Status |= C68K_HALTED;\n"); wf_op("\tCCnt = 0;\n"); // force end execution fterminate_op(4); } static void GenRTE() { start_all(GEN_RES); wf_op("\tif (!CPU->flag_S)\n"); wf_op("\t{\n"); gen_privilege_exception("\t\t"); quick_terminate_op(4); wf_op("\t}\n"); // restore SR and PC mem_op("\tPOP_16_F(res)\n"); wf_op("\tSET_SR(res)\n"); mem_op("\tPOP_32_F(res)\n"); wf_op("\tSET_PC(res)\n"); // if S flag not set --> we swap stack pointer wf_op("\tif (!CPU->flag_S)\n"); wf_op("\t{\n"); wf_op("\t\tres = CPU->A[7];\n"); wf_op("\t\tCPU->A[7] = CPU->USP;\n"); wf_op("\t\tCPU->USP = res;\n"); wf_op("\t}\n"); // check for interrupt fterminate_op(20); } static void GenRTS() { start_all(GEN_RES); mem_op("\tPOP_32_F(res)\n"); wf_op("\tSET_PC(res)\n"); terminate_op(16); } static void GenRTR() { start_all(GEN_RES); mem_op("\tPOP_16_F(res)\n"); wf_op("\tSET_CCR(res)\n"); mem_op("\tPOP_32_F(res)\n"); wf_op("\tSET_PC(res)\n"); terminate_op(20); } static void GenJSR() { start_all(GEN_ADR); // get adr _ea_calc_free(current_ea, current_op->reg_sft); mem_op("\tPUSH_32_F((u32)(PC - CPU->BasePC))\n"); wf_op("\tSET_PC(adr)\n"); terminate_op(jmp_jsr_cycle_table[current_ea] + 12); } static void GenJMP() { start_all(GEN_ADR); // get adr _ea_calc_free(current_ea, current_op->reg_sft); wf_op("\tSET_PC(adr)\n"); terminate_op(jmp_jsr_cycle_table[current_ea] + 4); } static void GenSTCC() { u32 base, cond; base = get_current_opcode_base(); for(cond = 0; cond < 0x10; cond++) { // generate jump table gen_opjumptable(base + (cond << 8)); // generate label & declarations if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_op(base + (cond << 8), GEN_RES); else start_op(base + (cond << 8), GEN_ADR | GEN_RES); set_current_size(SIZE_BYTE); if (is_ea_memory(current_ea)) current_cycle += 4; // op _ea_calc(current_ea, current_op->reg_sft); if ((cond != COND_TR) && (cond != COND_FA)) { wf_op("\tif %s\n", get_cond_as_cond(cond, 0)); wf_op("\t{\n"); } if (cond != COND_FA) { wf_op("\tres = 0xFF;\n"); // write _ea_write(current_ea, current_op->reg_sft); if (!is_ea_memory(current_ea)) quick_terminate_op(6); else quick_terminate_op(4); } if ((cond != COND_TR) && (cond != COND_FA)) { wf_op("\t}\n"); } if (cond != COND_TR) { wf_op("\tres = 0;\n"); // write _ea_write(current_ea, current_op->reg_sft); quick_terminate_op(4); } wf_op("}\n"); } } static void GenDBCC() { u32 base, cond; base = get_current_opcode_base(); current_ea = EA_DREG; set_current_size(SIZE_WORD); for(cond = 0; cond < 0x10; cond++) { // generate jump table gen_opjumptable(base + (cond << 8)); // generate label & declarations start_op(base + (cond << 8), cond==COND_TR ? 0 : GEN_RES); if (cond != COND_TR) { if (cond != COND_FA) { wf_op("\tif %s\n", get_cond_as_cond(cond, 1)); wf_op("\t{\n"); } // read Dx _ea_calc(current_ea, current_op->reg_sft); _ea_read(current_ea, current_op->reg_sft); // dec Dx wf_op("\tres--;\n"); // write Dx _ea_write(current_ea, current_op->reg_sft); wf_op("\tif ((s32)res != -1)\n"); wf_op("\t{\n"); wf_op("\t\tPC += (s32)(s16)FETCH_WORD;\n"); // unbase PC wf_op("\t\tPC -= CPU->BasePC;\n"); // rebase PC wf_op("\t\tSET_PC(PC);\n"); quick_terminate_op(10); wf_op("\t}\n"); if (cond != COND_FA) { wf_op("\t}\n"); wf_op("\telse\n"); wf_op("\t{\n"); wf_op("\t\tPC += 2;\n"); quick_terminate_op(12); wf_op("\t}\n"); } } wf_op("\tPC += 2;\n"); if (cond == COND_TR) terminate_op(12); else terminate_op(14); } } static void GenBCC() { u32 base, cond; base = get_current_opcode_base(); for(cond = 2; cond < 0x10; cond++) { // generate jump table gen_opjumptable_ext(base + (cond << 8), 0x01, 0xFF, 1, base + (cond << 8) + 0x01); // generate label & declarations start_op(base + (cond << 8) + 0x01, 0); // op wf_op("\tif %s\n", get_cond_as_cond(cond, 0)); wf_op("\t{\n"); wf_op("\t\tPC += (s32)(s8)Opcode;\n"); // no rebase needed for 8 bits deplacement add_CCnt(2); wf_op("\t}\n"); terminate_op(8); } } static void GenBCC16() { u32 base, cond; base = get_current_opcode_base(); for(cond = 2; cond < 0x10; cond++) { // generate jump table gen_opjumptable(base + (cond << 8)); // generate label & declarations start_op(base + (cond << 8), 0); // op wf_op("\tif %s\n", get_cond_as_cond(cond, 0)); wf_op("\t{\n"); wf_op("\t\tPC += (s32)(s16)FETCH_WORD;\n"); // unbase PC wf_op("\t\tPC -= CPU->BasePC;\n"); // rebase PC wf_op("\t\tSET_PC(PC);\n"); quick_terminate_op(10); wf_op("\t}\n"); wf_op("\tPC += 2;\n"); terminate_op(12); } } static void GenBRA() { u32 base = get_current_opcode_base(); // generate jump table gen_opjumptable_ext(base, 0x01, 0xFF, 1, base + 0x01); // generate label & declarations start_op(base + 0x01, 0); wf_op("\tPC += (s32)(s8)Opcode;\n"); // no rebase needed for 8 bits deplacement terminate_op(10); } static void GenBRA16() { u32 base = get_current_opcode_base(); // generate jump table gen_opjumptable(base + 0x00); // generate label & declarations start_op(base + 0x00, 0); wf_op("\tPC += (s32)(s16)FETCH_WORD;\n"); // unbase PC wf_op("\tPC -= CPU->BasePC;\n"); // rebase PC wf_op("\tSET_PC(PC);\n"); terminate_op(10); } static void GenBSR() { u32 base = get_current_opcode_base(); // generate jump table gen_opjumptable_ext(base, 0x01, 0xFF, 1, base + 0x01); // generate label & declarations start_op(base + 0x01, 0); mem_op("\tPUSH_32_F((u32)(PC - CPU->BasePC))\n"); wf_op("\tPC += (s32)(s8)Opcode;\n"); // no rebase needed for 8 bits deplacement terminate_op(18); } static void GenBSR16() { u32 base = get_current_opcode_base(); // generate jump table gen_opjumptable(base + 0x00); // generate label & declarations start_op(base + 0x00, GEN_RES); wf_op("\tres = (s32)(s16)FETCH_WORD;\n"); // unbase PC wf_op("\tPC -= CPU->BasePC;\n"); mem_op("\tPUSH_32_F((u32)PC + 2)\n"); wf_op("\tPC += (s32) res;\n"); // rebase PC for 16 bits deplacement wf_op("\tSET_PC(PC);\n"); terminate_op(18); } static void GenArithQ(char op) { u32 base; if ((current_ea == EA_AREG) && (current_size == SIZE_BYTE)) return; base = get_current_opcode_base(); // generate jump table gen_opjumptable_ext(base, (0 << 9), (7 << 9), (1 << 9), base); // generate label & declarations if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_op(base, GEN_DST | GEN_RES | GEN_SRC); else start_op(base, GEN_ALL); if (current_ea == EA_AREG) set_current_size(SIZE_LONG); if (is_ea_memory(current_ea)) current_cycle += 4; if (current_size == SIZE_LONG) current_cycle += 4; // read src wf_op("\tsrc = (((Opcode >> 9) - 1) & 7) + 1;\n"); // read dst _ea_calc(current_ea, current_op->reg_sft); _ea_read_dst(current_ea, current_op->reg_sft); // op wf_op("\tres = (u32)(dst %c src);\n", op); // flag calculation if (current_ea != EA_AREG) { if (op == '+') set_add_flag(); else set_sub_flag(); } // write dst _ea_write(current_ea, current_op->reg_sft); terminate_op(4); } static void GenADDQ() { GenArithQ('+'); } static void GenSUBQ() { GenArithQ('-'); } static void GenLogicaD(char op) { // generate jump table & opcode declaration current_ea2 = EA_DREG; if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_all(GEN_RES | GEN_SRC); else start_all(GEN_ADR | GEN_RES | GEN_SRC); if (current_size == SIZE_LONG) { if (!is_ea_memory(current_ea)) current_cycle += 2; else current_cycle += 4; } // read src _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // read dst (Dx) _ea_calc(current_ea2, current_op->reg2_sft); _ea_read(current_ea2, current_op->reg2_sft); // op wf_op("\tres %c= src;\n", op); // flag calculation set_logic_flag(); // write dst (Dx) _ea_write(current_ea2, current_op->reg2_sft); terminate_op(4); } static void GenLogicDa(char op) { // generate jump table & opcode declaration current_ea2 = EA_DREG; if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_all(GEN_RES | GEN_SRC); else start_all(GEN_ADR | GEN_RES | GEN_SRC); if (current_size == SIZE_LONG) current_cycle += 4; // read src (Dx) _ea_calc(current_ea2, current_op->reg2_sft); _ea_read_src(current_ea2, current_op->reg2_sft); // read dst _ea_calc(current_ea, current_op->reg_sft); _ea_read(current_ea, current_op->reg_sft); // op wf_op("\tres %c= src;\n", op); // flag calculation set_logic_flag(); // write dst _ea_write(current_ea, current_op->reg_sft); if (current_ea == EA_DREG) terminate_op(4); else terminate_op(8); } static void GenANDaD() { GenLogicaD('&'); } static void GenANDDa() { GenLogicDa('&'); } static void GenORaD() { GenLogicaD('|'); } static void GenORDa() { GenLogicDa('|'); } static void GenEORDa() { GenLogicDa('^'); } static void GenNBCD() { set_current_size(SIZE_BYTE); // generate jump table & opcode declaration if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_all(GEN_RES); else start_all(GEN_ADR | GEN_RES); if (is_ea_memory(current_ea)) current_cycle += 2; // read _ea_calc(current_ea, current_op->reg_sft); _ea_read(current_ea, current_op->reg_sft); // op wf_op("\tres = 0x9a - res - ((CPU->flag_X >> C68K_SR_X_SFT) & 1);\n"); wf_op("\n"); wf_op("\tif (res != 0x9a)\n"); wf_op("\t{\n"); wf_op("\t\tif ((res & 0x0f) == 0xa) res = (res & 0xf0) + 0x10;\n"); wf_op("\t\tres &= 0xFF;\n"); // write _ea_write(current_ea, current_op->reg_sft); // flag calculation wf_op("\t\tCPU->flag_notZ |= res;\n"); wf_op("\t\tCPU->flag_X = CPU->flag_C = C68K_SR_C;\n"); wf_op("\t}\n"); wf_op("\telse CPU->flag_X = CPU->flag_C = 0;\n"); wf_op("\tCPU->flag_N = res;\n"); terminate_op(6); } static void GenBCD(char op) { // op wf_op("\tres = (dst & 0xF) %c (src & 0xF) %c ((CPU->flag_X >> C68K_SR_X_SFT) & 1);\n", op, op); wf_op("\tif (res > 9) res %c= 6;\n", op); wf_op("\tres += (dst & 0xF0) %c (src & 0xF0);\n", op, op); // flag calculation wf_op("\tif (res > 0x99)\n"); wf_op("\t{\n"); switch (op) { case '+': wf_op("\t\tres -= 0xA0;\n"); break; case '-': wf_op("\t\tres += 0xA0;\n"); break; } wf_op("\t\tCPU->flag_X = CPU->flag_C = C68K_SR_C;\n"); wf_op("\t}\n"); wf_op("\telse CPU->flag_X = CPU->flag_C = 0;\n"); wf_op("\tCPU->flag_notZ |= res & 0xFF;\n"); wf_op("\tCPU->flag_N = res;\n"); } static void GenxBCD(char op) { set_current_size(SIZE_BYTE); // generate jump table & opcode declaration current_ea = EA_DREG; current_ea2 = EA_DREG; start_all(GEN_DST | GEN_RES | GEN_SRC); // read src (Dx) _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // read dst (Dx) _ea_calc(current_ea2, current_op->reg2_sft); _ea_read_dst(current_ea2, current_op->reg2_sft); // op & flag calculation GenBCD(op); // write dst (Dx) _ea_write(current_ea2, current_op->reg2_sft); terminate_op(6); } static void GenxBCDM(char op) { set_current_size(SIZE_BYTE); // generate jump table & opcode declaration current_ea = EA_ADEC; current_ea2 = EA_ADEC; start_all(GEN_ALL); // read src (ADEC) _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // read dst (ADEC) _ea_calc(current_ea2, current_op->reg2_sft); _ea_read_dst(current_ea2, current_op->reg2_sft); // op & flag calculation GenBCD(op); // write dst (ADEC) _ea_write(current_ea2, current_op->reg2_sft); terminate_op(6); } static void GenxBCD7M(char op) { set_current_size(SIZE_BYTE); // generate jump table & opcode declaration current_ea = EA_ADEC7; current_ea2 = EA_ADEC; start_all(GEN_ALL); // read src (ADEC7) _ea_calc(current_ea, 0); _ea_read_src(current_ea, 0); // read dst (ADEC) _ea_calc(current_ea2, current_op->reg2_sft); _ea_read_dst(current_ea2, current_op->reg2_sft); // op & flag calculation GenBCD(op); // write dst (ADEC) _ea_write(current_ea2, current_op->reg2_sft); terminate_op(6); } static void GenxBCDM7(char op) { set_current_size(SIZE_BYTE); // generate jump table & opcode declaration current_ea = EA_ADEC; current_ea2 = EA_ADEC7; start_all(GEN_ALL); // read src (ADEC) _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // read dst (ADEC7) _ea_calc(current_ea2, 0); _ea_read_dst(current_ea2, 0); // op & flag calculation GenBCD(op); // write dst (ADEC7) _ea_write(current_ea2, 0); terminate_op(6); } static void GenxBCD7M7(char op) { set_current_size(SIZE_BYTE); // generate jump table & opcode declaration current_ea = EA_ADEC7; current_ea2 = EA_ADEC7; start_all(GEN_ALL); // read src (ADEC7) _ea_calc(current_ea, 0); _ea_read_src(current_ea, 0); // read dst (ADEC7) _ea_calc(current_ea2, 0); _ea_read_dst(current_ea2, 0); // op & flag calculation GenBCD(op); // write dst (ADEC7) _ea_write(current_ea2, 0); terminate_op(6); } static void GenABCD() { GenxBCD('+'); } static void GenABCDM() { GenxBCDM('+'); } static void GenABCD7M() { GenxBCD7M('+'); } static void GenABCDM7() { GenxBCDM7('+'); } static void GenABCD7M7() { GenxBCD7M7('+'); } static void GenSBCD() { GenxBCD('-'); } static void GenSBCDM() { GenxBCDM('-'); } static void GenSBCD7M() { GenxBCD7M('-'); } static void GenSBCDM7() { GenxBCDM7('-'); } static void GenSBCD7M7() { GenxBCD7M7('-'); } static void GenDIVU() { // generate jump table & opcode declaration current_ea2 = EA_DREG; if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_all(GEN_DST | GEN_RES | GEN_SRC); else start_all(GEN_ALL); set_current_size(SIZE_WORD); // read src _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // division by zero wf_op("\tif (src == 0)\n"); wf_op("\t{\n"); gen_exception("\t\t", "C68K_ZERO_DIVIDE_EX"); quick_terminate_op(10); wf_op("\t}\n"); set_current_size(SIZE_LONG); // read dst (Dx) _ea_calc(current_ea2, current_op->reg2_sft); _ea_read_dst(current_ea2, current_op->reg2_sft); wf_op("\t{\n"); wf_op("\t\tu32 q, r;\n"); wf_op("\n"); wf_op("\t\tq = (u32)dst / (u32)src;\n"); wf_op("\t\tr = (u32)dst %% (u32)src;\n"); wf_op("\n"); wf_op("\t\tif (q & 0xFFFF0000)\n"); wf_op("\t\t{\n"); // overflow occured wf_op("\t\t\tCPU->flag_V = C68K_SR_V;\n"); quick_terminate_op(70); wf_op("\t\t}\n"); // quotient size = word set_current_size(SIZE_WORD); wf_op("\t\tq &= 0x%.8X;\n", current_bits_mask); wf_op("\t\tCPU->flag_notZ = q;\n"); wf_op("\t\tCPU->flag_N = q >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\t\tCPU->flag_V = CPU->flag_C = 0;\n"); wf_op("\t\tres = q | (r << 16);\n"); set_current_size(SIZE_LONG); // write dst (Dx) _ea_write(current_ea2, current_op->reg2_sft); wf_op("\t}\n"); // max cycle = 140 terminate_op(140 - 50); } static void GenDIVS() { // generate jump table & opcode declaration current_ea2 = EA_DREG; if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_all(GEN_DST | GEN_RES | GEN_SRC); else start_all(GEN_ALL); set_current_size(SIZE_WORD); // read src _ea_calc(current_ea, current_op->reg_sft); _ea_read_src_sx(current_ea, current_op->reg_sft); // division by zero wf_op("\tif (src == 0)\n"); wf_op("\t{\n"); gen_exception("\t\t", "C68K_ZERO_DIVIDE_EX"); quick_terminate_op(10); wf_op("\t}\n"); set_current_size(SIZE_LONG); // read dst (Dx) _ea_calc(current_ea2, current_op->reg2_sft); _ea_read_dst(current_ea2, current_op->reg2_sft); // division by zero wf_op("\tif ((dst == 0x80000000) && (src == -1))\n"); wf_op("\t{\n"); wf_op("\t\tCPU->flag_notZ = CPU->flag_N = 0;\n"); wf_op("\t\tCPU->flag_V = CPU->flag_C = 0;\n"); wf_op("\t\tres = 0;\n"); // write dst (Dx) _ea_write(current_ea2, current_op->reg2_sft); quick_terminate_op(50); wf_op("\t}\n"); wf_op("\t{\n"); wf_op("\t\ts32 q, r;\n"); wf_op("\n"); wf_op("\t\tq = (s32)dst / (s32)src;\n"); wf_op("\t\tr = (s32)dst %% (s32)src;\n"); wf_op("\n"); wf_op("\t\tif ((q > 0x7FFF) || (q < -0x8000))\n"); wf_op("\t\t{\n"); // overflow occured wf_op("\t\t\tCPU->flag_V = C68K_SR_V;\n"); quick_terminate_op(80); wf_op("\t\t}\n"); // quotient size = word set_current_size(SIZE_WORD); wf_op("\t\tq &= 0x%.8X;\n", current_bits_mask); wf_op("\t\tCPU->flag_notZ = q;\n"); wf_op("\t\tCPU->flag_N = q >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\t\tCPU->flag_V = CPU->flag_C = 0;\n"); wf_op("\t\tres = q | (r << 16);\n"); set_current_size(SIZE_LONG); // write dst (Dx) _ea_write(current_ea2, current_op->reg2_sft); wf_op("\t}\n"); // max cycle = 158 terminate_op(158 - 50); } static void GenMULU() { // generate jump table & opcode declaration current_ea2 = EA_DREG; if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_all(GEN_RES | GEN_SRC); else start_all(GEN_ADR | GEN_RES | GEN_SRC); set_current_size(SIZE_WORD); // read src _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // read dst (Dx) _ea_calc(current_ea2, current_op->reg2_sft); _ea_read(current_ea2, current_op->reg2_sft); set_current_size(SIZE_LONG); // op wf_op("\tres *= (u32)src;\n"); // flag calculation wf_op("\tCPU->flag_N = res >> 24;\n"); wf_op("\tCPU->flag_notZ = res;\n"); wf_op("\tCPU->flag_V = CPU->flag_C = 0;\n"); // write dst (Dx) _ea_write(current_ea2, current_op->reg2_sft); // min cycle = 38; max cycle = 70 terminate_op(38 + (2 * 6)); } static void GenMULS() { // generate jump table & opcode declaration current_ea2 = EA_DREG; if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_all(GEN_RES | GEN_SRC); else start_all(GEN_ADR | GEN_RES | GEN_SRC); set_current_size(SIZE_WORD); // read src signed _ea_calc(current_ea, current_op->reg_sft); _ea_read_src_sx(current_ea, current_op->reg_sft); // read dst signed (Dx) _ea_calc(current_ea2, current_op->reg2_sft); _ea_read_sx(current_ea2, current_op->reg2_sft); set_current_size(SIZE_LONG); // op //wf_op("\t(s32)res *= (s32)src;\n"); wf_op("\tres *= (s32)src;\n"); // antime fix // flag calculation wf_op("\tCPU->flag_N = res >> 24;\n"); wf_op("\tCPU->flag_notZ = res;\n"); wf_op("\tCPU->flag_V = CPU->flag_C = 0;\n"); // write dst (Dx) _ea_write(current_ea2, current_op->reg2_sft); // min cycle = 38; max cycle = 70 terminate_op(38 + (2 * 6)); } static void GenArithaD(char op) { // generate jump table & opcode declaration current_ea2 = EA_DREG; if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_all(GEN_DST | GEN_RES | GEN_SRC); else start_all(GEN_ALL); if (current_size == SIZE_LONG) { if (!is_ea_memory(current_ea)) current_cycle += 2; else current_cycle += 4; } // read src _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // read dst (Dx) _ea_calc(current_ea2, current_op->reg2_sft); _ea_read_dst(current_ea2, current_op->reg2_sft); if (op == ' ') { // op wf_op("\tres = (u32)(dst - src);\n"); // flag calculation set_cmp_flag(); } else { // op wf_op("\tres = (u32)(dst %c src);\n", op); // flag calculation if (op == '+') set_add_flag(); else set_sub_flag(); // write dst (Dx) _ea_write(current_ea2, current_op->reg2_sft); } terminate_op(4); } static void GenArithDa(char op) { // generate jump table & opcode declaration current_ea2 = EA_DREG; start_all(GEN_ALL); if (current_size == SIZE_LONG) current_cycle += 4; // read src (Dx) _ea_calc(current_ea2, current_op->reg2_sft); _ea_read_src(current_ea2, current_op->reg2_sft); // read dst _ea_calc(current_ea, current_op->reg_sft); _ea_read_dst(current_ea, current_op->reg_sft); // op wf_op("\tres = (u32)(dst %c src);\n", op); // flag calculation if (op == '+') set_add_flag(); else set_sub_flag(); // write dst _ea_write(current_ea, current_op->reg_sft); terminate_op(8); } static void GenArithA(char op) { // generate jump table & opcode declaration current_ea2 = EA_AREG; if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_all(GEN_DST | GEN_RES | GEN_SRC); else start_all(GEN_ALL); if ((op != ' ') && ((current_size == SIZE_WORD) || (is_ea_memory(current_ea)))) current_cycle += 2; // read src _ea_calc(current_ea, current_op->reg_sft); _ea_read_src_sx(current_ea, current_op->reg_sft); // read dst (Ax) set_current_size(SIZE_LONG); _ea_calc(current_ea2, current_op->reg2_sft); _ea_read_dst(current_ea2, current_op->reg2_sft); // op if (op == ' ') { // op wf_op("\tres = (u32)(dst - src);\n"); // flag calculation set_cmp_flag(); } else { // op wf_op("\tres = (u32)(dst %c src);\n", op); // write dst (Ax) _ea_write(current_ea2, current_op->reg2_sft); } terminate_op(6); } static void GenArithX(char op) { // generate jump table & opcode declaration current_ea = EA_DREG; current_ea2 = EA_DREG; if ((current_ea == EA_AREG) || (current_ea == EA_DREG) || (current_ea == EA_IMM)) start_all(GEN_DST | GEN_RES | GEN_SRC); else start_all(GEN_ALL); if (current_size == SIZE_LONG) current_cycle += 4; // read src (Dx) _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // read dst (Dx) _ea_calc(current_ea2, current_op->reg2_sft); _ea_read_dst(current_ea2, current_op->reg2_sft); // op wf_op("\tres = (u32)dst %c (u32)src %c ((CPU->flag_X >> 8) & 1);\n", op, op); // flag calculation if (op == '+') set_addx_flag(); else set_subx_flag(); // write dst (Dx) _ea_write(current_ea2, current_op->reg2_sft); terminate_op(4); } static void GenArithXM(char op) { // generate jump table & opcode declaration current_ea = EA_ADEC; current_ea2 = EA_ADEC; start_all(GEN_ALL); if (current_size == SIZE_LONG) current_cycle += 4; // read src (ADEC) _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // read dst (ADEC) _ea_calc(current_ea2, current_op->reg2_sft); _ea_read_dst(current_ea2, current_op->reg2_sft); // op wf_op("\tres = (u32)dst %c (u32)src %c ((CPU->flag_X >> 8) & 1);\n", op, op); // flag calculation if (op == '+') set_addx_flag(); else set_subx_flag(); // write dst (ADEC) _ea_write(current_ea2, current_op->reg2_sft); terminate_op(6); } static void GenArithX7M(char op) { // generate jump table & opcode declaration current_ea = EA_ADEC7; current_ea2 = EA_ADEC; start_all(GEN_ALL); if (current_size == SIZE_LONG) current_cycle += 4; // read src (ADEC7) _ea_calc(current_ea, 0); _ea_read_src(current_ea, 0); // read dst (ADEC) _ea_calc(current_ea2, current_op->reg2_sft); _ea_read_dst(current_ea2, current_op->reg2_sft); // op wf_op("\tres = (u32)dst %c (u32)src %c ((CPU->flag_X >> 8) & 1);\n", op, op); // flag calculation if (op == '+') set_addx_flag(); else set_subx_flag(); // write dst (ADEC) _ea_write(current_ea2, current_op->reg2_sft); terminate_op(6); } static void GenArithXM7(char op) { // generate jump table & opcode declaration current_ea = EA_ADEC; current_ea2 = EA_ADEC7; start_all(GEN_ALL); if (current_size == SIZE_LONG) current_cycle += 4; // read src (ADEC) _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // read dst (ADEC7) _ea_calc(current_ea2, 0); _ea_read_dst(current_ea2, 0); // op wf_op("\tres = (u32)dst %c (u32)src %c ((CPU->flag_X >> 8) & 1);\n", op, op); // flag calculation if (op == '+') set_addx_flag(); else set_subx_flag(); // write dst (ADEC7) _ea_write(current_ea2, 0); terminate_op(6); } static void GenArithX7M7(char op) { // generate jump table & opcode declaration current_ea = EA_ADEC7; current_ea2 = EA_ADEC7; start_all(GEN_ALL); if (current_size == SIZE_LONG) current_cycle += 4; // read src (ADEC7) _ea_calc(current_ea, 0); _ea_read_src(current_ea, 0); // read dst (ADEC7) _ea_calc(current_ea2, 0); _ea_read_dst(current_ea2, 0); // op wf_op("\tres = (u32)dst %c (u32)src %c ((CPU->flag_X >> 8) & 1);\n", op, op); // flag calculation if (op == '+') set_addx_flag(); else set_subx_flag(); // write dst (ADEC7) _ea_write(current_ea2, 0); terminate_op(6); } static void GenADDaD() { GenArithaD('+'); } static void GenADDDa() { GenArithDa('+'); } static void GenADDA() { GenArithA('+'); } static void GenADDX() { GenArithX('+'); } static void GenADDXM() { GenArithXM('+'); } static void GenADDX7M() { GenArithX7M('+'); } static void GenADDXM7() { GenArithXM7('+'); } static void GenADDX7M7() { GenArithX7M7('+'); } static void GenSUBaD() { GenArithaD('-'); } static void GenSUBDa() { GenArithDa('-'); } static void GenSUBA() { GenArithA('-'); } static void GenSUBX() { GenArithX('-'); } static void GenSUBXM() { GenArithXM('-'); } static void GenSUBX7M() { GenArithX7M('-'); } static void GenSUBXM7() { GenArithXM7('-'); } static void GenSUBX7M7() { GenArithX7M7('-'); } static void GenCMP() { GenArithaD(' '); } static void GenCMPA() { GenArithA(' '); } static void GenCMPM() { // generate jump table & opcode declaration current_ea = EA_AINC; current_ea2 = EA_AINC; start_all(GEN_ALL); // read src (ADEC) _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // read dst (ADEC) _ea_calc(current_ea2, current_op->reg2_sft); _ea_read_dst(current_ea2, current_op->reg2_sft); // op wf_op("\tres = (u32)(dst - src);\n"); // flag calculation set_cmp_flag(); terminate_op(4); } static void GenCMP7M() { // generate jump table & opcode declaration current_ea = EA_AINC7; current_ea2 = EA_AINC; start_all(GEN_ALL); // read src (ADEC) _ea_calc(current_ea, 0); _ea_read_src(current_ea, 0); // read dst (ADEC) _ea_calc(current_ea2, current_op->reg2_sft); _ea_read_dst(current_ea2, current_op->reg2_sft); // op wf_op("\tres = (u32)(dst - src);\n"); // flag calculation set_cmp_flag(); terminate_op(4); } static void GenCMPM7() { // generate jump table & opcode declaration current_ea = EA_AINC; current_ea2 = EA_AINC7; start_all(GEN_ALL); // read src (ADEC) _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // read dst (ADEC) _ea_calc(current_ea2, 0); _ea_read_dst(current_ea2, 0); // op wf_op("\tres = (u32)(dst - src);\n"); // flag calculation set_cmp_flag(); terminate_op(4); } static void GenCMP7M7() { // generate jump table & opcode declaration current_ea = EA_AINC7; current_ea2 = EA_AINC7; start_all(GEN_ALL); // read src (ADEC) _ea_calc(current_ea, 0); _ea_read_src(current_ea, 0); // read dst (ADEC) _ea_calc(current_ea2, 0); _ea_read_dst(current_ea2, 0); // op wf_op("\tres = (u32)(dst - src);\n"); // flag calculation set_cmp_flag(); terminate_op(4); } static void GenEXGDD() { // generate jump table & opcode declaration set_current_size(SIZE_LONG); current_ea = EA_DREG; current_ea2 = EA_DREG; start_all(GEN_RES | GEN_SRC); // read R1 _ea_calc(current_ea, current_op->reg_sft); _ea_read(current_ea, current_op->reg_sft); // read R2 _ea_calc(current_ea2, current_op->reg2_sft); _ea_read_src(current_ea2, current_op->reg2_sft); // write R1 _ea_write(current_ea2, current_op->reg2_sft); wf_op("\tres = (u32)src;\n"); // write R2 _ea_write(current_ea, current_op->reg_sft); terminate_op(6); } static void GenEXGAA() { // generate jump table & opcode declaration set_current_size(SIZE_LONG); current_ea = EA_AREG; current_ea2 = EA_AREG; start_all(GEN_RES | GEN_SRC); // read R1 _ea_calc(current_ea, current_op->reg_sft); _ea_read(current_ea, current_op->reg_sft); // read R2 _ea_calc(current_ea2, current_op->reg2_sft); _ea_read_src(current_ea2, current_op->reg2_sft); // write R1 _ea_write(current_ea2, current_op->reg2_sft); wf_op("\tres = (u32)src;\n"); // write R2 _ea_write(current_ea, current_op->reg_sft); terminate_op(6); } static void GenEXGAD() { // generate jump table & opcode declaration set_current_size(SIZE_LONG); current_ea = EA_AREG; current_ea2 = EA_DREG; start_all(GEN_RES | GEN_SRC); // read R1 _ea_calc(current_ea, current_op->reg_sft); _ea_read(current_ea, current_op->reg_sft); // read R2 _ea_calc(current_ea2, current_op->reg2_sft); _ea_read_src(current_ea2, current_op->reg2_sft); // write R1 _ea_write(current_ea2, current_op->reg2_sft); wf_op("\tres = (u32)src;\n"); // write R2 _ea_write(current_ea, current_op->reg_sft); terminate_op(6); } static void GenASRk() { u32 base; current_ea = EA_DREG; // dst = Dx base = get_current_opcode_base(); // generate jump table gen_opjumptable_ext(base, 0x0000, 0x0E00, 0x0200, base); // generate label & declarations start_op(base, GEN_RES | GEN_SRC); if (current_size == SIZE_LONG) current_cycle += 2; wf_op("\tu32 sft;\n"); wf_op("\n"); wf_op("\tsft = (((Opcode >> 9) - 1) & 7) + 1;\n"); adds_CCnt("sft * 2"); // read (sign extend) _ea_calc(current_ea, current_op->reg_sft); _ea_read_src_sx(current_ea, current_op->reg_sft); // op & flag calculation wf_op("\tCPU->flag_V = 0;\n"); wf_op("\tCPU->flag_X = CPU->flag_C = (u32)src << ((C68K_SR_C_SFT + 1) - sft);\n"); wf_op("\tres = ((s32)src) >> sft;\n"); wf_op("\tCPU->flag_N = res >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\tCPU->flag_notZ = res;\n"); // write _ea_write(current_ea, current_op->reg_sft); terminate_op(6); } static void GenLSRk() { u32 base; current_ea = EA_DREG; // dst = Dx base = get_current_opcode_base(); // generate jump table gen_opjumptable_ext(base, 0x0000, 0x0E00, 0x0200, base); // generate label & declarations start_op(base, GEN_RES | GEN_SRC); if (current_size == SIZE_LONG) current_cycle += 2; wf_op("\tu32 sft;\n"); wf_op("\n"); wf_op("\tsft = (((Opcode >> 9) - 1) & 7) + 1;\n"); adds_CCnt("sft * 2"); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // op & flag calculation wf_op("\tCPU->flag_N = CPU->flag_V = 0;\n"); wf_op("\tCPU->flag_X = CPU->flag_C = (u32)src << ((C68K_SR_C_SFT + 1) - sft);\n"); wf_op("\tres = (u32)src >> sft;\n"); wf_op("\tCPU->flag_notZ = res;\n"); // write _ea_write(current_ea, current_op->reg_sft); terminate_op(6); } static void GenROXRk() { u32 base; current_ea = EA_DREG; // dst = Dx base = get_current_opcode_base(); // generate jump table gen_opjumptable_ext(base, 0x0000, 0x0E00, 0x0200, base); // generate label & declarations start_op(base, GEN_RES | GEN_SRC); if (current_size == SIZE_LONG) current_cycle += 2; wf_op("\tu32 sft;\n"); wf_op("\n"); wf_op("\tsft = (((Opcode >> 9) - 1) & 7) + 1;\n"); adds_CCnt("sft * 2"); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // op & C / X flags calculation if (current_size != SIZE_LONG) { wf_op("\tsrc |= (CPU->flag_X & C68K_SR_X) << %d;\n", (current_sft_mask + 1) - C68K_SR_X_SFT); wf_op("\tres = ((u32)src >> sft) | ((u32)src << (%d - sft));\n", current_sft_mask + 2); wf_op("\tCPU->flag_X = CPU->flag_C = res >> %d;\n", (current_sft_mask + 1) - C68K_SR_X_SFT); } else { wf_op("\tCPU->flag_C = (u32)src << ((C68K_SR_C_SFT + 1) - sft);\n"); wf_op("\tif (sft == 1) res = ((u32)src >> 1) | ((CPU->flag_X & C68K_SR_X) << (32 - (C68K_SR_X_SFT + 1)));\n"); wf_op("\telse res = ((u32)src >> sft) | ((u32)src << (33 - sft)) | ((CPU->flag_X & C68K_SR_X) << (32 - (C68K_SR_X_SFT + sft)));\n"); wf_op("\tCPU->flag_X = CPU->flag_C;\n"); } // V / N / Z flags calculation wf_op("\tCPU->flag_V = 0;\n"); wf_op("\tCPU->flag_N = res >> %d;\n", current_sft_mask - C68K_SR_N_SFT); if (current_size == SIZE_LONG) wf_op("\tCPU->flag_notZ = res;\n"); else wf_op("\tCPU->flag_notZ = res & 0x%.8X;\n", current_bits_mask); // write _ea_write(current_ea, current_op->reg_sft); terminate_op(6); } static void GenRORk() { u32 base; current_ea = EA_DREG; // dst = Dx base = get_current_opcode_base(); // generate jump table gen_opjumptable_ext(base, 0x0000, 0x0E00, 0x0200, base); // generate label & declarations start_op(base, GEN_RES | GEN_SRC); if (current_size == SIZE_LONG) current_cycle += 2; wf_op("\tu32 sft;\n"); wf_op("\n"); wf_op("\tsft = (((Opcode >> 9) - 1) & 7) + 1;\n"); adds_CCnt("sft * 2"); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // op & flag calculation wf_op("\tCPU->flag_V = 0;\n"); wf_op("\tCPU->flag_C = (u32)src << ((C68K_SR_C_SFT + 1) - sft);\n"); wf_op("\tres = ((u32)src >> sft) | ((u32)src << (%d - sft));\n", current_sft_mask + 1); wf_op("\tCPU->flag_N = res >> %d;\n", current_sft_mask - C68K_SR_N_SFT); if (current_size == SIZE_LONG) wf_op("\tCPU->flag_notZ = res;\n"); else wf_op("\tCPU->flag_notZ = res & 0x%.8X;\n", current_bits_mask); // write _ea_write(current_ea, current_op->reg_sft); terminate_op(6); } static void GenASLk() { u32 base; current_ea = EA_DREG; // dst = Dx base = get_current_opcode_base(); // generate jump table gen_opjumptable_ext(base, 0x0000, 0x0E00, 0x0200, base); // generate label & declarations start_op(base, GEN_RES | GEN_SRC); if (current_size == SIZE_LONG) current_cycle += 2; wf_op("\tu32 sft;\n"); wf_op("\n"); wf_op("\tsft = (((Opcode >> 9) - 1) & 7) + 1;\n"); adds_CCnt("sft * 2"); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // if (shift < size op) ... only for BYTE here if (current_size == SIZE_BYTE) { wf_op("\tif (sft < %d)\n", current_sft_mask + 1); wf_op("\t{\n"); } // op & flag X, C, N, Z calculation if (((current_sft_mask + 1) - C68K_SR_C_SFT) < 8) wf_op("\t\tCPU->flag_X = CPU->flag_C = (u32)src << (%d + sft);\n", current_sft_mask + 1 - C68K_SR_C_SFT); else wf_op("\t\tCPU->flag_X = CPU->flag_C = (u32)src >> (%d - sft);\n", current_sft_mask + 1 - C68K_SR_C_SFT); wf_op("\t\tres = (u32)src << sft;\n"); wf_op("\t\tCPU->flag_N = res >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\t\tCPU->flag_notZ = res & 0x%.8X;\n", current_bits_mask); // write _ea_write(current_ea, current_op->reg_sft); // we do V flag calculation at end for a better register usage wf_op("\t\tCPU->flag_V = 0;\n"); if (current_size == SIZE_BYTE) { wf_op("\t\tif ((sft > %d) && (src)) CPU->flag_V = C68K_SR_V;\n", current_sft_mask); wf_op("\t\telse\n"); } wf_op("\t\t{\n"); wf_op("\t\t\tu32 msk = (((s32)0x80000000) >> (sft + %d)) & 0x%.8X;\n", 31 - current_sft_mask, current_bits_mask); wf_op("\t\t\tsrc &= msk;\n"); wf_op("\t\t\tif ((src) && (src != msk)) CPU->flag_V = C68K_SR_V;\n"); wf_op("\t\t}\n"); if (current_size == SIZE_BYTE) { quick_terminate_op(6); wf_op("\t}\n"); wf_op("\n"); // special case of shift == size op (sft = 8 for byte operation) wf_op("\tif (src) CPU->flag_V = C68K_SR_V;\n"); wf_op("\telse CPU->flag_V = 0;\n"); wf_op("\tCPU->flag_X = CPU->flag_C = (u32)src << C68K_SR_C_SFT;\n"); // write wf_op("\tres = 0;\n"); _ea_write(current_ea, current_op->reg_sft); // others flags wf_op("\tCPU->flag_N = 0;\n"); wf_op("\tCPU->flag_notZ = 0;\n"); } terminate_op(6); } static void GenLSLk() { u32 base; current_ea = EA_DREG; // dst = Dx base = get_current_opcode_base(); // generate jump table gen_opjumptable_ext(base, 0x0000, 0x0E00, 0x0200, base); // generate label & declarations start_op(base, GEN_RES | GEN_SRC); if (current_size == SIZE_LONG) current_cycle += 2; wf_op("\tu32 sft;\n"); wf_op("\n"); wf_op("\tsft = (((Opcode >> 9) - 1) & 7) + 1;\n"); adds_CCnt("sft * 2"); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // op & flag calculation wf_op("\tCPU->flag_V = 0;\n"); if (((current_sft_mask + 1) - C68K_SR_C_SFT) < 8) wf_op("\tCPU->flag_X = CPU->flag_C = (u32)src << (%d + sft);\n", current_sft_mask + 1 - C68K_SR_C_SFT); else wf_op("\tCPU->flag_X = CPU->flag_C = (u32)src >> (%d - sft);\n", current_sft_mask + 1 - C68K_SR_C_SFT); wf_op("\tres = (u32)src << sft;\n"); wf_op("\tCPU->flag_N = res >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\tCPU->flag_notZ = res & 0x%.8X;\n", current_bits_mask); // write _ea_write(current_ea, current_op->reg_sft); terminate_op(6); } static void GenROXLk() { u32 base; current_ea = EA_DREG; // dst = Dx base = get_current_opcode_base(); // generate jump table gen_opjumptable_ext(base, 0x0000, 0x0E00, 0x0200, base); // generate label & declarations start_op(base, GEN_RES | GEN_SRC); if (current_size == SIZE_LONG) current_cycle += 2; wf_op("\tu32 sft;\n"); wf_op("\n"); wf_op("\tsft = (((Opcode >> 9) - 1) & 7) + 1;\n"); adds_CCnt("sft * 2"); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // op & C / X flags calculation if (current_size != SIZE_LONG) { wf_op("\tsrc |= (CPU->flag_X & C68K_SR_X) << %d;\n", (current_sft_mask + 1) - C68K_SR_X_SFT); wf_op("\tres = ((u32)src << sft) | ((u32)src >> (%d - sft));\n", current_sft_mask + 2); wf_op("\tCPU->flag_X = CPU->flag_C = res >> %d;\n", (current_sft_mask + 1) - C68K_SR_X_SFT); } else { wf_op("\tCPU->flag_C = (u32)src >> ((32 - C68K_SR_C_SFT) - sft);\n"); wf_op("\tif (sft == 1) res = ((u32)src << 1) | ((CPU->flag_X & C68K_SR_X) >> ((C68K_SR_X_SFT + 1) - 1));\n"); wf_op("\telse res = ((u32)src << sft) | ((u32)src >> (33 - sft)) | ((CPU->flag_X & C68K_SR_X) >> ((C68K_SR_X_SFT + 1) - sft));\n"); wf_op("\tCPU->flag_X = CPU->flag_C;\n"); } // V / N / Z flags calculation wf_op("\tCPU->flag_V = 0;\n"); wf_op("\tCPU->flag_N = res >> %d;\n", current_sft_mask - C68K_SR_N_SFT); if (current_size == SIZE_LONG) wf_op("\tCPU->flag_notZ = res;\n"); else wf_op("\tCPU->flag_notZ = res & 0x%.8X;\n", current_bits_mask); // write _ea_write(current_ea, current_op->reg_sft); terminate_op(6); } static void GenROLk() { u32 base; current_ea = EA_DREG; // dst = Dx base = get_current_opcode_base(); // generate jump table gen_opjumptable_ext(base, 0x0000, 0x0E00, 0x0200, base); // generate label & declarations start_op(base, GEN_RES | GEN_SRC); if (current_size == SIZE_LONG) current_cycle += 2; wf_op("\tu32 sft;\n"); wf_op("\n"); wf_op("\tsft = (((Opcode >> 9) - 1) & 7) + 1;\n"); adds_CCnt("sft * 2"); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // op & flag calculation wf_op("\tCPU->flag_V = 0;\n"); if (((current_sft_mask + 1) - C68K_SR_C_SFT) < 8) wf_op("\tCPU->flag_C = (u32)src << (%d + sft);\n", current_sft_mask + 1 - C68K_SR_C_SFT); else wf_op("\tCPU->flag_C = (u32)src >> (%d - sft);\n", current_sft_mask + 1 - C68K_SR_C_SFT); wf_op("\tres = ((u32)src << sft) | ((u32)src >> (%d - sft));\n", current_sft_mask + 1); wf_op("\tCPU->flag_N = res >> %d;\n", current_sft_mask - C68K_SR_N_SFT); if (current_size == SIZE_LONG) wf_op("\tCPU->flag_notZ = res;\n"); else wf_op("\tCPU->flag_notZ = res & 0x%.8X;\n", current_bits_mask); // write _ea_write(current_ea, current_op->reg_sft); terminate_op(6); } static void GenASRD() { // u32 base = get_current_opcode_base(); current_ea = EA_DREG; // dst = Dx start_all(GEN_RES | GEN_SRC); if (current_size == SIZE_LONG) current_cycle += 2; wf_op("\tu32 sft;\n"); wf_op("\n"); wf_op("\tsft = CPU->D[(Opcode >> %d) & 7] & 0x3F;\n", current_op->reg2_sft); // read (sign extend) _ea_calc(current_ea, current_op->reg_sft); _ea_read_src_sx(current_ea, current_op->reg_sft); // if (shift != 0) wf_op("\tif (sft)\n"); wf_op("\t{\n"); adds_CCnt("sft * 2"); // if (shift < size op) wf_op("\t\tif (sft < %d)\n", current_sft_mask + 1); wf_op("\t\t{\n"); // op & flag calculation wf_op("\t\t\tCPU->flag_V = 0;\n"); if (current_size == SIZE_BYTE) wf_op("\t\t\tCPU->flag_X = CPU->flag_C = (u32)src << ((C68K_SR_C_SFT + 1) - sft);\n"); else wf_op("\t\t\tCPU->flag_X = CPU->flag_C = ((u32)src >> (sft - 1)) << C68K_SR_C_SFT;\n"); wf_op("\t\t\tres = ((s32)src) >> sft;\n", szcs); wf_op("\t\t\tCPU->flag_N = res >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\t\t\tCPU->flag_notZ = res;\n"); // write _ea_write(current_ea, current_op->reg_sft); quick_terminate_op(6); wf_op("\t\t}\n"); wf_op("\n"); // special case of shift >= size op // if signed wf_op("\t\tif (src & (1 << %d))\n", current_sft_mask); wf_op("\t\t{\n"); // op & flag calculation wf_op("\t\t\tCPU->flag_N = C68K_SR_N;\n"); wf_op("\t\t\tCPU->flag_notZ = 1;\n"); wf_op("\t\t\tCPU->flag_V = 0;\n"); wf_op("\t\t\tCPU->flag_C = C68K_SR_C;\n"); wf_op("\t\t\tCPU->flag_X = C68K_SR_X;\n"); wf_op("\t\t\tres = 0x%.8X;\n", current_bits_mask); // write _ea_write(current_ea, current_op->reg_sft); quick_terminate_op(6); wf_op("\t\t}\n"); wf_op("\n"); // if not signed wf_op("\t\tCPU->flag_N = 0;\n"); wf_op("\t\tCPU->flag_notZ = 0;\n"); wf_op("\t\tCPU->flag_V = 0;\n"); wf_op("\t\tCPU->flag_C = 0;\n"); wf_op("\t\tCPU->flag_X = 0;\n"); wf_op("\t\tres = 0;\n"); // write _ea_write(current_ea, current_op->reg_sft); quick_terminate_op(6); wf_op("\t}\n"); wf_op("\n"); // special case of (shift == 0) wf_op("\tCPU->flag_V = 0;\n"); wf_op("\tCPU->flag_C = 0;\n"); wf_op("\tCPU->flag_N = (u32)src >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\tCPU->flag_notZ = (u32)src;\n"); terminate_op(6); } static void GenLSRD() { // u32 base = get_current_opcode_base(); current_ea = EA_DREG; // dst = Dx start_all(GEN_RES | GEN_SRC); if (current_size == SIZE_LONG) current_cycle += 2; wf_op("\tu32 sft;\n"); wf_op("\n"); wf_op("\tsft = CPU->D[(Opcode >> %d) & 7] & 0x3F;\n", current_op->reg2_sft); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // if (shift != 0) wf_op("\tif (sft)\n"); wf_op("\t{\n"); adds_CCnt("sft * 2"); // if (shift <= size op) if (current_size == SIZE_LONG) wf_op("\t\tif (sft < 32)\n"); else wf_op("\t\tif (sft <= %d)\n", current_sft_mask + 1); wf_op("\t\t{\n"); // op & flag calculation wf_op("\t\t\tCPU->flag_N = CPU->flag_V = 0;\n"); if (current_size == SIZE_BYTE) wf_op("\t\t\tCPU->flag_X = CPU->flag_C = (u32)src << ((C68K_SR_C_SFT + 1) - sft);\n"); else wf_op("\t\t\tCPU->flag_X = CPU->flag_C = ((u32)src >> (sft - 1)) << C68K_SR_C_SFT;\n"); wf_op("\t\t\tres = (u32)src >> sft;\n", szcs); wf_op("\t\t\tCPU->flag_notZ = res;\n"); // write _ea_write(current_ea, current_op->reg_sft); quick_terminate_op(6); wf_op("\t\t}\n"); wf_op("\n"); // special case of shift > size op if (current_size == SIZE_LONG) { wf_op("\t\tif (sft == 32) CPU->flag_C = (u32)src >> (31 - C68K_SR_C_SFT);\n"); wf_op("\t\telse CPU->flag_C = 0;\n"); wf_op("\t\tCPU->flag_X = CPU->flag_C;\n"); } else wf_op("\t\tCPU->flag_X = CPU->flag_C = 0;\n"); wf_op("\t\tCPU->flag_N = 0;\n"); wf_op("\t\tCPU->flag_notZ = 0;\n"); wf_op("\t\tCPU->flag_V = 0;\n"); wf_op("\t\tres = 0;\n"); // write _ea_write(current_ea, current_op->reg_sft); quick_terminate_op(6); wf_op("\t}\n"); wf_op("\n"); // special case of (shift == 0) wf_op("\tCPU->flag_V = 0;\n"); wf_op("\tCPU->flag_C = 0;\n"); wf_op("\tCPU->flag_N = (u32)src >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\tCPU->flag_notZ = (u32)src;\n"); terminate_op(6); } static void GenROXRD() { // u32 base = get_current_opcode_base(); current_ea = EA_DREG; // dst = Dx start_all(GEN_RES | GEN_SRC); if (current_size == SIZE_LONG) current_cycle += 2; wf_op("\tu32 sft;\n"); wf_op("\n"); wf_op("\tsft = CPU->D[(Opcode >> %d) & 7] & 0x3F;\n", current_op->reg2_sft); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // if (shift != 0) wf_op("\tif (sft)\n"); wf_op("\t{\n"); adds_CCnt("sft * 2"); wf_op("\t\tsft %%= %d;\n", current_sft_mask + 2); wf_op("\n"); // op & C / X flag calculation if (current_size != SIZE_LONG) { wf_op("\t\tsrc |= (CPU->flag_X & C68K_SR_X) << %d;\n", (current_sft_mask + 1) - C68K_SR_X_SFT); wf_op("\t\tres = ((u32)src >> sft) | ((u32)src << (%d - sft));\n", current_sft_mask + 2); wf_op("\t\tCPU->flag_X = CPU->flag_C = res >> %d;\n", (current_sft_mask + 1) - C68K_SR_X_SFT); } else { wf_op("\t\tif (sft != 0)\n"); wf_op("\t\t{\n"); wf_op("\t\t\tif (sft == 1) res = ((u32)src >> 1) | ((CPU->flag_X & C68K_SR_X) << (32 - (C68K_SR_X_SFT + 1)));\n"); wf_op("\t\t\telse res = ((u32)src >> sft) | ((u32)src << (33 - sft)) | (((CPU->flag_X & C68K_SR_X) << (32 - (C68K_SR_X_SFT + 1))) >> (sft - 1));\n"); wf_op("\t\t\tCPU->flag_X = ((u32)src >> (32 - sft)) << C68K_SR_X_SFT;\n"); wf_op("\t\t}\n"); wf_op("\t\telse res = (u32)src;\n"); wf_op("\t\tCPU->flag_C = CPU->flag_X;\n"); } // V / N / Z flag calculation wf_op("\t\tCPU->flag_V = 0;\n"); wf_op("\t\tCPU->flag_N = res >> %d;\n", current_sft_mask - C68K_SR_N_SFT); if (current_size == SIZE_LONG) wf_op("\t\tCPU->flag_notZ = res;\n"); else wf_op("\t\tCPU->flag_notZ = res & 0x%.8X;\n", current_bits_mask); // write _ea_write(current_ea, current_op->reg_sft); quick_terminate_op(6); wf_op("\t}\n"); wf_op("\n"); // special case of (shift == 0) wf_op("\tCPU->flag_V = 0;\n"); wf_op("\tCPU->flag_C = CPU->flag_X;\n"); wf_op("\tCPU->flag_N = (u32)src >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\tCPU->flag_notZ = (u32)src;\n"); terminate_op(6); } static void GenRORD() { // u32 base = get_current_opcode_base(); current_ea = EA_DREG; // dst = Dx start_all(GEN_RES | GEN_SRC); if (current_size == SIZE_LONG) current_cycle += 2; wf_op("\tu32 sft;\n"); wf_op("\n"); wf_op("\tsft = CPU->D[(Opcode >> %d) & 7] & 0x3F;\n", current_op->reg2_sft); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // if (shift != 0) wf_op("\tif (sft)\n"); wf_op("\t{\n"); adds_CCnt("sft * 2"); wf_op("\t\tsft &= 0x%.2X;\n", current_sft_mask); wf_op("\t\t\n"); // op & flag calculation if (current_size == SIZE_BYTE) wf_op("\t\tCPU->flag_C = (u32)src << (C68K_SR_C_SFT - ((sft - 1) & 7));\n"); else wf_op("\t\tCPU->flag_C = ((u32)src >> ((sft - 1) & %d)) << C68K_SR_C_SFT;\n", current_sft_mask); wf_op("\t\tres = ((u32)src >> sft) | ((u32)src << (%d - sft));\n", current_sft_mask + 1); wf_op("\t\tCPU->flag_V = 0;\n"); wf_op("\t\tCPU->flag_N = res >> %d;\n", current_sft_mask - C68K_SR_N_SFT); if (current_size == SIZE_LONG) wf_op("\t\tCPU->flag_notZ = res;\n"); else wf_op("\t\tCPU->flag_notZ = res & 0x%.8X;\n", current_bits_mask); // write _ea_write(current_ea, current_op->reg_sft); quick_terminate_op(6); wf_op("\t}\n"); wf_op("\n"); // special case of (shift == 0) wf_op("\tCPU->flag_V = 0;\n"); wf_op("\tCPU->flag_C = 0;\n"); wf_op("\tCPU->flag_N = (u32)src >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\tCPU->flag_notZ = (u32)src;\n"); terminate_op(6); } static void GenASLD() { // u32 base = get_current_opcode_base(); current_ea = EA_DREG; // dst = Dx start_all(GEN_RES | GEN_SRC); if (current_size == SIZE_LONG) current_cycle += 2; wf_op("\tu32 sft;\n"); wf_op("\n"); wf_op("\tsft = CPU->D[(Opcode >> %d) & 7] & 0x3F;\n", current_op->reg2_sft); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // if (shift != 0) wf_op("\tif (sft)\n"); wf_op("\t{\n"); adds_CCnt("sft * 2"); // if (shift < size op) wf_op("\t\tif (sft < %d)\n", current_sft_mask + 1); wf_op("\t\t{\n"); // op & flag calculation if (current_size != SIZE_LONG) { wf_op("\t\t\tCPU->flag_X = CPU->flag_C = ((u32)src << sft) >> %d;\n", (current_sft_mask + 1) - C68K_SR_C_SFT); wf_op("\t\t\tres = ((u32)src << sft) & 0x%.8X;\n", current_bits_mask); } else { wf_op("\t\t\tCPU->flag_X = CPU->flag_C = ((u32)src >> (32 - sft)) << C68K_SR_C_SFT;\n"); wf_op("\t\t\tres = (u32)(src << sft);\n"); } wf_op("\t\t\tCPU->flag_N = res >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\t\t\tCPU->flag_notZ = res;\n", current_bits_mask); // write _ea_write(current_ea, current_op->reg_sft); // we do V flag calculation at end for a better register usage wf_op("\t\t\tCPU->flag_V = 0;\n"); wf_op("\t\t\t{\n"); wf_op("\t\t\t\tu32 msk = (((s32)0x80000000) >> (sft + %d)) & 0x%.8X;\n", 31 - current_sft_mask, current_bits_mask); wf_op("\t\t\t\tsrc &= msk;\n"); wf_op("\t\t\t\tif ((src) && (src != msk)) CPU->flag_V = C68K_SR_V;\n"); wf_op("\t\t\t}\n"); quick_terminate_op(6); wf_op("\t\t}\n"); wf_op("\n"); // special case of shift >= size op wf_op("\t\tif (sft == %d) CPU->flag_C = (u32)src << C68K_SR_C_SFT;\n", current_bits_mask + 1); wf_op("\t\telse CPU->flag_C = 0;\n"); wf_op("\t\tCPU->flag_X = CPU->flag_C;\n"); wf_op("\t\tif (src) CPU->flag_V = C68K_SR_V;\n"); wf_op("\t\telse CPU->flag_V = 0;\n"); wf_op("\t\tres = 0;\n"); // write _ea_write(current_ea, current_op->reg_sft); // others flags wf_op("\t\tCPU->flag_N = 0;\n"); wf_op("\t\tCPU->flag_notZ = 0;\n"); quick_terminate_op(6); wf_op("\t}\n"); wf_op("\n"); // special case of (shift == 0) wf_op("\tCPU->flag_V = 0;\n"); wf_op("\tCPU->flag_C = 0;\n"); wf_op("\tCPU->flag_N = (u32)src >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\tCPU->flag_notZ = (u32)src;\n"); terminate_op(6); } static void GenLSLD() { // u32 base = get_current_opcode_base(); current_ea = EA_DREG; // dst = Dx start_all(GEN_RES | GEN_SRC); if (current_size == SIZE_LONG) current_cycle += 2; wf_op("\tu32 sft;\n"); wf_op("\n"); wf_op("\tsft = CPU->D[(Opcode >> %d) & 7] & 0x3F;\n", current_op->reg2_sft); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // if (shift != 0) wf_op("\tif (sft)\n"); wf_op("\t{\n"); adds_CCnt("sft * 2"); // if (shift <= size op) if (current_size == SIZE_LONG) wf_op("\t\tif (sft < 32)\n"); else wf_op("\t\tif (sft <= %d)\n", current_sft_mask + 1); wf_op("\t\t{\n"); // op & flag calculation if (current_size != SIZE_LONG) { wf_op("\t\t\tCPU->flag_X = CPU->flag_C = ((u32)src << sft) >> %d;\n", (current_sft_mask + 1) - C68K_SR_C_SFT); wf_op("\t\t\tres = (src << sft) & 0x%.8X;\n", current_bits_mask); } else { wf_op("\t\t\tCPU->flag_X = CPU->flag_C = ((u32)src >> (32 - sft)) << C68K_SR_C_SFT;\n"); wf_op("\t\t\tres = (u32)(src << sft);\n"); } wf_op("\t\t\tCPU->flag_V = 0;\n"); wf_op("\t\t\tCPU->flag_N = res >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\t\t\tCPU->flag_notZ = res;\n", current_bits_mask); // write _ea_write(current_ea, current_op->reg_sft); quick_terminate_op(6); wf_op("\t\t}\n"); wf_op("\n"); // special case of shift > size op if (current_size == SIZE_LONG) { wf_op("\t\tif (sft == 32) CPU->flag_C = (u32)src << C68K_SR_C_SFT;\n"); wf_op("\t\telse CPU->flag_C = 0;\n"); wf_op("\t\tCPU->flag_X = CPU->flag_C;\n"); } else wf_op("\t\tCPU->flag_X = CPU->flag_C = 0;\n"); wf_op("\t\tCPU->flag_N = 0;\n"); wf_op("\t\tCPU->flag_notZ = 0;\n"); wf_op("\t\tCPU->flag_V = 0;\n"); wf_op("\t\tres = 0;\n"); // write _ea_write(current_ea, current_op->reg_sft); quick_terminate_op(6); wf_op("\t}\n"); wf_op("\n"); // special case of (shift == 0) wf_op("\tCPU->flag_V = 0;\n"); wf_op("\tCPU->flag_C = 0;\n"); wf_op("\tCPU->flag_N = (u32)src >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\tCPU->flag_notZ = (u32)src;\n"); terminate_op(6); } static void GenROXLD() { // u32 base = get_current_opcode_base(); current_ea = EA_DREG; // dst = Dx start_all(GEN_RES | GEN_SRC); if (current_size == SIZE_LONG) current_cycle += 2; wf_op("\tu32 sft;\n"); wf_op("\n"); wf_op("\tsft = CPU->D[(Opcode >> %d) & 7] & 0x3F;\n", current_op->reg2_sft); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // if (shift != 0) wf_op("\tif (sft)\n"); wf_op("\t{\n"); adds_CCnt("sft * 2"); wf_op("\t\tsft %%= %d;\n", current_sft_mask + 2); wf_op("\n"); // op & C/X flags calculation if (current_size != SIZE_LONG) { wf_op("\t\tsrc |= (CPU->flag_X & C68K_SR_X) << %d;\n", (current_sft_mask + 1) - C68K_SR_X_SFT); wf_op("\t\tres = ((u32)src << sft) | ((u32)src >> (%d - sft));\n", current_sft_mask + 2); wf_op("\t\tCPU->flag_X = CPU->flag_C = res >> %d;\n", (current_sft_mask + 1) - C68K_SR_X_SFT); } else { wf_op("\t\tif (sft != 0)\n"); wf_op("\t\t{\n"); wf_op("\t\t\tif (sft == 1) res = ((u32)src << 1) | ((CPU->flag_X >> ((C68K_SR_X_SFT + 1) - 1)) & 1);\n"); wf_op("\t\t\telse res = ((u32)src << sft) | ((u32)src >> (33 - sft)) | (((CPU->flag_X >> ((C68K_SR_X_SFT + 1) - 1)) & 1) << (sft - 1));\n"); wf_op("\t\t\tCPU->flag_X = ((u32)src >> (32 - sft)) << C68K_SR_X_SFT;\n"); wf_op("\t\t}\n"); wf_op("\t\telse res = (u32)src;\n"); wf_op("\t\tCPU->flag_C = CPU->flag_X;\n"); } // V / N / Z flags calculation wf_op("\t\tCPU->flag_V = 0;\n"); wf_op("\t\tCPU->flag_N = res >> %d;\n", current_sft_mask - C68K_SR_N_SFT); if (current_size == SIZE_LONG) wf_op("\t\tCPU->flag_notZ = res;\n"); else wf_op("\t\tCPU->flag_notZ = res & 0x%.8X;\n", current_bits_mask); // write _ea_write(current_ea, current_op->reg_sft); quick_terminate_op(6); wf_op("\t}\n"); wf_op("\n"); // special case of (shift == 0) wf_op("\tCPU->flag_V = 0;\n"); wf_op("\tCPU->flag_C = CPU->flag_X;\n"); wf_op("\tCPU->flag_N = (u32)src >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\tCPU->flag_notZ = (u32)src;\n"); terminate_op(6); } static void GenROLD() { // u32 base = get_current_opcode_base(); current_ea = EA_DREG; // dst = Dx start_all(GEN_RES | GEN_SRC); if (current_size == SIZE_LONG) current_cycle += 2; wf_op("\tu32 sft;\n"); wf_op("\n"); wf_op("\tsft = CPU->D[(Opcode >> %d) & 7] & 0x3F;\n", current_op->reg2_sft); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // if (shift != 0) wf_op("\tif (sft)\n"); wf_op("\t{\n"); adds_CCnt("sft * 2"); // if ((shift & size op) != 0) wf_op("\t\tif (sft &= 0x%.2X)\n", current_sft_mask); wf_op("\t\t{\n"); // op & flag calculation if (current_size != SIZE_LONG) { wf_op("\t\t\tCPU->flag_C = (u32)((src << sft) >> %d);\n", (current_sft_mask + 1) - C68K_SR_C_SFT); wf_op("\t\t\tres = (u32)(((src << sft) | (src >> (%d - sft))) & 0x%.8X);\n", current_sft_mask + 1, current_bits_mask); } else { wf_op("\t\t\tCPU->flag_C = (u32)((src >> (32 - sft)) << C68K_SR_C_SFT);\n"); wf_op("\t\t\tres = (u32)((src << sft) | (src >> (%d - sft)));\n", current_sft_mask + 1); } wf_op("\t\t\tCPU->flag_V = 0;\n"); wf_op("\t\t\tCPU->flag_N = res >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\t\t\tCPU->flag_notZ = res;\n"); // write _ea_write(current_ea, current_op->reg_sft); quick_terminate_op(6); wf_op("\t\t}\n"); wf_op("\n"); // special case of ((shift & size op) == 0) wf_op("\t\tCPU->flag_V = 0;\n"); wf_op("\t\tCPU->flag_C = (u32)(src << C68K_SR_C_SFT);\n"); wf_op("\t\tCPU->flag_N = (u32)src >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\t\tCPU->flag_notZ = (u32)src;\n"); quick_terminate_op(6); wf_op("\t}\n"); wf_op("\n"); // special case of (shift == 0) wf_op("\tCPU->flag_V = 0;\n"); wf_op("\tCPU->flag_C = 0;\n"); wf_op("\tCPU->flag_N = (u32)src >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\tCPU->flag_notZ = (u32)src;\n"); terminate_op(6); } static void GenASR() { set_current_size(SIZE_WORD); // dst = mem (word operation) start_all(GEN_ADR | GEN_RES | GEN_SRC); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // op & flag calculation wf_op("\tCPU->flag_V = 0;\n"); wf_op("\tCPU->flag_X = CPU->flag_C = (u32)src << C68K_SR_C_SFT;\n"); wf_op("\tres = ((u32)src >> 1) | ((u32)src & (1 << %d));\n", current_sft_mask); wf_op("\tCPU->flag_N = res >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\tCPU->flag_notZ = res;\n"); // write _ea_write(current_ea, current_op->reg_sft); terminate_op(8); } static void GenLSR() { set_current_size(SIZE_WORD); // dst = mem (word operation) start_all(GEN_ADR | GEN_RES | GEN_SRC); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // op & flag calculation wf_op("\tCPU->flag_N = CPU->flag_V = 0;\n"); wf_op("\tCPU->flag_X = CPU->flag_C = (u32)src << C68K_SR_C_SFT;\n"); wf_op("\tres = (u32)(src >> 1);\n"); wf_op("\tCPU->flag_notZ = res;\n"); // write _ea_write(current_ea, current_op->reg_sft); terminate_op(8); } static void GenROXR() { set_current_size(SIZE_WORD); // dst = mem (word operation) start_all(GEN_ADR | GEN_RES | GEN_SRC); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // op & flag calculation wf_op("\tCPU->flag_V = 0;\n"); wf_op("\tres = ((u32)src >> 1) | ((CPU->flag_X & C68K_SR_X) << %d);\n", current_sft_mask - C68K_SR_X_SFT); wf_op("\tCPU->flag_C = CPU->flag_X = (u32)(src << C68K_SR_C_SFT);\n"); wf_op("\tCPU->flag_N = res >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\tCPU->flag_notZ = res;\n"); // write _ea_write(current_ea, current_op->reg_sft); terminate_op(8); } static void GenROR() { set_current_size(SIZE_WORD); // dst = mem (word operation) start_all(GEN_ADR | GEN_RES | GEN_SRC); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // op & flag calculation wf_op("\tCPU->flag_V = 0;\n"); wf_op("\tCPU->flag_C = (u32)(src << C68K_SR_C_SFT);\n"); wf_op("\tres = ((u32)src >> 1) | ((u32)src << %d);\n", current_sft_mask); wf_op("\tCPU->flag_N = res >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\tCPU->flag_notZ = res & 0x%.8X;\n", current_bits_mask); // write _ea_write(current_ea, current_op->reg_sft); terminate_op(8); } static void GenASL() { set_current_size(SIZE_WORD); // dst = mem (word operation) start_all(GEN_ADR | GEN_RES | GEN_SRC); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // op & flag calculation wf_op("\tCPU->flag_X = CPU->flag_C = (u32)(src >> %d);\n", current_sft_mask - C68K_SR_C_SFT); wf_op("\tres = (u32)(src << 1);\n"); wf_op("\tCPU->flag_V = ((u32)src ^ res) >> %d;\n", current_sft_mask - C68K_SR_V_SFT); wf_op("\tCPU->flag_N = res >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\tCPU->flag_notZ = res & 0x%.8X;\n", current_bits_mask); // write _ea_write(current_ea, current_op->reg_sft); terminate_op(8); } static void GenLSL() { set_current_size(SIZE_WORD); // dst = mem (word operation) start_all(GEN_ADR | GEN_RES | GEN_SRC); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // op & flag calculation wf_op("\tCPU->flag_V = 0;\n"); wf_op("\tCPU->flag_X = CPU->flag_C = (u32)(src >> %d);\n", current_sft_mask - C68K_SR_C_SFT); wf_op("\tres = (u32)(src << 1);\n"); wf_op("\tCPU->flag_N = res >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\tCPU->flag_notZ = res & 0x%.8X;\n", current_bits_mask); // write _ea_write(current_ea, current_op->reg_sft); terminate_op(8); } static void GenROXL() { set_current_size(SIZE_WORD); // dst = mem (word operation) start_all(GEN_ADR | GEN_RES | GEN_SRC); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // op & flag calculation wf_op("\tCPU->flag_V = 0;\n"); wf_op("\tres = (u32)(src << 1) | ((CPU->flag_X & C68K_SR_X) >> %d);\n", C68K_SR_X_SFT); wf_op("\tCPU->flag_X = CPU->flag_C = (u32)(src >> %d);\n", current_sft_mask - C68K_SR_C_SFT); wf_op("\tCPU->flag_N = res >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\tCPU->flag_notZ = res & 0x%.8X;\n", current_bits_mask); // write _ea_write(current_ea, current_op->reg_sft); terminate_op(8); } static void GenROL() { set_current_size(SIZE_WORD); // dst = mem (word operation) start_all(GEN_ADR | GEN_RES | GEN_SRC); // read _ea_calc(current_ea, current_op->reg_sft); _ea_read_src(current_ea, current_op->reg_sft); // op & flag calculation wf_op("\tCPU->flag_V = 0;\n"); wf_op("\tCPU->flag_C = (u32)(src >> %d);\n", current_sft_mask - C68K_SR_C_SFT); wf_op("\tres = ((u32)src << 1) | ((u32)src >> %d);\n", current_sft_mask); wf_op("\tCPU->flag_N = res >> %d;\n", current_sft_mask - C68K_SR_N_SFT); wf_op("\tCPU->flag_notZ = res & 0x%.8X;\n", current_bits_mask); // write _ea_write(current_ea, current_op->reg_sft); terminate_op(8); } static void Gen1010() { u32 base; base = get_current_opcode_base(); // generate jump table gen_opjumptable_ext(base, 0x0000, 0x0FFF, 0x1, base); // generate label & declarations start_op(base, GEN_RES); wf_op("\tPC -= 2;\n"); gen_exception("\t", "C68K_1010_EX"); terminate_op(4); } static void Gen1111() { u32 base; base = get_current_opcode_base(); // generate jump table gen_opjumptable_ext(base, 0x0000, 0x0FFF, 0x1, base); // generate label & declarations start_op(base, GEN_RES); wf_op("\tPC -= 2;\n"); gen_exception("\t", "C68K_1111_EX"); terminate_op(4); } #ifdef NEOCD_HLE static void Gen0xFABE() { start_all(GEN_ALL); wf_op("\tneogeo_exit();\n"); terminate_op(0); } static void Gen0xFABF() { start_all(GEN_ALL); wf_op("\timg_display = 1;\n"); wf_op("\tcdrom_load_files();\n"); terminate_op(0); } static void Gen0xFAC0() { start_all(GEN_ALL); wf_op("\timg_display = 0;\n"); wf_op("\tcdrom_load_files();\n"); terminate_op(0); } static void Gen0xFAC1() { start_all(GEN_ALL); wf_op("\tneogeo_upload();\n"); terminate_op(0); } static void Gen0xFAC2() { start_all(GEN_ALL); wf_op("\tneogeo_prio_switch();\n"); terminate_op(0); } static void Gen0xFAC3() { start_all(GEN_ALL); wf_op("\tneogeo_cdda_control();\n"); terminate_op(0); } #endif // main function ///////////////// int main(void) { u32 i; u32 s; u32 smax; // clear opcode files for(i = 0; i < 0x10; i++) { char fn[16]; sprintf(fn, "c68k_op%.1X.inc", (int)i); opcode_file = fopen(fn, "wt"); if (opcode_file != NULL) { fclose(opcode_file); opcode_file = NULL; } } // init opcode jump table ini_file = fopen("c68k_ini.inc", "wt"); #ifndef C68K_NO_JUMP_TABLE #ifdef C68K_CONST_JUMP_TABLE for(i = 0; i < 0x10000; i++) op_jump_table[i] = OP_ILLEGAL; #else // defaut ILLEGAL instruction gen_jumptable(0x0000, 0x0000, 0xFFFF, 1, 0, 0, 0, 0, 0, 0, 0x4AFC); #endif #endif // generate opcode files for(i = 0; i < OP_INFO_TABLE_LEN; i++) { current_op = &(op_info_table[i]); if (prepare_generate()) return 1; // s = size to start current_size = 0; smax = SIZE_LONG; if (current_op->size_type == 0) smax = 0; else if (current_op->size_type == 1) current_size = 1; for(s = current_size; s <= smax; s++) { if (current_op->eam_sft != -1) { for(current_ea = 0; current_ea <= EA_ADEC7; current_ea++) { if (!has_ea(current_ea)) continue; current_eam = _ea_to_eamreg(current_ea) >> 3; current_reg = _ea_to_eamreg(current_ea) & 7; if (op_info_table[i].eam2_sft != -1) { for(current_ea2 = 0; current_ea2 <= EA_ADEC7; current_ea2++) { if (!has_ea2(current_ea2)) continue; current_eam2 = _ea_to_eamreg(current_ea2) >> 3; current_reg2 = _ea_to_eamreg(current_ea2) & 7; set_current_size(s); current_op->genfunc(); } } else { current_reg2 = 0; set_current_size(s); current_op->genfunc(); } } } else { current_reg = 0; set_current_size(s); current_op->genfunc(); } } } // generate jumptable file #ifdef C68K_CONST_JUMP_TABLE if (ini_file != NULL) { fprintf(ini_file, "\tstatic const void *JumpTable[0x10000] =\n"); fprintf(ini_file, "\t{\n"); for(i = 0; i < (0x10000 - 4); i += 4) fprintf(ini_file, "\t\t&&OP_0x%.4X, &&OP_0x%.4X, &&OP_0x%.4X, &&OP_0x%.4X,\n", op_jump_table[i + 0], op_jump_table[i + 1], op_jump_table[i + 2], op_jump_table[i + 3]); fprintf(ini_file, "\t\t&&OP_0x%.4X, &&OP_0x%.4X, &&OP_0x%.4X, &&OP_0x%.4X\n", op_jump_table[0xFFFC], op_jump_table[0xFFFD], op_jump_table[0xFFFE], op_jump_table[0xFFFF]); fprintf(ini_file, "\t};\n\n"); } #endif // close handle if (ini_file != NULL) fclose(ini_file); if (opcode_file != NULL) fclose(opcode_file); return 0; } #endif yabause-0.9.15/src/c68k/c68k.h000644 001750 001750 00000013500 12755623101 017540 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2004 Stephane Dallongeville Copyright 2004 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /********************************************************************************* * C68K.H : * * C68K include file * ********************************************************************************/ #ifndef _C68K_H_ #define _C68K_H_ #ifdef __cplusplus extern "C" { #endif #include "../core.h" // setting /////////// //#define NEOCD_HLE //#define C68K_GEN #define C68K_BYTE_SWAP_OPT #ifdef WORDS_BIGENDIAN #define C68K_BIG_ENDIAN #endif #ifdef C68K_BIG_ENDIAN #define BYTE_OFF 3 #define WORD_OFF 1 #else #define BYTE_OFF 0 #define WORD_OFF 0 #endif //#define C68K_NO_JUMP_TABLE //#define C68K_DEBUG #define C68K_TAS_CAN_SET_MEMORY //#define C68K_CONST_JUMP_TABLE //#define C68K_AUTOVECTOR_CALLBACK // 68K core types definitions ////////////////////////////// #define C68K_FETCH_BITS 8 // [4-12] default = 8 #define C68K_ADR_BITS 24 #define C68K_FETCH_SFT (C68K_ADR_BITS - C68K_FETCH_BITS) #define C68K_FETCH_BANK (1 << C68K_FETCH_BITS) #define C68K_FETCH_MASK (C68K_FETCH_BANK - 1) #define C68K_SR_C_SFT 8 #define C68K_SR_V_SFT 7 #define C68K_SR_Z_SFT 0 #define C68K_SR_N_SFT 7 #define C68K_SR_X_SFT 8 #define C68K_SR_S_SFT 13 #define C68K_SR_C (1 << C68K_SR_C_SFT) #define C68K_SR_V (1 << C68K_SR_V_SFT) #define C68K_SR_Z 0 #define C68K_SR_N (1 << C68K_SR_N_SFT) #define C68K_SR_X (1 << C68K_SR_X_SFT) #define C68K_SR_S (1 << C68K_SR_S_SFT) #define C68K_CCR_MASK 0x1F #define C68K_SR_MASK (0x2700 | C68K_CCR_MASK) // exception defines taken from musashi core #define C68K_RESET_EX 1 #define C68K_BUS_ERROR_EX 2 #define C68K_ADDRESS_ERROR_EX 3 #define C68K_ILLEGAL_INSTRUCTION_EX 4 #define C68K_ZERO_DIVIDE_EX 5 #define C68K_CHK_EX 6 #define C68K_TRAPV_EX 7 #define C68K_PRIVILEGE_VIOLATION_EX 8 #define C68K_TRACE_EX 9 #define C68K_1010_EX 10 #define C68K_1111_EX 11 #define C68K_FORMAT_ERROR_EX 14 #define C68K_UNINITIALIZED_INTERRUPT_EX 15 #define C68K_SPURIOUS_INTERRUPT_EX 24 #define C68K_INTERRUPT_AUTOVECTOR_EX 24 #define C68K_TRAP_BASE_EX 32 #define C68K_INT_ACK_AUTOVECTOR -1 #define C68K_RUNNING 0x01 #define C68K_HALTED 0x02 #define C68K_WAITING 0x04 #define C68K_DISABLE 0x10 #define C68K_FAULTED 0x40 typedef u32 FASTCALL C68K_READ(const u32 adr); typedef void FASTCALL C68K_WRITE(const u32 adr, u32 data); typedef s32 FASTCALL C68K_INT_CALLBACK(s32 level); typedef void FASTCALL C68K_RESET_CALLBACK(void); typedef struct { u32 D[8]; // 32 bytes aligned u32 A[8]; // 16 bytes aligned u32 flag_C; // 32 bytes aligned u32 flag_V; u32 flag_notZ; u32 flag_N; u32 flag_X; // 16 bytes aligned u32 flag_I; u32 flag_S; u32 USP; pointer PC; // 32 bytes aligned pointer BasePC; u32 Status; s32 IRQLine; s32 CycleToDo; // 16 bytes aligned s32 CycleIO; s32 CycleSup; u32 dirty1; C68K_READ *Read_Byte; // 32 bytes aligned C68K_READ *Read_Word; C68K_WRITE *Write_Byte; C68K_WRITE *Write_Word; C68K_INT_CALLBACK *Interrupt_CallBack; // 16 bytes aligned C68K_RESET_CALLBACK *Reset_CallBack; pointer Fetch[C68K_FETCH_BANK]; // 32 bytes aligned } c68k_struc; // 68K core var declaration //////////////////////////// extern c68k_struc C68K; // 68K core function declaration ///////////////////////////////// void C68k_Init(c68k_struc *cpu, C68K_INT_CALLBACK *int_cb); s32 FASTCALL C68k_Reset(c68k_struc *cpu); // if < 0 --> error (cpu state returned) // if >= 0 --> number of extras cycles done s32 FASTCALL C68k_Exec(c68k_struc *cpu, s32 cycle); void FASTCALL C68k_Set_IRQ(c68k_struc *cpu, s32 level); s32 FASTCALL C68k_Get_CycleToDo(c68k_struc *cpu); s32 FASTCALL C68k_Get_CycleRemaining(c68k_struc *cpu); s32 FASTCALL C68k_Get_CycleDone(c68k_struc *cpu); void FASTCALL C68k_Release_Cycle(c68k_struc *cpu); void FASTCALL C68k_Add_Cycle(c68k_struc *cpu, s32 cycle); void C68k_Set_Fetch(c68k_struc *cpu, u32 low_adr, u32 high_adr, pointer fetch_adr); void C68k_Set_ReadB(c68k_struc *cpu, C68K_READ *Func); void C68k_Set_ReadW(c68k_struc *cpu, C68K_READ *Func); void C68k_Set_WriteB(c68k_struc *cpu, C68K_WRITE *Func); void C68k_Set_WriteW(c68k_struc *cpu, C68K_WRITE *Func); u32 C68k_Get_DReg(c68k_struc *cpu, u32 num); u32 C68k_Get_AReg(c68k_struc *cpu, u32 num); u32 C68k_Get_PC(c68k_struc *cpu); u32 C68k_Get_SR(c68k_struc *cpu); u32 C68k_Get_USP(c68k_struc *cpu); u32 C68k_Get_MSP(c68k_struc *cpu); void C68k_Set_DReg(c68k_struc *cpu, u32 num, u32 val); void C68k_Set_AReg(c68k_struc *cpu, u32 num, u32 val); void C68k_Set_PC(c68k_struc *cpu, u32 val); void C68k_Set_SR(c68k_struc *cpu, u32 val); void C68k_Set_USP(c68k_struc *cpu, u32 val); void C68k_Set_MSP(c68k_struc *cpu, u32 val); #ifdef __cplusplus } #endif #endif // _C68K_H_ yabause-0.9.15/src/sh2idle.c000644 001750 001750 00000045075 12755623101 017553 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005-2006 Fabien Coulon This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file sh2idle.c \brief SH2 interpreter interface with idle detection. */ #include "sh2core.h" #include "sh2idle.h" #include "sh2int.h" #include "sh2d.h" #include "memory.h" #define MAX_CYCLE_CHECK 14 // idle loops greater than MAX_CYCLE_CHECK instructions will not be detected. /* Detection of idle loops: ie loops in which no write to memory is done, ending with a conditional jump, at the point of which all registers are "deterministic" in the sense they don't depend on the number of executed loops */ /* bDet : Bitwise register markers. 1: register is deterministic bChg : Bitwise register markers. 1: register has been changed, not in a deterministic way */ u32 bDet, bChg; /* Macro : makes changes resulting from the execution of an instruction in which the content of register only depends on register(s) (and potentially constant values, including memory content which is constant in an idle loop) */ #define delayCheck(PC) SH2idleCheckIterate(context, ((fetchfunc *)context->fetchlist)[((PC) >> 20) & 0x0FF](context, PC), PC ) #define implies(dest,src) if ( src ) bDet |= dest; else bChg |= dest; #define implies2(dest,dest2,src) if ( src ) bDet |= dest|dest2; else bChg |= dest|dest2; #define implies3(dest,dest2,dest3,src) if ( src ) bDet |= dest|dest2|dest3; else bChg |= dest|dest2|dest3; #define destRB (1< // return 0 : cannot continue idle check, probably because of a memory write switch (INSTRUCTION_A(instruction)) { case 0: switch (INSTRUCTION_D(instruction)) { case 2: switch (INSTRUCTION_C(instruction)) { case 0: implies(destRB, srcSR); //stcsr break; case 1: implies(destRB, srcGBR); //stcgbr; break; case 2: implies(destRB, srcVBR); //stcvbr; break; } break; case 3: switch (INSTRUCTION_C(instruction)) { case 0: implies( destPR, 1 ); //bsrf; case 2: isConst( srcRB ); return delayCheck(PC+2); //braf; } break; case 4: //movbs0; case 5: //movws0; case 6: return 0; //movls0; case 7: implies(destMACL, srcRC && srcRB ); // mull break; case 8: switch (INSTRUCTION_C(instruction)) { case 0: //clrt; case 1: implies( destSRT, 1 ); //sett; break; case 2: implies( destMAC, 1 ); //clrmac; break; } break; case 9: switch (INSTRUCTION_C(instruction)) { case 0: //nop; break; case 1: implies3( destSRM, destSRQ, destSRT, 1 ); //div0u; break; case 2: implies(destRB, srcSRT ); //movt; break; } break; case 10: switch (INSTRUCTION_C(instruction)) { case 0: implies(destRB, srcMACH); //stsmach; break; case 1: implies(destRB, srcMACL); //stsmacl; break; case 2: implies(destRB, srcPR); //stspr; break; } break; case 11: switch (INSTRUCTION_C(instruction)) { case 1: //sleep; break; case 0: isConst(srcPR); //rts; return delayCheck(PC+2); case 2: isConst(srcR15); implies(destSR, srcR15); return delayCheck(PC+2); //rte; } break; case 12: //movbl0; case 13: //movwl0; case 14: implies(destRB, srcRC && srcR0); //movll0; break; case 15: implies(destMAC, srcRC && srcRB && srcSRS && srcMACL && srcMACH); //macl break; } break; case 1: return 0; //movls4; case 2: switch (INSTRUCTION_D(instruction)) { case 0: //movbs; case 1: //movws; case 2: return 0; //movls; case 4: //movbm; case 5: //movwm; case 6: return 0;//movlm; case 7: implies(destSR, srcRC && srcRB ); //div0s break; case 8: implies(destSRT, srcRC && srcRB ); //tst break; case 9: //y_and; case 10: //y_xor; case 11: implies( destRB, srcRB && srcRC ); //y_or break; case 12: implies( destSRT, srcRC && srcRB ); //cmpstr; break; case 13: implies( destRB, srcRB && srcRC ); //xtrct break; case 14: implies( destMAC, srcRB && srcRC ); //mulu break; case 15: implies( destMACL, srcRB && srcRC ); //muls break; } break; case 3: switch(INSTRUCTION_D(instruction)) { case 0: //cmpeq; case 2: //cmphs; case 6: //cmphi; case 7: //cmpgt; case 3: implies( destSRT, srcRB && srcRC ); break; case 4: implies3( destSRQ, destSRT, destRB, srcRB && srcRC && srcSRQ && srcSRM ); //div1; /* CHECK ME */ break; case 13: //dmuls; case 5: implies( destMAC, srcRB && srcRC ); // dmulu break; case 8: implies( destRB, srcRB && srcRC ); //sub break; case 15: //addv; case 11: implies( destSRT, srcRB && srcRC ); //subv break; case 12: implies( destRB, srcRB && srcRC ); //add break; case 10: //subc; case 14: implies2( destRB, destSRT, srcRB && srcRC && srcSRT ); //addc break; } break; case 4: switch(INSTRUCTION_D(instruction)) { case 0: switch(INSTRUCTION_C(instruction)) { case 1: //dt; case 0: //shll; case 2: implies2( destSRT, destRB, srcRB ); //shal break; } break; case 1: switch(INSTRUCTION_C(instruction)) { case 2: case 0: implies2( destSRT, destRB, srcRB ); //shlr; break; case 1: implies( destSRT, srcRB ); //cmppz break; } break; case 2: switch(INSTRUCTION_C(instruction)) { case 0: //stsmmach; case 1: //stsmmacl; case 2: return 0;//stsmpr; } break; case 3: switch(INSTRUCTION_C(instruction)) { case 0: //stcmsr; case 1: //stcmgbr; case 2: return 0; //stcmvbr; } break; case 4: switch(INSTRUCTION_C(instruction)) { case 0: //rotl; case 2: implies2( destRB, destSRT, srcRB ); //rotcl } break; case 5: switch(INSTRUCTION_C(instruction)) { case 0: implies2( destRB, destSRT, srcRB ); //rotr; break; case 1: implies( destSRT, srcRB ); //cmppl; break; case 2: implies2( destSRT, destRB, srcSRT && srcRB ); //rotcr break; } break; case 6: switch(INSTRUCTION_C(instruction)) { case 0: implies( destMACH, srcRB ); //ldsmmach break; case 1: implies( destMACL, srcRB ); //lsdmmacl break; case 2: implies( destPR, srcRB ); //ldsmpr break; } break; case 7: switch(INSTRUCTION_C(instruction)) { case 0: implies( destSR, srcRB ); //ldcmsr break; case 1: implies( destGBR, srcRB ); //ldcmgbr break; case 2: implies( destVBR, srcRB ); //lscmvbr break; } break; case 8: switch(INSTRUCTION_C(instruction)) { case 0: //shll2; case 1: //shll8; case 2: implies( destRB, srcRB ); //shll16 } break; case 9: switch(INSTRUCTION_C(instruction)) { case 0: //shlr2; case 1: //shlr8; case 2: implies( destRB, srcRB ); //shlr16 } break; case 10: switch(INSTRUCTION_C(instruction)) { case 0: implies( destMACH, srcRB ); //ldsmach break; case 1: implies( destMACL, srcRB ); //ldsmacl break; case 2: implies( destPR, srcRB ); //ldspr break; } break; case 11: switch(INSTRUCTION_C(instruction)) { case 0: isConst( srcRB ); implies( destPR, 1 ); break; //jsr case 1: return 0; //tas; case 2: isConst( srcRB ); return delayCheck(PC+2); //jmp } break; case 14: switch(INSTRUCTION_C(instruction)) { case 0: implies( destSR, srcRB ); //ldcsr break; case 1: implies( destGBR, srcRB ); //ldcgbr break; case 2: implies( destVBR, srcRB ); //ldcvrb break; } break; case 15: implies( destMAC, srcRB && srcRC && srcMAC ); //macw break; } case 5: implies( destRB, srcRC ); //movll4 break; case 6: switch (INSTRUCTION_D(instruction)) { case 6: //movlp; case 5: //movwp; case 4: return 0; //movbp; case 0: //movbl; case 1: //movwl; case 2: //movll; case 3: //mov; case 7: //y_not; case 8: //swapb; case 11: //neg; case 12: //extub; case 13: //extuw; case 14: //extsb; case 15: //extsw; case 9: implies( destRB, srcRC ); //swapw; break; case 10: implies2( destRB, destSRT, srcRB && srcSRT ); //negc break; } break; case 7: implies( destRB, srcRB ); //addi; break; case 8: switch (INSTRUCTION_B(instruction)) { case 0: //movbs4; case 1: return 0; //movws4; case 4: //movbl4; case 5: implies( destR0, srcRC ); //movwl4; break; case 8: implies( destSRT, srcR0 ); //cmpim; break; case 9: //bt; case 11: //bf; case 13: //bts; case 15: return 0; //bfs; } break; case 9: implies( destRB, 1 ); //movwi; break; case 10: return delayCheck(PC+2); //bra; case 11: implies( destPR, 1 ); return delayCheck(PC+2); //bsr; case 12: switch(INSTRUCTION_B(instruction)) { case 0: //movbsg; case 1: //movwsg; case 2: //movlsg; case 3: return 0; //trapa; case 4: //movblg; case 5: //movwlg; case 6: implies( destR0, srcGBR ); //movllg break; case 7: implies( destR0, 1 ); //mova; break; case 8: implies( destSRT, srcR0 ); //tsti; break; case 9: //andi; case 10: //xori; case 11: implies( destR0, srcR0 ); //ori; break; case 12: implies( destSRT, srcGBR && srcR0 ); //tstm; break; case 13: //andm; case 14: //xorm; case 15: return 0;//orm; } break; case 13: //movli; case 14: implies( destRB, 1 ); //movi; break; } return 1; } #ifdef IDLE_DETECT_VERBOSE static u32 idleCheckCount = 0; static u32 sh2cycleCount = 0; static u32 sh2oldCycleCount = 0; static u32 oldCheckCount = 0; #define DROP_IDLE {\ idleCheckCount += cycles - context->cycles; \ context->cycles = cycles;} #define IDLE_VERBOSE_SH2_COUNT {\ sh2cycleCount += cycles; \ if ( sh2cycleCount-sh2oldCycleCount > 0x4ffffff ) { \ fprintf( stderr, "%lu idle instructions dropped / %lu sh2 instructions parsed : %g %%\n", \ idleCheckCount-oldCheckCount, sh2cycleCount-sh2oldCycleCount, \ (float)(idleCheckCount-oldCheckCount)/(sh2cycleCount-sh2oldCycleCount)*100 ); \ oldCheckCount = idleCheckCount; \ sh2oldCycleCount = sh2cycleCount; \ }} #else #define DROP_IDLE context->cycles = cycles; #define IDLE_VERBOSE_SH2_COUNT #endif void FASTCALL SH2idleCheck(SH2_struct *context, u32 cycles) { // try to find an idle loop while interpreting u8 isDelayed = 0; u32 loopEnd; u32 loopBegin; s32 disp; u32 cyclesCheckEnd; u32 PC1, PC2, PC3; IDLE_VERBOSE_SH2_COUNT; // run until conditional branching - delayed instruction excluded for (;;) { // Fetch Instruction context->instruction = ((fetchfunc *)context->fetchlist)[(context->regs.PC >> 20) & 0x0FF](context, context->regs.PC); if ( INSTRUCTION_A(context->instruction)==8 ) { switch( INSTRUCTION_B(context->instruction) ) { case 13: //SH2bts isDelayed = 1; case 9: //SH2bt if (context->regs.SR.part.T != 1) { context->regs.PC += 2; context->cycles++; return; } loopEnd = context->regs.PC; disp = (s32)(s8)context->instruction; loopBegin = context->regs.PC = context->regs.PC+(disp<<1)+4; context->cycles += 3; goto branching_reached; break; case 15: //SH2bfs isDelayed = 1; case 11: //SH2bf if (context->regs.SR.part.T == 1) { context->regs.PC += 2; context->cycles++; return; } loopEnd = context->regs.PC; disp = (s32)(s8)context->instruction; loopBegin = context->regs.PC = context->regs.PC+(disp<<1)+4; context->cycles += 3; goto branching_reached; break; default: ((opcodefunc *)context->opcodes)[context->instruction](context); } } else ((opcodefunc *)context->opcodes)[context->instruction](context); if ( context->cycles >= cycles ) return; } branching_reached: // if branching, execute (delayed included) until getting back to the conditional instruction bDet = bChg = 0; // initialize markers cyclesCheckEnd = context->cycles + MAX_CYCLE_CHECK; if ( isDelayed ) { context->instruction = ((fetchfunc *)context->fetchlist)[((loopEnd+2) >> 20) & 0x0FF](context, loopEnd+2); ((opcodefunc *)context->opcodes)[context->instruction](context); context->regs.PC -= 2; if ( !SH2idleCheckIterate(context,context->instruction,0) ) return; } // First pass while ( context->regs.PC != loopEnd ) { PC1 = context->regs.PC; context->instruction = ((fetchfunc *)context->fetchlist)[(PC1 >> 20) & 0x0FF](context, PC1); if ( !SH2idleCheckIterate(context,context->instruction,PC1) ) return; ((opcodefunc *)context->opcodes)[context->instruction](context); if ( context->cycles >= cyclesCheckEnd ) return; } // conditional jump PC2 = context->regs.PC; context->instruction = ((fetchfunc *)context->fetchlist)[(PC2 >> 20) & 0x0FF](context, PC2); ((opcodefunc *)context->opcodes)[context->instruction](context); if ( context->regs.PC != loopBegin ) return; // We are not in a single loop... forget it // Mark unchanged registers as deterministic registers bDet = ~bChg; bDet |= destCONST; // some values need to be constant. From now, changing them is forbidden. // Second pass if ( isDelayed ) if ( !SH2idleCheckIterate(context,((fetchfunc *)context->fetchlist)[((loopEnd+2) >> 20) & 0x0FF](context, loopEnd+2),0) ) return; while ( context->regs.PC != loopEnd ) { PC3 = context->regs.PC; context->instruction = ((fetchfunc *)context->fetchlist)[(PC3 >> 20) & 0x0FF](context, PC3); if ( !SH2idleCheckIterate(context,context->instruction,PC3) ) return; ((opcodefunc *)context->opcodes)[context->instruction](context); } context->instruction = ((fetchfunc *)context->fetchlist)[(PC2 >> 20) & 0x0FF](context, PC2); ((opcodefunc *)context->opcodes)[context->instruction](context); if ( context->regs.PC != loopBegin ) return; #ifdef IDLE_DETECT_VERBOSE { static u32 oldLoopBegin[2][2] = {{0,0},{0,0}}; if (( !~bDet )&&(loopBegin!=oldLoopBegin[context==MSH2][0])&&(loopBegin!=oldLoopBegin[context==MSH2][1])) { char lineBuf[64]; u32 offset,end; printf( "New %s idle loop at %X -- %X\n", (context==MSH2)?"master":"slave", (int)loopBegin, (int)loopEnd ); if ( loopEnd > loopBegin ) { offset = loopBegin; end = loopEnd; } else { offset = loopEnd; end = loopBegin; } for ( ; offset <= end ; offset+=2 ) { SH2Disasm(offset, MappedMemoryReadWord(offset), 0, lineBuf); printf( "%s\n", lineBuf ); } oldLoopBegin[context==MSH2][1] = oldLoopBegin[context==MSH2][0]; oldLoopBegin[context==MSH2][0] = loopBegin; } } #endif if ( !~bDet ) { DROP_IDLE; context->isIdle = 1; } } void FASTCALL SH2idleParse( SH2_struct *context, u32 cycles ) { // called when is in idle state : check whether we are still idle IDLE_VERBOSE_SH2_COUNT; for(;;) { u32 PC = context->regs.PC; context->instruction = ((fetchfunc *)context->fetchlist)[(PC >> 20) & 0x0FF](context, PC); if ( INSTRUCTION_A(context->instruction)==8 ) { switch( INSTRUCTION_B(context->instruction) ) { case 13: //SH2bts case 9: //SH2bt if ( !context->regs.SR.part.T ) context->isIdle = 0; else DROP_IDLE; ((opcodefunc *)context->opcodes)[context->instruction](context); return; case 15: //SH2bfs case 11: //SH2bf if ( context->regs.SR.part.T ) context->isIdle = 0; else DROP_IDLE; ((opcodefunc *)context->opcodes)[context->instruction](context); return; } } ((opcodefunc *)context->opcodes)[context->instruction](context); } } /* ------------------------------------------------------ */ /* Code markers */ /* typedef struct { u32 begin, end; u16 instruction; } idlemarker; idlemarker idleMark[1024]; int topMark = 0; void addMarker( u32 begin, u32 end ) { if ( topMark < 1024 ) { idleMark[topMark].instruction = MappedMemoryReadWord(begin); if ( (idleMark[topMark].instruction & 0xff0000ff) == OPCODE_HC ) return; idleMark[topMark].begin = begin; idleMark[topMark].end = end; idleMark[topMark].instruction = MappedMemoryReadWord(begin); MappedMemoryWriteWord( begin, OPCODE_HC | (topMark<<8) ); topMark++; } else printf( stderr, "Code Marker overflow !\n" ); } void markerExec( SH2_struct *sh, u16 nMark ) { opcodes[sh->instruction = idleMark[instruction]](sh); // execute the hidden instruction for{;;} { u32 PC = sh->regs.PC; sh->instruction = fetchlist[(PC >> 20) & 0x0FF](PC); if ( INSTRUCTION_A(context->instruction)==8 ) { switch( INSTRUCTION_B(context->instruction) ) { case 13: //SH2bts case 9: //SH2bt if ( sh->regs.SR.T ) cycles = 0xffffffff; return; case 15: //SH2bfs case 11: //SH2bf if ( ! sh->regs.SR.T ) cycles = 0xffffffff; return; } opcodes[context->instruction](context); } } */ yabause-0.9.15/src/config.h.in000644 001750 001750 00000000203 12755623101 020060 0ustar00guillaumeguillaume000000 000000 #cmakedefine HAVE_C68K 1 #cmakedefine HAVE_Q68 1 #cmakedefine SH2_DYNAREC 1 #cmakedefine HAVE_OPENSL 1 #cmakedefine HAVE_MUSASHI 1 yabause-0.9.15/src/japmodem.c000644 001750 001750 00000006426 12755623101 020012 0ustar00guillaumeguillaume000000 000000 /* Copyright 2013 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file japmodem.c \brief Japanese modem emulation functions. */ #include #include "cs2.h" #include "error.h" #include "japmodem.h" #include "netlink.h" #include "debug.h" #include "sh2core.h" #include "scu.h" JapModem *JapModemArea = NULL; u8 FASTCALL JapModemCs0ReadByte(SH2_struct *sh, u32 addr) { NETLINK_LOG("%08X Cs0 byte read. PC = %08X", addr, MSH2->regs.PC); if (addr & 0x1) return 0xA5; else return 0xFF; } u16 FASTCALL JapModemCs0ReadWord(SH2_struct *sh, u32 addr) { NETLINK_LOG("%08X Cs0 word read. PC = %08X", addr, MSH2->regs.PC); return 0xFFA5; } u32 FASTCALL JapModemCs0ReadLong(SH2_struct *sh, u32 addr) { NETLINK_LOG("%08X Cs0 long read. PC = %08X", addr, MSH2->regs.PC); return 0xFFA5FFA5; } u8 FASTCALL JapModemCs1ReadByte(SH2_struct *sh, u32 addr) { NETLINK_LOG("%08X Cs1 byte read. PC = %08X", addr, MSH2->regs.PC); return 0xFF; } u16 FASTCALL JapModemCs1ReadWord(SH2_struct *sh, u32 addr) { NETLINK_LOG("%08X Cs1 word read. PC = %08X", addr, MSH2->regs.PC); return 0xFFFF; } u32 FASTCALL JapModemCs1ReadLong(SH2_struct *sh, u32 addr) { NETLINK_LOG("%08X Cs1 long read. PC = %08X", addr, MSH2->regs.PC); return 0xFFFFFFFF; } void FASTCALL JapModemCs1WriteByte(SH2_struct *sh, u32 addr, u8 val) { NETLINK_LOG("%08X Cs1 byte write. PC = %08X", addr, MSH2->regs.PC); return; } void FASTCALL JapModemCs1WriteWord(SH2_struct *sh, u32 addr, u16 val) { NETLINK_LOG("%08X Cs1 word write. PC = %08X", addr, MSH2->regs.PC); return; } void FASTCALL JapModemCs1WriteLong(SH2_struct *sh, u32 addr, u32 val) { NETLINK_LOG("%08X Cs1 long write. PC = %08X", addr, MSH2->regs.PC); return; } u8 FASTCALL JapModemCs2ReadByte(SH2_struct *sh, u32 addr) { NETLINK_LOG("%08X Cs2 byte read. PC = %08X", addr, MSH2->regs.PC); return 0xFF; } void FASTCALL JapModemCs2WriteByte(SH2_struct *sh, u32 addr, u8 val) { NETLINK_LOG("%08X Cs2 byte write. PC = %08X", addr, MSH2->regs.PC); } int JapModemInit(const char *ip, const char *port) { if ((JapModemArea = malloc(sizeof(JapModem))) == NULL) { Cs2Area->carttype = CART_NONE; YabSetError(YAB_ERR_CANNOTINIT, (void *)"Japanese Modem"); return 0; } return NetlinkInit(ip, port); } void JapModemDeInit(void) { NetlinkDeInit(); } void JapModemExec(u32 timing) { NetlinkExec(timing); } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/core.h000644 001750 001750 00000017336 12755623101 017155 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005 Guillaume Duhamel Copyright 2005-2006 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef CORE_H #define CORE_H #include #include #ifndef ALIGNED #ifdef _MSC_VER #define ALIGNED(x) __declspec(align(x)) #else #define ALIGNED(x) __attribute__((aligned(x))) #endif #endif #ifndef STDCALL #ifdef _MSC_VER #define STDCALL __stdcall #else #define STDCALL #endif #endif #ifndef FASTCALL #ifdef __MINGW32__ #define FASTCALL __attribute__((fastcall)) #elif defined (__i386__) #define FASTCALL __attribute__((regparm(3))) #else #define FASTCALL #endif #endif /* When building multiple arches on OS X you must use the compiler- provided endian flags instead of the one provided by autoconf */ #if defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__) #undef WORDS_BIGENDIAN #ifdef __BIG_ENDIAN__ #define WORDS_BIGENDIAN #endif #endif #ifndef INLINE #ifdef _MSC_VER #define INLINE _inline #else #define INLINE inline #endif #endif #ifdef GEKKO /* Wii have both stdint.h and "yabause" definitions of fixed size types */ #include typedef unsigned long pointer; #else /* ! GEKKO */ #ifdef HAVE_STDINT_H #include typedef uint8_t u8; typedef int8_t s8; typedef uint16_t u16; typedef int16_t s16; typedef uint32_t u32; typedef int32_t s32; typedef uint64_t u64; typedef int64_t s64; typedef uintptr_t pointer; #else // !HAVE_STDINT_H typedef unsigned char u8; typedef unsigned short u16; typedef signed char s8; typedef signed short s16; #if defined(__LP64__) // Generic 64-bit typedef unsigned int u32; typedef unsigned long u64; typedef unsigned long pointer; typedef signed int s32; typedef signed long s64; #elif defined(_MSC_VER) typedef unsigned long u32; typedef unsigned __int64 u64; typedef unsigned long long u64; #ifdef _WIN64 typedef __int64 pointer; #else typedef unsigned long pointer; #endif typedef signed long s32; typedef __int64 s64; typedef signed long long s64; #else // 32-bit Linux GCC/MINGW/etc. typedef unsigned long u32; typedef unsigned long long u64; typedef unsigned long pointer; typedef signed long s32; typedef signed long long s64; #endif #endif // !HAVE_STDINT_H #endif // !GEKKO typedef struct { unsigned int size; unsigned int done; } IOCheck_struct; static INLINE void ywrite(IOCheck_struct * check, void * ptr, size_t size, size_t nmemb, FILE * stream) { check->done += (unsigned int)fwrite(ptr, size, nmemb, stream); check->size += (unsigned int)nmemb; } static INLINE void yread(IOCheck_struct * check, void * ptr, size_t size, size_t nmemb, FILE * stream) { check->done += (unsigned int)fread(ptr, size, nmemb, stream); check->size += (unsigned int)nmemb; } static INLINE int StateWriteHeader(FILE *fp, const char *name, int version) { IOCheck_struct check = { 0, 0 }; fprintf(fp, "%s", name); check.done = 0; check.size = 0; ywrite(&check, (void *)&version, sizeof(version), 1, fp); ywrite(&check, (void *)&version, sizeof(version), 1, fp); // place holder for size return (check.done == check.size) ? ftell(fp) : -1; } static INLINE int StateFinishHeader(FILE *fp, int offset) { IOCheck_struct check = { 0, 0 }; int size = 0; size = ftell(fp) - offset; fseek(fp, offset - 4, SEEK_SET); check.done = 0; check.size = 0; ywrite(&check, (void *)&size, sizeof(size), 1, fp); // write true size fseek(fp, 0, SEEK_END); return (check.done == check.size) ? (size + 12) : -1; } static INLINE int StateCheckRetrieveHeader(FILE *fp, const char *name, int *version, int *size) { char id[4]; size_t ret; if ((ret = fread((void *)id, 1, 4, fp)) != 4) return -1; if (strncmp(name, id, 4) != 0) return -2; if ((ret = fread((void *)version, 4, 1, fp)) != 1) return -1; if (fread((void *)size, 4, 1, fp) != 1) return -1; return 0; } ////////////////////////////////////////////////////////////////////////////// // Terrible, but I'm not sure how to do the equivalent in inline #ifdef HAVE_C99_VARIADIC_MACROS #define AddString(s, ...) \ { \ sprintf(s, __VA_ARGS__); \ s += strlen(s); \ } #else #define AddString(s, r...) \ { \ sprintf(s, ## r); \ s += strlen(s); \ } #endif ////////////////////////////////////////////////////////////////////////////// #ifdef HAVE_LIBMINI18N #include "mini18n.h" #else #ifndef _ #define _(a) (a) #endif #endif ////////////////////////////////////////////////////////////////////////////// /* Minimum/maximum values */ #undef MIN #undef MAX #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) ////////////////////////////////////////////////////////////////////////////// /* * BSWAP16(x) swaps two bytes in a 16-bit value (AABB -> BBAA) or adjacent * bytes in a 32-bit value (AABBCCDD -> BBAADDCC). * * BSWAP32(x) reverses four bytes in a 32-bit value (AABBCCDD -> DDCCBBAA). * * WSWAP32(x) swaps two 16-bit words in a 32-bit value (AABBCCDD -> CCDDAABB). * * Any of these can be left undefined if there is no platform-specific * optimization for them; the defaults below will then be used instead. */ #ifdef PSP # define BSWAP16(x) ((typeof(x)) __builtin_allegrex_wsbh((x))) # define BSWAP16L(x) BSWAP16(x) # define BSWAP32(x) ((typeof(x)) __builtin_allegrex_wsbw((x))) # define WSWAP32(x) ((typeof(x)) __builtin_allegrex_rotr((x), 16)) #endif #ifdef __GNUC__ #ifdef HAVE_BUILTIN_BSWAP16 # define BSWAP16(x) ((__builtin_bswap16((x) >> 16) << 16) | __builtin_bswap16((x))) # define BSWAP16L(x) (__builtin_bswap16((x))) #endif #ifdef HAVE_BUILTIN_BSWAP32 # define BSWAP32(x) (__builtin_bswap32((x))) #endif #endif #ifdef _MSC_VER # define BSWAP16(x) ((_byteswap_ushort((x) >> 16) << 16) | _byteswap_ushort((x))) # define BSWAP16L(x) (_byteswap_ushort((x))) # define BSWAP32(x) (_byteswap_ulong((x))) # define WSWAP32(x) (_lrotr((x), 16)) #endif /* Defaults: */ #ifndef BSWAP16 # define BSWAP16(x) (((u32)(x)>>8 & 0x00FF00FF) | ((u32)(x) & 0x00FF00FF) << 8) #endif #ifndef BSWAP16L # define BSWAP16L(x) (((u16)(x)>>8 & 0xFF) | ((u16)(x) & 0xFF) << 8) #endif #ifndef BSWAP32 # define BSWAP32(x) ((u32)(x)>>24 | ((u32)(x)>>8 & 0xFF00) | ((u32)(x) & 0xFF00)<<8 | (u32)(x)<<24) #endif #ifndef WSWAP32 # define WSWAP32(x) ((u32)(x)>>16 | (u32)(x)<<16) #endif ////////////////////////////////////////////////////////////////////////////// #ifdef __GNUC__ #define UNUSED __attribute ((unused)) #ifdef DEBUG #define USED_IF_DEBUG #else #define USED_IF_DEBUG __attribute ((unused)) #endif #ifdef SMPC_DEBUG #define USED_IF_SMPC_DEBUG #else #define USED_IF_SMPC_DEBUG __attribute ((unused)) #endif /* LIKELY(x) indicates that x is likely to be true (nonzero); * UNLIKELY(x) indicates that x is likely to be false (zero). * Use like: "if (UNLIKELY(a < b)) {...}" */ #define LIKELY(x) (__builtin_expect(!!(x), 1)) #define UNLIKELY(x) (__builtin_expect(!!(x), 0)) #else #define UNUSED #define USED_IF_DEBUG #define USED_IF_SMPC_DEBUG #define LIKELY(x) (x) #define UNLIKELY(x) (x) #endif #ifdef USE_16BPP typedef u16 pixel_t; #else typedef u32 pixel_t; #endif #ifdef _MSC_VER #define snprintf sprintf_s #endif #endif yabause-0.9.15/src/ygl.h000644 001750 001750 00000023663 12755623101 017020 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005 Guillaume Duhamel Copyright 2005-2006 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #if defined(HAVE_LIBGL) || defined(__ANDROID__) #if defined(__ANDROID__) #include #include #include #elif defined(_WIN32) #include #if defined(_USEGLEW_) #include #include #include "glext.h" #else #include #include "glext.h" extern PFNGLACTIVETEXTUREPROC glActiveTexture; #endif #elif defined(__APPLE__) #include #include #else // Linux? #if defined(_OGLES3_)||defined(_OGL3_) #define GL_GLEXT_PROTOTYPES 1 #define GLX_GLXEXT_PROTOTYPES 1 #include #include #else #include #endif #endif #include #include #ifndef YGL_H #define YGL_H #include "core.h" #include "threads.h" #include "vidshared.h" typedef struct { float vertices[8]; int w; int h; int flip; int priority; int dst; int uclipmode; int blendmode; s32 cor; s32 cog; s32 cob; int linescreen; } YglSprite; typedef struct { float x; float y; } YglCache; typedef struct { unsigned int * textdata; unsigned int w; } YglTexture; typedef struct { unsigned int currentX; unsigned int currentY; unsigned int yMax; unsigned int * texture; unsigned int width; unsigned int height; } YglTextureManager; extern YglTextureManager * YglTM; void YglTMInit(unsigned int, unsigned int); void YglTMDeInit(void); void YglTMReset(void); void YglTMAllocate(YglTexture *, unsigned int, unsigned int, unsigned int *, unsigned int *); enum { PG_NORMAL=1, PG_VDP1_NORMAL, PG_VFP1_GOURAUDSAHDING, PG_VFP1_STARTUSERCLIP, PG_VFP1_ENDUSERCLIP, PG_VFP1_HALFTRANS, PG_VFP1_GOURAUDSAHDING_HALFTRANS, PG_VDP2_ADDBLEND, PG_VDP2_DRAWFRAMEBUFF, PG_VDP2_STARTWINDOW, PG_VDP2_ENDWINDOW, PG_WINDOW, PG_LINECOLOR_INSERT, PG_VDP2_DRAWFRAMEBUFF_LINECOLOR, PG_VDP2_DRAWFRAMEBUFF_ADDCOLOR, PG_MAX, }; typedef struct { int prgid; GLuint prg; GLuint vertexBuffer; float * quads; float * textcoords; float * vertexAttribute; int currentQuad; int maxQuad; int vaid; char uClipMode; short ux1,uy1,ux2,uy2; int blendmode; int bwin0,logwin0,bwin1,logwin1,winmode; GLuint vertexp; GLuint texcoordp; GLuint mtxModelView; GLuint mtxTexture; GLuint color_offset; GLuint tex0; GLuint tex1; float color_offset_val[4]; int (*setupUniform)(void *); int (*cleanupUniform)(void *); } YglProgram; typedef struct { int prgcount; int prgcurrent; int uclipcurrent; short ux1,uy1,ux2,uy2; int blendmode; YglProgram * prg; } YglLevel; typedef struct { GLfloat m[4][4]; } YglMatrix; typedef struct { GLuint texture; GLuint pixelBufferID; int st; char message[512]; int msglength; unsigned int width; unsigned int height; unsigned int depth; float clear_r; float clear_g; float clear_b; // VDP1 Info int vdp1_maxpri; int vdp1_minpri; // VDP1 Framebuffer int rwidth; int rheight; int drawframe; int readframe; GLuint rboid_depth; GLuint rboid_stencil; GLuint vdp1fbo; GLuint vdp1FrameBuff[2]; GLuint smallfbo; GLuint smallfbotex; GLuint vdp1pixelBufferID; void * pFrameBuffer; // Message Layer int msgwidth; int msgheight; GLuint msgtexture; u32 * messagebuf; int bUpdateWindow; int win0v[512*4]; int win0_vertexcnt; int win1v[512*4]; int win1_vertexcnt; YglMatrix mtxModelView; YglMatrix mtxTexture; YglProgram windowpg; YglProgram renderfb; YglLevel * levels; u32 lincolor_tex; u32 linecolor_pbo; u32 * lincolor_buf; } Ygl; extern Ygl * _Ygl; int YglGLInit(int, int); int YglInit(int, int, unsigned int); void YglDeInit(void); float * YglQuad(YglSprite *, YglTexture *,YglCache * c); void YglQuadOffset(YglSprite * input, YglTexture * output, YglCache * c, int cx, int cy, float sx, float sy); void YglCachedQuadOffset(YglSprite * input, YglCache * cache, int cx, int cy, float sx, float sy); void YglCachedQuad(YglSprite *, YglCache *); void YglRender(void); void YglReset(void); void YglShowTexture(void); void YglChangeResolution(int, int); void YglCacheQuadGrowShading(YglSprite * input, float * colors, YglCache * cache); int YglQuadGrowShading(YglSprite * input, YglTexture * output, float * colors,YglCache * c); void YglSetClearColor(float r, float g, float b); void YglStartWindow( vdp2draw_struct * info, int win0, int logwin0, int win1, int logwin1, int mode ); void YglEndWindow( vdp2draw_struct * info ); void YglCacheInit(void); void YglCacheDeInit(void); int YglIsCached(u32,YglCache *); void YglCacheAdd(u32,YglCache *); void YglCacheReset(void); // 0.. no belnd, 1.. Alpha, 2.. Add int YglSetLevelBlendmode( int pri, int mode ); void Ygl_uniformVDP2DrawFramebuffer_linecolor(void * p, float from, float to, float * offsetcol); int Ygl_uniformVDP2DrawFramebuffer_addcolor(void * p, float from, float to, float * offsetcol); void Ygl_uniformVDP2DrawFramebuffer( void * p,float from, float to , float * offsetcol ); void YglNeedToUpdateWindow(); void YglScalef(YglMatrix *result, GLfloat sx, GLfloat sy, GLfloat sz); void YglTranslatef(YglMatrix *result, GLfloat tx, GLfloat ty, GLfloat tz); void YglRotatef(YglMatrix *result, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); void YglFrustum(YglMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ); void YglPerspective(YglMatrix *result, float fovy, float aspect, float nearZ, float farZ); void YglOrtho(YglMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ); void YglLoadIdentity(YglMatrix *result); void YglMatrixMultiply(YglMatrix *result, YglMatrix *srcA, YglMatrix *srcB); int YglInitVertexBuffer( int initsize ); void YglDeleteVertexBuffer(); int YglUnMapVertexBuffer(); int YglMapVertexBuffer(); int YglUserDirectVertexBuffer(); int YglUserVertexBuffer(); int YglGetVertexBuffer( int size, void ** vpos, void **tcpos, void **vapos ); int YglExpandVertexBuffer( int addsize, void ** vpos, void **tcpos, void **vapos ); intptr_t YglGetOffset( void* address ); int YglBlitFramebuffer(u32 srcTexture, u32 targetFbo, float w, float h); void YglRenderVDP1(void); u32 * YglGetLineColorPointer(); void YglSetLineColor(u32 * pbuf, int size); int Ygl_uniformWindow(void * p ); int YglProgramInit(); int YglProgramChange( YglLevel * level, int prgid ); #if !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_USEGLEW_) && !defined(_OGLES3_) extern GLuint (STDCALL *glCreateProgram)(void); extern GLuint (STDCALL *glCreateShader)(GLenum); extern void (STDCALL *glShaderSource)(GLuint,GLsizei,const GLchar **,const GLint *); extern void (STDCALL *glCompileShader)(GLuint); extern void (STDCALL *glAttachShader)(GLuint,GLuint); extern void (STDCALL *glLinkProgram)(GLuint); extern void (STDCALL *glUseProgram)(GLuint); extern GLint (STDCALL *glGetUniformLocation)(GLuint,const GLchar *); extern void (STDCALL *glUniform1i)(GLint,GLint); extern void (STDCALL *glGetShaderInfoLog)(GLuint,GLsizei,GLsizei *,GLchar *); extern void (STDCALL *glVertexAttribPointer)(GLuint index,GLint size, GLenum type, GLboolean normalized, GLsizei stride,const void *pointer); extern void (STDCALL *glBindAttribLocation)( GLuint program, GLuint index, const GLchar * name); extern void (STDCALL *glGetProgramiv)( GLuint program, GLenum pname, GLint * params); extern void (STDCALL *glGetShaderiv)(GLuint shader,GLenum pname,GLint * params); extern GLint (STDCALL *glGetAttribLocation)(GLuint program,const GLchar * name); extern void (STDCALL *glEnableVertexAttribArray)(GLuint index); extern void (STDCALL *glDisableVertexAttribArray)(GLuint index); //GL_ARB_framebuffer_object extern PFNGLISRENDERBUFFERPROC glIsRenderbuffer; extern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer; extern PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers; extern PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers; extern PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage; extern PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv; extern PFNGLISFRAMEBUFFERPROC glIsFramebuffer; extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; extern PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers; extern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; extern PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus; extern PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D; extern PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D; extern PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D; extern PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer; extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv; extern PFNGLGENERATEMIPMAPPROC glGenerateMipmap; extern PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer; extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample; extern PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer; extern PFNGLUNIFORM4FPROC glUniform4f; extern PFNGLUNIFORM1FPROC glUniform1f; extern PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv; #endif // !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_USEGLEW_) #endif // YGL_H #endif // defined(HAVE_LIBGL) || defined(__ANDROID__) yabause-0.9.15/src/m68kc68k.c000644 001750 001750 00000016101 12755623101 017466 0ustar00guillaumeguillaume000000 000000 /* Copyright 2007 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file m68kc68k.c \brief C68K 68000 interface. */ #include "m68kc68k.h" #include "c68k/c68k.h" #include "memory.h" #include "yabause.h" /** * PROFILE_68K: Perform simple profiling of the 68000 emulation, reporting * the average time per 68000 clock cycle. (Realtime execution would be * around 88.5 nsec/cycle.) */ // #define PROFILE_68K static u8 *SoundDummy=NULL; static int M68KC68KInit(void) { int i; // Setup a 64k buffer filled with invalid 68k instructions to serve // as a default map if ((SoundDummy = T2MemoryInit(0x10000)) != NULL) memset(SoundDummy, 0xFF, 0x10000); C68k_Init(&C68K, NULL); // not sure if I need the int callback or not for (i = 0x10; i < 0x100; i++) M68K->SetFetch(i << 16, (i << 16) + 0xFFFF, (pointer)SoundDummy); return 0; } static void M68KC68KDeInit(void) { if (SoundDummy) T2MemoryDeInit(SoundDummy); SoundDummy = NULL; } static void M68KC68KReset(void) { C68k_Reset(&C68K); } static s32 FASTCALL M68KC68KExec(s32 cycle) { #ifdef PROFILE_68K static u32 tot_cycles = 0, tot_usec = 0, tot_ticks = 0, last_report = 0; u32 start, end; start = (u32) YabauseGetTicks(); int retval = C68k_Exec(&C68K, cycle); end = (u32) YabauseGetTicks(); tot_cycles += cycle; tot_ticks += end - start; if (tot_cycles/1000000 > last_report) { tot_usec += (u64)tot_ticks * 1000000 / yabsys.tickfreq; tot_ticks = 0; fprintf(stderr, "%ld cycles in %.3f sec = %.3f nsec/cycle\n", (long)tot_cycles, (double)tot_usec/1000000, ((double)tot_usec / (double)tot_cycles) * 1000); last_report = tot_cycles/1000000; } return retval; #else return C68k_Exec(&C68K, cycle); #endif } static void M68KC68KSync(void) { } static u32 M68KC68KGetDReg(u32 num) { return C68k_Get_DReg(&C68K, num); } static u32 M68KC68KGetAReg(u32 num) { return C68k_Get_AReg(&C68K, num); } static u32 M68KC68KGetPC(void) { return C68k_Get_PC(&C68K); } static u32 M68KC68KGetSR(void) { return C68k_Get_SR(&C68K); } static u32 M68KC68KGetUSP(void) { return C68k_Get_USP(&C68K); } static u32 M68KC68KGetMSP(void) { return C68k_Get_MSP(&C68K); } static void M68KC68KSetDReg(u32 num, u32 val) { C68k_Set_DReg(&C68K, num, val); } static void M68KC68KSetAReg(u32 num, u32 val) { C68k_Set_AReg(&C68K, num, val); } static void M68KC68KSetPC(u32 val) { C68k_Set_PC(&C68K, val); } static void M68KC68KSetSR(u32 val) { C68k_Set_SR(&C68K, val); } static void M68KC68KSetUSP(u32 val) { C68k_Set_USP(&C68K, val); } static void M68KC68KSetMSP(u32 val) { C68k_Set_MSP(&C68K, val); } static void M68KC68KSetFetch(u32 low_adr, u32 high_adr, pointer fetch_adr) { C68k_Set_Fetch(&C68K, low_adr, high_adr, fetch_adr); } static void FASTCALL M68KC68KSetIRQ(s32 level) { C68k_Set_IRQ(&C68K, level); } static void FASTCALL M68KC68KWriteNotify(u32 address, u32 size) { /* nothing to do */ } static void M68KC68KSetReadB(M68K_READ *Func) { C68k_Set_ReadB(&C68K, Func); } static void M68KC68KSetReadW(M68K_READ *Func) { C68k_Set_ReadW(&C68K, Func); } static void M68KC68KSetWriteB(M68K_WRITE *Func) { C68k_Set_WriteB(&C68K, Func); } static void M68KC68KSetWriteW(M68K_WRITE *Func) { C68k_Set_WriteW(&C68K, Func); } static void C68k_Save_State(c68k_struc *mcpu, FILE * fp) { IOCheck_struct check = { 0, 0 }; int i = 0; u32 pc = 0; for (i = 0; i < 8; i++) ywrite(&check, (void *)&mcpu->D[i], sizeof(u32), 1, fp); for (i = 0; i < 8; i++) ywrite(&check, (void *)&mcpu->A[i], sizeof(u32), 1, fp); ywrite(&check, (void *)&mcpu->flag_C, sizeof(u32), 1, fp); ywrite(&check, (void *)&mcpu->flag_V, sizeof(u32), 1, fp); ywrite(&check, (void *)&mcpu->flag_notZ, sizeof(u32), 1, fp); ywrite(&check, (void *)&mcpu->flag_N, sizeof(u32), 1, fp); ywrite(&check, (void *)&mcpu->flag_X, sizeof(u32), 1, fp); ywrite(&check, (void *)&mcpu->flag_I, sizeof(u32), 1, fp); ywrite(&check, (void *)&mcpu->flag_S, sizeof(u32), 1, fp); ywrite(&check, (void *)&mcpu->USP, sizeof(u32), 1, fp); pc = C68k_Get_PC(&C68K); ywrite(&check, (void *)&pc, sizeof(u32), 1, fp); ywrite(&check, (void *)&mcpu->Status, sizeof(u32), 1, fp); ywrite(&check, (void *)&mcpu->IRQLine, sizeof(s32), 1, fp); ywrite(&check, (void *)&mcpu->CycleToDo, sizeof(s32), 1, fp); ywrite(&check, (void *)&mcpu->CycleIO, sizeof(s32), 1, fp); ywrite(&check, (void *)&mcpu->CycleSup, sizeof(s32), 1, fp); ywrite(&check, (void *)&mcpu->dirty1, sizeof(u32), 1, fp); } static void M68KC68KSaveState(FILE *fp) { C68k_Save_State(&C68K, fp); } static void C68k_Load_State(c68k_struc *mcpu, FILE * fp) { IOCheck_struct check = { 0, 0 }; int i = 0; u32 pc = 0; for (i = 0; i < 8; i++) yread(&check, (void *)&mcpu->D[i], sizeof(u32), 1, fp); for (i = 0; i < 8; i++) yread(&check, (void *)&mcpu->A[i], sizeof(u32), 1, fp); yread(&check, (void *)&mcpu->flag_C, sizeof(u32), 1, fp); yread(&check, (void *)&mcpu->flag_V, sizeof(u32), 1, fp); yread(&check, (void *)&mcpu->flag_notZ, sizeof(u32), 1, fp); yread(&check, (void *)&mcpu->flag_N, sizeof(u32), 1, fp); yread(&check, (void *)&mcpu->flag_X, sizeof(u32), 1, fp); yread(&check, (void *)&mcpu->flag_I, sizeof(u32), 1, fp); yread(&check, (void *)&mcpu->flag_S, sizeof(u32), 1, fp); yread(&check, (void *)&mcpu->USP, sizeof(u32), 1, fp); yread(&check, (void *)&pc, sizeof(u32), 1, fp); C68k_Set_PC(&C68K, pc); yread(&check, (void *)&mcpu->Status, sizeof(u32), 1, fp); yread(&check, (void *)&mcpu->IRQLine, sizeof(s32), 1, fp); yread(&check, (void *)&mcpu->CycleToDo, sizeof(s32), 1, fp); yread(&check, (void *)&mcpu->CycleIO, sizeof(s32), 1, fp); yread(&check, (void *)&mcpu->CycleSup, sizeof(s32), 1, fp); yread(&check, (void *)&mcpu->dirty1, sizeof(u32), 1, fp); } static void M68KC68KLoadState(FILE *fp) { C68k_Load_State(&C68K, fp); } M68K_struct M68KC68K = { 1, "C68k Interface", M68KC68KInit, M68KC68KDeInit, M68KC68KReset, M68KC68KExec, M68KC68KSync, M68KC68KGetDReg, M68KC68KGetAReg, M68KC68KGetPC, M68KC68KGetSR, M68KC68KGetUSP, M68KC68KGetMSP, M68KC68KSetDReg, M68KC68KSetAReg, M68KC68KSetPC, M68KC68KSetSR, M68KC68KSetUSP, M68KC68KSetMSP, M68KC68KSetFetch, M68KC68KSetIRQ, M68KC68KWriteNotify, M68KC68KSetReadB, M68KC68KSetReadW, M68KC68KSetWriteB, M68KC68KSetWriteW, M68KC68KSaveState, M68KC68KLoadState }; yabause-0.9.15/src/sndal.h000644 001750 001750 00000001602 12755623101 017313 0ustar00guillaumeguillaume000000 000000 /* Copyright 2009 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SNDAL_H #define SNDAL_H #define SNDCORE_AL 4 extern SoundInterface_struct SNDAL; #endif /* !SNDAL_H */ yabause-0.9.15/src/scu.h000644 001750 001750 00000015352 12757373537 017034 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2005 Guillaume Duhamel Copyright 2005-2006 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SCU_H #define SCU_H #include "core.h" #include "memory.h" typedef struct { u32 addr; } scucodebreakpoint_struct; #define MAX_BREAKPOINTS 10 typedef struct { u8 vector; u8 level; u16 mask; u32 statusbit; } scuinterrupt_struct; typedef struct { /* DMA registers */ u32 D0R; u32 D0W; u32 D0C; u32 D0AD; u32 D0EN; u32 D0MD; u32 D1R; u32 D1W; u32 D1C; u32 D1AD; u32 D1EN; u32 D1MD; u32 D2R; u32 D2W; u32 D2C; u32 D2AD; u32 D2EN; u32 D2MD; u32 DSTP; u32 DSTA; /* DSP registers */ u32 PPAF; u32 PPD; u32 PDA; u32 PDD; /* Timer registers */ u32 T0C; u32 T1S; u32 T1MD; /* Interrupt registers */ u32 IMS; u32 IST; /* A-bus registers */ u32 AIACK; u32 ASR0; u32 ASR1; u32 AREF; /* SCU registers */ u32 RSEL; u32 VER; /* internal variables */ u32 timer0; u32 timer1; scuinterrupt_struct interrupts[30]; u32 NumberOfInterrupts; } Scu; extern Scu * ScuRegs; typedef struct { scucodebreakpoint_struct codebreakpoint[MAX_BREAKPOINTS]; int numcodebreakpoints; void (*BreakpointCallBack)(u32); u8 inbreakpoint; } scubp_struct; typedef struct { u32 ProgramRam[256]; u32 MD[4][64]; #ifdef WORDS_BIGENDIAN union { struct { u32 unused1:5; u32 PR:1; // Pause cancel flag u32 EP:1; // Temporary stop execution flag u32 unused2:1; u32 T0:1; // D0 bus use DMA execute flag u32 S:1; // Sine flag u32 Z:1; // Zero flag u32 C:1; // Carry flag u32 V:1; // Overflow flag u32 E:1; // Program end interrupt flag u32 ES:1; // Program step execute control bit u32 EX:1; // Program execute control bit u32 LE:1; // Program counter load enable bit u32 unused3:7; u32 P:8; // Program Ram Address } part; u32 all; } ProgControlPort; #else union { struct { u32 P:8; // Program Ram Address u32 unused3:7; u32 LE:1; // Program counter load enable bit u32 EX:1; // Program execute control bit u32 ES:1; // Program step execute control bit u32 E:1; // Program end interrupt flag u32 V:1; // Overflow flag u32 C:1; // Carry flag u32 Z:1; // Zero flag u32 S:1; // Sine flag u32 T0:1; // D0 bus use DMA execute flag u32 unused2:1; u32 EP:1; // Temporary stop execution flag u32 PR:1; // Pause cancel flag u32 unused1:5; } part; u32 all; } ProgControlPort; #endif u8 PC; u8 TOP; u16 LOP; s32 jmpaddr; int delayed; u8 DataRamPage; u8 DataRamReadAddress; u8 CT[4]; s32 RX; s32 RY; u32 RA0; u32 WA0; #ifdef WORDS_BIGENDIAN union { struct { s64 unused:16; s64 H:16; s64 L:32; } part; s64 all; } AC; union { struct { s64 unused:16; s64 H:16; s64 L:32; } part; s64 all; } P; union { struct { s64 unused:16; s64 H:16; s64 L:32; } part; s64 all; } ALU; union { struct { s64 unused:16; s64 H:16; s64 L:32; } part; s64 all; } MUL; #else union { struct { s64 L:32; s64 H:16; s64 unused:16; } part; s64 all; } AC; union { struct { s64 L:32; s64 H:16; s64 unused:16; } part; s64 all; } P; union { struct { s64 L:32; s64 H:16; s64 unused:16; } part; s64 all; } ALU; union { struct { s64 L:32; s64 H:16; s64 unused:16; } part; s64 all; } MUL; #endif } scudspregs_struct; typedef struct { int mode; u32 ReadAddress; u32 WriteAddress; u32 TransferNumber; u32 AddValue; u32 ModeAddressUpdate; } scudmainfo_struct; int ScuInit(void); void ScuDeInit(void); void ScuReset(void); void ScuExec(u32 timing); u8 FASTCALL ScuReadByte(u32); u16 FASTCALL ScuReadWord(u32); u32 FASTCALL ScuReadLong(u32); void FASTCALL ScuWriteByte(u32, u8); void FASTCALL ScuWriteWord( u32, u16); void FASTCALL ScuWriteLong( u32, u32); u8 FASTCALL Sh2ScuReadByte(SH2_struct *, u32); u16 FASTCALL Sh2ScuReadWord(SH2_struct *, u32); u32 FASTCALL Sh2ScuReadLong(SH2_struct *, u32); void FASTCALL Sh2ScuWriteByte(SH2_struct *, u32, u8); void FASTCALL Sh2ScuWriteWord(SH2_struct *, u32, u16); void FASTCALL Sh2ScuWriteLong(SH2_struct *, u32, u32); void ScuSendVBlankIN(void); void ScuSendVBlankOUT(void); void ScuSendHBlankIN(void); void ScuSendTimer0(void); void ScuSendTimer1(void); void ScuSendDSPEnd(void); void ScuSendSoundRequest(void); void ScuSendSystemManager(void); void ScuSendPadInterrupt(void); void ScuSendLevel2DMAEnd(void); void ScuSendLevel1DMAEnd(void); void ScuSendLevel0DMAEnd(void); void ScuSendDMAIllegal(void); void ScuSendDrawEnd(void); void ScuSendExternalInterrupt00(void); void ScuSendExternalInterrupt01(void); void ScuSendExternalInterrupt02(void); void ScuSendExternalInterrupt03(void); void ScuSendExternalInterrupt04(void); void ScuSendExternalInterrupt05(void); void ScuSendExternalInterrupt06(void); void ScuSendExternalInterrupt07(void); void ScuSendExternalInterrupt08(void); void ScuSendExternalInterrupt09(void); void ScuSendExternalInterrupt10(void); void ScuSendExternalInterrupt11(void); void ScuSendExternalInterrupt12(void); void ScuSendExternalInterrupt13(void); void ScuSendExternalInterrupt14(void); void ScuSendExternalInterrupt15(void); void ScuDspDisasm(u8 addr, char *outstring); void ScuDspStep(void); int ScuDspSaveProgram(const char *filename); int ScuDspSaveMD(const char *filename, int num); void ScuDspGetRegisters(scudspregs_struct *regs); void ScuDspSetRegisters(scudspregs_struct *regs); void ScuDspSetBreakpointCallBack(void (*func)(u32)); int ScuDspAddCodeBreakpoint(u32 addr); int ScuDspDelCodeBreakpoint(u32 addr); scucodebreakpoint_struct *ScuDspGetBreakpointList(void); void ScuDspClearCodeBreakpoints(void); int ScuSaveState(FILE *fp); int ScuLoadState(FILE *fp, int version, int size); #endif yabause-0.9.15/src/thr-windows.c000644 001750 001750 00000007060 12755623101 020476 0ustar00guillaumeguillaume000000 000000 /* src/thr-windows.c: Windows thread functions Copyright 2013 Theo Berkau. Based on code by Andrew Church and Lawrence Sebald. This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file thr-windows.c \brief Windows port's threading functions */ #include #include "core.h" #include "threads.h" struct thd_s { int running; HANDLE thd; void (*func)(void *); void *arg; CRITICAL_SECTION mutex; HANDLE cond; }; static struct thd_s thread_handle[YAB_NUM_THREADS]; static int hnd_key; static int hnd_key_once=FALSE; ////////////////////////////////////////////////////////////////////////////// static DWORD wrapper(void *hnd) { struct thd_s *hnds = (struct thd_s *)hnd; EnterCriticalSection(&hnds->mutex); /* Set the handle for the thread, and call the actual thread function. */ TlsSetValue(hnd_key, hnd); hnds->func(hnds->arg); LeaveCriticalSection(&hnds->mutex); return 0; } int YabThreadStart(unsigned int id, void (*func)(void *), void *arg) { if (!hnd_key_once) { hnd_key=TlsAlloc(); hnd_key_once = 1; } if (thread_handle[id].running) { fprintf(stderr, "YabThreadStart: thread %u is already started!\n", id); return -1; } // Create CS and condition variable for thread InitializeCriticalSection(&thread_handle[id].mutex); if ((thread_handle[id].cond = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) { perror("CreateEvent"); return -1; } thread_handle[id].func = func; thread_handle[id].arg = arg; if ((thread_handle[id].thd = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)wrapper, &thread_handle[id], 0, NULL)) == NULL) { perror("CreateThread"); return -1; } thread_handle[id].running = 1; return 0; } void YabThreadWait(unsigned int id) { if (!thread_handle[id].thd) return; // Thread wasn't running in the first place WaitForSingleObject(thread_handle[id].thd,INFINITE); CloseHandle(thread_handle[id].thd); thread_handle[id].thd = NULL; thread_handle[id].running = 0; if (thread_handle[id].cond) CloseHandle(thread_handle[id].cond); } void YabThreadYield(void) { SwitchToThread(); } void YabThreadSleep(void) { struct thd_s *thd = (struct thd_s *)TlsGetValue(hnd_key); WaitForSingleObject(thd->cond,INFINITE); } void YabThreadRemoteSleep(unsigned int id) { if (!thread_handle[id].thd) return; // Thread wasn't running in the first place WaitForSingleObject(thread_handle[id].cond,INFINITE); } void YabThreadWake(unsigned int id) { if (!thread_handle[id].thd) return; // Thread wasn't running in the first place SetEvent(thread_handle[id].cond); } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/aosdk/000755 001750 001750 00000000000 12757373644 017163 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/aosdk/corlett.c000644 001750 001750 00000023535 12755623101 020773 0ustar00guillaumeguillaume000000 000000 /* Audio Overload SDK Copyright (c) 2007-2008, R. Belmont and Richard Bannister. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the names of R. Belmont and Richard Bannister nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // corlett.c // Decodes file format designed by Neill Corlett (PSF, QSF, ...) /* - First 3 bytes: ASCII signature: "PSF" (case sensitive) - Next 1 byte: Version byte The version byte is used to determine the type of PSF file. It does NOT affect the basic structure of the file in any way. Currently accepted version bytes are: 0x01: Playstation (PSF1) 0x02: Playstation 2 (PSF2) 0x11: Saturn (SSF) [TENTATIVE] 0x12: Dreamcast (DSF) [TENTATIVE] 0x21: Nintendo 64 (USF) [RESERVED] 0x41: Capcom QSound (QSF) - Next 4 bytes: Size of reserved area (R), little-endian unsigned long - Next 4 bytes: Compressed program length (N), little-endian unsigned long This is the length of the program data _after_ compression. - Next 4 bytes: Compressed program CRC-32, little-endian unsigned long This is the CRC-32 of the program data _after_ compression. Filling in this value is mandatory, as a PSF file may be regarded as corrupt if it does not match. - Next R bytes: Reserved area. May be empty if R is 0 bytes. - Next N bytes: Compressed program, in zlib compress() format. May be empty if N is 0 bytes. The following data is optional and may be omitted: - Next 5 bytes: ASCII signature: "[TAG]" (case sensitive) If these 5 bytes do not match, then the remainder of the file may be regarded as invalid and discarded. - Remainder of file: Uncompressed ASCII tag data. */ #include #include #include #include "ao.h" #include "corlett.h" #include #include #define DECOMP_MAX_SIZE ((32 * 1024 * 1024) + 12) int corlett_decode(u8 *input, u32 input_len, u8 **output, u64 *size, corlett_t **c) { u32 *buf; u32 res_area, comp_crc, actual_crc; u8 *decomp_dat, *tag_dec; uLongf decomp_length, comp_length; // 32-bit pointer to data buf = (u32 *)input; // Check we have a PSF format file. if ((input[0] != 'P') || (input[1] != 'S') || (input[2] != 'F')) { return AO_FAIL; } // Get our values res_area = LE32(buf[1]); comp_length = LE32(buf[2]); comp_crc = LE32(buf[3]); if (comp_length > 0) { // Check length if (input_len < comp_length + 16) return AO_FAIL; // Check CRC is correct actual_crc = crc32(0, (unsigned char *)&buf[4+(res_area/4)], comp_length); if (actual_crc != comp_crc) return AO_FAIL; // Decompress data if any decomp_dat = malloc(DECOMP_MAX_SIZE); decomp_length = DECOMP_MAX_SIZE; if (uncompress(decomp_dat, &decomp_length, (unsigned char *)&buf[4+(res_area/4)], comp_length) != Z_OK) { free(decomp_dat); return AO_FAIL; } // Resize memory buffer to what we actually need decomp_dat = realloc(decomp_dat, (size_t)decomp_length + 1); } else { decomp_dat = NULL; decomp_length = 0; } // Make structure *c = malloc(sizeof(corlett_t)); if (!(*c)) { free(decomp_dat); return AO_FAIL; } memset(*c, 0, sizeof(corlett_t)); strcpy((*c)->inf_title, "n/a"); strcpy((*c)->inf_copy, "n/a"); strcpy((*c)->inf_artist, "n/a"); strcpy((*c)->inf_game, "n/a"); strcpy((*c)->inf_year, "n/a"); strcpy((*c)->inf_length, "n/a"); strcpy((*c)->inf_fade, "n/a"); // set reserved section pointer (*c)->res_section = &buf[4]; (*c)->res_size = res_area; // Return it *output = decomp_dat; *size = decomp_length; // Next check for tags input_len -= (comp_length + 16 + res_area); if (input_len < 5) return AO_SUCCESS; // printf("\n\nNew corlett: input len %d\n", input_len); tag_dec = input + (comp_length + res_area + 16); if ((tag_dec[0] == '[') && (tag_dec[1] == 'T') && (tag_dec[2] == 'A') && (tag_dec[3] == 'G') && (tag_dec[4] == ']')) { int tag, l, num_tags, data; // Tags found! tag_dec += 5; input_len -= 5; tag = 0; data = 0;//false num_tags = 0; l = 0; while (input_len && (num_tags < MAX_UNKNOWN_TAGS)) { if (data) { if ((*tag_dec == 0xA) || (*tag_dec == 0x00)) { (*c)->tag_data[num_tags][l] = 0; data = 0;//false num_tags++; l = 0; } else { (*c)->tag_data[num_tags][l++] = *tag_dec; } } else { if (*tag_dec == '=') { (*c)->tag_name[num_tags][l] = 0; l = 0; data = 1;//true } else { (*c)->tag_name[num_tags][l++] = *tag_dec; } } tag_dec++; input_len--; } // Now, process that tag array into what we expect for (num_tags = 0; num_tags < MAX_UNKNOWN_TAGS; num_tags++) { // See if tag belongs in one of the special fields we have if (!strcasecmp((*c)->tag_name[num_tags], "_lib")) { strcpy((*c)->lib, (*c)->tag_data[num_tags]); (*c)->tag_data[num_tags][0] = 0; (*c)->tag_name[num_tags][0] = 0; } else if (!strncmp((*c)->tag_name[num_tags], "_lib2", 5)) { strcpy((*c)->libaux[0], (*c)->tag_data[num_tags]); (*c)->tag_data[num_tags][0] = 0; (*c)->tag_name[num_tags][0] = 0; } else if (!strncmp((*c)->tag_name[num_tags], "_lib3", 5)) { strcpy((*c)->libaux[1], (*c)->tag_data[num_tags]); (*c)->tag_data[num_tags][0] = 0; (*c)->tag_name[num_tags][0] = 0; } else if (!strncmp((*c)->tag_name[num_tags], "_lib4", 5)) { strcpy((*c)->libaux[2], (*c)->tag_data[num_tags]); (*c)->tag_data[num_tags][0] = 0; (*c)->tag_name[num_tags][0] = 0; } else if (!strncmp((*c)->tag_name[num_tags], "_lib5", 5)) { strcpy((*c)->libaux[3], (*c)->tag_data[num_tags]); (*c)->tag_data[num_tags][0] = 0; (*c)->tag_name[num_tags][0] = 0; } else if (!strncmp((*c)->tag_name[num_tags], "_lib6", 5)) { strcpy((*c)->libaux[4], (*c)->tag_data[num_tags]); (*c)->tag_data[num_tags][0] = 0; (*c)->tag_name[num_tags][0] = 0; } else if (!strncmp((*c)->tag_name[num_tags], "_lib7", 5)) { strcpy((*c)->libaux[5], (*c)->tag_data[num_tags]); (*c)->tag_data[num_tags][0] = 0; (*c)->tag_name[num_tags][0] = 0; } else if (!strncmp((*c)->tag_name[num_tags], "_lib8", 5)) { strcpy((*c)->libaux[6], (*c)->tag_data[num_tags]); (*c)->tag_data[num_tags][0] = 0; (*c)->tag_name[num_tags][0] = 0; } else if (!strncmp((*c)->tag_name[num_tags], "_lib9", 5)) { strcpy((*c)->libaux[7], (*c)->tag_data[num_tags]); (*c)->tag_data[num_tags][0] = 0; (*c)->tag_name[num_tags][0] = 0; } else if (!strncmp((*c)->tag_name[num_tags], "_refresh", 8)) { strcpy((*c)->inf_refresh, (*c)->tag_data[num_tags]); (*c)->tag_data[num_tags][0] = 0; (*c)->tag_name[num_tags][0] = 0; } else if (!strncmp((*c)->tag_name[num_tags], "title", 5)) { strcpy((*c)->inf_title, (*c)->tag_data[num_tags]); (*c)->tag_data[num_tags][0] = 0; (*c)->tag_name[num_tags][0] = 0; } else if (!strncmp((*c)->tag_name[num_tags], "copyright", 9)) { strcpy((*c)->inf_copy, (*c)->tag_data[num_tags]); (*c)->tag_data[num_tags][0] = 0; (*c)->tag_name[num_tags][0] = 0; } else if (!strncmp((*c)->tag_name[num_tags], "artist", 6)) { strcpy((*c)->inf_artist, (*c)->tag_data[num_tags]); (*c)->tag_data[num_tags][0] = 0; (*c)->tag_name[num_tags][0] = 0; } else if (!strncmp((*c)->tag_name[num_tags], "game", 4)) { strcpy((*c)->inf_game, (*c)->tag_data[num_tags]); (*c)->tag_data[num_tags][0] = 0; (*c)->tag_name[num_tags][0] = 0; } else if (!strncmp((*c)->tag_name[num_tags], "year", 4)) { strcpy((*c)->inf_year, (*c)->tag_data[num_tags]); (*c)->tag_data[num_tags][0] = 0; (*c)->tag_name[num_tags][0] = 0; } else if (!strncmp((*c)->tag_name[num_tags], "length", 6)) { strcpy((*c)->inf_length, (*c)->tag_data[num_tags]); (*c)->tag_data[num_tags][0] = 0; (*c)->tag_name[num_tags][0] = 0; } else if (!strncmp((*c)->tag_name[num_tags], "fade", 4)) { strcpy((*c)->inf_fade, (*c)->tag_data[num_tags]); (*c)->tag_data[num_tags][0] = 0; (*c)->tag_name[num_tags][0] = 0; } } } // Bingo return AO_SUCCESS; } u32 psfTimeToMS(char *str) { int x, c=0; u32 acc=0; char s[100]; strncpy(s,str,100); s[99]=0; for (x=(int)strlen(s); x>=0; x--) { if (s[x]=='.' || s[x]==',') { acc=atoi(s+x+1); s[x]=0; } else if (s[x]==':') { if(c==0) { acc+=atoi(s+x+1)*10; } else if(c==1) { acc+=atoi(s+x+(x?1:0))*10*60; } c++; s[x]=0; } else if (x==0) { if(c==0) { acc+=atoi(s+x)*10; } else if(c==1) { acc+=atoi(s+x)*10*60; } else if(c==2) { acc+=atoi(s+x)*10*60*60; } } } acc*=100; return(acc); } yabause-0.9.15/src/aosdk/ao.h000644 001750 001750 00000002372 12755623101 017717 0ustar00guillaumeguillaume000000 000000 // // Audio Overload SDK // // Fake ao.h to set up the general Audio Overload style environment // #ifndef __AO_H #define __AO_H #include "../yabause.h" #define AO_SUCCESS 1 #define AO_FAIL 0 enum { COMMAND_NONE = 0, COMMAND_PREV, COMMAND_NEXT, COMMAND_RESTART, COMMAND_HAS_PREV, COMMAND_HAS_NEXT, COMMAND_GET_MIN, COMMAND_GET_MAX, COMMAND_JUMP }; #define MAX_DISP_INFO_LENGTH 256 typedef struct { char title[9][MAX_DISP_INFO_LENGTH]; char info[9][MAX_DISP_INFO_LENGTH]; } ao_display_info; extern ao_display_info ssf_info; int ao_get_lib(char *filename, u8 **buffer, u64 *length); s32 ssf_start(u8 *buffer, u32 length, int m68k_core, int sndcore, char* filename); s32 ssf_fill_info(ao_display_info *); #ifdef _MSC_VER #define strcasecmp _strcmpi #endif #ifndef WORDS_BIG_ENDIAN #define LE16(x) (x) #define LE32(x) (x) #else static unsigned short INLINE LE16(unsigned short x) { unsigned short res = (((x & 0xFF00) >> 8) | ((x & 0xFF) << 8)); return res; } static unsigned long INLINE LE32(unsigned long addr) { unsigned long res = (((addr & 0xff000000) >> 24) | ((addr & 0x00ff0000) >> 8) | ((addr & 0x0000ff00) << 8) | ((addr & 0x000000ff) << 24)); return res; } #endif #endif // AO_H yabause-0.9.15/src/aosdk/ssf.h000644 001750 001750 00000003221 12755623101 020105 0ustar00guillaumeguillaume000000 000000 /* Audio Overload SDK Copyright (c) 2007-2008, R. Belmont and Richard Bannister. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the names of R. Belmont and Richard Bannister nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ //export only what yabause needs int load_ssf(char *filename, int m68k_core, int sndcore); void get_ssf_info(int num, char * data_out);yabause-0.9.15/src/aosdk/corlett.h000644 001750 001750 00000001145 12755623101 020771 0ustar00guillaumeguillaume000000 000000 // // Audio Overload // Emulated music player // // (C) 2000-2008 Richard F. Bannister // // corlett.h #define MAX_UNKNOWN_TAGS 32 typedef struct { char lib[256]; char libaux[8][256]; char inf_title[256]; char inf_copy[256]; char inf_artist[256]; char inf_game[256]; char inf_year[256]; char inf_length[256]; char inf_fade[256]; char inf_refresh[256]; char tag_name[MAX_UNKNOWN_TAGS][256]; char tag_data[MAX_UNKNOWN_TAGS][256]; u32 *res_section; u32 res_size; } corlett_t; int corlett_decode(u8 *input, u32 input_len, u8 **output, u64 *size, corlett_t **c); u32 psfTimeToMS(char *str); yabause-0.9.15/src/aosdk/license.txt000644 001750 001750 00000002755 12755623101 021337 0ustar00guillaumeguillaume000000 000000 Copyright (c) 2007-2009, R. Belmont and Richard Bannister. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the names of R. Belmont and Richard Bannister nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. yabause-0.9.15/src/aosdk/eng_ssf.c000644 001750 001750 00000017273 12755623101 020745 0ustar00guillaumeguillaume000000 000000 /* Audio Overload SDK - SSF file format engine Copyright (c) 2007 R. Belmont and Richard Bannister. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the names of R. Belmont and Richard Bannister nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Sega driver commands: 00 - NOP 01 - SEQUENCE_START 02 - SEQUENCE_STOP 03 - SEQUENCE_PAUSE 04 - SEQUENCE_CONTINUE 05 - SEQUENCE_VOLUME 06 - SEQUENCE_ALLSTOP 07 - SEQUENCE_TEMPO 08 - SEQUENCE_MAP 09 - HOST_MIDI 0A - VOLUME_ANALYZE_START 0B - VOLUME_ANALYZE_STOP 0C - DSP CLEAR 0D - ALL OFF 0E - SEQUENCE PAN 0F - N/A 10 - SOUND INITIALIZE 11 - Yamaha 3D check (8C) 12 - QSound check (8B) 13 - Yamaha 3D init (8D) 80 - CD level 81 - CD pan 82 - MASTER VOLUME 83 - EFFECT_CHANGE 84 - NOP 85 - PCM stream play start 86 - PCM stream play end 87 - MIXER_CHANGE 88 - Mixer parameter change 89 - Hardware check 8A - PCM parameter change 8B - QSound check 8C - Yamaha 3D check 8D - Yamaha 3D init */ #include #include #include #include "ao.h" #include "corlett.h" #include "../m68kcore.h" #include "../scsp.h" #define DEBUG_LOADER (0) static corlett_t *c = NULL; static char psfby[256]; static u32 decaybegin, decayend, total_samples; //get current directory then append the libfile name int get_lib_file(char* path, char* libfile, char * output) { char * end = NULL; size_t len = 0; if (!path || !libfile || !output) return 0; len = strlen(path); end = path + len - 1; while (end > path && *end != '/') end--; strncpy(output, path, (end - path)+1); strcat(output, libfile); return 1;//success } s32 ssf_start(u8 *buffer, u32 length, int m68k_core, int sndcore, char* filename) { u8 *file, *lib_decoded, *lib_raw_file; u32 offset, lengthMS, fadeMS; u64 file_len, lib_len, lib_raw_length; corlett_t *lib; char *libfile; int i; M68KInit(m68k_core); ScspInit(sndcore); // clear Saturn work RAM before we start scribbling in it memset((void *)SoundRam, 0, 0x80000); // Decode the current SSF if (corlett_decode(buffer, length, &file, &file_len, &c) != AO_SUCCESS) { return AO_FAIL; } #if DEBUG_LOADER printf("%d bytes decoded\n", file_len); #endif // Get the library file, if any for (i=0; i<9; i++) { libfile = i ? c->libaux[i-1] : c->lib; if (libfile[0] != 0) { u64 tmp_length; char libfile_path[2048] = { 0 }; if (!get_lib_file(filename, libfile, libfile_path)) return AO_FAIL; #if DEBUG_LOADER printf("Loading library: %s\n", c->lib); #endif if (ao_get_lib(libfile_path, &lib_raw_file, &tmp_length) != AO_SUCCESS) { return AO_FAIL; } lib_raw_length = tmp_length; if (corlett_decode(lib_raw_file, lib_raw_length, &lib_decoded, &lib_len, &lib) != AO_SUCCESS) { free(lib_raw_file); free(file); return AO_FAIL; } // Free up raw file free(lib_raw_file); // patch the file into ram offset = lib_decoded[0] | lib_decoded[1]<<8 | lib_decoded[2]<<16 | lib_decoded[3]<<24; // guard against invalid data if ((offset + (lib_len-4)) > 0x7ffff) { lib_len = 0x80000-offset+4; } memcpy(&SoundRam[offset], lib_decoded+4, lib_len-4); // Dispose the corlett structure for the lib - we don't use it free(lib); } } // now patch the file into RAM over the libraries offset = file[3]<<24 | file[2]<<16 | file[1]<<8 | file[0]; // guard against invalid data if ((offset + (file_len-4)) > 0x7ffff) { file_len = 0x80000-offset+4; } memcpy(&SoundRam[offset], file+4, file_len-4); free(file); // Finally, set psfby tag strcpy(psfby, "n/a"); if (c) { for (i = 0; i < MAX_UNKNOWN_TAGS; i++) { if (!strcasecmp(c->tag_name[i], "psfby")) strcpy(psfby, c->tag_data[i]); } } #if DEBUG_LOADER && 1 { FILE *f; f = fopen("satram.bin", "wb"); fwrite(sat_ram, 512*1024, 1, f); fclose(f); } #endif // now flip everything (this makes sense because he's using starscream) for (i = 0; i < 512*1024; i+=2) { u8 temp; temp = SoundRam[i]; SoundRam[i] = SoundRam[i+1]; SoundRam[i+1] = temp; } M68KStart (); // now figure out the time in samples for the length/fade lengthMS = psfTimeToMS(c->inf_length); fadeMS = psfTimeToMS(c->inf_fade); total_samples = 0; if (lengthMS == 0) { lengthMS = ~0; } if (lengthMS == ~0) { decaybegin = lengthMS; } else { lengthMS = (lengthMS * 441) / 10; fadeMS = (fadeMS * 441) / 10; decaybegin = lengthMS; decayend = lengthMS + fadeMS; } return AO_SUCCESS; } s32 ssf_gen(s16 *buffer, u32 samples) { int i; s16 output[44100/30], output2[44100/30]; //s16 *stereo[2]; s16 *outp = buffer; int opos; opos = 0; for (i = 0; i < samples; i++) { s32 bufL=0, bufR=0; s16 buf16[2]; M68KExec((11300000/60)/735); scsp_update_timer(1); scsp_update(&bufL, &bufR, 1); scsp_update_monitor(); ScspConvert32uto16s (&bufL, &bufR, buf16, 1); output[opos] = buf16[0]; output2[opos] = buf16[1]; opos++; } for (i = 0; i < samples; i++) { // process the fade tags if (total_samples >= decaybegin) { if (total_samples >= decayend) { // song is done here, call out as necessary to make your player stop output[i] = 0; output2[i] = 0; return AO_FAIL; } else { s32 fader = 256 - (256*(total_samples - decaybegin)/(decayend-decaybegin)); output[i] = (output[i] * fader)>>8; output2[i] = (output2[i] * fader)>>8; total_samples++; } } else { total_samples++; } *outp++ = output[i]; *outp++ = output2[i]; } return AO_SUCCESS; } s32 ssf_stop(void) { return AO_SUCCESS; } s32 ssf_command(s32 command, s32 parameter) { switch (command) { case COMMAND_RESTART: return AO_SUCCESS; } return AO_FAIL; } s32 ssf_fill_info(ao_display_info *info) { if (c == NULL) return AO_FAIL; strcpy(info->title[1], "Name: "); sprintf(info->info[1], "%s", c->inf_title); strcpy(info->title[2], "Game: "); sprintf(info->info[2], "%s", c->inf_game); strcpy(info->title[3], "Artist: "); sprintf(info->info[3], "%s", c->inf_artist); strcpy(info->title[4], "Copyright: "); sprintf(info->info[4], "%s", c->inf_copy); strcpy(info->title[5], "Year: "); sprintf(info->info[5], "%s", c->inf_year); strcpy(info->title[6], "Length: "); sprintf(info->info[6], "%s", c->inf_length); strcpy(info->title[7], "Fade: "); sprintf(info->info[7], "%s", c->inf_fade); strcpy(info->title[8], "Ripper: "); sprintf(info->info[8], "%s", psfby); return AO_SUCCESS; } yabause-0.9.15/src/aosdk/ssf.c000644 001750 001750 00000007560 12755623101 020112 0ustar00guillaumeguillaume000000 000000 /* Audio Overload SDK - main driver. for demonstration only, not user friendly! Copyright (c) 2007-2009 R. Belmont and Richard Bannister. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the names of R. Belmont and Richard Bannister nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "ctype.h" #include "../error.h" #include "ao.h" /* file types */ static u32 type; ao_display_info ssf_info; /* ao_get_lib: called to load secondary files */ int ao_get_lib(char *filename, u8 **buffer, u64 *length) { u8 *filebuf; long size; FILE *auxfile; size_t fread_val = 0; auxfile = fopen(filename, "rb"); if (!auxfile) { printf("Unable to find auxiliary file %s\n", filename); return AO_FAIL; } fseek(auxfile, 0, SEEK_END); size = ftell(auxfile); if (size <= 0) { YabSetError(YAB_ERR_FILEREAD, filename); fclose(auxfile); return AO_FAIL; } fseek(auxfile, 0, SEEK_SET); filebuf = malloc(size); if (!filebuf) { fclose(auxfile); printf("ERROR: could not allocate %d bytes of memory\n", (int)size); return AO_FAIL; } fread_val = fread(filebuf, size, 1, auxfile); fclose(auxfile); *buffer = filebuf; *length = (u64)size; return AO_SUCCESS; } //osd core doesn't have lower case void upper_case(char * str) { if (str) { size_t len = strlen(str); int i; for (i = 0; i < len; i++) str[i] = toupper(str[i]); } } int load_ssf(char *filename, int m68k_core, int sndcore) { long size; FILE *fp = fopen(filename, "rb"); unsigned char *buffer; int ret; int i; size_t fread_val = 0; if (!fp) return 0;//false // Get file size fseek(fp, 0, SEEK_END); size = ftell(fp); if (size <= 0) { YabSetError(YAB_ERR_FILEREAD, filename); fclose(fp); return AO_FAIL; } fseek(fp, 0, SEEK_SET); buffer = (unsigned char *)malloc(size); if (buffer == NULL) { fclose(fp); return 0;//false } fread_val = fread(buffer, 1, size, fp); fclose(fp); // Read ID if (buffer[0] != 0x50 || buffer[1] != 0x53 || buffer[2] != 0x46 || buffer[3] != 0x11) { // Can't identify file free(buffer); return 0;//false } if ((ret = ssf_start(buffer, size, m68k_core, sndcore, filename)) != AO_SUCCESS) { free(buffer); return ret; } ssf_fill_info(&ssf_info); for (i = 0; i < 9; i++) { upper_case(ssf_info.title[i]); upper_case(ssf_info.info[i]); } return 1;//true } void get_ssf_info(int num, char * data_out) { if (!data_out) return; strcpy(data_out, ssf_info.info[num]); } yabause-0.9.15/src/snddx.h000644 001750 001750 00000001567 12755623101 017344 0ustar00guillaumeguillaume000000 000000 /* Copyright 2006 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SNDDX_H #define SNDDX_H #define SNDCORE_DIRECTX 2 extern SoundInterface_struct SNDDIRECTX; #endif yabause-0.9.15/src/vidsoft.c000644 001750 001750 00000372017 12755623101 017676 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2004 Guillaume Duhamel Copyright 2004-2008 Theo Berkau Copyright 2006 Fabien Coulon Copyright 2015 R. Danbrook This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file vidsoft.c \brief Software video renderer interface. */ #include "vidsoft.h" #include "ygl.h" #include "vidshared.h" #include "debug.h" #include "vdp2.h" #include "titan/titan.h" #ifdef HAVE_LIBGL #define USE_OPENGL #endif #ifdef USE_OPENGL #include "ygl.h" #endif #include "yui.h" #include "threads.h" #include #include #if defined WORDS_BIGENDIAN static INLINE u32 COLSAT2YAB16(int priority,u32 temp) { return (priority | (temp & 0x7C00) << 1 | (temp & 0x3E0) << 14 | (temp & 0x1F) << 27); } static INLINE u32 COLSAT2YAB32(int priority,u32 temp) { return (((temp & 0xFF) << 24) | ((temp & 0xFF00) << 8) | ((temp & 0xFF0000) >> 8) | priority); } static INLINE u32 COLSAT2YAB32_2(int priority,u32 temp1,u32 temp2) { return (((temp2 & 0xFF) << 24) | ((temp2 & 0xFF00) << 8) | ((temp1 & 0xFF) << 8) | priority); } static INLINE u32 COLSATSTRIPPRIORITY(u32 pixel) { return (pixel | 0xFF); } #else static INLINE u32 COLSAT2YAB16(int priority,u32 temp) { return (priority << 24 | (temp & 0x1F) << 3 | (temp & 0x3E0) << 6 | (temp & 0x7C00) << 9); } static INLINE u32 COLSAT2YAB32(int priority, u32 temp) { return (priority << 24 | (temp & 0xFF0000) | (temp & 0xFF00) | (temp & 0xFF)); } static INLINE u32 COLSAT2YAB32_2(int priority,u32 temp1,u32 temp2) { return (priority << 24 | ((temp1 & 0xFF) << 16) | (temp2 & 0xFF00) | (temp2 & 0xFF)); } static INLINE u32 COLSATSTRIPPRIORITY(u32 pixel) { return (0xFF000000 | pixel); } #endif #define COLOR_ADDt(b) (b>0xFF?0xFF:(b<0?0:b)) #define COLOR_ADDb(b1,b2) COLOR_ADDt((signed) (b1) + (b2)) #ifdef WORDS_BIGENDIAN #define COLOR_ADD(l,r,g,b) (l & 0xFF) | \ (COLOR_ADDb((l >> 8) & 0xFF, b) << 8) | \ (COLOR_ADDb((l >> 16) & 0xFF, g) << 16) | \ (COLOR_ADDb((l >> 24), r) << 24) #else #define COLOR_ADD(l,r,g,b) COLOR_ADDb((l & 0xFF), r) | \ (COLOR_ADDb((l >> 8) & 0xFF, g) << 8) | \ (COLOR_ADDb((l >> 16) & 0xFF, b) << 16) | \ (l & 0xFF000000) #endif int VIDSoftInit(void); void VIDSoftSetupGL(void); void VIDSoftDeInit(void); void VIDSoftResize(unsigned int, unsigned int, int); int VIDSoftIsFullscreen(void); int VIDSoftVdp1Reset(void); void VIDSoftVdp1DrawStart(void); void VIDSoftVdp1DrawEnd(void); void VIDSoftVdp1NormalSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDSoftVdp1ScaledSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDSoftVdp1DistortedSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDSoftVdp1PolygonDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDSoftVdp1PolylineDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDSoftVdp1LineDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDSoftVdp1UserClipping(u8 * ram, Vdp1 * regs); void VIDSoftVdp1SystemClipping(u8 * ram, Vdp1 * regs); void VIDSoftVdp1LocalCoordinate(u8 * ram, Vdp1 * regs); void VIDSoftVdp1ReadFrameBuffer(u32 type, u32 addr, void * out); void VIDSoftVdp1WriteFrameBuffer(u32 type, u32 addr, u32 val); int VIDSoftVdp2Reset(void); void VIDSoftVdp2DrawStart(void); void VIDSoftVdp2DrawEnd(void); void VIDSoftVdp2DrawScreens(void); void VIDSoftVdp2SetResolution(u16 TVMD); void VIDSoftGetGlSize(int *width, int *height); void VIDSoftVdp1SwapFrameBuffer(void); void VIDSoftVdp1EraseFrameBuffer(Vdp1* regs, u8 * back_framebuffer); void VidsoftDrawSprite(Vdp2 * vdp2_regs, u8 * sprite_window_mask, u8* vdp1_front_framebuffer, u8 * vdp2_ram, Vdp1* vdp1_regs, Vdp2* vdp2_lines, u8*color_ram); void VIDSoftGetNativeResolution(int *width, int *height, int*interlace); void VIDSoftVdp2DispOff(void); VideoInterface_struct VIDSoft = { VIDCORE_SOFT, "Software Video Interface", VIDSoftInit, VIDSoftDeInit, VIDSoftResize, VIDSoftIsFullscreen, VIDSoftVdp1Reset, VIDSoftVdp1DrawStart, VIDSoftVdp1DrawEnd, VIDSoftVdp1NormalSpriteDraw, VIDSoftVdp1ScaledSpriteDraw, VIDSoftVdp1DistortedSpriteDraw, //for the actual hardware, polygons are essentially identical to distorted sprites //the actual hardware draws using diagonal lines, which is why using half-transparent processing //on distorted sprites and polygons is not recommended since the hardware overdraws to prevent gaps //thus, with half-transparent processing some pixels will be processed more than once, producing moire patterns in the drawn shapes VIDSoftVdp1DistortedSpriteDraw, VIDSoftVdp1PolylineDraw, VIDSoftVdp1LineDraw, VIDSoftVdp1UserClipping, VIDSoftVdp1SystemClipping, VIDSoftVdp1LocalCoordinate, VIDSoftVdp1ReadFrameBuffer, VIDSoftVdp1WriteFrameBuffer, VIDSoftVdp2Reset, VIDSoftVdp2DrawStart, VIDSoftVdp2DrawEnd, VIDSoftVdp2DrawScreens, VIDSoftGetGlSize, VIDSoftGetNativeResolution, VIDSoftVdp2DispOff }; pixel_t *dispbuffer=NULL; u8 *vdp1framebuffer[2]= { NULL, NULL }; u8 *vdp1frontframebuffer; u8 *vdp1backframebuffer; u8 sprite_window_mask[704 * 512]; static int vdp1width; static int vdp1height; static int vdp1interlace; static int vdp1pixelsize; int vdp2width; int rbg0width = 0; int vdp2height; #ifdef USE_OPENGL static int outputwidth; static int outputheight; GLuint vao = 0; GLuint vbo = 0; GLuint vshader = 0; GLuint fshader = 0; GLuint gl_shader_prog = 0; GLuint gl_texture_id = 0; #endif int vdp2_x_hires = 0; int vdp2_interlace = 0; static int rbg0height = 0; int bilinear = 0; int vidsoft_num_layer_threads = 0; int bad_cycle_setting[6] = { 0 }; struct VidsoftVdp1ThreadContext { volatile int draw_finished; volatile int need_draw; Vdp1 regs; u8 ram[0x80000]; u8 back_framebuffer[0x40000]; }vidsoft_vdp1_thread_context; int vidsoft_vdp1_thread_enabled = 0; typedef struct { s16 x; s16 y; } vdp1vertex; typedef struct { int pagepixelwh, pagepixelwh_bits, pagepixelwh_mask; int planepixelwidth, planepixelwidth_bits, planepixelwidth_mask; int planepixelheight, planepixelheight_bits, planepixelheight_mask; int screenwidth; int screenheight; int oldcellx, oldcelly, oldcellcheck; int xmask, ymask; u32 planetbl[16]; } screeninfo_struct; ////////////////////////////////////////////////////////////////////////////// static INLINE u32 FASTCALL Vdp2ColorRamGetColor(u32 addr, u8* vdp2_color_ram) { switch(Vdp2Internal.ColorMode) { case 0: { u32 tmp; addr <<= 1; tmp = T2ReadWord(vdp2_color_ram, addr & 0xFFF); /* we preserve MSB for special color calculation mode 3 (see Vdp2 user's manual 3.4 and 12.3) */ return (((tmp & 0x1F) << 3) | ((tmp & 0x03E0) << 6) | ((tmp & 0x7C00) << 9)) | ((tmp & 0x8000) << 16); } case 1: { u32 tmp; addr <<= 1; tmp = T2ReadWord(vdp2_color_ram, addr & 0xFFF); /* we preserve MSB for special color calculation mode 3 (see Vdp2 user's manual 3.4 and 12.3) */ return (((tmp & 0x1F) << 3) | ((tmp & 0x03E0) << 6) | ((tmp & 0x7C00) << 9)) | ((tmp & 0x8000) << 16); } case 2: { addr <<= 2; return T2ReadLong(vdp2_color_ram, addr & 0xFFF); } default: break; } return 0; } ////////////////////////////////////////////////////////////////////////////// static INLINE void Vdp2PatternAddr(vdp2draw_struct *info, Vdp2* regs, u8* ram) { switch(info->patterndatasize) { case 1: { u16 tmp = T1ReadWord(ram, info->addr); info->addr += 2; info->specialfunction = (info->supplementdata >> 9) & 0x1; info->specialcolorfunction = (info->supplementdata >> 8) & 0x1; switch(info->colornumber) { case 0: // in 16 colors info->paladdr = ((tmp & 0xF000) >> 8) | ((info->supplementdata & 0xE0) << 3); break; default: // not in 16 colors info->paladdr = (tmp & 0x7000) >> 4; break; } switch(info->auxmode) { case 0: info->flipfunction = (tmp & 0xC00) >> 10; switch(info->patternwh) { case 1: info->charaddr = (tmp & 0x3FF) | ((info->supplementdata & 0x1F) << 10); break; case 2: info->charaddr = ((tmp & 0x3FF) << 2) | (info->supplementdata & 0x3) | ((info->supplementdata & 0x1C) << 10); break; } break; case 1: info->flipfunction = 0; switch(info->patternwh) { case 1: info->charaddr = (tmp & 0xFFF) | ((info->supplementdata & 0x1C) << 10); break; case 2: info->charaddr = ((tmp & 0xFFF) << 2) | (info->supplementdata & 0x3) | ((info->supplementdata & 0x10) << 10); break; } break; } break; } case 2: { u16 tmp1 = T1ReadWord(ram, info->addr); u16 tmp2 = T1ReadWord(ram, info->addr+2); info->addr += 4; info->charaddr = tmp2 & 0x7FFF; info->flipfunction = (tmp1 & 0xC000) >> 14; switch(info->colornumber) { case 0: info->paladdr = (tmp1 & 0x7F) << 4; break; default: info->paladdr = ((tmp1 & 0x70) << 4); break; } info->specialfunction = (tmp1 & 0x2000) >> 13; info->specialcolorfunction = (tmp1 & 0x1000) >> 12; break; } } if (!(regs->VRSIZE & 0x8000)) info->charaddr &= 0x3FFF; info->charaddr *= 0x20; // selon Runik if (info->specialprimode == 1) { info->priority = (info->priority & 0xE) | (info->specialfunction & 1); } } ////////////////////////////////////////////////////////////////////////////// static INLINE u32 FASTCALL DoNothing(UNUSED void *info, u32 pixel) { return pixel; } ////////////////////////////////////////////////////////////////////////////// static INLINE u32 FASTCALL DoColorOffset(void *info, u32 pixel) { return COLOR_ADD(pixel, ((vdp2draw_struct *)info)->cor, ((vdp2draw_struct *)info)->cog, ((vdp2draw_struct *)info)->cob); } ////////////////////////////////////////////////////////////////////////////// static INLINE void ReadVdp2ColorOffset(Vdp2 * regs, vdp2draw_struct *info, int clofmask, int ccmask) { if (regs->CLOFEN & clofmask) { // color offset enable if (regs->CLOFSL & clofmask) { // color offset B info->cor = regs->COBR & 0xFF; if (regs->COBR & 0x100) info->cor |= 0xFFFFFF00; info->cog = regs->COBG & 0xFF; if (regs->COBG & 0x100) info->cog |= 0xFFFFFF00; info->cob = regs->COBB & 0xFF; if (regs->COBB & 0x100) info->cob |= 0xFFFFFF00; } else { // color offset A info->cor = regs->COAR & 0xFF; if (regs->COAR & 0x100) info->cor |= 0xFFFFFF00; info->cog = regs->COAG & 0xFF; if (regs->COAG & 0x100) info->cog |= 0xFFFFFF00; info->cob = regs->COAB & 0xFF; if (regs->COAB & 0x100) info->cob |= 0xFFFFFF00; } info->PostPixelFetchCalc = &DoColorOffset; } else // color offset disable info->PostPixelFetchCalc = &DoNothing; } ////////////////////////////////////////////////////////////////////////////// static INLINE int Vdp2FetchPixel(vdp2draw_struct *info, int x, int y, u32 *color, u32 *dot, u8 * ram, int charaddr, int paladdr, u8* vdp2_color_ram) { switch(info->colornumber) { case 0: // 4 BPP *dot = T1ReadByte(ram, ((charaddr + ((y * info->cellw) + x) / 2) & 0x7FFFF)); if (!(x & 0x1)) *dot >>= 4; if (!(*dot & 0xF) && info->transparencyenable) return 0; else { *color = Vdp2ColorRamGetColor(info->coloroffset + (paladdr | (*dot & 0xF)),vdp2_color_ram); return 1; } case 1: // 8 BPP *dot = T1ReadByte(ram, ((charaddr + (y * info->cellw) + x) & 0x7FFFF)); if (!(*dot & 0xFF) && info->transparencyenable) return 0; else { *color = Vdp2ColorRamGetColor(info->coloroffset + (paladdr | (*dot & 0xFF)), vdp2_color_ram); return 1; } case 2: // 16 BPP(palette) *dot = T1ReadWord(ram, ((charaddr + ((y * info->cellw) + x) * 2) & 0x7FFFF)); if ((*dot == 0) && info->transparencyenable) return 0; else { *color = Vdp2ColorRamGetColor(info->coloroffset + *dot, vdp2_color_ram); return 1; } case 3: // 16 BPP(RGB) *dot = T1ReadWord(ram, ((charaddr + ((y * info->cellw) + x) * 2) & 0x7FFFF)); if (!(*dot & 0x8000) && info->transparencyenable) return 0; else { *color = COLSAT2YAB16(0, *dot); return 1; } case 4: // 32 BPP *dot = T1ReadLong(ram, ((charaddr + ((y * info->cellw) + x) * 4) & 0x7FFFF)); if (!(*dot & 0x80000000) && info->transparencyenable) return 0; else { *color = COLSAT2YAB32(0, *dot); return 1; } default: return 0; } } ////////////////////////////////////////////////////////////////////////////// static INLINE int TestWindow(int wctl, int enablemask, int inoutmask, clipping_struct *clip, int x, int y) { if (wctl & enablemask) { if (wctl & inoutmask) { // Draw inside of window if (x < clip->xstart || x > clip->xend || y < clip->ystart || y > clip->yend) return 0; } else { // Draw outside of window if (x >= clip->xstart && x <= clip->xend && y >= clip->ystart && y <= clip->yend) return 0; //it seems to overflow vertically on hardware if(clip->yend > vdp2height && (x >= clip->xstart && x <= clip->xend )) return 0; } return 1; // return inactive; } return 3; // return disabled | inactive; } ////////////////////////////////////////////////////////////////////////////// int TestSpriteWindow(int wctl, int x, int y) { int mask; int addr = (y*vdp2width) + x; if (addr >= (704 * 512)) return 0; mask = sprite_window_mask[addr]; if (wctl & 0x20)//sprite window enabled on layer { if (wctl & 0x10)//inside or outside { if (mask == 0) return 0; } else { if (mask) return 0; } return 1; } return 3; } ////////////////////////////////////////////////////////////////////////////// int WindowLogic(int wctl, int w0, int w1) { if (((wctl & 0x80) == 0x80)) /* AND logic, returns 0 only if both the windows are active */ return w0 || w1; else /* OR logic, returns 0 if one of the windows is active */ return w0 && w1; } ////////////////////////////////////////////////////////////////////////////// static INLINE int TestBothWindow(int wctl, clipping_struct *clip, int x, int y) { int w0 = TestWindow(wctl, 0x2, 0x1, &clip[0], x, y); int w1 = TestWindow(wctl, 0x8, 0x4, &clip[1], x, y); int spr = TestSpriteWindow(wctl, x,y); //all windows disabled if ((wctl & 0x2a) == 0) { if ((wctl & 0x80) == 0x80) return 0; else return 1; } //if only window 0 is enabled if ((w1 & 2) && (spr & 2)) return w0 & 1; //if only window 1 is enabled if ((w0 & 2) && (spr & 2)) return w1 & 1; //window 0 and 1, sprite disabled if ((spr & 2)) return WindowLogic(wctl, w0, w1); //if only sprite window is enabled if ((w1 & 2) && (w0 & 2)) return spr & 1; //window 0 and sprite enabled if ((wctl & 0x2a) == 0x22) return WindowLogic(wctl, w0, spr); //window 1 and sprite enabled if ((wctl & 0x2a) == 0x28) return WindowLogic(wctl, w1, spr); //all three windows enabled if ((wctl & 0x2a) == 0x2a) { if ((wctl & 0x80) == 0x80) return w0 || w1 || spr;//and logic else return w0 && w1 && spr;//or logic } return 1; } ////////////////////////////////////////////////////////////////////////////// static INLINE void GeneratePlaneAddrTable(vdp2draw_struct *info, u32 *planetbl, void FASTCALL (* PlaneAddr)(void *, int, Vdp2* ), Vdp2* regs) { int i; for (i = 0; i < (info->mapwh*info->mapwh); i++) { PlaneAddr(info, i, regs); planetbl[i] = info->addr; } } ////////////////////////////////////////////////////////////////////////////// static INLINE void FASTCALL Vdp2MapCalcXY(vdp2draw_struct *info, int *x, int *y, screeninfo_struct *sinfo, Vdp2* regs, u8 * ram, int bad_cycle) { int planenum; int flipfunction; const int pagesize_bits=info->pagewh_bits*2; const int cellwh=(2 + info->patternwh); const int check = ((y[0] >> cellwh) << 16) | (x[0] >> cellwh); //if ((x[0] >> cellwh) != sinfo->oldcellx || (y[0] >> cellwh) != sinfo->oldcelly) if(check != sinfo->oldcellcheck) { sinfo->oldcellx = x[0] >> cellwh; sinfo->oldcelly = y[0] >> cellwh; sinfo->oldcellcheck = (sinfo->oldcelly << 16) | sinfo->oldcellx; // Calculate which plane we're dealing with planenum = ((y[0] >> sinfo->planepixelheight_bits) * info->mapwh) + (x[0] >> sinfo->planepixelwidth_bits); x[0] = (x[0] & sinfo->planepixelwidth_mask); y[0] = (y[0] & sinfo->planepixelheight_mask); // Fetch and decode pattern name data info->addr = sinfo->planetbl[planenum]; // Figure out which page it's on(if plane size is not 1x1) info->addr += (( ((y[0] >> sinfo->pagepixelwh_bits) << pagesize_bits) << info->planew_bits) + ( (x[0] >> sinfo->pagepixelwh_bits) << pagesize_bits) + (((y[0] & sinfo->pagepixelwh_mask) >> cellwh) << info->pagewh_bits) + ((x[0] & sinfo->pagepixelwh_mask) >> cellwh)) << (info->patterndatasize_bits+1); Vdp2PatternAddr(info, regs, ram); // Heh, this could be optimized //pipeline the tiles so that they shift over by 1 info->pipe[0] = info->pipe[1]; info->pipe[1].paladdr = info->paladdr; info->pipe[1].charaddr = info->charaddr; info->pipe[1].flipfunction = info->flipfunction; } if (bad_cycle) { flipfunction = info->pipe[0].flipfunction; } else { flipfunction = info->flipfunction; } // Figure out which pixel in the tile we want if (info->patternwh == 1) { x[0] &= 8-1; y[0] &= 8-1; switch(flipfunction & 0x3) { case 0: //none break; case 1: //horizontal flip x[0] = 8 - 1 - x[0]; break; case 2: // vertical flip y[0] = 8 - 1 - y[0]; break; case 3: //flip both x[0] = 8 - 1 - x[0]; y[0] = 8 - 1 - y[0]; break; } } else { if (flipfunction) { y[0] &= 16 - 1; if (flipfunction & 0x2) { if (!(y[0] & 8)) y[0] = 8 - 1 - y[0] + 16; else y[0] = 16 - 1 - y[0]; } else if (y[0] & 8) y[0] += 8; if (flipfunction & 0x1) { if (!(x[0] & 8)) y[0] += 8; x[0] &= 8-1; x[0] = 8 - 1 - x[0]; } else if (x[0] & 8) { y[0] += 8; x[0] &= 8-1; } else x[0] &= 8-1; } else { y[0] &= 16 - 1; if (y[0] & 8) y[0] += 8; if (x[0] & 8) y[0] += 8; x[0] &= 8-1; } } } ////////////////////////////////////////////////////////////////////////////// static INLINE void SetupScreenVars(vdp2draw_struct *info, screeninfo_struct *sinfo, void FASTCALL (* PlaneAddr)(void *, int, Vdp2*), Vdp2* regs) { if (!info->isbitmap) { sinfo->pagepixelwh=64*8; sinfo->pagepixelwh_bits = 9; sinfo->pagepixelwh_mask = 511; sinfo->planepixelwidth=info->planew*sinfo->pagepixelwh; sinfo->planepixelwidth_bits = 8+info->planew; sinfo->planepixelwidth_mask = (1<<(sinfo->planepixelwidth_bits))-1; sinfo->planepixelheight=info->planeh*sinfo->pagepixelwh; sinfo->planepixelheight_bits = 8+info->planeh; sinfo->planepixelheight_mask = (1<<(sinfo->planepixelheight_bits))-1; sinfo->screenwidth=info->mapwh*sinfo->planepixelwidth; sinfo->screenheight=info->mapwh*sinfo->planepixelheight; sinfo->oldcellx=-1; sinfo->oldcelly=-1; sinfo->oldcellcheck=-1; sinfo->xmask = sinfo->screenwidth-1; sinfo->ymask = sinfo->screenheight-1; GeneratePlaneAddrTable(info, sinfo->planetbl, PlaneAddr, regs); } else { sinfo->pagepixelwh = 0; sinfo->pagepixelwh_bits = 0; sinfo->pagepixelwh_mask = 0; sinfo->planepixelwidth=0; sinfo->planepixelwidth_bits=0; sinfo->planepixelwidth_mask=0; sinfo->planepixelheight=0; sinfo->planepixelheight_bits=0; sinfo->planepixelheight_mask=0; sinfo->screenwidth=0; sinfo->screenheight=0; sinfo->oldcellx=0; sinfo->oldcelly=0; sinfo->oldcellcheck=0; sinfo->xmask = info->cellw-1; sinfo->ymask = info->cellh-1; } } ////////////////////////////////////////////////////////////////////////////// static u8 FASTCALL GetAlpha(vdp2draw_struct * info, u32 color, u32 dot) { if (((info->specialcolormode == 1) || (info->specialcolormode == 2)) && ((info->specialcolorfunction & 1) == 0)) { /* special color calculation mode 1 and 2 enables color calculation only when special color function = 1 */ return 0x3F; } else if (info->specialcolormode == 2) { /* special color calculation 2 enables color calculation according to lower bits of the color code */ if ((info->specialcode & (1 << ((dot & 0xF) >> 1))) == 0) { return 0x3F; } } else if ((info->specialcolormode == 3) && ((color & 0x80000000) == 0)) { /* special color calculation mode 3 enables color calculation only for dots with MSB = 1 */ return 0x3F; } return info->alpha; } ////////////////////////////////////////////////////////////////////////////// int PixelIsSpecialPriority(int specialcode, int dot) { dot &= 0xf; if (specialcode & 0x01) { if (dot == 0 || dot == 1) return 1; } if (specialcode & 0x02) { if (dot == 2 || dot == 3) return 1; } if (specialcode & 0x04) { if (dot == 4 || dot == 5) return 1; } if (specialcode & 0x08) { if (dot == 6 || dot == 7) return 1; } if (specialcode & 0x10) { if (dot == 8 || dot == 9) return 1; } if (specialcode & 0x20) { if (dot == 0xa || dot == 0xb) return 1; } if (specialcode & 0x40) { if (dot == 0xc || dot == 0xd) return 1; } if (specialcode & 0x80) { if (dot == 0xe || dot == 0xf) return 1; } return 0; } ////////////////////////////////////////////////////////////////////////////// void Vdp2GetInterlaceInfo(int * start_line, int * line_increment) { if (vdp2_interlace) { if (vdp2_is_odd_frame) { *start_line = 1; } else { *start_line = 0; } *line_increment = 2; } else { *start_line = 0; *line_increment = 1; } } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL Vdp2DrawScroll(vdp2draw_struct *info, Vdp2* lines, Vdp2* regs, u8* ram, u8* color_ram, struct CellScrollData * cell_data) { int i, j; int x, y; clipping_struct clip[2]; u32 linewnd0addr, linewnd1addr; u32 line_window_base[2] = { 0 }; screeninfo_struct sinfo; int scrolly; int *mosaic_y, *mosaic_x; clipping_struct colorcalcwindow[2]; int start_line = 0, line_increment = 0; int bad_cycle = bad_cycle_setting[info->titan_which_layer]; int charaddr, paladdr; int output_y = 0; u32 linescrollx_table[512] = { 0 }; u32 linescrolly_table[512] = { 0 }; float lineszoom_table[512] = { 0 }; int num_vertical_cell_scroll_enabled = 0; SetupScreenVars(info, &sinfo, info->PlaneAddr, regs); scrolly = info->y; clip[0].xstart = clip[0].ystart = clip[0].xend = clip[0].yend = 0; clip[1].xstart = clip[1].ystart = clip[1].xend = clip[1].yend = 0; ReadWindowData(info->wctl, clip, regs); linewnd0addr = linewnd1addr = 0; ReadLineWindowData(&info->islinewindow, info->wctl, &linewnd0addr, &linewnd1addr,regs); line_window_base[0] = linewnd0addr; line_window_base[1] = linewnd1addr; /* color calculation window: in => no color calc, out => color calc */ ReadWindowData(regs->WCTLD >> 8, colorcalcwindow, regs); { static int tables_initialized = 0; static int mosaic_table[16][1024]; if(!tables_initialized) { tables_initialized = 1; for(i=0;i<16;i++) { int m = i+1; for(j=0;j<1024;j++) mosaic_table[i][j] = j/m*m; } } mosaic_x = mosaic_table[info->mosaicxmask-1]; mosaic_y = mosaic_table[info->mosaicymask-1]; } Vdp2GetInterlaceInfo(&start_line, &line_increment); if (regs->SCRCTL & 1) num_vertical_cell_scroll_enabled++; if (regs->SCRCTL & 0x100) num_vertical_cell_scroll_enabled++; //pre-generate line scroll tables for (j = start_line; j < vdp2height; j++) { if (info->islinescroll) { //line scroll interval bit int need_increment = ((j != 0) && (((j + 1) % info->lineinc) == 0)); //horizontal line scroll if (info->islinescroll & 0x1) { linescrollx_table[j] = (T1ReadLong(ram, info->linescrolltbl) >> 16) & 0x7FF; if (need_increment) info->linescrolltbl += 4; } //vertical line scroll if (info->islinescroll & 0x2) { linescrolly_table[j] = ((T1ReadWord(ram, info->linescrolltbl) & 0x7FF)) + scrolly; if (need_increment) info->linescrolltbl += 4; y = info->y; } //line zoom if (info->islinescroll & 0x4) { lineszoom_table[j] = (T1ReadLong(ram, info->linescrolltbl) & 0x7FF00) / (float)65536.0; if (need_increment) info->linescrolltbl += 4; } } } for (j = start_line; j < vdp2height; j += line_increment) { int Y; int linescrollx = 0; // precalculate the coordinate for the line(it's faster) and do line // scroll if (info->islinescroll) { //horizontal line scroll if (info->islinescroll & 0x1) { linescrollx = linescrollx_table[j]; } //vertical line scroll if (info->islinescroll & 0x2) { info->y = linescrolly_table[j]; y = info->y; } else //y = info->y+((int)(info->coordincy *(float)(info->mosaicymask > 1 ? (j / info->mosaicymask * info->mosaicymask) : j))); y = info->y + info->coordincy*mosaic_y[j]; //line zoom if (info->islinescroll & 0x4) { info->coordincx = lineszoom_table[j]; } } else //y = info->y+((int)(info->coordincy *(float)(info->mosaicymask > 1 ? (j / info->mosaicymask * info->mosaicymask) : j))); y = info->y + info->coordincy*mosaic_y[j]; if (vdp2_interlace) { linewnd0addr = line_window_base[0] + (j * 4); linewnd1addr = line_window_base[1] + (j * 4); } // if line window is enabled, adjust clipping values ReadLineWindowClip(info->islinewindow, clip, &linewnd0addr, &linewnd1addr, ram, regs); y &= sinfo.ymask; if (info->isverticalscroll && (!vdp2_x_hires))//seems to be ignored in hi res { // this is *wrong*, vertical scroll use a different value per cell // info->verticalscrolltbl should be incremented by info->verticalscrollinc // each time there's a cell change and reseted at the end of the line... // or something like that :) u32 scroll_value = 0; int y_value = 0; if (vdp2_interlace) y_value = j / 2; else y_value = j; if (num_vertical_cell_scroll_enabled == 1) { scroll_value = cell_data[y_value].data[0] >> 16; } else { if (info->titan_which_layer == TITAN_NBG0) scroll_value = cell_data[y_value].data[0] >> 16;//reload cell data per line for sonic 2, 2 player mode else if (info->titan_which_layer == TITAN_NBG1) scroll_value = cell_data[y_value].data[1] >> 16; } y += scroll_value; y &= 0x1FF; } Y=y; if (vdp2_interlace) info->LoadLineParams(info, &sinfo, j / 2, lines); else info->LoadLineParams(info, &sinfo, j, lines); if (!info->enable) continue; for (i = 0; i < vdp2width; i++) { u32 color, dot; /* I'm really not sure about this... but I think the way we handle high resolution gets in the way with window process. I may be wrong... This was added for Cotton Boomerang */ int priority; // See if screen position is clipped, if it isn't, continue if (!TestBothWindow(info->wctl, clip, i, j)) { continue; } //x = info->x+((int)(info->coordincx*(float)((info->mosaicxmask > 1) ? (i / info->mosaicxmask * info->mosaicxmask) : i))); x = info->x + mosaic_x[i]*info->coordincx; x &= sinfo.xmask; if (linescrollx) { x += linescrollx; x &= 0x3FF; } // Fetch Pixel, if it isn't transparent, continue if (!info->isbitmap) { // Tile y=Y; Vdp2MapCalcXY(info, &x, &y, &sinfo, regs, ram, bad_cycle); } if (!bad_cycle) { charaddr = info->charaddr; paladdr = info->paladdr; } else { charaddr = info->pipe[0].charaddr; paladdr = info->pipe[0].paladdr; } if (!Vdp2FetchPixel(info, x, y, &color, &dot, ram, charaddr, paladdr,color_ram)) { continue; } priority = info->priority; //per-pixel priority is on if (info->specialprimode == 2) { priority = info->priority & 0xE; if (info->specialfunction & 1) { if (PixelIsSpecialPriority(info->specialcode,dot)) { priority |= 1; } } } // Apply color offset and color calculation/special color calculation // and then continue. // We almost need to know well ahead of time what the top // and second pixel is in order to work this. { u8 alpha; /* if we're in the valid area of the color calculation window, don't do color calculation */ if (!TestBothWindow(regs->WCTLD >> 8, colorcalcwindow, i, j)) alpha = 0x3F; else alpha = GetAlpha(info, color, dot); TitanPutPixel(priority, i, output_y, info->PostPixelFetchCalc(info, COLSAT2YAB32(alpha, color)), info->linescreen, info); } } output_y++; } } ////////////////////////////////////////////////////////////////////////////// void Rbg0PutHiresPixel(vdp2draw_struct *info, u32 color, u32 dot, int i, int j) { u32 pixel = info->PostPixelFetchCalc(info, COLSAT2YAB32(GetAlpha(info, color, dot), color)); int x_pos = i * 2; TitanPutPixel(info->priority, x_pos, j, pixel, info->linescreen, info); TitanPutPixel(info->priority, x_pos + 1, j, pixel, info->linescreen, info); } ////////////////////////////////////////////////////////////////////////////// void Rbg0PutPixel(vdp2draw_struct *info, u32 color, u32 dot, int i, int j) { if (vdp2_x_hires) { Rbg0PutHiresPixel(info, color, dot, i, j); } else TitanPutPixel(info->priority, i, j, info->PostPixelFetchCalc(info, COLSAT2YAB32(GetAlpha(info, color, dot), color)), info->linescreen, info); } ////////////////////////////////////////////////////////////////////////////// int CheckBanks(Vdp2* regs, int compare_value) { if (((regs->RAMCTL >> 0) & 3) == compare_value)//a0 return 0; if (((regs->RAMCTL >> 2) & 3) == compare_value)//a1 return 0; if (((regs->RAMCTL >> 4) & 3) == compare_value)//b0 return 0; if (((regs->RAMCTL >> 6) & 3) == compare_value)//b1 return 0; return 1;//no setting present } int Rbg0CheckRam(Vdp2* regs) { if (((regs->RAMCTL >> 8) & 3) == 3)//both banks are divided { //ignore delta kax if the coefficient table //bank is unspecified if (CheckBanks(regs, 1)) return 1; } return 0; } static void FASTCALL Vdp2DrawRotationFP(vdp2draw_struct *info, vdp2rotationparameterfp_struct *parameter, Vdp2* lines, Vdp2* regs, u8* ram, u8* color_ram, struct CellScrollData * cell_data) { int i, j; int x, y; screeninfo_struct sinfo; vdp2rotationparameterfp_struct *p=¶meter[info->rotatenum]; clipping_struct clip[2]; u32 linewnd0addr, linewnd1addr; clip[0].xstart = clip[0].ystart = clip[0].xend = clip[0].yend = 0; clip[1].xstart = clip[1].ystart = clip[1].xend = clip[1].yend = 0; ReadWindowData(info->wctl, clip, regs); linewnd0addr = linewnd1addr = 0; ReadLineWindowData(&info->islinewindow, info->wctl, &linewnd0addr, &linewnd1addr, regs); Vdp2ReadRotationTableFP(info->rotatenum, p, regs, ram); if (!p->coefenab) { fixed32 xmul, ymul, C, F; // Since coefficients aren't being used, we can simplify the drawing process if (IsScreenRotatedFP(p)) { // No rotation info->x = touint(mulfixed(p->kx, (p->Xst - p->Px)) + p->Px + p->Mx); info->y = touint(mulfixed(p->ky, (p->Yst - p->Py)) + p->Py + p->My); info->coordincx = tofloat(p->kx); info->coordincy = tofloat(p->ky); } else { GenerateRotatedVarFP(p, &xmul, &ymul, &C, &F); // Do simple rotation CalculateRotationValuesFP(p); SetupScreenVars(info, &sinfo, info->PlaneAddr, regs); for (j = 0; j < vdp2height; j++) { info->LoadLineParams(info, &sinfo, j, lines); ReadLineWindowClip(info->islinewindow, clip, &linewnd0addr, &linewnd1addr, ram, regs); for (i = 0; i < rbg0width; i++) { u32 color, dot; if (!TestBothWindow(info->wctl, clip, i, j)) continue; x = GenerateRotatedXPosFP(p, i, xmul, ymul, C) & sinfo.xmask; y = GenerateRotatedYPosFP(p, i, xmul, ymul, F) & sinfo.ymask; // Convert coordinates into graphics if (!info->isbitmap) { // Tile Vdp2MapCalcXY(info, &x, &y, &sinfo, regs, ram,0); } // Fetch pixel if (!Vdp2FetchPixel(info, x, y, &color, &dot, ram, info->charaddr,info->paladdr, color_ram)) { continue; } Rbg0PutPixel(info, color, dot, i, j); } xmul += p->deltaXst; ymul += p->deltaYst; } return; } } else { fixed32 xmul, ymul, C, F; u32 coefx, coefy; u32 rcoefx, rcoefy; u32 lineAddr, lineColor, lineInc; u16 lineColorAddr; fixed32 xmul2, ymul2, C2, F2; u32 coefx2, coefy2; u32 rcoefx2, rcoefy2; screeninfo_struct sinfo2; vdp2rotationparameterfp_struct *p2 = NULL; clipping_struct rpwindow[2]; int userpwindow = 0; int isrplinewindow = 0; u32 rplinewnd0addr, rplinewnd1addr; if ((regs->RPMD & 3) == 2) p2 = ¶meter[1 - info->rotatenum]; else if ((regs->RPMD & 3) == 3) { ReadWindowData(regs->WCTLD, rpwindow, regs); rplinewnd0addr = rplinewnd1addr = 0; ReadLineWindowData(&isrplinewindow, regs->WCTLD, &rplinewnd0addr, &rplinewnd1addr, regs); userpwindow = 1; p2 = ¶meter[1 - info->rotatenum]; } GenerateRotatedVarFP(p, &xmul, &ymul, &C, &F); // Rotation using Coefficient Tables(now this stuff just gets wacky. It // has to be done in software, no exceptions) CalculateRotationValuesFP(p); SetupScreenVars(info, &sinfo, p->PlaneAddr, regs); coefx = coefy = 0; rcoefx = rcoefy = 0; if (p2 != NULL) { Vdp2ReadRotationTableFP(1 - info->rotatenum, p2, regs, ram); GenerateRotatedVarFP(p2, &xmul2, &ymul2, &C2, &F2); CalculateRotationValuesFP(p2); SetupScreenVars(info, &sinfo2, p2->PlaneAddr, regs); coefx2 = coefy2 = 0; rcoefx2 = rcoefy2 = 0; } if (Rbg0CheckRam(regs))//sonic r / all star baseball 97 { if (p->coefenab && p->coefmode == 0) { p->deltaKAx = 0; } if (p2 && p2->coefenab && p2->coefmode == 0) { p2->deltaKAx = 0; } } if (info->linescreen) { if ((info->rotatenum == 0) && (regs->KTCTL & 0x10)) info->linescreen = 2; else if (regs->KTCTL & 0x1000) info->linescreen = 3; if (regs->VRSIZE & 0x8000) lineAddr = (regs->LCTA.all & 0x7FFFF) << 1; else lineAddr = (regs->LCTA.all & 0x3FFFF) << 1; lineInc = regs->LCTA.part.U & 0x8000 ? 2 : 0; } for (j = 0; j < rbg0height; j++) { if (p->deltaKAx == 0) { Vdp2ReadCoefficientFP(p, p->coeftbladdr + (coefy + touint(rcoefy)) * p->coefdatasize, ram); } if ((p2 != NULL) && p2->coefenab && (p2->deltaKAx == 0)) { Vdp2ReadCoefficientFP(p2, p2->coeftbladdr + (coefy2 + touint(rcoefy2)) * p2->coefdatasize, ram); } if (info->linescreen > 1) { lineColorAddr = (T1ReadWord(ram, lineAddr) & 0x780) | p->linescreen; lineColor = Vdp2ColorRamGetColor(lineColorAddr, color_ram); lineAddr += lineInc; TitanPutLineHLine(info->linescreen, j, COLSAT2YAB32(0x3F, lineColor)); } info->LoadLineParams(info, &sinfo, j, lines); ReadLineWindowClip(info->islinewindow, clip, &linewnd0addr, &linewnd1addr, ram, regs); if (userpwindow) ReadLineWindowClip(isrplinewindow, rpwindow, &rplinewnd0addr, &rplinewnd1addr, ram, regs); for (i = 0; i < rbg0width; i++) { u32 color, dot; if (p->deltaKAx != 0) { Vdp2ReadCoefficientFP(p, p->coeftbladdr + (coefy + coefx + toint(rcoefx + rcoefy)) * p->coefdatasize, ram); coefx += toint(p->deltaKAx); rcoefx += decipart(p->deltaKAx); } if ((p2 != NULL) && p2->coefenab && (p2->deltaKAx != 0)) { Vdp2ReadCoefficientFP(p2, p2->coeftbladdr + (coefy2 + coefx2 + toint(rcoefx2 + rcoefy2)) * p2->coefdatasize, ram); coefx2 += toint(p2->deltaKAx); rcoefx2 += decipart(p2->deltaKAx); } if (!TestBothWindow(info->wctl, clip, i, j)) continue; if (((! userpwindow) && p->msb) || (userpwindow && (! TestBothWindow(regs->WCTLD, rpwindow, i, j)))) { if ((p2 == NULL) || (p2->coefenab && p2->msb)) continue; x = GenerateRotatedXPosFP(p2, i, xmul2, ymul2, C2); y = GenerateRotatedYPosFP(p2, i, xmul2, ymul2, F2); switch(p2->screenover) { case 0: x &= sinfo2.xmask; y &= sinfo2.ymask; break; case 1: VDP2LOG("Screen-over mode 1 not implemented"); x &= sinfo2.xmask; y &= sinfo2.ymask; break; case 2: if ((x > sinfo2.xmask) || (y > sinfo2.ymask)) continue; break; case 3: if ((x > 512) || (y > 512)) continue; } // Convert coordinates into graphics if (!info->isbitmap) { // Tile Vdp2MapCalcXY(info, &x, &y, &sinfo2, regs, ram, 0); } } else if (p->msb) continue; else { x = GenerateRotatedXPosFP(p, i, xmul, ymul, C); y = GenerateRotatedYPosFP(p, i, xmul, ymul, F); switch(p->screenover) { case 0: x &= sinfo.xmask; y &= sinfo.ymask; break; case 1: VDP2LOG("Screen-over mode 1 not implemented"); x &= sinfo.xmask; y &= sinfo.ymask; break; case 2: if ((x > sinfo.xmask) || (y > sinfo.ymask)) continue; break; case 3: if ((x > 512) || (y > 512)) continue; } // Convert coordinates into graphics if (!info->isbitmap) { // Tile Vdp2MapCalcXY(info, &x, &y, &sinfo, regs, ram, 0); } } // Fetch pixel if (!Vdp2FetchPixel(info, x, y, &color, &dot, ram, info->charaddr, info->paladdr, color_ram)) { continue; } Rbg0PutPixel(info, color, dot, i, j); } xmul += p->deltaXst; ymul += p->deltaYst; coefx = 0; rcoefx = 0; coefy += toint(p->deltaKAst); rcoefy += decipart(p->deltaKAst); if (p2 != NULL) { xmul2 += p2->deltaXst; ymul2 += p2->deltaYst; if (p2->coefenab) { coefx2 = 0; rcoefx2 = 0; coefy2 += toint(p2->deltaKAst); rcoefy2 += decipart(p2->deltaKAst); } } } return; } Vdp2DrawScroll(info, lines, regs, ram, color_ram, cell_data); } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawBackScreen(void) { int i, j; // Only draw black if TVMD's DISP and BDCLMD bits are cleared if ((Vdp2Regs->TVMD & 0x8000) == 0 && (Vdp2Regs->TVMD & 0x100) == 0) { // Draw Black for (j = 0; j < vdp2height; j++) TitanPutBackHLine(j, COLSAT2YAB32(0x3F, 0)); } else { // Draw Back Screen u32 scrAddr; u16 dot; vdp2draw_struct info = { 0 }; ReadVdp2ColorOffset(Vdp2Regs, &info, (1 << 5), 0); if (Vdp2Regs->VRSIZE & 0x8000) scrAddr = (((Vdp2Regs->BKTAU & 0x7) << 16) | Vdp2Regs->BKTAL) * 2; else scrAddr = (((Vdp2Regs->BKTAU & 0x3) << 16) | Vdp2Regs->BKTAL) * 2; if (Vdp2Regs->BKTAU & 0x8000) { // Per Line for (i = 0; i < vdp2height; i++) { dot = T1ReadWord(Vdp2Ram, scrAddr); scrAddr += 2; TitanPutBackHLine(i, info.PostPixelFetchCalc(&info, COLSAT2YAB16(0x3f, dot))); } } else { // Single Color dot = T1ReadWord(Vdp2Ram, scrAddr); for (j = 0; j < vdp2height; j++) TitanPutBackHLine(j, info.PostPixelFetchCalc(&info, COLSAT2YAB16(0x3f, dot))); } } } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawLineScreen(void) { u32 scrAddr; u16 color; u32 dot; int i; int alpha; /* no need to go further if no screen is using the line screen */ if (Vdp2Regs->LNCLEN == 0) return; if (Vdp2Regs->VRSIZE & 0x8000) scrAddr = (Vdp2Regs->LCTA.all & 0x7FFFF) << 1; else scrAddr = (Vdp2Regs->LCTA.all & 0x3FFFF) << 1; alpha = (Vdp2Regs->CCRLB & 0x1f) << 1; if (Vdp2Regs->LCTA.part.U & 0x8000) { /* per line */ for (i = 0; i < vdp2height; i++) { color = T1ReadWord(Vdp2Ram, scrAddr) & 0x7FF; dot = Vdp2ColorRamGetColor(color, Vdp2ColorRam); scrAddr += 2; TitanPutLineHLine(1, i, COLSAT2YAB32(alpha, dot)); } } else { /* single color, implemented but not tested... */ color = T1ReadWord(Vdp2Ram, scrAddr) & 0x7FF; dot = Vdp2ColorRamGetColor(color, Vdp2ColorRam); for (i = 0; i < vdp2height; i++) TitanPutLineHLine(1, i, COLSAT2YAB32(alpha, dot)); } } ////////////////////////////////////////////////////////////////////////////// static void LoadLineParamsNBG0(vdp2draw_struct * info, screeninfo_struct * sinfo, int line, Vdp2* lines) { Vdp2 * regs; regs = Vdp2RestoreRegs(line, lines); if (regs == NULL) return; ReadVdp2ColorOffset(regs, info, 0x1, 0x1); info->specialprimode = regs->SFPRMD & 0x3; info->enable = regs->BGON & 0x1 || regs->BGON & 0x20;//nbg0 or rbg1 GeneratePlaneAddrTable(info, sinfo->planetbl, info->PlaneAddr, regs);//sonic 2, 2 player mode } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawNBG0(Vdp2* lines, Vdp2* regs, u8* ram, u8* color_ram, struct CellScrollData * cell_data) { vdp2draw_struct info = { 0 }; vdp2rotationparameterfp_struct parameter[2]; info.titan_which_layer = TITAN_NBG0; info.titan_shadow_enabled = (regs->SDCTL >> 0) & 1; parameter[0].PlaneAddr = (void FASTCALL (*)(void *, int, Vdp2*))&Vdp2ParameterAPlaneAddr; parameter[1].PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2ParameterBPlaneAddr; if (regs->BGON & 0x20) { // RBG1 mode info.enable = regs->BGON & 0x20; // Read in Parameter B Vdp2ReadRotationTableFP(1, ¶meter[1], regs, ram); if((info.isbitmap = regs->CHCTLA & 0x2) != 0) { // Bitmap Mode ReadBitmapSize(&info, regs->CHCTLA >> 2, 0x3); info.charaddr = (regs->MPOFR & 0x70) * 0x2000; info.paladdr = (regs->BMPNA & 0x7) << 8; info.flipfunction = 0; info.specialfunction = 0; info.specialcolorfunction = (regs->BMPNA & 0x10) >> 4; } else { // Tile Mode info.mapwh = 4; ReadPlaneSize(&info, regs->PLSZ >> 12); ReadPatternData(&info, regs->PNCN0, regs->CHCTLA & 0x1); } info.rotatenum = 1; info.rotatemode = 0; info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2ParameterBPlaneAddr; } else if (regs->BGON & 0x1) { // NBG0 mode info.enable = regs->BGON & 0x1; if((info.isbitmap = regs->CHCTLA & 0x2) != 0) { // Bitmap Mode ReadBitmapSize(&info, regs->CHCTLA >> 2, 0x3); info.x = regs->SCXIN0 & 0x7FF; info.y = regs->SCYIN0 & 0x7FF; info.charaddr = (regs->MPOFN & 0x7) * 0x20000; info.paladdr = (regs->BMPNA & 0x7) << 8; info.flipfunction = 0; info.specialfunction = 0; info.specialcolorfunction = (regs->BMPNA & 0x10) >> 4; } else { // Tile Mode info.mapwh = 2; ReadPlaneSize(&info, regs->PLSZ); info.x = regs->SCXIN0 & 0x7FF; info.y = regs->SCYIN0 & 0x7FF; ReadPatternData(&info, regs->PNCN0, regs->CHCTLA & 0x1); } info.coordincx = (regs->ZMXN0.all & 0x7FF00) / (float) 65536; info.coordincy = (regs->ZMYN0.all & 0x7FF00) / (float) 65536; info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2NBG0PlaneAddr; } info.transparencyenable = !(regs->BGON & 0x100); info.specialprimode = regs->SFPRMD & 0x3; info.colornumber = (regs->CHCTLA & 0x70) >> 4; if (regs->CCCTL & 0x201) info.alpha = ((~regs->CCRNA & 0x1F) << 1) + 1; else info.alpha = 0x3F; if ((regs->CCCTL & 0x201) == 0x201) info.alpha |= 0x80; else if ((regs->CCCTL & 0x101) == 0x101) info.alpha |= 0x80; info.specialcolormode = regs->SFCCMD & 0x3; if (regs->SFSEL & 0x1) info.specialcode = regs->SFCODE >> 8; else info.specialcode = regs->SFCODE & 0xFF; info.linescreen = 0; if (regs->LNCLEN & 0x1) info.linescreen = 1; info.coloroffset = (regs->CRAOFA & 0x7) << 8; ReadVdp2ColorOffset(regs, &info, 0x1, 0x1); info.priority = regs->PRINA & 0x7; if (!(info.enable & Vdp2External.disptoggle)) return; ReadMosaicData(&info, 0x1, regs); ReadLineScrollData(&info, regs->SCRCTL & 0xFF, regs->LSTA0.all); if (regs->SCRCTL & 1) { info.isverticalscroll = 1; info.verticalscrolltbl = (regs->VCSTA.all & 0x7FFFE) << 1; if (regs->SCRCTL & 0x100) info.verticalscrollinc = 8; else info.verticalscrollinc = 4; } else info.isverticalscroll = 0; info.wctl = regs->WCTLA; info.LoadLineParams = (void (*)(void *, void *,int ,Vdp2*)) LoadLineParamsNBG0; if (info.enable == 1) { // NBG0 draw Vdp2DrawScroll(&info, lines, regs, ram, color_ram, cell_data); } else { // RBG1 draw Vdp2DrawRotationFP(&info, parameter, lines, regs, ram, color_ram, cell_data); } } ////////////////////////////////////////////////////////////////////////////// static void LoadLineParamsNBG1(vdp2draw_struct * info, screeninfo_struct * sinfo, int line, Vdp2* lines) { Vdp2 * regs; regs = Vdp2RestoreRegs(line, lines); if (regs == NULL) return; ReadVdp2ColorOffset(regs, info, 0x2, 0x2); info->specialprimode = (regs->SFPRMD >> 2) & 0x3; info->enable = regs->BGON & 0x2;//f1 challenge map when zoomed out GeneratePlaneAddrTable(info, sinfo->planetbl, info->PlaneAddr, regs); } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawNBG1(Vdp2* lines, Vdp2* regs, u8* ram, u8* color_ram, struct CellScrollData * cell_data) { vdp2draw_struct info = { 0 }; info.titan_which_layer = TITAN_NBG1; info.titan_shadow_enabled = (regs->SDCTL >> 1) & 1; info.enable = regs->BGON & 0x2; info.transparencyenable = !(regs->BGON & 0x200); info.specialprimode = (regs->SFPRMD >> 2) & 0x3; info.colornumber = (regs->CHCTLA & 0x3000) >> 12; if((info.isbitmap = regs->CHCTLA & 0x200) != 0) { ReadBitmapSize(&info, regs->CHCTLA >> 10, 0x3); info.x = regs->SCXIN1 & 0x7FF; info.y = regs->SCYIN1 & 0x7FF; info.charaddr = ((regs->MPOFN & 0x70) >> 4) * 0x20000; info.paladdr = regs->BMPNA & 0x700; info.flipfunction = 0; info.specialfunction = 0; info.specialcolorfunction = (regs->BMPNA & 0x1000) >> 12; } else { info.mapwh = 2; ReadPlaneSize(&info, regs->PLSZ >> 2); info.x = regs->SCXIN1 & 0x7FF; info.y = regs->SCYIN1 & 0x7FF; ReadPatternData(&info, regs->PNCN1, regs->CHCTLA & 0x100); } if (regs->CCCTL & 0x202) info.alpha = ((~regs->CCRNA & 0x1F00) >> 7) + 1; else info.alpha = 0x3F; if ((regs->CCCTL & 0x202) == 0x202) info.alpha |= 0x80; else if ((regs->CCCTL & 0x102) == 0x102) info.alpha |= 0x80; info.specialcolormode = (regs->SFCCMD >> 2) & 0x3; if (regs->SFSEL & 0x2) info.specialcode = regs->SFCODE >> 8; else info.specialcode = regs->SFCODE & 0xFF; info.linescreen = 0; if (regs->LNCLEN & 0x2) info.linescreen = 1; info.coloroffset = (regs->CRAOFA & 0x70) << 4; ReadVdp2ColorOffset(regs, &info, 0x2, 0x2); info.coordincx = (regs->ZMXN1.all & 0x7FF00) / (float) 65536; info.coordincy = (regs->ZMYN1.all & 0x7FF00) / (float) 65536; info.priority = (regs->PRINA >> 8) & 0x7; info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2NBG1PlaneAddr; if (!(info.enable & Vdp2External.disptoggle) || (regs->BGON & 0x1 && (regs->CHCTLA & 0x70) >> 4 == 4)) // If NBG0 16M mode is enabled, don't draw return; ReadMosaicData(&info, 0x2, regs); ReadLineScrollData(&info, regs->SCRCTL >> 8, regs->LSTA1.all); if (regs->SCRCTL & 0x100) { info.isverticalscroll = 1; if (regs->SCRCTL & 0x1) { info.verticalscrolltbl = 4 + ((regs->VCSTA.all & 0x7FFFE) << 1); info.verticalscrollinc = 8; } else { info.verticalscrolltbl = (regs->VCSTA.all & 0x7FFFE) << 1; info.verticalscrollinc = 4; } } else info.isverticalscroll = 0; info.wctl = regs->WCTLA >> 8; info.LoadLineParams = (void(*)(void *, void*, int, Vdp2*)) LoadLineParamsNBG1; Vdp2DrawScroll(&info, lines, regs, ram, color_ram, cell_data); } ////////////////////////////////////////////////////////////////////////////// static void LoadLineParamsNBG2(vdp2draw_struct * info, screeninfo_struct * sinfo, int line, Vdp2* lines) { Vdp2 * regs; regs = Vdp2RestoreRegs(line, lines); if (regs == NULL) return; ReadVdp2ColorOffset(regs, info, 0x4, 0x4); info->specialprimode = (regs->SFPRMD >> 4) & 0x3; info->enable = regs->BGON & 0x4; GeneratePlaneAddrTable(info, sinfo->planetbl, info->PlaneAddr, regs); } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawNBG2(Vdp2* lines, Vdp2* regs, u8* ram, u8* color_ram, struct CellScrollData * cell_data) { vdp2draw_struct info = { 0 }; info.titan_which_layer = TITAN_NBG2; info.titan_shadow_enabled = (regs->SDCTL >> 2) & 1; info.enable = regs->BGON & 0x4; info.transparencyenable = !(regs->BGON & 0x400); info.specialprimode = (regs->SFPRMD >> 4) & 0x3; info.colornumber = (regs->CHCTLB & 0x2) >> 1; info.mapwh = 2; ReadPlaneSize(&info, regs->PLSZ >> 4); info.x = regs->SCXN2 & 0x7FF; info.y = regs->SCYN2 & 0x7FF; ReadPatternData(&info, regs->PNCN2, regs->CHCTLB & 0x1); if (regs->CCCTL & 0x204) info.alpha = ((~regs->CCRNB & 0x1F) << 1) + 1; else info.alpha = 0x3F; if ((regs->CCCTL & 0x204) == 0x204) info.alpha |= 0x80; else if ((regs->CCCTL & 0x104) == 0x104) info.alpha |= 0x80; info.specialcolormode = (regs->SFCCMD >> 4) & 0x3; if (regs->SFSEL & 0x4) info.specialcode = regs->SFCODE >> 8; else info.specialcode = regs->SFCODE & 0xFF; info.linescreen = 0; if (regs->LNCLEN & 0x4) info.linescreen = 1; info.coloroffset = regs->CRAOFA & 0x700; ReadVdp2ColorOffset(regs, &info, 0x4, 0x4); info.coordincx = info.coordincy = 1; info.priority = regs->PRINB & 0x7; info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2NBG2PlaneAddr; if (!(info.enable & Vdp2External.disptoggle) || (regs->BGON & 0x1 && (regs->CHCTLA & 0x70) >> 4 >= 2)) // If NBG0 2048/32786/16M mode is enabled, don't draw return; ReadMosaicData(&info, 0x4, regs); info.islinescroll = 0; info.isverticalscroll = 0; info.wctl = regs->WCTLB; info.isbitmap = 0; info.LoadLineParams = (void(*)(void *,void*, int, Vdp2*)) LoadLineParamsNBG2; Vdp2DrawScroll(&info, lines, regs, ram, color_ram, cell_data); } ////////////////////////////////////////////////////////////////////////////// static void LoadLineParamsNBG3(vdp2draw_struct * info, screeninfo_struct * sinfo, int line, Vdp2* lines) { Vdp2 * regs; regs = Vdp2RestoreRegs(line, lines); if (regs == NULL) return; ReadVdp2ColorOffset(regs, info, 0x8, 0x8); info->specialprimode = (regs->SFPRMD >> 6) & 0x3; info->enable = regs->BGON & 0x8; GeneratePlaneAddrTable(info, sinfo->planetbl, info->PlaneAddr, regs); } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawNBG3(Vdp2* lines, Vdp2* regs, u8* ram, u8* color_ram, struct CellScrollData * cell_data) { vdp2draw_struct info = { 0 }; info.titan_which_layer = TITAN_NBG3; info.titan_shadow_enabled = (regs->SDCTL >> 3) & 1; info.enable = regs->BGON & 0x8; info.transparencyenable = !(regs->BGON & 0x800); info.specialprimode = (regs->SFPRMD >> 6) & 0x3; info.colornumber = (regs->CHCTLB & 0x20) >> 5; info.mapwh = 2; ReadPlaneSize(&info, regs->PLSZ >> 6); info.x = regs->SCXN3 & 0x7FF; info.y = regs->SCYN3 & 0x7FF; ReadPatternData(&info, regs->PNCN3, regs->CHCTLB & 0x10); if (regs->CCCTL & 0x208) info.alpha = ((~regs->CCRNB & 0x1F00) >> 7) + 1; else info.alpha = 0x3F; if ((regs->CCCTL & 0x208) == 0x208) info.alpha |= 0x80; else if ((regs->CCCTL & 0x108) == 0x108) info.alpha |= 0x80; info.specialcolormode = (regs->SFCCMD >> 6) & 0x3; if (regs->SFSEL & 0x8) info.specialcode = regs->SFCODE >> 8; else info.specialcode = regs->SFCODE & 0xFF; info.linescreen = 0; if (regs->LNCLEN & 0x8) info.linescreen = 1; info.coloroffset = (regs->CRAOFA & 0x7000) >> 4; ReadVdp2ColorOffset(regs, &info, 0x8, 0x8); info.coordincx = info.coordincy = 1; info.priority = (regs->PRINB >> 8) & 0x7; info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2NBG3PlaneAddr; if (!(info.enable & Vdp2External.disptoggle) || (regs->BGON & 0x1 && (regs->CHCTLA & 0x70) >> 4 == 4) || // If NBG0 16M mode is enabled, don't draw (regs->BGON & 0x2 && (regs->CHCTLA & 0x3000) >> 12 >= 2)) // If NBG1 2048/32786 is enabled, don't draw return; ReadMosaicData(&info, 0x8, regs); info.islinescroll = 0; info.isverticalscroll = 0; info.wctl = regs->WCTLB >> 8; info.isbitmap = 0; info.LoadLineParams = (void(*)(void *, void*, int, Vdp2*)) LoadLineParamsNBG3; Vdp2DrawScroll(&info, lines, regs, ram, color_ram, cell_data); } ////////////////////////////////////////////////////////////////////////////// static void LoadLineParamsRBG0(vdp2draw_struct * info, screeninfo_struct * sinfo, int line, Vdp2* lines) { Vdp2 * regs; regs = Vdp2RestoreRegs(line, lines); if (regs == NULL) return; ReadVdp2ColorOffset(regs, info, 0x10, 0x10); info->specialprimode = (regs->SFPRMD >> 8) & 0x3; } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawRBG0(Vdp2* lines, Vdp2* regs, u8* ram, u8* color_ram, struct CellScrollData * cell_data) { vdp2draw_struct info = { 0 }; vdp2rotationparameterfp_struct parameter[2]; info.titan_which_layer = TITAN_RBG0; info.titan_shadow_enabled = (regs->SDCTL >> 4) & 1; parameter[0].PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2ParameterAPlaneAddr; parameter[1].PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2ParameterBPlaneAddr; info.enable = regs->BGON & 0x10; info.priority = regs->PRIR & 0x7; if (!(info.enable & Vdp2External.disptoggle)) return; info.transparencyenable = !(regs->BGON & 0x1000); info.specialprimode = (regs->SFPRMD >> 8) & 0x3; info.colornumber = (regs->CHCTLB & 0x7000) >> 12; // Figure out which Rotation Parameter we're using switch (regs->RPMD & 0x3) { case 0: // Parameter A info.rotatenum = 0; info.rotatemode = 0; info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2ParameterAPlaneAddr; break; case 1: // Parameter B info.rotatenum = 1; info.rotatemode = 0; info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2ParameterBPlaneAddr; break; case 2: // Parameter A+B switched via coefficients case 3: // Parameter A+B switched via rotation parameter window default: info.rotatenum = 0; info.rotatemode = 1 + (regs->RPMD & 0x1); info.PlaneAddr = (void FASTCALL(*)(void *, int, Vdp2*))&Vdp2ParameterAPlaneAddr; break; } Vdp2ReadRotationTableFP(info.rotatenum, ¶meter[info.rotatenum], regs, ram); if((info.isbitmap = regs->CHCTLB & 0x200) != 0) { // Bitmap Mode ReadBitmapSize(&info, regs->CHCTLB >> 10, 0x1); if (info.rotatenum == 0) // Parameter A info.charaddr = (regs->MPOFR & 0x7) * 0x20000; else // Parameter B info.charaddr = (regs->MPOFR & 0x70) * 0x2000; info.paladdr = (regs->BMPNB & 0x7) << 8; info.flipfunction = 0; info.specialfunction = 0; info.specialcolorfunction = (regs->BMPNB & 0x10) >> 4; } else { // Tile Mode info.mapwh = 4; if (info.rotatenum == 0) // Parameter A ReadPlaneSize(&info, regs->PLSZ >> 8); else // Parameter B ReadPlaneSize(&info, regs->PLSZ >> 12); ReadPatternData(&info, regs->PNCR, regs->CHCTLB & 0x100); } if (regs->CCCTL & 0x210) info.alpha = ((~regs->CCRR & 0x1F) << 1) + 1; else info.alpha = 0x3F; if ((regs->CCCTL & 0x210) == 0x210) info.alpha |= 0x80; else if ((regs->CCCTL & 0x110) == 0x110) info.alpha |= 0x80; info.specialcolormode = (regs->SFCCMD >> 8) & 0x3; if (regs->SFSEL & 0x10) info.specialcode = regs->SFCODE >> 8; else info.specialcode = regs->SFCODE & 0xFF; info.linescreen = 0; if (regs->LNCLEN & 0x10) info.linescreen = 1; info.coloroffset = (regs->CRAOFB & 0x7) << 8; ReadVdp2ColorOffset(regs, &info, 0x10, 0x10); info.coordincx = info.coordincy = 1; ReadMosaicData(&info, 0x10, regs); info.islinescroll = 0; info.isverticalscroll = 0; info.wctl = regs->WCTLC; info.LoadLineParams = (void(*)(void *, void*, int, Vdp2*)) LoadLineParamsRBG0; Vdp2DrawRotationFP(&info, parameter, lines, regs, ram, color_ram, cell_data); } ////////////////////////////////////////////////////////////////////////////// static void LoadLineParamsSprite(vdp2draw_struct * info, int line, Vdp2* lines) { Vdp2 * regs; regs = Vdp2RestoreRegs(line, lines); if (regs == NULL) return; ReadVdp2ColorOffset(regs, info, 0x40, 0x40); } ////////////////////////////////////////////////////////////////////////////// struct { volatile int need_draw[6]; volatile int draw_finished[6]; Vdp2 lines[270]; Vdp2 regs; u8 ram[0x80000]; u8 color_ram[0x1000]; struct CellScrollData cell_scroll_data[270]; }vidsoft_thread_context; #define DECLARE_THREAD(NAME, LAYER, FUNC) \ void NAME(void * data) \ { \ for (;;) \ { \ if (vidsoft_thread_context.need_draw[LAYER]) \ { \ vidsoft_thread_context.need_draw[LAYER] = 0; \ FUNC(vidsoft_thread_context.lines, &vidsoft_thread_context.regs, vidsoft_thread_context.ram, vidsoft_thread_context.color_ram, vidsoft_thread_context.cell_scroll_data); \ vidsoft_thread_context.draw_finished[LAYER] = 1; \ } \ YabThreadSleep(); \ } \ } DECLARE_THREAD(VidsoftRbg0Thread, TITAN_RBG0, Vdp2DrawRBG0) DECLARE_THREAD(VidsoftNbg0Thread, TITAN_NBG0, Vdp2DrawNBG0) DECLARE_THREAD(VidsoftNbg1Thread, TITAN_NBG1, Vdp2DrawNBG1) DECLARE_THREAD(VidsoftNbg2Thread, TITAN_NBG2, Vdp2DrawNBG2) DECLARE_THREAD(VidsoftNbg3Thread, TITAN_NBG3, Vdp2DrawNBG3) ////////////////////////////////////////////////////////////////////////////// void VIDSoftSetNumLayerThreads(int num) { vidsoft_num_layer_threads = num; } ////////////////////////////////////////////////////////////////////////////// void VidsoftVdp1Thread(void* data) { for (;;) { if (vidsoft_vdp1_thread_context.need_draw) { vidsoft_vdp1_thread_context.need_draw = 0; Vdp1DrawCommands(vidsoft_vdp1_thread_context.ram, &vidsoft_vdp1_thread_context.regs, vidsoft_vdp1_thread_context.back_framebuffer); memcpy(vdp1backframebuffer, vidsoft_vdp1_thread_context.back_framebuffer, 0x40000); vidsoft_vdp1_thread_context.draw_finished = 1; } YabThreadSleep(); } } ////////////////////////////////////////////////////////////////////////////// void VidsoftWaitForVdp1Thread() { if (vidsoft_vdp1_thread_enabled) { while (!vidsoft_vdp1_thread_context.draw_finished){} } } ////////////////////////////////////////////////////////////////////////////// void VIDSoftSetVdp1ThreadEnable(int b) { vidsoft_vdp1_thread_enabled = b; } void VidsoftSpriteThread(void * data) { for (;;) { if (vidsoft_thread_context.need_draw[TITAN_SPRITE]) { vidsoft_thread_context.need_draw[TITAN_SPRITE] = 0; VidsoftDrawSprite(&vidsoft_thread_context.regs, sprite_window_mask, vdp1frontframebuffer, vidsoft_thread_context.ram, Vdp1Regs,vidsoft_thread_context.lines, vidsoft_thread_context.color_ram); vidsoft_thread_context.draw_finished[TITAN_SPRITE] = 1; } YabThreadSleep(); } } ////////////////////////////////////////////////////////////////////////////// int VIDSoftInit(void) { int i; if (TitanInit() == -1) return -1; if ((dispbuffer = (pixel_t *)calloc(sizeof(pixel_t), 704 * 512)) == NULL) return -1; // Initialize VDP1 framebuffer 1 if ((vdp1framebuffer[0] = (u8 *)calloc(sizeof(u8), 0x40000)) == NULL) return -1; // Initialize VDP1 framebuffer 2 if ((vdp1framebuffer[1] = (u8 *)calloc(sizeof(u8), 0x40000)) == NULL) return -1; vdp1backframebuffer = vdp1framebuffer[0]; vdp1frontframebuffer = vdp1framebuffer[1]; rbg0width = vdp2width = 320; vdp2height = 224; #ifdef USE_OPENGL VIDSoftSetupGL(); #endif for (i = 0; i < 6; i++) { vidsoft_thread_context.draw_finished[i] = 1; vidsoft_thread_context.need_draw[i] = 0; } vidsoft_vdp1_thread_context.need_draw = 0; vidsoft_vdp1_thread_context.draw_finished = 1; YabThreadStart(YAB_THREAD_VIDSOFT_VDP1, VidsoftVdp1Thread, 0); YabThreadStart(YAB_THREAD_VIDSOFT_LAYER_RBG0, VidsoftRbg0Thread, 0); YabThreadStart(YAB_THREAD_VIDSOFT_LAYER_NBG0, VidsoftNbg0Thread, 0); YabThreadStart(YAB_THREAD_VIDSOFT_LAYER_NBG1, VidsoftNbg1Thread, 0); YabThreadStart(YAB_THREAD_VIDSOFT_LAYER_NBG2, VidsoftNbg2Thread, 0); YabThreadStart(YAB_THREAD_VIDSOFT_LAYER_NBG3, VidsoftNbg3Thread, 0); YabThreadStart(YAB_THREAD_VIDSOFT_LAYER_SPRITE, VidsoftSpriteThread, 0); return 0; } ////////////////////////////////////////////////////////////////////////////// void VIDSoftSetBilinear(int b) { bilinear = b; } ////////////////////////////////////////////////////////////////////////////// void VIDSoftSetupGL(void) { #ifdef USE_OPENGL GLint status; GLint texAttrib; GLint posAttrib; // Shader sources const GLchar* vshader_src = "#version 330 core\n" "in vec2 position;" "in vec2 texcoord;" "out vec2 outcoord;" "void main() {" " outcoord = texcoord;" " gl_Position = vec4(position, 0.0, 1.0);" "}"; const GLchar* fshader_src = "#version 330 core\n" "in vec2 outcoord;" "out vec4 fragcolor;" "uniform sampler2D sattex;" "void main() {" " fragcolor = texture(sattex, outcoord);" "}"; const float vertices[16] = { -1.0f, -1.0f, // Vertex 1 (X, Y) -1.0f, 1.0f, // Vertex 2 (X, Y) 1.0f, -1.0f, // Vertex 3 (X, Y) 1.0f, 1.0f, // Vertex 4 (X, Y) 0.0, 1.0, // Texture 1 (X, Y) 0.0, 0.0, // Texture 2 (X, Y) 1.0, 1.0, // Texture 3 (X, Y) 1.0, 0.0 // Texture 4 (X, Y) }; outputwidth = vdp2width; outputheight = vdp2height; glewInit(); glGenVertexArrays(1, &vao); glBindVertexArray(vao); glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); vshader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vshader, 1, &vshader_src, NULL); glCompileShader(vshader); glGetShaderiv(vshader, GL_COMPILE_STATUS, &status); if (status == GL_FALSE) { YGLLOG("Failed to compile vertex shader\n"); } fshader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fshader, 1, &fshader_src, NULL); glCompileShader(fshader); glGetShaderiv(fshader, GL_COMPILE_STATUS, &status); if (status == GL_FALSE) { YGLLOG("Failed to compile fragment shader\n"); } gl_shader_prog = glCreateProgram(); glAttachShader(gl_shader_prog, vshader); glAttachShader(gl_shader_prog, fshader); glLinkProgram(gl_shader_prog); glValidateProgram(gl_shader_prog); glGetProgramiv(gl_shader_prog, GL_LINK_STATUS, &status); if (status == GL_FALSE) { YGLLOG("Failed to link shader program\n"); } glUseProgram(gl_shader_prog); posAttrib = glGetAttribLocation(gl_shader_prog, "position"); glEnableVertexAttribArray(posAttrib); glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0); texAttrib = glGetAttribLocation(gl_shader_prog, "texcoord"); glEnableVertexAttribArray(texAttrib); glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 0, (void*)(8 * sizeof(GLfloat))); glGenTextures(1, &gl_texture_id); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, gl_texture_id); if (bilinear) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glViewport(0, 0, outputwidth, outputheight); glUniform1i(glGetUniformLocation(gl_shader_prog, "sattex"), 0); #endif } ////////////////////////////////////////////////////////////////////////////// void VIDSoftDeInit(void) { if (dispbuffer) { free(dispbuffer); dispbuffer = NULL; } if (vdp1framebuffer[0]) free(vdp1framebuffer[0]); if (vdp1framebuffer[1]) free(vdp1framebuffer[1]); #ifdef USE_OPENGL if (gl_texture_id) { glDeleteTextures(1, &gl_texture_id); } if (gl_shader_prog) { glDeleteProgram(gl_shader_prog); } if (vshader) { glDeleteShader(vshader); } if (fshader) { glDeleteShader(fshader); } if (vao) { glDeleteVertexArrays(1, &vao); } if (vbo) { glDeleteBuffers(1, &vbo); } #endif } ////////////////////////////////////////////////////////////////////////////// static int IsFullscreen = 0; void VIDSoftResize(unsigned int w, unsigned int h, int on) { #ifdef USE_OPENGL IsFullscreen = on; glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, w, h); outputwidth = w; outputheight = h; #endif } ////////////////////////////////////////////////////////////////////////////// int VIDSoftIsFullscreen(void) { return IsFullscreen; } ////////////////////////////////////////////////////////////////////////////// int VIDSoftVdp1Reset(void) { Vdp1Regs->userclipX1 = Vdp1Regs->systemclipX1 = 0; Vdp1Regs->userclipY1 = Vdp1Regs->systemclipY1 = 0; Vdp1Regs->userclipX2 = Vdp1Regs->systemclipX2 = 512; Vdp1Regs->userclipY2 = Vdp1Regs->systemclipY2 = 256; return 0; } ////////////////////////////////////////////////////////////////////////////// void VIDSoftVdp1DrawStartBody(Vdp1* regs, u8 * back_framebuffer) { if (regs->FBCR & 8) vdp1interlace = 2; else vdp1interlace = 1; if (regs->TVMR & 0x1) { if (regs->TVMR & 0x2) { // Rotation 8-bit vdp1width = 512; vdp1height = 512; } else { // Normal 8-bit vdp1width = 1024; vdp1height = 256; } vdp1pixelsize = 1; } else { // Rotation/Normal 16-bit vdp1width = 512; vdp1height = 256; vdp1pixelsize = 2; } VIDSoftVdp1EraseFrameBuffer(regs, back_framebuffer); //night warriors doesn't set clipping most frames and uses //the last part of the vdp1 framebuffer as scratch ram //the previously set clipping values need to be reused } ////////////////////////////////////////////////////////////////////////////// void VIDSoftVdp1DrawStart() { if (vidsoft_vdp1_thread_enabled) { VidsoftWaitForVdp1Thread(); //take a snapshot of the vdp1 state, to be used by the thread memcpy(vidsoft_vdp1_thread_context.ram, Vdp1Ram, 0x80000); memcpy(&vidsoft_vdp1_thread_context.regs, Vdp1Regs, sizeof(Vdp1)); memcpy(vidsoft_vdp1_thread_context.back_framebuffer, vdp1backframebuffer, 0x40000); VIDSoftVdp1DrawStartBody(&vidsoft_vdp1_thread_context.regs, vidsoft_vdp1_thread_context.back_framebuffer); //start thread vidsoft_vdp1_thread_context.draw_finished = 0; vidsoft_vdp1_thread_context.need_draw = 1; YabThreadWake(YAB_THREAD_VIDSOFT_VDP1); Vdp1FakeDrawCommands(Vdp1Ram, Vdp1Regs); } else { VIDSoftVdp1DrawStartBody(Vdp1Regs, vdp1backframebuffer); Vdp1DrawCommands(Vdp1Ram, Vdp1Regs, vdp1backframebuffer); } } ////////////////////////////////////////////////////////////////////////////// void VIDSoftVdp1DrawEnd(void) { } ////////////////////////////////////////////////////////////////////////////// static INLINE u16 Vdp1ReadPattern16( u32 base, u32 offset , u8 * ram) { u16 dot = T1ReadByte(ram, (base + (offset >> 1)) & 0x7FFFF); if ((offset & 0x1) == 0) dot >>= 4; // Even pixel else dot &= 0xF; // Odd pixel return dot; } static INLINE u16 Vdp1ReadPattern64(u32 base, u32 offset, u8 * ram) { return T1ReadByte(ram, (base + offset) & 0x7FFFF) & 0x3F; } static INLINE u16 Vdp1ReadPattern128(u32 base, u32 offset, u8 * ram) { return T1ReadByte(ram, (base + offset) & 0x7FFFF) & 0x7F; } static INLINE u16 Vdp1ReadPattern256(u32 base, u32 offset, u8 * ram) { return T1ReadByte(ram, (base + offset) & 0x7FFFF) & 0xFF; } static INLINE u16 Vdp1ReadPattern64k(u32 base, u32 offset, u8 * ram) { return T1ReadWord(ram, ( base + 2*offset) & 0x7FFFF); } //////////////////////////////////////////////////////////////////////////////// static INLINE u32 alphablend16(u32 d, u32 s, u32 level) { int r,g,b,sr,sg,sb,dr,dg,db; int invlevel = 256-level; sr = s & 0x001f; dr = d & 0x001f; r = (sr*level + dr*invlevel)>>8; r&= 0x1f; sg = s & 0x03e0; dg = d & 0x03e0; g = (sg*level + dg*invlevel)>>8; g&= 0x03e0; sb = s & 0x7c00; db = d & 0x7c00; b = (sb*level + db*invlevel)>>8; b&= 0x7c00; return r|g|b; } typedef struct _COLOR_PARAMS { double r,g,b; } COLOR_PARAMS; COLOR_PARAMS leftColumnColor; int currentPixel; int currentPixelIsVisible; int characterWidth; int characterHeight; static int getpixel(int linenumber, int currentlineindex, vdp1cmd_struct *cmd, u8 * ram) { u32 characterAddress; u32 colorlut; u16 colorbank; u8 SPD; int endcode; int endcodesEnabled; int untexturedColor = 0; int isTextured = 1; int currentShape = cmd->CMDCTRL & 0x7; int flip; characterAddress = cmd->CMDSRCA << 3; colorbank = cmd->CMDCOLR; colorlut = (u32)colorbank << 3; SPD = ((cmd->CMDPMOD & 0x40) != 0);//show the actual color of transparent pixels if 1 (they won't be drawn transparent) endcodesEnabled = ((cmd->CMDPMOD & 0x80) == 0) ? 1 : 0; flip = (cmd->CMDCTRL & 0x30) >> 4; //4 polygon, 5 polyline or 6 line if(currentShape == 4 || currentShape == 5 || currentShape == 6) { isTextured = 0; untexturedColor = cmd->CMDCOLR; } switch( flip ) { case 1: // Horizontal flipping currentlineindex = characterWidth - currentlineindex-1; break; case 2: // Vertical flipping linenumber = characterHeight - linenumber-1; break; case 3: // Horizontal/Vertical flipping linenumber = characterHeight - linenumber-1; currentlineindex = characterWidth - currentlineindex-1; break; } switch ((cmd->CMDPMOD >> 3) & 0x7) { case 0x0: //4bpp bank endcode = 0xf; currentPixel = Vdp1ReadPattern16( characterAddress + (linenumber*(characterWidth>>1)), currentlineindex , ram); if(isTextured && endcodesEnabled && currentPixel == endcode) return 1; if (!((currentPixel == 0) && !SPD)) currentPixel = (colorbank &0xfff0)| currentPixel; currentPixelIsVisible = 0xf; break; case 0x1://4bpp lut endcode = 0xf; currentPixel = Vdp1ReadPattern16(characterAddress + (linenumber*(characterWidth >> 1)), currentlineindex, ram); if(isTextured && endcodesEnabled && currentPixel == endcode) return 1; if (!(currentPixel == 0 && !SPD)) currentPixel = T1ReadWord(ram, (currentPixel * 2 + colorlut) & 0x7FFFF); currentPixelIsVisible = 0xffff; break; case 0x2://8pp bank (64 color) //is there a hardware bug with endcodes in this color mode? //there are white lines around some characters in scud //using an endcode of 63 eliminates the white lines //but also causes some dropout due to endcodes being triggered that aren't triggered on hardware //the closest thing i can do to match the hardware is make all pixels with color index 63 transparent //this needs more hardware testing endcode = 63; currentPixel = Vdp1ReadPattern64(characterAddress + (linenumber*(characterWidth)), currentlineindex, ram); if(isTextured && endcodesEnabled && currentPixel == endcode) currentPixel = 0; // return 1; if (!((currentPixel == 0) && !SPD)) currentPixel = (colorbank&0xffc0) | currentPixel; currentPixelIsVisible = 0x3f; break; case 0x3://128 color endcode = 0xff; currentPixel = Vdp1ReadPattern128(characterAddress + (linenumber*characterWidth), currentlineindex, ram); if(isTextured && endcodesEnabled && currentPixel == endcode) return 1; if (!((currentPixel == 0) && !SPD)) currentPixel = (colorbank&0xff80) | currentPixel;//dead or alive needs colorbank to be masked currentPixelIsVisible = 0x7f; break; case 0x4://256 color endcode = 0xff; currentPixel = Vdp1ReadPattern256(characterAddress + (linenumber*characterWidth), currentlineindex, ram); if(isTextured && endcodesEnabled && currentPixel == endcode) return 1; currentPixelIsVisible = 0xff; if (!((currentPixel == 0) && !SPD)) currentPixel = (colorbank&0xff00) | currentPixel; break; case 0x5://16bpp bank endcode = 0x7fff; currentPixel = Vdp1ReadPattern64k(characterAddress + (linenumber*characterWidth * 2), currentlineindex, ram); if(isTextured && endcodesEnabled && currentPixel == endcode) return 1; /* the transparent pixel in 16bpp is supposed to be 0x0000 but some games use pixels with invalid values and expect them to be transparent (see vdp1 doc p. 92) */ if (!(currentPixel & 0x8000) && !SPD) currentPixel = 0; currentPixelIsVisible = 0xffff; break; } if(!isTextured) currentPixel = untexturedColor; //force the MSB to be on if MSBON is set //currentPixel |= cmd.CMDPMOD & (1 << 15); return 0; } static int gouraudAdjust( int color, int tableValue ) { color += (tableValue - 0x10); if ( color < 0 ) color = 0; if ( color > 0x1f ) color = 0x1f; return color; } static int CheckDil(int y, Vdp1 * regs) { int dil = (regs->FBCR >> 2) & 1; if (vdp1interlace == 2) { if (dil) { if ((y & 1) == 0) return 1; } else { if ((y & 1)) return 1; } } return 0; } static INLINE int IsUserClipped(int x, int y, Vdp1* regs) { return !(x >= regs->userclipX1 && x <= regs->userclipX2 && y >= regs->userclipY1 && y <= regs->userclipY2); } static INLINE int IsSystemClipped(int x, int y, Vdp1* regs) { return !(x >= 0 && x <= regs->systemclipX2 && y >= 0 && y <= regs->systemclipY2); } int IsClipped(int x, int y, Vdp1* regs, vdp1cmd_struct * cmd) { if (cmd->CMDPMOD & 0x0400)//user clipping enabled { int is_user_clipped = IsUserClipped(x, y, regs); if (((cmd->CMDPMOD >> 9) & 0x3) == 0x3)//outside clipping mode is_user_clipped = !is_user_clipped; return is_user_clipped || IsSystemClipped(x, y, regs); } else { return IsSystemClipped(x, y, regs); } } static void putpixel8(int x, int y, Vdp1 * regs, vdp1cmd_struct *cmd, u8 * back_framebuffer) { int y2 = y / vdp1interlace; u8 * iPix = &back_framebuffer[(y2 * vdp1width) + x]; int mesh = cmd->CMDPMOD & 0x0100; int SPD = ((cmd->CMDPMOD & 0x40) != 0);//show the actual color of transparent pixels if 1 (they won't be drawn transparent) if (iPix >= (back_framebuffer + 0x40000)) return; if (CheckDil(y, regs)) return; currentPixel &= 0xFF; if (mesh && ((x ^ y2) & 1)) { return; } if (IsClipped(x, y, regs, cmd)) return; if ( SPD || (currentPixel & currentPixelIsVisible)) { switch( cmd->CMDPMOD & 0x7 )//we want bits 0,1,2 { default: case 0: // replace if (!((currentPixel == 0) && !SPD)) *(iPix) = currentPixel; break; } } } static void putpixel(int x, int y, Vdp1* regs, vdp1cmd_struct * cmd, u8 * back_framebuffer) { u16* iPix; int mesh = cmd->CMDPMOD & 0x0100; int SPD = ((cmd->CMDPMOD & 0x40) != 0);//show the actual color of transparent pixels if 1 (they won't be drawn transparent) int original_y = y; if (CheckDil(y, regs)) return; y /= vdp1interlace; iPix = &((u16 *)back_framebuffer)[(y * vdp1width) + x]; if (iPix >= (u16*)(back_framebuffer + 0x40000)) return; if(mesh && (x^y)&1) return; if (IsClipped(x, original_y, regs, cmd)) return; if (cmd->CMDPMOD & (1 << 15)) { if (currentPixel) { *iPix |= 0x8000; return; } } if ( SPD || (currentPixel & currentPixelIsVisible)) { switch( cmd->CMDPMOD & 0x7 )//we want bits 0,1,2 { case 0: // replace if (!((currentPixel == 0) && !SPD)) *(iPix) = currentPixel; break; case 1: // shadow if (*(iPix) & (1 << 15)) // only if MSB of framebuffer data is set *(iPix) = alphablend16(*(iPix), 0, (1 << 7)) | (1 << 15); break; case 2: // half luminance *(iPix) = ((currentPixel & ~0x8421) >> 1) | (1 << 15); break; case 3: // half transparent if ( *(iPix) & (1 << 15) )//only if MSB of framebuffer data is set *(iPix) = alphablend16( *(iPix), currentPixel, (1 << 7) ) | (1 << 15); else *(iPix) = currentPixel; break; case 4: //gouraud #define COLOR(r,g,b) (((r)&0x1F)|(((g)&0x1F)<<5)|(((b)&0x1F)<<10) |0x8000 ) //handle the special case demonstrated in the sgl chrome demo //if we are in a paletted bank mode and the other two colors are unused, adjust the index value instead of rgb if( (((cmd->CMDPMOD >> 3) & 0x7) != 5) && (((cmd->CMDPMOD >> 3) & 0x7) != 1) && (int)leftColumnColor.g == 16 && (int)leftColumnColor.b == 16) { int c = (int)(leftColumnColor.r-0x10); if(c < 0) c = 0; currentPixel = currentPixel+c; *(iPix) = currentPixel; break; } *(iPix) = COLOR( gouraudAdjust( currentPixel&0x001F, (int)leftColumnColor.r), gouraudAdjust( (currentPixel&0x03e0) >> 5, (int)leftColumnColor.g), gouraudAdjust( (currentPixel&0x7c00) >> 10, (int)leftColumnColor.b) ); break; default: *(iPix) = alphablend16( COLOR((int)leftColumnColor.r,(int)leftColumnColor.g, (int)leftColumnColor.b), currentPixel, (1 << 7) ) | (1 << 15); break; } } } static int iterateOverLine(int x1, int y1, int x2, int y2, int greedy, void *data, int(*line_callback)(int x, int y, int i, void *data, Vdp1* regs, vdp1cmd_struct * cmd, u8* ram, u8* back_framebuffer), Vdp1* regs, vdp1cmd_struct * cmd, u8 * ram, u8* back_framebuffer) { int i, a, ax, ay, dx, dy; a = i = 0; dx = x2 - x1; dy = y2 - y1; ax = (dx >= 0) ? 1 : -1; ay = (dy >= 0) ? 1 : -1; //burning rangers tries to draw huge shapes //this will at least let it run if(abs(dx) > 999 || abs(dy) > 999) return INT_MAX; if (abs(dx) > abs(dy)) { if (ax != ay) dx = -dx; for (; x1 != x2; x1 += ax, i++) { if (line_callback && line_callback(x1, y1, i, data, regs, cmd, ram, back_framebuffer) != 0) return i + 1; a += dy; if (abs(a) >= abs(dx)) { a -= dx; y1 += ay; // Make sure we 'fill holes' the same as the Saturn if (greedy) { i ++; if (ax == ay) { if (line_callback && line_callback(x1 + ax, y1 - ay, i, data, regs, cmd, ram, back_framebuffer) != 0) return i + 1; } else { if (line_callback && line_callback(x1, y1, i, data, regs, cmd, ram, back_framebuffer) != 0) return i + 1; } } } } // If the line isn't greedy here, we end up with gaps that don't occur on the Saturn if (/*(i == 0) || (y1 != y2)*/1) { if (line_callback) line_callback(x2, y2, i, data, regs, cmd, ram, back_framebuffer); i ++; } } else { if (ax != ay) dy = -dy; for (; y1 != y2; y1 += ay, i++) { if (line_callback && line_callback(x1, y1, i, data, regs, cmd, ram, back_framebuffer) != 0) return i + 1; a += dx; if (abs(a) >= abs(dy)) { a -= dy; x1 += ax; if (greedy) { i ++; if (ay == ax) { if (line_callback && line_callback(x1, y1, i, data, regs, cmd, ram, back_framebuffer) != 0) return i + 1; } else { if (line_callback && line_callback(x1 - ax, y1 + ay, i, data, regs, cmd, ram, back_framebuffer) != 0) return i + 1; } } } } if (/*(i == 0) || (y1 != y2)*/1) { if (line_callback) line_callback(x2, y2, i, data, regs, cmd, ram, back_framebuffer); i ++; } } return i; } typedef struct { double linenumber; double texturestep; double xredstep; double xgreenstep; double xbluestep; int endcodesdetected; int previousStep; } DrawLineData; static int DrawLineCallback(int x, int y, int i, void *data, Vdp1* regs, vdp1cmd_struct * cmd, u8* ram, u8* back_framebuffer) { int currentStep; DrawLineData *linedata = data; leftColumnColor.r += linedata->xredstep; leftColumnColor.g += linedata->xgreenstep; leftColumnColor.b += linedata->xbluestep; currentStep = (int)i * linedata->texturestep; if (getpixel(linedata->linenumber, currentStep, cmd, ram)) { if (currentStep != linedata->previousStep) { linedata->previousStep = currentStep; linedata->endcodesdetected ++; } } else if (vdp1pixelsize == 2) { putpixel(x, y, regs, cmd, back_framebuffer); } else { putpixel8(x, y, regs, cmd, back_framebuffer); } if (linedata->endcodesdetected == 2) return -1; return 0; } static int DrawLine(int x1, int y1, int x2, int y2, int greedy, double linenumber, double texturestep, double xredstep, double xgreenstep, double xbluestep, Vdp1* regs, vdp1cmd_struct *cmd, u8 * ram, u8* back_framebuffer) { DrawLineData data; data.linenumber = linenumber; data.texturestep = texturestep; data.xredstep = xredstep; data.xgreenstep = xgreenstep; data.xbluestep = xbluestep; data.endcodesdetected = 0; data.previousStep = 123456789; return iterateOverLine(x1, y1, x2, y2, greedy, &data, DrawLineCallback, regs, cmd, ram, back_framebuffer); } static INLINE double interpolate(double start, double end, int numberofsteps) { double stepvalue = 0; if(numberofsteps == 0) return 1; stepvalue = (end - start) / numberofsteps; return stepvalue; } typedef union _COLOR { // xbgr x555 struct { #ifdef WORDS_BIGENDIAN u16 x:1; u16 b:5; u16 g:5; u16 r:5; #else u16 r:5; u16 g:5; u16 b:5; u16 x:1; #endif }; u16 value; } COLOR; COLOR gouraudA; COLOR gouraudB; COLOR gouraudC; COLOR gouraudD; static void gouraudTable(u8* ram, Vdp1* regs, vdp1cmd_struct * cmd) { int gouraudTableAddress; gouraudTableAddress = (((unsigned int)cmd->CMDGRDA) << 3); gouraudA.value = T1ReadWord(ram, gouraudTableAddress); gouraudB.value = T1ReadWord(ram, gouraudTableAddress + 2); gouraudC.value = T1ReadWord(ram, gouraudTableAddress + 4); gouraudD.value = T1ReadWord(ram, gouraudTableAddress + 6); } int xleft[1000]; int yleft[1000]; int xright[1000]; int yright[1000]; static int storeLineCoords(int x, int y, int i, void *arrays, Vdp1* regs, vdp1cmd_struct * cmd, u8* ram, u8* back_framebuffer) { int **intArrays = arrays; intArrays[0][i] = x; intArrays[1][i] = y; return 0; } //skip objects that are completely outside of system clipping int is_pre_clipped(s16 tl_x, s16 tl_y, s16 bl_x, s16 bl_y, s16 tr_x, s16 tr_y, s16 br_x, s16 br_y, Vdp1* regs) { int y_val = regs->systemclipY2; if (vdp1interlace) y_val *= 2; //if all x values are to the left of the screen if ((tl_x < 0) && (bl_x < 0) && (tr_x < 0) && (br_x < 0)) return 1; //to the right if ((tl_x > regs->systemclipX2) && (bl_x > regs->systemclipX2) && (tr_x > regs->systemclipX2) && (br_x > regs->systemclipX2)) return 1; //above if ((tl_y < 0) && (bl_y < 0) && (tr_y < 0) && (br_y < 0)) return 1; //below if ((tl_y > y_val) && (bl_y > y_val) && (tr_y > y_val) && (br_y > y_val)) return 1; return 0; } //a real vdp1 draws with arbitrary lines //this is why endcodes are possible //this is also the reason why half-transparent shading causes moire patterns //and the reason why gouraud shading can be applied to a single line draw command static void drawQuad(s16 tl_x, s16 tl_y, s16 bl_x, s16 bl_y, s16 tr_x, s16 tr_y, s16 br_x, s16 br_y, u8 * ram, Vdp1* regs, vdp1cmd_struct * cmd, u8* back_framebuffer){ int totalleft; int totalright; int total; int i; int *intarrays[2]; COLOR_PARAMS topLeftToBottomLeftColorStep = {0,0,0}, topRightToBottomRightColorStep = {0,0,0}; //how quickly we step through the line arrays double leftLineStep = 1; double rightLineStep = 1; //a lookup table for the gouraud colors COLOR colors[4]; if (is_pre_clipped(tl_x, tl_y, bl_x, bl_y, tr_x, tr_y, br_x, br_y, regs)) return; characterWidth = ((cmd->CMDSIZE >> 8) & 0x3F) * 8; characterHeight = cmd->CMDSIZE & 0xFF; intarrays[0] = xleft; intarrays[1] = yleft; totalleft = iterateOverLine(tl_x, tl_y, bl_x, bl_y, 0, intarrays, storeLineCoords, regs, cmd, ram, back_framebuffer); intarrays[0] = xright; intarrays[1] = yright; totalright = iterateOverLine(tr_x, tr_y, br_x, br_y, 0, intarrays, storeLineCoords, regs, cmd, ram, back_framebuffer); //just for now since burning rangers will freeze up trying to draw huge shapes if(totalleft == INT_MAX || totalright == INT_MAX) return; total = totalleft > totalright ? totalleft : totalright; if (cmd->CMDPMOD & (1 << 2)) { gouraudTable(ram, regs, cmd); { colors[0] = gouraudA; colors[1] = gouraudD; colors[2] = gouraudB; colors[3] = gouraudC; } topLeftToBottomLeftColorStep.r = interpolate(colors[0].r,colors[1].r,total); topLeftToBottomLeftColorStep.g = interpolate(colors[0].g,colors[1].g,total); topLeftToBottomLeftColorStep.b = interpolate(colors[0].b,colors[1].b,total); topRightToBottomRightColorStep.r = interpolate(colors[2].r,colors[3].r,total); topRightToBottomRightColorStep.g = interpolate(colors[2].g,colors[3].g,total); topRightToBottomRightColorStep.b = interpolate(colors[2].b,colors[3].b,total); } //we have to step the equivalent of less than one pixel on the shorter side //to make sure textures stretch properly and the shape is correct if(total == totalleft && totalleft != totalright) { //left side is larger leftLineStep = 1; rightLineStep = (double)totalright / totalleft; } else if(totalleft != totalright){ //right side is larger rightLineStep = 1; leftLineStep = (double)totalleft / totalright; } for(i = 0; i < total; i++) { int xlinelength; double xtexturestep; double ytexturestep; COLOR_PARAMS rightColumnColor; COLOR_PARAMS leftToRightStep = {0,0,0}; //get the length of the line we are about to draw xlinelength = iterateOverLine( xleft[(int)(i*leftLineStep)], yleft[(int)(i*leftLineStep)], xright[(int)(i*rightLineStep)], yright[(int)(i*rightLineStep)], 1, NULL, NULL, regs, cmd, ram, back_framebuffer); //so from 0 to the width of the texture / the length of the line is how far we need to step xtexturestep=interpolate(0,characterWidth,xlinelength); //now we need to interpolate the y texture coordinate across multiple lines ytexturestep=interpolate(0,characterHeight,total); //gouraud interpolation if(cmd->CMDPMOD & (1 << 2)) { //for each new line we need to step once more through each column //and add the orignal color + the number of steps taken times the step value to the bottom of the shape //to get the current colors to use to interpolate across the line leftColumnColor.r = colors[0].r +(topLeftToBottomLeftColorStep.r*i); leftColumnColor.g = colors[0].g +(topLeftToBottomLeftColorStep.g*i); leftColumnColor.b = colors[0].b +(topLeftToBottomLeftColorStep.b*i); rightColumnColor.r = colors[2].r +(topRightToBottomRightColorStep.r*i); rightColumnColor.g = colors[2].g +(topRightToBottomRightColorStep.g*i); rightColumnColor.b = colors[2].b +(topRightToBottomRightColorStep.b*i); //interpolate colors across to get the right step values leftToRightStep.r = interpolate(leftColumnColor.r,rightColumnColor.r,xlinelength); leftToRightStep.g = interpolate(leftColumnColor.g,rightColumnColor.g,xlinelength); leftToRightStep.b = interpolate(leftColumnColor.b,rightColumnColor.b,xlinelength); } DrawLine( xleft[(int)(i*leftLineStep)], yleft[(int)(i*leftLineStep)], xright[(int)(i*rightLineStep)], yright[(int)(i*rightLineStep)], 1, ytexturestep*i, xtexturestep, leftToRightStep.r, leftToRightStep.g, leftToRightStep.b, regs, cmd, ram, back_framebuffer ); } } void VIDSoftVdp1NormalSpriteDraw(u8 * ram, Vdp1 * regs, u8 * back_framebuffer) { s16 topLeftx,topLefty,topRightx,topRighty,bottomRightx,bottomRighty,bottomLeftx,bottomLefty; int spriteWidth; int spriteHeight; vdp1cmd_struct cmd; Vdp1ReadCommand(&cmd, regs->addr, ram); topLeftx = cmd.CMDXA + regs->localX; topLefty = cmd.CMDYA + regs->localY; spriteWidth = ((cmd.CMDSIZE >> 8) & 0x3F) * 8; spriteHeight = cmd.CMDSIZE & 0xFF; topRightx = topLeftx + (spriteWidth - 1); topRighty = topLefty; bottomRightx = topLeftx + (spriteWidth - 1); bottomRighty = topLefty + (spriteHeight - 1); bottomLeftx = topLeftx; bottomLefty = topLefty + (spriteHeight - 1); drawQuad(topLeftx, topLefty, bottomLeftx, bottomLefty, topRightx, topRighty, bottomRightx, bottomRighty, ram, regs, &cmd, back_framebuffer); } void VIDSoftVdp1ScaledSpriteDraw(u8* ram, Vdp1*regs, u8 * back_framebuffer){ s32 topLeftx,topLefty,topRightx,topRighty,bottomRightx,bottomRighty,bottomLeftx,bottomLefty; int x0,y0,x1,y1; vdp1cmd_struct cmd; Vdp1ReadCommand(&cmd, regs->addr, ram); x0 = cmd.CMDXA + regs->localX; y0 = cmd.CMDYA + regs->localY; switch ((cmd.CMDCTRL >> 8) & 0xF) { case 0x0: // Only two coordinates default: x1 = ((int)cmd.CMDXC) - x0 + regs->localX + 1; y1 = ((int)cmd.CMDYC) - y0 + regs->localY + 1; break; case 0x5: // Upper-left x1 = ((int)cmd.CMDXB) + 1; y1 = ((int)cmd.CMDYB) + 1; break; case 0x6: // Upper-Center x1 = ((int)cmd.CMDXB); y1 = ((int)cmd.CMDYB); x0 = x0 - x1/2; x1++; y1++; break; case 0x7: // Upper-Right x1 = ((int)cmd.CMDXB); y1 = ((int)cmd.CMDYB); x0 = x0 - x1; x1++; y1++; break; case 0x9: // Center-left x1 = ((int)cmd.CMDXB); y1 = ((int)cmd.CMDYB); y0 = y0 - y1/2; x1++; y1++; break; case 0xA: // Center-center x1 = ((int)cmd.CMDXB); y1 = ((int)cmd.CMDYB); x0 = x0 - x1/2; y0 = y0 - y1/2; x1++; y1++; break; case 0xB: // Center-right x1 = ((int)cmd.CMDXB); y1 = ((int)cmd.CMDYB); x0 = x0 - x1; y0 = y0 - y1/2; x1++; y1++; break; case 0xD: // Lower-left x1 = ((int)cmd.CMDXB); y1 = ((int)cmd.CMDYB); y0 = y0 - y1; x1++; y1++; break; case 0xE: // Lower-center x1 = ((int)cmd.CMDXB); y1 = ((int)cmd.CMDYB); x0 = x0 - x1/2; y0 = y0 - y1; x1++; y1++; break; case 0xF: // Lower-right x1 = ((int)cmd.CMDXB); y1 = ((int)cmd.CMDYB); x0 = x0 - x1; y0 = y0 - y1; x1++; y1++; break; } topLeftx = x0; topLefty = y0; topRightx = x1+x0 - 1; topRighty = topLefty; bottomRightx = x1+x0 - 1; bottomRighty = y1+y0 - 1; bottomLeftx = topLeftx; bottomLefty = y1+y0 - 1; drawQuad(topLeftx, topLefty, bottomLeftx, bottomLefty, topRightx, topRighty, bottomRightx, bottomRighty, ram, regs, &cmd, back_framebuffer); } void VIDSoftVdp1DistortedSpriteDraw(u8* ram, Vdp1*regs, u8 * back_framebuffer) { s32 xa,ya,xb,yb,xc,yc,xd,yd; vdp1cmd_struct cmd; Vdp1ReadCommand(&cmd, regs->addr, ram); xa = (s32)(cmd.CMDXA + regs->localX); ya = (s32)(cmd.CMDYA + regs->localY); xb = (s32)(cmd.CMDXB + regs->localX); yb = (s32)(cmd.CMDYB + regs->localY); xc = (s32)(cmd.CMDXC + regs->localX); yc = (s32)(cmd.CMDYC + regs->localY); xd = (s32)(cmd.CMDXD + regs->localX); yd = (s32)(cmd.CMDYD + regs->localY); drawQuad(xa, ya, xd, yd, xb, yb, xc, yc, ram, regs, &cmd, back_framebuffer); } static void gouraudLineSetup(double * redstep, double * greenstep, double * bluestep, int length, COLOR table1, COLOR table2, u8* ram, Vdp1* regs, vdp1cmd_struct * cmd, u8 * back_framebuffer) { gouraudTable(ram ,regs, cmd); *redstep =interpolate(table1.r,table2.r,length); *greenstep =interpolate(table1.g,table2.g,length); *bluestep =interpolate(table1.b,table2.b,length); leftColumnColor.r = table1.r; leftColumnColor.g = table1.g; leftColumnColor.b = table1.b; } void VIDSoftVdp1PolylineDraw(u8* ram, Vdp1*regs, u8 * back_framebuffer) { int X[4]; int Y[4]; double redstep = 0, greenstep = 0, bluestep = 0; int length; vdp1cmd_struct cmd; Vdp1ReadCommand(&cmd, regs->addr, ram); X[0] = (int)regs->localX + (int)((s16)T1ReadWord(ram, regs->addr + 0x0C)); Y[0] = (int)regs->localY + (int)((s16)T1ReadWord(ram, regs->addr + 0x0E)); X[1] = (int)regs->localX + (int)((s16)T1ReadWord(ram, regs->addr + 0x10)); Y[1] = (int)regs->localY + (int)((s16)T1ReadWord(ram, regs->addr + 0x12)); X[2] = (int)regs->localX + (int)((s16)T1ReadWord(ram, regs->addr + 0x14)); Y[2] = (int)regs->localY + (int)((s16)T1ReadWord(ram, regs->addr + 0x16)); X[3] = (int)regs->localX + (int)((s16)T1ReadWord(ram, regs->addr + 0x18)); Y[3] = (int)regs->localY + (int)((s16)T1ReadWord(ram, regs->addr + 0x1A)); length = iterateOverLine(X[0], Y[0], X[1], Y[1], 1, NULL, NULL, regs, &cmd, ram, back_framebuffer); gouraudLineSetup(&redstep, &greenstep, &bluestep, length, gouraudA, gouraudB, ram, regs, &cmd, back_framebuffer); DrawLine(X[0], Y[0], X[1], Y[1], 0, 0, 0, redstep, greenstep, bluestep, regs, &cmd, ram, back_framebuffer); length = iterateOverLine(X[1], Y[1], X[2], Y[2], 1, NULL, NULL, regs, &cmd, ram, back_framebuffer); gouraudLineSetup(&redstep, &greenstep, &bluestep, length, gouraudB, gouraudC, ram, regs, &cmd, back_framebuffer); DrawLine(X[1], Y[1], X[2], Y[2], 0, 0, 0, redstep, greenstep, bluestep, regs, &cmd, ram, back_framebuffer); length = iterateOverLine(X[2], Y[2], X[3], Y[3], 1, NULL, NULL, regs, &cmd, ram, back_framebuffer); gouraudLineSetup(&redstep, &greenstep, &bluestep, length, gouraudD, gouraudC, ram, regs, &cmd, back_framebuffer); DrawLine(X[3], Y[3], X[2], Y[2], 0, 0, 0, redstep, greenstep, bluestep, regs, &cmd, ram, back_framebuffer); length = iterateOverLine(X[3], Y[3], X[0], Y[0], 1, NULL, NULL, regs, &cmd, ram, back_framebuffer); gouraudLineSetup(&redstep, &greenstep, &bluestep, length, gouraudA, gouraudD, ram, regs, &cmd, back_framebuffer); DrawLine(X[0], Y[0], X[3], Y[3], 0, 0, 0, redstep, greenstep, bluestep, regs, &cmd, ram, back_framebuffer); } void VIDSoftVdp1LineDraw(u8* ram, Vdp1*regs, u8* back_framebuffer) { int x1, y1, x2, y2; double redstep = 0, greenstep = 0, bluestep = 0; int length; vdp1cmd_struct cmd; Vdp1ReadCommand(&cmd, regs->addr, ram); x1 = (int)regs->localX + (int)((s16)T1ReadWord(ram, regs->addr + 0x0C)); y1 = (int)regs->localY + (int)((s16)T1ReadWord(ram, regs->addr + 0x0E)); x2 = (int)regs->localX + (int)((s16)T1ReadWord(ram, regs->addr + 0x10)); y2 = (int)regs->localY + (int)((s16)T1ReadWord(ram, regs->addr + 0x12)); length = iterateOverLine(x1, y1, x2, y2, 1, NULL, NULL, regs, &cmd, ram, back_framebuffer); gouraudLineSetup(&redstep, &bluestep, &greenstep, length, gouraudA, gouraudB, ram, regs, &cmd, back_framebuffer); DrawLine(x1, y1, x2, y2, 0, 0, 0, redstep, greenstep, bluestep, regs, &cmd, ram, back_framebuffer); } ////////////////////////////////////////////////////////////////////////////// void VIDSoftVdp1UserClipping(u8* ram, Vdp1*regs) { regs->userclipX1 = T1ReadWord(ram, regs->addr + 0xC); regs->userclipY1 = T1ReadWord(ram, regs->addr + 0xE); regs->userclipX2 = T1ReadWord(ram, regs->addr + 0x14); regs->userclipY2 = T1ReadWord(ram, regs->addr + 0x16); } ////////////////////////////////////////////////////////////////////////////// void VIDSoftVdp1SystemClipping(u8* ram, Vdp1*regs) { regs->systemclipX1 = 0; regs->systemclipY1 = 0; regs->systemclipX2 = T1ReadWord(ram, regs->addr + 0x14); regs->systemclipY2 = T1ReadWord(ram, regs->addr + 0x16); } ////////////////////////////////////////////////////////////////////////////// void VIDSoftVdp1LocalCoordinate(u8* ram, Vdp1*regs) { regs->localX = T1ReadWord(ram, regs->addr + 0xC); regs->localY = T1ReadWord(ram, regs->addr + 0xE); } ////////////////////////////////////////////////////////////////////////////// void VIDSoftVdp1ReadFrameBuffer(u32 type, u32 addr, void * out) { u32 val; VidsoftWaitForVdp1Thread(); switch (type) { case 0: val = T1ReadByte(vdp1backframebuffer, addr); *(u8*)out = val; break; case 1: val = T1ReadWord(vdp1backframebuffer, addr); #ifndef WORDS_BIGENDIAN val = BSWAP16L(val); #endif *(u16*)out = val; break; case 2: #if 0 //enable when burning rangers is fixed val = T1ReadLong(vdp1backframebuffer, addr); #ifndef WORDS_BIGENDIAN val = BSWAP32(val); #endif val = (val & 0xffff) << 16 | (val & 0xffff0000) >> 16; *(u32*)out = val; #else *(u32*)out = 0; #endif break; default: break; } } ////////////////////////////////////////////////////////////////////////////// void VIDSoftVdp1WriteFrameBuffer(u32 type, u32 addr, u32 val) { VidsoftWaitForVdp1Thread(); switch (type) { case 0: T1WriteByte(vdp1backframebuffer, addr, val); break; case 1: #ifndef WORDS_BIGENDIAN val = BSWAP16L(val); #endif T1WriteWord(vdp1backframebuffer, addr, val); break; case 2: #ifndef WORDS_BIGENDIAN val = BSWAP32(val); #endif val = (val & 0xffff) << 16 | (val & 0xffff0000) >> 16; T1WriteLong(vdp1backframebuffer, addr, val); break; default: break; } } ////////////////////////////////////////////////////////////////////////////// int VIDSoftVdp2Reset(void) { return 0; } ////////////////////////////////////////////////////////////////////////////// void VIDSoftVdp2DrawStart(void) { int titanblendmode = TITAN_BLEND_TOP; if (Vdp2Regs->CCCTL & 0x100) titanblendmode = TITAN_BLEND_ADD; else if (Vdp2Regs->CCCTL & 0x200) titanblendmode = TITAN_BLEND_BOTTOM; TitanSetBlendingMode(titanblendmode); Vdp2DrawBackScreen(); Vdp2DrawLineScreen(); //dracula x bad cycle setting if (Vdp2Regs->CYCA0L == 0x5566 && Vdp2Regs->CYCA0U == 0x47ff && Vdp2Regs->CYCA1L == 0xffff && Vdp2Regs->CYCA1U == 0xffff && Vdp2Regs->CYCB0L == 0x12ff && Vdp2Regs->CYCB0U == 0x03ff && Vdp2Regs->CYCB1L == 0xffff && Vdp2Regs->CYCB1U == 0xffff) { bad_cycle_setting[TITAN_NBG3] = 1; } else bad_cycle_setting[TITAN_NBG3] = 0; } ////////////////////////////////////////////////////////////////////////////// void VidsoftDrawSprite(Vdp2 * vdp2_regs, u8 * spr_window_mask, u8* vdp1_front_framebuffer, u8 * vdp2_ram, Vdp1* vdp1_regs, Vdp2* vdp2_lines, u8*color_ram) { int i, i2; u16 pixel; u8 prioritytable[8]; u32 vdp1coloroffset; int colormode = vdp2_regs->SPCTL & 0x20; vdp2draw_struct info = { 0 }; int islinewindow; clipping_struct clip[2]; u32 linewnd0addr, linewnd1addr; int wctl; clipping_struct colorcalcwindow[2]; int framebuffer_readout_y = 0; int start_line = 0, line_increment = 0; int sprite_window_enabled = vdp2_regs->SPCTL & 0x10; int vdp1spritetype = 0; if (sprite_window_enabled) { memset(spr_window_mask, 0, 704 * 512); } // Figure out whether to draw vdp1 framebuffer or vdp2 framebuffer pixels // based on priority if (Vdp1External.disptoggle && (vdp2_regs->TVMD & 0x8000)) { int SPCCCS = (vdp2_regs->SPCTL >> 12) & 0x3; int SPCCN = (vdp2_regs->SPCTL >> 8) & 0x7; u8 colorcalctable[8]; vdp2rotationparameterfp_struct p; int x, y; int output_y = 0; prioritytable[0] = vdp2_regs->PRISA & 0x7; prioritytable[1] = (vdp2_regs->PRISA >> 8) & 0x7; prioritytable[2] = vdp2_regs->PRISB & 0x7; prioritytable[3] = (vdp2_regs->PRISB >> 8) & 0x7; prioritytable[4] = vdp2_regs->PRISC & 0x7; prioritytable[5] = (vdp2_regs->PRISC >> 8) & 0x7; prioritytable[6] = vdp2_regs->PRISD & 0x7; prioritytable[7] = (vdp2_regs->PRISD >> 8) & 0x7; colorcalctable[0] = ((~vdp2_regs->CCRSA & 0x1F) << 1) + 1; colorcalctable[1] = ((~vdp2_regs->CCRSA >> 7) & 0x3E) + 1; colorcalctable[2] = ((~vdp2_regs->CCRSB & 0x1F) << 1) + 1; colorcalctable[3] = ((~vdp2_regs->CCRSB >> 7) & 0x3E) + 1; colorcalctable[4] = ((~vdp2_regs->CCRSC & 0x1F) << 1) + 1; colorcalctable[5] = ((~vdp2_regs->CCRSC >> 7) & 0x3E) + 1; colorcalctable[6] = ((~vdp2_regs->CCRSD & 0x1F) << 1) + 1; colorcalctable[7] = ((~vdp2_regs->CCRSD >> 7) & 0x3E) + 1; vdp1coloroffset = (vdp2_regs->CRAOFB & 0x70) << 4; vdp1spritetype = vdp2_regs->SPCTL & 0xF; ReadVdp2ColorOffset(vdp2_regs, &info, 0x40, 0x40); wctl = vdp2_regs->WCTLC >> 8; clip[0].xstart = clip[0].ystart = clip[0].xend = clip[0].yend = 0; clip[1].xstart = clip[1].ystart = clip[1].xend = clip[1].yend = 0; ReadWindowData(wctl, clip, vdp2_regs); linewnd0addr = linewnd1addr = 0; ReadLineWindowData(&islinewindow, wctl, &linewnd0addr, &linewnd1addr, vdp2_regs); /* color calculation window: in => no color calc, out => color calc */ ReadWindowData(vdp2_regs->WCTLD >> 8, colorcalcwindow, vdp2_regs); if (vdp1_regs->TVMR & 2) Vdp2ReadRotationTableFP(0, &p, vdp2_regs, vdp2_ram); info.titan_which_layer = TITAN_SPRITE; info.linescreen = (vdp2_regs->LNCLEN >> 5) & 1; Vdp2GetInterlaceInfo(&start_line, &line_increment); for (i2 = start_line; i2 < vdp2height; i2 += line_increment) { float framebuffer_readout_pos = 0; ReadLineWindowClip(islinewindow, clip, &linewnd0addr, &linewnd1addr, vdp2_ram, vdp2_regs); if (vdp2_interlace) LoadLineParamsSprite(&info, i2 / 2, vdp2_lines); else LoadLineParamsSprite(&info, i2, vdp2_lines); if (vdp2_interlace) { y = framebuffer_readout_y; framebuffer_readout_y += 1; } else { y = i2; } for (i = 0; i < vdp2width; i++) { info.titan_shadow_type = 0; // See if screen position is clipped, if it isn't, continue if (!(vdp2_regs->SPCTL & 0x10)) { if (!TestBothWindow(wctl, clip, i, i2)) { continue; } } if (vdp1_regs->TVMR & 2) { x = (touint(p.Xst + i * p.deltaX + i2 * p.deltaXst)) & (vdp1width - 1); y = (touint(p.Yst + i * p.deltaY + i2 * p.deltaYst)) & (vdp1height - 1); } else { if (vdp1width == 1024 && vdp2_x_hires) { //hi res vdp1 and hi res vdp2 //pixels 1:1 x = (int)framebuffer_readout_pos; framebuffer_readout_pos += 1; } else if (vdp1width == 512 && vdp2_x_hires) { //low res vdp1,hi res vdp2 //vdp1 pixel doubling x = (int)framebuffer_readout_pos; framebuffer_readout_pos += .5; } else if (vdp1width == 1024 && (!vdp2_x_hires)) { //hi res vdp1, low res vdp2 //the vdp1 framebuffer is read out at half-res x = (int)framebuffer_readout_pos; framebuffer_readout_pos += 2; } else x = i; } if (vdp1pixelsize == 2) { // 16-bit pixel size pixel = ((u16 *)vdp1_front_framebuffer)[(y * vdp1width) + x]; if (pixel == 0) ; else if (pixel & 0x8000 && colormode) { // 16 BPP u8 alpha = 0x3F; if ((SPCCCS == 3) && TestBothWindow(vdp2_regs->WCTLD >> 8, colorcalcwindow, i, i2) && (vdp2_regs->CCCTL & 0x40)) { alpha = colorcalctable[0]; if (vdp2_regs->CCCTL & 0x300) alpha |= 0x80; } // if pixel is 0x8000, only draw pixel if sprite window // is disabled/sprite type 2-7. sprite types 0 and 1 are // -always- drawn and sprite types 8-F are always // transparent. if (pixel != 0x8000 || vdp1spritetype < 2 || (vdp1spritetype < 8 && !(vdp2_regs->SPCTL & 0x10))) TitanPutPixel(prioritytable[0], i, output_y, info.PostPixelFetchCalc(&info, COLSAT2YAB16(alpha, pixel)), info.linescreen, &info); } else { // Color bank spritepixelinfo_struct spi; u8 alpha = 0x3F; u32 dot; Vdp1GetSpritePixelInfo(vdp1spritetype, &pixel, &spi); if (spi.normalshadow) { info.titan_shadow_type = TITAN_NORMAL_SHADOW; TitanPutPixel(prioritytable[spi.priority], i, output_y, COLSAT2YAB16(0x3f, 0), info.linescreen, &info); continue; } dot = Vdp2ColorRamGetColor(vdp1coloroffset + pixel,color_ram); if (TestBothWindow(vdp2_regs->WCTLD >> 8, colorcalcwindow, i, i2) && (vdp2_regs->CCCTL & 0x40)) { int transparent = 0; /* Sprite color calculation */ switch (SPCCCS) { case 0: if (prioritytable[spi.priority] <= SPCCN) transparent = 1; break; case 1: if (prioritytable[spi.priority] == SPCCN) transparent = 1; break; case 2: if (prioritytable[spi.priority] >= SPCCN) transparent = 1; break; case 3: if (dot & 0x80000000) transparent = 1; break; } if (vdp2_regs->CCCTL & 0x200) { /* "bottom" mode, the alpha channel will be used by another layer, so we set it regardless of whether sprites are transparent or not. The highest priority bit is only set if the sprite is transparent (in this case, it's the alpha channel of the lower priority layer that will be used. */ alpha = colorcalctable[spi.colorcalc]; if (transparent) alpha |= 0x80; } else if (transparent) { alpha = colorcalctable[spi.colorcalc]; if (vdp2_regs->CCCTL & 0x100) alpha |= 0x80; } } if (spi.msbshadow) { if (sprite_window_enabled) { spr_window_mask[(y*vdp2width) + x] = 1; info.titan_shadow_type = TITAN_MSB_SHADOW; } else { info.titan_shadow_type = TITAN_MSB_SHADOW; } if (pixel == 0) { TitanPutPixel(prioritytable[spi.priority], i, output_y, info.PostPixelFetchCalc(&info, COLSAT2YAB32(alpha, 0)), info.linescreen, &info); continue; } } if ((sprite_window_enabled)) { if (!TestBothWindow(wctl, clip, i, i2)) { continue; } } TitanPutPixel(prioritytable[spi.priority], i, output_y, info.PostPixelFetchCalc(&info, COLSAT2YAB32(alpha, dot)), info.linescreen, &info); } } else { // 8-bit pixel size pixel = vdp1_front_framebuffer[(y * vdp1width) + x]; if (pixel != 0) { // Color bank(fix me) spritepixelinfo_struct spi; u8 alpha = 0x3F; u32 dot; Vdp1GetSpritePixelInfo(vdp1spritetype, &pixel, &spi); if (spi.normalshadow) { info.titan_shadow_type = TITAN_NORMAL_SHADOW; TitanPutPixel(prioritytable[spi.priority], i, output_y, COLSAT2YAB16(0x3f, 0), info.linescreen, &info); continue; } dot = Vdp2ColorRamGetColor(vdp1coloroffset + pixel, color_ram); if (TestBothWindow(vdp2_regs->WCTLD >> 8, colorcalcwindow, i, i2) && (vdp2_regs->CCCTL & 0x40)) { int transparent = 0; /* Sprite color calculation */ switch (SPCCCS) { case 0: if (prioritytable[spi.priority] <= SPCCN) transparent = 1; break; case 1: if (prioritytable[spi.priority] == SPCCN) transparent = 1; break; case 2: if (prioritytable[spi.priority] >= SPCCN) transparent = 1; break; case 3: if (dot & 0x80000000) transparent = 1; break; } if (vdp2_regs->CCCTL & 0x200) { /* "bottom" mode, the alpha channel will be used by another layer, so we set it regardless of whether sprites are transparent or not. The highest priority bit is only set if the sprite is transparent (in this case, it's the alpha channel of the lower priority layer that will be used. */ alpha = colorcalctable[spi.colorcalc]; if (transparent) alpha |= 0x80; } else if (transparent) { alpha = colorcalctable[spi.colorcalc]; if (vdp2_regs->CCCTL & 0x100) alpha |= 0x80; } } TitanPutPixel(prioritytable[spi.priority], i, output_y, info.PostPixelFetchCalc(&info, COLSAT2YAB32(alpha, dot)), info.linescreen, &info); } } } output_y++; } } } void VIDSoftVdp2DrawEnd(void) { if (vidsoft_num_layer_threads > 0) { while (!vidsoft_thread_context.draw_finished[TITAN_NBG0]){} while (!vidsoft_thread_context.draw_finished[TITAN_NBG1]){} while (!vidsoft_thread_context.draw_finished[TITAN_NBG2]){} while (!vidsoft_thread_context.draw_finished[TITAN_NBG3]){} while (!vidsoft_thread_context.draw_finished[TITAN_RBG0]){} while (!vidsoft_thread_context.draw_finished[TITAN_SPRITE]){} } TitanRender(dispbuffer); VIDSoftVdp1SwapFrameBuffer(); if (OSDUseBuffer()) OSDDisplayMessages(dispbuffer, vdp2width, vdp2height); #ifdef USE_OPENGL glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, vdp2width, vdp2height, 0, GL_RGBA, GL_UNSIGNED_BYTE, dispbuffer); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); if (! OSDUseBuffer()) OSDDisplayMessages(NULL, -1, -1); #endif YuiSwapBuffers(); } ////////////////////////////////////////////////////////////////////////////// void VidsoftStartLayerThread(int * layer_priority, int * draw_priority_0, int * num_threads_dispatched, int which_layer, void(*layer_func) (Vdp2* lines, Vdp2* regs, u8* ram, u8* color_ram, struct CellScrollData * cell_data)) { if (layer_priority[which_layer] > 0 || draw_priority_0[which_layer]) { if (*num_threads_dispatched < vidsoft_num_layer_threads) { vidsoft_thread_context.need_draw[which_layer] = 1; vidsoft_thread_context.draw_finished[which_layer] = 0; YabThreadWake(YAB_THREAD_VIDSOFT_LAYER_NBG3 + which_layer); *num_threads_dispatched = *num_threads_dispatched + 1; } else { (*layer_func) (Vdp2Lines, Vdp2Regs, Vdp2Ram, Vdp2ColorRam, cell_scroll_data); } } } ////////////////////////////////////////////////////////////////////////////// int IsSpriteWindowEnabled(u16 wtcl) { if (((wtcl& (1 << 13)) == 0) && ((wtcl & (1 << 5)) == 0)) return 0; return 1; } int CanUseSpriteThread() { //check if sprite window is enabled if ((Vdp2Regs->SPCTL & (1 << 4)) == 0) return 1; //check if any layers are using it if (IsSpriteWindowEnabled(Vdp2Regs->WCTLA) || IsSpriteWindowEnabled(Vdp2Regs->WCTLB) || IsSpriteWindowEnabled(Vdp2Regs->WCTLC) || IsSpriteWindowEnabled(Vdp2Regs->WCTLD)) { //thread cannot be used return 0; } return 1; } void VIDSoftVdp2DrawScreens(void) { int draw_priority_0[6] = { 0 }; int layer_priority[6] = { 0 }; int num_threads_dispatched = 0; VIDSoftVdp2SetResolution(Vdp2Regs->TVMD); layer_priority[TITAN_NBG0] = Vdp2Regs->PRINA & 0x7; layer_priority[TITAN_NBG1] = ((Vdp2Regs->PRINA >> 8) & 0x7); layer_priority[TITAN_NBG2] = (Vdp2Regs->PRINB & 0x7); layer_priority[TITAN_NBG3] = ((Vdp2Regs->PRINB >> 8) & 0x7); layer_priority[TITAN_RBG0] = (Vdp2Regs->PRIR & 0x7); TitanErase(); if (Vdp2Regs->SFPRMD & 0x3FF) { draw_priority_0[TITAN_NBG0] = (Vdp2Regs->SFPRMD >> 0) & 0x3; draw_priority_0[TITAN_NBG1] = (Vdp2Regs->SFPRMD >> 2) & 0x3; draw_priority_0[TITAN_NBG2] = (Vdp2Regs->SFPRMD >> 4) & 0x3; draw_priority_0[TITAN_NBG3] = (Vdp2Regs->SFPRMD >> 6) & 0x3; draw_priority_0[TITAN_RBG0] = (Vdp2Regs->SFPRMD >> 8) & 0x3; } if (vidsoft_num_layer_threads > 0) { memcpy(vidsoft_thread_context.lines, Vdp2Lines, sizeof(Vdp2) * 270); memcpy(&vidsoft_thread_context.regs, Vdp2Regs, sizeof(Vdp2)); memcpy(vidsoft_thread_context.ram, Vdp2Ram, 0x80000); memcpy(vidsoft_thread_context.color_ram, Vdp2ColorRam, 0x1000); memcpy(vidsoft_thread_context.cell_scroll_data, cell_scroll_data, sizeof(struct CellScrollData) * 270); } //draw vdp2 sprite layer on a thread if sprite window is not enabled if (CanUseSpriteThread() && vidsoft_num_layer_threads > 0) { vidsoft_thread_context.need_draw[TITAN_SPRITE] = 1; vidsoft_thread_context.draw_finished[TITAN_SPRITE] = 0; YabThreadWake(YAB_THREAD_VIDSOFT_LAYER_SPRITE); num_threads_dispatched++; } else { VidsoftDrawSprite(Vdp2Regs, sprite_window_mask, vdp1frontframebuffer, Vdp2Ram, Vdp1Regs, Vdp2Lines, Vdp2ColorRam); } if (vidsoft_num_layer_threads > 0) { VidsoftStartLayerThread(layer_priority, draw_priority_0, &num_threads_dispatched, TITAN_NBG0, Vdp2DrawNBG0); VidsoftStartLayerThread(layer_priority, draw_priority_0, &num_threads_dispatched, TITAN_RBG0, Vdp2DrawRBG0); VidsoftStartLayerThread(layer_priority, draw_priority_0, &num_threads_dispatched, TITAN_NBG1, Vdp2DrawNBG1); VidsoftStartLayerThread(layer_priority, draw_priority_0, &num_threads_dispatched, TITAN_NBG2, Vdp2DrawNBG2); VidsoftStartLayerThread(layer_priority, draw_priority_0, &num_threads_dispatched, TITAN_NBG3, Vdp2DrawNBG3); } else { Vdp2DrawNBG0(Vdp2Lines, Vdp2Regs, Vdp2Ram, Vdp2ColorRam, cell_scroll_data); Vdp2DrawNBG1(Vdp2Lines, Vdp2Regs, Vdp2Ram, Vdp2ColorRam, cell_scroll_data); Vdp2DrawNBG2(Vdp2Lines, Vdp2Regs, Vdp2Ram, Vdp2ColorRam, cell_scroll_data); Vdp2DrawNBG3(Vdp2Lines, Vdp2Regs, Vdp2Ram, Vdp2ColorRam, cell_scroll_data); Vdp2DrawRBG0(Vdp2Lines, Vdp2Regs, Vdp2Ram, Vdp2ColorRam, cell_scroll_data); } } ////////////////////////////////////////////////////////////////////////////// void VIDSoftVdp2DrawScreen(int screen) { VIDSoftVdp2SetResolution(Vdp2Regs->TVMD); switch(screen) { case 0: Vdp2DrawNBG0(Vdp2Lines, Vdp2Regs, Vdp2Ram, Vdp2ColorRam, cell_scroll_data); break; case 1: Vdp2DrawNBG1(Vdp2Lines, Vdp2Regs, Vdp2Ram, Vdp2ColorRam, cell_scroll_data); break; case 2: Vdp2DrawNBG2(Vdp2Lines, Vdp2Regs, Vdp2Ram, Vdp2ColorRam, cell_scroll_data); break; case 3: Vdp2DrawNBG3(Vdp2Lines, Vdp2Regs, Vdp2Ram, Vdp2ColorRam, cell_scroll_data); break; case 4: Vdp2DrawRBG0(Vdp2Lines, Vdp2Regs, Vdp2Ram, Vdp2ColorRam, cell_scroll_data); break; } } ////////////////////////////////////////////////////////////////////////////// void VIDSoftVdp2SetResolution(u16 TVMD) { // This needs some work // Horizontal Resolution switch (TVMD & 0x7) { case 0: rbg0width = vdp2width = 320; break; case 1: rbg0width = vdp2width = 352; break; case 2: vdp2width = 640; rbg0width = 320; break; case 3: vdp2width = 704; rbg0width = 352; break; case 4: rbg0width = vdp2width = 320; break; case 5: rbg0width = vdp2width = 352; break; case 6: vdp2width = 640; rbg0width = 320; break; case 7: vdp2width = 704; rbg0width = 352; break; } if ((vdp2width == 704) || (vdp2width == 640)) vdp2_x_hires = 1; else vdp2_x_hires = 0; // Vertical Resolution switch ((TVMD >> 4) & 0x3) { case 0: rbg0height = vdp2height = 224; break; case 1: rbg0height = vdp2height = 240; break; case 2: rbg0height = vdp2height = 256; break; default: break; } // Check for interlace switch ((TVMD >> 6) & 0x3) { case 3: // Double-density Interlace vdp2height *= 2; vdp2_interlace=1; break; case 2: // Single-density Interlace case 0: // Non-interlace default: vdp2_interlace = 0; break; } TitanSetResolution(vdp2width, vdp2height); } ////////////////////////////////////////////////////////////////////////////// void VIDSoftVdp1SwapFrameBuffer(void) { if (((Vdp1Regs->FBCR & 2) == 0) || Vdp1External.manualchange) { u8 *temp; if (vidsoft_vdp1_thread_enabled) { VidsoftWaitForVdp1Thread(); } temp = vdp1frontframebuffer; vdp1frontframebuffer = vdp1backframebuffer; vdp1backframebuffer = temp; Vdp1External.manualchange = 0; } } ////////////////////////////////////////////////////////////////////////////// void VIDSoftVdp1EraseFrameBuffer(Vdp1* regs, u8 * back_framebuffer) { int i,i2; int w,h; if (((regs->FBCR & 2) == 0) || Vdp1External.manualerase) { h = (regs->EWRR & 0x1FF) + 1; if (h > vdp1height) h = vdp1height; w = ((regs->EWRR >> 6) & 0x3F8) + 8; if (w > vdp1width) w = vdp1width; if (vdp1pixelsize == 2) { for (i2 = (regs->EWLR & 0x1FF); i2 < h; i2++) { for (i = ((regs->EWLR >> 6) & 0x1F8); i < w; i++) ((u16 *)back_framebuffer)[(i2 * vdp1width) + i] = regs->EWDR; } } else { w = regs->EWRR >> 9; w *= 16; for (i2 = (regs->EWLR & 0x1FF); i2 < h; i2++) { for (i = ((regs->EWLR >> 6) & 0x1F8); i < w; i++) { int pos = (i2 * vdp1width) + i; if (pos < 0x3FFFF) back_framebuffer[pos] = regs->EWDR & 0xFF; } } } Vdp1External.manualerase = 0; } } ////////////////////////////////////////////////////////////////////////////// void VIDSoftGetGlSize(int *width, int *height) { #ifdef USE_OPENGL *width = outputwidth; *height = outputheight; #else *width = vdp2width; *height = vdp2height; #endif } void VIDSoftGetNativeResolution(int *width, int *height, int* interlace) { *width = vdp2width; *height = vdp2height; *interlace = vdp2_interlace; } void VIDSoftVdp2DispOff() { TitanErase(); }yabause-0.9.15/src/bios.h000644 001750 001750 00000003411 12755623101 017146 0ustar00guillaumeguillaume000000 000000 /* Copyright 2006 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file bios.h \brief Header for emulated bios functions required for running games and saving backup ram. */ #ifndef BIOS_H #define BIOS_H #include "sh2core.h" typedef struct { char filename[12]; char comment[11]; u8 language; u8 year; u8 month; u8 day; u8 hour; u8 minute; u8 week; u32 datasize; u16 blocksize; } saveinfo_struct; typedef struct { u8 id; char name[32]; } deviceinfo_struct; void BiosInit(void); int FASTCALL BiosHandleFunc(SH2_struct * sh); deviceinfo_struct *BupGetDeviceList(int *numdevices); int BupGetStats(SH2_struct *sh, u32 device, u32 *freespace, u32 *maxspace); saveinfo_struct *BupGetSaveList(SH2_struct *sh, u32 device, int *numsaves); int BupDeleteSave(SH2_struct *sh, u32 device, const char *savename); void BupFormat(u32 device); int BupCopySave(u32 srcdevice, u32 dstdevice, const char *savename); int BupImportSave(u32 device, const char *filename); int BupExportSave(u32 device, const char *savename, const char *filename); #endif yabause-0.9.15/src/perlinuxjoy.h000644 001750 001750 00000001653 12755623101 020610 0ustar00guillaumeguillaume000000 000000 /* Copyright 2009 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef PERLINUXJOY_H #define PERLINUXJOY_H #include "peripheral.h" /** @addtogroup peripheral * @{ */ #define PERCORE_LINUXJOY 4 extern PerInterface_struct PERLinuxJoy; /** @} */ #endif yabause-0.9.15/src/vdp2debug.h000644 001750 001750 00000002377 12755623101 020106 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005-2008 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef VDP2DEBUG_H #define VDP2DEBUG_H #define VDP2_DEBUG_STRING_SIZE 2048 void Vdp2DebugStatsRBG0(char *outstring, int *isenabled); void Vdp2DebugStatsNBG0(char *outstring, int *isenabled); void Vdp2DebugStatsNBG1(char *outstring, int *isenabled); void Vdp2DebugStatsNBG2(char *outstring, int *isenabled); void Vdp2DebugStatsNBG3(char *outstring, int *isenabled); void Vdp2DebugStatsGeneral(char *outstring, int *isenabled); pixel_t *Vdp2DebugTexture(u32 screen, int * w, int * h); #endif yabause-0.9.15/src/sh2d.c000644 001750 001750 00000072753 12755623101 017064 0ustar00guillaumeguillaume000000 000000 /* * sh2d * Bart Trzynadlowski, July 24, 2000 * Public domain */ /*! \file sh2d.c \brief SH2 disassembler. */ #include #include #include #include "sh2core.h" #include "sh2d.h" #if 0 #include #endif #define ZERO_F 0 /* 0 format */ #define N_F 1 /* n format */ #define M_F 2 /* m format */ #define NM_F 3 /* nm format */ #define MD_F 4 /* md format */ #define ND4_F 5 /* nd4 format */ #define NMD_F 6 /* nmd format */ #define D_F 7 /* d format */ #define D12_F 8 /* d12 format */ #define ND8_F 9 /* nd8 format */ #define I_F 10 /* i format */ #define NI_F 11 /* ni format */ typedef struct { int format; const char *mnem; unsigned short mask; /* mask used to obtain opcode bits */ unsigned short bits; /* opcode bits */ int dat; /* specific data for situation */ int sh2; /* SH-2 specific */ } i_descr; i_descr trace[] = { { ZERO_F, "clrt", 0xffff, 0x8, 0, 0 }, { ZERO_F, "clrmac", 0xffff, 0x28, 0, 0 }, { ZERO_F, "div0u", 0xffff, 0x19, 0, 0 }, { ZERO_F, "nop", 0xffff, 0x9, 0, 0 }, { ZERO_F, "rte", 0xffff, 0x2b, 0, 0 }, { ZERO_F, "rts", 0xffff, 0xb, 0, 0 }, { ZERO_F, "sett", 0xffff, 0x18, 0, 0 }, { ZERO_F, "sleep", 0xffff, 0x1b, 0, 0 }, { N_F, "cmp/pl ((r%d)0x%08X)", 0xf0ff, 0x4015, 0, 0 }, { N_F, "cmp/pz ((r%d)0x%08X)", 0xf0ff, 0x4011, 0, 0 }, { N_F, "dt ((r%d)0x%08X)", 0xf0ff, 0x4010, 0, 1 }, { N_F, "movt ((r%d)0x%08X)", 0xf0ff, 0x0029, 0, 0 }, { N_F, "rotl ((r%d)0x%08X)", 0xf0ff, 0x4004, 0, 0 }, { N_F, "rotr ((r%d)0x%08X)", 0xf0ff, 0x4005, 0, 0 }, { N_F, "rotcl ((r%d)0x%08X)", 0xf0ff, 0x4024, 0, 0 }, { N_F, "rotcr ((r%d)0x%08X)", 0xf0ff, 0x4025, 0, 0 }, { N_F, "shal ((r%d)0x%08X)", 0xf0ff, 0x4020, 0, 0 }, { N_F, "shar ((r%d)0x%08X)", 0xf0ff, 0x4021, 0, 0 }, { N_F, "shll ((r%d)0x%08X)", 0xf0ff, 0x4000, 0, 0 }, { N_F, "shlr ((r%d)0x%08X)", 0xf0ff, 0x4001, 0, 0 }, { N_F, "shll2 ((r%d)0x%08X)", 0xf0ff, 0x4008, 0, 0 }, { N_F, "shlr2 ((r%d)0x%08X)", 0xf0ff, 0x4009, 0, 0 }, { N_F, "shll8 ((r%d)0x%08X)", 0xf0ff, 0x4018, 0, 0 }, { N_F, "shlr8 ((r%d)0x%08X)", 0xf0ff, 0x4019, 0, 0 }, { N_F, "shll16 ((r%d)0x%08X)", 0xf0ff, 0x4028, 0, 0 }, { N_F, "shlr16 ((r%d)0x%08X)", 0xf0ff, 0x4029, 0, 0 }, { N_F, "stc sr, ((r%d)0x%08X)", 0xf0ff, 0x0002, 0, 0 }, { N_F, "stc gbr, ((r%d)0x%08X)", 0xf0ff, 0x0012, 0, 0 }, { N_F, "stc vbr, ((r%d)0x%08X)", 0xf0ff, 0x0022, 0, 0 }, { N_F, "sts mach, ((r%d)0x%08X)", 0xf0ff, 0x000a, 0, 0 }, { N_F, "sts macl, ((r%d)0x%08X)", 0xf0ff, 0x001a, 0, 0 }, { N_F, "sts pr, ((r%d)0x%08X)", 0xf0ff, 0x002a, 0, 0 }, { N_F, "tas.b @((r%d)0x%08X)", 0xf0ff, 0x401b, 0, 0 }, { N_F, "stc.l sr, @-((r%d)0x%08X)", 0xf0ff, 0x4003, 0, 0 }, { N_F, "stc.l gbr, @-((r%d)0x%08X)", 0xf0ff, 0x4013, 0, 0 }, { N_F, "stc.l vbr, @-((r%d)0x%08X)", 0xf0ff, 0x4023, 0, 0 }, { N_F, "sts.l mach, @-((r%d)0x%08X)", 0xf0ff, 0x4002, 0, 0 }, { N_F, "sts.l macl, @-((r%d)0x%08X)", 0xf0ff, 0x4012, 0, 0 }, { N_F, "sts.l pr, @-((r%d)0x%08X)", 0xf0ff, 0x4022, 0, 0 }, { M_F, "ldc ((r%d)0x%08X), sr", 0xf0ff, 0x400e, 0, 0 }, { M_F, "ldc ((r%d)0x%08X), gbr", 0xf0ff, 0x401e, 0, 0 }, { M_F, "ldc ((r%d)0x%08X), vbr", 0xf0ff, 0x402e, 0, 0 }, { M_F, "lds ((r%d)0x%08X), mach", 0xf0ff, 0x400a, 0, 0 }, { M_F, "lds ((r%d)0x%08X), macl", 0xf0ff, 0x401a, 0, 0 }, { M_F, "lds ((r%d)0x%08X), pr", 0xf0ff, 0x402a, 0, 0 }, { M_F, "jmp @((r%d)0x%08X)", 0xf0ff, 0x402b, 0, 0 }, { M_F, "jsr @((r%d)0x%08X)", 0xf0ff, 0x400b, 0, 0 }, { M_F, "ldc.l @((r%d)0x%08X)+, sr", 0xf0ff, 0x4007, 0, 0 }, { M_F, "ldc.l @((r%d)0x%08X)+, gbr", 0xf0ff, 0x4017, 0, 0 }, { M_F, "ldc.l @((r%d)0x%08X)+, vbr", 0xf0ff, 0x4027, 0, 0 }, { M_F, "lds.l @((r%d)0x%08X)+, mach", 0xf0ff, 0x4006, 0, 0 }, { M_F, "lds.l @((r%d)0x%08X)+, macl", 0xf0ff, 0x4016, 0, 0 }, { M_F, "lds.l @((r%d)0x%08X)+, pr", 0xf0ff, 0x4026, 0, 0 }, { M_F, "braf ((r%d)0x%08X)", 0xf0ff, 0x0023, 0, 1 }, { M_F, "bsrf ((r%d)0x%08X)", 0xf0ff, 0x0003, 0, 1 }, { NM_F, "add ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x300c, 0, 0 }, { NM_F, "addc ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x300e, 0, 0 }, { NM_F, "addv ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x300f, 0, 0 }, { NM_F, "and ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x2009, 0, 0 }, { NM_F, "cmp/eq ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x3000, 0, 0 }, { NM_F, "cmp/hs ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x3002, 0, 0 }, { NM_F, "cmp/ge ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x3003, 0, 0 }, { NM_F, "cmp/hi ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x3006, 0, 0 }, { NM_F, "cmp/gt ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x3007, 0, 0 }, { NM_F, "cmp/str ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x200c, 0, 0 }, { NM_F, "div1 ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x3004, 0, 0 }, { NM_F, "div0s ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x2007, 0, 0 }, { NM_F, "dmuls.l ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x300d, 0, 1 }, { NM_F, "dmulu.l ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x3005, 0, 1 }, { NM_F, "exts.b ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x600e, 0, 0 }, { NM_F, "exts.w ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x600f, 0, 0 }, { NM_F, "extu.b ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x600c, 0, 0 }, { NM_F, "extu.w ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x600d, 0, 0 }, { NM_F, "mov ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x6003, 0, 0 }, { NM_F, "mul.l ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x0007, 0, 1 }, { NM_F, "muls.w ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x200f, 0, 0 }, { NM_F, "mulu.w ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x200e, 0, 0 }, { NM_F, "neg ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x600b, 0, 0 }, { NM_F, "negc ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x600a, 0, 0 }, { NM_F, "not ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x6007, 0, 0 }, { NM_F, "or ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x200b, 0, 0 }, { NM_F, "sub ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x3008, 0, 0 }, { NM_F, "subc ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x300a, 0, 0 }, { NM_F, "subv ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x300b, 0, 0 }, { NM_F, "swap.b ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x6008, 0, 0 }, { NM_F, "swap.w ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x6009, 0, 0 }, { NM_F, "tst ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x2008, 0, 0 }, { NM_F, "xor ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x200a, 0, 0 }, { NM_F, "xtrct ((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x200d, 0, 0 }, { NM_F, "mov.b ((r%d)0x%08X), @((r%d)0x%08X)", 0xf00f, 0x2000, 0, 0 }, { NM_F, "mov.w ((r%d)0x%08X), @((r%d)0x%08X)", 0xf00f, 0x2001, 0, 0 }, { NM_F, "mov.l ((r%d)0x%08X), @((r%d)0x%08X)", 0xf00f, 0x2002, 0, 0 }, { NM_F, "mov.b @((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x6000, 0, 0 }, { NM_F, "mov.w @((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x6001, 0, 0 }, { NM_F, "mov.l @((r%d)0x%08X), ((r%d)0x%08X)", 0xf00f, 0x6002, 0, 0 }, { NM_F, "mac.l @((r%d)0x%08X)+, @((r%d)0x%08X)+", 0xf00f, 0x000f, 0, 1 }, { NM_F, "mac.w @((r%d)0x%08X)+, @((r%d)0x%08X)+", 0xf00f, 0x400f, 0, 0 }, { NM_F, "mov.b @((r%d)0x%08X)+, ((r%d)0x%08X)", 0xf00f, 0x6004, 0, 0 }, { NM_F, "mov.w @((r%d)0x%08X)+, ((r%d)0x%08X)", 0xf00f, 0x6005, 0, 0 }, { NM_F, "mov.l @((r%d)0x%08X)+, ((r%d)0x%08X)", 0xf00f, 0x6006, 0, 0 }, { NM_F, "mov.b ((r%d)0x%08X), @-((r%d)0x%08X)", 0xf00f, 0x2004, 0, 0 }, { NM_F, "mov.w ((r%d)0x%08X), @-((r%d)0x%08X)", 0xf00f, 0x2005, 0, 0 }, { NM_F, "mov.l ((r%d)0x%08X), @-((r%d)0x%08X)", 0xf00f, 0x2006, 0, 0 }, { NM_F, "mov.b ((r%d)0x%08X), @(r0, ((r%d)0x%08X))", 0xf00f, 0x0004, 0, 0 }, { NM_F, "mov.w ((r%d)0x%08X), @(r0, ((r%d)0x%08X))", 0xf00f, 0x0005, 0, 0 }, { NM_F, "mov.l ((r%d)0x%08X), @(r0, ((r%d)0x%08X))", 0xf00f, 0x0006, 0, 0 }, { NM_F, "mov.b @(r0, ((r%d)0x%08X)), ((r%d)0x%08X)", 0xf00f, 0x000c, 0, 0 }, { NM_F, "mov.w @(r0, ((r%d)0x%08X)), ((r%d)0x%08X)", 0xf00f, 0x000d, 0, 0 }, { NM_F, "mov.l @(r0, ((r%d)0x%08X)), ((r%d)0x%08X)", 0xf00f, 0x000e, 0, 0 }, { MD_F, "mov.b @(0x%03X, ((r%d)0x%08X)), r0", 0xff00, 0x8400, 0, 0 }, { MD_F, "mov.w @(0x%03X, ((r%d)0x%08X)), r0", 0xff00, 0x8500, 0, 0 }, { ND4_F, "mov.b r0, @(0x%03X, ((r%d)0x%08X))", 0xff00, 0x8000, 0, 0 }, { ND4_F, "mov.w r0, @(0x%03X, ((r%d)0x%08X))", 0xff00, 0x8100, 0, 0 }, { NMD_F, "mov.l ((r%d)0x%08X), @(0x%03X, ((r%d)0x%08X))", 0xf000, 0x1000, 0,0 }, { NMD_F, "mov.l @(0x%03X, ((r%d)0x%08X)), ((r%d)0x%08X)", 0xf000, 0x5000, 0,0 }, { D_F, "mov.b r0, @(0x%03X, gbr)", 0xff00, 0xc000, 1, 0 }, { D_F, "mov.w r0, @(0x%03X, gbr)", 0xff00, 0xc100, 2, 0 }, { D_F, "mov.l r0, @(0x%03X, gbr)", 0xff00, 0xc200, 4, 0 }, { D_F, "mov.b @(0x%03X, gbr), r0", 0xff00, 0xc400, 1, 0 }, { D_F, "mov.w @(0x%03X, gbr), r0", 0xff00, 0xc500, 2, 0 }, { D_F, "mov.l @(0x%03X, gbr), r0", 0xff00, 0xc600, 4, 0 }, { D_F, "mova @(0x%03X, pc), r0", 0xff00, 0xc700, 4, 0 }, { D_F, "bf 0x%08X", 0xff00, 0x8b00, 5, 0 }, { D_F, "bf/s 0x%08X", 0xff00, 0x8f00, 5, 1 }, { D_F, "bt 0x%08X", 0xff00, 0x8900, 5, 0 }, { D_F, "bt/s 0x%08X", 0xff00, 0x8d00, 5, 1 }, { D12_F, "bra 0x%08X", 0xf000, 0xa000, 0, 0 }, { D12_F, "bsr 0x%08X", 0xf000, 0xb000, 0, 0 }, { ND8_F, "mov.w @(0x%03X, pc), ((r%d)0x%08X)", 0xf000, 0x9000, 2, 0 }, { ND8_F, "mov.l @(0x%03X, pc), ((r%d)0x%08X)", 0xf000, 0xd000, 4, 0 }, { I_F, "and.b #0x%02X, @(r0, gbr)", 0xff00, 0xcd00, 0,0 }, { I_F, "or.b #0x%02X, @(r0, gbr)", 0xff00, 0xcf00, 0,0 }, { I_F, "tst.b #0x%02X, @(r0, gbr)", 0xff00, 0xcc00, 0,0 }, { I_F, "xor.b #0x%02X, @(r0, gbr)", 0xff00, 0xce00, 0,0 }, { I_F, "and #0x%02X, r0", 0xff00, 0xc900, 0, 0 }, { I_F, "cmp/eq #0x%02X, r0", 0xff00, 0x8800, 0, 0 }, { I_F, "or #0x%02X, r0", 0xff00, 0xcb00, 0, 0 }, { I_F, "tst #0x%02X, r0", 0xff00, 0xc800, 0, 0 }, { I_F, "xor #0x%02X, r0", 0xff00, 0xca00, 0, 0 }, { I_F, "trapa #0x%X", 0xff00, 0xc300, 0, 0 }, { NI_F, "add #0x%02X, ((r%d)0x%08X)", 0xf000, 0x7000, 0, 0 }, { NI_F, "mov #0x%02X, ((r%d)0x%08X)", 0xf000, 0xe000, 0, 0 }, { 0, NULL, 0, 0, 0, 0 } }; i_descr tab[] = { { ZERO_F, "clrt", 0xffff, 0x8, 0, 0 }, { ZERO_F, "clrmac", 0xffff, 0x28, 0, 0 }, { ZERO_F, "div0u", 0xffff, 0x19, 0, 0 }, { ZERO_F, "nop", 0xffff, 0x9, 0, 0 }, { ZERO_F, "rte", 0xffff, 0x2b, 0, 0 }, { ZERO_F, "rts", 0xffff, 0xb, 0, 0 }, { ZERO_F, "sett", 0xffff, 0x18, 0, 0 }, { ZERO_F, "sleep", 0xffff, 0x1b, 0, 0 }, { N_F, "cmp/pl r%d", 0xf0ff, 0x4015, 0, 0 }, { N_F, "cmp/pz r%d", 0xf0ff, 0x4011, 0, 0 }, { N_F, "dt r%d", 0xf0ff, 0x4010, 0, 1 }, { N_F, "movt r%d", 0xf0ff, 0x0029, 0, 0 }, { N_F, "rotl r%d", 0xf0ff, 0x4004, 0, 0 }, { N_F, "rotr r%d", 0xf0ff, 0x4005, 0, 0 }, { N_F, "rotcl r%d", 0xf0ff, 0x4024, 0, 0 }, { N_F, "rotcr r%d", 0xf0ff, 0x4025, 0, 0 }, { N_F, "shal r%d", 0xf0ff, 0x4020, 0, 0 }, { N_F, "shar r%d", 0xf0ff, 0x4021, 0, 0 }, { N_F, "shll r%d", 0xf0ff, 0x4000, 0, 0 }, { N_F, "shlr r%d", 0xf0ff, 0x4001, 0, 0 }, { N_F, "shll2 r%d", 0xf0ff, 0x4008, 0, 0 }, { N_F, "shlr2 r%d", 0xf0ff, 0x4009, 0, 0 }, { N_F, "shll8 r%d", 0xf0ff, 0x4018, 0, 0 }, { N_F, "shlr8 r%d", 0xf0ff, 0x4019, 0, 0 }, { N_F, "shll16 r%d", 0xf0ff, 0x4028, 0, 0 }, { N_F, "shlr16 r%d", 0xf0ff, 0x4029, 0, 0 }, { N_F, "stc sr, r%d", 0xf0ff, 0x0002, 0, 0 }, { N_F, "stc gbr, r%d", 0xf0ff, 0x0012, 0, 0 }, { N_F, "stc vbr, r%d", 0xf0ff, 0x0022, 0, 0 }, { N_F, "sts mach, r%d", 0xf0ff, 0x000a, 0, 0 }, { N_F, "sts macl, r%d", 0xf0ff, 0x001a, 0, 0 }, { N_F, "sts pr, r%d", 0xf0ff, 0x002a, 0, 0 }, { N_F, "tas.b @r%d", 0xf0ff, 0x401b, 0, 0 }, { N_F, "stc.l sr, @-r%d", 0xf0ff, 0x4003, 0, 0 }, { N_F, "stc.l gbr, @-r%d", 0xf0ff, 0x4013, 0, 0 }, { N_F, "stc.l vbr, @-r%d", 0xf0ff, 0x4023, 0, 0 }, { N_F, "sts.l mach, @-r%d", 0xf0ff, 0x4002, 0, 0 }, { N_F, "sts.l macl, @-r%d", 0xf0ff, 0x4012, 0, 0 }, { N_F, "sts.l pr, @-r%d", 0xf0ff, 0x4022, 0, 0 }, { M_F, "ldc r%d, sr", 0xf0ff, 0x400e, 0, 0 }, { M_F, "ldc r%d, gbr", 0xf0ff, 0x401e, 0, 0 }, { M_F, "ldc r%d, vbr", 0xf0ff, 0x402e, 0, 0 }, { M_F, "lds r%d, mach", 0xf0ff, 0x400a, 0, 0 }, { M_F, "lds r%d, macl", 0xf0ff, 0x401a, 0, 0 }, { M_F, "lds r%d, pr", 0xf0ff, 0x402a, 0, 0 }, { M_F, "jmp @r%d", 0xf0ff, 0x402b, 0, 0 }, { M_F, "jsr @r%d", 0xf0ff, 0x400b, 0, 0 }, { M_F, "ldc.l @r%d+, sr", 0xf0ff, 0x4007, 0, 0 }, { M_F, "ldc.l @r%d+, gbr", 0xf0ff, 0x4017, 0, 0 }, { M_F, "ldc.l @r%d+, vbr", 0xf0ff, 0x4027, 0, 0 }, { M_F, "lds.l @r%d+, mach", 0xf0ff, 0x4006, 0, 0 }, { M_F, "lds.l @r%d+, macl", 0xf0ff, 0x4016, 0, 0 }, { M_F, "lds.l @r%d+, pr", 0xf0ff, 0x4026, 0, 0 }, { M_F, "braf r%d", 0xf0ff, 0x0023, 0, 1 }, { M_F, "bsrf r%d", 0xf0ff, 0x0003, 0, 1 }, { NM_F, "add r%d, r%d", 0xf00f, 0x300c, 0, 0 }, { NM_F, "addc r%d, r%d", 0xf00f, 0x300e, 0, 0 }, { NM_F, "addv r%d, r%d", 0xf00f, 0x300f, 0, 0 }, { NM_F, "and r%d, r%d", 0xf00f, 0x2009, 0, 0 }, { NM_F, "cmp/eq r%d, r%d", 0xf00f, 0x3000, 0, 0 }, { NM_F, "cmp/hs r%d, r%d", 0xf00f, 0x3002, 0, 0 }, { NM_F, "cmp/ge r%d, r%d", 0xf00f, 0x3003, 0, 0 }, { NM_F, "cmp/hi r%d, r%d", 0xf00f, 0x3006, 0, 0 }, { NM_F, "cmp/gt r%d, r%d", 0xf00f, 0x3007, 0, 0 }, { NM_F, "cmp/str r%d, r%d", 0xf00f, 0x200c, 0, 0 }, { NM_F, "div1 r%d, r%d", 0xf00f, 0x3004, 0, 0 }, { NM_F, "div0s r%d, r%d", 0xf00f, 0x2007, 0, 0 }, { NM_F, "dmuls.l r%d, r%d", 0xf00f, 0x300d, 0, 1 }, { NM_F, "dmulu.l r%d, r%d", 0xf00f, 0x3005, 0, 1 }, { NM_F, "exts.b r%d, r%d", 0xf00f, 0x600e, 0, 0 }, { NM_F, "exts.w r%d, r%d", 0xf00f, 0x600f, 0, 0 }, { NM_F, "extu.b r%d, r%d", 0xf00f, 0x600c, 0, 0 }, { NM_F, "extu.w r%d, r%d", 0xf00f, 0x600d, 0, 0 }, { NM_F, "mov r%d, r%d", 0xf00f, 0x6003, 0, 0 }, { NM_F, "mul.l r%d, r%d", 0xf00f, 0x0007, 0, 1 }, { NM_F, "muls.w r%d, r%d", 0xf00f, 0x200f, 0, 0 }, { NM_F, "mulu.w r%d, r%d", 0xf00f, 0x200e, 0, 0 }, { NM_F, "neg r%d, r%d", 0xf00f, 0x600b, 0, 0 }, { NM_F, "negc r%d, r%d", 0xf00f, 0x600a, 0, 0 }, { NM_F, "not r%d, r%d", 0xf00f, 0x6007, 0, 0 }, { NM_F, "or r%d, r%d", 0xf00f, 0x200b, 0, 0 }, { NM_F, "sub r%d, r%d", 0xf00f, 0x3008, 0, 0 }, { NM_F, "subc r%d, r%d", 0xf00f, 0x300a, 0, 0 }, { NM_F, "subv r%d, r%d", 0xf00f, 0x300b, 0, 0 }, { NM_F, "swap.b r%d, r%d", 0xf00f, 0x6008, 0, 0 }, { NM_F, "swap.w r%d, r%d", 0xf00f, 0x6009, 0, 0 }, { NM_F, "tst r%d, r%d", 0xf00f, 0x2008, 0, 0 }, { NM_F, "xor r%d, r%d", 0xf00f, 0x200a, 0, 0 }, { NM_F, "xtrct r%d, r%d", 0xf00f, 0x200d, 0, 0 }, { NM_F, "mov.b r%d, @r%d", 0xf00f, 0x2000, 0, 0 }, { NM_F, "mov.w r%d, @r%d", 0xf00f, 0x2001, 0, 0 }, { NM_F, "mov.l r%d, @r%d", 0xf00f, 0x2002, 0, 0 }, { NM_F, "mov.b @r%d, r%d", 0xf00f, 0x6000, 0, 0 }, { NM_F, "mov.w @r%d, r%d", 0xf00f, 0x6001, 0, 0 }, { NM_F, "mov.l @r%d, r%d", 0xf00f, 0x6002, 0, 0 }, { NM_F, "mac.l @r%d+, @r%d+", 0xf00f, 0x000f, 0, 1 }, { NM_F, "mac.w @r%d+, @r%d+", 0xf00f, 0x400f, 0, 0 }, { NM_F, "mov.b @r%d+, r%d", 0xf00f, 0x6004, 0, 0 }, { NM_F, "mov.w @r%d+, r%d", 0xf00f, 0x6005, 0, 0 }, { NM_F, "mov.l @r%d+, r%d", 0xf00f, 0x6006, 0, 0 }, { NM_F, "mov.b r%d, @-r%d", 0xf00f, 0x2004, 0, 0 }, { NM_F, "mov.w r%d, @-r%d", 0xf00f, 0x2005, 0, 0 }, { NM_F, "mov.l r%d, @-r%d", 0xf00f, 0x2006, 0, 0 }, { NM_F, "mov.b r%d, @(r0, r%d)", 0xf00f, 0x0004, 0, 0 }, { NM_F, "mov.w r%d, @(r0, r%d)", 0xf00f, 0x0005, 0, 0 }, { NM_F, "mov.l r%d, @(r0, r%d)", 0xf00f, 0x0006, 0, 0 }, { NM_F, "mov.b @(r0, r%d), r%d", 0xf00f, 0x000c, 0, 0 }, { NM_F, "mov.w @(r0, r%d), r%d", 0xf00f, 0x000d, 0, 0 }, { NM_F, "mov.l @(r0, r%d), r%d", 0xf00f, 0x000e, 0, 0 }, { MD_F, "mov.b @(0x%03X, r%d), r0", 0xff00, 0x8400, 0, 0 }, { MD_F, "mov.w @(0x%03X, r%d), r0", 0xff00, 0x8500, 0, 0 }, { ND4_F, "mov.b r0, @(0x%03X, r%d)", 0xff00, 0x8000, 0, 0 }, { ND4_F, "mov.w r0, @(0x%03X, r%d)", 0xff00, 0x8100, 0, 0 }, { NMD_F, "mov.l r%d, @(0x%03X, r%d)", 0xf000, 0x1000, 0,0 }, { NMD_F, "mov.l @(0x%03X, r%d), r%d", 0xf000, 0x5000, 0,0 }, { D_F, "mov.b r0, @(0x%03X, gbr)", 0xff00, 0xc000, 1, 0 }, { D_F, "mov.w r0, @(0x%03X, gbr)", 0xff00, 0xc100, 2, 0 }, { D_F, "mov.l r0, @(0x%03X, gbr)", 0xff00, 0xc200, 4, 0 }, { D_F, "mov.b @(0x%03X, gbr), r0", 0xff00, 0xc400, 1, 0 }, { D_F, "mov.w @(0x%03X, gbr), r0", 0xff00, 0xc500, 2, 0 }, { D_F, "mov.l @(0x%03X, gbr), r0", 0xff00, 0xc600, 4, 0 }, { D_F, "mova @(0x%03X, pc), r0", 0xff00, 0xc700, 4, 0 }, { D_F, "bf 0x%08X", 0xff00, 0x8b00, 5, 0 }, { D_F, "bf/s 0x%08X", 0xff00, 0x8f00, 5, 1 }, { D_F, "bt 0x%08X", 0xff00, 0x8900, 5, 0 }, { D_F, "bt/s 0x%08X", 0xff00, 0x8d00, 5, 1 }, { D12_F, "bra 0x%08X", 0xf000, 0xa000, 0, 0 }, { D12_F, "bsr 0x%08X", 0xf000, 0xb000, 0, 0 }, { ND8_F, "mov.w @(0x%03X, pc), r%d", 0xf000, 0x9000, 2, 0 }, { ND8_F, "mov.l @(0x%03X, pc), r%d", 0xf000, 0xd000, 4, 0 }, { I_F, "and.b #0x%02X, @(r0, gbr)", 0xff00, 0xcd00, 0,0 }, { I_F, "or.b #0x%02X, @(r0, gbr)", 0xff00, 0xcf00, 0,0 }, { I_F, "tst.b #0x%02X, @(r0, gbr)", 0xff00, 0xcc00, 0,0 }, { I_F, "xor.b #0x%02X, @(r0, gbr)", 0xff00, 0xce00, 0,0 }, { I_F, "and #0x%02X, r0", 0xff00, 0xc900, 0, 0 }, { I_F, "cmp/eq #0x%02X, r0", 0xff00, 0x8800, 0, 0 }, { I_F, "or #0x%02X, r0", 0xff00, 0xcb00, 0, 0 }, { I_F, "tst #0x%02X, r0", 0xff00, 0xc800, 0, 0 }, { I_F, "xor #0x%02X, r0", 0xff00, 0xca00, 0, 0 }, { I_F, "trapa #0x%X", 0xff00, 0xc300, 0, 0 }, { NI_F, "add #0x%02X, r%d", 0xf000, 0x7000, 0, 0 }, { NI_F, "mov #0x%02X, r%d", 0xf000, 0xe000, 0, 0 }, { 0, NULL, 0, 0, 0, 0 } }; /* * SH2Disasm(): SH-1/SH-2 disassembler routine. If mode = 0 then SH-2 mode, * otherwise SH-1 mode */ void SH2Disasm(u32 v_addr, u16 op, int mode, sh2regs_struct *regs, char *string) { int i; sprintf(string,"0x%08X: ", (unsigned int)v_addr); string+=strlen(string); //TODO : Clean this up and not be lazy :) if (regs != NULL) { for (i = 0; trace[i].mnem != NULL; i++) /* 0 format */ { if ((op & trace[i].mask) == trace[i].bits) { int rtype_1 = (op >> 4) & 0xf; int rtype_2 = (op >> 8) & 0xf; if (trace[i].sh2 && mode) /* if SH-1 mode, no SH-2 */ sprintf(string, "unrecognized"); else if (trace[i].format == ZERO_F) sprintf(string, "%s", trace[i].mnem); else if (trace[i].format == N_F) sprintf(string, trace[i].mnem, rtype_2, regs->R[rtype_2]); else if (trace[i].format == M_F) sprintf(string, trace[i].mnem, rtype_2, regs->R[rtype_2]); else if (trace[i].format == NM_F) sprintf(string, trace[i].mnem, rtype_1, regs->R[rtype_1], rtype_2, regs->R[rtype_2]); else if (trace[i].format == MD_F) { if (op & 0x100) sprintf(string, trace[i].mnem, (op & 0xf) * 2, rtype_1, regs->R[rtype_1]); else sprintf(string, trace[i].mnem, op & 0xf, rtype_1, regs->R[rtype_1]); } else if (trace[i].format == ND4_F) { if (op & 0x100) sprintf(string, trace[i].mnem, (op & 0xf) * 2, rtype_1, regs->R[rtype_1]); else sprintf(string, trace[i].mnem, (op & 0xf), rtype_1, regs->R[rtype_1]); } else if (trace[i].format == NMD_F) { if ((op & 0xf000) == 0x1000) sprintf(string, trace[i].mnem, rtype_1, regs->R[rtype_1], (op & 0xf) * 4, rtype_2, regs->R[rtype_2]); else sprintf(string, trace[i].mnem, (op & 0xf) * 4, rtype_1, regs->R[rtype_1], rtype_2, regs->R[rtype_2]); } else if (trace[i].format == D_F) { if (trace[i].dat <= 4) { if ((op & 0xff00) == 0xc700) { sprintf(string, trace[i].mnem, (op & 0xff) * trace[i].dat + 4); string += strlen(string); sprintf(string, " ; 0x%08X", ((op & 0xff) * trace[i].dat + 4 + (unsigned int)v_addr) & 0xfffffffc); } else sprintf(string, trace[i].mnem, (op & 0xff) * trace[i].dat); } else { if (op & 0x80) /* sign extend */ sprintf(string, trace[i].mnem, (((op & 0xff) + 0xffffff00) * 2) + v_addr + 4); else sprintf(string, trace[i].mnem, ((op & 0xff) * 2) + v_addr + 4); } } else if (trace[i].format == D12_F) { if (op & 0x800) /* sign extend */ sprintf(string, trace[i].mnem, ((op & 0xfff) + 0xfffff000) * 2 + v_addr + 4); else sprintf(string, trace[i].mnem, (op & 0xfff) * 2 + v_addr + 4); } else if (trace[i].format == ND8_F) { if ((op & 0xf000) == 0x9000) /* .W */ { sprintf(string, trace[i].mnem, (op & 0xff) * trace[i].dat + 4, rtype_2, regs->R[rtype_2]); string += strlen(string); sprintf(string, " ; 0x%08X", ((op & 0xff) * trace[i].dat + 4 + (unsigned int)v_addr)); } else /* .L */ { sprintf(string, trace[i].mnem, (op & 0xff) * trace[i].dat + 4, rtype_2, regs->R[rtype_2]); string += strlen(string); sprintf(string, " ; 0x%08X", ((op & 0xff) * trace[i].dat + 4 + (unsigned int)v_addr) & 0xfffffffc); } } else if (trace[i].format == I_F) sprintf(string, trace[i].mnem, op & 0xff); else if (trace[i].format == NI_F) sprintf(string, trace[i].mnem, op & 0xff, rtype_2, regs->R[rtype_2]); else sprintf(string, "unrecognized"); return; } } } else { for (i = 0; tab[i].mnem != NULL; i++) /* 0 format */ { if ((op & tab[i].mask) == tab[i].bits) { if (tab[i].sh2 && mode) /* if SH-1 mode, no SH-2 */ sprintf(string, "unrecognized"); else if (tab[i].format == ZERO_F) sprintf(string, "%s", tab[i].mnem); else if (tab[i].format == N_F) sprintf(string, tab[i].mnem, (op >> 8) & 0xf); else if (tab[i].format == M_F) sprintf(string, tab[i].mnem, (op >> 8) & 0xf); else if (tab[i].format == NM_F) sprintf(string, tab[i].mnem, (op >> 4) & 0xf, (op >> 8) & 0xf); else if (tab[i].format == MD_F) { if (op & 0x100) sprintf(string, tab[i].mnem, (op & 0xf) * 2, (op >> 4) & 0xf); else sprintf(string, tab[i].mnem, op & 0xf, (op >> 4) & 0xf); } else if (tab[i].format == ND4_F) { if (op & 0x100) sprintf(string, tab[i].mnem, (op & 0xf) * 2, (op >> 4) & 0xf); else sprintf(string, tab[i].mnem, (op & 0xf), (op >> 4) & 0xf); } else if (tab[i].format == NMD_F) { if ((op & 0xf000) == 0x1000) sprintf(string, tab[i].mnem, (op >> 4) & 0xf, (op & 0xf) * 4, (op >> 8) & 0xf); else sprintf(string, tab[i].mnem, (op & 0xf) * 4, (op >> 4) & 0xf, (op >> 8) & 0xf); } else if (tab[i].format == D_F) { if (tab[i].dat <= 4) { if ((op & 0xff00) == 0xc700) { sprintf(string, tab[i].mnem, (op & 0xff) * tab[i].dat + 4); string += strlen(string); sprintf(string, " ; 0x%08X", ((op & 0xff) * tab[i].dat + 4 + (unsigned int)v_addr) & 0xfffffffc); } else sprintf(string, tab[i].mnem, (op & 0xff) * tab[i].dat); } else { if (op & 0x80) /* sign extend */ sprintf(string, tab[i].mnem, (((op & 0xff) + 0xffffff00) * 2) + v_addr + 4); else sprintf(string, tab[i].mnem, ((op & 0xff) * 2) + v_addr + 4); } } else if (tab[i].format == D12_F) { if (op & 0x800) /* sign extend */ sprintf(string, tab[i].mnem, ((op & 0xfff) + 0xfffff000) * 2 + v_addr + 4); else sprintf(string, tab[i].mnem, (op & 0xfff) * 2 + v_addr + 4); } else if (tab[i].format == ND8_F) { if ((op & 0xf000) == 0x9000) /* .W */ { sprintf(string, tab[i].mnem, (op & 0xff) * tab[i].dat + 4, (op >> 8) & 0xf); string += strlen(string); sprintf(string, " ; 0x%08X", (op & 0xff) * tab[i].dat + 4 + (unsigned int)v_addr); } else /* .L */ { sprintf(string, tab[i].mnem, (op & 0xff) * tab[i].dat + 4, (op >> 8) & 0xf); string += strlen(string); sprintf(string, " ; 0x%08X", ((op & 0xff) * tab[i].dat + 4 + (unsigned int)v_addr) & 0xfffffffc); } } else if (tab[i].format == I_F) sprintf(string, tab[i].mnem, op & 0xff); else if (tab[i].format == NI_F) sprintf(string, tab[i].mnem, op & 0xff, (op >> 8) & 0xf); else sprintf(string, "unrecognized"); return; } } } sprintf(string,"unrecognized"); } yabause-0.9.15/src/logo.svg000644 001750 001750 00000017503 12755623101 017531 0ustar00guillaumeguillaume000000 000000 image/svg+xml Yabause Logo yabause-0.9.15/src/scspdsp.c000644 001750 001750 00000033101 12757373537 017704 0ustar00guillaumeguillaume000000 000000 /* Copyright 2015 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "scsp.h" #include "scspdsp.h" s32 float_to_int(u16 f_val); u16 int_to_float(u32 i_val); //saturate 24 bit signed integer static INLINE s32 saturate_24(s32 value) { if (value > 8388607) value = 8388607; if (value < (-8388608)) value = (-8388608); return value; } void ScspDspExec(ScspDsp* dsp, int addr, u8 * sound_ram) { u16* sound_ram_16 = (u16*)sound_ram; u64 mul_temp = 0; int nofl = 0; u32 x_temp = 0; s32 y_extended = 0; union ScspDspInstruction instruction; u32 address = 0; s32 shift_temp = 0; instruction.all = scsp_dsp.mpro[addr]; nofl = (instruction.all >> 8) & 1; if (instruction.part.ira <= 0x1f) dsp->inputs = dsp->mems[instruction.part.ira & 0x1f]; else if (instruction.part.ira >= 0x20 && instruction.part.ira <= 0x2f) dsp->inputs = dsp->mixs[instruction.part.ira - 0x20] << 4; else if (instruction.part.ira == 0x30 || instruction.part.ira == 0x31) dsp->inputs = dsp->exts[(instruction.part.ira - 0x30) & 1]; if (instruction.part.iwt) dsp->mems[instruction.part.iwa] = dsp->mrd_value; if (instruction.part.bsel == 0) { s32 temp_val = dsp->temp[(instruction.part.tra + dsp->mdec_ct) & 0x7f]; if (temp_val & 0x800000) temp_val |= 0x3000000;//sign extend to 26 bits dsp->b = temp_val; } else if (instruction.part.bsel == 1) dsp->b = dsp->acc; if (instruction.part.negb) dsp->b = 0 - dsp->b; if (instruction.part.zero) dsp->b = 0; if (instruction.part.xsel == 0) dsp->x = dsp->temp[(instruction.part.tra + dsp->mdec_ct) & 0x7f]; else if (instruction.part.xsel == 1) dsp->x = dsp->inputs; if (instruction.part.ysel == 0) dsp->y = dsp->frc_reg; else if (instruction.part.ysel == 1) { dsp->y = dsp->coef[instruction.part.coef]; if (dsp->coef[instruction.part.coef] & 0x8000) dsp->y |= 0xE000; } else if (instruction.part.ysel == 2) dsp->y = (dsp->y_reg >> 11) & 0x1FFF; else if (instruction.part.ysel == 3) dsp->y = (dsp->y_reg >> 4) & 0xFFF; y_extended = dsp->y; if (dsp->y & (1 << 12)) y_extended |= 0xffffe000; if (instruction.part.yrl) dsp->y_reg = dsp->inputs; shift_temp = 0; if (instruction.part.shift == 0) shift_temp = saturate_24(dsp->acc); else if (instruction.part.shift == 1) shift_temp = saturate_24(dsp->acc * 2); else if (instruction.part.shift == 2) shift_temp = (dsp->acc * 2) & 0xffffff; else if (instruction.part.shift == 2) shift_temp = dsp->acc & 0xffffff; if (instruction.part.ewt) dsp->efreg[instruction.part.ewa] = (shift_temp >> 8) & 0xffff; x_temp = dsp->x; if (dsp->x & 0x800000) x_temp |= 0xff000000; mul_temp = (u64)(s32)x_temp * (u64)y_extended;//prevent clipping dsp->acc = (mul_temp >> 12) + dsp->b; dsp->mul_out = (mul_temp >> 12); dsp->acc &= 0xffffff; if (dsp->acc & 0x800000) dsp->acc |= 0xff000000; if (instruction.part.twt) dsp->temp[(instruction.part.twa + dsp->mdec_ct) & 0x7f] = shift_temp & 0xffffff; dsp->shifted = dsp->acc & 0x3ffffff; if (instruction.part.frcl) { if (instruction.part.shift == 3) dsp->frc_reg = shift_temp & 0xFFF; else dsp->frc_reg = (shift_temp >> 11) & 0x1FFF; } address = dsp->madrs[instruction.part.masa]; if (instruction.part.table == 0) address += dsp->mdec_ct; if (instruction.part.adreb) address += dsp->adrs_reg & 0xfff; if (instruction.part.nxadr) address += 1; if (instruction.part.table == 0) { if (dsp->rbl == 0) address &= 0x1fff; else if (dsp->rbl == 1) address &= 0x3fff; else if (dsp->rbl == 2) address &= 0x7fff; else if (dsp->rbl == 3) address &= 0xffff; } else if (instruction.part.table == 1) address &= 0xffff; address += (dsp->rbp << 11) * 2; if (dsp->need_read) { u16 temp = sound_ram_16[dsp->io_addr & 0x7ffff]; if (dsp->need_nofl) dsp->mrd_value = temp << 8; else dsp->mrd_value = float_to_int(temp) & 0xffffff; dsp->need_read = 0; dsp->need_nofl = 0; } if (dsp->need_write) { sound_ram_16[dsp->io_addr] = dsp->write_data; dsp->need_write = 0; } dsp->io_addr = address; if (instruction.part.mrd) { dsp->need_read = 1; dsp->need_nofl = nofl; } if (instruction.part.mwt) { dsp->need_write = 1; if (nofl) dsp->write_data = shift_temp >> 8; else dsp->write_data = int_to_float(shift_temp); } if (instruction.part.adrl) { if (instruction.part.shift == 3) dsp->adrs_reg = (shift_temp >> 12) & 0xFFF; else dsp->adrs_reg = dsp->inputs >> 16; } } //sign extended to 32 bits instead of 24 s32 float_to_int(u16 f_val) { u32 sign = (f_val >> 15) & 1; u32 sign_inverse = (!sign) & 1; u32 exponent = (f_val >> 11) & 0xf; u32 mantissa = f_val & 0x7FF; s32 ret_val = sign << 31; if (exponent > 11) { exponent = 11; ret_val |= (sign << 30); } else ret_val |= (sign_inverse << 30); ret_val |= mantissa << 19; ret_val = ret_val >> (exponent + (1 << 3)); return ret_val; } u16 int_to_float(u32 i_val) { u32 sign = (i_val >> 23) & 1; u32 exponent = 0; if (sign != 0) i_val = (~i_val) & 0x7FFFFF; if (i_val <= 0x1FFFF) { i_val *= 64; exponent += 0x3000; } if (i_val <= 0xFFFFF) { i_val *= 8; exponent += 0x1800; } if (i_val <= 0x3FFFFF) { i_val *= 2; exponent += 0x800; } if (i_val <= 0x3FFFFF) { i_val *= 2; exponent += 0x800; } if (i_val <= 0x3FFFFF) exponent += 0x800; i_val >>= 11; i_val &= 0x7ff; i_val |= exponent; if (sign != 0) i_val ^= (0x7ff | (1 << 15)); return i_val; } int ScspDspAssembleGetValue(char* instruction) { char temp[512] = { 0 }; int value = 0; sscanf(instruction, "%s %d", temp, &value); return value; } u64 ScspDspAssembleLine(char* line) { union ScspDspInstruction instruction = { 0 }; char* temp = NULL; if ((temp = strstr(line, "tra"))) { instruction.part.tra = ScspDspAssembleGetValue(temp); } if (strstr(line, "twt")) { instruction.part.twt = 1; } if ((temp = strstr(line, "twa"))) { instruction.part.twa = ScspDspAssembleGetValue(temp); } if (strstr(line, "xsel")) { instruction.part.xsel = 1; } if ((temp = strstr(line, "ysel"))) { instruction.part.ysel = ScspDspAssembleGetValue(temp); } if ((temp = strstr(line, "ira"))) { instruction.part.ira = ScspDspAssembleGetValue(temp); } if (strstr(line, "iwt")) { instruction.part.iwt = 1; } if ((temp = strstr(line, "iwa"))) { instruction.part.iwa = ScspDspAssembleGetValue(temp); } if (strstr(line, "table")) { instruction.part.table = 1; } if (strstr(line, "mwt")) { instruction.part.mwt = 1; } if (strstr(line, "mrd")) { instruction.part.mrd = 1; } if (strstr(line, "ewt")) { instruction.part.ewt = 1; } if ((temp = strstr(line, "ewa"))) { instruction.part.ewa = ScspDspAssembleGetValue(temp); } if (strstr(line, "adrl")) { instruction.part.adrl = 1; } if (strstr(line, "frcl")) { instruction.part.frcl = 1; } if ((temp = strstr(line, "shift"))) { instruction.part.shift = ScspDspAssembleGetValue(temp); } if (strstr(line, "yrl")) { instruction.part.yrl = 1; } if (strstr(line, "negb")) { instruction.part.negb = 1; } if (strstr(line, "zero")) { instruction.part.zero = 1; } if (strstr(line, "bsel")) { instruction.part.bsel = 1; } if (strstr(line, "nofl")) { instruction.part.nofl = 1; } if ((temp = strstr(line, "coef"))) { instruction.part.coef = ScspDspAssembleGetValue(temp); } if ((temp = strstr(line, "masa"))) { instruction.part.masa = ScspDspAssembleGetValue(temp); } if (strstr(line, "adreb")) { instruction.part.adreb = 1; } if (strstr(line, "nxadr")) { instruction.part.adreb = 1; } if (strstr(line, "nop")) { instruction.all = 0; } return instruction.all; } void ScspDspAssembleFromFile(char * filename, u64* output) { int i; char line[1024] = { 0 }; FILE * fp = fopen(filename, "r"); if (!fp) { return; } for (i = 0; i < 128; i++) { char * result = fgets(line, sizeof(line), fp); output[i] = ScspDspAssembleLine(line); } fclose(fp); } void ScspDspDisasm(u8 addr, char *outstring) { union ScspDspInstruction instruction; instruction.all = scsp_dsp.mpro[addr]; sprintf(outstring, "%02X: ", addr); outstring += strlen(outstring); if (instruction.all == 0) { sprintf(outstring, "nop "); outstring += strlen(outstring); return; } if (instruction.part.nofl) { sprintf(outstring, "nofl "); outstring += strlen(outstring); } if (instruction.part.coef) { sprintf(outstring, "coef %02X ", (unsigned int)(instruction.part.coef & 0x3F)); outstring += strlen(outstring); } if (instruction.part.masa) { sprintf(outstring, "masa %02X ", (unsigned int)(instruction.part.masa & 0x1F)); outstring += strlen(outstring); } if (instruction.part.adreb) { sprintf(outstring, "adreb "); outstring += strlen(outstring); } if (instruction.part.nxadr) { sprintf(outstring, "nxadr "); outstring += strlen(outstring); } if (instruction.part.table) { sprintf(outstring, "table "); outstring += strlen(outstring); } if (instruction.part.mwt) { sprintf(outstring, "mwt "); outstring += strlen(outstring); } if (instruction.part.mrd) { sprintf(outstring, "mrd "); outstring += strlen(outstring); } if (instruction.part.ewt) { sprintf(outstring, "ewt "); outstring += strlen(outstring); } if (instruction.part.ewa) { sprintf(outstring, "ewa %01X ", (unsigned int)(instruction.part.ewa & 0xf)); outstring += strlen(outstring); } if (instruction.part.adrl) { sprintf(outstring, "adrl "); outstring += strlen(outstring); } if (instruction.part.frcl) { sprintf(outstring, "frcl "); outstring += strlen(outstring); } if (instruction.part.shift) { sprintf(outstring, "shift %d ", (int)(instruction.part.shift & 3)); outstring += strlen(outstring); } if (instruction.part.yrl) { sprintf(outstring, "yrl "); outstring += strlen(outstring); } if (instruction.part.negb) { sprintf(outstring, "negb "); outstring += strlen(outstring); } if (instruction.part.zero) { sprintf(outstring, "zero "); outstring += strlen(outstring); } if (instruction.part.bsel) { sprintf(outstring, "bsel "); outstring += strlen(outstring); } if (instruction.part.xsel) { sprintf(outstring, "xsel "); outstring += strlen(outstring); } if (instruction.part.ysel) { sprintf(outstring, "ysel %d ", (int)(instruction.part.ysel & 3)); outstring += strlen(outstring); } if (instruction.part.ira) { sprintf(outstring, "ira %02X ", (int)(instruction.part.ira & 0x3F)); outstring += strlen(outstring); } if (instruction.part.iwt) { sprintf(outstring, "iwt "); outstring += strlen(outstring); } if (instruction.part.iwa) { sprintf(outstring, "iwa %02X ", (unsigned int)(instruction.part.iwa & 0x1F)); outstring += strlen(outstring); } if (instruction.part.tra) { sprintf(outstring, "tra %02X ", (unsigned int)(instruction.part.tra & 0x7F)); outstring += strlen(outstring); } if (instruction.part.twt) { sprintf(outstring, "twt "); outstring += strlen(outstring); } if (instruction.part.twa) { sprintf(outstring, "twa %02X ", (unsigned int)(instruction.part.twa & 0x7F)); outstring += strlen(outstring); } if (instruction.part.unknown) { sprintf(outstring, "unknown "); outstring += strlen(outstring); } if (instruction.part.unknown2) { sprintf(outstring, "unknown2 "); outstring += strlen(outstring); } if (instruction.part.unknown3) { sprintf(outstring, "unknown3 %d", (int)(instruction.part.unknown3 & 3)); outstring += strlen(outstring); } } void ScspDspDisassembleToFile(char * filename) { int i; FILE * fp = fopen(filename, "w"); if (!fp) { return; } for (i = 0; i < 128; i++) { char output[1024] = { 0 }; ScspDspDisasm(i, output); fprintf(fp, "%s\n", output); } fclose(fp); } yabause-0.9.15/src/bios.c000644 001750 001750 00000160636 12755623101 017156 0ustar00guillaumeguillaume000000 000000 /* Copyright 2006-2007 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file bios.c \brief Emulated bios functions required for running games and saving backup ram. */ #include "memory.h" #include "cs0.h" #include "debug.h" #include "sh2core.h" #include "bios.h" #include "smpc.h" #include "yabause.h" #include "error.h" static u8 sh2masklist[0x20] = { 0xF0, 0xE0, 0xD0, 0xC0, 0xB0, 0xA0, 0x90, 0x80, 0x80, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70 }; static u32 scumasklist[0x20] = { 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFC, 0xFFFFFFF8, 0xFFFFFFF0, 0xFFFFFFE0, 0xFFFFFFC0, 0xFFFFFF80, 0xFFFFFF80, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00, 0xFFFFFE00 }; u32 interruptlist[2][0x80]; ////////////////////////////////////////////////////////////////////////////// void BiosInit(void) { int i; // Setup vectors MappedMemoryWriteLongNocache(MSH2, 0x06000600, 0x002B0009); // rte, nop MappedMemoryWriteLongNocache(MSH2, 0x06000604, 0xE0F0600C); // mov #0xF0, r0; extu.b r0, r0 MappedMemoryWriteLongNocache(MSH2, 0x06000608, 0x400E8BFE); // ldc r0, sr; bf MappedMemoryWriteLongNocache(MSH2, 0x0600060C, 0x00090009); // nop MappedMemoryWriteLongNocache(MSH2, 0x06000610, 0x000B0009); // rts, nop for (i = 0; i < 0x200; i+=4) { MappedMemoryWriteLongNocache(MSH2, 0x06000000+i, 0x06000600); MappedMemoryWriteLongNocache(MSH2, 0x06000400+i, 0x06000600); interruptlist[0][i >> 2] = 0x06000600; interruptlist[1][i >> 2] = 0x06000600; } MappedMemoryWriteLongNocache(MSH2, 0x06000010, 0x06000604); MappedMemoryWriteLongNocache(MSH2, 0x06000018, 0x06000604); MappedMemoryWriteLongNocache(MSH2, 0x06000024, 0x06000604); MappedMemoryWriteLongNocache(MSH2, 0x06000028, 0x06000604); interruptlist[0][4] = 0x06000604; interruptlist[0][6] = 0x06000604; interruptlist[0][9] = 0x06000604; interruptlist[0][10] = 0x06000604; MappedMemoryWriteLongNocache(MSH2, 0x06000410, 0x06000604); MappedMemoryWriteLongNocache(MSH2, 0x06000418, 0x06000604); MappedMemoryWriteLongNocache(MSH2, 0x06000424, 0x06000604); MappedMemoryWriteLongNocache(MSH2, 0x06000428, 0x06000604); interruptlist[1][4] = 0x06000604; interruptlist[1][6] = 0x06000604; interruptlist[1][9] = 0x06000604; interruptlist[1][10] = 0x06000604; // Scu Interrupts for (i = 0; i < 0x38; i+=4) { MappedMemoryWriteLongNocache(MSH2, 0x06000100+i, 0x00000400+i); interruptlist[0][0x40+(i >> 2)] = 0x00000400+i; } for (i = 0; i < 0x40; i+=4) { MappedMemoryWriteLongNocache(MSH2, 0x06000140+i, 0x00000440+i); interruptlist[0][0x50+(i >> 2)] = 0x00000440+i; } for (i = 0; i < 0x100; i+=4) MappedMemoryWriteLongNocache(MSH2, 0x06000A00+i, 0x06000610); // Setup Bios Functions MappedMemoryWriteLongNocache(MSH2, 0x06000210, 0x00000210); MappedMemoryWriteLongNocache(MSH2, 0x0600026C, 0x0000026C); MappedMemoryWriteLongNocache(MSH2, 0x06000274, 0x00000274); MappedMemoryWriteLongNocache(MSH2, 0x06000280, 0x00000280); MappedMemoryWriteLongNocache(MSH2, 0x0600029C, 0x0000029C); MappedMemoryWriteLongNocache(MSH2, 0x060002DC, 0x000002DC); MappedMemoryWriteLongNocache(MSH2, 0x06000300, 0x00000300); MappedMemoryWriteLongNocache(MSH2, 0x06000304, 0x00000304); MappedMemoryWriteLongNocache(MSH2, 0x06000310, 0x00000310); MappedMemoryWriteLongNocache(MSH2, 0x06000314, 0x00000314); MappedMemoryWriteLongNocache(MSH2, 0x06000320, 0x00000320); MappedMemoryWriteLongNocache(MSH2, 0x06000324, 0x00000000); MappedMemoryWriteLongNocache(MSH2, 0x06000330, 0x00000330); MappedMemoryWriteLongNocache(MSH2, 0x06000334, 0x00000334); MappedMemoryWriteLongNocache(MSH2, 0x06000340, 0x00000340); MappedMemoryWriteLongNocache(MSH2, 0x06000344, 0x00000344); MappedMemoryWriteLongNocache(MSH2, 0x06000348, 0xFFFFFFFF); MappedMemoryWriteLongNocache(MSH2, 0x06000354, 0x00000000); MappedMemoryWriteLongNocache(MSH2, 0x06000358, 0x00000358); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosSetScuInterrupt(SH2_struct * sh) { SH2GetRegisters(sh, &sh->regs); // LOG("BiosSetScuInterrupt. vector = %02X, func = %08X\n", sh->regs.R[4], sh->regs.R[5]); if (sh->regs.R[5] == 0) { sh->MappedMemoryWriteLong(sh, 0x06000900+(sh->regs.R[4] << 2), 0x06000610); sh->cycles += 8; } else { sh->MappedMemoryWriteLong(sh, 0x06000900+(sh->regs.R[4] << 2), sh->regs.R[5]); sh->cycles += 9; } sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosGetScuInterrupt(SH2_struct * sh) { SH2GetRegisters(sh, &sh->regs); // check me // LOG("BiosGetScuInterrupt\n"); sh->regs.R[0] = sh->MappedMemoryReadLong(sh, 0x06000900+(sh->regs.R[4] << 2)); sh->cycles += 5; sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosSetSh2Interrupt(SH2_struct * sh) { SH2GetRegisters(sh, &sh->regs); // LOG("BiosSetSh2Interrupt\n"); if (sh->regs.R[5] == 0) { sh->MappedMemoryWriteLong(sh, sh->regs.VBR+(sh->regs.R[4] << 2), interruptlist[sh->isslave][sh->regs.R[4]]); sh->cycles += 8; } else { sh->MappedMemoryWriteLong(sh, sh->regs.VBR+(sh->regs.R[4] << 2), sh->regs.R[5]); sh->cycles += 9; } sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosGetSh2Interrupt(SH2_struct * sh) { SH2GetRegisters(sh, &sh->regs); // check me // LOG("BiosGetSh2Interrupt\n"); sh->regs.R[0] = sh->MappedMemoryReadLong(sh, sh->regs.VBR+(sh->regs.R[4] << 2)); sh->cycles += 5; sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosSetScuInterruptMask(SH2_struct * sh) { SH2GetRegisters(sh, &sh->regs); // check me LOG("BiosSetScuInterruptMask\n"); if (!sh->isslave) { sh->MappedMemoryWriteLong(sh, 0x06000348, sh->regs.R[4]); sh->MappedMemoryWriteLong(sh, 0x25FE00A0, sh->regs.R[4]); // Interrupt Mask Register } if (!(sh->regs.R[4] & 0x8000)) // double check this sh->MappedMemoryWriteLong(sh, 0x25FE00A8, 1); // A-bus Interrupt Acknowledge sh->cycles += 17; sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosChangeScuInterruptMask(SH2_struct * sh) { u32 newmask; SH2GetRegisters(sh, &sh->regs); // LOG("BiosChangeScuInterruptMask\n"); // Read Stored Scu Interrupt Mask, AND it by R4, OR it by R5, then put it back newmask = (sh->MappedMemoryReadLong(sh, 0x06000348) & sh->regs.R[4]) | sh->regs.R[5]; if (!sh->isslave) { sh->MappedMemoryWriteLong(sh, 0x06000348, newmask); sh->MappedMemoryWriteLong(sh, 0x25FE00A0, newmask); // Interrupt Mask Register sh->MappedMemoryWriteLong(sh, 0x25FE00A4, (u32)(s16)sh->regs.R[4]); // Interrupt Status Register } if (!(sh->regs.R[4] & 0x8000)) // double check this sh->MappedMemoryWriteLong(sh, 0x25FE00A8, 1); // A-bus Interrupt Acknowledge sh->cycles += 20; sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosCDINIT2(SH2_struct * sh) { SH2GetRegisters(sh, &sh->regs); sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosCDINIT1(SH2_struct * sh) { SH2GetRegisters(sh, &sh->regs); sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosGetSemaphore(SH2_struct * sh) { u8 temp; SH2GetRegisters(sh, &sh->regs); // check me LOG("BiosGetSemaphore\n"); if ((temp = sh->MappedMemoryReadByte(sh, 0x06000B00 + sh->regs.R[4])) == 0) sh->regs.R[0] = 1; else sh->regs.R[0] = 0; temp |= 0x80; sh->MappedMemoryWriteByte(sh, 0x06000B00 + sh->regs.R[4], temp); sh->cycles += 11; sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosClearSemaphore(SH2_struct * sh) { SH2GetRegisters(sh, &sh->regs); // check me LOG("BiosClearSemaphore\n"); sh->MappedMemoryWriteByte(sh, 0x06000B00 + sh->regs.R[4], 0); sh->cycles += 5; sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosChangeSystemClock(SH2_struct * sh) { int i, j; u32 mask; SH2GetRegisters(sh, &sh->regs); LOG("BiosChangeSystemClock\n"); // Set new system clock speed sh->MappedMemoryWriteLong(sh, 0x06000324, sh->regs.R[4]); sh->MappedMemoryWriteLong(sh, 0x25FE00A8, 0); // Clear A-bus Interrupt ACK sh->MappedMemoryWriteLong(sh, 0x25FE00B8, 0); // Clear A-Bus Refresh sh->MappedMemoryWriteByte(sh, 0xFFFFFE91, 0x80); // Transition to standby mode sh->MappedMemoryWriteWord(sh, 0xFFFFFE80, 0xA51D); // Set WDT counter sh->MappedMemoryWriteWord(sh, 0xFFFFFEE0, 0x8000); // Set NMI edge select to high if (sh->regs.R[4] == 0) SmpcCKCHG320(); else SmpcCKCHG352(); // Clear SCU DMA Regs for (j = 0; j < 3; j++) { for (i = 0; i < 7; i++) sh->MappedMemoryWriteLong(sh, 0x25FE0000+(j*0xC)+(i*4), 0); } sh->MappedMemoryWriteLong(sh, 0x25FE0060, 0); // Clear DMA force stop sh->MappedMemoryWriteLong(sh, 0x25FE0080, 0); // Clear DSP Control Port sh->MappedMemoryWriteLong(sh, 0x25FE00B0, 0x1FF01FF0); // Reset A-Bus Set sh->MappedMemoryWriteLong(sh, 0x25FE00B4, 0x1FF01FF0); sh->MappedMemoryWriteLong(sh, 0x25FE00B8, 0x1F); // Reset A-Bus Refresh sh->MappedMemoryWriteLong(sh, 0x25FE00A8, 0x1); // Reset A-bus Interrupt ACK sh->MappedMemoryWriteLong(sh, 0x25FE0090, 0x3FF); // Reset Timer 0 Compare sh->MappedMemoryWriteLong(sh, 0x25FE0094, 0x1FF); // Reset Timer 1 Set Data sh->MappedMemoryWriteLong(sh, 0x25FE0098, 0); // Reset Timer 1 Mode mask = sh->MappedMemoryReadLong(sh, 0x06000348); sh->MappedMemoryWriteLong(sh, 0x25FE00A0, mask); // Interrupt Mask Register if (!(mask & 0x8000)) sh->MappedMemoryWriteLong(sh, 0x25FE00A8, 1); // A-bus Interrupt Acknowledge sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosChangeScuInterruptPriority(SH2_struct * sh) { int i; SH2GetRegisters(sh, &sh->regs); // check me // LOG("BiosChangeScuInterruptPriority\n"); for (i = 0; i < 0x20; i++) { scumasklist[i] = sh->MappedMemoryReadLong(sh, sh->regs.R[4]+(i << 2)); sh2masklist[i] = (scumasklist[i] >> 16); if (scumasklist[i] & 0x8000) scumasklist[i] |= 0xFFFF0000; else scumasklist[i] &= 0x0000FFFF; } sh->cycles += 186; sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosExecuteCDPlayer(SH2_struct * sh) { SH2GetRegisters(sh, &sh->regs); LOG("BiosExecuteCDPlayer\n"); sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosPowerOnMemoryClear(SH2_struct * sh) { SH2GetRegisters(sh, &sh->regs); LOG("BiosPowerOnMemoryClear\n"); sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosCheckMPEGCard(SH2_struct * sh) { SH2GetRegisters(sh, &sh->regs); LOG("BiosCheckMPEGCard\n"); sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static u32 GetDeviceStats(u32 device, u32 *size, u32 *addr, u32 *blocksize) { switch(device) { case 0: *addr = 0x00180000; *size = 0x8000; *blocksize = 0x40; return 0; case 1: if ((CartridgeArea->cartid & 0xF0) == 0x20) { *addr = 0x04000000; *size = 0x40000 << (CartridgeArea->cartid & 0x0F); if (CartridgeArea->cartid == 0x24) *blocksize = 0x400; else *blocksize = 0x200; return 0; } else return 1; default: *addr = 0; *size = 0; *blocksize = 0; return 1; } return 1; } ////////////////////////////////////////////////////////////////////////////// static int CheckHeader(UNUSED u32 device) { return 0; } ////////////////////////////////////////////////////////////////////////////// static int CalcSaveSize(SH2_struct *sh, u32 tableaddr, int blocksize) { int numblocks=0; // Now figure out how many blocks this save is for(;;) { u16 block; block = (sh->MappedMemoryReadByte(sh, tableaddr) << 8) | sh->MappedMemoryReadByte(sh, tableaddr + 2); if (block == 0) break; tableaddr += 4; if (((tableaddr-1) & ((blocksize << 1) - 1)) == 0) tableaddr += 8; numblocks++; } return numblocks; } ////////////////////////////////////////////////////////////////////////////// static u32 GetFreeSpace(SH2_struct *sh, UNUSED u32 device, u32 size, u32 addr, u32 blocksize) { u32 i; u32 usedblocks=0; for (i = ((2 * blocksize) << 1); i < (size << 1); i += (blocksize << 1)) { // Find a block with the start of a save if (((s8)sh->MappedMemoryReadByte(sh, addr + i + 1)) < 0) { // Now figure out how many blocks this save is usedblocks += (CalcSaveSize(sh, addr+i+0x45, blocksize) + 1); } } return ((size / blocksize) - 2 - usedblocks); } ////////////////////////////////////////////////////////////////////////////// static u32 FindSave(SH2_struct *sh, UNUSED u32 device, u32 stringaddr, u32 blockoffset, u32 size, u32 addr, u32 blocksize) { u32 i; for (i = ((blockoffset * blocksize) << 1); i < (size << 1); i += (blocksize << 1)) { // Find a block with the start of a save if (((s8)sh->MappedMemoryReadByte(sh, addr + i + 1)) < 0) { int i3; // See if string matches, or if there's no string to check, just copy // the data over for (i3 = 0; i3 < 11; i3++) { u8 data = sh->MappedMemoryReadByte(sh, stringaddr+i3); if (sh->MappedMemoryReadByte(sh, addr+i+0x9+(i3*2)) != data) { if (data == 0) // There's no string to match return ((i / blocksize) >> 1); else // No Match, move onto the next block i3 = 12; } else { // Match if (i3 == 10 || data == 0) return ((i / blocksize) >> 1); } } } } return 0; } ////////////////////////////////////////////////////////////////////////////// static u32 FindSave2(SH2_struct *sh, UNUSED u32 device, const char *string, u32 blockoffset, u32 size, u32 addr, u32 blocksize) { u32 i; for (i = ((blockoffset * blocksize) << 1); i < (size << 1); i += (blocksize << 1)) { // Find a block with the start of a save if (((s8)sh->MappedMemoryReadByte(sh, addr + i + 1)) < 0) { int i3; // See if string matches, or if there's no string to check, just copy // the data over for (i3 = 0; i3 < 11; i3++) { if (sh->MappedMemoryReadByte(sh, addr+i+0x9+(i3*2)) != string[i3]) { if (string[i3] == 0) // There's no string to match return ((i / blocksize) >> 1); else // No Match, move onto the next block i3 = 12; } else { // Match if (i3 == 10 || string[i3] == 0) return ((i / blocksize) >> 1); } } } } return 0; } ////////////////////////////////////////////////////////////////////////////// static void DeleteSave(SH2_struct *sh, u32 addr, u32 blockoffset, u32 blocksize) { sh->MappedMemoryWriteByte(sh, addr + (blockoffset * blocksize * 2) + 0x1, 0x00); } ////////////////////////////////////////////////////////////////////////////// static u16 *GetFreeBlocks(SH2_struct *sh, u32 addr, u32 blocksize, u32 numblocks, u32 size) { u8 *blocktbl; u16 *freetbl; u32 tableaddr; u32 i; u32 blockcount=0; // Create a table that tells us which blocks are free and used if ((blocktbl = (u8 *)malloc(sizeof(u8) * (size / blocksize))) == NULL) return NULL; memset(blocktbl, 0, (size / blocksize)); for (i = ((2 * blocksize) << 1); i < (size << 1); i += (blocksize << 1)) { // Find a block with the start of a save if (((s8)sh->MappedMemoryReadByte(sh, addr + i + 1)) < 0) { tableaddr = addr+i+0x45; blocktbl[i / (blocksize << 1)] = 1; // Now let's figure out which blocks are used for(;;) { u16 block; block = (sh->MappedMemoryReadByte(sh, tableaddr) << 8) | sh->MappedMemoryReadByte(sh, tableaddr + 2); if (block == 0) break; tableaddr += 4; if (((tableaddr-1) & ((blocksize << 1) - 1)) == 0) tableaddr += 8; // block is used blocktbl[block] = 1; } } } if ((freetbl = (u16 *)malloc(sizeof(u16) * numblocks)) == NULL) { free(blocktbl); return NULL; } // Find some free blocks for us to use for (i = 2; i < (size / blocksize); i++) { if (blocktbl[i] == 0) { freetbl[blockcount] = (u16)i; blockcount++; if (blockcount >= numblocks) break; } } // Ok, we're all done free(blocktbl); return freetbl; } ////////////////////////////////////////////////////////////////////////////// static u16 *ReadBlockTable(SH2_struct *sh, u32 addr, u32 *tableaddr, int block, int blocksize, int *numblocks, int *blocksread) { u16 *blocktbl = NULL; int i=0; tableaddr[0] = addr + (block * blocksize * 2) + 0x45; blocksread[0]=0; // First of all figure out how large of buffer we need numblocks[0] = CalcSaveSize(sh, tableaddr[0], blocksize); // Allocate buffer if ((blocktbl = (u16 *)malloc(sizeof(u16) * numblocks[0])) == NULL) return NULL; // Now read in the table for(i = 0; i < numblocks[0]; i++) { u16 block; block = (sh->MappedMemoryReadByte(sh, tableaddr[0]) << 8) | sh->MappedMemoryReadByte(sh, tableaddr[0] + 2); tableaddr[0] += 4; if (((tableaddr[0]-1) & ((blocksize << 1) - 1)) == 0) { tableaddr[0] = addr + (blocktbl[blocksread[0]] * blocksize * 2) + 9; blocksread[0]++; } blocktbl[i] = block; } tableaddr[0] += 4; return blocktbl; } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosBUPInit(SH2_struct * sh) { SH2GetRegisters(sh, &sh->regs); // LOG("BiosBUPInit. arg1 = %08X, arg2 = %08X, arg3 = %08X\n", sh->regs.R[4], sh->regs.R[5], sh->regs.R[6]); // Setup Function table sh->MappedMemoryWriteLong(sh, 0x06000354, sh->regs.R[5]); sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x00, 0x00000380); sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x04, 0x00000384); sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x08, 0x00000388); sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x0C, 0x0000038C); sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x10, 0x00000390); sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x14, 0x00000394); sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x18, 0x00000398); sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x1C, 0x0000039C); sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x20, 0x000003A0); sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x24, 0x000003A4); sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x28, 0x000003A8); sh->MappedMemoryWriteLong(sh, sh->regs.R[5]+0x2C, 0x000003AC); // Setup Device list // First Device sh->MappedMemoryWriteWord(sh, sh->regs.R[6], 1); // ID sh->MappedMemoryWriteWord(sh, sh->regs.R[6]+0x2, 1); // Number of partitions // Second Device if ((CartridgeArea->cartid & 0xF0) == 0x20) { sh->MappedMemoryWriteWord(sh, sh->regs.R[6]+0x4, 2); // ID sh->MappedMemoryWriteWord(sh, sh->regs.R[6]+0x6, 1); // Number of partitions } else { sh->MappedMemoryWriteWord(sh, sh->regs.R[6]+0x4, 0); // ID sh->MappedMemoryWriteWord(sh, sh->regs.R[6]+0x6, 0); // Number of partitions } // Third Device sh->MappedMemoryWriteWord(sh, sh->regs.R[6]+0x08, 0); // ID sh->MappedMemoryWriteWord(sh, sh->regs.R[6]+0x0A, 0); // Number of partitions // cycles need to be incremented sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosBUPSelectPartition(SH2_struct * sh) { SH2GetRegisters(sh, &sh->regs); LOG("BiosBUPSelectPartition. PR = %08X\n", sh->regs.PR); sh->regs.R[0] = 0; // returns 0 if there's no error sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosBUPFormat(SH2_struct * sh) { SH2GetRegisters(sh, &sh->regs); // LOG("BiosBUPFormat. PR = %08X\n", sh->regs.PR); BupFormat(sh->regs.R[4]); sh->regs.R[0] = 0; // returns 0 if there's no error sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosBUPStatus(SH2_struct * sh) { u32 size; u32 addr; u32 blocksize; u32 ret; u32 freeblocks=0; u32 needsize; int aftersize; SH2GetRegisters(sh, &sh->regs); // LOG("BiosBUPStatus. arg1 = %d, arg2 = %d, arg3 = %08X, PR = %08X\n", sh->regs.R[4], sh->regs.R[5], sh->regs.R[6], sh->regs.PR); // Fill in status variables ret = GetDeviceStats(sh->regs.R[4], &size, &addr, &blocksize); // Make sure there's a proper header, and return if there's any other errors if (ret == 1 || CheckHeader(sh->regs.R[4]) != 0) { // Error sh->regs.R[0] = ret; sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); return; } freeblocks = GetFreeSpace(sh, sh->regs.R[4], size, addr, blocksize); needsize = sh->regs.R[5]; aftersize = (((blocksize - 6) * freeblocks) - 30) - needsize; if (aftersize < 0) aftersize = 0; sh->MappedMemoryWriteLong(sh, sh->regs.R[6], size); // Size of Backup Ram (in bytes) sh->MappedMemoryWriteLong(sh, sh->regs.R[6]+0x4, size / blocksize); // Size of Backup Ram (in blocks) sh->MappedMemoryWriteLong(sh, sh->regs.R[6]+0x8, blocksize); // Size of block sh->MappedMemoryWriteLong(sh, sh->regs.R[6]+0xC, ((blocksize - 6) * freeblocks) - 30); // Free space(in bytes) sh->MappedMemoryWriteLong(sh, sh->regs.R[6]+0x10, freeblocks); // Free space(in blocks) sh->MappedMemoryWriteLong(sh, sh->regs.R[6]+0x14, aftersize / blocksize); // writable block size // cycles need to be incremented sh->regs.R[0] = ret; // returns 0 if there's no error sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosBUPWrite(SH2_struct * sh) { u32 size; u32 addr; u32 blocksize; u32 block; u32 ret; u32 savesize; u16 *blocktbl; u32 workaddr; u32 blockswritten=0; u32 datasize; u32 i; SH2GetRegisters(sh, &sh->regs); LOG("BiosBUPWrite. arg1 = %d, arg2 = %08X, arg3 = %08X, arg4 = %d, PR = %08X\n", sh->regs.R[4], sh->regs.R[5], sh->regs.R[6], sh->regs.R[7], sh->regs.PR); // Fill in status variables ret = GetDeviceStats(sh->regs.R[4], &size, &addr, &blocksize); if (ret == 1) { // Error sh->regs.R[0] = ret; sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); return; } // See if save exists already if ((block = FindSave(sh, sh->regs.R[4], sh->regs.R[5], 2, size, addr, blocksize)) != 0) { // save exists // Should we be overwriting it? if (sh->regs.R[7] != 0) { // Nope, let's bail instead sh->regs.R[0] = 6; sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); return; } // Delete old save DeleteSave(sh, addr, block, blocksize); } // Let's figure out how many blocks will be needed for the save datasize = sh->MappedMemoryReadLong(sh, sh->regs.R[5]+0x1C); savesize = (datasize + 0x1D) / (blocksize - 6); if ((datasize + 0x1D) % (blocksize - 6)) savesize++; // Will it blend? Err... fit if (savesize > GetFreeSpace(sh, sh->regs.R[4], size, addr, blocksize)) { // Nope, time to bail sh->regs.R[0] = 4; sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); return; } // Find free blocks for the save if ((blocktbl = GetFreeBlocks(sh, addr, blocksize, savesize, size)) == NULL) { // Just return an error that might make sense sh->regs.R[0] = 8; sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); return; } // Create save workaddr = addr + (blocktbl[0] * blocksize * 2); sh->MappedMemoryWriteByte(sh, workaddr+0x1, 0x80); // Copy over filename for (i = workaddr+0x9; i < ((workaddr+0x9) + (11 * 2)); i+=2) { sh->MappedMemoryWriteByte(sh, i, sh->MappedMemoryReadByte(sh, sh->regs.R[5])); sh->regs.R[5]++; } sh->regs.R[5]++; // Copy over comment for (i = workaddr+0x21; i < ((workaddr+0x21) + (10 * 2)); i+=2) { sh->MappedMemoryWriteByte(sh, i, sh->MappedMemoryReadByte(sh, sh->regs.R[5])); sh->regs.R[5]++; } // Copy over language sh->MappedMemoryWriteByte(sh, workaddr+0x1F, sh->MappedMemoryReadByte(sh, sh->regs.R[5])); sh->regs.R[5]++; sh->regs.R[5]++; // Copy over date for (i = workaddr+0x35; i < ((workaddr+0x35) + (4 * 2)); i+=2) { sh->MappedMemoryWriteByte(sh, i, sh->MappedMemoryReadByte(sh, sh->regs.R[5])); sh->regs.R[5]++; } // Copy over data size for (i = workaddr+0x3D; i < ((workaddr+0x3D) + (4 * 2)); i+=2) { sh->MappedMemoryWriteByte(sh, i, sh->MappedMemoryReadByte(sh, sh->regs.R[5])); sh->regs.R[5]++; } // write the block table workaddr += 0x45; for (i = 1; i < savesize; i++) { sh->MappedMemoryWriteByte(sh, workaddr, (u8)(blocktbl[i] >> 8)); workaddr+=2; sh->MappedMemoryWriteByte(sh, workaddr, (u8)blocktbl[i]); workaddr+=2; if (((workaddr-1) & ((blocksize << 1) - 1)) == 0) { // Next block blockswritten++; workaddr = addr + (blocktbl[blockswritten] * blocksize * 2) + 9; } } // Write 2 blank bytes so we now how large the table size is next time sh->MappedMemoryWriteByte(sh, workaddr, 0); workaddr+=2; sh->MappedMemoryWriteByte(sh, workaddr, 0); workaddr+=2; // Lastly, write the actual save data while (datasize > 0) { sh->MappedMemoryWriteByte(sh, workaddr, sh->MappedMemoryReadByte(sh, sh->regs.R[6])); datasize--; sh->regs.R[6]++; workaddr+=2; if (((workaddr-1) & ((blocksize << 1) - 1)) == 0) { // Next block blockswritten++; workaddr = addr + (blocktbl[blockswritten] * blocksize * 2) + 9; } } free(blocktbl); YabFlushBackups(); sh->regs.R[0] = 0; // returns 0 if there's no error sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosBUPRead(SH2_struct * sh) { u32 size; u32 addr; u32 blocksize; u32 block; u32 ret; u32 tableaddr; u16 *blocktbl; int numblocks; int blocksread; u32 datasize; SH2GetRegisters(sh, &sh->regs); LOG("BiosBUPRead\n", sh->regs.PR); ret = GetDeviceStats(sh->regs.R[4], &size, &addr, &blocksize); if (ret == 1) { // Error sh->regs.R[0] = ret; sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); return; } // See if save exists if ((block = FindSave(sh, sh->regs.R[4], sh->regs.R[5], 2, size, addr, blocksize)) == 0) { // save doesn't exist sh->regs.R[0] = 5; sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); return; } tableaddr = addr + (block * blocksize * 2) + 0x3D; datasize = (sh->MappedMemoryReadByte(sh, tableaddr) << 24) | (sh->MappedMemoryReadByte(sh, tableaddr + 2) << 16) | (sh->MappedMemoryReadByte(sh, tableaddr+4) << 8) | sh->MappedMemoryReadByte(sh, tableaddr + 6); // Read in Block Table if ((blocktbl = ReadBlockTable(sh, addr, &tableaddr, block, blocksize, &numblocks, &blocksread)) == NULL) { // Just return an error that might make sense sh->regs.R[0] = 8; sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); return; } // Now let's read in the data while (datasize > 0) { sh->MappedMemoryWriteByte(sh, sh->regs.R[6], sh->MappedMemoryReadByte(sh, tableaddr)); datasize--; sh->regs.R[6]++; tableaddr+=2; if (((tableaddr-1) & ((blocksize << 1) - 1)) == 0) { // Load up the next block tableaddr = addr + (blocktbl[blocksread] * blocksize * 2) + 9; blocksread++; } } free(blocktbl); sh->regs.R[0] = 0; // returns 0 if there's no error sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosBUPDelete(SH2_struct * sh) { u32 size; u32 addr; u32 blocksize; u32 block; u32 ret; SH2GetRegisters(sh, &sh->regs); LOG("BiosBUPDelete. PR = %08X\n", sh->regs.PR); // Fill in status variables ret = GetDeviceStats(sh->regs.R[4], &size, &addr, &blocksize); if (ret == 1) { // Error sh->regs.R[0] = ret; sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); return; } // See if save exists if ((block = FindSave(sh, sh->regs.R[4], sh->regs.R[5], 2, size, addr, blocksize)) == 0) { // Since the save doesn't exist, let's bail with an error sh->regs.R[0] = 5; sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); return; } DeleteSave(sh, addr, block, blocksize); sh->regs.R[0] = 0; // returns 0 if there's no error sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosBUPDirectory(SH2_struct * sh) { u32 size; u32 addr; u32 blocksize; u32 ret; u32 i; char filename[12]; u32 blockoffset=2; SH2GetRegisters(sh, &sh->regs); // int findmatch = MappedMemoryReadByte(sh->regs.R[5]); for (i = 0; i < 12; i++) filename[i] = sh->MappedMemoryReadByte(sh, sh->regs.R[5]+i); LOG("BiosBUPDirectory. arg1 = %d, arg2 = %s, arg3 = %08X, arg4 = %08X, PR = %08X\n", sh->regs.R[4], filename, sh->regs.R[6], sh->regs.R[7], sh->regs.PR); ret = GetDeviceStats(sh->regs.R[4], &size, &addr, &blocksize); if (ret == 1) { // Error sh->regs.R[0] = ret; sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); return; } // Count Max size for (i = 0; i < 256; i++) { u32 block = FindSave(sh, sh->regs.R[4], sh->regs.R[5], blockoffset, size, addr, blocksize); if (block == 0) break; blockoffset = block + 1; block = addr + (blocksize * block * 2); } if (sh->regs.R[6] < i) { sh->regs.R[0] = -(s32)i; // returns the number of successfully read dir entries sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); return; } // reset offet blockoffset = 2; for (i = 0; i < sh->regs.R[6]; i++) { u32 i4; u32 datasize=0; u32 block = FindSave(sh, sh->regs.R[4], sh->regs.R[5], blockoffset, size, addr, blocksize); if (block == 0) break; blockoffset = block+1; // Alright, we found a match :) Time to copy over some data block = addr + (blocksize * block * 2); // Copy over filename for (i4 = block+0x9; i4 < ((block+0x9) + (11 * 2)); i4+=2) { sh->MappedMemoryWriteByte(sh, sh->regs.R[7], sh->MappedMemoryReadByte(sh, i4)); sh->regs.R[7]++; } sh->MappedMemoryWriteByte(sh, sh->regs.R[7], 0); sh->regs.R[7]++; // Copy over comment for (i4 = block+0x21; i4 < ((block+0x21) + (10 * 2)); i4+=2) { sh->MappedMemoryWriteByte(sh, sh->regs.R[7], sh->MappedMemoryReadByte(sh, i4)); sh->regs.R[7]++; } // Copy over language sh->MappedMemoryWriteByte(sh, sh->regs.R[7], sh->MappedMemoryReadByte(sh, block+0x1F)); sh->regs.R[7]++; sh->MappedMemoryWriteByte(sh, sh->regs.R[7], 0); sh->regs.R[7]++; // Copy over date for (i4 = block+0x35; i4 < ((block+0x35) + (4 * 2)); i4+=2) { sh->MappedMemoryWriteByte(sh, sh->regs.R[7], sh->MappedMemoryReadByte(sh, i4)); sh->regs.R[7]++; } // Copy over data size for (i4 = block+0x3D; i4 < ((block+0x3D) + (4 * 2)); i4+=2) { u8 data; datasize <<= 8; data = sh->MappedMemoryReadByte(sh, i4); sh->MappedMemoryWriteByte(sh, sh->regs.R[7], data); datasize |= data; sh->regs.R[7]++; } // Calculate block size from the data size, and then copy it over sh->MappedMemoryWriteWord(sh, sh->regs.R[7], (u16)(((datasize + 0x1D) / (blocksize - 6)) + 1)); sh->regs.R[7] += 4; } sh->regs.R[0] = i; // returns the number of successfully read dir entries sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosBUPVerify(SH2_struct * sh) { u32 size; u32 addr; u32 blocksize; u32 block; u32 ret; u32 tableaddr; u32 datasize; u16 *blocktbl; int numblocks; int blocksread; SH2GetRegisters(sh, &sh->regs); LOG("BiosBUPVerify. PR = %08X\n", sh->regs.PR); ret = GetDeviceStats(sh->regs.R[4], &size, &addr, &blocksize); if (ret == 1) { // Error sh->regs.R[0] = ret; sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); return; } // See if save exists if ((block = FindSave(sh, sh->regs.R[4], sh->regs.R[5], 2, size, addr, blocksize)) == 0) { // Since the save doesn't exist, let's bail with an error sh->regs.R[0] = 5; // Not found sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); return; } tableaddr = addr + (block * blocksize * 2) + 0x3D; datasize = (sh->MappedMemoryReadByte(sh, tableaddr) << 24) | (sh->MappedMemoryReadByte(sh, tableaddr + 2) << 16) | (sh->MappedMemoryReadByte(sh, tableaddr+4) << 8) | sh->MappedMemoryReadByte(sh, tableaddr + 6); // Read in Block Table if ((blocktbl = ReadBlockTable(sh, addr, &tableaddr, block, blocksize, &numblocks, &blocksread)) == NULL) { // Just return an error that might make sense sh->regs.R[0] = 8; // Broken sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); return; } // Now let's read in the data, and check to see if it matches while (datasize > 0) { if (sh->MappedMemoryReadByte(sh, sh->regs.R[6]) != sh->MappedMemoryReadByte(sh, tableaddr)) { free(blocktbl); // Ok, the data doesn't match sh->regs.R[0] = 7; // No match sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); return; } datasize--; sh->regs.R[6]++; tableaddr+=2; if (((tableaddr-1) & ((blocksize << 1) - 1)) == 0) { // Load up the next block tableaddr = addr + (blocktbl[blocksread] * blocksize * 2) + 9; blocksread++; } } free(blocktbl); sh->regs.R[0] = 0; // returns 0 if there's no error sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void ConvertMonthAndDay(SH2_struct *sh, u32 data, u32 monthaddr, u32 dayaddr, int type) { int i; u16 monthtbl[11] = { 31, 31+28, 31+28+31, 31+28+31+30, 31+28+31+30+31, 31+28+31+30+31+30, 31+28+31+30+31+30+31, 31+28+31+30+31+30+31+31, 31+28+31+30+31+30+31+31+30, 31+28+31+30+31+30+31+31+30+31, 31+28+31+30+31+30+31+31+30+31+30 }; if (data < monthtbl[0]) { // Month sh->MappedMemoryWriteByte(sh, monthaddr, 1); // Day sh->MappedMemoryWriteByte(sh, dayaddr, (u8)(data + 1)); return; } for (i = 1; i < 11; i++) { if (data <= monthtbl[i]) break; } if (type == 1) { // Month sh->MappedMemoryWriteByte(sh, monthaddr, (u8)(i + 1)); // Day if ((i + 1) == 2) sh->MappedMemoryWriteByte(sh, dayaddr, (u8)(data - monthtbl[(i - 1)] + 1)); else sh->MappedMemoryWriteByte(sh, dayaddr, (u8)(data - monthtbl[(i - 1)])); } else { // Month sh->MappedMemoryWriteByte(sh, monthaddr, (u8)(i + 1)); // Day sh->MappedMemoryWriteByte(sh, dayaddr, (u8)(data - monthtbl[(i - 1)] + 1)); } } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosBUPGetDate(SH2_struct * sh) { u32 date; u32 div; u32 yearoffset; u32 yearremainder; SH2GetRegisters(sh, &sh->regs); LOG("BiosBUPGetDate. PR = %08X\n", sh->regs.PR); date = sh->regs.R[4]; // Time sh->MappedMemoryWriteByte(sh, sh->regs.R[5]+3, (u8)((date % 0x5A0) / 0x3C)); // Minute sh->MappedMemoryWriteByte(sh, sh->regs.R[5]+4, (u8)(date % 0x3C)); div = date / 0x5A0; // Week if (div > 0xAB71) sh->MappedMemoryWriteByte(sh, sh->regs.R[5]+5, (u8)((div + 1) % 7)); else sh->MappedMemoryWriteByte(sh, sh->regs.R[5]+5, (u8)((div + 2) % 7)); yearremainder = div % 0x5B5; if (yearremainder > 0x16E) { yearoffset = (yearremainder - 1) / 0x16D; ConvertMonthAndDay(sh, (yearremainder - 1) % 0x16D, sh->regs.R[5]+1, sh->regs.R[5]+2, 0); } else { yearoffset = 0; ConvertMonthAndDay(sh, 0, sh->regs.R[5]+1, sh->regs.R[5]+2, 1); } // Year sh->MappedMemoryWriteByte(sh, sh->regs.R[5], (u8)(((div / 0x5B5) * 4) + yearoffset)); sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosBUPSetDate(SH2_struct * sh) { u32 date; u8 data; u32 remainder; u16 monthtbl[11] = { 31, 31+28, 31+28+31, 31+28+31+30, 31+28+31+30+31, 31+28+31+30+31+30, 31+28+31+30+31+30+31, 31+28+31+30+31+30+31+31, 31+28+31+30+31+30+31+31+30, 31+28+31+30+31+30+31+31+30+31, 31+28+31+30+31+30+31+31+30+31+30 }; SH2GetRegisters(sh, &sh->regs); LOG("BiosBUPSetDate. PR = %08X\n", sh->regs.PR); // Year data = sh->MappedMemoryReadByte(sh, sh->regs.R[4]); date = (data / 4) * 0x5B5; remainder = data % 4; if (remainder) date += (remainder * 0x16D) + 1; // Month data = sh->MappedMemoryReadByte(sh, sh->regs.R[4]+1); if (data != 1 && data < 13) { date += monthtbl[data - 2]; if (date > 2 && remainder == 0) date++; } // Day date += sh->MappedMemoryReadByte(sh, sh->regs.R[4]+2) - 1; date *= 0x5A0; // Hour date += (sh->MappedMemoryReadByte(sh, sh->regs.R[4]+3) * 0x3C); // Minute date += sh->MappedMemoryReadByte(sh, sh->regs.R[4]+4); sh->regs.R[0] = date; sh->regs.PC = sh->regs.PR; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosHandleScuInterrupt(SH2_struct * sh, int vector) { SH2GetRegisters(sh, &sh->regs); // Save R0-R7, PR, GBR, and old Interrupt mask to stack sh->regs.R[15] -= 4; sh->MappedMemoryWriteLong(sh, sh->regs.R[15], sh->regs.R[0]); sh->regs.R[15] -= 4; sh->MappedMemoryWriteLong(sh, sh->regs.R[15], sh->regs.R[1]); sh->regs.R[15] -= 4; sh->MappedMemoryWriteLong(sh, sh->regs.R[15], sh->regs.R[2]); sh->regs.R[15] -= 4; sh->MappedMemoryWriteLong(sh, sh->regs.R[15], sh->regs.R[3]); sh->regs.R[15] -= 4; sh->MappedMemoryWriteLong(sh, sh->regs.R[15], sh->MappedMemoryReadLong(sh, 0x06000348)); sh->regs.R[15] -= 4; sh->MappedMemoryWriteLong(sh, sh->regs.R[15], sh->regs.R[4]); sh->regs.R[15] -= 4; sh->MappedMemoryWriteLong(sh, sh->regs.R[15], sh->regs.R[5]); sh->regs.R[15] -= 4; sh->MappedMemoryWriteLong(sh, sh->regs.R[15], sh->regs.R[6]); sh->regs.R[15] -= 4; sh->MappedMemoryWriteLong(sh, sh->regs.R[15], sh->regs.R[7]); sh->regs.R[15] -= 4; sh->MappedMemoryWriteLong(sh, sh->regs.R[15], sh->regs.PR); sh->regs.R[15] -= 4; sh->MappedMemoryWriteLong(sh, sh->regs.R[15], sh->regs.GBR); // Set SR according to vector sh->regs.SR.all = (u32)sh2masklist[vector - 0x40]; // Write new Interrupt mask value sh->MappedMemoryWriteLong(sh, 0x06000348, sh->MappedMemoryReadLong(sh, 0x06000348) | scumasklist[vector - 0x40]); sh->MappedMemoryWriteLong(sh, 0x25FE00A0, sh->MappedMemoryReadLong(sh, 0x06000348) | scumasklist[vector - 0x40]); // Set PR to our Interrupt Return handler sh->regs.PR = 0x00000480; // Now execute the interrupt sh->regs.PC = sh->MappedMemoryReadLong(sh, 0x06000900+(vector << 2)); // LOG("Interrupt PC = %08X. Read from %08X\n", sh->regs.PC, 0x06000900+(vector << 2)); sh->cycles += 33; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL BiosHandleScuInterruptReturn(SH2_struct * sh) { u32 oldmask; SH2GetRegisters(sh, &sh->regs); // Restore R0-R7, PR, GBR, and old Interrupt mask from stack sh->regs.GBR = sh->MappedMemoryReadLong(sh, sh->regs.R[15]); sh->regs.R[15] += 4; sh->regs.PR = sh->MappedMemoryReadLong(sh, sh->regs.R[15]); sh->regs.R[15] += 4; sh->regs.R[7] = sh->MappedMemoryReadLong(sh, sh->regs.R[15]); sh->regs.R[15] += 4; sh->regs.R[6] = sh->MappedMemoryReadLong(sh, sh->regs.R[15]); sh->regs.R[15] += 4; sh->regs.R[5] = sh->MappedMemoryReadLong(sh, sh->regs.R[15]); sh->regs.R[15] += 4; sh->regs.R[4] = sh->MappedMemoryReadLong(sh, sh->regs.R[15]); sh->regs.R[15] += 4; // Return SR back to normal sh->regs.SR.all = 0xF0; oldmask = sh->MappedMemoryReadLong(sh, sh->regs.R[15]); sh->MappedMemoryWriteLong(sh, 0x06000348, oldmask); sh->MappedMemoryWriteLong(sh, 0x25FE00A0, oldmask); sh->regs.R[15] += 4; sh->regs.R[3] = sh->MappedMemoryReadLong(sh, sh->regs.R[15]); sh->regs.R[15] += 4; sh->regs.R[2] = sh->MappedMemoryReadLong(sh, sh->regs.R[15]); sh->regs.R[15] += 4; sh->regs.R[1] = sh->MappedMemoryReadLong(sh, sh->regs.R[15]); sh->regs.R[15] += 4; sh->regs.R[0] = sh->MappedMemoryReadLong(sh, sh->regs.R[15]); sh->regs.R[15] += 4; sh->regs.PC = sh->MappedMemoryReadLong(sh, sh->regs.R[15]); sh->regs.R[15] += 4; sh->regs.SR.all = sh->MappedMemoryReadLong(sh, sh->regs.R[15]) & 0x000003F3; sh->regs.R[15] += 4; sh->cycles += 24; SH2SetRegisters(sh, &sh->regs); } ////////////////////////////////////////////////////////////////////////////// int FASTCALL BiosHandleFunc(SH2_struct * sh) { SH2GetRegisters(sh, &sh->regs); // Let's see if it's a bios function switch((sh->regs.PC - 0x200) >> 2) { case 0x04: // 0x06000210 BiosPowerOnMemoryClear(sh); break; case 0x1B: // 0x0600026C BiosExecuteCDPlayer(sh); break; case 0x1D: // 0x06000274 BiosCheckMPEGCard(sh); break; case 0x20: // 0x06000280 BiosChangeScuInterruptPriority(sh); break; case 0x27: // 0x0600029C BiosCDINIT2(sh); break; case 0x37: // 0x060002DC BiosCDINIT1(sh); break; case 0x40: // 0x06000300 BiosSetScuInterrupt(sh); break; case 0x41: // 0x06000304 BiosGetScuInterrupt(sh); break; case 0x44: // 0x06000310 BiosSetSh2Interrupt(sh); break; case 0x45: // 0x06000314 BiosGetSh2Interrupt(sh); break; case 0x48: // 0x06000320 BiosChangeSystemClock(sh); break; case 0x4C: // 0x06000330 BiosGetSemaphore(sh); break; case 0x4D: // 0x06000334 BiosClearSemaphore(sh); break; case 0x50: // 0x06000340 BiosSetScuInterruptMask(sh); break; case 0x51: // 0x06000344 BiosChangeScuInterruptMask(sh); break; case 0x56: // 0x06000358 BiosBUPInit(sh); break; case 0x60: // 0x06000380 break; case 0x61: // 0x06000384 BiosBUPSelectPartition(sh); break; case 0x62: // 0x06000388 BiosBUPFormat(sh); break; case 0x63: // 0x0600038C BiosBUPStatus(sh); break; case 0x64: // 0x06000390 BiosBUPWrite(sh); break; case 0x65: // 0x06000394 BiosBUPRead(sh); break; case 0x66: // 0x06000398 BiosBUPDelete(sh); break; case 0x67: // 0x0600039C BiosBUPDirectory(sh); break; case 0x68: // 0x060003A0 BiosBUPVerify(sh); break; case 0x69: // 0x060003A4 BiosBUPGetDate(sh); break; case 0x6A: // 0x060003A8 BiosBUPSetDate(sh); break; case 0x6B: // 0x060003AC break; case 0x80: // Interrupt Handler case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: case 0x98: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: case 0x9E: case 0x9F: BiosHandleScuInterrupt(sh, (sh->regs.PC - 0x300) >> 2); break; case 0xA0: // Interrupt Handler Return BiosHandleScuInterruptReturn(sh); break; default: return 0; } return 1; } ////////////////////////////////////////////////////////////////////////////// deviceinfo_struct *BupGetDeviceList(int *numdevices) { deviceinfo_struct *device; int devicecount=1; if ((CartridgeArea->cartid & 0xF0) == 0x20) devicecount++; if ((device = (deviceinfo_struct *)malloc(devicecount * sizeof(deviceinfo_struct))) == NULL) { *numdevices = 0; return NULL; } *numdevices = devicecount; device[0].id = 0; sprintf(device[0].name, "Internal Backup RAM"); if ((CartridgeArea->cartid & 0xF0) == 0x20) { device[1].id = 1; sprintf(device[1].name, "%d Mbit Backup RAM Cartridge", 1 << ((CartridgeArea->cartid & 0xF)+1)); } // For now it's only internal backup ram and cartridge, no floppy :( // device[2].id = 2; // sprintf(device[1].name, "Floppy Disk Drive"); return device; } ////////////////////////////////////////////////////////////////////////////// int BupGetStats(SH2_struct *sh, u32 device, u32 *freespace, u32 *maxspace) { u32 ret; u32 size; u32 addr; u32 blocksize; ret = GetDeviceStats(device, &size, &addr, &blocksize); // Make sure there's a proper header, and return if there's any other errors if (ret == 1 || CheckHeader(device) != 0) return 0; *maxspace = size / blocksize; *freespace = GetFreeSpace(sh, device, size, addr, blocksize); return 1; } ////////////////////////////////////////////////////////////////////////////// saveinfo_struct *BupGetSaveList(SH2_struct *sh, u32 device, int *numsaves) { u32 ret; u32 size; u32 addr; u32 blocksize; saveinfo_struct *save; int savecount=0; u32 i, j; u32 workaddr; ret = GetDeviceStats(device, &size, &addr, &blocksize); // Make sure there's a proper header, and return if there's any other errors if (ret == 1 || CheckHeader(device) != 0) { *numsaves = 0; return NULL; } for (i = ((2 * blocksize) << 1); i < (size << 1); i += (blocksize << 1)) { // Find a block with the start of a save if (((s8)sh->MappedMemoryReadByte(sh, addr + i + 1)) < 0) savecount++; } if ((save = (saveinfo_struct *)malloc(savecount * sizeof(saveinfo_struct))) == NULL) { *numsaves = 0; return NULL; } *numsaves = savecount; savecount = 0; for (i = ((2 * blocksize) << 1); i < (size << 1); i += (blocksize << 1)) { // Find a block with the start of a save if (((s8)sh->MappedMemoryReadByte(sh, addr + i + 1)) < 0) { workaddr = addr + i; // Copy over filename for (j = 0; j < 11; j++) save[savecount].filename[j] = sh->MappedMemoryReadByte(sh, workaddr+0x9+(j * 2)); save[savecount].filename[11] = '\0'; // Copy over comment for (j = 0; j < 10; j++) save[savecount].comment[j] = sh->MappedMemoryReadByte(sh, workaddr+0x21+(j * 2)); save[savecount].comment[10] = '\0'; // Copy over language save[savecount].language = sh->MappedMemoryReadByte(sh, workaddr+0x1F); // Copy over Date(fix me) save[savecount].year = 0; save[savecount].month = 0; save[savecount].day = 0; save[savecount].hour = 0; save[savecount].minute = 0; save[savecount].week = 0; // Copy over data size save[savecount].datasize = (sh->MappedMemoryReadByte(sh, workaddr+0x3D) << 24) | (sh->MappedMemoryReadByte(sh, workaddr+0x3F) << 16) | (sh->MappedMemoryReadByte(sh, workaddr+0x41) << 8) | sh->MappedMemoryReadByte(sh, workaddr+0x43); // Calculate size in blocks save[savecount].blocksize = CalcSaveSize(sh, workaddr+0x45, blocksize) + 1; savecount++; } } return save; } ////////////////////////////////////////////////////////////////////////////// int BupDeleteSave(SH2_struct *sh, u32 device, const char *savename) { u32 ret; u32 size; u32 addr; u32 blocksize; u32 block; ret = GetDeviceStats(device, &size, &addr, &blocksize); // Make sure there's a proper header, and return if there's any other errors if (ret == 1 || CheckHeader(device) != 0) return -1; // Let's find and delete the save game if ((block = FindSave2(sh, device, savename, 2, size, addr, blocksize)) != 0) { // Delete old save DeleteSave(sh, addr, block, blocksize); return 0; } return -2; } ////////////////////////////////////////////////////////////////////////////// void BupFormat(u32 device) { switch (device) { case 0: FormatBackupRam(BupRam, 0x10000); break; case 1: if ((CartridgeArea->cartid & 0xF0) == 0x20) { switch (CartridgeArea->cartid & 0xF) { case 1: FormatBackupRam(CartridgeArea->bupram, 0x100000); break; case 2: FormatBackupRam(CartridgeArea->bupram, 0x200000); break; case 3: FormatBackupRam(CartridgeArea->bupram, 0x400000); break; case 4: FormatBackupRam(CartridgeArea->bupram, 0x800000); break; default: break; } } break; case 2: LOG("Formatting FDD not supported\n"); default: break; } } ////////////////////////////////////////////////////////////////////////////// int BupCopySave(UNUSED u32 srcdevice, UNUSED u32 dstdevice, UNUSED const char *savename) { return 0; } ////////////////////////////////////////////////////////////////////////////// int BupImportSave(UNUSED u32 device, const char *filename) { FILE *fp; long filesize; u8 *buffer; size_t num_read = 0; if (!filename) return -1; if ((fp = fopen(filename, "rb")) == NULL) return -1; // Calculate file size fseek(fp, 0, SEEK_END); filesize = ftell(fp); if (filesize <= 0) { YabSetError(YAB_ERR_FILEREAD, filename); fclose(fp); return -1; } fseek(fp, 0, SEEK_SET); if ((buffer = (u8 *)malloc(filesize)) == NULL) { fclose(fp); return -2; } num_read = fread((void *)buffer, 1, filesize, fp); fclose(fp); // Write save here free(buffer); return 0; } ////////////////////////////////////////////////////////////////////////////// int BupExportSave(UNUSED u32 device, UNUSED const char *savename, UNUSED const char *filename) { return 0; } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/vidogl.h000644 001750 001750 00000001705 12755623101 017502 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005-2006 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef VIDOGL_H #define VIDOGL_H #if defined(HAVE_LIBGL) || defined(__ANDROID__) #include "vdp1.h" #define VIDCORE_OGL 1 extern VideoInterface_struct VIDOGL; #endif #endif yabause-0.9.15/src/Makefile.dc000644 001750 001750 00000004201 12755623101 020064 0ustar00guillaumeguillaume000000 000000 # Makefile.dc # Dreamcast Makefile # Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Lawrence Sebald # Based on KOS makefiles (C) by Dan Potter # # 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 Street, Fifth Floor, Boston, MA 02110-1301 USA # all: yabause.bin include $(KOS_BASE)/Makefile.rules KOS_CFLAGS += -I. -DDEBUG -DNO_CLI -DVERSION="0.9.15" KOS_ASFLAGS += -g OBJS = bios.o cdbase.o cheat.o cs0.o cs1.o cs2.o debug.o error.o m68kd.o \ memory.o netlink.o peripheral.o profile.o scsp.o scu.o sh2core.o sh2idle.o \ sh2int.o sh2d.o smpc.o vdp1.o vdp2.o yabause.o m68kcore.o coffelf.o \ m68kc68k.o movie.o snddummy.o japmodem.o osdcore.o C68K_OBJS = c68k/c68k.o c68k/c68kexec.o c68k/gen68k.o ARCH_OBJS = dreamcast/yui.o dreamcast/perdc.o dreamcast/viddc.o \ dreamcast/localtime.o dreamcast/cd.o dreamcast/sh2rec/sh2rec.o \ dreamcast/sh2rec/sh2rec_htab.o dreamcast/sh2rec/sh2exec.o \ dreamcast/sh2rec/sh2rec_mem.o c68k/c68kexec.o: c68k/gen68k c68k/gen68k: c68k/c68kexec.c c68k/c68k.c c68k/gen68k.c $(CC) $(CFLAGS) -DC68K_GEN -o $@ $^ cd c68k && ./gen68k yabause.elf: $(OBJS) $(ARCH_OBJS) $(C68K_OBJS) kos-cc -o $@ $^ -lm yabause.bin: yabause.elf $(KOS_OBJCOPY) -R .stack -O binary yabause.elf yabause.bin cdtest.elf: dreamcast/cd.o tools/cdtest.o kos-cc -o $@ $^ cdtest.bin: cdtest.elf $(KOS_OBJCOPY) -R .stack -O binary cdtest.elf cdtest.bin run: yabause.bin $(KOS_LOADER) yabause.bin clean: rm -f $(OBJS) $(ARCH_OBJS) rm -f tools/cdtest.o rm -f yabause.elf rm -f cdtest.elf rm -f cdtest.bin distclean: clean rm -f yabause.bin yabause-0.9.15/src/sh1-pseudo.txt000644 001750 001750 00000076756 12755623101 020620 0ustar00guillaumeguillaume000000 000000 #define RDR0 (*(u8*)(0x5FFFEC5)) #define TDR0 (*(u8*)(0x5FFFEC3)) #define SSR0 (*(u8*)(0x5FFFEC4)) u8 unk_F0002C4[12]; // just a pointer in ram, but is used like an array of 12 bytes struct // data is at 0x0F0002D0(11 byte structure) { u8 status; // F0002D0 u8 q; // F0002D1 u8 track; // F0002D2 u8 index; // F0002D3 u16 mmss; // F0002D4 u8 ff; // F0002D6 u8 zero_not; // F0002D7 u8 abs_mm; // F0002D8 u8 abs_ss; // F0002D9 u8 abs_ff; // F0002DA } cd_rx; #define TRANSFER_STATUS (*(u8*)(0xf0002db)) u8 cd_mech_buff[12]; // data is at 0x0F000304 #define cd_mech_csum (*(u8*)(0xf000310)) #define cd_mech_bytes (*(u8*)(0xf000311)) void vectITU3IMIB3() { // interrupt when OE from the drive mech falls // PB3 is output enable, PB2 is start strobe TSR3 &= 0xFD; cd_mech_return_method = 0; r1 = cd_mech_bytes & 0x7F; if (!(cd_mech_bytes & 0x7F)) { // start of new transfer(loc_97CE) // backup register R4-R13, PR, GBR, MACH/MACL // save stack to running_task[tcb.saved_sp] // set stack to 0xF0008F8 cd_mech_return_method = 1; if (PBDR & 0x4) { // 9828 cd_mech_bytes = 0x80; //goto 9794 } else { // 9802 if (cd_mech_bytes == 0) { // 980A if (unk_F0002C4[11] == 0) { // 9832 memset(cd_mech_buff, 0, 11); cd_mech_buff[11] = 0xFF; } else { // 9832 memcpy(cd_mech_buff, unk_F0002C4, 12); u8 chksum = cd_mech_buff[0]; for (i = 1; i < 11; i++) chksum = cd_mech_buff[i]; cd_mech_buff[11] = ~chksum; unk_F0002C4[11] = 0; } } // 981E TRANSFER_STATUS = 0; // clears rx packet ok flag cd_mech_csum2 = 0; // clears csum } } // old transfer else if (PBDR & 0x4) goto 9768; //97ca reset the byte count cd_mech_bytes = 0; //mov #0, r1 //9768 cd_mech_bytes++; //add #1, r1 , mov r1, r0 , mov.b r0, @(0xd, r3) // Is upcoming data parity byte(number 13 is somewhat deceiving) if (cd_mech_bytes == 13) //cmp/eq #13, r0 { //97ac u8 received_data = RDR0;//mov.b @((RDR0 - SMR0), gbr), r0 received_data = ~received_data; //97ae invert checksum u8 data_to_transmit; //97B2 make sure checksum matches calculated checksum if (received_data != cd_mech_csum) { //97c6 // checksum failure data_to_transmit = 1; } else { //97b6 // checksum is good TRANSFER_STATUS = 1; data_to_transmit = 0; } //97be TDR0 = data_to_transmit; SSR0 |= 0x40; } else { //9776 u8 to_transmit = cd_mech_buff[cd_mech_bytes-1];//mov r3, r2. add #-1, r2. mov.b @(r0, r2), r0 TDR0 = to_transmit;//mov.b r0, @((TDR0 - SMR0), gbr) if (cd_mech_bytes != 1)//cmp/eq #1, r0 { //9784 u8 received_data = RDR0; *((u8 *)cd_rx)[cd_mech_bytes-2] = received_data; // even though this is referenced as F0002CE, // it really end up being cd_rx_status since // cd_mech_bytes >= 2 cd_mech_csum += received_data; } } //97be, 9784, 9776 and 9828 all come here SSR0 = 0;//9794 if (cd_mech_return_method != 0)//cmp/eq #0, r0 { //9876 next_task(); //mov.l #schedule_running_task, r1, jmp @r1 } else return;//979e } //task6 #define YGR_CR1_REG (*(u16*)(0xA000010)) #define YGR_CR2_REG (*(u16*)(0xA000012)) #define YGR_CR3_REG (*(u16*)(0xA000014)) #define YGR_CR4_REG (*(u16*)(0xA000016)) #define YGR_HIRQ_REG (*(u16*)(0xA00001E)) #define YGR_1A_REG (*(u16*)(0xA00001A)) #define UNKN (*(u8*)(0xf000894)) #define UNKN2 (*(u8*)(0xf0002A6)) #define PBDR_L (*(u8*)(0x5FFFFC3))//lower byte of pbdr #define AUTH_BUSY (*(u8*)(0xf0007b0)) #define CR_BUFFER ((u8*)(0x0F00026C)) void loc_2914() { //PB6, pin 104, deemphasis output //low == demp off //high == demp on PBDR_L &= 0xBF; } void loc_28b0() { if (UNKN & 0x10) { //28dc YGR_1A_REG &= 0xffef; if (UNKN2 & 0x28)//gbr == 0xf00025c { goto loc_2920; } else { //28ee if (cd_stat == 6) { loc_28f8: //28f8 //0x4 means reading? //readtoc == 0x4 //readdata == 0x36 (0x4 is set) //readaudio == 0x34 if(cd_rx.status & 0x4)//F0002D0 goto loc_2920; else { if (cd_stat == 0) { goto loc_2920; } else { //subcode q data has preemphasis set? //turn deemphasis pin on or off if (cd_rx.q & 0x10)//F0002D1 goto loc_2914; else goto loc_290a; } } } else { //28f4 if (cd_stat == 0xc) goto loc_2914; else goto loc_28f8; } } } else { //28c0 YGR_1A_REG |= 0x10; if (UNKN & 0x80) { //290a PBDR_L |= 0x40;//PB6 goto loc_291c; } else { //28d2 loc_2914(); goto loc_291c; } } u16 cr1, cr2, cr3, cr4; loc_291c: //reload gbr with cd stat loc_2920: if (AUTH_BUSY & 1) { //2932 if (cd_stat != 0)//2938 { //use the second cr response cr1 = CR_BUFFER[4]; cr2 = CR_BUFFER[5]; cr3 = CR_BUFFER[6]; cr4 = CR_BUFFER[7]; } else { cr1 = CR_BUFFER[0]; cr2 = CR_BUFFER[1]; cr3 = CR_BUFFER[2]; cr4 = CR_BUFFER[3]; } cr1 |= 0x2000;//periodic } else { //2928 cr1 = 0x20ff; cr2 = 0xffff; cr3 = 0xffff; cr4 = 0xffff; } loc_296a: if (mbx_stat & 2) { //2982 YGR_CR1_REG = cr1; YGR_CR2_REG = cr2; YGR_CR3_REG = cr3; YGR_CR4_REG = cr4; } //298a YGR_HIRQ_REG |= 0x400; wait();//2994 } { //3858 if (cd_rx_status & 0x4 && cd_rx_track == 0) { // 4 must be set to read TOC and track must be zero //386A auth_counter1 = cd_rx_track+1; if (cd_rx_status & 0x8) { //3876 count_Q_and_8++; } else { //387E count_Q_and_not_8++; } //3884 if (cd_rx_Q & 0xF == 1) { //388C drive_version = cd_rx_zero_not; u32 track = bcd2num(&cd_rx_status+cd_rx_index); if (track < 1) goto loc_38D0; if (track > 99) goto loc_38D8; for (;;) { //38AC u32 toc_data = msf2frames(&cd_rx_status+8 /* F0002D8 */) | (cd_rx_Q << 24); // is track leadout? if (track_index != 102) { //38DC put_toc_entry(track_index, toc_data); // put toc_data into toc[track_index] for(;;) { //38E6 if (cd_leadout != 0xFFFFFFFF && cd_first_info_track != 0xFFFFFFFF) { //38F6 u8 ctladr = r2 = (cd_first_info_track >> 16) & 0xFF if (cd_last_info_track != 0xFFFFFFFF) { //a0,a1,a2 entries in toc //3904 r3 = (cd_last_info_track >> 16) & 0xFF if (r3 >= r2) { //390C r0 = (cd_first_info_track >> 8) & 0xFF; if (r0 == 0x10) { //3914 ctladr = (cd_store_last_infotrack >> 16) & 0xFF; ctladr += !((cd_store_last_infotrack >> 24) & 0x40) r2 = (cd_first_info_track >> 16) & 0xFF; r1 = (cd_last_info_track >> 16) & 0xFF; if (r2 == r3) { //392E r0 = cd_last_info_track >> 3; if (!(r0 & 0x40)) goto loc_394A; } } //3936 r2 = toc_data+r2; r3 = toc_data+r3; while (r2 <= r3) { //3940 //check all info tracks present if (r2[0] == 0xFFFFFFFF) goto loc_39AC; } //394A // TOC read complete. ((unsigned char *)&dram_nsession)[byte_F000289] = ctladr; byte_F000289++; if (unk_F00025F & 0x80) goto loc_382C; //395E cd_leadout = task6_dtype2a; cd_last_info_track = task6_dtype1a; cd_first_info_track = task6_dtype0a; *((unsigned char *)&dram_nsession) = ctladr; if (toc_data[0] == 0xFFFFFFFF) { //3982 toc_data[0] = cd_leadout; } //398A *((unsigned char *)toc_data)[0] = ctladr; byte_F0002A4 = 0; cd_seek_now = dword_9000214+0x96 sub_2E2C(cd_seek_now, 0, 0); // assuming that args are r5, r6, r7(doesn't look like r4 is used) task6_state = 0x16; } } } //39AC goto loc_28B0; //39B0 if (r0 != 5 || r5[3] != 0xB0) goto loc_39AC; toc_data[0] = msf2frames(r5+8); r0 = msf2frames(r5+4); if (r0 > unk_9000210) { //39E2 dword_9000214 = unk_9000210; unk_9000210 = r0; } //39E6 unk_F00025F |= 3; goto loc_39AC; //39EC r4 = byte_F000289-1; goto loc_395E; //39F4 //task6_handle_toc_Q u32 *toc_ptr; if (cd_rx_index == 0xA0) { //39FA toc_ptr = &cd_first_info_track; } //3A04 else if (cd_rx_index == 0xA1) { toc_ptr = &cd_last_info_track; } //3A3E else if (cd_rx_index == 0xA2) { // leadout r1 = 102; break; // goto loc_38AC } else goto loc_39AC; // Write 0xA0/0xA1 info tracks //3A0A u32 toc = bcd2num(r5+byte_F0002D8) | (cd_rx_Q << 8); toc <<= 16; toc |= (byte_F0002D8 << 8) >> 16; *toc_ptr = toc; toc_ptr+=0xC; // was first info track? if (toc_ptr == &task6_dtype0a) { //3A34 // don't set info track twice if (*toc_ptr != 0xFFFFFFFF) continue; // goto loc_38E6 } *toc_ptr = toc; // goto loc_38E6 } } else goto loc_3A46; } } else goto loc_39B0 } else goto loc_3262 } #define YGR_0C (*(volatile u16 *)0xA00000C) #define MPEG_00 (*(volatile u16 *)0xA100000) #define MPEG_16 (*(volatile u16 *)0xA100016) #define MPEG_1A (*(volatile u16 *)0xA10001A) #define MPEG_22 (*(volatile u16 *)0xA100022) #define MPEG_30 (*(volatile u16 *)0xA100030) #define MPEG_32 (*(volatile u16 *)0xA100032) #define MPEG_34 (*(volatile u16 *)0xA100034) #define MPEG_36 (*(volatile u16 *)0xA100036) #define mpeg_sound_control_reg (*(volatile u16 *)0xA180008) #define UNK_F0007B1 (*(volatile u8 *)0xF0007B1) #define mpeg_req_e0e2 (*(volatile u8 *)0x907538a) //mpeg_asic_kick_check2 //it seems that to succeed, r11 must be less than 0x400, //r12 must be less than 0x200 and count_r13 must not //become negative int mpeg_c01c(u32 input) { u32 count_r13 = 0;//loop counter u32 r8 = input & 0xFF;//value set before function call loc_c01c: count_r13 = 0x20; u16 r0 = MPEG_34; u32 r12 = 0; u32 r11 = 0; loc_c01e: if (r0 & 1) { //c038 r0 = r12; r0 <<= 8; r0 >>= 1; MPEG_30 = r0; MPEG_32 = 0xFE00; MPEG_34 = 0xFFFC; r11 = 0; loc_c04a: //c04a count_r13 = 0x50; loc_c04c: //c04c r0 = MPEG_34; if (r0 & 4) { //c05c MPEG_36 = r12 + r11 + r8;//r0 gets overwritten r11 += 2; if (r11 >= 0x400) goto loc_c04a;//loop else { r12 += 1; if (r12 >= 0x200) goto loc_c01c; else return 0;//success } } else { //c052 count_r13--; if (count_r13 >= 0) goto loc_c04c;//loop else return -1;//fail } } else { //c024 MPEG_34 = 0xffff; r0 = MPEG_36; MPEG_36 = 0; count_r13--; if (count_r13 >= 0) goto loc_c01e;//loop else return -1;//fail } return -1; } //mpeg_initcall3 //test dma of undecoded mpeg sound data to sound chip? void loc_be7c() { //dma is 16 bit //incoming data is valid //clock divide factor = 80 mpeg_sound_control_reg = 0x8209; CHCR3 = 0x1808; TIOR0 = 0xd; TIER0 = 1; u32 source_data_addr = 0x907539c; //zero the buffer while (r0 < 0x24) { (*(volatile u16 *)source_data_addr + r0) = 0; r0 += 2; } //no dma should have occured thus far if (CHCR3 & 2) goto fail; SAR3 = source_data_addr; DAR3 = 0xA180000;//sound chip data rx reg DTR3 = 4;//length CHCR3 |= 1;//start dma r12 = 5 << 8; //wait for dma to complete while (r12 > 0) { r12--; } //dma didn't happen, fail if (!(CHCR3 & 2)) goto fail; return 0;//success fail: return -1; } //mpeg_initcall1 void loc_bcc4() { MPEG_1A = 0xfff; //same as the audio one, mpeg dma buffer it seems u32 dma_data[] = 0x907539c; dma_data[0] = 0x1b3;//sequence header dma_data[3] = 0x1b5;//visual object start code dma_data[4] = 0x1b2;//user data start code dma_data[5] = 0x1b8;//group of pictures start code dma_data[7] = 0x1b5;//group extension data /* [0x00000000] 0x000001b3 [0x00000001] 0x64eafa3e [0x00000002] 0x20b9f728 [0x00000003] 0x000001b5 [0x00000004] 0x000001b2 [0x00000005] 0x000001b8 [0x00000006] 0x97abd9e8 [0x00000007] 0x000001b5 [0x00000008] 0x00000000 */ //no dma must have occured if (CHCR2 & 2) goto fail; SAR2 = 0x907539c; DAR2 = 0xA10001E; DTCR2 = 0x12; CHCR2 |= 1;//start dma if (!(CHCR3 & 2)) goto fail; return 0; fail: return -1; } void loc_907c974() { u16 sound_status = *(volatile u16 *)0xA180008); //check header decode results if (sound_status & 0x8000)//layer 1 or 2 goto loc_907c99e; else if ((sound_status & 0x3000) == 0x3000)//frequency is "reserved" goto loc_907c99e; else if ((sound_status & 0x0F00) == 0)//bitrate is "free format" goto loc_907c99e; else if ((sound_status & 0x0F00) == 0x0F00)//bitrate is "invalid" goto loc_907c99e; else goto 907c9c4; loc_907c99e: //loc_907ca12 //setting clkdiv r0 = *unk_f000884; r0 &= 0xfff0; r4 &= 0xf; r0 |= r4; *unk_f000884 = r0; *sound_status = r0; } //get time code void loc_907f46e() { //GOP timecode format //hours minutes seconds picture //byte 4 .hhhhhmm //byte 5 mmmm.sss //byte 6 sssppppp //byte 7 p....... MPEG_22 = 6;//offset into GOP r12 = MPEG_22; MPEG_22 = 4; r13 = (MPEG_22 & 0xff) << 16; MPEG_22 = 5; r13 |= MPEG_22 & 0xffff; //loc_907f560 //convert into //hour min sec pic format //1 byte each } void loc_9e92() { MPEG_22 = 0; r11 = (MPEG_22 & 0xfff) << 16; MPEG_22 = 1; r13 = MPEG_22 & 0xfff; r13 |= r11; } void loc_9fbe() { //f000854 == partial video reg mirror? MPEG_02 = *(f000854 + 2); MPEG_04 = *(f000854 + 4); MPEG_06 = *(f000854 + 6); MPEG_08 = *(f000854 + 8); MPEG_0a = *(f000854 + 0xa); MPEG_0c = *(f000854 + 0xc); MPEG_0e = *(f000854 + 0xe); MPEG_10 = *(f000854 + 0x10); } void rom_a018() { MPEG_1A = 0x7fff; } #define MPEG_INT_FLAGS_ADDR 0xf000848 #define MPEG_INT_FLAGS_ARR (volatile u8 *)(MPEG_INT_FLAGS_ADDR) #define MPEG_INT_FLAGS (*(volatile u32 *)(MPEG_INT_FLAGS_ADDR)) #define MPEG_INT_MASK_ADDR 0xf00084c #define MPEG_INT_MASK (*(volatile u32 *)(MPEG_INT_MASK_ADDR)) //software-specific #define SEQUENCE_END 0x00000400 #define VIDEO_DECODING_ERROR 0x00000010 #define VIDEO_PLAY_STATUS (*(volatile u8 *)(0xf00089c)) #define AUDIO_PLAY_STATUS (*(volatile u8 *)(0xf00089d)) //lower byte of cr3 #define MPEG_AUDIO_STATUS (*(volatile u8 *)(0xf000845)) #define VPS_TRANSFERRING 0x4 #define VPS_CHANGING 0x5 //CR4 in mpeg status #define MPEG_VIDEO_STATUS (*(volatile u16 *)(0xf000846)) #define MVS_DECODING_OPERATION 1 #define MVS_DISPLAY 2 #define MVS_PAUSE 4 #define MVS_FREEZE 8 #define MVS_LAST_PICTURE_DISPLAY 0x10 #define MVS_ODD_NUMBER_FIELD 0x20 #define MVS_UPDATE_PICTURE 0x40 #define MVS_VIDEO_ERROR 0x80 #define MVS_OUTPUT_PREP_COMPLETE 0x100 #define MVS_FIRST_PICTURE_DISPLAY 0x800 #define MVS_VIDEO_BUFFER_EMPTY 0x1000 #define VIDEO_DMA_SRC_ADDR (*(u32*)(0x90752C0)); #define DMA_UNK_SRC_04 (*(u32*)(0x90752C0 + 0x4)); #define AUDIO_DMA_SRC_ADDR (*(u32*)(0x90752C0 + 0xC)); #define AUDIO_DMA_DEST (*(u32*)(0x90752C0 + 0x14)); #define VIDEO_DMA_COUNT (*(u16*)(0x90752C0 + 0x18)); #define DMA_UNK_COUNT_1A (*(u16*)(0x90752C0 + 0x1a)); #define AUDIO_DMA_COUNT (*(u16*)(0x90752C0 + 0x1E)); void irqITU2IMIB2() { TSR2 &= 0xfd; r0 = MPEG_00; r1_status = MPEG_00; r0 &= r1_status; r1_status = MPEG_00; r1_status &= r0; if (mpeg_inited & 0x80)//unk_f000890 + 2 { //a1f0 r5 = *(unk_f000850 + 2); *(unk_f000850 + 2) = 0xffff; r1_status &= r5 | 0x30f; *unk_f000850 = r1_status; //update video status cr4 u16 r2_flags_to_clear = MVS_DECODING_OPERATION | MVS_DISPLAY | MVS_PAUSE | MVS_FREEZE | MVS_ODD_NUMBER_FIELD | MVS_UPDATE_PICTURE | MVS_OUTPUT_PREP_COMPLETE; r0 = (~r1_status) & flags_to_clear;//0x16f; r7_mpeg_stat = MPEG_VIDEO_STATUS; //a20e if (r1_status & 0x10) r7_mpeg_stat &= ~flags_to_clear;//~0x016f //a216 MPEG_VIDEO_STATUS = r7_mpeg_stat | r0; r4 = 0; //a220 if (r1_status & 0x40) { r4 |= r5; r0 = *(unk_f000890 + 3); if (r0 & 0x44) do_dram_call28(); } //a23c if (r1_status & 0x2000) { //a244 *(unk_f000890 + 1) = *(unk_f000890 + 1) | 1; MPEG_INT_FLAGS |= SEQUENCE_END; if (MPEG_INT_MASK & SEQUENCE_END) asic_hirq_set = 0x2000; } //a260 if (r1_status & 0x1000)//r5 shifted right by 1 { *(unk_f000890 + 1) = *(unk_f000890 + 1) | 4; } //a26e if (r1_status & 0x0800)//r6 shifted right by 1 { r4 |= r5; } //a27c if (r1_status & 0x0080)//r6 shifted right by 4 { MPEG_INT_FLAGS |= VIDEO_DECODING_ERROR; if (MPEG_INT_MASK & VIDEO_DECODING_ERROR) asic_hirq_set = 0x2000; } r5 >>= 2; //a278 if (r1_status & 0x10) { //a29c r4 |= r5; if (*(unk_f000890 + 3) & 0x11) goto set_mpcm; //a2a6 if ((mpeg_reg_mirror_14 & 0x41) == 0x41)//mode == playing video and vsync goto set_mpcm; //a2b2 if (VIDEO_PLAY_STATUS != VPS_TRANSFERRING) { if (VIDEO_PLAY_STATUS == VPS_CHANGING) goto set_mpcm; } //a2be if ((r0 & 1) == 0) do_dram_call26(); //a2cc if ((r0 & 0x10) == 0) do_dram_call27(); } set_mpcm: asic_hirq_set = 0x1000; if (!r4) { r0 = *(unk_f000890 + 6); *(unk_f000890 + 6) = r0 | r4; r11 = 0x88c0010; trap(0x21); } } else { //a340 //incrementing a timer? if (r0 & 0x10) r3 = 0x0100;//a34c if (r0 & 0x20) r3 += 1;//a352 *unk_f00089e += r3; } schedule_running_task(); } void status() { r0 = *f00089c; r2 = ((r0 & 0xff) << 8) |( (r0 & 0xff00 )>> 8); r0 >>= 8; r2 >>= 4; r0 |= r2; r3 = (*f000891) >> 1;//byte r0 = r0 & 0xffff0000 >> 16 | ; r0 |= r12; } //test dmas for mpeg void setup_dma_to_cs2() { r10 = 0xa100000; r9 = 0xa180000; MPEG_1A = 0x7fff; //dma is all 0s *unk_f000840 = 0;//long write clear_chcr23_timer012(); MPEG_02 = 0x6c; SAR2 = unk_f000840; SAR3 = unk_f000840; DAR2 = 0xa10001e; DAR3 = 0xa180000; MPEG_20 = 0xffef; } void timer_check_and_init_mpeg() { r8 = 0; if (MPEG_02 == 0x006c) { } else r8 |= 1; } void rom_call21() { MPEG_20 = 0x47af; MPEG_1A = 0xff7e; MPEG_14 = 0xfff3; MPEG_02 = 0x0096; MPEG_00 = 0x88fe; } //bad6 void rom_call4C() { r0 = *unk_9075388; r6 = *unk_9075389; r0 |= r6; if (r0 & 0xf) { loc_ba5e: //ba5e r0 = *unk_9075388; //ba62 if (r0 & 1) { do_dram_call36(); r0 = *unk_9075388; } //ba74 if (r0 & 2) { do_dram_call35(); r0 = *unk_9075388; } //ba86 if (r0 & 4) { do_dram_call45(); r0 = *unk_9075388; } //ba98 if (r0 & 8) { do_dram_call46(); r0 = *unk_9075388; } //baa6 r0 = *unk_9075389; if (r0 == 0) goto rom_call4C; //baae if (r0 & 1) do_dram_call4E(); //bab8 if (r0 & 2) do_dram_call4D(); //bac2 if (r0 & 4) do_dram_call50(); //bacc if (r0 & 8) do_dram_call4F(); //bace goto rom_call4C; } else { task9(); } } int return_zero() { return 0; } int mpeg_initcall1() { return 0; } int mpeg_initcall3() { return 0; } int mpeg_initcall4() { return 0; } int do_dram_call56() { return 0; } int(*init_ptrs[5]) (void) = { return_zero, mpeg_initcall1, return_zero, mpeg_initcall3, mpeg_initcall4 }; void task9() { trap(0x23); r0 = r11 & 0xff; if (r0 == 0) { if (mpeg_inited & 0x80) goto loc_ba5e;//check if dram calls need to be made else { //bae8 r0 = r11 & 0xff; if (r0 >= 2) { //baf4 *f0007b1 = 0; //bafe //function pointer call loop int which = 0;//r1 u32 r2 = 1; for (;;) { int return_value = 1;//r0 return_value = init_ptrs[which](); if (return_value != 0) UNK_F0007B1 |= r2;//test failed which++;//r1+=4 r2 <<= 1; if (which > 4)// r1 < r5, r5 == 0x10 break; } //bb1e if (UNK_F0007B1 == 0) { //bb28 //all tests passed if (mpeg_req_e0e2 & 1)//cmd e0 was sucessful (authenticate device) { r0 = load_mpeg_rom(); //r1 will be 2 either way so the //return value of load_mpeg_rom seems to have //no effect r2 = mpeg_authL << 8; goto bba4; } if (mpeg_req_e0e2 & 2)//cmd e2 was sucessful (get mpeg rom) { //bb54 do_dram_call56(); r2 = 2; if (!r13) r2 = 3; //bb66 r1 = mpeg_authL; goto bba4; } goto task9; } else { //bb6e //one or more tests failed if (mpeg_req_e0e2 & 1)//mpeg_req_e0e2 is set to 1 in cmd_E0 (authenticate device) if success { bb7e: clear_dram_907b000_to9080000(); //bb86 } if (mpeg_req_e0e2 & 2)//and set to 2 in cmd_E2 (get mpeg rom) if success { //bb90 } else goto bb7e;//clear dram } } else goto task9; } } else { //bbc6 YGR_0C = 3; MPEG_1A = 0; if (mpeg_inited & 0x80) { //bbe2 _a4d0_mpeg_erase(); asic_hirq_set = 0x800; goto task9; } else { r11 = 0x8090004; trap(0x21); goto task9; } } } //erase 0xf000840-0xf0008a0 //and 0x90752a0-0x90753EC //this apparently erases mpeg_inited (0xf000892) void _a4d0_mpeg_erase() { r11 = 0xf00089c + 4;//f0008a0 r12 = 0xf000840; r0 = 0; while (r11 != r12) { *r11 = 0; r11--; } r11 = 0x90753e8 + 4; r12 = 0x90752a0; while (r11 != r12) { *r11 = 0; r11--; } } void bba4() { r1 <<= 24; // 0xff000000 temp = (r2 << 16) & 0xFFFF0000;//r2 can be 0, 1, 3, others? r1 = (r1 >> 16) & 0x0000FFFF; r1 |= temp; r1 >>= 8; mpeg_authL = r1; mpeg_req_e0e2 = 0; auth_busy = 0; asic_hirq_set = 0x80; task9(); } void loc_907bd02() { *(unk_f000890 + 4) &= 0xfc; *(unk_f000890 + 4) |= 1; *(unk_9075324 + 0x4) = *(unk_9075324 + 0xc);//long *(unk_9075324 + 0x14) = *(unk_9075324 + 0x1c);//long *(unk_9075324 + 0) = *(unk_9075324 + 0x24);//word *(unk_9075324 + 0x1c) = 0; //... TCR2 = DMA_UNK_COUNT_1A; SAR2 = DMA_UNK_SRC_04; DAR2 = 0xa10001e; MPEG_0C = 8; CHCR2 &= 0xfd;//lower byte only CHCR2 |= 4;//enable interrupt MPEG_INT_FLAGS |= VIDEO_STREAM_CHANGED;//0x02 if (MPEG_INT_MASK & VIDEO_STREAM_CHANGED) asic_hirq_set = 0x2000; } void loc_907e78a() { MPEG_30 = 0; MPEG_32 = 0xfa04; MPEG_34 = 0xfffc; r13 = 0x50; while (r13 > 0) { r0 = MPEG_36; r13--; } _907e6f4(); r0 = MPEG_34; r0 = MPEG_34; } void loc_907e76e() { count = 0x20; while (count > 0) { if (MPEG_34 & 1) return 0; else { MPEG_34 = 0xffff; temp = MPEG_36; MPEG_36 = temp; count--; } } return -1; } void ___() { //907e382 MPEG_30 = r8; MPEG_32 = 0xfa04; MPEG_34 = 0xfffc; //907e43a MPEG_30 = r8; MPEG_32 = 0xfe04; MPEG_34 = 0xfffc; } void sub_907e6f4(int * count) { *count = 0x20; while (*count > 0) { *count--; if (MPEG_34 & 1) { //dummy reads temp = MPEG_34; temp = MPEG_34; return 0; } else { MPEG_34 = 0xffff; temp = MPEG_34; MPEG_34 = temp; } } return -1; } void _907dc5a() { MPEG_30 = r2 >> 3; MPEG_32 = 0xffb0; MPEG_34 = 0xfffc; sub_907e7ec(); r0 = 0x50; } void _907da9e() { r0 = MPEG_00; r0 &= unk_f00852; unk_f00852 = r0; r0 >>= 8; if (r0 & 1) { MPEG_16 = 0x00fe; do_rom_call59(); } else { //907daf6 do_dram_call43(); } } void sub_907d9f6() { unk_f000897 |= 2; r7 = unk_f000854 | 1; unk_f000854 = r7; MPEG_00 = r7; unk_f000897 &= 0xfd; } void sub_907d9b0() { unk_f000897 |= 4; r7 = (*(unk_f000854 + 0x16)) & 0xcfff; MPEG_1A = r7; MPEG_1A = r7; unk_f000897 &= 0xfb; } void sub_907d994() { unk_f000897 |= 2; r7 = unk_f000854 & 0xfffe; unk_f000854 = r7; MPEG_00 = r7; unk_f000897 &= 0xfd; } void sub_907d988() { MPEG_18 = 0xffdf; } void _907d7be() { if ((MPEG_06 & 0x3f) == unk_907537a) { //907d7d2 } else return; } void loc_907d5ce() { MPEG_22 = 6; r0 = (MPEG_22 >> 8) & 0xe0; if (r0 == 0x20) { if (r0 == 0x40) { do_dram_call3d(); return; } else { //loc_907d614 } } else { //loc_907d614 } } void loc_907d6a0() { unk_f000897 |= 8; MPEG_22 = 6; r0 = (MPEG_22 >> 8) & 0xe0; if (r0 == 0x20) { *unk_907537a = MPEG_22 & 0x3f; // byte ptr *unk_9075378 = 8; } else { } } void loc_907d4ae() { unk_f000897 |= 4; r7 = (*(unk_f000854 + 0x16)) & 0x8fff; MPEG_1A = r7; MPEG_1A = r7; unk_f000897 &= 0xfb; } void loc_907d24a() { if (r0 & 0x20) { r6 = (*(unk_f000854 + 0x16)) & 0x8fff; MPEG_1A = r6; MPEG_1A = r6; } else if (r0 & 0x10) { //907d2c0 } else { r6 = (*(unk_f000854 + 0x16)) & 0xcfff; MPEG_1A = r6; MPEG_1A = r6; } } void loc_907d320() { MPEG_0C = 8; *unk_f000894 |= 1; VIDEO_PLAY_STATUS |= VPS_TRANSFERRING; MPEG_1E = 0; SAR2 = VIDEO_DMA_SRC_ADDR; DAR2 = 0xa10001e; TCR2 = VIDEO_DMA_COUNT; CHCR2 = 0x190d; } void loc_907d948() { SAR3 = AUDIO_DMA_SRC_ADDR; DAR3 = AUDIO_DMA_DEST; TCR3 = AUDIO_DMA_COUNT; u32 flags = AUDIO_STREAM_DATA_ERROR | NEXT_AUDIO_STREAM_DATA_ERROR; MPEG_INT_FLAGS |= flags;//0x000A0000 if(MPEG_INT_MASK & flags) asic_hirq_set = 0x2000; } #define STATUS_PIC_INFO (*(u8*)(0xf000844)); #define I_FRAME 1 #define P_FRAME 2 #define B_FRAME 3 #define D_FRAME 4 void sub_907d078() { MPEG_22 = 6; if (unk_f000895 & 1) { goto loc_907d0b6; } else { } //907d0c6 STATUS_PIC_INFO = MPEG_22 >> 13; r0 = 0x3e; r2 = MPEG_AUDIO_STATUS; } void loc_907b9ce() { u8 val1 = *(0x90752e4 + 0x2c); u32 *ptr = *(0x90752e4 + 0x30); ptr[0] = (val1 << 16) | (r2 & 0xffff); unk_f000897 |= 8; //set flag? //get upper byte? MPEG_22 = 4; r0 = MPEG_22 & 0xff; r2 = r0 << 16; //get lower word? MPEG_22 = 5; r0 = MPEG_22 & 0xffff; r2 |= r0; r0 = r2; MPEG_34 = r0; *unk_f000897 = r0 & 0xf7; //clear flag? //907ba2c if (*F000850 & 0x40)//sequence start detected { MPEG_INT_FLAGS |= SEQUENCE_START_DETECTED; if (MPEG_INT_MASK & SEQUENCE_START_DETECTED) asic_hirq_set = 0x2000; } }yabause-0.9.15/src/glext.h000644 001750 001750 00002402153 12755623101 017345 0ustar00guillaumeguillaume000000 000000 #ifndef __glext_h_ #define __glext_h_ #ifdef __cplusplus extern "C" { #endif /* ** Copyright (c) 2007-2011 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the ** "Materials"), to deal in the Materials without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Materials, and to ** permit persons to whom the Materials are furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be included ** in all copies or substantial portions of the Materials. ** ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. */ /* Header file version number, required by OpenGL ABI for Linux */ /* glext.h last updated $Date: 2011-10-02 22:22:16 -0700 (Sun, 02 Oct 2011) $ */ /* Current version at http://www.opengl.org/registry/ */ #define GL_GLEXT_VERSION 73 /* Function declaration macros - to move into glplatform.h */ #if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) #define WIN32_LEAN_AND_MEAN 1 #include #endif #ifndef APIENTRY #define APIENTRY #endif #ifndef APIENTRYP #define APIENTRYP APIENTRY * #endif #ifndef GLAPI #define GLAPI extern #endif /*************************************************************/ #ifndef GL_VERSION_1_2 #define GL_UNSIGNED_BYTE_3_3_2 0x8032 #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 #define GL_UNSIGNED_INT_8_8_8_8 0x8035 #define GL_UNSIGNED_INT_10_10_10_2 0x8036 #define GL_TEXTURE_BINDING_3D 0x806A #define GL_PACK_SKIP_IMAGES 0x806B #define GL_PACK_IMAGE_HEIGHT 0x806C #define GL_UNPACK_SKIP_IMAGES 0x806D #define GL_UNPACK_IMAGE_HEIGHT 0x806E #define GL_TEXTURE_3D 0x806F #define GL_PROXY_TEXTURE_3D 0x8070 #define GL_TEXTURE_DEPTH 0x8071 #define GL_TEXTURE_WRAP_R 0x8072 #define GL_MAX_3D_TEXTURE_SIZE 0x8073 #define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 #define GL_UNSIGNED_SHORT_5_6_5 0x8363 #define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 #define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 #define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 #define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 #define GL_BGR 0x80E0 #define GL_BGRA 0x80E1 #define GL_MAX_ELEMENTS_VERTICES 0x80E8 #define GL_MAX_ELEMENTS_INDICES 0x80E9 #define GL_CLAMP_TO_EDGE 0x812F #define GL_TEXTURE_MIN_LOD 0x813A #define GL_TEXTURE_MAX_LOD 0x813B #define GL_TEXTURE_BASE_LEVEL 0x813C #define GL_TEXTURE_MAX_LEVEL 0x813D #define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 #define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 #define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 #define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 #define GL_ALIASED_LINE_WIDTH_RANGE 0x846E #endif #ifndef GL_VERSION_1_2_DEPRECATED #define GL_RESCALE_NORMAL 0x803A #define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 #define GL_SINGLE_COLOR 0x81F9 #define GL_SEPARATE_SPECULAR_COLOR 0x81FA #define GL_ALIASED_POINT_SIZE_RANGE 0x846D #endif #ifndef GL_ARB_imaging #define GL_CONSTANT_COLOR 0x8001 #define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 #define GL_CONSTANT_ALPHA 0x8003 #define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 #define GL_BLEND_COLOR 0x8005 #define GL_FUNC_ADD 0x8006 #define GL_MIN 0x8007 #define GL_MAX 0x8008 #define GL_BLEND_EQUATION 0x8009 #define GL_FUNC_SUBTRACT 0x800A #define GL_FUNC_REVERSE_SUBTRACT 0x800B #endif #ifndef GL_ARB_imaging_DEPRECATED #define GL_CONVOLUTION_1D 0x8010 #define GL_CONVOLUTION_2D 0x8011 #define GL_SEPARABLE_2D 0x8012 #define GL_CONVOLUTION_BORDER_MODE 0x8013 #define GL_CONVOLUTION_FILTER_SCALE 0x8014 #define GL_CONVOLUTION_FILTER_BIAS 0x8015 #define GL_REDUCE 0x8016 #define GL_CONVOLUTION_FORMAT 0x8017 #define GL_CONVOLUTION_WIDTH 0x8018 #define GL_CONVOLUTION_HEIGHT 0x8019 #define GL_MAX_CONVOLUTION_WIDTH 0x801A #define GL_MAX_CONVOLUTION_HEIGHT 0x801B #define GL_POST_CONVOLUTION_RED_SCALE 0x801C #define GL_POST_CONVOLUTION_GREEN_SCALE 0x801D #define GL_POST_CONVOLUTION_BLUE_SCALE 0x801E #define GL_POST_CONVOLUTION_ALPHA_SCALE 0x801F #define GL_POST_CONVOLUTION_RED_BIAS 0x8020 #define GL_POST_CONVOLUTION_GREEN_BIAS 0x8021 #define GL_POST_CONVOLUTION_BLUE_BIAS 0x8022 #define GL_POST_CONVOLUTION_ALPHA_BIAS 0x8023 #define GL_HISTOGRAM 0x8024 #define GL_PROXY_HISTOGRAM 0x8025 #define GL_HISTOGRAM_WIDTH 0x8026 #define GL_HISTOGRAM_FORMAT 0x8027 #define GL_HISTOGRAM_RED_SIZE 0x8028 #define GL_HISTOGRAM_GREEN_SIZE 0x8029 #define GL_HISTOGRAM_BLUE_SIZE 0x802A #define GL_HISTOGRAM_ALPHA_SIZE 0x802B #define GL_HISTOGRAM_LUMINANCE_SIZE 0x802C #define GL_HISTOGRAM_SINK 0x802D #define GL_MINMAX 0x802E #define GL_MINMAX_FORMAT 0x802F #define GL_MINMAX_SINK 0x8030 #define GL_TABLE_TOO_LARGE 0x8031 #define GL_COLOR_MATRIX 0x80B1 #define GL_COLOR_MATRIX_STACK_DEPTH 0x80B2 #define GL_MAX_COLOR_MATRIX_STACK_DEPTH 0x80B3 #define GL_POST_COLOR_MATRIX_RED_SCALE 0x80B4 #define GL_POST_COLOR_MATRIX_GREEN_SCALE 0x80B5 #define GL_POST_COLOR_MATRIX_BLUE_SCALE 0x80B6 #define GL_POST_COLOR_MATRIX_ALPHA_SCALE 0x80B7 #define GL_POST_COLOR_MATRIX_RED_BIAS 0x80B8 #define GL_POST_COLOR_MATRIX_GREEN_BIAS 0x80B9 #define GL_POST_COLOR_MATRIX_BLUE_BIAS 0x80BA #define GL_POST_COLOR_MATRIX_ALPHA_BIAS 0x80BB #define GL_COLOR_TABLE 0x80D0 #define GL_POST_CONVOLUTION_COLOR_TABLE 0x80D1 #define GL_POST_COLOR_MATRIX_COLOR_TABLE 0x80D2 #define GL_PROXY_COLOR_TABLE 0x80D3 #define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4 #define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5 #define GL_COLOR_TABLE_SCALE 0x80D6 #define GL_COLOR_TABLE_BIAS 0x80D7 #define GL_COLOR_TABLE_FORMAT 0x80D8 #define GL_COLOR_TABLE_WIDTH 0x80D9 #define GL_COLOR_TABLE_RED_SIZE 0x80DA #define GL_COLOR_TABLE_GREEN_SIZE 0x80DB #define GL_COLOR_TABLE_BLUE_SIZE 0x80DC #define GL_COLOR_TABLE_ALPHA_SIZE 0x80DD #define GL_COLOR_TABLE_LUMINANCE_SIZE 0x80DE #define GL_COLOR_TABLE_INTENSITY_SIZE 0x80DF #define GL_CONSTANT_BORDER 0x8151 #define GL_REPLICATE_BORDER 0x8153 #define GL_CONVOLUTION_BORDER_COLOR 0x8154 #endif #ifndef GL_VERSION_1_3 #define GL_TEXTURE0 0x84C0 #define GL_TEXTURE1 0x84C1 #define GL_TEXTURE2 0x84C2 #define GL_TEXTURE3 0x84C3 #define GL_TEXTURE4 0x84C4 #define GL_TEXTURE5 0x84C5 #define GL_TEXTURE6 0x84C6 #define GL_TEXTURE7 0x84C7 #define GL_TEXTURE8 0x84C8 #define GL_TEXTURE9 0x84C9 #define GL_TEXTURE10 0x84CA #define GL_TEXTURE11 0x84CB #define GL_TEXTURE12 0x84CC #define GL_TEXTURE13 0x84CD #define GL_TEXTURE14 0x84CE #define GL_TEXTURE15 0x84CF #define GL_TEXTURE16 0x84D0 #define GL_TEXTURE17 0x84D1 #define GL_TEXTURE18 0x84D2 #define GL_TEXTURE19 0x84D3 #define GL_TEXTURE20 0x84D4 #define GL_TEXTURE21 0x84D5 #define GL_TEXTURE22 0x84D6 #define GL_TEXTURE23 0x84D7 #define GL_TEXTURE24 0x84D8 #define GL_TEXTURE25 0x84D9 #define GL_TEXTURE26 0x84DA #define GL_TEXTURE27 0x84DB #define GL_TEXTURE28 0x84DC #define GL_TEXTURE29 0x84DD #define GL_TEXTURE30 0x84DE #define GL_TEXTURE31 0x84DF #define GL_ACTIVE_TEXTURE 0x84E0 #define GL_MULTISAMPLE 0x809D #define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E #define GL_SAMPLE_ALPHA_TO_ONE 0x809F #define GL_SAMPLE_COVERAGE 0x80A0 #define GL_SAMPLE_BUFFERS 0x80A8 #define GL_SAMPLES 0x80A9 #define GL_SAMPLE_COVERAGE_VALUE 0x80AA #define GL_SAMPLE_COVERAGE_INVERT 0x80AB #define GL_TEXTURE_CUBE_MAP 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A #define GL_PROXY_TEXTURE_CUBE_MAP 0x851B #define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C #define GL_COMPRESSED_RGB 0x84ED #define GL_COMPRESSED_RGBA 0x84EE #define GL_TEXTURE_COMPRESSION_HINT 0x84EF #define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 #define GL_TEXTURE_COMPRESSED 0x86A1 #define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 #define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 #define GL_CLAMP_TO_BORDER 0x812D #endif #ifndef GL_VERSION_1_3_DEPRECATED #define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 #define GL_MAX_TEXTURE_UNITS 0x84E2 #define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 #define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 #define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 #define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 #define GL_MULTISAMPLE_BIT 0x20000000 #define GL_NORMAL_MAP 0x8511 #define GL_REFLECTION_MAP 0x8512 #define GL_COMPRESSED_ALPHA 0x84E9 #define GL_COMPRESSED_LUMINANCE 0x84EA #define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB #define GL_COMPRESSED_INTENSITY 0x84EC #define GL_COMBINE 0x8570 #define GL_COMBINE_RGB 0x8571 #define GL_COMBINE_ALPHA 0x8572 #define GL_SOURCE0_RGB 0x8580 #define GL_SOURCE1_RGB 0x8581 #define GL_SOURCE2_RGB 0x8582 #define GL_SOURCE0_ALPHA 0x8588 #define GL_SOURCE1_ALPHA 0x8589 #define GL_SOURCE2_ALPHA 0x858A #define GL_OPERAND0_RGB 0x8590 #define GL_OPERAND1_RGB 0x8591 #define GL_OPERAND2_RGB 0x8592 #define GL_OPERAND0_ALPHA 0x8598 #define GL_OPERAND1_ALPHA 0x8599 #define GL_OPERAND2_ALPHA 0x859A #define GL_RGB_SCALE 0x8573 #define GL_ADD_SIGNED 0x8574 #define GL_INTERPOLATE 0x8575 #define GL_SUBTRACT 0x84E7 #define GL_CONSTANT 0x8576 #define GL_PRIMARY_COLOR 0x8577 #define GL_PREVIOUS 0x8578 #define GL_DOT3_RGB 0x86AE #define GL_DOT3_RGBA 0x86AF #endif #ifndef GL_VERSION_1_4 #define GL_BLEND_DST_RGB 0x80C8 #define GL_BLEND_SRC_RGB 0x80C9 #define GL_BLEND_DST_ALPHA 0x80CA #define GL_BLEND_SRC_ALPHA 0x80CB #define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 #define GL_DEPTH_COMPONENT16 0x81A5 #define GL_DEPTH_COMPONENT24 0x81A6 #define GL_DEPTH_COMPONENT32 0x81A7 #define GL_MIRRORED_REPEAT 0x8370 #define GL_MAX_TEXTURE_LOD_BIAS 0x84FD #define GL_TEXTURE_LOD_BIAS 0x8501 #define GL_INCR_WRAP 0x8507 #define GL_DECR_WRAP 0x8508 #define GL_TEXTURE_DEPTH_SIZE 0x884A #define GL_TEXTURE_COMPARE_MODE 0x884C #define GL_TEXTURE_COMPARE_FUNC 0x884D #endif #ifndef GL_VERSION_1_4_DEPRECATED #define GL_POINT_SIZE_MIN 0x8126 #define GL_POINT_SIZE_MAX 0x8127 #define GL_POINT_DISTANCE_ATTENUATION 0x8129 #define GL_GENERATE_MIPMAP 0x8191 #define GL_GENERATE_MIPMAP_HINT 0x8192 #define GL_FOG_COORDINATE_SOURCE 0x8450 #define GL_FOG_COORDINATE 0x8451 #define GL_FRAGMENT_DEPTH 0x8452 #define GL_CURRENT_FOG_COORDINATE 0x8453 #define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 #define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 #define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 #define GL_FOG_COORDINATE_ARRAY 0x8457 #define GL_COLOR_SUM 0x8458 #define GL_CURRENT_SECONDARY_COLOR 0x8459 #define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A #define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B #define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C #define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D #define GL_SECONDARY_COLOR_ARRAY 0x845E #define GL_TEXTURE_FILTER_CONTROL 0x8500 #define GL_DEPTH_TEXTURE_MODE 0x884B #define GL_COMPARE_R_TO_TEXTURE 0x884E #endif #ifndef GL_VERSION_1_5 #define GL_BUFFER_SIZE 0x8764 #define GL_BUFFER_USAGE 0x8765 #define GL_QUERY_COUNTER_BITS 0x8864 #define GL_CURRENT_QUERY 0x8865 #define GL_QUERY_RESULT 0x8866 #define GL_QUERY_RESULT_AVAILABLE 0x8867 #define GL_ARRAY_BUFFER 0x8892 #define GL_ELEMENT_ARRAY_BUFFER 0x8893 #define GL_ARRAY_BUFFER_BINDING 0x8894 #define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 #define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F #define GL_READ_ONLY 0x88B8 #define GL_WRITE_ONLY 0x88B9 #define GL_READ_WRITE 0x88BA #define GL_BUFFER_ACCESS 0x88BB #define GL_BUFFER_MAPPED 0x88BC #define GL_BUFFER_MAP_POINTER 0x88BD #define GL_STREAM_DRAW 0x88E0 #define GL_STREAM_READ 0x88E1 #define GL_STREAM_COPY 0x88E2 #define GL_STATIC_DRAW 0x88E4 #define GL_STATIC_READ 0x88E5 #define GL_STATIC_COPY 0x88E6 #define GL_DYNAMIC_DRAW 0x88E8 #define GL_DYNAMIC_READ 0x88E9 #define GL_DYNAMIC_COPY 0x88EA #define GL_SAMPLES_PASSED 0x8914 #endif #ifndef GL_VERSION_1_5_DEPRECATED #define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 #define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 #define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 #define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 #define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A #define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B #define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C #define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D #define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E #define GL_FOG_COORD_SRC 0x8450 #define GL_FOG_COORD 0x8451 #define GL_CURRENT_FOG_COORD 0x8453 #define GL_FOG_COORD_ARRAY_TYPE 0x8454 #define GL_FOG_COORD_ARRAY_STRIDE 0x8455 #define GL_FOG_COORD_ARRAY_POINTER 0x8456 #define GL_FOG_COORD_ARRAY 0x8457 #define GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D #define GL_SRC0_RGB 0x8580 #define GL_SRC1_RGB 0x8581 #define GL_SRC2_RGB 0x8582 #define GL_SRC0_ALPHA 0x8588 #define GL_SRC1_ALPHA 0x8589 #define GL_SRC2_ALPHA 0x858A #endif #ifndef GL_VERSION_2_0 #define GL_BLEND_EQUATION_RGB 0x8009 #define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 #define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 #define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 #define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 #define GL_CURRENT_VERTEX_ATTRIB 0x8626 #define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 #define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 #define GL_STENCIL_BACK_FUNC 0x8800 #define GL_STENCIL_BACK_FAIL 0x8801 #define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 #define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 #define GL_MAX_DRAW_BUFFERS 0x8824 #define GL_DRAW_BUFFER0 0x8825 #define GL_DRAW_BUFFER1 0x8826 #define GL_DRAW_BUFFER2 0x8827 #define GL_DRAW_BUFFER3 0x8828 #define GL_DRAW_BUFFER4 0x8829 #define GL_DRAW_BUFFER5 0x882A #define GL_DRAW_BUFFER6 0x882B #define GL_DRAW_BUFFER7 0x882C #define GL_DRAW_BUFFER8 0x882D #define GL_DRAW_BUFFER9 0x882E #define GL_DRAW_BUFFER10 0x882F #define GL_DRAW_BUFFER11 0x8830 #define GL_DRAW_BUFFER12 0x8831 #define GL_DRAW_BUFFER13 0x8832 #define GL_DRAW_BUFFER14 0x8833 #define GL_DRAW_BUFFER15 0x8834 #define GL_BLEND_EQUATION_ALPHA 0x883D #define GL_MAX_VERTEX_ATTRIBS 0x8869 #define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A #define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 #define GL_FRAGMENT_SHADER 0x8B30 #define GL_VERTEX_SHADER 0x8B31 #define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 #define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A #define GL_MAX_VARYING_FLOATS 0x8B4B #define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D #define GL_SHADER_TYPE 0x8B4F #define GL_FLOAT_VEC2 0x8B50 #define GL_FLOAT_VEC3 0x8B51 #define GL_FLOAT_VEC4 0x8B52 #define GL_INT_VEC2 0x8B53 #define GL_INT_VEC3 0x8B54 #define GL_INT_VEC4 0x8B55 #define GL_BOOL 0x8B56 #define GL_BOOL_VEC2 0x8B57 #define GL_BOOL_VEC3 0x8B58 #define GL_BOOL_VEC4 0x8B59 #define GL_FLOAT_MAT2 0x8B5A #define GL_FLOAT_MAT3 0x8B5B #define GL_FLOAT_MAT4 0x8B5C #define GL_SAMPLER_1D 0x8B5D #define GL_SAMPLER_2D 0x8B5E #define GL_SAMPLER_3D 0x8B5F #define GL_SAMPLER_CUBE 0x8B60 #define GL_SAMPLER_1D_SHADOW 0x8B61 #define GL_SAMPLER_2D_SHADOW 0x8B62 #define GL_DELETE_STATUS 0x8B80 #define GL_COMPILE_STATUS 0x8B81 #define GL_LINK_STATUS 0x8B82 #define GL_VALIDATE_STATUS 0x8B83 #define GL_INFO_LOG_LENGTH 0x8B84 #define GL_ATTACHED_SHADERS 0x8B85 #define GL_ACTIVE_UNIFORMS 0x8B86 #define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 #define GL_SHADER_SOURCE_LENGTH 0x8B88 #define GL_ACTIVE_ATTRIBUTES 0x8B89 #define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A #define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B #define GL_SHADING_LANGUAGE_VERSION 0x8B8C #define GL_CURRENT_PROGRAM 0x8B8D #define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 #define GL_LOWER_LEFT 0x8CA1 #define GL_UPPER_LEFT 0x8CA2 #define GL_STENCIL_BACK_REF 0x8CA3 #define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 #define GL_STENCIL_BACK_WRITEMASK 0x8CA5 #endif #ifndef GL_VERSION_2_0_DEPRECATED #define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 #define GL_POINT_SPRITE 0x8861 #define GL_COORD_REPLACE 0x8862 #define GL_MAX_TEXTURE_COORDS 0x8871 #endif #ifndef GL_VERSION_2_1 #define GL_PIXEL_PACK_BUFFER 0x88EB #define GL_PIXEL_UNPACK_BUFFER 0x88EC #define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED #define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF #define GL_FLOAT_MAT2x3 0x8B65 #define GL_FLOAT_MAT2x4 0x8B66 #define GL_FLOAT_MAT3x2 0x8B67 #define GL_FLOAT_MAT3x4 0x8B68 #define GL_FLOAT_MAT4x2 0x8B69 #define GL_FLOAT_MAT4x3 0x8B6A #define GL_SRGB 0x8C40 #define GL_SRGB8 0x8C41 #define GL_SRGB_ALPHA 0x8C42 #define GL_SRGB8_ALPHA8 0x8C43 #define GL_COMPRESSED_SRGB 0x8C48 #define GL_COMPRESSED_SRGB_ALPHA 0x8C49 #endif #ifndef GL_VERSION_2_1_DEPRECATED #define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F #define GL_SLUMINANCE_ALPHA 0x8C44 #define GL_SLUMINANCE8_ALPHA8 0x8C45 #define GL_SLUMINANCE 0x8C46 #define GL_SLUMINANCE8 0x8C47 #define GL_COMPRESSED_SLUMINANCE 0x8C4A #define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B #endif #ifndef GL_VERSION_3_0 #define GL_COMPARE_REF_TO_TEXTURE 0x884E #define GL_CLIP_DISTANCE0 0x3000 #define GL_CLIP_DISTANCE1 0x3001 #define GL_CLIP_DISTANCE2 0x3002 #define GL_CLIP_DISTANCE3 0x3003 #define GL_CLIP_DISTANCE4 0x3004 #define GL_CLIP_DISTANCE5 0x3005 #define GL_CLIP_DISTANCE6 0x3006 #define GL_CLIP_DISTANCE7 0x3007 #define GL_MAX_CLIP_DISTANCES 0x0D32 #define GL_MAJOR_VERSION 0x821B #define GL_MINOR_VERSION 0x821C #define GL_NUM_EXTENSIONS 0x821D #define GL_CONTEXT_FLAGS 0x821E #define GL_COMPRESSED_RED 0x8225 #define GL_COMPRESSED_RG 0x8226 #define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x0001 #define GL_RGBA32F 0x8814 #define GL_RGB32F 0x8815 #define GL_RGBA16F 0x881A #define GL_RGB16F 0x881B #define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD #define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF #define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 #define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 #define GL_CLAMP_READ_COLOR 0x891C #define GL_FIXED_ONLY 0x891D #define GL_MAX_VARYING_COMPONENTS 0x8B4B #define GL_TEXTURE_1D_ARRAY 0x8C18 #define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 #define GL_TEXTURE_2D_ARRAY 0x8C1A #define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B #define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C #define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D #define GL_R11F_G11F_B10F 0x8C3A #define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B #define GL_RGB9_E5 0x8C3D #define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E #define GL_TEXTURE_SHARED_SIZE 0x8C3F #define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 #define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 #define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 #define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 #define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 #define GL_PRIMITIVES_GENERATED 0x8C87 #define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 #define GL_RASTERIZER_DISCARD 0x8C89 #define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B #define GL_INTERLEAVED_ATTRIBS 0x8C8C #define GL_SEPARATE_ATTRIBS 0x8C8D #define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E #define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F #define GL_RGBA32UI 0x8D70 #define GL_RGB32UI 0x8D71 #define GL_RGBA16UI 0x8D76 #define GL_RGB16UI 0x8D77 #define GL_RGBA8UI 0x8D7C #define GL_RGB8UI 0x8D7D #define GL_RGBA32I 0x8D82 #define GL_RGB32I 0x8D83 #define GL_RGBA16I 0x8D88 #define GL_RGB16I 0x8D89 #define GL_RGBA8I 0x8D8E #define GL_RGB8I 0x8D8F #define GL_RED_INTEGER 0x8D94 #define GL_GREEN_INTEGER 0x8D95 #define GL_BLUE_INTEGER 0x8D96 #define GL_RGB_INTEGER 0x8D98 #define GL_RGBA_INTEGER 0x8D99 #define GL_BGR_INTEGER 0x8D9A #define GL_BGRA_INTEGER 0x8D9B #define GL_SAMPLER_1D_ARRAY 0x8DC0 #define GL_SAMPLER_2D_ARRAY 0x8DC1 #define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 #define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 #define GL_SAMPLER_CUBE_SHADOW 0x8DC5 #define GL_UNSIGNED_INT_VEC2 0x8DC6 #define GL_UNSIGNED_INT_VEC3 0x8DC7 #define GL_UNSIGNED_INT_VEC4 0x8DC8 #define GL_INT_SAMPLER_1D 0x8DC9 #define GL_INT_SAMPLER_2D 0x8DCA #define GL_INT_SAMPLER_3D 0x8DCB #define GL_INT_SAMPLER_CUBE 0x8DCC #define GL_INT_SAMPLER_1D_ARRAY 0x8DCE #define GL_INT_SAMPLER_2D_ARRAY 0x8DCF #define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 #define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 #define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 #define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 #define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 #define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 #define GL_QUERY_WAIT 0x8E13 #define GL_QUERY_NO_WAIT 0x8E14 #define GL_QUERY_BY_REGION_WAIT 0x8E15 #define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 #define GL_BUFFER_ACCESS_FLAGS 0x911F #define GL_BUFFER_MAP_LENGTH 0x9120 #define GL_BUFFER_MAP_OFFSET 0x9121 /* Reuse tokens from ARB_depth_buffer_float */ /* reuse GL_DEPTH_COMPONENT32F */ /* reuse GL_DEPTH32F_STENCIL8 */ /* reuse GL_FLOAT_32_UNSIGNED_INT_24_8_REV */ /* Reuse tokens from ARB_framebuffer_object */ /* reuse GL_INVALID_FRAMEBUFFER_OPERATION */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE */ /* reuse GL_FRAMEBUFFER_DEFAULT */ /* reuse GL_FRAMEBUFFER_UNDEFINED */ /* reuse GL_DEPTH_STENCIL_ATTACHMENT */ /* reuse GL_INDEX */ /* reuse GL_MAX_RENDERBUFFER_SIZE */ /* reuse GL_DEPTH_STENCIL */ /* reuse GL_UNSIGNED_INT_24_8 */ /* reuse GL_DEPTH24_STENCIL8 */ /* reuse GL_TEXTURE_STENCIL_SIZE */ /* reuse GL_TEXTURE_RED_TYPE */ /* reuse GL_TEXTURE_GREEN_TYPE */ /* reuse GL_TEXTURE_BLUE_TYPE */ /* reuse GL_TEXTURE_ALPHA_TYPE */ /* reuse GL_TEXTURE_DEPTH_TYPE */ /* reuse GL_UNSIGNED_NORMALIZED */ /* reuse GL_FRAMEBUFFER_BINDING */ /* reuse GL_DRAW_FRAMEBUFFER_BINDING */ /* reuse GL_RENDERBUFFER_BINDING */ /* reuse GL_READ_FRAMEBUFFER */ /* reuse GL_DRAW_FRAMEBUFFER */ /* reuse GL_READ_FRAMEBUFFER_BINDING */ /* reuse GL_RENDERBUFFER_SAMPLES */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER */ /* reuse GL_FRAMEBUFFER_COMPLETE */ /* reuse GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT */ /* reuse GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT */ /* reuse GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER */ /* reuse GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER */ /* reuse GL_FRAMEBUFFER_UNSUPPORTED */ /* reuse GL_MAX_COLOR_ATTACHMENTS */ /* reuse GL_COLOR_ATTACHMENT0 */ /* reuse GL_COLOR_ATTACHMENT1 */ /* reuse GL_COLOR_ATTACHMENT2 */ /* reuse GL_COLOR_ATTACHMENT3 */ /* reuse GL_COLOR_ATTACHMENT4 */ /* reuse GL_COLOR_ATTACHMENT5 */ /* reuse GL_COLOR_ATTACHMENT6 */ /* reuse GL_COLOR_ATTACHMENT7 */ /* reuse GL_COLOR_ATTACHMENT8 */ /* reuse GL_COLOR_ATTACHMENT9 */ /* reuse GL_COLOR_ATTACHMENT10 */ /* reuse GL_COLOR_ATTACHMENT11 */ /* reuse GL_COLOR_ATTACHMENT12 */ /* reuse GL_COLOR_ATTACHMENT13 */ /* reuse GL_COLOR_ATTACHMENT14 */ /* reuse GL_COLOR_ATTACHMENT15 */ /* reuse GL_DEPTH_ATTACHMENT */ /* reuse GL_STENCIL_ATTACHMENT */ /* reuse GL_FRAMEBUFFER */ /* reuse GL_RENDERBUFFER */ /* reuse GL_RENDERBUFFER_WIDTH */ /* reuse GL_RENDERBUFFER_HEIGHT */ /* reuse GL_RENDERBUFFER_INTERNAL_FORMAT */ /* reuse GL_STENCIL_INDEX1 */ /* reuse GL_STENCIL_INDEX4 */ /* reuse GL_STENCIL_INDEX8 */ /* reuse GL_STENCIL_INDEX16 */ /* reuse GL_RENDERBUFFER_RED_SIZE */ /* reuse GL_RENDERBUFFER_GREEN_SIZE */ /* reuse GL_RENDERBUFFER_BLUE_SIZE */ /* reuse GL_RENDERBUFFER_ALPHA_SIZE */ /* reuse GL_RENDERBUFFER_DEPTH_SIZE */ /* reuse GL_RENDERBUFFER_STENCIL_SIZE */ /* reuse GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE */ /* reuse GL_MAX_SAMPLES */ /* Reuse tokens from ARB_framebuffer_sRGB */ /* reuse GL_FRAMEBUFFER_SRGB */ /* Reuse tokens from ARB_half_float_vertex */ /* reuse GL_HALF_FLOAT */ /* Reuse tokens from ARB_map_buffer_range */ /* reuse GL_MAP_READ_BIT */ /* reuse GL_MAP_WRITE_BIT */ /* reuse GL_MAP_INVALIDATE_RANGE_BIT */ /* reuse GL_MAP_INVALIDATE_BUFFER_BIT */ /* reuse GL_MAP_FLUSH_EXPLICIT_BIT */ /* reuse GL_MAP_UNSYNCHRONIZED_BIT */ /* Reuse tokens from ARB_texture_compression_rgtc */ /* reuse GL_COMPRESSED_RED_RGTC1 */ /* reuse GL_COMPRESSED_SIGNED_RED_RGTC1 */ /* reuse GL_COMPRESSED_RG_RGTC2 */ /* reuse GL_COMPRESSED_SIGNED_RG_RGTC2 */ /* Reuse tokens from ARB_texture_rg */ /* reuse GL_RG */ /* reuse GL_RG_INTEGER */ /* reuse GL_R8 */ /* reuse GL_R16 */ /* reuse GL_RG8 */ /* reuse GL_RG16 */ /* reuse GL_R16F */ /* reuse GL_R32F */ /* reuse GL_RG16F */ /* reuse GL_RG32F */ /* reuse GL_R8I */ /* reuse GL_R8UI */ /* reuse GL_R16I */ /* reuse GL_R16UI */ /* reuse GL_R32I */ /* reuse GL_R32UI */ /* reuse GL_RG8I */ /* reuse GL_RG8UI */ /* reuse GL_RG16I */ /* reuse GL_RG16UI */ /* reuse GL_RG32I */ /* reuse GL_RG32UI */ /* Reuse tokens from ARB_vertex_array_object */ /* reuse GL_VERTEX_ARRAY_BINDING */ #endif #ifndef GL_VERSION_3_0_DEPRECATED #define GL_CLAMP_VERTEX_COLOR 0x891A #define GL_CLAMP_FRAGMENT_COLOR 0x891B #define GL_ALPHA_INTEGER 0x8D97 /* Reuse tokens from ARB_framebuffer_object */ /* reuse GL_TEXTURE_LUMINANCE_TYPE */ /* reuse GL_TEXTURE_INTENSITY_TYPE */ #endif #ifndef GL_VERSION_3_1 #define GL_SAMPLER_2D_RECT 0x8B63 #define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 #define GL_SAMPLER_BUFFER 0x8DC2 #define GL_INT_SAMPLER_2D_RECT 0x8DCD #define GL_INT_SAMPLER_BUFFER 0x8DD0 #define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 #define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 #define GL_TEXTURE_BUFFER 0x8C2A #define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B #define GL_TEXTURE_BINDING_BUFFER 0x8C2C #define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D #define GL_TEXTURE_BUFFER_FORMAT 0x8C2E #define GL_TEXTURE_RECTANGLE 0x84F5 #define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 #define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 #define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 #define GL_RED_SNORM 0x8F90 #define GL_RG_SNORM 0x8F91 #define GL_RGB_SNORM 0x8F92 #define GL_RGBA_SNORM 0x8F93 #define GL_R8_SNORM 0x8F94 #define GL_RG8_SNORM 0x8F95 #define GL_RGB8_SNORM 0x8F96 #define GL_RGBA8_SNORM 0x8F97 #define GL_R16_SNORM 0x8F98 #define GL_RG16_SNORM 0x8F99 #define GL_RGB16_SNORM 0x8F9A #define GL_RGBA16_SNORM 0x8F9B #define GL_SIGNED_NORMALIZED 0x8F9C #define GL_PRIMITIVE_RESTART 0x8F9D #define GL_PRIMITIVE_RESTART_INDEX 0x8F9E /* Reuse tokens from ARB_copy_buffer */ /* reuse GL_COPY_READ_BUFFER */ /* reuse GL_COPY_WRITE_BUFFER */ /* Reuse tokens from ARB_draw_instanced (none) */ /* Reuse tokens from ARB_uniform_buffer_object */ /* reuse GL_UNIFORM_BUFFER */ /* reuse GL_UNIFORM_BUFFER_BINDING */ /* reuse GL_UNIFORM_BUFFER_START */ /* reuse GL_UNIFORM_BUFFER_SIZE */ /* reuse GL_MAX_VERTEX_UNIFORM_BLOCKS */ /* reuse GL_MAX_FRAGMENT_UNIFORM_BLOCKS */ /* reuse GL_MAX_COMBINED_UNIFORM_BLOCKS */ /* reuse GL_MAX_UNIFORM_BUFFER_BINDINGS */ /* reuse GL_MAX_UNIFORM_BLOCK_SIZE */ /* reuse GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS */ /* reuse GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS */ /* reuse GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT */ /* reuse GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH */ /* reuse GL_ACTIVE_UNIFORM_BLOCKS */ /* reuse GL_UNIFORM_TYPE */ /* reuse GL_UNIFORM_SIZE */ /* reuse GL_UNIFORM_NAME_LENGTH */ /* reuse GL_UNIFORM_BLOCK_INDEX */ /* reuse GL_UNIFORM_OFFSET */ /* reuse GL_UNIFORM_ARRAY_STRIDE */ /* reuse GL_UNIFORM_MATRIX_STRIDE */ /* reuse GL_UNIFORM_IS_ROW_MAJOR */ /* reuse GL_UNIFORM_BLOCK_BINDING */ /* reuse GL_UNIFORM_BLOCK_DATA_SIZE */ /* reuse GL_UNIFORM_BLOCK_NAME_LENGTH */ /* reuse GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS */ /* reuse GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES */ /* reuse GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER */ /* reuse GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER */ /* reuse GL_INVALID_INDEX */ #endif #ifndef GL_VERSION_3_2 #define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 #define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 #define GL_LINES_ADJACENCY 0x000A #define GL_LINE_STRIP_ADJACENCY 0x000B #define GL_TRIANGLES_ADJACENCY 0x000C #define GL_TRIANGLE_STRIP_ADJACENCY 0x000D #define GL_PROGRAM_POINT_SIZE 0x8642 #define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 #define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 #define GL_GEOMETRY_SHADER 0x8DD9 #define GL_GEOMETRY_VERTICES_OUT 0x8916 #define GL_GEOMETRY_INPUT_TYPE 0x8917 #define GL_GEOMETRY_OUTPUT_TYPE 0x8918 #define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF #define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 #define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 #define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 #define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 #define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 #define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 #define GL_CONTEXT_PROFILE_MASK 0x9126 /* reuse GL_MAX_VARYING_COMPONENTS */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER */ /* Reuse tokens from ARB_depth_clamp */ /* reuse GL_DEPTH_CLAMP */ /* Reuse tokens from ARB_draw_elements_base_vertex (none) */ /* Reuse tokens from ARB_fragment_coord_conventions (none) */ /* Reuse tokens from ARB_provoking_vertex */ /* reuse GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION */ /* reuse GL_FIRST_VERTEX_CONVENTION */ /* reuse GL_LAST_VERTEX_CONVENTION */ /* reuse GL_PROVOKING_VERTEX */ /* Reuse tokens from ARB_seamless_cube_map */ /* reuse GL_TEXTURE_CUBE_MAP_SEAMLESS */ /* Reuse tokens from ARB_sync */ /* reuse GL_MAX_SERVER_WAIT_TIMEOUT */ /* reuse GL_OBJECT_TYPE */ /* reuse GL_SYNC_CONDITION */ /* reuse GL_SYNC_STATUS */ /* reuse GL_SYNC_FLAGS */ /* reuse GL_SYNC_FENCE */ /* reuse GL_SYNC_GPU_COMMANDS_COMPLETE */ /* reuse GL_UNSIGNALED */ /* reuse GL_SIGNALED */ /* reuse GL_ALREADY_SIGNALED */ /* reuse GL_TIMEOUT_EXPIRED */ /* reuse GL_CONDITION_SATISFIED */ /* reuse GL_WAIT_FAILED */ /* reuse GL_TIMEOUT_IGNORED */ /* reuse GL_SYNC_FLUSH_COMMANDS_BIT */ /* reuse GL_TIMEOUT_IGNORED */ /* Reuse tokens from ARB_texture_multisample */ /* reuse GL_SAMPLE_POSITION */ /* reuse GL_SAMPLE_MASK */ /* reuse GL_SAMPLE_MASK_VALUE */ /* reuse GL_MAX_SAMPLE_MASK_WORDS */ /* reuse GL_TEXTURE_2D_MULTISAMPLE */ /* reuse GL_PROXY_TEXTURE_2D_MULTISAMPLE */ /* reuse GL_TEXTURE_2D_MULTISAMPLE_ARRAY */ /* reuse GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY */ /* reuse GL_TEXTURE_BINDING_2D_MULTISAMPLE */ /* reuse GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY */ /* reuse GL_TEXTURE_SAMPLES */ /* reuse GL_TEXTURE_FIXED_SAMPLE_LOCATIONS */ /* reuse GL_SAMPLER_2D_MULTISAMPLE */ /* reuse GL_INT_SAMPLER_2D_MULTISAMPLE */ /* reuse GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE */ /* reuse GL_SAMPLER_2D_MULTISAMPLE_ARRAY */ /* reuse GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY */ /* reuse GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY */ /* reuse GL_MAX_COLOR_TEXTURE_SAMPLES */ /* reuse GL_MAX_DEPTH_TEXTURE_SAMPLES */ /* reuse GL_MAX_INTEGER_SAMPLES */ /* Don't need to reuse tokens from ARB_vertex_array_bgra since they're already in 1.2 core */ #endif #ifndef GL_VERSION_3_3 #define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE /* Reuse tokens from ARB_blend_func_extended */ /* reuse GL_SRC1_COLOR */ /* reuse GL_ONE_MINUS_SRC1_COLOR */ /* reuse GL_ONE_MINUS_SRC1_ALPHA */ /* reuse GL_MAX_DUAL_SOURCE_DRAW_BUFFERS */ /* Reuse tokens from ARB_explicit_attrib_location (none) */ /* Reuse tokens from ARB_occlusion_query2 */ /* reuse GL_ANY_SAMPLES_PASSED */ /* Reuse tokens from ARB_sampler_objects */ /* reuse GL_SAMPLER_BINDING */ /* Reuse tokens from ARB_shader_bit_encoding (none) */ /* Reuse tokens from ARB_texture_rgb10_a2ui */ /* reuse GL_RGB10_A2UI */ /* Reuse tokens from ARB_texture_swizzle */ /* reuse GL_TEXTURE_SWIZZLE_R */ /* reuse GL_TEXTURE_SWIZZLE_G */ /* reuse GL_TEXTURE_SWIZZLE_B */ /* reuse GL_TEXTURE_SWIZZLE_A */ /* reuse GL_TEXTURE_SWIZZLE_RGBA */ /* Reuse tokens from ARB_timer_query */ /* reuse GL_TIME_ELAPSED */ /* reuse GL_TIMESTAMP */ /* Reuse tokens from ARB_vertex_type_2_10_10_10_rev */ /* reuse GL_INT_2_10_10_10_REV */ #endif #ifndef GL_VERSION_4_0 #define GL_SAMPLE_SHADING 0x8C36 #define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37 #define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E #define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F #define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009 #define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A #define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B #define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C #define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D #define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E #define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F /* Reuse tokens from ARB_texture_query_lod (none) */ /* Reuse tokens from ARB_draw_buffers_blend (none) */ /* Reuse tokens from ARB_draw_indirect */ /* reuse GL_DRAW_INDIRECT_BUFFER */ /* reuse GL_DRAW_INDIRECT_BUFFER_BINDING */ /* Reuse tokens from ARB_gpu_shader5 */ /* reuse GL_GEOMETRY_SHADER_INVOCATIONS */ /* reuse GL_MAX_GEOMETRY_SHADER_INVOCATIONS */ /* reuse GL_MIN_FRAGMENT_INTERPOLATION_OFFSET */ /* reuse GL_MAX_FRAGMENT_INTERPOLATION_OFFSET */ /* reuse GL_FRAGMENT_INTERPOLATION_OFFSET_BITS */ /* reuse GL_MAX_VERTEX_STREAMS */ /* Reuse tokens from ARB_gpu_shader_fp64 */ /* reuse GL_DOUBLE_VEC2 */ /* reuse GL_DOUBLE_VEC3 */ /* reuse GL_DOUBLE_VEC4 */ /* reuse GL_DOUBLE_MAT2 */ /* reuse GL_DOUBLE_MAT3 */ /* reuse GL_DOUBLE_MAT4 */ /* reuse GL_DOUBLE_MAT2x3 */ /* reuse GL_DOUBLE_MAT2x4 */ /* reuse GL_DOUBLE_MAT3x2 */ /* reuse GL_DOUBLE_MAT3x4 */ /* reuse GL_DOUBLE_MAT4x2 */ /* reuse GL_DOUBLE_MAT4x3 */ /* Reuse tokens from ARB_shader_subroutine */ /* reuse GL_ACTIVE_SUBROUTINES */ /* reuse GL_ACTIVE_SUBROUTINE_UNIFORMS */ /* reuse GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS */ /* reuse GL_ACTIVE_SUBROUTINE_MAX_LENGTH */ /* reuse GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH */ /* reuse GL_MAX_SUBROUTINES */ /* reuse GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS */ /* reuse GL_NUM_COMPATIBLE_SUBROUTINES */ /* reuse GL_COMPATIBLE_SUBROUTINES */ /* Reuse tokens from ARB_tessellation_shader */ /* reuse GL_PATCHES */ /* reuse GL_PATCH_VERTICES */ /* reuse GL_PATCH_DEFAULT_INNER_LEVEL */ /* reuse GL_PATCH_DEFAULT_OUTER_LEVEL */ /* reuse GL_TESS_CONTROL_OUTPUT_VERTICES */ /* reuse GL_TESS_GEN_MODE */ /* reuse GL_TESS_GEN_SPACING */ /* reuse GL_TESS_GEN_VERTEX_ORDER */ /* reuse GL_TESS_GEN_POINT_MODE */ /* reuse GL_ISOLINES */ /* reuse GL_FRACTIONAL_ODD */ /* reuse GL_FRACTIONAL_EVEN */ /* reuse GL_MAX_PATCH_VERTICES */ /* reuse GL_MAX_TESS_GEN_LEVEL */ /* reuse GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS */ /* reuse GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS */ /* reuse GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS */ /* reuse GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS */ /* reuse GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS */ /* reuse GL_MAX_TESS_PATCH_COMPONENTS */ /* reuse GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS */ /* reuse GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS */ /* reuse GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS */ /* reuse GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS */ /* reuse GL_MAX_TESS_CONTROL_INPUT_COMPONENTS */ /* reuse GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS */ /* reuse GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS */ /* reuse GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS */ /* reuse GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER */ /* reuse GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER */ /* reuse GL_TESS_EVALUATION_SHADER */ /* reuse GL_TESS_CONTROL_SHADER */ /* Reuse tokens from ARB_texture_buffer_object_rgb32 (none) */ /* Reuse tokens from ARB_transform_feedback2 */ /* reuse GL_TRANSFORM_FEEDBACK */ /* reuse GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED */ /* reuse GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE */ /* reuse GL_TRANSFORM_FEEDBACK_BINDING */ /* Reuse tokens from ARB_transform_feedback3 */ /* reuse GL_MAX_TRANSFORM_FEEDBACK_BUFFERS */ /* reuse GL_MAX_VERTEX_STREAMS */ #endif #ifndef GL_VERSION_4_1 /* Reuse tokens from ARB_ES2_compatibility */ /* reuse GL_FIXED */ /* reuse GL_IMPLEMENTATION_COLOR_READ_TYPE */ /* reuse GL_IMPLEMENTATION_COLOR_READ_FORMAT */ /* reuse GL_LOW_FLOAT */ /* reuse GL_MEDIUM_FLOAT */ /* reuse GL_HIGH_FLOAT */ /* reuse GL_LOW_INT */ /* reuse GL_MEDIUM_INT */ /* reuse GL_HIGH_INT */ /* reuse GL_SHADER_COMPILER */ /* reuse GL_NUM_SHADER_BINARY_FORMATS */ /* reuse GL_MAX_VERTEX_UNIFORM_VECTORS */ /* reuse GL_MAX_VARYING_VECTORS */ /* reuse GL_MAX_FRAGMENT_UNIFORM_VECTORS */ /* Reuse tokens from ARB_get_program_binary */ /* reuse GL_PROGRAM_BINARY_RETRIEVABLE_HINT */ /* reuse GL_PROGRAM_BINARY_LENGTH */ /* reuse GL_NUM_PROGRAM_BINARY_FORMATS */ /* reuse GL_PROGRAM_BINARY_FORMATS */ /* Reuse tokens from ARB_separate_shader_objects */ /* reuse GL_VERTEX_SHADER_BIT */ /* reuse GL_FRAGMENT_SHADER_BIT */ /* reuse GL_GEOMETRY_SHADER_BIT */ /* reuse GL_TESS_CONTROL_SHADER_BIT */ /* reuse GL_TESS_EVALUATION_SHADER_BIT */ /* reuse GL_ALL_SHADER_BITS */ /* reuse GL_PROGRAM_SEPARABLE */ /* reuse GL_ACTIVE_PROGRAM */ /* reuse GL_PROGRAM_PIPELINE_BINDING */ /* Reuse tokens from ARB_shader_precision (none) */ /* Reuse tokens from ARB_vertex_attrib_64bit - all are in GL 3.0 and 4.0 already */ /* Reuse tokens from ARB_viewport_array - some are in GL 1.1 and ARB_provoking_vertex already */ /* reuse GL_MAX_VIEWPORTS */ /* reuse GL_VIEWPORT_SUBPIXEL_BITS */ /* reuse GL_VIEWPORT_BOUNDS_RANGE */ /* reuse GL_LAYER_PROVOKING_VERTEX */ /* reuse GL_VIEWPORT_INDEX_PROVOKING_VERTEX */ /* reuse GL_UNDEFINED_VERTEX */ #endif #ifndef GL_VERSION_4_2 /* Reuse tokens from ARB_base_instance (none) */ /* Reuse tokens from ARB_shading_language_420pack (none) */ /* Reuse tokens from ARB_transform_feedback_instanced (none) */ /* Reuse tokens from ARB_compressed_texture_pixel_storage */ /* reuse GL_UNPACK_COMPRESSED_BLOCK_WIDTH */ /* reuse GL_UNPACK_COMPRESSED_BLOCK_HEIGHT */ /* reuse GL_UNPACK_COMPRESSED_BLOCK_DEPTH */ /* reuse GL_UNPACK_COMPRESSED_BLOCK_SIZE */ /* reuse GL_PACK_COMPRESSED_BLOCK_WIDTH */ /* reuse GL_PACK_COMPRESSED_BLOCK_HEIGHT */ /* reuse GL_PACK_COMPRESSED_BLOCK_DEPTH */ /* reuse GL_PACK_COMPRESSED_BLOCK_SIZE */ /* Reuse tokens from ARB_conservative_depth (none) */ /* Reuse tokens from ARB_internalformat_query */ /* reuse GL_NUM_SAMPLE_COUNTS */ /* Reuse tokens from ARB_map_buffer_alignment */ /* reuse GL_MIN_MAP_BUFFER_ALIGNMENT */ /* Reuse tokens from ARB_shader_atomic_counters */ /* reuse GL_ATOMIC_COUNTER_BUFFER */ /* reuse GL_ATOMIC_COUNTER_BUFFER_BINDING */ /* reuse GL_ATOMIC_COUNTER_BUFFER_START */ /* reuse GL_ATOMIC_COUNTER_BUFFER_SIZE */ /* reuse GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE */ /* reuse GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS */ /* reuse GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES */ /* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER */ /* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER */ /* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER */ /* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER */ /* reuse GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER */ /* reuse GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS */ /* reuse GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS */ /* reuse GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS */ /* reuse GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS */ /* reuse GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS */ /* reuse GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS */ /* reuse GL_MAX_VERTEX_ATOMIC_COUNTERS */ /* reuse GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS */ /* reuse GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS */ /* reuse GL_MAX_GEOMETRY_ATOMIC_COUNTERS */ /* reuse GL_MAX_FRAGMENT_ATOMIC_COUNTERS */ /* reuse GL_MAX_COMBINED_ATOMIC_COUNTERS */ /* reuse GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE */ /* reuse GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS */ /* reuse GL_ACTIVE_ATOMIC_COUNTER_BUFFERS */ /* reuse GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX */ /* reuse GL_UNSIGNED_INT_ATOMIC_COUNTER */ /* Reuse tokens from ARB_shader_image_load_store */ /* reuse GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT */ /* reuse GL_ELEMENT_ARRAY_BARRIER_BIT */ /* reuse GL_UNIFORM_BARRIER_BIT */ /* reuse GL_TEXTURE_FETCH_BARRIER_BIT */ /* reuse GL_SHADER_IMAGE_ACCESS_BARRIER_BIT */ /* reuse GL_COMMAND_BARRIER_BIT */ /* reuse GL_PIXEL_BUFFER_BARRIER_BIT */ /* reuse GL_TEXTURE_UPDATE_BARRIER_BIT */ /* reuse GL_BUFFER_UPDATE_BARRIER_BIT */ /* reuse GL_FRAMEBUFFER_BARRIER_BIT */ /* reuse GL_TRANSFORM_FEEDBACK_BARRIER_BIT */ /* reuse GL_ATOMIC_COUNTER_BARRIER_BIT */ /* reuse GL_ALL_BARRIER_BITS */ /* reuse GL_MAX_IMAGE_UNITS */ /* reuse GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS */ /* reuse GL_IMAGE_BINDING_NAME */ /* reuse GL_IMAGE_BINDING_LEVEL */ /* reuse GL_IMAGE_BINDING_LAYERED */ /* reuse GL_IMAGE_BINDING_LAYER */ /* reuse GL_IMAGE_BINDING_ACCESS */ /* reuse GL_IMAGE_1D */ /* reuse GL_IMAGE_2D */ /* reuse GL_IMAGE_3D */ /* reuse GL_IMAGE_2D_RECT */ /* reuse GL_IMAGE_CUBE */ /* reuse GL_IMAGE_BUFFER */ /* reuse GL_IMAGE_1D_ARRAY */ /* reuse GL_IMAGE_2D_ARRAY */ /* reuse GL_IMAGE_CUBE_MAP_ARRAY */ /* reuse GL_IMAGE_2D_MULTISAMPLE */ /* reuse GL_IMAGE_2D_MULTISAMPLE_ARRAY */ /* reuse GL_INT_IMAGE_1D */ /* reuse GL_INT_IMAGE_2D */ /* reuse GL_INT_IMAGE_3D */ /* reuse GL_INT_IMAGE_2D_RECT */ /* reuse GL_INT_IMAGE_CUBE */ /* reuse GL_INT_IMAGE_BUFFER */ /* reuse GL_INT_IMAGE_1D_ARRAY */ /* reuse GL_INT_IMAGE_2D_ARRAY */ /* reuse GL_INT_IMAGE_CUBE_MAP_ARRAY */ /* reuse GL_INT_IMAGE_2D_MULTISAMPLE */ /* reuse GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY */ /* reuse GL_UNSIGNED_INT_IMAGE_1D */ /* reuse GL_UNSIGNED_INT_IMAGE_2D */ /* reuse GL_UNSIGNED_INT_IMAGE_3D */ /* reuse GL_UNSIGNED_INT_IMAGE_2D_RECT */ /* reuse GL_UNSIGNED_INT_IMAGE_CUBE */ /* reuse GL_UNSIGNED_INT_IMAGE_BUFFER */ /* reuse GL_UNSIGNED_INT_IMAGE_1D_ARRAY */ /* reuse GL_UNSIGNED_INT_IMAGE_2D_ARRAY */ /* reuse GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY */ /* reuse GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE */ /* reuse GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY */ /* reuse GL_MAX_IMAGE_SAMPLES */ /* reuse GL_IMAGE_BINDING_FORMAT */ /* reuse GL_IMAGE_FORMAT_COMPATIBILITY_TYPE */ /* reuse GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE */ /* reuse GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS */ /* reuse GL_MAX_VERTEX_IMAGE_UNIFORMS */ /* reuse GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS */ /* reuse GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS */ /* reuse GL_MAX_GEOMETRY_IMAGE_UNIFORMS */ /* reuse GL_MAX_FRAGMENT_IMAGE_UNIFORMS */ /* reuse GL_MAX_COMBINED_IMAGE_UNIFORMS */ /* Reuse tokens from ARB_shading_language_packing (none) */ /* Reuse tokens from ARB_texture_storage */ /* reuse GL_TEXTURE_IMMUTABLE_FORMAT */ #endif #ifndef GL_ARB_multitexture #define GL_TEXTURE0_ARB 0x84C0 #define GL_TEXTURE1_ARB 0x84C1 #define GL_TEXTURE2_ARB 0x84C2 #define GL_TEXTURE3_ARB 0x84C3 #define GL_TEXTURE4_ARB 0x84C4 #define GL_TEXTURE5_ARB 0x84C5 #define GL_TEXTURE6_ARB 0x84C6 #define GL_TEXTURE7_ARB 0x84C7 #define GL_TEXTURE8_ARB 0x84C8 #define GL_TEXTURE9_ARB 0x84C9 #define GL_TEXTURE10_ARB 0x84CA #define GL_TEXTURE11_ARB 0x84CB #define GL_TEXTURE12_ARB 0x84CC #define GL_TEXTURE13_ARB 0x84CD #define GL_TEXTURE14_ARB 0x84CE #define GL_TEXTURE15_ARB 0x84CF #define GL_TEXTURE16_ARB 0x84D0 #define GL_TEXTURE17_ARB 0x84D1 #define GL_TEXTURE18_ARB 0x84D2 #define GL_TEXTURE19_ARB 0x84D3 #define GL_TEXTURE20_ARB 0x84D4 #define GL_TEXTURE21_ARB 0x84D5 #define GL_TEXTURE22_ARB 0x84D6 #define GL_TEXTURE23_ARB 0x84D7 #define GL_TEXTURE24_ARB 0x84D8 #define GL_TEXTURE25_ARB 0x84D9 #define GL_TEXTURE26_ARB 0x84DA #define GL_TEXTURE27_ARB 0x84DB #define GL_TEXTURE28_ARB 0x84DC #define GL_TEXTURE29_ARB 0x84DD #define GL_TEXTURE30_ARB 0x84DE #define GL_TEXTURE31_ARB 0x84DF #define GL_ACTIVE_TEXTURE_ARB 0x84E0 #define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1 #define GL_MAX_TEXTURE_UNITS_ARB 0x84E2 #endif #ifndef GL_ARB_transpose_matrix #define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3 #define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4 #define GL_TRANSPOSE_TEXTURE_MATRIX_ARB 0x84E5 #define GL_TRANSPOSE_COLOR_MATRIX_ARB 0x84E6 #endif #ifndef GL_ARB_multisample #define GL_MULTISAMPLE_ARB 0x809D #define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E #define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F #define GL_SAMPLE_COVERAGE_ARB 0x80A0 #define GL_SAMPLE_BUFFERS_ARB 0x80A8 #define GL_SAMPLES_ARB 0x80A9 #define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA #define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB #define GL_MULTISAMPLE_BIT_ARB 0x20000000 #endif #ifndef GL_ARB_texture_env_add #endif #ifndef GL_ARB_texture_cube_map #define GL_NORMAL_MAP_ARB 0x8511 #define GL_REFLECTION_MAP_ARB 0x8512 #define GL_TEXTURE_CUBE_MAP_ARB 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP_ARB 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A #define GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B #define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C #endif #ifndef GL_ARB_texture_compression #define GL_COMPRESSED_ALPHA_ARB 0x84E9 #define GL_COMPRESSED_LUMINANCE_ARB 0x84EA #define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB #define GL_COMPRESSED_INTENSITY_ARB 0x84EC #define GL_COMPRESSED_RGB_ARB 0x84ED #define GL_COMPRESSED_RGBA_ARB 0x84EE #define GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF #define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0 #define GL_TEXTURE_COMPRESSED_ARB 0x86A1 #define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2 #define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 #endif #ifndef GL_ARB_texture_border_clamp #define GL_CLAMP_TO_BORDER_ARB 0x812D #endif #ifndef GL_ARB_point_parameters #define GL_POINT_SIZE_MIN_ARB 0x8126 #define GL_POINT_SIZE_MAX_ARB 0x8127 #define GL_POINT_FADE_THRESHOLD_SIZE_ARB 0x8128 #define GL_POINT_DISTANCE_ATTENUATION_ARB 0x8129 #endif #ifndef GL_ARB_vertex_blend #define GL_MAX_VERTEX_UNITS_ARB 0x86A4 #define GL_ACTIVE_VERTEX_UNITS_ARB 0x86A5 #define GL_WEIGHT_SUM_UNITY_ARB 0x86A6 #define GL_VERTEX_BLEND_ARB 0x86A7 #define GL_CURRENT_WEIGHT_ARB 0x86A8 #define GL_WEIGHT_ARRAY_TYPE_ARB 0x86A9 #define GL_WEIGHT_ARRAY_STRIDE_ARB 0x86AA #define GL_WEIGHT_ARRAY_SIZE_ARB 0x86AB #define GL_WEIGHT_ARRAY_POINTER_ARB 0x86AC #define GL_WEIGHT_ARRAY_ARB 0x86AD #define GL_MODELVIEW0_ARB 0x1700 #define GL_MODELVIEW1_ARB 0x850A #define GL_MODELVIEW2_ARB 0x8722 #define GL_MODELVIEW3_ARB 0x8723 #define GL_MODELVIEW4_ARB 0x8724 #define GL_MODELVIEW5_ARB 0x8725 #define GL_MODELVIEW6_ARB 0x8726 #define GL_MODELVIEW7_ARB 0x8727 #define GL_MODELVIEW8_ARB 0x8728 #define GL_MODELVIEW9_ARB 0x8729 #define GL_MODELVIEW10_ARB 0x872A #define GL_MODELVIEW11_ARB 0x872B #define GL_MODELVIEW12_ARB 0x872C #define GL_MODELVIEW13_ARB 0x872D #define GL_MODELVIEW14_ARB 0x872E #define GL_MODELVIEW15_ARB 0x872F #define GL_MODELVIEW16_ARB 0x8730 #define GL_MODELVIEW17_ARB 0x8731 #define GL_MODELVIEW18_ARB 0x8732 #define GL_MODELVIEW19_ARB 0x8733 #define GL_MODELVIEW20_ARB 0x8734 #define GL_MODELVIEW21_ARB 0x8735 #define GL_MODELVIEW22_ARB 0x8736 #define GL_MODELVIEW23_ARB 0x8737 #define GL_MODELVIEW24_ARB 0x8738 #define GL_MODELVIEW25_ARB 0x8739 #define GL_MODELVIEW26_ARB 0x873A #define GL_MODELVIEW27_ARB 0x873B #define GL_MODELVIEW28_ARB 0x873C #define GL_MODELVIEW29_ARB 0x873D #define GL_MODELVIEW30_ARB 0x873E #define GL_MODELVIEW31_ARB 0x873F #endif #ifndef GL_ARB_matrix_palette #define GL_MATRIX_PALETTE_ARB 0x8840 #define GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841 #define GL_MAX_PALETTE_MATRICES_ARB 0x8842 #define GL_CURRENT_PALETTE_MATRIX_ARB 0x8843 #define GL_MATRIX_INDEX_ARRAY_ARB 0x8844 #define GL_CURRENT_MATRIX_INDEX_ARB 0x8845 #define GL_MATRIX_INDEX_ARRAY_SIZE_ARB 0x8846 #define GL_MATRIX_INDEX_ARRAY_TYPE_ARB 0x8847 #define GL_MATRIX_INDEX_ARRAY_STRIDE_ARB 0x8848 #define GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849 #endif #ifndef GL_ARB_texture_env_combine #define GL_COMBINE_ARB 0x8570 #define GL_COMBINE_RGB_ARB 0x8571 #define GL_COMBINE_ALPHA_ARB 0x8572 #define GL_SOURCE0_RGB_ARB 0x8580 #define GL_SOURCE1_RGB_ARB 0x8581 #define GL_SOURCE2_RGB_ARB 0x8582 #define GL_SOURCE0_ALPHA_ARB 0x8588 #define GL_SOURCE1_ALPHA_ARB 0x8589 #define GL_SOURCE2_ALPHA_ARB 0x858A #define GL_OPERAND0_RGB_ARB 0x8590 #define GL_OPERAND1_RGB_ARB 0x8591 #define GL_OPERAND2_RGB_ARB 0x8592 #define GL_OPERAND0_ALPHA_ARB 0x8598 #define GL_OPERAND1_ALPHA_ARB 0x8599 #define GL_OPERAND2_ALPHA_ARB 0x859A #define GL_RGB_SCALE_ARB 0x8573 #define GL_ADD_SIGNED_ARB 0x8574 #define GL_INTERPOLATE_ARB 0x8575 #define GL_SUBTRACT_ARB 0x84E7 #define GL_CONSTANT_ARB 0x8576 #define GL_PRIMARY_COLOR_ARB 0x8577 #define GL_PREVIOUS_ARB 0x8578 #endif #ifndef GL_ARB_texture_env_crossbar #endif #ifndef GL_ARB_texture_env_dot3 #define GL_DOT3_RGB_ARB 0x86AE #define GL_DOT3_RGBA_ARB 0x86AF #endif #ifndef GL_ARB_texture_mirrored_repeat #define GL_MIRRORED_REPEAT_ARB 0x8370 #endif #ifndef GL_ARB_depth_texture #define GL_DEPTH_COMPONENT16_ARB 0x81A5 #define GL_DEPTH_COMPONENT24_ARB 0x81A6 #define GL_DEPTH_COMPONENT32_ARB 0x81A7 #define GL_TEXTURE_DEPTH_SIZE_ARB 0x884A #define GL_DEPTH_TEXTURE_MODE_ARB 0x884B #endif #ifndef GL_ARB_shadow #define GL_TEXTURE_COMPARE_MODE_ARB 0x884C #define GL_TEXTURE_COMPARE_FUNC_ARB 0x884D #define GL_COMPARE_R_TO_TEXTURE_ARB 0x884E #endif #ifndef GL_ARB_shadow_ambient #define GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF #endif #ifndef GL_ARB_window_pos #endif #ifndef GL_ARB_vertex_program #define GL_COLOR_SUM_ARB 0x8458 #define GL_VERTEX_PROGRAM_ARB 0x8620 #define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622 #define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623 #define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624 #define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625 #define GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626 #define GL_PROGRAM_LENGTH_ARB 0x8627 #define GL_PROGRAM_STRING_ARB 0x8628 #define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E #define GL_MAX_PROGRAM_MATRICES_ARB 0x862F #define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640 #define GL_CURRENT_MATRIX_ARB 0x8641 #define GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642 #define GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643 #define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645 #define GL_PROGRAM_ERROR_POSITION_ARB 0x864B #define GL_PROGRAM_BINDING_ARB 0x8677 #define GL_MAX_VERTEX_ATTRIBS_ARB 0x8869 #define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A #define GL_PROGRAM_ERROR_STRING_ARB 0x8874 #define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 #define GL_PROGRAM_FORMAT_ARB 0x8876 #define GL_PROGRAM_INSTRUCTIONS_ARB 0x88A0 #define GL_MAX_PROGRAM_INSTRUCTIONS_ARB 0x88A1 #define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2 #define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3 #define GL_PROGRAM_TEMPORARIES_ARB 0x88A4 #define GL_MAX_PROGRAM_TEMPORARIES_ARB 0x88A5 #define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6 #define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7 #define GL_PROGRAM_PARAMETERS_ARB 0x88A8 #define GL_MAX_PROGRAM_PARAMETERS_ARB 0x88A9 #define GL_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AA #define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB #define GL_PROGRAM_ATTRIBS_ARB 0x88AC #define GL_MAX_PROGRAM_ATTRIBS_ARB 0x88AD #define GL_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AE #define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF #define GL_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B0 #define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1 #define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2 #define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3 #define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4 #define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5 #define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6 #define GL_TRANSPOSE_CURRENT_MATRIX_ARB 0x88B7 #define GL_MATRIX0_ARB 0x88C0 #define GL_MATRIX1_ARB 0x88C1 #define GL_MATRIX2_ARB 0x88C2 #define GL_MATRIX3_ARB 0x88C3 #define GL_MATRIX4_ARB 0x88C4 #define GL_MATRIX5_ARB 0x88C5 #define GL_MATRIX6_ARB 0x88C6 #define GL_MATRIX7_ARB 0x88C7 #define GL_MATRIX8_ARB 0x88C8 #define GL_MATRIX9_ARB 0x88C9 #define GL_MATRIX10_ARB 0x88CA #define GL_MATRIX11_ARB 0x88CB #define GL_MATRIX12_ARB 0x88CC #define GL_MATRIX13_ARB 0x88CD #define GL_MATRIX14_ARB 0x88CE #define GL_MATRIX15_ARB 0x88CF #define GL_MATRIX16_ARB 0x88D0 #define GL_MATRIX17_ARB 0x88D1 #define GL_MATRIX18_ARB 0x88D2 #define GL_MATRIX19_ARB 0x88D3 #define GL_MATRIX20_ARB 0x88D4 #define GL_MATRIX21_ARB 0x88D5 #define GL_MATRIX22_ARB 0x88D6 #define GL_MATRIX23_ARB 0x88D7 #define GL_MATRIX24_ARB 0x88D8 #define GL_MATRIX25_ARB 0x88D9 #define GL_MATRIX26_ARB 0x88DA #define GL_MATRIX27_ARB 0x88DB #define GL_MATRIX28_ARB 0x88DC #define GL_MATRIX29_ARB 0x88DD #define GL_MATRIX30_ARB 0x88DE #define GL_MATRIX31_ARB 0x88DF #endif #ifndef GL_ARB_fragment_program #define GL_FRAGMENT_PROGRAM_ARB 0x8804 #define GL_PROGRAM_ALU_INSTRUCTIONS_ARB 0x8805 #define GL_PROGRAM_TEX_INSTRUCTIONS_ARB 0x8806 #define GL_PROGRAM_TEX_INDIRECTIONS_ARB 0x8807 #define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808 #define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809 #define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A #define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B #define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C #define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D #define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E #define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F #define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810 #define GL_MAX_TEXTURE_COORDS_ARB 0x8871 #define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872 #endif #ifndef GL_ARB_vertex_buffer_object #define GL_BUFFER_SIZE_ARB 0x8764 #define GL_BUFFER_USAGE_ARB 0x8765 #define GL_ARRAY_BUFFER_ARB 0x8892 #define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893 #define GL_ARRAY_BUFFER_BINDING_ARB 0x8894 #define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895 #define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896 #define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897 #define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898 #define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899 #define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A #define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B #define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C #define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D #define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E #define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F #define GL_READ_ONLY_ARB 0x88B8 #define GL_WRITE_ONLY_ARB 0x88B9 #define GL_READ_WRITE_ARB 0x88BA #define GL_BUFFER_ACCESS_ARB 0x88BB #define GL_BUFFER_MAPPED_ARB 0x88BC #define GL_BUFFER_MAP_POINTER_ARB 0x88BD #define GL_STREAM_DRAW_ARB 0x88E0 #define GL_STREAM_READ_ARB 0x88E1 #define GL_STREAM_COPY_ARB 0x88E2 #define GL_STATIC_DRAW_ARB 0x88E4 #define GL_STATIC_READ_ARB 0x88E5 #define GL_STATIC_COPY_ARB 0x88E6 #define GL_DYNAMIC_DRAW_ARB 0x88E8 #define GL_DYNAMIC_READ_ARB 0x88E9 #define GL_DYNAMIC_COPY_ARB 0x88EA #endif #ifndef GL_ARB_occlusion_query #define GL_QUERY_COUNTER_BITS_ARB 0x8864 #define GL_CURRENT_QUERY_ARB 0x8865 #define GL_QUERY_RESULT_ARB 0x8866 #define GL_QUERY_RESULT_AVAILABLE_ARB 0x8867 #define GL_SAMPLES_PASSED_ARB 0x8914 #endif #ifndef GL_ARB_shader_objects #define GL_PROGRAM_OBJECT_ARB 0x8B40 #define GL_SHADER_OBJECT_ARB 0x8B48 #define GL_OBJECT_TYPE_ARB 0x8B4E #define GL_OBJECT_SUBTYPE_ARB 0x8B4F #define GL_FLOAT_VEC2_ARB 0x8B50 #define GL_FLOAT_VEC3_ARB 0x8B51 #define GL_FLOAT_VEC4_ARB 0x8B52 #define GL_INT_VEC2_ARB 0x8B53 #define GL_INT_VEC3_ARB 0x8B54 #define GL_INT_VEC4_ARB 0x8B55 #define GL_BOOL_ARB 0x8B56 #define GL_BOOL_VEC2_ARB 0x8B57 #define GL_BOOL_VEC3_ARB 0x8B58 #define GL_BOOL_VEC4_ARB 0x8B59 #define GL_FLOAT_MAT2_ARB 0x8B5A #define GL_FLOAT_MAT3_ARB 0x8B5B #define GL_FLOAT_MAT4_ARB 0x8B5C #define GL_SAMPLER_1D_ARB 0x8B5D #define GL_SAMPLER_2D_ARB 0x8B5E #define GL_SAMPLER_3D_ARB 0x8B5F #define GL_SAMPLER_CUBE_ARB 0x8B60 #define GL_SAMPLER_1D_SHADOW_ARB 0x8B61 #define GL_SAMPLER_2D_SHADOW_ARB 0x8B62 #define GL_SAMPLER_2D_RECT_ARB 0x8B63 #define GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64 #define GL_OBJECT_DELETE_STATUS_ARB 0x8B80 #define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81 #define GL_OBJECT_LINK_STATUS_ARB 0x8B82 #define GL_OBJECT_VALIDATE_STATUS_ARB 0x8B83 #define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84 #define GL_OBJECT_ATTACHED_OBJECTS_ARB 0x8B85 #define GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86 #define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87 #define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88 #endif #ifndef GL_ARB_vertex_shader #define GL_VERTEX_SHADER_ARB 0x8B31 #define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A #define GL_MAX_VARYING_FLOATS_ARB 0x8B4B #define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D #define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89 #define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A #endif #ifndef GL_ARB_fragment_shader #define GL_FRAGMENT_SHADER_ARB 0x8B30 #define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49 #define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B #endif #ifndef GL_ARB_shading_language_100 #define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C #endif #ifndef GL_ARB_texture_non_power_of_two #endif #ifndef GL_ARB_point_sprite #define GL_POINT_SPRITE_ARB 0x8861 #define GL_COORD_REPLACE_ARB 0x8862 #endif #ifndef GL_ARB_fragment_program_shadow #endif #ifndef GL_ARB_draw_buffers #define GL_MAX_DRAW_BUFFERS_ARB 0x8824 #define GL_DRAW_BUFFER0_ARB 0x8825 #define GL_DRAW_BUFFER1_ARB 0x8826 #define GL_DRAW_BUFFER2_ARB 0x8827 #define GL_DRAW_BUFFER3_ARB 0x8828 #define GL_DRAW_BUFFER4_ARB 0x8829 #define GL_DRAW_BUFFER5_ARB 0x882A #define GL_DRAW_BUFFER6_ARB 0x882B #define GL_DRAW_BUFFER7_ARB 0x882C #define GL_DRAW_BUFFER8_ARB 0x882D #define GL_DRAW_BUFFER9_ARB 0x882E #define GL_DRAW_BUFFER10_ARB 0x882F #define GL_DRAW_BUFFER11_ARB 0x8830 #define GL_DRAW_BUFFER12_ARB 0x8831 #define GL_DRAW_BUFFER13_ARB 0x8832 #define GL_DRAW_BUFFER14_ARB 0x8833 #define GL_DRAW_BUFFER15_ARB 0x8834 #endif #ifndef GL_ARB_texture_rectangle #define GL_TEXTURE_RECTANGLE_ARB 0x84F5 #define GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6 #define GL_PROXY_TEXTURE_RECTANGLE_ARB 0x84F7 #define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8 #endif #ifndef GL_ARB_color_buffer_float #define GL_RGBA_FLOAT_MODE_ARB 0x8820 #define GL_CLAMP_VERTEX_COLOR_ARB 0x891A #define GL_CLAMP_FRAGMENT_COLOR_ARB 0x891B #define GL_CLAMP_READ_COLOR_ARB 0x891C #define GL_FIXED_ONLY_ARB 0x891D #endif #ifndef GL_ARB_half_float_pixel #define GL_HALF_FLOAT_ARB 0x140B #endif #ifndef GL_ARB_texture_float #define GL_TEXTURE_RED_TYPE_ARB 0x8C10 #define GL_TEXTURE_GREEN_TYPE_ARB 0x8C11 #define GL_TEXTURE_BLUE_TYPE_ARB 0x8C12 #define GL_TEXTURE_ALPHA_TYPE_ARB 0x8C13 #define GL_TEXTURE_LUMINANCE_TYPE_ARB 0x8C14 #define GL_TEXTURE_INTENSITY_TYPE_ARB 0x8C15 #define GL_TEXTURE_DEPTH_TYPE_ARB 0x8C16 #define GL_UNSIGNED_NORMALIZED_ARB 0x8C17 #define GL_RGBA32F_ARB 0x8814 #define GL_RGB32F_ARB 0x8815 #define GL_ALPHA32F_ARB 0x8816 #define GL_INTENSITY32F_ARB 0x8817 #define GL_LUMINANCE32F_ARB 0x8818 #define GL_LUMINANCE_ALPHA32F_ARB 0x8819 #define GL_RGBA16F_ARB 0x881A #define GL_RGB16F_ARB 0x881B #define GL_ALPHA16F_ARB 0x881C #define GL_INTENSITY16F_ARB 0x881D #define GL_LUMINANCE16F_ARB 0x881E #define GL_LUMINANCE_ALPHA16F_ARB 0x881F #endif #ifndef GL_ARB_pixel_buffer_object #define GL_PIXEL_PACK_BUFFER_ARB 0x88EB #define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC #define GL_PIXEL_PACK_BUFFER_BINDING_ARB 0x88ED #define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF #endif #ifndef GL_ARB_depth_buffer_float #define GL_DEPTH_COMPONENT32F 0x8CAC #define GL_DEPTH32F_STENCIL8 0x8CAD #define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD #endif #ifndef GL_ARB_draw_instanced #endif #ifndef GL_ARB_framebuffer_object #define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 #define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 #define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 #define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 #define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 #define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 #define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 #define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 #define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 #define GL_FRAMEBUFFER_DEFAULT 0x8218 #define GL_FRAMEBUFFER_UNDEFINED 0x8219 #define GL_DEPTH_STENCIL_ATTACHMENT 0x821A #define GL_MAX_RENDERBUFFER_SIZE 0x84E8 #define GL_DEPTH_STENCIL 0x84F9 #define GL_UNSIGNED_INT_24_8 0x84FA #define GL_DEPTH24_STENCIL8 0x88F0 #define GL_TEXTURE_STENCIL_SIZE 0x88F1 #define GL_TEXTURE_RED_TYPE 0x8C10 #define GL_TEXTURE_GREEN_TYPE 0x8C11 #define GL_TEXTURE_BLUE_TYPE 0x8C12 #define GL_TEXTURE_ALPHA_TYPE 0x8C13 #define GL_TEXTURE_DEPTH_TYPE 0x8C16 #define GL_UNSIGNED_NORMALIZED 0x8C17 #define GL_FRAMEBUFFER_BINDING 0x8CA6 #define GL_DRAW_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING #define GL_RENDERBUFFER_BINDING 0x8CA7 #define GL_READ_FRAMEBUFFER 0x8CA8 #define GL_DRAW_FRAMEBUFFER 0x8CA9 #define GL_READ_FRAMEBUFFER_BINDING 0x8CAA #define GL_RENDERBUFFER_SAMPLES 0x8CAB #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 #define GL_FRAMEBUFFER_COMPLETE 0x8CD5 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB #define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC #define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD #define GL_MAX_COLOR_ATTACHMENTS 0x8CDF #define GL_COLOR_ATTACHMENT0 0x8CE0 #define GL_COLOR_ATTACHMENT1 0x8CE1 #define GL_COLOR_ATTACHMENT2 0x8CE2 #define GL_COLOR_ATTACHMENT3 0x8CE3 #define GL_COLOR_ATTACHMENT4 0x8CE4 #define GL_COLOR_ATTACHMENT5 0x8CE5 #define GL_COLOR_ATTACHMENT6 0x8CE6 #define GL_COLOR_ATTACHMENT7 0x8CE7 #define GL_COLOR_ATTACHMENT8 0x8CE8 #define GL_COLOR_ATTACHMENT9 0x8CE9 #define GL_COLOR_ATTACHMENT10 0x8CEA #define GL_COLOR_ATTACHMENT11 0x8CEB #define GL_COLOR_ATTACHMENT12 0x8CEC #define GL_COLOR_ATTACHMENT13 0x8CED #define GL_COLOR_ATTACHMENT14 0x8CEE #define GL_COLOR_ATTACHMENT15 0x8CEF #define GL_DEPTH_ATTACHMENT 0x8D00 #define GL_STENCIL_ATTACHMENT 0x8D20 #define GL_FRAMEBUFFER 0x8D40 #define GL_RENDERBUFFER 0x8D41 #define GL_RENDERBUFFER_WIDTH 0x8D42 #define GL_RENDERBUFFER_HEIGHT 0x8D43 #define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 #define GL_STENCIL_INDEX1 0x8D46 #define GL_STENCIL_INDEX4 0x8D47 #define GL_STENCIL_INDEX8 0x8D48 #define GL_STENCIL_INDEX16 0x8D49 #define GL_RENDERBUFFER_RED_SIZE 0x8D50 #define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 #define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 #define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 #define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 #define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 #define GL_MAX_SAMPLES 0x8D57 #endif #ifndef GL_ARB_framebuffer_object_DEPRECATED #define GL_INDEX 0x8222 #define GL_TEXTURE_LUMINANCE_TYPE 0x8C14 #define GL_TEXTURE_INTENSITY_TYPE 0x8C15 #endif #ifndef GL_ARB_framebuffer_sRGB #define GL_FRAMEBUFFER_SRGB 0x8DB9 #endif #ifndef GL_ARB_geometry_shader4 #define GL_LINES_ADJACENCY_ARB 0x000A #define GL_LINE_STRIP_ADJACENCY_ARB 0x000B #define GL_TRIANGLES_ADJACENCY_ARB 0x000C #define GL_TRIANGLE_STRIP_ADJACENCY_ARB 0x000D #define GL_PROGRAM_POINT_SIZE_ARB 0x8642 #define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB 0x8C29 #define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB 0x8DA7 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB 0x8DA8 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB 0x8DA9 #define GL_GEOMETRY_SHADER_ARB 0x8DD9 #define GL_GEOMETRY_VERTICES_OUT_ARB 0x8DDA #define GL_GEOMETRY_INPUT_TYPE_ARB 0x8DDB #define GL_GEOMETRY_OUTPUT_TYPE_ARB 0x8DDC #define GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB 0x8DDD #define GL_MAX_VERTEX_VARYING_COMPONENTS_ARB 0x8DDE #define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF #define GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0 #define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1 /* reuse GL_MAX_VARYING_COMPONENTS */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER */ #endif #ifndef GL_ARB_half_float_vertex #define GL_HALF_FLOAT 0x140B #endif #ifndef GL_ARB_instanced_arrays #define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB 0x88FE #endif #ifndef GL_ARB_map_buffer_range #define GL_MAP_READ_BIT 0x0001 #define GL_MAP_WRITE_BIT 0x0002 #define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 #define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 #define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 #define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 #endif #ifndef GL_ARB_texture_buffer_object #define GL_TEXTURE_BUFFER_ARB 0x8C2A #define GL_MAX_TEXTURE_BUFFER_SIZE_ARB 0x8C2B #define GL_TEXTURE_BINDING_BUFFER_ARB 0x8C2C #define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB 0x8C2D #define GL_TEXTURE_BUFFER_FORMAT_ARB 0x8C2E #endif #ifndef GL_ARB_texture_compression_rgtc #define GL_COMPRESSED_RED_RGTC1 0x8DBB #define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC #define GL_COMPRESSED_RG_RGTC2 0x8DBD #define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE #endif #ifndef GL_ARB_texture_rg #define GL_RG 0x8227 #define GL_RG_INTEGER 0x8228 #define GL_R8 0x8229 #define GL_R16 0x822A #define GL_RG8 0x822B #define GL_RG16 0x822C #define GL_R16F 0x822D #define GL_R32F 0x822E #define GL_RG16F 0x822F #define GL_RG32F 0x8230 #define GL_R8I 0x8231 #define GL_R8UI 0x8232 #define GL_R16I 0x8233 #define GL_R16UI 0x8234 #define GL_R32I 0x8235 #define GL_R32UI 0x8236 #define GL_RG8I 0x8237 #define GL_RG8UI 0x8238 #define GL_RG16I 0x8239 #define GL_RG16UI 0x823A #define GL_RG32I 0x823B #define GL_RG32UI 0x823C #endif #ifndef GL_ARB_vertex_array_object #define GL_VERTEX_ARRAY_BINDING 0x85B5 #endif #ifndef GL_ARB_uniform_buffer_object #define GL_UNIFORM_BUFFER 0x8A11 #define GL_UNIFORM_BUFFER_BINDING 0x8A28 #define GL_UNIFORM_BUFFER_START 0x8A29 #define GL_UNIFORM_BUFFER_SIZE 0x8A2A #define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B #define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C #define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D #define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E #define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F #define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 #define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 #define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 #define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 #define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 #define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 #define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 #define GL_UNIFORM_TYPE 0x8A37 #define GL_UNIFORM_SIZE 0x8A38 #define GL_UNIFORM_NAME_LENGTH 0x8A39 #define GL_UNIFORM_BLOCK_INDEX 0x8A3A #define GL_UNIFORM_OFFSET 0x8A3B #define GL_UNIFORM_ARRAY_STRIDE 0x8A3C #define GL_UNIFORM_MATRIX_STRIDE 0x8A3D #define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E #define GL_UNIFORM_BLOCK_BINDING 0x8A3F #define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 #define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 #define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 #define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 #define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 #define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 #define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 #define GL_INVALID_INDEX 0xFFFFFFFFu #endif #ifndef GL_ARB_compatibility /* ARB_compatibility just defines tokens from core 3.0 */ #endif #ifndef GL_ARB_copy_buffer #define GL_COPY_READ_BUFFER 0x8F36 #define GL_COPY_WRITE_BUFFER 0x8F37 #endif #ifndef GL_ARB_shader_texture_lod #endif #ifndef GL_ARB_depth_clamp #define GL_DEPTH_CLAMP 0x864F #endif #ifndef GL_ARB_draw_elements_base_vertex #endif #ifndef GL_ARB_fragment_coord_conventions #endif #ifndef GL_ARB_provoking_vertex #define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C #define GL_FIRST_VERTEX_CONVENTION 0x8E4D #define GL_LAST_VERTEX_CONVENTION 0x8E4E #define GL_PROVOKING_VERTEX 0x8E4F #endif #ifndef GL_ARB_seamless_cube_map #define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F #endif #ifndef GL_ARB_sync #define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 #define GL_OBJECT_TYPE 0x9112 #define GL_SYNC_CONDITION 0x9113 #define GL_SYNC_STATUS 0x9114 #define GL_SYNC_FLAGS 0x9115 #define GL_SYNC_FENCE 0x9116 #define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 #define GL_UNSIGNALED 0x9118 #define GL_SIGNALED 0x9119 #define GL_ALREADY_SIGNALED 0x911A #define GL_TIMEOUT_EXPIRED 0x911B #define GL_CONDITION_SATISFIED 0x911C #define GL_WAIT_FAILED 0x911D #define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 #define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull #endif #ifndef GL_ARB_texture_multisample #define GL_SAMPLE_POSITION 0x8E50 #define GL_SAMPLE_MASK 0x8E51 #define GL_SAMPLE_MASK_VALUE 0x8E52 #define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 #define GL_TEXTURE_2D_MULTISAMPLE 0x9100 #define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 #define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 #define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 #define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 #define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 #define GL_TEXTURE_SAMPLES 0x9106 #define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 #define GL_SAMPLER_2D_MULTISAMPLE 0x9108 #define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 #define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A #define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B #define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C #define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D #define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E #define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F #define GL_MAX_INTEGER_SAMPLES 0x9110 #endif #ifndef GL_ARB_vertex_array_bgra /* reuse GL_BGRA */ #endif #ifndef GL_ARB_draw_buffers_blend #endif #ifndef GL_ARB_sample_shading #define GL_SAMPLE_SHADING_ARB 0x8C36 #define GL_MIN_SAMPLE_SHADING_VALUE_ARB 0x8C37 #endif #ifndef GL_ARB_texture_cube_map_array #define GL_TEXTURE_CUBE_MAP_ARRAY_ARB 0x9009 #define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB 0x900A #define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB 0x900B #define GL_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900C #define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB 0x900D #define GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900E #define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900F #endif #ifndef GL_ARB_texture_gather #define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5E #define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5F #endif #ifndef GL_ARB_texture_query_lod #endif #ifndef GL_ARB_shading_language_include #define GL_SHADER_INCLUDE_ARB 0x8DAE #define GL_NAMED_STRING_LENGTH_ARB 0x8DE9 #define GL_NAMED_STRING_TYPE_ARB 0x8DEA #endif #ifndef GL_ARB_texture_compression_bptc #define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C #define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D #define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E #define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F #endif #ifndef GL_ARB_blend_func_extended #define GL_SRC1_COLOR 0x88F9 /* reuse GL_SRC1_ALPHA */ #define GL_ONE_MINUS_SRC1_COLOR 0x88FA #define GL_ONE_MINUS_SRC1_ALPHA 0x88FB #define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC #endif #ifndef GL_ARB_explicit_attrib_location #endif #ifndef GL_ARB_occlusion_query2 #define GL_ANY_SAMPLES_PASSED 0x8C2F #endif #ifndef GL_ARB_sampler_objects #define GL_SAMPLER_BINDING 0x8919 #endif #ifndef GL_ARB_shader_bit_encoding #endif #ifndef GL_ARB_texture_rgb10_a2ui #define GL_RGB10_A2UI 0x906F #endif #ifndef GL_ARB_texture_swizzle #define GL_TEXTURE_SWIZZLE_R 0x8E42 #define GL_TEXTURE_SWIZZLE_G 0x8E43 #define GL_TEXTURE_SWIZZLE_B 0x8E44 #define GL_TEXTURE_SWIZZLE_A 0x8E45 #define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 #endif #ifndef GL_ARB_timer_query #define GL_TIME_ELAPSED 0x88BF #define GL_TIMESTAMP 0x8E28 #endif #ifndef GL_ARB_vertex_type_2_10_10_10_rev /* reuse GL_UNSIGNED_INT_2_10_10_10_REV */ #define GL_INT_2_10_10_10_REV 0x8D9F #endif #ifndef GL_ARB_draw_indirect #define GL_DRAW_INDIRECT_BUFFER 0x8F3F #define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 #endif #ifndef GL_ARB_gpu_shader5 #define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F #define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A #define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B #define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C #define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D /* reuse GL_MAX_VERTEX_STREAMS */ #endif #ifndef GL_ARB_gpu_shader_fp64 /* reuse GL_DOUBLE */ #define GL_DOUBLE_VEC2 0x8FFC #define GL_DOUBLE_VEC3 0x8FFD #define GL_DOUBLE_VEC4 0x8FFE #define GL_DOUBLE_MAT2 0x8F46 #define GL_DOUBLE_MAT3 0x8F47 #define GL_DOUBLE_MAT4 0x8F48 #define GL_DOUBLE_MAT2x3 0x8F49 #define GL_DOUBLE_MAT2x4 0x8F4A #define GL_DOUBLE_MAT3x2 0x8F4B #define GL_DOUBLE_MAT3x4 0x8F4C #define GL_DOUBLE_MAT4x2 0x8F4D #define GL_DOUBLE_MAT4x3 0x8F4E #endif #ifndef GL_ARB_shader_subroutine #define GL_ACTIVE_SUBROUTINES 0x8DE5 #define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6 #define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47 #define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48 #define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49 #define GL_MAX_SUBROUTINES 0x8DE7 #define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8 #define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A #define GL_COMPATIBLE_SUBROUTINES 0x8E4B /* reuse GL_UNIFORM_SIZE */ /* reuse GL_UNIFORM_NAME_LENGTH */ #endif #ifndef GL_ARB_tessellation_shader #define GL_PATCHES 0x000E #define GL_PATCH_VERTICES 0x8E72 #define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 #define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 #define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75 #define GL_TESS_GEN_MODE 0x8E76 #define GL_TESS_GEN_SPACING 0x8E77 #define GL_TESS_GEN_VERTEX_ORDER 0x8E78 #define GL_TESS_GEN_POINT_MODE 0x8E79 /* reuse GL_TRIANGLES */ /* reuse GL_QUADS */ #define GL_ISOLINES 0x8E7A /* reuse GL_EQUAL */ #define GL_FRACTIONAL_ODD 0x8E7B #define GL_FRACTIONAL_EVEN 0x8E7C /* reuse GL_CCW */ /* reuse GL_CW */ #define GL_MAX_PATCH_VERTICES 0x8E7D #define GL_MAX_TESS_GEN_LEVEL 0x8E7E #define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F #define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80 #define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81 #define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82 #define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83 #define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84 #define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85 #define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86 #define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89 #define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A #define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C #define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D #define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E #define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F #define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0 #define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1 #define GL_TESS_EVALUATION_SHADER 0x8E87 #define GL_TESS_CONTROL_SHADER 0x8E88 #endif #ifndef GL_ARB_texture_buffer_object_rgb32 /* reuse GL_RGB32F */ /* reuse GL_RGB32UI */ /* reuse GL_RGB32I */ #endif #ifndef GL_ARB_transform_feedback2 #define GL_TRANSFORM_FEEDBACK 0x8E22 #define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23 #define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24 #define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 #endif #ifndef GL_ARB_transform_feedback3 #define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70 #define GL_MAX_VERTEX_STREAMS 0x8E71 #endif #ifndef GL_ARB_ES2_compatibility #define GL_FIXED 0x140C #define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A #define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B #define GL_LOW_FLOAT 0x8DF0 #define GL_MEDIUM_FLOAT 0x8DF1 #define GL_HIGH_FLOAT 0x8DF2 #define GL_LOW_INT 0x8DF3 #define GL_MEDIUM_INT 0x8DF4 #define GL_HIGH_INT 0x8DF5 #define GL_SHADER_COMPILER 0x8DFA #define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 #define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB #define GL_MAX_VARYING_VECTORS 0x8DFC #define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD #endif #ifndef GL_ARB_get_program_binary #define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 #define GL_PROGRAM_BINARY_LENGTH 0x8741 #define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE #define GL_PROGRAM_BINARY_FORMATS 0x87FF #endif #ifndef GL_ARB_separate_shader_objects #define GL_VERTEX_SHADER_BIT 0x00000001 #define GL_FRAGMENT_SHADER_BIT 0x00000002 #define GL_GEOMETRY_SHADER_BIT 0x00000004 #define GL_TESS_CONTROL_SHADER_BIT 0x00000008 #define GL_TESS_EVALUATION_SHADER_BIT 0x00000010 #define GL_ALL_SHADER_BITS 0xFFFFFFFF #define GL_PROGRAM_SEPARABLE 0x8258 #define GL_ACTIVE_PROGRAM 0x8259 #define GL_PROGRAM_PIPELINE_BINDING 0x825A #endif #ifndef GL_ARB_shader_precision #endif #ifndef GL_ARB_vertex_attrib_64bit /* reuse GL_RGB32I */ /* reuse GL_DOUBLE_VEC2 */ /* reuse GL_DOUBLE_VEC3 */ /* reuse GL_DOUBLE_VEC4 */ /* reuse GL_DOUBLE_MAT2 */ /* reuse GL_DOUBLE_MAT3 */ /* reuse GL_DOUBLE_MAT4 */ /* reuse GL_DOUBLE_MAT2x3 */ /* reuse GL_DOUBLE_MAT2x4 */ /* reuse GL_DOUBLE_MAT3x2 */ /* reuse GL_DOUBLE_MAT3x4 */ /* reuse GL_DOUBLE_MAT4x2 */ /* reuse GL_DOUBLE_MAT4x3 */ #endif #ifndef GL_ARB_viewport_array /* reuse GL_SCISSOR_BOX */ /* reuse GL_VIEWPORT */ /* reuse GL_DEPTH_RANGE */ /* reuse GL_SCISSOR_TEST */ #define GL_MAX_VIEWPORTS 0x825B #define GL_VIEWPORT_SUBPIXEL_BITS 0x825C #define GL_VIEWPORT_BOUNDS_RANGE 0x825D #define GL_LAYER_PROVOKING_VERTEX 0x825E #define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F #define GL_UNDEFINED_VERTEX 0x8260 /* reuse GL_FIRST_VERTEX_CONVENTION */ /* reuse GL_LAST_VERTEX_CONVENTION */ /* reuse GL_PROVOKING_VERTEX */ #endif #ifndef GL_ARB_cl_event #define GL_SYNC_CL_EVENT_ARB 0x8240 #define GL_SYNC_CL_EVENT_COMPLETE_ARB 0x8241 #endif #ifndef GL_ARB_debug_output #define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 #define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 #define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244 #define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245 #define GL_DEBUG_SOURCE_API_ARB 0x8246 #define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247 #define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248 #define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249 #define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A #define GL_DEBUG_SOURCE_OTHER_ARB 0x824B #define GL_DEBUG_TYPE_ERROR_ARB 0x824C #define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D #define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E #define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F #define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250 #define GL_DEBUG_TYPE_OTHER_ARB 0x8251 #define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143 #define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144 #define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145 #define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146 #define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147 #define GL_DEBUG_SEVERITY_LOW_ARB 0x9148 #endif #ifndef GL_ARB_robustness /* reuse GL_NO_ERROR */ #define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 0x00000004 #define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 #define GL_GUILTY_CONTEXT_RESET_ARB 0x8253 #define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 #define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 #define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 #define GL_NO_RESET_NOTIFICATION_ARB 0x8261 #endif #ifndef GL_ARB_shader_stencil_export #endif #ifndef GL_ARB_base_instance #endif #ifndef GL_ARB_shading_language_420pack #endif #ifndef GL_ARB_transform_feedback_instanced #endif #ifndef GL_ARB_compressed_texture_pixel_storage #define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127 #define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128 #define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129 #define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A #define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B #define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C #define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D #define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E #endif #ifndef GL_ARB_conservative_depth #endif #ifndef GL_ARB_internalformat_query #define GL_NUM_SAMPLE_COUNTS 0x9380 #endif #ifndef GL_ARB_map_buffer_alignment #define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC #endif #ifndef GL_ARB_shader_atomic_counters #define GL_ATOMIC_COUNTER_BUFFER 0x92C0 #define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1 #define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2 #define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3 #define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4 #define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5 #define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6 #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7 #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8 #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9 #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB #define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC #define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD #define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE #define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF #define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0 #define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1 #define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2 #define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3 #define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4 #define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5 #define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6 #define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7 #define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8 #define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC #define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9 #define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA #define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB #endif #ifndef GL_ARB_shader_image_load_store #define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 #define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 #define GL_UNIFORM_BARRIER_BIT 0x00000004 #define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 #define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020 #define GL_COMMAND_BARRIER_BIT 0x00000040 #define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 #define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 #define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 #define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 #define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800 #define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 #define GL_ALL_BARRIER_BITS 0xFFFFFFFF #define GL_MAX_IMAGE_UNITS 0x8F38 #define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39 #define GL_IMAGE_BINDING_NAME 0x8F3A #define GL_IMAGE_BINDING_LEVEL 0x8F3B #define GL_IMAGE_BINDING_LAYERED 0x8F3C #define GL_IMAGE_BINDING_LAYER 0x8F3D #define GL_IMAGE_BINDING_ACCESS 0x8F3E #define GL_IMAGE_1D 0x904C #define GL_IMAGE_2D 0x904D #define GL_IMAGE_3D 0x904E #define GL_IMAGE_2D_RECT 0x904F #define GL_IMAGE_CUBE 0x9050 #define GL_IMAGE_BUFFER 0x9051 #define GL_IMAGE_1D_ARRAY 0x9052 #define GL_IMAGE_2D_ARRAY 0x9053 #define GL_IMAGE_CUBE_MAP_ARRAY 0x9054 #define GL_IMAGE_2D_MULTISAMPLE 0x9055 #define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056 #define GL_INT_IMAGE_1D 0x9057 #define GL_INT_IMAGE_2D 0x9058 #define GL_INT_IMAGE_3D 0x9059 #define GL_INT_IMAGE_2D_RECT 0x905A #define GL_INT_IMAGE_CUBE 0x905B #define GL_INT_IMAGE_BUFFER 0x905C #define GL_INT_IMAGE_1D_ARRAY 0x905D #define GL_INT_IMAGE_2D_ARRAY 0x905E #define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F #define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060 #define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061 #define GL_UNSIGNED_INT_IMAGE_1D 0x9062 #define GL_UNSIGNED_INT_IMAGE_2D 0x9063 #define GL_UNSIGNED_INT_IMAGE_3D 0x9064 #define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065 #define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066 #define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067 #define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068 #define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 #define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A #define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B #define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C #define GL_MAX_IMAGE_SAMPLES 0x906D #define GL_IMAGE_BINDING_FORMAT 0x906E #define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7 #define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8 #define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9 #define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA #define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB #define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC #define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD #define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE #define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF #endif #ifndef GL_ARB_shading_language_packing #endif #ifndef GL_ARB_texture_storage #define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F #endif #ifndef GL_EXT_abgr #define GL_ABGR_EXT 0x8000 #endif #ifndef GL_EXT_blend_color #define GL_CONSTANT_COLOR_EXT 0x8001 #define GL_ONE_MINUS_CONSTANT_COLOR_EXT 0x8002 #define GL_CONSTANT_ALPHA_EXT 0x8003 #define GL_ONE_MINUS_CONSTANT_ALPHA_EXT 0x8004 #define GL_BLEND_COLOR_EXT 0x8005 #endif #ifndef GL_EXT_polygon_offset #define GL_POLYGON_OFFSET_EXT 0x8037 #define GL_POLYGON_OFFSET_FACTOR_EXT 0x8038 #define GL_POLYGON_OFFSET_BIAS_EXT 0x8039 #endif #ifndef GL_EXT_texture #define GL_ALPHA4_EXT 0x803B #define GL_ALPHA8_EXT 0x803C #define GL_ALPHA12_EXT 0x803D #define GL_ALPHA16_EXT 0x803E #define GL_LUMINANCE4_EXT 0x803F #define GL_LUMINANCE8_EXT 0x8040 #define GL_LUMINANCE12_EXT 0x8041 #define GL_LUMINANCE16_EXT 0x8042 #define GL_LUMINANCE4_ALPHA4_EXT 0x8043 #define GL_LUMINANCE6_ALPHA2_EXT 0x8044 #define GL_LUMINANCE8_ALPHA8_EXT 0x8045 #define GL_LUMINANCE12_ALPHA4_EXT 0x8046 #define GL_LUMINANCE12_ALPHA12_EXT 0x8047 #define GL_LUMINANCE16_ALPHA16_EXT 0x8048 #define GL_INTENSITY_EXT 0x8049 #define GL_INTENSITY4_EXT 0x804A #define GL_INTENSITY8_EXT 0x804B #define GL_INTENSITY12_EXT 0x804C #define GL_INTENSITY16_EXT 0x804D #define GL_RGB2_EXT 0x804E #define GL_RGB4_EXT 0x804F #define GL_RGB5_EXT 0x8050 #define GL_RGB8_EXT 0x8051 #define GL_RGB10_EXT 0x8052 #define GL_RGB12_EXT 0x8053 #define GL_RGB16_EXT 0x8054 #define GL_RGBA2_EXT 0x8055 #define GL_RGBA4_EXT 0x8056 #define GL_RGB5_A1_EXT 0x8057 #define GL_RGBA8_EXT 0x8058 #define GL_RGB10_A2_EXT 0x8059 #define GL_RGBA12_EXT 0x805A #define GL_RGBA16_EXT 0x805B #define GL_TEXTURE_RED_SIZE_EXT 0x805C #define GL_TEXTURE_GREEN_SIZE_EXT 0x805D #define GL_TEXTURE_BLUE_SIZE_EXT 0x805E #define GL_TEXTURE_ALPHA_SIZE_EXT 0x805F #define GL_TEXTURE_LUMINANCE_SIZE_EXT 0x8060 #define GL_TEXTURE_INTENSITY_SIZE_EXT 0x8061 #define GL_REPLACE_EXT 0x8062 #define GL_PROXY_TEXTURE_1D_EXT 0x8063 #define GL_PROXY_TEXTURE_2D_EXT 0x8064 #define GL_TEXTURE_TOO_LARGE_EXT 0x8065 #endif #ifndef GL_EXT_texture3D #define GL_PACK_SKIP_IMAGES_EXT 0x806B #define GL_PACK_IMAGE_HEIGHT_EXT 0x806C #define GL_UNPACK_SKIP_IMAGES_EXT 0x806D #define GL_UNPACK_IMAGE_HEIGHT_EXT 0x806E #define GL_TEXTURE_3D_EXT 0x806F #define GL_PROXY_TEXTURE_3D_EXT 0x8070 #define GL_TEXTURE_DEPTH_EXT 0x8071 #define GL_TEXTURE_WRAP_R_EXT 0x8072 #define GL_MAX_3D_TEXTURE_SIZE_EXT 0x8073 #endif #ifndef GL_SGIS_texture_filter4 #define GL_FILTER4_SGIS 0x8146 #define GL_TEXTURE_FILTER4_SIZE_SGIS 0x8147 #endif #ifndef GL_EXT_subtexture #endif #ifndef GL_EXT_copy_texture #endif #ifndef GL_EXT_histogram #define GL_HISTOGRAM_EXT 0x8024 #define GL_PROXY_HISTOGRAM_EXT 0x8025 #define GL_HISTOGRAM_WIDTH_EXT 0x8026 #define GL_HISTOGRAM_FORMAT_EXT 0x8027 #define GL_HISTOGRAM_RED_SIZE_EXT 0x8028 #define GL_HISTOGRAM_GREEN_SIZE_EXT 0x8029 #define GL_HISTOGRAM_BLUE_SIZE_EXT 0x802A #define GL_HISTOGRAM_ALPHA_SIZE_EXT 0x802B #define GL_HISTOGRAM_LUMINANCE_SIZE_EXT 0x802C #define GL_HISTOGRAM_SINK_EXT 0x802D #define GL_MINMAX_EXT 0x802E #define GL_MINMAX_FORMAT_EXT 0x802F #define GL_MINMAX_SINK_EXT 0x8030 #define GL_TABLE_TOO_LARGE_EXT 0x8031 #endif #ifndef GL_EXT_convolution #define GL_CONVOLUTION_1D_EXT 0x8010 #define GL_CONVOLUTION_2D_EXT 0x8011 #define GL_SEPARABLE_2D_EXT 0x8012 #define GL_CONVOLUTION_BORDER_MODE_EXT 0x8013 #define GL_CONVOLUTION_FILTER_SCALE_EXT 0x8014 #define GL_CONVOLUTION_FILTER_BIAS_EXT 0x8015 #define GL_REDUCE_EXT 0x8016 #define GL_CONVOLUTION_FORMAT_EXT 0x8017 #define GL_CONVOLUTION_WIDTH_EXT 0x8018 #define GL_CONVOLUTION_HEIGHT_EXT 0x8019 #define GL_MAX_CONVOLUTION_WIDTH_EXT 0x801A #define GL_MAX_CONVOLUTION_HEIGHT_EXT 0x801B #define GL_POST_CONVOLUTION_RED_SCALE_EXT 0x801C #define GL_POST_CONVOLUTION_GREEN_SCALE_EXT 0x801D #define GL_POST_CONVOLUTION_BLUE_SCALE_EXT 0x801E #define GL_POST_CONVOLUTION_ALPHA_SCALE_EXT 0x801F #define GL_POST_CONVOLUTION_RED_BIAS_EXT 0x8020 #define GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021 #define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022 #define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023 #endif #ifndef GL_SGI_color_matrix #define GL_COLOR_MATRIX_SGI 0x80B1 #define GL_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B2 #define GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B3 #define GL_POST_COLOR_MATRIX_RED_SCALE_SGI 0x80B4 #define GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI 0x80B5 #define GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI 0x80B6 #define GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI 0x80B7 #define GL_POST_COLOR_MATRIX_RED_BIAS_SGI 0x80B8 #define GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI 0x80B9 #define GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI 0x80BA #define GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI 0x80BB #endif #ifndef GL_SGI_color_table #define GL_COLOR_TABLE_SGI 0x80D0 #define GL_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D1 #define GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D2 #define GL_PROXY_COLOR_TABLE_SGI 0x80D3 #define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D4 #define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D5 #define GL_COLOR_TABLE_SCALE_SGI 0x80D6 #define GL_COLOR_TABLE_BIAS_SGI 0x80D7 #define GL_COLOR_TABLE_FORMAT_SGI 0x80D8 #define GL_COLOR_TABLE_WIDTH_SGI 0x80D9 #define GL_COLOR_TABLE_RED_SIZE_SGI 0x80DA #define GL_COLOR_TABLE_GREEN_SIZE_SGI 0x80DB #define GL_COLOR_TABLE_BLUE_SIZE_SGI 0x80DC #define GL_COLOR_TABLE_ALPHA_SIZE_SGI 0x80DD #define GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE #define GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF #endif #ifndef GL_SGIS_pixel_texture #define GL_PIXEL_TEXTURE_SGIS 0x8353 #define GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS 0x8354 #define GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS 0x8355 #define GL_PIXEL_GROUP_COLOR_SGIS 0x8356 #endif #ifndef GL_SGIX_pixel_texture #define GL_PIXEL_TEX_GEN_SGIX 0x8139 #define GL_PIXEL_TEX_GEN_MODE_SGIX 0x832B #endif #ifndef GL_SGIS_texture4D #define GL_PACK_SKIP_VOLUMES_SGIS 0x8130 #define GL_PACK_IMAGE_DEPTH_SGIS 0x8131 #define GL_UNPACK_SKIP_VOLUMES_SGIS 0x8132 #define GL_UNPACK_IMAGE_DEPTH_SGIS 0x8133 #define GL_TEXTURE_4D_SGIS 0x8134 #define GL_PROXY_TEXTURE_4D_SGIS 0x8135 #define GL_TEXTURE_4DSIZE_SGIS 0x8136 #define GL_TEXTURE_WRAP_Q_SGIS 0x8137 #define GL_MAX_4D_TEXTURE_SIZE_SGIS 0x8138 #define GL_TEXTURE_4D_BINDING_SGIS 0x814F #endif #ifndef GL_SGI_texture_color_table #define GL_TEXTURE_COLOR_TABLE_SGI 0x80BC #define GL_PROXY_TEXTURE_COLOR_TABLE_SGI 0x80BD #endif #ifndef GL_EXT_cmyka #define GL_CMYK_EXT 0x800C #define GL_CMYKA_EXT 0x800D #define GL_PACK_CMYK_HINT_EXT 0x800E #define GL_UNPACK_CMYK_HINT_EXT 0x800F #endif #ifndef GL_EXT_texture_object #define GL_TEXTURE_PRIORITY_EXT 0x8066 #define GL_TEXTURE_RESIDENT_EXT 0x8067 #define GL_TEXTURE_1D_BINDING_EXT 0x8068 #define GL_TEXTURE_2D_BINDING_EXT 0x8069 #define GL_TEXTURE_3D_BINDING_EXT 0x806A #endif #ifndef GL_SGIS_detail_texture #define GL_DETAIL_TEXTURE_2D_SGIS 0x8095 #define GL_DETAIL_TEXTURE_2D_BINDING_SGIS 0x8096 #define GL_LINEAR_DETAIL_SGIS 0x8097 #define GL_LINEAR_DETAIL_ALPHA_SGIS 0x8098 #define GL_LINEAR_DETAIL_COLOR_SGIS 0x8099 #define GL_DETAIL_TEXTURE_LEVEL_SGIS 0x809A #define GL_DETAIL_TEXTURE_MODE_SGIS 0x809B #define GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS 0x809C #endif #ifndef GL_SGIS_sharpen_texture #define GL_LINEAR_SHARPEN_SGIS 0x80AD #define GL_LINEAR_SHARPEN_ALPHA_SGIS 0x80AE #define GL_LINEAR_SHARPEN_COLOR_SGIS 0x80AF #define GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS 0x80B0 #endif #ifndef GL_EXT_packed_pixels #define GL_UNSIGNED_BYTE_3_3_2_EXT 0x8032 #define GL_UNSIGNED_SHORT_4_4_4_4_EXT 0x8033 #define GL_UNSIGNED_SHORT_5_5_5_1_EXT 0x8034 #define GL_UNSIGNED_INT_8_8_8_8_EXT 0x8035 #define GL_UNSIGNED_INT_10_10_10_2_EXT 0x8036 #endif #ifndef GL_SGIS_texture_lod #define GL_TEXTURE_MIN_LOD_SGIS 0x813A #define GL_TEXTURE_MAX_LOD_SGIS 0x813B #define GL_TEXTURE_BASE_LEVEL_SGIS 0x813C #define GL_TEXTURE_MAX_LEVEL_SGIS 0x813D #endif #ifndef GL_SGIS_multisample #define GL_MULTISAMPLE_SGIS 0x809D #define GL_SAMPLE_ALPHA_TO_MASK_SGIS 0x809E #define GL_SAMPLE_ALPHA_TO_ONE_SGIS 0x809F #define GL_SAMPLE_MASK_SGIS 0x80A0 #define GL_1PASS_SGIS 0x80A1 #define GL_2PASS_0_SGIS 0x80A2 #define GL_2PASS_1_SGIS 0x80A3 #define GL_4PASS_0_SGIS 0x80A4 #define GL_4PASS_1_SGIS 0x80A5 #define GL_4PASS_2_SGIS 0x80A6 #define GL_4PASS_3_SGIS 0x80A7 #define GL_SAMPLE_BUFFERS_SGIS 0x80A8 #define GL_SAMPLES_SGIS 0x80A9 #define GL_SAMPLE_MASK_VALUE_SGIS 0x80AA #define GL_SAMPLE_MASK_INVERT_SGIS 0x80AB #define GL_SAMPLE_PATTERN_SGIS 0x80AC #endif #ifndef GL_EXT_rescale_normal #define GL_RESCALE_NORMAL_EXT 0x803A #endif #ifndef GL_EXT_vertex_array #define GL_VERTEX_ARRAY_EXT 0x8074 #define GL_NORMAL_ARRAY_EXT 0x8075 #define GL_COLOR_ARRAY_EXT 0x8076 #define GL_INDEX_ARRAY_EXT 0x8077 #define GL_TEXTURE_COORD_ARRAY_EXT 0x8078 #define GL_EDGE_FLAG_ARRAY_EXT 0x8079 #define GL_VERTEX_ARRAY_SIZE_EXT 0x807A #define GL_VERTEX_ARRAY_TYPE_EXT 0x807B #define GL_VERTEX_ARRAY_STRIDE_EXT 0x807C #define GL_VERTEX_ARRAY_COUNT_EXT 0x807D #define GL_NORMAL_ARRAY_TYPE_EXT 0x807E #define GL_NORMAL_ARRAY_STRIDE_EXT 0x807F #define GL_NORMAL_ARRAY_COUNT_EXT 0x8080 #define GL_COLOR_ARRAY_SIZE_EXT 0x8081 #define GL_COLOR_ARRAY_TYPE_EXT 0x8082 #define GL_COLOR_ARRAY_STRIDE_EXT 0x8083 #define GL_COLOR_ARRAY_COUNT_EXT 0x8084 #define GL_INDEX_ARRAY_TYPE_EXT 0x8085 #define GL_INDEX_ARRAY_STRIDE_EXT 0x8086 #define GL_INDEX_ARRAY_COUNT_EXT 0x8087 #define GL_TEXTURE_COORD_ARRAY_SIZE_EXT 0x8088 #define GL_TEXTURE_COORD_ARRAY_TYPE_EXT 0x8089 #define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A #define GL_TEXTURE_COORD_ARRAY_COUNT_EXT 0x808B #define GL_EDGE_FLAG_ARRAY_STRIDE_EXT 0x808C #define GL_EDGE_FLAG_ARRAY_COUNT_EXT 0x808D #define GL_VERTEX_ARRAY_POINTER_EXT 0x808E #define GL_NORMAL_ARRAY_POINTER_EXT 0x808F #define GL_COLOR_ARRAY_POINTER_EXT 0x8090 #define GL_INDEX_ARRAY_POINTER_EXT 0x8091 #define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092 #define GL_EDGE_FLAG_ARRAY_POINTER_EXT 0x8093 #endif #ifndef GL_EXT_misc_attribute #endif #ifndef GL_SGIS_generate_mipmap #define GL_GENERATE_MIPMAP_SGIS 0x8191 #define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192 #endif #ifndef GL_SGIX_clipmap #define GL_LINEAR_CLIPMAP_LINEAR_SGIX 0x8170 #define GL_TEXTURE_CLIPMAP_CENTER_SGIX 0x8171 #define GL_TEXTURE_CLIPMAP_FRAME_SGIX 0x8172 #define GL_TEXTURE_CLIPMAP_OFFSET_SGIX 0x8173 #define GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8174 #define GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX 0x8175 #define GL_TEXTURE_CLIPMAP_DEPTH_SGIX 0x8176 #define GL_MAX_CLIPMAP_DEPTH_SGIX 0x8177 #define GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8178 #define GL_NEAREST_CLIPMAP_NEAREST_SGIX 0x844D #define GL_NEAREST_CLIPMAP_LINEAR_SGIX 0x844E #define GL_LINEAR_CLIPMAP_NEAREST_SGIX 0x844F #endif #ifndef GL_SGIX_shadow #define GL_TEXTURE_COMPARE_SGIX 0x819A #define GL_TEXTURE_COMPARE_OPERATOR_SGIX 0x819B #define GL_TEXTURE_LEQUAL_R_SGIX 0x819C #define GL_TEXTURE_GEQUAL_R_SGIX 0x819D #endif #ifndef GL_SGIS_texture_edge_clamp #define GL_CLAMP_TO_EDGE_SGIS 0x812F #endif #ifndef GL_SGIS_texture_border_clamp #define GL_CLAMP_TO_BORDER_SGIS 0x812D #endif #ifndef GL_EXT_blend_minmax #define GL_FUNC_ADD_EXT 0x8006 #define GL_MIN_EXT 0x8007 #define GL_MAX_EXT 0x8008 #define GL_BLEND_EQUATION_EXT 0x8009 #endif #ifndef GL_EXT_blend_subtract #define GL_FUNC_SUBTRACT_EXT 0x800A #define GL_FUNC_REVERSE_SUBTRACT_EXT 0x800B #endif #ifndef GL_EXT_blend_logic_op #endif #ifndef GL_SGIX_interlace #define GL_INTERLACE_SGIX 0x8094 #endif #ifndef GL_SGIX_pixel_tiles #define GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX 0x813E #define GL_PIXEL_TILE_CACHE_INCREMENT_SGIX 0x813F #define GL_PIXEL_TILE_WIDTH_SGIX 0x8140 #define GL_PIXEL_TILE_HEIGHT_SGIX 0x8141 #define GL_PIXEL_TILE_GRID_WIDTH_SGIX 0x8142 #define GL_PIXEL_TILE_GRID_HEIGHT_SGIX 0x8143 #define GL_PIXEL_TILE_GRID_DEPTH_SGIX 0x8144 #define GL_PIXEL_TILE_CACHE_SIZE_SGIX 0x8145 #endif #ifndef GL_SGIS_texture_select #define GL_DUAL_ALPHA4_SGIS 0x8110 #define GL_DUAL_ALPHA8_SGIS 0x8111 #define GL_DUAL_ALPHA12_SGIS 0x8112 #define GL_DUAL_ALPHA16_SGIS 0x8113 #define GL_DUAL_LUMINANCE4_SGIS 0x8114 #define GL_DUAL_LUMINANCE8_SGIS 0x8115 #define GL_DUAL_LUMINANCE12_SGIS 0x8116 #define GL_DUAL_LUMINANCE16_SGIS 0x8117 #define GL_DUAL_INTENSITY4_SGIS 0x8118 #define GL_DUAL_INTENSITY8_SGIS 0x8119 #define GL_DUAL_INTENSITY12_SGIS 0x811A #define GL_DUAL_INTENSITY16_SGIS 0x811B #define GL_DUAL_LUMINANCE_ALPHA4_SGIS 0x811C #define GL_DUAL_LUMINANCE_ALPHA8_SGIS 0x811D #define GL_QUAD_ALPHA4_SGIS 0x811E #define GL_QUAD_ALPHA8_SGIS 0x811F #define GL_QUAD_LUMINANCE4_SGIS 0x8120 #define GL_QUAD_LUMINANCE8_SGIS 0x8121 #define GL_QUAD_INTENSITY4_SGIS 0x8122 #define GL_QUAD_INTENSITY8_SGIS 0x8123 #define GL_DUAL_TEXTURE_SELECT_SGIS 0x8124 #define GL_QUAD_TEXTURE_SELECT_SGIS 0x8125 #endif #ifndef GL_SGIX_sprite #define GL_SPRITE_SGIX 0x8148 #define GL_SPRITE_MODE_SGIX 0x8149 #define GL_SPRITE_AXIS_SGIX 0x814A #define GL_SPRITE_TRANSLATION_SGIX 0x814B #define GL_SPRITE_AXIAL_SGIX 0x814C #define GL_SPRITE_OBJECT_ALIGNED_SGIX 0x814D #define GL_SPRITE_EYE_ALIGNED_SGIX 0x814E #endif #ifndef GL_SGIX_texture_multi_buffer #define GL_TEXTURE_MULTI_BUFFER_HINT_SGIX 0x812E #endif #ifndef GL_EXT_point_parameters #define GL_POINT_SIZE_MIN_EXT 0x8126 #define GL_POINT_SIZE_MAX_EXT 0x8127 #define GL_POINT_FADE_THRESHOLD_SIZE_EXT 0x8128 #define GL_DISTANCE_ATTENUATION_EXT 0x8129 #endif #ifndef GL_SGIS_point_parameters #define GL_POINT_SIZE_MIN_SGIS 0x8126 #define GL_POINT_SIZE_MAX_SGIS 0x8127 #define GL_POINT_FADE_THRESHOLD_SIZE_SGIS 0x8128 #define GL_DISTANCE_ATTENUATION_SGIS 0x8129 #endif #ifndef GL_SGIX_instruments #define GL_INSTRUMENT_BUFFER_POINTER_SGIX 0x8180 #define GL_INSTRUMENT_MEASUREMENTS_SGIX 0x8181 #endif #ifndef GL_SGIX_texture_scale_bias #define GL_POST_TEXTURE_FILTER_BIAS_SGIX 0x8179 #define GL_POST_TEXTURE_FILTER_SCALE_SGIX 0x817A #define GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX 0x817B #define GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX 0x817C #endif #ifndef GL_SGIX_framezoom #define GL_FRAMEZOOM_SGIX 0x818B #define GL_FRAMEZOOM_FACTOR_SGIX 0x818C #define GL_MAX_FRAMEZOOM_FACTOR_SGIX 0x818D #endif #ifndef GL_SGIX_tag_sample_buffer #endif #ifndef GL_FfdMaskSGIX #define GL_TEXTURE_DEFORMATION_BIT_SGIX 0x00000001 #define GL_GEOMETRY_DEFORMATION_BIT_SGIX 0x00000002 #endif #ifndef GL_SGIX_polynomial_ffd #define GL_GEOMETRY_DEFORMATION_SGIX 0x8194 #define GL_TEXTURE_DEFORMATION_SGIX 0x8195 #define GL_DEFORMATIONS_MASK_SGIX 0x8196 #define GL_MAX_DEFORMATION_ORDER_SGIX 0x8197 #endif #ifndef GL_SGIX_reference_plane #define GL_REFERENCE_PLANE_SGIX 0x817D #define GL_REFERENCE_PLANE_EQUATION_SGIX 0x817E #endif #ifndef GL_SGIX_flush_raster #endif #ifndef GL_SGIX_depth_texture #define GL_DEPTH_COMPONENT16_SGIX 0x81A5 #define GL_DEPTH_COMPONENT24_SGIX 0x81A6 #define GL_DEPTH_COMPONENT32_SGIX 0x81A7 #endif #ifndef GL_SGIS_fog_function #define GL_FOG_FUNC_SGIS 0x812A #define GL_FOG_FUNC_POINTS_SGIS 0x812B #define GL_MAX_FOG_FUNC_POINTS_SGIS 0x812C #endif #ifndef GL_SGIX_fog_offset #define GL_FOG_OFFSET_SGIX 0x8198 #define GL_FOG_OFFSET_VALUE_SGIX 0x8199 #endif #ifndef GL_HP_image_transform #define GL_IMAGE_SCALE_X_HP 0x8155 #define GL_IMAGE_SCALE_Y_HP 0x8156 #define GL_IMAGE_TRANSLATE_X_HP 0x8157 #define GL_IMAGE_TRANSLATE_Y_HP 0x8158 #define GL_IMAGE_ROTATE_ANGLE_HP 0x8159 #define GL_IMAGE_ROTATE_ORIGIN_X_HP 0x815A #define GL_IMAGE_ROTATE_ORIGIN_Y_HP 0x815B #define GL_IMAGE_MAG_FILTER_HP 0x815C #define GL_IMAGE_MIN_FILTER_HP 0x815D #define GL_IMAGE_CUBIC_WEIGHT_HP 0x815E #define GL_CUBIC_HP 0x815F #define GL_AVERAGE_HP 0x8160 #define GL_IMAGE_TRANSFORM_2D_HP 0x8161 #define GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8162 #define GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8163 #endif #ifndef GL_HP_convolution_border_modes #define GL_IGNORE_BORDER_HP 0x8150 #define GL_CONSTANT_BORDER_HP 0x8151 #define GL_REPLICATE_BORDER_HP 0x8153 #define GL_CONVOLUTION_BORDER_COLOR_HP 0x8154 #endif #ifndef GL_INGR_palette_buffer #endif #ifndef GL_SGIX_texture_add_env #define GL_TEXTURE_ENV_BIAS_SGIX 0x80BE #endif #ifndef GL_EXT_color_subtable #endif #ifndef GL_PGI_vertex_hints #define GL_VERTEX_DATA_HINT_PGI 0x1A22A #define GL_VERTEX_CONSISTENT_HINT_PGI 0x1A22B #define GL_MATERIAL_SIDE_HINT_PGI 0x1A22C #define GL_MAX_VERTEX_HINT_PGI 0x1A22D #define GL_COLOR3_BIT_PGI 0x00010000 #define GL_COLOR4_BIT_PGI 0x00020000 #define GL_EDGEFLAG_BIT_PGI 0x00040000 #define GL_INDEX_BIT_PGI 0x00080000 #define GL_MAT_AMBIENT_BIT_PGI 0x00100000 #define GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI 0x00200000 #define GL_MAT_DIFFUSE_BIT_PGI 0x00400000 #define GL_MAT_EMISSION_BIT_PGI 0x00800000 #define GL_MAT_COLOR_INDEXES_BIT_PGI 0x01000000 #define GL_MAT_SHININESS_BIT_PGI 0x02000000 #define GL_MAT_SPECULAR_BIT_PGI 0x04000000 #define GL_NORMAL_BIT_PGI 0x08000000 #define GL_TEXCOORD1_BIT_PGI 0x10000000 #define GL_TEXCOORD2_BIT_PGI 0x20000000 #define GL_TEXCOORD3_BIT_PGI 0x40000000 #define GL_TEXCOORD4_BIT_PGI 0x80000000 #define GL_VERTEX23_BIT_PGI 0x00000004 #define GL_VERTEX4_BIT_PGI 0x00000008 #endif #ifndef GL_PGI_misc_hints #define GL_PREFER_DOUBLEBUFFER_HINT_PGI 0x1A1F8 #define GL_CONSERVE_MEMORY_HINT_PGI 0x1A1FD #define GL_RECLAIM_MEMORY_HINT_PGI 0x1A1FE #define GL_NATIVE_GRAPHICS_HANDLE_PGI 0x1A202 #define GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI 0x1A203 #define GL_NATIVE_GRAPHICS_END_HINT_PGI 0x1A204 #define GL_ALWAYS_FAST_HINT_PGI 0x1A20C #define GL_ALWAYS_SOFT_HINT_PGI 0x1A20D #define GL_ALLOW_DRAW_OBJ_HINT_PGI 0x1A20E #define GL_ALLOW_DRAW_WIN_HINT_PGI 0x1A20F #define GL_ALLOW_DRAW_FRG_HINT_PGI 0x1A210 #define GL_ALLOW_DRAW_MEM_HINT_PGI 0x1A211 #define GL_STRICT_DEPTHFUNC_HINT_PGI 0x1A216 #define GL_STRICT_LIGHTING_HINT_PGI 0x1A217 #define GL_STRICT_SCISSOR_HINT_PGI 0x1A218 #define GL_FULL_STIPPLE_HINT_PGI 0x1A219 #define GL_CLIP_NEAR_HINT_PGI 0x1A220 #define GL_CLIP_FAR_HINT_PGI 0x1A221 #define GL_WIDE_LINE_HINT_PGI 0x1A222 #define GL_BACK_NORMALS_HINT_PGI 0x1A223 #endif #ifndef GL_EXT_paletted_texture #define GL_COLOR_INDEX1_EXT 0x80E2 #define GL_COLOR_INDEX2_EXT 0x80E3 #define GL_COLOR_INDEX4_EXT 0x80E4 #define GL_COLOR_INDEX8_EXT 0x80E5 #define GL_COLOR_INDEX12_EXT 0x80E6 #define GL_COLOR_INDEX16_EXT 0x80E7 #define GL_TEXTURE_INDEX_SIZE_EXT 0x80ED #endif #ifndef GL_EXT_clip_volume_hint #define GL_CLIP_VOLUME_CLIPPING_HINT_EXT 0x80F0 #endif #ifndef GL_SGIX_list_priority #define GL_LIST_PRIORITY_SGIX 0x8182 #endif #ifndef GL_SGIX_ir_instrument1 #define GL_IR_INSTRUMENT1_SGIX 0x817F #endif #ifndef GL_SGIX_calligraphic_fragment #define GL_CALLIGRAPHIC_FRAGMENT_SGIX 0x8183 #endif #ifndef GL_SGIX_texture_lod_bias #define GL_TEXTURE_LOD_BIAS_S_SGIX 0x818E #define GL_TEXTURE_LOD_BIAS_T_SGIX 0x818F #define GL_TEXTURE_LOD_BIAS_R_SGIX 0x8190 #endif #ifndef GL_SGIX_shadow_ambient #define GL_SHADOW_AMBIENT_SGIX 0x80BF #endif #ifndef GL_EXT_index_texture #endif #ifndef GL_EXT_index_material #define GL_INDEX_MATERIAL_EXT 0x81B8 #define GL_INDEX_MATERIAL_PARAMETER_EXT 0x81B9 #define GL_INDEX_MATERIAL_FACE_EXT 0x81BA #endif #ifndef GL_EXT_index_func #define GL_INDEX_TEST_EXT 0x81B5 #define GL_INDEX_TEST_FUNC_EXT 0x81B6 #define GL_INDEX_TEST_REF_EXT 0x81B7 #endif #ifndef GL_EXT_index_array_formats #define GL_IUI_V2F_EXT 0x81AD #define GL_IUI_V3F_EXT 0x81AE #define GL_IUI_N3F_V2F_EXT 0x81AF #define GL_IUI_N3F_V3F_EXT 0x81B0 #define GL_T2F_IUI_V2F_EXT 0x81B1 #define GL_T2F_IUI_V3F_EXT 0x81B2 #define GL_T2F_IUI_N3F_V2F_EXT 0x81B3 #define GL_T2F_IUI_N3F_V3F_EXT 0x81B4 #endif #ifndef GL_EXT_compiled_vertex_array #define GL_ARRAY_ELEMENT_LOCK_FIRST_EXT 0x81A8 #define GL_ARRAY_ELEMENT_LOCK_COUNT_EXT 0x81A9 #endif #ifndef GL_EXT_cull_vertex #define GL_CULL_VERTEX_EXT 0x81AA #define GL_CULL_VERTEX_EYE_POSITION_EXT 0x81AB #define GL_CULL_VERTEX_OBJECT_POSITION_EXT 0x81AC #endif #ifndef GL_SGIX_ycrcb #define GL_YCRCB_422_SGIX 0x81BB #define GL_YCRCB_444_SGIX 0x81BC #endif #ifndef GL_SGIX_fragment_lighting #define GL_FRAGMENT_LIGHTING_SGIX 0x8400 #define GL_FRAGMENT_COLOR_MATERIAL_SGIX 0x8401 #define GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX 0x8402 #define GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX 0x8403 #define GL_MAX_FRAGMENT_LIGHTS_SGIX 0x8404 #define GL_MAX_ACTIVE_LIGHTS_SGIX 0x8405 #define GL_CURRENT_RASTER_NORMAL_SGIX 0x8406 #define GL_LIGHT_ENV_MODE_SGIX 0x8407 #define GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX 0x8408 #define GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX 0x8409 #define GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX 0x840A #define GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX 0x840B #define GL_FRAGMENT_LIGHT0_SGIX 0x840C #define GL_FRAGMENT_LIGHT1_SGIX 0x840D #define GL_FRAGMENT_LIGHT2_SGIX 0x840E #define GL_FRAGMENT_LIGHT3_SGIX 0x840F #define GL_FRAGMENT_LIGHT4_SGIX 0x8410 #define GL_FRAGMENT_LIGHT5_SGIX 0x8411 #define GL_FRAGMENT_LIGHT6_SGIX 0x8412 #define GL_FRAGMENT_LIGHT7_SGIX 0x8413 #endif #ifndef GL_IBM_rasterpos_clip #define GL_RASTER_POSITION_UNCLIPPED_IBM 0x19262 #endif #ifndef GL_HP_texture_lighting #define GL_TEXTURE_LIGHTING_MODE_HP 0x8167 #define GL_TEXTURE_POST_SPECULAR_HP 0x8168 #define GL_TEXTURE_PRE_SPECULAR_HP 0x8169 #endif #ifndef GL_EXT_draw_range_elements #define GL_MAX_ELEMENTS_VERTICES_EXT 0x80E8 #define GL_MAX_ELEMENTS_INDICES_EXT 0x80E9 #endif #ifndef GL_WIN_phong_shading #define GL_PHONG_WIN 0x80EA #define GL_PHONG_HINT_WIN 0x80EB #endif #ifndef GL_WIN_specular_fog #define GL_FOG_SPECULAR_TEXTURE_WIN 0x80EC #endif #ifndef GL_EXT_light_texture #define GL_FRAGMENT_MATERIAL_EXT 0x8349 #define GL_FRAGMENT_NORMAL_EXT 0x834A #define GL_FRAGMENT_COLOR_EXT 0x834C #define GL_ATTENUATION_EXT 0x834D #define GL_SHADOW_ATTENUATION_EXT 0x834E #define GL_TEXTURE_APPLICATION_MODE_EXT 0x834F #define GL_TEXTURE_LIGHT_EXT 0x8350 #define GL_TEXTURE_MATERIAL_FACE_EXT 0x8351 #define GL_TEXTURE_MATERIAL_PARAMETER_EXT 0x8352 /* reuse GL_FRAGMENT_DEPTH_EXT */ #endif #ifndef GL_SGIX_blend_alpha_minmax #define GL_ALPHA_MIN_SGIX 0x8320 #define GL_ALPHA_MAX_SGIX 0x8321 #endif #ifndef GL_SGIX_impact_pixel_texture #define GL_PIXEL_TEX_GEN_Q_CEILING_SGIX 0x8184 #define GL_PIXEL_TEX_GEN_Q_ROUND_SGIX 0x8185 #define GL_PIXEL_TEX_GEN_Q_FLOOR_SGIX 0x8186 #define GL_PIXEL_TEX_GEN_ALPHA_REPLACE_SGIX 0x8187 #define GL_PIXEL_TEX_GEN_ALPHA_NO_REPLACE_SGIX 0x8188 #define GL_PIXEL_TEX_GEN_ALPHA_LS_SGIX 0x8189 #define GL_PIXEL_TEX_GEN_ALPHA_MS_SGIX 0x818A #endif #ifndef GL_EXT_bgra #define GL_BGR_EXT 0x80E0 #define GL_BGRA_EXT 0x80E1 #endif #ifndef GL_SGIX_async #define GL_ASYNC_MARKER_SGIX 0x8329 #endif #ifndef GL_SGIX_async_pixel #define GL_ASYNC_TEX_IMAGE_SGIX 0x835C #define GL_ASYNC_DRAW_PIXELS_SGIX 0x835D #define GL_ASYNC_READ_PIXELS_SGIX 0x835E #define GL_MAX_ASYNC_TEX_IMAGE_SGIX 0x835F #define GL_MAX_ASYNC_DRAW_PIXELS_SGIX 0x8360 #define GL_MAX_ASYNC_READ_PIXELS_SGIX 0x8361 #endif #ifndef GL_SGIX_async_histogram #define GL_ASYNC_HISTOGRAM_SGIX 0x832C #define GL_MAX_ASYNC_HISTOGRAM_SGIX 0x832D #endif #ifndef GL_INTEL_texture_scissor #endif #ifndef GL_INTEL_parallel_arrays #define GL_PARALLEL_ARRAYS_INTEL 0x83F4 #define GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL 0x83F5 #define GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6 #define GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7 #define GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8 #endif #ifndef GL_HP_occlusion_test #define GL_OCCLUSION_TEST_HP 0x8165 #define GL_OCCLUSION_TEST_RESULT_HP 0x8166 #endif #ifndef GL_EXT_pixel_transform #define GL_PIXEL_TRANSFORM_2D_EXT 0x8330 #define GL_PIXEL_MAG_FILTER_EXT 0x8331 #define GL_PIXEL_MIN_FILTER_EXT 0x8332 #define GL_PIXEL_CUBIC_WEIGHT_EXT 0x8333 #define GL_CUBIC_EXT 0x8334 #define GL_AVERAGE_EXT 0x8335 #define GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8336 #define GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8337 #define GL_PIXEL_TRANSFORM_2D_MATRIX_EXT 0x8338 #endif #ifndef GL_EXT_pixel_transform_color_table #endif #ifndef GL_EXT_shared_texture_palette #define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB #endif #ifndef GL_EXT_separate_specular_color #define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 #define GL_SINGLE_COLOR_EXT 0x81F9 #define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA #endif #ifndef GL_EXT_secondary_color #define GL_COLOR_SUM_EXT 0x8458 #define GL_CURRENT_SECONDARY_COLOR_EXT 0x8459 #define GL_SECONDARY_COLOR_ARRAY_SIZE_EXT 0x845A #define GL_SECONDARY_COLOR_ARRAY_TYPE_EXT 0x845B #define GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT 0x845C #define GL_SECONDARY_COLOR_ARRAY_POINTER_EXT 0x845D #define GL_SECONDARY_COLOR_ARRAY_EXT 0x845E #endif #ifndef GL_EXT_texture_perturb_normal #define GL_PERTURB_EXT 0x85AE #define GL_TEXTURE_NORMAL_EXT 0x85AF #endif #ifndef GL_EXT_multi_draw_arrays #endif #ifndef GL_EXT_fog_coord #define GL_FOG_COORDINATE_SOURCE_EXT 0x8450 #define GL_FOG_COORDINATE_EXT 0x8451 #define GL_FRAGMENT_DEPTH_EXT 0x8452 #define GL_CURRENT_FOG_COORDINATE_EXT 0x8453 #define GL_FOG_COORDINATE_ARRAY_TYPE_EXT 0x8454 #define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455 #define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456 #define GL_FOG_COORDINATE_ARRAY_EXT 0x8457 #endif #ifndef GL_REND_screen_coordinates #define GL_SCREEN_COORDINATES_REND 0x8490 #define GL_INVERTED_SCREEN_W_REND 0x8491 #endif #ifndef GL_EXT_coordinate_frame #define GL_TANGENT_ARRAY_EXT 0x8439 #define GL_BINORMAL_ARRAY_EXT 0x843A #define GL_CURRENT_TANGENT_EXT 0x843B #define GL_CURRENT_BINORMAL_EXT 0x843C #define GL_TANGENT_ARRAY_TYPE_EXT 0x843E #define GL_TANGENT_ARRAY_STRIDE_EXT 0x843F #define GL_BINORMAL_ARRAY_TYPE_EXT 0x8440 #define GL_BINORMAL_ARRAY_STRIDE_EXT 0x8441 #define GL_TANGENT_ARRAY_POINTER_EXT 0x8442 #define GL_BINORMAL_ARRAY_POINTER_EXT 0x8443 #define GL_MAP1_TANGENT_EXT 0x8444 #define GL_MAP2_TANGENT_EXT 0x8445 #define GL_MAP1_BINORMAL_EXT 0x8446 #define GL_MAP2_BINORMAL_EXT 0x8447 #endif #ifndef GL_EXT_texture_env_combine #define GL_COMBINE_EXT 0x8570 #define GL_COMBINE_RGB_EXT 0x8571 #define GL_COMBINE_ALPHA_EXT 0x8572 #define GL_RGB_SCALE_EXT 0x8573 #define GL_ADD_SIGNED_EXT 0x8574 #define GL_INTERPOLATE_EXT 0x8575 #define GL_CONSTANT_EXT 0x8576 #define GL_PRIMARY_COLOR_EXT 0x8577 #define GL_PREVIOUS_EXT 0x8578 #define GL_SOURCE0_RGB_EXT 0x8580 #define GL_SOURCE1_RGB_EXT 0x8581 #define GL_SOURCE2_RGB_EXT 0x8582 #define GL_SOURCE0_ALPHA_EXT 0x8588 #define GL_SOURCE1_ALPHA_EXT 0x8589 #define GL_SOURCE2_ALPHA_EXT 0x858A #define GL_OPERAND0_RGB_EXT 0x8590 #define GL_OPERAND1_RGB_EXT 0x8591 #define GL_OPERAND2_RGB_EXT 0x8592 #define GL_OPERAND0_ALPHA_EXT 0x8598 #define GL_OPERAND1_ALPHA_EXT 0x8599 #define GL_OPERAND2_ALPHA_EXT 0x859A #endif #ifndef GL_APPLE_specular_vector #define GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE 0x85B0 #endif #ifndef GL_APPLE_transform_hint #define GL_TRANSFORM_HINT_APPLE 0x85B1 #endif #ifndef GL_SGIX_fog_scale #define GL_FOG_SCALE_SGIX 0x81FC #define GL_FOG_SCALE_VALUE_SGIX 0x81FD #endif #ifndef GL_SUNX_constant_data #define GL_UNPACK_CONSTANT_DATA_SUNX 0x81D5 #define GL_TEXTURE_CONSTANT_DATA_SUNX 0x81D6 #endif #ifndef GL_SUN_global_alpha #define GL_GLOBAL_ALPHA_SUN 0x81D9 #define GL_GLOBAL_ALPHA_FACTOR_SUN 0x81DA #endif #ifndef GL_SUN_triangle_list #define GL_RESTART_SUN 0x0001 #define GL_REPLACE_MIDDLE_SUN 0x0002 #define GL_REPLACE_OLDEST_SUN 0x0003 #define GL_TRIANGLE_LIST_SUN 0x81D7 #define GL_REPLACEMENT_CODE_SUN 0x81D8 #define GL_REPLACEMENT_CODE_ARRAY_SUN 0x85C0 #define GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1 #define GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2 #define GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3 #define GL_R1UI_V3F_SUN 0x85C4 #define GL_R1UI_C4UB_V3F_SUN 0x85C5 #define GL_R1UI_C3F_V3F_SUN 0x85C6 #define GL_R1UI_N3F_V3F_SUN 0x85C7 #define GL_R1UI_C4F_N3F_V3F_SUN 0x85C8 #define GL_R1UI_T2F_V3F_SUN 0x85C9 #define GL_R1UI_T2F_N3F_V3F_SUN 0x85CA #define GL_R1UI_T2F_C4F_N3F_V3F_SUN 0x85CB #endif #ifndef GL_SUN_vertex #endif #ifndef GL_EXT_blend_func_separate #define GL_BLEND_DST_RGB_EXT 0x80C8 #define GL_BLEND_SRC_RGB_EXT 0x80C9 #define GL_BLEND_DST_ALPHA_EXT 0x80CA #define GL_BLEND_SRC_ALPHA_EXT 0x80CB #endif #ifndef GL_INGR_color_clamp #define GL_RED_MIN_CLAMP_INGR 0x8560 #define GL_GREEN_MIN_CLAMP_INGR 0x8561 #define GL_BLUE_MIN_CLAMP_INGR 0x8562 #define GL_ALPHA_MIN_CLAMP_INGR 0x8563 #define GL_RED_MAX_CLAMP_INGR 0x8564 #define GL_GREEN_MAX_CLAMP_INGR 0x8565 #define GL_BLUE_MAX_CLAMP_INGR 0x8566 #define GL_ALPHA_MAX_CLAMP_INGR 0x8567 #endif #ifndef GL_INGR_interlace_read #define GL_INTERLACE_READ_INGR 0x8568 #endif #ifndef GL_EXT_stencil_wrap #define GL_INCR_WRAP_EXT 0x8507 #define GL_DECR_WRAP_EXT 0x8508 #endif #ifndef GL_EXT_422_pixels #define GL_422_EXT 0x80CC #define GL_422_REV_EXT 0x80CD #define GL_422_AVERAGE_EXT 0x80CE #define GL_422_REV_AVERAGE_EXT 0x80CF #endif #ifndef GL_NV_texgen_reflection #define GL_NORMAL_MAP_NV 0x8511 #define GL_REFLECTION_MAP_NV 0x8512 #endif #ifndef GL_EXT_texture_cube_map #define GL_NORMAL_MAP_EXT 0x8511 #define GL_REFLECTION_MAP_EXT 0x8512 #define GL_TEXTURE_CUBE_MAP_EXT 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP_EXT 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A #define GL_PROXY_TEXTURE_CUBE_MAP_EXT 0x851B #define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT 0x851C #endif #ifndef GL_SUN_convolution_border_modes #define GL_WRAP_BORDER_SUN 0x81D4 #endif #ifndef GL_EXT_texture_env_add #endif #ifndef GL_EXT_texture_lod_bias #define GL_MAX_TEXTURE_LOD_BIAS_EXT 0x84FD #define GL_TEXTURE_FILTER_CONTROL_EXT 0x8500 #define GL_TEXTURE_LOD_BIAS_EXT 0x8501 #endif #ifndef GL_EXT_texture_filter_anisotropic #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF #endif #ifndef GL_EXT_vertex_weighting #define GL_MODELVIEW0_STACK_DEPTH_EXT GL_MODELVIEW_STACK_DEPTH #define GL_MODELVIEW1_STACK_DEPTH_EXT 0x8502 #define GL_MODELVIEW0_MATRIX_EXT GL_MODELVIEW_MATRIX #define GL_MODELVIEW1_MATRIX_EXT 0x8506 #define GL_VERTEX_WEIGHTING_EXT 0x8509 #define GL_MODELVIEW0_EXT GL_MODELVIEW #define GL_MODELVIEW1_EXT 0x850A #define GL_CURRENT_VERTEX_WEIGHT_EXT 0x850B #define GL_VERTEX_WEIGHT_ARRAY_EXT 0x850C #define GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT 0x850D #define GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT 0x850E #define GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F #define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510 #endif #ifndef GL_NV_light_max_exponent #define GL_MAX_SHININESS_NV 0x8504 #define GL_MAX_SPOT_EXPONENT_NV 0x8505 #endif #ifndef GL_NV_vertex_array_range #define GL_VERTEX_ARRAY_RANGE_NV 0x851D #define GL_VERTEX_ARRAY_RANGE_LENGTH_NV 0x851E #define GL_VERTEX_ARRAY_RANGE_VALID_NV 0x851F #define GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520 #define GL_VERTEX_ARRAY_RANGE_POINTER_NV 0x8521 #endif #ifndef GL_NV_register_combiners #define GL_REGISTER_COMBINERS_NV 0x8522 #define GL_VARIABLE_A_NV 0x8523 #define GL_VARIABLE_B_NV 0x8524 #define GL_VARIABLE_C_NV 0x8525 #define GL_VARIABLE_D_NV 0x8526 #define GL_VARIABLE_E_NV 0x8527 #define GL_VARIABLE_F_NV 0x8528 #define GL_VARIABLE_G_NV 0x8529 #define GL_CONSTANT_COLOR0_NV 0x852A #define GL_CONSTANT_COLOR1_NV 0x852B #define GL_PRIMARY_COLOR_NV 0x852C #define GL_SECONDARY_COLOR_NV 0x852D #define GL_SPARE0_NV 0x852E #define GL_SPARE1_NV 0x852F #define GL_DISCARD_NV 0x8530 #define GL_E_TIMES_F_NV 0x8531 #define GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532 #define GL_UNSIGNED_IDENTITY_NV 0x8536 #define GL_UNSIGNED_INVERT_NV 0x8537 #define GL_EXPAND_NORMAL_NV 0x8538 #define GL_EXPAND_NEGATE_NV 0x8539 #define GL_HALF_BIAS_NORMAL_NV 0x853A #define GL_HALF_BIAS_NEGATE_NV 0x853B #define GL_SIGNED_IDENTITY_NV 0x853C #define GL_SIGNED_NEGATE_NV 0x853D #define GL_SCALE_BY_TWO_NV 0x853E #define GL_SCALE_BY_FOUR_NV 0x853F #define GL_SCALE_BY_ONE_HALF_NV 0x8540 #define GL_BIAS_BY_NEGATIVE_ONE_HALF_NV 0x8541 #define GL_COMBINER_INPUT_NV 0x8542 #define GL_COMBINER_MAPPING_NV 0x8543 #define GL_COMBINER_COMPONENT_USAGE_NV 0x8544 #define GL_COMBINER_AB_DOT_PRODUCT_NV 0x8545 #define GL_COMBINER_CD_DOT_PRODUCT_NV 0x8546 #define GL_COMBINER_MUX_SUM_NV 0x8547 #define GL_COMBINER_SCALE_NV 0x8548 #define GL_COMBINER_BIAS_NV 0x8549 #define GL_COMBINER_AB_OUTPUT_NV 0x854A #define GL_COMBINER_CD_OUTPUT_NV 0x854B #define GL_COMBINER_SUM_OUTPUT_NV 0x854C #define GL_MAX_GENERAL_COMBINERS_NV 0x854D #define GL_NUM_GENERAL_COMBINERS_NV 0x854E #define GL_COLOR_SUM_CLAMP_NV 0x854F #define GL_COMBINER0_NV 0x8550 #define GL_COMBINER1_NV 0x8551 #define GL_COMBINER2_NV 0x8552 #define GL_COMBINER3_NV 0x8553 #define GL_COMBINER4_NV 0x8554 #define GL_COMBINER5_NV 0x8555 #define GL_COMBINER6_NV 0x8556 #define GL_COMBINER7_NV 0x8557 /* reuse GL_TEXTURE0_ARB */ /* reuse GL_TEXTURE1_ARB */ /* reuse GL_ZERO */ /* reuse GL_NONE */ /* reuse GL_FOG */ #endif #ifndef GL_NV_fog_distance #define GL_FOG_DISTANCE_MODE_NV 0x855A #define GL_EYE_RADIAL_NV 0x855B #define GL_EYE_PLANE_ABSOLUTE_NV 0x855C /* reuse GL_EYE_PLANE */ #endif #ifndef GL_NV_texgen_emboss #define GL_EMBOSS_LIGHT_NV 0x855D #define GL_EMBOSS_CONSTANT_NV 0x855E #define GL_EMBOSS_MAP_NV 0x855F #endif #ifndef GL_NV_blend_square #endif #ifndef GL_NV_texture_env_combine4 #define GL_COMBINE4_NV 0x8503 #define GL_SOURCE3_RGB_NV 0x8583 #define GL_SOURCE3_ALPHA_NV 0x858B #define GL_OPERAND3_RGB_NV 0x8593 #define GL_OPERAND3_ALPHA_NV 0x859B #endif #ifndef GL_MESA_resize_buffers #endif #ifndef GL_MESA_window_pos #endif #ifndef GL_EXT_texture_compression_s3tc #define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 #endif #ifndef GL_IBM_cull_vertex #define GL_CULL_VERTEX_IBM 103050 #endif #ifndef GL_IBM_multimode_draw_arrays #endif #ifndef GL_IBM_vertex_array_lists #define GL_VERTEX_ARRAY_LIST_IBM 103070 #define GL_NORMAL_ARRAY_LIST_IBM 103071 #define GL_COLOR_ARRAY_LIST_IBM 103072 #define GL_INDEX_ARRAY_LIST_IBM 103073 #define GL_TEXTURE_COORD_ARRAY_LIST_IBM 103074 #define GL_EDGE_FLAG_ARRAY_LIST_IBM 103075 #define GL_FOG_COORDINATE_ARRAY_LIST_IBM 103076 #define GL_SECONDARY_COLOR_ARRAY_LIST_IBM 103077 #define GL_VERTEX_ARRAY_LIST_STRIDE_IBM 103080 #define GL_NORMAL_ARRAY_LIST_STRIDE_IBM 103081 #define GL_COLOR_ARRAY_LIST_STRIDE_IBM 103082 #define GL_INDEX_ARRAY_LIST_STRIDE_IBM 103083 #define GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM 103084 #define GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085 #define GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086 #define GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087 #endif #ifndef GL_SGIX_subsample #define GL_PACK_SUBSAMPLE_RATE_SGIX 0x85A0 #define GL_UNPACK_SUBSAMPLE_RATE_SGIX 0x85A1 #define GL_PIXEL_SUBSAMPLE_4444_SGIX 0x85A2 #define GL_PIXEL_SUBSAMPLE_2424_SGIX 0x85A3 #define GL_PIXEL_SUBSAMPLE_4242_SGIX 0x85A4 #endif #ifndef GL_SGIX_ycrcb_subsample #endif #ifndef GL_SGIX_ycrcba #define GL_YCRCB_SGIX 0x8318 #define GL_YCRCBA_SGIX 0x8319 #endif #ifndef GL_SGI_depth_pass_instrument #define GL_DEPTH_PASS_INSTRUMENT_SGIX 0x8310 #define GL_DEPTH_PASS_INSTRUMENT_COUNTERS_SGIX 0x8311 #define GL_DEPTH_PASS_INSTRUMENT_MAX_SGIX 0x8312 #endif #ifndef GL_3DFX_texture_compression_FXT1 #define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0 #define GL_COMPRESSED_RGBA_FXT1_3DFX 0x86B1 #endif #ifndef GL_3DFX_multisample #define GL_MULTISAMPLE_3DFX 0x86B2 #define GL_SAMPLE_BUFFERS_3DFX 0x86B3 #define GL_SAMPLES_3DFX 0x86B4 #define GL_MULTISAMPLE_BIT_3DFX 0x20000000 #endif #ifndef GL_3DFX_tbuffer #endif #ifndef GL_EXT_multisample #define GL_MULTISAMPLE_EXT 0x809D #define GL_SAMPLE_ALPHA_TO_MASK_EXT 0x809E #define GL_SAMPLE_ALPHA_TO_ONE_EXT 0x809F #define GL_SAMPLE_MASK_EXT 0x80A0 #define GL_1PASS_EXT 0x80A1 #define GL_2PASS_0_EXT 0x80A2 #define GL_2PASS_1_EXT 0x80A3 #define GL_4PASS_0_EXT 0x80A4 #define GL_4PASS_1_EXT 0x80A5 #define GL_4PASS_2_EXT 0x80A6 #define GL_4PASS_3_EXT 0x80A7 #define GL_SAMPLE_BUFFERS_EXT 0x80A8 #define GL_SAMPLES_EXT 0x80A9 #define GL_SAMPLE_MASK_VALUE_EXT 0x80AA #define GL_SAMPLE_MASK_INVERT_EXT 0x80AB #define GL_SAMPLE_PATTERN_EXT 0x80AC #define GL_MULTISAMPLE_BIT_EXT 0x20000000 #endif #ifndef GL_SGIX_vertex_preclip #define GL_VERTEX_PRECLIP_SGIX 0x83EE #define GL_VERTEX_PRECLIP_HINT_SGIX 0x83EF #endif #ifndef GL_SGIX_convolution_accuracy #define GL_CONVOLUTION_HINT_SGIX 0x8316 #endif #ifndef GL_SGIX_resample #define GL_PACK_RESAMPLE_SGIX 0x842C #define GL_UNPACK_RESAMPLE_SGIX 0x842D #define GL_RESAMPLE_REPLICATE_SGIX 0x842E #define GL_RESAMPLE_ZERO_FILL_SGIX 0x842F #define GL_RESAMPLE_DECIMATE_SGIX 0x8430 #endif #ifndef GL_SGIS_point_line_texgen #define GL_EYE_DISTANCE_TO_POINT_SGIS 0x81F0 #define GL_OBJECT_DISTANCE_TO_POINT_SGIS 0x81F1 #define GL_EYE_DISTANCE_TO_LINE_SGIS 0x81F2 #define GL_OBJECT_DISTANCE_TO_LINE_SGIS 0x81F3 #define GL_EYE_POINT_SGIS 0x81F4 #define GL_OBJECT_POINT_SGIS 0x81F5 #define GL_EYE_LINE_SGIS 0x81F6 #define GL_OBJECT_LINE_SGIS 0x81F7 #endif #ifndef GL_SGIS_texture_color_mask #define GL_TEXTURE_COLOR_WRITEMASK_SGIS 0x81EF #endif #ifndef GL_EXT_texture_env_dot3 #define GL_DOT3_RGB_EXT 0x8740 #define GL_DOT3_RGBA_EXT 0x8741 #endif #ifndef GL_ATI_texture_mirror_once #define GL_MIRROR_CLAMP_ATI 0x8742 #define GL_MIRROR_CLAMP_TO_EDGE_ATI 0x8743 #endif #ifndef GL_NV_fence #define GL_ALL_COMPLETED_NV 0x84F2 #define GL_FENCE_STATUS_NV 0x84F3 #define GL_FENCE_CONDITION_NV 0x84F4 #endif #ifndef GL_IBM_texture_mirrored_repeat #define GL_MIRRORED_REPEAT_IBM 0x8370 #endif #ifndef GL_NV_evaluators #define GL_EVAL_2D_NV 0x86C0 #define GL_EVAL_TRIANGULAR_2D_NV 0x86C1 #define GL_MAP_TESSELLATION_NV 0x86C2 #define GL_MAP_ATTRIB_U_ORDER_NV 0x86C3 #define GL_MAP_ATTRIB_V_ORDER_NV 0x86C4 #define GL_EVAL_FRACTIONAL_TESSELLATION_NV 0x86C5 #define GL_EVAL_VERTEX_ATTRIB0_NV 0x86C6 #define GL_EVAL_VERTEX_ATTRIB1_NV 0x86C7 #define GL_EVAL_VERTEX_ATTRIB2_NV 0x86C8 #define GL_EVAL_VERTEX_ATTRIB3_NV 0x86C9 #define GL_EVAL_VERTEX_ATTRIB4_NV 0x86CA #define GL_EVAL_VERTEX_ATTRIB5_NV 0x86CB #define GL_EVAL_VERTEX_ATTRIB6_NV 0x86CC #define GL_EVAL_VERTEX_ATTRIB7_NV 0x86CD #define GL_EVAL_VERTEX_ATTRIB8_NV 0x86CE #define GL_EVAL_VERTEX_ATTRIB9_NV 0x86CF #define GL_EVAL_VERTEX_ATTRIB10_NV 0x86D0 #define GL_EVAL_VERTEX_ATTRIB11_NV 0x86D1 #define GL_EVAL_VERTEX_ATTRIB12_NV 0x86D2 #define GL_EVAL_VERTEX_ATTRIB13_NV 0x86D3 #define GL_EVAL_VERTEX_ATTRIB14_NV 0x86D4 #define GL_EVAL_VERTEX_ATTRIB15_NV 0x86D5 #define GL_MAX_MAP_TESSELLATION_NV 0x86D6 #define GL_MAX_RATIONAL_EVAL_ORDER_NV 0x86D7 #endif #ifndef GL_NV_packed_depth_stencil #define GL_DEPTH_STENCIL_NV 0x84F9 #define GL_UNSIGNED_INT_24_8_NV 0x84FA #endif #ifndef GL_NV_register_combiners2 #define GL_PER_STAGE_CONSTANTS_NV 0x8535 #endif #ifndef GL_NV_texture_compression_vtc #endif #ifndef GL_NV_texture_rectangle #define GL_TEXTURE_RECTANGLE_NV 0x84F5 #define GL_TEXTURE_BINDING_RECTANGLE_NV 0x84F6 #define GL_PROXY_TEXTURE_RECTANGLE_NV 0x84F7 #define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV 0x84F8 #endif #ifndef GL_NV_texture_shader #define GL_OFFSET_TEXTURE_RECTANGLE_NV 0x864C #define GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV 0x864D #define GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV 0x864E #define GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV 0x86D9 #define GL_UNSIGNED_INT_S8_S8_8_8_NV 0x86DA #define GL_UNSIGNED_INT_8_8_S8_S8_REV_NV 0x86DB #define GL_DSDT_MAG_INTENSITY_NV 0x86DC #define GL_SHADER_CONSISTENT_NV 0x86DD #define GL_TEXTURE_SHADER_NV 0x86DE #define GL_SHADER_OPERATION_NV 0x86DF #define GL_CULL_MODES_NV 0x86E0 #define GL_OFFSET_TEXTURE_MATRIX_NV 0x86E1 #define GL_OFFSET_TEXTURE_SCALE_NV 0x86E2 #define GL_OFFSET_TEXTURE_BIAS_NV 0x86E3 #define GL_OFFSET_TEXTURE_2D_MATRIX_NV GL_OFFSET_TEXTURE_MATRIX_NV #define GL_OFFSET_TEXTURE_2D_SCALE_NV GL_OFFSET_TEXTURE_SCALE_NV #define GL_OFFSET_TEXTURE_2D_BIAS_NV GL_OFFSET_TEXTURE_BIAS_NV #define GL_PREVIOUS_TEXTURE_INPUT_NV 0x86E4 #define GL_CONST_EYE_NV 0x86E5 #define GL_PASS_THROUGH_NV 0x86E6 #define GL_CULL_FRAGMENT_NV 0x86E7 #define GL_OFFSET_TEXTURE_2D_NV 0x86E8 #define GL_DEPENDENT_AR_TEXTURE_2D_NV 0x86E9 #define GL_DEPENDENT_GB_TEXTURE_2D_NV 0x86EA #define GL_DOT_PRODUCT_NV 0x86EC #define GL_DOT_PRODUCT_DEPTH_REPLACE_NV 0x86ED #define GL_DOT_PRODUCT_TEXTURE_2D_NV 0x86EE #define GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV 0x86F0 #define GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV 0x86F1 #define GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV 0x86F2 #define GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV 0x86F3 #define GL_HILO_NV 0x86F4 #define GL_DSDT_NV 0x86F5 #define GL_DSDT_MAG_NV 0x86F6 #define GL_DSDT_MAG_VIB_NV 0x86F7 #define GL_HILO16_NV 0x86F8 #define GL_SIGNED_HILO_NV 0x86F9 #define GL_SIGNED_HILO16_NV 0x86FA #define GL_SIGNED_RGBA_NV 0x86FB #define GL_SIGNED_RGBA8_NV 0x86FC #define GL_SIGNED_RGB_NV 0x86FE #define GL_SIGNED_RGB8_NV 0x86FF #define GL_SIGNED_LUMINANCE_NV 0x8701 #define GL_SIGNED_LUMINANCE8_NV 0x8702 #define GL_SIGNED_LUMINANCE_ALPHA_NV 0x8703 #define GL_SIGNED_LUMINANCE8_ALPHA8_NV 0x8704 #define GL_SIGNED_ALPHA_NV 0x8705 #define GL_SIGNED_ALPHA8_NV 0x8706 #define GL_SIGNED_INTENSITY_NV 0x8707 #define GL_SIGNED_INTENSITY8_NV 0x8708 #define GL_DSDT8_NV 0x8709 #define GL_DSDT8_MAG8_NV 0x870A #define GL_DSDT8_MAG8_INTENSITY8_NV 0x870B #define GL_SIGNED_RGB_UNSIGNED_ALPHA_NV 0x870C #define GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D #define GL_HI_SCALE_NV 0x870E #define GL_LO_SCALE_NV 0x870F #define GL_DS_SCALE_NV 0x8710 #define GL_DT_SCALE_NV 0x8711 #define GL_MAGNITUDE_SCALE_NV 0x8712 #define GL_VIBRANCE_SCALE_NV 0x8713 #define GL_HI_BIAS_NV 0x8714 #define GL_LO_BIAS_NV 0x8715 #define GL_DS_BIAS_NV 0x8716 #define GL_DT_BIAS_NV 0x8717 #define GL_MAGNITUDE_BIAS_NV 0x8718 #define GL_VIBRANCE_BIAS_NV 0x8719 #define GL_TEXTURE_BORDER_VALUES_NV 0x871A #define GL_TEXTURE_HI_SIZE_NV 0x871B #define GL_TEXTURE_LO_SIZE_NV 0x871C #define GL_TEXTURE_DS_SIZE_NV 0x871D #define GL_TEXTURE_DT_SIZE_NV 0x871E #define GL_TEXTURE_MAG_SIZE_NV 0x871F #endif #ifndef GL_NV_texture_shader2 #define GL_DOT_PRODUCT_TEXTURE_3D_NV 0x86EF #endif #ifndef GL_NV_vertex_array_range2 #define GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533 #endif #ifndef GL_NV_vertex_program #define GL_VERTEX_PROGRAM_NV 0x8620 #define GL_VERTEX_STATE_PROGRAM_NV 0x8621 #define GL_ATTRIB_ARRAY_SIZE_NV 0x8623 #define GL_ATTRIB_ARRAY_STRIDE_NV 0x8624 #define GL_ATTRIB_ARRAY_TYPE_NV 0x8625 #define GL_CURRENT_ATTRIB_NV 0x8626 #define GL_PROGRAM_LENGTH_NV 0x8627 #define GL_PROGRAM_STRING_NV 0x8628 #define GL_MODELVIEW_PROJECTION_NV 0x8629 #define GL_IDENTITY_NV 0x862A #define GL_INVERSE_NV 0x862B #define GL_TRANSPOSE_NV 0x862C #define GL_INVERSE_TRANSPOSE_NV 0x862D #define GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV 0x862E #define GL_MAX_TRACK_MATRICES_NV 0x862F #define GL_MATRIX0_NV 0x8630 #define GL_MATRIX1_NV 0x8631 #define GL_MATRIX2_NV 0x8632 #define GL_MATRIX3_NV 0x8633 #define GL_MATRIX4_NV 0x8634 #define GL_MATRIX5_NV 0x8635 #define GL_MATRIX6_NV 0x8636 #define GL_MATRIX7_NV 0x8637 #define GL_CURRENT_MATRIX_STACK_DEPTH_NV 0x8640 #define GL_CURRENT_MATRIX_NV 0x8641 #define GL_VERTEX_PROGRAM_POINT_SIZE_NV 0x8642 #define GL_VERTEX_PROGRAM_TWO_SIDE_NV 0x8643 #define GL_PROGRAM_PARAMETER_NV 0x8644 #define GL_ATTRIB_ARRAY_POINTER_NV 0x8645 #define GL_PROGRAM_TARGET_NV 0x8646 #define GL_PROGRAM_RESIDENT_NV 0x8647 #define GL_TRACK_MATRIX_NV 0x8648 #define GL_TRACK_MATRIX_TRANSFORM_NV 0x8649 #define GL_VERTEX_PROGRAM_BINDING_NV 0x864A #define GL_PROGRAM_ERROR_POSITION_NV 0x864B #define GL_VERTEX_ATTRIB_ARRAY0_NV 0x8650 #define GL_VERTEX_ATTRIB_ARRAY1_NV 0x8651 #define GL_VERTEX_ATTRIB_ARRAY2_NV 0x8652 #define GL_VERTEX_ATTRIB_ARRAY3_NV 0x8653 #define GL_VERTEX_ATTRIB_ARRAY4_NV 0x8654 #define GL_VERTEX_ATTRIB_ARRAY5_NV 0x8655 #define GL_VERTEX_ATTRIB_ARRAY6_NV 0x8656 #define GL_VERTEX_ATTRIB_ARRAY7_NV 0x8657 #define GL_VERTEX_ATTRIB_ARRAY8_NV 0x8658 #define GL_VERTEX_ATTRIB_ARRAY9_NV 0x8659 #define GL_VERTEX_ATTRIB_ARRAY10_NV 0x865A #define GL_VERTEX_ATTRIB_ARRAY11_NV 0x865B #define GL_VERTEX_ATTRIB_ARRAY12_NV 0x865C #define GL_VERTEX_ATTRIB_ARRAY13_NV 0x865D #define GL_VERTEX_ATTRIB_ARRAY14_NV 0x865E #define GL_VERTEX_ATTRIB_ARRAY15_NV 0x865F #define GL_MAP1_VERTEX_ATTRIB0_4_NV 0x8660 #define GL_MAP1_VERTEX_ATTRIB1_4_NV 0x8661 #define GL_MAP1_VERTEX_ATTRIB2_4_NV 0x8662 #define GL_MAP1_VERTEX_ATTRIB3_4_NV 0x8663 #define GL_MAP1_VERTEX_ATTRIB4_4_NV 0x8664 #define GL_MAP1_VERTEX_ATTRIB5_4_NV 0x8665 #define GL_MAP1_VERTEX_ATTRIB6_4_NV 0x8666 #define GL_MAP1_VERTEX_ATTRIB7_4_NV 0x8667 #define GL_MAP1_VERTEX_ATTRIB8_4_NV 0x8668 #define GL_MAP1_VERTEX_ATTRIB9_4_NV 0x8669 #define GL_MAP1_VERTEX_ATTRIB10_4_NV 0x866A #define GL_MAP1_VERTEX_ATTRIB11_4_NV 0x866B #define GL_MAP1_VERTEX_ATTRIB12_4_NV 0x866C #define GL_MAP1_VERTEX_ATTRIB13_4_NV 0x866D #define GL_MAP1_VERTEX_ATTRIB14_4_NV 0x866E #define GL_MAP1_VERTEX_ATTRIB15_4_NV 0x866F #define GL_MAP2_VERTEX_ATTRIB0_4_NV 0x8670 #define GL_MAP2_VERTEX_ATTRIB1_4_NV 0x8671 #define GL_MAP2_VERTEX_ATTRIB2_4_NV 0x8672 #define GL_MAP2_VERTEX_ATTRIB3_4_NV 0x8673 #define GL_MAP2_VERTEX_ATTRIB4_4_NV 0x8674 #define GL_MAP2_VERTEX_ATTRIB5_4_NV 0x8675 #define GL_MAP2_VERTEX_ATTRIB6_4_NV 0x8676 #define GL_MAP2_VERTEX_ATTRIB7_4_NV 0x8677 #define GL_MAP2_VERTEX_ATTRIB8_4_NV 0x8678 #define GL_MAP2_VERTEX_ATTRIB9_4_NV 0x8679 #define GL_MAP2_VERTEX_ATTRIB10_4_NV 0x867A #define GL_MAP2_VERTEX_ATTRIB11_4_NV 0x867B #define GL_MAP2_VERTEX_ATTRIB12_4_NV 0x867C #define GL_MAP2_VERTEX_ATTRIB13_4_NV 0x867D #define GL_MAP2_VERTEX_ATTRIB14_4_NV 0x867E #define GL_MAP2_VERTEX_ATTRIB15_4_NV 0x867F #endif #ifndef GL_SGIX_texture_coordinate_clamp #define GL_TEXTURE_MAX_CLAMP_S_SGIX 0x8369 #define GL_TEXTURE_MAX_CLAMP_T_SGIX 0x836A #define GL_TEXTURE_MAX_CLAMP_R_SGIX 0x836B #endif #ifndef GL_SGIX_scalebias_hint #define GL_SCALEBIAS_HINT_SGIX 0x8322 #endif #ifndef GL_OML_interlace #define GL_INTERLACE_OML 0x8980 #define GL_INTERLACE_READ_OML 0x8981 #endif #ifndef GL_OML_subsample #define GL_FORMAT_SUBSAMPLE_24_24_OML 0x8982 #define GL_FORMAT_SUBSAMPLE_244_244_OML 0x8983 #endif #ifndef GL_OML_resample #define GL_PACK_RESAMPLE_OML 0x8984 #define GL_UNPACK_RESAMPLE_OML 0x8985 #define GL_RESAMPLE_REPLICATE_OML 0x8986 #define GL_RESAMPLE_ZERO_FILL_OML 0x8987 #define GL_RESAMPLE_AVERAGE_OML 0x8988 #define GL_RESAMPLE_DECIMATE_OML 0x8989 #endif #ifndef GL_NV_copy_depth_to_color #define GL_DEPTH_STENCIL_TO_RGBA_NV 0x886E #define GL_DEPTH_STENCIL_TO_BGRA_NV 0x886F #endif #ifndef GL_ATI_envmap_bumpmap #define GL_BUMP_ROT_MATRIX_ATI 0x8775 #define GL_BUMP_ROT_MATRIX_SIZE_ATI 0x8776 #define GL_BUMP_NUM_TEX_UNITS_ATI 0x8777 #define GL_BUMP_TEX_UNITS_ATI 0x8778 #define GL_DUDV_ATI 0x8779 #define GL_DU8DV8_ATI 0x877A #define GL_BUMP_ENVMAP_ATI 0x877B #define GL_BUMP_TARGET_ATI 0x877C #endif #ifndef GL_ATI_fragment_shader #define GL_FRAGMENT_SHADER_ATI 0x8920 #define GL_REG_0_ATI 0x8921 #define GL_REG_1_ATI 0x8922 #define GL_REG_2_ATI 0x8923 #define GL_REG_3_ATI 0x8924 #define GL_REG_4_ATI 0x8925 #define GL_REG_5_ATI 0x8926 #define GL_REG_6_ATI 0x8927 #define GL_REG_7_ATI 0x8928 #define GL_REG_8_ATI 0x8929 #define GL_REG_9_ATI 0x892A #define GL_REG_10_ATI 0x892B #define GL_REG_11_ATI 0x892C #define GL_REG_12_ATI 0x892D #define GL_REG_13_ATI 0x892E #define GL_REG_14_ATI 0x892F #define GL_REG_15_ATI 0x8930 #define GL_REG_16_ATI 0x8931 #define GL_REG_17_ATI 0x8932 #define GL_REG_18_ATI 0x8933 #define GL_REG_19_ATI 0x8934 #define GL_REG_20_ATI 0x8935 #define GL_REG_21_ATI 0x8936 #define GL_REG_22_ATI 0x8937 #define GL_REG_23_ATI 0x8938 #define GL_REG_24_ATI 0x8939 #define GL_REG_25_ATI 0x893A #define GL_REG_26_ATI 0x893B #define GL_REG_27_ATI 0x893C #define GL_REG_28_ATI 0x893D #define GL_REG_29_ATI 0x893E #define GL_REG_30_ATI 0x893F #define GL_REG_31_ATI 0x8940 #define GL_CON_0_ATI 0x8941 #define GL_CON_1_ATI 0x8942 #define GL_CON_2_ATI 0x8943 #define GL_CON_3_ATI 0x8944 #define GL_CON_4_ATI 0x8945 #define GL_CON_5_ATI 0x8946 #define GL_CON_6_ATI 0x8947 #define GL_CON_7_ATI 0x8948 #define GL_CON_8_ATI 0x8949 #define GL_CON_9_ATI 0x894A #define GL_CON_10_ATI 0x894B #define GL_CON_11_ATI 0x894C #define GL_CON_12_ATI 0x894D #define GL_CON_13_ATI 0x894E #define GL_CON_14_ATI 0x894F #define GL_CON_15_ATI 0x8950 #define GL_CON_16_ATI 0x8951 #define GL_CON_17_ATI 0x8952 #define GL_CON_18_ATI 0x8953 #define GL_CON_19_ATI 0x8954 #define GL_CON_20_ATI 0x8955 #define GL_CON_21_ATI 0x8956 #define GL_CON_22_ATI 0x8957 #define GL_CON_23_ATI 0x8958 #define GL_CON_24_ATI 0x8959 #define GL_CON_25_ATI 0x895A #define GL_CON_26_ATI 0x895B #define GL_CON_27_ATI 0x895C #define GL_CON_28_ATI 0x895D #define GL_CON_29_ATI 0x895E #define GL_CON_30_ATI 0x895F #define GL_CON_31_ATI 0x8960 #define GL_MOV_ATI 0x8961 #define GL_ADD_ATI 0x8963 #define GL_MUL_ATI 0x8964 #define GL_SUB_ATI 0x8965 #define GL_DOT3_ATI 0x8966 #define GL_DOT4_ATI 0x8967 #define GL_MAD_ATI 0x8968 #define GL_LERP_ATI 0x8969 #define GL_CND_ATI 0x896A #define GL_CND0_ATI 0x896B #define GL_DOT2_ADD_ATI 0x896C #define GL_SECONDARY_INTERPOLATOR_ATI 0x896D #define GL_NUM_FRAGMENT_REGISTERS_ATI 0x896E #define GL_NUM_FRAGMENT_CONSTANTS_ATI 0x896F #define GL_NUM_PASSES_ATI 0x8970 #define GL_NUM_INSTRUCTIONS_PER_PASS_ATI 0x8971 #define GL_NUM_INSTRUCTIONS_TOTAL_ATI 0x8972 #define GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973 #define GL_NUM_LOOPBACK_COMPONENTS_ATI 0x8974 #define GL_COLOR_ALPHA_PAIRING_ATI 0x8975 #define GL_SWIZZLE_STR_ATI 0x8976 #define GL_SWIZZLE_STQ_ATI 0x8977 #define GL_SWIZZLE_STR_DR_ATI 0x8978 #define GL_SWIZZLE_STQ_DQ_ATI 0x8979 #define GL_SWIZZLE_STRQ_ATI 0x897A #define GL_SWIZZLE_STRQ_DQ_ATI 0x897B #define GL_RED_BIT_ATI 0x00000001 #define GL_GREEN_BIT_ATI 0x00000002 #define GL_BLUE_BIT_ATI 0x00000004 #define GL_2X_BIT_ATI 0x00000001 #define GL_4X_BIT_ATI 0x00000002 #define GL_8X_BIT_ATI 0x00000004 #define GL_HALF_BIT_ATI 0x00000008 #define GL_QUARTER_BIT_ATI 0x00000010 #define GL_EIGHTH_BIT_ATI 0x00000020 #define GL_SATURATE_BIT_ATI 0x00000040 #define GL_COMP_BIT_ATI 0x00000002 #define GL_NEGATE_BIT_ATI 0x00000004 #define GL_BIAS_BIT_ATI 0x00000008 #endif #ifndef GL_ATI_pn_triangles #define GL_PN_TRIANGLES_ATI 0x87F0 #define GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1 #define GL_PN_TRIANGLES_POINT_MODE_ATI 0x87F2 #define GL_PN_TRIANGLES_NORMAL_MODE_ATI 0x87F3 #define GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4 #define GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5 #define GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6 #define GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7 #define GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8 #endif #ifndef GL_ATI_vertex_array_object #define GL_STATIC_ATI 0x8760 #define GL_DYNAMIC_ATI 0x8761 #define GL_PRESERVE_ATI 0x8762 #define GL_DISCARD_ATI 0x8763 #define GL_OBJECT_BUFFER_SIZE_ATI 0x8764 #define GL_OBJECT_BUFFER_USAGE_ATI 0x8765 #define GL_ARRAY_OBJECT_BUFFER_ATI 0x8766 #define GL_ARRAY_OBJECT_OFFSET_ATI 0x8767 #endif #ifndef GL_EXT_vertex_shader #define GL_VERTEX_SHADER_EXT 0x8780 #define GL_VERTEX_SHADER_BINDING_EXT 0x8781 #define GL_OP_INDEX_EXT 0x8782 #define GL_OP_NEGATE_EXT 0x8783 #define GL_OP_DOT3_EXT 0x8784 #define GL_OP_DOT4_EXT 0x8785 #define GL_OP_MUL_EXT 0x8786 #define GL_OP_ADD_EXT 0x8787 #define GL_OP_MADD_EXT 0x8788 #define GL_OP_FRAC_EXT 0x8789 #define GL_OP_MAX_EXT 0x878A #define GL_OP_MIN_EXT 0x878B #define GL_OP_SET_GE_EXT 0x878C #define GL_OP_SET_LT_EXT 0x878D #define GL_OP_CLAMP_EXT 0x878E #define GL_OP_FLOOR_EXT 0x878F #define GL_OP_ROUND_EXT 0x8790 #define GL_OP_EXP_BASE_2_EXT 0x8791 #define GL_OP_LOG_BASE_2_EXT 0x8792 #define GL_OP_POWER_EXT 0x8793 #define GL_OP_RECIP_EXT 0x8794 #define GL_OP_RECIP_SQRT_EXT 0x8795 #define GL_OP_SUB_EXT 0x8796 #define GL_OP_CROSS_PRODUCT_EXT 0x8797 #define GL_OP_MULTIPLY_MATRIX_EXT 0x8798 #define GL_OP_MOV_EXT 0x8799 #define GL_OUTPUT_VERTEX_EXT 0x879A #define GL_OUTPUT_COLOR0_EXT 0x879B #define GL_OUTPUT_COLOR1_EXT 0x879C #define GL_OUTPUT_TEXTURE_COORD0_EXT 0x879D #define GL_OUTPUT_TEXTURE_COORD1_EXT 0x879E #define GL_OUTPUT_TEXTURE_COORD2_EXT 0x879F #define GL_OUTPUT_TEXTURE_COORD3_EXT 0x87A0 #define GL_OUTPUT_TEXTURE_COORD4_EXT 0x87A1 #define GL_OUTPUT_TEXTURE_COORD5_EXT 0x87A2 #define GL_OUTPUT_TEXTURE_COORD6_EXT 0x87A3 #define GL_OUTPUT_TEXTURE_COORD7_EXT 0x87A4 #define GL_OUTPUT_TEXTURE_COORD8_EXT 0x87A5 #define GL_OUTPUT_TEXTURE_COORD9_EXT 0x87A6 #define GL_OUTPUT_TEXTURE_COORD10_EXT 0x87A7 #define GL_OUTPUT_TEXTURE_COORD11_EXT 0x87A8 #define GL_OUTPUT_TEXTURE_COORD12_EXT 0x87A9 #define GL_OUTPUT_TEXTURE_COORD13_EXT 0x87AA #define GL_OUTPUT_TEXTURE_COORD14_EXT 0x87AB #define GL_OUTPUT_TEXTURE_COORD15_EXT 0x87AC #define GL_OUTPUT_TEXTURE_COORD16_EXT 0x87AD #define GL_OUTPUT_TEXTURE_COORD17_EXT 0x87AE #define GL_OUTPUT_TEXTURE_COORD18_EXT 0x87AF #define GL_OUTPUT_TEXTURE_COORD19_EXT 0x87B0 #define GL_OUTPUT_TEXTURE_COORD20_EXT 0x87B1 #define GL_OUTPUT_TEXTURE_COORD21_EXT 0x87B2 #define GL_OUTPUT_TEXTURE_COORD22_EXT 0x87B3 #define GL_OUTPUT_TEXTURE_COORD23_EXT 0x87B4 #define GL_OUTPUT_TEXTURE_COORD24_EXT 0x87B5 #define GL_OUTPUT_TEXTURE_COORD25_EXT 0x87B6 #define GL_OUTPUT_TEXTURE_COORD26_EXT 0x87B7 #define GL_OUTPUT_TEXTURE_COORD27_EXT 0x87B8 #define GL_OUTPUT_TEXTURE_COORD28_EXT 0x87B9 #define GL_OUTPUT_TEXTURE_COORD29_EXT 0x87BA #define GL_OUTPUT_TEXTURE_COORD30_EXT 0x87BB #define GL_OUTPUT_TEXTURE_COORD31_EXT 0x87BC #define GL_OUTPUT_FOG_EXT 0x87BD #define GL_SCALAR_EXT 0x87BE #define GL_VECTOR_EXT 0x87BF #define GL_MATRIX_EXT 0x87C0 #define GL_VARIANT_EXT 0x87C1 #define GL_INVARIANT_EXT 0x87C2 #define GL_LOCAL_CONSTANT_EXT 0x87C3 #define GL_LOCAL_EXT 0x87C4 #define GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5 #define GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6 #define GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7 #define GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8 #define GL_MAX_VERTEX_SHADER_LOCALS_EXT 0x87C9 #define GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA #define GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB #define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC #define GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD #define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE #define GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF #define GL_VERTEX_SHADER_VARIANTS_EXT 0x87D0 #define GL_VERTEX_SHADER_INVARIANTS_EXT 0x87D1 #define GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2 #define GL_VERTEX_SHADER_LOCALS_EXT 0x87D3 #define GL_VERTEX_SHADER_OPTIMIZED_EXT 0x87D4 #define GL_X_EXT 0x87D5 #define GL_Y_EXT 0x87D6 #define GL_Z_EXT 0x87D7 #define GL_W_EXT 0x87D8 #define GL_NEGATIVE_X_EXT 0x87D9 #define GL_NEGATIVE_Y_EXT 0x87DA #define GL_NEGATIVE_Z_EXT 0x87DB #define GL_NEGATIVE_W_EXT 0x87DC #define GL_ZERO_EXT 0x87DD #define GL_ONE_EXT 0x87DE #define GL_NEGATIVE_ONE_EXT 0x87DF #define GL_NORMALIZED_RANGE_EXT 0x87E0 #define GL_FULL_RANGE_EXT 0x87E1 #define GL_CURRENT_VERTEX_EXT 0x87E2 #define GL_MVP_MATRIX_EXT 0x87E3 #define GL_VARIANT_VALUE_EXT 0x87E4 #define GL_VARIANT_DATATYPE_EXT 0x87E5 #define GL_VARIANT_ARRAY_STRIDE_EXT 0x87E6 #define GL_VARIANT_ARRAY_TYPE_EXT 0x87E7 #define GL_VARIANT_ARRAY_EXT 0x87E8 #define GL_VARIANT_ARRAY_POINTER_EXT 0x87E9 #define GL_INVARIANT_VALUE_EXT 0x87EA #define GL_INVARIANT_DATATYPE_EXT 0x87EB #define GL_LOCAL_CONSTANT_VALUE_EXT 0x87EC #define GL_LOCAL_CONSTANT_DATATYPE_EXT 0x87ED #endif #ifndef GL_ATI_vertex_streams #define GL_MAX_VERTEX_STREAMS_ATI 0x876B #define GL_VERTEX_STREAM0_ATI 0x876C #define GL_VERTEX_STREAM1_ATI 0x876D #define GL_VERTEX_STREAM2_ATI 0x876E #define GL_VERTEX_STREAM3_ATI 0x876F #define GL_VERTEX_STREAM4_ATI 0x8770 #define GL_VERTEX_STREAM5_ATI 0x8771 #define GL_VERTEX_STREAM6_ATI 0x8772 #define GL_VERTEX_STREAM7_ATI 0x8773 #define GL_VERTEX_SOURCE_ATI 0x8774 #endif #ifndef GL_ATI_element_array #define GL_ELEMENT_ARRAY_ATI 0x8768 #define GL_ELEMENT_ARRAY_TYPE_ATI 0x8769 #define GL_ELEMENT_ARRAY_POINTER_ATI 0x876A #endif #ifndef GL_SUN_mesh_array #define GL_QUAD_MESH_SUN 0x8614 #define GL_TRIANGLE_MESH_SUN 0x8615 #endif #ifndef GL_SUN_slice_accum #define GL_SLICE_ACCUM_SUN 0x85CC #endif #ifndef GL_NV_multisample_filter_hint #define GL_MULTISAMPLE_FILTER_HINT_NV 0x8534 #endif #ifndef GL_NV_depth_clamp #define GL_DEPTH_CLAMP_NV 0x864F #endif #ifndef GL_NV_occlusion_query #define GL_PIXEL_COUNTER_BITS_NV 0x8864 #define GL_CURRENT_OCCLUSION_QUERY_ID_NV 0x8865 #define GL_PIXEL_COUNT_NV 0x8866 #define GL_PIXEL_COUNT_AVAILABLE_NV 0x8867 #endif #ifndef GL_NV_point_sprite #define GL_POINT_SPRITE_NV 0x8861 #define GL_COORD_REPLACE_NV 0x8862 #define GL_POINT_SPRITE_R_MODE_NV 0x8863 #endif #ifndef GL_NV_texture_shader3 #define GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV 0x8850 #define GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV 0x8851 #define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8852 #define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV 0x8853 #define GL_OFFSET_HILO_TEXTURE_2D_NV 0x8854 #define GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV 0x8855 #define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV 0x8856 #define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8857 #define GL_DEPENDENT_HILO_TEXTURE_2D_NV 0x8858 #define GL_DEPENDENT_RGB_TEXTURE_3D_NV 0x8859 #define GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV 0x885A #define GL_DOT_PRODUCT_PASS_THROUGH_NV 0x885B #define GL_DOT_PRODUCT_TEXTURE_1D_NV 0x885C #define GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV 0x885D #define GL_HILO8_NV 0x885E #define GL_SIGNED_HILO8_NV 0x885F #define GL_FORCE_BLUE_TO_ONE_NV 0x8860 #endif #ifndef GL_NV_vertex_program1_1 #endif #ifndef GL_EXT_shadow_funcs #endif #ifndef GL_EXT_stencil_two_side #define GL_STENCIL_TEST_TWO_SIDE_EXT 0x8910 #define GL_ACTIVE_STENCIL_FACE_EXT 0x8911 #endif #ifndef GL_ATI_text_fragment_shader #define GL_TEXT_FRAGMENT_SHADER_ATI 0x8200 #endif #ifndef GL_APPLE_client_storage #define GL_UNPACK_CLIENT_STORAGE_APPLE 0x85B2 #endif #ifndef GL_APPLE_element_array #define GL_ELEMENT_ARRAY_APPLE 0x8A0C #define GL_ELEMENT_ARRAY_TYPE_APPLE 0x8A0D #define GL_ELEMENT_ARRAY_POINTER_APPLE 0x8A0E #endif #ifndef GL_APPLE_fence #define GL_DRAW_PIXELS_APPLE 0x8A0A #define GL_FENCE_APPLE 0x8A0B #endif #ifndef GL_APPLE_vertex_array_object #define GL_VERTEX_ARRAY_BINDING_APPLE 0x85B5 #endif #ifndef GL_APPLE_vertex_array_range #define GL_VERTEX_ARRAY_RANGE_APPLE 0x851D #define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E #define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F #define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521 #define GL_STORAGE_CLIENT_APPLE 0x85B4 #define GL_STORAGE_CACHED_APPLE 0x85BE #define GL_STORAGE_SHARED_APPLE 0x85BF #endif #ifndef GL_APPLE_ycbcr_422 #define GL_YCBCR_422_APPLE 0x85B9 #define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA #define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB #endif #ifndef GL_S3_s3tc #define GL_RGB_S3TC 0x83A0 #define GL_RGB4_S3TC 0x83A1 #define GL_RGBA_S3TC 0x83A2 #define GL_RGBA4_S3TC 0x83A3 #endif #ifndef GL_ATI_draw_buffers #define GL_MAX_DRAW_BUFFERS_ATI 0x8824 #define GL_DRAW_BUFFER0_ATI 0x8825 #define GL_DRAW_BUFFER1_ATI 0x8826 #define GL_DRAW_BUFFER2_ATI 0x8827 #define GL_DRAW_BUFFER3_ATI 0x8828 #define GL_DRAW_BUFFER4_ATI 0x8829 #define GL_DRAW_BUFFER5_ATI 0x882A #define GL_DRAW_BUFFER6_ATI 0x882B #define GL_DRAW_BUFFER7_ATI 0x882C #define GL_DRAW_BUFFER8_ATI 0x882D #define GL_DRAW_BUFFER9_ATI 0x882E #define GL_DRAW_BUFFER10_ATI 0x882F #define GL_DRAW_BUFFER11_ATI 0x8830 #define GL_DRAW_BUFFER12_ATI 0x8831 #define GL_DRAW_BUFFER13_ATI 0x8832 #define GL_DRAW_BUFFER14_ATI 0x8833 #define GL_DRAW_BUFFER15_ATI 0x8834 #endif #ifndef GL_ATI_pixel_format_float #define GL_TYPE_RGBA_FLOAT_ATI 0x8820 #define GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI 0x8835 #endif #ifndef GL_ATI_texture_env_combine3 #define GL_MODULATE_ADD_ATI 0x8744 #define GL_MODULATE_SIGNED_ADD_ATI 0x8745 #define GL_MODULATE_SUBTRACT_ATI 0x8746 #endif #ifndef GL_ATI_texture_float #define GL_RGBA_FLOAT32_ATI 0x8814 #define GL_RGB_FLOAT32_ATI 0x8815 #define GL_ALPHA_FLOAT32_ATI 0x8816 #define GL_INTENSITY_FLOAT32_ATI 0x8817 #define GL_LUMINANCE_FLOAT32_ATI 0x8818 #define GL_LUMINANCE_ALPHA_FLOAT32_ATI 0x8819 #define GL_RGBA_FLOAT16_ATI 0x881A #define GL_RGB_FLOAT16_ATI 0x881B #define GL_ALPHA_FLOAT16_ATI 0x881C #define GL_INTENSITY_FLOAT16_ATI 0x881D #define GL_LUMINANCE_FLOAT16_ATI 0x881E #define GL_LUMINANCE_ALPHA_FLOAT16_ATI 0x881F #endif #ifndef GL_NV_float_buffer #define GL_FLOAT_R_NV 0x8880 #define GL_FLOAT_RG_NV 0x8881 #define GL_FLOAT_RGB_NV 0x8882 #define GL_FLOAT_RGBA_NV 0x8883 #define GL_FLOAT_R16_NV 0x8884 #define GL_FLOAT_R32_NV 0x8885 #define GL_FLOAT_RG16_NV 0x8886 #define GL_FLOAT_RG32_NV 0x8887 #define GL_FLOAT_RGB16_NV 0x8888 #define GL_FLOAT_RGB32_NV 0x8889 #define GL_FLOAT_RGBA16_NV 0x888A #define GL_FLOAT_RGBA32_NV 0x888B #define GL_TEXTURE_FLOAT_COMPONENTS_NV 0x888C #define GL_FLOAT_CLEAR_COLOR_VALUE_NV 0x888D #define GL_FLOAT_RGBA_MODE_NV 0x888E #endif #ifndef GL_NV_fragment_program #define GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV 0x8868 #define GL_FRAGMENT_PROGRAM_NV 0x8870 #define GL_MAX_TEXTURE_COORDS_NV 0x8871 #define GL_MAX_TEXTURE_IMAGE_UNITS_NV 0x8872 #define GL_FRAGMENT_PROGRAM_BINDING_NV 0x8873 #define GL_PROGRAM_ERROR_STRING_NV 0x8874 #endif #ifndef GL_NV_half_float #define GL_HALF_FLOAT_NV 0x140B #endif #ifndef GL_NV_pixel_data_range #define GL_WRITE_PIXEL_DATA_RANGE_NV 0x8878 #define GL_READ_PIXEL_DATA_RANGE_NV 0x8879 #define GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A #define GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B #define GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C #define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D #endif #ifndef GL_NV_primitive_restart #define GL_PRIMITIVE_RESTART_NV 0x8558 #define GL_PRIMITIVE_RESTART_INDEX_NV 0x8559 #endif #ifndef GL_NV_texture_expand_normal #define GL_TEXTURE_UNSIGNED_REMAP_MODE_NV 0x888F #endif #ifndef GL_NV_vertex_program2 #endif #ifndef GL_ATI_map_object_buffer #endif #ifndef GL_ATI_separate_stencil #define GL_STENCIL_BACK_FUNC_ATI 0x8800 #define GL_STENCIL_BACK_FAIL_ATI 0x8801 #define GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI 0x8802 #define GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI 0x8803 #endif #ifndef GL_ATI_vertex_attrib_array_object #endif #ifndef GL_OES_read_format #define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A #define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B #endif #ifndef GL_EXT_depth_bounds_test #define GL_DEPTH_BOUNDS_TEST_EXT 0x8890 #define GL_DEPTH_BOUNDS_EXT 0x8891 #endif #ifndef GL_EXT_texture_mirror_clamp #define GL_MIRROR_CLAMP_EXT 0x8742 #define GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743 #define GL_MIRROR_CLAMP_TO_BORDER_EXT 0x8912 #endif #ifndef GL_EXT_blend_equation_separate #define GL_BLEND_EQUATION_RGB_EXT 0x8009 #define GL_BLEND_EQUATION_ALPHA_EXT 0x883D #endif #ifndef GL_MESA_pack_invert #define GL_PACK_INVERT_MESA 0x8758 #endif #ifndef GL_MESA_ycbcr_texture #define GL_UNSIGNED_SHORT_8_8_MESA 0x85BA #define GL_UNSIGNED_SHORT_8_8_REV_MESA 0x85BB #define GL_YCBCR_MESA 0x8757 #endif #ifndef GL_EXT_pixel_buffer_object #define GL_PIXEL_PACK_BUFFER_EXT 0x88EB #define GL_PIXEL_UNPACK_BUFFER_EXT 0x88EC #define GL_PIXEL_PACK_BUFFER_BINDING_EXT 0x88ED #define GL_PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF #endif #ifndef GL_NV_fragment_program_option #endif #ifndef GL_NV_fragment_program2 #define GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4 #define GL_MAX_PROGRAM_CALL_DEPTH_NV 0x88F5 #define GL_MAX_PROGRAM_IF_DEPTH_NV 0x88F6 #define GL_MAX_PROGRAM_LOOP_DEPTH_NV 0x88F7 #define GL_MAX_PROGRAM_LOOP_COUNT_NV 0x88F8 #endif #ifndef GL_NV_vertex_program2_option /* reuse GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV */ /* reuse GL_MAX_PROGRAM_CALL_DEPTH_NV */ #endif #ifndef GL_NV_vertex_program3 /* reuse GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB */ #endif #ifndef GL_EXT_framebuffer_object #define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506 #define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8 #define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6 #define GL_RENDERBUFFER_BINDING_EXT 0x8CA7 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4 #define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9 #define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA #define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB #define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC #define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD #define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF #define GL_COLOR_ATTACHMENT0_EXT 0x8CE0 #define GL_COLOR_ATTACHMENT1_EXT 0x8CE1 #define GL_COLOR_ATTACHMENT2_EXT 0x8CE2 #define GL_COLOR_ATTACHMENT3_EXT 0x8CE3 #define GL_COLOR_ATTACHMENT4_EXT 0x8CE4 #define GL_COLOR_ATTACHMENT5_EXT 0x8CE5 #define GL_COLOR_ATTACHMENT6_EXT 0x8CE6 #define GL_COLOR_ATTACHMENT7_EXT 0x8CE7 #define GL_COLOR_ATTACHMENT8_EXT 0x8CE8 #define GL_COLOR_ATTACHMENT9_EXT 0x8CE9 #define GL_COLOR_ATTACHMENT10_EXT 0x8CEA #define GL_COLOR_ATTACHMENT11_EXT 0x8CEB #define GL_COLOR_ATTACHMENT12_EXT 0x8CEC #define GL_COLOR_ATTACHMENT13_EXT 0x8CED #define GL_COLOR_ATTACHMENT14_EXT 0x8CEE #define GL_COLOR_ATTACHMENT15_EXT 0x8CEF #define GL_DEPTH_ATTACHMENT_EXT 0x8D00 #define GL_STENCIL_ATTACHMENT_EXT 0x8D20 #define GL_FRAMEBUFFER_EXT 0x8D40 #define GL_RENDERBUFFER_EXT 0x8D41 #define GL_RENDERBUFFER_WIDTH_EXT 0x8D42 #define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43 #define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44 #define GL_STENCIL_INDEX1_EXT 0x8D46 #define GL_STENCIL_INDEX4_EXT 0x8D47 #define GL_STENCIL_INDEX8_EXT 0x8D48 #define GL_STENCIL_INDEX16_EXT 0x8D49 #define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50 #define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51 #define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52 #define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53 #define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54 #define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55 #endif #ifndef GL_GREMEDY_string_marker #endif #ifndef GL_EXT_packed_depth_stencil #define GL_DEPTH_STENCIL_EXT 0x84F9 #define GL_UNSIGNED_INT_24_8_EXT 0x84FA #define GL_DEPTH24_STENCIL8_EXT 0x88F0 #define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 #endif #ifndef GL_EXT_stencil_clear_tag #define GL_STENCIL_TAG_BITS_EXT 0x88F2 #define GL_STENCIL_CLEAR_TAG_VALUE_EXT 0x88F3 #endif #ifndef GL_EXT_texture_sRGB #define GL_SRGB_EXT 0x8C40 #define GL_SRGB8_EXT 0x8C41 #define GL_SRGB_ALPHA_EXT 0x8C42 #define GL_SRGB8_ALPHA8_EXT 0x8C43 #define GL_SLUMINANCE_ALPHA_EXT 0x8C44 #define GL_SLUMINANCE8_ALPHA8_EXT 0x8C45 #define GL_SLUMINANCE_EXT 0x8C46 #define GL_SLUMINANCE8_EXT 0x8C47 #define GL_COMPRESSED_SRGB_EXT 0x8C48 #define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49 #define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A #define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B #define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F #endif #ifndef GL_EXT_framebuffer_blit #define GL_READ_FRAMEBUFFER_EXT 0x8CA8 #define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 #define GL_DRAW_FRAMEBUFFER_BINDING_EXT GL_FRAMEBUFFER_BINDING_EXT #define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA #endif #ifndef GL_EXT_framebuffer_multisample #define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 #define GL_MAX_SAMPLES_EXT 0x8D57 #endif #ifndef GL_MESAX_texture_stack #define GL_TEXTURE_1D_STACK_MESAX 0x8759 #define GL_TEXTURE_2D_STACK_MESAX 0x875A #define GL_PROXY_TEXTURE_1D_STACK_MESAX 0x875B #define GL_PROXY_TEXTURE_2D_STACK_MESAX 0x875C #define GL_TEXTURE_1D_STACK_BINDING_MESAX 0x875D #define GL_TEXTURE_2D_STACK_BINDING_MESAX 0x875E #endif #ifndef GL_EXT_timer_query #define GL_TIME_ELAPSED_EXT 0x88BF #endif #ifndef GL_EXT_gpu_program_parameters #endif #ifndef GL_APPLE_flush_buffer_range #define GL_BUFFER_SERIALIZED_MODIFY_APPLE 0x8A12 #define GL_BUFFER_FLUSHING_UNMAP_APPLE 0x8A13 #endif #ifndef GL_NV_gpu_program4 #define GL_MIN_PROGRAM_TEXEL_OFFSET_NV 0x8904 #define GL_MAX_PROGRAM_TEXEL_OFFSET_NV 0x8905 #define GL_PROGRAM_ATTRIB_COMPONENTS_NV 0x8906 #define GL_PROGRAM_RESULT_COMPONENTS_NV 0x8907 #define GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV 0x8908 #define GL_MAX_PROGRAM_RESULT_COMPONENTS_NV 0x8909 #define GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV 0x8DA5 #define GL_MAX_PROGRAM_GENERIC_RESULTS_NV 0x8DA6 #endif #ifndef GL_NV_geometry_program4 #define GL_LINES_ADJACENCY_EXT 0x000A #define GL_LINE_STRIP_ADJACENCY_EXT 0x000B #define GL_TRIANGLES_ADJACENCY_EXT 0x000C #define GL_TRIANGLE_STRIP_ADJACENCY_EXT 0x000D #define GL_GEOMETRY_PROGRAM_NV 0x8C26 #define GL_MAX_PROGRAM_OUTPUT_VERTICES_NV 0x8C27 #define GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV 0x8C28 #define GL_GEOMETRY_VERTICES_OUT_EXT 0x8DDA #define GL_GEOMETRY_INPUT_TYPE_EXT 0x8DDB #define GL_GEOMETRY_OUTPUT_TYPE_EXT 0x8DDC #define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT 0x8C29 #define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT 0x8DA7 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT 0x8DA8 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT 0x8DA9 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT 0x8CD4 #define GL_PROGRAM_POINT_SIZE_EXT 0x8642 #endif #ifndef GL_EXT_geometry_shader4 #define GL_GEOMETRY_SHADER_EXT 0x8DD9 /* reuse GL_GEOMETRY_VERTICES_OUT_EXT */ /* reuse GL_GEOMETRY_INPUT_TYPE_EXT */ /* reuse GL_GEOMETRY_OUTPUT_TYPE_EXT */ /* reuse GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT */ #define GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT 0x8DDD #define GL_MAX_VERTEX_VARYING_COMPONENTS_EXT 0x8DDE #define GL_MAX_VARYING_COMPONENTS_EXT 0x8B4B #define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8DDF #define GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT 0x8DE0 #define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT 0x8DE1 /* reuse GL_LINES_ADJACENCY_EXT */ /* reuse GL_LINE_STRIP_ADJACENCY_EXT */ /* reuse GL_TRIANGLES_ADJACENCY_EXT */ /* reuse GL_TRIANGLE_STRIP_ADJACENCY_EXT */ /* reuse GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT */ /* reuse GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT */ /* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT */ /* reuse GL_PROGRAM_POINT_SIZE_EXT */ #endif #ifndef GL_NV_vertex_program4 #define GL_VERTEX_ATTRIB_ARRAY_INTEGER_NV 0x88FD #endif #ifndef GL_EXT_gpu_shader4 #define GL_SAMPLER_1D_ARRAY_EXT 0x8DC0 #define GL_SAMPLER_2D_ARRAY_EXT 0x8DC1 #define GL_SAMPLER_BUFFER_EXT 0x8DC2 #define GL_SAMPLER_1D_ARRAY_SHADOW_EXT 0x8DC3 #define GL_SAMPLER_2D_ARRAY_SHADOW_EXT 0x8DC4 #define GL_SAMPLER_CUBE_SHADOW_EXT 0x8DC5 #define GL_UNSIGNED_INT_VEC2_EXT 0x8DC6 #define GL_UNSIGNED_INT_VEC3_EXT 0x8DC7 #define GL_UNSIGNED_INT_VEC4_EXT 0x8DC8 #define GL_INT_SAMPLER_1D_EXT 0x8DC9 #define GL_INT_SAMPLER_2D_EXT 0x8DCA #define GL_INT_SAMPLER_3D_EXT 0x8DCB #define GL_INT_SAMPLER_CUBE_EXT 0x8DCC #define GL_INT_SAMPLER_2D_RECT_EXT 0x8DCD #define GL_INT_SAMPLER_1D_ARRAY_EXT 0x8DCE #define GL_INT_SAMPLER_2D_ARRAY_EXT 0x8DCF #define GL_INT_SAMPLER_BUFFER_EXT 0x8DD0 #define GL_UNSIGNED_INT_SAMPLER_1D_EXT 0x8DD1 #define GL_UNSIGNED_INT_SAMPLER_2D_EXT 0x8DD2 #define GL_UNSIGNED_INT_SAMPLER_3D_EXT 0x8DD3 #define GL_UNSIGNED_INT_SAMPLER_CUBE_EXT 0x8DD4 #define GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT 0x8DD5 #define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT 0x8DD6 #define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT 0x8DD7 #define GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8 #endif #ifndef GL_EXT_draw_instanced #endif #ifndef GL_EXT_packed_float #define GL_R11F_G11F_B10F_EXT 0x8C3A #define GL_UNSIGNED_INT_10F_11F_11F_REV_EXT 0x8C3B #define GL_RGBA_SIGNED_COMPONENTS_EXT 0x8C3C #endif #ifndef GL_EXT_texture_array #define GL_TEXTURE_1D_ARRAY_EXT 0x8C18 #define GL_PROXY_TEXTURE_1D_ARRAY_EXT 0x8C19 #define GL_TEXTURE_2D_ARRAY_EXT 0x8C1A #define GL_PROXY_TEXTURE_2D_ARRAY_EXT 0x8C1B #define GL_TEXTURE_BINDING_1D_ARRAY_EXT 0x8C1C #define GL_TEXTURE_BINDING_2D_ARRAY_EXT 0x8C1D #define GL_MAX_ARRAY_TEXTURE_LAYERS_EXT 0x88FF #define GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT 0x884E /* reuse GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT */ #endif #ifndef GL_EXT_texture_buffer_object #define GL_TEXTURE_BUFFER_EXT 0x8C2A #define GL_MAX_TEXTURE_BUFFER_SIZE_EXT 0x8C2B #define GL_TEXTURE_BINDING_BUFFER_EXT 0x8C2C #define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT 0x8C2D #define GL_TEXTURE_BUFFER_FORMAT_EXT 0x8C2E #endif #ifndef GL_EXT_texture_compression_latc #define GL_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70 #define GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71 #define GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72 #define GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73 #endif #ifndef GL_EXT_texture_compression_rgtc #define GL_COMPRESSED_RED_RGTC1_EXT 0x8DBB #define GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC #define GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD #define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE #endif #ifndef GL_EXT_texture_shared_exponent #define GL_RGB9_E5_EXT 0x8C3D #define GL_UNSIGNED_INT_5_9_9_9_REV_EXT 0x8C3E #define GL_TEXTURE_SHARED_SIZE_EXT 0x8C3F #endif #ifndef GL_NV_depth_buffer_float #define GL_DEPTH_COMPONENT32F_NV 0x8DAB #define GL_DEPTH32F_STENCIL8_NV 0x8DAC #define GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV 0x8DAD #define GL_DEPTH_BUFFER_FLOAT_MODE_NV 0x8DAF #endif #ifndef GL_NV_fragment_program4 #endif #ifndef GL_NV_framebuffer_multisample_coverage #define GL_RENDERBUFFER_COVERAGE_SAMPLES_NV 0x8CAB #define GL_RENDERBUFFER_COLOR_SAMPLES_NV 0x8E10 #define GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV 0x8E11 #define GL_MULTISAMPLE_COVERAGE_MODES_NV 0x8E12 #endif #ifndef GL_EXT_framebuffer_sRGB #define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 #define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA #endif #ifndef GL_NV_geometry_shader4 #endif #ifndef GL_NV_parameter_buffer_object #define GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV 0x8DA0 #define GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV 0x8DA1 #define GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV 0x8DA2 #define GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV 0x8DA3 #define GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV 0x8DA4 #endif #ifndef GL_EXT_draw_buffers2 #endif #ifndef GL_NV_transform_feedback #define GL_BACK_PRIMARY_COLOR_NV 0x8C77 #define GL_BACK_SECONDARY_COLOR_NV 0x8C78 #define GL_TEXTURE_COORD_NV 0x8C79 #define GL_CLIP_DISTANCE_NV 0x8C7A #define GL_VERTEX_ID_NV 0x8C7B #define GL_PRIMITIVE_ID_NV 0x8C7C #define GL_GENERIC_ATTRIB_NV 0x8C7D #define GL_TRANSFORM_FEEDBACK_ATTRIBS_NV 0x8C7E #define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV 0x8C7F #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV 0x8C80 #define GL_ACTIVE_VARYINGS_NV 0x8C81 #define GL_ACTIVE_VARYING_MAX_LENGTH_NV 0x8C82 #define GL_TRANSFORM_FEEDBACK_VARYINGS_NV 0x8C83 #define GL_TRANSFORM_FEEDBACK_BUFFER_START_NV 0x8C84 #define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV 0x8C85 #define GL_TRANSFORM_FEEDBACK_RECORD_NV 0x8C86 #define GL_PRIMITIVES_GENERATED_NV 0x8C87 #define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV 0x8C88 #define GL_RASTERIZER_DISCARD_NV 0x8C89 #define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_ATTRIBS_NV 0x8C8A #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV 0x8C8B #define GL_INTERLEAVED_ATTRIBS_NV 0x8C8C #define GL_SEPARATE_ATTRIBS_NV 0x8C8D #define GL_TRANSFORM_FEEDBACK_BUFFER_NV 0x8C8E #define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV 0x8C8F #define GL_LAYER_NV 0x8DAA #define GL_NEXT_BUFFER_NV -2 #define GL_SKIP_COMPONENTS4_NV -3 #define GL_SKIP_COMPONENTS3_NV -4 #define GL_SKIP_COMPONENTS2_NV -5 #define GL_SKIP_COMPONENTS1_NV -6 #endif #ifndef GL_EXT_bindable_uniform #define GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT 0x8DE2 #define GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT 0x8DE3 #define GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT 0x8DE4 #define GL_MAX_BINDABLE_UNIFORM_SIZE_EXT 0x8DED #define GL_UNIFORM_BUFFER_EXT 0x8DEE #define GL_UNIFORM_BUFFER_BINDING_EXT 0x8DEF #endif #ifndef GL_EXT_texture_integer #define GL_RGBA32UI_EXT 0x8D70 #define GL_RGB32UI_EXT 0x8D71 #define GL_ALPHA32UI_EXT 0x8D72 #define GL_INTENSITY32UI_EXT 0x8D73 #define GL_LUMINANCE32UI_EXT 0x8D74 #define GL_LUMINANCE_ALPHA32UI_EXT 0x8D75 #define GL_RGBA16UI_EXT 0x8D76 #define GL_RGB16UI_EXT 0x8D77 #define GL_ALPHA16UI_EXT 0x8D78 #define GL_INTENSITY16UI_EXT 0x8D79 #define GL_LUMINANCE16UI_EXT 0x8D7A #define GL_LUMINANCE_ALPHA16UI_EXT 0x8D7B #define GL_RGBA8UI_EXT 0x8D7C #define GL_RGB8UI_EXT 0x8D7D #define GL_ALPHA8UI_EXT 0x8D7E #define GL_INTENSITY8UI_EXT 0x8D7F #define GL_LUMINANCE8UI_EXT 0x8D80 #define GL_LUMINANCE_ALPHA8UI_EXT 0x8D81 #define GL_RGBA32I_EXT 0x8D82 #define GL_RGB32I_EXT 0x8D83 #define GL_ALPHA32I_EXT 0x8D84 #define GL_INTENSITY32I_EXT 0x8D85 #define GL_LUMINANCE32I_EXT 0x8D86 #define GL_LUMINANCE_ALPHA32I_EXT 0x8D87 #define GL_RGBA16I_EXT 0x8D88 #define GL_RGB16I_EXT 0x8D89 #define GL_ALPHA16I_EXT 0x8D8A #define GL_INTENSITY16I_EXT 0x8D8B #define GL_LUMINANCE16I_EXT 0x8D8C #define GL_LUMINANCE_ALPHA16I_EXT 0x8D8D #define GL_RGBA8I_EXT 0x8D8E #define GL_RGB8I_EXT 0x8D8F #define GL_ALPHA8I_EXT 0x8D90 #define GL_INTENSITY8I_EXT 0x8D91 #define GL_LUMINANCE8I_EXT 0x8D92 #define GL_LUMINANCE_ALPHA8I_EXT 0x8D93 #define GL_RED_INTEGER_EXT 0x8D94 #define GL_GREEN_INTEGER_EXT 0x8D95 #define GL_BLUE_INTEGER_EXT 0x8D96 #define GL_ALPHA_INTEGER_EXT 0x8D97 #define GL_RGB_INTEGER_EXT 0x8D98 #define GL_RGBA_INTEGER_EXT 0x8D99 #define GL_BGR_INTEGER_EXT 0x8D9A #define GL_BGRA_INTEGER_EXT 0x8D9B #define GL_LUMINANCE_INTEGER_EXT 0x8D9C #define GL_LUMINANCE_ALPHA_INTEGER_EXT 0x8D9D #define GL_RGBA_INTEGER_MODE_EXT 0x8D9E #endif #ifndef GL_GREMEDY_frame_terminator #endif #ifndef GL_NV_conditional_render #define GL_QUERY_WAIT_NV 0x8E13 #define GL_QUERY_NO_WAIT_NV 0x8E14 #define GL_QUERY_BY_REGION_WAIT_NV 0x8E15 #define GL_QUERY_BY_REGION_NO_WAIT_NV 0x8E16 #endif #ifndef GL_NV_present_video #define GL_FRAME_NV 0x8E26 #define GL_FIELDS_NV 0x8E27 #define GL_CURRENT_TIME_NV 0x8E28 #define GL_NUM_FILL_STREAMS_NV 0x8E29 #define GL_PRESENT_TIME_NV 0x8E2A #define GL_PRESENT_DURATION_NV 0x8E2B #endif #ifndef GL_EXT_transform_feedback #define GL_TRANSFORM_FEEDBACK_BUFFER_EXT 0x8C8E #define GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT 0x8C84 #define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT 0x8C85 #define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT 0x8C8F #define GL_INTERLEAVED_ATTRIBS_EXT 0x8C8C #define GL_SEPARATE_ATTRIBS_EXT 0x8C8D #define GL_PRIMITIVES_GENERATED_EXT 0x8C87 #define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT 0x8C88 #define GL_RASTERIZER_DISCARD_EXT 0x8C89 #define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT 0x8C8A #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT 0x8C8B #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT 0x8C80 #define GL_TRANSFORM_FEEDBACK_VARYINGS_EXT 0x8C83 #define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT 0x8C7F #define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT 0x8C76 #endif #ifndef GL_EXT_direct_state_access #define GL_PROGRAM_MATRIX_EXT 0x8E2D #define GL_TRANSPOSE_PROGRAM_MATRIX_EXT 0x8E2E #define GL_PROGRAM_MATRIX_STACK_DEPTH_EXT 0x8E2F #endif #ifndef GL_EXT_vertex_array_bgra /* reuse GL_BGRA */ #endif #ifndef GL_EXT_texture_swizzle #define GL_TEXTURE_SWIZZLE_R_EXT 0x8E42 #define GL_TEXTURE_SWIZZLE_G_EXT 0x8E43 #define GL_TEXTURE_SWIZZLE_B_EXT 0x8E44 #define GL_TEXTURE_SWIZZLE_A_EXT 0x8E45 #define GL_TEXTURE_SWIZZLE_RGBA_EXT 0x8E46 #endif #ifndef GL_NV_explicit_multisample #define GL_SAMPLE_POSITION_NV 0x8E50 #define GL_SAMPLE_MASK_NV 0x8E51 #define GL_SAMPLE_MASK_VALUE_NV 0x8E52 #define GL_TEXTURE_BINDING_RENDERBUFFER_NV 0x8E53 #define GL_TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV 0x8E54 #define GL_TEXTURE_RENDERBUFFER_NV 0x8E55 #define GL_SAMPLER_RENDERBUFFER_NV 0x8E56 #define GL_INT_SAMPLER_RENDERBUFFER_NV 0x8E57 #define GL_UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV 0x8E58 #define GL_MAX_SAMPLE_MASK_WORDS_NV 0x8E59 #endif #ifndef GL_NV_transform_feedback2 #define GL_TRANSFORM_FEEDBACK_NV 0x8E22 #define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED_NV 0x8E23 #define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE_NV 0x8E24 #define GL_TRANSFORM_FEEDBACK_BINDING_NV 0x8E25 #endif #ifndef GL_ATI_meminfo #define GL_VBO_FREE_MEMORY_ATI 0x87FB #define GL_TEXTURE_FREE_MEMORY_ATI 0x87FC #define GL_RENDERBUFFER_FREE_MEMORY_ATI 0x87FD #endif #ifndef GL_AMD_performance_monitor #define GL_COUNTER_TYPE_AMD 0x8BC0 #define GL_COUNTER_RANGE_AMD 0x8BC1 #define GL_UNSIGNED_INT64_AMD 0x8BC2 #define GL_PERCENTAGE_AMD 0x8BC3 #define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4 #define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5 #define GL_PERFMON_RESULT_AMD 0x8BC6 #endif #ifndef GL_AMD_texture_texture4 #endif #ifndef GL_AMD_vertex_shader_tesselator #define GL_SAMPLER_BUFFER_AMD 0x9001 #define GL_INT_SAMPLER_BUFFER_AMD 0x9002 #define GL_UNSIGNED_INT_SAMPLER_BUFFER_AMD 0x9003 #define GL_TESSELLATION_MODE_AMD 0x9004 #define GL_TESSELLATION_FACTOR_AMD 0x9005 #define GL_DISCRETE_AMD 0x9006 #define GL_CONTINUOUS_AMD 0x9007 #endif #ifndef GL_EXT_provoking_vertex #define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT 0x8E4C #define GL_FIRST_VERTEX_CONVENTION_EXT 0x8E4D #define GL_LAST_VERTEX_CONVENTION_EXT 0x8E4E #define GL_PROVOKING_VERTEX_EXT 0x8E4F #endif #ifndef GL_EXT_texture_snorm #define GL_ALPHA_SNORM 0x9010 #define GL_LUMINANCE_SNORM 0x9011 #define GL_LUMINANCE_ALPHA_SNORM 0x9012 #define GL_INTENSITY_SNORM 0x9013 #define GL_ALPHA8_SNORM 0x9014 #define GL_LUMINANCE8_SNORM 0x9015 #define GL_LUMINANCE8_ALPHA8_SNORM 0x9016 #define GL_INTENSITY8_SNORM 0x9017 #define GL_ALPHA16_SNORM 0x9018 #define GL_LUMINANCE16_SNORM 0x9019 #define GL_LUMINANCE16_ALPHA16_SNORM 0x901A #define GL_INTENSITY16_SNORM 0x901B /* reuse GL_RED_SNORM */ /* reuse GL_RG_SNORM */ /* reuse GL_RGB_SNORM */ /* reuse GL_RGBA_SNORM */ /* reuse GL_R8_SNORM */ /* reuse GL_RG8_SNORM */ /* reuse GL_RGB8_SNORM */ /* reuse GL_RGBA8_SNORM */ /* reuse GL_R16_SNORM */ /* reuse GL_RG16_SNORM */ /* reuse GL_RGB16_SNORM */ /* reuse GL_RGBA16_SNORM */ /* reuse GL_SIGNED_NORMALIZED */ #endif #ifndef GL_AMD_draw_buffers_blend #endif #ifndef GL_APPLE_texture_range #define GL_TEXTURE_RANGE_LENGTH_APPLE 0x85B7 #define GL_TEXTURE_RANGE_POINTER_APPLE 0x85B8 #define GL_TEXTURE_STORAGE_HINT_APPLE 0x85BC #define GL_STORAGE_PRIVATE_APPLE 0x85BD /* reuse GL_STORAGE_CACHED_APPLE */ /* reuse GL_STORAGE_SHARED_APPLE */ #endif #ifndef GL_APPLE_float_pixels #define GL_HALF_APPLE 0x140B #define GL_RGBA_FLOAT32_APPLE 0x8814 #define GL_RGB_FLOAT32_APPLE 0x8815 #define GL_ALPHA_FLOAT32_APPLE 0x8816 #define GL_INTENSITY_FLOAT32_APPLE 0x8817 #define GL_LUMINANCE_FLOAT32_APPLE 0x8818 #define GL_LUMINANCE_ALPHA_FLOAT32_APPLE 0x8819 #define GL_RGBA_FLOAT16_APPLE 0x881A #define GL_RGB_FLOAT16_APPLE 0x881B #define GL_ALPHA_FLOAT16_APPLE 0x881C #define GL_INTENSITY_FLOAT16_APPLE 0x881D #define GL_LUMINANCE_FLOAT16_APPLE 0x881E #define GL_LUMINANCE_ALPHA_FLOAT16_APPLE 0x881F #define GL_COLOR_FLOAT_APPLE 0x8A0F #endif #ifndef GL_APPLE_vertex_program_evaluators #define GL_VERTEX_ATTRIB_MAP1_APPLE 0x8A00 #define GL_VERTEX_ATTRIB_MAP2_APPLE 0x8A01 #define GL_VERTEX_ATTRIB_MAP1_SIZE_APPLE 0x8A02 #define GL_VERTEX_ATTRIB_MAP1_COEFF_APPLE 0x8A03 #define GL_VERTEX_ATTRIB_MAP1_ORDER_APPLE 0x8A04 #define GL_VERTEX_ATTRIB_MAP1_DOMAIN_APPLE 0x8A05 #define GL_VERTEX_ATTRIB_MAP2_SIZE_APPLE 0x8A06 #define GL_VERTEX_ATTRIB_MAP2_COEFF_APPLE 0x8A07 #define GL_VERTEX_ATTRIB_MAP2_ORDER_APPLE 0x8A08 #define GL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE 0x8A09 #endif #ifndef GL_APPLE_aux_depth_stencil #define GL_AUX_DEPTH_STENCIL_APPLE 0x8A14 #endif #ifndef GL_APPLE_object_purgeable #define GL_BUFFER_OBJECT_APPLE 0x85B3 #define GL_RELEASED_APPLE 0x8A19 #define GL_VOLATILE_APPLE 0x8A1A #define GL_RETAINED_APPLE 0x8A1B #define GL_UNDEFINED_APPLE 0x8A1C #define GL_PURGEABLE_APPLE 0x8A1D #endif #ifndef GL_APPLE_row_bytes #define GL_PACK_ROW_BYTES_APPLE 0x8A15 #define GL_UNPACK_ROW_BYTES_APPLE 0x8A16 #endif #ifndef GL_APPLE_rgb_422 #define GL_RGB_422_APPLE 0x8A1F /* reuse GL_UNSIGNED_SHORT_8_8_APPLE */ /* reuse GL_UNSIGNED_SHORT_8_8_REV_APPLE */ #endif #ifndef GL_NV_video_capture #define GL_VIDEO_BUFFER_NV 0x9020 #define GL_VIDEO_BUFFER_BINDING_NV 0x9021 #define GL_FIELD_UPPER_NV 0x9022 #define GL_FIELD_LOWER_NV 0x9023 #define GL_NUM_VIDEO_CAPTURE_STREAMS_NV 0x9024 #define GL_NEXT_VIDEO_CAPTURE_BUFFER_STATUS_NV 0x9025 #define GL_VIDEO_CAPTURE_TO_422_SUPPORTED_NV 0x9026 #define GL_LAST_VIDEO_CAPTURE_STATUS_NV 0x9027 #define GL_VIDEO_BUFFER_PITCH_NV 0x9028 #define GL_VIDEO_COLOR_CONVERSION_MATRIX_NV 0x9029 #define GL_VIDEO_COLOR_CONVERSION_MAX_NV 0x902A #define GL_VIDEO_COLOR_CONVERSION_MIN_NV 0x902B #define GL_VIDEO_COLOR_CONVERSION_OFFSET_NV 0x902C #define GL_VIDEO_BUFFER_INTERNAL_FORMAT_NV 0x902D #define GL_PARTIAL_SUCCESS_NV 0x902E #define GL_SUCCESS_NV 0x902F #define GL_FAILURE_NV 0x9030 #define GL_YCBYCR8_422_NV 0x9031 #define GL_YCBAYCR8A_4224_NV 0x9032 #define GL_Z6Y10Z6CB10Z6Y10Z6CR10_422_NV 0x9033 #define GL_Z6Y10Z6CB10Z6A10Z6Y10Z6CR10Z6A10_4224_NV 0x9034 #define GL_Z4Y12Z4CB12Z4Y12Z4CR12_422_NV 0x9035 #define GL_Z4Y12Z4CB12Z4A12Z4Y12Z4CR12Z4A12_4224_NV 0x9036 #define GL_Z4Y12Z4CB12Z4CR12_444_NV 0x9037 #define GL_VIDEO_CAPTURE_FRAME_WIDTH_NV 0x9038 #define GL_VIDEO_CAPTURE_FRAME_HEIGHT_NV 0x9039 #define GL_VIDEO_CAPTURE_FIELD_UPPER_HEIGHT_NV 0x903A #define GL_VIDEO_CAPTURE_FIELD_LOWER_HEIGHT_NV 0x903B #define GL_VIDEO_CAPTURE_SURFACE_ORIGIN_NV 0x903C #endif #ifndef GL_NV_copy_image #endif #ifndef GL_EXT_separate_shader_objects #define GL_ACTIVE_PROGRAM_EXT 0x8B8D #endif #ifndef GL_NV_parameter_buffer_object2 #endif #ifndef GL_NV_shader_buffer_load #define GL_BUFFER_GPU_ADDRESS_NV 0x8F1D #define GL_GPU_ADDRESS_NV 0x8F34 #define GL_MAX_SHADER_BUFFER_ADDRESS_NV 0x8F35 #endif #ifndef GL_NV_vertex_buffer_unified_memory #define GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV 0x8F1E #define GL_ELEMENT_ARRAY_UNIFIED_NV 0x8F1F #define GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV 0x8F20 #define GL_VERTEX_ARRAY_ADDRESS_NV 0x8F21 #define GL_NORMAL_ARRAY_ADDRESS_NV 0x8F22 #define GL_COLOR_ARRAY_ADDRESS_NV 0x8F23 #define GL_INDEX_ARRAY_ADDRESS_NV 0x8F24 #define GL_TEXTURE_COORD_ARRAY_ADDRESS_NV 0x8F25 #define GL_EDGE_FLAG_ARRAY_ADDRESS_NV 0x8F26 #define GL_SECONDARY_COLOR_ARRAY_ADDRESS_NV 0x8F27 #define GL_FOG_COORD_ARRAY_ADDRESS_NV 0x8F28 #define GL_ELEMENT_ARRAY_ADDRESS_NV 0x8F29 #define GL_VERTEX_ATTRIB_ARRAY_LENGTH_NV 0x8F2A #define GL_VERTEX_ARRAY_LENGTH_NV 0x8F2B #define GL_NORMAL_ARRAY_LENGTH_NV 0x8F2C #define GL_COLOR_ARRAY_LENGTH_NV 0x8F2D #define GL_INDEX_ARRAY_LENGTH_NV 0x8F2E #define GL_TEXTURE_COORD_ARRAY_LENGTH_NV 0x8F2F #define GL_EDGE_FLAG_ARRAY_LENGTH_NV 0x8F30 #define GL_SECONDARY_COLOR_ARRAY_LENGTH_NV 0x8F31 #define GL_FOG_COORD_ARRAY_LENGTH_NV 0x8F32 #define GL_ELEMENT_ARRAY_LENGTH_NV 0x8F33 #define GL_DRAW_INDIRECT_UNIFIED_NV 0x8F40 #define GL_DRAW_INDIRECT_ADDRESS_NV 0x8F41 #define GL_DRAW_INDIRECT_LENGTH_NV 0x8F42 #endif #ifndef GL_NV_texture_barrier #endif #ifndef GL_AMD_shader_stencil_export #endif #ifndef GL_AMD_seamless_cubemap_per_texture /* reuse GL_TEXTURE_CUBE_MAP_SEAMLESS */ #endif #ifndef GL_AMD_conservative_depth #endif #ifndef GL_EXT_shader_image_load_store #define GL_MAX_IMAGE_UNITS_EXT 0x8F38 #define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS_EXT 0x8F39 #define GL_IMAGE_BINDING_NAME_EXT 0x8F3A #define GL_IMAGE_BINDING_LEVEL_EXT 0x8F3B #define GL_IMAGE_BINDING_LAYERED_EXT 0x8F3C #define GL_IMAGE_BINDING_LAYER_EXT 0x8F3D #define GL_IMAGE_BINDING_ACCESS_EXT 0x8F3E #define GL_IMAGE_1D_EXT 0x904C #define GL_IMAGE_2D_EXT 0x904D #define GL_IMAGE_3D_EXT 0x904E #define GL_IMAGE_2D_RECT_EXT 0x904F #define GL_IMAGE_CUBE_EXT 0x9050 #define GL_IMAGE_BUFFER_EXT 0x9051 #define GL_IMAGE_1D_ARRAY_EXT 0x9052 #define GL_IMAGE_2D_ARRAY_EXT 0x9053 #define GL_IMAGE_CUBE_MAP_ARRAY_EXT 0x9054 #define GL_IMAGE_2D_MULTISAMPLE_EXT 0x9055 #define GL_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9056 #define GL_INT_IMAGE_1D_EXT 0x9057 #define GL_INT_IMAGE_2D_EXT 0x9058 #define GL_INT_IMAGE_3D_EXT 0x9059 #define GL_INT_IMAGE_2D_RECT_EXT 0x905A #define GL_INT_IMAGE_CUBE_EXT 0x905B #define GL_INT_IMAGE_BUFFER_EXT 0x905C #define GL_INT_IMAGE_1D_ARRAY_EXT 0x905D #define GL_INT_IMAGE_2D_ARRAY_EXT 0x905E #define GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x905F #define GL_INT_IMAGE_2D_MULTISAMPLE_EXT 0x9060 #define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9061 #define GL_UNSIGNED_INT_IMAGE_1D_EXT 0x9062 #define GL_UNSIGNED_INT_IMAGE_2D_EXT 0x9063 #define GL_UNSIGNED_INT_IMAGE_3D_EXT 0x9064 #define GL_UNSIGNED_INT_IMAGE_2D_RECT_EXT 0x9065 #define GL_UNSIGNED_INT_IMAGE_CUBE_EXT 0x9066 #define GL_UNSIGNED_INT_IMAGE_BUFFER_EXT 0x9067 #define GL_UNSIGNED_INT_IMAGE_1D_ARRAY_EXT 0x9068 #define GL_UNSIGNED_INT_IMAGE_2D_ARRAY_EXT 0x9069 #define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x906A #define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_EXT 0x906B #define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x906C #define GL_MAX_IMAGE_SAMPLES_EXT 0x906D #define GL_IMAGE_BINDING_FORMAT_EXT 0x906E #define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT_EXT 0x00000001 #define GL_ELEMENT_ARRAY_BARRIER_BIT_EXT 0x00000002 #define GL_UNIFORM_BARRIER_BIT_EXT 0x00000004 #define GL_TEXTURE_FETCH_BARRIER_BIT_EXT 0x00000008 #define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT_EXT 0x00000020 #define GL_COMMAND_BARRIER_BIT_EXT 0x00000040 #define GL_PIXEL_BUFFER_BARRIER_BIT_EXT 0x00000080 #define GL_TEXTURE_UPDATE_BARRIER_BIT_EXT 0x00000100 #define GL_BUFFER_UPDATE_BARRIER_BIT_EXT 0x00000200 #define GL_FRAMEBUFFER_BARRIER_BIT_EXT 0x00000400 #define GL_TRANSFORM_FEEDBACK_BARRIER_BIT_EXT 0x00000800 #define GL_ATOMIC_COUNTER_BARRIER_BIT_EXT 0x00001000 #define GL_ALL_BARRIER_BITS_EXT 0xFFFFFFFF #endif #ifndef GL_EXT_vertex_attrib_64bit /* reuse GL_DOUBLE */ #define GL_DOUBLE_VEC2_EXT 0x8FFC #define GL_DOUBLE_VEC3_EXT 0x8FFD #define GL_DOUBLE_VEC4_EXT 0x8FFE #define GL_DOUBLE_MAT2_EXT 0x8F46 #define GL_DOUBLE_MAT3_EXT 0x8F47 #define GL_DOUBLE_MAT4_EXT 0x8F48 #define GL_DOUBLE_MAT2x3_EXT 0x8F49 #define GL_DOUBLE_MAT2x4_EXT 0x8F4A #define GL_DOUBLE_MAT3x2_EXT 0x8F4B #define GL_DOUBLE_MAT3x4_EXT 0x8F4C #define GL_DOUBLE_MAT4x2_EXT 0x8F4D #define GL_DOUBLE_MAT4x3_EXT 0x8F4E #endif #ifndef GL_NV_gpu_program5 #define GL_MAX_GEOMETRY_PROGRAM_INVOCATIONS_NV 0x8E5A #define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5B #define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5C #define GL_FRAGMENT_PROGRAM_INTERPOLATION_OFFSET_BITS_NV 0x8E5D #define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5E #define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5F #define GL_MAX_PROGRAM_SUBROUTINE_PARAMETERS_NV 0x8F44 #define GL_MAX_PROGRAM_SUBROUTINE_NUM_NV 0x8F45 #endif #ifndef GL_NV_gpu_shader5 #define GL_INT64_NV 0x140E #define GL_UNSIGNED_INT64_NV 0x140F #define GL_INT8_NV 0x8FE0 #define GL_INT8_VEC2_NV 0x8FE1 #define GL_INT8_VEC3_NV 0x8FE2 #define GL_INT8_VEC4_NV 0x8FE3 #define GL_INT16_NV 0x8FE4 #define GL_INT16_VEC2_NV 0x8FE5 #define GL_INT16_VEC3_NV 0x8FE6 #define GL_INT16_VEC4_NV 0x8FE7 #define GL_INT64_VEC2_NV 0x8FE9 #define GL_INT64_VEC3_NV 0x8FEA #define GL_INT64_VEC4_NV 0x8FEB #define GL_UNSIGNED_INT8_NV 0x8FEC #define GL_UNSIGNED_INT8_VEC2_NV 0x8FED #define GL_UNSIGNED_INT8_VEC3_NV 0x8FEE #define GL_UNSIGNED_INT8_VEC4_NV 0x8FEF #define GL_UNSIGNED_INT16_NV 0x8FF0 #define GL_UNSIGNED_INT16_VEC2_NV 0x8FF1 #define GL_UNSIGNED_INT16_VEC3_NV 0x8FF2 #define GL_UNSIGNED_INT16_VEC4_NV 0x8FF3 #define GL_UNSIGNED_INT64_VEC2_NV 0x8FF5 #define GL_UNSIGNED_INT64_VEC3_NV 0x8FF6 #define GL_UNSIGNED_INT64_VEC4_NV 0x8FF7 #define GL_FLOAT16_NV 0x8FF8 #define GL_FLOAT16_VEC2_NV 0x8FF9 #define GL_FLOAT16_VEC3_NV 0x8FFA #define GL_FLOAT16_VEC4_NV 0x8FFB /* reuse GL_PATCHES */ #endif #ifndef GL_NV_shader_buffer_store #define GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV 0x00000010 /* reuse GL_READ_WRITE */ /* reuse GL_WRITE_ONLY */ #endif #ifndef GL_NV_tessellation_program5 #define GL_MAX_PROGRAM_PATCH_ATTRIBS_NV 0x86D8 #define GL_TESS_CONTROL_PROGRAM_NV 0x891E #define GL_TESS_EVALUATION_PROGRAM_NV 0x891F #define GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV 0x8C74 #define GL_TESS_EVALUATION_PROGRAM_PARAMETER_BUFFER_NV 0x8C75 #endif #ifndef GL_NV_vertex_attrib_integer_64bit /* reuse GL_INT64_NV */ /* reuse GL_UNSIGNED_INT64_NV */ #endif #ifndef GL_NV_multisample_coverage #define GL_COVERAGE_SAMPLES_NV 0x80A9 #define GL_COLOR_SAMPLES_NV 0x8E20 #endif #ifndef GL_AMD_name_gen_delete #define GL_DATA_BUFFER_AMD 0x9151 #define GL_PERFORMANCE_MONITOR_AMD 0x9152 #define GL_QUERY_OBJECT_AMD 0x9153 #define GL_VERTEX_ARRAY_OBJECT_AMD 0x9154 #define GL_SAMPLER_OBJECT_AMD 0x9155 #endif #ifndef GL_AMD_debug_output #define GL_MAX_DEBUG_LOGGED_MESSAGES_AMD 0x9144 #define GL_DEBUG_LOGGED_MESSAGES_AMD 0x9145 #define GL_DEBUG_SEVERITY_HIGH_AMD 0x9146 #define GL_DEBUG_SEVERITY_MEDIUM_AMD 0x9147 #define GL_DEBUG_SEVERITY_LOW_AMD 0x9148 #define GL_DEBUG_CATEGORY_API_ERROR_AMD 0x9149 #define GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD 0x914A #define GL_DEBUG_CATEGORY_DEPRECATION_AMD 0x914B #define GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD 0x914C #define GL_DEBUG_CATEGORY_PERFORMANCE_AMD 0x914D #define GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD 0x914E #define GL_DEBUG_CATEGORY_APPLICATION_AMD 0x914F #define GL_DEBUG_CATEGORY_OTHER_AMD 0x9150 #endif #ifndef GL_NV_vdpau_interop #define GL_SURFACE_STATE_NV 0x86EB #define GL_SURFACE_REGISTERED_NV 0x86FD #define GL_SURFACE_MAPPED_NV 0x8700 #define GL_WRITE_DISCARD_NV 0x88BE #endif #ifndef GL_AMD_transform_feedback3_lines_triangles #endif #ifndef GL_AMD_depth_clamp_separate #define GL_DEPTH_CLAMP_NEAR_AMD 0x901E #define GL_DEPTH_CLAMP_FAR_AMD 0x901F #endif #ifndef GL_EXT_texture_sRGB_decode #define GL_TEXTURE_SRGB_DECODE_EXT 0x8A48 #define GL_DECODE_EXT 0x8A49 #define GL_SKIP_DECODE_EXT 0x8A4A #endif #ifndef GL_NV_texture_multisample #define GL_TEXTURE_COVERAGE_SAMPLES_NV 0x9045 #define GL_TEXTURE_COLOR_SAMPLES_NV 0x9046 #endif #ifndef GL_AMD_blend_minmax_factor #define GL_FACTOR_MIN_AMD 0x901C #define GL_FACTOR_MAX_AMD 0x901D #endif #ifndef GL_AMD_sample_positions #define GL_SUBSAMPLE_DISTANCE_AMD 0x883F #endif #ifndef GL_EXT_x11_sync_object #define GL_SYNC_X11_FENCE_EXT 0x90E1 #endif #ifndef GL_AMD_multi_draw_indirect #endif #ifndef GL_EXT_framebuffer_multisample_blit_scaled #define GL_SCALED_RESOLVE_FASTEST_EXT 0x90BA #define GL_SCALED_RESOLVE_NICEST_EXT 0x90BB #endif /*************************************************************/ #include #ifndef GL_VERSION_2_0 /* GL type for program/shader text */ typedef char GLchar; #endif #ifndef GL_VERSION_1_5 /* GL types for handling large vertex buffer objects */ typedef ptrdiff_t GLintptr; typedef ptrdiff_t GLsizeiptr; #endif #ifndef GL_ARB_vertex_buffer_object /* GL types for handling large vertex buffer objects */ typedef ptrdiff_t GLintptrARB; typedef ptrdiff_t GLsizeiptrARB; #endif #ifndef GL_ARB_shader_objects /* GL types for program/shader text and shader object handles */ typedef char GLcharARB; typedef unsigned int GLhandleARB; #endif /* GL type for "half" precision (s10e5) float data in host memory */ #ifndef GL_ARB_half_float_pixel typedef unsigned short GLhalfARB; #endif #ifndef GL_NV_half_float typedef unsigned short GLhalfNV; #endif #ifndef GLEXT_64_TYPES_DEFINED /* This code block is duplicated in glxext.h, so must be protected */ #define GLEXT_64_TYPES_DEFINED /* Define int32_t, int64_t, and uint64_t types for UST/MSC */ /* (as used in the GL_EXT_timer_query extension). */ #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L #include #elif defined(__sun__) || defined(__digital__) #include #if defined(__STDC__) #if defined(__arch64__) || defined(_LP64) typedef long int int64_t; typedef unsigned long int uint64_t; #else typedef long long int int64_t; typedef unsigned long long int uint64_t; #endif /* __arch64__ */ #endif /* __STDC__ */ #elif defined( __VMS ) || defined(__sgi) #include #elif defined(__SCO__) || defined(__USLC__) #include #elif defined(__UNIXOS2__) || defined(__SOL64__) typedef long int int32_t; typedef long long int int64_t; typedef unsigned long long int uint64_t; #elif defined(_WIN32) && defined(__GNUC__) #include #elif defined(_WIN32) typedef __int32 int32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #else /* Fallback if nothing above works */ #include #endif #endif #ifndef GL_EXT_timer_query typedef int64_t GLint64EXT; typedef uint64_t GLuint64EXT; #endif #ifndef GL_ARB_sync typedef int64_t GLint64; typedef uint64_t GLuint64; typedef struct __GLsync *GLsync; #endif #ifndef GL_ARB_cl_event /* These incomplete types let us declare types compatible with OpenCL's cl_context and cl_event */ struct _cl_context; struct _cl_event; #endif #ifndef GL_ARB_debug_output typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam); #endif #ifndef GL_AMD_debug_output typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam); #endif #ifndef GL_NV_vdpau_interop typedef GLintptr GLvdpauSurfaceNV; #endif #ifndef GL_VERSION_1_2 #define GL_VERSION_1_2 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); GLAPI void APIENTRY glBlendEquation (GLenum mode); GLAPI void APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); GLAPI void APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); GLAPI void APIENTRY glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); GLAPI void APIENTRY glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); #endif #ifndef GL_VERSION_1_2_DEPRECATED #define GL_VERSION_1_2_DEPRECATED 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorTable (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); GLAPI void APIENTRY glColorTableParameterfv (GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glColorTableParameteriv (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glCopyColorTable (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); GLAPI void APIENTRY glGetColorTable (GLenum target, GLenum format, GLenum type, GLvoid *table); GLAPI void APIENTRY glGetColorTableParameterfv (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetColorTableParameteriv (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glColorSubTable (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); GLAPI void APIENTRY glCopyColorSubTable (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); GLAPI void APIENTRY glConvolutionFilter1D (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); GLAPI void APIENTRY glConvolutionFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); GLAPI void APIENTRY glConvolutionParameterf (GLenum target, GLenum pname, GLfloat params); GLAPI void APIENTRY glConvolutionParameterfv (GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glConvolutionParameteri (GLenum target, GLenum pname, GLint params); GLAPI void APIENTRY glConvolutionParameteriv (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glCopyConvolutionFilter1D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); GLAPI void APIENTRY glCopyConvolutionFilter2D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glGetConvolutionFilter (GLenum target, GLenum format, GLenum type, GLvoid *image); GLAPI void APIENTRY glGetConvolutionParameterfv (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetConvolutionParameteriv (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetSeparableFilter (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); GLAPI void APIENTRY glSeparableFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); GLAPI void APIENTRY glGetHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); GLAPI void APIENTRY glGetHistogramParameterfv (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetHistogramParameteriv (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); GLAPI void APIENTRY glGetMinmaxParameterfv (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetMinmaxParameteriv (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glHistogram (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); GLAPI void APIENTRY glMinmax (GLenum target, GLenum internalformat, GLboolean sink); GLAPI void APIENTRY glResetHistogram (GLenum target); GLAPI void APIENTRY glResetMinmax (GLenum target); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image); typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); typedef void (APIENTRYP PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); typedef void (APIENTRYP PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink); typedef void (APIENTRYP PFNGLRESETHISTOGRAMPROC) (GLenum target); typedef void (APIENTRYP PFNGLRESETMINMAXPROC) (GLenum target); #endif #ifndef GL_VERSION_1_3 #define GL_VERSION_1_3 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glActiveTexture (GLenum texture); GLAPI void APIENTRY glSampleCoverage (GLclampf value, GLboolean invert); GLAPI void APIENTRY glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); GLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); GLAPI void APIENTRY glCompressedTexImage1D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); GLAPI void APIENTRY glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); GLAPI void APIENTRY glCompressedTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); GLAPI void APIENTRY glGetCompressedTexImage (GLenum target, GLint level, GLvoid *img); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLclampf value, GLboolean invert); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, GLvoid *img); #endif #ifndef GL_VERSION_1_3_DEPRECATED #define GL_VERSION_1_3_DEPRECATED 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glClientActiveTexture (GLenum texture); GLAPI void APIENTRY glMultiTexCoord1d (GLenum target, GLdouble s); GLAPI void APIENTRY glMultiTexCoord1dv (GLenum target, const GLdouble *v); GLAPI void APIENTRY glMultiTexCoord1f (GLenum target, GLfloat s); GLAPI void APIENTRY glMultiTexCoord1fv (GLenum target, const GLfloat *v); GLAPI void APIENTRY glMultiTexCoord1i (GLenum target, GLint s); GLAPI void APIENTRY glMultiTexCoord1iv (GLenum target, const GLint *v); GLAPI void APIENTRY glMultiTexCoord1s (GLenum target, GLshort s); GLAPI void APIENTRY glMultiTexCoord1sv (GLenum target, const GLshort *v); GLAPI void APIENTRY glMultiTexCoord2d (GLenum target, GLdouble s, GLdouble t); GLAPI void APIENTRY glMultiTexCoord2dv (GLenum target, const GLdouble *v); GLAPI void APIENTRY glMultiTexCoord2f (GLenum target, GLfloat s, GLfloat t); GLAPI void APIENTRY glMultiTexCoord2fv (GLenum target, const GLfloat *v); GLAPI void APIENTRY glMultiTexCoord2i (GLenum target, GLint s, GLint t); GLAPI void APIENTRY glMultiTexCoord2iv (GLenum target, const GLint *v); GLAPI void APIENTRY glMultiTexCoord2s (GLenum target, GLshort s, GLshort t); GLAPI void APIENTRY glMultiTexCoord2sv (GLenum target, const GLshort *v); GLAPI void APIENTRY glMultiTexCoord3d (GLenum target, GLdouble s, GLdouble t, GLdouble r); GLAPI void APIENTRY glMultiTexCoord3dv (GLenum target, const GLdouble *v); GLAPI void APIENTRY glMultiTexCoord3f (GLenum target, GLfloat s, GLfloat t, GLfloat r); GLAPI void APIENTRY glMultiTexCoord3fv (GLenum target, const GLfloat *v); GLAPI void APIENTRY glMultiTexCoord3i (GLenum target, GLint s, GLint t, GLint r); GLAPI void APIENTRY glMultiTexCoord3iv (GLenum target, const GLint *v); GLAPI void APIENTRY glMultiTexCoord3s (GLenum target, GLshort s, GLshort t, GLshort r); GLAPI void APIENTRY glMultiTexCoord3sv (GLenum target, const GLshort *v); GLAPI void APIENTRY glMultiTexCoord4d (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); GLAPI void APIENTRY glMultiTexCoord4dv (GLenum target, const GLdouble *v); GLAPI void APIENTRY glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); GLAPI void APIENTRY glMultiTexCoord4fv (GLenum target, const GLfloat *v); GLAPI void APIENTRY glMultiTexCoord4i (GLenum target, GLint s, GLint t, GLint r, GLint q); GLAPI void APIENTRY glMultiTexCoord4iv (GLenum target, const GLint *v); GLAPI void APIENTRY glMultiTexCoord4s (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); GLAPI void APIENTRY glMultiTexCoord4sv (GLenum target, const GLshort *v); GLAPI void APIENTRY glLoadTransposeMatrixf (const GLfloat *m); GLAPI void APIENTRY glLoadTransposeMatrixd (const GLdouble *m); GLAPI void APIENTRY glMultTransposeMatrixf (const GLfloat *m); GLAPI void APIENTRY glMultTransposeMatrixd (const GLdouble *m); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture); typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC) (GLenum target, GLint s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m); typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m); typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m); typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m); #endif #ifndef GL_VERSION_1_4 #define GL_VERSION_1_4 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); GLAPI void APIENTRY glMultiDrawArrays (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); GLAPI void APIENTRY glMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); GLAPI void APIENTRY glPointParameterf (GLenum pname, GLfloat param); GLAPI void APIENTRY glPointParameterfv (GLenum pname, const GLfloat *params); GLAPI void APIENTRY glPointParameteri (GLenum pname, GLint param); GLAPI void APIENTRY glPointParameteriv (GLenum pname, const GLint *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params); #endif #ifndef GL_VERSION_1_4_DEPRECATED #define GL_VERSION_1_4_DEPRECATED 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFogCoordf (GLfloat coord); GLAPI void APIENTRY glFogCoordfv (const GLfloat *coord); GLAPI void APIENTRY glFogCoordd (GLdouble coord); GLAPI void APIENTRY glFogCoorddv (const GLdouble *coord); GLAPI void APIENTRY glFogCoordPointer (GLenum type, GLsizei stride, const GLvoid *pointer); GLAPI void APIENTRY glSecondaryColor3b (GLbyte red, GLbyte green, GLbyte blue); GLAPI void APIENTRY glSecondaryColor3bv (const GLbyte *v); GLAPI void APIENTRY glSecondaryColor3d (GLdouble red, GLdouble green, GLdouble blue); GLAPI void APIENTRY glSecondaryColor3dv (const GLdouble *v); GLAPI void APIENTRY glSecondaryColor3f (GLfloat red, GLfloat green, GLfloat blue); GLAPI void APIENTRY glSecondaryColor3fv (const GLfloat *v); GLAPI void APIENTRY glSecondaryColor3i (GLint red, GLint green, GLint blue); GLAPI void APIENTRY glSecondaryColor3iv (const GLint *v); GLAPI void APIENTRY glSecondaryColor3s (GLshort red, GLshort green, GLshort blue); GLAPI void APIENTRY glSecondaryColor3sv (const GLshort *v); GLAPI void APIENTRY glSecondaryColor3ub (GLubyte red, GLubyte green, GLubyte blue); GLAPI void APIENTRY glSecondaryColor3ubv (const GLubyte *v); GLAPI void APIENTRY glSecondaryColor3ui (GLuint red, GLuint green, GLuint blue); GLAPI void APIENTRY glSecondaryColor3uiv (const GLuint *v); GLAPI void APIENTRY glSecondaryColor3us (GLushort red, GLushort green, GLushort blue); GLAPI void APIENTRY glSecondaryColor3usv (const GLushort *v); GLAPI void APIENTRY glSecondaryColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); GLAPI void APIENTRY glWindowPos2d (GLdouble x, GLdouble y); GLAPI void APIENTRY glWindowPos2dv (const GLdouble *v); GLAPI void APIENTRY glWindowPos2f (GLfloat x, GLfloat y); GLAPI void APIENTRY glWindowPos2fv (const GLfloat *v); GLAPI void APIENTRY glWindowPos2i (GLint x, GLint y); GLAPI void APIENTRY glWindowPos2iv (const GLint *v); GLAPI void APIENTRY glWindowPos2s (GLshort x, GLshort y); GLAPI void APIENTRY glWindowPos2sv (const GLshort *v); GLAPI void APIENTRY glWindowPos3d (GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glWindowPos3dv (const GLdouble *v); GLAPI void APIENTRY glWindowPos3f (GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glWindowPos3fv (const GLfloat *v); GLAPI void APIENTRY glWindowPos3i (GLint x, GLint y, GLint z); GLAPI void APIENTRY glWindowPos3iv (const GLint *v); GLAPI void APIENTRY glWindowPos3s (GLshort x, GLshort y, GLshort z); GLAPI void APIENTRY glWindowPos3sv (const GLshort *v); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFOGCOORDFPROC) (GLfloat coord); typedef void (APIENTRYP PFNGLFOGCOORDFVPROC) (const GLfloat *coord); typedef void (APIENTRYP PFNGLFOGCOORDDPROC) (GLdouble coord); typedef void (APIENTRYP PFNGLFOGCOORDDVPROC) (const GLdouble *coord); typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC) (const GLbyte *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC) (const GLint *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC) (const GLuint *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC) (const GLushort *v); typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS2IPROC) (GLint x, GLint y); typedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS2SPROC) (GLshort x, GLshort y); typedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC) (const GLshort *v); #endif #ifndef GL_VERSION_1_5 #define GL_VERSION_1_5 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGenQueries (GLsizei n, GLuint *ids); GLAPI void APIENTRY glDeleteQueries (GLsizei n, const GLuint *ids); GLAPI GLboolean APIENTRY glIsQuery (GLuint id); GLAPI void APIENTRY glBeginQuery (GLenum target, GLuint id); GLAPI void APIENTRY glEndQuery (GLenum target); GLAPI void APIENTRY glGetQueryiv (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetQueryObjectiv (GLuint id, GLenum pname, GLint *params); GLAPI void APIENTRY glGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params); GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer); GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); GLAPI GLboolean APIENTRY glIsBuffer (GLuint buffer); GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); GLAPI void APIENTRY glGetBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); GLAPI GLvoid* APIENTRY glMapBuffer (GLenum target, GLenum access); GLAPI GLboolean APIENTRY glUnmapBuffer (GLenum target); GLAPI void APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetBufferPointerv (GLenum target, GLenum pname, GLvoid* *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids); typedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids); typedef GLboolean (APIENTRYP PFNGLISQUERYPROC) (GLuint id); typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id); typedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target); typedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access); typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target); typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, GLvoid* *params); #endif #ifndef GL_VERSION_2_0 #define GL_VERSION_2_0 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha); GLAPI void APIENTRY glDrawBuffers (GLsizei n, const GLenum *bufs); GLAPI void APIENTRY glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); GLAPI void APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask); GLAPI void APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask); GLAPI void APIENTRY glAttachShader (GLuint program, GLuint shader); GLAPI void APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name); GLAPI void APIENTRY glCompileShader (GLuint shader); GLAPI GLuint APIENTRY glCreateProgram (void); GLAPI GLuint APIENTRY glCreateShader (GLenum type); GLAPI void APIENTRY glDeleteProgram (GLuint program); GLAPI void APIENTRY glDeleteShader (GLuint shader); GLAPI void APIENTRY glDetachShader (GLuint program, GLuint shader); GLAPI void APIENTRY glDisableVertexAttribArray (GLuint index); GLAPI void APIENTRY glEnableVertexAttribArray (GLuint index); GLAPI void APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); GLAPI void APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); GLAPI void APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *obj); GLAPI GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name); GLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params); GLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); GLAPI void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params); GLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); GLAPI void APIENTRY glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); GLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name); GLAPI void APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat *params); GLAPI void APIENTRY glGetUniformiv (GLuint program, GLint location, GLint *params); GLAPI void APIENTRY glGetVertexAttribdv (GLuint index, GLenum pname, GLdouble *params); GLAPI void APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params); GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid* *pointer); GLAPI GLboolean APIENTRY glIsProgram (GLuint program); GLAPI GLboolean APIENTRY glIsShader (GLuint shader); GLAPI void APIENTRY glLinkProgram (GLuint program); GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar* *string, const GLint *length); GLAPI void APIENTRY glUseProgram (GLuint program); GLAPI void APIENTRY glUniform1f (GLint location, GLfloat v0); GLAPI void APIENTRY glUniform2f (GLint location, GLfloat v0, GLfloat v1); GLAPI void APIENTRY glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); GLAPI void APIENTRY glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); GLAPI void APIENTRY glUniform1i (GLint location, GLint v0); GLAPI void APIENTRY glUniform2i (GLint location, GLint v0, GLint v1); GLAPI void APIENTRY glUniform3i (GLint location, GLint v0, GLint v1, GLint v2); GLAPI void APIENTRY glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); GLAPI void APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glValidateProgram (GLuint program); GLAPI void APIENTRY glVertexAttrib1d (GLuint index, GLdouble x); GLAPI void APIENTRY glVertexAttrib1dv (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib1f (GLuint index, GLfloat x); GLAPI void APIENTRY glVertexAttrib1fv (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib1s (GLuint index, GLshort x); GLAPI void APIENTRY glVertexAttrib1sv (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib2d (GLuint index, GLdouble x, GLdouble y); GLAPI void APIENTRY glVertexAttrib2dv (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y); GLAPI void APIENTRY glVertexAttrib2fv (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib2s (GLuint index, GLshort x, GLshort y); GLAPI void APIENTRY glVertexAttrib2sv (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib3d (GLuint index, GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glVertexAttrib3dv (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glVertexAttrib3fv (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib3s (GLuint index, GLshort x, GLshort y, GLshort z); GLAPI void APIENTRY glVertexAttrib3sv (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib4Nbv (GLuint index, const GLbyte *v); GLAPI void APIENTRY glVertexAttrib4Niv (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttrib4Nsv (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib4Nub (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); GLAPI void APIENTRY glVertexAttrib4Nubv (GLuint index, const GLubyte *v); GLAPI void APIENTRY glVertexAttrib4Nuiv (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttrib4Nusv (GLuint index, const GLushort *v); GLAPI void APIENTRY glVertexAttrib4bv (GLuint index, const GLbyte *v); GLAPI void APIENTRY glVertexAttrib4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glVertexAttrib4dv (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glVertexAttrib4fv (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib4iv (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttrib4s (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); GLAPI void APIENTRY glVertexAttrib4sv (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib4ubv (GLuint index, const GLubyte *v); GLAPI void APIENTRY glVertexAttrib4uiv (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttrib4usv (GLuint index, const GLushort *v); GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha); typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs); typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask); typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask); typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name); typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void); typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program); typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader); typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader); typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index); typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *obj); typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name); typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name); typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params); typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, GLvoid* *pointer); typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program); typedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader); typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* *string, const GLint *length); typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program); typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1); typedef void (APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0); typedef void (APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1); typedef void (APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2); typedef void (APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program); typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); #endif #ifndef GL_VERSION_2_1 #define GL_VERSION_2_1 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glUniformMatrix2x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glUniformMatrix3x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glUniformMatrix2x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glUniformMatrix4x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glUniformMatrix3x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glUniformMatrix4x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); #endif #ifndef GL_VERSION_3_0 #define GL_VERSION_3_0 1 /* OpenGL 3.0 also reuses entry points from these extensions: */ /* ARB_framebuffer_object */ /* ARB_map_buffer_range */ /* ARB_vertex_array_object */ #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorMaski (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); GLAPI void APIENTRY glGetBooleani_v (GLenum target, GLuint index, GLboolean *data); GLAPI void APIENTRY glGetIntegeri_v (GLenum target, GLuint index, GLint *data); GLAPI void APIENTRY glEnablei (GLenum target, GLuint index); GLAPI void APIENTRY glDisablei (GLenum target, GLuint index); GLAPI GLboolean APIENTRY glIsEnabledi (GLenum target, GLuint index); GLAPI void APIENTRY glBeginTransformFeedback (GLenum primitiveMode); GLAPI void APIENTRY glEndTransformFeedback (void); GLAPI void APIENTRY glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); GLAPI void APIENTRY glBindBufferBase (GLenum target, GLuint index, GLuint buffer); GLAPI void APIENTRY glTransformFeedbackVaryings (GLuint program, GLsizei count, const GLchar* *varyings, GLenum bufferMode); GLAPI void APIENTRY glGetTransformFeedbackVarying (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); GLAPI void APIENTRY glClampColor (GLenum target, GLenum clamp); GLAPI void APIENTRY glBeginConditionalRender (GLuint id, GLenum mode); GLAPI void APIENTRY glEndConditionalRender (void); GLAPI void APIENTRY glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); GLAPI void APIENTRY glGetVertexAttribIiv (GLuint index, GLenum pname, GLint *params); GLAPI void APIENTRY glGetVertexAttribIuiv (GLuint index, GLenum pname, GLuint *params); GLAPI void APIENTRY glVertexAttribI1i (GLuint index, GLint x); GLAPI void APIENTRY glVertexAttribI2i (GLuint index, GLint x, GLint y); GLAPI void APIENTRY glVertexAttribI3i (GLuint index, GLint x, GLint y, GLint z); GLAPI void APIENTRY glVertexAttribI4i (GLuint index, GLint x, GLint y, GLint z, GLint w); GLAPI void APIENTRY glVertexAttribI1ui (GLuint index, GLuint x); GLAPI void APIENTRY glVertexAttribI2ui (GLuint index, GLuint x, GLuint y); GLAPI void APIENTRY glVertexAttribI3ui (GLuint index, GLuint x, GLuint y, GLuint z); GLAPI void APIENTRY glVertexAttribI4ui (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); GLAPI void APIENTRY glVertexAttribI1iv (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttribI2iv (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttribI3iv (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttribI4iv (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttribI1uiv (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttribI2uiv (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttribI3uiv (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttribI4uiv (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttribI4bv (GLuint index, const GLbyte *v); GLAPI void APIENTRY glVertexAttribI4sv (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttribI4ubv (GLuint index, const GLubyte *v); GLAPI void APIENTRY glVertexAttribI4usv (GLuint index, const GLushort *v); GLAPI void APIENTRY glGetUniformuiv (GLuint program, GLint location, GLuint *params); GLAPI void APIENTRY glBindFragDataLocation (GLuint program, GLuint color, const GLchar *name); GLAPI GLint APIENTRY glGetFragDataLocation (GLuint program, const GLchar *name); GLAPI void APIENTRY glUniform1ui (GLint location, GLuint v0); GLAPI void APIENTRY glUniform2ui (GLint location, GLuint v0, GLuint v1); GLAPI void APIENTRY glUniform3ui (GLint location, GLuint v0, GLuint v1, GLuint v2); GLAPI void APIENTRY glUniform4ui (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); GLAPI void APIENTRY glUniform1uiv (GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glUniform2uiv (GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glUniform3uiv (GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glUniform4uiv (GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glTexParameterIiv (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glTexParameterIuiv (GLenum target, GLenum pname, const GLuint *params); GLAPI void APIENTRY glGetTexParameterIiv (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetTexParameterIuiv (GLenum target, GLenum pname, GLuint *params); GLAPI void APIENTRY glClearBufferiv (GLenum buffer, GLint drawbuffer, const GLint *value); GLAPI void APIENTRY glClearBufferuiv (GLenum buffer, GLint drawbuffer, const GLuint *value); GLAPI void APIENTRY glClearBufferfv (GLenum buffer, GLint drawbuffer, const GLfloat *value); GLAPI void APIENTRY glClearBufferfi (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); GLAPI const GLubyte * APIENTRY glGetStringi (GLenum name, GLuint index); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOLORMASKIPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data); typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data); typedef void (APIENTRYP PFNGLENABLEIPROC) (GLenum target, GLuint index); typedef void (APIENTRYP PFNGLDISABLEIPROC) (GLenum target, GLuint index); typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC) (GLenum target, GLuint index); typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode); typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC) (void); typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer); typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar* *varyings, GLenum bufferMode); typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); typedef void (APIENTRYP PFNGLCLAMPCOLORPROC) (GLenum target, GLenum clamp); typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC) (GLuint id, GLenum mode); typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC) (void); typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC) (GLuint index, GLint x); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC) (GLuint index, GLint x, GLint y); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC) (GLuint index, GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC) (GLuint index, GLuint x); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC) (GLuint index, GLuint x, GLuint y); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC) (GLuint index, const GLbyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC) (GLuint index, const GLushort *v); typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params); typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC) (GLuint program, GLuint color, const GLchar *name); typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name); typedef void (APIENTRYP PFNGLUNIFORM1UIPROC) (GLint location, GLuint v0); typedef void (APIENTRYP PFNGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1); typedef void (APIENTRYP PFNGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); typedef void (APIENTRYP PFNGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, const GLuint *params); typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value); typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value); typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value); typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index); #endif #ifndef GL_VERSION_3_1 #define GL_VERSION_3_1 1 /* OpenGL 3.1 also reuses entry points from these extensions: */ /* ARB_copy_buffer */ /* ARB_uniform_buffer_object */ #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei primcount); GLAPI void APIENTRY glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); GLAPI void APIENTRY glTexBuffer (GLenum target, GLenum internalformat, GLuint buffer); GLAPI void APIENTRY glPrimitiveRestartIndex (GLuint index); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount); typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); typedef void (APIENTRYP PFNGLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer); typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC) (GLuint index); #endif #ifndef GL_VERSION_3_2 #define GL_VERSION_3_2 1 /* OpenGL 3.2 also reuses entry points from these extensions: */ /* ARB_draw_elements_base_vertex */ /* ARB_provoking_vertex */ /* ARB_sync */ /* ARB_texture_multisample */ #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetInteger64i_v (GLenum target, GLuint index, GLint64 *data); GLAPI void APIENTRY glGetBufferParameteri64v (GLenum target, GLenum pname, GLint64 *params); GLAPI void APIENTRY glFramebufferTexture (GLenum target, GLenum attachment, GLuint texture, GLint level); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data); typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); #endif #ifndef GL_VERSION_3_3 #define GL_VERSION_3_3 1 /* OpenGL 3.3 also reuses entry points from these extensions: */ /* ARB_blend_func_extended */ /* ARB_sampler_objects */ /* ARB_explicit_attrib_location, but it has none */ /* ARB_occlusion_query2 (no entry points) */ /* ARB_shader_bit_encoding (no entry points) */ /* ARB_texture_rgb10_a2ui (no entry points) */ /* ARB_texture_swizzle (no entry points) */ /* ARB_timer_query */ /* ARB_vertex_type_2_10_10_10_rev */ #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttribDivisor (GLuint index, GLuint divisor); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor); #endif #ifndef GL_VERSION_4_0 #define GL_VERSION_4_0 1 /* OpenGL 4.0 also reuses entry points from these extensions: */ /* ARB_texture_query_lod (no entry points) */ /* ARB_draw_indirect */ /* ARB_gpu_shader5 (no entry points) */ /* ARB_gpu_shader_fp64 */ /* ARB_shader_subroutine */ /* ARB_tessellation_shader */ /* ARB_texture_buffer_object_rgb32 (no entry points) */ /* ARB_texture_cube_map_array (no entry points) */ /* ARB_texture_gather (no entry points) */ /* ARB_transform_feedback2 */ /* ARB_transform_feedback3 */ #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMinSampleShading (GLclampf value); GLAPI void APIENTRY glBlendEquationi (GLuint buf, GLenum mode); GLAPI void APIENTRY glBlendEquationSeparatei (GLuint buf, GLenum modeRGB, GLenum modeAlpha); GLAPI void APIENTRY glBlendFunci (GLuint buf, GLenum src, GLenum dst); GLAPI void APIENTRY glBlendFuncSeparatei (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLMINSAMPLESHADINGPROC) (GLclampf value); typedef void (APIENTRYP PFNGLBLENDEQUATIONIPROC) (GLuint buf, GLenum mode); typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); typedef void (APIENTRYP PFNGLBLENDFUNCIPROC) (GLuint buf, GLenum src, GLenum dst); typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); #endif #ifndef GL_VERSION_4_1 #define GL_VERSION_4_1 1 /* OpenGL 4.1 reuses entry points from these extensions: */ /* ARB_ES2_compatibility */ /* ARB_get_program_binary */ /* ARB_separate_shader_objects */ /* ARB_shader_precision (no entry points) */ /* ARB_vertex_attrib_64bit */ /* ARB_viewport_array */ #endif #ifndef GL_VERSION_4_2 #define GL_VERSION_4_2 1 /* OpenGL 4.2 reuses entry points from these extensions: */ /* ARB_base_instance */ /* ARB_shading_language_420pack (no entry points) */ /* ARB_transform_feedback_instanced */ /* ARB_compressed_texture_pixel_storage (no entry points) */ /* ARB_conservative_depth (no entry points) */ /* ARB_internalformat_query */ /* ARB_map_buffer_alignment (no entry points) */ /* ARB_shader_atomic_counters */ /* ARB_shader_image_load_store */ /* ARB_shading_language_packing (no entry points) */ /* ARB_texture_storage */ #endif #ifndef GL_ARB_multitexture #define GL_ARB_multitexture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glActiveTextureARB (GLenum texture); GLAPI void APIENTRY glClientActiveTextureARB (GLenum texture); GLAPI void APIENTRY glMultiTexCoord1dARB (GLenum target, GLdouble s); GLAPI void APIENTRY glMultiTexCoord1dvARB (GLenum target, const GLdouble *v); GLAPI void APIENTRY glMultiTexCoord1fARB (GLenum target, GLfloat s); GLAPI void APIENTRY glMultiTexCoord1fvARB (GLenum target, const GLfloat *v); GLAPI void APIENTRY glMultiTexCoord1iARB (GLenum target, GLint s); GLAPI void APIENTRY glMultiTexCoord1ivARB (GLenum target, const GLint *v); GLAPI void APIENTRY glMultiTexCoord1sARB (GLenum target, GLshort s); GLAPI void APIENTRY glMultiTexCoord1svARB (GLenum target, const GLshort *v); GLAPI void APIENTRY glMultiTexCoord2dARB (GLenum target, GLdouble s, GLdouble t); GLAPI void APIENTRY glMultiTexCoord2dvARB (GLenum target, const GLdouble *v); GLAPI void APIENTRY glMultiTexCoord2fARB (GLenum target, GLfloat s, GLfloat t); GLAPI void APIENTRY glMultiTexCoord2fvARB (GLenum target, const GLfloat *v); GLAPI void APIENTRY glMultiTexCoord2iARB (GLenum target, GLint s, GLint t); GLAPI void APIENTRY glMultiTexCoord2ivARB (GLenum target, const GLint *v); GLAPI void APIENTRY glMultiTexCoord2sARB (GLenum target, GLshort s, GLshort t); GLAPI void APIENTRY glMultiTexCoord2svARB (GLenum target, const GLshort *v); GLAPI void APIENTRY glMultiTexCoord3dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r); GLAPI void APIENTRY glMultiTexCoord3dvARB (GLenum target, const GLdouble *v); GLAPI void APIENTRY glMultiTexCoord3fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r); GLAPI void APIENTRY glMultiTexCoord3fvARB (GLenum target, const GLfloat *v); GLAPI void APIENTRY glMultiTexCoord3iARB (GLenum target, GLint s, GLint t, GLint r); GLAPI void APIENTRY glMultiTexCoord3ivARB (GLenum target, const GLint *v); GLAPI void APIENTRY glMultiTexCoord3sARB (GLenum target, GLshort s, GLshort t, GLshort r); GLAPI void APIENTRY glMultiTexCoord3svARB (GLenum target, const GLshort *v); GLAPI void APIENTRY glMultiTexCoord4dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); GLAPI void APIENTRY glMultiTexCoord4dvARB (GLenum target, const GLdouble *v); GLAPI void APIENTRY glMultiTexCoord4fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); GLAPI void APIENTRY glMultiTexCoord4fvARB (GLenum target, const GLfloat *v); GLAPI void APIENTRY glMultiTexCoord4iARB (GLenum target, GLint s, GLint t, GLint r, GLint q); GLAPI void APIENTRY glMultiTexCoord4ivARB (GLenum target, const GLint *v); GLAPI void APIENTRY glMultiTexCoord4sARB (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); GLAPI void APIENTRY glMultiTexCoord4svARB (GLenum target, const GLshort *v); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLACTIVETEXTUREARBPROC) (GLenum texture); typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture); typedef void (APIENTRYP PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v); #endif #ifndef GL_ARB_transpose_matrix #define GL_ARB_transpose_matrix 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glLoadTransposeMatrixfARB (const GLfloat *m); GLAPI void APIENTRY glLoadTransposeMatrixdARB (const GLdouble *m); GLAPI void APIENTRY glMultTransposeMatrixfARB (const GLfloat *m); GLAPI void APIENTRY glMultTransposeMatrixdARB (const GLdouble *m); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); #endif #ifndef GL_ARB_multisample #define GL_ARB_multisample 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSampleCoverageARB (GLclampf value, GLboolean invert); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC) (GLclampf value, GLboolean invert); #endif #ifndef GL_ARB_texture_env_add #define GL_ARB_texture_env_add 1 #endif #ifndef GL_ARB_texture_cube_map #define GL_ARB_texture_cube_map 1 #endif #ifndef GL_ARB_texture_compression #define GL_ARB_texture_compression 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCompressedTexImage3DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); GLAPI void APIENTRY glCompressedTexImage2DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); GLAPI void APIENTRY glCompressedTexImage1DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); GLAPI void APIENTRY glCompressedTexSubImage3DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); GLAPI void APIENTRY glCompressedTexSubImage2DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); GLAPI void APIENTRY glCompressedTexSubImage1DARB (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); GLAPI void APIENTRY glGetCompressedTexImageARB (GLenum target, GLint level, GLvoid *img); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, GLvoid *img); #endif #ifndef GL_ARB_texture_border_clamp #define GL_ARB_texture_border_clamp 1 #endif #ifndef GL_ARB_point_parameters #define GL_ARB_point_parameters 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPointParameterfARB (GLenum pname, GLfloat param); GLAPI void APIENTRY glPointParameterfvARB (GLenum pname, const GLfloat *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params); #endif #ifndef GL_ARB_vertex_blend #define GL_ARB_vertex_blend 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glWeightbvARB (GLint size, const GLbyte *weights); GLAPI void APIENTRY glWeightsvARB (GLint size, const GLshort *weights); GLAPI void APIENTRY glWeightivARB (GLint size, const GLint *weights); GLAPI void APIENTRY glWeightfvARB (GLint size, const GLfloat *weights); GLAPI void APIENTRY glWeightdvARB (GLint size, const GLdouble *weights); GLAPI void APIENTRY glWeightubvARB (GLint size, const GLubyte *weights); GLAPI void APIENTRY glWeightusvARB (GLint size, const GLushort *weights); GLAPI void APIENTRY glWeightuivARB (GLint size, const GLuint *weights); GLAPI void APIENTRY glWeightPointerARB (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); GLAPI void APIENTRY glVertexBlendARB (GLint count); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights); typedef void (APIENTRYP PFNGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights); typedef void (APIENTRYP PFNGLWEIGHTIVARBPROC) (GLint size, const GLint *weights); typedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights); typedef void (APIENTRYP PFNGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights); typedef void (APIENTRYP PFNGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights); typedef void (APIENTRYP PFNGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights); typedef void (APIENTRYP PFNGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights); typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count); #endif #ifndef GL_ARB_matrix_palette #define GL_ARB_matrix_palette 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCurrentPaletteMatrixARB (GLint index); GLAPI void APIENTRY glMatrixIndexubvARB (GLint size, const GLubyte *indices); GLAPI void APIENTRY glMatrixIndexusvARB (GLint size, const GLushort *indices); GLAPI void APIENTRY glMatrixIndexuivARB (GLint size, const GLuint *indices); GLAPI void APIENTRY glMatrixIndexPointerARB (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index); typedef void (APIENTRYP PFNGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices); typedef void (APIENTRYP PFNGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices); typedef void (APIENTRYP PFNGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices); typedef void (APIENTRYP PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); #endif #ifndef GL_ARB_texture_env_combine #define GL_ARB_texture_env_combine 1 #endif #ifndef GL_ARB_texture_env_crossbar #define GL_ARB_texture_env_crossbar 1 #endif #ifndef GL_ARB_texture_env_dot3 #define GL_ARB_texture_env_dot3 1 #endif #ifndef GL_ARB_texture_mirrored_repeat #define GL_ARB_texture_mirrored_repeat 1 #endif #ifndef GL_ARB_depth_texture #define GL_ARB_depth_texture 1 #endif #ifndef GL_ARB_shadow #define GL_ARB_shadow 1 #endif #ifndef GL_ARB_shadow_ambient #define GL_ARB_shadow_ambient 1 #endif #ifndef GL_ARB_window_pos #define GL_ARB_window_pos 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glWindowPos2dARB (GLdouble x, GLdouble y); GLAPI void APIENTRY glWindowPos2dvARB (const GLdouble *v); GLAPI void APIENTRY glWindowPos2fARB (GLfloat x, GLfloat y); GLAPI void APIENTRY glWindowPos2fvARB (const GLfloat *v); GLAPI void APIENTRY glWindowPos2iARB (GLint x, GLint y); GLAPI void APIENTRY glWindowPos2ivARB (const GLint *v); GLAPI void APIENTRY glWindowPos2sARB (GLshort x, GLshort y); GLAPI void APIENTRY glWindowPos2svARB (const GLshort *v); GLAPI void APIENTRY glWindowPos3dARB (GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glWindowPos3dvARB (const GLdouble *v); GLAPI void APIENTRY glWindowPos3fARB (GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glWindowPos3fvARB (const GLfloat *v); GLAPI void APIENTRY glWindowPos3iARB (GLint x, GLint y, GLint z); GLAPI void APIENTRY glWindowPos3ivARB (const GLint *v); GLAPI void APIENTRY glWindowPos3sARB (GLshort x, GLshort y, GLshort z); GLAPI void APIENTRY glWindowPos3svARB (const GLshort *v); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLWINDOWPOS2DVARBPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLWINDOWPOS2FVARBPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS2IARBPROC) (GLint x, GLint y); typedef void (APIENTRYP PFNGLWINDOWPOS2IVARBPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y); typedef void (APIENTRYP PFNGLWINDOWPOS2SVARBPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLWINDOWPOS3DVARBPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLWINDOWPOS3FVARBPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLWINDOWPOS3IVARBPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLWINDOWPOS3SVARBPROC) (const GLshort *v); #endif #ifndef GL_ARB_vertex_program #define GL_ARB_vertex_program 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttrib1dARB (GLuint index, GLdouble x); GLAPI void APIENTRY glVertexAttrib1dvARB (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib1fARB (GLuint index, GLfloat x); GLAPI void APIENTRY glVertexAttrib1fvARB (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib1sARB (GLuint index, GLshort x); GLAPI void APIENTRY glVertexAttrib1svARB (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib2dARB (GLuint index, GLdouble x, GLdouble y); GLAPI void APIENTRY glVertexAttrib2dvARB (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib2fARB (GLuint index, GLfloat x, GLfloat y); GLAPI void APIENTRY glVertexAttrib2fvARB (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib2sARB (GLuint index, GLshort x, GLshort y); GLAPI void APIENTRY glVertexAttrib2svARB (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib3dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glVertexAttrib3dvARB (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib3fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glVertexAttrib3fvARB (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib3sARB (GLuint index, GLshort x, GLshort y, GLshort z); GLAPI void APIENTRY glVertexAttrib3svARB (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib4NbvARB (GLuint index, const GLbyte *v); GLAPI void APIENTRY glVertexAttrib4NivARB (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttrib4NsvARB (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib4NubARB (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); GLAPI void APIENTRY glVertexAttrib4NubvARB (GLuint index, const GLubyte *v); GLAPI void APIENTRY glVertexAttrib4NuivARB (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttrib4NusvARB (GLuint index, const GLushort *v); GLAPI void APIENTRY glVertexAttrib4bvARB (GLuint index, const GLbyte *v); GLAPI void APIENTRY glVertexAttrib4dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glVertexAttrib4dvARB (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib4fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glVertexAttrib4fvARB (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib4ivARB (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttrib4sARB (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); GLAPI void APIENTRY glVertexAttrib4svARB (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib4ubvARB (GLuint index, const GLubyte *v); GLAPI void APIENTRY glVertexAttrib4uivARB (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttrib4usvARB (GLuint index, const GLushort *v); GLAPI void APIENTRY glVertexAttribPointerARB (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); GLAPI void APIENTRY glEnableVertexAttribArrayARB (GLuint index); GLAPI void APIENTRY glDisableVertexAttribArrayARB (GLuint index); GLAPI void APIENTRY glProgramStringARB (GLenum target, GLenum format, GLsizei len, const GLvoid *string); GLAPI void APIENTRY glBindProgramARB (GLenum target, GLuint program); GLAPI void APIENTRY glDeleteProgramsARB (GLsizei n, const GLuint *programs); GLAPI void APIENTRY glGenProgramsARB (GLsizei n, GLuint *programs); GLAPI void APIENTRY glProgramEnvParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glProgramEnvParameter4dvARB (GLenum target, GLuint index, const GLdouble *params); GLAPI void APIENTRY glProgramEnvParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glProgramEnvParameter4fvARB (GLenum target, GLuint index, const GLfloat *params); GLAPI void APIENTRY glProgramLocalParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glProgramLocalParameter4dvARB (GLenum target, GLuint index, const GLdouble *params); GLAPI void APIENTRY glProgramLocalParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glProgramLocalParameter4fvARB (GLenum target, GLuint index, const GLfloat *params); GLAPI void APIENTRY glGetProgramEnvParameterdvARB (GLenum target, GLuint index, GLdouble *params); GLAPI void APIENTRY glGetProgramEnvParameterfvARB (GLenum target, GLuint index, GLfloat *params); GLAPI void APIENTRY glGetProgramLocalParameterdvARB (GLenum target, GLuint index, GLdouble *params); GLAPI void APIENTRY glGetProgramLocalParameterfvARB (GLenum target, GLuint index, GLfloat *params); GLAPI void APIENTRY glGetProgramivARB (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetProgramStringARB (GLenum target, GLenum pname, GLvoid *string); GLAPI void APIENTRY glGetVertexAttribdvARB (GLuint index, GLenum pname, GLdouble *params); GLAPI void APIENTRY glGetVertexAttribfvARB (GLuint index, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetVertexAttribivARB (GLuint index, GLenum pname, GLint *params); GLAPI void APIENTRY glGetVertexAttribPointervARB (GLuint index, GLenum pname, GLvoid* *pointer); GLAPI GLboolean APIENTRY glIsProgramARB (GLuint program); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const GLvoid *string); typedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program); typedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs); typedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, GLvoid *string); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, GLvoid* *pointer); typedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC) (GLuint program); #endif #ifndef GL_ARB_fragment_program #define GL_ARB_fragment_program 1 /* All ARB_fragment_program entry points are shared with ARB_vertex_program. */ #endif #ifndef GL_ARB_vertex_buffer_object #define GL_ARB_vertex_buffer_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindBufferARB (GLenum target, GLuint buffer); GLAPI void APIENTRY glDeleteBuffersARB (GLsizei n, const GLuint *buffers); GLAPI void APIENTRY glGenBuffersARB (GLsizei n, GLuint *buffers); GLAPI GLboolean APIENTRY glIsBufferARB (GLuint buffer); GLAPI void APIENTRY glBufferDataARB (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); GLAPI void APIENTRY glBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); GLAPI void APIENTRY glGetBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data); GLAPI GLvoid* APIENTRY glMapBufferARB (GLenum target, GLenum access); GLAPI GLboolean APIENTRY glUnmapBufferARB (GLenum target); GLAPI void APIENTRY glGetBufferParameterivARB (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetBufferPointervARB (GLenum target, GLenum pname, GLvoid* *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer); typedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers); typedef void (APIENTRYP PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers); typedef GLboolean (APIENTRYP PFNGLISBUFFERARBPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); typedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data); typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access); typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC) (GLenum target); typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, GLvoid* *params); #endif #ifndef GL_ARB_occlusion_query #define GL_ARB_occlusion_query 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGenQueriesARB (GLsizei n, GLuint *ids); GLAPI void APIENTRY glDeleteQueriesARB (GLsizei n, const GLuint *ids); GLAPI GLboolean APIENTRY glIsQueryARB (GLuint id); GLAPI void APIENTRY glBeginQueryARB (GLenum target, GLuint id); GLAPI void APIENTRY glEndQueryARB (GLenum target); GLAPI void APIENTRY glGetQueryivARB (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetQueryObjectivARB (GLuint id, GLenum pname, GLint *params); GLAPI void APIENTRY glGetQueryObjectuivARB (GLuint id, GLenum pname, GLuint *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids); typedef void (APIENTRYP PFNGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids); typedef GLboolean (APIENTRYP PFNGLISQUERYARBPROC) (GLuint id); typedef void (APIENTRYP PFNGLBEGINQUERYARBPROC) (GLenum target, GLuint id); typedef void (APIENTRYP PFNGLENDQUERYARBPROC) (GLenum target); typedef void (APIENTRYP PFNGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params); #endif #ifndef GL_ARB_shader_objects #define GL_ARB_shader_objects 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDeleteObjectARB (GLhandleARB obj); GLAPI GLhandleARB APIENTRY glGetHandleARB (GLenum pname); GLAPI void APIENTRY glDetachObjectARB (GLhandleARB containerObj, GLhandleARB attachedObj); GLAPI GLhandleARB APIENTRY glCreateShaderObjectARB (GLenum shaderType); GLAPI void APIENTRY glShaderSourceARB (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length); GLAPI void APIENTRY glCompileShaderARB (GLhandleARB shaderObj); GLAPI GLhandleARB APIENTRY glCreateProgramObjectARB (void); GLAPI void APIENTRY glAttachObjectARB (GLhandleARB containerObj, GLhandleARB obj); GLAPI void APIENTRY glLinkProgramARB (GLhandleARB programObj); GLAPI void APIENTRY glUseProgramObjectARB (GLhandleARB programObj); GLAPI void APIENTRY glValidateProgramARB (GLhandleARB programObj); GLAPI void APIENTRY glUniform1fARB (GLint location, GLfloat v0); GLAPI void APIENTRY glUniform2fARB (GLint location, GLfloat v0, GLfloat v1); GLAPI void APIENTRY glUniform3fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); GLAPI void APIENTRY glUniform4fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); GLAPI void APIENTRY glUniform1iARB (GLint location, GLint v0); GLAPI void APIENTRY glUniform2iARB (GLint location, GLint v0, GLint v1); GLAPI void APIENTRY glUniform3iARB (GLint location, GLint v0, GLint v1, GLint v2); GLAPI void APIENTRY glUniform4iARB (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); GLAPI void APIENTRY glUniform1fvARB (GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glUniform2fvARB (GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glUniform3fvARB (GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glUniform4fvARB (GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glUniform1ivARB (GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glUniform2ivARB (GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glUniform3ivARB (GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glUniform4ivARB (GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glUniformMatrix2fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glUniformMatrix3fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glUniformMatrix4fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glGetObjectParameterfvARB (GLhandleARB obj, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetObjectParameterivARB (GLhandleARB obj, GLenum pname, GLint *params); GLAPI void APIENTRY glGetInfoLogARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); GLAPI void APIENTRY glGetAttachedObjectsARB (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); GLAPI GLint APIENTRY glGetUniformLocationARB (GLhandleARB programObj, const GLcharARB *name); GLAPI void APIENTRY glGetActiveUniformARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); GLAPI void APIENTRY glGetUniformfvARB (GLhandleARB programObj, GLint location, GLfloat *params); GLAPI void APIENTRY glGetUniformivARB (GLhandleARB programObj, GLint location, GLint *params); GLAPI void APIENTRY glGetShaderSourceARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj); typedef GLhandleARB (APIENTRYP PFNGLGETHANDLEARBPROC) (GLenum pname); typedef void (APIENTRYP PFNGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj); typedef GLhandleARB (APIENTRYP PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType); typedef void (APIENTRYP PFNGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length); typedef void (APIENTRYP PFNGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj); typedef GLhandleARB (APIENTRYP PFNGLCREATEPROGRAMOBJECTARBPROC) (void); typedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj); typedef void (APIENTRYP PFNGLLINKPROGRAMARBPROC) (GLhandleARB programObj); typedef void (APIENTRYP PFNGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj); typedef void (APIENTRYP PFNGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj); typedef void (APIENTRYP PFNGLUNIFORM1FARBPROC) (GLint location, GLfloat v0); typedef void (APIENTRYP PFNGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1); typedef void (APIENTRYP PFNGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (APIENTRYP PFNGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (APIENTRYP PFNGLUNIFORM1IARBPROC) (GLint location, GLint v0); typedef void (APIENTRYP PFNGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1); typedef void (APIENTRYP PFNGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2); typedef void (APIENTRYP PFNGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (APIENTRYP PFNGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); typedef void (APIENTRYP PFNGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); typedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params); typedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params); typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); #endif #ifndef GL_ARB_vertex_shader #define GL_ARB_vertex_shader 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindAttribLocationARB (GLhandleARB programObj, GLuint index, const GLcharARB *name); GLAPI void APIENTRY glGetActiveAttribARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); GLAPI GLint APIENTRY glGetAttribLocationARB (GLhandleARB programObj, const GLcharARB *name); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name); typedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); #endif #ifndef GL_ARB_fragment_shader #define GL_ARB_fragment_shader 1 #endif #ifndef GL_ARB_shading_language_100 #define GL_ARB_shading_language_100 1 #endif #ifndef GL_ARB_texture_non_power_of_two #define GL_ARB_texture_non_power_of_two 1 #endif #ifndef GL_ARB_point_sprite #define GL_ARB_point_sprite 1 #endif #ifndef GL_ARB_fragment_program_shadow #define GL_ARB_fragment_program_shadow 1 #endif #ifndef GL_ARB_draw_buffers #define GL_ARB_draw_buffers 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawBuffersARB (GLsizei n, const GLenum *bufs); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs); #endif #ifndef GL_ARB_texture_rectangle #define GL_ARB_texture_rectangle 1 #endif #ifndef GL_ARB_color_buffer_float #define GL_ARB_color_buffer_float 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glClampColorARB (GLenum target, GLenum clamp); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp); #endif #ifndef GL_ARB_half_float_pixel #define GL_ARB_half_float_pixel 1 #endif #ifndef GL_ARB_texture_float #define GL_ARB_texture_float 1 #endif #ifndef GL_ARB_pixel_buffer_object #define GL_ARB_pixel_buffer_object 1 #endif #ifndef GL_ARB_depth_buffer_float #define GL_ARB_depth_buffer_float 1 #endif #ifndef GL_ARB_draw_instanced #define GL_ARB_draw_instanced 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawArraysInstancedARB (GLenum mode, GLint first, GLsizei count, GLsizei primcount); GLAPI void APIENTRY glDrawElementsInstancedARB (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDARBPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount); typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDARBPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); #endif #ifndef GL_ARB_framebuffer_object #define GL_ARB_framebuffer_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLboolean APIENTRY glIsRenderbuffer (GLuint renderbuffer); GLAPI void APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer); GLAPI void APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers); GLAPI void APIENTRY glGenRenderbuffers (GLsizei n, GLuint *renderbuffers); GLAPI void APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); GLAPI void APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint *params); GLAPI GLboolean APIENTRY glIsFramebuffer (GLuint framebuffer); GLAPI void APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer); GLAPI void APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers); GLAPI void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers); GLAPI GLenum APIENTRY glCheckFramebufferStatus (GLenum target); GLAPI void APIENTRY glFramebufferTexture1D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); GLAPI void APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); GLAPI void APIENTRY glFramebufferTexture3D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); GLAPI void APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); GLAPI void APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint *params); GLAPI void APIENTRY glGenerateMipmap (GLenum target); GLAPI void APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); GLAPI void APIENTRY glRenderbufferStorageMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); GLAPI void APIENTRY glFramebufferTextureLayer (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC) (GLuint renderbuffer); typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer); typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers); typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC) (GLuint framebuffer); typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers); typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC) (GLenum target); typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); #endif #ifndef GL_ARB_framebuffer_sRGB #define GL_ARB_framebuffer_sRGB 1 #endif #ifndef GL_ARB_geometry_shader4 #define GL_ARB_geometry_shader4 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramParameteriARB (GLuint program, GLenum pname, GLint value); GLAPI void APIENTRY glFramebufferTextureARB (GLenum target, GLenum attachment, GLuint texture, GLint level); GLAPI void APIENTRY glFramebufferTextureLayerARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); GLAPI void APIENTRY glFramebufferTextureFaceARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIARBPROC) (GLuint program, GLenum pname, GLint value); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); #endif #ifndef GL_ARB_half_float_vertex #define GL_ARB_half_float_vertex 1 #endif #ifndef GL_ARB_instanced_arrays #define GL_ARB_instanced_arrays 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttribDivisorARB (GLuint index, GLuint divisor); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORARBPROC) (GLuint index, GLuint divisor); #endif #ifndef GL_ARB_map_buffer_range #define GL_ARB_map_buffer_range 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLvoid* APIENTRY glMapBufferRange (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); GLAPI void APIENTRY glFlushMappedBufferRange (GLenum target, GLintptr offset, GLsizeiptr length); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length); #endif #ifndef GL_ARB_texture_buffer_object #define GL_ARB_texture_buffer_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexBufferARB (GLenum target, GLenum internalformat, GLuint buffer); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXBUFFERARBPROC) (GLenum target, GLenum internalformat, GLuint buffer); #endif #ifndef GL_ARB_texture_compression_rgtc #define GL_ARB_texture_compression_rgtc 1 #endif #ifndef GL_ARB_texture_rg #define GL_ARB_texture_rg 1 #endif #ifndef GL_ARB_vertex_array_object #define GL_ARB_vertex_array_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindVertexArray (GLuint array); GLAPI void APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays); GLAPI void APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays); GLAPI GLboolean APIENTRY glIsVertexArray (GLuint array); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array); typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays); typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC) (GLuint array); #endif #ifndef GL_ARB_uniform_buffer_object #define GL_ARB_uniform_buffer_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetUniformIndices (GLuint program, GLsizei uniformCount, const GLchar* *uniformNames, GLuint *uniformIndices); GLAPI void APIENTRY glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); GLAPI void APIENTRY glGetActiveUniformName (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); GLAPI GLuint APIENTRY glGetUniformBlockIndex (GLuint program, const GLchar *uniformBlockName); GLAPI void APIENTRY glGetActiveUniformBlockiv (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); GLAPI void APIENTRY glGetActiveUniformBlockName (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); GLAPI void APIENTRY glUniformBlockBinding (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar* *uniformNames, GLuint *uniformIndices); typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName); typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); #endif #ifndef GL_ARB_compatibility #define GL_ARB_compatibility 1 #endif #ifndef GL_ARB_copy_buffer #define GL_ARB_copy_buffer 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCopyBufferSubData (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); #endif #ifndef GL_ARB_shader_texture_lod #define GL_ARB_shader_texture_lod 1 #endif #ifndef GL_ARB_depth_clamp #define GL_ARB_depth_clamp 1 #endif #ifndef GL_ARB_draw_elements_base_vertex #define GL_ARB_draw_elements_base_vertex 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); GLAPI void APIENTRY glDrawRangeElementsBaseVertex (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); GLAPI void APIENTRY glDrawElementsInstancedBaseVertex (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount, GLint basevertex); GLAPI void APIENTRY glMultiDrawElementsBaseVertex (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount, const GLint *basevertex); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount, GLint basevertex); typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount, const GLint *basevertex); #endif #ifndef GL_ARB_fragment_coord_conventions #define GL_ARB_fragment_coord_conventions 1 #endif #ifndef GL_ARB_provoking_vertex #define GL_ARB_provoking_vertex 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProvokingVertex (GLenum mode); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC) (GLenum mode); #endif #ifndef GL_ARB_seamless_cube_map #define GL_ARB_seamless_cube_map 1 #endif #ifndef GL_ARB_sync #define GL_ARB_sync 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLsync APIENTRY glFenceSync (GLenum condition, GLbitfield flags); GLAPI GLboolean APIENTRY glIsSync (GLsync sync); GLAPI void APIENTRY glDeleteSync (GLsync sync); GLAPI GLenum APIENTRY glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); GLAPI void APIENTRY glWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); GLAPI void APIENTRY glGetInteger64v (GLenum pname, GLint64 *params); GLAPI void APIENTRY glGetSynciv (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC) (GLenum condition, GLbitfield flags); typedef GLboolean (APIENTRYP PFNGLISSYNCPROC) (GLsync sync); typedef void (APIENTRYP PFNGLDELETESYNCPROC) (GLsync sync); typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); typedef void (APIENTRYP PFNGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); typedef void (APIENTRYP PFNGLGETINTEGER64VPROC) (GLenum pname, GLint64 *params); typedef void (APIENTRYP PFNGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); #endif #ifndef GL_ARB_texture_multisample #define GL_ARB_texture_multisample 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexImage2DMultisample (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); GLAPI void APIENTRY glTexImage3DMultisample (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); GLAPI void APIENTRY glGetMultisamplefv (GLenum pname, GLuint index, GLfloat *val); GLAPI void APIENTRY glSampleMaski (GLuint index, GLbitfield mask); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val); typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC) (GLuint index, GLbitfield mask); #endif #ifndef GL_ARB_vertex_array_bgra #define GL_ARB_vertex_array_bgra 1 #endif #ifndef GL_ARB_draw_buffers_blend #define GL_ARB_draw_buffers_blend 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendEquationiARB (GLuint buf, GLenum mode); GLAPI void APIENTRY glBlendEquationSeparateiARB (GLuint buf, GLenum modeRGB, GLenum modeAlpha); GLAPI void APIENTRY glBlendFunciARB (GLuint buf, GLenum src, GLenum dst); GLAPI void APIENTRY glBlendFuncSeparateiARB (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDEQUATIONIARBPROC) (GLuint buf, GLenum mode); typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIARBPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); typedef void (APIENTRYP PFNGLBLENDFUNCIARBPROC) (GLuint buf, GLenum src, GLenum dst); typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIARBPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); #endif #ifndef GL_ARB_sample_shading #define GL_ARB_sample_shading 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMinSampleShadingARB (GLclampf value); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLMINSAMPLESHADINGARBPROC) (GLclampf value); #endif #ifndef GL_ARB_texture_cube_map_array #define GL_ARB_texture_cube_map_array 1 #endif #ifndef GL_ARB_texture_gather #define GL_ARB_texture_gather 1 #endif #ifndef GL_ARB_texture_query_lod #define GL_ARB_texture_query_lod 1 #endif #ifndef GL_ARB_shading_language_include #define GL_ARB_shading_language_include 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glNamedStringARB (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string); GLAPI void APIENTRY glDeleteNamedStringARB (GLint namelen, const GLchar *name); GLAPI void APIENTRY glCompileShaderIncludeARB (GLuint shader, GLsizei count, const GLchar* *path, const GLint *length); GLAPI GLboolean APIENTRY glIsNamedStringARB (GLint namelen, const GLchar *name); GLAPI void APIENTRY glGetNamedStringARB (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string); GLAPI void APIENTRY glGetNamedStringivARB (GLint namelen, const GLchar *name, GLenum pname, GLint *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLNAMEDSTRINGARBPROC) (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string); typedef void (APIENTRYP PFNGLDELETENAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name); typedef void (APIENTRYP PFNGLCOMPILESHADERINCLUDEARBPROC) (GLuint shader, GLsizei count, const GLchar* *path, const GLint *length); typedef GLboolean (APIENTRYP PFNGLISNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name); typedef void (APIENTRYP PFNGLGETNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string); typedef void (APIENTRYP PFNGLGETNAMEDSTRINGIVARBPROC) (GLint namelen, const GLchar *name, GLenum pname, GLint *params); #endif #ifndef GL_ARB_texture_compression_bptc #define GL_ARB_texture_compression_bptc 1 #endif #ifndef GL_ARB_blend_func_extended #define GL_ARB_blend_func_extended 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindFragDataLocationIndexed (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); GLAPI GLint APIENTRY glGetFragDataIndex (GLuint program, const GLchar *name); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); typedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC) (GLuint program, const GLchar *name); #endif #ifndef GL_ARB_explicit_attrib_location #define GL_ARB_explicit_attrib_location 1 #endif #ifndef GL_ARB_occlusion_query2 #define GL_ARB_occlusion_query2 1 #endif #ifndef GL_ARB_sampler_objects #define GL_ARB_sampler_objects 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGenSamplers (GLsizei count, GLuint *samplers); GLAPI void APIENTRY glDeleteSamplers (GLsizei count, const GLuint *samplers); GLAPI GLboolean APIENTRY glIsSampler (GLuint sampler); GLAPI void APIENTRY glBindSampler (GLuint unit, GLuint sampler); GLAPI void APIENTRY glSamplerParameteri (GLuint sampler, GLenum pname, GLint param); GLAPI void APIENTRY glSamplerParameteriv (GLuint sampler, GLenum pname, const GLint *param); GLAPI void APIENTRY glSamplerParameterf (GLuint sampler, GLenum pname, GLfloat param); GLAPI void APIENTRY glSamplerParameterfv (GLuint sampler, GLenum pname, const GLfloat *param); GLAPI void APIENTRY glSamplerParameterIiv (GLuint sampler, GLenum pname, const GLint *param); GLAPI void APIENTRY glSamplerParameterIuiv (GLuint sampler, GLenum pname, const GLuint *param); GLAPI void APIENTRY glGetSamplerParameteriv (GLuint sampler, GLenum pname, GLint *params); GLAPI void APIENTRY glGetSamplerParameterIiv (GLuint sampler, GLenum pname, GLint *params); GLAPI void APIENTRY glGetSamplerParameterfv (GLuint sampler, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetSamplerParameterIuiv (GLuint sampler, GLenum pname, GLuint *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers); typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers); typedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC) (GLuint sampler); typedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler); typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param); typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param); typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, const GLint *param); typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, const GLuint *param); typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, GLuint *params); #endif #ifndef GL_ARB_shader_bit_encoding #define GL_ARB_shader_bit_encoding 1 #endif #ifndef GL_ARB_texture_rgb10_a2ui #define GL_ARB_texture_rgb10_a2ui 1 #endif #ifndef GL_ARB_texture_swizzle #define GL_ARB_texture_swizzle 1 #endif #ifndef GL_ARB_timer_query #define GL_ARB_timer_query 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glQueryCounter (GLuint id, GLenum target); GLAPI void APIENTRY glGetQueryObjecti64v (GLuint id, GLenum pname, GLint64 *params); GLAPI void APIENTRY glGetQueryObjectui64v (GLuint id, GLenum pname, GLuint64 *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLQUERYCOUNTERPROC) (GLuint id, GLenum target); typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC) (GLuint id, GLenum pname, GLint64 *params); typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC) (GLuint id, GLenum pname, GLuint64 *params); #endif #ifndef GL_ARB_vertex_type_2_10_10_10_rev #define GL_ARB_vertex_type_2_10_10_10_rev 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexP2ui (GLenum type, GLuint value); GLAPI void APIENTRY glVertexP2uiv (GLenum type, const GLuint *value); GLAPI void APIENTRY glVertexP3ui (GLenum type, GLuint value); GLAPI void APIENTRY glVertexP3uiv (GLenum type, const GLuint *value); GLAPI void APIENTRY glVertexP4ui (GLenum type, GLuint value); GLAPI void APIENTRY glVertexP4uiv (GLenum type, const GLuint *value); GLAPI void APIENTRY glTexCoordP1ui (GLenum type, GLuint coords); GLAPI void APIENTRY glTexCoordP1uiv (GLenum type, const GLuint *coords); GLAPI void APIENTRY glTexCoordP2ui (GLenum type, GLuint coords); GLAPI void APIENTRY glTexCoordP2uiv (GLenum type, const GLuint *coords); GLAPI void APIENTRY glTexCoordP3ui (GLenum type, GLuint coords); GLAPI void APIENTRY glTexCoordP3uiv (GLenum type, const GLuint *coords); GLAPI void APIENTRY glTexCoordP4ui (GLenum type, GLuint coords); GLAPI void APIENTRY glTexCoordP4uiv (GLenum type, const GLuint *coords); GLAPI void APIENTRY glMultiTexCoordP1ui (GLenum texture, GLenum type, GLuint coords); GLAPI void APIENTRY glMultiTexCoordP1uiv (GLenum texture, GLenum type, const GLuint *coords); GLAPI void APIENTRY glMultiTexCoordP2ui (GLenum texture, GLenum type, GLuint coords); GLAPI void APIENTRY glMultiTexCoordP2uiv (GLenum texture, GLenum type, const GLuint *coords); GLAPI void APIENTRY glMultiTexCoordP3ui (GLenum texture, GLenum type, GLuint coords); GLAPI void APIENTRY glMultiTexCoordP3uiv (GLenum texture, GLenum type, const GLuint *coords); GLAPI void APIENTRY glMultiTexCoordP4ui (GLenum texture, GLenum type, GLuint coords); GLAPI void APIENTRY glMultiTexCoordP4uiv (GLenum texture, GLenum type, const GLuint *coords); GLAPI void APIENTRY glNormalP3ui (GLenum type, GLuint coords); GLAPI void APIENTRY glNormalP3uiv (GLenum type, const GLuint *coords); GLAPI void APIENTRY glColorP3ui (GLenum type, GLuint color); GLAPI void APIENTRY glColorP3uiv (GLenum type, const GLuint *color); GLAPI void APIENTRY glColorP4ui (GLenum type, GLuint color); GLAPI void APIENTRY glColorP4uiv (GLenum type, const GLuint *color); GLAPI void APIENTRY glSecondaryColorP3ui (GLenum type, GLuint color); GLAPI void APIENTRY glSecondaryColorP3uiv (GLenum type, const GLuint *color); GLAPI void APIENTRY glVertexAttribP1ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); GLAPI void APIENTRY glVertexAttribP1uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); GLAPI void APIENTRY glVertexAttribP2ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); GLAPI void APIENTRY glVertexAttribP2uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); GLAPI void APIENTRY glVertexAttribP3ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); GLAPI void APIENTRY glVertexAttribP3uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); GLAPI void APIENTRY glVertexAttribP4ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); GLAPI void APIENTRY glVertexAttribP4uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXP2UIPROC) (GLenum type, GLuint value); typedef void (APIENTRYP PFNGLVERTEXP2UIVPROC) (GLenum type, const GLuint *value); typedef void (APIENTRYP PFNGLVERTEXP3UIPROC) (GLenum type, GLuint value); typedef void (APIENTRYP PFNGLVERTEXP3UIVPROC) (GLenum type, const GLuint *value); typedef void (APIENTRYP PFNGLVERTEXP4UIPROC) (GLenum type, GLuint value); typedef void (APIENTRYP PFNGLVERTEXP4UIVPROC) (GLenum type, const GLuint *value); typedef void (APIENTRYP PFNGLTEXCOORDP1UIPROC) (GLenum type, GLuint coords); typedef void (APIENTRYP PFNGLTEXCOORDP1UIVPROC) (GLenum type, const GLuint *coords); typedef void (APIENTRYP PFNGLTEXCOORDP2UIPROC) (GLenum type, GLuint coords); typedef void (APIENTRYP PFNGLTEXCOORDP2UIVPROC) (GLenum type, const GLuint *coords); typedef void (APIENTRYP PFNGLTEXCOORDP3UIPROC) (GLenum type, GLuint coords); typedef void (APIENTRYP PFNGLTEXCOORDP3UIVPROC) (GLenum type, const GLuint *coords); typedef void (APIENTRYP PFNGLTEXCOORDP4UIPROC) (GLenum type, GLuint coords); typedef void (APIENTRYP PFNGLTEXCOORDP4UIVPROC) (GLenum type, const GLuint *coords); typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIPROC) (GLenum texture, GLenum type, GLuint coords); typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIPROC) (GLenum texture, GLenum type, GLuint coords); typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIPROC) (GLenum texture, GLenum type, GLuint coords); typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIPROC) (GLenum texture, GLenum type, GLuint coords); typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); typedef void (APIENTRYP PFNGLNORMALP3UIPROC) (GLenum type, GLuint coords); typedef void (APIENTRYP PFNGLNORMALP3UIVPROC) (GLenum type, const GLuint *coords); typedef void (APIENTRYP PFNGLCOLORP3UIPROC) (GLenum type, GLuint color); typedef void (APIENTRYP PFNGLCOLORP3UIVPROC) (GLenum type, const GLuint *color); typedef void (APIENTRYP PFNGLCOLORP4UIPROC) (GLenum type, GLuint color); typedef void (APIENTRYP PFNGLCOLORP4UIVPROC) (GLenum type, const GLuint *color); typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIPROC) (GLenum type, GLuint color); typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC) (GLenum type, const GLuint *color); typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); #endif #ifndef GL_ARB_draw_indirect #define GL_ARB_draw_indirect 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawArraysIndirect (GLenum mode, const GLvoid *indirect); GLAPI void APIENTRY glDrawElementsIndirect (GLenum mode, GLenum type, const GLvoid *indirect); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const GLvoid *indirect); typedef void (APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const GLvoid *indirect); #endif #ifndef GL_ARB_gpu_shader5 #define GL_ARB_gpu_shader5 1 #endif #ifndef GL_ARB_gpu_shader_fp64 #define GL_ARB_gpu_shader_fp64 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glUniform1d (GLint location, GLdouble x); GLAPI void APIENTRY glUniform2d (GLint location, GLdouble x, GLdouble y); GLAPI void APIENTRY glUniform3d (GLint location, GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glUniform4d (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glUniform1dv (GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glUniform2dv (GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glUniform3dv (GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glUniform4dv (GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glUniformMatrix2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glUniformMatrix3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glUniformMatrix4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glUniformMatrix2x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glUniformMatrix2x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glUniformMatrix3x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glUniformMatrix3x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glUniformMatrix4x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glUniformMatrix4x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glGetUniformdv (GLuint program, GLint location, GLdouble *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLUNIFORM1DPROC) (GLint location, GLdouble x); typedef void (APIENTRYP PFNGLUNIFORM2DPROC) (GLint location, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLUNIFORM3DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLUNIFORM4DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLUNIFORM1DVPROC) (GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORM2DVPROC) (GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORM3DVPROC) (GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORM4DVPROC) (GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLGETUNIFORMDVPROC) (GLuint program, GLint location, GLdouble *params); #endif #ifndef GL_ARB_shader_subroutine #define GL_ARB_shader_subroutine 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLint APIENTRY glGetSubroutineUniformLocation (GLuint program, GLenum shadertype, const GLchar *name); GLAPI GLuint APIENTRY glGetSubroutineIndex (GLuint program, GLenum shadertype, const GLchar *name); GLAPI void APIENTRY glGetActiveSubroutineUniformiv (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); GLAPI void APIENTRY glGetActiveSubroutineUniformName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); GLAPI void APIENTRY glGetActiveSubroutineName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); GLAPI void APIENTRY glUniformSubroutinesuiv (GLenum shadertype, GLsizei count, const GLuint *indices); GLAPI void APIENTRY glGetUniformSubroutineuiv (GLenum shadertype, GLint location, GLuint *params); GLAPI void APIENTRY glGetProgramStageiv (GLuint program, GLenum shadertype, GLenum pname, GLint *values); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLint (APIENTRYP PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC) (GLuint program, GLenum shadertype, const GLchar *name); typedef GLuint (APIENTRYP PFNGLGETSUBROUTINEINDEXPROC) (GLuint program, GLenum shadertype, const GLchar *name); typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC) (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINENAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); typedef void (APIENTRYP PFNGLUNIFORMSUBROUTINESUIVPROC) (GLenum shadertype, GLsizei count, const GLuint *indices); typedef void (APIENTRYP PFNGLGETUNIFORMSUBROUTINEUIVPROC) (GLenum shadertype, GLint location, GLuint *params); typedef void (APIENTRYP PFNGLGETPROGRAMSTAGEIVPROC) (GLuint program, GLenum shadertype, GLenum pname, GLint *values); #endif #ifndef GL_ARB_tessellation_shader #define GL_ARB_tessellation_shader 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPatchParameteri (GLenum pname, GLint value); GLAPI void APIENTRY glPatchParameterfv (GLenum pname, const GLfloat *values); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPATCHPARAMETERIPROC) (GLenum pname, GLint value); typedef void (APIENTRYP PFNGLPATCHPARAMETERFVPROC) (GLenum pname, const GLfloat *values); #endif #ifndef GL_ARB_texture_buffer_object_rgb32 #define GL_ARB_texture_buffer_object_rgb32 1 #endif #ifndef GL_ARB_transform_feedback2 #define GL_ARB_transform_feedback2 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindTransformFeedback (GLenum target, GLuint id); GLAPI void APIENTRY glDeleteTransformFeedbacks (GLsizei n, const GLuint *ids); GLAPI void APIENTRY glGenTransformFeedbacks (GLsizei n, GLuint *ids); GLAPI GLboolean APIENTRY glIsTransformFeedback (GLuint id); GLAPI void APIENTRY glPauseTransformFeedback (void); GLAPI void APIENTRY glResumeTransformFeedback (void); GLAPI void APIENTRY glDrawTransformFeedback (GLenum mode, GLuint id); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC) (GLenum target, GLuint id); typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint *ids); typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids); typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC) (GLuint id); typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC) (void); typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC) (void); typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKPROC) (GLenum mode, GLuint id); #endif #ifndef GL_ARB_transform_feedback3 #define GL_ARB_transform_feedback3 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawTransformFeedbackStream (GLenum mode, GLuint id, GLuint stream); GLAPI void APIENTRY glBeginQueryIndexed (GLenum target, GLuint index, GLuint id); GLAPI void APIENTRY glEndQueryIndexed (GLenum target, GLuint index); GLAPI void APIENTRY glGetQueryIndexediv (GLenum target, GLuint index, GLenum pname, GLint *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC) (GLenum mode, GLuint id, GLuint stream); typedef void (APIENTRYP PFNGLBEGINQUERYINDEXEDPROC) (GLenum target, GLuint index, GLuint id); typedef void (APIENTRYP PFNGLENDQUERYINDEXEDPROC) (GLenum target, GLuint index); typedef void (APIENTRYP PFNGLGETQUERYINDEXEDIVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); #endif #ifndef GL_ARB_ES2_compatibility #define GL_ARB_ES2_compatibility 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glReleaseShaderCompiler (void); GLAPI void APIENTRY glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const GLvoid *binary, GLsizei length); GLAPI void APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); GLAPI void APIENTRY glDepthRangef (GLclampf n, GLclampf f); GLAPI void APIENTRY glClearDepthf (GLclampf d); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC) (void); typedef void (APIENTRYP PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const GLvoid *binary, GLsizei length); typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC) (GLclampf n, GLclampf f); typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC) (GLclampf d); #endif #ifndef GL_ARB_get_program_binary #define GL_ARB_get_program_binary 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); GLAPI void APIENTRY glProgramBinary (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLsizei length); GLAPI void APIENTRY glProgramParameteri (GLuint program, GLenum pname, GLint value); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); typedef void (APIENTRYP PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLsizei length); typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value); #endif #ifndef GL_ARB_separate_shader_objects #define GL_ARB_separate_shader_objects 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glUseProgramStages (GLuint pipeline, GLbitfield stages, GLuint program); GLAPI void APIENTRY glActiveShaderProgram (GLuint pipeline, GLuint program); GLAPI GLuint APIENTRY glCreateShaderProgramv (GLenum type, GLsizei count, const GLchar* *strings); GLAPI void APIENTRY glBindProgramPipeline (GLuint pipeline); GLAPI void APIENTRY glDeleteProgramPipelines (GLsizei n, const GLuint *pipelines); GLAPI void APIENTRY glGenProgramPipelines (GLsizei n, GLuint *pipelines); GLAPI GLboolean APIENTRY glIsProgramPipeline (GLuint pipeline); GLAPI void APIENTRY glGetProgramPipelineiv (GLuint pipeline, GLenum pname, GLint *params); GLAPI void APIENTRY glProgramUniform1i (GLuint program, GLint location, GLint v0); GLAPI void APIENTRY glProgramUniform1iv (GLuint program, GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glProgramUniform1f (GLuint program, GLint location, GLfloat v0); GLAPI void APIENTRY glProgramUniform1fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glProgramUniform1d (GLuint program, GLint location, GLdouble v0); GLAPI void APIENTRY glProgramUniform1dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glProgramUniform1ui (GLuint program, GLint location, GLuint v0); GLAPI void APIENTRY glProgramUniform1uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glProgramUniform2i (GLuint program, GLint location, GLint v0, GLint v1); GLAPI void APIENTRY glProgramUniform2iv (GLuint program, GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glProgramUniform2f (GLuint program, GLint location, GLfloat v0, GLfloat v1); GLAPI void APIENTRY glProgramUniform2fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glProgramUniform2d (GLuint program, GLint location, GLdouble v0, GLdouble v1); GLAPI void APIENTRY glProgramUniform2dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glProgramUniform2ui (GLuint program, GLint location, GLuint v0, GLuint v1); GLAPI void APIENTRY glProgramUniform2uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glProgramUniform3i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); GLAPI void APIENTRY glProgramUniform3iv (GLuint program, GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glProgramUniform3f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); GLAPI void APIENTRY glProgramUniform3fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glProgramUniform3d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); GLAPI void APIENTRY glProgramUniform3dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glProgramUniform3ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); GLAPI void APIENTRY glProgramUniform3uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glProgramUniform4i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); GLAPI void APIENTRY glProgramUniform4iv (GLuint program, GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glProgramUniform4f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); GLAPI void APIENTRY glProgramUniform4fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glProgramUniform4d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); GLAPI void APIENTRY glProgramUniform4dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glProgramUniform4ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); GLAPI void APIENTRY glProgramUniform4uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glProgramUniformMatrix2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix2x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix3x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix2x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix4x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix3x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix4x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix2x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix3x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix2x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix4x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix3x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix4x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glValidateProgramPipeline (GLuint pipeline); GLAPI void APIENTRY glGetProgramPipelineInfoLog (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLUSEPROGRAMSTAGESPROC) (GLuint pipeline, GLbitfield stages, GLuint program); typedef void (APIENTRYP PFNGLACTIVESHADERPROGRAMPROC) (GLuint pipeline, GLuint program); typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMVPROC) (GLenum type, GLsizei count, const GLchar* *strings); typedef void (APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC) (GLuint pipeline); typedef void (APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC) (GLsizei n, const GLuint *pipelines); typedef void (APIENTRYP PFNGLGENPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines); typedef GLboolean (APIENTRYP PFNGLISPROGRAMPIPELINEPROC) (GLuint pipeline); typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC) (GLuint pipeline, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IPROC) (GLuint program, GLint location, GLint v0); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FPROC) (GLuint program, GLint location, GLfloat v0); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DPROC) (GLuint program, GLint location, GLdouble v0); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC) (GLuint program, GLint location, GLuint v0); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IPROC) (GLuint program, GLint location, GLint v0, GLint v1); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC) (GLuint pipeline); typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); #endif #ifndef GL_ARB_vertex_attrib_64bit #define GL_ARB_vertex_attrib_64bit 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttribL1d (GLuint index, GLdouble x); GLAPI void APIENTRY glVertexAttribL2d (GLuint index, GLdouble x, GLdouble y); GLAPI void APIENTRY glVertexAttribL3d (GLuint index, GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glVertexAttribL4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glVertexAttribL1dv (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttribL2dv (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttribL3dv (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttribL4dv (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttribLPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); GLAPI void APIENTRY glGetVertexAttribLdv (GLuint index, GLenum pname, GLdouble *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DPROC) (GLuint index, GLdouble x); typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DPROC) (GLuint index, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVPROC) (GLuint index, GLenum pname, GLdouble *params); #endif #ifndef GL_ARB_viewport_array #define GL_ARB_viewport_array 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glViewportArrayv (GLuint first, GLsizei count, const GLfloat *v); GLAPI void APIENTRY glViewportIndexedf (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); GLAPI void APIENTRY glViewportIndexedfv (GLuint index, const GLfloat *v); GLAPI void APIENTRY glScissorArrayv (GLuint first, GLsizei count, const GLint *v); GLAPI void APIENTRY glScissorIndexed (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); GLAPI void APIENTRY glScissorIndexedv (GLuint index, const GLint *v); GLAPI void APIENTRY glDepthRangeArrayv (GLuint first, GLsizei count, const GLclampd *v); GLAPI void APIENTRY glDepthRangeIndexed (GLuint index, GLclampd n, GLclampd f); GLAPI void APIENTRY glGetFloati_v (GLenum target, GLuint index, GLfloat *data); GLAPI void APIENTRY glGetDoublei_v (GLenum target, GLuint index, GLdouble *data); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVIEWPORTARRAYVPROC) (GLuint first, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLSCISSORARRAYVPROC) (GLuint first, GLsizei count, const GLint *v); typedef void (APIENTRYP PFNGLSCISSORINDEXEDPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLSCISSORINDEXEDVPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLDEPTHRANGEARRAYVPROC) (GLuint first, GLsizei count, const GLclampd *v); typedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDPROC) (GLuint index, GLclampd n, GLclampd f); typedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data); typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data); #endif #ifndef GL_ARB_cl_event #define GL_ARB_cl_event 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLsync APIENTRY glCreateSyncFromCLeventARB (struct _cl_context * context, struct _cl_event * event, GLbitfield flags); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLsync (APIENTRYP PFNGLCREATESYNCFROMCLEVENTARBPROC) (struct _cl_context * context, struct _cl_event * event, GLbitfield flags); #endif #ifndef GL_ARB_debug_output #define GL_ARB_debug_output 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDebugMessageControlARB (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); GLAPI void APIENTRY glDebugMessageInsertARB (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); GLAPI void APIENTRY glDebugMessageCallbackARB (GLDEBUGPROCARB callback, const GLvoid *userParam); GLAPI GLuint APIENTRY glGetDebugMessageLogARB (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTARBPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKARBPROC) (GLDEBUGPROCARB callback, const GLvoid *userParam); typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); #endif #ifndef GL_ARB_robustness #define GL_ARB_robustness 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLenum APIENTRY glGetGraphicsResetStatusARB (void); GLAPI void APIENTRY glGetnMapdvARB (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); GLAPI void APIENTRY glGetnMapfvARB (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); GLAPI void APIENTRY glGetnMapivARB (GLenum target, GLenum query, GLsizei bufSize, GLint *v); GLAPI void APIENTRY glGetnPixelMapfvARB (GLenum map, GLsizei bufSize, GLfloat *values); GLAPI void APIENTRY glGetnPixelMapuivARB (GLenum map, GLsizei bufSize, GLuint *values); GLAPI void APIENTRY glGetnPixelMapusvARB (GLenum map, GLsizei bufSize, GLushort *values); GLAPI void APIENTRY glGetnPolygonStippleARB (GLsizei bufSize, GLubyte *pattern); GLAPI void APIENTRY glGetnColorTableARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, GLvoid *table); GLAPI void APIENTRY glGetnConvolutionFilterARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, GLvoid *image); GLAPI void APIENTRY glGetnSeparableFilterARB (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, GLvoid *row, GLsizei columnBufSize, GLvoid *column, GLvoid *span); GLAPI void APIENTRY glGetnHistogramARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, GLvoid *values); GLAPI void APIENTRY glGetnMinmaxARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, GLvoid *values); GLAPI void APIENTRY glGetnTexImageARB (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid *img); GLAPI void APIENTRY glReadnPixelsARB (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *data); GLAPI void APIENTRY glGetnCompressedTexImageARB (GLenum target, GLint lod, GLsizei bufSize, GLvoid *img); GLAPI void APIENTRY glGetnUniformfvARB (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); GLAPI void APIENTRY glGetnUniformivARB (GLuint program, GLint location, GLsizei bufSize, GLint *params); GLAPI void APIENTRY glGetnUniformuivARB (GLuint program, GLint location, GLsizei bufSize, GLuint *params); GLAPI void APIENTRY glGetnUniformdvARB (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSARBPROC) (void); typedef void (APIENTRYP PFNGLGETNMAPDVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); typedef void (APIENTRYP PFNGLGETNMAPFVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); typedef void (APIENTRYP PFNGLGETNMAPIVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLint *v); typedef void (APIENTRYP PFNGLGETNPIXELMAPFVARBPROC) (GLenum map, GLsizei bufSize, GLfloat *values); typedef void (APIENTRYP PFNGLGETNPIXELMAPUIVARBPROC) (GLenum map, GLsizei bufSize, GLuint *values); typedef void (APIENTRYP PFNGLGETNPIXELMAPUSVARBPROC) (GLenum map, GLsizei bufSize, GLushort *values); typedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEARBPROC) (GLsizei bufSize, GLubyte *pattern); typedef void (APIENTRYP PFNGLGETNCOLORTABLEARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, GLvoid *table); typedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, GLvoid *image); typedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, GLvoid *row, GLsizei columnBufSize, GLvoid *column, GLvoid *span); typedef void (APIENTRYP PFNGLGETNHISTOGRAMARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, GLvoid *values); typedef void (APIENTRYP PFNGLGETNMINMAXARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, GLvoid *values); typedef void (APIENTRYP PFNGLGETNTEXIMAGEARBPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid *img); typedef void (APIENTRYP PFNGLREADNPIXELSARBPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *data); typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, GLsizei bufSize, GLvoid *img); typedef void (APIENTRYP PFNGLGETNUNIFORMFVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); typedef void (APIENTRYP PFNGLGETNUNIFORMIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); typedef void (APIENTRYP PFNGLGETNUNIFORMUIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params); typedef void (APIENTRYP PFNGLGETNUNIFORMDVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); #endif #ifndef GL_ARB_shader_stencil_export #define GL_ARB_shader_stencil_export 1 #endif #ifndef GL_ARB_base_instance #define GL_ARB_base_instance 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawArraysInstancedBaseInstance (GLenum mode, GLint first, GLsizei count, GLsizei primcount, GLuint baseinstance); GLAPI void APIENTRY glDrawElementsInstancedBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLuint baseinstance); GLAPI void APIENTRY glDrawElementsInstancedBaseVertexBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLint basevertex, GLuint baseinstance); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount, GLuint baseinstance); typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLuint baseinstance); typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLint basevertex, GLuint baseinstance); #endif #ifndef GL_ARB_shading_language_420pack #define GL_ARB_shading_language_420pack 1 #endif #ifndef GL_ARB_transform_feedback_instanced #define GL_ARB_transform_feedback_instanced 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawTransformFeedbackInstanced (GLenum mode, GLuint id, GLsizei primcount); GLAPI void APIENTRY glDrawTransformFeedbackStreamInstanced (GLenum mode, GLuint id, GLuint stream, GLsizei primcount); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) (GLenum mode, GLuint id, GLsizei primcount); typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenum mode, GLuint id, GLuint stream, GLsizei primcount); #endif #ifndef GL_ARB_compressed_texture_pixel_storage #define GL_ARB_compressed_texture_pixel_storage 1 #endif #ifndef GL_ARB_conservative_depth #define GL_ARB_conservative_depth 1 #endif #ifndef GL_ARB_internalformat_query #define GL_ARB_internalformat_query 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); #endif #ifndef GL_ARB_map_buffer_alignment #define GL_ARB_map_buffer_alignment 1 #endif #ifndef GL_ARB_shader_atomic_counters #define GL_ARB_shader_atomic_counters 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetActiveAtomicCounterBufferiv (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); #endif #ifndef GL_ARB_shader_image_load_store #define GL_ARB_shader_image_load_store 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindImageTexture (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); GLAPI void APIENTRY glMemoryBarrier (GLbitfield barriers); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers); #endif #ifndef GL_ARB_shading_language_packing #define GL_ARB_shading_language_packing 1 #endif #ifndef GL_ARB_texture_storage #define GL_ARB_texture_storage 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexStorage1D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); GLAPI void APIENTRY glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); GLAPI void APIENTRY glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); GLAPI void APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); GLAPI void APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); GLAPI void APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); typedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); typedef void (APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); #endif #ifndef GL_EXT_abgr #define GL_EXT_abgr 1 #endif #ifndef GL_EXT_blend_color #define GL_EXT_blend_color 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendColorEXT (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDCOLOREXTPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); #endif #ifndef GL_EXT_polygon_offset #define GL_EXT_polygon_offset 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPolygonOffsetEXT (GLfloat factor, GLfloat bias); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPOLYGONOFFSETEXTPROC) (GLfloat factor, GLfloat bias); #endif #ifndef GL_EXT_texture #define GL_EXT_texture 1 #endif #ifndef GL_EXT_texture3D #define GL_EXT_texture3D 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexImage3DEXT (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); GLAPI void APIENTRY glTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); #endif #ifndef GL_SGIS_texture_filter4 #define GL_SGIS_texture_filter4 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetTexFilterFuncSGIS (GLenum target, GLenum filter, GLfloat *weights); GLAPI void APIENTRY glTexFilterFuncSGIS (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGETTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLfloat *weights); typedef void (APIENTRYP PFNGLTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); #endif #ifndef GL_EXT_subtexture #define GL_EXT_subtexture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); GLAPI void APIENTRY glTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); #endif #ifndef GL_EXT_copy_texture #define GL_EXT_copy_texture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCopyTexImage1DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); GLAPI void APIENTRY glCopyTexImage2DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); GLAPI void APIENTRY glCopyTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); GLAPI void APIENTRY glCopyTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glCopyTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); #endif #ifndef GL_EXT_histogram #define GL_EXT_histogram 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetHistogramEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); GLAPI void APIENTRY glGetHistogramParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetHistogramParameterivEXT (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetMinmaxEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); GLAPI void APIENTRY glGetMinmaxParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetMinmaxParameterivEXT (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glHistogramEXT (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); GLAPI void APIENTRY glMinmaxEXT (GLenum target, GLenum internalformat, GLboolean sink); GLAPI void APIENTRY glResetHistogramEXT (GLenum target); GLAPI void APIENTRY glResetMinmaxEXT (GLenum target); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); typedef void (APIENTRYP PFNGLMINMAXEXTPROC) (GLenum target, GLenum internalformat, GLboolean sink); typedef void (APIENTRYP PFNGLRESETHISTOGRAMEXTPROC) (GLenum target); typedef void (APIENTRYP PFNGLRESETMINMAXEXTPROC) (GLenum target); #endif #ifndef GL_EXT_convolution #define GL_EXT_convolution 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); GLAPI void APIENTRY glConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); GLAPI void APIENTRY glConvolutionParameterfEXT (GLenum target, GLenum pname, GLfloat params); GLAPI void APIENTRY glConvolutionParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glConvolutionParameteriEXT (GLenum target, GLenum pname, GLint params); GLAPI void APIENTRY glConvolutionParameterivEXT (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glCopyConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); GLAPI void APIENTRY glCopyConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glGetConvolutionFilterEXT (GLenum target, GLenum format, GLenum type, GLvoid *image); GLAPI void APIENTRY glGetConvolutionParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetConvolutionParameterivEXT (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetSeparableFilterEXT (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); GLAPI void APIENTRY glSeparableFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image); typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); #endif #ifndef GL_SGI_color_matrix #define GL_SGI_color_matrix 1 #endif #ifndef GL_SGI_color_table #define GL_SGI_color_table 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorTableSGI (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); GLAPI void APIENTRY glColorTableParameterfvSGI (GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glColorTableParameterivSGI (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glCopyColorTableSGI (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); GLAPI void APIENTRY glGetColorTableSGI (GLenum target, GLenum format, GLenum type, GLvoid *table); GLAPI void APIENTRY glGetColorTableParameterfvSGI (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetColorTableParameterivSGI (GLenum target, GLenum pname, GLint *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint *params); #endif #ifndef GL_SGIX_pixel_texture #define GL_SGIX_pixel_texture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPixelTexGenSGIX (GLenum mode); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPIXELTEXGENSGIXPROC) (GLenum mode); #endif #ifndef GL_SGIS_pixel_texture #define GL_SGIS_pixel_texture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPixelTexGenParameteriSGIS (GLenum pname, GLint param); GLAPI void APIENTRY glPixelTexGenParameterivSGIS (GLenum pname, const GLint *params); GLAPI void APIENTRY glPixelTexGenParameterfSGIS (GLenum pname, GLfloat param); GLAPI void APIENTRY glPixelTexGenParameterfvSGIS (GLenum pname, const GLfloat *params); GLAPI void APIENTRY glGetPixelTexGenParameterivSGIS (GLenum pname, GLint *params); GLAPI void APIENTRY glGetPixelTexGenParameterfvSGIS (GLenum pname, GLfloat *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERISGISPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFSGISPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, GLfloat *params); #endif #ifndef GL_SGIS_texture4D #define GL_SGIS_texture4D 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexImage4DSGIS (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels); GLAPI void APIENTRY glTexSubImage4DSGIS (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels); #endif #ifndef GL_SGI_texture_color_table #define GL_SGI_texture_color_table 1 #endif #ifndef GL_EXT_cmyka #define GL_EXT_cmyka 1 #endif #ifndef GL_EXT_texture_object #define GL_EXT_texture_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLboolean APIENTRY glAreTexturesResidentEXT (GLsizei n, const GLuint *textures, GLboolean *residences); GLAPI void APIENTRY glBindTextureEXT (GLenum target, GLuint texture); GLAPI void APIENTRY glDeleteTexturesEXT (GLsizei n, const GLuint *textures); GLAPI void APIENTRY glGenTexturesEXT (GLsizei n, GLuint *textures); GLAPI GLboolean APIENTRY glIsTextureEXT (GLuint texture); GLAPI void APIENTRY glPrioritizeTexturesEXT (GLsizei n, const GLuint *textures, const GLclampf *priorities); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTEXTPROC) (GLsizei n, const GLuint *textures, GLboolean *residences); typedef void (APIENTRYP PFNGLBINDTEXTUREEXTPROC) (GLenum target, GLuint texture); typedef void (APIENTRYP PFNGLDELETETEXTURESEXTPROC) (GLsizei n, const GLuint *textures); typedef void (APIENTRYP PFNGLGENTEXTURESEXTPROC) (GLsizei n, GLuint *textures); typedef GLboolean (APIENTRYP PFNGLISTEXTUREEXTPROC) (GLuint texture); typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESEXTPROC) (GLsizei n, const GLuint *textures, const GLclampf *priorities); #endif #ifndef GL_SGIS_detail_texture #define GL_SGIS_detail_texture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDetailTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points); GLAPI void APIENTRY glGetDetailTexFuncSGIS (GLenum target, GLfloat *points); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDETAILTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points); typedef void (APIENTRYP PFNGLGETDETAILTEXFUNCSGISPROC) (GLenum target, GLfloat *points); #endif #ifndef GL_SGIS_sharpen_texture #define GL_SGIS_sharpen_texture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSharpenTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points); GLAPI void APIENTRY glGetSharpenTexFuncSGIS (GLenum target, GLfloat *points); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSHARPENTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points); typedef void (APIENTRYP PFNGLGETSHARPENTEXFUNCSGISPROC) (GLenum target, GLfloat *points); #endif #ifndef GL_EXT_packed_pixels #define GL_EXT_packed_pixels 1 #endif #ifndef GL_SGIS_texture_lod #define GL_SGIS_texture_lod 1 #endif #ifndef GL_SGIS_multisample #define GL_SGIS_multisample 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSampleMaskSGIS (GLclampf value, GLboolean invert); GLAPI void APIENTRY glSamplePatternSGIS (GLenum pattern); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSAMPLEMASKSGISPROC) (GLclampf value, GLboolean invert); typedef void (APIENTRYP PFNGLSAMPLEPATTERNSGISPROC) (GLenum pattern); #endif #ifndef GL_EXT_rescale_normal #define GL_EXT_rescale_normal 1 #endif #ifndef GL_EXT_vertex_array #define GL_EXT_vertex_array 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glArrayElementEXT (GLint i); GLAPI void APIENTRY glColorPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); GLAPI void APIENTRY glDrawArraysEXT (GLenum mode, GLint first, GLsizei count); GLAPI void APIENTRY glEdgeFlagPointerEXT (GLsizei stride, GLsizei count, const GLboolean *pointer); GLAPI void APIENTRY glGetPointervEXT (GLenum pname, GLvoid* *params); GLAPI void APIENTRY glIndexPointerEXT (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); GLAPI void APIENTRY glNormalPointerEXT (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); GLAPI void APIENTRY glTexCoordPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); GLAPI void APIENTRY glVertexPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLARRAYELEMENTEXTPROC) (GLint i); typedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); typedef void (APIENTRYP PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count); typedef void (APIENTRYP PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean *pointer); typedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC) (GLenum pname, GLvoid* *params); typedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); typedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); typedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); typedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); #endif #ifndef GL_EXT_misc_attribute #define GL_EXT_misc_attribute 1 #endif #ifndef GL_SGIS_generate_mipmap #define GL_SGIS_generate_mipmap 1 #endif #ifndef GL_SGIX_clipmap #define GL_SGIX_clipmap 1 #endif #ifndef GL_SGIX_shadow #define GL_SGIX_shadow 1 #endif #ifndef GL_SGIS_texture_edge_clamp #define GL_SGIS_texture_edge_clamp 1 #endif #ifndef GL_SGIS_texture_border_clamp #define GL_SGIS_texture_border_clamp 1 #endif #ifndef GL_EXT_blend_minmax #define GL_EXT_blend_minmax 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendEquationEXT (GLenum mode); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDEQUATIONEXTPROC) (GLenum mode); #endif #ifndef GL_EXT_blend_subtract #define GL_EXT_blend_subtract 1 #endif #ifndef GL_EXT_blend_logic_op #define GL_EXT_blend_logic_op 1 #endif #ifndef GL_SGIX_interlace #define GL_SGIX_interlace 1 #endif #ifndef GL_SGIX_pixel_tiles #define GL_SGIX_pixel_tiles 1 #endif #ifndef GL_SGIX_texture_select #define GL_SGIX_texture_select 1 #endif #ifndef GL_SGIX_sprite #define GL_SGIX_sprite 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSpriteParameterfSGIX (GLenum pname, GLfloat param); GLAPI void APIENTRY glSpriteParameterfvSGIX (GLenum pname, const GLfloat *params); GLAPI void APIENTRY glSpriteParameteriSGIX (GLenum pname, GLint param); GLAPI void APIENTRY glSpriteParameterivSGIX (GLenum pname, const GLint *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSPRITEPARAMETERFSGIXPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLSPRITEPARAMETERFVSGIXPROC) (GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLSPRITEPARAMETERISGIXPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLSPRITEPARAMETERIVSGIXPROC) (GLenum pname, const GLint *params); #endif #ifndef GL_SGIX_texture_multi_buffer #define GL_SGIX_texture_multi_buffer 1 #endif #ifndef GL_EXT_point_parameters #define GL_EXT_point_parameters 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPointParameterfEXT (GLenum pname, GLfloat param); GLAPI void APIENTRY glPointParameterfvEXT (GLenum pname, const GLfloat *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params); #endif #ifndef GL_SGIS_point_parameters #define GL_SGIS_point_parameters 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPointParameterfSGIS (GLenum pname, GLfloat param); GLAPI void APIENTRY glPointParameterfvSGIS (GLenum pname, const GLfloat *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPOINTPARAMETERFSGISPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPOINTPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params); #endif #ifndef GL_SGIX_instruments #define GL_SGIX_instruments 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLint APIENTRY glGetInstrumentsSGIX (void); GLAPI void APIENTRY glInstrumentsBufferSGIX (GLsizei size, GLint *buffer); GLAPI GLint APIENTRY glPollInstrumentsSGIX (GLint *marker_p); GLAPI void APIENTRY glReadInstrumentsSGIX (GLint marker); GLAPI void APIENTRY glStartInstrumentsSGIX (void); GLAPI void APIENTRY glStopInstrumentsSGIX (GLint marker); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLint (APIENTRYP PFNGLGETINSTRUMENTSSGIXPROC) (void); typedef void (APIENTRYP PFNGLINSTRUMENTSBUFFERSGIXPROC) (GLsizei size, GLint *buffer); typedef GLint (APIENTRYP PFNGLPOLLINSTRUMENTSSGIXPROC) (GLint *marker_p); typedef void (APIENTRYP PFNGLREADINSTRUMENTSSGIXPROC) (GLint marker); typedef void (APIENTRYP PFNGLSTARTINSTRUMENTSSGIXPROC) (void); typedef void (APIENTRYP PFNGLSTOPINSTRUMENTSSGIXPROC) (GLint marker); #endif #ifndef GL_SGIX_texture_scale_bias #define GL_SGIX_texture_scale_bias 1 #endif #ifndef GL_SGIX_framezoom #define GL_SGIX_framezoom 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFrameZoomSGIX (GLint factor); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFRAMEZOOMSGIXPROC) (GLint factor); #endif #ifndef GL_SGIX_tag_sample_buffer #define GL_SGIX_tag_sample_buffer 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTagSampleBufferSGIX (void); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTAGSAMPLEBUFFERSGIXPROC) (void); #endif #ifndef GL_SGIX_polynomial_ffd #define GL_SGIX_polynomial_ffd 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDeformationMap3dSGIX (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points); GLAPI void APIENTRY glDeformationMap3fSGIX (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points); GLAPI void APIENTRY glDeformSGIX (GLbitfield mask); GLAPI void APIENTRY glLoadIdentityDeformationMapSGIX (GLbitfield mask); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDEFORMATIONMAP3DSGIXPROC) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points); typedef void (APIENTRYP PFNGLDEFORMATIONMAP3FSGIXPROC) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points); typedef void (APIENTRYP PFNGLDEFORMSGIXPROC) (GLbitfield mask); typedef void (APIENTRYP PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC) (GLbitfield mask); #endif #ifndef GL_SGIX_reference_plane #define GL_SGIX_reference_plane 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glReferencePlaneSGIX (const GLdouble *equation); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLREFERENCEPLANESGIXPROC) (const GLdouble *equation); #endif #ifndef GL_SGIX_flush_raster #define GL_SGIX_flush_raster 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFlushRasterSGIX (void); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFLUSHRASTERSGIXPROC) (void); #endif #ifndef GL_SGIX_depth_texture #define GL_SGIX_depth_texture 1 #endif #ifndef GL_SGIS_fog_function #define GL_SGIS_fog_function 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFogFuncSGIS (GLsizei n, const GLfloat *points); GLAPI void APIENTRY glGetFogFuncSGIS (GLfloat *points); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFOGFUNCSGISPROC) (GLsizei n, const GLfloat *points); typedef void (APIENTRYP PFNGLGETFOGFUNCSGISPROC) (GLfloat *points); #endif #ifndef GL_SGIX_fog_offset #define GL_SGIX_fog_offset 1 #endif #ifndef GL_HP_image_transform #define GL_HP_image_transform 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glImageTransformParameteriHP (GLenum target, GLenum pname, GLint param); GLAPI void APIENTRY glImageTransformParameterfHP (GLenum target, GLenum pname, GLfloat param); GLAPI void APIENTRY glImageTransformParameterivHP (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glImageTransformParameterfvHP (GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glGetImageTransformParameterivHP (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetImageTransformParameterfvHP (GLenum target, GLenum pname, GLfloat *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params); #endif #ifndef GL_HP_convolution_border_modes #define GL_HP_convolution_border_modes 1 #endif #ifndef GL_SGIX_texture_add_env #define GL_SGIX_texture_add_env 1 #endif #ifndef GL_EXT_color_subtable #define GL_EXT_color_subtable 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorSubTableEXT (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); GLAPI void APIENTRY glCopyColorSubTableEXT (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); #endif #ifndef GL_PGI_vertex_hints #define GL_PGI_vertex_hints 1 #endif #ifndef GL_PGI_misc_hints #define GL_PGI_misc_hints 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glHintPGI (GLenum target, GLint mode); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLHINTPGIPROC) (GLenum target, GLint mode); #endif #ifndef GL_EXT_paletted_texture #define GL_EXT_paletted_texture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorTableEXT (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); GLAPI void APIENTRY glGetColorTableEXT (GLenum target, GLenum format, GLenum type, GLvoid *data); GLAPI void APIENTRY glGetColorTableParameterivEXT (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetColorTableParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); typedef void (APIENTRYP PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *data); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); #endif #ifndef GL_EXT_clip_volume_hint #define GL_EXT_clip_volume_hint 1 #endif #ifndef GL_SGIX_list_priority #define GL_SGIX_list_priority 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetListParameterfvSGIX (GLuint list, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetListParameterivSGIX (GLuint list, GLenum pname, GLint *params); GLAPI void APIENTRY glListParameterfSGIX (GLuint list, GLenum pname, GLfloat param); GLAPI void APIENTRY glListParameterfvSGIX (GLuint list, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glListParameteriSGIX (GLuint list, GLenum pname, GLint param); GLAPI void APIENTRY glListParameterivSGIX (GLuint list, GLenum pname, const GLint *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGETLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLLISTPARAMETERFSGIXPROC) (GLuint list, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLLISTPARAMETERISGIXPROC) (GLuint list, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, const GLint *params); #endif #ifndef GL_SGIX_ir_instrument1 #define GL_SGIX_ir_instrument1 1 #endif #ifndef GL_SGIX_calligraphic_fragment #define GL_SGIX_calligraphic_fragment 1 #endif #ifndef GL_SGIX_texture_lod_bias #define GL_SGIX_texture_lod_bias 1 #endif #ifndef GL_SGIX_shadow_ambient #define GL_SGIX_shadow_ambient 1 #endif #ifndef GL_EXT_index_texture #define GL_EXT_index_texture 1 #endif #ifndef GL_EXT_index_material #define GL_EXT_index_material 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glIndexMaterialEXT (GLenum face, GLenum mode); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLINDEXMATERIALEXTPROC) (GLenum face, GLenum mode); #endif #ifndef GL_EXT_index_func #define GL_EXT_index_func 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glIndexFuncEXT (GLenum func, GLclampf ref); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLINDEXFUNCEXTPROC) (GLenum func, GLclampf ref); #endif #ifndef GL_EXT_index_array_formats #define GL_EXT_index_array_formats 1 #endif #ifndef GL_EXT_compiled_vertex_array #define GL_EXT_compiled_vertex_array 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glLockArraysEXT (GLint first, GLsizei count); GLAPI void APIENTRY glUnlockArraysEXT (void); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count); typedef void (APIENTRYP PFNGLUNLOCKARRAYSEXTPROC) (void); #endif #ifndef GL_EXT_cull_vertex #define GL_EXT_cull_vertex 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCullParameterdvEXT (GLenum pname, GLdouble *params); GLAPI void APIENTRY glCullParameterfvEXT (GLenum pname, GLfloat *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCULLPARAMETERDVEXTPROC) (GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLCULLPARAMETERFVEXTPROC) (GLenum pname, GLfloat *params); #endif #ifndef GL_SGIX_ycrcb #define GL_SGIX_ycrcb 1 #endif #ifndef GL_SGIX_fragment_lighting #define GL_SGIX_fragment_lighting 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFragmentColorMaterialSGIX (GLenum face, GLenum mode); GLAPI void APIENTRY glFragmentLightfSGIX (GLenum light, GLenum pname, GLfloat param); GLAPI void APIENTRY glFragmentLightfvSGIX (GLenum light, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glFragmentLightiSGIX (GLenum light, GLenum pname, GLint param); GLAPI void APIENTRY glFragmentLightivSGIX (GLenum light, GLenum pname, const GLint *params); GLAPI void APIENTRY glFragmentLightModelfSGIX (GLenum pname, GLfloat param); GLAPI void APIENTRY glFragmentLightModelfvSGIX (GLenum pname, const GLfloat *params); GLAPI void APIENTRY glFragmentLightModeliSGIX (GLenum pname, GLint param); GLAPI void APIENTRY glFragmentLightModelivSGIX (GLenum pname, const GLint *params); GLAPI void APIENTRY glFragmentMaterialfSGIX (GLenum face, GLenum pname, GLfloat param); GLAPI void APIENTRY glFragmentMaterialfvSGIX (GLenum face, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glFragmentMaterialiSGIX (GLenum face, GLenum pname, GLint param); GLAPI void APIENTRY glFragmentMaterialivSGIX (GLenum face, GLenum pname, const GLint *params); GLAPI void APIENTRY glGetFragmentLightfvSGIX (GLenum light, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetFragmentLightivSGIX (GLenum light, GLenum pname, GLint *params); GLAPI void APIENTRY glGetFragmentMaterialfvSGIX (GLenum face, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetFragmentMaterialivSGIX (GLenum face, GLenum pname, GLint *params); GLAPI void APIENTRY glLightEnviSGIX (GLenum pname, GLint param); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFRAGMENTCOLORMATERIALSGIXPROC) (GLenum face, GLenum mode); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFSGIXPROC) (GLenum light, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTISGIXPROC) (GLenum light, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFSGIXPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFVSGIXPROC) (GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELISGIXPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELIVSGIXPROC) (GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFSGIXPROC) (GLenum face, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLFRAGMENTMATERIALISGIXPROC) (GLenum face, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLLIGHTENVISGIXPROC) (GLenum pname, GLint param); #endif #ifndef GL_IBM_rasterpos_clip #define GL_IBM_rasterpos_clip 1 #endif #ifndef GL_HP_texture_lighting #define GL_HP_texture_lighting 1 #endif #ifndef GL_EXT_draw_range_elements #define GL_EXT_draw_range_elements 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawRangeElementsEXT (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); #endif #ifndef GL_WIN_phong_shading #define GL_WIN_phong_shading 1 #endif #ifndef GL_WIN_specular_fog #define GL_WIN_specular_fog 1 #endif #ifndef GL_EXT_light_texture #define GL_EXT_light_texture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glApplyTextureEXT (GLenum mode); GLAPI void APIENTRY glTextureLightEXT (GLenum pname); GLAPI void APIENTRY glTextureMaterialEXT (GLenum face, GLenum mode); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLAPPLYTEXTUREEXTPROC) (GLenum mode); typedef void (APIENTRYP PFNGLTEXTURELIGHTEXTPROC) (GLenum pname); typedef void (APIENTRYP PFNGLTEXTUREMATERIALEXTPROC) (GLenum face, GLenum mode); #endif #ifndef GL_SGIX_blend_alpha_minmax #define GL_SGIX_blend_alpha_minmax 1 #endif #ifndef GL_EXT_bgra #define GL_EXT_bgra 1 #endif #ifndef GL_SGIX_async #define GL_SGIX_async 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glAsyncMarkerSGIX (GLuint marker); GLAPI GLint APIENTRY glFinishAsyncSGIX (GLuint *markerp); GLAPI GLint APIENTRY glPollAsyncSGIX (GLuint *markerp); GLAPI GLuint APIENTRY glGenAsyncMarkersSGIX (GLsizei range); GLAPI void APIENTRY glDeleteAsyncMarkersSGIX (GLuint marker, GLsizei range); GLAPI GLboolean APIENTRY glIsAsyncMarkerSGIX (GLuint marker); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLASYNCMARKERSGIXPROC) (GLuint marker); typedef GLint (APIENTRYP PFNGLFINISHASYNCSGIXPROC) (GLuint *markerp); typedef GLint (APIENTRYP PFNGLPOLLASYNCSGIXPROC) (GLuint *markerp); typedef GLuint (APIENTRYP PFNGLGENASYNCMARKERSSGIXPROC) (GLsizei range); typedef void (APIENTRYP PFNGLDELETEASYNCMARKERSSGIXPROC) (GLuint marker, GLsizei range); typedef GLboolean (APIENTRYP PFNGLISASYNCMARKERSGIXPROC) (GLuint marker); #endif #ifndef GL_SGIX_async_pixel #define GL_SGIX_async_pixel 1 #endif #ifndef GL_SGIX_async_histogram #define GL_SGIX_async_histogram 1 #endif #ifndef GL_INTEL_parallel_arrays #define GL_INTEL_parallel_arrays 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexPointervINTEL (GLint size, GLenum type, const GLvoid* *pointer); GLAPI void APIENTRY glNormalPointervINTEL (GLenum type, const GLvoid* *pointer); GLAPI void APIENTRY glColorPointervINTEL (GLint size, GLenum type, const GLvoid* *pointer); GLAPI void APIENTRY glTexCoordPointervINTEL (GLint size, GLenum type, const GLvoid* *pointer); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer); typedef void (APIENTRYP PFNGLNORMALPOINTERVINTELPROC) (GLenum type, const GLvoid* *pointer); typedef void (APIENTRYP PFNGLCOLORPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer); typedef void (APIENTRYP PFNGLTEXCOORDPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid* *pointer); #endif #ifndef GL_HP_occlusion_test #define GL_HP_occlusion_test 1 #endif #ifndef GL_EXT_pixel_transform #define GL_EXT_pixel_transform 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPixelTransformParameteriEXT (GLenum target, GLenum pname, GLint param); GLAPI void APIENTRY glPixelTransformParameterfEXT (GLenum target, GLenum pname, GLfloat param); GLAPI void APIENTRY glPixelTransformParameterivEXT (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glPixelTransformParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); #endif #ifndef GL_EXT_pixel_transform_color_table #define GL_EXT_pixel_transform_color_table 1 #endif #ifndef GL_EXT_shared_texture_palette #define GL_EXT_shared_texture_palette 1 #endif #ifndef GL_EXT_separate_specular_color #define GL_EXT_separate_specular_color 1 #endif #ifndef GL_EXT_secondary_color #define GL_EXT_secondary_color 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSecondaryColor3bEXT (GLbyte red, GLbyte green, GLbyte blue); GLAPI void APIENTRY glSecondaryColor3bvEXT (const GLbyte *v); GLAPI void APIENTRY glSecondaryColor3dEXT (GLdouble red, GLdouble green, GLdouble blue); GLAPI void APIENTRY glSecondaryColor3dvEXT (const GLdouble *v); GLAPI void APIENTRY glSecondaryColor3fEXT (GLfloat red, GLfloat green, GLfloat blue); GLAPI void APIENTRY glSecondaryColor3fvEXT (const GLfloat *v); GLAPI void APIENTRY glSecondaryColor3iEXT (GLint red, GLint green, GLint blue); GLAPI void APIENTRY glSecondaryColor3ivEXT (const GLint *v); GLAPI void APIENTRY glSecondaryColor3sEXT (GLshort red, GLshort green, GLshort blue); GLAPI void APIENTRY glSecondaryColor3svEXT (const GLshort *v); GLAPI void APIENTRY glSecondaryColor3ubEXT (GLubyte red, GLubyte green, GLubyte blue); GLAPI void APIENTRY glSecondaryColor3ubvEXT (const GLubyte *v); GLAPI void APIENTRY glSecondaryColor3uiEXT (GLuint red, GLuint green, GLuint blue); GLAPI void APIENTRY glSecondaryColor3uivEXT (const GLuint *v); GLAPI void APIENTRY glSecondaryColor3usEXT (GLushort red, GLushort green, GLushort blue); GLAPI void APIENTRY glSecondaryColor3usvEXT (const GLushort *v); GLAPI void APIENTRY glSecondaryColorPointerEXT (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BEXTPROC) (GLbyte red, GLbyte green, GLbyte blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVEXTPROC) (const GLbyte *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DEXTPROC) (GLdouble red, GLdouble green, GLdouble blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVEXTPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FEXTPROC) (GLfloat red, GLfloat green, GLfloat blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVEXTPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IEXTPROC) (GLint red, GLint green, GLint blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVEXTPROC) (const GLint *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SEXTPROC) (GLshort red, GLshort green, GLshort blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVEXTPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBEXTPROC) (GLubyte red, GLubyte green, GLubyte blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVEXTPROC) (const GLubyte *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIEXTPROC) (GLuint red, GLuint green, GLuint blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVEXTPROC) (const GLuint *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USEXTPROC) (GLushort red, GLushort green, GLushort blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVEXTPROC) (const GLushort *v); typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); #endif #ifndef GL_EXT_texture_perturb_normal #define GL_EXT_texture_perturb_normal 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTextureNormalEXT (GLenum mode); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXTURENORMALEXTPROC) (GLenum mode); #endif #ifndef GL_EXT_multi_draw_arrays #define GL_EXT_multi_draw_arrays 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMultiDrawArraysEXT (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); GLAPI void APIENTRY glMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); #endif #ifndef GL_EXT_fog_coord #define GL_EXT_fog_coord 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFogCoordfEXT (GLfloat coord); GLAPI void APIENTRY glFogCoordfvEXT (const GLfloat *coord); GLAPI void APIENTRY glFogCoorddEXT (GLdouble coord); GLAPI void APIENTRY glFogCoorddvEXT (const GLdouble *coord); GLAPI void APIENTRY glFogCoordPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFOGCOORDFEXTPROC) (GLfloat coord); typedef void (APIENTRYP PFNGLFOGCOORDFVEXTPROC) (const GLfloat *coord); typedef void (APIENTRYP PFNGLFOGCOORDDEXTPROC) (GLdouble coord); typedef void (APIENTRYP PFNGLFOGCOORDDVEXTPROC) (const GLdouble *coord); typedef void (APIENTRYP PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); #endif #ifndef GL_REND_screen_coordinates #define GL_REND_screen_coordinates 1 #endif #ifndef GL_EXT_coordinate_frame #define GL_EXT_coordinate_frame 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTangent3bEXT (GLbyte tx, GLbyte ty, GLbyte tz); GLAPI void APIENTRY glTangent3bvEXT (const GLbyte *v); GLAPI void APIENTRY glTangent3dEXT (GLdouble tx, GLdouble ty, GLdouble tz); GLAPI void APIENTRY glTangent3dvEXT (const GLdouble *v); GLAPI void APIENTRY glTangent3fEXT (GLfloat tx, GLfloat ty, GLfloat tz); GLAPI void APIENTRY glTangent3fvEXT (const GLfloat *v); GLAPI void APIENTRY glTangent3iEXT (GLint tx, GLint ty, GLint tz); GLAPI void APIENTRY glTangent3ivEXT (const GLint *v); GLAPI void APIENTRY glTangent3sEXT (GLshort tx, GLshort ty, GLshort tz); GLAPI void APIENTRY glTangent3svEXT (const GLshort *v); GLAPI void APIENTRY glBinormal3bEXT (GLbyte bx, GLbyte by, GLbyte bz); GLAPI void APIENTRY glBinormal3bvEXT (const GLbyte *v); GLAPI void APIENTRY glBinormal3dEXT (GLdouble bx, GLdouble by, GLdouble bz); GLAPI void APIENTRY glBinormal3dvEXT (const GLdouble *v); GLAPI void APIENTRY glBinormal3fEXT (GLfloat bx, GLfloat by, GLfloat bz); GLAPI void APIENTRY glBinormal3fvEXT (const GLfloat *v); GLAPI void APIENTRY glBinormal3iEXT (GLint bx, GLint by, GLint bz); GLAPI void APIENTRY glBinormal3ivEXT (const GLint *v); GLAPI void APIENTRY glBinormal3sEXT (GLshort bx, GLshort by, GLshort bz); GLAPI void APIENTRY glBinormal3svEXT (const GLshort *v); GLAPI void APIENTRY glTangentPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer); GLAPI void APIENTRY glBinormalPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTANGENT3BEXTPROC) (GLbyte tx, GLbyte ty, GLbyte tz); typedef void (APIENTRYP PFNGLTANGENT3BVEXTPROC) (const GLbyte *v); typedef void (APIENTRYP PFNGLTANGENT3DEXTPROC) (GLdouble tx, GLdouble ty, GLdouble tz); typedef void (APIENTRYP PFNGLTANGENT3DVEXTPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLTANGENT3FEXTPROC) (GLfloat tx, GLfloat ty, GLfloat tz); typedef void (APIENTRYP PFNGLTANGENT3FVEXTPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLTANGENT3IEXTPROC) (GLint tx, GLint ty, GLint tz); typedef void (APIENTRYP PFNGLTANGENT3IVEXTPROC) (const GLint *v); typedef void (APIENTRYP PFNGLTANGENT3SEXTPROC) (GLshort tx, GLshort ty, GLshort tz); typedef void (APIENTRYP PFNGLTANGENT3SVEXTPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLBINORMAL3BEXTPROC) (GLbyte bx, GLbyte by, GLbyte bz); typedef void (APIENTRYP PFNGLBINORMAL3BVEXTPROC) (const GLbyte *v); typedef void (APIENTRYP PFNGLBINORMAL3DEXTPROC) (GLdouble bx, GLdouble by, GLdouble bz); typedef void (APIENTRYP PFNGLBINORMAL3DVEXTPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLBINORMAL3FEXTPROC) (GLfloat bx, GLfloat by, GLfloat bz); typedef void (APIENTRYP PFNGLBINORMAL3FVEXTPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLBINORMAL3IEXTPROC) (GLint bx, GLint by, GLint bz); typedef void (APIENTRYP PFNGLBINORMAL3IVEXTPROC) (const GLint *v); typedef void (APIENTRYP PFNGLBINORMAL3SEXTPROC) (GLshort bx, GLshort by, GLshort bz); typedef void (APIENTRYP PFNGLBINORMAL3SVEXTPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); #endif #ifndef GL_EXT_texture_env_combine #define GL_EXT_texture_env_combine 1 #endif #ifndef GL_APPLE_specular_vector #define GL_APPLE_specular_vector 1 #endif #ifndef GL_APPLE_transform_hint #define GL_APPLE_transform_hint 1 #endif #ifndef GL_SGIX_fog_scale #define GL_SGIX_fog_scale 1 #endif #ifndef GL_SUNX_constant_data #define GL_SUNX_constant_data 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFinishTextureSUNX (void); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFINISHTEXTURESUNXPROC) (void); #endif #ifndef GL_SUN_global_alpha #define GL_SUN_global_alpha 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGlobalAlphaFactorbSUN (GLbyte factor); GLAPI void APIENTRY glGlobalAlphaFactorsSUN (GLshort factor); GLAPI void APIENTRY glGlobalAlphaFactoriSUN (GLint factor); GLAPI void APIENTRY glGlobalAlphaFactorfSUN (GLfloat factor); GLAPI void APIENTRY glGlobalAlphaFactordSUN (GLdouble factor); GLAPI void APIENTRY glGlobalAlphaFactorubSUN (GLubyte factor); GLAPI void APIENTRY glGlobalAlphaFactorusSUN (GLushort factor); GLAPI void APIENTRY glGlobalAlphaFactoruiSUN (GLuint factor); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORBSUNPROC) (GLbyte factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORSSUNPROC) (GLshort factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORISUNPROC) (GLint factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORFSUNPROC) (GLfloat factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORDSUNPROC) (GLdouble factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUBSUNPROC) (GLubyte factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUSSUNPROC) (GLushort factor); typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUISUNPROC) (GLuint factor); #endif #ifndef GL_SUN_triangle_list #define GL_SUN_triangle_list 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glReplacementCodeuiSUN (GLuint code); GLAPI void APIENTRY glReplacementCodeusSUN (GLushort code); GLAPI void APIENTRY glReplacementCodeubSUN (GLubyte code); GLAPI void APIENTRY glReplacementCodeuivSUN (const GLuint *code); GLAPI void APIENTRY glReplacementCodeusvSUN (const GLushort *code); GLAPI void APIENTRY glReplacementCodeubvSUN (const GLubyte *code); GLAPI void APIENTRY glReplacementCodePointerSUN (GLenum type, GLsizei stride, const GLvoid* *pointer); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLREPLACEMENTCODEUISUNPROC) (GLuint code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSSUNPROC) (GLushort code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBSUNPROC) (GLubyte code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVSUNPROC) (const GLuint *code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSVSUNPROC) (const GLushort *code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBVSUNPROC) (const GLubyte *code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const GLvoid* *pointer); #endif #ifndef GL_SUN_vertex #define GL_SUN_vertex 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColor4ubVertex2fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); GLAPI void APIENTRY glColor4ubVertex2fvSUN (const GLubyte *c, const GLfloat *v); GLAPI void APIENTRY glColor4ubVertex3fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glColor4ubVertex3fvSUN (const GLubyte *c, const GLfloat *v); GLAPI void APIENTRY glColor3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glColor3fVertex3fvSUN (const GLfloat *c, const GLfloat *v); GLAPI void APIENTRY glNormal3fVertex3fSUN (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glNormal3fVertex3fvSUN (const GLfloat *n, const GLfloat *v); GLAPI void APIENTRY glColor4fNormal3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glColor4fNormal3fVertex3fvSUN (const GLfloat *c, const GLfloat *n, const GLfloat *v); GLAPI void APIENTRY glTexCoord2fVertex3fSUN (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glTexCoord2fVertex3fvSUN (const GLfloat *tc, const GLfloat *v); GLAPI void APIENTRY glTexCoord4fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glTexCoord4fVertex4fvSUN (const GLfloat *tc, const GLfloat *v); GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fSUN (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fvSUN (const GLfloat *tc, const GLubyte *c, const GLfloat *v); GLAPI void APIENTRY glTexCoord2fColor3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glTexCoord2fColor3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *v); GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *n, const GLfloat *v); GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); GLAPI void APIENTRY glReplacementCodeuiVertex3fSUN (GLuint rc, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glReplacementCodeuiVertex3fvSUN (const GLuint *rc, const GLfloat *v); GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fSUN (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *rc, const GLubyte *c, const GLfloat *v); GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *v); GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fSUN (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *n, const GLfloat *v); GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *v); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FVSUNPROC) (const GLubyte *c, const GLfloat *v); typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FVSUNPROC) (const GLubyte *c, const GLfloat *v); typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *v); typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FSUNPROC) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC) (const GLfloat *tc, const GLubyte *c, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC) (GLuint rc, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC) (const GLuint *rc, const GLubyte *c, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); #endif #ifndef GL_EXT_blend_func_separate #define GL_EXT_blend_func_separate 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendFuncSeparateEXT (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEEXTPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); #endif #ifndef GL_INGR_blend_func_separate #define GL_INGR_blend_func_separate 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendFuncSeparateINGR (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINGRPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); #endif #ifndef GL_INGR_color_clamp #define GL_INGR_color_clamp 1 #endif #ifndef GL_INGR_interlace_read #define GL_INGR_interlace_read 1 #endif #ifndef GL_EXT_stencil_wrap #define GL_EXT_stencil_wrap 1 #endif #ifndef GL_EXT_422_pixels #define GL_EXT_422_pixels 1 #endif #ifndef GL_NV_texgen_reflection #define GL_NV_texgen_reflection 1 #endif #ifndef GL_SUN_convolution_border_modes #define GL_SUN_convolution_border_modes 1 #endif #ifndef GL_EXT_texture_env_add #define GL_EXT_texture_env_add 1 #endif #ifndef GL_EXT_texture_lod_bias #define GL_EXT_texture_lod_bias 1 #endif #ifndef GL_EXT_texture_filter_anisotropic #define GL_EXT_texture_filter_anisotropic 1 #endif #ifndef GL_EXT_vertex_weighting #define GL_EXT_vertex_weighting 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexWeightfEXT (GLfloat weight); GLAPI void APIENTRY glVertexWeightfvEXT (const GLfloat *weight); GLAPI void APIENTRY glVertexWeightPointerEXT (GLsizei size, GLenum type, GLsizei stride, const GLvoid *pointer); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight); typedef void (APIENTRYP PFNGLVERTEXWEIGHTFVEXTPROC) (const GLfloat *weight); typedef void (APIENTRYP PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLsizei size, GLenum type, GLsizei stride, const GLvoid *pointer); #endif #ifndef GL_NV_light_max_exponent #define GL_NV_light_max_exponent 1 #endif #ifndef GL_NV_vertex_array_range #define GL_NV_vertex_array_range 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFlushVertexArrayRangeNV (void); GLAPI void APIENTRY glVertexArrayRangeNV (GLsizei length, const GLvoid *pointer); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void); typedef void (APIENTRYP PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, const GLvoid *pointer); #endif #ifndef GL_NV_register_combiners #define GL_NV_register_combiners 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCombinerParameterfvNV (GLenum pname, const GLfloat *params); GLAPI void APIENTRY glCombinerParameterfNV (GLenum pname, GLfloat param); GLAPI void APIENTRY glCombinerParameterivNV (GLenum pname, const GLint *params); GLAPI void APIENTRY glCombinerParameteriNV (GLenum pname, GLint param); GLAPI void APIENTRY glCombinerInputNV (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); GLAPI void APIENTRY glCombinerOutputNV (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); GLAPI void APIENTRY glFinalCombinerInputNV (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); GLAPI void APIENTRY glGetCombinerInputParameterfvNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetCombinerInputParameterivNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); GLAPI void APIENTRY glGetCombinerOutputParameterfvNV (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetCombinerOutputParameterivNV (GLenum stage, GLenum portion, GLenum pname, GLint *params); GLAPI void APIENTRY glGetFinalCombinerInputParameterfvNV (GLenum variable, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetFinalCombinerInputParameterivNV (GLenum variable, GLenum pname, GLint *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFVNVPROC) (GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFNVPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLCOMBINERPARAMETERIVNVPROC) (GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOMBINERPARAMETERINVPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLCOMBINERINPUTNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); typedef void (APIENTRYP PFNGLCOMBINEROUTPUTNVPROC) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); typedef void (APIENTRYP PFNGLFINALCOMBINERINPUTNVPROC) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC) (GLenum variable, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC) (GLenum variable, GLenum pname, GLint *params); #endif #ifndef GL_NV_fog_distance #define GL_NV_fog_distance 1 #endif #ifndef GL_NV_texgen_emboss #define GL_NV_texgen_emboss 1 #endif #ifndef GL_NV_blend_square #define GL_NV_blend_square 1 #endif #ifndef GL_NV_texture_env_combine4 #define GL_NV_texture_env_combine4 1 #endif #ifndef GL_MESA_resize_buffers #define GL_MESA_resize_buffers 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glResizeBuffersMESA (void); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLRESIZEBUFFERSMESAPROC) (void); #endif #ifndef GL_MESA_window_pos #define GL_MESA_window_pos 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glWindowPos2dMESA (GLdouble x, GLdouble y); GLAPI void APIENTRY glWindowPos2dvMESA (const GLdouble *v); GLAPI void APIENTRY glWindowPos2fMESA (GLfloat x, GLfloat y); GLAPI void APIENTRY glWindowPos2fvMESA (const GLfloat *v); GLAPI void APIENTRY glWindowPos2iMESA (GLint x, GLint y); GLAPI void APIENTRY glWindowPos2ivMESA (const GLint *v); GLAPI void APIENTRY glWindowPos2sMESA (GLshort x, GLshort y); GLAPI void APIENTRY glWindowPos2svMESA (const GLshort *v); GLAPI void APIENTRY glWindowPos3dMESA (GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glWindowPos3dvMESA (const GLdouble *v); GLAPI void APIENTRY glWindowPos3fMESA (GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glWindowPos3fvMESA (const GLfloat *v); GLAPI void APIENTRY glWindowPos3iMESA (GLint x, GLint y, GLint z); GLAPI void APIENTRY glWindowPos3ivMESA (const GLint *v); GLAPI void APIENTRY glWindowPos3sMESA (GLshort x, GLshort y, GLshort z); GLAPI void APIENTRY glWindowPos3svMESA (const GLshort *v); GLAPI void APIENTRY glWindowPos4dMESA (GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glWindowPos4dvMESA (const GLdouble *v); GLAPI void APIENTRY glWindowPos4fMESA (GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glWindowPos4fvMESA (const GLfloat *v); GLAPI void APIENTRY glWindowPos4iMESA (GLint x, GLint y, GLint z, GLint w); GLAPI void APIENTRY glWindowPos4ivMESA (const GLint *v); GLAPI void APIENTRY glWindowPos4sMESA (GLshort x, GLshort y, GLshort z, GLshort w); GLAPI void APIENTRY glWindowPos4svMESA (const GLshort *v); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLWINDOWPOS2DMESAPROC) (GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLWINDOWPOS2DVMESAPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS2FMESAPROC) (GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLWINDOWPOS2FVMESAPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS2IMESAPROC) (GLint x, GLint y); typedef void (APIENTRYP PFNGLWINDOWPOS2IVMESAPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS2SMESAPROC) (GLshort x, GLshort y); typedef void (APIENTRYP PFNGLWINDOWPOS2SVMESAPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLWINDOWPOS3DMESAPROC) (GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLWINDOWPOS3DVMESAPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS3FMESAPROC) (GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLWINDOWPOS3FVMESAPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS3IMESAPROC) (GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLWINDOWPOS3IVMESAPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS3SMESAPROC) (GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLWINDOWPOS3SVMESAPROC) (const GLshort *v); typedef void (APIENTRYP PFNGLWINDOWPOS4DMESAPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLWINDOWPOS4DVMESAPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS4FMESAPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLWINDOWPOS4FVMESAPROC) (const GLfloat *v); typedef void (APIENTRYP PFNGLWINDOWPOS4IMESAPROC) (GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLWINDOWPOS4IVMESAPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS4SMESAPROC) (GLshort x, GLshort y, GLshort z, GLshort w); typedef void (APIENTRYP PFNGLWINDOWPOS4SVMESAPROC) (const GLshort *v); #endif #ifndef GL_IBM_cull_vertex #define GL_IBM_cull_vertex 1 #endif #ifndef GL_IBM_multimode_draw_arrays #define GL_IBM_multimode_draw_arrays 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMultiModeDrawArraysIBM (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); GLAPI void APIENTRY glMultiModeDrawElementsIBM (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei primcount, GLint modestride); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLMULTIMODEDRAWARRAYSIBMPROC) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); typedef void (APIENTRYP PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid* const *indices, GLsizei primcount, GLint modestride); #endif #ifndef GL_IBM_vertex_array_lists #define GL_IBM_vertex_array_lists 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); GLAPI void APIENTRY glSecondaryColorPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); GLAPI void APIENTRY glEdgeFlagPointerListIBM (GLint stride, const GLboolean* *pointer, GLint ptrstride); GLAPI void APIENTRY glFogCoordPointerListIBM (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); GLAPI void APIENTRY glIndexPointerListIBM (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); GLAPI void APIENTRY glNormalPointerListIBM (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); GLAPI void APIENTRY glTexCoordPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); GLAPI void APIENTRY glVertexPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERLISTIBMPROC) (GLint stride, const GLboolean* *pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid* *pointer, GLint ptrstride); #endif #ifndef GL_SGIX_subsample #define GL_SGIX_subsample 1 #endif #ifndef GL_SGIX_ycrcba #define GL_SGIX_ycrcba 1 #endif #ifndef GL_SGIX_ycrcb_subsample #define GL_SGIX_ycrcb_subsample 1 #endif #ifndef GL_SGIX_depth_pass_instrument #define GL_SGIX_depth_pass_instrument 1 #endif #ifndef GL_3DFX_texture_compression_FXT1 #define GL_3DFX_texture_compression_FXT1 1 #endif #ifndef GL_3DFX_multisample #define GL_3DFX_multisample 1 #endif #ifndef GL_3DFX_tbuffer #define GL_3DFX_tbuffer 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTbufferMask3DFX (GLuint mask); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTBUFFERMASK3DFXPROC) (GLuint mask); #endif #ifndef GL_EXT_multisample #define GL_EXT_multisample 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSampleMaskEXT (GLclampf value, GLboolean invert); GLAPI void APIENTRY glSamplePatternEXT (GLenum pattern); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSAMPLEMASKEXTPROC) (GLclampf value, GLboolean invert); typedef void (APIENTRYP PFNGLSAMPLEPATTERNEXTPROC) (GLenum pattern); #endif #ifndef GL_SGIX_vertex_preclip #define GL_SGIX_vertex_preclip 1 #endif #ifndef GL_SGIX_convolution_accuracy #define GL_SGIX_convolution_accuracy 1 #endif #ifndef GL_SGIX_resample #define GL_SGIX_resample 1 #endif #ifndef GL_SGIS_point_line_texgen #define GL_SGIS_point_line_texgen 1 #endif #ifndef GL_SGIS_texture_color_mask #define GL_SGIS_texture_color_mask 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTextureColorMaskSGIS (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXTURECOLORMASKSGISPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); #endif #ifndef GL_SGIX_igloo_interface #define GL_SGIX_igloo_interface 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glIglooInterfaceSGIX (GLenum pname, const GLvoid *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLIGLOOINTERFACESGIXPROC) (GLenum pname, const GLvoid *params); #endif #ifndef GL_EXT_texture_env_dot3 #define GL_EXT_texture_env_dot3 1 #endif #ifndef GL_ATI_texture_mirror_once #define GL_ATI_texture_mirror_once 1 #endif #ifndef GL_NV_fence #define GL_NV_fence 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDeleteFencesNV (GLsizei n, const GLuint *fences); GLAPI void APIENTRY glGenFencesNV (GLsizei n, GLuint *fences); GLAPI GLboolean APIENTRY glIsFenceNV (GLuint fence); GLAPI GLboolean APIENTRY glTestFenceNV (GLuint fence); GLAPI void APIENTRY glGetFenceivNV (GLuint fence, GLenum pname, GLint *params); GLAPI void APIENTRY glFinishFenceNV (GLuint fence); GLAPI void APIENTRY glSetFenceNV (GLuint fence, GLenum condition); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences); typedef void (APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences); typedef GLboolean (APIENTRYP PFNGLISFENCENVPROC) (GLuint fence); typedef GLboolean (APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence); typedef void (APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence); typedef void (APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition); #endif #ifndef GL_NV_evaluators #define GL_NV_evaluators 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points); GLAPI void APIENTRY glMapParameterivNV (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glMapParameterfvNV (GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glGetMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points); GLAPI void APIENTRY glGetMapParameterivNV (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetMapParameterfvNV (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetMapAttribParameterivNV (GLenum target, GLuint index, GLenum pname, GLint *params); GLAPI void APIENTRY glGetMapAttribParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params); GLAPI void APIENTRY glEvalMapsNV (GLenum target, GLenum mode); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points); typedef void (APIENTRYP PFNGLMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points); typedef void (APIENTRYP PFNGLGETMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERIVNVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLEVALMAPSNVPROC) (GLenum target, GLenum mode); #endif #ifndef GL_NV_packed_depth_stencil #define GL_NV_packed_depth_stencil 1 #endif #ifndef GL_NV_register_combiners2 #define GL_NV_register_combiners2 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCombinerStageParameterfvNV (GLenum stage, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glGetCombinerStageParameterfvNV (GLenum stage, GLenum pname, GLfloat *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, GLfloat *params); #endif #ifndef GL_NV_texture_compression_vtc #define GL_NV_texture_compression_vtc 1 #endif #ifndef GL_NV_texture_rectangle #define GL_NV_texture_rectangle 1 #endif #ifndef GL_NV_texture_shader #define GL_NV_texture_shader 1 #endif #ifndef GL_NV_texture_shader2 #define GL_NV_texture_shader2 1 #endif #ifndef GL_NV_vertex_array_range2 #define GL_NV_vertex_array_range2 1 #endif #ifndef GL_NV_vertex_program #define GL_NV_vertex_program 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLboolean APIENTRY glAreProgramsResidentNV (GLsizei n, const GLuint *programs, GLboolean *residences); GLAPI void APIENTRY glBindProgramNV (GLenum target, GLuint id); GLAPI void APIENTRY glDeleteProgramsNV (GLsizei n, const GLuint *programs); GLAPI void APIENTRY glExecuteProgramNV (GLenum target, GLuint id, const GLfloat *params); GLAPI void APIENTRY glGenProgramsNV (GLsizei n, GLuint *programs); GLAPI void APIENTRY glGetProgramParameterdvNV (GLenum target, GLuint index, GLenum pname, GLdouble *params); GLAPI void APIENTRY glGetProgramParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetProgramivNV (GLuint id, GLenum pname, GLint *params); GLAPI void APIENTRY glGetProgramStringNV (GLuint id, GLenum pname, GLubyte *program); GLAPI void APIENTRY glGetTrackMatrixivNV (GLenum target, GLuint address, GLenum pname, GLint *params); GLAPI void APIENTRY glGetVertexAttribdvNV (GLuint index, GLenum pname, GLdouble *params); GLAPI void APIENTRY glGetVertexAttribfvNV (GLuint index, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetVertexAttribivNV (GLuint index, GLenum pname, GLint *params); GLAPI void APIENTRY glGetVertexAttribPointervNV (GLuint index, GLenum pname, GLvoid* *pointer); GLAPI GLboolean APIENTRY glIsProgramNV (GLuint id); GLAPI void APIENTRY glLoadProgramNV (GLenum target, GLuint id, GLsizei len, const GLubyte *program); GLAPI void APIENTRY glProgramParameter4dNV (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glProgramParameter4dvNV (GLenum target, GLuint index, const GLdouble *v); GLAPI void APIENTRY glProgramParameter4fNV (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glProgramParameter4fvNV (GLenum target, GLuint index, const GLfloat *v); GLAPI void APIENTRY glProgramParameters4dvNV (GLenum target, GLuint index, GLsizei count, const GLdouble *v); GLAPI void APIENTRY glProgramParameters4fvNV (GLenum target, GLuint index, GLsizei count, const GLfloat *v); GLAPI void APIENTRY glRequestResidentProgramsNV (GLsizei n, const GLuint *programs); GLAPI void APIENTRY glTrackMatrixNV (GLenum target, GLuint address, GLenum matrix, GLenum transform); GLAPI void APIENTRY glVertexAttribPointerNV (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer); GLAPI void APIENTRY glVertexAttrib1dNV (GLuint index, GLdouble x); GLAPI void APIENTRY glVertexAttrib1dvNV (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib1fNV (GLuint index, GLfloat x); GLAPI void APIENTRY glVertexAttrib1fvNV (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib1sNV (GLuint index, GLshort x); GLAPI void APIENTRY glVertexAttrib1svNV (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib2dNV (GLuint index, GLdouble x, GLdouble y); GLAPI void APIENTRY glVertexAttrib2dvNV (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib2fNV (GLuint index, GLfloat x, GLfloat y); GLAPI void APIENTRY glVertexAttrib2fvNV (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib2sNV (GLuint index, GLshort x, GLshort y); GLAPI void APIENTRY glVertexAttrib2svNV (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib3dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glVertexAttrib3dvNV (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib3fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glVertexAttrib3fvNV (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib3sNV (GLuint index, GLshort x, GLshort y, GLshort z); GLAPI void APIENTRY glVertexAttrib3svNV (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib4dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glVertexAttrib4dvNV (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib4fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glVertexAttrib4fvNV (GLuint index, const GLfloat *v); GLAPI void APIENTRY glVertexAttrib4sNV (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); GLAPI void APIENTRY glVertexAttrib4svNV (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib4ubNV (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); GLAPI void APIENTRY glVertexAttrib4ubvNV (GLuint index, const GLubyte *v); GLAPI void APIENTRY glVertexAttribs1dvNV (GLuint index, GLsizei count, const GLdouble *v); GLAPI void APIENTRY glVertexAttribs1fvNV (GLuint index, GLsizei count, const GLfloat *v); GLAPI void APIENTRY glVertexAttribs1svNV (GLuint index, GLsizei count, const GLshort *v); GLAPI void APIENTRY glVertexAttribs2dvNV (GLuint index, GLsizei count, const GLdouble *v); GLAPI void APIENTRY glVertexAttribs2fvNV (GLuint index, GLsizei count, const GLfloat *v); GLAPI void APIENTRY glVertexAttribs2svNV (GLuint index, GLsizei count, const GLshort *v); GLAPI void APIENTRY glVertexAttribs3dvNV (GLuint index, GLsizei count, const GLdouble *v); GLAPI void APIENTRY glVertexAttribs3fvNV (GLuint index, GLsizei count, const GLfloat *v); GLAPI void APIENTRY glVertexAttribs3svNV (GLuint index, GLsizei count, const GLshort *v); GLAPI void APIENTRY glVertexAttribs4dvNV (GLuint index, GLsizei count, const GLdouble *v); GLAPI void APIENTRY glVertexAttribs4fvNV (GLuint index, GLsizei count, const GLfloat *v); GLAPI void APIENTRY glVertexAttribs4svNV (GLuint index, GLsizei count, const GLshort *v); GLAPI void APIENTRY glVertexAttribs4ubvNV (GLuint index, GLsizei count, const GLubyte *v); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLboolean (APIENTRYP PFNGLAREPROGRAMSRESIDENTNVPROC) (GLsizei n, const GLuint *programs, GLboolean *residences); typedef void (APIENTRYP PFNGLBINDPROGRAMNVPROC) (GLenum target, GLuint id); typedef void (APIENTRYP PFNGLDELETEPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); typedef void (APIENTRYP PFNGLEXECUTEPROGRAMNVPROC) (GLenum target, GLuint id, const GLfloat *params); typedef void (APIENTRYP PFNGLGENPROGRAMSNVPROC) (GLsizei n, GLuint *programs); typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERDVNVPROC) (GLenum target, GLuint index, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETPROGRAMIVNVPROC) (GLuint id, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGNVPROC) (GLuint id, GLenum pname, GLubyte *program); typedef void (APIENTRYP PFNGLGETTRACKMATRIXIVNVPROC) (GLenum target, GLuint address, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVNVPROC) (GLuint index, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVNVPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVNVPROC) (GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, GLvoid* *pointer); typedef GLboolean (APIENTRYP PFNGLISPROGRAMNVPROC) (GLuint id); typedef void (APIENTRYP PFNGLLOADPROGRAMNVPROC) (GLenum target, GLuint id, GLsizei len, const GLubyte *program); typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DNVPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DVNVPROC) (GLenum target, GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FNVPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FVNVPROC) (GLenum target, GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4DVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLdouble *v); typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4FVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLREQUESTRESIDENTPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); typedef void (APIENTRYP PFNGLTRACKMATRIXNVPROC) (GLenum target, GLuint address, GLenum matrix, GLenum transform); typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLVERTEXATTRIB1DNVPROC) (GLuint index, GLdouble x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVNVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FNVPROC) (GLuint index, GLfloat x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVNVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SNVPROC) (GLuint index, GLshort x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVNVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DNVPROC) (GLuint index, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVNVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FNVPROC) (GLuint index, GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVNVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SNVPROC) (GLuint index, GLshort x, GLshort y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVNVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVNVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVNVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVNVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVNVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVNVPROC) (GLuint index, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVNVPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBNVPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVNVPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS1DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS1FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS1SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS2DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS2FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS2SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS3DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS3FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS3SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS4DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS4FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS4SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS4UBVNVPROC) (GLuint index, GLsizei count, const GLubyte *v); #endif #ifndef GL_SGIX_texture_coordinate_clamp #define GL_SGIX_texture_coordinate_clamp 1 #endif #ifndef GL_SGIX_scalebias_hint #define GL_SGIX_scalebias_hint 1 #endif #ifndef GL_OML_interlace #define GL_OML_interlace 1 #endif #ifndef GL_OML_subsample #define GL_OML_subsample 1 #endif #ifndef GL_OML_resample #define GL_OML_resample 1 #endif #ifndef GL_NV_copy_depth_to_color #define GL_NV_copy_depth_to_color 1 #endif #ifndef GL_ATI_envmap_bumpmap #define GL_ATI_envmap_bumpmap 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexBumpParameterivATI (GLenum pname, const GLint *param); GLAPI void APIENTRY glTexBumpParameterfvATI (GLenum pname, const GLfloat *param); GLAPI void APIENTRY glGetTexBumpParameterivATI (GLenum pname, GLint *param); GLAPI void APIENTRY glGetTexBumpParameterfvATI (GLenum pname, GLfloat *param); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERIVATIPROC) (GLenum pname, const GLint *param); typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERFVATIPROC) (GLenum pname, const GLfloat *param); typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERIVATIPROC) (GLenum pname, GLint *param); typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERFVATIPROC) (GLenum pname, GLfloat *param); #endif #ifndef GL_ATI_fragment_shader #define GL_ATI_fragment_shader 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLuint APIENTRY glGenFragmentShadersATI (GLuint range); GLAPI void APIENTRY glBindFragmentShaderATI (GLuint id); GLAPI void APIENTRY glDeleteFragmentShaderATI (GLuint id); GLAPI void APIENTRY glBeginFragmentShaderATI (void); GLAPI void APIENTRY glEndFragmentShaderATI (void); GLAPI void APIENTRY glPassTexCoordATI (GLuint dst, GLuint coord, GLenum swizzle); GLAPI void APIENTRY glSampleMapATI (GLuint dst, GLuint interp, GLenum swizzle); GLAPI void APIENTRY glColorFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); GLAPI void APIENTRY glColorFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); GLAPI void APIENTRY glColorFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); GLAPI void APIENTRY glAlphaFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); GLAPI void APIENTRY glAlphaFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); GLAPI void APIENTRY glAlphaFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); GLAPI void APIENTRY glSetFragmentShaderConstantATI (GLuint dst, const GLfloat *value); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLuint (APIENTRYP PFNGLGENFRAGMENTSHADERSATIPROC) (GLuint range); typedef void (APIENTRYP PFNGLBINDFRAGMENTSHADERATIPROC) (GLuint id); typedef void (APIENTRYP PFNGLDELETEFRAGMENTSHADERATIPROC) (GLuint id); typedef void (APIENTRYP PFNGLBEGINFRAGMENTSHADERATIPROC) (void); typedef void (APIENTRYP PFNGLENDFRAGMENTSHADERATIPROC) (void); typedef void (APIENTRYP PFNGLPASSTEXCOORDATIPROC) (GLuint dst, GLuint coord, GLenum swizzle); typedef void (APIENTRYP PFNGLSAMPLEMAPATIPROC) (GLuint dst, GLuint interp, GLenum swizzle); typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); typedef void (APIENTRYP PFNGLSETFRAGMENTSHADERCONSTANTATIPROC) (GLuint dst, const GLfloat *value); #endif #ifndef GL_ATI_pn_triangles #define GL_ATI_pn_triangles 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPNTrianglesiATI (GLenum pname, GLint param); GLAPI void APIENTRY glPNTrianglesfATI (GLenum pname, GLfloat param); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPNTRIANGLESIATIPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLPNTRIANGLESFATIPROC) (GLenum pname, GLfloat param); #endif #ifndef GL_ATI_vertex_array_object #define GL_ATI_vertex_array_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLuint APIENTRY glNewObjectBufferATI (GLsizei size, const GLvoid *pointer, GLenum usage); GLAPI GLboolean APIENTRY glIsObjectBufferATI (GLuint buffer); GLAPI void APIENTRY glUpdateObjectBufferATI (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve); GLAPI void APIENTRY glGetObjectBufferfvATI (GLuint buffer, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetObjectBufferivATI (GLuint buffer, GLenum pname, GLint *params); GLAPI void APIENTRY glFreeObjectBufferATI (GLuint buffer); GLAPI void APIENTRY glArrayObjectATI (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); GLAPI void APIENTRY glGetArrayObjectfvATI (GLenum array, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetArrayObjectivATI (GLenum array, GLenum pname, GLint *params); GLAPI void APIENTRY glVariantArrayObjectATI (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); GLAPI void APIENTRY glGetVariantArrayObjectfvATI (GLuint id, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetVariantArrayObjectivATI (GLuint id, GLenum pname, GLint *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const GLvoid *pointer, GLenum usage); typedef GLboolean (APIENTRYP PFNGLISOBJECTBUFFERATIPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve); typedef void (APIENTRYP PFNGLGETOBJECTBUFFERFVATIPROC) (GLuint buffer, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETOBJECTBUFFERIVATIPROC) (GLuint buffer, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLFREEOBJECTBUFFERATIPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLARRAYOBJECTATIPROC) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); typedef void (APIENTRYP PFNGLGETARRAYOBJECTFVATIPROC) (GLenum array, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETARRAYOBJECTIVATIPROC) (GLenum array, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLVARIANTARRAYOBJECTATIPROC) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTFVATIPROC) (GLuint id, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTIVATIPROC) (GLuint id, GLenum pname, GLint *params); #endif #ifndef GL_EXT_vertex_shader #define GL_EXT_vertex_shader 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBeginVertexShaderEXT (void); GLAPI void APIENTRY glEndVertexShaderEXT (void); GLAPI void APIENTRY glBindVertexShaderEXT (GLuint id); GLAPI GLuint APIENTRY glGenVertexShadersEXT (GLuint range); GLAPI void APIENTRY glDeleteVertexShaderEXT (GLuint id); GLAPI void APIENTRY glShaderOp1EXT (GLenum op, GLuint res, GLuint arg1); GLAPI void APIENTRY glShaderOp2EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2); GLAPI void APIENTRY glShaderOp3EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); GLAPI void APIENTRY glSwizzleEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); GLAPI void APIENTRY glWriteMaskEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); GLAPI void APIENTRY glInsertComponentEXT (GLuint res, GLuint src, GLuint num); GLAPI void APIENTRY glExtractComponentEXT (GLuint res, GLuint src, GLuint num); GLAPI GLuint APIENTRY glGenSymbolsEXT (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); GLAPI void APIENTRY glSetInvariantEXT (GLuint id, GLenum type, const GLvoid *addr); GLAPI void APIENTRY glSetLocalConstantEXT (GLuint id, GLenum type, const GLvoid *addr); GLAPI void APIENTRY glVariantbvEXT (GLuint id, const GLbyte *addr); GLAPI void APIENTRY glVariantsvEXT (GLuint id, const GLshort *addr); GLAPI void APIENTRY glVariantivEXT (GLuint id, const GLint *addr); GLAPI void APIENTRY glVariantfvEXT (GLuint id, const GLfloat *addr); GLAPI void APIENTRY glVariantdvEXT (GLuint id, const GLdouble *addr); GLAPI void APIENTRY glVariantubvEXT (GLuint id, const GLubyte *addr); GLAPI void APIENTRY glVariantusvEXT (GLuint id, const GLushort *addr); GLAPI void APIENTRY glVariantuivEXT (GLuint id, const GLuint *addr); GLAPI void APIENTRY glVariantPointerEXT (GLuint id, GLenum type, GLuint stride, const GLvoid *addr); GLAPI void APIENTRY glEnableVariantClientStateEXT (GLuint id); GLAPI void APIENTRY glDisableVariantClientStateEXT (GLuint id); GLAPI GLuint APIENTRY glBindLightParameterEXT (GLenum light, GLenum value); GLAPI GLuint APIENTRY glBindMaterialParameterEXT (GLenum face, GLenum value); GLAPI GLuint APIENTRY glBindTexGenParameterEXT (GLenum unit, GLenum coord, GLenum value); GLAPI GLuint APIENTRY glBindTextureUnitParameterEXT (GLenum unit, GLenum value); GLAPI GLuint APIENTRY glBindParameterEXT (GLenum value); GLAPI GLboolean APIENTRY glIsVariantEnabledEXT (GLuint id, GLenum cap); GLAPI void APIENTRY glGetVariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); GLAPI void APIENTRY glGetVariantIntegervEXT (GLuint id, GLenum value, GLint *data); GLAPI void APIENTRY glGetVariantFloatvEXT (GLuint id, GLenum value, GLfloat *data); GLAPI void APIENTRY glGetVariantPointervEXT (GLuint id, GLenum value, GLvoid* *data); GLAPI void APIENTRY glGetInvariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); GLAPI void APIENTRY glGetInvariantIntegervEXT (GLuint id, GLenum value, GLint *data); GLAPI void APIENTRY glGetInvariantFloatvEXT (GLuint id, GLenum value, GLfloat *data); GLAPI void APIENTRY glGetLocalConstantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); GLAPI void APIENTRY glGetLocalConstantIntegervEXT (GLuint id, GLenum value, GLint *data); GLAPI void APIENTRY glGetLocalConstantFloatvEXT (GLuint id, GLenum value, GLfloat *data); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBEGINVERTEXSHADEREXTPROC) (void); typedef void (APIENTRYP PFNGLENDVERTEXSHADEREXTPROC) (void); typedef void (APIENTRYP PFNGLBINDVERTEXSHADEREXTPROC) (GLuint id); typedef GLuint (APIENTRYP PFNGLGENVERTEXSHADERSEXTPROC) (GLuint range); typedef void (APIENTRYP PFNGLDELETEVERTEXSHADEREXTPROC) (GLuint id); typedef void (APIENTRYP PFNGLSHADEROP1EXTPROC) (GLenum op, GLuint res, GLuint arg1); typedef void (APIENTRYP PFNGLSHADEROP2EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2); typedef void (APIENTRYP PFNGLSHADEROP3EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); typedef void (APIENTRYP PFNGLSWIZZLEEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); typedef void (APIENTRYP PFNGLWRITEMASKEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); typedef void (APIENTRYP PFNGLINSERTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); typedef void (APIENTRYP PFNGLEXTRACTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); typedef GLuint (APIENTRYP PFNGLGENSYMBOLSEXTPROC) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); typedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr); typedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr); typedef void (APIENTRYP PFNGLVARIANTBVEXTPROC) (GLuint id, const GLbyte *addr); typedef void (APIENTRYP PFNGLVARIANTSVEXTPROC) (GLuint id, const GLshort *addr); typedef void (APIENTRYP PFNGLVARIANTIVEXTPROC) (GLuint id, const GLint *addr); typedef void (APIENTRYP PFNGLVARIANTFVEXTPROC) (GLuint id, const GLfloat *addr); typedef void (APIENTRYP PFNGLVARIANTDVEXTPROC) (GLuint id, const GLdouble *addr); typedef void (APIENTRYP PFNGLVARIANTUBVEXTPROC) (GLuint id, const GLubyte *addr); typedef void (APIENTRYP PFNGLVARIANTUSVEXTPROC) (GLuint id, const GLushort *addr); typedef void (APIENTRYP PFNGLVARIANTUIVEXTPROC) (GLuint id, const GLuint *addr); typedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, const GLvoid *addr); typedef void (APIENTRYP PFNGLENABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); typedef void (APIENTRYP PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); typedef GLuint (APIENTRYP PFNGLBINDLIGHTPARAMETEREXTPROC) (GLenum light, GLenum value); typedef GLuint (APIENTRYP PFNGLBINDMATERIALPARAMETEREXTPROC) (GLenum face, GLenum value); typedef GLuint (APIENTRYP PFNGLBINDTEXGENPARAMETEREXTPROC) (GLenum unit, GLenum coord, GLenum value); typedef GLuint (APIENTRYP PFNGLBINDTEXTUREUNITPARAMETEREXTPROC) (GLenum unit, GLenum value); typedef GLuint (APIENTRYP PFNGLBINDPARAMETEREXTPROC) (GLenum value); typedef GLboolean (APIENTRYP PFNGLISVARIANTENABLEDEXTPROC) (GLuint id, GLenum cap); typedef void (APIENTRYP PFNGLGETVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); typedef void (APIENTRYP PFNGLGETVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); typedef void (APIENTRYP PFNGLGETVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); typedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, GLvoid* *data); typedef void (APIENTRYP PFNGLGETINVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); typedef void (APIENTRYP PFNGLGETINVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); typedef void (APIENTRYP PFNGLGETINVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); typedef void (APIENTRYP PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); typedef void (APIENTRYP PFNGLGETLOCALCONSTANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); typedef void (APIENTRYP PFNGLGETLOCALCONSTANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); #endif #ifndef GL_ATI_vertex_streams #define GL_ATI_vertex_streams 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexStream1sATI (GLenum stream, GLshort x); GLAPI void APIENTRY glVertexStream1svATI (GLenum stream, const GLshort *coords); GLAPI void APIENTRY glVertexStream1iATI (GLenum stream, GLint x); GLAPI void APIENTRY glVertexStream1ivATI (GLenum stream, const GLint *coords); GLAPI void APIENTRY glVertexStream1fATI (GLenum stream, GLfloat x); GLAPI void APIENTRY glVertexStream1fvATI (GLenum stream, const GLfloat *coords); GLAPI void APIENTRY glVertexStream1dATI (GLenum stream, GLdouble x); GLAPI void APIENTRY glVertexStream1dvATI (GLenum stream, const GLdouble *coords); GLAPI void APIENTRY glVertexStream2sATI (GLenum stream, GLshort x, GLshort y); GLAPI void APIENTRY glVertexStream2svATI (GLenum stream, const GLshort *coords); GLAPI void APIENTRY glVertexStream2iATI (GLenum stream, GLint x, GLint y); GLAPI void APIENTRY glVertexStream2ivATI (GLenum stream, const GLint *coords); GLAPI void APIENTRY glVertexStream2fATI (GLenum stream, GLfloat x, GLfloat y); GLAPI void APIENTRY glVertexStream2fvATI (GLenum stream, const GLfloat *coords); GLAPI void APIENTRY glVertexStream2dATI (GLenum stream, GLdouble x, GLdouble y); GLAPI void APIENTRY glVertexStream2dvATI (GLenum stream, const GLdouble *coords); GLAPI void APIENTRY glVertexStream3sATI (GLenum stream, GLshort x, GLshort y, GLshort z); GLAPI void APIENTRY glVertexStream3svATI (GLenum stream, const GLshort *coords); GLAPI void APIENTRY glVertexStream3iATI (GLenum stream, GLint x, GLint y, GLint z); GLAPI void APIENTRY glVertexStream3ivATI (GLenum stream, const GLint *coords); GLAPI void APIENTRY glVertexStream3fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glVertexStream3fvATI (GLenum stream, const GLfloat *coords); GLAPI void APIENTRY glVertexStream3dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glVertexStream3dvATI (GLenum stream, const GLdouble *coords); GLAPI void APIENTRY glVertexStream4sATI (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); GLAPI void APIENTRY glVertexStream4svATI (GLenum stream, const GLshort *coords); GLAPI void APIENTRY glVertexStream4iATI (GLenum stream, GLint x, GLint y, GLint z, GLint w); GLAPI void APIENTRY glVertexStream4ivATI (GLenum stream, const GLint *coords); GLAPI void APIENTRY glVertexStream4fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glVertexStream4fvATI (GLenum stream, const GLfloat *coords); GLAPI void APIENTRY glVertexStream4dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glVertexStream4dvATI (GLenum stream, const GLdouble *coords); GLAPI void APIENTRY glNormalStream3bATI (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); GLAPI void APIENTRY glNormalStream3bvATI (GLenum stream, const GLbyte *coords); GLAPI void APIENTRY glNormalStream3sATI (GLenum stream, GLshort nx, GLshort ny, GLshort nz); GLAPI void APIENTRY glNormalStream3svATI (GLenum stream, const GLshort *coords); GLAPI void APIENTRY glNormalStream3iATI (GLenum stream, GLint nx, GLint ny, GLint nz); GLAPI void APIENTRY glNormalStream3ivATI (GLenum stream, const GLint *coords); GLAPI void APIENTRY glNormalStream3fATI (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); GLAPI void APIENTRY glNormalStream3fvATI (GLenum stream, const GLfloat *coords); GLAPI void APIENTRY glNormalStream3dATI (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); GLAPI void APIENTRY glNormalStream3dvATI (GLenum stream, const GLdouble *coords); GLAPI void APIENTRY glClientActiveVertexStreamATI (GLenum stream); GLAPI void APIENTRY glVertexBlendEnviATI (GLenum pname, GLint param); GLAPI void APIENTRY glVertexBlendEnvfATI (GLenum pname, GLfloat param); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXSTREAM1SATIPROC) (GLenum stream, GLshort x); typedef void (APIENTRYP PFNGLVERTEXSTREAM1SVATIPROC) (GLenum stream, const GLshort *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM1IATIPROC) (GLenum stream, GLint x); typedef void (APIENTRYP PFNGLVERTEXSTREAM1IVATIPROC) (GLenum stream, const GLint *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM1FATIPROC) (GLenum stream, GLfloat x); typedef void (APIENTRYP PFNGLVERTEXSTREAM1FVATIPROC) (GLenum stream, const GLfloat *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM1DATIPROC) (GLenum stream, GLdouble x); typedef void (APIENTRYP PFNGLVERTEXSTREAM1DVATIPROC) (GLenum stream, const GLdouble *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM2SATIPROC) (GLenum stream, GLshort x, GLshort y); typedef void (APIENTRYP PFNGLVERTEXSTREAM2SVATIPROC) (GLenum stream, const GLshort *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM2IATIPROC) (GLenum stream, GLint x, GLint y); typedef void (APIENTRYP PFNGLVERTEXSTREAM2IVATIPROC) (GLenum stream, const GLint *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM2FATIPROC) (GLenum stream, GLfloat x, GLfloat y); typedef void (APIENTRYP PFNGLVERTEXSTREAM2FVATIPROC) (GLenum stream, const GLfloat *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM2DATIPROC) (GLenum stream, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLVERTEXSTREAM2DVATIPROC) (GLenum stream, const GLdouble *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM3SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLVERTEXSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM3IATIPROC) (GLenum stream, GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLVERTEXSTREAM3IVATIPROC) (GLenum stream, const GLint *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM3FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLVERTEXSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM3DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLVERTEXSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM4SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); typedef void (APIENTRYP PFNGLVERTEXSTREAM4SVATIPROC) (GLenum stream, const GLshort *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM4IATIPROC) (GLenum stream, GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLVERTEXSTREAM4IVATIPROC) (GLenum stream, const GLint *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM4FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLVERTEXSTREAM4FVATIPROC) (GLenum stream, const GLfloat *coords); typedef void (APIENTRYP PFNGLVERTEXSTREAM4DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLVERTEXSTREAM4DVATIPROC) (GLenum stream, const GLdouble *coords); typedef void (APIENTRYP PFNGLNORMALSTREAM3BATIPROC) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); typedef void (APIENTRYP PFNGLNORMALSTREAM3BVATIPROC) (GLenum stream, const GLbyte *coords); typedef void (APIENTRYP PFNGLNORMALSTREAM3SATIPROC) (GLenum stream, GLshort nx, GLshort ny, GLshort nz); typedef void (APIENTRYP PFNGLNORMALSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords); typedef void (APIENTRYP PFNGLNORMALSTREAM3IATIPROC) (GLenum stream, GLint nx, GLint ny, GLint nz); typedef void (APIENTRYP PFNGLNORMALSTREAM3IVATIPROC) (GLenum stream, const GLint *coords); typedef void (APIENTRYP PFNGLNORMALSTREAM3FATIPROC) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); typedef void (APIENTRYP PFNGLNORMALSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords); typedef void (APIENTRYP PFNGLNORMALSTREAM3DATIPROC) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); typedef void (APIENTRYP PFNGLNORMALSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords); typedef void (APIENTRYP PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC) (GLenum stream); typedef void (APIENTRYP PFNGLVERTEXBLENDENVIATIPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLVERTEXBLENDENVFATIPROC) (GLenum pname, GLfloat param); #endif #ifndef GL_ATI_element_array #define GL_ATI_element_array 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glElementPointerATI (GLenum type, const GLvoid *pointer); GLAPI void APIENTRY glDrawElementArrayATI (GLenum mode, GLsizei count); GLAPI void APIENTRY glDrawRangeElementArrayATI (GLenum mode, GLuint start, GLuint end, GLsizei count); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC) (GLenum type, const GLvoid *pointer); typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYATIPROC) (GLenum mode, GLsizei count); typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYATIPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count); #endif #ifndef GL_SUN_mesh_array #define GL_SUN_mesh_array 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawMeshArraysSUN (GLenum mode, GLint first, GLsizei count, GLsizei width); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDRAWMESHARRAYSSUNPROC) (GLenum mode, GLint first, GLsizei count, GLsizei width); #endif #ifndef GL_SUN_slice_accum #define GL_SUN_slice_accum 1 #endif #ifndef GL_NV_multisample_filter_hint #define GL_NV_multisample_filter_hint 1 #endif #ifndef GL_NV_depth_clamp #define GL_NV_depth_clamp 1 #endif #ifndef GL_NV_occlusion_query #define GL_NV_occlusion_query 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGenOcclusionQueriesNV (GLsizei n, GLuint *ids); GLAPI void APIENTRY glDeleteOcclusionQueriesNV (GLsizei n, const GLuint *ids); GLAPI GLboolean APIENTRY glIsOcclusionQueryNV (GLuint id); GLAPI void APIENTRY glBeginOcclusionQueryNV (GLuint id); GLAPI void APIENTRY glEndOcclusionQueryNV (void); GLAPI void APIENTRY glGetOcclusionQueryivNV (GLuint id, GLenum pname, GLint *params); GLAPI void APIENTRY glGetOcclusionQueryuivNV (GLuint id, GLenum pname, GLuint *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGENOCCLUSIONQUERIESNVPROC) (GLsizei n, GLuint *ids); typedef void (APIENTRYP PFNGLDELETEOCCLUSIONQUERIESNVPROC) (GLsizei n, const GLuint *ids); typedef GLboolean (APIENTRYP PFNGLISOCCLUSIONQUERYNVPROC) (GLuint id); typedef void (APIENTRYP PFNGLBEGINOCCLUSIONQUERYNVPROC) (GLuint id); typedef void (APIENTRYP PFNGLENDOCCLUSIONQUERYNVPROC) (void); typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYIVNVPROC) (GLuint id, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYUIVNVPROC) (GLuint id, GLenum pname, GLuint *params); #endif #ifndef GL_NV_point_sprite #define GL_NV_point_sprite 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPointParameteriNV (GLenum pname, GLint param); GLAPI void APIENTRY glPointParameterivNV (GLenum pname, const GLint *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPOINTPARAMETERINVPROC) (GLenum pname, GLint param); typedef void (APIENTRYP PFNGLPOINTPARAMETERIVNVPROC) (GLenum pname, const GLint *params); #endif #ifndef GL_NV_texture_shader3 #define GL_NV_texture_shader3 1 #endif #ifndef GL_NV_vertex_program1_1 #define GL_NV_vertex_program1_1 1 #endif #ifndef GL_EXT_shadow_funcs #define GL_EXT_shadow_funcs 1 #endif #ifndef GL_EXT_stencil_two_side #define GL_EXT_stencil_two_side 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glActiveStencilFaceEXT (GLenum face); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face); #endif #ifndef GL_ATI_text_fragment_shader #define GL_ATI_text_fragment_shader 1 #endif #ifndef GL_APPLE_client_storage #define GL_APPLE_client_storage 1 #endif #ifndef GL_APPLE_element_array #define GL_APPLE_element_array 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glElementPointerAPPLE (GLenum type, const GLvoid *pointer); GLAPI void APIENTRY glDrawElementArrayAPPLE (GLenum mode, GLint first, GLsizei count); GLAPI void APIENTRY glDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); GLAPI void APIENTRY glMultiDrawElementArrayAPPLE (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); GLAPI void APIENTRY glMultiDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const GLvoid *pointer); typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, GLint first, GLsizei count); typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); typedef void (APIENTRYP PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); #endif #ifndef GL_APPLE_fence #define GL_APPLE_fence 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGenFencesAPPLE (GLsizei n, GLuint *fences); GLAPI void APIENTRY glDeleteFencesAPPLE (GLsizei n, const GLuint *fences); GLAPI void APIENTRY glSetFenceAPPLE (GLuint fence); GLAPI GLboolean APIENTRY glIsFenceAPPLE (GLuint fence); GLAPI GLboolean APIENTRY glTestFenceAPPLE (GLuint fence); GLAPI void APIENTRY glFinishFenceAPPLE (GLuint fence); GLAPI GLboolean APIENTRY glTestObjectAPPLE (GLenum object, GLuint name); GLAPI void APIENTRY glFinishObjectAPPLE (GLenum object, GLint name); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGENFENCESAPPLEPROC) (GLsizei n, GLuint *fences); typedef void (APIENTRYP PFNGLDELETEFENCESAPPLEPROC) (GLsizei n, const GLuint *fences); typedef void (APIENTRYP PFNGLSETFENCEAPPLEPROC) (GLuint fence); typedef GLboolean (APIENTRYP PFNGLISFENCEAPPLEPROC) (GLuint fence); typedef GLboolean (APIENTRYP PFNGLTESTFENCEAPPLEPROC) (GLuint fence); typedef void (APIENTRYP PFNGLFINISHFENCEAPPLEPROC) (GLuint fence); typedef GLboolean (APIENTRYP PFNGLTESTOBJECTAPPLEPROC) (GLenum object, GLuint name); typedef void (APIENTRYP PFNGLFINISHOBJECTAPPLEPROC) (GLenum object, GLint name); #endif #ifndef GL_APPLE_vertex_array_object #define GL_APPLE_vertex_array_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindVertexArrayAPPLE (GLuint array); GLAPI void APIENTRY glDeleteVertexArraysAPPLE (GLsizei n, const GLuint *arrays); GLAPI void APIENTRY glGenVertexArraysAPPLE (GLsizei n, GLuint *arrays); GLAPI GLboolean APIENTRY glIsVertexArrayAPPLE (GLuint array); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBINDVERTEXARRAYAPPLEPROC) (GLuint array); typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays); typedef void (APIENTRYP PFNGLGENVERTEXARRAYSAPPLEPROC) (GLsizei n, GLuint *arrays); typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array); #endif #ifndef GL_APPLE_vertex_array_range #define GL_APPLE_vertex_array_range 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexArrayRangeAPPLE (GLsizei length, GLvoid *pointer); GLAPI void APIENTRY glFlushVertexArrayRangeAPPLE (GLsizei length, GLvoid *pointer); GLAPI void APIENTRY glVertexArrayParameteriAPPLE (GLenum pname, GLint param); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer); typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer); typedef void (APIENTRYP PFNGLVERTEXARRAYPARAMETERIAPPLEPROC) (GLenum pname, GLint param); #endif #ifndef GL_APPLE_ycbcr_422 #define GL_APPLE_ycbcr_422 1 #endif #ifndef GL_S3_s3tc #define GL_S3_s3tc 1 #endif #ifndef GL_ATI_draw_buffers #define GL_ATI_draw_buffers 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawBuffersATI (GLsizei n, const GLenum *bufs); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDRAWBUFFERSATIPROC) (GLsizei n, const GLenum *bufs); #endif #ifndef GL_ATI_pixel_format_float #define GL_ATI_pixel_format_float 1 /* This is really a WGL extension, but defines some associated GL enums. * ATI does not export "GL_ATI_pixel_format_float" in the GL_EXTENSIONS string. */ #endif #ifndef GL_ATI_texture_env_combine3 #define GL_ATI_texture_env_combine3 1 #endif #ifndef GL_ATI_texture_float #define GL_ATI_texture_float 1 #endif #ifndef GL_NV_float_buffer #define GL_NV_float_buffer 1 #endif #ifndef GL_NV_fragment_program #define GL_NV_fragment_program 1 /* Some NV_fragment_program entry points are shared with ARB_vertex_program. */ #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramNamedParameter4fNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glProgramNamedParameter4dNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glProgramNamedParameter4fvNV (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); GLAPI void APIENTRY glProgramNamedParameter4dvNV (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); GLAPI void APIENTRY glGetProgramNamedParameterfvNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); GLAPI void APIENTRY glGetProgramNamedParameterdvNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); #endif #ifndef GL_NV_half_float #define GL_NV_half_float 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertex2hNV (GLhalfNV x, GLhalfNV y); GLAPI void APIENTRY glVertex2hvNV (const GLhalfNV *v); GLAPI void APIENTRY glVertex3hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z); GLAPI void APIENTRY glVertex3hvNV (const GLhalfNV *v); GLAPI void APIENTRY glVertex4hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); GLAPI void APIENTRY glVertex4hvNV (const GLhalfNV *v); GLAPI void APIENTRY glNormal3hNV (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); GLAPI void APIENTRY glNormal3hvNV (const GLhalfNV *v); GLAPI void APIENTRY glColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue); GLAPI void APIENTRY glColor3hvNV (const GLhalfNV *v); GLAPI void APIENTRY glColor4hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); GLAPI void APIENTRY glColor4hvNV (const GLhalfNV *v); GLAPI void APIENTRY glTexCoord1hNV (GLhalfNV s); GLAPI void APIENTRY glTexCoord1hvNV (const GLhalfNV *v); GLAPI void APIENTRY glTexCoord2hNV (GLhalfNV s, GLhalfNV t); GLAPI void APIENTRY glTexCoord2hvNV (const GLhalfNV *v); GLAPI void APIENTRY glTexCoord3hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r); GLAPI void APIENTRY glTexCoord3hvNV (const GLhalfNV *v); GLAPI void APIENTRY glTexCoord4hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); GLAPI void APIENTRY glTexCoord4hvNV (const GLhalfNV *v); GLAPI void APIENTRY glMultiTexCoord1hNV (GLenum target, GLhalfNV s); GLAPI void APIENTRY glMultiTexCoord1hvNV (GLenum target, const GLhalfNV *v); GLAPI void APIENTRY glMultiTexCoord2hNV (GLenum target, GLhalfNV s, GLhalfNV t); GLAPI void APIENTRY glMultiTexCoord2hvNV (GLenum target, const GLhalfNV *v); GLAPI void APIENTRY glMultiTexCoord3hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); GLAPI void APIENTRY glMultiTexCoord3hvNV (GLenum target, const GLhalfNV *v); GLAPI void APIENTRY glMultiTexCoord4hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); GLAPI void APIENTRY glMultiTexCoord4hvNV (GLenum target, const GLhalfNV *v); GLAPI void APIENTRY glFogCoordhNV (GLhalfNV fog); GLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *fog); GLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue); GLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *v); GLAPI void APIENTRY glVertexWeighthNV (GLhalfNV weight); GLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *weight); GLAPI void APIENTRY glVertexAttrib1hNV (GLuint index, GLhalfNV x); GLAPI void APIENTRY glVertexAttrib1hvNV (GLuint index, const GLhalfNV *v); GLAPI void APIENTRY glVertexAttrib2hNV (GLuint index, GLhalfNV x, GLhalfNV y); GLAPI void APIENTRY glVertexAttrib2hvNV (GLuint index, const GLhalfNV *v); GLAPI void APIENTRY glVertexAttrib3hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); GLAPI void APIENTRY glVertexAttrib3hvNV (GLuint index, const GLhalfNV *v); GLAPI void APIENTRY glVertexAttrib4hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); GLAPI void APIENTRY glVertexAttrib4hvNV (GLuint index, const GLhalfNV *v); GLAPI void APIENTRY glVertexAttribs1hvNV (GLuint index, GLsizei n, const GLhalfNV *v); GLAPI void APIENTRY glVertexAttribs2hvNV (GLuint index, GLsizei n, const GLhalfNV *v); GLAPI void APIENTRY glVertexAttribs3hvNV (GLuint index, GLsizei n, const GLhalfNV *v); GLAPI void APIENTRY glVertexAttribs4hvNV (GLuint index, GLsizei n, const GLhalfNV *v); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEX2HNVPROC) (GLhalfNV x, GLhalfNV y); typedef void (APIENTRYP PFNGLVERTEX2HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEX3HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z); typedef void (APIENTRYP PFNGLVERTEX3HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEX4HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); typedef void (APIENTRYP PFNGLVERTEX4HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLNORMAL3HNVPROC) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); typedef void (APIENTRYP PFNGLNORMAL3HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); typedef void (APIENTRYP PFNGLCOLOR3HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLCOLOR4HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); typedef void (APIENTRYP PFNGLCOLOR4HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLTEXCOORD1HNVPROC) (GLhalfNV s); typedef void (APIENTRYP PFNGLTEXCOORD1HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLTEXCOORD2HNVPROC) (GLhalfNV s, GLhalfNV t); typedef void (APIENTRYP PFNGLTEXCOORD2HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLTEXCOORD3HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r); typedef void (APIENTRYP PFNGLTEXCOORD3HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLTEXCOORD4HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); typedef void (APIENTRYP PFNGLTEXCOORD4HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD1HNVPROC) (GLenum target, GLhalfNV s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1HVNVPROC) (GLenum target, const GLhalfNV *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD2HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t); typedef void (APIENTRYP PFNGLMULTITEXCOORD2HVNVPROC) (GLenum target, const GLhalfNV *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD3HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); typedef void (APIENTRYP PFNGLMULTITEXCOORD3HVNVPROC) (GLenum target, const GLhalfNV *v); typedef void (APIENTRYP PFNGLMULTITEXCOORD4HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); typedef void (APIENTRYP PFNGLMULTITEXCOORD4HVNVPROC) (GLenum target, const GLhalfNV *v); typedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog); typedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight); typedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight); typedef void (APIENTRYP PFNGLVERTEXATTRIB1HNVPROC) (GLuint index, GLhalfNV x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1HVNVPROC) (GLuint index, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB2HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y); typedef void (APIENTRYP PFNGLVERTEXATTRIB2HVNVPROC) (GLuint index, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB3HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); typedef void (APIENTRYP PFNGLVERTEXATTRIB3HVNVPROC) (GLuint index, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); typedef void (APIENTRYP PFNGLVERTEXATTRIB4HVNVPROC) (GLuint index, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS1HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS2HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS3HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBS4HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); #endif #ifndef GL_NV_pixel_data_range #define GL_NV_pixel_data_range 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPixelDataRangeNV (GLenum target, GLsizei length, GLvoid *pointer); GLAPI void APIENTRY glFlushPixelDataRangeNV (GLenum target); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, GLvoid *pointer); typedef void (APIENTRYP PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target); #endif #ifndef GL_NV_primitive_restart #define GL_NV_primitive_restart 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPrimitiveRestartNV (void); GLAPI void APIENTRY glPrimitiveRestartIndexNV (GLuint index); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPRIMITIVERESTARTNVPROC) (void); typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXNVPROC) (GLuint index); #endif #ifndef GL_NV_texture_expand_normal #define GL_NV_texture_expand_normal 1 #endif #ifndef GL_NV_vertex_program2 #define GL_NV_vertex_program2 1 #endif #ifndef GL_ATI_map_object_buffer #define GL_ATI_map_object_buffer 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLvoid* APIENTRY glMapObjectBufferATI (GLuint buffer); GLAPI void APIENTRY glUnmapObjectBufferATI (GLuint buffer); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLvoid* (APIENTRYP PFNGLMAPOBJECTBUFFERATIPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLUNMAPOBJECTBUFFERATIPROC) (GLuint buffer); #endif #ifndef GL_ATI_separate_stencil #define GL_ATI_separate_stencil 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glStencilOpSeparateATI (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); GLAPI void APIENTRY glStencilFuncSeparateATI (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEATIPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEATIPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); #endif #ifndef GL_ATI_vertex_attrib_array_object #define GL_ATI_vertex_attrib_array_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttribArrayObjectATI (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); GLAPI void APIENTRY glGetVertexAttribArrayObjectfvATI (GLuint index, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetVertexAttribArrayObjectivATI (GLuint index, GLenum pname, GLint *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXATTRIBARRAYOBJECTATIPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC) (GLuint index, GLenum pname, GLint *params); #endif #ifndef GL_OES_read_format #define GL_OES_read_format 1 #endif #ifndef GL_EXT_depth_bounds_test #define GL_EXT_depth_bounds_test 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDepthBoundsEXT (GLclampd zmin, GLclampd zmax); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDEPTHBOUNDSEXTPROC) (GLclampd zmin, GLclampd zmax); #endif #ifndef GL_EXT_texture_mirror_clamp #define GL_EXT_texture_mirror_clamp 1 #endif #ifndef GL_EXT_blend_equation_separate #define GL_EXT_blend_equation_separate 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendEquationSeparateEXT (GLenum modeRGB, GLenum modeAlpha); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEEXTPROC) (GLenum modeRGB, GLenum modeAlpha); #endif #ifndef GL_MESA_pack_invert #define GL_MESA_pack_invert 1 #endif #ifndef GL_MESA_ycbcr_texture #define GL_MESA_ycbcr_texture 1 #endif #ifndef GL_EXT_pixel_buffer_object #define GL_EXT_pixel_buffer_object 1 #endif #ifndef GL_NV_fragment_program_option #define GL_NV_fragment_program_option 1 #endif #ifndef GL_NV_fragment_program2 #define GL_NV_fragment_program2 1 #endif #ifndef GL_NV_vertex_program2_option #define GL_NV_vertex_program2_option 1 #endif #ifndef GL_NV_vertex_program3 #define GL_NV_vertex_program3 1 #endif #ifndef GL_EXT_framebuffer_object #define GL_EXT_framebuffer_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLboolean APIENTRY glIsRenderbufferEXT (GLuint renderbuffer); GLAPI void APIENTRY glBindRenderbufferEXT (GLenum target, GLuint renderbuffer); GLAPI void APIENTRY glDeleteRenderbuffersEXT (GLsizei n, const GLuint *renderbuffers); GLAPI void APIENTRY glGenRenderbuffersEXT (GLsizei n, GLuint *renderbuffers); GLAPI void APIENTRY glRenderbufferStorageEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); GLAPI void APIENTRY glGetRenderbufferParameterivEXT (GLenum target, GLenum pname, GLint *params); GLAPI GLboolean APIENTRY glIsFramebufferEXT (GLuint framebuffer); GLAPI void APIENTRY glBindFramebufferEXT (GLenum target, GLuint framebuffer); GLAPI void APIENTRY glDeleteFramebuffersEXT (GLsizei n, const GLuint *framebuffers); GLAPI void APIENTRY glGenFramebuffersEXT (GLsizei n, GLuint *framebuffers); GLAPI GLenum APIENTRY glCheckFramebufferStatusEXT (GLenum target); GLAPI void APIENTRY glFramebufferTexture1DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); GLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); GLAPI void APIENTRY glFramebufferTexture3DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); GLAPI void APIENTRY glFramebufferRenderbufferEXT (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); GLAPI void APIENTRY glGetFramebufferAttachmentParameterivEXT (GLenum target, GLenum attachment, GLenum pname, GLint *params); GLAPI void APIENTRY glGenerateMipmapEXT (GLenum target); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer); typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer); typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers); typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers); typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer); typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer); typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers); typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers); typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target); #endif #ifndef GL_GREMEDY_string_marker #define GL_GREMEDY_string_marker 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glStringMarkerGREMEDY (GLsizei len, const GLvoid *string); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const GLvoid *string); #endif #ifndef GL_EXT_packed_depth_stencil #define GL_EXT_packed_depth_stencil 1 #endif #ifndef GL_EXT_stencil_clear_tag #define GL_EXT_stencil_clear_tag 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glStencilClearTagEXT (GLsizei stencilTagBits, GLuint stencilClearTag); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSTENCILCLEARTAGEXTPROC) (GLsizei stencilTagBits, GLuint stencilClearTag); #endif #ifndef GL_EXT_texture_sRGB #define GL_EXT_texture_sRGB 1 #endif #ifndef GL_EXT_framebuffer_blit #define GL_EXT_framebuffer_blit 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlitFramebufferEXT (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLITFRAMEBUFFEREXTPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); #endif #ifndef GL_EXT_framebuffer_multisample #define GL_EXT_framebuffer_multisample 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glRenderbufferStorageMultisampleEXT (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); #endif #ifndef GL_MESAX_texture_stack #define GL_MESAX_texture_stack 1 #endif #ifndef GL_EXT_timer_query #define GL_EXT_timer_query 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetQueryObjecti64vEXT (GLuint id, GLenum pname, GLint64EXT *params); GLAPI void APIENTRY glGetQueryObjectui64vEXT (GLuint id, GLenum pname, GLuint64EXT *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VEXTPROC) (GLuint id, GLenum pname, GLint64EXT *params); typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VEXTPROC) (GLuint id, GLenum pname, GLuint64EXT *params); #endif #ifndef GL_EXT_gpu_program_parameters #define GL_EXT_gpu_program_parameters 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramEnvParameters4fvEXT (GLenum target, GLuint index, GLsizei count, const GLfloat *params); GLAPI void APIENTRY glProgramLocalParameters4fvEXT (GLenum target, GLuint index, GLsizei count, const GLfloat *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params); #endif #ifndef GL_APPLE_flush_buffer_range #define GL_APPLE_flush_buffer_range 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBufferParameteriAPPLE (GLenum target, GLenum pname, GLint param); GLAPI void APIENTRY glFlushMappedBufferRangeAPPLE (GLenum target, GLintptr offset, GLsizeiptr size); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBUFFERPARAMETERIAPPLEPROC) (GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC) (GLenum target, GLintptr offset, GLsizeiptr size); #endif #ifndef GL_NV_gpu_program4 #define GL_NV_gpu_program4 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramLocalParameterI4iNV (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); GLAPI void APIENTRY glProgramLocalParameterI4ivNV (GLenum target, GLuint index, const GLint *params); GLAPI void APIENTRY glProgramLocalParametersI4ivNV (GLenum target, GLuint index, GLsizei count, const GLint *params); GLAPI void APIENTRY glProgramLocalParameterI4uiNV (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); GLAPI void APIENTRY glProgramLocalParameterI4uivNV (GLenum target, GLuint index, const GLuint *params); GLAPI void APIENTRY glProgramLocalParametersI4uivNV (GLenum target, GLuint index, GLsizei count, const GLuint *params); GLAPI void APIENTRY glProgramEnvParameterI4iNV (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); GLAPI void APIENTRY glProgramEnvParameterI4ivNV (GLenum target, GLuint index, const GLint *params); GLAPI void APIENTRY glProgramEnvParametersI4ivNV (GLenum target, GLuint index, GLsizei count, const GLint *params); GLAPI void APIENTRY glProgramEnvParameterI4uiNV (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); GLAPI void APIENTRY glProgramEnvParameterI4uivNV (GLenum target, GLuint index, const GLuint *params); GLAPI void APIENTRY glProgramEnvParametersI4uivNV (GLenum target, GLuint index, GLsizei count, const GLuint *params); GLAPI void APIENTRY glGetProgramLocalParameterIivNV (GLenum target, GLuint index, GLint *params); GLAPI void APIENTRY glGetProgramLocalParameterIuivNV (GLenum target, GLuint index, GLuint *params); GLAPI void APIENTRY glGetProgramEnvParameterIivNV (GLenum target, GLuint index, GLint *params); GLAPI void APIENTRY glGetProgramEnvParameterIuivNV (GLenum target, GLuint index, GLuint *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params); typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params); typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params); typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params); typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params); typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params); typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params); #endif #ifndef GL_NV_geometry_program4 #define GL_NV_geometry_program4 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramVertexLimitNV (GLenum target, GLint limit); GLAPI void APIENTRY glFramebufferTextureEXT (GLenum target, GLenum attachment, GLuint texture, GLint level); GLAPI void APIENTRY glFramebufferTextureLayerEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); GLAPI void APIENTRY glFramebufferTextureFaceEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPROGRAMVERTEXLIMITNVPROC) (GLenum target, GLint limit); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); #endif #ifndef GL_EXT_geometry_shader4 #define GL_EXT_geometry_shader4 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramParameteriEXT (GLuint program, GLenum pname, GLint value); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value); #endif #ifndef GL_NV_vertex_program4 #define GL_NV_vertex_program4 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttribI1iEXT (GLuint index, GLint x); GLAPI void APIENTRY glVertexAttribI2iEXT (GLuint index, GLint x, GLint y); GLAPI void APIENTRY glVertexAttribI3iEXT (GLuint index, GLint x, GLint y, GLint z); GLAPI void APIENTRY glVertexAttribI4iEXT (GLuint index, GLint x, GLint y, GLint z, GLint w); GLAPI void APIENTRY glVertexAttribI1uiEXT (GLuint index, GLuint x); GLAPI void APIENTRY glVertexAttribI2uiEXT (GLuint index, GLuint x, GLuint y); GLAPI void APIENTRY glVertexAttribI3uiEXT (GLuint index, GLuint x, GLuint y, GLuint z); GLAPI void APIENTRY glVertexAttribI4uiEXT (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); GLAPI void APIENTRY glVertexAttribI1ivEXT (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttribI2ivEXT (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttribI3ivEXT (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttribI4ivEXT (GLuint index, const GLint *v); GLAPI void APIENTRY glVertexAttribI1uivEXT (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttribI2uivEXT (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttribI3uivEXT (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttribI4uivEXT (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttribI4bvEXT (GLuint index, const GLbyte *v); GLAPI void APIENTRY glVertexAttribI4svEXT (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttribI4ubvEXT (GLuint index, const GLubyte *v); GLAPI void APIENTRY glVertexAttribI4usvEXT (GLuint index, const GLushort *v); GLAPI void APIENTRY glVertexAttribIPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); GLAPI void APIENTRY glGetVertexAttribIivEXT (GLuint index, GLenum pname, GLint *params); GLAPI void APIENTRY glGetVertexAttribIuivEXT (GLuint index, GLenum pname, GLuint *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IEXTPROC) (GLuint index, GLint x); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IEXTPROC) (GLuint index, GLint x, GLint y); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IEXTPROC) (GLuint index, GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IEXTPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIEXTPROC) (GLuint index, GLuint x); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIEXTPROC) (GLuint index, GLuint x, GLuint y); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVEXTPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVEXTPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVEXTPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVEXTPROC) (GLuint index, const GLint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVEXTPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVEXTPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVEXTPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVEXTPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVEXTPROC) (GLuint index, const GLbyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVEXTPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVEXTPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVEXTPROC) (GLuint index, const GLushort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVEXTPROC) (GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVEXTPROC) (GLuint index, GLenum pname, GLuint *params); #endif #ifndef GL_EXT_gpu_shader4 #define GL_EXT_gpu_shader4 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetUniformuivEXT (GLuint program, GLint location, GLuint *params); GLAPI void APIENTRY glBindFragDataLocationEXT (GLuint program, GLuint color, const GLchar *name); GLAPI GLint APIENTRY glGetFragDataLocationEXT (GLuint program, const GLchar *name); GLAPI void APIENTRY glUniform1uiEXT (GLint location, GLuint v0); GLAPI void APIENTRY glUniform2uiEXT (GLint location, GLuint v0, GLuint v1); GLAPI void APIENTRY glUniform3uiEXT (GLint location, GLuint v0, GLuint v1, GLuint v2); GLAPI void APIENTRY glUniform4uiEXT (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); GLAPI void APIENTRY glUniform1uivEXT (GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glUniform2uivEXT (GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glUniform3uivEXT (GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glUniform4uivEXT (GLint location, GLsizei count, const GLuint *value); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGETUNIFORMUIVEXTPROC) (GLuint program, GLint location, GLuint *params); typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name); typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONEXTPROC) (GLuint program, const GLchar *name); typedef void (APIENTRYP PFNGLUNIFORM1UIEXTPROC) (GLint location, GLuint v0); typedef void (APIENTRYP PFNGLUNIFORM2UIEXTPROC) (GLint location, GLuint v0, GLuint v1); typedef void (APIENTRYP PFNGLUNIFORM3UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); typedef void (APIENTRYP PFNGLUNIFORM4UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); typedef void (APIENTRYP PFNGLUNIFORM1UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLUNIFORM2UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLUNIFORM3UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLUNIFORM4UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); #endif #ifndef GL_EXT_draw_instanced #define GL_EXT_draw_instanced 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawArraysInstancedEXT (GLenum mode, GLint start, GLsizei count, GLsizei primcount); GLAPI void APIENTRY glDrawElementsInstancedEXT (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount); typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); #endif #ifndef GL_EXT_packed_float #define GL_EXT_packed_float 1 #endif #ifndef GL_EXT_texture_array #define GL_EXT_texture_array 1 #endif #ifndef GL_EXT_texture_buffer_object #define GL_EXT_texture_buffer_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexBufferEXT (GLenum target, GLenum internalformat, GLuint buffer); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer); #endif #ifndef GL_EXT_texture_compression_latc #define GL_EXT_texture_compression_latc 1 #endif #ifndef GL_EXT_texture_compression_rgtc #define GL_EXT_texture_compression_rgtc 1 #endif #ifndef GL_EXT_texture_shared_exponent #define GL_EXT_texture_shared_exponent 1 #endif #ifndef GL_NV_depth_buffer_float #define GL_NV_depth_buffer_float 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDepthRangedNV (GLdouble zNear, GLdouble zFar); GLAPI void APIENTRY glClearDepthdNV (GLdouble depth); GLAPI void APIENTRY glDepthBoundsdNV (GLdouble zmin, GLdouble zmax); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDEPTHRANGEDNVPROC) (GLdouble zNear, GLdouble zFar); typedef void (APIENTRYP PFNGLCLEARDEPTHDNVPROC) (GLdouble depth); typedef void (APIENTRYP PFNGLDEPTHBOUNDSDNVPROC) (GLdouble zmin, GLdouble zmax); #endif #ifndef GL_NV_fragment_program4 #define GL_NV_fragment_program4 1 #endif #ifndef GL_NV_framebuffer_multisample_coverage #define GL_NV_framebuffer_multisample_coverage 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glRenderbufferStorageMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); #endif #ifndef GL_EXT_framebuffer_sRGB #define GL_EXT_framebuffer_sRGB 1 #endif #ifndef GL_NV_geometry_shader4 #define GL_NV_geometry_shader4 1 #endif #ifndef GL_NV_parameter_buffer_object #define GL_NV_parameter_buffer_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramBufferParametersfvNV (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLfloat *params); GLAPI void APIENTRY glProgramBufferParametersIivNV (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLint *params); GLAPI void APIENTRY glProgramBufferParametersIuivNV (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLuint *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC) (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLfloat *params); typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIIVNVPROC) (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLint *params); typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIUIVNVPROC) (GLenum target, GLuint buffer, GLuint index, GLsizei count, const GLuint *params); #endif #ifndef GL_EXT_draw_buffers2 #define GL_EXT_draw_buffers2 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glColorMaskIndexedEXT (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); GLAPI void APIENTRY glGetBooleanIndexedvEXT (GLenum target, GLuint index, GLboolean *data); GLAPI void APIENTRY glGetIntegerIndexedvEXT (GLenum target, GLuint index, GLint *data); GLAPI void APIENTRY glEnableIndexedEXT (GLenum target, GLuint index); GLAPI void APIENTRY glDisableIndexedEXT (GLenum target, GLuint index); GLAPI GLboolean APIENTRY glIsEnabledIndexedEXT (GLenum target, GLuint index); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOLORMASKINDEXEDEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); typedef void (APIENTRYP PFNGLGETBOOLEANINDEXEDVEXTPROC) (GLenum target, GLuint index, GLboolean *data); typedef void (APIENTRYP PFNGLGETINTEGERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLint *data); typedef void (APIENTRYP PFNGLENABLEINDEXEDEXTPROC) (GLenum target, GLuint index); typedef void (APIENTRYP PFNGLDISABLEINDEXEDEXTPROC) (GLenum target, GLuint index); typedef GLboolean (APIENTRYP PFNGLISENABLEDINDEXEDEXTPROC) (GLenum target, GLuint index); #endif #ifndef GL_NV_transform_feedback #define GL_NV_transform_feedback 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBeginTransformFeedbackNV (GLenum primitiveMode); GLAPI void APIENTRY glEndTransformFeedbackNV (void); GLAPI void APIENTRY glTransformFeedbackAttribsNV (GLuint count, const GLint *attribs, GLenum bufferMode); GLAPI void APIENTRY glBindBufferRangeNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); GLAPI void APIENTRY glBindBufferOffsetNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset); GLAPI void APIENTRY glBindBufferBaseNV (GLenum target, GLuint index, GLuint buffer); GLAPI void APIENTRY glTransformFeedbackVaryingsNV (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode); GLAPI void APIENTRY glActiveVaryingNV (GLuint program, const GLchar *name); GLAPI GLint APIENTRY glGetVaryingLocationNV (GLuint program, const GLchar *name); GLAPI void APIENTRY glGetActiveVaryingNV (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); GLAPI void APIENTRY glGetTransformFeedbackVaryingNV (GLuint program, GLuint index, GLint *location); GLAPI void APIENTRY glTransformFeedbackStreamAttribsNV (GLsizei count, const GLint *attribs, GLsizei nbuffers, const GLint *bufstreams, GLenum bufferMode); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKNVPROC) (GLenum primitiveMode); typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKNVPROC) (void); typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKATTRIBSNVPROC) (GLuint count, const GLint *attribs, GLenum bufferMode); typedef void (APIENTRYP PFNGLBINDBUFFERRANGENVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETNVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset); typedef void (APIENTRYP PFNGLBINDBUFFERBASENVPROC) (GLenum target, GLuint index, GLuint buffer); typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSNVPROC) (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode); typedef void (APIENTRYP PFNGLACTIVEVARYINGNVPROC) (GLuint program, const GLchar *name); typedef GLint (APIENTRYP PFNGLGETVARYINGLOCATIONNVPROC) (GLuint program, const GLchar *name); typedef void (APIENTRYP PFNGLGETACTIVEVARYINGNVPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGNVPROC) (GLuint program, GLuint index, GLint *location); typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKSTREAMATTRIBSNVPROC) (GLsizei count, const GLint *attribs, GLsizei nbuffers, const GLint *bufstreams, GLenum bufferMode); #endif #ifndef GL_EXT_bindable_uniform #define GL_EXT_bindable_uniform 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glUniformBufferEXT (GLuint program, GLint location, GLuint buffer); GLAPI GLint APIENTRY glGetUniformBufferSizeEXT (GLuint program, GLint location); GLAPI GLintptr APIENTRY glGetUniformOffsetEXT (GLuint program, GLint location); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLUNIFORMBUFFEREXTPROC) (GLuint program, GLint location, GLuint buffer); typedef GLint (APIENTRYP PFNGLGETUNIFORMBUFFERSIZEEXTPROC) (GLuint program, GLint location); typedef GLintptr (APIENTRYP PFNGLGETUNIFORMOFFSETEXTPROC) (GLuint program, GLint location); #endif #ifndef GL_EXT_texture_integer #define GL_EXT_texture_integer 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexParameterIivEXT (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glTexParameterIuivEXT (GLenum target, GLenum pname, const GLuint *params); GLAPI void APIENTRY glGetTexParameterIivEXT (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetTexParameterIuivEXT (GLenum target, GLenum pname, GLuint *params); GLAPI void APIENTRY glClearColorIiEXT (GLint red, GLint green, GLint blue, GLint alpha); GLAPI void APIENTRY glClearColorIuiEXT (GLuint red, GLuint green, GLuint blue, GLuint alpha); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params); typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLCLEARCOLORIIEXTPROC) (GLint red, GLint green, GLint blue, GLint alpha); typedef void (APIENTRYP PFNGLCLEARCOLORIUIEXTPROC) (GLuint red, GLuint green, GLuint blue, GLuint alpha); #endif #ifndef GL_GREMEDY_frame_terminator #define GL_GREMEDY_frame_terminator 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFrameTerminatorGREMEDY (void); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLFRAMETERMINATORGREMEDYPROC) (void); #endif #ifndef GL_NV_conditional_render #define GL_NV_conditional_render 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBeginConditionalRenderNV (GLuint id, GLenum mode); GLAPI void APIENTRY glEndConditionalRenderNV (void); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERNVPROC) (GLuint id, GLenum mode); typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERNVPROC) (void); #endif #ifndef GL_NV_present_video #define GL_NV_present_video 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glPresentFrameKeyedNV (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLuint key0, GLenum target1, GLuint fill1, GLuint key1); GLAPI void APIENTRY glPresentFrameDualFillNV (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLenum target1, GLuint fill1, GLenum target2, GLuint fill2, GLenum target3, GLuint fill3); GLAPI void APIENTRY glGetVideoivNV (GLuint video_slot, GLenum pname, GLint *params); GLAPI void APIENTRY glGetVideouivNV (GLuint video_slot, GLenum pname, GLuint *params); GLAPI void APIENTRY glGetVideoi64vNV (GLuint video_slot, GLenum pname, GLint64EXT *params); GLAPI void APIENTRY glGetVideoui64vNV (GLuint video_slot, GLenum pname, GLuint64EXT *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPRESENTFRAMEKEYEDNVPROC) (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLuint key0, GLenum target1, GLuint fill1, GLuint key1); typedef void (APIENTRYP PFNGLPRESENTFRAMEDUALFILLNVPROC) (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLenum target1, GLuint fill1, GLenum target2, GLuint fill2, GLenum target3, GLuint fill3); typedef void (APIENTRYP PFNGLGETVIDEOIVNVPROC) (GLuint video_slot, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVIDEOUIVNVPROC) (GLuint video_slot, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLGETVIDEOI64VNVPROC) (GLuint video_slot, GLenum pname, GLint64EXT *params); typedef void (APIENTRYP PFNGLGETVIDEOUI64VNVPROC) (GLuint video_slot, GLenum pname, GLuint64EXT *params); #endif #ifndef GL_EXT_transform_feedback #define GL_EXT_transform_feedback 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBeginTransformFeedbackEXT (GLenum primitiveMode); GLAPI void APIENTRY glEndTransformFeedbackEXT (void); GLAPI void APIENTRY glBindBufferRangeEXT (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); GLAPI void APIENTRY glBindBufferOffsetEXT (GLenum target, GLuint index, GLuint buffer, GLintptr offset); GLAPI void APIENTRY glBindBufferBaseEXT (GLenum target, GLuint index, GLuint buffer); GLAPI void APIENTRY glTransformFeedbackVaryingsEXT (GLuint program, GLsizei count, const GLchar* *varyings, GLenum bufferMode); GLAPI void APIENTRY glGetTransformFeedbackVaryingEXT (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKEXTPROC) (GLenum primitiveMode); typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKEXTPROC) (void); typedef void (APIENTRYP PFNGLBINDBUFFERRANGEEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset); typedef void (APIENTRYP PFNGLBINDBUFFERBASEEXTPROC) (GLenum target, GLuint index, GLuint buffer); typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC) (GLuint program, GLsizei count, const GLchar* *varyings, GLenum bufferMode); typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGEXTPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); #endif #ifndef GL_EXT_direct_state_access #define GL_EXT_direct_state_access 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glClientAttribDefaultEXT (GLbitfield mask); GLAPI void APIENTRY glPushClientAttribDefaultEXT (GLbitfield mask); GLAPI void APIENTRY glMatrixLoadfEXT (GLenum mode, const GLfloat *m); GLAPI void APIENTRY glMatrixLoaddEXT (GLenum mode, const GLdouble *m); GLAPI void APIENTRY glMatrixMultfEXT (GLenum mode, const GLfloat *m); GLAPI void APIENTRY glMatrixMultdEXT (GLenum mode, const GLdouble *m); GLAPI void APIENTRY glMatrixLoadIdentityEXT (GLenum mode); GLAPI void APIENTRY glMatrixRotatefEXT (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glMatrixRotatedEXT (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glMatrixScalefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glMatrixScaledEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glMatrixTranslatefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glMatrixTranslatedEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glMatrixFrustumEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); GLAPI void APIENTRY glMatrixOrthoEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); GLAPI void APIENTRY glMatrixPopEXT (GLenum mode); GLAPI void APIENTRY glMatrixPushEXT (GLenum mode); GLAPI void APIENTRY glMatrixLoadTransposefEXT (GLenum mode, const GLfloat *m); GLAPI void APIENTRY glMatrixLoadTransposedEXT (GLenum mode, const GLdouble *m); GLAPI void APIENTRY glMatrixMultTransposefEXT (GLenum mode, const GLfloat *m); GLAPI void APIENTRY glMatrixMultTransposedEXT (GLenum mode, const GLdouble *m); GLAPI void APIENTRY glTextureParameterfEXT (GLuint texture, GLenum target, GLenum pname, GLfloat param); GLAPI void APIENTRY glTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glTextureParameteriEXT (GLuint texture, GLenum target, GLenum pname, GLint param); GLAPI void APIENTRY glTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); GLAPI void APIENTRY glTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); GLAPI void APIENTRY glTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); GLAPI void APIENTRY glTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); GLAPI void APIENTRY glCopyTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); GLAPI void APIENTRY glCopyTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); GLAPI void APIENTRY glCopyTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); GLAPI void APIENTRY glCopyTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glGetTextureImageEXT (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); GLAPI void APIENTRY glGetTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetTextureLevelParameterfvEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetTextureLevelParameterivEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params); GLAPI void APIENTRY glTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); GLAPI void APIENTRY glTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); GLAPI void APIENTRY glCopyTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glMultiTexParameterfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param); GLAPI void APIENTRY glMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glMultiTexParameteriEXT (GLenum texunit, GLenum target, GLenum pname, GLint param); GLAPI void APIENTRY glMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); GLAPI void APIENTRY glMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); GLAPI void APIENTRY glMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); GLAPI void APIENTRY glMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); GLAPI void APIENTRY glCopyMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); GLAPI void APIENTRY glCopyMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); GLAPI void APIENTRY glCopyMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); GLAPI void APIENTRY glCopyMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glGetMultiTexImageEXT (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); GLAPI void APIENTRY glGetMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetMultiTexLevelParameterfvEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetMultiTexLevelParameterivEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params); GLAPI void APIENTRY glMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); GLAPI void APIENTRY glMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); GLAPI void APIENTRY glCopyMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glBindMultiTextureEXT (GLenum texunit, GLenum target, GLuint texture); GLAPI void APIENTRY glEnableClientStateIndexedEXT (GLenum array, GLuint index); GLAPI void APIENTRY glDisableClientStateIndexedEXT (GLenum array, GLuint index); GLAPI void APIENTRY glMultiTexCoordPointerEXT (GLenum texunit, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); GLAPI void APIENTRY glMultiTexEnvfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param); GLAPI void APIENTRY glMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glMultiTexEnviEXT (GLenum texunit, GLenum target, GLenum pname, GLint param); GLAPI void APIENTRY glMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glMultiTexGendEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble param); GLAPI void APIENTRY glMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params); GLAPI void APIENTRY glMultiTexGenfEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat param); GLAPI void APIENTRY glMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glMultiTexGeniEXT (GLenum texunit, GLenum coord, GLenum pname, GLint param); GLAPI void APIENTRY glMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, const GLint *params); GLAPI void APIENTRY glGetMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params); GLAPI void APIENTRY glGetMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, GLint *params); GLAPI void APIENTRY glGetFloatIndexedvEXT (GLenum target, GLuint index, GLfloat *data); GLAPI void APIENTRY glGetDoubleIndexedvEXT (GLenum target, GLuint index, GLdouble *data); GLAPI void APIENTRY glGetPointerIndexedvEXT (GLenum target, GLuint index, GLvoid* *data); GLAPI void APIENTRY glCompressedTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); GLAPI void APIENTRY glCompressedTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); GLAPI void APIENTRY glCompressedTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); GLAPI void APIENTRY glCompressedTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); GLAPI void APIENTRY glCompressedTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); GLAPI void APIENTRY glCompressedTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); GLAPI void APIENTRY glGetCompressedTextureImageEXT (GLuint texture, GLenum target, GLint lod, GLvoid *img); GLAPI void APIENTRY glCompressedMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); GLAPI void APIENTRY glCompressedMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); GLAPI void APIENTRY glCompressedMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); GLAPI void APIENTRY glCompressedMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); GLAPI void APIENTRY glCompressedMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); GLAPI void APIENTRY glCompressedMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); GLAPI void APIENTRY glGetCompressedMultiTexImageEXT (GLenum texunit, GLenum target, GLint lod, GLvoid *img); GLAPI void APIENTRY glNamedProgramStringEXT (GLuint program, GLenum target, GLenum format, GLsizei len, const GLvoid *string); GLAPI void APIENTRY glNamedProgramLocalParameter4dEXT (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glNamedProgramLocalParameter4dvEXT (GLuint program, GLenum target, GLuint index, const GLdouble *params); GLAPI void APIENTRY glNamedProgramLocalParameter4fEXT (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI void APIENTRY glNamedProgramLocalParameter4fvEXT (GLuint program, GLenum target, GLuint index, const GLfloat *params); GLAPI void APIENTRY glGetNamedProgramLocalParameterdvEXT (GLuint program, GLenum target, GLuint index, GLdouble *params); GLAPI void APIENTRY glGetNamedProgramLocalParameterfvEXT (GLuint program, GLenum target, GLuint index, GLfloat *params); GLAPI void APIENTRY glGetNamedProgramivEXT (GLuint program, GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetNamedProgramStringEXT (GLuint program, GLenum target, GLenum pname, GLvoid *string); GLAPI void APIENTRY glNamedProgramLocalParameters4fvEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params); GLAPI void APIENTRY glNamedProgramLocalParameterI4iEXT (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); GLAPI void APIENTRY glNamedProgramLocalParameterI4ivEXT (GLuint program, GLenum target, GLuint index, const GLint *params); GLAPI void APIENTRY glNamedProgramLocalParametersI4ivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params); GLAPI void APIENTRY glNamedProgramLocalParameterI4uiEXT (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); GLAPI void APIENTRY glNamedProgramLocalParameterI4uivEXT (GLuint program, GLenum target, GLuint index, const GLuint *params); GLAPI void APIENTRY glNamedProgramLocalParametersI4uivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params); GLAPI void APIENTRY glGetNamedProgramLocalParameterIivEXT (GLuint program, GLenum target, GLuint index, GLint *params); GLAPI void APIENTRY glGetNamedProgramLocalParameterIuivEXT (GLuint program, GLenum target, GLuint index, GLuint *params); GLAPI void APIENTRY glTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, const GLuint *params); GLAPI void APIENTRY glGetTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, GLuint *params); GLAPI void APIENTRY glMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, const GLuint *params); GLAPI void APIENTRY glGetMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, GLuint *params); GLAPI void APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat v0); GLAPI void APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1); GLAPI void APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); GLAPI void APIENTRY glProgramUniform4fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); GLAPI void APIENTRY glProgramUniform1iEXT (GLuint program, GLint location, GLint v0); GLAPI void APIENTRY glProgramUniform2iEXT (GLuint program, GLint location, GLint v0, GLint v1); GLAPI void APIENTRY glProgramUniform3iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); GLAPI void APIENTRY glProgramUniform4iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); GLAPI void APIENTRY glProgramUniform1fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glProgramUniform2fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glProgramUniform3fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glProgramUniform4fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); GLAPI void APIENTRY glProgramUniform1ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glProgramUniform2ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glProgramUniform3ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glProgramUniform4ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); GLAPI void APIENTRY glProgramUniformMatrix2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix2x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix3x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix2x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix4x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix3x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniformMatrix4x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glProgramUniform1uiEXT (GLuint program, GLint location, GLuint v0); GLAPI void APIENTRY glProgramUniform2uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1); GLAPI void APIENTRY glProgramUniform3uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); GLAPI void APIENTRY glProgramUniform4uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); GLAPI void APIENTRY glProgramUniform1uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glProgramUniform2uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glProgramUniform3uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glProgramUniform4uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); GLAPI void APIENTRY glNamedBufferDataEXT (GLuint buffer, GLsizeiptr size, const GLvoid *data, GLenum usage); GLAPI void APIENTRY glNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, const GLvoid *data); GLAPI GLvoid* APIENTRY glMapNamedBufferEXT (GLuint buffer, GLenum access); GLAPI GLboolean APIENTRY glUnmapNamedBufferEXT (GLuint buffer); GLAPI GLvoid* APIENTRY glMapNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); GLAPI void APIENTRY glFlushMappedNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length); GLAPI void APIENTRY glNamedCopyBufferSubDataEXT (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); GLAPI void APIENTRY glGetNamedBufferParameterivEXT (GLuint buffer, GLenum pname, GLint *params); GLAPI void APIENTRY glGetNamedBufferPointervEXT (GLuint buffer, GLenum pname, GLvoid* *params); GLAPI void APIENTRY glGetNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, GLvoid *data); GLAPI void APIENTRY glTextureBufferEXT (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); GLAPI void APIENTRY glMultiTexBufferEXT (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); GLAPI void APIENTRY glNamedRenderbufferStorageEXT (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); GLAPI void APIENTRY glGetNamedRenderbufferParameterivEXT (GLuint renderbuffer, GLenum pname, GLint *params); GLAPI GLenum APIENTRY glCheckNamedFramebufferStatusEXT (GLuint framebuffer, GLenum target); GLAPI void APIENTRY glNamedFramebufferTexture1DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); GLAPI void APIENTRY glNamedFramebufferTexture2DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); GLAPI void APIENTRY glNamedFramebufferTexture3DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); GLAPI void APIENTRY glNamedFramebufferRenderbufferEXT (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); GLAPI void APIENTRY glGetNamedFramebufferAttachmentParameterivEXT (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); GLAPI void APIENTRY glGenerateTextureMipmapEXT (GLuint texture, GLenum target); GLAPI void APIENTRY glGenerateMultiTexMipmapEXT (GLenum texunit, GLenum target); GLAPI void APIENTRY glFramebufferDrawBufferEXT (GLuint framebuffer, GLenum mode); GLAPI void APIENTRY glFramebufferDrawBuffersEXT (GLuint framebuffer, GLsizei n, const GLenum *bufs); GLAPI void APIENTRY glFramebufferReadBufferEXT (GLuint framebuffer, GLenum mode); GLAPI void APIENTRY glGetFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params); GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleEXT (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleCoverageEXT (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); GLAPI void APIENTRY glNamedFramebufferTextureEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); GLAPI void APIENTRY glNamedFramebufferTextureLayerEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); GLAPI void APIENTRY glNamedFramebufferTextureFaceEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face); GLAPI void APIENTRY glTextureRenderbufferEXT (GLuint texture, GLenum target, GLuint renderbuffer); GLAPI void APIENTRY glMultiTexRenderbufferEXT (GLenum texunit, GLenum target, GLuint renderbuffer); GLAPI void APIENTRY glProgramUniform1dEXT (GLuint program, GLint location, GLdouble x); GLAPI void APIENTRY glProgramUniform2dEXT (GLuint program, GLint location, GLdouble x, GLdouble y); GLAPI void APIENTRY glProgramUniform3dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glProgramUniform4dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glProgramUniform1dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glProgramUniform2dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glProgramUniform3dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glProgramUniform4dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix2x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix2x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix3x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix3x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix4x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI void APIENTRY glProgramUniformMatrix4x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask); typedef void (APIENTRYP PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask); typedef void (APIENTRYP PFNGLMATRIXLOADFEXTPROC) (GLenum mode, const GLfloat *m); typedef void (APIENTRYP PFNGLMATRIXLOADDEXTPROC) (GLenum mode, const GLdouble *m); typedef void (APIENTRYP PFNGLMATRIXMULTFEXTPROC) (GLenum mode, const GLfloat *m); typedef void (APIENTRYP PFNGLMATRIXMULTDEXTPROC) (GLenum mode, const GLdouble *m); typedef void (APIENTRYP PFNGLMATRIXLOADIDENTITYEXTPROC) (GLenum mode); typedef void (APIENTRYP PFNGLMATRIXROTATEFEXTPROC) (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLMATRIXROTATEDEXTPROC) (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLMATRIXSCALEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLMATRIXSCALEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLMATRIXTRANSLATEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z); typedef void (APIENTRYP PFNGLMATRIXTRANSLATEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLMATRIXFRUSTUMEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); typedef void (APIENTRYP PFNGLMATRIXORTHOEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); typedef void (APIENTRYP PFNGLMATRIXPOPEXTPROC) (GLenum mode); typedef void (APIENTRYP PFNGLMATRIXPUSHEXTPROC) (GLenum mode); typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m); typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m); typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m); typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLBINDMULTITEXTUREEXTPROC) (GLenum texunit, GLenum target, GLuint texture); typedef void (APIENTRYP PFNGLENABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index); typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index); typedef void (APIENTRYP PFNGLMULTITEXCOORDPOINTEREXTPROC) (GLenum texunit, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLMULTITEXENVFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLMULTITEXENVIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLMULTITEXGENDEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble param); typedef void (APIENTRYP PFNGLMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params); typedef void (APIENTRYP PFNGLMULTITEXGENFEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLMULTITEXGENIEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLGETMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLGETMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETFLOATINDEXEDVEXTPROC) (GLenum target, GLuint index, GLfloat *data); typedef void (APIENTRYP PFNGLGETDOUBLEINDEXEDVEXTPROC) (GLenum target, GLuint index, GLdouble *data); typedef void (APIENTRYP PFNGLGETPOINTERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLvoid* *data); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint lod, GLvoid *img); typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); typedef void (APIENTRYP PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint lod, GLvoid *img); typedef void (APIENTRYP PFNGLNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum format, GLsizei len, const GLvoid *string); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLdouble *params); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLfloat *params); typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERDVEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble *params); typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERFVEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat *params); typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMIVEXTPROC) (GLuint program, GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum pname, GLvoid *string); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IEXTPROC) (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLint *params); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLuint *params); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params); typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLint *params); typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIUIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint *params); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLuint *params); typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLuint *params); typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); typedef void (APIENTRYP PFNGLNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLsizeiptr size, const GLvoid *data, GLenum usage); typedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const GLvoid *data); typedef GLvoid* (APIENTRYP PFNGLMAPNAMEDBUFFEREXTPROC) (GLuint buffer, GLenum access); typedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFEREXTPROC) (GLuint buffer); typedef GLvoid* (APIENTRYP PFNGLMAPNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); typedef void (APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); typedef void (APIENTRYP PFNGLNAMEDCOPYBUFFERSUBDATAEXTPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVEXTPROC) (GLuint buffer, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVEXTPROC) (GLuint buffer, GLenum pname, GLvoid* *params); typedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLvoid *data); typedef void (APIENTRYP PFNGLTEXTUREBUFFEREXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); typedef void (APIENTRYP PFNGLMULTITEXBUFFEREXTPROC) (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVEXTPROC) (GLuint renderbuffer, GLenum pname, GLint *params); typedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSEXTPROC) (GLuint framebuffer, GLenum target); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE1DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE2DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE3DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFEREXTPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGENERATETEXTUREMIPMAPEXTPROC) (GLuint texture, GLenum target); typedef void (APIENTRYP PFNGLGENERATEMULTITEXMIPMAPEXTPROC) (GLenum texunit, GLenum target); typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFEREXTPROC) (GLuint framebuffer, GLenum mode); typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFERSEXTPROC) (GLuint framebuffer, GLsizei n, const GLenum *bufs); typedef void (APIENTRYP PFNGLFRAMEBUFFERREADBUFFEREXTPROC) (GLuint framebuffer, GLenum mode); typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC) (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYEREXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREFACEEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face); typedef void (APIENTRYP PFNGLTEXTURERENDERBUFFEREXTPROC) (GLuint texture, GLenum target, GLuint renderbuffer); typedef void (APIENTRYP PFNGLMULTITEXRENDERBUFFEREXTPROC) (GLenum texunit, GLenum target, GLuint renderbuffer); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DEXTPROC) (GLuint program, GLint location, GLdouble x); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); #endif #ifndef GL_EXT_vertex_array_bgra #define GL_EXT_vertex_array_bgra 1 #endif #ifndef GL_EXT_texture_swizzle #define GL_EXT_texture_swizzle 1 #endif #ifndef GL_NV_explicit_multisample #define GL_NV_explicit_multisample 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetMultisamplefvNV (GLenum pname, GLuint index, GLfloat *val); GLAPI void APIENTRY glSampleMaskIndexedNV (GLuint index, GLbitfield mask); GLAPI void APIENTRY glTexRenderbufferNV (GLenum target, GLuint renderbuffer); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVNVPROC) (GLenum pname, GLuint index, GLfloat *val); typedef void (APIENTRYP PFNGLSAMPLEMASKINDEXEDNVPROC) (GLuint index, GLbitfield mask); typedef void (APIENTRYP PFNGLTEXRENDERBUFFERNVPROC) (GLenum target, GLuint renderbuffer); #endif #ifndef GL_NV_transform_feedback2 #define GL_NV_transform_feedback2 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindTransformFeedbackNV (GLenum target, GLuint id); GLAPI void APIENTRY glDeleteTransformFeedbacksNV (GLsizei n, const GLuint *ids); GLAPI void APIENTRY glGenTransformFeedbacksNV (GLsizei n, GLuint *ids); GLAPI GLboolean APIENTRY glIsTransformFeedbackNV (GLuint id); GLAPI void APIENTRY glPauseTransformFeedbackNV (void); GLAPI void APIENTRY glResumeTransformFeedbackNV (void); GLAPI void APIENTRY glDrawTransformFeedbackNV (GLenum mode, GLuint id); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKNVPROC) (GLenum target, GLuint id); typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSNVPROC) (GLsizei n, const GLuint *ids); typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSNVPROC) (GLsizei n, GLuint *ids); typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKNVPROC) (GLuint id); typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKNVPROC) (void); typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKNVPROC) (void); typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKNVPROC) (GLenum mode, GLuint id); #endif #ifndef GL_ATI_meminfo #define GL_ATI_meminfo 1 #endif #ifndef GL_AMD_performance_monitor #define GL_AMD_performance_monitor 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups); GLAPI void APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); GLAPI void APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); GLAPI void APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); GLAPI void APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, GLvoid *data); GLAPI void APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors); GLAPI void APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors); GLAPI void APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList); GLAPI void APIENTRY glBeginPerfMonitorAMD (GLuint monitor); GLAPI void APIENTRY glEndPerfMonitorAMD (GLuint monitor); GLAPI void APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups); typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, GLvoid *data); typedef void (APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); typedef void (APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); typedef void (APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList); typedef void (APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor); typedef void (APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor); typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); #endif #ifndef GL_AMD_texture_texture4 #define GL_AMD_texture_texture4 1 #endif #ifndef GL_AMD_vertex_shader_tesselator #define GL_AMD_vertex_shader_tesselator 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTessellationFactorAMD (GLfloat factor); GLAPI void APIENTRY glTessellationModeAMD (GLenum mode); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTESSELLATIONFACTORAMDPROC) (GLfloat factor); typedef void (APIENTRYP PFNGLTESSELLATIONMODEAMDPROC) (GLenum mode); #endif #ifndef GL_EXT_provoking_vertex #define GL_EXT_provoking_vertex 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProvokingVertexEXT (GLenum mode); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPROVOKINGVERTEXEXTPROC) (GLenum mode); #endif #ifndef GL_EXT_texture_snorm #define GL_EXT_texture_snorm 1 #endif #ifndef GL_AMD_draw_buffers_blend #define GL_AMD_draw_buffers_blend 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendFuncIndexedAMD (GLuint buf, GLenum src, GLenum dst); GLAPI void APIENTRY glBlendFuncSeparateIndexedAMD (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); GLAPI void APIENTRY glBlendEquationIndexedAMD (GLuint buf, GLenum mode); GLAPI void APIENTRY glBlendEquationSeparateIndexedAMD (GLuint buf, GLenum modeRGB, GLenum modeAlpha); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBLENDFUNCINDEXEDAMDPROC) (GLuint buf, GLenum src, GLenum dst); typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINDEXEDAMDPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); typedef void (APIENTRYP PFNGLBLENDEQUATIONINDEXEDAMDPROC) (GLuint buf, GLenum mode); typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEINDEXEDAMDPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); #endif #ifndef GL_APPLE_texture_range #define GL_APPLE_texture_range 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTextureRangeAPPLE (GLenum target, GLsizei length, const GLvoid *pointer); GLAPI void APIENTRY glGetTexParameterPointervAPPLE (GLenum target, GLenum pname, GLvoid* *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXTURERANGEAPPLEPROC) (GLenum target, GLsizei length, const GLvoid *pointer); typedef void (APIENTRYP PFNGLGETTEXPARAMETERPOINTERVAPPLEPROC) (GLenum target, GLenum pname, GLvoid* *params); #endif #ifndef GL_APPLE_float_pixels #define GL_APPLE_float_pixels 1 #endif #ifndef GL_APPLE_vertex_program_evaluators #define GL_APPLE_vertex_program_evaluators 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glEnableVertexAttribAPPLE (GLuint index, GLenum pname); GLAPI void APIENTRY glDisableVertexAttribAPPLE (GLuint index, GLenum pname); GLAPI GLboolean APIENTRY glIsVertexAttribEnabledAPPLE (GLuint index, GLenum pname); GLAPI void APIENTRY glMapVertexAttrib1dAPPLE (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); GLAPI void APIENTRY glMapVertexAttrib1fAPPLE (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); GLAPI void APIENTRY glMapVertexAttrib2dAPPLE (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); GLAPI void APIENTRY glMapVertexAttrib2fAPPLE (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBAPPLEPROC) (GLuint index, GLenum pname); typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBAPPLEPROC) (GLuint index, GLenum pname); typedef GLboolean (APIENTRYP PFNGLISVERTEXATTRIBENABLEDAPPLEPROC) (GLuint index, GLenum pname); typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB1DAPPLEPROC) (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB1FAPPLEPROC) (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB2DAPPLEPROC) (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB2FAPPLEPROC) (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); #endif #ifndef GL_APPLE_aux_depth_stencil #define GL_APPLE_aux_depth_stencil 1 #endif #ifndef GL_APPLE_object_purgeable #define GL_APPLE_object_purgeable 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLenum APIENTRY glObjectPurgeableAPPLE (GLenum objectType, GLuint name, GLenum option); GLAPI GLenum APIENTRY glObjectUnpurgeableAPPLE (GLenum objectType, GLuint name, GLenum option); GLAPI void APIENTRY glGetObjectParameterivAPPLE (GLenum objectType, GLuint name, GLenum pname, GLint *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLenum (APIENTRYP PFNGLOBJECTPURGEABLEAPPLEPROC) (GLenum objectType, GLuint name, GLenum option); typedef GLenum (APIENTRYP PFNGLOBJECTUNPURGEABLEAPPLEPROC) (GLenum objectType, GLuint name, GLenum option); typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVAPPLEPROC) (GLenum objectType, GLuint name, GLenum pname, GLint *params); #endif #ifndef GL_APPLE_row_bytes #define GL_APPLE_row_bytes 1 #endif #ifndef GL_APPLE_rgb_422 #define GL_APPLE_rgb_422 1 #endif #ifndef GL_NV_video_capture #define GL_NV_video_capture 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBeginVideoCaptureNV (GLuint video_capture_slot); GLAPI void APIENTRY glBindVideoCaptureStreamBufferNV (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset); GLAPI void APIENTRY glBindVideoCaptureStreamTextureNV (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture); GLAPI void APIENTRY glEndVideoCaptureNV (GLuint video_capture_slot); GLAPI void APIENTRY glGetVideoCaptureivNV (GLuint video_capture_slot, GLenum pname, GLint *params); GLAPI void APIENTRY glGetVideoCaptureStreamivNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params); GLAPI void APIENTRY glGetVideoCaptureStreamfvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetVideoCaptureStreamdvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params); GLAPI GLenum APIENTRY glVideoCaptureNV (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time); GLAPI void APIENTRY glVideoCaptureStreamParameterivNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params); GLAPI void APIENTRY glVideoCaptureStreamParameterfvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glVideoCaptureStreamParameterdvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBEGINVIDEOCAPTURENVPROC) (GLuint video_capture_slot); typedef void (APIENTRYP PFNGLBINDVIDEOCAPTURESTREAMBUFFERNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset); typedef void (APIENTRYP PFNGLBINDVIDEOCAPTURESTREAMTEXTURENVPROC) (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture); typedef void (APIENTRYP PFNGLENDVIDEOCAPTURENVPROC) (GLuint video_capture_slot); typedef void (APIENTRYP PFNGLGETVIDEOCAPTUREIVNVPROC) (GLuint video_capture_slot, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMIVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMFVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMDVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params); typedef GLenum (APIENTRYP PFNGLVIDEOCAPTURENVPROC) (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time); typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERIVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERFVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERDVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params); #endif #ifndef GL_NV_copy_image #define GL_NV_copy_image 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCopyImageSubDataNV (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATANVPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); #endif #ifndef GL_EXT_separate_shader_objects #define GL_EXT_separate_shader_objects 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glUseShaderProgramEXT (GLenum type, GLuint program); GLAPI void APIENTRY glActiveProgramEXT (GLuint program); GLAPI GLuint APIENTRY glCreateShaderProgramEXT (GLenum type, const GLchar *string); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLUSESHADERPROGRAMEXTPROC) (GLenum type, GLuint program); typedef void (APIENTRYP PFNGLACTIVEPROGRAMEXTPROC) (GLuint program); typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMEXTPROC) (GLenum type, const GLchar *string); #endif #ifndef GL_NV_parameter_buffer_object2 #define GL_NV_parameter_buffer_object2 1 #endif #ifndef GL_NV_shader_buffer_load #define GL_NV_shader_buffer_load 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMakeBufferResidentNV (GLenum target, GLenum access); GLAPI void APIENTRY glMakeBufferNonResidentNV (GLenum target); GLAPI GLboolean APIENTRY glIsBufferResidentNV (GLenum target); GLAPI void APIENTRY glMakeNamedBufferResidentNV (GLuint buffer, GLenum access); GLAPI void APIENTRY glMakeNamedBufferNonResidentNV (GLuint buffer); GLAPI GLboolean APIENTRY glIsNamedBufferResidentNV (GLuint buffer); GLAPI void APIENTRY glGetBufferParameterui64vNV (GLenum target, GLenum pname, GLuint64EXT *params); GLAPI void APIENTRY glGetNamedBufferParameterui64vNV (GLuint buffer, GLenum pname, GLuint64EXT *params); GLAPI void APIENTRY glGetIntegerui64vNV (GLenum value, GLuint64EXT *result); GLAPI void APIENTRY glUniformui64NV (GLint location, GLuint64EXT value); GLAPI void APIENTRY glUniformui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); GLAPI void APIENTRY glGetUniformui64vNV (GLuint program, GLint location, GLuint64EXT *params); GLAPI void APIENTRY glProgramUniformui64NV (GLuint program, GLint location, GLuint64EXT value); GLAPI void APIENTRY glProgramUniformui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLMAKEBUFFERRESIDENTNVPROC) (GLenum target, GLenum access); typedef void (APIENTRYP PFNGLMAKEBUFFERNONRESIDENTNVPROC) (GLenum target); typedef GLboolean (APIENTRYP PFNGLISBUFFERRESIDENTNVPROC) (GLenum target); typedef void (APIENTRYP PFNGLMAKENAMEDBUFFERRESIDENTNVPROC) (GLuint buffer, GLenum access); typedef void (APIENTRYP PFNGLMAKENAMEDBUFFERNONRESIDENTNVPROC) (GLuint buffer); typedef GLboolean (APIENTRYP PFNGLISNAMEDBUFFERRESIDENTNVPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERUI64VNVPROC) (GLenum target, GLenum pname, GLuint64EXT *params); typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERUI64VNVPROC) (GLuint buffer, GLenum pname, GLuint64EXT *params); typedef void (APIENTRYP PFNGLGETINTEGERUI64VNVPROC) (GLenum value, GLuint64EXT *result); typedef void (APIENTRYP PFNGLUNIFORMUI64NVPROC) (GLint location, GLuint64EXT value); typedef void (APIENTRYP PFNGLUNIFORMUI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); typedef void (APIENTRYP PFNGLGETUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLuint64EXT *params); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64NVPROC) (GLuint program, GLint location, GLuint64EXT value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); #endif #ifndef GL_NV_vertex_buffer_unified_memory #define GL_NV_vertex_buffer_unified_memory 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBufferAddressRangeNV (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length); GLAPI void APIENTRY glVertexFormatNV (GLint size, GLenum type, GLsizei stride); GLAPI void APIENTRY glNormalFormatNV (GLenum type, GLsizei stride); GLAPI void APIENTRY glColorFormatNV (GLint size, GLenum type, GLsizei stride); GLAPI void APIENTRY glIndexFormatNV (GLenum type, GLsizei stride); GLAPI void APIENTRY glTexCoordFormatNV (GLint size, GLenum type, GLsizei stride); GLAPI void APIENTRY glEdgeFlagFormatNV (GLsizei stride); GLAPI void APIENTRY glSecondaryColorFormatNV (GLint size, GLenum type, GLsizei stride); GLAPI void APIENTRY glFogCoordFormatNV (GLenum type, GLsizei stride); GLAPI void APIENTRY glVertexAttribFormatNV (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride); GLAPI void APIENTRY glVertexAttribIFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride); GLAPI void APIENTRY glGetIntegerui64i_vNV (GLenum value, GLuint index, GLuint64EXT *result); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBUFFERADDRESSRANGENVPROC) (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length); typedef void (APIENTRYP PFNGLVERTEXFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); typedef void (APIENTRYP PFNGLNORMALFORMATNVPROC) (GLenum type, GLsizei stride); typedef void (APIENTRYP PFNGLCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); typedef void (APIENTRYP PFNGLINDEXFORMATNVPROC) (GLenum type, GLsizei stride); typedef void (APIENTRYP PFNGLTEXCOORDFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); typedef void (APIENTRYP PFNGLEDGEFLAGFORMATNVPROC) (GLsizei stride); typedef void (APIENTRYP PFNGLSECONDARYCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); typedef void (APIENTRYP PFNGLFOGCOORDFORMATNVPROC) (GLenum type, GLsizei stride); typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride); typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride); typedef void (APIENTRYP PFNGLGETINTEGERUI64I_VNVPROC) (GLenum value, GLuint index, GLuint64EXT *result); #endif #ifndef GL_NV_texture_barrier #define GL_NV_texture_barrier 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTextureBarrierNV (void); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXTUREBARRIERNVPROC) (void); #endif #ifndef GL_AMD_shader_stencil_export #define GL_AMD_shader_stencil_export 1 #endif #ifndef GL_AMD_seamless_cubemap_per_texture #define GL_AMD_seamless_cubemap_per_texture 1 #endif #ifndef GL_AMD_conservative_depth #define GL_AMD_conservative_depth 1 #endif #ifndef GL_EXT_shader_image_load_store #define GL_EXT_shader_image_load_store 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindImageTextureEXT (GLuint index, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLint format); GLAPI void APIENTRY glMemoryBarrierEXT (GLbitfield barriers); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREEXTPROC) (GLuint index, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLint format); typedef void (APIENTRYP PFNGLMEMORYBARRIEREXTPROC) (GLbitfield barriers); #endif #ifndef GL_EXT_vertex_attrib_64bit #define GL_EXT_vertex_attrib_64bit 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttribL1dEXT (GLuint index, GLdouble x); GLAPI void APIENTRY glVertexAttribL2dEXT (GLuint index, GLdouble x, GLdouble y); GLAPI void APIENTRY glVertexAttribL3dEXT (GLuint index, GLdouble x, GLdouble y, GLdouble z); GLAPI void APIENTRY glVertexAttribL4dEXT (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glVertexAttribL1dvEXT (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttribL2dvEXT (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttribL3dvEXT (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttribL4dvEXT (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttribLPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); GLAPI void APIENTRY glGetVertexAttribLdvEXT (GLuint index, GLenum pname, GLdouble *params); GLAPI void APIENTRY glVertexArrayVertexAttribLOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DEXTPROC) (GLuint index, GLdouble x); typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DEXTPROC) (GLuint index, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVEXTPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVEXTPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVEXTPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVEXTPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVEXTPROC) (GLuint index, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); #endif #ifndef GL_NV_gpu_program5 #define GL_NV_gpu_program5 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramSubroutineParametersuivNV (GLenum target, GLsizei count, const GLuint *params); GLAPI void APIENTRY glGetProgramSubroutineParameteruivNV (GLenum target, GLuint index, GLuint *param); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLPROGRAMSUBROUTINEPARAMETERSUIVNVPROC) (GLenum target, GLsizei count, const GLuint *params); typedef void (APIENTRYP PFNGLGETPROGRAMSUBROUTINEPARAMETERUIVNVPROC) (GLenum target, GLuint index, GLuint *param); #endif #ifndef GL_NV_gpu_shader5 #define GL_NV_gpu_shader5 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glUniform1i64NV (GLint location, GLint64EXT x); GLAPI void APIENTRY glUniform2i64NV (GLint location, GLint64EXT x, GLint64EXT y); GLAPI void APIENTRY glUniform3i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); GLAPI void APIENTRY glUniform4i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); GLAPI void APIENTRY glUniform1i64vNV (GLint location, GLsizei count, const GLint64EXT *value); GLAPI void APIENTRY glUniform2i64vNV (GLint location, GLsizei count, const GLint64EXT *value); GLAPI void APIENTRY glUniform3i64vNV (GLint location, GLsizei count, const GLint64EXT *value); GLAPI void APIENTRY glUniform4i64vNV (GLint location, GLsizei count, const GLint64EXT *value); GLAPI void APIENTRY glUniform1ui64NV (GLint location, GLuint64EXT x); GLAPI void APIENTRY glUniform2ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y); GLAPI void APIENTRY glUniform3ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); GLAPI void APIENTRY glUniform4ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); GLAPI void APIENTRY glUniform1ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); GLAPI void APIENTRY glUniform2ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); GLAPI void APIENTRY glUniform3ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); GLAPI void APIENTRY glUniform4ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); GLAPI void APIENTRY glGetUniformi64vNV (GLuint program, GLint location, GLint64EXT *params); GLAPI void APIENTRY glProgramUniform1i64NV (GLuint program, GLint location, GLint64EXT x); GLAPI void APIENTRY glProgramUniform2i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); GLAPI void APIENTRY glProgramUniform3i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); GLAPI void APIENTRY glProgramUniform4i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); GLAPI void APIENTRY glProgramUniform1i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); GLAPI void APIENTRY glProgramUniform2i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); GLAPI void APIENTRY glProgramUniform3i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); GLAPI void APIENTRY glProgramUniform4i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); GLAPI void APIENTRY glProgramUniform1ui64NV (GLuint program, GLint location, GLuint64EXT x); GLAPI void APIENTRY glProgramUniform2ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); GLAPI void APIENTRY glProgramUniform3ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); GLAPI void APIENTRY glProgramUniform4ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); GLAPI void APIENTRY glProgramUniform1ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); GLAPI void APIENTRY glProgramUniform2ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); GLAPI void APIENTRY glProgramUniform3ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); GLAPI void APIENTRY glProgramUniform4ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLUNIFORM1I64NVPROC) (GLint location, GLint64EXT x); typedef void (APIENTRYP PFNGLUNIFORM2I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y); typedef void (APIENTRYP PFNGLUNIFORM3I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); typedef void (APIENTRYP PFNGLUNIFORM4I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); typedef void (APIENTRYP PFNGLUNIFORM1I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); typedef void (APIENTRYP PFNGLUNIFORM2I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); typedef void (APIENTRYP PFNGLUNIFORM3I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); typedef void (APIENTRYP PFNGLUNIFORM4I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); typedef void (APIENTRYP PFNGLUNIFORM1UI64NVPROC) (GLint location, GLuint64EXT x); typedef void (APIENTRYP PFNGLUNIFORM2UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y); typedef void (APIENTRYP PFNGLUNIFORM3UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); typedef void (APIENTRYP PFNGLUNIFORM4UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); typedef void (APIENTRYP PFNGLUNIFORM1UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); typedef void (APIENTRYP PFNGLUNIFORM2UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); typedef void (APIENTRYP PFNGLUNIFORM3UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); typedef void (APIENTRYP PFNGLUNIFORM4UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); typedef void (APIENTRYP PFNGLGETUNIFORMI64VNVPROC) (GLuint program, GLint location, GLint64EXT *params); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64NVPROC) (GLuint program, GLint location, GLint64EXT x); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); #endif #ifndef GL_NV_shader_buffer_store #define GL_NV_shader_buffer_store 1 #endif #ifndef GL_NV_tessellation_program5 #define GL_NV_tessellation_program5 1 #endif #ifndef GL_NV_vertex_attrib_integer_64bit #define GL_NV_vertex_attrib_integer_64bit 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttribL1i64NV (GLuint index, GLint64EXT x); GLAPI void APIENTRY glVertexAttribL2i64NV (GLuint index, GLint64EXT x, GLint64EXT y); GLAPI void APIENTRY glVertexAttribL3i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z); GLAPI void APIENTRY glVertexAttribL4i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); GLAPI void APIENTRY glVertexAttribL1i64vNV (GLuint index, const GLint64EXT *v); GLAPI void APIENTRY glVertexAttribL2i64vNV (GLuint index, const GLint64EXT *v); GLAPI void APIENTRY glVertexAttribL3i64vNV (GLuint index, const GLint64EXT *v); GLAPI void APIENTRY glVertexAttribL4i64vNV (GLuint index, const GLint64EXT *v); GLAPI void APIENTRY glVertexAttribL1ui64NV (GLuint index, GLuint64EXT x); GLAPI void APIENTRY glVertexAttribL2ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y); GLAPI void APIENTRY glVertexAttribL3ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); GLAPI void APIENTRY glVertexAttribL4ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); GLAPI void APIENTRY glVertexAttribL1ui64vNV (GLuint index, const GLuint64EXT *v); GLAPI void APIENTRY glVertexAttribL2ui64vNV (GLuint index, const GLuint64EXT *v); GLAPI void APIENTRY glVertexAttribL3ui64vNV (GLuint index, const GLuint64EXT *v); GLAPI void APIENTRY glVertexAttribL4ui64vNV (GLuint index, const GLuint64EXT *v); GLAPI void APIENTRY glGetVertexAttribLi64vNV (GLuint index, GLenum pname, GLint64EXT *params); GLAPI void APIENTRY glGetVertexAttribLui64vNV (GLuint index, GLenum pname, GLuint64EXT *params); GLAPI void APIENTRY glVertexAttribLFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64NVPROC) (GLuint index, GLint64EXT x); typedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y); typedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z); typedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); typedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64VNVPROC) (GLuint index, const GLint64EXT *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64VNVPROC) (GLuint index, const GLint64EXT *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64VNVPROC) (GLuint index, const GLint64EXT *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64VNVPROC) (GLuint index, const GLint64EXT *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64NVPROC) (GLuint index, GLuint64EXT x); typedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y); typedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); typedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VNVPROC) (GLuint index, const GLuint64EXT *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64VNVPROC) (GLuint index, const GLuint64EXT *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64VNVPROC) (GLuint index, const GLuint64EXT *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64VNVPROC) (GLuint index, const GLuint64EXT *v); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLI64VNVPROC) (GLuint index, GLenum pname, GLint64EXT *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VNVPROC) (GLuint index, GLenum pname, GLuint64EXT *params); typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride); #endif #ifndef GL_NV_multisample_coverage #define GL_NV_multisample_coverage 1 #endif #ifndef GL_AMD_name_gen_delete #define GL_AMD_name_gen_delete 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGenNamesAMD (GLenum identifier, GLuint num, GLuint *names); GLAPI void APIENTRY glDeleteNamesAMD (GLenum identifier, GLuint num, const GLuint *names); GLAPI GLboolean APIENTRY glIsNameAMD (GLenum identifier, GLuint name); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLGENNAMESAMDPROC) (GLenum identifier, GLuint num, GLuint *names); typedef void (APIENTRYP PFNGLDELETENAMESAMDPROC) (GLenum identifier, GLuint num, const GLuint *names); typedef GLboolean (APIENTRYP PFNGLISNAMEAMDPROC) (GLenum identifier, GLuint name); #endif #ifndef GL_AMD_debug_output #define GL_AMD_debug_output 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDebugMessageEnableAMD (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); GLAPI void APIENTRY glDebugMessageInsertAMD (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf); GLAPI void APIENTRY glDebugMessageCallbackAMD (GLDEBUGPROCAMD callback, GLvoid *userParam); GLAPI GLuint APIENTRY glGetDebugMessageLogAMD (GLuint count, GLsizei bufsize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLDEBUGMESSAGEENABLEAMDPROC) (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTAMDPROC) (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf); typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKAMDPROC) (GLDEBUGPROCAMD callback, GLvoid *userParam); typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGAMDPROC) (GLuint count, GLsizei bufsize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message); #endif #ifndef GL_NV_vdpau_interop #define GL_NV_vdpau_interop 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVDPAUInitNV (const GLvoid *vdpDevice, const GLvoid *getProcAddress); GLAPI void APIENTRY glVDPAUFiniNV (void); GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterVideoSurfaceNV (GLvoid *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterOutputSurfaceNV (GLvoid *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); GLAPI void APIENTRY glVDPAUIsSurfaceNV (GLvdpauSurfaceNV surface); GLAPI void APIENTRY glVDPAUUnregisterSurfaceNV (GLvdpauSurfaceNV surface); GLAPI void APIENTRY glVDPAUGetSurfaceivNV (GLvdpauSurfaceNV surface, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); GLAPI void APIENTRY glVDPAUSurfaceAccessNV (GLvdpauSurfaceNV surface, GLenum access); GLAPI void APIENTRY glVDPAUMapSurfacesNV (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces); GLAPI void APIENTRY glVDPAUUnmapSurfacesNV (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLVDPAUINITNVPROC) (const GLvoid *vdpDevice, const GLvoid *getProcAddress); typedef void (APIENTRYP PFNGLVDPAUFININVPROC) (void); typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTERVIDEOSURFACENVPROC) (GLvoid *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC) (GLvoid *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); typedef void (APIENTRYP PFNGLVDPAUISSURFACENVPROC) (GLvdpauSurfaceNV surface); typedef void (APIENTRYP PFNGLVDPAUUNREGISTERSURFACENVPROC) (GLvdpauSurfaceNV surface); typedef void (APIENTRYP PFNGLVDPAUGETSURFACEIVNVPROC) (GLvdpauSurfaceNV surface, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); typedef void (APIENTRYP PFNGLVDPAUSURFACEACCESSNVPROC) (GLvdpauSurfaceNV surface, GLenum access); typedef void (APIENTRYP PFNGLVDPAUMAPSURFACESNVPROC) (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces); typedef void (APIENTRYP PFNGLVDPAUUNMAPSURFACESNVPROC) (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces); #endif #ifndef GL_AMD_transform_feedback3_lines_triangles #define GL_AMD_transform_feedback3_lines_triangles 1 #endif #ifndef GL_AMD_depth_clamp_separate #define GL_AMD_depth_clamp_separate 1 #endif #ifndef GL_EXT_texture_sRGB_decode #define GL_EXT_texture_sRGB_decode 1 #endif #ifndef GL_NV_texture_multisample #define GL_NV_texture_multisample 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTexImage2DMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); GLAPI void APIENTRY glTexImage3DMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); GLAPI void APIENTRY glTextureImage2DMultisampleNV (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); GLAPI void APIENTRY glTextureImage3DMultisampleNV (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); GLAPI void APIENTRY glTextureImage2DMultisampleCoverageNV (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); GLAPI void APIENTRY glTextureImage3DMultisampleCoverageNV (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DMULTISAMPLENVPROC) (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DMULTISAMPLENVPROC) (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DMULTISAMPLECOVERAGENVPROC) (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DMULTISAMPLECOVERAGENVPROC) (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); #endif #ifndef GL_AMD_blend_minmax_factor #define GL_AMD_blend_minmax_factor 1 #endif #ifndef GL_AMD_sample_positions #define GL_AMD_sample_positions 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSetMultisamplefvAMD (GLenum pname, GLuint index, const GLfloat *val); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLSETMULTISAMPLEFVAMDPROC) (GLenum pname, GLuint index, const GLfloat *val); #endif #ifndef GL_EXT_x11_sync_object #define GL_EXT_x11_sync_object 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI GLsync APIENTRY glImportSyncEXT (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags); #endif /* GL_GLEXT_PROTOTYPES */ typedef GLsync (APIENTRYP PFNGLIMPORTSYNCEXTPROC) (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags); #endif #ifndef GL_AMD_multi_draw_indirect #define GL_AMD_multi_draw_indirect 1 #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMultiDrawArraysIndirectAMD (GLenum mode, const GLvoid *indirect, GLsizei primcount, GLsizei stride); GLAPI void APIENTRY glMultiDrawElementsIndirectAMD (GLenum mode, GLenum type, const GLvoid *indirect, GLsizei primcount, GLsizei stride); #endif /* GL_GLEXT_PROTOTYPES */ typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC) (GLenum mode, const GLvoid *indirect, GLsizei primcount, GLsizei stride); typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC) (GLenum mode, GLenum type, const GLvoid *indirect, GLsizei primcount, GLsizei stride); #endif #ifndef GL_EXT_framebuffer_multisample_blit_scaled #define GL_EXT_framebuffer_multisample_blit_scaled 1 #endif #ifdef __cplusplus } #endif #endif yabause-0.9.15/src/m68kcore.c000644 001750 001750 00000007100 12755623101 017642 0ustar00guillaumeguillaume000000 000000 /* Copyright 2007 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file m68kcore.c \brief 68000 Dummy interface. */ #include "m68kcore.h" #include "m68kc68k.h" #include "memory.h" extern u8 * SoundRam; M68K_struct * M68K = NULL; extern M68K_struct * M68KCoreList[]; int M68KInit(int coreid) { int i; M68K = &M68KDummy; // Go through core list and find the id for (i = 0; M68KCoreList[i] != NULL; i++) { if (M68KCoreList[i]->id == coreid) { // Set to current core M68K = M68KCoreList[i]; break; } } return 0; } static int M68KDummyInit(void) { return 0; } static void M68KDummyDeInit(void) { } static void M68KDummyReset(void) { } static s32 FASTCALL M68KDummyExec(UNUSED s32 cycle) { T2WriteWord(SoundRam, 0x700, 0); T2WriteWord(SoundRam, 0x710, 0); T2WriteWord(SoundRam, 0x720, 0); T2WriteWord(SoundRam, 0x730, 0); T2WriteWord(SoundRam, 0x740, 0); T2WriteWord(SoundRam, 0x750, 0); T2WriteWord(SoundRam, 0x760, 0); T2WriteWord(SoundRam, 0x770, 0); T2WriteWord(SoundRam, 0x790, 0); T2WriteWord(SoundRam, 0x792, 0); return 0; } static void M68KDummySync(void) { } static u32 M68KDummyGetDReg(UNUSED u32 num) { return 0; } static u32 M68KDummyGetAReg(UNUSED u32 num) { return 0; } static u32 M68KDummyGetPC(void) { return 0; } static u32 M68KDummyGetSR(void) { return 0; } static u32 M68KDummyGetUSP(void) { return 0; } static u32 M68KDummyGetMSP(void) { return 0; } static void M68KDummySetDReg(UNUSED u32 num, UNUSED u32 val) { } static void M68KDummySetAReg(UNUSED u32 num, UNUSED u32 val) { } static void M68KDummySetPC(UNUSED u32 val) { } static void M68KDummySetSR(UNUSED u32 val) { } static void M68KDummySetUSP(UNUSED u32 val) { } static void M68KDummySetMSP(UNUSED u32 val) { } static void M68KDummySetFetch(UNUSED u32 low_adr, UNUSED u32 high_adr, UNUSED pointer fetch_adr) { } static void FASTCALL M68KDummySetIRQ(UNUSED s32 level) { } static void FASTCALL M68KDummyWriteNotify(u32 address, u32 size) { } static void M68KDummySetReadB(UNUSED M68K_READ *Func) { } static void M68KDummySetReadW(UNUSED M68K_READ *Func) { } static void M68KDummySetWriteB(UNUSED M68K_WRITE *Func) { } static void M68KDummySetWriteW(UNUSED M68K_WRITE *Func) { } static void M68KDummySaveState(UNUSED FILE *fp) { } static void M68KDummyLoadState(UNUSED FILE *fp) { } M68K_struct M68KDummy = { 0, "Dummy 68k Interface", M68KDummyInit, M68KDummyDeInit, M68KDummyReset, M68KDummyExec, M68KDummySync, M68KDummyGetDReg, M68KDummyGetAReg, M68KDummyGetPC, M68KDummyGetSR, M68KDummyGetUSP, M68KDummyGetMSP, M68KDummySetDReg, M68KDummySetAReg, M68KDummySetPC, M68KDummySetSR, M68KDummySetUSP, M68KDummySetMSP, M68KDummySetFetch, M68KDummySetIRQ, M68KDummyWriteNotify, M68KDummySetReadB, M68KDummySetReadW, M68KDummySetWriteB, M68KDummySetWriteW, M68KDummySaveState, M68KDummyLoadState }; yabause-0.9.15/src/logo.ico000644 001750 001750 00000004276 12755623101 017507 0ustar00guillaumeguillaume000000 000000  ¨( @HHÿÿÿ'F·ìëÍÂʳ¬°8#)Œ„çØÜ´­¯seh)SACbQS¥“•ˆ|}š*& TAAo^^p__€qqŽ˜ŒŒÑËËÔÏÏãßßÓÏÏñïï  %83y Ou z +8k ~  T A ‚I Q „/ > RT5B*8"!UBAz 6 0 ‰!‹%l ’-%€,%™7.H7W N¢B9A9<§[T¾„€€rq›h)#¨JA«NE[,'L%!²XNµZP†E>]0+N)%}a^êÈĪ Ÿ½f[ÅodŽPHxE>ÇtiÏ}q؉}Þ©¢¸°¯Í€sÖ‡z¤i_Ûà“†Ü‘„³ukØƒèž‘Þ˜í¦™ä·°ÆÀ¿åšŒâ˜ŠæœŽî¦˜ð©›ö°¡ù´¥ÿ¼­ýþþüýþõ÷ûúûýæê÷óõûñóùùúý1†2‰/„-| <¡9™#A­$B¯#@ª'F¶&D³(G·%@¤(F°,Kº-L¼)E«-K¹.L¹*E§0Nº&<‹6T½8UÀ9U½:W½8Sµ=Y¾5M¥A^Ç?[¿B]À4I”E`ÁXsÒSlÆI^ªVnÇLa«ZrÈe{Ìo†ÛrŠßlÎr†ÐyŽÛvŠÒiz¸‚”Õ‡˜×ˆ™×|‹ÂžÙ‘¡Ú•¤Ûz‡³¨·í«ÝŒ—¼¡­×¬¸ã²½å¨²ÓºÄè¼ÅäÂËêÅÎìÐ×ïÒÙðÕÛñÖÜñÖÚèâæôëîùñóúíïö#>¦)G¸2/KµNhÎKdÃSmÒ|‘âVcš|ŽÔ—¥Ü˜¦Ý¦²à©µãž¦Ç½Æé¹ÁßÎÖöÄËéÊÑí²¸ÑÏÕîÃÉàÌÒêÑÖêÙÞòßãôàäõÛßîøùý÷øüÈÍäîðùõöüäåíÂÃß¿¿Ìûûþþþÿ!{((=>=9F{þ‡õ VuUS@'{þÖÏ彸··¸¾äûˆÅ± š«¸Åð‡þ„篤ª§¢­áÏŠîÆÆì×ɤ§¸ÈÎÐñÒíêɾ³¤§ÍጎÚàÓÒªšºÐ‹ mzd ÷â±Â¿‘”Ø‘Žà×…¼—Àö&%prtxcų́“——•–‘숴ٱÕs|~|]ǘ£©©¢—”ŒÃò³—Àw€yb{ÇŸ®ß¶Üš“Ãó´ã]‚h̨®éÄÞ›’æøÁžáþ{u€‚ƒ‚yT»¦¹µ©—¬ôýËÝ­ó#Bi|‚q찜ۙ¬Ê…þˆ¼žÀþ]psw€wsa￲°»è†„ýÑ·¥Ë{Uklsvu}sljOŠÔÔø…õ‰Í´­ë#BYfjkaTokj`A!þþ„ýÖþöϸË@[_f`AC\gf_QC…ýöÖþ‡Ñ{LR[^?e!Dh^[SGXýýõÖ=KMRPCNZRMJA!…ý…‹‰W 1:IKL"#AYMKI6ù…„……n24:H<‰ˆ…e;IH:E0 öý…#A-,/35A#ѼÂÉÐ873/-Aúý*,,,.0‰òÐçäåü$D2,,,*n)+++++C……þ„ý†ø +++++)n#A!þ„ $$$A#!{{{{{{{{  {{{{{{{{!yabause-0.9.15/src/vdp2.c000644 001750 001750 00000073471 12755623101 017075 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2005 Guillaume Duhamel Copyright 2004-2007 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file vdp2.c \brief VDP2 emulation functions */ #include #include "vdp2.h" #include "debug.h" #include "peripheral.h" #include "scu.h" #include "sh2core.h" #include "smpc.h" #include "vdp1.h" #include "yabause.h" #include "movie.h" #include "osdcore.h" u8 * Vdp2Ram; u8 * Vdp2ColorRam; Vdp2 * Vdp2Regs; Vdp2Internal_struct Vdp2Internal; Vdp2External_struct Vdp2External; struct CellScrollData cell_scroll_data[270]; Vdp2 Vdp2Lines[270]; static int autoframeskipenab=0; static int throttlespeed=0; u64 lastticks=0; static int fps; int vdp2_is_odd_frame = 0; ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL Vdp2RamReadByte(u32 addr) { addr &= 0x7FFFF; return T1ReadByte(Vdp2Ram, addr); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL Vdp2RamReadWord(u32 addr) { addr &= 0x7FFFF; return T1ReadWord(Vdp2Ram, addr); } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL Vdp2RamReadLong(u32 addr) { addr &= 0x7FFFF; return T1ReadLong(Vdp2Ram, addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp2RamWriteByte(u32 addr, u8 val) { addr &= 0x7FFFF; T1WriteByte(Vdp2Ram, addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp2RamWriteWord(u32 addr, u16 val) { addr &= 0x7FFFF; T1WriteWord(Vdp2Ram, addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp2RamWriteLong(u32 addr, u32 val) { addr &= 0x7FFFF; T1WriteLong(Vdp2Ram, addr, val); } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL Vdp2ColorRamReadByte(u32 addr) { addr &= 0xFFF; return T2ReadByte(Vdp2ColorRam, addr); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL Vdp2ColorRamReadWord(u32 addr) { addr &= 0xFFF; return T2ReadWord(Vdp2ColorRam, addr); } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL Vdp2ColorRamReadLong(u32 addr) { addr &= 0xFFF; return T2ReadLong(Vdp2ColorRam, addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp2ColorRamWriteByte(u32 addr, u8 val) { addr &= 0xFFF; T2WriteByte(Vdp2ColorRam, addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp2ColorRamWriteWord(u32 addr, u16 val) { addr &= 0xFFF; T2WriteWord(Vdp2ColorRam, addr, val); // if (Vdp2Internal.ColorMode == 0) // T1WriteWord(Vdp2ColorRam, addr + 0x800, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp2ColorRamWriteLong(u32 addr, u32 val) { addr &= 0xFFF; T2WriteLong(Vdp2ColorRam, addr, val); } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL Sh2Vdp2RamReadByte(SH2_struct *sh, u32 addr) { return Vdp2RamReadByte(addr); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL Sh2Vdp2RamReadWord(SH2_struct *sh, u32 addr) { return Vdp2RamReadWord(addr); } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL Sh2Vdp2RamReadLong(SH2_struct *sh, u32 addr) { return Vdp2RamReadLong(addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2Vdp2RamWriteByte(SH2_struct *sh, u32 addr, u8 val) { Vdp2RamWriteByte(addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2Vdp2RamWriteWord(SH2_struct *sh, u32 addr, u16 val) { Vdp2RamWriteWord(addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2Vdp2RamWriteLong(SH2_struct *sh, u32 addr, u32 val) { Vdp2RamWriteLong(addr, val); } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL Sh2Vdp2ColorRamReadByte(SH2_struct *sh, u32 addr) { return Vdp2ColorRamReadByte(addr); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL Sh2Vdp2ColorRamReadWord(SH2_struct *sh, u32 addr) { return Vdp2ColorRamReadWord(addr); } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL Sh2Vdp2ColorRamReadLong(SH2_struct *sh, u32 addr) { return Vdp2ColorRamReadLong(addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2Vdp2ColorRamWriteByte(SH2_struct *sh, u32 addr, u8 val) { Vdp2ColorRamWriteByte(addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2Vdp2ColorRamWriteWord(SH2_struct *sh, u32 addr, u16 val) { Vdp2ColorRamWriteWord(addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2Vdp2ColorRamWriteLong(SH2_struct *sh, u32 addr, u32 val) { Vdp2ColorRamWriteLong(addr, val); } ////////////////////////////////////////////////////////////////////////////// int Vdp2Init(void) { if ((Vdp2Regs = (Vdp2 *) calloc(1, sizeof(Vdp2))) == NULL) return -1; if ((Vdp2Ram = T1MemoryInit(0x80000)) == NULL) return -1; if ((Vdp2ColorRam = T2MemoryInit(0x1000)) == NULL) return -1; Vdp2Reset(); return 0; } ////////////////////////////////////////////////////////////////////////////// void Vdp2DeInit(void) { if (Vdp2Regs) free(Vdp2Regs); Vdp2Regs = NULL; if (Vdp2Ram) T1MemoryDeInit(Vdp2Ram); Vdp2Ram = NULL; if (Vdp2ColorRam) T2MemoryDeInit(Vdp2ColorRam); Vdp2ColorRam = NULL; } ////////////////////////////////////////////////////////////////////////////// void Vdp2Reset(void) { Vdp2Regs->TVMD = 0x0000; Vdp2Regs->EXTEN = 0x0000; Vdp2Regs->TVSTAT = Vdp2Regs->TVSTAT & 0x1; Vdp2Regs->VRSIZE = 0x0000; // fix me(version should be set) Vdp2Regs->RAMCTL = 0x0000; Vdp2Regs->BGON = 0x0000; Vdp2Regs->CHCTLA = 0x0000; Vdp2Regs->CHCTLB = 0x0000; Vdp2Regs->BMPNA = 0x0000; Vdp2Regs->MPOFN = 0x0000; Vdp2Regs->MPABN2 = 0x0000; Vdp2Regs->MPCDN2 = 0x0000; Vdp2Regs->SCXIN0 = 0x0000; Vdp2Regs->SCXDN0 = 0x0000; Vdp2Regs->SCYIN0 = 0x0000; Vdp2Regs->SCYDN0 = 0x0000; Vdp2Regs->ZMXN0.all = 0x00000000; Vdp2Regs->ZMYN0.all = 0x00000000; Vdp2Regs->SCXIN1 = 0x0000; Vdp2Regs->SCXDN1 = 0x0000; Vdp2Regs->SCYIN1 = 0x0000; Vdp2Regs->SCYDN1 = 0x0000; Vdp2Regs->ZMXN1.all = 0x00000000; Vdp2Regs->ZMYN1.all = 0x00000000; Vdp2Regs->SCXN2 = 0x0000; Vdp2Regs->SCYN2 = 0x0000; Vdp2Regs->SCXN3 = 0x0000; Vdp2Regs->SCYN3 = 0x0000; Vdp2Regs->ZMCTL = 0x0000; Vdp2Regs->SCRCTL = 0x0000; Vdp2Regs->VCSTA.all = 0x00000000; Vdp2Regs->BKTAU = 0x0000; Vdp2Regs->BKTAL = 0x0000; Vdp2Regs->RPMD = 0x0000; Vdp2Regs->RPRCTL = 0x0000; Vdp2Regs->KTCTL = 0x0000; Vdp2Regs->KTAOF = 0x0000; Vdp2Regs->OVPNRA = 0x0000; Vdp2Regs->OVPNRB = 0x0000; Vdp2Regs->WPSX0 = 0x0000; Vdp2Regs->WPSY0 = 0x0000; Vdp2Regs->WPEX0 = 0x0000; Vdp2Regs->WPEY0 = 0x0000; Vdp2Regs->WPSX1 = 0x0000; Vdp2Regs->WPSY1 = 0x0000; Vdp2Regs->WPEX1 = 0x0000; Vdp2Regs->WPEY1 = 0x0000; Vdp2Regs->WCTLA = 0x0000; Vdp2Regs->WCTLB = 0x0000; Vdp2Regs->WCTLC = 0x0000; Vdp2Regs->WCTLD = 0x0000; Vdp2Regs->SPCTL = 0x0000; Vdp2Regs->SDCTL = 0x0000; Vdp2Regs->CRAOFA = 0x0000; Vdp2Regs->CRAOFB = 0x0000; Vdp2Regs->LNCLEN = 0x0000; Vdp2Regs->SFPRMD = 0x0000; Vdp2Regs->CCCTL = 0x0000; Vdp2Regs->SFCCMD = 0x0000; Vdp2Regs->PRISA = 0x0000; Vdp2Regs->PRISB = 0x0000; Vdp2Regs->PRISC = 0x0000; Vdp2Regs->PRISD = 0x0000; Vdp2Regs->PRINA = 0x0000; Vdp2Regs->PRINB = 0x0000; Vdp2Regs->PRIR = 0x0000; Vdp2Regs->CCRNA = 0x0000; Vdp2Regs->CCRNB = 0x0000; Vdp2Regs->CLOFEN = 0x0000; Vdp2Regs->CLOFSL = 0x0000; Vdp2Regs->COAR = 0x0000; Vdp2Regs->COAG = 0x0000; Vdp2Regs->COAB = 0x0000; Vdp2Regs->COBR = 0x0000; Vdp2Regs->COBG = 0x0000; Vdp2Regs->COBB = 0x0000; yabsys.VBlankLineCount = 225; Vdp2Internal.ColorMode = 0; Vdp2External.disptoggle = 0xFF; } ////////////////////////////////////////////////////////////////////////////// void Vdp2VBlankIN(void) { VIDCore->Vdp2DrawEnd(); /* this should be done after a frame change or a plot trigger */ Vdp1Regs->COPR = 0; /* I'm not 100% sure about this, but it seems that when using manual change we should swap framebuffers in the "next field" and thus, clear the CEF... now we're lying a little here as we're not swapping the framebuffers. */ if (Vdp1External.manualchange) Vdp1Regs->EDSR >>= 1; Vdp2Regs->TVSTAT |= 0x0008; ScuSendVBlankIN(); if (yabsys.IsSSH2Running) SH2SendInterrupt(SSH2, 0x43, 0x6); } ////////////////////////////////////////////////////////////////////////////// void Vdp2HBlankIN(void) { Vdp2Regs->TVSTAT |= 0x0004; ScuSendHBlankIN(); if (yabsys.IsSSH2Running) SH2SendInterrupt(SSH2, 0x41, 0x2); } ////////////////////////////////////////////////////////////////////////////// void Vdp2HBlankOUT(void) { int i; Vdp2Regs->TVSTAT &= ~0x0004; if (yabsys.LineCount < 270) { u32 cell_scroll_table_start_addr = (Vdp2Regs->VCSTA.all & 0x7FFFE) << 1; memcpy(Vdp2Lines + yabsys.LineCount, Vdp2Regs, sizeof(Vdp2)); for (i = 0; i < 88; i++) { cell_scroll_data[yabsys.LineCount].data[i] = T1ReadLong(Vdp2Ram, cell_scroll_table_start_addr + i * 4); } } } ////////////////////////////////////////////////////////////////////////////// Vdp2 * Vdp2RestoreRegs(int line, Vdp2* lines) { return line > 270 ? NULL : lines + line; } ////////////////////////////////////////////////////////////////////////////// static void FPSDisplay(void) { static int fpsframecount = 0; static u64 fpsticks; OSDPushMessage(OSDMSG_FPS, 1, "%02d/%02d FPS", fps, yabsys.IsPal ? 50 : 60); OSDPushMessage(OSDMSG_DEBUG, 1, "%d %d %s %s", framecounter, lagframecounter, MovieStatus, InputDisplayString); fpsframecount++; if(YabauseGetTicks() >= fpsticks + yabsys.tickfreq) { fps = fpsframecount; fpsframecount = 0; fpsticks = YabauseGetTicks(); } } ////////////////////////////////////////////////////////////////////////////// void SpeedThrottleEnable(void) { throttlespeed = 1; } ////////////////////////////////////////////////////////////////////////////// void SpeedThrottleDisable(void) { throttlespeed = 0; } ////////////////////////////////////////////////////////////////////////////// void Vdp2VBlankOUT(void) { static int framestoskip = 0; static int framesskipped = 0; static int skipnextframe = 0; static u64 curticks = 0; static u64 diffticks = 0; static u32 framecount = 0; static u64 onesecondticks = 0; static VideoInterface_struct * saved = NULL; if (vdp2_is_odd_frame) vdp2_is_odd_frame = 0; else vdp2_is_odd_frame = 1; Vdp2Regs->TVSTAT = ((Vdp2Regs->TVSTAT & ~0x0008) & ~0x0002) | (vdp2_is_odd_frame << 1); if (skipnextframe && (! saved)) { saved = VIDCore; VIDCore = &VIDDummy; } else if (saved && (! skipnextframe)) { VIDCore = saved; saved = NULL; } VIDCore->Vdp2DrawStart(); if (Vdp2Regs->TVMD & 0x8000) { VIDCore->Vdp2DrawScreens(); if (Vdp1Regs->PTMR == 2) Vdp1Draw(); } else { VIDCore->Vdp2DispOff(); if (Vdp1Regs->PTMR == 2) Vdp1Draw(); } FPSDisplay(); if ((Vdp1Regs->FBCR & 2) && (Vdp1Regs->TVMR & 8)) Vdp1External.manualerase = 1; if (!skipnextframe) { framesskipped = 0; if (framestoskip > 0) skipnextframe = 1; } else { framestoskip--; if (framestoskip < 1) skipnextframe = 0; else skipnextframe = 1; framesskipped++; } // Do Frame Skip/Frame Limiting/Speed Throttling here if (throttlespeed) { // Should really depend on how fast we're rendering the frames if (framestoskip < 1) framestoskip = 6; } //when in frame advance, disable frame skipping else if (autoframeskipenab && FrameAdvanceVariable == 0) { framecount++; if (framecount > (yabsys.IsPal ? 50 : 60)) { framecount = 1; onesecondticks = 0; } curticks = YabauseGetTicks(); diffticks = curticks-lastticks; if ((onesecondticks+diffticks) > ((yabsys.OneFrameTime * (u64)framecount) + (yabsys.OneFrameTime / 2)) && framesskipped < 9) { // Skip the next frame skipnextframe = 1; // How many frames should we skip? framestoskip = 1; } else if ((onesecondticks+diffticks) < ((yabsys.OneFrameTime * (u64)framecount) - (yabsys.OneFrameTime / 2))) { // Check to see if we need to limit speed at all for (;;) { curticks = YabauseGetTicks(); diffticks = curticks-lastticks; if ((onesecondticks+diffticks) >= (yabsys.OneFrameTime * (u64)framecount)) break; } } onesecondticks += diffticks; lastticks = curticks; } ScuSendVBlankOUT(); if (Vdp2Regs->EXTEN & 0x200) // Should be revised for accuracy(should occur only occur on the line it happens at, etc.) { // Only Latch if EXLTEN is enabled if (SmpcRegs->EXLE & 0x1) Vdp2SendExternalLatch((PORTDATA1.data[3]<<8)|PORTDATA1.data[4], (PORTDATA1.data[5]<<8)|PORTDATA1.data[6]); } } ////////////////////////////////////////////////////////////////////////////// void Vdp2SendExternalLatch(int hcnt, int vcnt) { Vdp2Regs->HCNT = hcnt << 1; Vdp2Regs->VCNT = vcnt; Vdp2Regs->TVSTAT |= 0x200; } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL Vdp2ReadByte(u32 addr) { LOG("VDP2 register byte read = %08X\n", addr); addr &= 0x1FF; return 0; } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL Vdp2ReadWord(u32 addr) { addr &= 0x1FF; switch (addr) { case 0x000: return Vdp2Regs->TVMD; case 0x002: if (!(Vdp2Regs->EXTEN & 0x200)) { // Latch HV counter on read // Vdp2Regs->HCNT = ?; Vdp2Regs->VCNT = yabsys.LineCount; Vdp2Regs->TVSTAT |= 0x200; } return Vdp2Regs->EXTEN; case 0x004: { u16 tvstat = Vdp2Regs->TVSTAT; // Clear External latch and sync flags Vdp2Regs->TVSTAT &= 0xFCFF; // if TVMD's DISP bit is cleared, TVSTAT's VBLANK bit is always set if (Vdp2Regs->TVMD & 0x8000) return tvstat; else return (tvstat | 0x8); } case 0x006: return Vdp2Regs->VRSIZE; case 0x008: return Vdp2Regs->HCNT; case 0x00A: return Vdp2Regs->VCNT; default: { LOG("Unhandled VDP2 word read: %08X\n", addr); break; } } return 0; } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL Vdp2ReadLong(u32 addr) { LOG("VDP2 register long read = %08X\n", addr); addr &= 0x1FF; return 0; } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp2WriteByte(u32 addr, UNUSED u8 val) { LOG("VDP2 register byte write = %08X\n", addr); addr &= 0x1FF; } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp2WriteWord(u32 addr, u16 val) { addr &= 0x1FF; switch (addr) { case 0x000: Vdp2Regs->TVMD = val; yabsys.VBlankLineCount = 225+(val & 0x30); return; case 0x002: Vdp2Regs->EXTEN = val; return; case 0x004: // TVSTAT is read-only return; case 0x006: Vdp2Regs->VRSIZE = val; return; case 0x008: // HCNT is read-only return; case 0x00A: // VCNT is read-only return; case 0x00C: // Reserved return; case 0x00E: Vdp2Regs->RAMCTL = val; Vdp2Internal.ColorMode = (val >> 12) & 0x3; return; case 0x010: Vdp2Regs->CYCA0L = val; return; case 0x012: Vdp2Regs->CYCA0U = val; return; case 0x014: Vdp2Regs->CYCA1L = val; return; case 0x016: Vdp2Regs->CYCA1U = val; return; case 0x018: Vdp2Regs->CYCB0L = val; return; case 0x01A: Vdp2Regs->CYCB0U = val; return; case 0x01C: Vdp2Regs->CYCB1L = val; return; case 0x01E: Vdp2Regs->CYCB1U = val; return; case 0x020: Vdp2Regs->BGON = val; return; case 0x022: Vdp2Regs->MZCTL = val; return; case 0x024: Vdp2Regs->SFSEL = val; return; case 0x026: Vdp2Regs->SFCODE = val; return; case 0x028: Vdp2Regs->CHCTLA = val; return; case 0x02A: Vdp2Regs->CHCTLB = val; return; case 0x02C: Vdp2Regs->BMPNA = val; return; case 0x02E: Vdp2Regs->BMPNB = val; return; case 0x030: Vdp2Regs->PNCN0 = val; return; case 0x032: Vdp2Regs->PNCN1 = val; return; case 0x034: Vdp2Regs->PNCN2 = val; return; case 0x036: Vdp2Regs->PNCN3 = val; return; case 0x038: Vdp2Regs->PNCR = val; return; case 0x03A: Vdp2Regs->PLSZ = val; return; case 0x03C: Vdp2Regs->MPOFN = val; return; case 0x03E: Vdp2Regs->MPOFR = val; return; case 0x040: Vdp2Regs->MPABN0 = val; return; case 0x042: Vdp2Regs->MPCDN0 = val; return; case 0x044: Vdp2Regs->MPABN1 = val; return; case 0x046: Vdp2Regs->MPCDN1 = val; return; case 0x048: Vdp2Regs->MPABN2 = val; return; case 0x04A: Vdp2Regs->MPCDN2 = val; return; case 0x04C: Vdp2Regs->MPABN3 = val; return; case 0x04E: Vdp2Regs->MPCDN3 = val; return; case 0x050: Vdp2Regs->MPABRA = val; return; case 0x052: Vdp2Regs->MPCDRA = val; return; case 0x054: Vdp2Regs->MPEFRA = val; return; case 0x056: Vdp2Regs->MPGHRA = val; return; case 0x058: Vdp2Regs->MPIJRA = val; return; case 0x05A: Vdp2Regs->MPKLRA = val; return; case 0x05C: Vdp2Regs->MPMNRA = val; return; case 0x05E: Vdp2Regs->MPOPRA = val; return; case 0x060: Vdp2Regs->MPABRB = val; return; case 0x062: Vdp2Regs->MPCDRB = val; return; case 0x064: Vdp2Regs->MPEFRB = val; return; case 0x066: Vdp2Regs->MPGHRB = val; return; case 0x068: Vdp2Regs->MPIJRB = val; return; case 0x06A: Vdp2Regs->MPKLRB = val; return; case 0x06C: Vdp2Regs->MPMNRB = val; return; case 0x06E: Vdp2Regs->MPOPRB = val; return; case 0x070: Vdp2Regs->SCXIN0 = val; return; case 0x072: Vdp2Regs->SCXDN0 = val; return; case 0x074: Vdp2Regs->SCYIN0 = val; return; case 0x076: Vdp2Regs->SCYDN0 = val; return; case 0x078: Vdp2Regs->ZMXN0.part.I = val; return; case 0x07A: Vdp2Regs->ZMXN0.part.D = val; return; case 0x07C: Vdp2Regs->ZMYN0.part.I = val; return; case 0x07E: Vdp2Regs->ZMYN0.part.D = val; return; case 0x080: Vdp2Regs->SCXIN1 = val; return; case 0x082: Vdp2Regs->SCXDN1 = val; return; case 0x084: Vdp2Regs->SCYIN1 = val; return; case 0x086: Vdp2Regs->SCYDN1 = val; return; case 0x088: Vdp2Regs->ZMXN1.part.I = val; return; case 0x08A: Vdp2Regs->ZMXN1.part.D = val; return; case 0x08C: Vdp2Regs->ZMYN1.part.I = val; return; case 0x08E: Vdp2Regs->ZMYN1.part.D = val; return; case 0x090: Vdp2Regs->SCXN2 = val; return; case 0x092: Vdp2Regs->SCYN2 = val; return; case 0x094: Vdp2Regs->SCXN3 = val; return; case 0x096: Vdp2Regs->SCYN3 = val; return; case 0x098: Vdp2Regs->ZMCTL = val; return; case 0x09A: Vdp2Regs->SCRCTL = val; return; case 0x09C: Vdp2Regs->VCSTA.part.U = val; return; case 0x09E: Vdp2Regs->VCSTA.part.L = val; return; case 0x0A0: Vdp2Regs->LSTA0.part.U = val; return; case 0x0A2: Vdp2Regs->LSTA0.part.L = val; return; case 0x0A4: Vdp2Regs->LSTA1.part.U = val; return; case 0x0A6: Vdp2Regs->LSTA1.part.L = val; return; case 0x0A8: Vdp2Regs->LCTA.part.U = val; return; case 0x0AA: Vdp2Regs->LCTA.part.L = val; return; case 0x0AC: Vdp2Regs->BKTAU = val; return; case 0x0AE: Vdp2Regs->BKTAL = val; return; case 0x0B0: Vdp2Regs->RPMD = val; return; case 0x0B2: Vdp2Regs->RPRCTL = val; return; case 0x0B4: Vdp2Regs->KTCTL = val; return; case 0x0B6: Vdp2Regs->KTAOF = val; return; case 0x0B8: Vdp2Regs->OVPNRA = val; return; case 0x0BA: Vdp2Regs->OVPNRB = val; return; case 0x0BC: Vdp2Regs->RPTA.part.U = val; return; case 0x0BE: Vdp2Regs->RPTA.part.L = val; return; case 0x0C0: Vdp2Regs->WPSX0 = val; return; case 0x0C2: Vdp2Regs->WPSY0 = val; return; case 0x0C4: Vdp2Regs->WPEX0 = val; return; case 0x0C6: Vdp2Regs->WPEY0 = val; return; case 0x0C8: Vdp2Regs->WPSX1 = val; return; case 0x0CA: Vdp2Regs->WPSY1 = val; return; case 0x0CC: Vdp2Regs->WPEX1 = val; return; case 0x0CE: Vdp2Regs->WPEY1 = val; return; case 0x0D0: Vdp2Regs->WCTLA = val; return; case 0x0D2: Vdp2Regs->WCTLB = val; return; case 0x0D4: Vdp2Regs->WCTLC = val; return; case 0x0D6: Vdp2Regs->WCTLD = val; return; case 0x0D8: Vdp2Regs->LWTA0.part.U = val; return; case 0x0DA: Vdp2Regs->LWTA0.part.L = val; return; case 0x0DC: Vdp2Regs->LWTA1.part.U = val; return; case 0x0DE: Vdp2Regs->LWTA1.part.L = val; return; case 0x0E0: Vdp2Regs->SPCTL = val; return; case 0x0E2: Vdp2Regs->SDCTL = val; return; case 0x0E4: Vdp2Regs->CRAOFA = val; return; case 0x0E6: Vdp2Regs->CRAOFB = val; return; case 0x0E8: Vdp2Regs->LNCLEN = val; return; case 0x0EA: Vdp2Regs->SFPRMD = val; return; case 0x0EC: Vdp2Regs->CCCTL = val; return; case 0x0EE: Vdp2Regs->SFCCMD = val; return; case 0x0F0: Vdp2Regs->PRISA = val; return; case 0x0F2: Vdp2Regs->PRISB = val; return; case 0x0F4: Vdp2Regs->PRISC = val; return; case 0x0F6: Vdp2Regs->PRISD = val; return; case 0x0F8: Vdp2Regs->PRINA = val; return; case 0x0FA: Vdp2Regs->PRINB = val; return; case 0x0FC: Vdp2Regs->PRIR = val; return; case 0x0FE: // Reserved return; case 0x100: Vdp2Regs->CCRSA = val; return; case 0x102: Vdp2Regs->CCRSB = val; return; case 0x104: Vdp2Regs->CCRSC = val; return; case 0x106: Vdp2Regs->CCRSD = val; return; case 0x108: Vdp2Regs->CCRNA = val; return; case 0x10A: Vdp2Regs->CCRNB = val; return; case 0x10C: Vdp2Regs->CCRR = val; return; case 0x10E: Vdp2Regs->CCRLB = val; return; case 0x110: Vdp2Regs->CLOFEN = val; return; case 0x112: Vdp2Regs->CLOFSL = val; return; case 0x114: Vdp2Regs->COAR = val; return; case 0x116: Vdp2Regs->COAG = val; return; case 0x118: Vdp2Regs->COAB = val; return; case 0x11A: Vdp2Regs->COBR = val; return; case 0x11C: Vdp2Regs->COBG = val; return; case 0x11E: Vdp2Regs->COBB = val; return; default: { LOG("Unhandled VDP2 word write: %08X\n", addr); break; } } } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp2WriteLong(u32 addr, u32 val) { Vdp2WriteWord(addr,val>>16); Vdp2WriteWord(addr+2,val&0xFFFF); return; } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL Sh2Vdp2ReadByte(SH2_struct *sh, u32 addr) { return Vdp2ReadByte(addr); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL Sh2Vdp2ReadWord(SH2_struct *sh, u32 addr) { return Vdp2ReadWord(addr); } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL Sh2Vdp2ReadLong(SH2_struct *sh, u32 addr) { return Vdp2ReadLong(addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2Vdp2WriteByte(SH2_struct *sh, u32 addr, UNUSED u8 val) { Vdp2WriteByte(addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2Vdp2WriteWord(SH2_struct *sh, u32 addr, u16 val) { Vdp2WriteWord(addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2Vdp2WriteLong(SH2_struct *sh, u32 addr, u32 val) { Vdp2WriteLong(addr, val); } ////////////////////////////////////////////////////////////////////////////// int Vdp2SaveState(FILE *fp) { int offset; IOCheck_struct check = { 0, 0 }; offset = StateWriteHeader(fp, "VDP2", 1); // Write registers ywrite(&check, (void *)Vdp2Regs, sizeof(Vdp2), 1, fp); // Write VDP2 ram ywrite(&check, (void *)Vdp2Ram, 0x80000, 1, fp); // Write CRAM ywrite(&check, (void *)Vdp2ColorRam, 0x1000, 1, fp); // Write internal variables ywrite(&check, (void *)&Vdp2Internal, sizeof(Vdp2Internal_struct), 1, fp); return StateFinishHeader(fp, offset); } ////////////////////////////////////////////////////////////////////////////// int Vdp2LoadState(FILE *fp, UNUSED int version, int size) { IOCheck_struct check = { 0, 0 }; // Read registers yread(&check, (void *)Vdp2Regs, sizeof(Vdp2), 1, fp); // Read VDP2 ram yread(&check, (void *)Vdp2Ram, 0x80000, 1, fp); // Read CRAM yread(&check, (void *)Vdp2ColorRam, 0x1000, 1, fp); // Read internal variables yread(&check, (void *)&Vdp2Internal, sizeof(Vdp2Internal_struct), 1, fp); return size; } ////////////////////////////////////////////////////////////////////////////// void ToggleNBG0(void) { Vdp2External.disptoggle ^= 0x1; } ////////////////////////////////////////////////////////////////////////////// void ToggleNBG1(void) { Vdp2External.disptoggle ^= 0x2; } ////////////////////////////////////////////////////////////////////////////// void ToggleNBG2(void) { Vdp2External.disptoggle ^= 0x4; } ////////////////////////////////////////////////////////////////////////////// void ToggleNBG3(void) { Vdp2External.disptoggle ^= 0x8; } ////////////////////////////////////////////////////////////////////////////// void ToggleRBG0(void) { Vdp2External.disptoggle ^= 0x10; } ////////////////////////////////////////////////////////////////////////////// void ToggleFullScreen(void) { if (VIDCore->IsFullscreen()) { VIDCore->Resize(320, 224, 0); } else { VIDCore->Resize(640, 480, 1); } } ////////////////////////////////////////////////////////////////////////////// void EnableAutoFrameSkip(void) { autoframeskipenab = 1; lastticks = YabauseGetTicks(); } ////////////////////////////////////////////////////////////////////////////// void DisableAutoFrameSkip(void) { autoframeskipenab = 0; } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/sndwav.c000644 001750 001750 00000014151 12755623101 017512 0ustar00guillaumeguillaume000000 000000 /* Copyright 2004 Stephane Dallongeville Copyright 2004-2007 Theo Berkau Copyright 2006 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "scsp.h" ////////////////////////////////////////////////////////////////////////////// // Wave File Output Sound Interface ////////////////////////////////////////////////////////////////////////////// static int SNDWavInit(void); static void SNDWavDeInit(void); static int SNDWavReset(void); static int SNDWavChangeVideoFormat(int vertfreq); static void SNDWavUpdateAudio(u32 *leftchanbuffer, u32 *rightchanbuffer, u32 num_samples); static u32 SNDWavGetAudioSpace(void); static void SNDWavMuteAudio(void); static void SNDWavUnMuteAudio(void); static void SNDWavSetVolume(int volume); #ifdef USE_SCSPMIDI int SNDWavMidiChangePorts(int inport, int outport); u8 SNDWavMidiIn(int *isdata); int SNDWavMidiOut(u8 data); #endif SoundInterface_struct SNDWave = { SNDCORE_WAV, "Wave File Ouput Interface", SNDWavInit, SNDWavDeInit, SNDWavReset, SNDWavChangeVideoFormat, SNDWavUpdateAudio, SNDWavGetAudioSpace, SNDWavMuteAudio, SNDWavUnMuteAudio, SNDWavSetVolume, #ifdef USE_SCSPMIDI SNDWavMidiChangePorts, SNDWavMidiIn, SNDWavMidiOut #endif }; char *wavefilename=NULL; static FILE *wavefp; typedef struct { char id[4]; u32 size; } chunk_struct; typedef struct { chunk_struct riff; char rifftype[4]; } waveheader_struct; typedef struct { chunk_struct chunk; u16 compress; u16 numchan; u32 rate; u32 bytespersec; u16 blockalign; u16 bitspersample; } fmt_struct; ////////////////////////////////////////////////////////////////////////////// static int SNDWavInit(void) { waveheader_struct waveheader; fmt_struct fmt; chunk_struct data; IOCheck_struct check = { 0, 0 }; if (wavefilename) { if ((wavefp = fopen(wavefilename, "wb")) == NULL) return -1; } else { if ((wavefp = fopen("scsp.wav", "wb")) == NULL) return -1; } // Do wave header memcpy(waveheader.riff.id, "RIFF", 4); waveheader.riff.size = 0; // we'll fix this after the file is closed memcpy(waveheader.rifftype, "WAVE", 4); ywrite(&check, (void *)&waveheader, 1, sizeof(waveheader_struct), wavefp); // fmt chunk memcpy(fmt.chunk.id, "fmt ", 4); fmt.chunk.size = 16; // we'll fix this at the end fmt.compress = 1; // PCM fmt.numchan = 2; // Stereo fmt.rate = 44100; fmt.bitspersample = 16; fmt.blockalign = fmt.bitspersample / 8 * fmt.numchan; fmt.bytespersec = fmt.rate * fmt.blockalign; ywrite(&check, (void *)&fmt, 1, sizeof(fmt_struct), wavefp); // data chunk memcpy(data.id, "data", 4); data.size = 0; // we'll fix this at the end ywrite(&check, (void *)&data, 1, sizeof(chunk_struct), wavefp); return 0; } ////////////////////////////////////////////////////////////////////////////// static void SNDWavDeInit(void) { if (wavefp) { long length = ftell(wavefp); IOCheck_struct check = { 0, 0 }; // Let's fix the riff chunk size and the data chunk size fseek(wavefp, sizeof(waveheader_struct)-0x8, SEEK_SET); length -= 0x4; ywrite(&check, (void *)&length, 1, 4, wavefp); fseek(wavefp, sizeof(waveheader_struct)+sizeof(fmt_struct)+0x4, SEEK_SET); length -= sizeof(waveheader_struct)+sizeof(fmt_struct); ywrite(&check, (void *)&length, 1, 4, wavefp); fclose(wavefp); } } ////////////////////////////////////////////////////////////////////////////// static int SNDWavReset(void) { return 0; } ////////////////////////////////////////////////////////////////////////////// static int SNDWavChangeVideoFormat(UNUSED int vertfreq) { return 0; } ////////////////////////////////////////////////////////////////////////////// static void SNDWavUpdateAudio(u32 *leftchanbuffer, u32 *rightchanbuffer, u32 num_samples) { s16 stereodata16[44100 / 50]; ScspConvert32uto16s((s32 *)leftchanbuffer, (s32 *)rightchanbuffer, (s16 *)stereodata16, num_samples); fwrite((void *)stereodata16, sizeof(s16) * 2, num_samples, wavefp); } ////////////////////////////////////////////////////////////////////////////// static u32 SNDWavGetAudioSpace(void) { /* A "hack" to get sound core working enough * so videos are not "freezing". Values have been * found by experiments... I don't have a clue why * they are working ^^; */ static int i = 0; i++; if (i == 55) { i = 0; return 85; } else { return 0; } } ////////////////////////////////////////////////////////////////////////////// static void SNDWavMuteAudio(void) { } ////////////////////////////////////////////////////////////////////////////// static void SNDWavUnMuteAudio(void) { } ////////////////////////////////////////////////////////////////////////////// static void SNDWavSetVolume(UNUSED int volume) { } ////////////////////////////////////////////////////////////////////////////// #ifdef USE_SCSPMIDI int SNDWavMidiChangePorts(int inport, int outport) { return 0; } ////////////////////////////////////////////////////////////////////////////// u8 SNDWavMidiIn(int *isdata) { *isdata = 0; /* Called when SCSP wants more MIDI data. Set isdata to 1 if there's data to return */ return 0; } ////////////////////////////////////////////////////////////////////////////// int SNDWavMidiOut(u8 data) { /* Called when SCSP wants to send out MIDI data. num is the number of bytes in buffer. Return 1 if data used, or 0 if not */ return 1; } #endif yabause-0.9.15/src/scspdsp.h000644 001750 001750 00000007031 12757373537 017714 0ustar00guillaumeguillaume000000 000000 /* Copyright 2015 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SCSPDSP_H #define SCSPDSP_H #include "core.h" typedef struct { u16 coef[64]; u16 madrs[32]; u64 mpro[128]; s32 temp[128]; s32 mems[32]; s32 mixs[16]; s16 efreg[16]; s16 exts[2]; u32 mdec_ct; s32 inputs; s32 b; s32 x; s16 y; s32 acc; s32 shifted; s32 y_reg; u16 frc_reg; u16 adrs_reg; s32 mul_out; u32 mrd_value; int rbl; int rbp; int need_read; int need_nofl; u32 io_addr; int need_write; u16 write_data; }ScspDsp; //dsp instruction format //bits 63-48 //| ? | tra | twt | twa | //| F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //bits 47-32 //|xsel | ysel | ? | ira | iwt | iwa | //| F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //bits 31-16 //|table| mwt | mrd | ewt | ewa |adrl |frcl | shift | yrl |negb |zero |bsel | //| F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //bits 15-0 //|nofl | coef | ? | masa |adreb|nxadr| //| F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | #ifdef WORDS_BIGENDIAN union ScspDspInstruction { struct { u64 unknown : 1; u64 tra : 7; u64 twt : 1; u64 twa : 7; u64 xsel : 1; u64 ysel : 2; u64 unknown2 : 1; u64 ira : 6; u64 iwt : 1; u64 iwa : 5; u64 table : 1; u64 mwt : 1; u64 mrd : 1; u64 ewt : 1; u64 ewa : 4; u64 adrl : 1; u64 frcl : 1; u64 shift : 2; u64 yrl : 1; u64 negb : 1; u64 zero : 1; u64 bsel : 1; u64 nofl : 1; u64 coef : 6; u64 unknown3 : 2; u64 masa : 5; u64 adreb : 1; u64 nxadr : 1; } part; u32 all; }; #else union ScspDspInstruction { struct { u64 nxadr : 1; u64 adreb : 1; u64 masa : 5; u64 unknown3 : 2; u64 coef : 6; u64 nofl : 1; u64 bsel : 1; u64 zero : 1; u64 negb : 1; u64 yrl : 1; u64 shift : 2; u64 frcl : 1; u64 adrl : 1; u64 ewa : 4; u64 ewt : 1; u64 mrd : 1; u64 mwt : 1; u64 table : 1; u64 iwa : 5; u64 iwt : 1; u64 ira : 6; u64 unknown2 : 1; u64 ysel : 2; u64 xsel : 1; u64 twa : 7; u64 twt : 1; u64 tra : 7; u64 unknown : 1; } part; u64 all; }; #endif void ScspDspDisasm(u8 addr, char *outstring); void ScspDspExec(ScspDsp* dsp, int addr, u8 * sound_ram); extern ScspDsp scsp_dsp; #endif yabause-0.9.15/src/m68kc68k.h000644 001750 001750 00000001565 12755623101 017503 0ustar00guillaumeguillaume000000 000000 /* Copyright 2007 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef M68KC68K_H #define M68KC68K_H #include "m68kcore.h" extern M68K_struct M68KC68K; #endif yabause-0.9.15/src/scsp2.h000644 001750 001750 00000012536 12755623101 017254 0ustar00guillaumeguillaume000000 000000 /* src/scsp2.h: Header for new SCSP implementation Copyright 2010 Andrew Church This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SCSP_H // Not SCSP2_H (we substitute for the original scsp.h) #define SCSP_H #include "core.h" // For sized integer types /////////////////////////////////////////////////////////////////////////// // Module interface declaration #define SNDCORE_DEFAULT -1 #define SNDCORE_DUMMY 0 #define SNDCORE_WAV 10 // Should be 1, but left as is for backward compat #define SCSP_MUTE_SYSTEM 1 #define SCSP_MUTE_USER 2 typedef struct { int id; const char *Name; int (*Init)(void); void (*DeInit)(void); int (*Reset)(void); int (*ChangeVideoFormat)(int vertfreq); // FIXME/SCSP1: u32* should be s32* (they're signed samples) void (*UpdateAudio)(u32 *leftchanbuffer, u32 *rightchanbuffer, u32 num_samples); u32 (*GetAudioSpace)(void); void (*MuteAudio)(void); void (*UnMuteAudio)(void); void (*SetVolume)(int volume); } SoundInterface_struct; extern SoundInterface_struct SNDDummy; extern SoundInterface_struct SNDWave; /////////////////////////////////////////////////////////////////////////// // Parameter block for M68K{Get,Set}Registers() typedef struct { u32 D[8]; u32 A[8]; u32 SR; u32 PC; } M68KRegs; // Breakpoint data structure (currently just an address) typedef struct { u32 addr; } M68KBreakpointInfo; // Maximum number of M68K breakpoints that can be set simultaneously #define M68K_MAX_BREAKPOINTS 10 /////////////////////////////////////////////////////////////////////////// // Data/function declarations extern u8 *SoundRam; extern int ScspInit(int coreid, void (*interrupt_handler)(void)); extern void ScspReset(void); extern int ScspChangeSoundCore(int coreid); extern int ScspChangeVideoFormat(int type); extern void ScspSetFrameAccurate(int on); extern void ScspMuteAudio(int flags); extern void ScspUnMuteAudio(int flags); extern void ScspSetVolume(int volume); extern void ScspDeInit(void); extern void ScspExec(int decilines); extern u8 FASTCALL SoundRamReadByte(u32 address); extern u16 FASTCALL SoundRamReadWord(u32 address); extern u32 FASTCALL SoundRamReadLong(u32 address); extern void FASTCALL SoundRamWriteByte(u32 address, u8 data); extern void FASTCALL SoundRamWriteWord(u32 address, u16 data); extern void FASTCALL SoundRamWriteLong(u32 address, u32 data); extern u8 FASTCALL ScspReadByte(u32 address); extern u16 FASTCALL ScspReadWord(u32 address); extern u32 FASTCALL ScspReadLong(u32 address); extern void FASTCALL ScspWriteByte(u32 address, u8 data); extern void FASTCALL ScspWriteWord(u32 address, u16 data); extern void FASTCALL ScspWriteLong(u32 address, u32 data); extern void ScspReceiveCDDA(const u8 *sector); extern int SoundSaveState(FILE *fp); extern int SoundLoadState(FILE *fp, int version, int size); extern void ScspSlotDebugStats(u8 slotnum, char *outstring); extern void ScspCommonControlRegisterDebugStats(char *outstring); extern int ScspSlotDebugSaveRegisters(u8 slotnum, const char *filename); extern int ScspSlotDebugAudioSaveWav(u8 slotnum, const char *filename); extern void ScspConvert32uto16s(s32 *srcL, s32 *srcR, s16 *dest, u32 len); extern void M68KStart(void); extern void M68KStop(void); extern void M68KStep(void); extern void M68KWriteNotify(u32 address, u32 size); extern void M68KGetRegisters(M68KRegs *regs); extern void M68KSetRegisters(const M68KRegs *regs); extern void M68KSetBreakpointCallBack(void (*func)(u32 address)); extern int M68KAddCodeBreakpoint(u32 address); extern int M68KDelCodeBreakpoint(u32 address); extern const M68KBreakpointInfo *M68KGetBreakpointList(void); extern void M68KClearCodeBreakpoints(void); extern u32 FASTCALL M68KReadByte(u32 address); extern u32 FASTCALL M68KReadWord(u32 address); extern void FASTCALL M68KWriteByte(u32 address, u32 data); extern void FASTCALL M68KWriteWord(u32 address, u32 data); /////////////////////////////////////////////////////////////////////////// // Compatibility macros to match scsp.h interface #define m68kregs_struct M68KRegs #define m68kcodebreakpoint_struct M68KBreakpointInfo #include "scu.h" #define ScspInit(coreid) ScspInit((coreid), ScuSendSoundRequest) #define scsp_r_b ScspReadByte #define scsp_r_w ScspReadWord #define scsp_r_d ScspReadLong #define scsp_w_b ScspWriteByte #define scsp_w_w ScspWriteWord #define scsp_w_d ScspWriteLong #define c68k_word_read M68KReadWord /////////////////////////////////////////////////////////////////////////// #endif // SCSP_H /* * Local variables: * c-file-style: "stroustrup" * c-basic-offset: 3 * c-file-offsets: ((case-label . *) (statement-case-intro . *)) * indent-tabs-mode: nil * End: * * vim: expandtab shiftwidth=3: */ yabause-0.9.15/src/perdx.h000644 001750 001750 00000002657 12755623101 017347 0ustar00guillaumeguillaume000000 000000 /* Copyright 2006 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef PERDX_H #define PERDX_H #define DIRECTINPUT_VERSION 0x0800 #include #include "dx.h" #include "peripheral.h" #define PERCORE_DIRECTX 2 extern PerInterface_struct PERDIRECTX; typedef struct { LPDIRECTINPUTDEVICE8 lpDIDevice; int type; int emulatetype; #ifdef HAVE_XINPUT int is_xinput_device; int xinput_num; #endif } padconf_struct; enum XIAXIS { XI_THUMBL=1, XI_THUMBLX=1, XI_THUMBLY=5, XI_THUMBR=9, XI_THUMBRX=9, XI_THUMBRY=13, XI_TRIGGERL=17, XI_TRIGGERR=19 }; int PERDXInit(void); void PERDXDeInit(void); int PERDXHandleEvents(void); void PERDXPerSetButtonMapping(void); u32 PERDXScan(u32 flags) ; void PERDXFlush(void); #endif yabause-0.9.15/src/m68kcore.h000644 001750 001750 00000004145 12755623101 017655 0ustar00guillaumeguillaume000000 000000 /* Copyright 2007 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef M68KCORE_H #define M68KCORE_H #include "core.h" #define M68KCORE_DEFAULT -1 #define M68KCORE_DUMMY 0 #define M68KCORE_C68K 1 #define M68KCORE_Q68 2 #define M68KCORE_MUSASHI 3 typedef u32 FASTCALL M68K_READ(const u32 adr); typedef void FASTCALL M68K_WRITE(const u32 adr, u32 data); typedef struct { int id; const char *Name; int (*Init)(void); void (*DeInit)(void); void (*Reset)(void); s32 FASTCALL (*Exec)(s32 cycle); void (*Sync)(void); u32 (*GetDReg)(u32 num); u32 (*GetAReg)(u32 num); u32 (*GetPC)(void); u32 (*GetSR)(void); u32 (*GetUSP)(void); u32 (*GetMSP)(void); void (*SetDReg)(u32 num, u32 val); void (*SetAReg)(u32 num, u32 val); void (*SetPC)(u32 val); void (*SetSR)(u32 val); void (*SetUSP)(u32 val); void (*SetMSP)(u32 val); void (*SetFetch)(u32 low_adr, u32 high_adr, pointer fetch_adr); void FASTCALL (*SetIRQ)(s32 level); void FASTCALL (*WriteNotify)(u32 address, u32 size); void (*SetReadB)(M68K_READ *Func); void (*SetReadW)(M68K_READ *Func); void (*SetWriteB)(M68K_WRITE *Func); void (*SetWriteW)(M68K_WRITE *Func); void (*SaveState)(FILE* fp); void (*LoadState)(FILE* fp); } M68K_struct; extern M68K_struct * M68K; int M68KInit(int coreid); extern M68K_struct M68KDummy; extern M68K_struct M68KC68K; extern M68K_struct M68KQ68; extern M68K_struct M68KMusashi; #endif yabause-0.9.15/src/scu.c000644 001750 001750 00000356274 12757373537 017042 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2006 Guillaume Duhamel Copyright 2005-2006 Theo Berkau Copyright 2015 Shinya Miyamoto(devmiyax) This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file scu.c \brief SCU emulation functions. */ #include #include "scu.h" #include "debug.h" #include "memory.h" #include "sh2core.h" #include "yabause.h" #include "cs0.h" #include "cs1.h" #include "cs2.h" #include "scsp.h" #include "vdp1.h" #include "vdp2.h" #include "ygr.h" #include "assert.h" #include #ifdef OPTIMIZED_DMA # include "cs2.h" # include "scsp.h" # include "vdp1.h" # include "vdp2.h" #endif Scu * ScuRegs; scudspregs_struct * ScuDsp; scubp_struct * ScuBP; static int incFlg[4] = { 0 }; static void ScuTestInterruptMask(void); ////////////////////////////////////////////////////////////////////////////// int ScuInit(void) { int i; if ((ScuRegs = (Scu *) calloc(1, sizeof(Scu))) == NULL) return -1; if ((ScuDsp = (scudspregs_struct *) calloc(1, sizeof(scudspregs_struct))) == NULL) return -1; if ((ScuBP = (scubp_struct *) calloc(1, sizeof(scubp_struct))) == NULL) return -1; ScuDsp->jmpaddr = 0xFFFFFFFF; for (i = 0; i < MAX_BREAKPOINTS; i++) ScuBP->codebreakpoint[i].addr = 0xFFFFFFFF; ScuBP->numcodebreakpoints = 0; ScuBP->BreakpointCallBack=NULL; ScuBP->inbreakpoint=0; return 0; } ////////////////////////////////////////////////////////////////////////////// void ScuDeInit(void) { if (ScuRegs) free(ScuRegs); ScuRegs = NULL; if (ScuDsp) free(ScuDsp); ScuDsp = NULL; if (ScuBP) free(ScuBP); ScuBP = NULL; } ////////////////////////////////////////////////////////////////////////////// void ScuReset(void) { ScuRegs->D0AD = ScuRegs->D1AD = ScuRegs->D2AD = 0x101; ScuRegs->D0EN = ScuRegs->D1EN = ScuRegs->D2EN = 0x0; ScuRegs->D0MD = ScuRegs->D1MD = ScuRegs->D2MD = 0x7; ScuRegs->DSTP = 0x0; ScuRegs->DSTA = 0x0; ScuDsp->ProgControlPort.all = 0; ScuRegs->PDA = 0x0; ScuRegs->T1MD = 0x0; ScuRegs->IMS = 0xBFFF; ScuRegs->IST = 0x0; ScuRegs->AIACK = 0x0; ScuRegs->ASR0 = ScuRegs->ASR1 = 0x0; ScuRegs->AREF = 0x0; ScuRegs->RSEL = 0x0; ScuRegs->VER = 0x04; // Looks like all consumer saturn's used at least version 4 ScuRegs->timer0 = 0; ScuRegs->timer1 = 0; memset((void *)ScuRegs->interrupts, 0, sizeof(scuinterrupt_struct) * 30); ScuRegs->NumberOfInterrupts = 0; } ////////////////////////////////////////////////////////////////////////////// #ifdef OPTIMIZED_DMA // Table of memory types for DMA optimization, in 512k (1<<19 byte) units: // 0x00 = no special handling // 0x12 = VDP1/2 RAM (8-bit organized, 16-bit copy unit) // 0x22 = M68K RAM (16-bit organized, 16-bit copy unit) // 0x23 = VDP2 color RAM (16-bit organized, 16-bit copy unit) // 0x24 = SH-2 RAM (16-bit organized, 32-bit copy unit) static const u8 DMAMemoryType[0x20000000>>19] = { [0x00200000>>19] = 0x24, [0x00280000>>19] = 0x24, [0x05A00000>>19] = 0x22, [0x05A80000>>19] = 0x22, [0x05C00000>>19] = 0x12, [0x05C00000>>19] = 0x12, [0x05E00000>>19] = 0x12, [0x05E80000>>19] = 0x12, [0x05F00000>>19] = 0x23, [0x06000000>>19] = 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, }; // Function to return the native pointer for an optimized address #ifdef __GNUC__ __attribute__((always_inline)) // Force it inline for better performance #endif static INLINE void *DMAMemoryPointer(u32 address) { u32 page = (address & 0x1FF80000) >> 19; switch (DMAMemoryType[page]) { case 0x12: switch (page) { case 0x05C00000>>19: return &Vdp1Ram[address & 0x7FFFF]; case 0x05E00000>>19: // fall through case 0x05E80000>>19: return &Vdp2Ram[address & 0x7FFFF]; default: return NULL; } case 0x22: return &SoundRam[address & 0x7FFFF]; case 0x23: return &Vdp2ColorRam[address & 0xFFF]; case 0x24: if (page == 0x00200000>>19) { return &LowWram[address & 0xFFFFF]; } else { return &HighWram[address & 0xFFFFF]; } default: return NULL; } } #endif // OPTIMIZED_DMA static void DoDMA(u32 ReadAddress, unsigned int ReadAdd, u32 WriteAddress, unsigned int WriteAdd, u32 TransferSize) { if (ReadAdd == 0) { // DMA fill #ifdef OPTIMIZED_DMA if (ReadAddress == 0x25818000 && WriteAdd == 4) { // Reading from the CD buffer, so optimize if possible. if ((WriteAddress & 0x1E000000) == 0x06000000) { Cs2RapidCopyT2(&HighWram[WriteAddress & 0xFFFFF], TransferSize/4); SH2WriteNotify(WriteAddress, TransferSize); return; } else if ((WriteAddress & 0x1FF00000) == 0x00200000) { Cs2RapidCopyT2(&LowWram[WriteAddress & 0xFFFFF], TransferSize/4); SH2WriteNotify(WriteAddress, TransferSize); return; } } #endif // Is it a constant source or a register whose value can change from // read to read? int constant_source = ((ReadAddress & 0x1FF00000) == 0x00200000) || ((ReadAddress & 0x1E000000) == 0x06000000) || ((ReadAddress & 0x1FF00000) == 0x05A00000) || ((ReadAddress & 0x1DF00000) == 0x05C00000); if ((WriteAddress & 0x1FFFFFFF) >= 0x5A00000 && (WriteAddress & 0x1FFFFFFF) < 0x5FF0000) { // Fill a 32-bit value in 16-bit units. We have to be careful to // avoid misaligned 32-bit accesses, because some hardware (e.g. // PSP) crashes on such accesses. if (constant_source) { u32 counter = 0; u32 val; if (ReadAddress & 2) { // Avoid misaligned access val = MappedMemoryReadWordNocache(MSH2, ReadAddress) << 16 | MappedMemoryReadWordNocache(MSH2, ReadAddress+2); } else { val = MappedMemoryReadLongNocache(MSH2, ReadAddress); } while (counter < TransferSize) { MappedMemoryWriteWordNocache(MSH2, WriteAddress, (u16)(val >> 16)); WriteAddress += WriteAdd; MappedMemoryWriteWordNocache(MSH2, WriteAddress, (u16)val); WriteAddress += WriteAdd; counter += 4; } } else { u32 counter = 0; while (counter < TransferSize) { u32 tmp = MappedMemoryReadLongNocache(MSH2, ReadAddress); MappedMemoryWriteWordNocache(MSH2, WriteAddress, (u16)(tmp >> 16)); WriteAddress += WriteAdd; MappedMemoryWriteWordNocache(MSH2, WriteAddress, (u16)tmp); WriteAddress += WriteAdd; ReadAddress += ReadAdd; counter += 4; } } } else { // Fill in 32-bit units (always aligned). u32 start = WriteAddress; if (constant_source) { u32 val = MappedMemoryReadLongNocache(MSH2, ReadAddress); u32 counter = 0; while (counter < TransferSize) { MappedMemoryWriteLongNocache(MSH2, WriteAddress, val); ReadAddress += ReadAdd; WriteAddress += WriteAdd; counter += 4; } } else { u32 counter = 0; while (counter < TransferSize) { MappedMemoryWriteLongNocache(MSH2, WriteAddress, MappedMemoryReadLongNocache(MSH2, ReadAddress)); ReadAddress += ReadAdd; WriteAddress += WriteAdd; counter += 4; } } // Inform the SH-2 core in case it was a write to main RAM. SH2WriteNotify(start, WriteAddress - start); } } else { // DMA copy #ifdef OPTIMIZED_DMA int source_type = DMAMemoryType[(ReadAddress & 0x1FF80000) >> 19]; int dest_type = DMAMemoryType[(WriteAddress & 0x1FF80000) >> 19]; if (WriteAdd == ((dest_type & 0x2) ? 2 : 4)) { // Writes don't skip any bytes, so use an optimized copy algorithm // if possible. const u8 *source_ptr = DMAMemoryPointer(ReadAddress); u8 *dest_ptr = DMAMemoryPointer(WriteAddress); # ifdef WORDS_BIGENDIAN if ((source_type & 0x30) && (dest_type & 0x30)) { // Source and destination are both directly accessible. memcpy(dest_ptr, source_ptr, TransferSize); if (dest_type == 0x24) { SH2WriteNotify(WriteAddress, TransferSize); } else if (dest_type == 0x22) { M68KWriteNotify(WriteAddress & 0x7FFFF, TransferSize); } return; } # else // !WORDS_BIGENDIAN if (source_type & dest_type & 0x10) { // Source and destination are both 8-bit organized. memcpy(dest_ptr, source_ptr, TransferSize); return; } else if (source_type & dest_type & 0x20) { // Source and destination are both 16-bit organized. memcpy(dest_ptr, source_ptr, TransferSize); if (dest_type == 0x24) { SH2WriteNotify(WriteAddress, TransferSize); } else if (dest_type == 0x22) { M68KWriteNotify(WriteAddress & 0x7FFFF, TransferSize); } return; } else if ((source_type | dest_type) >> 4 == 0x3) { // Need to convert between 8-bit and 16-bit organization. if ((ReadAddress | WriteAddress) & 2) { // Avoid misaligned access const u16 *source_16 = (u16 *)source_ptr; u16 *dest_16 = (u16 *)dest_ptr; u32 counter; for (counter = 0; counter < TransferSize-6; counter += 8, source_16 += 4, dest_16 += 4) { // Use "unsigned int" rather than "u16" because some // compilers try too hard to keep the high bits zero, // thus wasting cycles on every iteration. unsigned int val0 = BSWAP16(source_16[0]); unsigned int val1 = BSWAP16(source_16[1]); unsigned int val2 = BSWAP16(source_16[2]); unsigned int val3 = BSWAP16(source_16[3]); dest_16[0] = val0; dest_16[1] = val1; dest_16[2] = val2; dest_16[3] = val3; } for (; counter < TransferSize; counter += 2, source_16++, dest_16++) { *dest_16 = BSWAP16(*source_16); } } else { // 32-bit aligned accesses possible const u32 *source_32 = (u32 *)source_ptr; u32 *dest_32 = (u32 *)dest_ptr; u32 counter; for (counter = 0; counter < TransferSize-12; counter += 16, source_32 += 4, dest_32 += 4) { u32 val0 = BSWAP16(source_32[0]); u32 val1 = BSWAP16(source_32[1]); u32 val2 = BSWAP16(source_32[2]); u32 val3 = BSWAP16(source_32[3]); dest_32[0] = val0; dest_32[1] = val1; dest_32[2] = val2; dest_32[3] = val3; } for (; counter < TransferSize; counter += 4, source_32++, dest_32++) { *dest_32 = BSWAP16(*source_32); } } return; } # endif // WORDS_BIGENDIAN } #endif // OPTIMIZED_DMA if ((WriteAddress & 0x1FFFFFFF) >= 0x5A00000 && (WriteAddress & 0x1FFFFFFF) < 0x5FF0000) { // Copy in 16-bit units, avoiding misaligned accesses. u32 counter = 0; if (ReadAddress & 2) { // Avoid misaligned access u16 tmp = MappedMemoryReadWordNocache(MSH2, ReadAddress); MappedMemoryWriteWordNocache(MSH2, WriteAddress, tmp); WriteAddress += WriteAdd; ReadAddress += 2; counter += 2; } if (TransferSize >= 3) { while (counter < TransferSize-2) { u32 tmp = MappedMemoryReadLongNocache(MSH2, ReadAddress); MappedMemoryWriteWordNocache(MSH2, WriteAddress, (u16)(tmp >> 16)); WriteAddress += WriteAdd; MappedMemoryWriteWordNocache(MSH2, WriteAddress, (u16)tmp); WriteAddress += WriteAdd; ReadAddress += 4; counter += 4; } } if (counter < TransferSize) { u16 tmp = MappedMemoryReadWordNocache(MSH2, ReadAddress); MappedMemoryWriteWordNocache(MSH2, WriteAddress, tmp); WriteAddress += WriteAdd; ReadAddress += 2; counter += 2; } } else { u32 counter = 0; u32 start = WriteAddress; while (counter < TransferSize) { MappedMemoryWriteLongNocache(MSH2, WriteAddress, MappedMemoryReadLongNocache(MSH2, ReadAddress)); ReadAddress += 4; WriteAddress += WriteAdd; counter += 4; } /* Inform the SH-2 core in case it was a write to main RAM */ SH2WriteNotify(start, WriteAddress - start); } } // Fill / copy } ////////////////////////////////////// #define DMA_FINISHED 0 #define DMA_WAITING_FACTOR 1 #define DMA_QUEUED 2 #define DMA_ACTIVE 3 #define DMA_TRANSFER_A_TO_B 1 #define DMA_TRANSFER_CPU_TO_B 2 #define DMA_TRANSFER_A_TO_CPU 3 #define DMA_TRANSFER_B_TO_CPU 4 #define DMA_TRANSFER_CPU_TO_A 5 #define DMA_TRANSFER_B_TO_A 6 #define DSP_CPU_BUS 1 #define DSP_B_BUS 2 #define DSP_A_BUS 3 void scu_sort_dma(); struct QueuedDma { u32 read_address; u32 write_address; u32 count; u32 original_count; int count_mod_4; int status; int second_word; u32 buffer; u32 read_add; int add_setting; u32 write_add; int bus_type; int is_indirect; int read_addr_update; int write_addr_update; int starting_factor; int level; u32 indirect_address; int is_last_indirect; int is_dsp; int dsp_dma_type; int dsp_bank; int dsp_add; u32 dsp_address; u8 program_ram_counter; u8 dsp_add_setting; u32 dsp_orig_count; u8 ct; int num_written; int dsp_bus; }scu_dma_queue[16] = { 0 }; int get_write_add_value(u32 reg_val) { switch (reg_val & 0x7) { case 0: return 0; case 1: return 2; case 2: return 4; case 3: return 8; case 4: return 16; case 5: return 32; case 6: return 64; case 7: return 128; } return 0; } int scu_active_dma_exists() { int i = 0; for (i = 0; i < 16; i++) { if (scu_dma_queue[i].status == DMA_ACTIVE) return 1; } return 0; } void dma_finish(struct QueuedDma * dma) { memset(dma, 0, sizeof(struct QueuedDma)); dma->status = DMA_FINISHED; scu_sort_dma(); if (!scu_active_dma_exists()) { if (scu_dma_queue[0].status == DMA_QUEUED) scu_dma_queue[0].status = DMA_ACTIVE; } } void dma_finished(struct QueuedDma * dma) { if (dma->bus_type == DMA_TRANSFER_A_TO_B) ScuRegs->DSTA &= ~0x300000; //complete switch (dma->level) { case 0: ScuRegs->DSTA &= ~(1 << 4);//clear dma operation flag ScuSendLevel0DMAEnd(); break; case 1: ScuRegs->DSTA &= ~(1 << 8); ScuSendLevel1DMAEnd(); break; case 2: ScuRegs->DSTA &= ~(1 << 12); ScuSendLevel2DMAEnd(); break; } dma_finish(dma); } void dma_read_indirect(struct QueuedDma * dma) { u32 address = MappedMemoryReadLongNocache(MSH2, dma->indirect_address + 8); dma->original_count = dma->count = MappedMemoryReadLongNocache(MSH2, dma->indirect_address); dma->write_address = MappedMemoryReadLongNocache(MSH2, dma->indirect_address + 4); dma->read_address = address & (~0x80000000); dma->second_word = 0; if (address & 0x80000000) dma->is_last_indirect = 1; } int get_bus_type(u32 src, u32 dst); void check_dma_finished(struct QueuedDma *dma) { if (dma->count == 0) { if (dma->is_indirect) { if (dma->is_last_indirect) { dma->status = DMA_FINISHED; dma_finished(dma); } else { dma_read_indirect(dma); dma->bus_type = get_bus_type(dma->read_address, dma->write_address); dma->indirect_address += 0xC; } } else { dma_finished(dma); } } } void get_write_add_b(struct QueuedDma * dma) { switch (dma->add_setting) { case 0: break; case 1: dma->write_address += 2; break; case 2: dma->write_address += 4; break; case 3: dma->write_address += 8; break; case 4: dma->write_address += 16; break; case 5: dma->write_address += 32; break; case 6: dma->write_address += 64; break; case 7: dma->write_address += 128; break; } } void get_write_add_a_to_cpu(struct QueuedDma * dma) { switch (dma->add_setting) { case 0: break; case 1: if ((dma->num_written % 8) == 0) dma->write_address += 4; break; case 2: dma->write_address += 4; break; case 3: dma->write_address += 8; break; case 4: dma->write_address += 16; break; case 5: dma->write_address += 32; break; case 6: dma->write_address += 64; break; case 7: dma->write_address += 128; break; } } int sh2_check_wait(SH2_struct * sh, u32 addr, int size); void get_add(struct QueuedDma * dma); void do_writes_b(struct QueuedDma* dma) { if (!dma->second_word) { dma->buffer = MappedMemoryReadLongNocache(MSH2, dma->read_address); MappedMemoryWriteWordNocache(MSH2, dma->write_address, dma->buffer >> 16); dma->second_word = 1; dma->count -= 2; dma->num_written += 2; get_write_add_b(dma); } else { MappedMemoryWriteWordNocache(MSH2, dma->write_address, dma->buffer & 0xffff); dma->read_address += dma->read_add; dma->count -= 2; dma->num_written += 2; dma->second_word = 0; get_write_add_b(dma); } } void scu_dma_tick_to_b(struct QueuedDma *dma) { if (sh2_check_wait(NULL, dma->read_address, 2)) return; if (dma->count_mod_4 == 0) { do_writes_b(dma); } else if (dma->count_mod_4 == 1) { //this mode will write 0x90 at the end of a dma for some reason if ((dma->original_count >= 0x5 ) && (dma->add_setting >= 2 ) && dma->count == 1) { MappedMemoryWriteByteNocache(MSH2, dma->write_address, (dma->buffer >> 8) & 0xff); MappedMemoryWriteByteNocache(MSH2, dma->write_address + 2, 0x90); dma->count = 0; } else if (dma->count == 1 && dma->original_count > 1 && dma->add_setting == 0) { u8 byte = MappedMemoryReadByteNocache(MSH2, dma->read_address); MappedMemoryWriteByteNocache(MSH2, dma->write_address + 2, 0x90); dma->count = 0; } else if (dma->count == 1) { u8 byte = MappedMemoryReadByteNocache(MSH2, dma->read_address); MappedMemoryWriteByteNocache(MSH2, dma->write_address, byte); dma->count = 0; } else { do_writes_b(dma); } } else if (dma->count_mod_4 == 2) { if (dma->count == 2) { u16 word = MappedMemoryReadWordNocache(MSH2, dma->read_address); MappedMemoryWriteWordNocache(MSH2, dma->write_address, word); dma->count = 0; } else do_writes_b(dma); } else if (dma->count_mod_4 == 3) { if (dma->count == 3 && dma->original_count > 3) { dma->buffer = MappedMemoryReadLongNocache(MSH2, dma->read_address); MappedMemoryWriteWordNocache(MSH2, dma->write_address, dma->buffer >> 16); get_write_add_b(dma); MappedMemoryWriteByteNocache(MSH2, dma->write_address, (dma->buffer >> 8) & 0xFF); dma->count = 0; } else if (dma->count == 3) { dma->buffer = MappedMemoryReadLongNocache(MSH2, dma->read_address); MappedMemoryWriteWordNocache(MSH2, dma->write_address, dma->buffer >> 16); get_write_add_b(dma); MappedMemoryWriteByteNocache(MSH2, dma->write_address, (dma->buffer >> 8) & 0xFF); dma->count = 0; } else { do_writes_b(dma); } } check_dma_finished(dma); } void do_writes_a_to_cpu(struct QueuedDma * dma) { if (!dma->second_word) { dma->buffer = MappedMemoryReadWordNocache(MSH2, dma->read_address) << 16; dma->second_word = 1; dma->count -= 2; dma->num_written += 2; } else { dma->buffer |= MappedMemoryReadWordNocache(MSH2, dma->read_address + 2); MappedMemoryWriteLongNocache(MSH2, dma->write_address, dma->buffer); dma->read_address += dma->read_add; dma->count -= 2; dma->num_written += 2; dma->second_word = 0; get_write_add_a_to_cpu(dma); } } void scu_dma_tick_a_to_cpu(struct QueuedDma *dma) { if (sh2_check_wait(NULL, dma->read_address, 2)) return; if (dma->count_mod_4 == 0) { do_writes_a_to_cpu(dma); } else if (dma->count_mod_4 == 1) { if (dma->count == 1) { u8 byte = MappedMemoryReadByteNocache(MSH2, dma->read_address); MappedMemoryWriteByteNocache(MSH2, dma->write_address, byte); dma->count = 0; } else { do_writes_a_to_cpu(dma); } } else if (dma->count_mod_4 == 2) { if (dma->count == 2) { u16 word = MappedMemoryReadWordNocache(MSH2, dma->read_address); MappedMemoryWriteWordNocache(MSH2, dma->write_address, word); dma->count = 0; } else do_writes_a_to_cpu(dma); } else if (dma->count_mod_4 == 3) { if (dma->count == 3) { dma->buffer = MappedMemoryReadWordNocache(MSH2, dma->read_address) << 16; MappedMemoryWriteWordNocache(MSH2, dma->write_address, dma->buffer >> 16); dma->buffer |= MappedMemoryReadWordNocache(MSH2, dma->read_address + 2); MappedMemoryWriteByteNocache(MSH2, dma->write_address + 2, (dma->buffer >> 8) & 0xFF); dma->count = 0; } else { do_writes_a_to_cpu(dma); } } check_dma_finished(dma); } void swap_dma_queue(int i, int j) { struct QueuedDma temp = scu_dma_queue[i]; scu_dma_queue[i] = scu_dma_queue[j]; scu_dma_queue[j] = temp; } void scu_sort_dma() { int i = 0; //sort active, queued, starting factor, finished //statuses are defined in numerical order for (i = 0; i < 16; i++) { int j = 0; for (j = 0; j < 16; j++) { if (scu_dma_queue[i].status > scu_dma_queue[j].status) { swap_dma_queue(i, j); } } } } void scu_dma_tick_32(struct QueuedDma * dma) { u32 src_val = 0; if (sh2_check_wait(NULL, dma->read_address, 2)) return; src_val = MappedMemoryReadLongNocache(MSH2, dma->read_address); MappedMemoryWriteLongNocache(MSH2, dma->write_address, src_val); dma->read_address += dma->read_add; dma->write_address += dma->write_add; dma->count-=4; check_dma_finished(dma); } int is_a_bus(u32 addr) { addr &= 0xFFFFFFF; if (addr >= 0x2000000 && addr <= 0x58FFFFF) return 1; return 0; } int is_b_bus(u32 addr) { addr &= 0xFFFFFFF; if (addr >= 0x5A00000 && addr <= 0x5F8011F) return 1; return 0; } int is_cpu_bus(u32 addr) { addr &= 0xFFFFFFF; if (is_a_bus(addr)) return 0; if (is_b_bus(addr)) return 0; return 1; } int get_bus_type(u32 src, u32 dst) { u8 src_type_a = is_a_bus(src); u8 src_type_b = is_b_bus(src); u8 src_type_cpu = (src_type_a == 0) && (src_type_b == 0); u8 dst_type_a = is_a_bus(dst); u8 dst_type_b = is_b_bus(dst); u8 dst_type_cpu = (dst_type_a == 0) && (dst_type_b == 0); if (src_type_a && dst_type_b) return DMA_TRANSFER_A_TO_B; if (src_type_cpu && dst_type_b) return DMA_TRANSFER_CPU_TO_B; if (src_type_a && dst_type_cpu) return DMA_TRANSFER_A_TO_CPU; if (src_type_b && dst_type_cpu) return DMA_TRANSFER_B_TO_CPU; if (src_type_cpu && dst_type_a) return DMA_TRANSFER_CPU_TO_A; if (src_type_b && dst_type_a) return DMA_TRANSFER_B_TO_A; return 0; } void scu_dma_sort_activate(struct QueuedDma *dma) { scu_sort_dma(); if (!scu_active_dma_exists()) { if (scu_dma_queue[0].status == DMA_QUEUED) { scu_dma_queue[0].status = DMA_ACTIVE; if (scu_dma_queue[0].level == 0) ScuRegs->DSTA |= (1 << 4);//set dma operation flag else if (scu_dma_queue[0].level == 1) ScuRegs->DSTA |= (1 << 8); else if (scu_dma_queue[0].level == 2) ScuRegs->DSTA |= (1 << 12); if (dma->bus_type == DMA_TRANSFER_A_TO_B) ScuRegs->DSTA |= 0x300000; } } } void scu_enqueue_dma(struct QueuedDma *dma, u32 read_reg, u32 write_reg, u32 count_reg, u32 add_reg, u32 mode_reg, int level) { memset(dma, 0, sizeof(struct QueuedDma)); dma->read_address = read_reg; dma->indirect_address = dma->write_address = write_reg; dma->add_setting = add_reg & 0x7; dma->write_add = get_write_add_value(add_reg & 0x7); dma->is_indirect = (mode_reg >> 24) & 1; dma->read_addr_update = (mode_reg >> 16) & 1; dma->write_addr_update = (mode_reg >> 8) & 1; dma->starting_factor = mode_reg & 7; dma->original_count = dma->count = count_reg; dma->level = level; if (dma->is_indirect) dma_read_indirect(dma); dma->count_mod_4 = dma->count % 4; if (dma->starting_factor != 7) dma->status = DMA_WAITING_FACTOR;//wait for an event else dma->status = DMA_QUEUED; if ((add_reg >> 8) & 1) dma->read_add = 4; dma->bus_type = get_bus_type(dma->read_address, dma->write_address); if (!dma->is_indirect) { if (dma->level > 0) { dma->count &= 0xFFF; if (dma->count == 0) dma->count = 0x1000; } else { if (dma->count == 0) dma->count = 0x100000; } } //sort dmas, if there are queued dmas but none are active //then activate one scu_dma_sort_activate(dma); } void scu_insert_dma(u32 read_reg, u32 write_reg, u32 count_reg, u32 add_reg, u32 mode_reg, int level) { int i = 0; for (i = 0; i < 16; i++) { if (scu_dma_queue[i].status == DMA_FINISHED) { scu_enqueue_dma(&scu_dma_queue[i], read_reg, write_reg, count_reg, add_reg, mode_reg, level); break; } } scu_sort_dma(); } void adjust_ra0_wa0(struct QueuedDma * dma) { scudspregs_struct * sc = ScuDsp; int is_a_bus = ((dma->dsp_address & 0x0F000000) >= 0x02000000 && (dma->dsp_address & 0x0FF00000) <= 0x05800000); int is_c_bus = (dma->dsp_address & 0x0F000000) == 0x06000000; if (dma->dsp_dma_type == 1 || dma->dsp_dma_type == 3) { switch (dma->dsp_add_setting) { case 0: case 1: case 4: case 5: sc->RA0 += 1; break; case 2: case 3: case 6: case 7: sc->RA0 += dma->dsp_orig_count; default: break; } } else if (dma->dsp_dma_type == 2 || dma->dsp_dma_type == 4) { if (is_c_bus || is_a_bus) { switch (dma->dsp_add_setting) { case 0: sc->WA0 += 1; break; case 1: if (dma->dsp_orig_count == 1 || dma->dsp_orig_count == 2) sc->WA0 += 1; else sc->WA0 += (dma->dsp_orig_count >> 1) + 1; break; case 2: sc->WA0 += dma->dsp_orig_count; break; case 3: sc->WA0 += (dma->dsp_orig_count * 2) - 1; break; case 4: sc->WA0 += (dma->dsp_orig_count * 4) - 3; break; case 5: sc->WA0 += (dma->dsp_orig_count * 8) - 7; break; case 6: sc->WA0 += (dma->dsp_orig_count * 16) - 15; break; case 7: sc->WA0 += (dma->dsp_orig_count * 32) - 31; break; default: break; } } else { //b-bus switch (dma->dsp_add_setting) { case 0: sc->WA0 += 1; break; case 1: sc->WA0 += dma->dsp_orig_count; break; case 2: sc->WA0 += (dma->dsp_orig_count * 2) - 1; break; case 3: sc->WA0 += (dma->dsp_orig_count * 4) - 3; break; case 4: sc->WA0 += (dma->dsp_orig_count * 8) - 7; break; case 5: sc->WA0 += (dma->dsp_orig_count * 16) - 15; break; case 6: sc->WA0 += (dma->dsp_orig_count * 32) - 31; break; case 7: sc->WA0 += (dma->dsp_orig_count * 64) - 63; break; default: break; } } } } void scu_dma_tick_dsp(struct QueuedDma * dma) { scudspregs_struct * sc = ScuDsp; if (dma->dsp_dma_type == 1) { if (sh2_check_wait(NULL, dma->dsp_address, 2)) return; sc->MD[dma->dsp_bank][dma->ct] = MappedMemoryReadLongNocache(MSH2, dma->dsp_address); dma->ct++; dma->ct &= 0x3F; if (dma->dsp_bus == DSP_CPU_BUS || dma->dsp_bus == DSP_A_BUS) { switch (dma->dsp_add_setting) { case 0: case 1: case 4: case 5: break; case 2: case 3: case 6: case 7: dma->dsp_address += 4; break; default: break; } } else dma->dsp_address += 4; dma->count--; } else if (dma->dsp_dma_type == 2 || dma->dsp_dma_type == 4) { if (dma->dsp_bus == DSP_A_BUS || dma->dsp_bus == DSP_CPU_BUS) { u32 Val = sc->MD[dma->dsp_bank][dma->ct]; MappedMemoryWriteLongNocache(MSH2, dma->dsp_address, Val); switch (dma->dsp_add_setting) { case 0: break; case 1: if (dma->num_written & 1) dma->dsp_address += 4; dma->num_written++; break; case 2: dma->dsp_address += 4; break; case 3: dma->dsp_address += 8; break; case 4: dma->dsp_address += 16; break; case 5: dma->dsp_address += 32; break; case 6: dma->dsp_address += 64; break; case 7: dma->dsp_address += 128; break; default: break; } } else { u32 Val = sc->MD[dma->dsp_bank][dma->ct]; MappedMemoryWriteWordNocache(MSH2, dma->dsp_address, Val >> 16); dma->dsp_address += dma->dsp_add << 1; MappedMemoryWriteWordNocache(MSH2, dma->dsp_address, Val & 0xffff); dma->dsp_address += dma->dsp_add << 1; } dma->ct++; dma->ct &= 0x3F; dma->count--; } else if (dma->dsp_dma_type == 3) { if (dma->dsp_bank > 3) { sc->ProgramRam[dma->program_ram_counter++] = MappedMemoryReadLongNocache(MSH2, dma->dsp_address); dma->dsp_address += dma->dsp_add << 1; dma->count--; } else { if (sh2_check_wait(NULL, dma->dsp_address, 2)) return; sc->MD[dma->dsp_bank][dma->ct] = MappedMemoryReadLongNocache(MSH2, dma->dsp_address); dma->ct++; dma->ct &= 0x3F; if (dma->dsp_bus == DSP_CPU_BUS || dma->dsp_bus == DSP_A_BUS) { switch (dma->dsp_add_setting) { case 0: case 1: case 4: case 5: break; case 2: case 3: case 6: case 7: dma->dsp_address += 4; break; default: break; } } else dma->dsp_address += dma->dsp_add; dma->count--; } } if (dma->count == 0) { ScuRegs->DSTA &= ~1; ScuRegs->DSTA &= ~0x700000; sc->ProgControlPort.part.T0 = 0; dma_finish(dma); } } void get_write_add_from_b(struct QueuedDma * dma) { switch (dma->add_setting) { case 0: break; case 1: if ((dma->num_written % 8) == 0) dma->write_address += 4; break; case 2: if ((dma->num_written % 4) == 0) dma->write_address += 4; break; case 3: if ((dma->num_written % 4) == 0) dma->write_address += 8; break; case 4: if ((dma->num_written % 4) == 0) dma->write_address += 16; break; case 5: if ((dma->num_written % 4) == 0) dma->write_address += 32; break; case 6: if ((dma->num_written % 4) == 0) dma->write_address += 64; break; case 7: if ((dma->num_written % 4) == 0) dma->write_address += 128; break; } } void do_write_from_b(struct QueuedDma * dma) { if (!dma->second_word) { dma->buffer = MappedMemoryReadWordNocache(MSH2, dma->read_address) << 16; dma->second_word = 1; dma->count -= 2; dma->num_written += 2; } else { dma->buffer |= MappedMemoryReadWordNocache(MSH2, dma->read_address + 2); MappedMemoryWriteLongNocache(MSH2, dma->write_address, dma->buffer); dma->read_address += 4; dma->count -= 2; dma->num_written += 2; dma->second_word = 0; get_write_add_a_to_cpu(dma); } } void scu_dma_tick_from_b(struct QueuedDma * dma) { if (sh2_check_wait(NULL, dma->read_address, 1)) return; if(dma->count_mod_4 == 0) { do_write_from_b(dma); } else if (dma->count_mod_4 == 1) { if (dma->count == 1) { u8 byte = MappedMemoryReadByteNocache(MSH2, dma->read_address); MappedMemoryWriteByteNocache(MSH2, dma->write_address, byte); dma->count = 0; } else { do_write_from_b(dma); } } else if (dma->count_mod_4 == 2) { if (dma->count == 2) { u16 word = MappedMemoryReadWordNocache(MSH2, dma->read_address); MappedMemoryWriteWordNocache(MSH2, dma->write_address, word); dma->count = 0; } else do_write_from_b(dma); } else if (dma->count_mod_4 == 3) { if (dma->count == 3) { u8 byte; u16 word = MappedMemoryReadWordNocache(MSH2, dma->read_address); MappedMemoryWriteWordNocache(MSH2, dma->write_address, word); byte = MappedMemoryReadByteNocache(MSH2, dma->read_address + 2); MappedMemoryWriteByteNocache(MSH2, dma->write_address + 2, byte); dma->count = 0; } else { do_write_from_b(dma); } } check_dma_finished(dma); } void scu_dma_tick(struct QueuedDma * dma) { if (dma->is_dsp) scu_dma_tick_dsp(dma); //destination is b-bus else if (dma->bus_type == DMA_TRANSFER_CPU_TO_B || dma->bus_type == DMA_TRANSFER_A_TO_B) scu_dma_tick_to_b(dma); //a -> c , c -> a else if (dma->bus_type == DMA_TRANSFER_A_TO_CPU || dma->bus_type == DMA_TRANSFER_CPU_TO_A) scu_dma_tick_a_to_cpu(dma); //from b-bus else if (dma->bus_type == DMA_TRANSFER_B_TO_CPU || dma->bus_type == DMA_TRANSFER_B_TO_A) scu_dma_tick_from_b(dma); else //should not happen scu_dma_tick_32(dma); } void scu_dma_tick_all(u32 cycles) { int i = 0; for (i = 0; i < cycles; i++) { if (scu_dma_queue[0].status == DMA_ACTIVE) scu_dma_tick(&scu_dma_queue[0]); } } static void FASTCALL ScuDMA(scudmainfo_struct *dmainfo) { u8 ReadAdd, WriteAdd; if (dmainfo->AddValue & 0x100) ReadAdd = 4; else ReadAdd = 0; switch(dmainfo->AddValue & 0x7) { case 0x0: WriteAdd = 0; break; case 0x1: WriteAdd = 2; break; case 0x2: WriteAdd = 4; break; case 0x3: WriteAdd = 8; break; case 0x4: WriteAdd = 16; break; case 0x5: WriteAdd = 32; break; case 0x6: WriteAdd = 64; break; case 0x7: WriteAdd = 128; break; default: WriteAdd = 0; break; } if (dmainfo->ModeAddressUpdate & 0x1000000) { // Indirect DMA for (;;) { u32 ThisTransferSize = MappedMemoryReadLongNocache(MSH2,dmainfo->WriteAddress); u32 ThisWriteAddress = MappedMemoryReadLongNocache(MSH2, dmainfo->WriteAddress + 4); u32 ThisReadAddress = MappedMemoryReadLongNocache(MSH2, dmainfo->WriteAddress + 8); //LOG("SCU Indirect DMA: src %08x, dst %08x, size = %08x\n", ThisReadAddress, ThisWriteAddress, ThisTransferSize); DoDMA(ThisReadAddress & 0x7FFFFFFF, ReadAdd, ThisWriteAddress, WriteAdd, ThisTransferSize); if (ThisReadAddress & 0x80000000) break; dmainfo->WriteAddress+= 0xC; } switch(dmainfo->mode) { case 0: ScuSendLevel0DMAEnd(); break; case 1: ScuSendLevel1DMAEnd(); break; case 2: ScuSendLevel2DMAEnd(); break; } } else { // Direct DMA if (dmainfo->mode > 0) { dmainfo->TransferNumber &= 0xFFF; if (dmainfo->TransferNumber == 0) dmainfo->TransferNumber = 0x1000; } else { if (dmainfo->TransferNumber == 0) dmainfo->TransferNumber = 0x100000; } DoDMA(dmainfo->ReadAddress, ReadAdd, dmainfo->WriteAddress, WriteAdd, dmainfo->TransferNumber); switch(dmainfo->mode) { case 0: ScuSendLevel0DMAEnd(); break; case 1: ScuSendLevel1DMAEnd(); break; case 2: ScuSendLevel2DMAEnd(); break; } } } ////////////////////////////////////////////////////////////////////////////// static u32 readgensrc(u8 num) { u32 val; switch(num) { case 0x0: // M0 return ScuDsp->MD[0][ScuDsp->CT[0]]; case 0x1: // M1 return ScuDsp->MD[1][ScuDsp->CT[1]]; case 0x2: // M2 return ScuDsp->MD[2][ScuDsp->CT[2]]; case 0x3: // M3 return ScuDsp->MD[3][ScuDsp->CT[3]]; case 0x4: // MC0 val = ScuDsp->MD[0][ScuDsp->CT[0]]; incFlg[0] = 1; return val; case 0x5: // MC1 val = ScuDsp->MD[1][ScuDsp->CT[1]]; incFlg[1] = 1; return val; case 0x6: // MC2 val = ScuDsp->MD[2][ScuDsp->CT[2]]; incFlg[2] = 1; return val; case 0x7: // MC3 val = ScuDsp->MD[3][ScuDsp->CT[3]]; incFlg[3] = 1; return val; case 0x9: // ALL return (u32)ScuDsp->ALU.part.L; case 0xA: // ALH return (u32)((ScuDsp->ALU.all & (u64)(0x0000ffffffff0000)) >> 16); default: break; } return 0; } ////////////////////////////////////////////////////////////////////////////// static void writed1busdest(u8 num, u32 val) { switch(num) { case 0x0: ScuDsp->MD[0][ScuDsp->CT[0]] = val; ScuDsp->CT[0]++; ScuDsp->CT[0] &= 0x3f; return; case 0x1: ScuDsp->MD[1][ScuDsp->CT[1]] = val; ScuDsp->CT[1]++; ScuDsp->CT[1] &= 0x3f; return; case 0x2: ScuDsp->MD[2][ScuDsp->CT[2]] = val; ScuDsp->CT[2]++; ScuDsp->CT[2] &= 0x3f; return; case 0x3: ScuDsp->MD[3][ScuDsp->CT[3]] = val; ScuDsp->CT[3]++; ScuDsp->CT[3] &= 0x3f; return; case 0x4: ScuDsp->RX = val; return; case 0x5: ScuDsp->P.all = (signed)val; return; case 0x6: ScuDsp->RA0 = val; return; case 0x7: ScuDsp->WA0 = val; return; case 0xA: ScuDsp->LOP = (u16)val; return; case 0xB: ScuDsp->TOP = (u8)val; return; case 0xC: ScuDsp->CT[0] = (u8)val; return; case 0xD: ScuDsp->CT[1] = (u8)val; return; case 0xE: ScuDsp->CT[2] = (u8)val; return; case 0xF: ScuDsp->CT[3] = (u8)val; return; default: break; } } ////////////////////////////////////////////////////////////////////////////// static void writeloadimdest(u8 num, u32 val) { switch(num) { case 0x0: // MC0 ScuDsp->MD[0][ScuDsp->CT[0]] = val; ScuDsp->CT[0]++; ScuDsp->CT[0] &= 0x3f; return; case 0x1: // MC1 ScuDsp->MD[1][ScuDsp->CT[1]] = val; ScuDsp->CT[1]++; ScuDsp->CT[1] &= 0x3f; return; case 0x2: // MC2 ScuDsp->MD[2][ScuDsp->CT[2]] = val; ScuDsp->CT[2]++; ScuDsp->CT[2] &= 0x3f; return; case 0x3: // MC3 ScuDsp->MD[3][ScuDsp->CT[3]] = val; ScuDsp->CT[3]++; ScuDsp->CT[3] &= 0x3f; return; case 0x4: // RX ScuDsp->RX = val; return; case 0x5: // PL ScuDsp->P.all = (s64)val; return; case 0x6: // RA0 val = (val & 0x1FFFFFF); ScuDsp->RA0 = val; return; case 0x7: // WA0 val = (val & 0x1FFFFFF); ScuDsp->WA0 = val; return; case 0xA: // LOP ScuDsp->LOP = (u16)val; return; case 0xC: // PC->TOP, PC ScuDsp->TOP = ScuDsp->PC+1; ScuDsp->jmpaddr = val; ScuDsp->delayed = 0; return; default: break; } } ////////////////////////////////////////////////////////////////////////////// static u32 readdmasrc(u8 num, u8 add) { u32 val; switch(num) { case 0x0: // M0 val = ScuDsp->MD[0][ScuDsp->CT[0]]; ScuDsp->CT[0]+=add; return val; case 0x1: // M1 val = ScuDsp->MD[1][ScuDsp->CT[1]]; ScuDsp->CT[1]+=add; return val; case 0x2: // M2 val = ScuDsp->MD[2][ScuDsp->CT[2]]; ScuDsp->CT[2]+=add; return val; case 0x3: // M3 val = ScuDsp->MD[3][ScuDsp->CT[3]]; ScuDsp->CT[3]+=add; return val; default: break; } return 0; } int dsp_get_bus(u32 addr) { if (is_a_bus(addr)) return DSP_A_BUS; if (is_b_bus(addr)) return DSP_B_BUS; return DSP_CPU_BUS; } void scu_insert_dsp_dma(struct QueuedDma *dma) { int i = 0; if (dma->count == 0) dma->count = dma->dsp_orig_count = 256; dma->dsp_bus = dsp_get_bus(dma->dsp_address); ScuRegs->DSTA |= 1; dma->ct = ScuDsp->CT[dma->dsp_bank]; //count is added instantly for both reads and writes ScuDsp->CT[dma->dsp_bank] += dma->count; ScuDsp->CT[dma->dsp_bank] &= 0x3f; for (i = 0; i < 16; i++) { if (scu_dma_queue[i].status == DMA_FINISHED) { scu_dma_queue[i] = *dma; break; } } scu_dma_sort_activate(dma); } void set_dsta(u32 addr) { if (is_a_bus(addr)) ScuRegs->DSTA |= 0x500000; else if (is_b_bus(addr)) ScuRegs->DSTA |= 0x600000; } void dsp_dma01(scudspregs_struct *sc, u32 inst) { u32 imm = ((inst & 0xFF)); u8 sel = ((inst >> 8) & 0x03); u8 add; u8 addr = sc->CT[sel]; u32 i; switch (((inst >> 15) & 0x07)) { case 0: add = 0; break; case 1: add = 1; break; case 2: add = 2; break; case 3: add = 4; break; case 4: add = 8; break; case 5: add = 16; break; case 6: add = 32; break; case 7: add = 64; break; } if (yabsys.use_scu_dma_timing) { struct QueuedDma my_dma = { 0 }; struct QueuedDma * dma = &my_dma; dma->is_dsp = 1; dma->dsp_dma_type = 1; dma->dsp_add = add; dma->dsp_add_setting = (inst >> 15) & 0x07; dma->dsp_bank = sel; dma->count = dma->dsp_orig_count = imm; dma->dsp_address = sc->RA0 << 2; dma->status = DMA_QUEUED; dma->level = 3; set_dsta(sc->RA0 << 2); if (((inst >> 11) & 0x0F) != 0x08) adjust_ra0_wa0(dma); scu_insert_dsp_dma(&my_dma); sc->ProgControlPort.part.T0 = 1; return; } if (add != 1) { for (i = 0; i < imm; i++) { sc->MD[sel][sc->CT[sel]] = MappedMemoryReadLongNocache(MSH2, (sc->RA0 << 2)); sc->CT[sel]++; sc->CT[sel] &= 0x3F; sc->RA0 += 1; // add? } } else{ for (i = 0; i < imm; i++) { sc->MD[sel][sc->CT[sel]] = MappedMemoryReadLongNocache(MSH2, (sc->RA0 << 2)); sc->CT[sel]++; sc->CT[sel] &= 0x3F; sc->RA0 += 1; } } sc->ProgControlPort.part.T0 = 0; } void dsp_dma02(scudspregs_struct *sc, u32 inst) { u32 imm = ((inst & 0xFF)); u8 sel = ((inst >> 8) & 0x03); u8 addr = sc->CT[sel]; u8 add; u32 i; switch (((inst >> 15) & 0x07)) { case 0: add = 0; break; case 1: add = 1; break; case 2: add = 2; break; case 3: add = 4; break; case 4: add = 8; break; case 5: add = 16; break; case 6: add = 32; break; case 7: add = 64; break; } if (yabsys.use_scu_dma_timing) { struct QueuedDma dma = { 0 }; dma.is_dsp = 1; dma.dsp_dma_type = 2; dma.dsp_add = add; dma.dsp_bank = sel; dma.dsp_add_setting = (inst >> 15) & 0x07; dma.count = dma.dsp_orig_count = imm; dma.dsp_address = sc->WA0 << 2; dma.status = DMA_QUEUED; dma.level = 3; if (((inst >> 10) & 0x1F) != 0x14) adjust_ra0_wa0(&dma); set_dsta(sc->WA0 << 2); scu_insert_dsp_dma(&dma); sc->ProgControlPort.part.T0 = 1; return; } if (add != 1) { for (i = 0; i < imm; i++) { u32 Val = sc->MD[sel][sc->CT[sel]]; u32 Adr = (sc->WA0 << 2); //LOG("SCU DSP DMA02 D:%08x V:%08x", Adr, Val); MappedMemoryWriteLongNocache(MSH2, Adr, Val); sc->CT[sel]++; sc->WA0 += add >> 1; sc->CT[sel] &= 0x3F; } } else { for (i = 0; i < imm; i++) { u32 Val = sc->MD[sel][sc->CT[sel]]; u32 Adr = (sc->WA0 << 2); MappedMemoryWriteLongNocache(MSH2, Adr, Val); sc->CT[sel]++; sc->CT[sel] &= 0x3F; sc->WA0 += 1; } } sc->ProgControlPort.part.T0 = 0; } void determine_a_bus_add(struct QueuedDma* dma, u32 inst) { if ((is_a_bus(dma->dsp_address))) { if (((inst >> 15) & 0x01) == 0) dma->dsp_add = 0; } } void dsp_dma03(scudspregs_struct *sc, u32 inst) { u32 Counter = 0; u32 i; int DestinationId; switch ((inst & 0x7)) { case 0x00: Counter = sc->MD[0][sc->CT[0]]; break; case 0x01: Counter = sc->MD[1][sc->CT[1]]; break; case 0x02: Counter = sc->MD[2][sc->CT[2]]; break; case 0x03: Counter = sc->MD[3][sc->CT[3]]; break; case 0x04: Counter = sc->MD[0][sc->CT[0]]; ScuDsp->CT[0]++; break; case 0x05: Counter = sc->MD[1][sc->CT[1]]; ScuDsp->CT[1]++; break; case 0x06: Counter = sc->MD[2][sc->CT[2]]; ScuDsp->CT[2]++; break; case 0x07: Counter = sc->MD[3][sc->CT[3]]; ScuDsp->CT[3]++; break; } DestinationId = (inst >> 8) & 0x7; if (yabsys.use_scu_dma_timing) { struct QueuedDma dma = { 0 }; dma.is_dsp = 1; dma.dsp_dma_type = 3; dma.dsp_add = 4; dma.dsp_add_setting = (inst >> 15) & 0x7; dma.dsp_bank = DestinationId; dma.count = dma.dsp_orig_count = Counter; dma.dsp_address = sc->RA0 << 2; determine_a_bus_add(&dma, inst); dma.status = DMA_QUEUED; dma.level = 3; set_dsta(sc->RA0 << 2); if (((inst >> 11) & 0x0F) != 0x0C) adjust_ra0_wa0(&dma); scu_insert_dsp_dma(&dma); sc->ProgControlPort.part.T0 = 1; return; } if (DestinationId > 3) { int incl = 1; //((sc->inst >> 15) & 0x01); for (i = 0; i < Counter; i++) { u32 Adr = (sc->RA0 << 2); sc->ProgramRam[i] = MappedMemoryReadLongNocache(MSH2, Adr); sc->RA0 += incl; } } else{ int incl = 1; //((sc->inst >> 15) & 0x01); for (i = 0; i < Counter; i++) { u32 Adr = (sc->RA0 << 2); sc->MD[DestinationId][sc->CT[DestinationId]] = MappedMemoryReadLongNocache(MSH2, Adr); sc->CT[DestinationId]++; sc->CT[DestinationId] &= 0x3F; sc->RA0 += incl; } } sc->ProgControlPort.part.T0 = 0; } void dsp_dma04(scudspregs_struct *sc, u32 inst) { u32 Counter = 0; u32 add = 0; u32 sel = ((inst >> 8) & 0x03); u32 i; switch ((inst & 0x7)) { case 0x00: Counter = sc->MD[0][sc->CT[0]]; break; case 0x01: Counter = sc->MD[1][sc->CT[1]]; break; case 0x02: Counter = sc->MD[2][sc->CT[2]]; break; case 0x03: Counter = sc->MD[3][sc->CT[3]]; break; case 0x04: Counter = sc->MD[0][sc->CT[0]]; ScuDsp->CT[0]++; break; case 0x05: Counter = sc->MD[1][sc->CT[1]]; ScuDsp->CT[1]++; break; case 0x06: Counter = sc->MD[2][sc->CT[2]]; ScuDsp->CT[2]++; break; case 0x07: Counter = sc->MD[3][sc->CT[3]]; ScuDsp->CT[3]++; break; } switch (((inst >> 15) & 0x07)) { case 0: add = 0; break; case 1: add = 1; break; case 2: add = 2; break; case 3: add = 4; break; case 4: add = 8; break; case 5: add = 16; break; case 6: add = 32; break; case 7: add = 64; break; } if (yabsys.use_scu_dma_timing) { struct QueuedDma dma = { 0 }; dma.is_dsp = 1; dma.dsp_dma_type = 4; dma.dsp_add = add; dma.dsp_bank = sel; dma.dsp_add_setting = (inst >> 15) & 0x07; dma.count = dma.dsp_orig_count = Counter; dma.dsp_address = sc->WA0 << 2; dma.status = DMA_QUEUED; dma.level = 3; determine_a_bus_add(&dma, inst); if (((inst >> 10) & 0x1F) != 0x1C) adjust_ra0_wa0(&dma); set_dsta(sc->WA0 << 2); scu_insert_dsp_dma(&dma); sc->ProgControlPort.part.T0 = 1; return; } for (i = 0; i < Counter; i++) { u32 Val = sc->MD[sel][sc->CT[sel]]; u32 Adr = (sc->WA0 << 2); MappedMemoryWriteLongNocache(MSH2, Adr, Val); sc->CT[sel]++; sc->CT[sel] &= 0x3F; sc->WA0 += 1; } sc->ProgControlPort.part.T0 = 0; } void dsp_dma05(scudspregs_struct *sc, u32 inst) { u32 saveRa0 = sc->RA0; dsp_dma01(sc, inst); sc->RA0 = saveRa0; } void dsp_dma06(scudspregs_struct *sc, u32 inst) { u32 saveWa0 = sc->WA0; dsp_dma02(sc, inst); sc->WA0 = saveWa0; } void dsp_dma07(scudspregs_struct *sc, u32 inst) { u32 saveRa0 = sc->RA0; dsp_dma03(sc, inst); sc->RA0 = saveRa0; } void dsp_dma08(scudspregs_struct *sc, u32 inst) { u32 saveWa0 = sc->WA0; dsp_dma04(sc, inst); sc->WA0 = saveWa0; } ////////////////////////////////////////////////////////////////////////////// static void writedmadest(u8 num, u32 val, u8 add) { switch(num) { case 0x0: // M0 ScuDsp->MD[0][ScuDsp->CT[0]] = val; ScuDsp->CT[0]+=add; return; case 0x1: // M1 ScuDsp->MD[1][ScuDsp->CT[1]] = val; ScuDsp->CT[1]+=add; return; case 0x2: // M2 ScuDsp->MD[2][ScuDsp->CT[2]] = val; ScuDsp->CT[2]+=add; return; case 0x3: // M3 ScuDsp->MD[3][ScuDsp->CT[3]] = val; ScuDsp->CT[3]+=add; return; case 0x4: // Program Ram //LOG("scu\t: DMA Program writes not implemented\n"); // ScuDsp->ProgramRam[?] = val; // ?? += add; return; default: break; } } ////////////////////////////////////////////////////////////////////////////// void dsp_trace_log(const char * format, ...) { static int started = 0; static FILE* fp = NULL; va_list l; if (!started) { fp = fopen("C:/yabause/log.txt", "w"); if (!fp) { return; } started = 1; } va_start(l, format); vfprintf(fp, format, l); va_end(l); } void ScuExec(u32 cycles) { int i; u32 timing = cycles / 2; int scu_dma_cycles = cycles; int real_timing = 1; // is dsp executing? if (ScuDsp->ProgControlPort.part.EX) { while (timing > 0) { u32 instruction; // Make sure it isn't one of our breakpoints for (i=0; i < ScuBP->numcodebreakpoints; i++) { if ((ScuDsp->PC == ScuBP->codebreakpoint[i].addr) && ScuBP->inbreakpoint == 0) { ScuBP->inbreakpoint = 1; if (ScuBP->BreakpointCallBack) ScuBP->BreakpointCallBack(ScuBP->codebreakpoint[i].addr); ScuBP->inbreakpoint = 0; } } instruction = ScuDsp->ProgramRam[ScuDsp->PC]; if (real_timing && (scu_dma_queue[0].status == DMA_ACTIVE)) { scu_dma_tick(&scu_dma_queue[0]); scu_dma_cycles-=2; } incFlg[0] = 0; incFlg[1] = 0; incFlg[2] = 0; incFlg[3] = 0; // ALU commands switch (instruction >> 26) { case 0x0: // NOP //AC is moved as-is to the ALU ScuDsp->ALU.all = ScuDsp->AC.part.L; break; case 0x1: // AND //the upper 16 bits of AC are not modified for and, or, add, sub, rr and rl8 ScuDsp->ALU.all = (s64)(ScuDsp->AC.part.L & ScuDsp->P.part.L) | (ScuDsp->AC.part.L & 0xffff00000000); if (ScuDsp->ALU.part.L == 0) ScuDsp->ProgControlPort.part.Z = 1; else ScuDsp->ProgControlPort.part.Z = 0; if ((s64)ScuDsp->ALU.part.L < 0) ScuDsp->ProgControlPort.part.S = 1; else ScuDsp->ProgControlPort.part.S = 0; ScuDsp->ProgControlPort.part.C = 0; break; case 0x2: // OR ScuDsp->ALU.all = (s64)(ScuDsp->AC.part.L | ((u32)ScuDsp->P.part.L)) | (ScuDsp->AC.part.L & 0xffff00000000); if (ScuDsp->ALU.part.L == 0) ScuDsp->ProgControlPort.part.Z = 1; else ScuDsp->ProgControlPort.part.Z = 0; if ((s64)ScuDsp->ALU.part.L < 0) ScuDsp->ProgControlPort.part.S = 1; else ScuDsp->ProgControlPort.part.S = 0; ScuDsp->ProgControlPort.part.C = 0; break; case 0x3: // XOR ScuDsp->ALU.all = (s64)(ScuDsp->AC.part.L ^ (u32)ScuDsp->P.part.L) | (ScuDsp->AC.part.L & 0xffff00000000); if (ScuDsp->ALU.part.L == 0) ScuDsp->ProgControlPort.part.Z = 1; else ScuDsp->ProgControlPort.part.Z = 0; if ((s64)ScuDsp->ALU.part.L < 0) ScuDsp->ProgControlPort.part.S = 1; else ScuDsp->ProgControlPort.part.S = 0; ScuDsp->ProgControlPort.part.C = 0; break; case 0x4: // ADD ScuDsp->ALU.all = (u64)((u32)ScuDsp->AC.part.L + (u32)ScuDsp->P.part.L) | (ScuDsp->AC.part.L & 0xffff00000000); if (ScuDsp->ALU.part.L == 0) ScuDsp->ProgControlPort.part.Z = 1; else ScuDsp->ProgControlPort.part.Z = 0; if ((s64)ScuDsp->ALU.part.L < 0) ScuDsp->ProgControlPort.part.S = 1; else ScuDsp->ProgControlPort.part.S = 0; //0x00000001 + 0xFFFFFFFF will set the carry bit, needs to be unsigned math if (((u64)(u32)ScuDsp->P.part.L + (u64)(u32)ScuDsp->AC.part.L) & 0x100000000) ScuDsp->ProgControlPort.part.C = 1; else ScuDsp->ProgControlPort.part.C = 0; //if (ScuDsp->ALU.part.L ??) // set overflow flag // ScuDsp->ProgControlPort.part.V = 1; //else // ScuDsp->ProgControlPort.part.V = 0; break; case 0x5: // SUB ScuDsp->ALU.all = (s64)((s32)ScuDsp->AC.part.L - (u32)ScuDsp->P.part.L) | (ScuDsp->AC.part.L & 0xffff00000000); if (ScuDsp->ALU.part.L == 0) ScuDsp->ProgControlPort.part.Z = 1; else ScuDsp->ProgControlPort.part.Z = 0; if ((s64)ScuDsp->ALU.part.L < 0) ScuDsp->ProgControlPort.part.S = 1; else ScuDsp->ProgControlPort.part.S = 0; //0x00000001 - 0xFFFFFFFF will set the carry bit, needs to be unsigned math if ((((u64)(u32)ScuDsp->AC.part.L - (u64)(u32)ScuDsp->P.part.L)) & 0x100000000) ScuDsp->ProgControlPort.part.C = 1; else ScuDsp->ProgControlPort.part.C = 0; // if (ScuDsp->ALU.part.L ??) // set overflow flag // ScuDsp->ProgControlPort.part.V = 1; // else // ScuDsp->ProgControlPort.part.V = 0; break; case 0x6: // AD2 ScuDsp->ALU.all = (s64)ScuDsp->AC.all + (s64)ScuDsp->P.all; if (ScuDsp->ALU.all == 0) ScuDsp->ProgControlPort.part.Z = 1; else ScuDsp->ProgControlPort.part.Z = 0; //0x500000000000 + 0xd00000000000 will set the sign bit if (ScuDsp->ALU.all & 0x800000000000) ScuDsp->ProgControlPort.part.S = 1; else ScuDsp->ProgControlPort.part.S = 0; //AC.all and P.all are sign-extended so we need to mask it off and check for a carry if (((ScuDsp->AC.all & 0xffffffffffff) + (ScuDsp->P.all & 0xffffffffffff)) & (0x1000000000000)) ScuDsp->ProgControlPort.part.C = 1; else ScuDsp->ProgControlPort.part.C = 0; // if (ScuDsp->ALU.part.unused != 0) // ScuDsp->ProgControlPort.part.V = 1; // else // ScuDsp->ProgControlPort.part.V = 0; break; case 0x8: // SR ScuDsp->ProgControlPort.part.C = ScuDsp->AC.part.L & 0x1; ScuDsp->ALU.all = (s64)((ScuDsp->AC.part.L & 0x80000000) | (ScuDsp->AC.part.L >> 1)) | (ScuDsp->AC.part.L & 0xffff00000000); if (ScuDsp->ALU.all == 0) ScuDsp->ProgControlPort.part.Z = 1; else ScuDsp->ProgControlPort.part.Z = 0; if ((s64)ScuDsp->ALU.part.L < 0) ScuDsp->ProgControlPort.part.S = 1; else ScuDsp->ProgControlPort.part.S = 0; //0x00000001 >> 1 will set the carry bit //ScuDsp->ProgControlPort.part.C = ScuDsp->ALU.part.L >> 31; would not handle this case break; case 0x9: // RR ScuDsp->ProgControlPort.part.C = ScuDsp->AC.part.L & 0x1; ScuDsp->ALU.all = (s64)((ScuDsp->ProgControlPort.part.C << 31) | ((u32)ScuDsp->AC.part.L >> 1) | (ScuDsp->AC.part.L & 0xffff00000000)); if (ScuDsp->ALU.all == 0) ScuDsp->ProgControlPort.part.Z = 1; else ScuDsp->ProgControlPort.part.Z = 0; //rotating 0x00000001 right will produce 0x80000000 and set //the sign bit. if (ScuDsp->ALU.part.L < 0) ScuDsp->ProgControlPort.part.S = 1; else ScuDsp->ProgControlPort.part.S = 0; break; case 0xA: // SL ScuDsp->ProgControlPort.part.C = ScuDsp->AC.part.L >> 31; ScuDsp->ALU.all = (s64)((u32)(ScuDsp->AC.part.L << 1)) | (ScuDsp->AC.part.L & 0xffff00000000); if (ScuDsp->ALU.part.L == 0) ScuDsp->ProgControlPort.part.Z = 1; else ScuDsp->ProgControlPort.part.Z = 0; if ((s64)ScuDsp->ALU.part.L < 0) ScuDsp->ProgControlPort.part.S = 1; else ScuDsp->ProgControlPort.part.S = 0; break; case 0xB: // RL ScuDsp->ProgControlPort.part.C = ScuDsp->AC.part.L >> 31; ScuDsp->ALU.all = (s64)(((u32)ScuDsp->AC.part.L << 1) | ScuDsp->ProgControlPort.part.C) | (ScuDsp->AC.part.L & 0xffff00000000); if (ScuDsp->ALU.all == 0) ScuDsp->ProgControlPort.part.Z = 1; else ScuDsp->ProgControlPort.part.Z = 0; if ((s64)ScuDsp->ALU.part.L < 0) ScuDsp->ProgControlPort.part.S = 1; else ScuDsp->ProgControlPort.part.S = 0; break; case 0xF: // RL8 ScuDsp->ALU.all = (s64)((u32)(ScuDsp->AC.part.L << 8) | ((ScuDsp->AC.part.L >> 24) & 0xFF)) | (ScuDsp->AC.part.L & 0xffff00000000); if (ScuDsp->ALU.all == 0) ScuDsp->ProgControlPort.part.Z = 1; else ScuDsp->ProgControlPort.part.Z = 0; //rotating 0x00ffffff left 8 will produce 0xffffff00 and //set the sign bit if ((s64)ScuDsp->ALU.part.L < 0) ScuDsp->ProgControlPort.part.S = 1; else ScuDsp->ProgControlPort.part.S = 0; //rotating 0xff000000 left 8 will produce 0x000000ff and set the //carry bit ScuDsp->ProgControlPort.part.C = (ScuDsp->AC.part.L >> 24) & 1; break; default: break; } switch (instruction >> 30) { case 0x00: // Operation Commands // X-bus if ((instruction >> 23) & 0x4) { // MOV [s], X ScuDsp->RX = readgensrc((instruction >> 20) & 0x7); } switch ((instruction >> 23) & 0x3) { case 2: // MOV MUL, P ScuDsp->P.all = ScuDsp->MUL.all; break; case 3: // MOV [s], P //s32 cast to sign extend ScuDsp->P.all = (s64)(s32)readgensrc((instruction >> 20) & 0x7); break; default: break; } // Y-bus if ((instruction >> 17) & 0x4) { // MOV [s], Y ScuDsp->RY = readgensrc((instruction >> 14) & 0x7); } switch ((instruction >> 17) & 0x3) { case 1: // CLR A ScuDsp->AC.all = 0; break; case 2: // MOV ALU,A ScuDsp->AC.all = ScuDsp->ALU.all; break; case 3: // MOV [s],A //s32 cast to sign extend ScuDsp->AC.all = (s64)(s32)readgensrc((instruction >> 14) & 0x7); break; default: break; } if (incFlg[0] != 0){ ScuDsp->CT[0]++; ScuDsp->CT[0] &= 0x3f; incFlg[0] = 0; }; if (incFlg[1] != 0){ ScuDsp->CT[1]++; ScuDsp->CT[1] &= 0x3f; incFlg[1] = 0; }; if (incFlg[2] != 0){ ScuDsp->CT[2]++; ScuDsp->CT[2] &= 0x3f; incFlg[2] = 0; }; if (incFlg[3] != 0){ ScuDsp->CT[3]++; ScuDsp->CT[3] &= 0x3f; incFlg[3] = 0; }; // D1-bus switch ((instruction >> 12) & 0x3) { case 1: // MOV SImm,[d] writed1busdest((instruction >> 8) & 0xF, (u32)(signed char)(instruction & 0xFF)); break; case 3: // MOV [s],[d] writed1busdest((instruction >> 8) & 0xF, readgensrc(instruction & 0xF)); if (incFlg[0] != 0){ ScuDsp->CT[0]++; ScuDsp->CT[0] &= 0x3f; incFlg[0] = 0; }; if (incFlg[1] != 0){ ScuDsp->CT[1]++; ScuDsp->CT[1] &= 0x3f; incFlg[1] = 0; }; if (incFlg[2] != 0){ ScuDsp->CT[2]++; ScuDsp->CT[2] &= 0x3f; incFlg[2] = 0; }; if (incFlg[3] != 0){ ScuDsp->CT[3]++; ScuDsp->CT[3] &= 0x3f; incFlg[3] = 0; }; break; default: break; } break; case 0x02: // Load Immediate Commands if ((instruction >> 25) & 1) { switch ((instruction >> 19) & 0x3F) { case 0x01: // MVI Imm,[d]NZ if (!ScuDsp->ProgControlPort.part.Z) writeloadimdest((instruction >> 26) & 0xF, (instruction & 0x7FFFF) | ((instruction & 0x40000) ? 0xFFF80000 : 0x00000000)); break; case 0x02: // MVI Imm,[d]NS if (!ScuDsp->ProgControlPort.part.S) writeloadimdest((instruction >> 26) & 0xF, (instruction & 0x7FFFF) | ((instruction & 0x40000) ? 0xFFF80000 : 0x00000000)); break; case 0x03: // MVI Imm,[d]NZS if (!ScuDsp->ProgControlPort.part.Z || !ScuDsp->ProgControlPort.part.S) writeloadimdest((instruction >> 26) & 0xF, (instruction & 0x7FFFF) | ((instruction & 0x40000) ? 0xFFF80000 : 0x00000000)); break; case 0x04: // MVI Imm,[d]NC if (!ScuDsp->ProgControlPort.part.C) writeloadimdest((instruction >> 26) & 0xF, (instruction & 0x7FFFF) | ((instruction & 0x40000) ? 0xFFF80000 : 0x00000000)); break; case 0x08: // MVI Imm,[d]NT0 if (!ScuDsp->ProgControlPort.part.T0) writeloadimdest((instruction >> 26) & 0xF, (instruction & 0x7FFFF) | ((instruction & 0x40000) ? 0xFFF80000 : 0x00000000)); break; case 0x21: // MVI Imm,[d]Z if (ScuDsp->ProgControlPort.part.Z) writeloadimdest((instruction >> 26) & 0xF, (instruction & 0x7FFFF) | ((instruction & 0x40000) ? 0xFFF80000 : 0x00000000)); break; case 0x22: // MVI Imm,[d]S if (ScuDsp->ProgControlPort.part.S) writeloadimdest((instruction >> 26) & 0xF, (instruction & 0x7FFFF) | ((instruction & 0x40000) ? 0xFFF80000 : 0x00000000)); break; case 0x23: // MVI Imm,[d]ZS if (ScuDsp->ProgControlPort.part.Z || ScuDsp->ProgControlPort.part.S) writeloadimdest((instruction >> 26) & 0xF, (instruction & 0x7FFFF) | ((instruction & 0x40000) ? 0xFFF80000 : 0x00000000)); break; case 0x24: // MVI Imm,[d]C if (ScuDsp->ProgControlPort.part.C) writeloadimdest((instruction >> 26) & 0xF, (instruction & 0x7FFFF) | ((instruction & 0x40000) ? 0xFFF80000 : 0x00000000)); break; case 0x28: // MVI Imm,[d]T0 if (ScuDsp->ProgControlPort.part.T0) writeloadimdest((instruction >> 26) & 0xF, (instruction & 0x7FFFF) | ((instruction & 0x40000) ? 0xFFF80000 : 0x00000000)); break; default: break; } } else { // MVI Imm,[d] int value = (instruction & 0x1FFFFFF); if (value & 0x1000000) value |= 0xfe000000; writeloadimdest((instruction >> 26) & 0xF, value); } break; case 0x03: // Other { switch((instruction >> 28) & 0xF) { case 0x0C: // DMA Commands { if (((instruction >> 10) & 0x1F) == 0x00/*0x08*/) { dsp_dma01(ScuDsp, instruction); } else if (((instruction >> 10) & 0x1F) == 0x04) { dsp_dma02(ScuDsp, instruction); } else if (((instruction >> 11) & 0x0F) == 0x04) { dsp_dma03(ScuDsp, instruction); } else if (((instruction >> 10) & 0x1F) == 0x0C) { dsp_dma04(ScuDsp, instruction); } else if (((instruction >> 11) & 0x0F) == 0x08) { dsp_dma05(ScuDsp, instruction); } else if (((instruction >> 10) & 0x1F) == 0x14) { dsp_dma06(ScuDsp, instruction); } else if (((instruction >> 11) & 0x0F) == 0x0C) { dsp_dma07(ScuDsp, instruction); } else if (((instruction >> 10) & 0x1F) == 0x1C) { dsp_dma08(ScuDsp, instruction); } break; } case 0x0D: // Jump Commands switch ((instruction >> 19) & 0x7F) { case 0x00: // JMP Imm ScuDsp->jmpaddr = instruction & 0xFF; ScuDsp->delayed = 0; break; case 0x41: // JMP NZ, Imm if (!ScuDsp->ProgControlPort.part.Z) { ScuDsp->jmpaddr = instruction & 0xFF; ScuDsp->delayed = 0; } break; case 0x42: // JMP NS, Imm if (!ScuDsp->ProgControlPort.part.S) { ScuDsp->jmpaddr = instruction & 0xFF; ScuDsp->delayed = 0; } LOG("scu\t: JMP NS: S = %d, jmpaddr = %08X\n", (unsigned int)ScuDsp->ProgControlPort.part.S, (unsigned int)ScuDsp->jmpaddr); break; case 0x43: // JMP NZS, Imm if (!ScuDsp->ProgControlPort.part.Z || !ScuDsp->ProgControlPort.part.S) { ScuDsp->jmpaddr = instruction & 0xFF; ScuDsp->delayed = 0; } LOG("scu\t: JMP NZS: Z = %d, S = %d, jmpaddr = %08X\n", (unsigned int)ScuDsp->ProgControlPort.part.Z, (unsigned int)ScuDsp->ProgControlPort.part.S, (unsigned int)ScuDsp->jmpaddr); break; case 0x44: // JMP NC, Imm if (!ScuDsp->ProgControlPort.part.C) { ScuDsp->jmpaddr = instruction & 0xFF; ScuDsp->delayed = 0; } break; case 0x48: // JMP NT0, Imm if (!ScuDsp->ProgControlPort.part.T0) { ScuDsp->jmpaddr = instruction & 0xFF; ScuDsp->delayed = 0; } LOG("scu\t: JMP NT0: T0 = %d, jmpaddr = %08X\n", (unsigned int)ScuDsp->ProgControlPort.part.T0, (unsigned int)ScuDsp->jmpaddr); break; case 0x61: // JMP Z,Imm if (ScuDsp->ProgControlPort.part.Z) { ScuDsp->jmpaddr = instruction & 0xFF; ScuDsp->delayed = 0; } break; case 0x62: // JMP S, Imm if (ScuDsp->ProgControlPort.part.S) { ScuDsp->jmpaddr = instruction & 0xFF; ScuDsp->delayed = 0; } LOG("scu\t: JMP S: S = %d, jmpaddr = %08X\n", (unsigned int)ScuDsp->ProgControlPort.part.S, (unsigned int)ScuDsp->jmpaddr); break; case 0x63: // JMP ZS, Imm if (ScuDsp->ProgControlPort.part.Z || ScuDsp->ProgControlPort.part.S) { ScuDsp->jmpaddr = instruction & 0xFF; ScuDsp->delayed = 0; } LOG("scu\t: JMP ZS: Z = %d, S = %d, jmpaddr = %08X\n", ScuDsp->ProgControlPort.part.Z, (unsigned int)ScuDsp->ProgControlPort.part.S, (unsigned int)ScuDsp->jmpaddr); break; case 0x64: // JMP C, Imm if (ScuDsp->ProgControlPort.part.C) { ScuDsp->jmpaddr = instruction & 0xFF; ScuDsp->delayed = 0; } break; case 0x68: // JMP T0,Imm if (ScuDsp->ProgControlPort.part.T0) { ScuDsp->jmpaddr = instruction & 0xFF; ScuDsp->delayed = 0; } break; default: LOG("scu\t: Unknown JMP instruction not implemented\n"); break; } break; case 0x0E: // Loop bottom Commands if (instruction & 0x8000000) { // LPS if (ScuDsp->LOP != 0) { ScuDsp->jmpaddr = ScuDsp->PC; ScuDsp->delayed = 0; ScuDsp->LOP--; } } else { // BTM if (ScuDsp->LOP != 0) { ScuDsp->jmpaddr = ScuDsp->TOP; ScuDsp->delayed = 0; ScuDsp->LOP--; } } break; case 0x0F: // End Commands ScuDsp->ProgControlPort.part.EX = 0; if (instruction & 0x8000000) { // End with Interrupt ScuDsp->ProgControlPort.part.E = 1; ScuSendDSPEnd(); } LOG("dsp has ended\n"); //dsp_trace_log("END\n"); ScuDsp->ProgControlPort.part.P = ScuDsp->PC+1; timing = 1; break; default: break; } break; } default: LOG("scu\t: Invalid DSP opcode %08X at offset %02X\n", instruction, ScuDsp->PC); break; } ScuDsp->MUL.all = (s64)ScuDsp->RX * (s64)ScuDsp->RY; //LOG("RX=%08X,RY=%08X,MUL=%16X\n", ScuDsp->RX, ScuDsp->RY, ScuDsp->MUL.all); //LOG("RX=%08X,RY=%08X,MUL=%16X\n", ScuDsp->RX, ScuDsp->RY, ScuDsp->MUL.all); //dsp_trace_log("RX=%08X,RY=%08X,MUL=%16X\n", ScuDsp->RX, ScuDsp->RY, ScuDsp->MUL.all); ScuDsp->PC++; // Handle delayed jumps if (ScuDsp->jmpaddr != 0xFFFFFFFF) { if (ScuDsp->delayed) { ScuDsp->PC = (unsigned char)ScuDsp->jmpaddr; ScuDsp->jmpaddr = 0xFFFFFFFF; } else ScuDsp->delayed = 1; } timing--; } } if (scu_dma_cycles > 0) { scu_dma_tick_all(scu_dma_cycles); } } ////////////////////////////////////////////////////////////////////////////// static char *disd1bussrc(u8 num) { switch(num) { case 0x0: return "M0"; case 0x1: return "M1"; case 0x2: return "M2"; case 0x3: return "M3"; case 0x4: return "MC0"; case 0x5: return "MC1"; case 0x6: return "MC2"; case 0x7: return "MC3"; case 0x9: return "ALL"; case 0xA: return "ALH"; default: break; } return "??"; } ////////////////////////////////////////////////////////////////////////////// static char *disd1busdest(u8 num) { switch(num) { case 0x0: return "MC0"; case 0x1: return "MC1"; case 0x2: return "MC2"; case 0x3: return "MC3"; case 0x4: return "RX"; case 0x5: return "PL"; case 0x6: return "RA0"; case 0x7: return "WA0"; case 0xA: return "LOP"; case 0xB: return "TOP"; case 0xC: return "CT0"; case 0xD: return "CT1"; case 0xE: return "CT2"; case 0xF: return "CT3"; default: break; } return "??"; } ////////////////////////////////////////////////////////////////////////////// static char *disloadimdest(u8 num) { switch(num) { case 0x0: return "MC0"; case 0x1: return "MC1"; case 0x2: return "MC2"; case 0x3: return "MC3"; case 0x4: return "RX"; case 0x5: return "PL"; case 0x6: return "RA0"; case 0x7: return "WA0"; case 0xA: return "LOP"; case 0xC: return "PC"; default: break; } return "??"; } ////////////////////////////////////////////////////////////////////////////// static char *disdmaram(u8 num) { switch(num) { case 0x0: // MC0 return "MC0"; case 0x1: // MC1 return "MC1"; case 0x2: // MC2 return "MC2"; case 0x3: // MC3 return "MC3"; case 0x4: // Program Ram return "PRG"; default: break; } return "??"; } ////////////////////////////////////////////////////////////////////////////// void ScuDspDisasm(u8 addr, char *outstring) { u32 instruction; u8 counter=0; u8 filllength=0; instruction = ScuDsp->ProgramRam[addr]; sprintf(outstring, "%02X: ", addr); outstring+=strlen(outstring); if (instruction == 0) { sprintf(outstring, "NOP"); return; } // Handle ALU commands switch (instruction >> 26) { case 0x0: // NOP break; case 0x1: // AND sprintf(outstring, "AND"); counter = (u8)strlen(outstring); outstring+=(u8)strlen(outstring); break; case 0x2: // OR sprintf(outstring, "OR"); counter = (u8)strlen(outstring); outstring+=(u8)strlen(outstring); break; case 0x3: // XOR sprintf(outstring, "XOR"); counter = (u8)strlen(outstring); outstring+=(u8)strlen(outstring); break; case 0x4: // ADD sprintf(outstring, "ADD"); counter = (u8)strlen(outstring); outstring+=(u8)strlen(outstring); break; case 0x5: // SUB sprintf(outstring, "SUB"); counter = (u8)strlen(outstring); outstring+=(u8)strlen(outstring); break; case 0x6: // AD2 sprintf(outstring, "AD2"); counter = (u8)strlen(outstring); outstring+=(u8)strlen(outstring); break; case 0x8: // SR sprintf(outstring, "SR"); counter = (u8)strlen(outstring); outstring+=(u8)strlen(outstring); break; case 0x9: // RR sprintf(outstring, "RR"); counter = (u8)strlen(outstring); outstring+=(u8)strlen(outstring); break; case 0xA: // SL sprintf(outstring, "SL"); counter = (u8)strlen(outstring); outstring+=(u8)strlen(outstring); break; case 0xB: // RL sprintf(outstring, "RL"); counter = (u8)strlen(outstring); outstring+=(u8)strlen(outstring); break; case 0xF: // RL8 sprintf(outstring, "RL8"); counter = (u8)strlen(outstring); outstring+=(u8)strlen(outstring); break; default: break; } switch (instruction >> 30) { case 0x00: // Operation Commands filllength = 5 - counter; memset((void *)outstring, 0x20, filllength); counter += filllength; outstring += filllength; if ((instruction >> 23) & 0x4) { sprintf(outstring, "MOV %s, X", disd1bussrc((instruction >> 20) & 0x7)); counter+=(u8)strlen(outstring); outstring+=(u8)strlen(outstring); } filllength = 16 - counter; memset((void *)outstring, 0x20, filllength); counter += filllength; outstring += filllength; switch ((instruction >> 23) & 0x3) { case 2: sprintf(outstring, "MOV MUL, P"); counter+=(u8)strlen(outstring); outstring+=(u8)strlen(outstring); break; case 3: sprintf(outstring, "MOV %s, P", disd1bussrc((instruction >> 20) & 0x7)); counter+=(u8)strlen(outstring); outstring+=(u8)strlen(outstring); break; default: break; } filllength = 27 - counter; memset((void *)outstring, 0x20, filllength); counter += filllength; outstring += filllength; // Y-bus if ((instruction >> 17) & 0x4) { sprintf(outstring, "MOV %s, Y", disd1bussrc((instruction >> 14) & 0x7)); counter+=(u8)strlen(outstring); outstring+=(u8)strlen(outstring); } filllength = 38 - counter; memset((void *)outstring, 0x20, filllength); counter += filllength; outstring += filllength; switch ((instruction >> 17) & 0x3) { case 1: sprintf(outstring, "CLR A"); counter+=(u8)strlen(outstring); outstring+=(u8)strlen(outstring); break; case 2: sprintf(outstring, "MOV ALU, A"); counter+=(u8)strlen(outstring); outstring+=(u8)strlen(outstring); break; case 3: sprintf(outstring, "MOV %s, A", disd1bussrc((instruction >> 14) & 0x7)); counter+=(u8)strlen(outstring); outstring+=(u8)strlen(outstring); break; default: break; } filllength = 50 - counter; memset((void *)outstring, 0x20, filllength); counter += filllength; outstring += filllength; // D1-bus switch ((instruction >> 12) & 0x3) { case 1: sprintf(outstring, "MOV #$%02X, %s", (unsigned int)instruction & 0xFF, disd1busdest((instruction >> 8) & 0xF)); outstring+=(u8)strlen(outstring); break; case 3: sprintf(outstring, "MOV %s, %s", disd1bussrc(instruction & 0xF), disd1busdest((instruction >> 8) & 0xF)); outstring+=(u8)strlen(outstring); break; default: outstring[0] = 0x00; break; } break; case 0x02: // Load Immediate Commands if ((instruction >> 25) & 1) { switch ((instruction >> 19) & 0x3F) { case 0x01: sprintf(outstring, "MVI #$%05X,%s,NZ", (unsigned int)instruction & 0x7FFFF, disloadimdest((instruction >> 26) & 0xF)); break; case 0x02: sprintf(outstring, "MVI #$%05X,%s,NS", (unsigned int)instruction & 0x7FFFF, disloadimdest((instruction >> 26) & 0xF)); break; case 0x03: sprintf(outstring, "MVI #$%05X,%s,NZS", (unsigned int)instruction & 0x7FFFF, disloadimdest((instruction >> 26) & 0xF)); break; case 0x04: sprintf(outstring, "MVI #$%05X,%s,NC", (unsigned int)instruction & 0x7FFFF, disloadimdest((instruction >> 26) & 0xF)); break; case 0x08: sprintf(outstring, "MVI #$%05X,%s,NT0", (unsigned int)instruction & 0x7FFFF, disloadimdest((instruction >> 26) & 0xF)); break; case 0x21: sprintf(outstring, "MVI #$%05X,%s,Z", (unsigned int)instruction & 0x7FFFF, disloadimdest((instruction >> 26) & 0xF)); break; case 0x22: sprintf(outstring, "MVI #$%05X,%s,S", (unsigned int)instruction & 0x7FFFF, disloadimdest((instruction >> 26) & 0xF)); break; case 0x23: sprintf(outstring, "MVI #$%05X,%s,ZS", (unsigned int)instruction & 0x7FFFF, disloadimdest((instruction >> 26) & 0xF)); break; case 0x24: sprintf(outstring, "MVI #$%05X,%s,C", (unsigned int)instruction & 0x7FFFF, disloadimdest((instruction >> 26) & 0xF)); break; case 0x28: sprintf(outstring, "MVI #$%05X,%s,T0", (unsigned int)instruction & 0x7FFFF, disloadimdest((instruction >> 26) & 0xF)); break; default: break; } } else { //sprintf(outstring, "MVI #$%08X,%s", (instruction & 0xFFFFFF) | ((instruction & 0x1000000) ? 0xFF000000 : 0x00000000), disloadimdest((instruction >> 26) & 0xF)); sprintf(outstring, "MVI #$%08X,%s", (instruction & 0x1FFFFFF) << 2,disloadimdest((instruction >> 26) & 0xF)); } break; case 0x03: // Other switch((instruction >> 28) & 0x3) { case 0x00: // DMA Commands { int addressAdd; if (instruction & 0x1000) addressAdd = (instruction >> 15) & 0x7; else addressAdd = (instruction >> 15) & 0x1; switch(addressAdd) { case 0: // Add 0 addressAdd = 0; break; case 1: // Add 1 addressAdd = 1; break; case 2: // Add 2 addressAdd = 2; break; case 3: // Add 4 addressAdd = 4; break; case 4: // Add 8 addressAdd = 8; break; case 5: // Add 16 addressAdd = 16; break; case 6: // Add 32 addressAdd = 32; break; case 7: // Add 64 addressAdd = 64; break; default: addressAdd = 0; break; } LOG("DMA Add = %X, addressAdd = %d", (instruction >> 15) & 0x7, addressAdd); // Write Command name sprintf(outstring, "DMA"); outstring+=(u8)strlen(outstring); // Is h bit set? if (instruction & 0x4000) { outstring[0] = 'H'; outstring++; } sprintf(outstring, "%d ", addressAdd); outstring+=(u8)strlen(outstring); if (instruction & 0x2000) { // Command Format 2 if (instruction & 0x1000) sprintf(outstring, "%s, D0, %s", disdmaram((instruction >> 8) & 0x7), disd1bussrc(instruction & 0x7)); else sprintf(outstring, "D0, %s, %s", disdmaram((instruction >> 8) & 0x7), disd1bussrc(instruction & 0x7)); } else { // Command Format 1 if (instruction & 0x1000) sprintf(outstring, "%s, D0, #$%02X", disdmaram((instruction >> 8) & 0x7), (int)(instruction & 0xFF)); else sprintf(outstring, "D0, %s, #$%02X", disdmaram((instruction >> 8) & 0x7), (int)(instruction & 0xFF)); } break; } case 0x01: // Jump Commands switch ((instruction >> 19) & 0x7F) { case 0x00: sprintf(outstring, "JMP $%02X", (unsigned int)instruction & 0xFF); break; case 0x41: sprintf(outstring, "JMP NZ,$%02X", (unsigned int)instruction & 0xFF); break; case 0x42: sprintf(outstring, "JMP NS,$%02X", (unsigned int)instruction & 0xFF); break; case 0x43: sprintf(outstring, "JMP NZS,$%02X", (unsigned int)instruction & 0xFF); break; case 0x44: sprintf(outstring, "JMP NC,$%02X", (unsigned int)instruction & 0xFF); break; case 0x48: sprintf(outstring, "JMP NT0,$%02X", (unsigned int)instruction & 0xFF); break; case 0x61: sprintf(outstring, "JMP Z,$%02X", (unsigned int)instruction & 0xFF); break; case 0x62: sprintf(outstring, "JMP S,$%02X", (unsigned int)instruction & 0xFF); break; case 0x63: sprintf(outstring, "JMP ZS,$%02X", (unsigned int)instruction & 0xFF); break; case 0x64: sprintf(outstring, "JMP C,$%02X", (unsigned int)instruction & 0xFF); break; case 0x68: sprintf(outstring, "JMP T0,$%02X", (unsigned int)instruction & 0xFF); break; default: sprintf(outstring, "Unknown JMP"); break; } break; case 0x02: // Loop bottom Commands if (instruction & 0x8000000) sprintf(outstring, "LPS"); else sprintf(outstring, "BTM"); break; case 0x03: // End Commands if (instruction & 0x8000000) sprintf(outstring, "ENDI"); else sprintf(outstring, "END"); break; default: break; } break; default: sprintf(outstring, "Invalid opcode"); break; } } ////////////////////////////////////////////////////////////////////////////// void ScuDspStep(void) { if (ScuDsp) ScuExec(1); } ////////////////////////////////////////////////////////////////////////////// int ScuDspSaveProgram(const char *filename) { FILE *fp; u32 i; u8 *buffer; if (!filename) return -1; if ((fp = fopen(filename, "wb")) == NULL) return -1; if ((buffer = (u8 *)malloc(sizeof(ScuDsp->ProgramRam))) == NULL) { fclose(fp); return -2; } for (i = 0; i < 256; i++) { buffer[i * 4] = (u8)(ScuDsp->ProgramRam[i] >> 24); buffer[(i * 4)+1] = (u8)(ScuDsp->ProgramRam[i] >> 16); buffer[(i * 4)+2] = (u8)(ScuDsp->ProgramRam[i] >> 8); buffer[(i * 4)+3] = (u8)ScuDsp->ProgramRam[i]; } fwrite((void *)buffer, 1, sizeof(ScuDsp->ProgramRam), fp); fclose(fp); free(buffer); return 0; } ////////////////////////////////////////////////////////////////////////////// int ScuDspSaveMD(const char *filename, int num) { FILE *fp; u32 i; u8 *buffer; if (!filename) return -1; if ((fp = fopen(filename, "wb")) == NULL) return -1; if ((buffer = (u8 *)malloc(sizeof(ScuDsp->MD[num]))) == NULL) { fclose(fp); return -2; } for (i = 0; i < 64; i++) { buffer[i * 4] = (u8)(ScuDsp->MD[num][i] >> 24); buffer[(i * 4)+1] = (u8)(ScuDsp->MD[num][i] >> 16); buffer[(i * 4)+2] = (u8)(ScuDsp->MD[num][i] >> 8); buffer[(i * 4)+3] = (u8)ScuDsp->MD[num][i]; } fwrite((void *)buffer, 1, sizeof(ScuDsp->MD[num]), fp); fclose(fp); free(buffer); return 0; } ////////////////////////////////////////////////////////////////////////////// void ScuDspGetRegisters(scudspregs_struct *regs) { if (regs != NULL) { memcpy(regs->ProgramRam, ScuDsp->ProgramRam, sizeof(u32) * 256); memcpy(regs->MD, ScuDsp->MD, sizeof(u32) * 64 * 4); regs->ProgControlPort.all = ScuDsp->ProgControlPort.all; regs->ProgControlPort.part.P = regs->PC = ScuDsp->PC; regs->TOP = ScuDsp->TOP; regs->LOP = ScuDsp->LOP; regs->jmpaddr = ScuDsp->jmpaddr; regs->delayed = ScuDsp->delayed; regs->DataRamPage = ScuDsp->DataRamPage; regs->DataRamReadAddress = ScuDsp->DataRamReadAddress; memcpy(regs->CT, ScuDsp->CT, sizeof(u8) * 4); regs->RX = ScuDsp->RX; regs->RY = ScuDsp->RY; regs->RA0 = ScuDsp->RA0; regs->WA0 = ScuDsp->WA0; regs->AC.all = ScuDsp->AC.all; regs->P.all = ScuDsp->P.all; regs->ALU.all = ScuDsp->ALU.all; regs->MUL.all = ScuDsp->MUL.all; } } ////////////////////////////////////////////////////////////////////////////// void ScuDspSetRegisters(scudspregs_struct *regs) { if (regs != NULL) { memcpy(ScuDsp->ProgramRam, regs->ProgramRam, sizeof(u32) * 256); memcpy(ScuDsp->MD, regs->MD, sizeof(u32) * 64 * 4); ScuDsp->ProgControlPort.all = regs->ProgControlPort.all; ScuDsp->PC = regs->ProgControlPort.part.P; ScuDsp->TOP = regs->TOP; ScuDsp->LOP = regs->LOP; ScuDsp->jmpaddr = regs->jmpaddr; ScuDsp->delayed = regs->delayed; ScuDsp->DataRamPage = regs->DataRamPage; ScuDsp->DataRamReadAddress = regs->DataRamReadAddress; memcpy(ScuDsp->CT, regs->CT, sizeof(u8) * 4); ScuDsp->RX = regs->RX; ScuDsp->RY = regs->RY; ScuDsp->RA0 = regs->RA0; ScuDsp->WA0 = regs->WA0; ScuDsp->AC.all = regs->AC.all; ScuDsp->P.all = regs->P.all; ScuDsp->ALU.all = regs->ALU.all; ScuDsp->MUL.all = regs->MUL.all; } } ////////////////////////////////////////////////////////////////////////////// void ScuDspSetBreakpointCallBack(void (*func)(u32)) { ScuBP->BreakpointCallBack = func; } ////////////////////////////////////////////////////////////////////////////// int ScuDspAddCodeBreakpoint(u32 addr) { int i; if (ScuBP->numcodebreakpoints < MAX_BREAKPOINTS) { // Make sure it isn't already on the list for (i = 0; i < ScuBP->numcodebreakpoints; i++) { if (addr == ScuBP->codebreakpoint[i].addr) return -1; } ScuBP->codebreakpoint[ScuBP->numcodebreakpoints].addr = addr; ScuBP->numcodebreakpoints++; return 0; } return -1; } ////////////////////////////////////////////////////////////////////////////// static void ScuDspSortCodeBreakpoints(void) { int i, i2; u32 tmp; for (i = 0; i < (MAX_BREAKPOINTS-1); i++) { for (i2 = i+1; i2 < MAX_BREAKPOINTS; i2++) { if (ScuBP->codebreakpoint[i].addr == 0xFFFFFFFF && ScuBP->codebreakpoint[i2].addr != 0xFFFFFFFF) { tmp = ScuBP->codebreakpoint[i].addr; ScuBP->codebreakpoint[i].addr = ScuBP->codebreakpoint[i2].addr; ScuBP->codebreakpoint[i2].addr = tmp; } } } } ////////////////////////////////////////////////////////////////////////////// int ScuDspDelCodeBreakpoint(u32 addr) { int i; if (ScuBP->numcodebreakpoints > 0) { for (i = 0; i < ScuBP->numcodebreakpoints; i++) { if (ScuBP->codebreakpoint[i].addr == addr) { ScuBP->codebreakpoint[i].addr = 0xFFFFFFFF; ScuDspSortCodeBreakpoints(); ScuBP->numcodebreakpoints--; return 0; } } } return -1; } ////////////////////////////////////////////////////////////////////////////// scucodebreakpoint_struct *ScuDspGetBreakpointList(void) { return ScuBP->codebreakpoint; } ////////////////////////////////////////////////////////////////////////////// void ScuDspClearCodeBreakpoints(void) { int i; for (i = 0; i < MAX_BREAKPOINTS; i++) ScuBP->codebreakpoint[i].addr = 0xFFFFFFFF; ScuBP->numcodebreakpoints = 0; } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL ScuReadByte(u32 addr) { addr &= 0xFF; switch(addr) { case 0xA7: return (ScuRegs->IST & 0xFF); default: LOG("Unhandled SCU Register byte read %08X\n", addr); return 0; } return 0; } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL ScuReadWord(u32 addr) { addr &= 0xFF; LOG("Unhandled SCU Register word read %08X\n", addr); return 0; } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL ScuReadLong(u32 addr) { addr &= 0xFF; switch(addr) { case 0: return ScuRegs->D0R; case 4: return ScuRegs->D0W; case 8: return ScuRegs->D0C; case 0x20: return ScuRegs->D1R; case 0x24: return ScuRegs->D1W; case 0x28: return ScuRegs->D1C; case 0x40: return ScuRegs->D2R; case 0x44: return ScuRegs->D2W; case 0x48: return ScuRegs->D2C; case 0x7C: return ScuRegs->DSTA; case 0x80: // DSP Program Control Port return (ScuDsp->ProgControlPort.all & 0x00FD00FF); case 0x8C: // DSP Data Ram Data Port if (!ScuDsp->ProgControlPort.part.EX) return ScuDsp->MD[ScuDsp->DataRamPage][ScuDsp->DataRamReadAddress++]; else return 0; case 0xA4: return ScuRegs->IST; case 0xA8: return ScuRegs->AIACK; case 0xC4: return ScuRegs->RSEL; case 0xC8: return ScuRegs->VER; default: LOG("Unhandled SCU Register long read %08X\n", addr); return 0; } } ////////////////////////////////////////////////////////////////////////////// void FASTCALL ScuWriteByte(u32 addr, u8 val) { addr &= 0xFF; switch(addr) { case 0xA7: ScuRegs->IST &= (0xFFFFFF00 | val); // double check this return; default: LOG("Unhandled SCU Register byte write %08X\n", addr); return; } } ////////////////////////////////////////////////////////////////////////////// void FASTCALL ScuWriteWord(u32 addr, UNUSED u16 val) { addr &= 0xFF; LOG("Unhandled SCU Register word write %08X\n", addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL ScuWriteLong(u32 addr, u32 val) { addr &= 0xFF; switch(addr) { case 0: ScuRegs->D0R = val; break; case 4: ScuRegs->D0W = val; break; case 8: ScuRegs->D0C = val; break; case 0xC: ScuRegs->D0AD = val; break; case 0x10: if (val & 0x1) { if (yabsys.use_scu_dma_timing) scu_insert_dma(ScuRegs->D0R, ScuRegs->D0W, ScuRegs->D0C, ScuRegs->D0AD, ScuRegs->D0MD, 0); else { scudmainfo_struct dmainfo; dmainfo.mode = 0; dmainfo.ReadAddress = ScuRegs->D0R; dmainfo.WriteAddress = ScuRegs->D0W; dmainfo.TransferNumber = ScuRegs->D0C; dmainfo.AddValue = ScuRegs->D0AD; dmainfo.ModeAddressUpdate = ScuRegs->D0MD; ScuDMA(&dmainfo); } } ScuRegs->D0EN = val; break; case 0x14: if ((val & 0x7) != 7) { LOG("scu\t: DMA mode 0 interrupt start factor not implemented\n"); } ScuRegs->D0MD = val; break; case 0x20: ScuRegs->D1R = val; break; case 0x24: ScuRegs->D1W = val; break; case 0x28: ScuRegs->D1C = val; break; case 0x2C: ScuRegs->D1AD = val; break; case 0x30: if (val & 0x1) { if (yabsys.use_scu_dma_timing) scu_insert_dma(ScuRegs->D1R, ScuRegs->D1W, ScuRegs->D1C, ScuRegs->D1AD, ScuRegs->D1MD, 1); else { scudmainfo_struct dmainfo; dmainfo.mode = 1; dmainfo.ReadAddress = ScuRegs->D1R; dmainfo.WriteAddress = ScuRegs->D1W; dmainfo.TransferNumber = ScuRegs->D1C; dmainfo.AddValue = ScuRegs->D1AD; dmainfo.ModeAddressUpdate = ScuRegs->D1MD; ScuDMA(&dmainfo); } } ScuRegs->D1EN = val; break; case 0x34: if ((val & 0x7) != 7) { LOG("scu\t: DMA mode 1 interrupt start factor not implemented\n"); } ScuRegs->D1MD = val; break; case 0x40: ScuRegs->D2R = val; break; case 0x44: ScuRegs->D2W = val; break; case 0x48: ScuRegs->D2C = val; break; case 0x4C: ScuRegs->D2AD = val; break; case 0x50: if (val & 0x1) { if (yabsys.use_scu_dma_timing) scu_insert_dma(ScuRegs->D2R, ScuRegs->D2W, ScuRegs->D2C, ScuRegs->D2AD, ScuRegs->D2MD, 2); else { scudmainfo_struct dmainfo; dmainfo.mode = 2; dmainfo.ReadAddress = ScuRegs->D2R; dmainfo.WriteAddress = ScuRegs->D2W; dmainfo.TransferNumber = ScuRegs->D2C; dmainfo.AddValue = ScuRegs->D2AD; dmainfo.ModeAddressUpdate = ScuRegs->D2MD; ScuDMA(&dmainfo); } } ScuRegs->D2EN = val; break; case 0x54: if ((val & 0x7) != 7) { LOG("scu\t: DMA mode 2 interrupt start factor not implemented\n"); } ScuRegs->D2MD = val; break; case 0x60: ScuRegs->DSTP = val; break; case 0x80: // DSP Program Control Port LOG("scu\t: wrote %08X to DSP Program Control Port\n", val); ScuDsp->ProgControlPort.all = (ScuDsp->ProgControlPort.all & 0x00FC0000) | (val & 0x060380FF); if (ScuDsp->ProgControlPort.part.LE) { // set pc ScuDsp->PC = (u8)ScuDsp->ProgControlPort.part.P; LOG("scu\t: DSP set pc = %02X\n", ScuDsp->PC); } #if DEBUG if (ScuDsp->ProgControlPort.part.EX) LOG("scu\t: DSP executing: PC = %02X\n", ScuDsp->PC); #endif break; case 0x84: // DSP Program Ram Data Port // LOG("scu\t: wrote %08X to DSP Program ram offset %02X\n", val, ScuDsp->PC); ScuDsp->ProgramRam[ScuDsp->PC] = val; ScuDsp->PC++; ScuDsp->ProgControlPort.part.P = ScuDsp->PC; break; case 0x88: // DSP Data Ram Address Port ScuDsp->DataRamPage = (val >> 6) & 3; ScuDsp->DataRamReadAddress = val & 0x3F; break; case 0x8C: // DSP Data Ram Data Port // LOG("scu\t: wrote %08X to DSP Data Ram Data Port Page %d offset %02X\n", val, ScuDsp->DataRamPage, ScuDsp->DataRamReadAddress); if (!ScuDsp->ProgControlPort.part.EX) { ScuDsp->MD[ScuDsp->DataRamPage][ScuDsp->DataRamReadAddress] = val; ScuDsp->DataRamReadAddress++; } break; case 0x90: ScuRegs->T0C = val; break; case 0x94: ScuRegs->T1S = val; break; case 0x98: ScuRegs->T1MD = val; break; case 0xA0: ScuRegs->IMS = val; ScuTestInterruptMask(); break; case 0xA4: ScuRegs->IST &= val; break; case 0xA8: ScuRegs->AIACK = val; break; case 0xB0: ScuRegs->ASR0 = val; break; case 0xB4: ScuRegs->ASR1 = val; break; case 0xB8: ScuRegs->AREF = val; break; case 0xC4: ScuRegs->RSEL = val; break; default: LOG("Unhandled SCU Register long write %08X\n", addr); break; } } u8 FASTCALL Sh2ScuReadByte(SH2_struct *sh, u32 addr) { return ScuReadByte(addr); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL Sh2ScuReadWord(SH2_struct *sh, u32 addr) { return ScuReadWord(addr); } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL Sh2ScuReadLong(SH2_struct *sh, u32 addr) { return ScuReadLong(addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2ScuWriteByte(SH2_struct *sh, u32 addr, u8 val) { ScuWriteByte(addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2ScuWriteWord(SH2_struct *sh, u32 addr, UNUSED u16 val) { ScuWriteWord(addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2ScuWriteLong(SH2_struct *sh, u32 addr, u32 val) { ScuWriteLong(addr, val); } ////////////////////////////////////////////////////////////////////////////// void ScuTestInterruptMask() { unsigned int i, i2; // Handle SCU interrupts for (i = 0; i < ScuRegs->NumberOfInterrupts; i++) { if (!(ScuRegs->IMS & ScuRegs->interrupts[ScuRegs->NumberOfInterrupts-1-i].mask)) { SH2SendInterrupt(MSH2, ScuRegs->interrupts[ScuRegs->NumberOfInterrupts-1-i].vector, ScuRegs->interrupts[ScuRegs->NumberOfInterrupts-1-i].level); ScuRegs->IST &= ~ScuRegs->interrupts[ScuRegs->NumberOfInterrupts-1-i].statusbit; // Shorten list for (i2 = ScuRegs->NumberOfInterrupts-1-i; i2 < (ScuRegs->NumberOfInterrupts-1); i2++) memcpy(&ScuRegs->interrupts[i2], &ScuRegs->interrupts[i2+1], sizeof(scuinterrupt_struct)); ScuRegs->NumberOfInterrupts--; break; } } } ////////////////////////////////////////////////////////////////////////////// static void ScuQueueInterrupt(u8 vector, u8 level, u16 mask, u32 statusbit) { u32 i, i2; scuinterrupt_struct tmp; // Make sure interrupt doesn't already exist for (i = 0; i < ScuRegs->NumberOfInterrupts; i++) { if (ScuRegs->interrupts[i].vector == vector) return; } ScuRegs->interrupts[ScuRegs->NumberOfInterrupts].vector = vector; ScuRegs->interrupts[ScuRegs->NumberOfInterrupts].level = level; ScuRegs->interrupts[ScuRegs->NumberOfInterrupts].mask = mask; ScuRegs->interrupts[ScuRegs->NumberOfInterrupts].statusbit = statusbit; ScuRegs->NumberOfInterrupts++; // Sort interrupts for (i = 0; i < (ScuRegs->NumberOfInterrupts-1); i++) { for (i2 = i+1; i2 < ScuRegs->NumberOfInterrupts; i2++) { if (ScuRegs->interrupts[i].level > ScuRegs->interrupts[i2].level) { memcpy(&tmp, &ScuRegs->interrupts[i], sizeof(scuinterrupt_struct)); memcpy(&ScuRegs->interrupts[i], &ScuRegs->interrupts[i2], sizeof(scuinterrupt_struct)); memcpy(&ScuRegs->interrupts[i2], &tmp, sizeof(scuinterrupt_struct)); } } } } ////////////////////////////////////////////////////////////////////////////// static INLINE void SendInterrupt(u8 vector, u8 level, u16 mask, u32 statusbit) { if (!(ScuRegs->IMS & mask)) SH2SendInterrupt(MSH2, vector, level); else { ScuQueueInterrupt(vector, level, mask, statusbit); ScuRegs->IST |= statusbit; } } ////////////////////////////////////////////////////////////////////////////// void ScuSendVBlankIN(void) { SendInterrupt(0x40, 0xF, 0x0001, 0x0001); } ////////////////////////////////////////////////////////////////////////////// void ScuSendVBlankOUT(void) { SendInterrupt(0x41, 0xE, 0x0002, 0x0002); ScuRegs->timer0 = 0; if (ScuRegs->T1MD & 0x1) { if (ScuRegs->timer0 == ScuRegs->T0C) ScuSendTimer0(); } } ////////////////////////////////////////////////////////////////////////////// void ScuSendHBlankIN(void) { SendInterrupt(0x42, 0xD, 0x0004, 0x0004); ScuRegs->timer0++; if (ScuRegs->T1MD & 0x1) { // if timer0 equals timer 0 compare register, do an interrupt if (ScuRegs->timer0 == ScuRegs->T0C) ScuSendTimer0(); // FIX ME - Should handle timer 1 as well } } ////////////////////////////////////////////////////////////////////////////// void ScuSendTimer0(void) { SendInterrupt(0x43, 0xC, 0x0008, 0x00000008); } ////////////////////////////////////////////////////////////////////////////// void ScuSendTimer1(void) { SendInterrupt(0x44, 0xB, 0x0010, 0x00000010); } ////////////////////////////////////////////////////////////////////////////// void ScuSendDSPEnd(void) { SendInterrupt(0x45, 0xA, 0x0020, 0x00000020); } ////////////////////////////////////////////////////////////////////////////// void ScuSendSoundRequest(void) { SendInterrupt(0x46, 0x9, 0x0040, 0x00000040); } ////////////////////////////////////////////////////////////////////////////// void ScuSendSystemManager(void) { SendInterrupt(0x47, 0x8, 0x0080, 0x00000080); } ////////////////////////////////////////////////////////////////////////////// void ScuSendPadInterrupt(void) { SendInterrupt(0x48, 0x8, 0x0100, 0x00000100); } ////////////////////////////////////////////////////////////////////////////// void ScuSendLevel2DMAEnd(void) { SendInterrupt(0x49, 0x6, 0x0200, 0x00000200); } ////////////////////////////////////////////////////////////////////////////// void ScuSendLevel1DMAEnd(void) { SendInterrupt(0x4A, 0x6, 0x0400, 0x00000400); } ////////////////////////////////////////////////////////////////////////////// void ScuSendLevel0DMAEnd(void) { SendInterrupt(0x4B, 0x5, 0x0800, 0x00000800); } ////////////////////////////////////////////////////////////////////////////// void ScuSendDMAIllegal(void) { SendInterrupt(0x4C, 0x3, 0x1000, 0x00001000); } ////////////////////////////////////////////////////////////////////////////// void ScuSendDrawEnd(void) { SendInterrupt(0x4D, 0x2, 0x2000, 0x00002000); } ////////////////////////////////////////////////////////////////////////////// void ScuSendExternalInterrupt00(void) { SendInterrupt(0x50, 0x7, 0x8000, 0x00010000); } ////////////////////////////////////////////////////////////////////////////// void ScuSendExternalInterrupt01(void) { SendInterrupt(0x51, 0x7, 0x8000, 0x00020000); } ////////////////////////////////////////////////////////////////////////////// void ScuSendExternalInterrupt02(void) { SendInterrupt(0x52, 0x7, 0x8000, 0x00040000); } ////////////////////////////////////////////////////////////////////////////// void ScuSendExternalInterrupt03(void) { SendInterrupt(0x53, 0x7, 0x8000, 0x00080000); } ////////////////////////////////////////////////////////////////////////////// void ScuSendExternalInterrupt04(void) { SendInterrupt(0x54, 0x4, 0x8000, 0x00100000); } ////////////////////////////////////////////////////////////////////////////// void ScuSendExternalInterrupt05(void) { SendInterrupt(0x55, 0x4, 0x8000, 0x00200000); } ////////////////////////////////////////////////////////////////////////////// void ScuSendExternalInterrupt06(void) { SendInterrupt(0x56, 0x4, 0x8000, 0x00400000); } ////////////////////////////////////////////////////////////////////////////// void ScuSendExternalInterrupt07(void) { SendInterrupt(0x57, 0x4, 0x8000, 0x00800000); } ////////////////////////////////////////////////////////////////////////////// void ScuSendExternalInterrupt08(void) { SendInterrupt(0x58, 0x1, 0x8000, 0x01000000); } ////////////////////////////////////////////////////////////////////////////// void ScuSendExternalInterrupt09(void) { SendInterrupt(0x59, 0x1, 0x8000, 0x02000000); } ////////////////////////////////////////////////////////////////////////////// void ScuSendExternalInterrupt10(void) { SendInterrupt(0x5A, 0x1, 0x8000, 0x04000000); } ////////////////////////////////////////////////////////////////////////////// void ScuSendExternalInterrupt11(void) { SendInterrupt(0x5B, 0x1, 0x8000, 0x08000000); } ////////////////////////////////////////////////////////////////////////////// void ScuSendExternalInterrupt12(void) { SendInterrupt(0x5C, 0x1, 0x8000, 0x10000000); } ////////////////////////////////////////////////////////////////////////////// void ScuSendExternalInterrupt13(void) { SendInterrupt(0x5D, 0x1, 0x8000, 0x20000000); } ////////////////////////////////////////////////////////////////////////////// void ScuSendExternalInterrupt14(void) { SendInterrupt(0x5E, 0x1, 0x8000, 0x40000000); } ////////////////////////////////////////////////////////////////////////////// void ScuSendExternalInterrupt15(void) { SendInterrupt(0x5F, 0x1, 0x8000, 0x80000000); } ////////////////////////////////////////////////////////////////////////////// int ScuSaveState(FILE *fp) { int offset; IOCheck_struct check = { 0, 0 }; offset = StateWriteHeader(fp, "SCU ", 1); // Write registers and internal variables ywrite(&check, (void *)ScuRegs, sizeof(Scu), 1, fp); // Write DSP area ywrite(&check, (void *)ScuDsp, sizeof(scudspregs_struct), 1, fp); return StateFinishHeader(fp, offset); } ////////////////////////////////////////////////////////////////////////////// int ScuLoadState(FILE *fp, UNUSED int version, int size) { IOCheck_struct check = { 0, 0 }; // Read registers and internal variables yread(&check, (void *)ScuRegs, sizeof(Scu), 1, fp); // Read DSP area yread(&check, (void *)ScuDsp, sizeof(scudspregs_struct), 1, fp); return size; } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/profile.h000644 001750 001750 00000002674 12755623101 017664 0ustar00guillaumeguillaume000000 000000 /* copyright Patrick Kooman, 2002 Lightweight C & C++ profiler. Works both in debug- and release mode. For more info, read: http://www.2dgame-tutorial.com/sdl/profile.htm You are free to use / modify / re-distribute this code. */ #ifndef _PROFILE_H_ #define _PROFILE_H_ #include #include #include #include #include #ifdef DONT_PROFILE /* Profiling disabled: compiler won't generate machine instructions now. */ #define PROFILE_START(t) #define PROFILE_STOP(t) #define PROFILE_PRINT() #define PROFILE_RESET() #else /* Profiling enabled */ #define MAX_TAG_LEN 100 #define NUM_TAGS 100 typedef struct { char str_name [MAX_TAG_LEN] ; int i_calls ; clock_t start_time ; int i_stopped ; long l_total_ms ; } entry_t ; /* Compiler calls functions now. */ #define PROFILE_START(t) ProfileStart (t) #define PROFILE_STOP(t) ProfileStop (t) #define PROFILE_PRINT() ProfilePrint () #define PROFILE_RESET() ProfileReset () #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* Start timer for given tag */ void ProfileStart (char* str_tag) ; /* Stops timer for given tag and add time to total time for this tag */ void ProfileStop (char* str_tag) ; /* Prints result to stdout */ void ProfilePrint (void) ; /* Resets the profiler. */ void ProfileReset (void) ; #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* NO_PROFILE */ #endif /* _PROFILE_H_ */ yabause-0.9.15/src/sh2_dynarec/000755 001750 001750 00000000000 12757373644 020263 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/sh2_dynarec/linkage_arm.s000644 001750 001750 00000062044 12755623101 022706 0ustar00guillaumeguillaume000000 000000 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Yabause - linkage_arm.s * * Copyright (C) 2009-2011 Ari64 * * * * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /*.cpu arm9tdmi*/ /* .fpu softvfp .eabi_attribute 20, 1 .eabi_attribute 21, 1 .eabi_attribute 23, 3 .eabi_attribute 24, 1 .eabi_attribute 25, 1 .eabi_attribute 26, 2 .eabi_attribute 30, 6 .eabi_attribute 18, 4*/ .file "linkage_arm.s" .global sh2_dynarec_target .global dynarec_local .global master_reg .global master_cc .global master_pc .global master_ip .global slave_reg .global slave_cc .global slave_pc .global slave_ip .global mini_ht_master .global mini_ht_slave .global restore_candidate .global memory_map .global rccount .bss .align 12 .type sh2_dynarec_target, %object .size sh2_dynarec_target, 16777216 sh2_dynarec_target: .space 16777216 .align 4 .type dynarec_local, %object .size dynarec_local, 64 dynarec_local: .space 64+88+12+88+12+28+256+256+512+4194304 master_reg = dynarec_local + 64 .type master_reg, %object .size master_reg, 88 master_cc = master_reg + 88 .type master_cc, %object .size master_cc, 4 master_pc = master_cc + 4 .type master_pc, %object .size master_pc, 4 master_ip = master_pc + 4 .type master_ip, %object .size master_ip, 4 slave_reg = master_ip + 4 .type slave_reg, %object .size slave_reg, 88 slave_cc = slave_reg + 88 .type slave_cc, %object .size slave_cc, 4 slave_pc = slave_cc + 4 .type slave_pc, %object .size slave_pc, 4 slave_ip = slave_pc + 4 .type slave_ip, %object .size slave_ip, 4 m68kcenticycles = slave_ip + 4 .type m68kcenticycles, %object .size m68kcenticycles, 4 m68kcycles = m68kcenticycles + 4 .type m68kcycles, %object .size m68kcycles, 4 decilinecount = m68kcycles + 4 .type decilinecount, %object .size decilinecount, 4 decilinecycles = decilinecount + 4 .type decilinecycles, %object .size decilinecycles, 4 sh2cycles = decilinecycles + 4 .type sh2cycles, %object .size sh2cycles, 4 scucycles = sh2cycles + 4 .type scucycles, %object .size scucycles, 4 rccount = scucycles + 4 .type rccount, %object .size rccount, 4 mini_ht_master = rccount + 4 .type mini_ht_master, %object .size mini_ht_master, 256 mini_ht_slave = mini_ht_master + 256 .type mini_ht_slave, %object .size mini_ht_slave, 256 restore_candidate = mini_ht_slave + 256 .type restore_candidate, %object .size restore_candidate, 512 memory_map = restore_candidate + 512 .type memory_map, %object .size memory_map, 4194304 .text .align 2 .global YabauseDynarecOneFrameExec .type YabauseDynarecOneFrameExec, %function YabauseDynarecOneFrameExec: ldr r12, .dlptr str r0, [r12, #m68kcycles-dynarec_local-28] str r1, [r12, #m68kcenticycles-dynarec_local-28] mov r2, #0 stmia r12, {r4, r5, r6, r7, r8, r9, sl, fp, lr} sub fp, r12, #28 str r2, [r12, #decilinecount-dynarec_local-28] ldr r14, [r12, #master_ip-dynarec_local-28] newline: /*movw r0, #:lower16:decilinestop_p*/ /*movt r0, #:upper16:decilinestop_p*/ ldr r0, .dspptr /*movw r1, #:lower16:yabsys_timing_bits*/ /*movt r1, #:upper16:yabsys_timing_bits*/ ldr r1, .ytbptr /*movw r2, #:lower16:SH2CycleFrac_p*/ ldr r2, .scfptr ldr r0, [r0] /* pointer to decilinestop */ /*movt r2, #:upper16:SH2CycleFrac_p*/ /*movw r3, #:lower16:yabsys_timing_mask*/ ldr r3, .ytmptr ldr r1, [r1] /* yabsys_timing_bits */ /*movt r3, #:upper16:yabsys_timing_mask*/ ldr r2, [r2] /* pointer to SH2CycleFrac */ ldr r0, [r0] /* decilinestop */ ldr r3, [r3] /* yabsys_timing_mask */ ldr r4, [r2] /* SH2CycleFrac */ add r5, r0, r0 /* decilinestop*2 */ lsr r6, r0, r1 /* decilinecycles = decilinestop>>yabsys_timing_bits*/ add r5, r5, r0, lsl #3 /* cyclesinc=decilinestop*10 */ str r6, [fp, #decilinecycles-dynarec_local] add r1, r1, #1 /* yabsys_timing_bits+1 */ add r6, r6, r6, lsl #3 /* decilinecycles*9 */ add r3, r3, r3 add r5, r5, r4 /* cyclesinc+=SH2CycleFrac */ /*movw r7, #:lower16:MSH2*/ /*movt r7, #:upper16:MSH2*/ ldr r7, .msh2ptr orr r3, r3, #1 /* ((YABSYS_TIMING_MASK << 1) | 1) */ /*movw r8, #:lower16:NumberOfInterruptsOffset*/ /*movt r8, #:upper16:NumberOfInterruptsOffset*/ ldr r8, .nioptr and r3, r5, r3 /* SH2CycleFrac &= ... */ lsr r5, r5, r1 /* scucycles */ /*movw r9, #:lower16:CurrentSH2*/ /*movt r9, #:upper16:CurrentSH2*/ ldr r9, .csh2ptr ldr r7, [r7] /* MSH2 */ ldr r8, [r8] /* NumberOfInterruptsOffset */ str r5, [fp, #scucycles-dynarec_local] add r5, r5, r5 /* sh2cycles=scucycles*2 */ str r3, [r2] /* SH2CycleFrac */ sub r6, r5, r6 /* sh2cycles(full line) -= decilinecycles*9 */ ldr r12, [r7, r8] str r6, [fp, #sh2cycles-dynarec_local] str r7, [r9] /* CurrentSH2 */ tst r12, r12 bne master_handle_interrupts ldr r10, [fp, #master_cc-dynarec_local] sub r10, r10, r6 mov pc, r14 master_handle_interrupts: str r14, [fp, #master_ip-dynarec_local] bl DynarecMasterHandleInterrupts ldr r10, [fp, #master_cc-dynarec_local] ldr r14, [fp, #master_ip-dynarec_local] sub r10, r10, r6 mov pc, r14 .dlptr: .word dynarec_local+28 .dspptr: .word decilinestop_p .ytbptr: .word yabsys_timing_bits .scfptr: .word SH2CycleFrac_p .ytmptr: .word yabsys_timing_mask .msh2ptr: .word MSH2 .ssh2ptr: .word SSH2 .nioptr: .word NumberOfInterruptsOffset .csh2ptr: .word CurrentSH2 .lcpptr: .word linecount_p .vlcpptr: .word vblanklinecount_p .mlcpptr: .word maxlinecount_p .dupptr: .word decilineusec_p .ufpptr: .word UsecFrac_p .scptr: .word saved_centicycles .icptr: .word invalidate_count .ccptr: .word cached_code .size YabauseDynarecOneFrameExec, .-YabauseDynarecOneFrameExec .global slave_entry .type slave_entry, %function slave_entry: ldr r0, [fp, #sh2cycles-dynarec_local] str r10, [fp, #master_cc-dynarec_local] str r14, [fp, #master_ip-dynarec_local] bl FRTExec ldr r0, [fp, #sh2cycles-dynarec_local] bl WDTExec ldr r4, [fp, #slave_ip-dynarec_local] /*movw r7, #:lower16:SSH2*/ /*movt r7, #:upper16:SSH2*/ ldr r7, .ssh2ptr tst r4, r4 beq cc_interrupt_master /*movw r8, #:lower16:NumberOfInterruptsOffset*/ ldr r6, [fp, #sh2cycles-dynarec_local] /*movt r8, #:upper16:NumberOfInterruptsOffset*/ ldr r8, .nioptr /*movw r9, #:lower16:CurrentSH2*/ ldr r9, .csh2ptr ldr r7, [r7] /*movt r9, #:upper16:CurrentSH2*/ ldr r8, [r8] str r7, [r9] /* CurrentSH2 */ ldr r12, [r7, r8] tst r12, r12 bne slave_handle_interrupts ldr r10, [fp, #slave_cc-dynarec_local] sub r10, r10, r6 mov pc, r4 slave_handle_interrupts: bl DynarecSlaveHandleInterrupts ldr r10, [fp, #slave_cc-dynarec_local] sub r10, r10, r6 ldr pc, [fp, #slave_ip-dynarec_local] .size slave_entry, .-slave_entry .global cc_interrupt .type cc_interrupt, %function cc_interrupt: ldr r0, [fp, #sh2cycles-dynarec_local] str r10, [fp, #slave_cc-dynarec_local] str r8, [fp, #slave_ip-dynarec_local] bl FRTExec ldr r0, [fp, #sh2cycles-dynarec_local] bl WDTExec .size cc_interrupt, .-cc_interrupt .global cc_interrupt_master .type cc_interrupt_master, %function cc_interrupt_master: ldr r0, [fp, #decilinecount-dynarec_local] ldr r6, [fp, #decilinecycles-dynarec_local] cmp r0, #8 add r0, r0, #1 bhi .A3 str r0, [fp, #decilinecount-dynarec_local] beq .A2 str r6, [fp, #sh2cycles-dynarec_local] ldr r14, [fp, #master_ip-dynarec_local] .A1: /*movw r7, #:lower16:MSH2*/ /*movt r7, #:upper16:MSH2*/ /*movw r8, #:lower16:NumberOfInterruptsOffset*/ /*movt r8, #:upper16:NumberOfInterruptsOffset*/ /*movw r9, #:lower16:CurrentSH2*/ /*movt r9, #:upper16:CurrentSH2*/ ldr r7, .msh2ptr ldr r8, .nioptr ldr r9, .csh2ptr ldr r7, [r7] /* MSH2 */ ldr r8, [r8] /* NumberOfInterruptsOffset */ ldr r12, [r7, r8] str r7, [r9] /* CurrentSH2 */ tst r12, r12 bne master_handle_interrupts ldr r10, [fp, #master_cc-dynarec_local] sub r10, r10, r6 mov pc, r14 .A2: bl Vdp2HBlankIN ldr r14, [fp, #master_ip-dynarec_local] b .A1 .A3: ldr r0, [fp, #scucycles-dynarec_local] bl ScuExec /*movw r4, #:lower16:linecount_p*/ /*movt r4, #:upper16:linecount_p*/ ldr r4, .lcpptr bl M68KSync /*movw r5, #:lower16:vblanklinecount_p*/ /*movt r5, #:upper16:vblanklinecount_p*/ ldr r5, .vlcpptr bl Vdp2HBlankOUT /*movw r6, #:lower16:maxlinecount_p*/ /*movt r6, #:upper16:maxlinecount_p*/ ldr r6, .mlcpptr bl ScspExec ldr r4, [r4] /* pointer to linecount */ ldr r5, [r5] /* pointer to vblanklinecount */ ldr r6, [r6] /* pointer to maxlinecount */ mov r0, #0 ldr r7, [r4] /* linecount */ ldr r5, [r5] /* vblanklinecount */ ldr r6, [r6] /* maxlinecount */ add r7, r7, #1 str r0, [fp, #decilinecount-dynarec_local] cmp r5, r7 /* linecount==vblanklinecount ? */ beq vblankin cmp r6, r7 /* linecount==maxlinecount ? */ strne r7, [r4] /* linecount++ */ bleq Vdp2VBlankOUT nextline: /* finishline */ /*const u32 usecinc = yabsys.DecilineUsec * 10;*/ /*movw r3, #:lower16:decilineusec_p*/ /*movt r3, #:upper16:decilineusec_p*/ ldr r3, .dupptr /*movw r5, #:lower16:UsecFrac_p*/ /*movt r5, #:upper16:UsecFrac_p*/ ldr r5, .ufpptr /*movw r8, #:lower16:yabsys_timing_bits*/ /*movt r8, #:upper16:yabsys_timing_bits*/ ldr r8, .ytbptr /*movw r9, #:lower16:yabsys_timing_mask*/ /*movt r9, #:upper16:yabsys_timing_mask*/ ldr r9, .ytmptr ldr r3, [r3] /* pointer to decilineusec */ ldr r5, [r5] /* pointer to usecfrac */ ldr r8, [r8] /* yabsys_timing_bits */ ldr r3, [r3] /* decilineusec */ ldr r0, [r5] /* usecfrac */ ldr r9, [r9] /* yabsys_timing_mask */ add r0, r0, r3, lsl #3 /* UsecFrac += yabsys.DecilineUsec * 8 */ add r0, r0, r3, lsl #1 /* UsecFrac += yabsys.DecilineUsec * 2 */ str r0, [r5] lsr r0, r0, r8 bl SmpcExec /* SmpcExec may modify UsecFrac; must reload it */ ldr r10, [r5] /* usecfrac */ lsr r0, r10, r8 and r10, r10, r9 bl Cs2Exec /*movw r8, #:lower16:saved_centicycles*/ str r10, [r5] /* usecfrac */ /*movt r8, #:upper16:saved_centicycles*/ ldr r8, .scptr ldr r1, [fp, #m68kcenticycles-dynarec_local] ldr r2, [r8] ldr r0, [fp, #m68kcycles-dynarec_local] add r2, r2, r1 cmp r2, #100 subcs r2, r2, #100 addcs r0, r0, #1 str r2, [r8] /* saved_centicycles */ bl M68KExec ldr r14, [fp, #master_ip-dynarec_local] eors r1, r6, r7 /* linecount==maxlinecount ? */ bne newline nextframe: str r1, [r4] /* linecount=0 */ bl M68KSync ldr r2, [fp, #rccount-dynarec_local] /*movw r0, #:lower16:invalidate_count /* FIX: Put into dynarec_local? */ add r3, fp, #restore_candidate-dynarec_local /*movt r0, #:upper16:invalidate_count*/ ldr r0, .icptr add r2, r2, #1 and r2, r2, #0x3f str r2, [fp, #rccount-dynarec_local] ldr r4, [r3, r2, lsl #2] str r1, [r0] /* invalidate_count=0 */ tst r4, r4 bne .A5 .A4: add r12, fp, #28 ldmia r12, {r4, r5, r6, r7, r8, r9, sl, fp, pc} .A5: /* Move 'dirty' blocks to the 'clean' list */ lsl r5, r2, #5 str r1, [r3, r2, lsl #2] .A6: lsrs r4, r4, #1 mov r0, r5 add r5, r5, #1 blcs clean_blocks tst r5, #31 bne .A6 b .A4 vblankin: str r7, [r4] /* linecount++ */ bl SmpcINTBACKEnd add r0, r0, #0 /* NOP for Cortex-A8 branch predictor */ bl Vdp2VBlankIN add r0, r0, #0 /* NOP for Cortex-A8 branch predictor */ bl CheatDoPatches add r0, r0, #0 /* NOP for Cortex-A8 branch predictor */ b nextline .size cc_interrupt_master, .-cc_interrupt_master .align 2 .global dyna_linker .type dyna_linker, %function dyna_linker: /* r0 = virtual target address */ /* r1 = instruction to patch */ mov r6, #2048 ldr r3, .jiptr mvn r2, #0x20000 ldr r7, [r1] sub r6, r6, #1 and r2, r2, r0, lsr #12 and r6, r6, r0, lsr #12 cmp r2, #1024 add r12, r7, #2 orrcs r2, r6, #1024 ldr r5, [r3, r2, lsl #2] lsl r12, r12, #8 /* jump_in lookup */ .B1: movs r4, r5 beq .B3 ldr r3, [r5] ldr r5, [r4, #12] teq r3, r0 bne .B1 ldr r4, [r4, #8] .B2: mov r5, r1 add r1, r1, r12, asr #6 teq r1, r4 moveq pc, r4 /* Stale i-cache */ bl add_link sub r2, r4, r5 and r1, r7, #0xff000000 lsl r2, r2, #6 sub r1, r1, #2 add r1, r1, r2, lsr #8 str r1, [r5] mov pc, r4 .B3: /* hash_table lookup */ ldr r3, .jdptr eor r4, r0, r0, lsl #16 ldr r6, .htptr lsr r4, r4, #12 bic r4, r4, #15 ldr r5, [r3, r2, lsl #2] ldr r7, [r6, r4]! teq r7, r0 ldreq pc, [r6, #4] ldr r7, [r6, #8] teq r7, r0 ldreq pc, [r6, #12] /* jump_dirty lookup */ .B6: movs r4, r5 beq .B8 ldr r3, [r5] ldr r5, [r4, #12] teq r3, r0 bne .B6 .B7: ldr r1, [r4, #8] /* hash_table insert */ ldr r2, [r6] ldr r3, [r6, #4] str r0, [r6] str r1, [r6, #4] str r2, [r6, #8] str r3, [r6, #12] mov pc, r1 .B8: mov r4, r0 mov r5, r1 bl sh2_recompile_block tst r0, r0 mov r0, r4 mov r1, r5 beq dyna_linker /* shouldn't happen */ b .-8 .jiptr: .word jump_in .jdptr: .word jump_dirty .htptr: .word hash_table .align 2 .global jump_vaddr_r0_master .type jump_vaddr_r0_master, %function jump_vaddr_r0_master: eor r2, r0, r0, lsl #16 b jump_vaddr .size jump_vaddr_r0_master, .-jump_vaddr_r0_master .global jump_vaddr_r1_master .type jump_vaddr_r1_master, %function jump_vaddr_r1_master: eor r2, r1, r1, lsl #16 mov r0, r1 b jump_vaddr .size jump_vaddr_r1_master, .-jump_vaddr_r1_master .global jump_vaddr_r2_master .type jump_vaddr_r2_master, %function jump_vaddr_r2_master: mov r0, r2 eor r2, r2, r2, lsl #16 b jump_vaddr .size jump_vaddr_r2_master, .-jump_vaddr_r2_master .global jump_vaddr_r3_master .type jump_vaddr_r3_master, %function jump_vaddr_r3_master: eor r2, r3, r3, lsl #16 mov r0, r3 b jump_vaddr .size jump_vaddr_r3_master, .-jump_vaddr_r3_master .global jump_vaddr_r4_master .type jump_vaddr_r4_master, %function jump_vaddr_r4_master: eor r2, r4, r4, lsl #16 mov r0, r4 b jump_vaddr .size jump_vaddr_r4_master, .-jump_vaddr_r4_master .global jump_vaddr_r5_master .type jump_vaddr_r5_master, %function jump_vaddr_r5_master: eor r2, r5, r5, lsl #16 mov r0, r5 b jump_vaddr .size jump_vaddr_r5_master, .-jump_vaddr_r5_master .global jump_vaddr_r6_master .type jump_vaddr_r6_master, %function jump_vaddr_r6_master: eor r2, r6, r6, lsl #16 mov r0, r6 b jump_vaddr .size jump_vaddr_r6_master, .-jump_vaddr_r6_master .global jump_vaddr_r7_master .type jump_vaddr_r7_master, %function jump_vaddr_r7_master: eor r2, r7, r7, lsl #16 mov r0, r7 b jump_vaddr .size jump_vaddr_r7_master, .-jump_vaddr_r7_master .global jump_vaddr_r8_master .type jump_vaddr_r8_master, %function jump_vaddr_r8_master: eor r2, r8, r8, lsl #16 mov r0, r8 b jump_vaddr .size jump_vaddr_r8_master, .-jump_vaddr_r8_master .global jump_vaddr_r9_master .type jump_vaddr_r9_master, %function jump_vaddr_r9_master: eor r2, r9, r9, lsl #16 mov r0, r9 b jump_vaddr .size jump_vaddr_r9_master, .-jump_vaddr_r9_master .global jump_vaddr_r12_master .type jump_vaddr_r12_master, %function jump_vaddr_r12_master: eor r2, r12, r12, lsl #16 mov r0, r12 b jump_vaddr .size jump_vaddr_r12_master, .-jump_vaddr_r12_master .global jump_vaddr_r0_slave .type jump_vaddr_r0_slave, %function jump_vaddr_r0_slave: eor r2, r0, r0, lsl #16 b jump_vaddr_slave .size jump_vaddr_r0_slave, .-jump_vaddr_r0_slave .global jump_vaddr_r1_slave .type jump_vaddr_r1_slave, %function jump_vaddr_r1_slave: eor r2, r1, r1, lsl #16 mov r0, r1 b jump_vaddr_slave .size jump_vaddr_r1_slave, .-jump_vaddr_r1_slave .global jump_vaddr_r2_slave .type jump_vaddr_r2_slave, %function jump_vaddr_r2_slave: mov r0, r2 eor r2, r2, r2, lsl #16 b jump_vaddr_slave .size jump_vaddr_r2_slave, .-jump_vaddr_r2_slave .global jump_vaddr_r3_slave .type jump_vaddr_r3_slave, %function jump_vaddr_r3_slave: eor r2, r3, r3, lsl #16 mov r0, r3 b jump_vaddr_slave .size jump_vaddr_r3_slave, .-jump_vaddr_r3_slave .global jump_vaddr_r4_slave .type jump_vaddr_r4_slave, %function jump_vaddr_r4_slave: eor r2, r4, r4, lsl #16 mov r0, r4 b jump_vaddr_slave .size jump_vaddr_r4_slave, .-jump_vaddr_r4_slave .global jump_vaddr_r5_slave .type jump_vaddr_r5_slave, %function jump_vaddr_r5_slave: eor r2, r5, r5, lsl #16 mov r0, r5 b jump_vaddr_slave .size jump_vaddr_r5_slave, .-jump_vaddr_r5_slave .global jump_vaddr_r6_slave .type jump_vaddr_r6_slave, %function jump_vaddr_r6_slave: eor r2, r6, r6, lsl #16 mov r0, r6 b jump_vaddr_slave .size jump_vaddr_r6_slave, .-jump_vaddr_r6_slave .global jump_vaddr_r7_slave .type jump_vaddr_r7_slave, %function jump_vaddr_r7_slave: eor r2, r7, r7, lsl #16 mov r0, r7 b jump_vaddr_slave .size jump_vaddr_r7_slave, .-jump_vaddr_r7_slave .global jump_vaddr_r8_slave .type jump_vaddr_r8_slave, %function jump_vaddr_r8_slave: eor r2, r8, r8, lsl #16 mov r0, r8 b jump_vaddr_slave .size jump_vaddr_r8_slave, .-jump_vaddr_r8_slave .global jump_vaddr_r9_slave .type jump_vaddr_r9_slave, %function jump_vaddr_r9_slave: eor r2, r9, r9, lsl #16 mov r0, r9 b jump_vaddr_slave .size jump_vaddr_r9_slave, .-jump_vaddr_r9_slave .global jump_vaddr_r12_slave .type jump_vaddr_r12_slave, %function jump_vaddr_r12_slave: eor r2, r12, r12, lsl #16 mov r0, r12 b jump_vaddr_slave .size jump_vaddr_r12_slave, .-jump_vaddr_r12_slave .global jump_vaddr_slave .type jump_vaddr_slave, %function jump_vaddr_slave: add r2, r2, #65536 add r0, r0, #1 .size jump_vaddr_slave, .-jump_vaddr_slave .global jump_vaddr .type jump_vaddr, %function jump_vaddr: ldr r1, .htptr mvn r3, #15 and r2, r3, r2, lsr #12 ldr r2, [r1, r2]! teq r2, r0 ldreq pc, [r1, #4] ldr r2, [r1, #8] teq r2, r0 ldreq pc, [r1, #12] bl get_addr mov pc, r0 .size jump_vaddr, .-jump_vaddr .align 2 .global verify_code .type verify_code, %function verify_code: /* r1 = source */ /* r2 = target */ /* r3 = length */ tst r3, #4 mov r4, #0 add r3, r1, r3 mov r5, #0 ldrne r4, [r1], #4 mov r12, #0 ldrne r5, [r2], #4 teq r1, r3 beq .D3 .D2: ldr r7, [r1], #4 eor r9, r4, r5 ldr r8, [r2], #4 orrs r9, r9, r12 bne .D4 ldr r4, [r1], #4 eor r12, r7, r8 ldr r5, [r2], #4 cmp r1, r3 bcc .D2 teq r7, r8 .D3: teqeq r4, r5 .D4: moveq pc, lr .D5: bl get_addr mov pc, r0 .size verify_code, .-verify_code .align 2 .global WriteInvalidateLong .type WriteInvalidateLong, %function WriteInvalidateLong: /*movw r12, #:lower16:cached_code*/ lsr r2, r0, #17 /*movt r12, #:upper16:cached_code*/ ldr r12, .ccptr lsr r3, r0, #12 ldr r2, [r12, r2, lsl #2] mov r12, #1 tst r12, r2, ror r3 beq MappedMemoryWriteLongNocache push {r0, r1, r2, lr} bl invalidate_addr pop {r0, r1, r2, lr} b MappedMemoryWriteLongNocache .size WriteInvalidateLong, .-WriteInvalidateLong .align 2 .global WriteInvalidateWord .type WriteInvalidateWord, %function WriteInvalidateWord: /*movw r12, #:lower16:cached_code*/ lsr r2, r0, #17 /*movt r12, #:upper16:cached_code*/ ldr r12, .ccptr lsr r3, r0, #12 bic r1, r1, #0xFF000000 ldr r2, [r12, r2, lsl #2] mov r12, #1 /*movt r1, #0*/ /*uxth r1, r1*/ bic r1, r1, #0xFF0000 tst r12, r2, ror r3 beq MappedMemoryWriteWordNocache push {r0, r1, r2, lr} bl invalidate_addr pop {r0, r1, r2, lr} b MappedMemoryWriteWordNocache .size WriteInvalidateWord, .-WriteInvalidateWord .align 2 .global WriteInvalidateByteSwapped .type WriteInvalidateByteSwapped, %function WriteInvalidateByteSwapped: eor r0, r0, #1 .size WriteInvalidateByteSwapped, .-WriteInvalidateByteSwapped .global WriteInvalidateByte .type WriteInvalidateByte, %function WriteInvalidateByte: /*movw r12, #:lower16:cached_code*/ lsr r2, r0, #17 /*movt r12, #:upper16:cached_code*/ ldr r12, .ccptr lsr r3, r0, #12 ldr r2, [r12, r2, lsl #2] mov r12, #1 and r1, r1, #0xff tst r12, r2, ror r3 beq MappedMemoryWriteByteNocache push {r0, r1, r2, lr} bl invalidate_addr pop {r0, r1, r2, lr} b MappedMemoryWriteByteNocache .size WriteInvalidateByte, .-WriteInvalidateByte .align 2 .global div1 .type div1, %function div1: /* r0 = dividend */ /* r1 = divisor */ /* r2 = sr */ tst r2, #0x200 bne div1_negative_divisor lsrs r2, r2, #1 /* Get T bit and shift out */ adcs r0, r0, r0 /* rn=(rn<<1)+T */ adc r3, r3, r3 /* New Q in r3 */ mov r4, r1 /* divisor (rm) */ tst r2, #0x80 /* Get (shifted) Q bit */ mov r5, #1 rsbeq r4, r1, #0 /* inverted if old_Q clear */ moveq r5, #0 /* 0 if old_Q clear, 1 otherwise */ adds r0, r4, r0 /* rn+rm if old_Q, rn-rm if !old_Q */ /* carry set if rn < old_rn */ adc r3, r5, r3 /* low bit = (rn=old_rn)^new_Q */ orr r2, r2, #0x80 /* set (shifted) Q bit */ and r3, r3, #1 orrs r5, r4, r5 /* zero if old_Q==0 && rn==old_rn */ eoreq r3, r3, #1 /* invert result for old_Q==0 && rn==old_rn */ orr r2, r3, r2, lsl #1 /* New T = (Q==M) */ eor r2, r2, r3, lsl #8 /* save new Q (=!T) */ /* mov r4, r0 mov r5, r1 mov r6, r2 mov r7, r14 bl debug_division mov r0, r4 mov r1, r5 mov r2, r6 mov r14, r7 */ mov pc, lr div1_negative_divisor: lsrs r2, r2, #1 /* Get T bit and shift out */ adcs r0, r0, r0 /* rn=(rn<<1)+T */ adc r3, r3, r3 /* New Q in r3 */ mov r4, r1 /* divisor (rm) */ tst r2, #0x80 /* Get (shifted) Q bit */ mov r5, #1 rsbne r4, r1, #0 /* inverted if old_Q clear */ movne r5, #0 /* 0 if old_Q set, 1 otherwise */ adds r0, r4, r0 /* rn+rm if !old_Q, rn-rm if old_Q */ /* carry set if rn < old_rn */ adc r3, r5, r3 /* low bit = (rn=old_rn)^new_Q */ bic r2, r2, #0x80 /* clear (shifted) Q bit */ and r3, r3, #1 orrs r5, r4, r5 /* zero if old_Q==1 && rn==old_rn */ /*eoreq r3, r3, #1 /* invert result for old_Q==1 && rn==old_rn */ eorne r3, r3, #1 /* don't invert result for old_Q==1 && rn==old_rn */ orr r2, r3, r2, lsl #1 /* New T = (Q==M) */ orr r2, r2, r3, lsl #8 /* save new Q (=T) */ mov pc, lr .size div1, .-div1 .align 2 .global macl .type macl, %function macl: /* r4 = sr */ /* r5 = multiplicand address */ /* r6 = multiplicand address */ /* r0 = return MACL */ /* r1 = return MACH */ mov r7, r14 mov r8, r0 /* MACL */ mov r9, r1 /* MACH */ mov r0, r6 bl MappedMemoryReadLongNocache mov r10, r0 mov r0, r5 bl MappedMemoryReadLongNocache add r5, r5, #4 add r6, r6, #4 mov r12, r0 mov r0, r8 mov r1, r9 mov r14, r7 smlal r0, r1, r10, r12 tst r4, #2 moveq pc, lr macl_saturation: cmn r1, #0x8000 mov r7, #0x8000 movlt r0, #0 rsblt r1, r7, #0 cmp r1, #0x8000 mvnge r0, #0 subge r1, r7, #1 mov pc, lr .size macl, .-macl .align 2 .global macw .type macw, %function macw: /* r4 = sr */ /* r5 = multiplicand address */ /* r6 = multiplicand address */ /* r0 = return MACL */ /* r1 = return MACH */ mov r7, r14 mov r8, r0 /* MACL */ mov r9, r1 /* MACH */ mov r0, r6 bl MappedMemoryReadWordNocache /*sxth r10, r0*/ lsl r10, r0, #16 mov r0, r5 bl MappedMemoryReadWordNocache add r5, r5, #2 add r6, r6, #2 lsl r12, r0, #16 /*sxth r12, r0*/ mov r0, r8 mov r1, r9 asr r10, r10, #16 asr r12, r12, #16 mov r14, r7 smlal r0, r1, r10, r12 tst r4, #2 moveq pc, lr macw_saturation: cmn r0, #0x80000000 adcs r7, r1, #0 mvnne r0, #0x80000000 /* 0x7FFFFFFF */ movlt r0, #0x80000000 /* 0x80000000 */ mov r1, r9 mov pc, lr .size macw, .-macw .align 2 .global master_handle_bios .type master_handle_bios, %function master_handle_bios: /*movw r1, #:lower16:MSH2*/ str r0, [fp, #master_pc-dynarec_local] /*movt r1, #:upper16:MSH2*/ ldr r1, .msh2ptr str r10, [fp, #master_cc-dynarec_local] str r14, [fp, #master_ip-dynarec_local] ldr r0, [r1] /* MSH2 */ bl BiosHandleFunc ldr r14, [fp, #master_ip-dynarec_local] ldr r10, [fp, #master_cc-dynarec_local] mov pc, lr .size master_handle_bios, .-master_handle_bios .align 2 .global slave_handle_bios .type slave_handle_bios, %function slave_handle_bios: /*movw r1, #:lower16:SSH2*/ str r0, [fp, #slave_pc-dynarec_local] /*movt r1, #:upper16:SSH2*/ ldr r1, .ssh2ptr str r10, [fp, #slave_cc-dynarec_local] str r14, [fp, #slave_ip-dynarec_local] ldr r0, [r1] /* SSH2 */ bl BiosHandleFunc ldr r14, [fp, #slave_ip-dynarec_local] ldr r10, [fp, #slave_cc-dynarec_local] mov pc, lr .size slave_handle_bios, .-slave_handle_bios /* __clear_cache syscall for Linux OS with broken libraries */ .align 2 .global clear_cache .type clear_cache, %function clear_cache: push {r7, lr} mov r7, #2 mov r2, #0 orr r7, #0xf0000 svc 0x00000000 pop {r7, pc} .size clear_cache, .-clear_cache .align 2 .global breakpoint .type breakpoint, %function breakpoint: /* Set breakpoint here for debugging */ mov pc, lr .size breakpoint, .-breakpoint .section .note.GNU-stack,"",%progbits yabause-0.9.15/src/sh2_dynarec/sh2_dynarec.c000644 001750 001750 00001053110 12755623101 022611 0ustar00guillaumeguillaume000000 000000 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Yabause - sh2_dynarec.c * * Copyright (C) 2009-2011 Ari64 * * * * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include //include for uint64_t #include #include //include for memset #include #include "../memory.h" #include "../sh2core.h" #include "../yabause.h" #include "sh2_dynarec.h" #ifdef __i386__ #include "assem_x86.h" #endif #ifdef __x86_64__ #include "assem_x64.h" #endif #ifdef __arm__ #include "assem_arm.h" #endif #define MAXBLOCK 4096 #define MAX_OUTPUT_BLOCK_SIZE 262144 #define CLOCK_DIVIDER 1 #define SH2_REGS 23 struct regstat { signed char regmap_entry[HOST_REGS]; signed char regmap[HOST_REGS]; u32 wasdirty; u32 dirty; u64 u; u32 wasdoingcp; u32 isdoingcp; u32 cpmap[HOST_REGS]; u32 isconst; u32 constmap[SH2_REGS]; }; struct ll_entry { u32 vaddr; u32 reg32; void *addr; struct ll_entry *next; }; u32 start; u16 *source; void *alignedsource; u32 pagelimit; char insn[MAXBLOCK][10]; unsigned char itype[MAXBLOCK]; unsigned char opcode[MAXBLOCK]; unsigned char opcode2[MAXBLOCK]; unsigned char opcode3[MAXBLOCK]; unsigned char addrmode[MAXBLOCK]; unsigned char bt[MAXBLOCK]; signed char rs1[MAXBLOCK]; signed char rs2[MAXBLOCK]; signed char rs3[MAXBLOCK]; signed char rt1[MAXBLOCK]; signed char rt2[MAXBLOCK]; unsigned char us1[MAXBLOCK]; unsigned char us2[MAXBLOCK]; unsigned char dep1[MAXBLOCK]; unsigned char dep2[MAXBLOCK]; signed char lt1[MAXBLOCK]; int imm[MAXBLOCK]; u32 ba[MAXBLOCK]; char is_ds[MAXBLOCK]; char ooo[MAXBLOCK]; u64 unneeded_reg[MAXBLOCK]; u64 branch_unneeded_reg[MAXBLOCK]; signed char regmap_pre[MAXBLOCK][HOST_REGS]; u32 cpmap[MAXBLOCK][HOST_REGS]; struct regstat regs[MAXBLOCK]; struct regstat branch_regs[MAXBLOCK]; signed char minimum_free_regs[MAXBLOCK]; u32 needed_reg[MAXBLOCK]; u32 wont_dirty[MAXBLOCK]; u32 will_dirty[MAXBLOCK]; int cycles[MAXBLOCK]; int ccadj[MAXBLOCK]; int slen; pointer instr_addr[MAXBLOCK]; u32 link_addr[MAXBLOCK][3]; int linkcount; u32 stubs[MAXBLOCK*3][8]; int stubcount; pointer ccstub_return[MAXBLOCK]; u32 literals[1024][2]; int literalcount; int is_delayslot; u8 *out; struct ll_entry *jump_in[2048]; struct ll_entry *jump_out[2048]; struct ll_entry *jump_dirty[2048]; ALIGNED(16) u32 hash_table[65536][4]; ALIGNED(16) char shadow[2097152]; char *copy; int expirep; unsigned int stop_after_jal; //char invalid_code[0x100000]; char cached_code[0x20000]; char cached_code_words[2048*128]; u32 recent_writes[8]; u32 recent_write_index=0; unsigned int slave; u32 invalidate_count; extern int master_reg[22]; extern int master_cc; extern int master_pc; // Virtual PC extern void * master_ip; // Translated PC extern int slave_reg[22]; extern int slave_cc; extern int slave_pc; // Virtual PC extern void * slave_ip; // Translated PC extern u8 restore_candidate[512]; /* registers that may be allocated */ /* 0-15 gpr */ #define SR 16 // Status register, including T bit #define GBR 17 // Global base register #define VBR 18 // Vector base register #define MACH 19 // MACH #define MACL 20 // MACL #define PR 21 // Return address #define TBIT 22 // T bit, seperate from SR #define CCREG 23 // Cycle count #define MMREG 24 // Pointer to memory_map #define TEMPREG 25 #define PTEMP 25 // Prefetch temporary register #define MOREG 26 // offset from memory_map #define RHASH 27 // Return address hash #define RHTBL 28 // Return address hash table address #define RTEMP 29 // BRAF/BSRF address register #define MAXREG 29 #define AGEN1 30 // Address generation temporary register #define AGEN2 31 // Address generation temporary register #define MGEN1 32 // Maptable address generation temporary register #define MGEN2 33 // Maptable address generation temporary register /* instruction types */ #define NOP 0 // No operation #define LOAD 1 // Load #define STORE 2 // Store #define RMW 3 // Read-Modify-Write #define PCREL 4 // PC-relative Load #define MOV 5 // Move #define ALU 6 // Arithmetic/logic #define MULTDIV 7 // Multiply/divide #define SHIFTIMM 8// Shift by immediate #define IMM8 9 // 8-bit immediate #define EXT 10 // Sign/Zero Extension #define FLAGS 11 // SETT/CLRT/MOVT #define UJUMP 12 // Unconditional jump #define RJUMP 13 // Unconditional jump to register #define CJUMP 14 // Conditional branch (BT/BF) #define SJUMP 15 // Conditional branch with delay slot #define COMPLEX 16// Complex instructions (function call) #define SYSTEM 17 // Halt/Trap/Exception #define SYSCALL 18// SYSCALL (TRAPA) #define NI 19 // Not implemented #define DATA 20 // Constant pool data not decoded as instructions #define BIOS 21 // Emulate BIOS function /* addressing modes */ #define REGIND 1 // @Rn #define POSTINC 2 // @Rn+ #define PREDEC 3 // @-Rm #define DUALIND 4 // @(R0,Rn) #define GBRIND 5 // @(R0,GBR) #define GBRDISP 6 // @(disp,GBR) #define REGDISP 7 // @(disp,Rn) /* stubs */ #define CC_STUB 1 #define FP_STUB 2 #define LOADB_STUB 3 #define LOADW_STUB 4 #define LOADL_STUB 5 #define LOADS_STUB 6 #define STOREB_STUB 7 #define STOREW_STUB 8 #define STOREL_STUB 9 #define RMWT_STUB 10 #define RMWA_STUB 11 #define RMWX_STUB 12 #define RMWO_STUB 13 /* branch codes */ #define TAKEN 1 #define NOTTAKEN 2 #define NODS 3 // asm linkage int sh2_recompile_block(int addr); void *get_addr_ht(u32 vaddr); void get_bounds(pointer addr,u32 *start,u32 *end); void invalidate_addr(u32 addr); void remove_hash(int vaddr); void dyna_linker(); void verify_code(); void cc_interrupt(); void cc_interrupt_master(); void slave_entry(); void div1(); void macl(); void macw(); void master_handle_bios(); void slave_handle_bios(); // Needed by assembler void wb_register(signed char r,signed char regmap[],u32 dirty); void wb_dirtys(signed char i_regmap[],u32 i_dirty); void wb_needed_dirtys(signed char i_regmap[],u32 i_dirty,int addr); void load_regs(signed char entry[],signed char regmap[],int rs1,int rs2,int rs3); void load_all_regs(signed char i_regmap[]); void load_needed_regs(signed char i_regmap[],signed char next_regmap[]); void load_regs_entry(int t); void load_all_consts(signed char regmap[],u32 dirty,int i); int tracedebug=0; //#define DEBUG_CYCLE_COUNT 1 void nullf(const char *format, ...) {} //#define assem_debug printf //#define inv_debug printf #define assem_debug nullf #define inv_debug nullf // Get address from virtual address // This is called from the recompiled BRAF/BSRF instructions void *get_addr(u32 vaddr) { struct ll_entry *head; u32 page=(vaddr&0xDFFFFFFF)>>12; if(page>1024) page=1024+(page&1023); //printf("TRACE: count=%d next=%d (get_addr %x,page %d)\n",Count,next_interupt,vaddr,page); head=jump_in[page]; while(head!=NULL) { //printf("TRACE: (get_addr check %x: %x)\n",vaddr,(int)head->addr); if(head->vaddr==vaddr) { //printf("TRACE: count=%d next=%d (get_addr match %x: %x)\n",Count,next_interupt,vaddr,(int)head->addr); //printf("TRACE: (get_addr match %x: %x)\n",vaddr,(int)head->addr); u32 *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF]; ht_bin[3]=ht_bin[1]; ht_bin[2]=ht_bin[0]; ht_bin[1]=(int)head->addr; ht_bin[0]=vaddr; //printf("TRACE: get_addr clean (%x,%x)\n",vaddr,(int)head->addr); return head->addr; } head=head->next; } head=jump_dirty[page]; while(head!=NULL) { if(head->vaddr==vaddr) { //printf("TRACE: count=%d next=%d (get_addr match dirty %x: %x)\n",Count,next_interupt,vaddr,(int)head->addr); // Don't restore blocks which are about to expire from the cache if((((u32)head->addr-(u32)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) if(verify_dirty((pointer)head->addr)) { u32 start,end; u32 *ht_bin; //printf("restore candidate: %x (%d) d=%d\n",vaddr,page,(cached_code[vaddr>>15]>>((vaddr>>12)&7))&1); //invalid_code[vaddr>>12]=0; cached_code[vaddr>>15]|=1<<((vaddr>>12)&7); cached_code[(vaddr^0x20000000)>>15]|=1<<((vaddr>>12)&7); #ifdef POINTERS_64BIT memory_map[vaddr>>12]|=0x4000000000000000LL; memory_map[(vaddr^0x20000000)>>12]|=0x4000000000000000LL; #else memory_map[vaddr>>12]|=0x40000000; memory_map[(vaddr^0x20000000)>>12]|=0x40000000; #endif restore_candidate[page>>3]|=1<<(page&7); get_bounds((pointer)head->addr,&start,&end); if(start-(u32)HighWram<0x100000) { u32 vstart=start-(u32)HighWram+0x6000000; u32 vend=end-(u32)HighWram+0x6000000; int i; //printf("write protect: start=%x, end=%x\n",vstart,vend); for(i=0;i>5]|=1<<(((vstart+i)>>2)&7); } } if(start-(u32)LowWram<0x100000) { u32 vstart=start-(u32)LowWram+0x200000; u32 vend=end-(u32)LowWram+0x200000; int i; //printf("write protect: start=%x, end=%x\n",vstart,vend); for(i=0;i>5]|=1<<(((vstart+i)>>2)&7); } } ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF]; if(ht_bin[0]==vaddr) { ht_bin[1]=(int)head->addr; // Replace existing entry } else { ht_bin[3]=ht_bin[1]; ht_bin[2]=ht_bin[0]; ht_bin[1]=(int)head->addr; ht_bin[0]=vaddr; } //printf("TRACE: get_addr dirty (%x,%x)\n",vaddr,(int)head->addr); return head->addr; } } head=head->next; } sh2_recompile_block(vaddr); return get_addr(vaddr); } // Look up address in hash table first void *get_addr_ht(u32 vaddr) { //printf("TRACE: count=%d next=%d (get_addr_ht %x)\n",Count,next_interupt,vaddr); //if(vaddr>>12==0x60a0) printf("TRACE: (get_addr_ht %x)\n",vaddr); u32 *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF]; //if(vaddr>>12==0x60a0) printf("%x %x %x %x\n",ht_bin[0],ht_bin[1],ht_bin[2],ht_bin[3]); if(ht_bin[0]==vaddr) return (void *)ht_bin[1]; if(ht_bin[2]==vaddr) return (void *)ht_bin[3]; return get_addr(vaddr); } void clear_all_regs(signed char regmap[]) { int hr; for (hr=0;hr=0;hr--) if(hr!=EXCLUDE_REG&®map[hr]==r) return hr; return -1; } // Find a register that is available for two consecutive cycles signed char get_reg2(signed char regmap1[],signed char regmap2[],int r) { int hr; for (hr=0;hrregmap[hr]&63)==reg) { cur->dirty|=1<regmap[hr]==reg) { cur->isdoingcp|=1<cpmap[hr]=value; } else if((cur->regmap[hr]^64)==reg) { cur->isdoingcp|=1<cpmap[hr]=value>>32; } } } void clear_const(struct regstat *cur,signed char reg) { int hr; if(reg<0) return; for (hr=0;hrregmap[hr]&63)==reg) { cur->isdoingcp&=~(1<regmap[hr]&63)==reg) { return (cur->isdoingcp>>hr)&1; } } return 0; } u64 get_const(struct regstat *cur,signed char reg) { int hr; if(reg<0) return 0; for (hr=0;hrregmap[hr]==reg) { return cur->cpmap[hr]; } } printf("Unknown constant in r%d\n",reg); exit(1); } void sh2_set_const(u32 *isconst,u32 *constmap,signed char reg,u64 value) { *isconst|=1<=slen) { j=slen-i-1; break; } if(itype[i+j]==UJUMP||itype[i+j]==RJUMP) { // Don't go past an unconditonal jump j++; break; } } for(;j>=0;j--) { if(rs1[i+j]>=0) hsn[rs1[i+j]]=j; if(rs2[i+j]>=0) hsn[rs2[i+j]]=j; if(rs3[i+j]>=0) hsn[rs3[i+j]]=j; if(rt1[i+j]>=0) hsn[rt1[i+j]]=j; if(rt2[i+j]>=0) hsn[rt2[i+j]]=j; if(rs1[i+j]==TBIT) hsn[SR]=j; if(rs2[i+j]==TBIT) hsn[SR]=j; if(rs3[i+j]==TBIT) hsn[SR]=j; if(rt1[i+j]==TBIT) hsn[SR]=j; if(rt2[i+j]==TBIT) hsn[SR]=j; if(i+j>=0&&(itype[i+j]==UJUMP||itype[i+j]==CJUMP||itype[i+j]==SJUMP)) { hsn[CCREG]=j; b=j; } } if(b>=0) { if(ba[i+b]>=start && ba[i+b]<(start+slen*4)) { // Follow first branch int t=(ba[i+b]-start)>>2; j=7-b;if(t+j>=slen) j=slen-t-1; for(;j>=0;j--) { if(rs1[t+j]>=0) if(hsn[rs1[t+j]]>j+b+2) hsn[rs1[t+j]]=j+b+2; if(rs2[t+j]>=0) if(hsn[rs2[t+j]]>j+b+2) hsn[rs2[t+j]]=j+b+2; if(rs3[t+j]>=0) if(hsn[rs2[t+j]]>j+b+2) hsn[rs2[t+j]]=j+b+2; //if(rt1[t+j]) if(hsn[rt1[t+j]]>j+b+2) hsn[rt1[t+j]]=j+b+2; //if(rt2[t+j]) if(hsn[rt2[t+j]]>j+b+2) hsn[rt2[t+j]]=j+b+2; } } // TODO: preferred register based on backward branch } // Delay slot should preferably not overwrite branch conditions or cycle count if(i>0&&(itype[i-1]==RJUMP||itype[i-1]==UJUMP||itype[i-1]==SJUMP)) { if(rs1[i-1]>=0) if(hsn[rs1[i-1]]>1) hsn[rs1[i-1]]=1; if(rs2[i-1]>=0) if(hsn[rs2[i-1]]>1) hsn[rs2[i-1]]=1; if(rs3[i-1]>=0) if(hsn[rs3[i-1]]>1) hsn[rs3[i-1]]=1; if(itype[i-1]==SJUMP) if(hsn[SR]>1) hsn[SR]=1; hsn[CCREG]=1; // ...or hash tables hsn[RHASH]=1; hsn[RHTBL]=1; // .. or branch target hsn[RTEMP]=1; } // If reading/writing T bit, need SR if(rs1[i]==TBIT||rs2[i]==TBIT||rt1[i]==TBIT||rt2[i]==TBIT) { hsn[SR]=0; } // Don't remove the memory_map registers either if(itype[i]==LOAD || itype[i]==STORE || itype[i]==RMW || itype[i]==PCREL) { hsn[MOREG]=0; } if(itype[i]==UJUMP || itype[i]==RJUMP || itype[i]==SJUMP) { if(itype[i+1]==LOAD || itype[i+1]==STORE || itype[i+1]==RMW || itype[i+1]==PCREL) { hsn[MOREG]=0; } } if(itype[i]==SYSTEM && opcode[i]==12) { // TRAPA hsn[MOREG]=0; } // Don't remove the miniht registers if(itype[i]==UJUMP||itype[i]==RJUMP) { hsn[RHASH]=0; hsn[RHTBL]=0; // or branch target hsn[RTEMP]=0; } } // We only want to allocate registers if we're going to use them again soon int needed_again(int r, int i) { int j; int b=-1; int rn=10; if(i>0&&(itype[i-1]==UJUMP||itype[i-1]==RJUMP)) { if(ba[i-1]start+slen*4-4) return 0; // Don't need any registers if exiting the block } for(j=0;j<9;j++) { if(i+j>=slen) { j=slen-i-1; break; } if(itype[i+j]==UJUMP||itype[i+j]==RJUMP) { // Don't go past an unconditonal jump j++; break; } if(itype[i+j]==SYSCALL||itype[i+j]==SYSTEM) { break; } } for(;j>=1;j--) { if(rs1[i+j]==r) rn=j; if(rs2[i+j]==r) rn=j; if((unneeded_reg[i+j]>>r)&1) rn=10; if(i+j>=0&&(itype[i+j]==UJUMP||itype[i+j]==CJUMP||itype[i+j]==SJUMP)) { b=j; } } /* if(b>=0) { if(ba[i+b]>=start && ba[i+b]<(start+slen*4)) { // Follow first branch int o=rn; int t=(ba[i+b]-start)>>2; j=7-b;if(t+j>=slen) j=slen-t-1; for(;j>=0;j--) { if(!((unneeded_reg[t+j]>>r)&1)) { if(rs1[t+j]==r) if(rn>j+b+2) rn=j+b+2; if(rs2[t+j]==r) if(rn>j+b+2) rn=j+b+2; } else rn=o; } } }*/ if(rn<10) return 1; return 0; } // Try to match register allocations at the end of a loop with those // at the beginning int loop_reg(int i, int r, int hr) { int j,k; for(j=0;j<9;j++) { if(i+j>=slen) { j=slen-i-1; break; } if(itype[i+j]==UJUMP||itype[i+j]==RJUMP) { // Don't go past an unconditonal jump j++; break; } } k=0; if(i>0){ if(itype[i-1]==UJUMP||itype[i-1]==CJUMP||itype[i-1]==SJUMP) k--; } for(;k>r)&1)) return hr; if(i+k>=0&&(itype[i+k]==UJUMP||itype[i+k]==CJUMP||itype[i+k]==SJUMP)) { if(ba[i+k]>=start && ba[i+k]<(start+i*2)) { int t=(ba[i+k]-start)>>1; int reg=get_reg(regs[t].regmap_entry,r); if(reg>=0) return reg; //reg=get_reg(regs[t+1].regmap_entry,r); //if(reg>=0) return reg; } } } return hr; } // Allocate every register, preserving source/target regs void alloc_all(struct regstat *cur,int i) { int hr; for(hr=0;hrregmap[hr]&63)!=rs1[i])&&((cur->regmap[hr]&63)!=rs2[i])&&((cur->regmap[hr]&63)!=rs3[i])&& ((cur->regmap[hr]&63)!=rt1[i])&&((cur->regmap[hr]&63)!=rt2[i])) { cur->regmap[hr]=-1; cur->dirty&=~(1<vaddr=vaddr; new_entry->reg32=0; new_entry->addr=addr; new_entry->next=*head; *head=new_entry; } // Add to linked list only if there is not an existing record void ll_add_nodup(struct ll_entry **head,int vaddr,void *addr) { struct ll_entry *ptr; ptr=*head; while(ptr!=NULL) { if(ptr->vaddr==vaddr) { return; } ptr=ptr->next; } ll_add(head,vaddr,addr); } // Check if an address is already compiled // but don't return addresses which are about to expire from the cache void *check_addr(u32 vaddr) { struct ll_entry *head; u32 page; u32 *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF]; if(ht_bin[0]==vaddr) { if(((ht_bin[1]-MAX_OUTPUT_BLOCK_SIZE-(u32)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) if(isclean(ht_bin[1])) return (void *)ht_bin[1]; } if(ht_bin[2]==vaddr) { if(((ht_bin[3]-MAX_OUTPUT_BLOCK_SIZE-(u32)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) if(isclean(ht_bin[3])) return (void *)ht_bin[3]; } page=(vaddr&0xDFFFFFFF)>>12; if(page>1024) page=1024+(page&1023); head=jump_in[page]; while(head!=NULL) { if(head->vaddr==vaddr) { if((((u32)head->addr-(u32)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) { // Update existing entry with current address if(ht_bin[0]==vaddr) { ht_bin[1]=(int)head->addr; return head->addr; } if(ht_bin[2]==vaddr) { ht_bin[3]=(int)head->addr; return head->addr; } // Insert into hash table with low priority. // Don't evict existing entries, as they are probably // addresses that are being accessed frequently. if(ht_bin[0]==-1) { ht_bin[1]=(int)head->addr; ht_bin[0]=vaddr; }else if(ht_bin[2]==-1) { ht_bin[3]=(int)head->addr; ht_bin[2]=vaddr; } return head->addr; } } head=head->next; } return 0; } void remove_hash(int vaddr) { //printf("remove hash: %x\n",vaddr); u32 *ht_bin=hash_table[(((vaddr)>>16)^vaddr)&0xFFFF]; if(ht_bin[2]==vaddr) { ht_bin[2]=ht_bin[3]=-1; } if(ht_bin[0]==vaddr) { ht_bin[0]=ht_bin[2]; ht_bin[1]=ht_bin[3]; ht_bin[2]=ht_bin[3]=-1; } } void ll_remove_matching_addrs(struct ll_entry **head,int addr,int shift) { struct ll_entry *next; while(*head) { if(((u32)((*head)->addr)>>shift)==(addr>>shift) || ((u32)(((char *)(*head)->addr)-MAX_OUTPUT_BLOCK_SIZE)>>shift)==(addr>>shift)) { inv_debug("EXP: Remove pointer to %x (%x)\n",(int)(*head)->addr,(*head)->vaddr); remove_hash((*head)->vaddr); next=(*head)->next; free(*head); *head=next; } else { head=&((*head)->next); } } } // Remove all entries from linked list void ll_clear(struct ll_entry **head) { struct ll_entry *cur; struct ll_entry *next; if((cur=*head)) { *head=0; while(cur) { next=cur->next; free(cur); cur=next; } } } // Dereference the pointers and remove if it matches void ll_kill_pointers(struct ll_entry *head,int addr,int shift) { while(head) { int ptr=get_pointer(head->addr); inv_debug("EXP: Lookup pointer to %x at %x (%x)\n",(int)ptr,(int)head->addr,head->vaddr); if(((ptr>>shift)==(addr>>shift)) || (((ptr-MAX_OUTPUT_BLOCK_SIZE)>>shift)==(addr>>shift))) { u32 host_addr; inv_debug("EXP: Kill pointer at %x (%x)\n",(int)head->addr,head->vaddr); host_addr=(u32)kill_pointer(head->addr); #ifdef __arm__ needs_clear_cache[(host_addr-(u32)BASE_ADDR)>>17]|=1<<(((host_addr-(u32)BASE_ADDR)>>12)&31); #endif } head=head->next; } } // This is called when we write to a compiled block void invalidate_page(u32 page) { struct ll_entry *head; struct ll_entry *next; head=jump_in[page]; jump_in[page]=0; while(head!=NULL) { inv_debug("INVALIDATE: %x\n",head->vaddr); remove_hash(head->vaddr); next=head->next; free(head); head=next; } head=jump_out[page]; jump_out[page]=0; while(head!=NULL) { u32 host_addr; inv_debug("INVALIDATE: kill pointer to %x (%x)\n",head->vaddr,(int)head->addr); host_addr=(u32)kill_pointer(head->addr); #ifdef __arm__ needs_clear_cache[(host_addr-(u32)BASE_ADDR)>>17]|=1<<(((host_addr-(u32)BASE_ADDR)>>12)&31); #endif next=head->next; free(head); head=next; } } void invalidate_blocks(u32 firstblock,u32 lastblock) { u32 page; int block; u32 first,last; first=firstblock<1024?firstblock:1024+(firstblock&1023); last=lastblock<1024?lastblock:1024+(lastblock&1023); // Invalidate the adjacent pages if a block crosses a 4K boundary for(block=firstblock;block<=lastblock;block++) { struct ll_entry *head; page=block&0xDFFFF; if(page>1024) page=1024+(page&1023); inv_debug("INVALIDATE: %x..%x (%d)\n",firstblock<<12,lastblock<<12,page); //inv_debug("invalid_code[block]=%d\n",invalid_code[block]); head=jump_dirty[page]; //printf("page=%d vpage=%d\n",page,vpage); while(head!=NULL) { u32 start,end; if((head->vaddr>>12)==block) { // Ignore vaddr hash collision get_bounds((pointer)head->addr,&start,&end); //printf("start: %x end: %x\n",start,end); if(start>=(u32)LowWram&&end<(u32)LowWram+1048576) { if(((start-(u32)LowWram)>>12)<=page&&((end-1-(u32)LowWram)>>12)>=page) { if((((start-(u32)LowWram)>>12)+512)>12)&1023; if((((end-1-(u32)LowWram)>>12)+512)>last) last=((end-1-(u32)LowWram)>>12)&1023; } } // FIXME: Aliasing/mirroring is wrong here if(start>=(u32)HighWram&&end<(u32)HighWram+1048576) { if(((start-(u32)HighWram)>>12)<=page-1024&&((end-1-(u32)HighWram)>>12)>=page-1024) { if((((start-(u32)HighWram)>>12)&255)>12)&255)+1024; if((((end-1-(u32)HighWram)>>12)&255)>last-1024) last=(((end-1-(u32)HighWram)>>12)&255)+1024; } } } head=head->next; } } //printf("first=%d last=%d\n",first,last); while(first<=last) { invalidate_page(first); first++; } #ifdef __arm__ do_clear_cache(); #endif for(block=firstblock;block<=lastblock;block++) { // Don't trap writes cached_code[block>>3]&=~(1<<(block&7)); cached_code[(block^0x20000)>>3]&=~(1<<(block&7)); #ifdef POINTERS_64BIT if((block>=0x0200&&block<0x0300)||(block>=0x20200&&block<0x20300)) { memory_map[block]=((u64)LowWram-((block<<12)&0xFFF00000))>>2; memory_map[block^0x20000]=((u64)LowWram-(((block^0x20000)<<12)&0xFFF00000))>>2; } if((block>=0x6000&&block<0x8000)||(block>=0x26000&&block<0x28000)) { memory_map[block]=((u64)HighWram-((block<<12)&0xFFF00000))>>2; memory_map[block^0x20000]=((u64)HighWram-(((block^0x20000)<<12)&0xFFF00000))>>2; } #else if((block>=0x0200&&block<0x0300)||(block>=0x20200&&block<0x20300)) { memory_map[block]=((u32)LowWram-((block<<12)&0xFFF00000))>>2; memory_map[block^0x20000]=((u32)LowWram-(((block^0x20000)<<12)&0xFFF00000))>>2; } if((block>=0x6000&&block<0x8000)||(block>=0x26000&&block<0x28000)) { memory_map[block]=((u32)HighWram-((block<<12)&0xFFF00000))>>2; memory_map[block^0x20000]=((u32)HighWram-(((block^0x20000)<<12)&0xFFF00000))>>2; } #endif page=block&0xDFFFF; if(page>1024) page=1024+(page&1023); memset(cached_code_words+(page<<7),0,128); } #ifdef USE_MINI_HT memset(mini_ht_master,-1,sizeof(mini_ht_master)); memset(mini_ht_slave,-1,sizeof(mini_ht_slave)); #endif } void invalidate_addr(u32 addr) { u32 index=addr&0xDFFFFFFF; if(index>4194304) index=(addr|0x400000)&0x7fffff; if(!((cached_code_words[index>>5]>>((index>>2)&7))&1)) { // If we get an excessive number of these, // then we probably do want to invalidate the page if(invalidate_count++<500) { if((restore_candidate[index>>15]>>((index>>12)&7))&1) { recent_writes[recent_write_index]=addr; recent_write_index=(recent_write_index+1)&7; } return; } } //printf("invalidate_count: %d\n",invalidate_count); //printf("invalidate_addr(%x)\n",addr); //invalidate_block(addr>>12); invalidate_blocks(addr>>12,addr>>12); assert(!((cached_code_words[index>>5]>>((index>>2)&7))&1)); // Keep track of recent writes that invalidated the cache, so we don't // attempt constant propagation in areas that are frequently written recent_writes[recent_write_index]=addr; recent_write_index=(recent_write_index+1)&7; } // This is called when loading a save state. // Anything could have changed, so invalidate everything. void invalidate_all_pages() { u32 page; for(page=0;page<2048;page++) invalidate_page(page); for(page=0;page<256;page++) { if(cached_code[page]) { restore_candidate[page]|=cached_code[page]; // LowWram/bios } if(cached_code[3072+page]) { restore_candidate[page+256]|=cached_code[3072+page]; // HighWram } } memset(cached_code_words,0,262144); #ifdef __arm__ __clear_cache((void *)BASE_ADDR,(void *)BASE_ADDR+(1<>12; if(page>1024) page=1024+(page&1023); inv_debug("add_link: %x -> %x (%d)\n",(int)src,vaddr,page); ll_add(jump_out+page,vaddr,src); //int ptr=get_pointer(src); //inv_debug("add_link: Pointer is to %x\n",(int)ptr); } // If a code block was found to be unmodified (bit was set in // restore_candidate) and it remains unmodified (bit is set // in cached_code) then move the entries for that 4K page from // the dirty list to the clean list. void clean_blocks(u32 page) { struct ll_entry *head; inv_debug("INV: clean_blocks page=%d\n",page); head=jump_dirty[page]; while(head!=NULL) { if((cached_code[head->vaddr>>15]>>((head->vaddr>>12)&7))&1) {; // Don't restore blocks which are about to expire from the cache if((((u32)head->addr-(u32)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) { u32 start,end,vstart=0,vend; if(verify_dirty((int)head->addr)) { //printf("Possibly Restore %x (%x)\n",head->vaddr, (int)head->addr); u32 i; u32 inv=0; get_bounds((pointer)head->addr,&start,&end); if(start-(u32)HighWram<0x100000) { vstart=start-(u32)HighWram+0x6000000; vend=end-(u32)HighWram+0x6000000; for(i=(start-(u32)HighWram+0x6000000)>>12;i<=(end-1-(u32)HighWram+0x6000000)>>12;i++) { // Check that all the pages are write-protected if(!((cached_code[i>>3]>>(i&7))&1)) inv=1; } } if(start-(u32)LowWram<0x100000) { vstart=start-(u32)LowWram+0x200000; vend=end-(u32)LowWram+0x200000; for(i=(start-(u32)LowWram+0x200000)>>12;i<=(end-1-(u32)LowWram+0x200000)>>12;i++) { // Check that all the pages are write-protected if(!((cached_code[i>>3]>>(i&7))&1)) inv=1; } } // Don't restore stuff that recently got hit, it will probably get hit again if(vstart) for(i=0;i<8;i++) { if(recent_writes[i]>=vstart&&recent_writes[i]addr); if((((u32)clean_addr-(u32)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) { u32 *ht_bin; inv_debug("INV: Restored %x (%x/%x)\n",head->vaddr, (int)head->addr, (int)clean_addr); //printf("page=%x, addr=%x\n",page,head->vaddr); //assert(head->vaddr>>12==(page|0x80000)); ll_add_nodup(jump_in+page,head->vaddr,clean_addr); ht_bin=hash_table[((head->vaddr>>16)^head->vaddr)&0xFFFF]; if(ht_bin[0]==head->vaddr) { ht_bin[1]=(int)clean_addr; // Replace existing entry } if(ht_bin[2]==head->vaddr) { ht_bin[3]=(int)clean_addr; // Replace existing entry } } if(vstart) { //printf("start=%x, end=%x\n",vstart,vend); for(i=0;i>5]|=1<<(((vstart+i)>>2)&7); } } } } } } head=head->next; } } void do_consts(int i,u32 *isconst,u32 *constmap) { switch(itype[i]) { case LOAD: sh2_clear_const(isconst,constmap,rt1[i]); if(addrmode[i]==POSTINC) { int size=(opcode[i]==4)?2:(opcode2[i]&3); constmap[rt2[i]]+=1<>1)>1]; // MOV.W else value=(source[(((start+i*2+4)&~3)+imm[i]-start)>>1]<<16)+source[(((start+i*2+4)&~3)+imm[i]+2-start)>>1]; // MOV.L sh2_set_const(isconst,constmap,rt1[i],value); } else sh2_clear_const(isconst,constmap,rt1[i]); } break; case MOV: if(((*isconst)>>rs1[i])&1) { int v=constmap[rs1[i]]; sh2_set_const(isconst,constmap,rt1[i],v); } else sh2_clear_const(isconst,constmap,rt1[i]); break; case IMM8: if(opcode[i]==0x7) { // ADD if(((*isconst)>>rs1[i])&1) { int v=constmap[rs1[i]]; sh2_set_const(isconst,constmap,rt1[i],v+imm[i]); } else sh2_clear_const(isconst,constmap,rt1[i]); } else if(opcode[i]==0x8) { // CMP/EQ } else if(opcode[i]==12) { if(opcode2[i]==8) { // TST }else // AND/XOR/OR if(((*isconst)>>rs1[i])&1) { int v=constmap[rs1[i]]; if(opcode2[i]==0x09) sh2_set_const(isconst,constmap,rt1[i],v&imm[i]); if(opcode2[i]==0x0a) sh2_set_const(isconst,constmap,rt1[i],v^imm[i]); if(opcode2[i]==0x0b) sh2_set_const(isconst,constmap,rt1[i],v|imm[i]); } else sh2_clear_const(isconst,constmap,rt1[i]); } else { // opcode[i]==0xE assert(opcode[i]==0xE); sh2_set_const(isconst,constmap,rt1[i],imm[i]); // MOV } break; case FLAGS: if(opcode2[i]==9) { // MOVT sh2_clear_const(isconst,constmap,rt1[i]); } break; case ALU: sh2_clear_const(isconst,constmap,rt1[i]); break; case EXT: sh2_clear_const(isconst,constmap,rt1[i]); break; case MULTDIV: if(opcode[i]==0) { if(opcode2[i]==7) // MUL.L { sh2_clear_const(isconst,constmap,MACL); } if(opcode2[i]==8) // CLRMAC { sh2_clear_const(isconst,constmap,MACH); sh2_clear_const(isconst,constmap,MACL); } if(opcode2[i]==9) // DIV0U { } } if(opcode[i]==2) { if(opcode2[i]==7) // DIV0S { } if(opcode2[i]==14||opcode2[i]==15) // MULU.W / MULS.W { sh2_clear_const(isconst,constmap,MACL); } } if(opcode[i]==3) { // DMULU.L / DMULS.L sh2_clear_const(isconst,constmap,MACH); sh2_clear_const(isconst,constmap,MACL); } break; case SHIFTIMM: sh2_clear_const(isconst,constmap,rt1[i]); break; case UJUMP: case RJUMP: case SJUMP: case CJUMP: break; case SYSTEM: *isconst=0; break; case COMPLEX: *isconst=0; break; } } void mov_alloc(struct regstat *current,int i) { // Note: Don't need to actually alloc the source registers // TODO: Constant propagation //alloc_reg(current,i,rs1[i]); alloc_reg(current,i,rt1[i]); clear_const(current,rs1[i]); clear_const(current,rt1[i]); dirty_reg(current,rt1[i]); } void shiftimm_alloc(struct regstat *current,int i) { clear_const(current,rs1[i]); clear_const(current,rt1[i]); alloc_reg(current,i,rs1[i]); alloc_reg(current,i,rt1[i]); dirty_reg(current,rt1[i]); if(opcode[i]==4) { if(opcode2[i]<6) { // SHLL/SHAL/SHLR/SHAR/ROTL/ROTCL/ROTR/ROTCR if(opcode2[i]<4||opcode3[i]<2) { // SHL/SHA/ROT don't need T bit as a source, only a destination if(!(current->u&(1LL<8&&opcode2[i]<=11) { // AND/XOR/OR alloc_reg(current,i,rt1[i]); } else // TST or CMP/STR { alloc_reg(current,i,SR); // Liveness analysis on TBIT? dirty_reg(current,SR); //#ifdef __x86__ ? //#ifdef NEEDS_TEMP if(opcode2[i]==8) { // TST alloc_reg_temp(current,i,-1); minimum_free_regs[i]=1; } if(opcode2[i]==12) { // CMP/STR alloc_reg_temp(current,i,-1); minimum_free_regs[i]=1; } } } if(opcode[i]==3) { alloc_reg(current,i,rs1[i]); alloc_reg(current,i,rs2[i]); clear_const(current,rs2[i]); if(opcode2[i]<8) { // CMP intructions alloc_reg(current,i,SR); // Liveness analysis on TBIT? dirty_reg(current,SR); alloc_reg_temp(current,i,-1); minimum_free_regs[i]=1; }else{ // ADD/SUB alloc_reg(current,i,rt1[i]); if(opcode2[i]&3) { alloc_reg(current,i,SR); dirty_reg(current,SR); //#ifdef NEEDS_TEMP if((opcode2[i]&3)==3) { // Need a temporary register for ADDV/SUBV on x86 alloc_reg_temp(current,i,-1); minimum_free_regs[i]=1; } } } } if(opcode[i]==4) { // DT/CMPPZ/CMPPL // Single operand forms alloc_reg(current,i,rs1[i]); if(opcode2[i]==0) dirty_reg(current,rt1[i]); // DT alloc_reg(current,i,SR); // Liveness analysis on TBIT? dirty_reg(current,SR); if(opcode2[i]>0) { alloc_reg_temp(current,i,-1); minimum_free_regs[i]=1; } } if(opcode[i]==6) { // NOT/NEG/NEGC if(needed_again(rs1[i],i)) alloc_reg(current,i,rs1[i]); alloc_reg(current,i,rt1[i]); if(opcode2[i]==8||opcode2[i]==9) { // SWAP needs temp (?) alloc_reg_temp(current,i,-1); minimum_free_regs[i]=1; } if(opcode2[i]==10) { // NEGC sets T bit alloc_reg(current,i,SR); // Liveness analysis on TBIT? dirty_reg(current,SR); } } clear_const(current,rs1[i]); clear_const(current,rt1[i]); dirty_reg(current,rt1[i]); } void imm8_alloc(struct regstat *current,int i) { //if(rs1[i]>=0&&needed_again(rs1[i],i)) alloc_reg(current,i,rs1[i]); //else lt1[i]=rs1[i]; alloc_reg(current,i,rs1[i]); if(rt1[i]>=0&&rt1[i]!=TBIT) alloc_reg(current,i,rt1[i]); if(opcode[i]==0x7) { // ADD if(is_const(current,rs1[i])) { int v=get_const(current,rs1[i]); set_const(current,rt1[i],v+imm[i]); } else clear_const(current,rt1[i]); } else if(opcode[i]==0x8) { // CMP/EQ alloc_reg(current,i,SR); // Liveness analysis on TBIT? dirty_reg(current,SR); alloc_reg_temp(current,i,-1); minimum_free_regs[i]=1; } else if(opcode[i]==12) { if(opcode2[i]==8) { // TST alloc_reg(current,i,SR); // Liveness analysis on TBIT? dirty_reg(current,SR); alloc_reg_temp(current,i,-1); minimum_free_regs[i]=1; }else // AND/XOR/OR if(is_const(current,rs1[i])) { int v=get_const(current,rs1[i]); if(opcode2[i]==0x09) set_const(current,rt1[i],v&imm[i]); if(opcode2[i]==0x0a) set_const(current,rt1[i],v^imm[i]); if(opcode2[i]==0x0b) set_const(current,rt1[i],v|imm[i]); } else clear_const(current,rt1[i]); } else { // opcode[i]==0xE assert(opcode[i]==0xE); set_const(current,rt1[i],imm[i]); // MOV } if(rt1[i]>=0&&rt1[i]!=TBIT) dirty_reg(current,rt1[i]); } void ext_alloc(struct regstat *current,int i) { // Note: Don't need to actually alloc the source registers // FIXME: Constant propagation //alloc_reg(current,i,rs1[i]); alloc_reg(current,i,rt1[i]); clear_const(current,rs1[i]); clear_const(current,rt1[i]); dirty_reg(current,rt1[i]); } void flags_alloc(struct regstat *current,int i) { if(opcode2[i]==8) { // CLRT/SETT alloc_reg(current,i,SR); dirty_reg(current,SR); }else if(opcode2[i]==9) { // MOVT alloc_reg(current,i,SR); alloc_reg(current,i,rt1[i]); clear_const(current,rt1[i]); dirty_reg(current,rt1[i]); } } void load_alloc(struct regstat *current,int i) { int hr; clear_const(current,rt1[i]); //if(rs1[i]!=rt1[i]&&needed_again(rs1[i],i)) clear_const(current,rs1[i]); // Does this help or hurt? if(needed_again(rs1[i],i)) alloc_reg(current,i,rs1[i]); // if(rs2[i]>=0) alloc_reg(current,i,rs2[i]); alloc_reg(current,i,rt1[i]==TBIT?SR:rt1[i]); if(addrmode[i]==DUALIND||addrmode[i]==GBRIND) { alloc_reg(current,i,rs1[i]); alloc_reg(current,i,rs2[i]); if(!is_const(current,rs1[i])||!is_const(current,rs2[i])) { // Both must be constants to propagate the sum clear_const(current,rs1[i]); clear_const(current,rs2[i]); } } else if(addrmode[i]==POSTINC) { if(is_const(current,rt2[i])) { int v=get_const(current,rt2[i]); set_const(current,rt2[i],v+(1<<((opcode[i]==4)?2:(opcode2[i]&3)))); // Note: constant is preincremented, address_generation corrects the offset } else { alloc_reg(current,i,rt2[i]); dirty_reg(current,rt2[i]); } } // Need a register to load from memory_map alloc_reg(current,i,MOREG); if(rt1[i]==TBIT||get_reg(current->regmap,rt1[i])<0) { // dummy load, but we still need a register to calculate the address alloc_reg_temp(current,i,-1); minimum_free_regs[i]=1; } if(rt1[i]==TBIT) dirty_reg(current,SR); else dirty_reg(current,rt1[i]); // Make MOREG a temporary, give pass 5 another register to work with hr=get_reg(current->regmap,MOREG); assert(hr>=0); assert(current->regmap[hr]==MOREG); current->regmap[hr]=-1; minimum_free_regs[i]++; } void store_alloc(struct regstat *current,int i) { int hr; //printf("%x: eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d\n",start+i*2,current->regmap[0],current->regmap[1],current->regmap[2],current->regmap[3],current->regmap[5],current->regmap[6],current->regmap[7]); if(addrmode[i]==DUALIND) { alloc_reg(current,i,rs2[i]); alloc_reg(current,i,0); // rs3[i] if(!is_const(current,rs2[i])||!is_const(current,rs3[i])) { // Both must be constants to propagate the sum clear_const(current,rs2[i]); clear_const(current,rs3[i]); } } if(addrmode[i]==PREDEC) { if(is_const(current,rt1[i])) { int v=get_const(current,rt1[i]); set_const(current,rt1[i],v-(1<<((opcode[i]==4)?2:(opcode2[i]&3)))); } else { alloc_reg(current,i,rt1[i]); dirty_reg(current,rt1[i]); } } if(needed_again(rs2[i],i)) alloc_reg(current,i,rs2[i]); clear_const(current,rs1[i]); alloc_reg(current,i,rs1[i]); // Need a register to load from memory_map alloc_reg(current,i,MOREG); // We need a temporary register for address generation alloc_reg_temp(current,i,-1); minimum_free_regs[i]=1; // Make MOREG a temporary, give pass 5 another register to work with hr=get_reg(current->regmap,MOREG); assert(hr>=0); assert(current->regmap[hr]==MOREG); current->regmap[hr]=-1; minimum_free_regs[i]++; } void rmw_alloc(struct regstat *current,int i) { //printf("%x: eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d\n",start+i*2,current->regmap[0],current->regmap[1],current->regmap[2],current->regmap[3],current->regmap[5],current->regmap[6],current->regmap[7]); if(addrmode[i]==GBRIND) { alloc_reg(current,i,GBR); alloc_reg(current,i,0); if(!is_const(current,rs2[i])||!is_const(current,rs3[i])) { // Both must be constants to propagate the sum clear_const(current,rs2[i]); clear_const(current,rs3[i]); } } if(addrmode[i]==REGIND&&needed_again(rs1[i],i)) alloc_reg(current,i,rs1[i]); if(rt1[i]==TBIT) { alloc_reg(current,i,SR); dirty_reg(current,SR); } // Need a register to load from memory_map alloc_reg(current,i,MOREG); // We need a temporary register for address generation alloc_reg_temp(current,i,-1); // And one for the read-modify-write //alloc_reg_temp(current,i,-2); // Can re-use mapping reg for this minimum_free_regs[i]=1; } void pcrel_alloc(struct regstat *current,int i) { u32 addr; alloc_reg(current,i,rt1[i]); addr=((start+i*2+4)&~3)+imm[i]; if(opcode[i]==12) { // MOVA, address generation only set_const(current,rt1[i],addr); }else if((unsigned)((addr-start)>>1)>1]); } else // MOV.L set_const(current,rt1[i],(source[(addr-start)>>1]<<16)+source[(addr+2-start)>>1]); } else { // Do actual load //alloc_reg(current,i,MOREG); clear_const(current,rt1[i]); } dirty_reg(current,rt1[i]); } #ifndef multdiv_alloc void multdiv_alloc(struct regstat *current,int i) { //printf("%x: eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d\n",start+i*2,current->regmap[0],current->regmap[1],current->regmap[2],current->regmap[3],current->regmap[5],current->regmap[6],current->regmap[7]); if(opcode[i]==0) { if(opcode2[i]==7) // MUL.L { clear_const(current,rs1[i]); clear_const(current,rs2[i]); clear_const(current,MACL); alloc_reg(current,i,rs1[i]); alloc_reg(current,i,rs2[i]); alloc_reg(current,i,MACL); dirty_reg(current,MACL); } if(opcode2[i]==8) // CLRMAC { clear_const(current,MACH); clear_const(current,MACL); alloc_reg(current,i,MACH); alloc_reg(current,i,MACL); dirty_reg(current,MACH); dirty_reg(current,MACL); } if(opcode2[i]==9) // DIV0U { alloc_reg(current,i,SR); dirty_reg(current,SR); } } if(opcode[i]==2) { if(opcode2[i]==7) // DIV0S { clear_const(current,rs1[i]); // Is this necessary? clear_const(current,rs2[i]); // Is this necessary? alloc_reg(current,i,rs1[i]); alloc_reg(current,i,rs2[i]); alloc_reg(current,i,SR); dirty_reg(current,SR); #if defined(__i386__) || defined(__x86_64__) //#ifdef NEEDS_TEMP alloc_reg_temp(current,i,-1); minimum_free_regs[i]=1; #endif } if(opcode2[i]==14||opcode2[i]==15) // MULU.W / MULS.W { clear_const(current,rs1[i]); clear_const(current,rs2[i]); clear_const(current,MACL); alloc_reg(current,i,rs1[i]); alloc_reg(current,i,rs2[i]); alloc_reg(current,i,MACL); dirty_reg(current,MACL); //#ifdef NEEDS_TEMP alloc_reg_temp(current,i,-1); minimum_free_regs[i]=1; } } if(opcode[i]==3) { // DMULU.L / DMULS.L #if defined(__i386__) || defined(__x86_64__) if(!(current->u&(1LL<u&=~(1LL<u&(1LL<u&=~(1LL<isdoingcp=0; } void delayslot_alloc(struct regstat *current,int i) { switch(itype[i]) { case UJUMP: case CJUMP: case SJUMP: case RJUMP: case SYSCALL: assem_debug("jump in the delay slot. this shouldn't happen.\n");//exit(1); printf("Disabled speculative precompilation\n"); stop_after_jal=1; break; case IMM8: imm8_alloc(current,i); break; case LOAD: load_alloc(current,i); break; case STORE: store_alloc(current,i); break; case RMW: rmw_alloc(current,i); break; case PCREL: pcrel_alloc(current,i); break; case ALU: alu_alloc(current,i); break; case MULTDIV: multdiv_alloc(current,i); break; case SHIFTIMM: shiftimm_alloc(current,i); break; case MOV: mov_alloc(current,i); break; case EXT: ext_alloc(current,i); break; case FLAGS: flags_alloc(current,i); break; case COMPLEX: complex_alloc(current,i); break; } } void add_stub(int type,int addr,int retaddr,int a,int b,int c,int d,int e) { stubs[stubcount][0]=type; stubs[stubcount][1]=addr; stubs[stubcount][2]=retaddr; stubs[stubcount][3]=a; stubs[stubcount][4]=b; stubs[stubcount][5]=c; stubs[stubcount][6]=d; stubs[stubcount][7]=e; stubcount++; } // Write out a single register void wb_register(signed char r,signed char regmap[],u32 dirty) { int hr; for(hr=0;hr>hr)&1) { emit_storereg(r,hr); } } } } } /*int mchecksum() { //if(!tracedebug) return 0; int i; int sum=0; for(i=0;i<2097152;i++) { unsigned int temp=sum; sum<<=1; sum|=(~temp)>>31; sum^=((u_int *)rdram)[i]; } return sum; } int rchecksum() { int i; int sum=0; for(i=0;i<64;i++) sum^=((u_int *)reg)[i]; return sum; } int fchecksum() { int i; int sum=0; for(i=0;i<64;i++) sum^=((u_int *)reg_cop1_fgr_64)[i]; return sum; } void rlist() { int i; printf("TRACE: "); for(i=0;i<32;i++) printf("r%d:%8x%8x ",i,((int *)(reg+i))[1],((int *)(reg+i))[0]); printf("\n"); //printf("TRACE: "); //for(i=0;i<32;i++) // printf("f%d:%8x%8x ",i,((int*)reg_cop1_simple[i])[1],*((int*)reg_cop1_simple[i])); //printf("\n"); }*/ void enabletrace() { tracedebug=1; } #if 0 void memdebug(int i) { //printf("TRACE: count=%d next=%d (checksum %x) lo=%8x%8x\n",Count,next_interupt,mchecksum(),(int)(reg[LOREG]>>32),(int)reg[LOREG]); //printf("TRACE: count=%d next=%d (rchecksum %x)\n",Count,next_interupt,rchecksum()); //rlist(); //if(tracedebug) { //if(Count>=-2084597794) { //if((signed int)Count>=-2084597794&&(signed int)Count<0) { //if(0) { printf("TRACE: (checksum %x)\n",mchecksum()); //printf("TRACE: count=%d next=%d (checksum %x)\n",Count,next_interupt,mchecksum()); //printf("TRACE: count=%d next=%d (checksum %x) Status=%x\n",Count,next_interupt,mchecksum(),Status); //printf("TRACE: count=%d next=%d (checksum %x) hi=%8x%8x\n",Count,next_interupt,mchecksum(),(int)(reg[HIREG]>>32),(int)reg[HIREG]); //rlist(); #ifdef __i386__ printf("TRACE: %x\n",(&i)[-1]); #endif #ifdef __arm__ int j; printf("TRACE: %x \n",(&j)[10]); printf("TRACE: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n",(&j)[1],(&j)[2],(&j)[3],(&j)[4],(&j)[5],(&j)[6],(&j)[7],(&j)[8],(&j)[9],(&j)[10],(&j)[11],(&j)[12],(&j)[13],(&j)[14],(&j)[15],(&j)[16],(&j)[17],(&j)[18],(&j)[19],(&j)[20]); #endif //fflush(stdout); //} //printf("TRACE: %x\n",(&i)[-1]); } #endif void alu_assemble(int i,struct regstat *i_regs) { if(opcode[i]==2) { if(opcode2[i]>=9&&opcode2[i]<=11) { // AND/XOR/OR signed char s,t; s=get_reg(i_regs->regmap,rs1[i]); t=get_reg(i_regs->regmap,rt1[i]); //assert(s>=0); if(t>=0) { if(opcode2[i]==9) emit_and(s,t,t); if(opcode2[i]==10) emit_xor(rs1[i]>=0?s:t,t,t); if(opcode2[i]==11) emit_or(s,t,t); } } else { signed char s1,s2,sr,temp; s1=get_reg(i_regs->regmap,rs1[i]); s2=get_reg(i_regs->regmap,rs2[i]); sr=get_reg(i_regs->regmap,SR); temp=get_reg(i_regs->regmap,-1); assert(s1>=0); assert(s2>=0); assert(sr>=0); assert(temp>=0); // Not needed for TST on ARM? if(opcode2[i]==8) { // TST emit_sh2tst(s1,s2,sr,temp); } else if(opcode2[i]==12) { // CMP/STR emit_cmpstr(s1,s2,sr,temp); } } } if(opcode[i]==3) { // ADD/SUB if(opcode2[i]<8) { // CMP signed char s1,s2,sr,temp; s1=get_reg(i_regs->regmap,rs1[i]); s2=get_reg(i_regs->regmap,rs2[i]); sr=get_reg(i_regs->regmap,SR); temp=get_reg(i_regs->regmap,-1); assert(s1>=0); assert(s2>=0); assert(temp>=0); if(opcode2[i]==0) emit_cmpeq(s1,s2,sr,temp); if(opcode2[i]==2) emit_cmphs(s1,s2,sr,temp); if(opcode2[i]==3) emit_cmpge(s1,s2,sr,temp); if(opcode2[i]==6) emit_cmphi(s1,s2,sr,temp); if(opcode2[i]==7) emit_cmpgt(s1,s2,sr,temp); } else { signed char s,t,sr,temp; t=get_reg(i_regs->regmap,rt1[i]); if(t>=0) { s=get_reg(i_regs->regmap,rs1[i]); sr=get_reg(i_regs->regmap,SR); temp=get_reg(i_regs->regmap,-1); assert(s>=0); //assert(s2==t); if(opcode2[i]==8) emit_sub(t,s,t); if(opcode2[i]==10) emit_subc(s,t,sr); //if(opcode2[i]==11) emit_subv(s,sr,temp); assert(opcode2[i]!=11); if(opcode2[i]==12) emit_add(s,t,t); if(opcode2[i]==14) emit_addc(s,t,sr); //if(opcode2[i]==15) emit_addv(s,sr,temp); assert(opcode2[i]!=15); } } } if(opcode[i]==4) { // DT/CMPPZ/CMPPL signed char s,t,sr,temp; s=get_reg(i_regs->regmap,rs1[i]); sr=get_reg(i_regs->regmap,SR); assert(s>=0); assert(sr>=0); if(opcode2[i]==0) { t=get_reg(i_regs->regmap,rt1[i]); assert(t>=0); // FIXME - Liveness analysis assert(s==t); emit_dt(s,sr); } else if(opcode2[i]==1) emit_cmppz(s,sr); else if(opcode2[i]==5) { temp=get_reg(i_regs->regmap,-1); emit_cmppl(s,sr,temp); } } if(opcode[i]==6) { // NOT/SWAP/NEG int s=get_reg(i_regs->regmap,rs1[i]); int t=get_reg(i_regs->regmap,rt1[i]); if(s<0) { // FIXME: Preload? emit_loadreg(rs1[i],t); s=t; } if(t>=0) { if(opcode2[i]==7) emit_not(s,t); if(opcode2[i]==8) emit_swapb(s,t); if(opcode2[i]==9) emit_rorimm(s,16,t); if(opcode2[i]==11) emit_neg(s,t); } if(opcode2[i]==10) { // NEGC int sr=get_reg(i_regs->regmap,SR); if(i_regs->u&(1LL<=0); emit_negc(s,t,sr); } } } void imm8_assemble(int i,struct regstat *i_regs) { if(opcode[i]==0x7) { // ADD signed char s,t; t=get_reg(i_regs->regmap,rt1[i]); s=get_reg(i_regs->regmap,rs1[i]); //assert(t>=0); assert(s>=0); if(t>=0) { if(!((i_regs->isdoingcp>>t)&1)) { if(s<0) { if(i_regs->regmap_entry[t]!=rs1[i]) emit_loadreg(rs1[i],t); emit_addimm(t,imm[i],t); }else{ if(!((i_regs->wasdoingcp>>s)&1)) emit_addimm(s,imm[i],t); else emit_movimm(cpmap[i][s]+imm[i],t); } } } } else if(opcode[i]==0x8) { // CMP/EQ signed char s,sr,temp; s=get_reg(i_regs->regmap,rs1[i]); sr=get_reg(i_regs->regmap,SR); temp=get_reg(i_regs->regmap,-1); assert(s>=0); assert(sr>=0); // Liveness analysis? assert(temp>=0); emit_cmpeqimm(s,imm[i],sr,temp); } else if(opcode[i]==12) { if(opcode2[i]==8) { // TST signed char s,sr,temp; s=get_reg(i_regs->regmap,rs1[i]); sr=get_reg(i_regs->regmap,SR); temp=get_reg(i_regs->regmap,-1); assert(s>=0); assert(sr>=0); // Liveness analysis? assert(temp>=0); emit_sh2tstimm(s,imm[i],sr,temp); }else{ signed char s,t; t=get_reg(i_regs->regmap,rt1[i]); s=get_reg(i_regs->regmap,rs1[i]); if(t>=0 && !((i_regs->isdoingcp>>t)&1)) { if(opcode2[i]==9) //AND { if(s<0) { if(i_regs->regmap_entry[t]!=rs1[i]) emit_loadreg(rs1[i],t); emit_andimm(t,imm[i],t); }else{ if(!((i_regs->wasdoingcp>>s)&1)) emit_andimm(s,imm[i],t); else emit_movimm(cpmap[i][s]&imm[i],t); } } else if(opcode2[i]==10) //XOR { if(s<0) { if(i_regs->regmap_entry[t]!=rs1[i]) emit_loadreg(rs1[i],t); emit_xorimm(t,imm[i],t); }else{ if(!((i_regs->wasdoingcp>>s)&1)) emit_xorimm(s,imm[i],t); else emit_movimm(cpmap[i][s]^imm[i],t); } } else if(opcode2[i]==11) //OR { if(s<0) { if(i_regs->regmap_entry[t]!=rs1[i]) emit_loadreg(rs1[i],t); emit_orimm(t,imm[i],t); }else{ if(!((i_regs->wasdoingcp>>s)&1)) emit_orimm(s,imm[i],t); else emit_movimm(cpmap[i][s]|imm[i],t); } } } } } else { // opcode[i]==0xE signed char t; assert(opcode[i]==0xE); t=get_reg(i_regs->regmap,rt1[i]); //assert(t>=0); if(t>=0) { if(!((i_regs->isdoingcp>>t)&1)) emit_movimm(imm[i]<<16,t); } } } void shiftimm_assemble(int i,struct regstat *i_regs) { if(opcode[i]==4) // SHL/SHR { if(opcode2[i]<8) { signed char s,t,sr; s=get_reg(i_regs->regmap,rs1[i]); t=get_reg(i_regs->regmap,rt1[i]); sr=get_reg(i_regs->regmap,SR); assert(s==t); if(opcode2[i]==0) // SHLL/SHAL { if(i_regs->u&(1LL<u&(1LL<u&(1LL<u&(1LL<regmap,rs1[i]); t=get_reg(i_regs->regmap,rt1[i]); //assert(t>=0); if(t>=0){ if(opcode2[i]==8) // SHLL { if(opcode3[i]==0) emit_shlimm(s,2,t); if(opcode3[i]==1) emit_shlimm(s,8,t); if(opcode3[i]==2) emit_shlimm(s,16,t); } if(opcode2[i]==9) // SHLR { if(opcode3[i]==0) emit_shrimm(s,2,t); if(opcode3[i]==1) emit_shrimm(s,8,t); if(opcode3[i]==2) emit_shrimm(s,16,t); } } } } else if(opcode[i]==2) // XTRCT { signed char s,t,sr; s=get_reg(i_regs->regmap,rs1[i]); t=get_reg(i_regs->regmap,rt1[i]); assert(rs2[i]==rt1[i]); emit_shrdimm(t,s,16,t); } } void load_assemble(int i,struct regstat *i_regs) { int dummy; int s,o,t,addr,map=-1,cache=-1; int offset; int jaddr=0; int memtarget,c=0; int dualindex=(addrmode[i]==DUALIND||addrmode[i]==GBRIND); int size=(opcode[i]==4)?2:(opcode2[i]&3); unsigned int hr; u32 reglist=0; pointer constaddr; t=get_reg(i_regs->regmap,rt1[i]==TBIT?-1:rt1[i]); s=get_reg(i_regs->regmap,rs1[i]); o=get_reg(i_regs->regmap,rs2[i]); offset=imm[i]; for(hr=0;hrregmap[hr]>=0) reglist|=1<regmap[HOST_CCREG]==CCREG) reglist&=~(1<=0) { if(dualindex) c=(i_regs->wasdoingcp>>s)&(i_regs->wasdoingcp>>o)&1; else c=(i_regs->wasdoingcp>>s)&1; if(c) { if(dualindex) constaddr=cpmap[i][s]+cpmap[i][o]; else constaddr=cpmap[i][s]+offset; //if(dualindex) { // if((i_regs->isconst>>rs1[i])&(i_regs->isconst>>rs2[i])&1) // assert(constaddr==i_regs->constmap[rs1[i]]+i_regs->constmap[rs2[i]]); //}else // if((i_regs->isconst>>rs1[i])&1) // assert(constaddr==i_regs->constmap[rs1[i]]+offset); if(addrmode[i]==POSTINC) constaddr-=1<regmap,-1); if(!c) { if(dualindex) { c=(i_regs->isconst>>rs1[i])&(i_regs->isconst>>rs2[i])&1; } else { c=(i_regs->isconst>>rs1[i])&1; } if(c) { if(dualindex) constaddr=i_regs->constmap[rs1[i]]+i_regs->constmap[rs2[i]]; else constaddr=i_regs->constmap[rs1[i]]+offset; if(addrmode[i]==POSTINC) constaddr-=1<=0); // Even if the load is a NOP, we must check for I/O reglist&=~(1<regmap,MMREG); map=get_reg(i_regs->regmap,MOREG); if(map<0) map=get_alt_reg(i_regs->regmap,-1); assert(map>=0); assert(map!=s); assert(map!=t); reglist&=~(1<regmap,rt1[i])); // ignore loads to unneeded reg if(opcode[i]==12&&opcode2[i]==12) // TST.B dummy=i_regs->u&(1LL<regmap,rt1[i],ccadj[i],reglist); if(rt1[i]==TBIT&&!dummy) { // TST.B signed char sr; sr=get_reg(i_regs->regmap,SR); assert(sr>=0); // Liveness analysis? emit_sh2tstimm(t,imm[i],sr,t); } } if (size==1) { // MOV.W if(!c||memtarget) { if(!dummy) { #ifdef HOST_IMM_ADDR32 if(c) emit_movswl(constaddr,t); else #endif { int x=0; emit_movswl_indexed_map(0,addr,map,t); } } if(jaddr) add_stub(LOADW_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); } else inline_readstub(LOADW_STUB,i,constaddr,i_regs->regmap,rt1[i],ccadj[i],reglist); } if (size==2) { // MOV.L if(!c||memtarget) { if(!dummy) { #ifdef HOST_IMM_ADDR32 if(c) emit_readword(constaddr,t); else #endif emit_readword_indexed_map(0,addr,map,t); emit_rorimm(t,16,t); } if(jaddr) add_stub(LOADL_STUB,jaddr,(int)out,i,addr,(int)i_regs,ccadj[i],reglist); } else inline_readstub(LOADL_STUB,i,constaddr,i_regs->regmap,rt1[i],ccadj[i],reglist); } if(addrmode[i]==POSTINC) { if(!((i_regs->wasdoingcp>>s)&1)) { if(!(i_regs->u&(1LL<regmap,CCREG)<0) emit_loadreg(CCREG,HOST_CCREG); emit_add(HOST_CCREG,ECX,HOST_CCREG); emit_addimm(HOST_CCREG,2*ccadj[i],HOST_CCREG); emit_writeword(HOST_CCREG,(int)&Count); #endif #ifdef __arm__ if(get_reg(i_regs->regmap,CCREG)<0) emit_loadreg(CCREG,0); else emit_mov(HOST_CCREG,0); emit_add(0,ECX,0); emit_addimm(0,2*ccadj[i],0); emit_writeword(0,(int)&Count); #endif emit_call((int)memdebug); //emit_popa(); restore_regs(0x100f); }*/ } void store_assemble(int i,struct regstat *i_regs) { int s,t,o,map=-1,cache=-1; int addr,temp; int offset; int jaddr=0,jaddr2,type; int memtarget,c=0,constaddr; int dualindex=(addrmode[i]==DUALIND); int size=(opcode[i]==4)?2:(opcode2[i]&3); int agr=AGEN1+(i&1); unsigned int hr; u32 reglist=0; t=get_reg(i_regs->regmap,rs1[i]); s=get_reg(i_regs->regmap,rs2[i]); o=get_reg(i_regs->regmap,rs3[i]); temp=get_reg(i_regs->regmap,agr); if(temp<0) temp=get_reg(i_regs->regmap,-1); offset=imm[i]; for(hr=0;hrregmap[hr]>=0) reglist|=1<regmap[HOST_CCREG]==CCREG) reglist&=~(1<=0) { if(dualindex) c=(i_regs->wasdoingcp>>s)&(i_regs->wasdoingcp>>o)&1; else c=(i_regs->wasdoingcp>>s)&1; if(c) { if(dualindex) constaddr=cpmap[i][s]+cpmap[i][o]; else constaddr=cpmap[i][s]+offset; } //printf("constaddr=%x offset=%x\n",constaddr,offset); memtarget=can_direct_write(constaddr); } if(!c) { if(dualindex) { c=(i_regs->isconst>>rs2[i])&(i_regs->isconst>>rs3[i])&1; } else { c=(i_regs->isconst>>rs2[i])&1; } if(c) { if(dualindex) constaddr=i_regs->constmap[rs2[i]]+i_regs->constmap[rs3[i]]; else constaddr=i_regs->constmap[rs2[i]]+offset; //printf("constaddr=%x offset=%x\n",constaddr,offset); memtarget=can_direct_write(constaddr); // In this case, the constant is not already loaded into a register if(can_direct_write(constaddr)) { emit_movimm(constaddr^(!size),temp); map=get_reg(i_regs->regmap,MOREG); if(map<0) map=get_alt_reg(i_regs->regmap,-1); generate_map_const(constaddr,map); } } } assert(t>=0); assert(temp>=0); if(offset||dualindex||s<0||c) addr=temp; else addr=s; //printf("store_assemble: c=%d\n",c); if(addrmode[i]==PREDEC&&!c&&rt1[i]==rs1[i]) addr=temp; // Old value is written, so decremented address is in a temporary register if(addrmode[i]==REGIND&&!c&&rs1[i]==rs2[i]) {// Swapped value is written, so unswapped value must be used as the address emit_mov(addr,temp);addr=temp; } if(!c||memtarget) { int x=0; if (!c&&size==0) x=1; // MOV.B cache=get_reg(i_regs->regmap,MMREG); map=get_reg(i_regs->regmap,MOREG); if(map<0) map=get_alt_reg(i_regs->regmap,-1); assert(map>=0); assert(map!=temp); assert(map!=s); reglist&=~(1<u&(1LL<regmap,rs1[i],ccadj[i],reglist); } if(addrmode[i]==PREDEC) { assert(s>=0); if(!((i_regs->wasdoingcp>>s)&1)&&rt1[i]==rs1[i]) emit_addimm(s,-(1<regmap,CCREG)<0) emit_loadreg(CCREG,HOST_CCREG); emit_add(HOST_CCREG,ECX,HOST_CCREG); emit_addimm(HOST_CCREG,2*ccadj[i],HOST_CCREG); emit_writeword(HOST_CCREG,(int)&Count); #endif #ifdef __arm__ if(get_reg(i_regs->regmap,CCREG)<0) emit_loadreg(CCREG,0); else emit_mov(HOST_CCREG,0); emit_add(0,ECX,0); emit_addimm(0,2*ccadj[i],0); emit_writeword(0,(int)&Count); #endif emit_call((int)memdebug); //emit_popa(); restore_regs(0x100f); }*/ } void rmw_assemble(int i,struct regstat *i_regs) { int s,o,t,addr,map=-1,cache=-1; int jaddr=0; int type; int memtarget,c=0,constaddr; int dualindex=(addrmode[i]==GBRIND); unsigned int hr; u32 reglist=0; t=get_reg(i_regs->regmap,-1); s=get_reg(i_regs->regmap,rs1[i]); o=get_reg(i_regs->regmap,rs2[i]); for(hr=0;hrregmap[hr]>=0) reglist|=1<=0) { if(dualindex) c=(i_regs->wasdoingcp>>s)&(i_regs->wasdoingcp>>o)&1; else c=(i_regs->wasdoingcp>>s)&1; if(c) { if(dualindex) constaddr=cpmap[i][s]+cpmap[i][o]; else constaddr=cpmap[i][s]; } //printf("constaddr=%x offset=%x\n",constaddr,offset); memtarget=1; // FIXME } if(dualindex||s<0||c) addr=t; else addr=s; assert(t>=0); reglist&=~(1<regmap,MOREG); cache=get_reg(i_regs->regmap,MMREG); assert(map>=0); reglist&=~(1<regmap,SR); assert(sr>=0); // Liveness analysis? assert(rt1[i]==TBIT); if(sr>=0&&!(i_regs->u&(1LL<regmap,rt1[i]); offset=imm[i]; for(hr=0;hrregmap[hr]>=0) reglist|=1<regmap[HOST_CCREG]==CCREG) reglist&=~(1<=0) { if(!((i_regs->isdoingcp>>t)&1)) { int jaddr=0; // This is to handle the exceptional case where we can not do constant propagation assert(opcode[i]!=12); // MOVA should always be able to do constant propagation constaddr=((start+i*2+4)&~3)+imm[i]; if(opcode[i]==9) constaddr=(start+i*2+4)+imm[i]; // MOV.W assem_debug("Can't do constant propagation, doing PC-relatve load\n"); //int map=get_reg(i_regs->regmap,MOREG); //int cache=get_reg(i_regs->regmap,MMREG); //assert(map>=0); reglist&=~(1<regmap,rs1[i]); int s2=get_reg(i_regs->regmap,rs2[i]); int t=get_reg(i_regs->regmap,MACL); if(t>=0) emit_multiply(s1,s2,t); } if(opcode2[i]==8) // CLRMAC { int t1=get_reg(i_regs->regmap,rt1[i]); int t2=get_reg(i_regs->regmap,rt2[i]); if(!(i_regs->u&(1LL<u&(1LL<regmap,SR); emit_andimm(sr,0xfe,sr); } } if(opcode[i]==2) { if(opcode2[i]==7) // DIV0S { int s1=get_reg(i_regs->regmap,rs1[i]); int s2=get_reg(i_regs->regmap,rs2[i]); int sr=get_reg(i_regs->regmap,SR); int temp=get_reg(i_regs->regmap,-1); assert(s1>=0); assert(s2>=0); assert(sr>=0); emit_div0s(s1,s2,sr,temp); } if(opcode2[i]==14||opcode2[i]==15) // MULU.W / MULS.W { int s1=get_reg(i_regs->regmap,rs1[i]); int s2=get_reg(i_regs->regmap,rs2[i]); int t=get_reg(i_regs->regmap,MACL); #ifdef HOST_TEMPREG int temp=HOST_TEMPREG; #else int temp=get_reg(i_regs->regmap,-1); #endif if(t>=0) { assert(temp>=0); if(opcode2[i]==14) { // MULU.W emit_movzwl_reg(s1,t); emit_movzwl_reg(s2,temp); }else{ // MULS.W emit_movswl_reg(s1,t); emit_movswl_reg(s2,temp); } emit_multiply(t,temp,t); } /* DEBUG emit_pusha(); emit_pushreg(t); emit_pushreg(t); emit_pushreg(s2); emit_pushreg(s1); emit_call((int)debug_multiplication); emit_addimm(ESP,16,ESP); emit_popa();*/ } } if(opcode[i]==3) { int s1=get_reg(i_regs->regmap,rs1[i]); int s2=get_reg(i_regs->regmap,rs2[i]); int th=get_reg(i_regs->regmap,MACH); int tl=get_reg(i_regs->regmap,MACL); if(th>=0) { // DMULU.L / DMULS.L #if defined(__i386__) || defined(__x86_64__) assert(tl==EAX); assert(th==EDX); assert(s1!=EAX); // This would work only if s1 is clean or dead if(s1!=EAX) emit_mov(s1,EAX); if(opcode2[i]==5) emit_mul(s2); // DMULU.L if(opcode2[i]==13) emit_imul(s2); // DMULS.L #else if(opcode2[i]==5) emit_umull(s1,s2,th,tl); // DMULU.L if(opcode2[i]==13) emit_smull(s1,s2,th,tl); // DMULS.L #endif }else if(tl>=0) { // MACH is unneeded, 32-bit result only emit_multiply(s1,s2,tl); } /* DEBUG emit_pusha(); emit_pushreg(tl); emit_pushreg(th); emit_pushreg(s2); emit_pushreg(s1); emit_call((int)debug_multiplication); emit_addimm(ESP,16,ESP); emit_popa();*/ } } #endif void mov_assemble(int i,struct regstat *i_regs) { signed char s,t; t=get_reg(i_regs->regmap,rt1[i]); //assert(t>=0); if(t>=0) { s=get_reg(i_regs->regmap,rs1[i]); if(s>=0) {if(s!=t) emit_mov(s,t);} else emit_loadreg(rs1[i],t); } } void ext_assemble(int i,struct regstat *i_regs) { signed char s,t; t=get_reg(i_regs->regmap,rt1[i]); //assert(t>=0); if(t>=0) { s=get_reg(i_regs->regmap,rs1[i]); if(s>=0) { if(opcode2[i]==12) emit_movzbl_reg(s,t); if(opcode2[i]==13) emit_movzwl_reg(s,t); if(opcode2[i]==14) emit_movsbl_reg(s,t); if(opcode2[i]==15) emit_movswl_reg(s,t); } else { emit_loadreg(rs1[i],t); // Fix - do byte/halfword loads? if(opcode2[i]==12) emit_movzbl_reg(t,t); if(opcode2[i]==13) emit_movzwl_reg(t,t); if(opcode2[i]==14) emit_movsbl_reg(t,t); if(opcode2[i]==15) emit_movswl_reg(t,t); } } } void flags_assemble(int i,struct regstat *i_regs) { signed char sr,t; sr=get_reg(i_regs->regmap,SR); if(opcode2[i]==8) { // CLRT/SETT if(opcode3[i]==0) emit_andimm(sr,~1,sr); if(opcode3[i]==1) emit_orimm(sr,1,sr); }else if(opcode2[i]==9) { // MOVT t=get_reg(i_regs->regmap,rt1[i]); if(t>=0) emit_andimm(sr,1,t); } } void complex_assemble(int i,struct regstat *i_regs) { if(opcode[i]==3&&opcode2[i]==4) { // DIV1 emit_call((pointer)div1); } if(opcode[i]==0&&opcode2[i]==15) { // MAC.L load_regs(i_regs->regmap_entry,i_regs->regmap,MACL,MACH,MACH); // If both registers are the same, the register is incremented twice. // Pre-increment one of the function arguments. #if defined(__i386__) || defined(__x86_64__) if(rs1[i]==rs2[i]) {emit_mov(EDI,EBP);emit_addimm(EDI,4,EDI);} #else #if defined(__arm__) if(rs1[i]==rs2[i]) {emit_mov(6,5);emit_addimm(6,4,6);} #else // FIXME assert(0); #endif #endif /* DEBUG //if(i_regmap[HOST_CCREG]!=CCREG) { emit_loadreg(CCREG,ECX); emit_addimm(ECX,CLOCK_DIVIDER*(ccadj[i]),ECX); output_byte(0x03); output_modrm(1,4,ECX); output_sib(0,4,4); output_byte(4); emit_writeword(ECX,slave?(int)&SSH2->cycles:(int)&MSH2->cycles); // }*/ emit_call((pointer)macl); } if(opcode[i]==4&&opcode2[i]==15) { // MAC.W load_regs(i_regs->regmap_entry,i_regs->regmap,MACL,MACH,MACH); // If both registers are the same, the register is incremented twice. // Pre-increment one of the function arguments. #if defined(__i386__) || defined(__x86_64__) if(rs1[i]==rs2[i]) {emit_mov(EDI,EBP);emit_addimm(EDI,2,EDI);} #else #if defined(__arm__) if(rs1[i]==rs2[i]) {emit_mov(6,5);emit_addimm(6,2,6);} #else // FIXME assert(0); #endif #endif /* DEBUG //if(i_regmap[HOST_CCREG]!=CCREG) { emit_loadreg(CCREG,ECX); emit_addimm(ECX,CLOCK_DIVIDER*(ccadj[i]),ECX); output_byte(0x03); output_modrm(1,4,ECX); output_sib(0,4,4); output_byte(4); emit_writeword(ECX,slave?(int)&SSH2->cycles:(int)&MSH2->cycles); // }*/ emit_call((pointer)macw); } } void ds_assemble(int i,struct regstat *i_regs) { is_delayslot=1; switch(itype[i]) { case ALU: alu_assemble(i,i_regs);break; case IMM8: imm8_assemble(i,i_regs);break; case SHIFTIMM: shiftimm_assemble(i,i_regs);break; case LOAD: load_assemble(i,i_regs);break; case STORE: store_assemble(i,i_regs);break; case RMW: rmw_assemble(i,i_regs);break; case PCREL: pcrel_assemble(i,i_regs);break; case MULTDIV: multdiv_assemble(i,i_regs);break; case MOV: mov_assemble(i,i_regs);break; case EXT: ext_assemble(i,i_regs);break; case FLAGS: flags_assemble(i,i_regs);break; case COMPLEX: complex_assemble(i,i_regs);break; case SYSTEM: case SYSCALL: case UJUMP: case RJUMP: case CJUMP: case SJUMP: printf("Jump in the delay slot. This is probably a bug.\n"); } is_delayslot=0; } // Is the branch target a valid internal jump? int internal_branch(int addr) { if(addr&1) return 0; // Indirect (register) jump if(addr>=start && addr=0) { if((dirty>>hr)&1) { if(!((u>>pre[hr])&1)) { int nr; if((nr=get_reg(entry,pre[hr]))<0) { emit_storereg(pre[hr],hr); }else{ // Register move would overwrite another register, so write back if(pre[nr]>=0) if(get_reg(entry,pre[nr])>=0) emit_storereg(pre[hr],hr); } } } } } } } // Move from one register to another (no writeback) for(hr=0;hr=0&&(pre[hr]&63)=0) { if(pre[nr]<0||get_reg(entry,pre[nr])<0) { emit_mov(hr,nr); } } } } } } // Reload registers that couldn't be directly moved for(hr=0;hr=0&&(pre[hr]&63)=0) { if(pre[nr]>=0) { if(get_reg(entry,pre[nr])>=0) { emit_loadreg(pre[hr],nr); } } } } } } } } #endif // Load the specified registers // This only loads the registers given as arguments because // we don't want to load things that will be overwritten void load_regs(signed char entry[],signed char regmap[],int rs1,int rs2,int rs3) { int hr; if(rs1==TBIT) rs1=SR; if(rs2==TBIT) rs2=SR; if(rs3==TBIT) rs3=SR; // Load 32-bit regs for(hr=0;hr=0) { if(entry[hr]!=regmap[hr]) { if(regmap[hr]==rs1||regmap[hr]==rs2||regmap[hr]==rs3) { emit_loadreg(regmap[hr],hr); } } } } } // Load registers prior to the start of a loop // so that they are not loaded within the loop static void loop_preload(signed char pre[],signed char entry[]) { int hr; for(hr=0;hr=0) { if(get_reg(pre,entry[hr])<0) { assem_debug("loop preload:\n"); //printf("loop preload: %d\n",hr); if(entry[hr]regmap,rt1[i]); if(ra<0||rt1[i]==TBIT) ra=get_reg(i_regs->regmap,-1); assert(ra>=0); } if(itype[i]==STORE||itype[i]==RMW) { ra=get_reg(i_regs->regmap,agr); if(ra<0) ra=get_reg(i_regs->regmap,-1); assert(ra>=0); } if(itype[i]==STORE) { rs=get_reg(i_regs->regmap,rs2[i]); ri=get_reg(i_regs->regmap,rs3[i]); }else{ rs=get_reg(i_regs->regmap,rs1[i]); ri=get_reg(i_regs->regmap,rs2[i]); } rm=get_reg(i_regs->regmap,MOREG); if(rm<0) rm=get_alt_reg(i_regs->regmap,-1); if(ra>=0) { int offset=imm[i]; int c; u32 constaddr; if(addrmode[i]==DUALIND||addrmode[i]==GBRIND) { c=(i_regs->wasdoingcp>>rs)&(i_regs->wasdoingcp>>ri)&1; constaddr=cpmap[i][rs]+cpmap[i][ri]; }else{ c=(i_regs->wasdoingcp>>rs)&1; constaddr=cpmap[i][rs]+offset; if(addrmode[i]==POSTINC) constaddr-=1<<((opcode[i]==4)?2:(opcode2[i]&3)); } if(addrmode[i]==PREDEC&&!c) { if(rt1[i]!=rs1[i]) emit_addimm(rs,-(1<<((opcode[i]==4)?2:(opcode2[i]&3))),rs); else offset=-(1<<((opcode[i]==4)?2:(opcode2[i]&3))); } if(rs<0) { if(itype[i]==LOAD) { if(!entry||entry[ra]!=rs1[i]) emit_loadreg(rs1[i],ra); } if(itype[i]==STORE) { if(!entry||entry[ra]!=rs2[i]) emit_loadreg(rs2[i],ra); } //if(!entry||entry[ra]!=rs1[i]) // printf("poor load scheduling!\n"); } else if(c) { // Stores to memory go thru the mapper to detect self-modifying // code, loads don't. if(rm>=0) { if(!entry||entry[rm]!=mgr) { if(itype[i]==STORE) { if(can_direct_write(constaddr)) generate_map_const(constaddr,rm); } if(itype[i]==RMW) { generate_map_const(constaddr,rm); } } } if((opcode2[i]&3)==0||itype[i]==RMW) constaddr^=1; // byteswap for little-endian if(rs1[i]!=rt1[i]||itype[i]!=LOAD||addrmode[i]==DUALIND||addrmode[i]==GBRIND) { if(!entry||entry[ra]!=agr) { #ifdef HOST_IMM_ADDR32 if(itype[i]==RMW || (itype[i]==STORE && can_direct_write(constaddr))) #endif { if(itype[i]==LOAD&&can_direct_read(constaddr)) emit_movimm(map_address(constaddr),ra); else emit_movimm(constaddr,ra); } } // else did it in the previous cycle } // else load_consts already did it } if(!c) { if(rs>=0) { if(addrmode[i]==DUALIND||addrmode[i]==GBRIND) emit_add(rs,ri,ra); else if(offset) emit_addimm(rs,offset,ra); }else{ if(addrmode[i]==DUALIND||addrmode[i]==GBRIND) emit_add(ra,ri,ra); else if(offset) emit_addimm(ra,offset,ra); } } } } // Preload constants for next instruction if(itype[i+1]==LOAD||itype[i+1]==STORE||itype[i+1]==RMW) { int agr,ra,rm; #ifndef HOST_IMM_ADDR32 // Mapper entry agr=MGEN1+((i+1)&1); rm=get_reg(i_regs->regmap,agr); if(rm>=0) { int rs,ri; if(itype[i+1]==STORE) { rs=get_reg(regs[i+1].regmap,rs2[i+1]); ri=get_reg(regs[i+1].regmap,rs3[i+1]); }else{ rs=get_reg(regs[i+1].regmap,rs1[i+1]); ri=get_reg(regs[i+1].regmap,rs2[i+1]); } //int rm=get_reg(i_regs->regmap,MOREG); int offset=imm[i+1]; int c; u32 constaddr; if(addrmode[i+1]==DUALIND||addrmode[i+1]==GBRIND) { c=(regs[i+1].wasdoingcp>>rs)&(regs[i+1].wasdoingcp>>ri)&1; constaddr=cpmap[i+1][rs]+cpmap[i+1][ri]; }else{ c=(regs[i+1].wasdoingcp>>rs)&1; constaddr=cpmap[i+1][rs]+offset; if(addrmode[i+1]==POSTINC) constaddr-=1<<((opcode[i+1]==4)?2:(opcode2[i+1]&3)); } if((opcode2[i+1]&3)==0||itype[i+1]==RMW) constaddr^=1; // byteswap for little-endian if(c) { // Stores to memory go thru the mapper to detect self-modifying // code, loads don't. if(itype[i+1]==STORE) { if(can_direct_write(constaddr)) generate_map_const(constaddr,rm); } if(itype[i+1]==RMW) { generate_map_const(constaddr,rm); } } } #endif // Actual address agr=AGEN1+((i+1)&1); ra=get_reg(i_regs->regmap,agr); if(ra>=0) { int c; int offset; int rs,ri; u32 constaddr; if(itype[i+1]==STORE) { rs=get_reg(regs[i+1].regmap,rs2[i+1]); ri=get_reg(regs[i+1].regmap,rs3[i+1]); }else{ rs=get_reg(regs[i+1].regmap,rs1[i+1]); ri=get_reg(regs[i+1].regmap,rs2[i+1]); } offset=imm[i+1]; if(addrmode[i+1]==DUALIND||addrmode[i+1]==GBRIND) { c=(regs[i+1].wasdoingcp>>rs)&(regs[i+1].wasdoingcp>>ri)&1; constaddr=cpmap[i+1][rs]+cpmap[i+1][ri]; }else{ c=(regs[i+1].wasdoingcp>>rs)&1; constaddr=cpmap[i+1][rs]+offset; if(addrmode[i+1]==POSTINC) constaddr-=1<<((opcode[i+1]==4)?2:(opcode2[i+1]&3)); } if((opcode2[i+1]&3)==0||itype[i+1]==RMW) constaddr^=1; // byteswap for little-endian if(c&&(rs1[i+1]!=rt1[i+1]||itype[i+1]!=LOAD||addrmode[i+1]==DUALIND||addrmode[i+1]==GBRIND)) { //if(c&&(rs1[i+1]!=rt1[i+1]||itype[i+1]!=LOAD)) { #ifdef HOST_IMM_ADDR32 if(itype[i+1]==RMW || (itype[i+1]==STORE && can_direct_write(constaddr))) #endif { if(itype[i+1]==LOAD&&can_direct_read(constaddr)) emit_movimm(map_address(constaddr),ra); else emit_movimm(constaddr,ra); } } } } } int get_final_value(int hr, int i, int *value) { int reg=regs[i].regmap[hr]; while(i>hr)&1)) break; if(bt[i+1]) break; i++; } if(i>hr)&1)) { if(addrmode[i+2]==DUALIND||addrmode[i+2]==GBRIND) { *value=cpmap[i][hr]; return 1; } // Don't load address if can_direct_read and HOST_IMM_ADDR32 #ifdef HOST_IMM_ADDR32 if(can_direct_read(cpmap[i][hr]+imm[i+2])) return 0; #endif // Precompute load address *value=cpmap[i][hr]+imm[i+2]; if(can_direct_read(*value)) *value=map_address(*value); if((opcode2[i+2]&3)==0) *value^=1; // byteswap for little-endian return 1; } } if(itype[i+1]==LOAD&&rs1[i+1]==reg&&rt1[i+1]==reg) { if(addrmode[i+1]==DUALIND||addrmode[i+1]==GBRIND) { *value=cpmap[i][hr]; return 1; } // Don't load address if can_direct_read and HOST_IMM_ADDR32 #ifdef HOST_IMM_ADDR32 if(can_direct_read(cpmap[i][hr]+imm[i+1])) return 0; #endif // Precompute load address *value=cpmap[i][hr]+imm[i+1]; if(can_direct_read(*value)) *value=map_address(*value); if((opcode2[i+1]&3)==0) *value^=1; // byteswap for little-endian //printf("c=%x imm=%x\n",(int)cpmap[i][hr],imm[i+1]); return 1; } } } *value=cpmap[i][hr]; //printf("c=%x\n",(int)cpmap[i][hr]); if(i==slen-1) return 1; return !((unneeded_reg[i+1]>>reg)&1); } // Load registers with known constants void load_consts(signed char pre[],signed char regmap[],int i) { int hr; // Load 32-bit regs for(hr=0;hr=0) { if(i==0||!((regs[i-1].isdoingcp>>hr)&1)||pre[hr]!=regmap[hr]||bt[i]) { if(((regs[i].isdoingcp>>hr)&1)&®map[hr]<64&®map[hr]>=0) { int value; if(get_final_value(hr,i,&value)) { emit_movimm(value,hr); } } } } } } void load_all_consts(signed char regmap[],u32 dirty,int i) { int hr; // Load 32-bit regs for(hr=0;hr=0&&((dirty>>hr)&1)) { if(((regs[i].isdoingcp>>hr)&1)&®map[hr]<64&®map[hr]>=0) { int value=cpmap[i][hr]; emit_movimm(value,hr); } } } } // Write out all dirty registers (except cycle count) void wb_dirtys(signed char i_regmap[],u32 i_dirty) { int hr; for(hr=0;hr=0) { if(i_regmap[hr]!=CCREG) { if((i_dirty>>hr)&1) { emit_storereg(i_regmap[hr],hr); } } } } } } // Write out dirty registers that we need to reload (pair with load_needed_regs) // This writes the registers not written by store_regs_bt void wb_needed_dirtys(signed char i_regmap[],u32 i_dirty,int addr) { int hr; int t=(addr-start)>>1; for(hr=0;hr=0) { if(i_regmap[hr]!=CCREG) { if((i_regmap[hr]==regs[t].regmap_entry[hr] && ((regs[t].dirty>>hr)&1)) || i_regmap[hr]==SR || i_regmap[hr]==15) { if((i_dirty>>hr)&1) { emit_storereg(i_regmap[hr],hr); } } } } } } } // Load all registers (except cycle count) void load_all_regs(signed char i_regmap[]) { int hr; for(hr=0;hr=0 && i_regmap[hr]=0) { if(i_regmap[hr]>=0 && i_regmap[hr]=0&®s[t].regmap_entry[hr]>1; int hr; for(hr=0;hr=0 && i_regmap[hr]!=CCREG) { if(i_regmap[hr]!=regs[t].regmap_entry[hr] || !((regs[t].dirty>>hr)&1) ) { if((i_dirty>>hr)&1) { if(!((unneeded_reg[t]>>i_regmap[hr])&1)) { emit_storereg(i_regmap[hr],hr); } } } } } } } else { // Branch out of this block, write out all dirty regs wb_dirtys(i_regmap,i_dirty); } } // Load all needed registers for branch target void load_regs_bt(signed char i_regmap[],u32 i_dirty,int addr) { //if(addr>=start && addr<(start+slen*4)) if(internal_branch(addr)) { int t=(addr-start)>>1; int hr; // Store the cycle count before loading something else if(i_regmap[HOST_CCREG]!=CCREG) { assert(i_regmap[HOST_CCREG]==-1); } if(regs[t].regmap_entry[HOST_CCREG]!=CCREG) { emit_storereg(CCREG,HOST_CCREG); } // Load 32-bit regs for(hr=0;hr=0&®s[t].regmap_entry[hr]=start && addr>1; int hr; if(regs[t].regmap_entry[HOST_CCREG]!=CCREG) return 0; for(hr=0;hr=0&®s[t].regmap_entry[hr]>hr)&1) { if(!((unneeded_reg[t]>>i_regmap[hr])&1)) return 0; } } else // Same register but is it dirty? if(i_regmap[hr]>=0) { if(!((regs[t].dirty>>hr)&1)) { if((i_dirty>>hr)&1) { if(!((unneeded_reg[t]>>i_regmap[hr])&1)) { //printf("%x: dirty no match\n",addr); return 0; } } } } } } // Delay slots require additional processing, so do not match if(is_ds[t]) return 0; } else { int hr; for(hr=0;hr=0) { if(hr!=HOST_CCREG||i_regmap[hr]!=CCREG) { if((i_dirty>>hr)&1) { return 0; } } } } } } return 1; } // Used when a branch jumps into the delay slot of another branch void ds_assemble_entry(int i) { int t=(ba[i]-start)>>1; if(!instr_addr[t]) instr_addr[t]=(pointer)out; assem_debug("Assemble delay slot at %x\n",ba[i]); assem_debug("<->\n"); if(regs[t].regmap_entry[HOST_CCREG]==CCREG&®s[t].regmap[HOST_CCREG]!=CCREG) wb_register(CCREG,regs[t].regmap_entry,regs[t].wasdirty); load_regs(regs[t].regmap_entry,regs[t].regmap,rs1[t],rs2[t],rs3[t]); address_generation(t,®s[t],regs[t].regmap_entry); if(itype[t]==LOAD||itype[t]==STORE) load_regs(regs[t].regmap_entry,regs[t].regmap,MMREG,MMREG,MMREG); is_delayslot=0; switch(itype[t]) { case ALU: alu_assemble(t,®s[t]);break; case IMM8: imm8_assemble(t,®s[t]);break; case SHIFTIMM: shiftimm_assemble(t,®s[t]);break; case LOAD: load_assemble(t,®s[t]);break; case STORE: store_assemble(t,®s[t]);break; case RMW: rmw_assemble(t,®s[t]);break; case PCREL: pcrel_assemble(t,®s[t]);break; case MULTDIV: multdiv_assemble(t,®s[t]);break; case MOV: mov_assemble(t,®s[t]);break; case EXT: ext_assemble(i,®s[t]);break; case FLAGS: flags_assemble(i,®s[t]);break; case COMPLEX: complex_assemble(i,®s[t]);break; case SYSTEM: case SYSCALL: case UJUMP: case RJUMP: case CJUMP: case SJUMP: printf("Jump in the delay slot. This is probably a bug.\n"); } store_regs_bt(regs[t].regmap,regs[t].dirty,ba[i]+2); load_regs_bt(regs[t].regmap,regs[t].dirty,ba[i]+2); if(internal_branch(ba[i]+2)) assem_debug("branch: internal\n"); else assem_debug("branch: external\n"); assert(internal_branch(ba[i]+2)); add_to_linker((int)out,ba[i]+2,internal_branch(ba[i]+2)); emit_jmp(0); } void do_cc(int i,signed char i_regmap[],int *adj,int addr,int taken,int invert) { int count; int jaddr; int idle=0; if(itype[i]==RJUMP) { *adj=0; } //if(ba[i]>=start && ba[i]<(start+slen*4)) if(internal_branch(ba[i])) { int t=(ba[i]-start)>>1; if(is_ds[t]) *adj=ccadj[t+1]-cycles[t]; // Branch into delay slot adds an extra cycle else *adj=ccadj[t]; } else { *adj=0; } if(itype[i]==CJUMP) *adj-=2+cycles[i]; // Two extra cycles for taken BT/BF if(itype[i]==SJUMP) *adj-=1+cycles[i]+cycles[i+1]; // One extra cycle for taken BT/BF with delay slot count=ccadj[i]+((taken==NODS)?0:cycles[i]+cycles[i+1]); if(taken==TAKEN && i==(ba[i]-start)>>1 && source[i+1]==0) { // Idle loop // FIXME //if(count&1) emit_addimm_and_set_flags(2*(count+2),HOST_CCREG); idle=(int)out; //emit_subfrommem(&idlecount,HOST_CCREG); // Count idle cycles emit_andimm(HOST_CCREG,3,HOST_CCREG); jaddr=(int)out; emit_jmp(0); } else if(*adj==0||invert) { emit_addimm_and_set_flags(CLOCK_DIVIDER*count,HOST_CCREG); jaddr=(int)out; emit_jns(0); } else { emit_cmpimm(HOST_CCREG,-CLOCK_DIVIDER*count); jaddr=(int)out; emit_jns(0); } add_stub(CC_STUB,jaddr,idle?idle:(int)out,(*adj==0||invert||idle)?0:count,i,addr,taken,0); } void do_ccstub(int n) { int i; literal_pool(256); assem_debug("do_ccstub %x\n",start+stubs[n][4]*2); set_jump_target(stubs[n][1],(pointer)out); i=stubs[n][4]; if(stubs[n][6]==NODS) { if(itype[i+1]==LOAD&&rs1[i+1]==rt1[i+1]&&addrmode[i+1]!=DUALIND&&addrmode[i+1]!=GBRIND) { int hr=get_reg(regs[i].regmap,rs1[i+1]); if(hr>=0&&((regs[i].wasdoingcp>>hr)&1)) { emit_movimm(cpmap[i][hr],hr); } } wb_dirtys(regs[i].regmap_entry,regs[i].dirty); } else if(stubs[n][6]!=TAKEN) { wb_dirtys(branch_regs[i].regmap,branch_regs[i].dirty); } else { if(internal_branch(ba[i])) wb_needed_dirtys(branch_regs[i].regmap,branch_regs[i].dirty,ba[i]); } if(stubs[n][5]!=-1) { // Save PC as return address emit_movimm(stubs[n][5],0); emit_writeword(0,slave?(int)&slave_pc:(int)&master_pc); } else { // Return address is branch target if(itype[i]==RJUMP) { int r=get_reg(branch_regs[i].regmap,rs1[i]); if(rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1]) { r=get_reg(branch_regs[i].regmap,RTEMP); } else if(opcode[i]==0&&opcode2[i]==3) { // BSRF/BRAF r=get_reg(branch_regs[i].regmap,RTEMP); } else if(opcode[i]==0&&opcode2[i]==11&&opcode3[i]==2) { // RTE r=get_reg(branch_regs[i].regmap,RTEMP); } emit_writeword(r,slave?(int)&slave_pc:(int)&master_pc); } else {printf("Unknown branch type in do_ccstub\n");exit(1);} } // Update cycle count if(stubs[n][6]==NODS) assert(regs[i].regmap[HOST_CCREG]==CCREG||regs[i].regmap[HOST_CCREG]==-1); else assert(branch_regs[i].regmap[HOST_CCREG]==CCREG||branch_regs[i].regmap[HOST_CCREG]==-1); if(stubs[n][3]) emit_addimm(HOST_CCREG,CLOCK_DIVIDER*stubs[n][3],HOST_CCREG); if(slave) { emit_load_return_address(SLAVERA_REG); emit_jmp((pointer)cc_interrupt); } else { emit_call((pointer)slave_entry); } if(stubs[n][3]&&stubs[n][6]!=NODS) emit_addimm(HOST_CCREG,-CLOCK_DIVIDER*stubs[n][3],HOST_CCREG); if(stubs[n][6]==TAKEN) { if(internal_branch(ba[i])) load_needed_regs(branch_regs[i].regmap,regs[(ba[i]-start)>>1].regmap_entry); else if(itype[i]==RJUMP) { if(get_reg(branch_regs[i].regmap,RTEMP)>=0) emit_readword(slave?(int)&slave_pc:(int)&master_pc,get_reg(branch_regs[i].regmap,RTEMP)); else emit_loadreg(rs1[i],get_reg(branch_regs[i].regmap,rs1[i])); } }else if(stubs[n][6]==NOTTAKEN) { if(i=0&&((regs[i].wasdoingcp>>hr)&1)) { #ifdef HOST_IMM_ADDR32 if(!can_direct_read(cpmap[i][hr]+imm[i+1])) #endif { int value=cpmap[i][hr]+imm[i+1]; if(can_direct_read(value)) value=map_address(value); if((opcode2[i+1]&3)==0) value^=1; // byteswap for little-endian emit_movimm(value,hr); } } } ccstub_return[i]=0; } } else load_all_regs(branch_regs[i].regmap); } emit_jmp(stubs[n][2]); // return address } void add_to_linker(int addr,int target,int ext) { link_addr[linkcount][0]=addr; link_addr[linkcount][1]=target|slave; link_addr[linkcount][2]=ext; linkcount++; } void ujump_assemble(int i,struct regstat *i_regs) { u64 bc_unneeded; int cc,adj; signed char *i_regmap=i_regs->regmap; if(i==(ba[i]-start)>>1) assem_debug("idle loop\n"); address_generation(i+1,i_regs,regs[i].regmap_entry); #ifdef REG_PREFETCH int temp=get_reg(branch_regs[i].regmap,PTEMP); if(rt1[i]==PR&&temp>=0) { int return_address=start+i*2+4; if(get_reg(branch_regs[i].regmap,PR)>0) if(i_regmap[temp]==PTEMP) emit_movimm((int)hash_table[((return_address>>16)^return_address)&0xFFFF],temp); } #endif if(rt1[i]==PR) { if(rt1[i+1]==PR||rt2[i+1]==PR) { // Delay slot abuse, set PR before executing delay slot int rt; unsigned int return_address; rt=get_reg(regs[i].regmap,PR); return_address=start+i*2+4; assert(rt>=0); if(rt>=0) { #ifdef REG_PREFETCH if(temp>=0) { if(i_regmap[temp]!=PTEMP) emit_movimm((int)hash_table[((return_address>>16)^return_address)&0xFFFF],temp); } #endif emit_movimm(return_address,rt); // PC into link register } } } ds_assemble(i+1,i_regs); bc_unneeded=regs[i].u; bc_unneeded|=1LL<=0); return_address=start+i*2+4; if(rt>=0&&rt1[i+1]!=PR&&rt2[i+1]!=PR) { #ifdef USE_MINI_HT if(internal_branch(return_address)) { int temp=rt+1; if(temp==EXCLUDE_REG||temp>=HOST_REGS|| branch_regs[i].regmap[temp]>=0) { temp=get_reg(branch_regs[i].regmap,-1); } #ifdef HOST_TEMPREG if(temp<0) temp=HOST_TEMPREG; #endif if(temp>=0) do_miniht_insert(return_address,rt,temp); else emit_movimm(return_address,rt); } else #endif { #ifdef REG_PREFETCH if(temp>=0) { if(i_regmap[temp]!=PTEMP) emit_movimm((int)hash_table[((return_address>>16)^return_address)&0xFFFF],temp); } #endif emit_movimm(return_address,rt); // PC into link register #ifdef IMM_PREFETCH emit_prefetch(hash_table[((return_address>>16)^return_address)&0xFFFF]); #endif } } } cc=get_reg(branch_regs[i].regmap,CCREG); assert(cc==HOST_CCREG); store_regs_bt(branch_regs[i].regmap,branch_regs[i].dirty,ba[i]); #ifdef REG_PREFETCH if(rt1[i]==PR&&temp>=0) emit_prefetchreg(temp); #endif do_cc(i,branch_regs[i].regmap,&adj,ba[i],TAKEN,0); if(adj) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+cycles[i]+cycles[i+1]-adj),cc); load_regs_bt(branch_regs[i].regmap,branch_regs[i].dirty,ba[i]); if(internal_branch(ba[i])) assem_debug("branch: internal\n"); else assem_debug("branch: external\n"); if(internal_branch(ba[i])&&is_ds[(ba[i]-start)>>1]) { ds_assemble_entry(i); } else { add_to_linker((int)out,ba[i],internal_branch(ba[i])); emit_jmp(0); } } void rjump_assemble(int i,struct regstat *i_regs) { signed char *i_regmap=i_regs->regmap; int temp; int rs,cc,adj,rh,ht; u64 bc_unneeded; rs=get_reg(branch_regs[i].regmap,rs1[i]); assert(rs>=0); if(!((i_regs->wasdoingcp>>rs)&1)) { if(opcode[i]==0&&opcode2[i]==3) { // PC-relative branch, put PC in a temporary register temp=get_reg(branch_regs[i].regmap,RTEMP); assert(temp>=0); if(regs[i].regmap[temp]==RTEMP) emit_movimm(start+i*2+4,temp); } if(rs1[i]==rt1[i+1]||rs1[i]==rt2[i+1]) { // Delay slot abuse, make a copy of the branch address register temp=get_reg(branch_regs[i].regmap,RTEMP); assert(temp>=0); assert(regs[i].regmap[temp]==RTEMP); if(opcode[i]==0&&opcode2[i]==3) emit_add(rs,temp,temp); else emit_mov(rs,temp); rs=temp; } } address_generation(i+1,i_regs,regs[i].regmap_entry); #ifdef REG_PREFETCH if(rt1[i]==PR) { if((temp=get_reg(branch_regs[i].regmap,PTEMP))>=0) { int return_address=start+i*2+4; if(i_regmap[temp]==PTEMP) emit_movimm((int)hash_table[((return_address>>16)^return_address)&0xFFFF],temp); } } #endif #ifdef USE_MINI_HT if(rs1[i]==PR) { int rh=get_reg(regs[i].regmap,RHASH); if(rh>=0) do_preload_rhash(rh); } #endif if(rt1[i]==PR) { if(rt1[i+1]==PR||rt2[i+1]==PR) { // Delay slot abuse, set PR before executing delay slot int rt,return_address; rt=get_reg(regs[i].regmap,rt1[i]); assert(rt>=0); if(rt>=0) { return_address=start+i*2+4; #ifdef REG_PREFETCH if(temp>=0) { if(i_regmap[temp]!=PTEMP) emit_movimm((int)hash_table[((return_address>>16)^return_address)&0xFFFF],temp); } #endif emit_movimm(return_address,rt); // PC into link register } } } ds_assemble(i+1,i_regs); bc_unneeded=regs[i].u; bc_unneeded|=1LL<=0&&rt1[i+1]!=PR&&rt2[i+1]!=PR) { return_address=start+i*2+4; #ifdef REG_PREFETCH if(temp>=0) { if(i_regmap[temp]!=PTEMP) emit_movimm((int)hash_table[((return_address>>16)^return_address)&0xFFFF],temp); } #endif emit_movimm(return_address,rt); // PC into link register #ifdef IMM_PREFETCH emit_prefetch(hash_table[((return_address>>16)^return_address)&0xFFFF]); #endif } } cc=get_reg(branch_regs[i].regmap,CCREG); assert(cc==HOST_CCREG); #ifdef USE_MINI_HT rh=get_reg(branch_regs[i].regmap,RHASH); ht=get_reg(branch_regs[i].regmap,RHTBL); if(rs1[i]==PR) { if(regs[i].regmap[rh]!=RHASH) do_preload_rhash(rh); do_preload_rhtbl(ht); do_rhash(rs,rh); } #endif if(opcode[i]==0&&opcode2[i]==11&&opcode3[i]==2) { // Return From Exception (RTE) - pop PC and SR from stack //printf("RTE\n"); int map=get_reg(branch_regs[i].regmap,MOREG); int cache=get_reg(branch_regs[i].regmap,MMREG); int sp=get_reg(branch_regs[i].regmap,15); int sr=get_reg(branch_regs[i].regmap,SR); int jaddr=0; unsigned int hr; u32 reglist=0; temp=get_reg(branch_regs[i].regmap,RTEMP); for(hr=0;hrregmap[hr]>=0) reglist|=1<=0); assert(sr>=0); assert(temp>=0); assert(map>=0); reglist&=~(1<wasdoingcp>>rs)&1)&®s[i].regmap[rs]==branch_regs[i].regmap[rs]) ||((i_regs->isconst>>rs1[i])&1)) { // Do constant propagation, branch to fixed address u32 constaddr; if(((i_regs->wasdoingcp>>rs)&1)&®s[i].regmap[rs]==branch_regs[i].regmap[rs]) constaddr=cpmap[i][rs]; else constaddr=i_regs->constmap[rs1[i]]; if(opcode[i]==0&&opcode2[i]==3) { // PC-relative branch, add PC+4 constaddr+=start+i*2+4; } assert(ba[i]==constaddr); store_regs_bt(branch_regs[i].regmap,branch_regs[i].dirty,ba[i]); //emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+cycles[i]+cycles[i+1]),HOST_CCREG); //add_stub(CC_STUB,(int)out,jump_vaddr_reg[rs],0,i,-1,TAKEN,0); //emit_jns(0); do_cc(i,branch_regs[i].regmap,&adj,constaddr,TAKEN,0); if(adj) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+cycles[i]+cycles[i+1]-adj),cc); load_regs_bt(branch_regs[i].regmap,branch_regs[i].dirty,ba[i]); if(internal_branch(constaddr)) assert(bt[(constaddr-start)>>1]); if(internal_branch(constaddr)&&bt[(constaddr-start)>>1]) { assem_debug("branch: internal (constant address)\n"); if(is_ds[(constaddr-start)>>1]) { ds_assemble_entry(i); } else { add_to_linker((int)out,constaddr,1/*internal_branch*/); emit_jmp(0); } } else { assem_debug("branch: external (constant address)\n"); add_to_linker((int)out,constaddr,0/*internal_branch*/); emit_jmp(0); } } else { ba[i]=-1; store_regs_bt(branch_regs[i].regmap,branch_regs[i].dirty,-1); #ifdef REG_PREFETCH if(rt1[i]==PR&&temp>=0) emit_prefetchreg(temp); #endif #ifdef USE_MINI_HT if(rs1[i]==PR) { do_miniht_load(ht,rh); } #endif //#ifdef HOST_IMM_ADDR32 alternative using lea? if(rs1[i]!=rt1[i+1]&&rs1[i]!=rt2[i+1]) { if(opcode[i]==0&&opcode2[i]==3) { // PC-relative branch, add offset to PC temp=get_reg(branch_regs[i].regmap,RTEMP); if(regs[i].regmap[temp]!=RTEMP) { // Load PC if necessary emit_movimm(start+i*2+4,temp); } emit_add(rs,temp,temp); rs=temp; } } //do_cc(i,branch_regs[i].regmap,&adj,-1,TAKEN); //if(adj) emit_addimm(cc,2*(ccadj[i]+2-adj),cc); // ??? - Shouldn't happen //assert(adj==0); emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+cycles[i]+cycles[i+1]),HOST_CCREG); add_stub(CC_STUB,(int)out,jump_vaddr_reg[slave][rs],0,i,-1,TAKEN,0); emit_jns(0); //load_regs_bt(branch_regs[i].regmap,branch_regs[i].dirty,-1); #ifdef USE_MINI_HT if(rs1[i]==PR) { do_miniht_jump(rs,rh,ht); } else #endif { emit_jmp(jump_vaddr_reg[slave][rs]); } } } #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK if(rt1[i]!=PR&&iregmap; int cc; int match; int sr; int unconditional=0,nop=0; int adj; int invert=0; int internal; match=match_bt(regs[i].regmap,regs[i].dirty,ba[i]); assem_debug("match=%d\n",match); internal=internal_branch(ba[i]); if(i==(ba[i]-start)>>1) assem_debug("idle loop\n"); if(!match) invert=1; #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK if(i>(ba[i]-start)>>1) invert=1; #endif sr=get_reg(i_regmap,SR); assert(sr>=0); cc=get_reg(i_regmap,CCREG); assert(cc==HOST_CCREG); do_cc(i,regs[i].regmap,&adj,start+i*2,NODS,invert); if(unconditional) store_regs_bt(branch_regs[i].regmap,branch_regs[i].dirty,ba[i]); if(unconditional) { do_cc(i,branch_regs[i].regmap,&adj,ba[i],TAKEN,0); if(i!=(ba[i]-start)>>1 || source[i+1]!=0) { if(adj) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); load_regs_bt(branch_regs[i].regmap,branch_regs[i].dirty,ba[i]); if(internal) assem_debug("branch: internal\n"); else assem_debug("branch: external\n"); if(internal&&is_ds[(ba[i]-start)>>1]) { ds_assemble_entry(i); } else { add_to_linker((int)out,ba[i],internal); emit_jmp(0); } #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK if(((u32)out)&7) emit_addnop(0); #endif } } else if(nop) { int jaddr; emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),cc); jaddr=(int)out; emit_jns(0); add_stub(CC_STUB,jaddr,(int)out,0,i,start+i*2+4,NOTTAKEN,0); } else { pointer taken=0,nottaken=0,nottaken1=0; //do_cc(i,regs[i].regmap,&adj,-1,0,invert); if(adj&&!invert) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]-adj),cc); //printf("branch(%d): eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d\n",i,branch_regs[i].regmap[0],branch_regs[i].regmap[1],branch_regs[i].regmap[2],branch_regs[i].regmap[3],branch_regs[i].regmap[5],branch_regs[i].regmap[6],branch_regs[i].regmap[7]); emit_testimm(sr,1); if(opcode2[i]==9) // BT { if(invert){ nottaken=(pointer)out; emit_jeq(1); }else{ add_to_linker((int)out,ba[i],internal); emit_jne(0); } } if(opcode2[i]==11) // BF { if(invert){ nottaken=(pointer)out; emit_jne(1); }else{ add_to_linker((int)out,ba[i],internal); emit_jeq(0); } } if(invert) { if(taken) set_jump_target(taken,(pointer)out); #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK if(match&&(!internal||!is_ds[(ba[i]-start)>>1])) { if(adj) { emit_addimm(cc,-CLOCK_DIVIDER*adj,cc); add_to_linker((int)out,ba[i],internal); }else{ emit_addnop(13); add_to_linker((int)out,ba[i],internal*2); } emit_jmp(0); }else #endif { if(adj) emit_addimm(cc,-CLOCK_DIVIDER*adj,cc); store_regs_bt(regs[i].regmap,regs[i].dirty,ba[i]); load_regs_bt(regs[i].regmap,regs[i].dirty,ba[i]); if(internal) assem_debug("branch: internal\n"); else assem_debug("branch: external\n"); if(internal&&is_ds[(ba[i]-start)>>1]) { ds_assemble_entry(i); } else { add_to_linker((int)out,ba[i],internal); emit_jmp(0); } } set_jump_target(nottaken,(pointer)out); } //if(nottaken1) set_jump_target(nottaken1,(int)out); if(adj&&!invert) emit_addimm(cc,CLOCK_DIVIDER*adj,cc); } // (!unconditional) } void sjump_assemble(int i,struct regstat *i_regs) { signed char *i_regmap=i_regs->regmap; int cc; int adj; int match; int sr; int unconditional=0,nop=0; int invert=0; int internal=internal_branch(ba[i]); match=match_bt(branch_regs[i].regmap,branch_regs[i].dirty,ba[i]); assem_debug("match=%d\n",match); internal=internal_branch(ba[i]); if(i==(ba[i]-start)>>1) assem_debug("idle loop\n"); if(!match) invert=1; #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK if(i>(ba[i]-start)>>1) invert=1; #endif if(ooo[i]) { sr=get_reg(branch_regs[i].regmap,SR); } else { sr=get_reg(i_regmap,SR); } cc=get_reg(i_regmap,CCREG); assert(cc==HOST_CCREG); if(ooo[i]) { u64 bc_unneeded; // Out of order execution (delay slot first) //printf("OOOE\n"); do_cc(i,regs[i].regmap,&adj,start+i*2,NODS,invert); address_generation(i+1,i_regs,regs[i].regmap_entry); ds_assemble(i+1,i_regs); bc_unneeded=regs[i].u; bc_unneeded&=~((1LL<>1 || source[i+1]!=0) { if(adj) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]+2-adj),cc); load_regs_bt(branch_regs[i].regmap,branch_regs[i].dirty,ba[i]); if(internal) assem_debug("branch: internal\n"); else assem_debug("branch: external\n"); if(internal&&is_ds[(ba[i]-start)>>1]) { ds_assemble_entry(i); } else { add_to_linker((int)out,ba[i],internal); emit_jmp(0); } #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK if(((u32)out)&7) emit_addnop(0); #endif } } else if(nop) { int jaddr; emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+2),cc); jaddr=(int)out; emit_jns(0); add_stub(CC_STUB,jaddr,(int)out,0,i,start+i*2+4,NOTTAKEN,0); } else { pointer taken=0,nottaken=0,nottaken1=0; //do_cc(i,branch_regs[i].regmap,&adj,-1,0,invert); if(adj&&!invert) emit_addimm(cc,CLOCK_DIVIDER*(ccadj[i]-adj),cc); //printf("branch(%d): eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d\n",i,branch_regs[i].regmap[0],branch_regs[i].regmap[1],branch_regs[i].regmap[2],branch_regs[i].regmap[3],branch_regs[i].regmap[5],branch_regs[i].regmap[6],branch_regs[i].regmap[7]); assert(sr>=0); emit_testimm(sr,1); if(opcode2[i]==13) // BT/S { if(invert){ nottaken=(pointer)out; emit_jeq(1); }else{ add_to_linker((int)out,ba[i],internal); emit_jne(0); } } if(opcode2[i]==15) // BF/S { if(invert){ nottaken=(pointer)out; emit_jne(1); }else{ add_to_linker((int)out,ba[i],internal); emit_jeq(0); } } if(invert) { if(taken) set_jump_target(taken,(pointer)out); #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK if(match&&(!internal||!is_ds[(ba[i]-start)>>1])) { if(adj) { emit_addimm(cc,-CLOCK_DIVIDER*adj,cc); add_to_linker((int)out,ba[i],internal); }else{ emit_addnop(13); add_to_linker((int)out,ba[i],internal*2); } emit_jmp(0); }else #endif { if(adj) emit_addimm(cc,-CLOCK_DIVIDER*adj,cc); store_regs_bt(branch_regs[i].regmap,branch_regs[i].dirty,ba[i]); load_regs_bt(branch_regs[i].regmap,branch_regs[i].dirty,ba[i]); if(internal) assem_debug("branch: internal\n"); else assem_debug("branch: external\n"); if(internal&&is_ds[(ba[i]-start)>>1]) { ds_assemble_entry(i); } else { add_to_linker((int)out,ba[i],internal); emit_jmp(0); } } set_jump_target(nottaken,(pointer)out); } if(nottaken1) set_jump_target(nottaken1,(pointer)out); if(adj&&!invert) emit_addimm(cc,CLOCK_DIVIDER*adj,cc); } // (!unconditional) } // if(ooo) else { // In-order execution (branch first) //printf("IOE\n"); u64 ds_unneeded; pointer taken=0,nottaken=0,nottaken1=0; do_cc(i,regs[i].regmap,&adj,start+i*2,NODS,1); if(!unconditional&&!nop) { //printf("branch(%d): eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d\n",i,branch_regs[i].regmap[0],branch_regs[i].regmap[1],branch_regs[i].regmap[2],branch_regs[i].regmap[3],branch_regs[i].regmap[5],branch_regs[i].regmap[6],branch_regs[i].regmap[7]); assert(sr>=0); emit_testimm(sr,1); if(opcode2[i]==13) // BT/S { nottaken=(pointer)out; emit_jeq(2); } if(opcode2[i]==15) // BF/S { nottaken=(pointer)out; emit_jne(2); } } // if(!unconditional) ds_unneeded=regs[i].u; ds_unneeded&=~((1LL<>1]) { ds_assemble_entry(i); } else { add_to_linker((int)out,ba[i],internal); emit_jmp(0); } } // branch not taken if(!unconditional) { if(nottaken1) set_jump_target(nottaken1,(int)out); set_jump_target(nottaken,(int)out); assem_debug("2:\n"); wb_invalidate(regs[i].regmap,branch_regs[i].regmap,regs[i].dirty, ds_unneeded); load_regs(regs[i].regmap,branch_regs[i].regmap,rs1[i+1],rs2[i+1],rs3[i+1]); address_generation(i+1,&branch_regs[i],0); if(itype[i+1]==COMPLEX) { if((opcode[i+1]|4)==4&&opcode2[i+1]==15) { // MAC.W/MAC.L load_regs(regs[i].regmap,branch_regs[i].regmap,MACL,MACH,MACH); } } load_regs(regs[i].regmap,branch_regs[i].regmap,CCREG,CCREG,CCREG); ds_assemble(i+1,&branch_regs[i]); } } } void system_assemble(int i,struct regstat *i_regs) { signed char ccreg=get_reg(i_regs->regmap,CCREG); assert(ccreg==HOST_CCREG); assert(!is_delayslot); if(opcode[i]==0&&opcode2[i]==11&&opcode3[i]==1) { // SLEEP pointer jaddr, return_address; emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); jaddr=(pointer)out; emit_jns(0); return_address=(pointer)out; emit_zeroreg(HOST_CCREG); set_jump_target(jaddr,(pointer)out); add_stub(CC_STUB,(int)out,return_address,0,i,start+i*2,TAKEN,0); emit_jmp(0); // DEBUG: Count in multiples of three to match interpreter //emit_addimm_and_set_flags(CLOCK_DIVIDER*3,HOST_CCREG); //add_stub(CC_STUB,(int)out,return_address,0,i,start+i*2,TAKEN,0); //emit_jns(0); emit_jmp(return_address); } else { int b,t,sr,st,map=-1,cache=-1; int jaddr=0; unsigned int hr; u32 reglist=0; assert(opcode[i]==12); // TRAPA t=get_reg(i_regs->regmap,-1); b=get_reg(i_regs->regmap,VBR); sr=get_reg(i_regs->regmap,SR); st=get_reg(i_regs->regmap,15); // STACK for(hr=0;hrregmap[hr]>=0) reglist|=1<=0); assert(b>=0); assert(sr>=0); assert(st>=0); emit_addimm(st,-4,st); map=get_reg(i_regs->regmap,MOREG); cache=get_reg(i_regs->regmap,MMREG); assert(map>=0); reglist&=~(1<regmap,i_regs->dirty,-1); emit_movimm(start+i*2+2,sr); emit_addimm(b,imm[i]<<2,b); map=do_map_w(st,st,map,cache,0,0,0); do_map_w_branch(map,0,0,&jaddr); // Save PC emit_rorimm(sr,16,sr); emit_writeword_indexed_map(sr,0,st,map,map); if(jaddr) { add_stub(STOREL_STUB,jaddr,(int)out,i,st,(int)i_regs,ccadj[i],reglist); } // Load PC map=do_map_r(b,b,map,cache,0,-1,-1,0,0); do_map_r_branch(map,0,0,&jaddr); emit_readword_indexed_map(0,b,map,t); emit_rorimm(t,16,t); if(jaddr) add_stub(LOADL_STUB,jaddr,(int)out,i,t,(int)i_regs,ccadj[i],reglist); if(i_regs->regmap[HOST_CCREG]!=CCREG) { emit_loadreg(CCREG,HOST_CCREG); } emit_addimm_and_set_flags(CLOCK_DIVIDER*(ccadj[i]+cycles[i]),HOST_CCREG); //add_stub(CC_STUB,(int)out,jump_vaddr_reg[slave][t],0,i,-1,TAKEN,0); // FIXME //emit_jns(0); emit_jmp(jump_vaddr_reg[slave][t]); } } void bios_assemble(int i,struct regstat *i_regs) { signed char ccreg=get_reg(i_regs->regmap,CCREG); assert(ccreg==HOST_CCREG); assert(!is_delayslot); emit_movimm(start+i*2,0); //emit_writeword(0,slave?(int)&slave_pc:(int)&master_pc); emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); if(slave) emit_call((pointer)slave_handle_bios); // Probably doesn't work else emit_call((pointer)master_handle_bios); } // Basic liveness analysis for SH2 registers void unneeded_registers(int istart,int iend,int r) { int i; u64 u,uu,b,bu; u64 temp_u,temp_uu; u64 tdep; if(iend==slen-1) { u=0; }else{ u=unneeded_reg[iend+1]; u=0; } for (i=iend;i>=istart;i--) { //printf("unneeded registers i=%d (%d,%d) r=%d\n",i,istart,iend,r); if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP) { if(ba[i]=(start+slen*2)) { // Branch out of this block, flush all regs u=0; branch_unneeded_reg[i]=u; if(itype[i]!=CJUMP) { // Merge in delay slot if(rt1[i+1]>=0) u|=1LL<=0) u|=1LL<=0) u&=~(1LL<=0) u&=~(1LL<=0) u&=~(1LL<=0) temp_u|=1LL<=0) temp_u|=1LL<=0) temp_u&=~(1LL<=0) temp_u&=~(1LL<=0) temp_u&=~(1LL<=0) temp_u|=1LL<=0) temp_u|=1LL<=0) temp_u&=~(1LL<=0) temp_u&=~(1LL<=0) temp_u&=~(1LL<>1,i-1,r+1); }else{ unneeded_reg[(ba[i]-start)>>1]=0; } } /*else*/ if(1) { if(itype[i]==UJUMP||itype[i]==RJUMP) { // Unconditional branch u=unneeded_reg[(ba[i]-start)>>1]; // Always need stack and status in case of interrupt u&=~((1LL<<15)|(1LL<=0) u|=1LL<=0) u|=1LL<=0) u&=~(1LL<=0) u&=~(1LL<=0) u&=~(1LL<>1]; branch_unneeded_reg[i]=b; //b=0; // for debugging //branch_unneeded_reg[i]=b; // for debugging // Branch delay slot if(itype[i]!=CJUMP) { if(rt1[i+1]>=0) b|=1LL<=0) b|=1LL<=0) b&=~(1LL<=0) b&=~(1LL<=0) b&=~(1LL<>rt1[i])&1; // Written registers are unneeded if(rt1[i]>=0) u|=1LL<=0) u|=1LL<=0) u&=~(1LL<=0) u&=~(1LL<=0) u&=~(1LL<=istart;i--) { if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP) { if(ba[i]=(start+slen*2)) { // Branch out of this block, flush all regs if(itype[i]==RJUMP||itype[i]==UJUMP) { // Unconditional branch will_dirty_i=0; wont_dirty_i=0; // Merge in delay slot (will dirty) for(r=0;rTBIT) will_dirty_i&=~(1<TBIT) will_dirty_i&=~(1<TBIT) will_dirty_i&=~(1<TBIT) will_dirty_i&=~(1<TBIT) temp_will_dirty&=~(1<TBIT) temp_will_dirty&=~(1<TBIT) temp_will_dirty&=~(1<TBIT) temp_will_dirty&=~(1<=0 && (regmap_pre[i][r]&63)>(regmap_pre[i][r]&63))&1)<>(regmap_pre[i][r]&63))&1)<>1,i-1,0); }else{ // Limit recursion. It can take an excessive amount // of time if there are a lot of nested loops. will_dirty[(ba[i]-start)>>1]=0; wont_dirty[(ba[i]-start)>>1]=-1; } } /*else*/ if(1) { if(itype[i]==RJUMP||itype[i]==UJUMP) { // Unconditional branch will_dirty_i=0; wont_dirty_i=0; //if(ba[i]>start+i*4) { // Disable recursion (for debugging) for(r=0;r>1].regmap_entry[r]) { will_dirty_i|=will_dirty[(ba[i]-start)>>1]&(1<>1]&(1<=0) { will_dirty_i|=((unneeded_reg[(ba[i]-start)>>1]>>branch_regs[i].regmap[r])&1)<>1]>>branch_regs[i].regmap[r])&1)<TBIT) will_dirty_i&=~(1<TBIT) will_dirty_i&=~(1<start+i*4) { // Disable recursion (for debugging) for(r=0;r>1].regmap_entry[r]) { will_dirty_i&=will_dirty[(ba[i]-start)>>1]&(1<>1]&(1<=0) { will_dirty_i&=((unneeded_reg[(ba[i]-start)>>1]>>target_reg)&1)<>1]>>target_reg)&1)<TBIT) will_dirty_i&=~(1<TBIT) will_dirty_i&=~(1<TBIT) will_dirty_i&=~(1<istart) { if(itype[i]!=RJUMP&&itype[i]!=UJUMP&&itype[i]!=CJUMP&&itype[i]!=SJUMP) { // Don't store a register immediately after writing it, // may prevent dual-issue. if((regs[i].regmap[r]&63)==rt1[i-1]) wont_dirty_i|=1<>r)&1) { printf(" r%d",r); } } printf("\n");*/ regs[i].dirty|=will_dirty_i; //#ifndef DESTRUCTIVE_WRITEBACK regs[i].dirty&=wont_dirty_i; if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==SJUMP) { if(i>r)&1));*/} } } } } else { if(i>r)&1));*/} } } } } //#endif } // Deal with changed mappings temp_will_dirty=will_dirty_i; temp_wont_dirty=wont_dirty_i; for(r=0;r=0&&(nr=get_reg(regs[i].regmap,regmap_pre[i][r]))>=0) { // Register moved to a different register will_dirty_i&=~(1<>nr)&1)<>nr)&1)<=0 && (regmap_pre[i][r]&63)>(regmap_pre[i][r]&63))&1)<>(regmap_pre[i][r]&63))&1)<>r)&1));*/ } } } } } } /* disassembly */ void disassemble_inst(int i) { if (bt[i]) printf("*"); else printf(" "); switch(itype[i]) { case UJUMP: case CJUMP: case SJUMP: printf (" %x: %s %8x\n",start+i*2,insn[i],ba[i]);break; case RJUMP: printf (" %x: %s r%d\n",start+i*2,insn[i],rs1[i]);break; case IMM8: printf (" %x: %s #%d,r%d\n",start+i*2,insn[i],imm[i],opcode[i]==14?rt1[i]:rs1[i]); break; case LOAD: switch(addrmode[i]) { case REGIND: printf (" %x: %s @r%d,r%d\n",start+i*2,insn[i],rs1[i],rt1[i]); break; case POSTINC: printf (" %x: %s @r%d+,r%d\n",start+i*2,insn[i],rs1[i],rt1[i]); break; case PREDEC: printf (" %x: %s @-r%d,r%d\n",start+i*2,insn[i],rs1[i],rt1[i]); break; case DUALIND: printf (" %x: %s @(R0,r%d),r%d\n",start+i*2,insn[i],rs1[i],rt1[i]); break; case GBRIND: printf (" %x: %s #%d,@(R0,GBR)\n",start+i*2,insn[i],imm[i]); break; case GBRDISP: printf (" %x: %s @(%d,GBR),r%d\n",start+i*2,insn[i],imm[i],rt1[i]); break; case REGDISP: printf (" %x: %s @(%d,r%d),r%d\n",start+i*2,insn[i],imm[i],rs1[i],rt1[i]); break; } break; case STORE: switch(addrmode[i]) { case REGIND: printf (" %x: %s r%d,@r%d\n",start+i*2,insn[i],rs1[i],rs2[i]); break; case POSTINC: printf (" %x: %s r%d,@r%d+\n",start+i*2,insn[i],rs1[i],rs2[i]); break; case PREDEC: printf (" %x: %s r%d,@-r%d\n",start+i*2,insn[i],rs1[i],rs2[i]); break; case DUALIND: printf (" %x: %s r%d,@(R0,r%d)\n",start+i*2,insn[i],rs1[i],rs2[i]); break; case GBRDISP: printf (" %x: %s r%d,@(%d,GBR)\n",start+i*2,insn[i],rs1[i],imm[i]); break; case REGDISP: printf (" %x: %s r%d,@(%d,r%d)\n",start+i*2,insn[i],rs1[i],imm[i],rs2[i]); break; } break; case RMW: switch(addrmode[i]) { case REGIND: printf (" %x: %s @r%d\n",start+i*2,insn[i],rs1[i]); break; case GBRIND: printf (" %x: %s #%d,@(R0,GBR)\n",start+i*2,insn[i],imm[i]); break; } break; case PCREL: printf (" %x: %s @(%x,PC),r%d (PC+%d=%x)",start+i*2,insn[i],imm[i],rt1[i],imm[i],((start+i*2+4)&(opcode[i]==9?~1:~3))+imm[i]); if (opcode[i]==9 && (unsigned)(i+(imm[i]>>1))>1]); // MOV.W else if (opcode[i]==13 && (unsigned)(i+(imm[i]>>1))>1]<<16)+source[(((start+i*2+4)&~3)+imm[i]+2-start)>>1]); // MOV.L else printf("\n"); if (opcode[i]==13 && (unsigned)(i+(imm[i]>>1))>1]<<16)+source[(((start+i*2+4)&~3)+imm[i]+2-start)>>1]-(start+i*2)<(unsigned)1024) printf("Within 1024\n"); break; case ALU: if(rs1[i]<0&&rs2[i]<0) // XOR reg,reg case printf (" %x: %s r%d,r%d\n",start+i*2,insn[i],rt1[i],rt1[i]); else if(rs2[i]>=0&&rs2[i]!=TBIT) printf (" %x: %s r%d,r%d\n",start+i*2,insn[i],rs1[i],rs2[i]); else if(rt1[i]!=rs1[i]) printf (" %x: %s r%d,r%d\n",start+i*2,insn[i],rs1[i],rt1[i]); else printf (" %x: %s r%d\n",start+i*2,insn[i],rs1[i]); break; case MULTDIV: //printf (" %x: %s rt1=%d rt2=%d\n",start+i*2,insn[i],rt1[i],rt2[i]); printf (" %x: %s r%d,r%d\n",start+i*2,insn[i],rs1[i],rs2[i]); break; case SHIFTIMM: if(rs2[i]>=0) printf (" %x: %s r%d,r%d #%d\n",start+i*2,insn[i],rs1[i],rs2[i],imm[i]); else printf (" %x: %s r%d #%d\n",start+i*2,insn[i],rt1[i],imm[i]); break; case MOV: printf (" %x: %s r%d,r%d\n",start+i*2,insn[i],rs1[i],rt1[i]); break; case EXT: printf (" %x: %s r%d,r%d\n",start+i*2,insn[i],rs1[i],rt1[i]); break; case FLAGS: if(opcode2[i]==9) printf (" %x: %s r%d\n",start+i*2,insn[i],rt1[i]); else printf (" %x: %s\n",start+i*2,insn[i]); break; case COMPLEX: printf (" %x: %s r%d,r%d\n",start+i*2,insn[i],rs1[i],rs2[i]); break; case DATA: printf (" %x: WORD %4x\n",start+i*2,source[i]&0xFFFF); // Constant data break; default: //printf (" %s %8x\n",insn[i],source[i]); printf (" %x: %s\n",start+i*2,insn[i]); } } void sh2_dynarec_init() { int n; //printf("Init new dynarec\n"); out=(u8 *)BASE_ADDR; if (mmap (out, 1<>2)|0x4000000000000000LL; #else memory_map[n]=(((u32)BiosRom-((n<<12)&0x80000))>>2)|0x40000000; #endif }else if(n>=0x0200&&n<0x0300) { #ifdef POINTERS_64BIT memory_map[n]=((u64)LowWram-((n<<12)&0xFFF00000))>>2; #else memory_map[n]=((u32)LowWram-((n<<12)&0xFFF00000))>>2; #endif }else if(n>=0x6000&&n<0x8000) { #ifdef POINTERS_64BIT memory_map[n]=((u64)HighWram-((n<<12)&0xFFF00000))>>2; #else memory_map[n]=((u32)HighWram-((n<<12)&0xFFF00000))>>2; #endif }else if(n>=0x20200&&n<0x20300) { #ifdef POINTERS_64BIT memory_map[n]=((u64)LowWram-((n<<12)&0xFFF00000))>>2; #else memory_map[n]=((u32)LowWram-((n<<12)&0xFFF00000))>>2; #endif }else if(n>=0x26000&&n<0x28000) { #ifdef POINTERS_64BIT memory_map[n]=((u64)HighWram-((n<<12)&0xFFF00000))>>2; #else memory_map[n]=((u32)HighWram-((n<<12)&0xFFF00000))>>2; #endif }else memory_map[n]=-1LL; } master_cc=slave_cc=0; slave_ip=(void *)0; // Slave not running, go directly to interrupt handler arch_init(); } void SH2DynarecReset(SH2_struct *context) { //printf("SH2DynarecReset\n"); if(context==MSH2) master_cc=0; if(context==SSH2) { slave_ip=(void*)0; slave_cc=0; } } void sh2_dynarec_cleanup() { int n; if (munmap ((void *)BASE_ADDR, 1< %x\n", (int)addr, (int)out); //printf("NOTCOMPILED: addr = %x -> %x\n", (int)addr, (int)out); //printf("TRACE: count=%d next=%d (compile %x)\n",Count,next_interupt,addr); //if(debug) //printf("TRACE: count=%d next=%d (checksum %x)\n",Count,next_interupt,mchecksum()); //printf("fpu mapping=%x enabled=%x\n",(Status & 0x04000000)>>26,(Status & 0x20000000)>>29); /*if(Count>=312978186) { rlist(); }*/ //rlist(); start = (u32)addr&~1; slave = (u32)addr&1; cached_addr = start&~0x20000000; //assert(((u32)addr&1)==0); if (cached_addr >= 0x00000000 && cached_addr < 0x00100000) { source = (u16 *)((char *)BiosRom+(start & 0x7FFFF)); pagelimit = (addr|0x7FFFF) + 1; } else if (cached_addr >= 0x00200000 && cached_addr < 0x00300000) { source = (u16 *)((char *)LowWram+(start & 0xFFFFF)); pagelimit = (addr|0xFFFFF) + 1; } else if (cached_addr >= 0x06000000 && cached_addr < 0x08000000) { source = (u16 *)((char *)HighWram+(start & 0xFFFFF)); pagelimit = (addr|0xFFFFF) + 1; } else { printf("Compile at bogus memory address: %x \n", (int)addr); exit(1); } //printf("source= %x\n",(int)source); alignedsource=(void *)(((pointer)source)&~3); /* Pass 1: disassemble */ /* Pass 2: register dependencies, branch targets */ /* Pass 3: register allocation */ /* Pass 4: branch dependencies */ /* Pass 5: pre-alloc */ /* Pass 6: optimize clean/dirty state */ /* Pass 7: identify interrupt return locations */ /* Pass 8: assembly */ /* Pass 9: linker */ /* Pass 10: garbage collection / free memory */ slen=MAXBLOCK; //printf("addr = %x source = %x %x\n", addr,source,source[0]); /* Pass 1 disassembly */ for(i=0;i<8;i++) { //printf("recent write: %x\n",recent_writes[i]); if(recent_writes[i]start) writelimit=recent_writes[i]; } } for(i=0;!done;i++) { bt[i]=0;ooo[i]=0;op2=0;op3=0;mode=0; minimum_free_regs[i]=0; opcode[i]=op=source[i]>>12; strcpy(insn[i],"???"); type=NI; switch(op) { case 0x00: op2=source[i]&0xf; op3=(source[i]>>4)&0xf; switch(op2) { case 0x02: strcpy(insn[i],"STC"); type=MOV; break; case 0x03: switch(op3) { case 0x00: strcpy(insn[i],"BSRF"); type=RJUMP; break; case 0x02: strcpy(insn[i],"BRAF"); type=RJUMP; break; } break; case 0x04: strcpy(insn[i],"MOV.B"); type=STORE;mode=DUALIND; break; case 0x05: strcpy(insn[i],"MOV.W"); type=STORE;mode=DUALIND; break; case 0x06: strcpy(insn[i],"MOV.L"); type=STORE;mode=DUALIND; break; case 0x07: strcpy(insn[i],"MUL.L"); type=MULTDIV; break; case 0x08: switch(op3) { case 0x00: strcpy(insn[i],"CLRT"); type=FLAGS; break; case 0x01: strcpy(insn[i],"SETT"); type=FLAGS; break; case 0x02: strcpy(insn[i],"CLRMAC"); type=MULTDIV; break; } break; case 0x09: switch(op3) { case 0x00: strcpy(insn[i],"NOP"); type=NOP; break; case 0x01: strcpy(insn[i],"DIV0U"); type=MULTDIV; break; case 0x02: strcpy(insn[i],"MOVT"); type=FLAGS; break; } break; case 0x0A: strcpy(insn[i],"STS"); type=MOV; break; case 0x0B: switch(op3) { case 0x00: strcpy(insn[i],"RTS"); type=RJUMP; break; case 0x01: strcpy(insn[i],"SLEEP"); type=SYSTEM; break; case 0x02: strcpy(insn[i],"RTE"); type=RJUMP; break; } break; case 0x0C: strcpy(insn[i],"MOV.B"); type=LOAD;mode=DUALIND; break; case 0x0D: strcpy(insn[i],"MOV.W"); type=LOAD;mode=DUALIND; break; case 0x0E: strcpy(insn[i],"MOV.L"); type=LOAD;mode=DUALIND; break; case 0x0F: strcpy(insn[i],"MAC.L"); type=COMPLEX; break; } break; case 0x01: strcpy(insn[i],"MOV.L"); type=STORE;mode=REGDISP;op2=2; break; case 0x02: op2=source[i]&0xf; switch(op2) { case 0x00: strcpy(insn[i],"MOV.B"); type=STORE;mode=REGIND; break; case 0x01: strcpy(insn[i],"MOV.W"); type=STORE;mode=REGIND; break; case 0x02: strcpy(insn[i],"MOV.L"); type=STORE;mode=REGIND; break; case 0x04: strcpy(insn[i],"MOV.B"); type=STORE;mode=PREDEC; break; case 0x05: strcpy(insn[i],"MOV.W"); type=STORE;mode=PREDEC; break; case 0x06: strcpy(insn[i],"MOV.L"); type=STORE;mode=PREDEC; break; case 0x07: strcpy(insn[i],"DIV0S"); type=MULTDIV; break; case 0x08: strcpy(insn[i],"TST"); type=ALU; break; case 0x09: strcpy(insn[i],"AND"); type=ALU; break; case 0x0A: strcpy(insn[i],"XOR"); type=ALU; break; case 0x0B: strcpy(insn[i],"OR"); type=ALU; break; case 0x0C: strcpy(insn[i],"CMP/ST"); type=ALU; break; case 0x0D: strcpy(insn[i],"XTRCT"); type=SHIFTIMM; break; case 0x0E: strcpy(insn[i],"MULU.W"); type=MULTDIV; break; case 0x0F: strcpy(insn[i],"MULS.W"); type=MULTDIV; break; } break; case 0x03: op2=source[i]&0xf; switch(op2) { case 0x00: strcpy(insn[i],"CMP/EQ"); type=ALU; break; case 0x02: strcpy(insn[i],"CMP/HS"); type=ALU; break; case 0x03: strcpy(insn[i],"CMP/GE"); type=ALU; break; case 0x04: strcpy(insn[i],"DIV1"); type=COMPLEX; break; case 0x05: strcpy(insn[i],"DMULU.L"); type=MULTDIV; break; case 0x06: strcpy(insn[i],"CMP/HI"); type=ALU; break; case 0x07: strcpy(insn[i],"CMP/GT"); type=ALU; break; case 0x08: strcpy(insn[i],"SUB"); type=ALU; break; case 0x0A: strcpy(insn[i],"SUBC"); type=ALU; break; case 0x0B: strcpy(insn[i],"SUBV"); type=ALU; break; case 0x0C: strcpy(insn[i],"ADD"); type=ALU; break; case 0x0D: strcpy(insn[i],"DMULS.L"); type=MULTDIV; break; case 0x0E: strcpy(insn[i],"ADDC"); type=ALU; break; case 0x0F: strcpy(insn[i],"ADDV"); type=ALU; break; } break; case 0x04: op2=source[i]&0xf; op3=(source[i]>>4)&0xf; switch(op2) { case 0x00: switch(op3) { case 0x00: strcpy(insn[i],"SHLL"); type=SHIFTIMM; break; case 0x01: strcpy(insn[i],"DT"); type=ALU; break; case 0x02: strcpy(insn[i],"SHAL"); type=SHIFTIMM; break; } break; case 0x01: switch(op3) { case 0x00: strcpy(insn[i],"SHLR"); type=SHIFTIMM; break; case 0x01: strcpy(insn[i],"CMP/PZ"); type=ALU; break; case 0x02: strcpy(insn[i],"SHAR"); type=SHIFTIMM; break; } break; case 0x02: strcpy(insn[i],"STS.L"); type=STORE;mode=PREDEC; break; case 0x03: strcpy(insn[i],"STC.L"); type=STORE;mode=PREDEC; break; case 0x04: switch(op3) { case 0x00: strcpy(insn[i],"ROTL"); type=SHIFTIMM; break; case 0x02: strcpy(insn[i],"ROTCL"); type=SHIFTIMM; break; } break; case 0x05: switch(op3) { case 0x00: strcpy(insn[i],"ROTR"); type=SHIFTIMM; break; case 0x01: strcpy(insn[i],"CMP/PL"); type=ALU; break; case 0x02: strcpy(insn[i],"ROTCR"); type=SHIFTIMM; break; } break; case 0x06: strcpy(insn[i],"LDS.L"); type=LOAD;mode=POSTINC; break; case 0x07: strcpy(insn[i],"LDC.L"); type=LOAD;mode=POSTINC; break; case 0x08: switch(op3) { case 0x00: strcpy(insn[i],"SHLL2"); type=SHIFTIMM; break; case 0x01: strcpy(insn[i],"SHLL8"); type=SHIFTIMM; break; case 0x02: strcpy(insn[i],"SHLL16"); type=SHIFTIMM; break; } break; case 0x09: switch(op3) { case 0x00: strcpy(insn[i],"SHLR2"); type=SHIFTIMM; break; case 0x01: strcpy(insn[i],"SHLR8"); type=SHIFTIMM; break; case 0x02: strcpy(insn[i],"SHLR16"); type=SHIFTIMM; break; } break; case 0x0A: strcpy(insn[i],"LDS"); type=MOV; break; case 0x0B: switch(op3) { case 0x00: strcpy(insn[i],"JSR"); type=RJUMP; break; case 0x01: strcpy(insn[i],"TAS.B"); type=RMW;mode=REGIND; break; case 0x02: strcpy(insn[i],"JMP"); type=RJUMP; break; } break; case 0x0E: strcpy(insn[i],"LDC"); type=MOV; break; case 0x0F: strcpy(insn[i],"MAC.W"); type=COMPLEX; break; } break; case 0x05: strcpy(insn[i],"MOV.L"); type=LOAD;mode=REGDISP;op2=2; break; case 0x06: op2=source[i]&0xf; switch(op2) { case 0x00: strcpy(insn[i],"MOV.B"); type=LOAD;mode=REGIND; break; case 0x01: strcpy(insn[i],"MOV.W"); type=LOAD;mode=REGIND; break; case 0x02: strcpy(insn[i],"MOV.L"); type=LOAD;mode=REGIND; break; case 0x03: strcpy(insn[i],"MOV"); type=MOV; break; case 0x04: strcpy(insn[i],"MOV.B"); type=LOAD;mode=POSTINC; break; case 0x05: strcpy(insn[i],"MOV.W"); type=LOAD;mode=POSTINC; break; case 0x06: strcpy(insn[i],"MOV.L"); type=LOAD;mode=POSTINC; break; case 0x07: strcpy(insn[i],"NOT"); type=ALU; break; case 0x08: strcpy(insn[i],"SWAP.B"); type=ALU; break; case 0x09: strcpy(insn[i],"SWAP.W"); type=ALU; break; case 0x0A: strcpy(insn[i],"NEGC"); type=ALU; break; case 0x0B: strcpy(insn[i],"NEG"); type=ALU; break; case 0x0C: strcpy(insn[i],"EXTU.B"); type=EXT; break; case 0x0D: strcpy(insn[i],"EXTU.W"); type=EXT; break; case 0x0E: strcpy(insn[i],"EXTS.B"); type=EXT; break; case 0x0F: strcpy(insn[i],"EXTS.W"); type=EXT; break; } break; case 0x07: strcpy(insn[i],"ADD"); type=IMM8; break; case 0x08: op2=(source[i]>>8)&0xf; switch(op2) { case 0x00: strcpy(insn[i],"MOV.B"); type=STORE;mode=REGDISP; break; case 0x01: strcpy(insn[i],"MOV.W"); type=STORE;mode=REGDISP; break; case 0x04: strcpy(insn[i],"MOV.B"); type=LOAD;mode=REGDISP; break; case 0x05: strcpy(insn[i],"MOV.W"); type=LOAD;mode=REGDISP; break; case 0x08: strcpy(insn[i],"CMP/EQ"); type=IMM8; break; case 0x09: strcpy(insn[i],"BT"); type=CJUMP; break; case 0x0B: strcpy(insn[i],"BF"); type=CJUMP; break; case 0x0D: strcpy(insn[i],"BT/S"); type=SJUMP; break; case 0x0F: strcpy(insn[i],"BF/S"); type=SJUMP; break; } break; case 0x09: strcpy(insn[i],"MOV.W"); type=PCREL; break; case 0x0A: strcpy(insn[i],"BRA"); type=UJUMP; break; case 0x0B: strcpy(insn[i],"BSR"); type=UJUMP; break; case 0x0C: op2=(source[i]>>8)&0xf; switch(op2) { case 0x00: strcpy(insn[i],"MOV.B"); type=STORE;mode=GBRDISP; break; case 0x01: strcpy(insn[i],"MOV.W"); type=STORE;mode=GBRDISP; break; case 0x02: strcpy(insn[i],"MOV.L"); type=STORE;mode=GBRDISP; break; case 0x03: strcpy(insn[i],"TRAPA"); type=SYSTEM; break; case 0x04: strcpy(insn[i],"MOV.B"); type=LOAD;mode=GBRDISP; break; case 0x05: strcpy(insn[i],"MOV.W"); type=LOAD;mode=GBRDISP; break; case 0x06: strcpy(insn[i],"MOV.L"); type=LOAD;mode=GBRDISP; break; case 0x07: strcpy(insn[i],"MOVA"); type=PCREL; break; case 0x08: strcpy(insn[i],"TST"); type=IMM8; break; case 0x09: strcpy(insn[i],"AND"); type=IMM8; break; case 0x0A: strcpy(insn[i],"XOR"); type=IMM8; break; case 0x0B: strcpy(insn[i],"OR"); type=IMM8; break; case 0x0C: strcpy(insn[i],"TST.B"); type=LOAD;mode=GBRIND; break; case 0x0D: strcpy(insn[i],"AND.B"); type=RMW;mode=GBRIND; break; case 0x0E: strcpy(insn[i],"XOR.B"); type=RMW;mode=GBRIND; break; case 0x0F: strcpy(insn[i],"OR.B"); type=RMW;mode=GBRIND; break; } break; case 0x0D: strcpy(insn[i],"MOV.L"); type=PCREL; break; case 0x0E: strcpy(insn[i],"MOV"); type=IMM8; break; default: strcpy(insn[i],"???"); type=NI; break; } itype[i]=type; addrmode[i]=mode; opcode2[i]=op2; opcode3[i]=op3; /* Get registers/immediates */ rs1[i]=-1; rs2[i]=-1; rs3[i]=-1; rt1[i]=-1; rt2[i]=-1; lt1[i]=-1; cycles[i]=1; switch(type) { case LOAD: if(mode==GBRDISP||mode==GBRIND) rs1[i]=GBR; else rs1[i]=(source[i]>>4)&0xf; if(mode==DUALIND||mode==GBRIND) rs2[i]=0; if(op==4) { // LDS/LDC rs1[i]=(source[i]>>8)&0xf; if(op2==6) rt1[i]=((source[i]>>4)&0xf)+MACH; if(op2==7) {rt1[i]=((source[i]>>4)&0xf)+SR;cycles[i]=3;} if(rt1[i]==SR) rt2[i]=TBIT; } else if(op==8) rt1[i]=0; // (@disp,rm),r0 else if(op==12) { if(op2!=12) rt1[i]=0; // (@disp,GBR),r0 else { imm[i]=(unsigned int)((unsigned char)source[i]); rt1[i]=TBIT; // TST.B cycles[i]=3; } } else { rt1[i]=(source[i]>>8)&0xf; } if(mode==REGDISP) { imm[i]=(unsigned int)source[i]&0xF; if(op==5) imm[i]<<=2; // MOV.L if(op==8&&op2==5) imm[i]<<=1; // MOV.W } else if(mode==GBRDISP) { imm[i]=(unsigned int)((unsigned char)source[i])<<(op2&3); } else if(mode!=GBRIND) imm[i]=0; if(mode==POSTINC) rt2[i]=rs1[i]; break; case STORE: if(op==4) { // STS/STC if(op2==2) rs1[i]=((source[i]>>4)&0xf)+MACH; if(op2==3) {rs1[i]=((source[i]>>4)&0xf)+SR;cycles[i]=2;} if(rs1[i]==SR) rs3[i]=TBIT; } else if(op==8) rs1[i]=0; // r0,(@disp,rn) else if(op==12) rs1[i]=0; // r0,(@disp,GBR) else rs1[i]=(source[i]>>4)&0xf; if(mode==GBRDISP) rs2[i]=GBR; else if(op==8) rs2[i]=(source[i]>>4)&0xf; // r0,(@disp,rn) else rs2[i]=(source[i]>>8)&0xf; if(mode==DUALIND) rs3[i]=0; if(mode==REGDISP) { imm[i]=(unsigned int)source[i]&0xF; if(op==1) imm[i]<<=2; // MOV.L if(op==8&&op2==1) imm[i]<<=1; // MOV.W } else if(mode==GBRDISP) { imm[i]=(unsigned int)((unsigned char)source[i])<<(op2&3); } else imm[i]=0; if(mode==PREDEC) rt1[i]=rs2[i]; if( (mode==DUALIND&&((p_isconst>>rs2[i])&(p_isconst>>rs3[i])&1)) || (mode!=DUALIND&&((p_isconst>>rs2[i])&1)) ) { u32 addr; if(mode==DUALIND) addr=p_constmap[rs2[i]]+p_constmap[rs3[i]]; if(mode==REGDISP||mode==GBRDISP) addr=p_constmap[rs2[i]]+imm[i]; if(mode==PREDEC) addr=(p_constmap[rs2[i]]-=4); if(mode==REGIND) addr=p_constmap[rs2[i]]; if(addr>start+i*2&&addr>8)&0xf; rt1[i]=TBIT; imm[i]=0; cycles[i]=4; } if(op==12) // AND.B/XOR.B/OR.B { rs1[i]=GBR; rs2[i]=0; imm[i]=(unsigned int)((unsigned char)source[i]); cycles[i]=3; } break; case PCREL: imm[i]=(signed int)((unsigned char)source[i]); if(op==12) rt1[i]=0; // MOVA else rt1[i]=(source[i]>>8)&0xf; if(op==9) imm[i]<<=1; // MOV.W else imm[i]<<=2; // Extend block to include consts // FIXME: Don't go past limit if (op==9 && lastconst < (start+i*2+4)+imm[i]) // MOV.W lastconst = (start+i*2+4)+imm[i]; if (op==13 && lastconst < ((start+i*2+4)&~3)+imm[i]+2) // MOV.L lastconst = ((start+i*2+4)&~3)+imm[i]+2; //printf("lastconst=%x\n",lastconst); break; case MOV: if(op==6) { rs1[i]=(source[i]>>4)&0xf; rt1[i]=(source[i]>>8)&0xf; } if(op==0) { // STC/STS if(op2==2) rs1[i]=((source[i]>>4)&0xf)+SR; //STC if(op2==10) rs1[i]=((source[i]>>4)&0xf)+MACH; //STS rt1[i]=(source[i]>>8)&0xf; if(rs1[i]==SR) rs2[i]=TBIT; // For liveness analysis } if(op==4) { // LDC/LDS if(op2==14) rt1[i]=((source[i]>>4)&0xf)+SR; //LDC if(op2==10) rt1[i]=((source[i]>>4)&0xf)+MACH; //LDS rs1[i]=(source[i]>>8)&0xf; if(rt1[i]==SR) rt2[i]=TBIT; // For liveness analysis } break; case IMM8: if(op==8) { // CMP/EQ r0 rs1[i]=0; rt1[i]=TBIT; imm[i]=(signed int)((signed char)source[i]); }else if(op==12) { rs1[i]=0; if(op2==8) rt1[i]=TBIT; // TST else rt1[i]=0; // AND/XOR/OR imm[i]=(unsigned int)((unsigned char)source[i]); }else{ // ADD/MOV if(op==7) rs1[i]=(source[i]>>8)&0xf; // ADD rt1[i]=(source[i]>>8)&0xf; imm[i]=(signed int)((signed char)source[i]); } break; case FLAGS: if(op2==8) rt1[i]=TBIT; // CLRT/SETT if(op2==9) {rs1[i]=TBIT;rt1[i]=(source[i]>>8)&0xf;} // MOVT break; case ALU: if(op==2) { if(op2==8||op2==12) { // TST or CMP/STR rs1[i]=(source[i]>>4)&0xf; rs2[i]=(source[i]>>8)&0xf; rt1[i]=TBIT; } else { // AND/OR/XOR rs1[i]=(source[i]>>4)&0xf; rs2[i]=(source[i]>>8)&0xf; rt1[i]=(source[i]>>8)&0xf; if(op2==10&&rs1[i]==rs2[i]) { rs1[i]=-1;rs2[i]=-1; // Optimize XOR reg,reg } } } if(op==3) { if(op2<8) { // CMP rs1[i]=(source[i]>>4)&0xf; rs2[i]=(source[i]>>8)&0xf; rt1[i]=TBIT; } else { // ADD/SUB rs1[i]=(source[i]>>4)&0xf; rs2[i]=(source[i]>>8)&0xf; rt1[i]=(source[i]>>8)&0xf; if(op2==10||op2==14) rs3[i]=TBIT; // ADDC/SUBC read T bit if(op2!=8&&op2!=12) // ADDC/ADDV/SUBC/SUBV set T bit rt2[i]=TBIT; } } if(op==4) { // DT and compare with zero rs1[i]=(source[i]>>8)&0xf; if(op2==0) rt1[i]=(source[i]>>8)&0xf; // DT rt2[i]=TBIT; } if(op==6) { // NOT/NEG/NEGC/SWAP rs1[i]=(source[i]>>4)&0xf; rt1[i]=(source[i]>>8)&0xf; if(op2==10) rs2[i]=rt2[i]=TBIT; // NEGC sets T bit } break; case EXT: rs1[i]=(source[i]>>4)&0xf; rt1[i]=(source[i]>>8)&0xf; break; case MULTDIV: if(op==0) { if(op2==7) // MUL.L { rs1[i]=(source[i]>>4)&0xf; rs2[i]=(source[i]>>8)&0xf; rt1[i]=MACL; cycles[i]=2; } if(op2==8) // CLRMAC { rt1[i]=MACH; rt2[i]=MACL; } if(op2==9) // DIV0U { rs1[i]=SR; rt1[i]=SR; rt2[i]=TBIT; } } if(op==2) { if(op2==7) // DIV0S { rs1[i]=(source[i]>>4)&0xf; rs2[i]=(source[i]>>8)&0xf; rs3[i]=SR; rt1[i]=SR; rt2[i]=TBIT; } if(op2==14) // MULU.W { rs1[i]=(source[i]>>4)&0xf; rs2[i]=(source[i]>>8)&0xf; rt1[i]=MACL; } if(op2==15) // MULS.W { rs1[i]=(source[i]>>4)&0xf; rs2[i]=(source[i]>>8)&0xf; rt1[i]=MACL; } } if(op==3) { if(op2==5) // DMULU.L { rs1[i]=(source[i]>>4)&0xf; rs2[i]=(source[i]>>8)&0xf; rt1[i]=MACH; rt2[i]=MACL; cycles[i]=2; } if(op2==13) // DMULS.L { rs1[i]=(source[i]>>4)&0xf; rs2[i]=(source[i]>>8)&0xf; rt1[i]=MACH; rt2[i]=MACL; cycles[i]=2; } } break; case SHIFTIMM: rs1[i]=(source[i]>>8)&0xf; rt1[i]=(source[i]>>8)&0xf; if(op==4) { if(op2<6) rt2[i]=TBIT; if(op2==4||op2==5) {if(op3==2) rs2[i]=TBIT;} // ROTCL/ROTCR } if(op==2&op2==13) { // XTRCT rs1[i]=(source[i]>>4)&0xf; rs2[i]=(source[i]>>8)&0xf; } break; case UJUMP: rs2[i]=CCREG; if(op==11) rt1[i]=PR; // BSR cycles[i]=2; break; case RJUMP: rs1[i]=(source[i]>>8)&0xf; if (op==0&&op2==11&&op3==0) rs1[i]=PR; // RTS if ((op==0&&op2==3)||(op==4&&op2==11)) { // BSRF/JSR if(op3==0) rt1[i]=PR; } rs2[i]=CCREG; cycles[i]=2; if(op==0&&op2==11&&op3==2) { // RTE rs1[i]=15; // Stack pointer rs2[i]=CCREG; rt1[i]=SR; rt2[i]=15; cycles[i]=4; } break; case CJUMP: rs1[i]=TBIT; rs2[i]=CCREG; //cycles[i]=3; // Will be adjusted if branch is taken break; case SJUMP: rs1[i]=TBIT; rs2[i]=CCREG; //cycles[i]=2; // Will be adjusted if branch is taken break; case SYSTEM: if(op2==11&&op3==2) { // RTE rs1[i]=15; // Stack pointer rs2[i]=CCREG; rt1[i]=SR; rt2[i]=TBIT; cycles[i]=4; } else if(op==12) { // TRAPA rs1[i]=SR; // Status/flags //rs2[i]=CCREG; rs2[i]=VBR; rs3[i]=15; // Stack pointer imm[i]=(unsigned int)((unsigned char)source[i]); cycles[i]=8; } else { // SLEEP rs2[i]=CCREG; cycles[i]=8; } break; case COMPLEX: if(op==3&&op2==4) { // DIV1 rs1[i]=(source[i]>>4)&0xf; rs2[i]=(source[i]>>8)&0xf; rs3[i]=SR; rt1[i]=(source[i]>>8)&0xf; rt2[i]=SR; } if(op==0&&op2==15) { // MAC.L rs1[i]=(source[i]>>4)&0xf; rs2[i]=(source[i]>>8)&0xf; rs3[i]=SR; rt1[i]=(source[i]>>4)&0xf; rt2[i]=(source[i]>>8)&0xf; cycles[i]=3; } if(op==4&&op2==15) { // MAC.W rs1[i]=(source[i]>>4)&0xf; rs2[i]=(source[i]>>8)&0xf; rs3[i]=SR; rt1[i]=(source[i]>>4)&0xf; rt2[i]=(source[i]>>8)&0xf; cycles[i]=3; } break; } // Do preliminary constant propagation do_consts(i,&p_isconst,p_constmap); /* Calculate branch target addresses */ if(type==UJUMP) ba[i]=start+i*2+4+((((signed int)source[i])<<20)>>19); else if(type==CJUMP||type==SJUMP) ba[i]=start+i*2+4+((((signed int)source[i])<<24)>>23); else { ba[i]=-1; if(type==RJUMP) { if(op!=0||op2!=11||op3!=2) { // !RTE if((p_isconst>>rs1[i])&1) { u32 constaddr=p_constmap[rs1[i]]; if(op==0&&op2==3) { // PC-relative branch, add PC+4 constaddr+=start+i*2+4; } ba[i]=constaddr; } } } } // If the branch target was previously identified as data, back up if(ba[i]>start&&ba[i]>1]!=DATA); if(itype[(ba[i]-start)>>1]==DATA||itype[(ba[i]+2-start)>>1]==DATA) { //printf("back up and redecode %x\n",ba[i]); i=(ba[i]-2-start)>>1; continue; } } /* Is this the end of the block? */ if(i>0&&(itype[i-1]==UJUMP||itype[i-1]==RJUMP)) { if(rt1[i-1]!=PR) { // Continue past subroutine call (BSR/JSR) unsigned int firstbt=0xFFFFFFFF; done=1; // Find next branch target (if any) for(j=i-1;j>=0;j--) { if(ba[j]>start+i*2-2&&ba[j]>1;j>23); if(branch_addr>start+i*2&&branch_addr>19); if(branch_addr>start+i*2&&branch_addrMAXBLOCK/2) done=1; } if(yabsys.emulatebios) { if(start+i*2>=0x200&&start+i*2<0x600) { strcpy(insn[i],"(BIOS)"); itype[i]=BIOS; done=1; } } //if(i>0&&itype[i-1]==SYSCALL&&stop_after_jal) done=1; //if(i>0&&itype[i-1]==SYSTEM&&source[i-1]==0x002B) done=1; // RTE //assert(i0&&(itype[i-1]==UJUMP||itype[i-1]==RJUMP)) isconst[i+1]=0; if(i>0&&(itype[i-1]==UJUMP||itype[i-1]==RJUMP)) p_isconst=0; } } slen=i; assert(slen>0); /* Pass 2 - Register dependencies and branch targets */ // Flag branch targets for(i=0;i=start && ba[i]<(start+slen*2) ) { // Possibly internal branch, flag target bt[(ba[i]-start)>>1]=1; } } } // Do constant propagation p_isconst=0; for(i=0;i1&&(itype[i-2]==UJUMP||itype[i-2]==RJUMP)) p_isconst=0; if(i>0&&(itype[i-1]==UJUMP||itype[i-1]==RJUMP)) p_isconst=0; if(i>0&&(itype[i-1]==CJUMP||itype[i-1]==SJUMP)) p_isconst=0; do_consts(i,&p_isconst,p_constmap); if(itype[i]==RJUMP) { if(opcode[i]!=0||opcode2[i]!=11||opcode3[i]!=2) { // Not RTE if((p_isconst>>rs1[i])&1) { // Do constant propagation, branch to fixed address u32 constaddr=p_constmap[rs1[i]]; if(opcode[i]==0&&opcode2[i]==3) { // PC-relative branch, add PC+4 constaddr+=start+i*2+4; } ba[i]=constaddr; //if(internal_branch(constaddr)) // if(!bt[(constaddr-start)>>1]) printf("oops: %x\n",constaddr); //assert(bt[(constaddr-start)>>1]); } } } // No stack-based addressing modes in the delay slot, // to avoid incorrect constants due to pre-incrementing. // TODO: This really should only drop the address register if(itype[i]==UJUMP||itype[i]==RJUMP||itype[i]==SJUMP) { if((source[i+1]&0xF00A)==0x4002) p_isconst=0; if((source[i+1]&0xB00E)==0x2004) p_isconst=0; if((source[i+1]&0xB00F)==0x2006) p_isconst=0; } memcpy(regs[i].constmap,p_constmap,sizeof(u32)*SH2_REGS); regs[i].isconst=p_isconst; } unneeded_registers(0,slen-1,0); /* Pass 3 - Register allocation */ { struct regstat current; // Current register allocations/status int cc=0; current.dirty=0; current.u=unneeded_reg[0]; clear_all_regs(current.regmap); alloc_reg(¤t,0,CCREG); dirty_reg(¤t,CCREG); current.isdoingcp=0; current.wasdoingcp=0; for(i=0;i=0) current.u|=1LL<=0) current.u|=1LL<=0) current.u&=~(1LL<=0) current.u&=~(1LL<=0) current.u&=~(1LL<=0) current.u&=~(1LL<=0) current.u&=~(1LL<=0) current.u&=~(1LL<=0) current.u&=~(1LL<=0) current.u&=~(1LL<=0) current.u&=~(1LL<=0) current.u&=~(1LL<=0) { if(r!=regmap_pre[i][hr]) { regs[i].regmap_entry[hr]=-1; } else { if((current.u>>r)&1) { regs[i].regmap_entry[hr]=-1; regs[i].regmap[hr]=-1; //Don't clear regs in the delay slot as the branch might need them //current.regmap[hr]=-1; }else regs[i].regmap_entry[hr]=r; } } else { // First instruction expects CCREG to be allocated if(i==0&&hr==HOST_CCREG) regs[i].regmap_entry[hr]=CCREG; else regs[i].regmap_entry[hr]=-1; } } } else { // Not delay slot switch(itype[i]) { case UJUMP: //current.isdoingcp=0; // DEBUG //current.wasdoingcp=0; // DEBUG //regs[i].wasdoingcp=0; // DEBUG clear_const(¤t,rt1[i]); alloc_cc(¤t,i); dirty_reg(¤t,CCREG); if (rt1[i]==PR) { alloc_reg(¤t,i,PR); dirty_reg(¤t,PR); assert(rs1[i+1]!=PR&&rs2[i+1]!=PR); #ifdef REG_PREFETCH alloc_reg(¤t,i,PTEMP); #endif } ooo[i]=1; delayslot_alloc(¤t,i+1); //current.isdoingcp=0; // DEBUG ds=1; //printf("i=%d, isdoingcp=%x\n",i,current.isdoingcp); break; case RJUMP: //current.isdoingcp=0; //current.wasdoingcp=0; //regs[i].wasdoingcp=0; clear_const(¤t,rs1[i]); clear_const(¤t,rt1[i]); alloc_cc(¤t,i); dirty_reg(¤t,CCREG); if(opcode[i]==0&&opcode2[i]==11&&opcode3[i]==2) { // RTE alloc_reg(¤t,i,15); // Stack reg dirty_reg(¤t,15); alloc_reg(¤t,i,SR); // SR will be loaded from stack dirty_reg(¤t,SR); assert(rt1[i+1]!=15&&rt2[i+1]!=15); assert(rt1[i+1]!=SR&&rt2[i+1]!=SR); assert(rt1[i+1]!=TBIT&&rt2[i+1]!=TBIT); delayslot_alloc(¤t,i+1); } else if(rs1[i]!=rt1[i+1]&&rs1[i]!=rt2[i+1]) { alloc_reg(¤t,i,rs1[i]); if (rt1[i]==PR) { alloc_reg(¤t,i,rt1[i]); dirty_reg(¤t,rt1[i]); assert(rs1[i+1]!=PR&&rs2[i+1]!=PR); if(rs1[i+1]==PR||rs2[i+1]==PR) {printf("OOPS\n");} #ifdef REG_PREFETCH alloc_reg(¤t,i,PTEMP); #endif } #ifdef USE_MINI_HT if(rs1[i]==PR) { // BSRF/JSR alloc_reg(¤t,i,RHASH); #ifndef HOST_IMM_ADDR32 alloc_reg(¤t,i,RHTBL); #endif } #endif // PC-relative branch needs a temporary register to add PC if(opcode[i]==0&&opcode2[i]==3) alloc_reg(¤t,i,RTEMP); delayslot_alloc(¤t,i+1); } else { // The delay slot overwrites our source register, // allocate a temporary register to hold the old value. current.isdoingcp=0; current.wasdoingcp=0; regs[i].wasdoingcp=0; delayslot_alloc(¤t,i+1); current.isdoingcp=0; alloc_reg(¤t,i,RTEMP); } //current.isdoingcp=0; // DEBUG ooo[i]=1; ds=1; break; case CJUMP: //current.isdoingcp=0; //current.wasdoingcp=0; //regs[i].wasdoingcp=0; clear_const(¤t,rs1[i]); clear_const(¤t,rs2[i]); alloc_cc(¤t,i); dirty_reg(¤t,CCREG); alloc_reg(¤t,i,SR); // No delay slot, don't do constant propagation current.isdoingcp=0; current.wasdoingcp=0; regs[i].wasdoingcp=0; //ds=1; // BT/BF don't have delay slots break; case SJUMP: //current.isdoingcp=0; //current.wasdoingcp=0; //regs[i].wasdoingcp=0; clear_const(¤t,rs1[i]); clear_const(¤t,rt1[i]); alloc_cc(¤t,i); dirty_reg(¤t,CCREG); alloc_reg(¤t,i,SR); if(rt1[i+1]==TBIT||rt2[i+1]==TBIT||rt1[i+1]==SR||rt2[i+1]==SR) { // The delay slot overwrites the branch condition. // Allocate the branch condition registers instead. current.isdoingcp=0; current.wasdoingcp=0; regs[i].wasdoingcp=0; } else if(itype[i+1]==COMPLEX) { // The MAC and DIV instructions make function calls which // do not save registers. Do the branch and update the // cycle count first. current.isdoingcp=0; current.wasdoingcp=0; regs[i].wasdoingcp=0; } else { ooo[i]=1; delayslot_alloc(¤t,i+1); } ds=1; //current.isdoingcp=0; break; case IMM8: imm8_alloc(¤t,i); break; case LOAD: load_alloc(¤t,i); break; case STORE: store_alloc(¤t,i); break; case RMW: rmw_alloc(¤t,i); break; case PCREL: pcrel_alloc(¤t,i); break; case ALU: alu_alloc(¤t,i); break; case MULTDIV: multdiv_alloc(¤t,i); break; case SHIFTIMM: shiftimm_alloc(¤t,i); break; case MOV: mov_alloc(¤t,i); break; case EXT: ext_alloc(¤t,i); break; case FLAGS: flags_alloc(¤t,i); break; case COMPLEX: complex_alloc(¤t,i); break; case SYSTEM: system_alloc(¤t,i); break; } //printf("xxx: eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d\n",current.regmap[0],current.regmap[1],current.regmap[2],current.regmap[3],current.regmap[5],current.regmap[6],current.regmap[7]); // Create entry (branch target) regmap for(hr=0;hr=0) { if(r!=regmap_pre[i][hr]) { // TODO: delay slot (?) or=get_reg(regmap_pre[i],r); // Get old mapping for this register if(or<0||(r&63)>=TEMPREG){ regs[i].regmap_entry[hr]=-1; } else { // Just move it to a different register regs[i].regmap_entry[hr]=r; // If it was dirty before, it's still dirty if((regs[i].wasdirty>>or)&1) dirty_reg(¤t,r&63); } } else { if(r<64){ if((current.u>>r)&1) { regs[i].regmap_entry[hr]=-1; //regs[i].regmap[hr]=-1; current.regmap[hr]=-1; }else regs[i].regmap_entry[hr]=r; } } } else { // Branches expect CCREG to be allocated at the target if(regmap_pre[i][hr]==CCREG) regs[i].regmap_entry[hr]=CCREG; else regs[i].regmap_entry[hr]=-1; } } memcpy(regs[i].regmap,current.regmap,sizeof(current.regmap)); } /* Branch post-alloc */ if(i>0) { current.wasdirty=current.dirty; switch(itype[i-1]) { case UJUMP: memcpy(&branch_regs[i-1],¤t,sizeof(current)); branch_regs[i-1].isdoingcp=0; branch_regs[i-1].wasdoingcp=0; branch_regs[i-1].isconst=0; branch_regs[i-1].u=branch_unneeded_reg[i-1]&~((1LL<=0;j--) { if(ba[j]==start+i*2+2) { if(itype[j]==CJUMP) { memcpy(current.regmap,regs[j].regmap,sizeof(current.regmap)); current.dirty=regs[j].dirty; }else{ memcpy(current.regmap,branch_regs[j].regmap,sizeof(current.regmap)); current.dirty=branch_regs[j].dirty; } break; } } while(j>=0) { if(ba[j]==start+i*2+2) { for(hr=0;hr0&&(itype[i-1]==RJUMP||itype[i-1]==UJUMP)) { cc=0; } else if(itype[i]==CJUMP||itype[i]==SJUMP) { cc=1; } else { cc+=cycles[i]; } if(!is_ds[i]) { regs[i].dirty=current.dirty; regs[i].isdoingcp=current.isdoingcp; memcpy(cpmap[i],current.cpmap,sizeof(current.cpmap)); } for(hr=0;hr=0) { if(regmap_pre[i][hr]!=regs[i].regmap[hr]) { regs[i].wasdoingcp&=~(1<=0;i--) { int hr; if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP) { if(ba[i]=(start+slen*2)) { // Branch out of this block, don't need anything nr=0; } else { // Internal branch // Need whatever matches the target int t=(ba[i]-start)>>1; nr=0; for(hr=0;hr=0) { if(regs[i].regmap_entry[hr]==regs[t].regmap_entry[hr]) nr|=1<=0&&get_reg(regs[i+2].regmap_entry,regmap_pre[i+2][hr])<0) nr&=~(1<=0) if(!((nr>>hr)&1)) printf("%x-bogus(%d=%d)\n",start+i*2,hr,regmap_entry[i+2][hr]); } } } else if(itype[i]==CJUMP) { if(i=0&&get_reg(regs[i+1].regmap_entry,regmap_pre[i+1][hr])<0) nr&=~(1<=0) if(!((nr>>hr)&1)) printf("%x-bogus(%d=%d)\n",start+i*2,hr,regmap_entry[i+2][hr]); } } } // Don't need stuff which is overwritten for(hr=0;hr=0&&rt1[i+1]==(regs[i].regmap[hr]&63)) nr&=~(1<=0&&rt2[i+1]==(regs[i].regmap[hr]&63)) nr&=~(1<=0&&rs1[i+1]==regmap_pre[i][hr]) nr|=1<=0&&rs2[i+1]==regmap_pre[i][hr]) nr|=1<=0&&rs3[i+1]==regmap_pre[i][hr]) nr|=1<=0&&rs1[i+1]==regs[i].regmap_entry[hr]) nr|=1<=0&&rs2[i+1]==regs[i].regmap_entry[hr]) nr|=1<=0&&rs3[i+1]==regs[i].regmap_entry[hr]) nr|=1<>dep1[i+1])&1)) { // if(dep1[i+1]==(regmap_pre[i][hr]&63)) nr|=1<>dep2[i+1])&1)) { // if(dep1[i+1]==(regs[i].regmap_entry[hr]&63)) nr|=1<=0&&get_reg(regs[i+1].regmap_entry,regmap_pre[i+1][hr])<0) nr&=~(1<=0&&rt1[i]==(regs[i].regmap[hr]&63)) nr&=~(1<=0&&rt2[i]==(regs[i].regmap[hr]&63)) nr&=~(1<=0&&rs1[i]==regmap_pre[i][hr]) nr|=1<=0&&rs2[i]==regmap_pre[i][hr]) nr|=1<=0&&rs3[i]==regmap_pre[i][hr]) nr|=1<=0&&rs1[i]==regs[i].regmap_entry[hr]) nr|=1<=0&&rs2[i]==regs[i].regmap_entry[hr]) nr|=1<=0&&rs3[i]==regs[i].regmap_entry[hr]) nr|=1<>dep1[i])&1)) { // if(dep1[i]==(regmap_pre[i][hr]&63)) nr|=1<>dep2[i])&1)) { // if(dep2[i]==(regmap_pre[i][hr]&63)) nr|=1<0&&!bt[i]&&((regs[i].wasdirty>>hr)&1)) { if(regmap_pre[i][hr]>=0&&!((unneeded_reg[i]>>regmap_pre[i][hr])&1)) { if(rt1[i-1]==(regmap_pre[i][hr]&63)) nr|=1<=0&&!((unneeded_reg[i]>>regs[i].regmap_entry[hr])&1)) { if(rt1[i-1]==(regs[i].regmap_entry[hr]&63)) nr|=1<>hr)&1)) { if(regs[i].regmap_entry[hr]!=CCREG) regs[i].regmap_entry[hr]=-1; if((regs[i].regmap[hr]&63)!=rs1[i] && (regs[i].regmap[hr]&63)!=rs2[i] && (regs[i].regmap[hr]&63)!=rt1[i] && (regs[i].regmap[hr]&63)!=rt2[i] && (regs[i].regmap[hr]&63)!=PTEMP && (regs[i].regmap[hr]&63)!=CCREG) { if(itype[i]==CJUMP) { regs[i].regmap[hr]=-1; regs[i].isdoingcp&=~(1<=0||get_reg(branch_regs[i].regmap,rt1[i+1]|64)>=0) //{ // d1=dep1[i+1]; // d2=dep2[i+1]; //} if(itype[i+1]==LOAD || itype[i+1]==STORE || itype[i+1]==RMW || itype[i+1]==PCREL || itype[i+1]==SYSTEM || source[i]==0x002B /* RTE */ ) temp1=MOREG; if(itype[i+1]==COMPLEX) { temp1=MACH; temp2=MACL; } if(regs[i].regmap[hr]!=rs1[i] && regs[i].regmap[hr]!=rs2[i] && regs[i].regmap[hr]!=rs3[i] && regs[i].regmap[hr]!=rt1[i] && regs[i].regmap[hr]!=rt2[i] && regs[i].regmap[hr]!=rs1[i+1] && regs[i].regmap[hr]!=rs2[i+1] && regs[i].regmap[hr]!=rs3[i+1] && regs[i].regmap[hr]!=rt1[i+1] && regs[i].regmap[hr]!=rt2[i+1] && regs[i].regmap[hr]!=RHASH && regs[i].regmap[hr]!=RHTBL && regs[i].regmap[hr]!=RTEMP && regs[i].regmap[hr]!=PTEMP && regs[i].regmap[hr]!=CCREG && regs[i].regmap[hr]!=temp1 && regs[i].regmap[hr]!=temp2 ) { regs[i].regmap[hr]=-1; regs[i].isdoingcp&=~(1<0) { int temp1=-1,temp2=-1; //if(get_reg(regs[i].regmap,rt1[i]|64)>=0) //{ // d1=dep1[i]; // d2=dep2[i]; //} if(itype[i]==LOAD || itype[i]==STORE || itype[i]==RMW || itype[i]==PCREL || itype[i]==SYSTEM ) temp1=MOREG; if(itype[i]==COMPLEX) { temp1=MACH; temp2=MACL; } else if(itype[i]==SYSTEM) { temp2=CCREG; } if(regs[i].regmap[hr]!=rt1[i] && regs[i].regmap[hr]!=rt2[i] && regs[i].regmap[hr]!=rs1[i] && regs[i].regmap[hr]!=rs2[i] && regs[i].regmap[hr]!=rs3[i] && regs[i].regmap[hr]!=temp1 && regs[i].regmap[hr]!=temp2 && regs[i].regmap[hr]!=CCREG) { if(i=start && ba[i]<(start+i*2)) if(itype[i]==CJUMP||itype[i+1]==NOP||itype[i+1]==MOV||itype[i+1]==ALU ||itype[i+1]==SHIFTIMM||itype[i+1]==IMM8||itype[i+1]==LOAD ||itype[i+1]==STORE||itype[i+1]==RMW||itype[i+1]==PCREL||itype[i+1]==EXT||itype[i+1]==FLAGS) { // Track register allocation int t=(ba[i]-start)>>1; if(t>0&&(itype[t-1]!=UJUMP&&itype[t-1]!=RJUMP&&itype[t-1]!=SJUMP)) // loop_preload can't handle jumps into delay slots if(t<2||(itype[t-2]!=UJUMP&&itype[t-2]!=RJUMP)||rt1[t-2]!=PR) // call/ret assumes no registers allocated for(hr=0;hr=0) { if(f_regmap[hr]!=regs[i].regmap[hr]) { // dealloc old register int n; for(n=0;n=0) { if(f_regmap[hr]!=branch_regs[i].regmap[hr]) { // dealloc old register int n; for(n=0;nclean transition //if(t>0) if(get_reg(regmap_pre[t],f_regmap[hr])>=0) if((regs[t].wasdirty>>get_reg(regmap_pre[t],f_regmap[hr]))&1) f_regmap[hr]=-1; // This check isn't required, but it's a good idea. We can't hoist // the load if the register was already allocated, so there's no // point wasting time analyzing most of these cases. It only // "succeeds" when the mapping was different and the load can be // replaced with a mov, which is of negligible benefit. So such // cases are skipped below. if(f_regmap[hr]>=0) { if(regs[t].regmap[hr]==f_regmap[hr]||(regs[t].regmap_entry[hr]<0&&get_reg(regmap_pre[t],f_regmap[hr])<0)) { int r=f_regmap[hr]; for(j=t;j<=i;j++) { //printf("Test %x -> %x, %x %d/%d\n",start+i*2,ba[i],start+j*2,hr,r); if(r>r)&1)) break; if(regs[j].regmap[hr]==f_regmap[hr]&&(f_regmap[hr]&63) %x, %x %d/%d\n",start+i*2,ba[i],start+j*2,hr,r); int k; if(regs[i].regmap[hr]==-1&&branch_regs[i].regmap[hr]==-1) { if(get_reg(regs[i+2].regmap,f_regmap[hr])>=0) break; k=i; while(k>1&®s[k-1].regmap[hr]==-1) { if(count_free_regs(regs[k-1].regmap)<=minimum_free_regs[k-1]) { //printf("no free regs for store %x\n",start+(k-1)*4); break; } if(get_reg(regs[k-1].regmap,f_regmap[hr])>=0) { //printf("no-match due to different register\n"); break; } if(itype[k-2]==UJUMP||itype[k-2]==RJUMP||itype[k-2]==CJUMP||itype[k-2]==SJUMP) { //printf("no-match due to branch\n"); break; } // call/ret fast path assumes no registers allocated if(k>2&&(itype[k-3]==UJUMP||itype[k-3]==RJUMP)&&rt1[k-3]==PR) { break; } k--; } if(regs[k-1].regmap[hr]==f_regmap[hr]&®map_pre[k][hr]==f_regmap[hr]) { //printf("Extend r%d, %x ->\n",hr,start+k*4); while(k\n",hr,start+k*4); break; } assert(regs[i-1].regmap[hr]==f_regmap[hr]); if(regs[i-1].regmap[hr]==f_regmap[hr]&®map_pre[i][hr]==f_regmap[hr]) { //printf("OK fill %x (r%d)\n",start+i*4,hr); regs[i].regmap_entry[hr]=f_regmap[hr]; regs[i].regmap[hr]=f_regmap[hr]; regs[i].wasdirty&=~(1<=0) break; if(get_reg(regs[j].regmap,f_regmap[hr])>=0) { //printf("no-match due to different register\n"); break; } if(itype[j]==UJUMP||itype[j]==RJUMP) { // Stop on unconditional branch break; } if(itype[j]==SJUMP) { if(ooo[j]) { if(count_free_regs(regs[j].regmap)<=minimum_free_regs[j+1]) break; }else{ if(count_free_regs(branch_regs[j].regmap)<=minimum_free_regs[j+1]) break; } if(get_reg(branch_regs[j].regmap,f_regmap[hr])>=0) { //printf("no-match due to different register (branch)\n"); break; } } if(count_free_regs(regs[j].regmap)<=minimum_free_regs[j]) { //printf("No free regs for store %x\n",start+j*4); break; } } } } } } }else{ // Non branch or undetermined branch target for(hr=0;hr=0) { if(f_regmap[hr]!=regs[i].regmap[hr]) { // dealloc old register int n; for(n=0;n %x\n",start+k*4,start+j*4); while(ki&&f_regmap[HOST_CCREG]==CCREG) { //printf("Extend backwards\n"); int k; k=i; while(regs[k-1].regmap[HOST_CCREG]==-1) { if(count_free_regs(regs[k-1].regmap)<=minimum_free_regs[k-1]) { //printf("no free regs for store %x\n",start+(k-1)*4); break; } k--; } if(regs[k-1].regmap[HOST_CCREG]==CCREG) { //printf("Extend CC, %x ->\n",start+k*4); while(k<=i) { regs[k].regmap_entry[HOST_CCREG]=CCREG; regs[k].regmap[HOST_CCREG]=CCREG; regmap_pre[k+1][HOST_CCREG]=CCREG; regs[k+1].wasdirty|=1<\n",start+k*4); } } } // Don't try to add registers to complex instructions like MAC, division, etc. if(itype[i]!=STORE&&itype[i]!=RMW&&itype[i]!=PCREL&& itype[i]!=NOP&&itype[i]!=MOV&&itype[i]!=ALU&&itype[i]!=SHIFTIMM&& itype[i]!=IMM8&&itype[i]!=LOAD&&itype[i]!=EXT&&itype[i]!=FLAGS) { memcpy(f_regmap,regs[i].regmap,sizeof(f_regmap)); } } } // Cache memory_map pointer if a register is available #ifndef HOST_IMM_ADDR32 { int earliest_available[HOST_REGS]; int loop_start[HOST_REGS]; int score[HOST_REGS]; int end[HOST_REGS]; int reg=MMREG; // Init for(hr=0;hr=0) { score[hr]=0;earliest_available[hr]=i+1; loop_start[hr]=MAXBLOCK; } if(itype[i]==UJUMP||itype[i]==RJUMP||itype[i]==SJUMP) { if(branch_regs[i].regmap[hr]>=0) { score[hr]=0;earliest_available[hr]=i+2; loop_start[hr]=MAXBLOCK; } } } // No register allocations after unconditional jumps if(itype[i]==UJUMP||itype[i]==RJUMP) { for(hr=0;hr=0) break; if(itype[j]==UJUMP||itype[j]==RJUMP||itype[j]==SJUMP) { if(branch_regs[j].regmap[hr]>=0) break; if(ooo[j]) { if(count_free_regs(regs[j].regmap)<=minimum_free_regs[j+1]) break; }else{ if(count_free_regs(branch_regs[j].regmap)<=minimum_free_regs[j+1]) break; } } else if(count_free_regs(regs[j].regmap)<=minimum_free_regs[j]) break; if(itype[j]==UJUMP||itype[j]==RJUMP||itype[j]==CJUMP||itype[j]==SJUMP) { int t=(ba[j]-start)>>1; if(t=earliest_available[hr]) { if(t==1||(t>1&&itype[t-2]!=UJUMP&&itype[t-2]!=RJUMP)||(t>1&&rt1[t-2]!=PR)) { // call/ret assumes no registers allocated // Score a point for hoisting loop invariant if(tscore[maxscore]) { maxscore=hr; //printf("highest score: %d %d (%x->%x)\n",score[hr],hr,start+i*2,start+end[hr]*2); } } } if(score[maxscore]>1) { if(i=0) {printf("oops: %x %x was %d=%d\n",loop_start[maxscore]*2+start,j*2+start,maxscore,regs[j].regmap[maxscore]);} assert(regs[j].regmap[maxscore]<0); if(j>loop_start[maxscore]) regs[j].regmap_entry[maxscore]=reg; regs[j].regmap[maxscore]=reg; regs[j].dirty&=~(1<>1; if(t==loop_start[maxscore]) { if(t==1||(t>1&&itype[t-2]!=UJUMP&&itype[t-2]!=RJUMP)||(t>1&&rt1[t-2]!=PR)) // call/ret assumes no registers allocated regs[t].regmap_entry[maxscore]=reg; } } else { if(j<1||(itype[j-1]!=RJUMP&&itype[j-1]!=UJUMP&&itype[j-1]!=SJUMP)) { regmap_pre[j+1][maxscore]=reg; regs[j+1].wasdirty&=~(1<=0) { if((hr=get_reg(regs[i+1].regmap,rs1[i+1]==TBIT?SR:rs1[i+1]))>=0) { if(regs[i].regmap[hr]<0&®s[i+1].regmap_entry[hr]<0 &&count_free_regs(regs[i].regmap)>minimum_free_regs[i]) { regs[i].regmap[hr]=regs[i+1].regmap[hr]; regmap_pre[i+1][hr]=regs[i+1].regmap[hr]; regs[i+1].regmap_entry[hr]=regs[i+1].regmap[hr]; regs[i].isdoingcp&=~(1<=0) { if((hr=get_reg(regs[i+1].regmap,rs2[i+1]==TBIT?SR:rs2[i+1]))>=0) { if(regs[i].regmap[hr]<0&®s[i+1].regmap_entry[hr]<0 &&count_free_regs(regs[i].regmap)>minimum_free_regs[i]) { regs[i].regmap[hr]=regs[i+1].regmap[hr]; regmap_pre[i+1][hr]=regs[i+1].regmap[hr]; regs[i+1].regmap_entry[hr]=regs[i+1].regmap[hr]; regs[i].isdoingcp&=~(1<=0) { if((hr=get_reg(regs[i+1].regmap,rs3[i+1]==TBIT?SR:rs3[i+1]))>=0) { if(regs[i].regmap[hr]<0&®s[i+1].regmap_entry[hr]<0 &&count_free_regs(regs[i].regmap)>minimum_free_regs[i]) { regs[i].regmap[hr]=regs[i+1].regmap[hr]; regmap_pre[i+1][hr]=regs[i+1].regmap[hr]; regs[i+1].regmap_entry[hr]=regs[i+1].regmap[hr]; regs[i].isdoingcp&=~(1<=0) { if(regs[i].regmap[hr]<0&®s[i+1].regmap_entry[hr]<0 &&count_free_regs(regs[i].regmap)>minimum_free_regs[i]) { regs[i].regmap[hr]=regs[i+1].regmap[hr]; regmap_pre[i+1][hr]=regs[i+1].regmap[hr]; regs[i+1].regmap_entry[hr]=regs[i+1].regmap[hr]; regs[i].isdoingcp&=~(1<=0&&get_reg(regs[i+1].regmap,rs1[i+1])<0) { if((hr=get_reg(regs[i+1].regmap,rt1[i+1]))>=0) { if(regs[i].regmap[hr]<0&®s[i+1].regmap_entry[hr]<0 &&count_free_regs(regs[i].regmap)>minimum_free_regs[i]) { regs[i].regmap[hr]=rs1[i+1]; regmap_pre[i+1][hr]=rs1[i+1]; regs[i+1].regmap_entry[hr]=rs1[i+1]; regs[i].isdoingcp&=~(1<=0&&get_reg(regs[i+1].regmap,rs1[i+1])<0) { if((hr=get_reg(regs[i+1].regmap,rt1[i+1]))>=0) { if(regs[i].regmap[hr]<0&®s[i+1].regmap_entry[hr]<0 &&count_free_regs(regs[i].regmap)>minimum_free_regs[i]) { regs[i].regmap[hr]=rs1[i+1]; regmap_pre[i+1][hr]=rs1[i+1]; regs[i+1].regmap_entry[hr]=rs1[i+1]; regs[i].isdoingcp&=~(1<=0) { int sr=get_reg(regs[i+1].regmap,rs1[i+1]); if(sr>=0&&((regs[i+1].wasdoingcp>>sr)&1) &&count_free_regs(regs[i].regmap)>minimum_free_regs[i]) { int nr; if(regs[i].regmap[hr]<0&®s[i+1].regmap_entry[hr]<0) { regs[i].regmap[hr]=MGEN1+((i+1)&1); regmap_pre[i+1][hr]=MGEN1+((i+1)&1); regs[i+1].regmap_entry[hr]=MGEN1+((i+1)&1); regs[i].isdoingcp&=~(1<=0) { // move it to another register regs[i+1].regmap[hr]=-1; regmap_pre[i+2][hr]=-1; regs[i+1].regmap[nr]=MOREG; regmap_pre[i+2][nr]=MOREG; regs[i].regmap[nr]=MGEN1+((i+1)&1); regmap_pre[i+1][nr]=MGEN1+((i+1)&1); regs[i+1].regmap_entry[nr]=MGEN1+((i+1)&1); regs[i].isdoingcp&=~(1<=0); if(regs[i].regmap[hr]<0&®s[i+1].regmap_entry[hr]<0 &&count_free_regs(regs[i].regmap)>minimum_free_regs[i]) { regs[i].regmap[hr]=rs1[i+1]; regmap_pre[i+1][hr]=rs1[i+1]; regs[i+1].regmap_entry[hr]=rs1[i+1]; regs[i].isdoingcp&=~(1<=0&®s[i].regmap[hr]<0 &&count_free_regs(regs[i].regmap)>minimum_free_regs[i]) { int rs=get_reg(regs[i+1].regmap,rs1[i+1]); if(rs>=0&&((regs[i+1].wasdoingcp>>rs)&1)) { regs[i].regmap[hr]=AGEN1+((i+1)&1); regmap_pre[i+1][hr]=AGEN1+((i+1)&1); regs[i+1].regmap_entry[hr]=AGEN1+((i+1)&1); regs[i].isdoingcp&=~(1<=0;i--) { if(itype[i]==CJUMP||itype[i]==SJUMP) { // Avoid unnecessary constant propagation int hr; u32 sregs; for(hr=0;hr=0) { if(itype[i]==SJUMP) { if(regs[i].regmap_entry[hr]==rs1[i+1]) continue; if(regs[i].regmap_entry[hr]==rs2[i+1]) continue; if(regs[i].regmap_entry[hr]==rs3[i+1]) continue; if(regs[i].regmap_entry[hr]==rt1[i+1]) continue; if(regs[i].regmap_entry[hr]==rt2[i+1]) continue; } if(i>0) { if(regs[i].regmap_entry[hr]==rs1[i-1]) continue; if(regs[i].regmap_entry[hr]==rs2[i-1]) continue; if(regs[i].regmap_entry[hr]==rs3[i-1]) continue; if(regs[i].regmap_entry[hr]==rt1[i-1]) continue; if(regs[i].regmap_entry[hr]==rt2[i-1]) continue; } //if(regs[i].wasdoingcp&(1<=0) sregs|=1<=0) sregs|=1<=0) sregs|=1<=0) sregs|=1<>r)&1) { if(r==SR) printf(" SR(16)"); else if(r==GBR) printf(" GBR(17)"); else if(r==VBR) printf(" VBR(18)"); else if(r==MACH) printf(" MACH(19)"); else if(r==MACL) printf(" MACL(20)"); else if(r==PR) printf(" PR(21)"); else if(r==TBIT) printf(" T(22)"); else printf(" r%d",r); } } printf("\n"); #if defined(__i386__) || defined(__x86_64__) printf("pre: eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d\n",regmap_pre[i][0],regmap_pre[i][1],regmap_pre[i][2],regmap_pre[i][3],regmap_pre[i][5],regmap_pre[i][6],regmap_pre[i][7]); #endif #ifdef __arm__ printf("pre: r0=%d r1=%d r2=%d r3=%d r4=%d r5=%d r6=%d r7=%d r8=%d r9=%d r10=%d r12=%d\n",regmap_pre[i][0],regmap_pre[i][1],regmap_pre[i][2],regmap_pre[i][3],regmap_pre[i][4],regmap_pre[i][5],regmap_pre[i][6],regmap_pre[i][7],regmap_pre[i][8],regmap_pre[i][9],regmap_pre[i][10],regmap_pre[i][12]); #endif printf("needs: "); if(needed_reg[i]&1) printf("eax "); if((needed_reg[i]>>1)&1) printf("ecx "); if((needed_reg[i]>>2)&1) printf("edx "); if((needed_reg[i]>>3)&1) printf("ebx "); if((needed_reg[i]>>5)&1) printf("ebp "); if((needed_reg[i]>>6)&1) printf("esi "); if((needed_reg[i]>>7)&1) printf("edi "); printf("\n"); #if defined(__i386__) || defined(__x86_64__) printf("entry: eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d\n",regs[i].regmap_entry[0],regs[i].regmap_entry[1],regs[i].regmap_entry[2],regs[i].regmap_entry[3],regs[i].regmap_entry[5],regs[i].regmap_entry[6],regs[i].regmap_entry[7]); printf("dirty: "); if(regs[i].wasdirty&1) printf("eax "); if((regs[i].wasdirty>>1)&1) printf("ecx "); if((regs[i].wasdirty>>2)&1) printf("edx "); if((regs[i].wasdirty>>3)&1) printf("ebx "); if((regs[i].wasdirty>>5)&1) printf("ebp "); if((regs[i].wasdirty>>6)&1) printf("esi "); if((regs[i].wasdirty>>7)&1) printf("edi "); #endif #ifdef __arm__ printf("entry: r0=%d r1=%d r2=%d r3=%d r4=%d r5=%d r6=%d r7=%d r8=%d r9=%d r10=%d r12=%d\n",regs[i].regmap_entry[0],regs[i].regmap_entry[1],regs[i].regmap_entry[2],regs[i].regmap_entry[3],regs[i].regmap_entry[4],regs[i].regmap_entry[5],regs[i].regmap_entry[6],regs[i].regmap_entry[7],regs[i].regmap_entry[8],regs[i].regmap_entry[9],regs[i].regmap_entry[10],regs[i].regmap_entry[12]); printf("dirty: "); if(regs[i].wasdirty&1) printf("r0 "); if((regs[i].wasdirty>>1)&1) printf("r1 "); if((regs[i].wasdirty>>2)&1) printf("r2 "); if((regs[i].wasdirty>>3)&1) printf("r3 "); if((regs[i].wasdirty>>4)&1) printf("r4 "); if((regs[i].wasdirty>>5)&1) printf("r5 "); if((regs[i].wasdirty>>6)&1) printf("r6 "); if((regs[i].wasdirty>>7)&1) printf("r7 "); if((regs[i].wasdirty>>8)&1) printf("r8 "); if((regs[i].wasdirty>>9)&1) printf("r9 "); if((regs[i].wasdirty>>10)&1) printf("r10 "); if((regs[i].wasdirty>>12)&1) printf("r12 "); #endif printf("ccadj=%d",ccadj[i]); printf("\n"); disassemble_inst(i); //printf ("ccadj[%d] = %d\n",i,ccadj[i]); #if defined(__i386__) || defined(__x86_64__) printf("eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d dirty: ",regs[i].regmap[0],regs[i].regmap[1],regs[i].regmap[2],regs[i].regmap[3],regs[i].regmap[5],regs[i].regmap[6],regs[i].regmap[7]); if(regs[i].dirty&1) printf("eax "); if((regs[i].dirty>>1)&1) printf("ecx "); if((regs[i].dirty>>2)&1) printf("edx "); if((regs[i].dirty>>3)&1) printf("ebx "); if((regs[i].dirty>>5)&1) printf("ebp "); if((regs[i].dirty>>6)&1) printf("esi "); if((regs[i].dirty>>7)&1) printf("edi "); #endif #ifdef __arm__ printf("r0=%d r1=%d r2=%d r3=%d r4=%d r5=%d r6=%d r7=%d r8=%d r9=%d r10=%d r12=%d dirty: ",regs[i].regmap[0],regs[i].regmap[1],regs[i].regmap[2],regs[i].regmap[3],regs[i].regmap[4],regs[i].regmap[5],regs[i].regmap[6],regs[i].regmap[7],regs[i].regmap[8],regs[i].regmap[9],regs[i].regmap[10],regs[i].regmap[12]); if(regs[i].dirty&1) printf("r0 "); if((regs[i].dirty>>1)&1) printf("r1 "); if((regs[i].dirty>>2)&1) printf("r2 "); if((regs[i].dirty>>3)&1) printf("r3 "); if((regs[i].dirty>>4)&1) printf("r4 "); if((regs[i].dirty>>5)&1) printf("r5 "); if((regs[i].dirty>>6)&1) printf("r6 "); if((regs[i].dirty>>7)&1) printf("r7 "); if((regs[i].dirty>>8)&1) printf("r8 "); if((regs[i].dirty>>9)&1) printf("r9 "); if((regs[i].dirty>>10)&1) printf("r10 "); if((regs[i].dirty>>12)&1) printf("r12 "); #endif printf("\n"); if(regs[i].isdoingcp) { printf("constants: "); #if defined(__i386__) || defined(__x86_64__) if(regs[i].isdoingcp&1) printf("eax=%x ",(int)cpmap[i][0]); if((regs[i].isdoingcp>>1)&1) printf("ecx=%x ",(int)cpmap[i][1]); if((regs[i].isdoingcp>>2)&1) printf("edx=%x ",(int)cpmap[i][2]); if((regs[i].isdoingcp>>3)&1) printf("ebx=%x ",(int)cpmap[i][3]); if((regs[i].isdoingcp>>5)&1) printf("ebp=%x ",(int)cpmap[i][5]); if((regs[i].isdoingcp>>6)&1) printf("esi=%x ",(int)cpmap[i][6]); if((regs[i].isdoingcp>>7)&1) printf("edi=%x ",(int)cpmap[i][7]); #endif #ifdef __arm__ if(regs[i].isdoingcp&1) printf("r0=%x ",(int)cpmap[i][0]); if((regs[i].isdoingcp>>1)&1) printf("r1=%x ",(int)cpmap[i][1]); if((regs[i].isdoingcp>>2)&1) printf("r2=%x ",(int)cpmap[i][2]); if((regs[i].isdoingcp>>3)&1) printf("r3=%x ",(int)cpmap[i][3]); if((regs[i].isdoingcp>>4)&1) printf("r4=%x ",(int)cpmap[i][4]); if((regs[i].isdoingcp>>5)&1) printf("r5=%x ",(int)cpmap[i][5]); if((regs[i].isdoingcp>>6)&1) printf("r6=%x ",(int)cpmap[i][6]); if((regs[i].isdoingcp>>7)&1) printf("r7=%x ",(int)cpmap[i][7]); if((regs[i].isdoingcp>>8)&1) printf("r8=%x ",(int)cpmap[i][8]); if((regs[i].isdoingcp>>9)&1) printf("r9=%x ",(int)cpmap[i][9]); if((regs[i].isdoingcp>>10)&1) printf("r10=%x ",(int)cpmap[i][10]); if((regs[i].isdoingcp>>12)&1) printf("r12=%x ",(int)cpmap[i][12]); #endif printf("\n"); } if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==CJUMP||itype[i]==SJUMP) { #if defined(__i386__) || defined(__x86_64__) printf("branch(%d): eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d dirty: ",i,branch_regs[i].regmap[0],branch_regs[i].regmap[1],branch_regs[i].regmap[2],branch_regs[i].regmap[3],branch_regs[i].regmap[5],branch_regs[i].regmap[6],branch_regs[i].regmap[7]); if(branch_regs[i].dirty&1) printf("eax "); if((branch_regs[i].dirty>>1)&1) printf("ecx "); if((branch_regs[i].dirty>>2)&1) printf("edx "); if((branch_regs[i].dirty>>3)&1) printf("ebx "); if((branch_regs[i].dirty>>5)&1) printf("ebp "); if((branch_regs[i].dirty>>6)&1) printf("esi "); if((branch_regs[i].dirty>>7)&1) printf("edi "); #endif #ifdef __arm__ printf("branch(%d): r0=%d r1=%d r2=%d r3=%d r4=%d r5=%d r6=%d r7=%d r8=%d r9=%d r10=%d r12=%d dirty: ",i,branch_regs[i].regmap[0],branch_regs[i].regmap[1],branch_regs[i].regmap[2],branch_regs[i].regmap[3],branch_regs[i].regmap[4],branch_regs[i].regmap[5],branch_regs[i].regmap[6],branch_regs[i].regmap[7],branch_regs[i].regmap[8],branch_regs[i].regmap[9],branch_regs[i].regmap[10],branch_regs[i].regmap[12]); if(branch_regs[i].dirty&1) printf("r0 "); if((branch_regs[i].dirty>>1)&1) printf("r1 "); if((branch_regs[i].dirty>>2)&1) printf("r2 "); if((branch_regs[i].dirty>>3)&1) printf("r3 "); if((branch_regs[i].dirty>>4)&1) printf("r4 "); if((branch_regs[i].dirty>>5)&1) printf("r5 "); if((branch_regs[i].dirty>>6)&1) printf("r6 "); if((branch_regs[i].dirty>>7)&1) printf("r7 "); if((branch_regs[i].dirty>>8)&1) printf("r8 "); if((branch_regs[i].dirty>>9)&1) printf("r9 "); if((branch_regs[i].dirty>>10)&1) printf("r10 "); if((branch_regs[i].dirty>>12)&1) printf("r12 "); #endif printf("\n"); } } /* Pass 8 - Assembly */ { u32 dirty_pre=0; linkcount=0;stubcount=0; ds=0;is_delayslot=0; beginning=(pointer)out; for(i=0;i\n"); // load regs if(regs[i].regmap_entry[HOST_CCREG]==CCREG&®s[i].regmap[HOST_CCREG]!=CCREG) wb_register(CCREG,regs[i].regmap_entry,regs[i].wasdirty); load_regs(regs[i].regmap_entry,regs[i].regmap,rs1[i],rs2[i],rs3[i]); srloaded=(rs1[i]==TBIT||rs2[i]==TBIT||rs3[i]==TBIT||rs1[i]==SR||rs2[i]==SR||rs3[i]==SR); if(rt1[i]==TBIT||rt2[i]==TBIT) if(!srloaded&&rt1[i]!=SR&&rt2[i]!=SR) {srloaded=1;load_regs(regs[i].regmap_entry,regs[i].regmap,SR,SR,SR);} address_generation(i,®s[i],regs[i].regmap_entry); load_consts(regmap_pre[i],regs[i].regmap,i); if(itype[i]==RJUMP||itype[i]==UJUMP||itype[i]==SJUMP) { // Load the delay slot registers if necessary if(!srloaded&&rt1[i+1]!=SR&&rt2[i+1]!=SR&&(rt1[i+1]==TBIT||rt2[i+1]==TBIT)) {srloaded=1;load_regs(regs[i].regmap_entry,regs[i].regmap,SR,SR,SR);} if(rs1[i+1]!=rs1[i]&&rs1[i+1]!=rs2[i]&&rs1[i+1]!=rs3[i]) if(!srloaded||(rs1[i+1]!=TBIT&&rs1[i+1]!=SR)) load_regs(regs[i].regmap_entry,regs[i].regmap,rs1[i+1],rs1[i+1],rs1[i+1]); if(rs2[i+1]!=rs1[i+1]&&rs2[i+1]!=rs1[i]&&rs2[i+1]!=rs2[i]&&rs2[i+1]!=rs3[i]) if(!srloaded||(rs2[i+1]!=TBIT&&rs2[i+1]!=SR)) load_regs(regs[i].regmap_entry,regs[i].regmap,rs2[i+1],rs2[i+1],rs2[i+1]); if(rs3[i+1]!=rs1[i+1]&&rs3[i+1]!=rs2[i+1]&&rs3[i+1]!=rs1[i]&&rs3[i+1]!=rs2[i]&&rs3[i+1]!=rs3[i]) if(!srloaded||(rs3[i+1]!=TBIT&&rs3[i+1]!=SR)) load_regs(regs[i].regmap_entry,regs[i].regmap,rs3[i+1],rs3[i+1],rs3[i+1]); } else if(i+1>16)==0x1000) literal_pool(1024); else literal_pool_jumpover(256); } } // If the block did not end with an unconditional branch, // add a jump to the next instruction. if(i>1) { if(itype[i-2]!=UJUMP&&itype[i-2]!=RJUMP&&itype[i-1]!=DATA) { assert(i==slen); if(itype[i-2]!=SJUMP) { store_regs_bt(regs[i-1].regmap,regs[i-1].dirty,start+i*2); if(regs[i-1].regmap[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG); emit_addimm(HOST_CCREG,CLOCK_DIVIDER*(ccadj[i-1]+1),HOST_CCREG); } else { store_regs_bt(regs[i-2].regmap,regs[i-2].dirty,start+i*2); assert(regs[i-2].regmap[HOST_CCREG]==CCREG); } add_to_linker((int)out,start+i*2,0); emit_jmp(0); } } else { assert(i>0); store_regs_bt(regs[i-1].regmap,regs[i-1].dirty,start+i*2); if(regs[i-1].regmap[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG); emit_addimm(HOST_CCREG,CLOCK_DIVIDER*(ccadj[i-1]+1),HOST_CCREG); add_to_linker((int)out,start+i*2,0); emit_jmp(0); } // Stubs for(i=0;i %8x\n",link_addr[i][0],link_addr[i][1]); literal_pool(64); if(!link_addr[i][2]) { void *stub=out; void *addr=check_addr(link_addr[i][1]); emit_extjump(link_addr[i][0],link_addr[i][1]); if(addr) { set_jump_target(link_addr[i][0],(int)addr); add_link(link_addr[i][1],stub); } else set_jump_target(link_addr[i][0],(int)stub); } else { // Internal branch int target=(link_addr[i][1]-start)>>1; assert(target>=0&&target>1); //#else set_jump_target(link_addr[i][0],instr_addr[target]); //#endif } } // External Branch Targets (jump_in) if(copy+slen*2+4>shadow+sizeof(shadow)) copy=shadow; for(i=0;i>12; if(page>1024) page=1024+(page&1023); literal_pool(256); assem_debug("%8x (%d) <- %8x\n",instr_addr[i],i,start+i*2); assem_debug("jump_in: %x\n",start+i*2); ll_add(jump_dirty+page,vaddr,(void *)out); entry_point=do_dirty_stub(i); ll_add_nodup(jump_in+page,vaddr,(void *)entry_point); if((itype[i]==CJUMP||itype[i]==SJUMP)&&ccstub_return[i]) set_jump_target(ccstub_return[i],entry_point); // If there was an existing entry in the hash table, // replace it with the new address. // Don't add new entries. We'll insert the // ones that actually get used in check_addr(). ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF]; if(ht_bin[0]==vaddr) { ht_bin[1]=entry_point; } if(ht_bin[2]==vaddr) { ht_bin[3]=entry_point; } } } } // Write out the literal pool if necessary literal_pool(0); #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK // Align code if(((u32)out)&7) emit_addnop(13); #endif assert((pointer)out-beginningBASE_ADDR+(1<>12;i<=(start+slen*2)>>12;i++) { //invalid_code[i]=0; cached_code[i>>3]|=1<<(i&7); cached_code[(i^0x20000)>>3]|=1<<(i&7); #ifdef POINTERS_64BIT memory_map[i]|=0x4000000000000000LL; memory_map[i^0x20000]|=0x4000000000000000LL; #else memory_map[i]|=0x40000000; memory_map[i^0x20000]|=0x40000000; #endif } alignedstart=start&~3; index=alignedstart&0xDFFFFFFF; if(index>4194304) index=(addr|0x400000)&0x7fffff; for(i=0;i>5]|=1<<(((index+i)>>2)&7); } } /* Pass 10 - Free memory by expiring oldest blocks */ { int end=((((int)out-BASE_ADDR)>>(TARGET_SIZE_2-16))+16384)&65535; while(expirep!=end) { int shift=TARGET_SIZE_2-3; // Divide into 8 blocks int base=BASE_ADDR+((expirep>>13)<>11)&3) { case 0: // Clear jump_in and jump_dirty ll_remove_matching_addrs(jump_in+(expirep&2047),base,shift); ll_remove_matching_addrs(jump_dirty+(expirep&2047),base,shift); break; case 1: // Clear pointers ll_kill_pointers(jump_out[expirep&2047],base,shift); break; case 2: // Clear hash table for(i=0;i<32;i++) { u32 *ht_bin=hash_table[((expirep&2047)<<5)+i]; if((ht_bin[3]>>shift)==(base>>shift) || ((ht_bin[3]-MAX_OUTPUT_BLOCK_SIZE)>>shift)==(base>>shift)) { inv_debug("EXP: Remove hash %x -> %x\n",ht_bin[2],ht_bin[3]); ht_bin[2]=ht_bin[3]=-1; } if((ht_bin[1]>>shift)==(base>>shift) || ((ht_bin[1]-MAX_OUTPUT_BLOCK_SIZE)>>shift)==(base>>shift)) { inv_debug("EXP: Remove hash %x -> %x\n",ht_bin[0],ht_bin[1]); ht_bin[0]=ht_bin[2]; ht_bin[1]=ht_bin[3]; ht_bin[2]=ht_bin[3]=-1; } } break; case 3: // Clear jump_out if((expirep&2047)==0) { #ifdef __arm__ do_clear_cache(); #endif #ifdef USE_MINI_HT memset(mini_ht_master,-1,sizeof(mini_ht_master)); memset(mini_ht_slave,-1,sizeof(mini_ht_slave)); #endif } ll_remove_matching_addrs(jump_out+(expirep&2047),base,shift); break; } expirep=(expirep+1)&65535; } } return 0; } #include "../sh2core.h" extern int framecounter; void DynarecMasterHandleInterrupts() { if (MSH2->interrupts[MSH2->NumberOfInterrupts-1].level > ((master_reg[SR]>>4)&0xF)) { master_reg[15] -= 4; MappedMemoryWriteLongNocache(MSH2, master_reg[15], master_reg[SR]); master_reg[15] -= 4; MappedMemoryWriteLongNocache(MSH2, master_reg[15], master_pc); master_reg[SR] &= 0xFFFFFF0F; master_reg[SR] |= (MSH2->interrupts[MSH2->NumberOfInterrupts-1].level)<<4; master_pc = MappedMemoryReadLongNocache(MSH2, master_reg[VBR] + (MSH2->interrupts[MSH2->NumberOfInterrupts-1].vector << 2)); master_ip = get_addr_ht(master_pc); MSH2->NumberOfInterrupts--; MSH2->isIdle = 0; MSH2->isSleeping = 0; } //printf("DynarecMasterHandleInterrupts pc=%x ip=%x\n",master_pc,(int)master_ip); //printf("master_cc=%d slave_cc=%d\n",master_cc,slave_cc); //printf("frame=%d\n",framecounter); } void DynarecSlaveHandleInterrupts() { if (SSH2->interrupts[SSH2->NumberOfInterrupts-1].level > ((slave_reg[SR]>>4)&0xF)) { slave_reg[15] -= 4; MappedMemoryWriteLongNocache(SSH2, slave_reg[15], slave_reg[SR]); slave_reg[15] -= 4; MappedMemoryWriteLongNocache(SSH2, slave_reg[15], slave_pc); slave_reg[SR] &= 0xFFFFFF0F; slave_reg[SR] |= (SSH2->interrupts[SSH2->NumberOfInterrupts-1].level)<<4; slave_pc = MappedMemoryReadLongNocache(SSH2, slave_reg[VBR] + (SSH2->interrupts[SSH2->NumberOfInterrupts-1].vector << 2)); slave_ip = get_addr_ht(slave_pc|1); SSH2->NumberOfInterrupts--; SSH2->isIdle = 0; SSH2->isSleeping = 0; } //printf("DynarecSlaveHandleInterrupts pc=%x ip=%x\n",slave_pc,(int)slave_ip); //printf("master_cc=%d slave_cc=%d\n",master_cc,slave_cc); } void SH2InterpreterSendInterrupt(SH2_struct *context, u8 level, u8 vector); int SH2InterpreterGetInterrupts(SH2_struct *context, interrupt_struct interrupts[MAX_INTERRUPTS]); void SH2InterpreterSetInterrupts(SH2_struct *context, int num_interrupts, const interrupt_struct interrupts[MAX_INTERRUPTS]); int SH2DynarecInit(enum SHMODELTYPE model, SH2_struct *msh, SH2_struct *ssh) {return 0;} void SH2DynarecDeInit() { sh2_dynarec_cleanup(); } void FASTCALL SH2DynarecExec(SH2_struct *context, u32 cycles) { printf("SH2DynarecExec called! oops\n"); printf("master_ip=%x\n",(int)master_ip); exit(1); } u32 SH2DynarecGetSR(SH2_struct *context) { if(context==MSH2) return master_reg[SR]; else return slave_reg[SR]; } u32 SH2DynarecGetGBR(SH2_struct *context) { if(context==MSH2) return master_reg[GBR]; else return slave_reg[GBR]; } u32 SH2DynarecGetVBR(SH2_struct *context) { if(context==MSH2) return master_reg[VBR]; else return slave_reg[VBR]; } u32 SH2DynarecGetMACH(SH2_struct *context) { if(context==MSH2) return master_reg[MACH]; else return slave_reg[MACH]; } u32 SH2DynarecGetMACL(SH2_struct *context) { if(context==MSH2) return master_reg[MACL]; else return slave_reg[MACL]; } u32 SH2DynarecGetPR(SH2_struct *context) { if(context==MSH2) return master_reg[PR]; else return slave_reg[PR]; } u32 SH2DynarecGetGPR(SH2_struct *context, int num) { if(context==MSH2) return master_reg[num]; else return slave_reg[num]; } u32 SH2DynarecGetPC(SH2_struct *context) { if(context==MSH2) return master_pc; else return slave_pc; } void SH2DynarecSetSR(SH2_struct *context, u32 value) { if(context==MSH2) master_reg[SR]=value; else slave_reg[SR]=value; } void SH2DynarecSetGBR(SH2_struct *context, u32 value) { if(context==MSH2) master_reg[GBR]=value; else slave_reg[GBR]=value; } void SH2DynarecSetVBR(SH2_struct *context, u32 value) { if(context==MSH2) master_reg[VBR]=value; else slave_reg[VBR]=value; } void SH2DynarecSetMACH(SH2_struct *context, u32 value) { if(context==MSH2) master_reg[MACH]=value; else slave_reg[MACH]=value; } void SH2DynarecSetMACL(SH2_struct *context, u32 value) { if(context==MSH2) master_reg[MACL]=value; else slave_reg[MACL]=value; } void SH2DynarecSetPR(SH2_struct *context, u32 value) { if(context==MSH2) master_reg[PR]=value; else slave_reg[PR]=value; } void SH2DynarecSetGPR(SH2_struct *context, int num, u32 value) { if(context==MSH2) master_reg[num]=value; else slave_reg[num]=value; } void SH2DynarecSetPC(SH2_struct *context, u32 value) { //printf("SH2DynarecSetPC(%s,%x)\n",(context==MSH2)?"master":"slave",value); if(context==MSH2) { master_pc=value; master_ip=get_addr_ht(value); } else { slave_pc=value; slave_ip=get_addr_ht(value+1); } } #undef SR #undef GBR #undef VBR #undef MACH #undef MACL #undef PR void SH2DynarecGetRegisters(SH2_struct *context, sh2regs_struct *regs) { if(context==MSH2) memcpy(&(regs->R), master_reg, 16*sizeof(int)); else memcpy(&(regs->R), slave_reg, 16*sizeof(int)); regs->SR.all=SH2DynarecGetSR(context); regs->GBR=SH2DynarecGetGBR(context); regs->VBR=SH2DynarecGetVBR(context); regs->MACH=SH2DynarecGetMACH(context); regs->MACL=SH2DynarecGetMACL(context); regs->PR=SH2DynarecGetPR(context); regs->PC=SH2DynarecGetPC(context); } void SH2DynarecSetRegisters(SH2_struct *context, const sh2regs_struct *regs) { if(context==MSH2) memcpy(master_reg, &(regs->R), 16*sizeof(int)); else memcpy(slave_reg, &(regs->R), 16*sizeof(int)); SH2DynarecSetSR(context, regs->SR.all); SH2DynarecSetGBR(context, regs->GBR); SH2DynarecSetVBR(context, regs->VBR); SH2DynarecSetMACH(context, regs->MACH); SH2DynarecSetMACL(context, regs->MACL); SH2DynarecSetPR(context, regs->PR); SH2DynarecSetPC(context, regs->PC); } void SH2DynarecWriteNotify(u32 start, u32 length) { int block,wp=0; // Ignore non-RAM regions if((start&0xDFF00000)!=0x200000&&(start&0xDE000000)!=0x6000000) return; // Check if any pages contain compiled code for(block=start>>12;block<=(start+length-1)>>12;block++) wp|=((cached_code[block>>3]>>(block&7))&1); if(!wp) return; //printf("SH2DynarecWriteNotify(%x,%x)\n",start,length); invalidate_blocks(start>>12,(start+length-1)>>12); } SH2Interface_struct SH2Dynarec = { SH2CORE_DYNAREC, "SH2 Dynamic Recompiler", SH2DynarecInit, SH2DynarecDeInit, SH2DynarecReset, SH2DynarecExec, SH2DynarecGetRegisters, SH2DynarecGetGPR, SH2DynarecGetSR, SH2DynarecGetGBR, SH2DynarecGetVBR, SH2DynarecGetMACH, SH2DynarecGetMACL, SH2DynarecGetPR, SH2DynarecGetPC, SH2DynarecSetRegisters, SH2DynarecSetGPR, SH2DynarecSetSR, SH2DynarecSetGBR, SH2DynarecSetVBR, SH2DynarecSetMACH, SH2DynarecSetMACL, SH2DynarecSetPR, SH2DynarecSetPC, SH2InterpreterSendInterrupt, SH2InterpreterGetInterrupts, SH2InterpreterSetInterrupts, SH2DynarecWriteNotify }; u32 * decilinestop_p = &yabsys.DecilineStop; u32 * decilineusec_p = &yabsys.DecilineUsec; u32 * SH2CycleFrac_p = &yabsys.SH2CycleFrac; u32 * UsecFrac_p = &yabsys.UsecFrac; //u32 decilinecycles = yabsys.DecilineStop >> YABSYS_TIMING_BITS; u32 yabsys_timing_bits = YABSYS_TIMING_BITS; u32 yabsys_timing_mask = YABSYS_TIMING_MASK; int * linecount_p = &yabsys.LineCount; int * vblanklinecount_p = &yabsys.VBlankLineCount; int * maxlinecount_p = &yabsys.MaxLineCount; void * NumberOfInterruptsOffset = &((SH2_struct *)0)->NumberOfInterrupts; yabause-0.9.15/src/sh2_dynarec/assem_arm.h000644 001750 001750 00000002173 12755623101 022366 0ustar00guillaumeguillaume000000 000000 #define HOST_REGS 13 #define HOST_CCREG 10 #define EXCLUDE_REG 11 #define SLAVERA_REG 8 #define HOST_IMM8 1 #define HAVE_CMOV_IMM 1 #define CORTEX_A8_BRANCH_PREDICTION_HACK 1 #define USE_MINI_HT 1 //#define REG_PREFETCH 1 /* ARM calling convention: r0-r3, r12: caller-save r4-r11: callee-save */ #define ARG1_REG 0 #define ARG2_REG 1 #define ARG3_REG 2 #define ARG4_REG 3 /* GCC register naming convention: r10 = sl (base) r11 = fp (frame pointer) r12 = ip (scratch) r13 = sp (stack pointer) r14 = lr (link register) r15 = pc (program counter) */ #define FP 11 #define LR 14 #define HOST_TEMPREG 14 // Note: FP is set to &dynarec_local when executing generated code. // Thus the local variables are actually global and not on the stack. extern u8 sh2_dynarec_target[16777216]; extern u32 memory_map[1048576]; // 32-bit //#define BASE_ADDR 0x6000000 // Code generator target address #define BASE_ADDR ((u32)&sh2_dynarec_target) // Code generator target address #define TARGET_SIZE_2 24 // 2^24 = 16 megabytes //#define TARGET_SIZE_2 25 // 2^25 = 32 megabytes #ifdef ANDROID #define __clear_cache clear_cache #endif yabause-0.9.15/src/sh2_dynarec/sh2_dynarec.h000644 001750 001750 00000000332 12755623101 022613 0ustar00guillaumeguillaume000000 000000 #ifndef SH2_DYNAREC_H #define SH2_DYNAREC_H #define SH2CORE_DYNAREC 2 void sh2_dynarec_init(void); int verify_dirty(pointer addr); void invalidate_all_pages(void); void YabauseDynarecOneFrameExec(int, int); #endif yabause-0.9.15/src/sh2_dynarec/assem_x86.c000644 001750 001750 00000231775 12755623101 022243 0ustar00guillaumeguillaume000000 000000 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Yabause - assem_x86.c * * Copyright (C) 2009-2011 Ari64 * * * * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ u32 memory_map[1048576]; ALIGNED(8) u32 mini_ht_master[32][2]; ALIGNED(8) u32 mini_ht_slave[32][2]; ALIGNED(4) u8 restore_candidate[512]; int rccount; int master_reg[22]; int master_cc; // Cycle count int master_pc; // Virtual PC void * master_ip; // Translated PC int slave_reg[22]; int slave_cc; // Cycle count int slave_pc; // Virtual PC void * slave_ip; // Translated PC void FASTCALL WriteInvalidateLong(u32 addr, u32 val); void FASTCALL WriteInvalidateWord(u32 addr, u32 val); void FASTCALL WriteInvalidateByte(u32 addr, u32 val); void FASTCALL WriteInvalidateByteSwapped(u32 addr, u32 val); u32 rmw_temp; // Temporary storage for TAS.B instruction void jump_vaddr_eax_master(); void jump_vaddr_ecx_master(); void jump_vaddr_edx_master(); void jump_vaddr_ebx_master(); void jump_vaddr_ebp_master(); void jump_vaddr_edi_master(); void jump_vaddr_eax_slave(); void jump_vaddr_ecx_slave(); void jump_vaddr_edx_slave(); void jump_vaddr_ebx_slave(); void jump_vaddr_ebp_slave(); void jump_vaddr_edi_slave(); const pointer jump_vaddr_reg[2][8] = { { (pointer)jump_vaddr_eax_master, (pointer)jump_vaddr_ecx_master, (pointer)jump_vaddr_edx_master, (pointer)jump_vaddr_ebx_master, 0, (pointer)jump_vaddr_ebp_master, 0, (pointer)jump_vaddr_edi_master },{ (pointer)jump_vaddr_eax_slave, (pointer)jump_vaddr_ecx_slave, (pointer)jump_vaddr_edx_slave, (pointer)jump_vaddr_ebx_slave, 0, (pointer)jump_vaddr_ebp_slave, 0, (pointer)jump_vaddr_edi_slave } }; // We need these for cmovcc instructions on x86 u32 const_zero=0; u32 const_one=1; /* Linker */ void set_jump_target(pointer addr,pointer target) { u8 *ptr=(u8 *)addr; if(*ptr==0x0f) { assert(ptr[1]>=0x80&&ptr[1]<=0x8f); u32 *ptr2=(u32 *)(ptr+2); *ptr2=target-(u32)ptr2-4; } else if(*ptr==0xe8||*ptr==0xe9) { u32 *ptr2=(u32 *)(ptr+1); *ptr2=target-(u32)ptr2-4; } else { assert(*ptr==0xc7); /* mov immediate (store address) */ u32 *ptr2=(u32 *)(ptr+6); *ptr2=target; } } void *kill_pointer(void *stub) { u32 *i_ptr=*((u32 **)(stub+6)); *i_ptr=(u32)stub-(u32)i_ptr-4; return i_ptr; } pointer get_pointer(void *stub) { s32 *i_ptr=*((u32 **)(stub+6)); return *i_ptr+(pointer)i_ptr+4; } // Find the "clean" entry point from a "dirty" entry point // by skipping past the call to verify_code pointer get_clean_addr(pointer addr) { u8 *ptr=(u8 *)addr; assert(ptr[20]==0xE8); // call instruction assert(ptr[25]==0x83); // pop (add esp,4) instruction if(ptr[28]==0xE9) return *(s32 *)(ptr+29)+addr+33; // follow jmp else return(addr+28); } int verify_dirty(pointer addr) { u8 *ptr=(u8 *)addr; assert(ptr[5]==0xB8); u32 source=*(u32 *)(ptr+6); u32 copy=*(u32 *)(ptr+11); u32 len=*(u32 *)(ptr+16); assert(ptr[20]==0xE8); // call instruction return !memcmp((void *)source,(void *)copy,len); } // This doesn't necessarily find all clean entry points, just // guarantees that it's not dirty int isclean(pointer addr) { u8 *ptr=(u8 *)addr; if(ptr[5]!=0xB8) return 1; // mov imm,%eax if(ptr[10]!=0xBB) return 1; // mov imm,%ebx if(ptr[15]!=0xB9) return 1; // mov imm,%ecx if(ptr[20]!=0xE8) return 1; // call instruction if(ptr[25]!=0x83) return 1; // pop (add esp,4) instruction return 0; } void get_bounds(pointer addr,u32 *start,u32 *end) { u8 *ptr=(u8 *)addr; assert(ptr[5]==0xB8); u32 source=*(u32 *)(ptr+6); //u32 copy=*(u32 *)(ptr+11); u32 len=*(u32 *)(ptr+16); assert(ptr[20]==0xE8); // call instruction if(start) *start=source; if(end) *end=source+len; } /* Register allocation */ // Note: registers are allocated clean (unmodified state) // if you intend to modify the register, you must call dirty_reg(). void alloc_reg(struct regstat *cur,int i,signed char reg) { int r,hr; int preferred_reg = (reg&3)+(reg>21)*4+(reg==24)+(reg==28)+(reg==32); if(reg==CCREG) preferred_reg=HOST_CCREG; // Don't allocate unused registers if((cur->u>>reg)&1) return; // see if it's already allocated for(hr=0;hrregmap[hr]==reg) return; } // Keep the same mapping if the register was already allocated in a loop preferred_reg = loop_reg(i,reg,preferred_reg); // Try to allocate the preferred register if(cur->regmap[preferred_reg]==-1) { cur->regmap[preferred_reg]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[preferred_reg]; if(r<64&&((cur->u>>r)&1)) { cur->regmap[preferred_reg]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]==-1) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]; if(r>=0) { if((cur->u>>r)&1) if(i==0||(unneeded_reg[i-1]>>r)&1) {cur->regmap[hr]=-1;break;} } } // Try to allocate any available register, but prefer // registers that have not been used recently. if(i>0) { for(hr=0;hrregmap[hr]==-1) { if(regs[i-1].regmap[hr]!=rs1[i-1]&®s[i-1].regmap[hr]!=rs2[i-1]&®s[i-1].regmap[hr]!=rt1[i-1]&®s[i-1].regmap[hr]!=rt2[i-1]) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]==-1) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[0]&63],hsn[cur->regmap[1]&63],hsn[cur->regmap[2]&63],hsn[cur->regmap[3]&63],hsn[cur->regmap[5]&63],hsn[cur->regmap[6]&63],hsn[cur->regmap[7]&63]); if(i>0) { // Don't evict the cycle count at entry points, otherwise the entry // stub will have to write it. if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP)) hsn[CCREG]=2; for(j=10;j>=3;j--) { // Alloc preferred register if available if(hsn[r=cur->regmap[preferred_reg]&63]==j) { for(hr=0;hrregmap[hr]&63)==r) { cur->regmap[hr]=-1; cur->dirty&=~(1<isdoingcp&=~(1<regmap[preferred_reg]=reg; return; } for(r=0;r<=MAXREG;r++) { if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<=0;j--) { for(r=0;r<=MAXREG;r++) { if(hsn[r]==j) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]==reg) return; } // Try to allocate any available register, starting with EDI, ESI, EBP... // We prefer EDI, ESI, EBP since the others are used for byte/halfword stores for(hr=HOST_REGS-1;hr>=0;hr--) { if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<=0;hr--) { r=cur->regmap[hr]; if(r>=0) { if((cur->u>>r)&1) { if(i==0||((unneeded_reg[i-1]>>r)&1)) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[0]&63],hsn[cur->regmap[1]&63],hsn[cur->regmap[2]&63],hsn[cur->regmap[3]&63],hsn[cur->regmap[5]&63],hsn[cur->regmap[6]&63],hsn[cur->regmap[7]&63]); if(i>0) { // Don't evict the cycle count at entry points, otherwise the entry // stub will have to write it. if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP)) hsn[CCREG]=2; for(j=10;j>=3;j--) { for(r=0;r<=MAXREG;r++) { if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<=0;j--) { for(r=0;r<=MAXREG;r++) { if(hsn[r]==j) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[n]==reg) { dirty=(cur->dirty>>n)&1; cur->regmap[n]=-1; } } cur->regmap[hr]=reg; cur->dirty&=~(1<dirty|=dirty<isdoingcp&=~(1<=-128&&rs<4) { output_byte(0xF6); output_modrm(3,rs,0); output_byte(imm); } else { output_byte(0xF7); output_modrm(3,rs,0); output_w32(imm); } } void emit_not(int rs,int rt) { if(rs!=rt) emit_mov(rs,rt); assem_debug("not %%%s\n",regname[rt]); output_byte(0xF7); output_modrm(3,rt,2); } void emit_and(unsigned int rs1,unsigned int rs2,unsigned int rt) { assert(rs1<8); assert(rs2<8); assert(rt<8); if(rs1==rt) { assem_debug("and %%%s,%%%s\n",regname[rs2],regname[rt]); output_byte(0x21); output_modrm(3,rs1,rs2); } else if(rs2==rt) { assem_debug("and %%%s,%%%s\n",regname[rs1],regname[rt]); output_byte(0x21); output_modrm(3,rs2,rs1); } else { emit_mov(rs1,rt); emit_and(rt,rs2,rt); } } void emit_or(unsigned int rs1,unsigned int rs2,unsigned int rt) { assert(rs1<8); assert(rs2<8); assert(rt<8); if(rs1==rt) { assem_debug("or %%%s,%%%s\n",regname[rs2],regname[rt]); output_byte(0x09); output_modrm(3,rs1,rs2); } else if(rs2==rt) { assem_debug("or %%%s,%%%s\n",regname[rs1],regname[rt]); output_byte(0x09); output_modrm(3,rs2,rs1); } else { emit_mov(rs1,rt); emit_or(rt,rs2,rt); } } void emit_or_and_set_flags(int rs1,int rs2,int rt) { emit_or(rs1,rs2,rt); } void emit_xor(unsigned int rs1,unsigned int rs2,unsigned int rt) { assert(rs1<8); assert(rs2<8); assert(rt<8); if(rs1==rt) { assem_debug("xor %%%s,%%%s\n",regname[rs2],regname[rt]); output_byte(0x31); output_modrm(3,rs1,rs2); } else if(rs2==rt) { assem_debug("xor %%%s,%%%s\n",regname[rs1],regname[rt]); output_byte(0x31); output_modrm(3,rs2,rs1); } else { emit_mov(rs1,rt); emit_xor(rt,rs2,rt); } } void emit_movimm(int imm,unsigned int rt) { assem_debug("mov $%d,%%%s\n",imm,regname[rt]); assert(rt<8); output_byte(0xB8+rt); output_w32(imm); } void emit_addimm(int rs,int imm,int rt) { if(rs==rt) { if(imm!=0) { assem_debug("add $%d,%%%s\n",imm,regname[rt]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,0); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,0); output_w32(imm); } } } else { if(imm!=0) { assem_debug("lea %d(%%%s),%%%s\n",imm,regname[rs],regname[rt]); output_byte(0x8D); if(imm<128&&imm>=-128) { output_modrm(1,rs,rt); output_byte(imm); }else{ output_modrm(2,rs,rt); output_w32(imm); } }else{ emit_mov(rs,rt); } } } void emit_addimm_and_set_flags(int imm,int rt) { assem_debug("add $%d,%%%s\n",imm,regname[rt]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,0); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,0); output_w32(imm); } } void emit_addimm_no_flags(int imm,int rt) { if(imm!=0) { assem_debug("lea %d(%%%s),%%%s\n",imm,regname[rt],regname[rt]); output_byte(0x8D); if(imm<128&&imm>=-128) { output_modrm(1,rt,rt); output_byte(imm); }else{ output_modrm(2,rt,rt); output_w32(imm); } } } void emit_adcimm(int imm,unsigned int rt) { assem_debug("adc $%d,%%%s\n",imm,regname[rt]); assert(rt<8); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,2); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,2); output_w32(imm); } } void emit_sbbimm(int imm,unsigned int rt) { assem_debug("sbb $%d,%%%s\n",imm,regname[rt]); assert(rt<8); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,3); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,3); output_w32(imm); } } void emit_addimm64_32(int rsh,int rsl,int imm,int rth,int rtl) { if(rsh==rth&&rsl==rtl) { assem_debug("add $%d,%%%s\n",imm,regname[rtl]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rtl,0); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rtl,0); output_w32(imm); } assem_debug("adc $%d,%%%s\n",imm>>31,regname[rth]); output_byte(0x83); output_modrm(3,rth,2); output_byte(imm>>31); } else { emit_mov(rsh,rth); emit_mov(rsl,rtl); emit_addimm64_32(rth,rtl,imm,rth,rtl); } } void emit_sbb(int rs1,int rs2) { assem_debug("sbb %%%s,%%%s\n",regname[rs1],regname[rs2]); output_byte(0x19); output_modrm(3,rs2,rs1); } void emit_andimm(int rs,int imm,int rt) { if(imm==0) { emit_zeroreg(rt); } else if(rs==rt) { assem_debug("and $%d,%%%s\n",imm,regname[rt]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,4); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,4); output_w32(imm); } } else { emit_mov(rs,rt); emit_andimm(rt,imm,rt); } } void emit_orimm(int rs,int imm,int rt) { if(rs==rt) { if(imm!=0) { assem_debug("or $%d,%%%s\n",imm,regname[rt]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,1); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,1); output_w32(imm); } } } else { emit_mov(rs,rt); emit_orimm(rt,imm,rt); } } void emit_xorimm(int rs,int imm,int rt) { if(rs==rt) { if(imm!=0) { assem_debug("xor $%d,%%%s\n",imm,regname[rt]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,6); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,6); output_w32(imm); } } } else { emit_mov(rs,rt); emit_xorimm(rt,imm,rt); } } void emit_shlimm(int rs,unsigned int imm,int rt) { if(rs==rt) { assem_debug("shl %%%s,%d\n",regname[rt],imm); assert(imm>0); if(imm==1) output_byte(0xD1); else output_byte(0xC1); output_modrm(3,rt,4); if(imm>1) output_byte(imm); } else { emit_mov(rs,rt); emit_shlimm(rt,imm,rt); } } void emit_shrimm(int rs,unsigned int imm,int rt) { if(rs==rt) { assem_debug("shr %%%s,%d\n",regname[rt],imm); assert(imm>0); if(imm==1) output_byte(0xD1); else output_byte(0xC1); output_modrm(3,rt,5); if(imm>1) output_byte(imm); } else { emit_mov(rs,rt); emit_shrimm(rt,imm,rt); } } void emit_sarimm(int rs,unsigned int imm,int rt) { if(rs==rt) { assem_debug("sar %%%s,%d\n",regname[rt],imm); assert(imm>0); if(imm==1) output_byte(0xD1); else output_byte(0xC1); output_modrm(3,rt,7); if(imm>1) output_byte(imm); } else { emit_mov(rs,rt); emit_sarimm(rt,imm,rt); } } void emit_rorimm(int rs,unsigned int imm,int rt) { if(rs==rt) { assem_debug("ror %%%s,%d\n",regname[rt],imm); assert(imm>0); if(imm==1) output_byte(0xD1); else output_byte(0xC1); output_modrm(3,rt,1); if(imm>1) output_byte(imm); } else { emit_mov(rs,rt); emit_rorimm(rt,imm,rt); } } void emit_swapb(int rs,int rt) { if(rs==rt) { assem_debug("ror %%%s,8\n",regname[rt]+1); output_byte(0x66); output_byte(0xC1); output_modrm(3,rt,1); output_byte(8); } else { emit_mov(rs,rt); emit_swapb(rt,rt); } } void emit_shldimm(int rs,int rs2,unsigned int imm,int rt) { if(rs==rt) { assem_debug("shld %%%s,%%%s,%d\n",regname[rt],regname[rs2],imm); assert(imm>0); output_byte(0x0F); output_byte(0xA4); output_modrm(3,rt,rs2); output_byte(imm); } else { emit_mov(rs,rt); emit_shldimm(rt,rs2,imm,rt); } } void emit_shrdimm(int rs,int rs2,unsigned int imm,int rt) { if(rs==rt) { assem_debug("shrd %%%s,%%%s,%d\n",regname[rt],regname[rs2],imm); assert(imm>0); output_byte(0x0F); output_byte(0xAC); output_modrm(3,rt,rs2); output_byte(imm); } else { emit_mov(rs,rt); emit_shrdimm(rt,rs2,imm,rt); } } void emit_shlcl(int r) { assem_debug("shl %%%s,%%cl\n",regname[r]); output_byte(0xD3); output_modrm(3,r,4); } void emit_shrcl(int r) { assem_debug("shr %%%s,%%cl\n",regname[r]); output_byte(0xD3); output_modrm(3,r,5); } void emit_sarcl(int r) { assem_debug("sar %%%s,%%cl\n",regname[r]); output_byte(0xD3); output_modrm(3,r,7); } void emit_shldcl(int r1,int r2) { assem_debug("shld %%%s,%%%s,%%cl\n",regname[r1],regname[r2]); output_byte(0x0F); output_byte(0xA5); output_modrm(3,r1,r2); } void emit_shrdcl(int r1,int r2) { assem_debug("shrd %%%s,%%%s,%%cl\n",regname[r1],regname[r2]); output_byte(0x0F); output_byte(0xAD); output_modrm(3,r1,r2); } void emit_cmpimm(int rs,int imm) { assem_debug("cmp $%d,%%%s\n",imm,regname[rs]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rs,7); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rs,7); output_w32(imm); } } void emit_cmovne(u32 *addr,int rt) { assem_debug("cmovne %x,%%%s",(int)addr,regname[rt]); if(addr==&const_zero) assem_debug(" [zero]\n"); else if(addr==&const_one) assem_debug(" [one]\n"); else assem_debug("\n"); output_byte(0x0F); output_byte(0x45); output_modrm(0,5,rt); output_w32((int)addr); } void emit_cmovl(u32 *addr,int rt) { assem_debug("cmovl %x,%%%s",(int)addr,regname[rt]); if(addr==&const_zero) assem_debug(" [zero]\n"); else if(addr==&const_one) assem_debug(" [one]\n"); else assem_debug("\n"); output_byte(0x0F); output_byte(0x4C); output_modrm(0,5,rt); output_w32((int)addr); } void emit_cmovs(u32 *addr,int rt) { assem_debug("cmovs %x,%%%s",(int)addr,regname[rt]); if(addr==&const_zero) assem_debug(" [zero]\n"); else if(addr==&const_one) assem_debug(" [one]\n"); else assem_debug("\n"); output_byte(0x0F); output_byte(0x48); output_modrm(0,5,rt); output_w32((int)addr); } void emit_cmovne_reg(int rs,int rt) { assem_debug("cmovne %%%s,%%%s\n",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x45); output_modrm(3,rs,rt); } void emit_cmovl_reg(int rs,int rt) { assem_debug("cmovl %%%s,%%%s\n",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x4C); output_modrm(3,rs,rt); } void emit_cmovle_reg(int rs,int rt) { assem_debug("cmovle %%%s,%%%s\n",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x4E); output_modrm(3,rs,rt); } void emit_cmovs_reg(int rs,int rt) { assem_debug("cmovs %%%s,%%%s\n",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x48); output_modrm(3,rs,rt); } void emit_cmovnc_reg(int rs,int rt) { assem_debug("cmovae %%%s,%%%s\n",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x43); output_modrm(3,rs,rt); } void emit_cmova_reg(int rs,int rt) { assem_debug("cmova %%%s,%%%s\n",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x47); output_modrm(3,rs,rt); } void emit_cmovp_reg(int rs,int rt) { assem_debug("cmovp %%%s,%%%s\n",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x4A); output_modrm(3,rs,rt); } void emit_cmovnp_reg(int rs,int rt) { assem_debug("cmovnp %%%s,%%%s\n",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x4B); output_modrm(3,rs,rt); } void emit_setl(int rt) { assem_debug("setl %%%s\n",regname[rt]); output_byte(0x0F); output_byte(0x9C); output_modrm(3,rt,2); } void emit_movzbl_reg(int rs, int rt) { if(rs<4) { assem_debug("movzbl %%%s,%%%s\n",regname[rs]+1,regname[rt]); output_byte(0x0F); output_byte(0xB6); output_modrm(3,rs,rt); } else if(rt<4) { emit_mov(rs,rt); emit_movzbl_reg(rt,rt); } else { emit_andimm(rs,0xFF,rt); } } void emit_movzwl_reg(int rs, int rt) { assem_debug("movzwl %%%s,%%%s\n",regname[rs]+1,regname[rt]); output_byte(0x0F); output_byte(0xB7); output_modrm(3,rs,rt); } void emit_movsbl_reg(int rs, int rt) { if(rs<4) { assem_debug("movsbl %%%s,%%%s\n",regname[rs]+1,regname[rt]); output_byte(0x0F); output_byte(0xBE); output_modrm(3,rs,rt); } else if(rt<4) { emit_mov(rs,rt); emit_movsbl_reg(rt,rt); } else { emit_shlimm(rs,24,rt); emit_sarimm(rt,24,rt); } } void emit_movswl_reg(int rs, int rt) { assem_debug("movswl %%%s,%%%s\n",regname[rs]+1,regname[rt]); output_byte(0x0F); output_byte(0xBF); output_modrm(3,rs,rt); } void emit_slti32(int rs,int imm,int rt) { if(rs!=rt) emit_zeroreg(rt); emit_cmpimm(rs,imm); if(rt<4) { emit_setl(rt); if(rs==rt) emit_movzbl_reg(rt,rt); } else { if(rs==rt) emit_movimm(0,rt); emit_cmovl(&const_one,rt); } } void emit_sltiu32(int rs,int imm,int rt) { if(rs!=rt) emit_zeroreg(rt); emit_cmpimm(rs,imm); if(rs==rt) emit_movimm(0,rt); emit_adcimm(0,rt); } void emit_slti64_32(int rsh,int rsl,int imm,int rt) { assert(rsh!=rt); emit_slti32(rsl,imm,rt); if(imm>=0) { emit_test(rsh,rsh); emit_cmovne(&const_zero,rt); emit_cmovs(&const_one,rt); } else { emit_cmpimm(rsh,-1); emit_cmovne(&const_zero,rt); emit_cmovl(&const_one,rt); } } void emit_sltiu64_32(int rsh,int rsl,int imm,int rt) { assert(rsh!=rt); emit_sltiu32(rsl,imm,rt); if(imm>=0) { emit_test(rsh,rsh); emit_cmovne(&const_zero,rt); } else { emit_cmpimm(rsh,-1); emit_cmovne(&const_one,rt); } } void emit_cmp(int rs,int rt) { assem_debug("cmp %%%s,%%%s\n",regname[rt],regname[rs]); output_byte(0x39); output_modrm(3,rs,rt); } void emit_set_gz32(int rs, int rt) { //assem_debug("set_gz32\n"); emit_cmpimm(rs,1); emit_movimm(1,rt); emit_cmovl(&const_zero,rt); } void emit_set_nz32(int rs, int rt) { //assem_debug("set_nz32\n"); emit_cmpimm(rs,1); emit_movimm(1,rt); emit_sbbimm(0,rt); } void emit_set_gz64_32(int rsh, int rsl, int rt) { //assem_debug("set_gz64\n"); emit_set_gz32(rsl,rt); emit_test(rsh,rsh); emit_cmovne(&const_one,rt); emit_cmovs(&const_zero,rt); } void emit_set_nz64_32(int rsh, int rsl, int rt) { //assem_debug("set_nz64\n"); emit_or_and_set_flags(rsh,rsl,rt); emit_cmovne(&const_one,rt); } void emit_set_if_less32(int rs1, int rs2, int rt) { //assem_debug("set if less (%%%s,%%%s),%%%s\n",regname[rs1],regname[rs2],regname[rt]); if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt); emit_cmp(rs1,rs2); if(rs1==rt||rs2==rt) emit_movimm(0,rt); emit_cmovl(&const_one,rt); } void emit_set_if_carry32(int rs1, int rs2, int rt) { //assem_debug("set if carry (%%%s,%%%s),%%%s\n",regname[rs1],regname[rs2],regname[rt]); if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt); emit_cmp(rs1,rs2); if(rs1==rt||rs2==rt) emit_movimm(0,rt); emit_adcimm(0,rt); } void emit_set_if_less64_32(int u1, int l1, int u2, int l2, int rt) { //assem_debug("set if less64 (%%%s,%%%s,%%%s,%%%s),%%%s\n",regname[u1],regname[l1],regname[u2],regname[l2],regname[rt]); assert(u1!=rt); assert(u2!=rt); emit_cmp(l1,l2); emit_mov(u1,rt); emit_sbb(u2,rt); emit_movimm(0,rt); emit_cmovl(&const_one,rt); } void emit_set_if_carry64_32(int u1, int l1, int u2, int l2, int rt) { //assem_debug("set if carry64 (%%%s,%%%s,%%%s,%%%s),%%%s\n",regname[u1],regname[l1],regname[u2],regname[l2],regname[rt]); assert(u1!=rt); assert(u2!=rt); emit_cmp(l1,l2); emit_mov(u1,rt); emit_sbb(u2,rt); emit_movimm(0,rt); emit_adcimm(0,rt); } void emit_adc(int rs,int rt) { assem_debug("adc %%%s,%%%s\n",regname[rs],regname[rt]); output_byte(0x11); output_modrm(3,rt,rs); } void emit_sh2tst(int s1, int s2, int sr, int temp) { assert(temp>=0); emit_orimm(sr,1,sr); emit_addimm(sr,-1,temp); emit_test(s1,s2); emit_cmovne_reg(temp,sr); } void emit_sh2tstimm(int s, int imm, int sr, int temp) { assert(temp>=0); emit_orimm(sr,1,sr); emit_testimm(s,imm); //emit_addimm(sr,-1,temp); assem_debug("lea -1(%%%s),%%%s\n",regname[sr],regname[temp]); output_byte(0x8D); output_modrm(1,sr,temp); output_byte(0xFF); emit_cmovne_reg(temp,sr); } void emit_cmpeq(int s1, int s2, int sr, int temp) { assert(temp>=0); emit_orimm(sr,1,sr); emit_addimm(sr,-1,temp); emit_cmp(s1,s2); emit_cmovne_reg(temp,sr); } void emit_cmpeqimm(int s, int imm, int sr, int temp) { assert(temp>=0); emit_orimm(sr,1,sr); emit_addimm(sr,-1,temp); emit_cmpimm(s,imm); emit_cmovne_reg(temp,sr); } void emit_cmpge(int s1, int s2, int sr, int temp) { assert(temp>=0); emit_orimm(sr,1,sr); emit_addimm(sr,-1,temp); emit_cmp(s2,s1); emit_cmovl_reg(temp,sr); } void emit_cmpgt(int s1, int s2, int sr, int temp) { assert(temp>=0); emit_orimm(sr,1,sr); emit_addimm(sr,-1,temp); emit_cmp(s2,s1); emit_cmovle_reg(temp,sr); } void emit_cmphi(int s1, int s2, int sr, int temp) { emit_andimm(sr,~1,sr); emit_cmp(s1,s2); emit_adcimm(0,sr); } void emit_cmphs(int s1, int s2, int sr, int temp) { emit_orimm(sr,1,sr); emit_cmp(s2,s1); emit_sbbimm(0,sr); } void emit_dt(int t, int sr) { emit_addimm(t,-2,t); emit_shrimm(sr,1,sr); emit_addimm(t,1,t); emit_adc(sr,sr); } void emit_cmppz(int s, int sr) { emit_shrimm(sr,1,sr); emit_cmpimm(s,0x80000000); emit_adc(sr,sr); } void emit_cmppl(int s, int sr, int temp) { assert(temp>=0); emit_orimm(sr,1,sr); emit_addimm(sr,-1,temp); emit_test(s,s); emit_cmovle_reg(temp,sr); } void emit_addc(int s, int t, int sr) { emit_shrimm(sr,1,sr); emit_adc(s,t); emit_adc(sr,sr); } void emit_subc(int s, int t, int sr) { emit_shrimm(sr,1,sr); emit_sbb(s,t); emit_adc(sr,sr); } void emit_shrsr(int t, int sr) { emit_shrimm(sr,1,sr); emit_shrimm(t,1,t); emit_adc(sr,sr); } void emit_sarsr(int t, int sr) { emit_shrimm(sr,1,sr); emit_sarimm(t,1,t); emit_adc(sr,sr); } void emit_shlsr(int t, int sr) { emit_shrimm(sr,1,sr); emit_shlimm(t,1,t); emit_adc(sr,sr); } void emit_rotl(int t) { assem_debug("rol %%%s\n",regname[t]); output_byte(0xD1); output_modrm(3,t,0); } void emit_rotlsr(int t, int sr) { emit_shrimm(sr,1,sr); emit_rotl(t); emit_adc(sr,sr); } void emit_rotr(int t) { assem_debug("ror %%%s\n",regname[t]); output_byte(0xD1); output_modrm(3,t,1); } void emit_rotrsr(int t, int sr) { emit_shrimm(sr,1,sr); emit_rotr(t); emit_adc(sr,sr); } void emit_rotclsr(int t, int sr) { emit_shrimm(sr,1,sr); assem_debug("rcl %%%s\n",regname[t]); output_byte(0xD1); output_modrm(3,t,2); emit_adc(sr,sr); } void emit_rotcrsr(int t, int sr) { emit_shrimm(sr,1,sr); assem_debug("rcr %%%s\n",regname[t]); output_byte(0xD1); output_modrm(3,t,3); emit_adc(sr,sr); } void emit_call(int a) { assem_debug("call %x (%x+%x)\n",a,(int)out+5,a-(int)out-5); output_byte(0xe8); output_w32(a-(int)out-4); } void emit_jmp(int a) { assem_debug("jmp %x (%x+%x)\n",a,(int)out+5,a-(int)out-5); output_byte(0xe9); output_w32(a-(int)out-4); } void emit_jne(int a) { assem_debug("jne %x\n",a); output_byte(0x0f); output_byte(0x85); output_w32(a-(int)out-4); } void emit_jeq(int a) { assem_debug("jeq %x\n",a); output_byte(0x0f); output_byte(0x84); output_w32(a-(int)out-4); } void emit_js(int a) { assem_debug("js %x\n",a); output_byte(0x0f); output_byte(0x88); output_w32(a-(int)out-4); } void emit_jns(int a) { assem_debug("jns %x\n",a); output_byte(0x0f); output_byte(0x89); output_w32(a-(int)out-4); } void emit_jl(int a) { assem_debug("jl %x\n",a); output_byte(0x0f); output_byte(0x8c); output_w32(a-(int)out-4); } void emit_jge(int a) { assem_debug("jge %x\n",a); output_byte(0x0f); output_byte(0x8d); output_w32(a-(int)out-4); } void emit_jno(int a) { assem_debug("jno %x\n",a); output_byte(0x0f); output_byte(0x81); output_w32(a-(int)out-4); } void emit_jc(int a) { assem_debug("jc %x\n",a); output_byte(0x0f); output_byte(0x82); output_w32(a-(int)out-4); } void emit_pushimm(int imm) { assem_debug("push $%x\n",imm); output_byte(0x68); output_w32(imm); } void emit_pushmem(int addr) { assem_debug("push *%x\n",addr); output_byte(0xFF); output_modrm(0,5,6); output_w32(addr); } void emit_pusha() { assem_debug("pusha\n"); output_byte(0x60); } void emit_popa() { assem_debug("popa\n"); output_byte(0x61); } void emit_pushreg(unsigned int r) { assem_debug("push %%%s\n",regname[r]); assert(r<8); output_byte(0x50+r); } void emit_popreg(unsigned int r) { assem_debug("pop %%%s\n",regname[r]); assert(r<8); output_byte(0x58+r); } void emit_callreg(unsigned int r) { assem_debug("call *%%%s\n",regname[r]); assert(r<8); output_byte(0xFF); output_modrm(3,r,2); } void emit_jmpreg(unsigned int r) { assem_debug("jmp *%%%s\n",regname[r]); assert(r<8); output_byte(0xFF); output_modrm(3,r,4); } void emit_jmpmem_indexed(u32 addr,unsigned int r) { assem_debug("jmp *%x(%%%s)\n",addr,regname[r]); assert(r<8); output_byte(0xFF); output_modrm(2,r,4); output_w32(addr); } void emit_cmpstr(int s1, int s2, int sr, int temp) { // Compare s1 and s2. If any byte is equal, set T. // Calculates the xor of the strings, then checks if any byte is // zero by subtracting 1 from each byte. If there is a carry/borrow // then a byte was zero. assert(temp>=0); emit_pushreg(s2); emit_xor(s1,s2,s2); emit_shrimm(sr,1,sr); emit_mov(s2,temp); emit_addimm_and_set_flags(0-0x01010101,temp); emit_adcimm(-1,temp); emit_not(s2,s2); emit_xor(temp,s2,temp); emit_andimm(temp,0x01010101,temp); emit_addimm_and_set_flags(-1,temp); emit_adc(sr,sr); emit_popreg(s2); } void emit_negc(int rs, int rt, int sr) { assert(rs>=0&&rs<8); if(rt<0) { emit_shrimm(sr,1,sr); // Get C flag emit_jc((pointer)out+10); // 6 emit_neg(rs,rs); // 2 emit_neg(rs,rs); // 2 emit_adc(sr,sr); // Save C flag }else{ if(rs!=rt) emit_mov(rs,rt); emit_shrimm(sr,1,sr); // Get C flag emit_jc((pointer)out+9); // 6 emit_addimm(rt,-1,rt); // 3 emit_adc(sr,sr); // Save C flag emit_not(rt,rt); } } void emit_readword(int addr, int rt) { assem_debug("mov %x,%%%s\n",addr,regname[rt]); output_byte(0x8B); output_modrm(0,5,rt); output_w32(addr); } void emit_readword_indexed(int addr, int rs, int rt) { assem_debug("mov %x+%%%s,%%%s\n",addr,regname[rs],regname[rt]); output_byte(0x8B); if(addr<128&&addr>=-128) { output_modrm(1,rs,rt); if(rs==ESP) output_sib(0,4,4); output_byte(addr); } else { output_modrm(2,rs,rt); if(rs==ESP) output_sib(0,4,4); output_w32(addr); } } void emit_readword_map(int addr, int map, int rt) { if(map<0) emit_readword(addr, rt); else { assem_debug("mov (%x,%%%s,4),%%%s\n",addr,regname[map],regname[rt]); output_byte(0x8B); output_modrm(0,4,rt); output_sib(2,map,5); output_w32(addr); } } void emit_readword_indexed_map(int addr, int rs, int map, int rt) { assert(map>=0); if(map<0) emit_readword_indexed(addr, rs, rt); else { assem_debug("mov %x(%%%s,%%%s,4),%%%s\n",addr,regname[rs],regname[map],regname[rt]); assert(rs!=ESP); output_byte(0x8B); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(2,map,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(2,map,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(2,map,rs); output_w32(addr); } } } void emit_movmem_indexedx4(int addr, int rs, int rt) { assem_debug("mov (%x,%%%s,4),%%%s\n",addr,regname[rs],regname[rt]); output_byte(0x8B); output_modrm(0,4,rt); output_sib(2,rs,5); output_w32(addr); } void emit_movsbl(int addr, int rt) { assem_debug("movsbl %x,%%%s\n",addr,regname[rt]); output_byte(0x0F); output_byte(0xBE); output_modrm(0,5,rt); output_w32(addr); } void emit_movsbl_indexed(int addr, int rs, int rt) { assem_debug("movsbl %x+%%%s,%%%s\n",addr,regname[rs],regname[rt]); output_byte(0x0F); output_byte(0xBE); output_modrm(2,rs,rt); output_w32(addr); } void emit_movsbl_map(int addr, int map, int rt) { if(map<0) emit_movsbl(addr, rt); else { assem_debug("movsbl (%x,%%%s,4),%%%s\n",addr,regname[map],regname[rt]); output_byte(0x0F); output_byte(0xBE); output_modrm(0,4,rt); output_sib(2,map,5); output_w32(addr); } } void emit_movsbl_indexed_map(int addr, int rs, int map, int rt) { if(map<0) emit_movsbl_indexed(addr, rs, rt); else { assem_debug("movsbl %x(%%%s,%%%s,4),%%%s\n",addr,regname[rs],regname[map],regname[rt]); assert(rs!=ESP); output_byte(0x0F); output_byte(0xBE); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(2,map,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(2,map,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(2,map,rs); output_w32(addr); } } } void emit_movswl(int addr, int rt) { assem_debug("movswl %x,%%%s\n",addr,regname[rt]); output_byte(0x0F); output_byte(0xBF); output_modrm(0,5,rt); output_w32(addr); } void emit_movswl_indexed(int addr, int rs, int rt) { assem_debug("movswl %x+%%%s,%%%s\n",addr,regname[rs],regname[rt]); output_byte(0x0F); output_byte(0xBF); output_modrm(2,rs,rt); output_w32(addr); } void emit_movswl_map(int addr, int map, int rt) { if(map<0) emit_movswl(addr, rt); else { assem_debug("movswl (%x,%%%s,4),%%%s\n",addr,regname[map],regname[rt]); output_byte(0x0F); output_byte(0xBF); output_modrm(0,4,rt); output_sib(2,map,5); output_w32(addr); } } void emit_movswl_indexed_map(int addr, int rs, int map, int rt) { assert(map>=0); if(map<0) emit_movswl_indexed(addr, rs, rt); else { assem_debug("movswl %x(%%%s,%%%s,4),%%%s\n",addr,regname[rs],regname[map],regname[rt]); assert(rs!=ESP); output_byte(0x0F); output_byte(0xBF); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(2,map,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(2,map,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(2,map,rs); output_w32(addr); } } } void emit_movzbl(int addr, int rt) { assem_debug("movzbl %x,%%%s\n",addr,regname[rt]); output_byte(0x0F); output_byte(0xB6); output_modrm(0,5,rt); output_w32(addr); } void emit_movzbl_indexed(int addr, int rs, int rt) { assem_debug("movzbl %x+%%%s,%%%s\n",addr,regname[rs],regname[rt]); output_byte(0x0F); output_byte(0xB6); output_modrm(2,rs,rt); output_w32(addr); } void emit_movzbl_map(int addr, int map, int rt) { if(map<0) emit_movzbl(addr, rt); else { assem_debug("movzbl (%x,%%%s,4),%%%s\n",addr,regname[map],regname[rt]); output_byte(0x0F); output_byte(0xB6); output_modrm(0,4,rt); output_sib(2,map,5); output_w32(addr); } } void emit_movzbl_indexed_map(int addr, int rs, int map, int rt) { if(map<0) emit_movzbl_indexed(addr, rs, rt); else { assem_debug("movzbl %x(%%%s,%%%s,4),%%%s\n",addr,regname[rs],regname[map],regname[rt]); assert(rs!=ESP); output_byte(0x0F); output_byte(0xB6); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(2,map,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(2,map,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(2,map,rs); output_w32(addr); } } } void emit_movzwl(int addr, int rt) { assem_debug("movzwl %x,%%%s\n",addr,regname[rt]); output_byte(0x0F); output_byte(0xB7); output_modrm(0,5,rt); output_w32(addr); } void emit_movzwl_indexed(int addr, int rs, int rt) { assem_debug("movzwl %x+%%%s,%%%s\n",addr,regname[rs],regname[rt]); output_byte(0x0F); output_byte(0xB7); output_modrm(2,rs,rt); output_w32(addr); } void emit_movzwl_map(int addr, int map, int rt) { if(map<0) emit_movzwl(addr, rt); else { assem_debug("movzwl (%x,%%%s,4),%%%s\n",addr,regname[map],regname[rt]); output_byte(0x0F); output_byte(0xB7); output_modrm(0,4,rt); output_sib(2,map,5); output_w32(addr); } } void emit_xchg(int rs, int rt) { assem_debug("xchg %%%s,%%%s\n",regname[rs],regname[rt]); if(rs==EAX) { output_byte(0x90+rt); } else { output_byte(0x87); output_modrm(3,rs,rt); } } void emit_writeword(int rt, int addr) { assem_debug("movl %%%s,%x\n",regname[rt],addr); output_byte(0x89); output_modrm(0,5,rt); output_w32(addr); } void emit_writeword_indexed(int rt, int addr, int rs) { assem_debug("mov %%%s,%x+%%%s\n",regname[rt],addr,regname[rs]); output_byte(0x89); if(addr<128&&addr>=-128) { output_modrm(1,rs,rt); if(rs==ESP) output_sib(0,4,4); output_byte(addr); } else { output_modrm(2,rs,rt); if(rs==ESP) output_sib(0,4,4); output_w32(addr); } } #if 0 void emit_writeword_map(int rt, int addr, int map) { if(map<0) { emit_writeword(rt, addr+(int)rdram-0x80000000); } else { emit_writeword_indexed(rt, addr+(int)rdram-0x80000000, map); } } #endif void emit_writeword_indexed_map(int rt, int addr, int rs, int map, int temp) { if(map<0) emit_writeword_indexed(rt, addr, rs); else { assem_debug("mov %%%s,%x(%%%s,%%%s,1)\n",regname[rt],addr,regname[rs],regname[map]); assert(rs!=ESP); output_byte(0x89); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(0,map,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(0,map,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(0,map,rs); output_w32(addr); } } } void emit_writehword(int rt, int addr) { assem_debug("movw %%%s,%x\n",regname[rt]+1,addr); output_byte(0x66); output_byte(0x89); output_modrm(0,5,rt); output_w32(addr); } void emit_writehword_indexed(int rt, int addr, int rs) { assem_debug("movw %%%s,%x+%%%s\n",regname[rt]+1,addr,regname[rs]); output_byte(0x66); output_byte(0x89); if(addr<128&&addr>=-128) { output_modrm(1,rs,rt); output_byte(addr); } else { output_modrm(2,rs,rt); output_w32(addr); } } #if 0 void emit_writehword_map(int rt, int addr, int map) { if(map<0) { emit_writehword(rt, addr+(int)rdram-0x80000000); } else { emit_writehword_indexed(rt, addr+(int)rdram-0x80000000, map); } } #endif void emit_writehword_indexed_map(int rt, int addr, int rs, int map, int temp) { if(map<0) emit_writeword_indexed(rt, addr, rs); else { assem_debug("movw %%%s,%x(%%%s,%%%s,1)\n",regname[rt]+1,addr,regname[rs],regname[map]); assert(rs!=ESP); output_byte(0x66); output_byte(0x89); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(0,map,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(0,map,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(0,map,rs); output_w32(addr); } } } void emit_writebyte(int rt, int addr) { if(rt<4) { assem_debug("movb %%%cl,%x\n",regname[rt][1],addr); output_byte(0x88); output_modrm(0,5,rt); output_w32(addr); } else { emit_xchg(EAX,rt); emit_writebyte(EAX,addr); emit_xchg(EAX,rt); } } void emit_writebyte_indexed(int rt, int addr, int rs) { if(rt<4) { assem_debug("movb %%%cl,%x+%%%s\n",regname[rt][1],addr,regname[rs]); output_byte(0x88); if(addr<128&&addr>=-128) { output_modrm(1,rs,rt); output_byte(addr); } else { output_modrm(2,rs,rt); output_w32(addr); } } else { emit_xchg(EAX,rt); emit_writebyte_indexed(EAX,addr,rs==EAX?rt:rs); emit_xchg(EAX,rt); } } #if 0 void emit_writebyte_map(int rt, int addr, int map) { if(map<0) { emit_writebyte(rt, addr+(int)rdram-0x80000000); } else { emit_writebyte_indexed(rt, addr+(int)rdram-0x80000000, map); } } #endif void emit_writebyte_indexed_map(int rt, int addr, int rs, int map, int temp) { if(map<0) emit_writebyte_indexed(rt, addr, rs); else if(rt<4) { assem_debug("movb %%%cl,%x(%%%s,%%%s,1)\n",regname[rt][1],addr,regname[rs],regname[map]); assert(rs!=ESP); output_byte(0x88); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(0,map,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(0,map,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(0,map,rs); output_w32(addr); } } else { emit_xchg(EAX,rt); emit_writebyte_indexed_map(EAX,addr,rs==EAX?rt:rs,map==EAX?rt:map,temp); emit_xchg(EAX,rt); } } void emit_writeword_imm(int imm, int addr) { assem_debug("movl $%x,%x\n",imm,addr); output_byte(0xC7); output_modrm(0,5,0); output_w32(addr); output_w32(imm); } void emit_writeword_imm_esp(int imm, int addr) { assem_debug("mov $%x,%x(%%esp)\n",imm,addr); assert(addr>=-128&&addr<128); output_byte(0xC7); output_modrm(1,4,0); output_sib(0,4,4); output_byte(addr); output_w32(imm); } void emit_writebyte_imm(int imm, int addr) { assem_debug("movb $%x,%x\n",imm,addr); assert(imm>=-128&&imm<128); output_byte(0xC6); output_modrm(0,5,0); output_w32(addr); output_byte(imm); } void emit_writebyte_imm_esp(int imm, int addr) { assem_debug("movb $%x,%x(%%esp)\n",imm,addr); assert(addr>=-128&&addr<128); output_byte(0xC6); output_modrm(1,4,0); output_sib(0,4,4); output_byte(addr); output_byte(imm); } void emit_rmw_andimm(int addr, int map, int imm) { if(map<0) { assem_debug("andb $0x%x,(%%%s)\n",imm,regname[addr]); assert(addr!=ESP); output_byte(0x80); output_modrm(0,addr,4); } else { assem_debug("andb $0x%x,(%%%s,%%%s,1)\n",imm,regname[addr],regname[map]); assert(addr!=ESP); output_byte(0x80); output_modrm(0,4,4); if(addr!=EBP) { output_sib(0,map,addr); } else { assert(addr!=map); output_sib(0,addr,map); } } output_byte(imm); } void emit_rmw_xorimm(int addr, int map, int imm) { if(map<0) { assem_debug("xorb $0x%x,(%%%s)\n",imm,regname[addr]); assert(addr!=ESP); output_byte(0x80); output_modrm(0,addr,6); } else { assem_debug("xorb $0x%x,(%%%s,%%%s,1)\n",imm,regname[addr],regname[map]); assert(addr!=ESP); output_byte(0x80); output_modrm(0,4,6); if(addr!=EBP) { output_sib(0,map,addr); } else { assert(addr!=map); output_sib(0,addr,map); } } output_byte(imm); } void emit_rmw_orimm(int addr, int map, int imm) { if(map<0) { assem_debug("orb $0x%x,(%%%s)\n",imm,regname[addr]); assert(addr!=ESP); output_byte(0x80); output_modrm(0,addr,1); } else { assem_debug("orb $0x%x,(%%%s,%%%s,1)\n",imm,regname[addr],regname[map]); assert(addr!=ESP); output_byte(0x80); output_modrm(0,4,1); if(addr!=EBP) { output_sib(0,map,addr); } else { assert(addr!=map); output_sib(0,addr,map); } } output_byte(imm); } void emit_sh2tas(int addr, int map, int sr) { emit_shrimm(sr,1,sr); if(map<0) { assem_debug("cmpb $1,(%%%s)\n",regname[addr]); assert(addr!=ESP); output_byte(0x80); output_modrm(0,addr,7); } else { assem_debug("cmpb $1,(%%%s,%%%s,1)\n",regname[addr],regname[map]); assert(addr!=ESP); output_byte(0x80); output_modrm(0,4,7); if(addr!=EBP) { output_sib(0,map,addr); } else { assert(addr!=map); output_sib(0,addr,map); } } output_byte(1); emit_adc(sr,sr); emit_rmw_orimm(addr,map,0x80); } void emit_mul(int rs) { assem_debug("mul %%%s\n",regname[rs]); output_byte(0xF7); output_modrm(3,rs,4); } void emit_imul(int rs) { assem_debug("imul %%%s\n",regname[rs]); output_byte(0xF7); output_modrm(3,rs,5); } void emit_multiply(int rs1,int rs2,int rt) { if(rs1==rt) { assem_debug("imul %%%s,%%%s\n",regname[rs2],regname[rt]); output_byte(0x0F); output_byte(0xAF); output_modrm(3,rs2,rt); } else { emit_mov(rs1,rt); emit_multiply(rt,rs2,rt); } } void emit_div(int rs) { assem_debug("div %%%s\n",regname[rs]); output_byte(0xF7); output_modrm(3,rs,6); } void emit_idiv(int rs) { assem_debug("idiv %%%s\n",regname[rs]); output_byte(0xF7); output_modrm(3,rs,7); } void emit_cdq() { assem_debug("cdq\n"); output_byte(0x99); } void emit_div0s(int s1, int s2, int sr, int temp) { emit_shlimm(sr,24,sr); emit_mov(s2,temp); assem_debug("bt %%%s,31\n",regname[s2]); output_byte(0x0f); output_byte(0xba); output_modrm(3,s2,4); output_byte(0x1f); assem_debug("rcr %%%s\n",regname[sr]); output_byte(0xD1); output_modrm(3,sr,3); emit_xor(temp,s1,temp); assem_debug("bt %%%s,31\n",regname[s1]); output_byte(0x0f); output_byte(0xba); output_modrm(3,s1,4); output_byte(0x1f); assem_debug("rcr %%%s,24\n",regname[sr]); output_byte(0xc1); output_modrm(3,sr,3); output_byte(24); assem_debug("bt %%%s,31\n",regname[temp]); output_byte(0x0f); output_byte(0xba); output_modrm(3,temp,4); output_byte(0x1f); emit_adc(sr,sr); } // Load return address void emit_load_return_address(unsigned int rt) { // (assumes this instruction will be followed by a 5-byte jmp instruction) emit_movimm((pointer)out+10,rt); } // Load 2 immediates optimizing for small code size void emit_mov2imm_compact(int imm1,unsigned int rt1,int imm2,unsigned int rt2) { emit_movimm(imm1,rt1); if(imm2-imm1<128&&imm2-imm1>=-128) emit_addimm(rt1,imm2-imm1,rt2); else emit_movimm(imm2,rt2); } // compare byte in memory void emit_cmpmem_imm_byte(pointer addr,int imm) { assert(imm<128&&imm>=-127); assem_debug("cmpb $%d,%x\n",imm,addr); output_byte(0x80); output_modrm(0,5,7); output_w32(addr); output_byte(imm); } // special case for checking invalid_code void emit_cmpmem_indexedsr12_imm(int addr,int r,int imm) { assert(imm<128&&imm>=-127); assert(r>=0&&r<8); emit_shrimm(r,12,r); assem_debug("cmp $%d,%x+%%%s\n",imm,addr,regname[r]); output_byte(0x80); output_modrm(2,r,7); output_w32(addr); output_byte(imm); } // special case for checking hash_table void emit_cmpmem_indexed(int addr,int rs,int rt) { assert(rs>=0&&rs<8); assert(rt>=0&&rt<8); assem_debug("cmp %x+%%%s,%%%s\n",addr,regname[rs],regname[rt]); output_byte(0x39); output_modrm(2,rs,rt); output_w32(addr); } // special case for checking memory_map in verify_mapping void emit_cmpmem(int addr,int rt) { assert(rt>=0&&rt<8); assem_debug("cmp %x,%%%s\n",addr,regname[rt]); output_byte(0x39); output_modrm(0,5,rt); output_w32(addr); } // Used to preload hash table entries void emit_prefetch(void *addr) { assem_debug("prefetch %x\n",(int)addr); output_byte(0x0F); output_byte(0x18); output_modrm(0,5,1); output_w32((int)addr); } /*void emit_submem(int r,int addr) { assert(r>=0&&r<8); assem_debug("sub %x,%%%s\n",addr,regname[r]); output_byte(0x2B); output_modrm(0,5,r); output_w32((int)addr); }*/ void emit_subfrommem(int addr,int r) { assert(r>=0&&r<8); assem_debug("sub %%%s,%x\n",regname[r],addr); output_byte(0x29); output_modrm(0,5,r); output_w32((int)addr); } void emit_flds(int r) { assem_debug("flds (%%%s)\n",regname[r]); output_byte(0xd9); if(r!=EBP) output_modrm(0,r,0); else {output_modrm(1,EBP,0);output_byte(0);} } void emit_fldl(int r) { assem_debug("fldl (%%%s)\n",regname[r]); output_byte(0xdd); if(r!=EBP) output_modrm(0,r,0); else {output_modrm(1,EBP,0);output_byte(0);} } void emit_fucomip(unsigned int r) { assem_debug("fucomip %d\n",r); assert(r<8); output_byte(0xdf); output_byte(0xe8+r); } void emit_fchs() { assem_debug("fchs\n"); output_byte(0xd9); output_byte(0xe0); } void emit_fabs() { assem_debug("fabs\n"); output_byte(0xd9); output_byte(0xe1); } void emit_fsqrt() { assem_debug("fsqrt\n"); output_byte(0xd9); output_byte(0xfa); } void emit_fadds(int r) { assem_debug("fadds (%%%s)\n",regname[r]); output_byte(0xd8); if(r!=EBP) output_modrm(0,r,0); else {output_modrm(1,EBP,0);output_byte(0);} } void emit_faddl(int r) { assem_debug("faddl (%%%s)\n",regname[r]); output_byte(0xdc); if(r!=EBP) output_modrm(0,r,0); else {output_modrm(1,EBP,0);output_byte(0);} } void emit_fadd(int r) { assem_debug("fadd st%d\n",r); output_byte(0xd8); output_byte(0xc0+r); } void emit_fsubs(int r) { assem_debug("fsubs (%%%s)\n",regname[r]); output_byte(0xd8); if(r!=EBP) output_modrm(0,r,4); else {output_modrm(1,EBP,4);output_byte(0);} } void emit_fsubl(int r) { assem_debug("fsubl (%%%s)\n",regname[r]); output_byte(0xdc); if(r!=EBP) output_modrm(0,r,4); else {output_modrm(1,EBP,4);output_byte(0);} } void emit_fsub(int r) { assem_debug("fsub st%d\n",r); output_byte(0xd8); output_byte(0xe0+r); } void emit_fmuls(int r) { assem_debug("fmuls (%%%s)\n",regname[r]); output_byte(0xd8); if(r!=EBP) output_modrm(0,r,1); else {output_modrm(1,EBP,1);output_byte(0);} } void emit_fmull(int r) { assem_debug("fmull (%%%s)\n",regname[r]); output_byte(0xdc); if(r!=EBP) output_modrm(0,r,1); else {output_modrm(1,EBP,1);output_byte(0);} } void emit_fmul(int r) { assem_debug("fmul st%d\n",r); output_byte(0xd8); output_byte(0xc8+r); } void emit_fdivs(int r) { assem_debug("fdivs (%%%s)\n",regname[r]); output_byte(0xd8); if(r!=EBP) output_modrm(0,r,6); else {output_modrm(1,EBP,6);output_byte(0);} } void emit_fdivl(int r) { assem_debug("fdivl (%%%s)\n",regname[r]); output_byte(0xdc); if(r!=EBP) output_modrm(0,r,6); else {output_modrm(1,EBP,6);output_byte(0);} } void emit_fdiv(int r) { assem_debug("fdiv st%d\n",r); output_byte(0xd8); output_byte(0xf0+r); } void emit_fpop() { // fstp st(0) assem_debug("fpop\n"); output_byte(0xdd); output_byte(0xd8); } void emit_fildl(int r) { assem_debug("fildl (%%%s)\n",regname[r]); output_byte(0xdb); if(r!=EBP) output_modrm(0,r,0); else {output_modrm(1,EBP,0);output_byte(0);} } void emit_fildll(int r) { assem_debug("fildll (%%%s)\n",regname[r]); output_byte(0xdf); if(r!=EBP) output_modrm(0,r,5); else {output_modrm(1,EBP,5);output_byte(0);} } void emit_fistpl(int r) { assem_debug("fistpl (%%%s)\n",regname[r]); output_byte(0xdb); if(r!=EBP) output_modrm(0,r,3); else {output_modrm(1,EBP,3);output_byte(0);} } void emit_fistpll(int r) { assem_debug("fistpll (%%%s)\n",regname[r]); output_byte(0xdf); if(r!=EBP) output_modrm(0,r,7); else {output_modrm(1,EBP,7);output_byte(0);} } void emit_fstps(int r) { assem_debug("fstps (%%%s)\n",regname[r]); output_byte(0xd9); if(r!=EBP) output_modrm(0,r,3); else {output_modrm(1,EBP,3);output_byte(0);} } void emit_fstpl(int r) { assem_debug("fstpl (%%%s)\n",regname[r]); output_byte(0xdd); if(r!=EBP) output_modrm(0,r,3); else {output_modrm(1,EBP,3);output_byte(0);} } void emit_fnstcw_stack() { assem_debug("fnstcw (%%esp)\n"); output_byte(0xd9); output_modrm(0,4,7); output_sib(0,4,4); } void emit_fldcw_stack() { assem_debug("fldcw (%%esp)\n"); output_byte(0xd9); output_modrm(0,4,5); output_sib(0,4,4); } void emit_fldcw_indexed(int addr,int r) { assem_debug("fldcw %x(%%%s)\n",addr,regname[r]); output_byte(0xd9); output_modrm(0,4,5); output_sib(1,r,5); output_w32(addr); } void emit_fldcw(int addr) { assem_debug("fldcw %x\n",addr); output_byte(0xd9); output_modrm(0,5,5); output_w32(addr); } void emit_movss_load(unsigned int addr,unsigned int ssereg) { assem_debug("movss (%%%s),xmm%d\n",regname[addr],ssereg); assert(ssereg<8); output_byte(0xf3); output_byte(0x0f); output_byte(0x10); if(addr!=EBP) output_modrm(0,addr,ssereg); else {output_modrm(1,EBP,ssereg);output_byte(0);} } void emit_movsd_load(unsigned int addr,unsigned int ssereg) { assem_debug("movsd (%%%s),xmm%d\n",regname[addr],ssereg); assert(ssereg<8); output_byte(0xf2); output_byte(0x0f); output_byte(0x10); if(addr!=EBP) output_modrm(0,addr,ssereg); else {output_modrm(1,EBP,ssereg);output_byte(0);} } void emit_movd_store(unsigned int ssereg,unsigned int addr) { assem_debug("movd xmm%d,(%%%s)\n",ssereg,regname[addr]); assert(ssereg<8); output_byte(0x66); output_byte(0x0f); output_byte(0x7e); if(addr!=EBP) output_modrm(0,addr,ssereg); else {output_modrm(1,EBP,ssereg);output_byte(0);} } void emit_cvttps2dq(unsigned int ssereg1,unsigned int ssereg2) { assem_debug("cvttps2dq xmm%d,xmm%d\n",ssereg1,ssereg2); assert(ssereg1<8); assert(ssereg2<8); output_byte(0xf3); output_byte(0x0f); output_byte(0x5b); output_modrm(3,ssereg1,ssereg2); } void emit_cvttpd2dq(unsigned int ssereg1,unsigned int ssereg2) { assem_debug("cvttpd2dq xmm%d,xmm%d\n",ssereg1,ssereg2); assert(ssereg1<8); assert(ssereg2<8); output_byte(0x66); output_byte(0x0f); output_byte(0xe6); output_modrm(3,ssereg1,ssereg2); } unsigned int count_bits(u32 reglist) { int count=0; while(reglist) { count+=reglist&1; reglist>>=1; } return count; } // Save registers before function call // This code is executed infrequently so we try to minimize code size // by pushing registers onto the stack instead of writing them to their // usual locations void save_regs(u32 reglist) { reglist&=0x7; // only save the caller-save registers, %eax, %ecx, %edx int hr; int count=count_bits(reglist); if(count) { for(hr=0;hr>hr)&1) { emit_pushreg(hr); } } } } if(slave) emit_addimm(ESP,-(4-count)*4,ESP); // slave has master's return address on stack else emit_addimm(ESP,-(5-count)*4,ESP); } // Restore registers after function call void restore_regs(u32 reglist) { int hr; reglist&=0x7; // only save the caller-save registers, %eax, %ecx, %edx int count=count_bits(reglist); if(slave) emit_addimm(ESP,(4-count)*4,ESP); else emit_addimm(ESP,(5-count)*4,ESP); if(count) { for(hr=HOST_REGS-1;hr>=0;hr--) { if(hr!=EXCLUDE_REG) { if((reglist>>hr)&1) { emit_popreg(hr); } } } } } /* Stubs/epilogue */ void emit_extjump(pointer addr, int target) { u8 *ptr=(u8 *)addr; if(*ptr==0x0f) { assert(ptr[1]>=0x80&&ptr[1]<=0x8f); addr+=2; } else { assert(*ptr==0xe8||*ptr==0xe9); addr++; } emit_movimm(target,EAX); //emit_movimm(target|slave,EAX); emit_movimm(addr,EBX); //assert(addr>=0x7000000&&addr<0x7FFFFFF); //DEBUG > #ifdef DEBUG_CYCLE_COUNT emit_readword((int)&last_count,ECX); emit_add(HOST_CCREG,ECX,HOST_CCREG); emit_readword((int)&next_interupt,ECX); emit_writeword(HOST_CCREG,(int)&Count); emit_sub(HOST_CCREG,ECX,HOST_CCREG); emit_writeword(ECX,(int)&last_count); #endif //DEBUG < emit_jmp((pointer)dyna_linker); } void do_readstub(int n) { assem_debug("do_readstub %x\n",start+stubs[n][3]*2); set_jump_target(stubs[n][1],(int)out); int type=stubs[n][0]; int i=stubs[n][3]; int rs=stubs[n][4]; struct regstat *i_regs=(struct regstat *)stubs[n][5]; u32 reglist=stubs[n][7]; signed char *i_regmap=i_regs->regmap; int addr=get_reg(i_regmap,AGEN1+(i&1)); int rt; rt=get_reg(i_regmap,rt1[i]==TBIT?-1:rt1[i]); assert(rs>=0); if(addr<0) addr=rt; if(addr<0) addr=get_reg(i_regmap,-1); assert(addr>=0); save_regs(reglist); if(rs!=EAX) emit_mov(rs,EAX); if(type==LOADB_STUB) emit_xorimm(EAX,1,EAX); //if(i_regmap[HOST_CCREG]==CCREG) emit_storereg(CCREG,HOST_CCREG);//DEBUG /*if(i_regmap[HOST_CCREG]==CCREG) { emit_addimm(HOST_CCREG,CLOCK_DIVIDER*(stubs[n][6]),HOST_CCREG); output_byte(0x03); output_modrm(1,4,HOST_CCREG); output_sib(0,4,4); output_byte(12+16); //emit_writeword(HOST_CCREG,(int)&MSH2->cycles); emit_writeword(HOST_CCREG,slave?(int)&SSH2->cycles:(int)&MSH2->cycles); output_byte(0x2B); output_modrm(1,4,HOST_CCREG); output_sib(0,4,4); output_byte(12+16); emit_addimm(HOST_CCREG,-CLOCK_DIVIDER*(stubs[n][6]),HOST_CCREG); } if(i_regmap[HOST_CCREG]!=CCREG) { emit_loadreg(CCREG,ECX); emit_addimm(ECX,CLOCK_DIVIDER*(stubs[n][6]),ECX); output_byte(0x03); output_modrm(1,4,ECX); output_sib(0,4,4); output_byte(12+16); //emit_writeword(ECX,(int)&MSH2->cycles); emit_writeword(ECX,slave?(int)&SSH2->cycles:(int)&MSH2->cycles); } /* int temp; int cc=get_reg(i_regmap,CCREG); if(cc<0) { if(addr==HOST_CCREG) { cc=0;temp=1; assert(cc!=HOST_CCREG); assert(temp!=HOST_CCREG); emit_loadreg(CCREG,cc); } else { cc=HOST_CCREG; emit_loadreg(CCREG,cc); temp=!addr; } } else { temp=!addr; }*/ if(type==LOADB_STUB) emit_call((int)MappedMemoryReadByteNocache); if(type==LOADW_STUB) emit_call((int)MappedMemoryReadWordNocache); if(type==LOADL_STUB) emit_call((int)MappedMemoryReadLongNocache); if(type==LOADS_STUB) { // RTE instruction, pop PC and SR from stack int pc=get_reg(i_regmap,RTEMP); assert(pc>=0); if(rs==EAX||rs==ECX||rs==EDX) emit_writeword_indexed(rs,0,ESP); emit_call((int)MappedMemoryReadLongNocache); if(rs==ECX||rs==EDX) emit_readword_indexed(0,ESP,rs); if(pc==EAX) { emit_writeword_indexed(EAX,0,ESP); } else { if(pc==ECX||pc==EDX) emit_writeword_indexed(EAX,0,ESP); else emit_mov(EAX,pc); if(rs==EAX) { emit_readword_indexed(0,ESP,EAX); emit_addimm(EAX,4,EAX); }else emit_addimm(rs,4,EAX); } emit_call((int)MappedMemoryReadLongNocache); assert(rt>=0); if(rt!=EAX) emit_mov(EAX,rt); if(pc==EAX||pc==ECX||pc==EDX) emit_readword_indexed(0,ESP,pc); } else if(type==LOADB_STUB) { if(rt>=0) emit_movsbl_reg(EAX,rt); } else if(type==LOADW_STUB) { if(rt>=0) emit_movswl_reg(EAX,rt); } else { if(rt!=EAX&&rt>=0) emit_mov(EAX,rt); } restore_regs(reglist); if(type==LOADS_STUB) emit_addimm(rs,8,rs); emit_jmp(stubs[n][2]); // return address } void inline_readstub(int type, int i, u32 addr, signed char regmap[], int target, int adj, u32 reglist) { assem_debug("inline_readstub\n"); //int rs=get_reg(regmap,target); int rt=get_reg(regmap,target); //if(rs<0) rs=get_reg(regmap,-1); if(rt<0) rt=get_reg(regmap,-1); //rt=get_reg(i_regmap,rt1[i]==TBIT?-1:rt1[i]); assert(rt>=0); //if(addr<0) addr=rt; //if(addr<0) addr=get_reg(i_regmap,-1); //assert(addr>=0); save_regs(reglist); emit_movimm(addr,EAX); if(type==LOADB_STUB) emit_call((int)MappedMemoryReadByteNocache); if(type==LOADW_STUB) emit_call((int)MappedMemoryReadWordNocache); if(type==LOADL_STUB) emit_call((int)MappedMemoryReadLongNocache); assert(type!=LOADS_STUB); if(type==LOADB_STUB) { if(rt>=0) emit_movsbl_reg(EAX,rt); } else if(type==LOADW_STUB) { if(rt>=0) emit_movswl_reg(EAX,rt); } else { if(rt!=EAX&&rt>=0) emit_mov(EAX,rt); } restore_regs(reglist); } void do_writestub(int n) { assem_debug("do_writestub %x\n",start+stubs[n][3]*2); set_jump_target(stubs[n][1],(int)out); int type=stubs[n][0]; int i=stubs[n][3]; int rs=stubs[n][4]; struct regstat *i_regs=(struct regstat *)stubs[n][5]; u32 reglist=stubs[n][7]; signed char *i_regmap=i_regs->regmap; int addr=get_reg(i_regmap,AGEN1+(i&1)); int rt=get_reg(i_regmap,rs1[i]); assert(rs>=0); assert(rt>=0); if(addr<0) addr=get_reg(i_regmap,-1); assert(addr>=0); save_regs(reglist); // "FASTCALL" api: address in eax, data in edx if(rs!=EAX) { if(rt==EAX) { if(rs==EDX) emit_xchg(EAX,EDX); else { emit_mov(rt,EDX); emit_mov(rs,EAX); } } else { emit_mov(rs,EAX); if(rt!=EDX) emit_mov(rt,EDX); } } else if(rt!=EDX) emit_mov(rt,EDX); //if(type==STOREB_STUB) emit_xorimm(EAX,1,EAX); // WriteInvalidateByteSwapped does this //if(i_regmap[HOST_CCREG]==CCREG) emit_storereg(CCREG,HOST_CCREG);//DEBUG /*if(i_regmap[HOST_CCREG]==CCREG) { emit_addimm(HOST_CCREG,CLOCK_DIVIDER*(stubs[n][6]),HOST_CCREG); output_byte(0x03); output_modrm(1,4,HOST_CCREG); output_sib(0,4,4); output_byte(12+16); //emit_writeword(HOST_CCREG,(int)&MSH2->cycles); emit_writeword(HOST_CCREG,slave?(int)&SSH2->cycles:(int)&MSH2->cycles); output_byte(0x2B); output_modrm(1,4,HOST_CCREG); output_sib(0,4,4); output_byte(12+16); emit_addimm(HOST_CCREG,-CLOCK_DIVIDER*(stubs[n][6]),HOST_CCREG); } if(i_regmap[HOST_CCREG]!=CCREG) { emit_loadreg(CCREG,ECX); emit_addimm(ECX,CLOCK_DIVIDER*(stubs[n][6]),ECX); output_byte(0x03); output_modrm(1,4,ECX); output_sib(0,4,4); output_byte(12+16); //emit_writeword(ECX,(int)&MSH2->cycles); emit_writeword(ECX,slave?(int)&SSH2->cycles:(int)&MSH2->cycles); } //ds=i_regs!=®s[i]; //int real_rs=get_reg(i_regmap,rs2[i]); //if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty&~(1<regmap_entry,i_regs->was32,i_regs->wasdirty&~(1<=0); assert(rt>=0); save_regs(reglist); // "FASTCALL" api: address in eax, data in edx if(rt!=EDX) emit_mov(rt,EDX); emit_movimm(addr,EAX); // FIXME - should be able to move the existing value if(type==STOREB_STUB) emit_call((int)WriteInvalidateByte); if(type==STOREW_STUB) emit_call((int)WriteInvalidateWord); if(type==STOREL_STUB) emit_call((int)WriteInvalidateLong); restore_regs(reglist); } void do_rmwstub(int n) { assem_debug("do_rmwstub %x\n",start+stubs[n][3]*2); set_jump_target(stubs[n][1],(int)out); int type=stubs[n][0]; int i=stubs[n][3]; int rs=stubs[n][4]; struct regstat *i_regs=(struct regstat *)stubs[n][5]; u32 reglist=stubs[n][7]; signed char *i_regmap=i_regs->regmap; int addr=get_reg(i_regmap,AGEN1+(i&1)); //int rt=get_reg(i_regmap,rs1[i]); assert(rs>=0); //assert(rt>=0); if(addr<0) addr=get_reg(i_regmap,-1); assert(addr>=0); save_regs(reglist); // "FASTCALL" api: address in eax, data in edx emit_xorimm(rs,1,rs); if(rs!=EAX) emit_mov(rs,EAX); if(rs==EAX||rs==ECX||rs==EDX) emit_writeword_indexed(rs,0,ESP); //if(i_regmap[HOST_CCREG]==CCREG) emit_storereg(CCREG,HOST_CCREG);//DEBUG /*if(i_regmap[HOST_CCREG]==CCREG) { emit_addimm(HOST_CCREG,CLOCK_DIVIDER*(stubs[n][6]),HOST_CCREG); output_byte(0x03); output_modrm(1,4,HOST_CCREG); output_sib(0,4,4); output_byte(12+16); emit_writeword(HOST_CCREG,(int)&MSH2->cycles); output_byte(0x2B); output_modrm(1,4,HOST_CCREG); output_sib(0,4,4); output_byte(12+16); emit_addimm(HOST_CCREG,-CLOCK_DIVIDER*(stubs[n][6]),HOST_CCREG); } if(i_regmap[HOST_CCREG]!=CCREG) { emit_loadreg(CCREG,ECX); emit_addimm(ECX,CLOCK_DIVIDER*(stubs[n][6]),ECX); output_byte(0x03); output_modrm(1,4,ECX); output_sib(0,4,4); output_byte(12+16); emit_writeword(ECX,(int)&MSH2->cycles); }*/ emit_call((int)MappedMemoryReadByteNocache); emit_mov(EAX,EDX); if(rs==EAX||rs==ECX||rs==EDX) emit_readword_indexed(0,ESP,EAX); else emit_mov(rs,EAX); if(type==RMWA_STUB) emit_andimm(EDX,imm[i],EDX); if(type==RMWX_STUB) emit_xorimm(EDX,imm[i],EDX); if(type==RMWO_STUB) emit_orimm(EDX,imm[i],EDX); if(type==RMWT_STUB) { // TAS.B //emit_writeword_indexed(EDX,0,ESP); emit_writeword(EDX,(pointer)&rmw_temp); emit_orimm(EDX,0x80,EDX); } //emit_call((int)MappedMemoryWriteByte); emit_call((int)WriteInvalidateByte); restore_regs(reglist); if(opcode2[i]==11) { // TAS.B signed char sr; sr=get_reg(i_regs->regmap,SR); assert(sr>=0); // Liveness analysis? emit_andimm(sr,~1,sr); //assem_debug("cmp $%d,%d+%%%s\n",1,-16,regname[ESP]); //output_byte(0x80); //output_modrm(1,4,7); //output_sib(0,4,4); //output_byte(-16); //output_byte(1); emit_cmpmem_imm_byte((pointer)&rmw_temp,1); emit_adcimm(0,sr); } emit_jmp(stubs[n][2]); // return address } void do_unalignedwritestub(int n) { set_jump_target(stubs[n][1],(int)out); output_byte(0xCC); emit_jmp(stubs[n][2]); // return address } void printregs(int edi,int esi,int ebp,int esp,int b,int d,int c,int a) { printf("regs: %x %x %x %x %x %x %x (%x)\n",a,b,c,d,ebp,esi,edi,(&edi)[-1]); } int do_dirty_stub(int i) { assem_debug("do_dirty_stub %x\n",start+i*2); u32 alignedlen=((((u32)source)+slen*2+2)&~2)-(u32)alignedsource; emit_pushimm(start+i*2+slave); emit_movimm(((u32)source)&~3,EAX); //alignedsource emit_movimm((u32)copy,EBX); emit_movimm((((u32)source+slen*2+2)&~3)-((u32)source&~3),ECX); emit_call((int)&verify_code); emit_addimm(ESP,4,ESP); int entry=(int)out; load_regs_entry(i); if(entry==(int)out) entry=instr_addr[i]; emit_jmp(instr_addr[i]); return entry; } /* Memory Map */ int do_map_r(int s,int ar,int map,int cache,int x,int a,int shift,int c,u32 addr) { if(c) { /*if(can_direct_read(addr)) { emit_readword((int)(memory_map+(addr>>12)),map); } else*/ return -1; // No mapping } else { if(s!=map) emit_mov(s,map); emit_shrimm(map,12,map); // Schedule this while we wait on the load if(x) emit_xorimm(s,x,ar); //if(shift>=0) emit_lea8(s,shift); //if(~a) emit_andimm(s,a,ar); emit_movmem_indexedx4((int)memory_map,map,map); } return map; } int do_map_r_branch(int map, int c, u32 addr, int *jaddr) { if(!c) { emit_test(map,map); *jaddr=(int)out; emit_js(0); } return map; } void gen_tlb_addr_r(int ar, int map) { if(map>=0) { emit_leairrx4(0,ar,map,ar); } } int do_map_w(int s,int ar,int map,int cache,int x,int c,u32 addr) { if(c) { if(can_direct_write(addr)) { emit_readword((int)(memory_map+(addr>>12)),map); } else return -1; // No mapping } else { if(s!=map) emit_mov(s,map); //if(s!=ar) emit_mov(s,ar); emit_shrimm(map,12,map); // Schedule this while we wait on the load if(x) emit_xorimm(s,x,ar); emit_movmem_indexedx4((int)memory_map,map,map); } emit_shlimm(map,2,map); return map; } void do_map_w_branch(int map, int c, u32 addr, int *jaddr) { if(!c||can_direct_write(addr)) { *jaddr=(int)out; emit_jc(0); } } void gen_tlb_addr_w(int ar, int map) { if(map>=0) { emit_leairrx1(0,ar,map,ar); } } // We don't need this for x86 void generate_map_const(u32 addr,int reg) { // void *mapaddr=memory_map+(addr>>12); } /* Special assem */ void do_preload_rhash(int r) { emit_movimm(0xf8,r); } void do_preload_rhtbl(int r) { // Don't need this for x86 } void do_rhash(int rs,int rh) { emit_and(rs,rh,rh); } void do_miniht_load(int ht,int rh) { // Don't need this for x86. The load and compare can be combined into // a single instruction (below) } void do_miniht_jump(int rs,int rh,int ht) { emit_cmpmem_indexed(slave?(u32)mini_ht_slave:(u32)mini_ht_master,rh,rs); emit_jne(jump_vaddr_reg[slave][rs]); emit_jmpmem_indexed(slave?(u32)mini_ht_slave+4:(u32)mini_ht_master+4,rh); } void do_miniht_insert(int return_address,int rt,int temp) { emit_movimm(return_address,rt); // PC into link register //emit_writeword_imm(return_address,(int)&mini_ht[(return_address&0xFF)>>8][0]); if(slave) emit_writeword(rt,(int)&mini_ht_slave[(return_address&0xFF)>>3][0]); else emit_writeword(rt,(int)&mini_ht_master[(return_address&0xFF)>>3][0]); add_to_linker((int)out,return_address,1); if(slave) emit_writeword_imm(0,(int)&mini_ht_slave[(return_address&0xFF)>>3][1]); else emit_writeword_imm(0,(int)&mini_ht_master[(return_address&0xFF)>>3][1]); } void wb_valid(signed char pre[],signed char entry[],u32 dirty_pre,u32 dirty,u64 u) { //if(dirty_pre==dirty) return; int hr,reg,new_hr; for(hr=0;hr>(reg&63))&1) { if(reg>=0) { if(((dirty_pre&~dirty)>>hr)&1) { if(reg>=0&®> YABSYS_TIMING_BITS; */ /* const u32 cyclesinc = yabsys.DecilineStop * 10; */ mov decilinestop_p, %rax mov yabsys_timing_bits, %ecx mov (%rax), %eax lea (%eax,%eax,4), %ebx /* decilinestop*5 */ shr %cl, %eax /* decilinecycles */ shl %ebx /* cyclesinc=decilinestop*10 */ lea (%eax,%eax,8), %edx /* decilinecycles*9 */ /* yabsys.SH2CycleFrac += cyclesinc;*/ /* sh2cycles = (yabsys.SH2CycleFrac >> (YABSYS_TIMING_BITS + 1)) << 1;*/ /* yabsys.SH2CycleFrac &= ((YABSYS_TIMING_MASK << 1) | 1);*/ mov SH2CycleFrac_p, %rsi mov yabsys_timing_mask, %edi inc %ecx /* yabsys_timing_bits+1 */ add (%rsi), %ebx /* SH2CycleFrac */ stc adc %edi, %edi /* ((YABSYS_TIMING_MASK << 1) | 1) */ mov %eax, -48(%rbp) /* decilinecycles */ and %ebx, %edi mov %edi, (%rsi) /* SH2CycleFrac */ shr %cl, %ebx mov %ebx, -56(%rbp) /* scucycles */ add %ebx, %ebx /* sh2cycles */ mov MSH2, %rax mov NumberOfInterruptsOffset, %ecx sub %edx, %ebx /* sh2cycles(full line) - decilinecycles*9 */ mov %ebx, -52(%rbp) /* sh2cycles */ cmp $0, (%rax, %rcx) jne master_handle_interrupts mov master_cc, %esi sub %ebx, %esi ret /* jmp master_ip */ .size YabauseDynarecOneFrameExec, .-YabauseDynarecOneFrameExec .globl master_handle_interrupts .type master_handle_interrupts, @function master_handle_interrupts: mov -80(%rbp), %rax /* get return address */ mov %rax, master_ip call DynarecMasterHandleInterrupts mov master_ip, %rax mov master_cc, %esi mov %rax,-80(%rbp) /* overwrite return address */ sub %ebx, %esi ret /* jmp master_ip */ .size master_handle_interrupts, .-master_handle_interrupts .globl slave_entry .type slave_entry, @function slave_entry: mov 28(%rsp), %ebx /* sh2cycles */ mov %esi, master_cc mov %ebx, %edi call FRTExec mov %ebx, %edi call WDTExec mov slave_ip, %rdx test %edx, %edx je cc_interrupt_master /* slave not running */ mov SSH2, %rax mov NumberOfInterruptsOffset, %ecx cmp $0, (%rax, %rcx) jne slave_handle_interrupts mov slave_cc, %esi sub %ebx, %esi jmp *%rdx /* jmp *slave_ip */ .size slave_entry, .-slave_entry .globl slave_handle_interrupts .type slave_handle_interrupts, @function slave_handle_interrupts: call DynarecSlaveHandleInterrupts mov slave_ip, %rdx mov slave_cc, %esi sub %ebx, %esi jmp *%rdx /* jmp *slave_ip */ .size slave_handle_interrupts, .-slave_handle_interrupts .globl cc_interrupt .type cc_interrupt, @function cc_interrupt: /* slave */ mov 28(%rsp), %ebx /* sh2cycles */ mov %rbp, slave_ip mov %esi, slave_cc mov %ebx, %edi call FRTExec mov %ebx, %edi call WDTExec .size cc_interrupt, .-cc_interrupt .globl cc_interrupt_master .type cc_interrupt_master, @function cc_interrupt_master: lea 80(%rsp), %rbp mov -44(%rbp), %eax /* decilinecount */ mov -48(%rbp), %ebx /* decilinecycles */ inc %eax cmp $9, %eax ja .A3 mov %eax, -44(%rbp) /* decilinecount++ */ je .A2 mov %ebx, -52(%rbp) /* sh2cycles */ .A1: mov master_cc, %esi mov MSH2, %rax mov NumberOfInterruptsOffset, %ecx cmpl $0, (%rax, %rcx) jne master_handle_interrupts sub %ebx, %esi ret /* jmp master_ip */ .A2: call Vdp2HBlankIN jmp .A1 .A3: mov -56(%rbp), %edi /* scucycles */ call ScuExec call M68KSync call Vdp2HBlankOUT call ScspExec mov linecount_p, %rbx mov maxlinecount_p, %rax mov vblanklinecount_p, %rcx mov (%rbx), %edx mov (%rax), %eax mov (%rcx), %ecx inc %edx andl $0, -44(%rbp) /* decilinecount=0 */ cmp %eax, %edx /* max ? */ je nextframe mov %edx, (%rbx) /* linecount++ */ cmp %ecx, %edx /* vblank ? */ je vblankin nextline: call finishline jmp newline finishline: /*const u32 usecinc = yabsys.DecilineUsec * 10;*/ mov decilineusec_p, %rax mov UsecFrac_p, %rbx mov yabsys_timing_bits, %ecx mov (%rax), %eax mov (%rbx), %edx lea (%eax,%eax,4), %edi add %edi, %edi /*yabsys.UsecFrac += usecinc;*/ add %edx, %edi add $-8, %rsp /* Align stack */ /*SmpcExec(yabsys.UsecFrac >> YABSYS_TIMING_BITS); /*Cs2Exec(yabsys.UsecFrac >> YABSYS_TIMING_BITS); /*yabsys.UsecFrac &= YABSYS_TIMING_MASK;*/ mov %edi, (%rbx) /* UsecFrac */ shr %cl, %edi call SmpcExec /* SmpcExec may modify UsecFrac; must reload it */ mov yabsys_timing_mask, %r12d mov (%rbx), %edi /* UsecFrac */ mov yabsys_timing_bits, %ecx and %edi, %r12d shr %cl, %edi call Cs2Exec mov %r12d, (%rbx) /* UsecFrac */ mov saved_centicycles, %ecx mov -60(%rbp), %ebx /* m68kcenticycles */ mov -64(%rbp), %edi /* m68kcycles */ add %ebx, %ecx mov %ecx, %ebx add $-100, %ecx cmovnc %ebx, %ecx adc $0, %edi mov %ecx, saved_centicycles call M68KExec add $8, %rsp /* Align stack */ ret vblankin: call SmpcINTBACKEnd call Vdp2VBlankIN call CheatDoPatches jmp nextline nextframe: call Vdp2VBlankOUT andl $0, (%rbx) /* linecount = 0 */ call finishline call M68KSync mov rccount, %esi inc %esi andl $0, invalidate_count and $0x3f, %esi cmpl $0, restore_candidate(,%esi,4) mov %esi, rccount jne .A5 .A4: mov (%rsp), %rax add $40, %rsp mov %rax, master_ip pop %r15 /* restore callee-save registers */ pop %r14 pop %r13 pop %r12 pop %rbx pop %rbp ret .A5: /* Move 'dirty' blocks to the 'clean' list */ mov restore_candidate(,%esi,4), %ebx mov %esi, %ebp andl $0, restore_candidate(,%esi,4) shl $5, %ebp .A6: shr $1, %ebx jnc .A7 mov %ebp, %edi call clean_blocks .A7: inc %ebp test $31, %ebp jne .A6 jmp .A4 .size cc_interrupt_master, .-cc_interrupt_master .globl dyna_linker .type dyna_linker, @function dyna_linker: /* eax = virtual target address */ /* ebx = instruction to patch */ mov %eax, %ecx mov $1023, %edx shr $12, %ecx and %ecx, %edx and $0xDFFFF, %ecx or $1024, %edx cmp %edx, %ecx cmova %edx, %ecx /* jump_in lookup */ movq jump_in(,%ecx,8), %r12 .B1: test %r12, %r12 je .B3 mov (%r12), %edi xor %eax, %edi je .B2 movq 16(%r12), %r12 jmp .B1 .B2: mov (%ebx), %edi mov %esi, %ebp lea 4(%ebx,%edi,1), %esi mov %eax, %edi call add_link mov 8(%r12), %edi mov %ebp, %esi lea -4(%edi), %edx subl %ebx, %edx movl %edx, (%ebx) jmp *%rdi .B3: /* hash_table lookup */ mov %eax, %edi shr $16, %edi xor %eax, %edi movzwl %di, %edi shl $4, %edi cmp hash_table(%edi), %eax jne .B5 .B4: mov hash_table+4(%edi), %edx jmp *%rdx .B5: cmp hash_table+8(%edi), %eax lea 8(%edi), %edi je .B4 /* jump_dirty lookup */ movq jump_dirty(,%ecx,8), %r12 .B6: test %r12, %r12 je .B8 mov (%r12), %ecx xor %eax, %ecx je .B7 movq 16(%r12), %r12 jmp .B6 .B7: movl 8(%r12), %edx /* hash_table insert */ mov hash_table-8(%edi), %ebx mov hash_table-4(%edi), %ecx mov %eax, hash_table-8(%edi) mov %edx, hash_table-4(%edi) mov %ebx, hash_table(%edi) mov %ecx, hash_table+4(%edi) jmp *%rdx .B8: mov %eax, %edi mov %eax, %ebp /* Note: assumes %rbx and %rbp are callee-saved */ mov %esi, %r12d call sh2_recompile_block test %eax, %eax mov %ebp, %eax mov %r12d, %esi je dyna_linker /* shouldn't happen */ int3 .size dyna_linker, .-dyna_linker .globl jump_vaddr_eax_master .type jump_vaddr_eax_master, @function jump_vaddr_eax_master: mov %eax, %edi jmp jump_vaddr_edi_master .size jump_vaddr_eax_master, .-jump_vaddr_eax_master .globl jump_vaddr_ecx_master .type jump_vaddr_ecx_master, @function jump_vaddr_ecx_master: mov %ecx, %edi jmp jump_vaddr_edi_master .size jump_vaddr_ecx_master, .-jump_vaddr_ecx_master .globl jump_vaddr_edx_master .type jump_vaddr_edx_master, @function jump_vaddr_edx_master: mov %edx, %edi jmp jump_vaddr_edi_master .size jump_vaddr_edx_master, .-jump_vaddr_edx_master .globl jump_vaddr_ebx_master .type jump_vaddr_ebx_master, @function jump_vaddr_ebx_master: mov %ebx, %edi jmp jump_vaddr_edi_master .size jump_vaddr_ebx_master, .-jump_vaddr_ebx_master .globl jump_vaddr_ebp_master .type jump_vaddr_ebp_master, @function jump_vaddr_ebp_master: mov %ebp, %edi jmp jump_vaddr_edi_master .size jump_vaddr_ebp_master, .-jump_vaddr_ebp_master .globl jump_vaddr_eax_slave .type jump_vaddr_eax_slave, @function jump_vaddr_eax_slave: mov %eax, %edi jmp jump_vaddr_edi_slave .size jump_vaddr_eax_slave, .-jump_vaddr_eax_slave .globl jump_vaddr_ecx_slave .type jump_vaddr_ecx_slave, @function jump_vaddr_ecx_slave: mov %ecx, %edi jmp jump_vaddr_edi_slave .size jump_vaddr_ecx_slave, .-jump_vaddr_ecx_slave .globl jump_vaddr_edx_slave .type jump_vaddr_edx_slave, @function jump_vaddr_edx_slave: mov %edx, %edi jmp jump_vaddr_edi_slave .size jump_vaddr_edx_slave, .-jump_vaddr_edx_slave .globl jump_vaddr_ebx_slave .type jump_vaddr_ebx_slave, @function jump_vaddr_ebx_slave: mov %ebx, %edi jmp jump_vaddr_edi_slave .size jump_vaddr_ebx_slave, .-jump_vaddr_ebx_slave .globl jump_vaddr_ebp_slave .type jump_vaddr_ebp_slave, @function jump_vaddr_ebp_slave: mov %ebp, %edi .size jump_vaddr_ebp_slave, .-jump_vaddr_ebp_slave .globl jump_vaddr_edi_slave .type jump_vaddr_edi_slave, @function jump_vaddr_edi_slave: or $1, %edi .size jump_vaddr_edi_slave, .-jump_vaddr_edi_slave .globl jump_vaddr_edi_master .type jump_vaddr_edi_master, @function jump_vaddr_edi_master: mov %edi, %eax .size jump_vaddr_edi_master, .-jump_vaddr_edi_master .globl jump_vaddr .type jump_vaddr, @function jump_vaddr: /* Check hash table */ shr $16, %eax xor %edi, %eax movzwl %ax, %eax shl $4, %eax cmp hash_table(%eax), %edi jne .C2 .C1: mov hash_table+4(%eax), %edi jmp *%rdi .C2: cmp hash_table+8(%eax), %edi lea 8(%eax), %eax je .C1 /* No hit on hash table, call compiler */ mov %esi, %ebx /* CCREG */ call get_addr mov %ebx, %esi jmp *%rax .size jump_vaddr, .-jump_vaddr .globl verify_code .type verify_code, @function verify_code: /* rax = source */ /* ebx = target */ /* ecx = length */ /* r12d = instruction pointer */ mov -4(%rax,%rcx,1), %edi xor -4(%ebx,%ecx,1), %edi jne .D4 mov %ecx, %edx add $-4, %ecx je .D3 test $4, %edx cmove %edx, %ecx .D2: mov -8(%rax,%rcx,1), %rdi cmp -8(%ebx,%ecx,1), %rdi jne .D4 add $-8, %ecx jne .D2 .D3: ret .D4: add $8, %rsp /* pop return address, we're not returning */ mov %r12d, %edi mov %esi, %ebx call get_addr mov %ebx, %esi jmp *%rax .size verify_code, .-verify_code .globl WriteInvalidateLong .type WriteInvalidateLong, @function WriteInvalidateLong: mov %edi, %ecx shr $12, %ecx bt %ecx, cached_code jnc MappedMemoryWriteLongNocache /*push %rax*/ /*push %rcx*/ push %rdx /* unused, for stack alignment */ push %rsi push %rdi call invalidate_addr pop %rdi pop %rsi pop %rdx /* unused, for stack alignment */ /*pop %rcx*/ /*pop %rax*/ jmp MappedMemoryWriteLongNocache .size WriteInvalidateLong, .-WriteInvalidateLong .globl WriteInvalidateWord .type WriteInvalidateWord, @function WriteInvalidateWord: mov %edi, %ecx shr $12, %ecx bt %ecx, cached_code jnc MappedMemoryWriteWordNocache /*push %rax*/ /*push %rcx*/ push %rdx /* unused, for stack alignment */ push %rsi push %rdi call invalidate_addr pop %rdi pop %rsi pop %rdx /* unused, for stack alignment */ /*pop %rcx*/ /*pop %rax*/ jmp MappedMemoryWriteWordNocache .size WriteInvalidateWord, .-WriteInvalidateWord .globl WriteInvalidateByteSwapped .type WriteInvalidateByteSwapped, @function WriteInvalidateByteSwapped: xor $1, %edi .size WriteInvalidateByteSwapped, .-WriteInvalidateByteSwapped .globl WriteInvalidateByte .type WriteInvalidateByte, @function WriteInvalidateByte: mov %edi, %ecx shr $12, %ecx bt %ecx, cached_code jnc MappedMemoryWriteByteNocache /*push %rax*/ /*push %rcx*/ push %rdx /* unused, for stack alignment */ push %rsi push %rdi call invalidate_addr pop %rdi pop %rsi pop %rdx /* unused, for stack alignment */ /*pop %rcx*/ /*pop %rax*/ jmp MappedMemoryWriteByteNocache .size WriteInvalidateByte, .-WriteInvalidateByte .globl div1 .type div1, @function div1: /* eax = dividend */ /* ecx = divisor */ /* edx = sr */ bt $9, %edx /* M bit */ jc div1_negative_divisor bts $0, %edx /* Get T bit and set */ adc %eax, %eax /* rn=(rn<<1)+T */ adc %ebx, %ebx /* New Q in ebx */ mov %ecx, %ebp btr $8, %edx /* Get Q bit and clear it */ cmc sbb %edi, %edi /* 0xFFFFFFFF if old_Q clear, 0 otherwise */ sbb $0, %ebp xor %edi, %ebp add %ebp, %eax /* rn+rm if old_Q, rn-rm if !old_Q */ /* carry set if rn < old_rn */ adc %edi, %ebx /* low bit = (rn=old_rn)^new_Q */ not %edi /* if old_Q clear, edi=0 */ or %ebp, %edi /* zero if old_Q==0 && rn==old_rn */ neg %edi /* clear carry if edi==0 */ adc $-1, %ebx /* invert result for old_Q==0 && rn==old_rn */ and $1, %ebx xor %ebx, %edx /* New T = (Q==M) */ shl $8, %ebx or %ebx, %edx /* save new Q */ /* push %edx push %eax push %ecx call debug_division pop %ecx pop %eax pop %edx */ ret div1_negative_divisor: btr $0, %edx /* Get T bit and clear */ adc %eax, %eax /* rn=(rn<<1)+T */ adc %ebx, %ebx /* New Q in ebx */ mov %ecx, %ebp btr $8, %edx /* Get Q bit and clear it */ sbb %edi, %edi /* 0xFFFFFFFF if old_Q set, 0 otherwise */ sbb $0, %ebp xor %edi, %ebp not %edi /* if old_Q clear, edi=-1 */ add %ebp, %eax /* rn+rm if !old_Q, rn-rm if old_Q */ /* carry set if rn < old_rn */ adc %edi, %ebx /* low bit = (rn=old_rn)^new_Q */ or %ebp, %edi /* zero if old_Q==1 && rn==old_rn */ neg %edi /* clear carry if edi==0 */ adc $-1, %ebx /* invert result for old_Q==1 && rn==old_rn */ and $1, %ebx xor %ebx, %edx /* New T = (Q==M) */ shl $8, %ebx or %ebx, %edx /* save new Q */ ret .size div1, .-div1 .globl macl .type macl, @function macl: /* ebx = sr */ /* ebp = multiplicand address */ /* edi = multiplicand address */ /* eax = return MACL */ /* edx = return MACH */ mov %edx, %r12d /* MACH */ mov %eax, %r13d /* MACL */ mov %ebp, %r14d mov %edi, %r15d call MappedMemoryReadLongNocache mov %eax, %esi mov %r14d, %edi call MappedMemoryReadLongNocache lea 4(%r14), %ebp lea 4(%r15), %edi imul %esi add %r13d, %eax /* MACL */ adc %r12d, %edx /* MACH */ test $0x2, %bl jne macl_saturation ret macl_saturation: mov $0xFFFF8000, %esi xor %ecx, %ecx cmp %esi, %edx cmovl %esi, %edx cmovl %ecx, %eax not %esi not %ecx cmp %esi, %edx cmovg %esi, %edx cmovg %ecx, %eax ret .size macl, .-macl .globl macw .type macw, @function macw: /* ebx = sr */ /* ebp = multiplicand address */ /* edi = multiplicand address */ /* eax = return MACL */ /* edx = return MACH */ mov %edx, %r12d /* MACH */ mov %eax, %r13d /* MACL */ mov %ebp, %r14d mov %edi, %r15d call MappedMemoryReadWordNocache movswl %ax, %esi mov %r14d, %edi call MappedMemoryReadWordNocache movswl %ax, %eax lea 2(%r14), %ebp lea 2(%r15), %edi imul %esi test $0x2, %bl jne macw_saturation add %r13d, %eax /* MACL */ adc %r12d, %edx /* MACH */ ret macw_saturation: mov %r13d, %esi sar $31, %esi add %r13d, %eax /* MACL */ adc %esi, %edx mov $0x80000000, %esi mov $0x7FFFFFFF, %ecx add %eax, %esi adc $0, %edx cmovne %ecx, %eax not %ecx cmovl %ecx, %eax mov %r12d, %edx ret .size macw, .-macw .globl master_handle_bios .type master_handle_bios, @function master_handle_bios: mov (%rsp), %rdx /* get return address */ mov %eax, master_pc mov %esi, master_cc mov %rdx, master_ip mov MSH2, %rdi call BiosHandleFunc mov master_ip, %rdx mov master_cc, %esi mov %rdx, (%rsp) ret /* jmp *master_ip */ .size master_handle_bios, .-master_handle_bios .globl slave_handle_bios .type slave_handle_bios, @function slave_handle_bios: pop %rdx /* get return address */ mov %eax, slave_pc mov %esi, slave_cc mov %rdx, slave_ip mov SSH2, %rdi call BiosHandleFunc mov slave_ip, %rdx mov slave_cc, %esi jmp *%rdx /* jmp *slave_ip */ .size slave_handle_bios, .-slave_handle_bios .globl breakpoint .type breakpoint, @function breakpoint: ret /* Set breakpoint here for debugging */ .size breakpoint, .-breakpoint yabause-0.9.15/src/sh2_dynarec/assem_x86.h000644 001750 001750 00000001231 12755623101 022226 0ustar00guillaumeguillaume000000 000000 #define HOST_REGS 8 #define HOST_CCREG 6 #define EXCLUDE_REG 4 #define SLAVERA_REG 5 //#define IMM_PREFETCH 1 #define HOST_IMM_ADDR32 1 #define INVERTED_CARRY 1 #define DESTRUCTIVE_WRITEBACK 1 #define DESTRUCTIVE_SHIFT 1 #define USE_MINI_HT 1 #define BASE_ADDR 0x70000000 // Code generator target address #define TARGET_SIZE_2 25 // 2^25 = 32 megabytes #define JUMP_TABLE_SIZE 0 // Not needed for 32-bit x86 /* x86 calling convention: caller-save: %eax %ecx %edx callee-save: %ebp %ebx %esi %edi */ #define EAX 0 #define ECX 1 #define EDX 2 #define EBX 3 #define ESP 4 #define EBP 5 #define ESI 6 #define EDI 7 extern u32 memory_map[1048576]; // 32-bit yabause-0.9.15/src/sh2_dynarec/linkage_x86.s000644 001750 001750 00000043214 12755623101 022552 0ustar00guillaumeguillaume000000 000000 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Yabause - linkage_x86.s * * Copyright (C) 2009-2011 Ari64 * * * * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ .file "linkage_x86.s" .bss .align 4 .section .rodata .text .globl YabauseDynarecOneFrameExec .type YabauseDynarecOneFrameExec, @function YabauseDynarecOneFrameExec: push %ebp mov %esp,%ebp mov master_ip, %eax xor %ecx, %ecx push %edi push %esi push %ebx push %ecx /* zero */ push %ecx push %ecx push %ecx push %ecx /* put m68k here (?) */ push %ecx call .+5 /* 40+4=44 */ mov %eax,-40(%ebp) /* overwrite return address */ /* Stack frame: arg2 - m68kcenticycles (+8/+12) arg1 - m68kcycles (+4/+8) return address (0) ebp (4/0) save edi (8/4) save esi (12/8) save ebx (16/12) decilinecount (20/16) decilinecycles (24/20) sh2cycles (28/24) scucycles (32/28) ... (36/32) ... (40/36) ret address/master_ip (44/40) (alternate esp at call) save %eax (48/44) save %ecx (52/48) save %edx (56/52) ... (esp at call) next return address (64/60) total = 64 */ /* usecinc? cyclesinc?*/ newline: /* const u32 decilinecycles = yabsys.DecilineStop >> YABSYS_TIMING_BITS; */ /* const u32 cyclesinc = yabsys.DecilineStop * 10; */ mov decilinestop_p, %eax mov yabsys_timing_bits, %ecx mov (%eax), %eax lea (%eax,%eax,4), %ebx /* decilinestop*5 */ shr %cl, %eax /* decilinecycles */ shl %ebx /* cyclesinc=decilinestop*10 */ lea (%eax,%eax,8), %edx /* decilinecycles*9 */ /* yabsys.SH2CycleFrac += cyclesinc;*/ /* sh2cycles = (yabsys.SH2CycleFrac >> (YABSYS_TIMING_BITS + 1)) << 1;*/ /* yabsys.SH2CycleFrac &= ((YABSYS_TIMING_MASK << 1) | 1);*/ mov SH2CycleFrac_p, %esi mov yabsys_timing_mask, %edi inc %ecx /* yabsys_timing_bits+1 */ add (%esi), %ebx /* SH2CycleFrac */ stc adc %edi, %edi /* ((YABSYS_TIMING_MASK << 1) | 1) */ mov %eax, -20(%ebp) /* decilinecycles */ and %ebx, %edi mov %edi, (%esi) /* SH2CycleFrac */ shr %cl, %ebx mov %ebx, -28(%ebp) /* scucycles */ add %ebx, %ebx /* sh2cycles */ mov MSH2, %eax mov NumberOfInterruptsOffset, %ecx sub %edx, %ebx /* sh2cycles(full line) - decilinecycles*9 */ mov %ebx, -24(%ebp) /* sh2cycles */ cmp $0, (%eax, %ecx) jne master_handle_interrupts mov master_cc, %esi sub %ebx, %esi ret /* jmp master_ip */ .size YabauseDynarecOneFrameExec, .-YabauseDynarecOneFrameExec .globl master_handle_interrupts .type master_handle_interrupts, @function master_handle_interrupts: mov -40(%ebp), %eax /* get return address */ mov %eax, master_ip call DynarecMasterHandleInterrupts mov master_ip, %eax mov master_cc, %esi mov %eax,-40(%ebp) /* overwrite return address */ sub %ebx, %esi ret /* jmp master_ip */ .size master_handle_interrupts, .-master_handle_interrupts .globl slave_entry .type slave_entry, @function slave_entry: mov 16(%esp), %ebx /* sh2cycles */ mov %esi, master_cc sub $12, %esp push %ebx call FRTExec mov %ebx, (%esp) call WDTExec mov slave_ip, %edx add $16, %esp test %edx, %edx je cc_interrupt_master /* slave not running */ mov SSH2, %eax mov NumberOfInterruptsOffset, %ecx cmp $0, (%eax, %ecx) jne slave_handle_interrupts mov slave_cc, %esi sub %ebx, %esi jmp *%edx /* jmp *slave_ip */ .size slave_entry, .-slave_entry .globl slave_handle_interrupts .type slave_handle_interrupts, @function slave_handle_interrupts: call DynarecSlaveHandleInterrupts mov slave_ip, %edx mov slave_cc, %esi sub %ebx, %esi jmp *%edx /* jmp *slave_ip */ .size slave_handle_interrupts, .-slave_handle_interrupts .globl cc_interrupt .type cc_interrupt, @function cc_interrupt: /* slave */ mov 16(%esp), %ebx /* sh2cycles */ mov %ebp, slave_ip mov %esi, slave_cc add $-12, %esp push %ebx call FRTExec mov %ebx, (%esp) call WDTExec add $16, %esp .size cc_interrupt, .-cc_interrupt .globl cc_interrupt_master .type cc_interrupt_master, @function cc_interrupt_master: lea 40(%esp), %ebp mov -16(%ebp), %eax /* decilinecount */ mov -20(%ebp), %ebx /* decilinecycles */ inc %eax cmp $9, %eax ja .A3 mov %eax, -16(%ebp) /* decilinecount++ */ je .A2 mov %ebx, -24(%ebp) /* sh2cycles */ .A1: mov master_cc, %esi mov MSH2, %eax mov NumberOfInterruptsOffset, %ecx cmp $0, (%eax, %ecx) jne master_handle_interrupts sub %ebx, %esi ret /* jmp master_ip */ .A2: call Vdp2HBlankIN jmp .A1 .A3: mov -28(%ebp), %ebx /* scucycles */ add $-12, %esp push %ebx call ScuExec call M68KSync call Vdp2HBlankOUT call ScspExec mov linecount_p, %ebx mov maxlinecount_p, %eax mov vblanklinecount_p, %ecx mov (%ebx), %edx mov (%eax), %eax mov (%ecx), %ecx inc %edx andl $0, -16(%ebp) /* decilinecount=0 */ cmp %eax, %edx /* max ? */ je nextframe mov %edx, (%ebx) /* linecount++ */ cmp %ecx, %edx /* vblank ? */ je vblankin nextline: add $16, %esp call finishline jmp newline finishline: /* CHECK - Stack align? */ /*const u32 usecinc = yabsys.DecilineUsec * 10;*/ mov decilineusec_p, %eax mov UsecFrac_p, %ebx mov yabsys_timing_bits, %ecx mov (%eax), %eax mov (%ebx), %edx lea (%eax,%eax,4), %esi mov yabsys_timing_mask, %edi add %esi, %esi /*yabsys.UsecFrac += usecinc;*/ add %edx, %esi add $-8, %esp /* Align stack */ /*SmpcExec(yabsys.UsecFrac >> YABSYS_TIMING_BITS); /*Cs2Exec(yabsys.UsecFrac >> YABSYS_TIMING_BITS); /*yabsys.UsecFrac &= YABSYS_TIMING_MASK;*/ mov %esi, (%ebx) /* UsecFrac */ shr %cl, %esi push %esi call SmpcExec /* SmpcExec may modify UsecFrac; must reload it */ mov (%ebx), %esi /* UsecFrac */ mov yabsys_timing_bits, %ecx and %esi, %edi shr %cl, %esi mov %esi, (%esp) call Cs2Exec mov %edi, (%ebx) /* UsecFrac */ mov saved_centicycles, %ecx mov 12(%ebp), %ebx /* m68kcenticycles */ mov 8(%ebp), %eax /* m68kcycles */ add %ebx, %ecx mov %ecx, %ebx add $-100, %ecx cmovnc %ebx, %ecx adc $0, %eax mov %ecx, saved_centicycles mov %eax, (%esp) /* cycles */ call M68KExec add $12, %esp ret vblankin: call SmpcINTBACKEnd call Vdp2VBlankIN call CheatDoPatches jmp nextline nextframe: call Vdp2VBlankOUT andl $0, (%ebx) /* linecount = 0 */ call finishline call M68KSync mov rccount, %esi inc %esi andl $0, invalidate_count and $0x3f, %esi cmpl $0, restore_candidate(,%esi,4) mov %esi, rccount jne .A5 .A4: mov 16(%esp), %eax add $44, %esp mov %eax, master_ip pop %ebx pop %esi pop %edi pop %ebp ret .A5: /* Move 'dirty' blocks to the 'clean' list */ mov restore_candidate(,%esi,4), %ebx mov %esi, %ebp andl $0, restore_candidate(,%esi,4) shl $5, %ebp .A6: shr $1, %ebx jnc .A7 mov %ebp, (%esp) call clean_blocks .A7: inc %ebp test $31, %ebp jne .A6 jmp .A4 .size cc_interrupt_master, .-cc_interrupt_master .globl dyna_linker .type dyna_linker, @function dyna_linker: /* eax = virtual target address */ /* ebx = instruction to patch */ mov %eax, %ecx mov $1023, %edx shr $12, %ecx and %ecx, %edx and $0xDFFFF, %ecx or $1024, %edx cmp %edx, %ecx cmova %edx, %ecx /* jump_in lookup */ mov jump_in(,%ecx,4), %edx .B1: test %edx, %edx je .B3 mov (%edx), %edi xor %eax, %edi je .B2 movl 12(%edx), %edx jmp .B1 .B2: mov (%ebx), %edi mov %esi, %ebp lea 4(%ebx,%edi,1), %esi mov %eax, %edi pusha call add_link popa mov 8(%edx), %edi mov %ebp, %esi lea -4(%edi), %edx subl %ebx, %edx movl %edx, (%ebx) jmp *%edi .B3: /* hash_table lookup */ mov %eax, %edi shr $16, %edi xor %eax, %edi movzwl %di, %edi shl $4, %edi cmp hash_table(%edi), %eax jne .B5 .B4: mov hash_table+4(%edi), %edx jmp *%edx .B5: cmp hash_table+8(%edi), %eax lea 8(%edi), %edi je .B4 /* jump_dirty lookup */ mov jump_dirty(,%ecx,4), %edx .B6: testl %edx, %edx je .B8 mov (%edx), %ecx xor %eax, %ecx je .B7 movl 12(%edx), %edx jmp .B6 .B7: mov 8(%edx), %edx /* hash_table insert */ mov hash_table-8(%edi), %ebx mov hash_table-4(%edi), %ecx mov %eax, hash_table-8(%edi) mov %edx, hash_table-4(%edi) mov %ebx, hash_table(%edi) mov %ecx, hash_table+4(%edi) jmp *%edx .B8: mov %eax, %edi pusha call sh2_recompile_block test %eax, %eax popa je dyna_linker /* shouldn't happen */ int3 .size dyna_linker, .-dyna_linker .globl jump_vaddr_eax_master .type jump_vaddr_eax_master, @function jump_vaddr_eax_master: mov %eax, %edi jmp jump_vaddr_edi_master .size jump_vaddr_eax_master, .-jump_vaddr_eax_master .globl jump_vaddr_ecx_master .type jump_vaddr_ecx_master, @function jump_vaddr_ecx_master: mov %ecx, %edi jmp jump_vaddr_edi_master .size jump_vaddr_ecx_master, .-jump_vaddr_ecx_master .globl jump_vaddr_edx_master .type jump_vaddr_edx_master, @function jump_vaddr_edx_master: mov %edx, %edi jmp jump_vaddr_edi_master .size jump_vaddr_edx_master, .-jump_vaddr_edx_master .globl jump_vaddr_ebx_master .type jump_vaddr_ebx_master, @function jump_vaddr_ebx_master: mov %ebx, %edi jmp jump_vaddr_edi_master .size jump_vaddr_ebx_master, .-jump_vaddr_ebx_master .globl jump_vaddr_ebp_master .type jump_vaddr_ebp_master, @function jump_vaddr_ebp_master: mov %ebp, %edi jmp jump_vaddr_edi_master .size jump_vaddr_ebp_master, .-jump_vaddr_ebp_master .globl jump_vaddr_eax_slave .type jump_vaddr_eax_slave, @function jump_vaddr_eax_slave: mov %eax, %edi jmp jump_vaddr_edi_slave .size jump_vaddr_eax_slave, .-jump_vaddr_eax_slave .globl jump_vaddr_ecx_slave .type jump_vaddr_ecx_slave, @function jump_vaddr_ecx_slave: mov %ecx, %edi jmp jump_vaddr_edi_slave .size jump_vaddr_ecx_slave, .-jump_vaddr_ecx_slave .globl jump_vaddr_edx_slave .type jump_vaddr_edx_slave, @function jump_vaddr_edx_slave: mov %edx, %edi jmp jump_vaddr_edi_slave .size jump_vaddr_edx_slave, .-jump_vaddr_edx_slave .globl jump_vaddr_ebx_slave .type jump_vaddr_ebx_slave, @function jump_vaddr_ebx_slave: mov %ebx, %edi jmp jump_vaddr_edi_slave .size jump_vaddr_ebx_slave, .-jump_vaddr_ebx_slave .globl jump_vaddr_ebp_slave .type jump_vaddr_ebp_slave, @function jump_vaddr_ebp_slave: mov %ebp, %edi .size jump_vaddr_ebp_slave, .-jump_vaddr_ebp_slave .globl jump_vaddr_edi_slave .type jump_vaddr_edi_slave, @function jump_vaddr_edi_slave: or $1, %edi .size jump_vaddr_edi_slave, .-jump_vaddr_edi_slave .globl jump_vaddr_edi_master .type jump_vaddr_edi_master, @function jump_vaddr_edi_master: mov %edi, %eax .size jump_vaddr_edi_master, .-jump_vaddr_edi_master .globl jump_vaddr .type jump_vaddr, @function jump_vaddr: /* Check hash table */ shr $16, %eax xor %edi, %eax movzwl %ax, %eax shl $4, %eax cmp hash_table(%eax), %edi jne .C2 .C1: mov hash_table+4(%eax), %edi jmp *%edi .C2: cmp hash_table+8(%eax), %edi lea 8(%eax), %eax je .C1 /* No hit on hash table, call compiler */ push %edi call get_addr add $4, %esp jmp *%eax .size jump_vaddr, .-jump_vaddr .globl verify_code .type verify_code, @function verify_code: /* eax = source */ /* ebx = target */ /* ecx = length */ mov -4(%eax,%ecx,1), %edi xor -4(%ebx,%ecx,1), %edi jne .D5 mov %ecx, %edx add $-4, %ecx je .D3 test $4, %edx cmove %edx, %ecx push %esi .D2: mov -4(%eax,%ecx,1), %edx mov -4(%ebx,%ecx,1), %ebp mov -8(%eax,%ecx,1), %esi xor %edx, %ebp mov -8(%ebx,%ecx,1), %edi jne .D4 xor %esi, %edi jne .D4 add $-8, %ecx jne .D2 pop %esi .D3: ret .D4: pop %esi .D5: add $4, %esp /* pop return address, we're not returning */ call get_addr add $4, %esp /* pop virtual address */ jmp *%eax .size verify_code, .-verify_code .globl WriteInvalidateLong .type WriteInvalidateLong, @function WriteInvalidateLong: mov %eax, %ecx shr $12, %ecx bt %ecx, cached_code jnc MappedMemoryWriteLongNocache push %eax push %edx push %eax call invalidate_addr pop %eax pop %edx pop %eax jmp MappedMemoryWriteLongNocache .size WriteInvalidateLong, .-WriteInvalidateLong .globl WriteInvalidateWord .type WriteInvalidateWord, @function WriteInvalidateWord: mov %eax, %ecx shr $12, %ecx bt %ecx, cached_code jnc MappedMemoryWriteWordNocache push %eax push %edx push %eax call invalidate_addr pop %eax pop %edx pop %eax jmp MappedMemoryWriteWordNocache .size WriteInvalidateWord, .-WriteInvalidateWord .globl WriteInvalidateByteSwapped .type WriteInvalidateByteSwapped, @function WriteInvalidateByteSwapped: xor $1, %eax .size WriteInvalidateByteSwapped, .-WriteInvalidateByteSwapped .globl WriteInvalidateByte .type WriteInvalidateByte, @function WriteInvalidateByte: mov %eax, %ecx shr $12, %ecx bt %ecx, cached_code jnc MappedMemoryWriteByteNocache push %eax push %edx push %eax call invalidate_addr pop %eax pop %edx pop %eax jmp MappedMemoryWriteByteNocache .size WriteInvalidateByte, .-WriteInvalidateByte .globl div1 .type div1, @function div1: /* eax = dividend */ /* ecx = divisor */ /* edx = sr */ bt $9, %edx /* M bit */ jc div1_negative_divisor bts $0, %edx /* Get T bit and set */ adc %eax, %eax /* rn=(rn<<1)+T */ adc %ebx, %ebx /* New Q in ebx */ mov %ecx, %ebp btr $8, %edx /* Get Q bit and clear it */ cmc sbb %edi, %edi /* 0xFFFFFFFF if old_Q clear, 0 otherwise */ sbb $0, %ebp xor %edi, %ebp add %ebp, %eax /* rn+rm if old_Q, rn-rm if !old_Q */ /* carry set if rn < old_rn */ adc %edi, %ebx /* low bit = (rn=old_rn)^new_Q */ not %edi /* if old_Q clear, edi=0 */ or %ebp, %edi /* zero if old_Q==0 && rn==old_rn */ neg %edi /* clear carry if edi==0 */ adc $-1, %ebx /* invert result for old_Q==0 && rn==old_rn */ and $1, %ebx xor %ebx, %edx /* New T = (Q==M) */ shl $8, %ebx or %ebx, %edx /* save new Q */ /* push %edx push %eax push %ecx call debug_division pop %ecx pop %eax pop %edx */ ret div1_negative_divisor: btr $0, %edx /* Get T bit and clear */ adc %eax, %eax /* rn=(rn<<1)+T */ adc %ebx, %ebx /* New Q in ebx */ mov %ecx, %ebp btr $8, %edx /* Get Q bit and clear it */ sbb %edi, %edi /* 0xFFFFFFFF if old_Q set, 0 otherwise */ sbb $0, %ebp xor %edi, %ebp not %edi /* if old_Q clear, edi=-1 */ add %ebp, %eax /* rn+rm if !old_Q, rn-rm if old_Q */ /* carry set if rn < old_rn */ adc %edi, %ebx /* low bit = (rn=old_rn)^new_Q */ or %ebp, %edi /* zero if old_Q==1 && rn==old_rn */ neg %edi /* clear carry if edi==0 */ adc $-1, %ebx /* invert result for old_Q==1 && rn==old_rn */ and $1, %ebx xor %ebx, %edx /* New T = (Q==M) */ shl $8, %ebx or %ebx, %edx /* save new Q */ ret .size div1, .-div1 .globl macl .type macl, @function macl: /* ebx = sr */ /* ebp = multiplicand address */ /* edi = multiplicand address */ /* eax = return MACL */ /* edx = return MACH */ push %edx /* MACH */ push %eax /* MACL */ mov %edi, %eax call MappedMemoryReadLongNocache mov %eax, %esi mov %ebp, %eax call MappedMemoryReadLongNocache add $4, %ebp add $4, %edi imul %esi add (%esp), %eax /* MACL */ adc 4(%esp), %edx /* MACH */ add $8, %esp test $0x2, %bl jne macl_saturation ret macl_saturation: mov $0xFFFF8000, %esi xor %ecx, %ecx cmp %esi, %edx cmovl %esi, %edx cmovl %ecx, %eax not %esi not %ecx cmp %esi, %edx cmovg %esi, %edx cmovg %ecx, %eax ret .size macl, .-macl .globl macw .type macw, @function macw: /* ebx = sr */ /* ebp = multiplicand address */ /* edi = multiplicand address */ /* eax = return MACL */ /* edx = return MACH */ push %edx /* MACH */ push %eax /* MACL */ mov %edi, %eax call MappedMemoryReadWordNocache movswl %ax, %esi mov %ebp, %eax call MappedMemoryReadWordNocache movswl %ax, %eax add $2, %ebp add $2, %edi imul %esi test $0x2, %bl jne macw_saturation add (%esp), %eax /* MACL */ adc 4(%esp), %edx /* MACH */ add $8, %esp ret macw_saturation: mov (%esp), %esi sar $31, %esi add (%esp), %eax /* MACL */ adc %esi, %edx mov $0x80000000, %esi mov $0x7FFFFFFF, %ecx add %eax, %esi adc $0, %edx cmovne %ecx, %eax not %ecx cmovl %ecx, %eax pop %edx pop %edx ret .size macw, .-macw .globl master_handle_bios .type master_handle_bios, @function master_handle_bios: mov (%esp), %edx /* get return address */ mov %eax, master_pc mov %esi, master_cc mov %edx, master_ip mov MSH2, %eax call BiosHandleFunc mov master_ip, %edx mov master_cc, %esi mov %edx, (%esp) ret /* jmp *master_ip */ .size master_handle_bios, .-master_handle_bios .globl slave_handle_bios .type slave_handle_bios, @function slave_handle_bios: pop %edx /* get return address */ mov %eax, slave_pc mov %esi, slave_cc mov %edx, slave_ip mov SSH2, %eax call BiosHandleFunc mov slave_ip, %edx mov slave_cc, %esi jmp *%edx /* jmp *slave_ip */ .size slave_handle_bios, .-slave_handle_bios .globl breakpoint .type breakpoint, @function breakpoint: ret /* Set breakpoint here for debugging */ .size breakpoint, .-breakpoint yabause-0.9.15/src/sh2_dynarec/assem_arm.c000644 001750 001750 00000263154 12755623101 022371 0ustar00guillaumeguillaume000000 000000 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Yabause - assem_arm.c * * Copyright (C) 2009-2011 Ari64 * * * * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ extern void *dynarec_local; extern u32 memory_map[1048576]; ALIGNED(8) extern u32 mini_ht_master[32][2]; ALIGNED(8) extern u32 mini_ht_slave[32][2]; ALIGNED(4) extern u8 restore_candidate[512]; void FASTCALL WriteInvalidateLong(u32 addr, u32 val); void FASTCALL WriteInvalidateWord(u32 addr, u32 val); void FASTCALL WriteInvalidateByte(u32 addr, u32 val); void FASTCALL WriteInvalidateByteSwapped(u32 addr, u32 val); void jump_vaddr_r0_master(); void jump_vaddr_r1_master(); void jump_vaddr_r2_master(); void jump_vaddr_r3_master(); void jump_vaddr_r4_master(); void jump_vaddr_r5_master(); void jump_vaddr_r6_master(); void jump_vaddr_r7_master(); void jump_vaddr_r8_master(); void jump_vaddr_r9_master(); void jump_vaddr_r12_master(); void jump_vaddr_r0_slave(); void jump_vaddr_r1_slave(); void jump_vaddr_r2_slave(); void jump_vaddr_r3_slave(); void jump_vaddr_r4_slave(); void jump_vaddr_r5_slave(); void jump_vaddr_r6_slave(); void jump_vaddr_r7_slave(); void jump_vaddr_r8_slave(); void jump_vaddr_r9_slave(); void jump_vaddr_r12_slave(); const pointer jump_vaddr_reg[2][16] = { { (pointer)jump_vaddr_r0_master, (pointer)jump_vaddr_r1_master, (pointer)jump_vaddr_r2_master, (pointer)jump_vaddr_r3_master, (pointer)jump_vaddr_r4_master, (pointer)jump_vaddr_r5_master, (pointer)jump_vaddr_r6_master, (pointer)jump_vaddr_r7_master, (pointer)jump_vaddr_r8_master, (pointer)jump_vaddr_r9_master, 0, 0, (pointer)jump_vaddr_r12_master, 0, 0, 0 },{ (pointer)jump_vaddr_r0_slave, (pointer)jump_vaddr_r1_slave, (pointer)jump_vaddr_r2_slave, (pointer)jump_vaddr_r3_slave, (pointer)jump_vaddr_r4_slave, (pointer)jump_vaddr_r5_slave, (pointer)jump_vaddr_r6_slave, (pointer)jump_vaddr_r7_slave, (pointer)jump_vaddr_r8_slave, (pointer)jump_vaddr_r9_slave, 0, 0, (pointer)jump_vaddr_r12_slave, 0, 0, 0 } }; u32 needs_clear_cache[1<<(TARGET_SIZE_2-17)]; //#define JUMP_TABLE_SIZE (sizeof(jump_table_symbols)*2) #define JUMP_TABLE_SIZE 0 /* Linker */ void set_jump_target(pointer addr,pointer target) { u8 *ptr=(u8 *)addr; u32 *ptr2=(u32 *)ptr; if(ptr[3]==0xe2) { assert((target-(u32)ptr2-8)<1024); assert((addr&3)==0); assert((target&3)==0); *ptr2=(*ptr2&0xFFFFF000)|((target-(u32)ptr2-8)>>2)|0xF00; //printf("target=%x addr=%x insn=%x\n",target,addr,*ptr2); } else if(ptr[3]==0x72) { // generated by emit_jno_unlikely if((target-(u32)ptr2-8)<1024) { assert((addr&3)==0); assert((target&3)==0); *ptr2=(*ptr2&0xFFFFF000)|((target-(u32)ptr2-8)>>2)|0xF00; } else if((target-(u32)ptr2-8)<4096&&!((target-(u32)ptr2-8)&15)) { assert((addr&3)==0); assert((target&3)==0); *ptr2=(*ptr2&0xFFFFF000)|((target-(u32)ptr2-8)>>4)|0xE00; } else *ptr2=(0x7A000000)|(((target-(u32)ptr2-8)<<6)>>8); } else { assert((ptr[3]&0x0e)==0xa); *ptr2=(*ptr2&0xFF000000)|(((target-(u32)ptr2-8)<<6)>>8); } } // This optionally copies the instruction from the target of the branch into // the space before the branch. Works, but the difference in speed is // usually insignificant. void set_jump_target_fillslot(int addr,u32 target,int copy) { u8 *ptr=(u8 *)addr; u32 *ptr2=(u32 *)ptr; assert(!copy||ptr2[-1]==0xe28dd000); if(ptr[3]==0xe2) { assert(!copy); assert((target-(u32)ptr2-8)<4096); *ptr2=(*ptr2&0xFFFFF000)|(target-(u32)ptr2-8); } else { assert((ptr[3]&0x0e)==0xa); u32 target_insn=*(u32 *)target; if((target_insn&0x0e100000)==0) { // ALU, no immediate, no flags copy=0; } if((target_insn&0x0c100000)==0x04100000) { // Load copy=0; } if(target_insn&0x08000000) { copy=0; } if(copy) { ptr2[-1]=target_insn; target+=4; } *ptr2=(*ptr2&0xFF000000)|(((target-(u32)ptr2-8)<<6)>>8); } } /* Literal pool */ add_literal(int addr,int val) { literals[literalcount][0]=addr; literals[literalcount][1]=val; literalcount++; } void *kill_pointer(void *stub) { int *ptr=(int *)(stub+4); assert((*ptr&0x0ff00000)==0x05900000); u32 offset=*ptr&0xfff; int **l_ptr=(void *)ptr+offset+8; int *i_ptr=*l_ptr; set_jump_target((int)i_ptr,(int)stub); return i_ptr; } pointer get_pointer(void *stub) { //printf("get_pointer(%x)\n",(int)stub); int *ptr=(int *)(stub+4); assert((*ptr&0x0ff00000)==0x05900000); u32 offset=*ptr&0xfff; int **l_ptr=(void *)ptr+offset+8; int *i_ptr=*l_ptr; assert((*i_ptr&0x0f000000)==0x0a000000); return (pointer)i_ptr+((*i_ptr<<8)>>6)+8; } // Find the "clean" entry point from a "dirty" entry point // by skipping past the call to verify_code pointer get_clean_addr(pointer addr) { int *ptr=(int *)addr; #ifndef HAVE_ARMv7 ptr+=4; #else ptr+=6; #endif if((*ptr&0xFF000000)!=0xeb000000) ptr++; assert((*ptr&0xFF000000)==0xeb000000); // bl instruction ptr++; if((*ptr&0xFF000000)==0xea000000) { return (int)ptr+((*ptr<<8)>>6)+8; // follow jump } return (pointer)ptr; } int verify_dirty(pointer addr) { u32 *ptr=(u32 *)addr; #ifndef HAVE_ARMv7 // get from literal pool assert((*ptr&0xFFF00000)==0xe5900000); u32 offset=*ptr&0xfff; u32 *l_ptr=(void *)ptr+offset+8; u32 source=l_ptr[0]; u32 copy=l_ptr[1]; u32 len=l_ptr[2]; ptr+=4; #else // ARMv7 movw/movt assert((*ptr&0xFFF00000)==0xe3000000); u32 source=(ptr[0]&0xFFF)+((ptr[0]>>4)&0xF000)+((ptr[2]<<16)&0xFFF0000)+((ptr[2]<<12)&0xF0000000); u32 copy=(ptr[1]&0xFFF)+((ptr[1]>>4)&0xF000)+((ptr[3]<<16)&0xFFF0000)+((ptr[3]<<12)&0xF0000000); u32 len=(ptr[4]&0xFFF)+((ptr[4]>>4)&0xF000); ptr+=6; #endif if((*ptr&0xFF000000)!=0xeb000000) ptr++; assert((*ptr&0xFF000000)==0xeb000000); // bl instruction //printf("verify_dirty: %x %x %x\n",source,copy,len); return !memcmp((void *)source,(void *)copy,len); } // This doesn't necessarily find all clean entry points, just // guarantees that it's not dirty int isclean(pointer addr) { #ifndef HAVE_ARMv7 int *ptr=((u32 *)addr)+4; #else int *ptr=((u32 *)addr)+6; #endif if((*ptr&0xFF000000)!=0xeb000000) ptr++; if((*ptr&0xFF000000)!=0xeb000000) return 1; // bl instruction if((int)ptr+((*ptr<<8)>>6)+8==(int)verify_code) return 0; return 1; } void get_bounds(pointer addr,u32 *start,u32 *end) { u32 *ptr=(u32 *)addr; #ifndef HAVE_ARMv7 // get from literal pool assert((*ptr&0xFFF00000)==0xe5900000); u32 offset=*ptr&0xfff; u32 *l_ptr=(void *)ptr+offset+8; u32 source=l_ptr[0]; //u32 copy=l_ptr[1]; u32 len=l_ptr[2]; ptr+=4; #else // ARMv7 movw/movt assert((*ptr&0xFFF00000)==0xe3000000); u32 source=(ptr[0]&0xFFF)+((ptr[0]>>4)&0xF000)+((ptr[2]<<16)&0xFFF0000)+((ptr[2]<<12)&0xF0000000); //u32 copy=(ptr[1]&0xFFF)+((ptr[1]>>4)&0xF000)+((ptr[3]<<16)&0xFFF0000)+((ptr[3]<<12)&0xF0000000); u32 len=(ptr[4]&0xFFF)+((ptr[4]>>4)&0xF000); ptr+=6; #endif if((*ptr&0xFF000000)!=0xeb000000) ptr++; assert((*ptr&0xFF000000)==0xeb000000); // bl instruction *start=source; *end=source+len; } /* Register allocation */ // Note: registers are allocated clean (unmodified state) // if you intend to modify the register, you must call dirty_reg(). void alloc_reg(struct regstat *cur,int i,signed char reg) { int r,hr; int preferred_reg = (reg&7); if(reg==CCREG) preferred_reg=HOST_CCREG; if(reg==PTEMP) preferred_reg=12; // Don't allocate unused registers if((cur->u>>reg)&1) return; // see if it's already allocated for(hr=0;hrregmap[hr]==reg) return; } // Keep the same mapping if the register was already allocated in a loop preferred_reg = loop_reg(i,reg,preferred_reg); // Try to allocate the preferred register if(cur->regmap[preferred_reg]==-1) { cur->regmap[preferred_reg]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[preferred_reg]; if(r<64&&((cur->u>>r)&1)) { cur->regmap[preferred_reg]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]; if(r>=0) { if((cur->u>>r)&1) if(i==0||(unneeded_reg[i-1]>>r)&1) {cur->regmap[hr]=-1;break;} } } // Try to allocate any available register, but prefer // registers that have not been used recently. if(i>0) { for(hr=0;hrregmap[hr]==-1) { if(regs[i-1].regmap[hr]!=rs1[i-1]&®s[i-1].regmap[hr]!=rs2[i-1]&®s[i-1].regmap[hr]!=rt1[i-1]&®s[i-1].regmap[hr]!=rt2[i-1]) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]==-1) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[0],cur->regmap[1],cur->regmap[2],cur->regmap[3],cur->regmap[5],cur->regmap[6],cur->regmap[7]); //printf("hsn(%x): %d %d %d %d %d %d %d\n",start+i*4,hsn[cur->regmap[0]&63],hsn[cur->regmap[1]&63],hsn[cur->regmap[2]&63],hsn[cur->regmap[3]&63],hsn[cur->regmap[5]&63],hsn[cur->regmap[6]&63],hsn[cur->regmap[7]&63]); if(i>0) { // Don't evict the cycle count at entry points, otherwise the entry // stub will have to write it. if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP)) hsn[CCREG]=2; for(j=10;j>=3;j--) { // Alloc preferred register if available if(hsn[r=cur->regmap[preferred_reg]&63]==j) { for(hr=0;hrregmap[hr]&63)==r) { cur->regmap[hr]=-1; cur->dirty&=~(1<isdoingcp&=~(1<regmap[preferred_reg]=reg; return; } for(r=0;r<=MAXREG;r++) { if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<=0;j--) { for(r=0;r<=MAXREG;r++) { if(hsn[r]==j) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]==reg) return; } // Try to allocate any available register for(hr=HOST_REGS-1;hr>=0;hr--) { if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<=0;hr--) { r=cur->regmap[hr]; if(r>=0) { if((cur->u>>r)&1) { if(i==0||((unneeded_reg[i-1]>>r)&1)) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[0]&63],hsn[cur->regmap[1]&63],hsn[cur->regmap[2]&63],hsn[cur->regmap[3]&63],hsn[cur->regmap[5]&63],hsn[cur->regmap[6]&63],hsn[cur->regmap[7]&63]); if(i>0) { // Don't evict the cycle count at entry points, otherwise the entry // stub will have to write it. if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP)) hsn[CCREG]=2; for(j=10;j>=3;j--) { for(r=0;r<=MAXREG;r++) { if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<=0;j--) { for(r=0;r<=MAXREG;r++) { if(hsn[r]==j) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[n]==reg) { dirty=(cur->dirty>>n)&1; cur->regmap[n]=-1; } } cur->regmap[hr]=reg; cur->dirty&=~(1<dirty|=dirty<isdoingcp&=~(1<0) { if(imm<256) { *encoded=((i&30)<<7)|imm; return 1; } imm=(imm>>2)|(imm<<30);i-=2; } return 0; } u32 genjmp(u32 addr) { if(addr<4) return 0; int offset=addr-(int)out-8; #if 0 if(offset<-33554432||offset>=33554432) { int n; for (n=0;n=-33554432&&offset<33554432); return ((u32)offset>>2)&0xffffff; } void emit_mov(int rs,int rt) { assem_debug("mov %s,%s\n",regname[rt],regname[rs]); output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)); } void emit_movs(int rs,int rt) { assem_debug("movs %s,%s\n",regname[rt],regname[rs]); output_w32(0xe1b00000|rd_rn_rm(rt,0,rs)); } void emit_add(int rs1,int rs2,int rt) { assem_debug("add %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0800000|rd_rn_rm(rt,rs1,rs2)); } void emit_adds(int rs1,int rs2,int rt) { assem_debug("adds %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0900000|rd_rn_rm(rt,rs1,rs2)); } void emit_adc(int rs1,int rs2,int rt) { assem_debug("adc %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0a00000|rd_rn_rm(rt,rs1,rs2)); } void emit_adcs(int rs1,int rs2,int rt) { assem_debug("adcs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0b00000|rd_rn_rm(rt,rs1,rs2)); } void emit_sbc(int rs1,int rs2,int rt) { assem_debug("sbc %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0c00000|rd_rn_rm(rt,rs1,rs2)); } void emit_sbcs(int rs1,int rs2,int rt) { assem_debug("sbcs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0d00000|rd_rn_rm(rt,rs1,rs2)); } void emit_neg(int rs, int rt) { assem_debug("rsb %s,%s,#0\n",regname[rt],regname[rs]); output_w32(0xe2600000|rd_rn_rm(rt,rs,0)); } void emit_negs(int rs, int rt) { assem_debug("rsbs %s,%s,#0\n",regname[rt],regname[rs]); output_w32(0xe2700000|rd_rn_rm(rt,rs,0)); } void emit_sub(int rs1,int rs2,int rt) { assem_debug("sub %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0400000|rd_rn_rm(rt,rs1,rs2)); } void emit_subs(int rs1,int rs2,int rt) { assem_debug("subs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0500000|rd_rn_rm(rt,rs1,rs2)); } void emit_zeroreg(int rt) { assem_debug("mov %s,#0\n",regname[rt]); output_w32(0xe3a00000|rd_rn_rm(rt,0,0)); } void emit_loadlp(u32 imm,unsigned int rt) { add_literal((int)out,imm); assem_debug("ldr %s,pc+? [=%x]\n",regname[rt],imm); output_w32(0xe5900000|rd_rn_rm(rt,15,0)); } void emit_movw(u32 imm,unsigned int rt) { assert(imm<65536); assem_debug("movw %s,#%d (0x%x)\n",regname[rt],imm,imm); output_w32(0xe3000000|rd_rn_rm(rt,0,0)|(imm&0xfff)|((imm<<4)&0xf0000)); } void emit_movt(u32 imm,unsigned int rt) { assem_debug("movt %s,#%d (0x%x)\n",regname[rt],imm&0xffff0000,imm&0xffff0000); output_w32(0xe3400000|rd_rn_rm(rt,0,0)|((imm>>16)&0xfff)|((imm>>12)&0xf0000)); } void emit_movimm(u32 imm,unsigned int rt) { u32 armval; if(genimm(imm,&armval)) { assem_debug("mov %s,#%d\n",regname[rt],imm); output_w32(0xe3a00000|rd_rn_rm(rt,0,0)|armval); }else if(genimm(~imm,&armval)) { assem_debug("mvn %s,#%d\n",regname[rt],imm); output_w32(0xe3e00000|rd_rn_rm(rt,0,0)|armval); }else if(imm<65536) { #ifndef HAVE_ARMv7 assem_debug("mov %s,#%d\n",regname[rt],imm&0xFF00); output_w32(0xe3a00000|rd_rn_imm_shift(rt,0,imm>>8,8)); assem_debug("add %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF); output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm&0xff,0)); #else emit_movw(imm,rt); #endif }else{ #ifndef HAVE_ARMv7 emit_loadlp(imm,rt); #else emit_movw(imm&0x0000FFFF,rt); emit_movt(imm&0xFFFF0000,rt); #endif } } void emit_pcreladdr(unsigned int rt) { assem_debug("add %s,pc,#?\n",regname[rt]); output_w32(0xe2800000|rd_rn_rm(rt,15,0)); } void emit_loadreg(int r, int hr) { if(r==MMREG) emit_movimm(((int)memory_map-(int)&dynarec_local)>>2,hr); else { int addr=(slave?(int)slave_reg:(int)master_reg)+(r<<2); if(r==CCREG) addr=slave?(int)&slave_cc:(int)&master_cc; u32 offset = addr-(u32)&dynarec_local; assert(offset<4096); assem_debug("ldr %s,fp+%d\n",regname[hr],offset); output_w32(0xe5900000|rd_rn_rm(hr,FP,0)|offset); } } void emit_storereg(int r, int hr) { int addr=(slave?(int)slave_reg:(int)master_reg)+(r<<2); if(r==CCREG) addr=slave?(int)&slave_cc:(int)&master_cc; u32 offset = addr-(u32)&dynarec_local; assert(offset<4096); assem_debug("str %s,fp+%d\n",regname[hr],offset); output_w32(0xe5800000|rd_rn_rm(hr,FP,0)|offset); } void emit_test(int rs, int rt) { assem_debug("tst %s,%s\n",regname[rs],regname[rt]); output_w32(0xe1100000|rd_rn_rm(0,rs,rt)); } void emit_testimm(int rs,int imm) { u32 armval; assem_debug("tst %s,#%d\n",regname[rs],imm); genimm(imm,&armval); output_w32(0xe3100000|rd_rn_rm(0,rs,0)|armval); } void emit_not(int rs,int rt) { assem_debug("mvn %s,%s\n",regname[rt],regname[rs]); output_w32(0xe1e00000|rd_rn_rm(rt,0,rs)); } void emit_and(unsigned int rs1,unsigned int rs2,unsigned int rt) { assem_debug("and %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0000000|rd_rn_rm(rt,rs1,rs2)); } void emit_or(unsigned int rs1,unsigned int rs2,unsigned int rt) { assem_debug("orr %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe1800000|rd_rn_rm(rt,rs1,rs2)); } void emit_or_and_set_flags(int rs1,int rs2,int rt) { assem_debug("orrs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe1900000|rd_rn_rm(rt,rs1,rs2)); } void emit_xor(unsigned int rs1,unsigned int rs2,unsigned int rt) { assem_debug("eor %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0200000|rd_rn_rm(rt,rs1,rs2)); } void emit_addimm(unsigned int rs,int imm,unsigned int rt) { assert(rs<16); assert(rt<16); if(imm!=0) { assert(imm>-65536&&imm<65536); u32 armval; if(genimm(imm,&armval)) { assem_debug("add %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0xe2800000|rd_rn_rm(rt,rs,0)|armval); }else if(genimm(-imm,&armval)) { assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0xe2400000|rd_rn_rm(rt,rs,0)|armval); }else if(imm<0) { assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rs],(-imm)&0xFF00); assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rt],(-imm)&0xFF); output_w32(0xe2400000|rd_rn_imm_shift(rt,rs,(-imm)>>8,8)); output_w32(0xe2400000|rd_rn_imm_shift(rt,rt,(-imm)&0xff,0)); }else{ assem_debug("add %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF00); assem_debug("add %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF); output_w32(0xe2800000|rd_rn_imm_shift(rt,rs,imm>>8,8)); output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm&0xff,0)); } } else if(rs!=rt) emit_mov(rs,rt); } void emit_addimm_and_set_flags(int imm,int rt) { assert(imm>-65536&&imm<65536); u32 armval; if(genimm(imm,&armval)) { assem_debug("adds %s,%s,#%d\n",regname[rt],regname[rt],imm); output_w32(0xe2900000|rd_rn_rm(rt,rt,0)|armval); }else if(genimm(-imm,&armval)) { assem_debug("subs %s,%s,#%d\n",regname[rt],regname[rt],imm); output_w32(0xe2500000|rd_rn_rm(rt,rt,0)|armval); }else if(imm<0) { assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rt],(-imm)&0xFF00); assem_debug("subs %s,%s,#%d\n",regname[rt],regname[rt],(-imm)&0xFF); output_w32(0xe2400000|rd_rn_imm_shift(rt,rt,(-imm)>>8,8)); output_w32(0xe2500000|rd_rn_imm_shift(rt,rt,(-imm)&0xff,0)); }else{ assem_debug("add %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF00); assem_debug("adds %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF); output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm>>8,8)); output_w32(0xe2900000|rd_rn_imm_shift(rt,rt,imm&0xff,0)); } } void emit_addimm_no_flags(u32 imm,unsigned int rt) { emit_addimm(rt,imm,rt); } void emit_addnop(unsigned int r) { assert(r<16); assem_debug("add %s,%s,#0 (nop)\n",regname[r],regname[r]); output_w32(0xe2800000|rd_rn_rm(r,r,0)); } void emit_adcimm(unsigned int rs,int imm,unsigned int rt) { u32 armval; genimm(imm,&armval); assem_debug("adc %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0xe2a00000|rd_rn_rm(rt,rs,0)|armval); } void emit_sbcimm(unsigned int rs,int imm,unsigned int rt) { u32 armval; genimm(imm,&armval); assem_debug("sbc %s,%s,#%d\n",regname[rt],regname[rt],imm); output_w32(0xe2c00000|rd_rn_rm(rt,rt,0)|armval); } void emit_sbbimm(int imm,unsigned int rt) { assem_debug("sbb $%d,%%%s\n",imm,regname[rt]); assert(rt<8); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,3); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,3); output_w32(imm); } } void emit_rscimm(int rs,int imm,unsigned int rt) { assert(0); u32 armval; genimm(imm,&armval); assem_debug("rsc %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0xe2e00000|rd_rn_rm(rt,rs,0)|armval); } void emit_addimm64_32(int rsh,int rsl,int imm,int rth,int rtl) { // TODO: if(genimm(imm,&armval)) ... // else emit_movimm(imm,HOST_TEMPREG); emit_adds(HOST_TEMPREG,rsl,rtl); emit_adcimm(rsh,0,rth); } void emit_sbb(int rs1,int rs2) { assem_debug("sbb %%%s,%%%s\n",regname[rs2],regname[rs1]); output_byte(0x19); output_modrm(3,rs1,rs2); } void emit_andimm(int rs,int imm,int rt) { u32 armval; if(imm==0) { emit_zeroreg(rt); }else if(genimm(imm,&armval)) { assem_debug("and %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0xe2000000|rd_rn_rm(rt,rs,0)|armval); }else if(genimm(~imm,&armval)) { assem_debug("bic %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0xe3c00000|rd_rn_rm(rt,rs,0)|armval); }else if(imm==65535) { #ifndef HAVE_ARMv6 assem_debug("bic %s,%s,#FF000000\n",regname[rt],regname[rs]); output_w32(0xe3c00000|rd_rn_rm(rt,rs,0)|0x4FF); assem_debug("bic %s,%s,#00FF0000\n",regname[rt],regname[rt]); output_w32(0xe3c00000|rd_rn_rm(rt,rt,0)|0x8FF); #else assem_debug("uxth %s,%s\n",regname[rt],regname[rs]); output_w32(0xe6ff0070|rd_rn_rm(rt,0,rs)); #endif }else{ assert(imm>0&&imm<65535); #ifndef HAVE_ARMv7 assem_debug("mov r14,#%d\n",imm&0xFF00); output_w32(0xe3a00000|rd_rn_imm_shift(HOST_TEMPREG,0,imm>>8,8)); assem_debug("add r14,r14,#%d\n",imm&0xFF); output_w32(0xe2800000|rd_rn_imm_shift(HOST_TEMPREG,HOST_TEMPREG,imm&0xff,0)); #else emit_movw(imm,HOST_TEMPREG); #endif assem_debug("and %s,%s,r14\n",regname[rt],regname[rs]); output_w32(0xe0000000|rd_rn_rm(rt,rs,HOST_TEMPREG)); } } void emit_orimm(int rs,int imm,int rt) { u32 armval; if(imm==0) { if(rs!=rt) emit_mov(rs,rt); }else if(genimm(imm,&armval)) { assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0xe3800000|rd_rn_rm(rt,rs,0)|armval); }else{ assert(imm>0&&imm<65536); assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF00); assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF); output_w32(0xe3800000|rd_rn_imm_shift(rt,rs,imm>>8,8)); output_w32(0xe3800000|rd_rn_imm_shift(rt,rt,imm&0xff,0)); } } void emit_xorimm(int rs,int imm,int rt) { u32 armval; if(imm==0) { if(rs!=rt) emit_mov(rs,rt); }else if(genimm(imm,&armval)) { assem_debug("eor %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0xe2200000|rd_rn_rm(rt,rs,0)|armval); }else{ assert(imm>0&&imm<65536); assem_debug("eor %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF00); assem_debug("eor %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF); output_w32(0xe2200000|rd_rn_imm_shift(rt,rs,imm>>8,8)); output_w32(0xe2200000|rd_rn_imm_shift(rt,rt,imm&0xff,0)); } } void emit_shlimm(int rs,unsigned int imm,int rt) { assert(imm>0); assert(imm<32); if(imm==1) emit_add(rs,rs,rt); else { assem_debug("lsl %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|(imm<<7)); } } void emit_lsls_imm(int rs,unsigned int imm,int rt) { assert(imm>0); assert(imm<32); if(imm==1) emit_adds(rs,rs,rt); else { assem_debug("lsls %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0xe1b00000|rd_rn_rm(rt,0,rs)|(imm<<7)); } } void emit_shrimm(int rs,unsigned int imm,int rt) { assert(imm>0); assert(imm<32); assem_debug("lsr %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7)); } void emit_lsrs_imm(int rs,unsigned int imm,int rt) { assert(imm>0); assert(imm<32); assem_debug("lsrs %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0xe1b00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7)); } void emit_sarimm(int rs,unsigned int imm,int rt) { assert(imm>0); assert(imm<32); assem_debug("asr %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x40|(imm<<7)); } void emit_asrs_imm(int rs,unsigned int imm,int rt) { assert(imm>0); assert(imm<32); assem_debug("asrs %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0xe1b00000|rd_rn_rm(rt,0,rs)|0x40|(imm<<7)); } void emit_rorimm(int rs,unsigned int imm,int rt) { assert(imm>0); assert(imm<32); assem_debug("ror %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x60|(imm<<7)); } void emit_rors_imm(int rs,unsigned int imm,int rt) { assert(imm>0); assert(imm<32); assem_debug("rors %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0xe1b00000|rd_rn_rm(rt,0,rs)|0x60|(imm<<7)); } void emit_rrxs(int rs, int rt) { assem_debug("rrxs %s,%s\n",regname[rt],regname[rs]); output_w32(0xe1b00060|rd_rn_rm(rt,0,rs)); } void emit_swapb(int rs,int rt) { #ifdef HAVE_ARMv6 assem_debug("rev16 %s,%s\n",regname[14],regname[rs]); output_w32(0xe6bf0fb0|rd_rn_rm(14,0,rs)); assem_debug("pkhbt %s,%s,%s\n",regname[rt],regname[14],regname[rs]); output_w32(0xe6800010|rd_rn_rm(rt,14,rs)); #else assem_debug("eor %s,%s,%s,lsr #%d\n",regname[14],regname[rs],regname[rs],8); output_w32(0xe0200020|rd_rn_rm(14,rs,rs)|(8<<7)); emit_andimm(14,0xff,14); emit_xor(14,rt,rt); assem_debug("eor %s,%s,%s,lsl #%d\n",regname[rt],regname[rt],regname[14],8); output_w32(0xe0200000|rd_rn_rm(rt,rt,14)|(8<<7)); #endif } void emit_shldimm(int rs,int rs2,unsigned int imm,int rt) { assem_debug("shld %%%s,%%%s,%d\n",regname[rt],regname[rs2],imm); assert(imm>0); assert(imm<32); //if(imm==1) ... assem_debug("lsl %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|(imm<<7)); assem_debug("orr %s,%s,%s,lsr #%d\n",regname[rt],regname[rt],regname[rs2],32-imm); output_w32(0xe1800020|rd_rn_rm(rt,rt,rs2)|((32-imm)<<7)); } void emit_shrdimm(int rs,int rs2,unsigned int imm,int rt) { assem_debug("shrd %%%s,%%%s,%d\n",regname[rt],regname[rs2],imm); assert(imm>0); assert(imm<32); //if(imm==1) ... assem_debug("lsr %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0xe1a00020|rd_rn_rm(rt,0,rs)|(imm<<7)); assem_debug("orr %s,%s,%s,lsl #%d\n",regname[rt],regname[rt],regname[rs2],32-imm); output_w32(0xe1800000|rd_rn_rm(rt,rt,rs2)|((32-imm)<<7)); } void emit_shl(unsigned int rs,unsigned int shift,unsigned int rt) { assert(rs<16); assert(rt<16); assert(shift<16); //if(imm==1) ... assem_debug("lsl %s,%s,%s\n",regname[rt],regname[rs],regname[shift]); output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x10|(shift<<8)); } void emit_shr(unsigned int rs,unsigned int shift,unsigned int rt) { assert(rs<16); assert(rt<16); assert(shift<16); assem_debug("lsr %s,%s,%s\n",regname[rt],regname[rs],regname[shift]); output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x30|(shift<<8)); } void emit_sar(unsigned int rs,unsigned int shift,unsigned int rt) { assert(rs<16); assert(rt<16); assert(shift<16); assem_debug("asr %s,%s,%s\n",regname[rt],regname[rs],regname[shift]); output_w32(0xe1a00000|rd_rn_rm(rt,0,rs)|0x50|(shift<<8)); } void emit_shlcl(int r) { assem_debug("shl %%%s,%%cl\n",regname[r]); assert(0); } void emit_shrcl(int r) { assem_debug("shr %%%s,%%cl\n",regname[r]); assert(0); } void emit_sarcl(int r) { assem_debug("sar %%%s,%%cl\n",regname[r]); assert(0); } void emit_shldcl(int r1,int r2) { assem_debug("shld %%%s,%%%s,%%cl\n",regname[r1],regname[r2]); assert(0); } void emit_shrdcl(int r1,int r2) { assem_debug("shrd %%%s,%%%s,%%cl\n",regname[r1],regname[r2]); assert(0); } void emit_orrshl(unsigned int rs,unsigned int shift,unsigned int rt) { assert(rs<16); assert(rt<16); assert(shift<16); assem_debug("orr %s,%s,%s,lsl %s\n",regname[rt],regname[rt],regname[rs],regname[shift]); output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|0x10|(shift<<8)); } void emit_orrshr(unsigned int rs,unsigned int shift,unsigned int rt) { assert(rs<16); assert(rt<16); assert(shift<16); assem_debug("orr %s,%s,%s,lsr %s\n",regname[rt],regname[rt],regname[rs],regname[shift]); output_w32(0xe1800000|rd_rn_rm(rt,rt,rs)|0x30|(shift<<8)); } void emit_cmpimm(int rs,int imm) { u32 armval; if(genimm(imm,&armval)) { assem_debug("cmp %s,#%d\n",regname[rs],imm); output_w32(0xe3500000|rd_rn_rm(0,rs,0)|armval); }else if(genimm(-imm,&armval)) { assem_debug("cmn %s,#%d\n",regname[rs],imm); output_w32(0xe3700000|rd_rn_rm(0,rs,0)|armval); }else if(imm>0) { assert(imm<65536); #ifndef HAVE_ARMv7 emit_movimm(imm,HOST_TEMPREG); #else emit_movw(imm,HOST_TEMPREG); #endif assem_debug("cmp %s,r14\n",regname[rs]); output_w32(0xe1500000|rd_rn_rm(0,rs,HOST_TEMPREG)); }else{ assert(imm>-65536); #ifndef HAVE_ARMv7 emit_movimm(-imm,HOST_TEMPREG); #else emit_movw(-imm,HOST_TEMPREG); #endif assem_debug("cmn %s,r14\n",regname[rs]); output_w32(0xe1700000|rd_rn_rm(0,rs,HOST_TEMPREG)); } } void emit_cmovne(u32 *addr,int rt) { assem_debug("cmovne %x,%%%s",(int)addr,regname[rt]); assert(0); } void emit_cmovl(u32 *addr,int rt) { assem_debug("cmovl %x,%%%s",(int)addr,regname[rt]); assert(0); } void emit_cmovs(u32 *addr,int rt) { assem_debug("cmovs %x,%%%s",(int)addr,regname[rt]); assert(0); } void emit_cmovne_imm(int imm,int rt) { assem_debug("movne %s,#%d\n",regname[rt],imm); u32 armval; genimm(imm,&armval); output_w32(0x13a00000|rd_rn_rm(rt,0,0)|armval); } void emit_cmovl_imm(int imm,int rt) { assem_debug("movlt %s,#%d\n",regname[rt],imm); u32 armval; genimm(imm,&armval); output_w32(0xb3a00000|rd_rn_rm(rt,0,0)|armval); } void emit_cmovb_imm(int imm,int rt) { assem_debug("movcc %s,#%d\n",regname[rt],imm); u32 armval; genimm(imm,&armval); output_w32(0x33a00000|rd_rn_rm(rt,0,0)|armval); } void emit_cmovs_imm(int imm,int rt) { assem_debug("movmi %s,#%d\n",regname[rt],imm); u32 armval; genimm(imm,&armval); output_w32(0x43a00000|rd_rn_rm(rt,0,0)|armval); } void emit_cmove_reg(int rs,int rt) { assem_debug("moveq %s,%s\n",regname[rt],regname[rs]); output_w32(0x01a00000|rd_rn_rm(rt,0,rs)); } void emit_cmovne_reg(int rs,int rt) { assem_debug("movne %s,%s\n",regname[rt],regname[rs]); output_w32(0x11a00000|rd_rn_rm(rt,0,rs)); } void emit_cmovl_reg(int rs,int rt) { assem_debug("movlt %s,%s\n",regname[rt],regname[rs]); output_w32(0xb1a00000|rd_rn_rm(rt,0,rs)); } void emit_cmovs_reg(int rs,int rt) { assem_debug("movmi %s,%s\n",regname[rt],regname[rs]); output_w32(0x41a00000|rd_rn_rm(rt,0,rs)); } void emit_movzbl_reg(int rs, int rt) { emit_andimm(rs,0xff,rt); } void emit_movzwl_reg(int rs, int rt) { emit_andimm(rs,0xffff,rt); } void emit_movsbl_reg(int rs, int rt) { #ifdef HAVE_ARMv6 assem_debug("sxtb %s,%s\n",regname[rt],regname[rs]); output_w32(0xe6af0070|rd_rn_rm(rt,0,rs)); #else emit_shlimm(rs,24,rt); emit_sarimm(rt,24,rt); #endif } void emit_movswl_reg(int rs, int rt) { #ifdef HAVE_ARMv6 assem_debug("sxth %s,%s\n",regname[rt],regname[rs]); output_w32(0xe6bf0070|rd_rn_rm(rt,0,rs)); #else emit_shlimm(rs,16,rt); emit_sarimm(rt,16,rt); #endif } void emit_slti32(int rs,int imm,int rt) { if(rs!=rt) emit_zeroreg(rt); emit_cmpimm(rs,imm); if(rs==rt) emit_movimm(0,rt); emit_cmovl_imm(1,rt); } void emit_sltiu32(int rs,int imm,int rt) { if(rs!=rt) emit_zeroreg(rt); emit_cmpimm(rs,imm); if(rs==rt) emit_movimm(0,rt); emit_cmovb_imm(1,rt); } void emit_slti64_32(int rsh,int rsl,int imm,int rt) { assert(rsh!=rt); emit_slti32(rsl,imm,rt); if(imm>=0) { emit_test(rsh,rsh); emit_cmovne_imm(0,rt); emit_cmovs_imm(1,rt); } else { emit_cmpimm(rsh,-1); emit_cmovne_imm(0,rt); emit_cmovl_imm(1,rt); } } void emit_sltiu64_32(int rsh,int rsl,int imm,int rt) { assert(rsh!=rt); emit_sltiu32(rsl,imm,rt); if(imm>=0) { emit_test(rsh,rsh); emit_cmovne_imm(0,rt); } else { emit_cmpimm(rsh,-1); emit_cmovne_imm(1,rt); } } void emit_cmp(int rs,int rt) { assem_debug("cmp %s,%s\n",regname[rs],regname[rt]); output_w32(0xe1500000|rd_rn_rm(0,rs,rt)); } void emit_set_gz32(int rs, int rt) { //assem_debug("set_gz32\n"); emit_cmpimm(rs,1); emit_movimm(1,rt); emit_cmovl_imm(0,rt); } void emit_set_nz32(int rs, int rt) { //assem_debug("set_nz32\n"); if(rs!=rt) emit_movs(rs,rt); else emit_test(rs,rs); emit_cmovne_imm(1,rt); } void emit_set_gz64_32(int rsh, int rsl, int rt) { //assem_debug("set_gz64\n"); emit_set_gz32(rsl,rt); emit_test(rsh,rsh); emit_cmovne_imm(1,rt); emit_cmovs_imm(0,rt); } void emit_set_nz64_32(int rsh, int rsl, int rt) { //assem_debug("set_nz64\n"); emit_or_and_set_flags(rsh,rsl,rt); emit_cmovne_imm(1,rt); } void emit_set_if_less32(int rs1, int rs2, int rt) { //assem_debug("set if less (%%%s,%%%s),%%%s\n",regname[rs1],regname[rs2],regname[rt]); if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt); emit_cmp(rs1,rs2); if(rs1==rt||rs2==rt) emit_movimm(0,rt); emit_cmovl_imm(1,rt); } void emit_set_if_carry32(int rs1, int rs2, int rt) { //assem_debug("set if carry (%%%s,%%%s),%%%s\n",regname[rs1],regname[rs2],regname[rt]); if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt); emit_cmp(rs1,rs2); if(rs1==rt||rs2==rt) emit_movimm(0,rt); emit_cmovb_imm(1,rt); } void emit_set_if_less64_32(int u1, int l1, int u2, int l2, int rt) { //assem_debug("set if less64 (%%%s,%%%s,%%%s,%%%s),%%%s\n",regname[u1],regname[l1],regname[u2],regname[l2],regname[rt]); assert(u1!=rt); assert(u2!=rt); emit_cmp(l1,l2); emit_movimm(0,rt); emit_sbcs(u1,u2,HOST_TEMPREG); emit_cmovl_imm(1,rt); } void emit_set_if_carry64_32(int u1, int l1, int u2, int l2, int rt) { //assem_debug("set if carry64 (%%%s,%%%s,%%%s,%%%s),%%%s\n",regname[u1],regname[l1],regname[u2],regname[l2],regname[rt]); assert(u1!=rt); assert(u2!=rt); emit_cmp(l1,l2); emit_movimm(0,rt); emit_sbcs(u1,u2,HOST_TEMPREG); emit_cmovb_imm(1,rt); } void emit_orreq_imm(int rs,int imm,int rt) { u32 armval; if(genimm(imm,&armval)) { assem_debug("orreq %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0x03800000|rd_rn_rm(rt,rs,0)|armval); }else{ assert(0); // FIXME assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF00); assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF); output_w32(0xe3800000|rd_rn_imm_shift(rt,rs,imm>>8,8)); output_w32(0xe3800000|rd_rn_imm_shift(rt,rt,imm&0xff,0)); } } void emit_orrne_imm(int rs,int imm,int rt) { u32 armval; if(genimm(imm,&armval)) { assem_debug("orrne %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0x13800000|rd_rn_rm(rt,rs,0)|armval); }else{ assert(0); // FIXME assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF00); assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF); output_w32(0xe3800000|rd_rn_imm_shift(rt,rs,imm>>8,8)); output_w32(0xe3800000|rd_rn_imm_shift(rt,rt,imm&0xff,0)); } } void emit_orrhi_imm(int rs,int imm,int rt) { u32 armval; if(genimm(imm,&armval)) { assem_debug("orrhi %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0x83800000|rd_rn_rm(rt,rs,0)|armval); }else{ assert(0); // FIXME assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF00); assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF); output_w32(0xe3800000|rd_rn_imm_shift(rt,rs,imm>>8,8)); output_w32(0xe3800000|rd_rn_imm_shift(rt,rt,imm&0xff,0)); } } void emit_orrge_imm(int rs,int imm,int rt) { u32 armval; if(genimm(imm,&armval)) { assem_debug("orrge %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0xa3800000|rd_rn_rm(rt,rs,0)|armval); }else{ assert(0); // FIXME assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF00); assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF); output_w32(0xe3800000|rd_rn_imm_shift(rt,rs,imm>>8,8)); output_w32(0xe3800000|rd_rn_imm_shift(rt,rt,imm&0xff,0)); } } void emit_orrgt_imm(int rs,int imm,int rt) { u32 armval; if(genimm(imm,&armval)) { assem_debug("orrgt %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0xc3800000|rd_rn_rm(rt,rs,0)|armval); }else{ assert(0); // FIXME assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF00); assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF); output_w32(0xe3800000|rd_rn_imm_shift(rt,rs,imm>>8,8)); output_w32(0xe3800000|rd_rn_imm_shift(rt,rt,imm&0xff,0)); } } void emit_orrmi_imm(int rs,int imm,int rt) { u32 armval; if(genimm(imm,&armval)) { assem_debug("orrmi %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0x43800000|rd_rn_rm(rt,rs,0)|armval); }else{ assert(0); // FIXME assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF00); assem_debug("orr %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF); output_w32(0xe3800000|rd_rn_imm_shift(rt,rs,imm>>8,8)); output_w32(0xe3800000|rd_rn_imm_shift(rt,rt,imm&0xff,0)); } } void emit_sh2tst(int s1, int s2, int sr, int temp) { emit_andimm(sr,~1,sr); emit_test(s1,s2); emit_orreq_imm(sr,1,sr); } void emit_sh2tstimm(int s, int imm, int sr, int temp) { emit_andimm(sr,~1,sr); emit_testimm(s,imm); emit_orreq_imm(sr,1,sr); } void emit_cmpeq(int s1, int s2, int sr, int temp) { emit_andimm(sr,~1,sr); emit_cmp(s1,s2); emit_orreq_imm(sr,1,sr); } void emit_cmpeqimm(int s, int imm, int sr, int temp) { emit_andimm(sr,~1,sr); emit_cmpimm(s,imm); emit_orreq_imm(sr,1,sr); } void emit_cmpge(int s1, int s2, int sr, int temp) { emit_andimm(sr,~1,sr); emit_cmp(s2,s1); emit_orrge_imm(sr,1,sr); } void emit_cmpgt(int s1, int s2, int sr, int temp) { emit_andimm(sr,~1,sr); emit_cmp(s2,s1); emit_orrgt_imm(sr,1,sr); } void emit_cmphi(int s1, int s2, int sr, int temp) { emit_andimm(sr,~1,sr); emit_cmp(s2,s1); emit_orrhi_imm(sr,1,sr); } void emit_cmphs(int s1, int s2, int sr, int temp) { emit_andimm(sr,~1,sr); emit_cmp(s2,s1); emit_adcimm(sr,0,sr); } void emit_dt(int t, int sr) { emit_andimm(sr,~1,sr); emit_addimm_and_set_flags(-1,t); emit_orreq_imm(sr,1,sr); } void emit_cmppz(int s, int sr) { emit_andimm(sr,~1,sr); emit_testimm(s,0x80000000); emit_orreq_imm(sr,1,sr); } void emit_cmppl(int s, int sr, int temp) { assert(temp>=0); emit_andimm(sr,~1,sr); emit_cmpimm(s,0); emit_orrgt_imm(sr,1,sr); } void emit_addc(int s, int t, int sr) { emit_lsrs_imm(sr,1,sr); emit_adcs(s,t,t); emit_adc(sr,sr,sr); } void emit_subc(int s, int t, int sr) { emit_xorimm(sr,1,sr); emit_lsrs_imm(sr,1,sr); emit_sbcs(t,s,t); emit_adc(sr,sr,sr); emit_xorimm(sr,1,sr); } void emit_shrsr(int t, int sr) { emit_andimm(sr,~1,sr); emit_lsrs_imm(t,1,t); emit_adcimm(sr,0,sr); } void emit_sarsr(int t, int sr) { emit_andimm(sr,~1,sr); emit_asrs_imm(t,1,t); emit_adcimm(sr,0,sr); } void emit_shlsr(int t, int sr) { emit_andimm(sr,~1,sr); emit_lsls_imm(t,1,t); emit_adcimm(sr,0,sr); } void emit_rotl(int t) { emit_rorimm(t,31,t); } void emit_rotlsr(int t, int sr) { emit_andimm(sr,~1,sr); emit_test(t,t); emit_rotl(t); emit_orrmi_imm(sr,1,sr); } void emit_rotr(int t) { emit_rorimm(t,1,t); } void emit_rotrsr(int t, int sr) { emit_andimm(sr,~1,sr); emit_rors_imm(t,1,t); emit_adcimm(sr,0,sr); } void emit_rotclsr(int t, int sr) { emit_lsrs_imm(sr,1,sr); emit_adcs(t,t,t); emit_adc(sr,sr,sr); } void emit_rotcrsr(int t, int sr) { emit_lsrs_imm(sr,1,sr); emit_rrxs(t,t); emit_adc(sr,sr,sr); } void emit_call(int a) { assem_debug("bl %x (%x+%x)\n",a,(int)out,a-(int)out-8); u32 offset=genjmp(a); output_w32(0xeb000000|offset); } void emit_jmp(int a) { assem_debug("b %x (%x+%x)\n",a,(int)out,a-(int)out-8); u32 offset=genjmp(a); output_w32(0xea000000|offset); } void emit_jne(int a) { assem_debug("bne %x\n",a); u32 offset=genjmp(a); output_w32(0x1a000000|offset); } void emit_jeq(int a) { assem_debug("beq %x\n",a); u32 offset=genjmp(a); output_w32(0x0a000000|offset); } void emit_js(int a) { assem_debug("bmi %x\n",a); u32 offset=genjmp(a); output_w32(0x4a000000|offset); } void emit_jns(int a) { assem_debug("bpl %x\n",a); u32 offset=genjmp(a); output_w32(0x5a000000|offset); } void emit_jl(int a) { assem_debug("blt %x\n",a); u32 offset=genjmp(a); output_w32(0xba000000|offset); } void emit_jge(int a) { assem_debug("bge %x\n",a); u32 offset=genjmp(a); output_w32(0xaa000000|offset); } void emit_jno(int a) { assem_debug("bvc %x\n",a); u32 offset=genjmp(a); output_w32(0x7a000000|offset); } void emit_jc(int a) { assem_debug("bcs %x\n",a); u32 offset=genjmp(a); output_w32(0x2a000000|offset); } void emit_jcc(int a) { assem_debug("bcc %x\n",a); u32 offset=genjmp(a); output_w32(0x3a000000|offset); } void emit_pushimm(int imm) { assem_debug("push $%x\n",imm); assert(0); } void emit_pusha() { assem_debug("pusha\n"); assert(0); } void emit_popa() { assem_debug("popa\n"); assert(0); } void emit_pushreg(unsigned int r) { assem_debug("push %%%s\n",regname[r]); assert(0); } void emit_popreg(unsigned int r) { assem_debug("pop %%%s\n",regname[r]); assert(0); } void emit_callreg(unsigned int r) { assem_debug("call *%%%s\n",regname[r]); assert(0); } void emit_jmpreg(unsigned int r) { assem_debug("mov pc,%s\n",regname[r]); output_w32(0xe1a00000|rd_rn_rm(15,0,r)); } void emit_cmpstr(int s1, int s2, int sr, int temp) { // Compare s1 and s2. If any byte is equal, set T. // Calculates the xor of the strings, then checks if any byte is zero emit_xor(s1,s2,14); emit_andimm(sr,~1,sr); emit_testimm(14,0xFF); emit_orreq_imm(sr,1,sr); emit_testimm(14,0xFF00); emit_orreq_imm(sr,1,sr); emit_testimm(14,0xFF0000); emit_orreq_imm(sr,1,sr); emit_testimm(14,0xFF000000); emit_orreq_imm(sr,1,sr); // Compare s1 and s2. If any byte is equal, set T. // Calculates the xor of the strings, then checks if any byte is // zero by subtracting 1 from each byte. If there is a carry/borrow // then a byte was zero. //assert(temp>=0); //emit_xor(s1,s2,s2); //emit_movimm(0x01010101,14); //emit_andimm(sr,~1,sr); //emit_subs(s2,14,temp); //emit_sbcimm(temp,0,temp); //emit_xor(temp,s2,temp); //emit_not(temp,temp); //emit_testimm(temp,14); //emit_xor(s1,s2,s2); //emit_orrne_imm(sr,1,sr); } void emit_negc(int rs, int rt, int sr) { assert(0); /* assert(rs>=0&&rs<8); if(rt<0) { emit_shrimm(sr,1,sr); // Get C flag emit_jc((int)out+10); // 6 emit_neg(rs,rs); // 2 emit_neg(rs,rs); // 2 emit_adc(sr,sr); // Save C flag }else{ if(rs!=rt) emit_mov(rs,rt); emit_shrimm(sr,1,sr); // Get C flag emit_jc((int)out+9); // 6 emit_addimm(rt,-1,rt); // 3 emit_adc(sr,sr); // Save C flag emit_not(rt,rt); } */ } void emit_readword_indexed(int offset, int rs, int rt) { assert(offset>-4096&&offset<4096); assem_debug("ldr %s,%s+%d\n",regname[rt],regname[rs],offset); if(offset>=0) { output_w32(0xe5900000|rd_rn_rm(rt,rs,0)|offset); }else{ output_w32(0xe5100000|rd_rn_rm(rt,rs,0)|(-offset)); } } void emit_readword_dualindexedx4(int rs1, int rs2, int rt) { assem_debug("ldr %s,%s,%s lsl #2\n",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe7900000|rd_rn_rm(rt,rs1,rs2)|0x100); } void emit_readword_indexed_map(int addr, int rs, int map, int rt) { if(map<0) emit_readword_indexed(addr, rs, rt); else { assert(addr==0); emit_readword_dualindexedx4(rs, map, rt); } } void emit_movsbl_indexed(int offset, int rs, int rt) { assert(offset>-256&&offset<256); assem_debug("ldrsb %s,%s+%d\n",regname[rt],regname[rs],offset); if(offset>=0) { output_w32(0xe1d000d0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf)); }else{ output_w32(0xe15000d0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf)); } } void emit_movsbl_indexed_map(int addr, int rs, int map, int rt) { if(map<0) emit_movsbl_indexed(addr, rs, rt); else { if(addr==0) { emit_shlimm(map,2,HOST_TEMPREG); assem_debug("ldrsb %s,%s+%s\n",regname[rt],regname[rs],regname[HOST_TEMPREG]); output_w32(0xe19000d0|rd_rn_rm(rt,rs,HOST_TEMPREG)); }else{ assert(addr>-256&&addr<256); assem_debug("add %s,%s,%s,lsl #2\n",regname[rt],regname[rs],regname[map]); output_w32(0xe0800000|rd_rn_rm(rt,rs,map)|(2<<7)); emit_movsbl_indexed(addr, rt, rt); } } } void emit_movswl_indexed(int offset, int rs, int rt) { assert(offset>-256&&offset<256); assem_debug("ldrsh %s,%s+%d\n",regname[rt],regname[rs],offset); if(offset>=0) { output_w32(0xe1d000f0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf)); }else{ output_w32(0xe15000f0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf)); } } void emit_movswl_indexed_map(int addr, int rs, int map, int rt) { if(map<0) emit_movswl_indexed(addr, rs, rt); else { if(addr==0) { emit_shlimm(map,2,HOST_TEMPREG); assem_debug("ldrsh %s,%s+%s\n",regname[rt],regname[rs],regname[HOST_TEMPREG]); output_w32(0xe19000f0|rd_rn_rm(rt,rs,HOST_TEMPREG)); }else{ assert(addr>-256&&addr<256); assem_debug("add %s,%s,%s,lsl #2\n",regname[rt],regname[rs],regname[map]); output_w32(0xe0800000|rd_rn_rm(rt,rs,map)|(2<<7)); emit_movswl_indexed(addr, rt, rt); } } } void emit_movzbl_indexed(int offset, int rs, int rt) { assert(offset>-4096&&offset<4096); assem_debug("ldrb %s,%s+%d\n",regname[rt],regname[rs],offset); if(offset>=0) { output_w32(0xe5d00000|rd_rn_rm(rt,rs,0)|offset); }else{ output_w32(0xe5500000|rd_rn_rm(rt,rs,0)|(-offset)); } } void emit_movzbl_dualindexedx4(int rs1, int rs2, int rt) { assem_debug("ldrb %s,%s,%s lsl #2\n",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe7d00000|rd_rn_rm(rt,rs1,rs2)|0x100); } void emit_movzbl_indexed_map(int addr, int rs, int map, int rt) { if(map<0) emit_movzbl_indexed(addr, rs, rt); else { if(addr==0) { emit_movzbl_dualindexedx4(rs, map, rt); }else{ emit_addimm(rs,addr,rt); emit_movzbl_dualindexedx4(rt, map, rt); } } } void emit_movzwl_indexed(int offset, int rs, int rt) { assert(offset>-256&&offset<256); assem_debug("ldrh %s,%s+%d\n",regname[rt],regname[rs],offset); if(offset>=0) { output_w32(0xe1d000b0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf)); }else{ output_w32(0xe15000b0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf)); } } void emit_readword(int addr, int rt) { u32 offset = addr-(u32)&dynarec_local; assert(offset<4096); assem_debug("ldr %s,fp+%d\n",regname[rt],offset); output_w32(0xe5900000|rd_rn_rm(rt,FP,0)|offset); } void emit_movsbl(int addr, int rt) { u32 offset = addr-(u32)&dynarec_local; assert(offset<256); assem_debug("ldrsb %s,fp+%d\n",regname[rt],offset); output_w32(0xe1d000d0|rd_rn_rm(rt,FP,0)|((offset<<4)&0xf00)|(offset&0xf)); } void emit_movswl(int addr, int rt) { u32 offset = addr-(u32)&dynarec_local; assert(offset<256); assem_debug("ldrsh %s,fp+%d\n",regname[rt],offset); output_w32(0xe1d000f0|rd_rn_rm(rt,FP,0)|((offset<<4)&0xf00)|(offset&0xf)); } void emit_movzbl(int addr, int rt) { u32 offset = addr-(u32)&dynarec_local; assert(offset<4096); assem_debug("ldrb %s,fp+%d\n",regname[rt],offset); output_w32(0xe5d00000|rd_rn_rm(rt,FP,0)|offset); } void emit_movzwl(int addr, int rt) { u32 offset = addr-(u32)&dynarec_local; assert(offset<256); assem_debug("ldrh %s,fp+%d\n",regname[rt],offset); output_w32(0xe1d000b0|rd_rn_rm(rt,FP,0)|((offset<<4)&0xf00)|(offset&0xf)); } void emit_xchg(int rs, int rt) { assem_debug("xchg %%%s,%%%s\n",regname[rs],regname[rt]); assert(0); } void emit_writeword_indexed(int rt, int offset, int rs) { assert(offset>-4096&&offset<4096); assem_debug("str %s,%s+%d\n",regname[rt],regname[rs],offset); if(offset>=0) { output_w32(0xe5800000|rd_rn_rm(rt,rs,0)|offset); }else{ output_w32(0xe5000000|rd_rn_rm(rt,rs,0)|(-offset)); } } void emit_writeword_dualindexedx4(int rt, int rs1, int rs2) { assem_debug("str %s,%s,%s lsl #2\n",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe7800000|rd_rn_rm(rt,rs1,rs2)|0x100); } void emit_writeword_indexed_map(int rt, int addr, int rs, int map, int temp) { if(map<0) emit_writeword_indexed(rt, addr, rs); else { assert(addr==0); emit_writeword_dualindexedx4(rt, rs, map); } } void emit_writehword_indexed(int rt, int offset, int rs) { assert(offset>-256&&offset<256); assem_debug("strh %s,%s+%d\n",regname[rt],regname[rs],offset); if(offset>=0) { output_w32(0xe1c000b0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf)); }else{ output_w32(0xe14000b0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf)); } } void emit_writebyte_indexed(int rt, int offset, int rs) { assert(offset>-4096&&offset<4096); assem_debug("strb %s,%s+%d\n",regname[rt],regname[rs],offset); if(offset>=0) { output_w32(0xe5c00000|rd_rn_rm(rt,rs,0)|offset); }else{ output_w32(0xe5400000|rd_rn_rm(rt,rs,0)|(-offset)); } } void emit_writebyte_dualindexedx4(int rt, int rs1, int rs2) { assem_debug("strb %s,%s,%s lsl #2\n",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe7c00000|rd_rn_rm(rt,rs1,rs2)|0x100); } void emit_writebyte_indexed_map(int rt, int addr, int rs, int map, int temp) { if(map<0) emit_writebyte_indexed(rt, addr, rs); else { if(addr==0) { emit_writebyte_dualindexedx4(rt, rs, map); }else{ emit_addimm(rs,addr,temp); emit_writebyte_dualindexedx4(rt, temp, map); } } } void emit_writehword_indexed_map(int rt, int addr, int rs, int map, int temp) { if(map<0) emit_writehword_indexed(rt, addr, rs); else { if(addr==0) { emit_shlimm(map,2,HOST_TEMPREG); assem_debug("strh %s,%s+%s\n",regname[rt],regname[rs],regname[HOST_TEMPREG]); output_w32(0xe18000b0|rd_rn_rm(rt,rs,HOST_TEMPREG)); }else{ assert(addr==0); } } } void emit_writeword(int rt, int addr) { u32 offset = addr-(u32)&dynarec_local; assert(offset<4096); assem_debug("str %s,fp+%d\n",regname[rt],offset); output_w32(0xe5800000|rd_rn_rm(rt,FP,0)|offset); } void emit_writehword(int rt, int addr) { u32 offset = addr-(u32)&dynarec_local; assert(offset<256); assem_debug("strh %s,fp+%d\n",regname[rt],offset); output_w32(0xe1c000b0|rd_rn_rm(rt,FP,0)|((offset<<4)&0xf00)|(offset&0xf)); } void emit_writebyte(int rt, int addr) { u32 offset = addr-(u32)&dynarec_local; assert(offset<4096); assem_debug("strb %s,fp+%d\n",regname[rt],offset); output_w32(0xe5c00000|rd_rn_rm(rt,FP,0)|offset); } void emit_writeword_imm(int imm, int addr) { assem_debug("movl $%x,%x\n",imm,addr); assert(0); } void emit_writebyte_imm(int imm, int addr) { assem_debug("movb $%x,%x\n",imm,addr); assert(0); } void emit_rmw_andimm(int addr, int map, int imm) { if(map<0) { assert(map>=0); } else { emit_movzbl_dualindexedx4(addr, map, 14); emit_andimm(14,imm,14); emit_writebyte_dualindexedx4(14, addr, map); } } void emit_rmw_xorimm(int addr, int map, int imm) { if(map<0) { assert(map>=0); } else { emit_movzbl_dualindexedx4(addr, map, 14); emit_xorimm(14,imm,14); emit_writebyte_dualindexedx4(14, addr, map); } } void emit_rmw_orimm(int addr, int map, int imm) { if(map<0) { assert(map>=0); } else { emit_movzbl_dualindexedx4(addr, map, 14); emit_orimm(14,imm,14); emit_writebyte_dualindexedx4(14, addr, map); } } void emit_sh2tas(int addr, int map, int sr) { if(map<0) { assert(map>=0); } else { emit_movzbl_dualindexedx4(addr, map, 14); emit_andimm(sr,~1,sr); emit_testimm(14,0xff); emit_orimm(14,0x80,14); emit_orreq_imm(sr,1,sr); emit_writebyte_dualindexedx4(14, addr, map); } } void emit_mul(int rs) { assem_debug("mul %%%s\n",regname[rs]); assert(0); } void emit_imul(int rs) { assem_debug("imul %%%s\n",regname[rs]); assert(0); } void emit_multiply(unsigned int rs1,unsigned int rs2,unsigned int rt) { if(rs1==rt&&rs2==rt) {emit_mov(rs1,14);emit_multiply(14,14,rt);} else if(rs1==rt) {emit_multiply(rs2,rs1,rt);} else { assem_debug("mul %s, %s, %s\n",regname[rt],regname[rs1],regname[rs2]); assert(rs1<16); assert(rs2<16); assert(rt<16); output_w32(0xe0000090|(rt<<16)|(rs2<<8)|rs1); } } void emit_umull(unsigned int rs1, unsigned int rs2, unsigned int hi, unsigned int lo) { assem_debug("umull %s, %s, %s, %s\n",regname[lo],regname[hi],regname[rs1],regname[rs2]); assert(rs1<16); assert(rs2<16); assert(hi<16); assert(lo<16); assert(hi!=rs1&&hi!=rs2); assert(lo!=rs1&&lo!=rs2); output_w32(0xe0800090|(hi<<16)|(lo<<12)|(rs2<<8)|rs1); } void emit_smull(unsigned int rs1, unsigned int rs2, unsigned int hi, unsigned int lo) { assem_debug("smull %s, %s, %s, %s\n",regname[lo],regname[hi],regname[rs1],regname[rs2]); assert(rs1<16); assert(rs2<16); assert(hi<16); assert(lo<16); assert(hi!=rs1&&hi!=rs2); assert(lo!=rs1&&lo!=rs2); output_w32(0xe0c00090|(hi<<16)|(lo<<12)|(rs2<<8)|rs1); } void emit_div(int rs) { assem_debug("div %%%s\n",regname[rs]); assert(0); } void emit_idiv(int rs) { assem_debug("idiv %%%s\n",regname[rs]); assert(0); } void emit_cdq() { assem_debug("cdq\n"); assert(0); } void emit_teq(int rs, int rt) { assem_debug("teq %s,%s\n",regname[rs],regname[rt]); output_w32(0xe1300000|rd_rn_rm(0,rs,rt)); } void emit_div0s(int s1, int s2, int sr, int temp) { emit_andimm(sr,0xfe,sr); emit_testimm(s2,0x80000000); emit_orrne_imm(sr,0x100,sr); emit_testimm(s1,0x80000000); emit_orrne_imm(sr,0x200,sr); emit_teq(s1,s2); emit_orrmi_imm(sr,1,sr); } // Load return address void emit_load_return_address(unsigned int rt) { // (assumes this instruction will be followed by a branch instruction) emit_mov(15,rt); //assem_debug("add %s,pc,#0\n",regname[rt]); //output_w32(0xe2800000|rd_rn_rm(rt,15,0)); } void emit_clz(int rs,int rt) { assem_debug("clz %s,%s\n",regname[rt],regname[rs]); output_w32(0xe16f0f10|rd_rn_rm(rt,0,rs)); } void emit_subcs(int rs1,int rs2,int rt) { assem_debug("subcs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); output_w32(0x20400000|rd_rn_rm(rt,rs1,rs2)); } void emit_shrcc_imm(int rs,unsigned int imm,int rt) { assert(imm>0); assert(imm<32); assem_debug("lsrcc %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0x31a00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7)); } void emit_negmi(int rs, int rt) { assem_debug("rsbmi %s,%s,#0\n",regname[rt],regname[rs]); output_w32(0x42600000|rd_rn_rm(rt,rs,0)); } void emit_negsmi(int rs, int rt) { assem_debug("rsbsmi %s,%s,#0\n",regname[rt],regname[rs]); output_w32(0x42700000|rd_rn_rm(rt,rs,0)); } void emit_orreq(unsigned int rs1,unsigned int rs2,unsigned int rt) { assem_debug("orreq %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); output_w32(0x01800000|rd_rn_rm(rt,rs1,rs2)); } void emit_orrne(unsigned int rs1,unsigned int rs2,unsigned int rt) { assem_debug("orrne %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); output_w32(0x11800000|rd_rn_rm(rt,rs1,rs2)); } void emit_bic_lsl(unsigned int rs1,unsigned int rs2,unsigned int shift,unsigned int rt) { assem_debug("bic %s,%s,%s lsl %s\n",regname[rt],regname[rs1],regname[rs2],regname[shift]); output_w32(0xe1C00000|rd_rn_rm(rt,rs1,rs2)|0x10|(shift<<8)); } void emit_biceq_lsl(unsigned int rs1,unsigned int rs2,unsigned int shift,unsigned int rt) { assem_debug("biceq %s,%s,%s lsl %s\n",regname[rt],regname[rs1],regname[rs2],regname[shift]); output_w32(0x01C00000|rd_rn_rm(rt,rs1,rs2)|0x10|(shift<<8)); } void emit_bicne_lsl(unsigned int rs1,unsigned int rs2,unsigned int shift,unsigned int rt) { assem_debug("bicne %s,%s,%s lsl %s\n",regname[rt],regname[rs1],regname[rs2],regname[shift]); output_w32(0x11C00000|rd_rn_rm(rt,rs1,rs2)|0x10|(shift<<8)); } void emit_bic_lsr(unsigned int rs1,unsigned int rs2,unsigned int shift,unsigned int rt) { assem_debug("bic %s,%s,%s lsr %s\n",regname[rt],regname[rs1],regname[rs2],regname[shift]); output_w32(0xe1C00000|rd_rn_rm(rt,rs1,rs2)|0x30|(shift<<8)); } void emit_biceq_lsr(unsigned int rs1,unsigned int rs2,unsigned int shift,unsigned int rt) { assem_debug("biceq %s,%s,%s lsr %s\n",regname[rt],regname[rs1],regname[rs2],regname[shift]); output_w32(0x01C00000|rd_rn_rm(rt,rs1,rs2)|0x30|(shift<<8)); } void emit_bicne_lsr(unsigned int rs1,unsigned int rs2,unsigned int shift,unsigned int rt) { assem_debug("bicne %s,%s,%s lsr %s\n",regname[rt],regname[rs1],regname[rs2],regname[shift]); output_w32(0x11C00000|rd_rn_rm(rt,rs1,rs2)|0x30|(shift<<8)); } void emit_rsbimm(int rs, int imm, int rt) { u32 armval; genimm(imm,&armval); assem_debug("rsb %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0xe2600000|rd_rn_rm(rt,rs,0)|armval); } // Load 2 immediates optimizing for small code size void emit_mov2imm_compact(int imm1,unsigned int rt1,int imm2,unsigned int rt2) { emit_movimm(imm1,rt1); u32 armval; if(genimm(imm2-imm1,&armval)) { assem_debug("add %s,%s,#%d\n",regname[rt2],regname[rt1],imm2-imm1); output_w32(0xe2800000|rd_rn_rm(rt2,rt1,0)|armval); }else if(genimm(imm1-imm2,&armval)) { assem_debug("sub %s,%s,#%d\n",regname[rt2],regname[rt1],imm1-imm2); output_w32(0xe2400000|rd_rn_rm(rt2,rt1,0)|armval); } else emit_movimm(imm2,rt2); } // Conditionally select one of two immediates, optimizing for small code size // This will only be called if HAVE_CMOV_IMM is defined void emit_cmov2imm_e_ne_compact(int imm1,int imm2,unsigned int rt) { u32 armval; if(genimm(imm2-imm1,&armval)) { emit_movimm(imm1,rt); assem_debug("addne %s,%s,#%d\n",regname[rt],regname[rt],imm2-imm1); output_w32(0x12800000|rd_rn_rm(rt,rt,0)|armval); }else if(genimm(imm1-imm2,&armval)) { emit_movimm(imm1,rt); assem_debug("subne %s,%s,#%d\n",regname[rt],regname[rt],imm1-imm2); output_w32(0x12400000|rd_rn_rm(rt,rt,0)|armval); } else { #ifndef HAVE_ARMv7 emit_movimm(imm1,rt); add_literal((int)out,imm2); assem_debug("ldrne %s,pc+? [=%x]\n",regname[rt],imm2); output_w32(0x15900000|rd_rn_rm(rt,15,0)); #else emit_movw(imm1&0x0000FFFF,rt); if((imm1&0xFFFF)!=(imm2&0xFFFF)) { assem_debug("movwne %s,#%d (0x%x)\n",regname[rt],imm2&0xFFFF,imm2&0xFFFF); output_w32(0x13000000|rd_rn_rm(rt,0,0)|(imm2&0xfff)|((imm2<<4)&0xf0000)); } emit_movt(imm1&0xFFFF0000,rt); if((imm1&0xFFFF0000)!=(imm2&0xFFFF0000)) { assem_debug("movtne %s,#%d (0x%x)\n",regname[rt],imm2&0xffff0000,imm2&0xffff0000); output_w32(0x13400000|rd_rn_rm(rt,0,0)|((imm2>>16)&0xfff)|((imm2>>12)&0xf0000)); } #endif } } // special case for checking invalid_code void emit_cmpmem_indexedsr12_imm(int addr,int r,int imm) { assert(0); } // special case for checking invalid_code void emit_cmpmem_indexedsr12_reg(int base,int r,int imm) { assert(imm<128&&imm>=0); assert(r>=0&&r<16); assem_debug("ldrb lr,%s,%s lsr #12\n",regname[base],regname[r]); output_w32(0xe7d00000|rd_rn_rm(HOST_TEMPREG,base,r)|0x620); emit_cmpimm(HOST_TEMPREG,imm); } // special case for memory map void emit_addsr12(int rs1,int rs2,int rt) { assem_debug("add %s,%s,%s lsr #12\n",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0800620|rd_rn_rm(rt,rs1,rs2)); } void emit_callne(int a) { assem_debug("blne %x\n",a); u32 offset=genjmp(a); output_w32(0x1b000000|offset); } // Used to preload hash table entries void emit_prefetch(void *addr) { assem_debug("prefetch %x\n",(int)addr); output_byte(0x0F); output_byte(0x18); output_modrm(0,5,1); output_w32((int)addr); } void emit_prefetchreg(int r) { assem_debug("pld %s\n",regname[r]); output_w32(0xf5d0f000|rd_rn_rm(0,r,0)); } // Special case for mini_ht void emit_ldreq_indexed(int rs, u32 offset, int rt) { assert(offset<4096); assem_debug("ldreq %s,[%s, #%d]\n",regname[rt],regname[rs],offset); output_w32(0x05900000|rd_rn_rm(rt,rs,0)|offset); } void emit_flds(int r,int sr) { assem_debug("flds s%d,[%s]\n",sr,regname[r]); output_w32(0xed900a00|((sr&14)<<11)|((sr&1)<<22)|(r<<16)); } void emit_vldr(int r,int vr) { assem_debug("vldr d%d,[%s]\n",vr,regname[r]); output_w32(0xed900b00|(vr<<12)|(r<<16)); } void emit_fsts(int sr,int r) { assem_debug("fsts s%d,[%s]\n",sr,regname[r]); output_w32(0xed800a00|((sr&14)<<11)|((sr&1)<<22)|(r<<16)); } void emit_vstr(int vr,int r) { assem_debug("vstr d%d,[%s]\n",vr,regname[r]); output_w32(0xed800b00|(vr<<12)|(r<<16)); } void emit_ftosizs(int s,int d) { assem_debug("ftosizs s%d,s%d\n",d,s); output_w32(0xeebd0ac0|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5)); } void emit_ftosizd(int s,int d) { assem_debug("ftosizd s%d,d%d\n",d,s); output_w32(0xeebd0bc0|((d&14)<<11)|((d&1)<<22)|(s&7)); } void emit_fsitos(int s,int d) { assem_debug("fsitos s%d,s%d\n",d,s); output_w32(0xeeb80ac0|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5)); } void emit_fsitod(int s,int d) { assem_debug("fsitod d%d,s%d\n",d,s); output_w32(0xeeb80bc0|((d&7)<<12)|((s&14)>>1)|((s&1)<<5)); } void emit_fcvtds(int s,int d) { assem_debug("fcvtds d%d,s%d\n",d,s); output_w32(0xeeb70ac0|((d&7)<<12)|((s&14)>>1)|((s&1)<<5)); } void emit_fcvtsd(int s,int d) { assem_debug("fcvtsd s%d,d%d\n",d,s); output_w32(0xeeb70bc0|((d&14)<<11)|((d&1)<<22)|(s&7)); } void emit_fsqrts(int s,int d) { assem_debug("fsqrts d%d,s%d\n",d,s); output_w32(0xeeb10ac0|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5)); } void emit_fsqrtd(int s,int d) { assem_debug("fsqrtd s%d,d%d\n",d,s); output_w32(0xeeb10bc0|((d&7)<<12)|(s&7)); } void emit_fabss(int s,int d) { assem_debug("fabss d%d,s%d\n",d,s); output_w32(0xeeb00ac0|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5)); } void emit_fabsd(int s,int d) { assem_debug("fabsd s%d,d%d\n",d,s); output_w32(0xeeb00bc0|((d&7)<<12)|(s&7)); } void emit_fnegs(int s,int d) { assem_debug("fnegs d%d,s%d\n",d,s); output_w32(0xeeb10a40|((d&14)<<11)|((d&1)<<22)|((s&14)>>1)|((s&1)<<5)); } void emit_fnegd(int s,int d) { assem_debug("fnegd s%d,d%d\n",d,s); output_w32(0xeeb10b40|((d&7)<<12)|(s&7)); } void emit_fadds(int s1,int s2,int d) { assem_debug("fadds s%d,s%d,s%d\n",d,s1,s2); output_w32(0xee300a00|((d&14)<<11)|((d&1)<<22)|((s1&14)<<15)|((s1&1)<<7)|((s2&14)>>1)|((s2&1)<<5)); } void emit_faddd(int s1,int s2,int d) { assem_debug("faddd d%d,d%d,d%d\n",d,s1,s2); output_w32(0xee300b00|((d&7)<<12)|((s1&7)<<16)|(s2&7)); } void emit_fsubs(int s1,int s2,int d) { assem_debug("fsubs s%d,s%d,s%d\n",d,s1,s2); output_w32(0xee300a40|((d&14)<<11)|((d&1)<<22)|((s1&14)<<15)|((s1&1)<<7)|((s2&14)>>1)|((s2&1)<<5)); } void emit_fsubd(int s1,int s2,int d) { assem_debug("fsubd d%d,d%d,d%d\n",d,s1,s2); output_w32(0xee300b40|((d&7)<<12)|((s1&7)<<16)|(s2&7)); } void emit_fmuls(int s1,int s2,int d) { assem_debug("fmuls s%d,s%d,s%d\n",d,s1,s2); output_w32(0xee200a00|((d&14)<<11)|((d&1)<<22)|((s1&14)<<15)|((s1&1)<<7)|((s2&14)>>1)|((s2&1)<<5)); } void emit_fmuld(int s1,int s2,int d) { assem_debug("fmuld d%d,d%d,d%d\n",d,s1,s2); output_w32(0xee200b00|((d&7)<<12)|((s1&7)<<16)|(s2&7)); } void emit_fdivs(int s1,int s2,int d) { assem_debug("fdivs s%d,s%d,s%d\n",d,s1,s2); output_w32(0xee800a00|((d&14)<<11)|((d&1)<<22)|((s1&14)<<15)|((s1&1)<<7)|((s2&14)>>1)|((s2&1)<<5)); } void emit_fdivd(int s1,int s2,int d) { assem_debug("fdivd d%d,d%d,d%d\n",d,s1,s2); output_w32(0xee800b00|((d&7)<<12)|((s1&7)<<16)|(s2&7)); } void emit_fcmps(int x,int y) { assem_debug("fcmps s14, s15\n"); output_w32(0xeeb47a67); } void emit_fcmpd(int x,int y) { assem_debug("fcmpd d6, d7\n"); output_w32(0xeeb46b47); } void emit_fmstat() { assem_debug("fmstat\n"); output_w32(0xeef1fa10); } void emit_bicne_imm(int rs,int imm,int rt) { u32 armval; genimm(imm,&armval); assem_debug("bicne %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0x13c00000|rd_rn_rm(rt,rs,0)|armval); } void emit_biccs_imm(int rs,int imm,int rt) { u32 armval; genimm(imm,&armval); assem_debug("biccs %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0x23c00000|rd_rn_rm(rt,rs,0)|armval); } void emit_bicvc_imm(int rs,int imm,int rt) { u32 armval; genimm(imm,&armval); assem_debug("bicvc %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0x73c00000|rd_rn_rm(rt,rs,0)|armval); } void emit_bichi_imm(int rs,int imm,int rt) { u32 armval; genimm(imm,&armval); assem_debug("bichi %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0x83c00000|rd_rn_rm(rt,rs,0)|armval); } void emit_orrvs_imm(int rs,int imm,int rt) { u32 armval; genimm(imm,&armval); assem_debug("orrvs %s,%s,#%d\n",regname[rt],regname[rs],imm); output_w32(0x63800000|rd_rn_rm(rt,rs,0)|armval); } void emit_jno_unlikely(int a) { //emit_jno(a); assem_debug("addvc pc,pc,#? (%x)\n",/*a-(int)out-8,*/a); output_w32(0x72800000|rd_rn_rm(15,15,0)); } // Save registers before function call void save_regs(u32 reglist) { reglist&=0x100f; // only save the caller-save registers, r0-r3, r12 if(!reglist) return; assem_debug("stmia fp,{"); if(reglist&1) assem_debug("r0, "); if(reglist&2) assem_debug("r1, "); if(reglist&4) assem_debug("r2, "); if(reglist&8) assem_debug("r3, "); if(reglist&0x1000) assem_debug("r12"); assem_debug("}\n"); output_w32(0xe88b0000|reglist); } // Restore registers after function call void restore_regs(u32 reglist) { reglist&=0x100f; // only restore the caller-save registers, r0-r3, r12 if(!reglist) return; assem_debug("ldmia fp,{"); if(reglist&1) assem_debug("r0, "); if(reglist&2) assem_debug("r1, "); if(reglist&4) assem_debug("r2, "); if(reglist&8) assem_debug("r3, "); if(reglist&0x1000) assem_debug("r12"); assem_debug("}\n"); output_w32(0xe89b0000|reglist); } /* Write back consts using r14 so we don't disturb the other registers void wb_consts(signed char i_regmap[],uint64_t i_is32,u_int i_dirty,int i) { int hr; for(hr=0;hr=0&&((i_dirty>>hr)&1)) { if(((regs[i].isdoingcp>>hr)&1)&&i_regmap[hr]>0) { if(i_regmap[hr]<64 || !((i_is32>>(i_regmap[hr]&63))&1) ) { int value=cpmap[i][hr]; if(value==0) { emit_zeroreg(HOST_TEMPREG); } else { emit_movimm(value,HOST_TEMPREG); } emit_storereg(i_regmap[hr],HOST_TEMPREG); if((i_is32>>i_regmap[hr])&1) { if(value!=-1&&value!=0) emit_sarimm(HOST_TEMPREG,31,HOST_TEMPREG); emit_storereg(i_regmap[hr]|64,HOST_TEMPREG); } } } } } }*/ /* Stubs/epilogue */ void literal_pool(int n) { if(!literalcount) return; if(n) { if((int)out-literals[0][0]<4096-n) return; } u32 *ptr; int i; for(i=0;i=0x7000000&&addr<0x7FFFFFF); //DEBUG > #ifdef DEBUG_CYCLE_COUNT emit_readword((int)&last_count,ECX); emit_add(HOST_CCREG,ECX,HOST_CCREG); emit_readword((int)&next_interupt,ECX); emit_writeword(HOST_CCREG,(int)&Count); emit_sub(HOST_CCREG,ECX,HOST_CCREG); emit_writeword(ECX,(int)&last_count); #endif //DEBUG < emit_jmp((pointer)dyna_linker); } void do_readstub(int n) { assem_debug("do_readstub %x\n",start+stubs[n][3]*2); literal_pool(256); set_jump_target(stubs[n][1],(int)out); int type=stubs[n][0]; int i=stubs[n][3]; int rs=stubs[n][4]; struct regstat *i_regs=(struct regstat *)stubs[n][5]; u32 reglist=stubs[n][7]; signed char *i_regmap=i_regs->regmap; int addr=get_reg(i_regmap,AGEN1+(i&1)); int rt; int ds; rt=get_reg(i_regmap,rt1[i]==TBIT?-1:rt1[i]); assert(rs>=0); if(addr<0) addr=rt; if(addr<0) addr=get_reg(i_regmap,-1); assert(addr>=0); save_regs(reglist); if(type==LOADB_STUB) emit_xorimm(rs,1,0); else {if(rs!=0) emit_mov(rs,0);} //ds=i_regs!=®s[i]; //int real_rs=(itype[i]==LOADLR)?-1:get_reg(i_regmap,rs1[i]); //u32 cmask=ds?-1:(0x100f|~i_regs->wasdoingcp); //if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty&~(1<regmap_entry,i_regs->was32,i_regs->wasdirty&cmask&~(1<=0); if(rs<4||rs==12) emit_writeword(rs,(int)&dynarec_local+24); emit_call((int)MappedMemoryReadLongNocache); if(rs==1||rs==2||rs==3||rs==12) emit_readword((int)&dynarec_local+24,rs); if(pc==0) { emit_writeword(0,(int)&dynarec_local+24); } else { if(pc==1||pc==2||pc==3||pc==12) emit_writeword(0,(int)&dynarec_local+24); else emit_mov(0,pc); if(rs==0) { emit_readword((int)&dynarec_local+24,rs); emit_addimm(rs,4,rs); }else emit_addimm(rs,4,0); } emit_call((int)MappedMemoryReadLongNocache); assert(rt>=0); if(rt!=0) emit_mov(0,rt); if(pc<4||pc==12) emit_readword((int)&dynarec_local+24,pc); } else if(type==LOADB_STUB) { if(rt>=0) emit_movsbl_reg(0,rt); } else if(type==LOADW_STUB) { if(rt>=0) emit_movswl_reg(0,rt); } else { if(rt>0) emit_mov(0,rt); } restore_regs(reglist); if(type==LOADS_STUB) emit_addimm(rs,8,rs); emit_jmp(stubs[n][2]); // return address } void inline_readstub(int type, int i, u32 addr, signed char regmap[], int target, int adj, u32 reglist) { assem_debug("inline_readstub\n"); //int rs=get_reg(regmap,target); int rt=get_reg(regmap,target); //if(rs<0) rs=get_reg(regmap,-1); if(rt<0) rt=get_reg(regmap,-1); //rt=get_reg(i_regmap,rt1[i]==TBIT?-1:rt1[i]); assert(rt>=0); //if(addr<0) addr=rt; //if(addr<0) addr=get_reg(i_regmap,-1); //assert(addr>=0); save_regs(reglist); emit_movimm(addr,0); if(type==LOADB_STUB) emit_call((int)MappedMemoryReadByteNocache); if(type==LOADW_STUB) emit_call((int)MappedMemoryReadWordNocache); if(type==LOADL_STUB) emit_call((int)MappedMemoryReadLongNocache); assert(type!=LOADS_STUB); if(type==LOADB_STUB) { if(rt>=0) emit_movsbl_reg(0,rt); } else if(type==LOADW_STUB) { if(rt>=0) emit_movswl_reg(0,rt); } else { if(rt>0) emit_mov(0,rt); } restore_regs(reglist); } void do_writestub(int n) { assem_debug("do_writestub %x\n",start+stubs[n][3]*2); literal_pool(256); set_jump_target(stubs[n][1],(int)out); int type=stubs[n][0]; int i=stubs[n][3]; int rs=stubs[n][4]; struct regstat *i_regs=(struct regstat *)stubs[n][5]; u32 reglist=stubs[n][7]; signed char *i_regmap=i_regs->regmap; int addr=get_reg(i_regmap,AGEN1+(i&1)); int rt=get_reg(i_regmap,rs1[i]); assert(rs>=0); assert(rt>=0); if(addr<0) addr=get_reg(i_regmap,-1); assert(addr>=0); save_regs(reglist); // "FASTCALL" api: address in r0, data in r1 if(rs!=0) { if(rt==0) { if(rs==1) { emit_mov(0,2); emit_mov(1,0); emit_mov(2,1); } else { emit_mov(rt,1); emit_mov(rs,0); } } else { emit_mov(rs,0); if(rt!=1) emit_mov(rt,1); } } else if(rt!=1) emit_mov(rt,1); //if(type==STOREB_STUB) emit_xorimm(EAX,1,EAX); // WriteInvalidateByteSwapped does this //if(i_regmap[HOST_CCREG]==CCREG) emit_storereg(CCREG,HOST_CCREG);//DEBUG //ds=i_regs!=®s[i]; //int real_rs=get_reg(i_regmap,rs2[i]); //if(!ds) load_all_consts(regs[i].regmap_entry,regs[i].was32,regs[i].wasdirty&~(1<regmap_entry,i_regs->was32,i_regs->wasdirty&~(1<=0); assert(rt>=0); save_regs(reglist); // "FASTCALL" api: address in r0, data in r1 if(rt!=1) emit_mov(rt,1); emit_movimm(addr,0); // FIXME - should be able to move the existing value if(type==STOREB_STUB) emit_call((int)WriteInvalidateByte); if(type==STOREW_STUB) emit_call((int)WriteInvalidateWord); if(type==STOREL_STUB) emit_call((int)WriteInvalidateLong); restore_regs(reglist); } void do_rmwstub(int n) { assem_debug("do_rmwstub %x\n",start+stubs[n][3]*2); set_jump_target(stubs[n][1],(int)out); int type=stubs[n][0]; int i=stubs[n][3]; int rs=stubs[n][4]; struct regstat *i_regs=(struct regstat *)stubs[n][5]; u32 reglist=stubs[n][7]; signed char *i_regmap=i_regs->regmap; int addr=get_reg(i_regmap,AGEN1+(i&1)); //int rt=get_reg(i_regmap,rs1[i]); assert(rs>=0); //assert(rt>=0); if(addr<0) addr=get_reg(i_regmap,-1); assert(addr>=0); save_regs(reglist); // "FASTCALL" api: address in r0, data in r1 emit_xorimm(rs,1,rs); if(rs!=0) emit_mov(rs,0); if(rs<4||rs==12) emit_writeword(0,(int)&dynarec_local+24); //if(i_regmap[HOST_CCREG]==CCREG) emit_storereg(CCREG,HOST_CCREG);//DEBUG emit_call((int)MappedMemoryReadByteNocache); //emit_mov(0,1); if(type==RMWA_STUB) emit_andimm(0,imm[i],1); if(type==RMWX_STUB) emit_xorimm(0,imm[i],1); if(type==RMWO_STUB) emit_orimm(0,imm[i],1); if(type==RMWT_STUB) { // TAS.B emit_writeword(0,(int)&dynarec_local+20); emit_orimm(0,0x80,1); } if(rs<4||rs==12) emit_readword((int)&dynarec_local+24,0); else emit_mov(rs,0); //emit_call((int)MappedMemoryWriteByte); emit_call((int)WriteInvalidateByte); restore_regs(reglist); if(opcode2[i]==11) { // TAS.B emit_readword((int)&dynarec_local+20,14); signed char sr; sr=get_reg(i_regs->regmap,SR); assert(sr>=0); // Liveness analysis? emit_andimm(sr,~1,sr); emit_testimm(14,0xff); emit_orreq_imm(sr,1,sr); } emit_jmp(stubs[n][2]); // return address } void do_unalignedwritestub(int n) { set_jump_target(stubs[n][1],(int)out); output_w32(0xef000000); emit_jmp(stubs[n][2]); // return address } void printregs(int edi,int esi,int ebp,int esp,int b,int d,int c,int a) { printf("regs: %x %x %x %x %x %x %x (%x)\n",a,b,c,d,ebp,esi,edi,(&edi)[-1]); } int do_dirty_stub(int i) { assem_debug("do_dirty_stub %x\n",start+i*2); u32 alignedlen=((((u32)source)+slen*2+2)&~2)-(u32)alignedsource; // Careful about the code output here, verify_dirty needs to parse it. #ifndef HAVE_ARMv7 emit_loadlp(((int)source&~3),1); emit_loadlp((int)copy,2); emit_loadlp((((u32)source+slen*2+2)&~3)-((u32)source&~3),3); #else emit_movw(((u32)source&~3)&0x0000FFFF,1); emit_movw(((u32)copy)&0x0000FFFF,2); emit_movt(((u32)source&~3)&0xFFFF0000,1); emit_movt(((u32)copy)&0xFFFF0000,2); emit_movw((((u32)source+slen*2+2)&~3)-((u32)source&~3),3); #endif emit_movimm(start+i*2+slave,0); emit_call((int)&verify_code); int entry=(int)out; load_regs_entry(i); if(entry==(int)out) entry=instr_addr[i]; emit_jmp(instr_addr[i]); return entry; } /* Memory Map */ int do_map_r(int s,int ar,int map,int cache,int x,int a,int shift,int c,u32 addr) { if(c) { return -1; // No mapping } else { assert(s!=map); if(cache>=0) { // Use cached offset to memory map emit_addsr12(cache,s,map); }else{ emit_movimm(((int)memory_map-(int)&dynarec_local)>>2,map); emit_addsr12(map,s,map); } // Schedule this while we wait on the load if(x) emit_xorimm(s,x,ar); //if(shift>=0) emit_shlimm(s,3,shift); //if(~a) emit_andimm(s,a,ar); emit_readword_dualindexedx4(FP,map,map); } return map; } int do_map_r_branch(int map, int c, u32 addr, int *jaddr) { if(!c) { emit_test(map,map); *jaddr=(int)out; emit_js(0); } return map; } void gen_tlb_addr_r(int ar, int map) { if(map>=0) { assem_debug("add %s,%s,%s lsl #2\n",regname[ar],regname[ar],regname[map]); output_w32(0xe0800100|rd_rn_rm(ar,ar,map)); } } int do_map_w(int s,int ar,int map,int cache,int x,int c,u32 addr) { if(c) { if(can_direct_write(addr)) { // address_generation already loaded the const emit_readword_dualindexedx4(FP,map,map); } else return -1; // No mapping } else { assert(s!=map); if(cache>=0) { // Use cached offset to memory map emit_addsr12(cache,s,map); }else{ emit_movimm(((int)memory_map-(int)&dynarec_local)>>2,map); emit_addsr12(map,s,map); } // Schedule this while we wait on the load if(x) emit_xorimm(s,x,ar); emit_readword_dualindexedx4(FP,map,map); } return map; } void do_map_w_branch(int map, int c, u32 addr, int *jaddr) { if(!c||can_direct_write(addr)) { emit_testimm(map,0x40000000); *jaddr=(int)out; emit_jne(0); } } void gen_tlb_addr_w(int ar, int map) { if(map>=0) { assem_debug("add %s,%s,%s lsl #2\n",regname[ar],regname[ar],regname[map]); output_w32(0xe0800100|rd_rn_rm(ar,ar,map)); } } // This reverses the above operation int gen_orig_addr_w(int ar, int map) { if(map>=0) { assem_debug("sub %s,%s,%s lsl #2\n",regname[ar],regname[ar],regname[map]); output_w32(0xe0400100|rd_rn_rm(ar,ar,map)); } } // Generate the address of the memory_map entry, relative to dynarec_local void generate_map_const(u32 addr,int reg) { //printf("generate_map_const(%x,%s)\n",addr,regname[reg]); emit_movimm((addr>>12)+(((u32)memory_map-(u32)&dynarec_local)>>2),reg); } /* Special assem */ void do_preload_rhash(int r) { // Don't need this for ARM. On x86, this puts the value 0xf8 into the // register. On ARM the hash can be done with a single instruction (below) } void do_preload_rhtbl(int ht) { if(slave) emit_addimm(FP,(int)&mini_ht_slave-(int)&dynarec_local,ht); else emit_addimm(FP,(int)&mini_ht_master-(int)&dynarec_local,ht); } void do_rhash(int rs,int rh) { emit_andimm(rs,0xf8,rh); } void do_miniht_load(int ht,int rh) { assem_debug("ldr %s,[%s,%s]!\n",regname[rh],regname[ht],regname[rh]); output_w32(0xe7b00000|rd_rn_rm(rh,ht,rh)); } void do_miniht_jump(int rs,int rh,int ht) { emit_cmp(rh,rs); emit_ldreq_indexed(ht,4,15); #ifdef CORTEX_A8_BRANCH_PREDICTION_HACK emit_mov(rs,7); emit_jmp(jump_vaddr_reg[slave][7]); #else emit_jmp(jump_vaddr_reg[slave][rs]); #endif } void do_miniht_insert(u32 return_address,int rt,int temp) { #ifndef HAVE_ARMv7 emit_movimm(return_address,rt); // PC into link register add_to_linker((int)out,return_address,1); emit_pcreladdr(temp); if(slave) emit_writeword(rt,(int)&mini_ht_slave[(return_address&0xFF)>>3][0]); else emit_writeword(rt,(int)&mini_ht_master[(return_address&0xFF)>>3][0]); if(slave) emit_writeword(temp,(int)&mini_ht_slave[(return_address&0xFF)>>3][1]); else emit_writeword(temp,(int)&mini_ht_master[(return_address&0xFF)>>3][1]); #else emit_movw(return_address&0x0000FFFF,rt); add_to_linker((int)out,return_address,1); emit_pcreladdr(temp); if(slave) emit_writeword(temp,(int)&mini_ht_slave[(return_address&0xFF)>>3][1]); else emit_writeword(temp,(int)&mini_ht_master[(return_address&0xFF)>>3][1]); emit_movt(return_address&0xFFFF0000,rt); if(slave) emit_writeword(rt,(int)&mini_ht_slave[(return_address&0xFF)>>3][0]); else emit_writeword(rt,(int)&mini_ht_master[(return_address&0xFF)>>3][0]); #endif } void wb_valid(signed char pre[],signed char entry[],u32 dirty_pre,u32 dirty,u64 u) { //if(dirty_pre==dirty) return; int hr,reg,new_hr; for(hr=0;hr>(reg&63))&1) { if(reg>=0) { if(((dirty_pre&~dirty)>>hr)&1) { if(reg>=0&®=0;hr--) { if(hr!=EXCLUDE_REG) { if(pre[hr]!=entry[hr]) { if(pre[hr]>=0) { if((dirty>>hr)&1) { if(get_reg(entry,pre[hr])<0) { if(pre[hr]<64) { if(!((u>>pre[hr])&1)) { if(hr<10&&(~hr&1)&&(pre[hr+1]<0||wrote==hr+1)) { if( ((is32>>pre[hr])&1) && !((uu>>pre[hr])&1) ) { emit_sarimm(hr,31,hr+1); emit_strdreg(pre[hr],hr); } else emit_storereg(pre[hr],hr); }else{ emit_storereg(pre[hr],hr); if( ((is32>>pre[hr])&1) && !((uu>>pre[hr])&1) ) { emit_sarimm(hr,31,hr); emit_storereg(pre[hr]|64,hr); } } } }else{ if(!((uu>>(pre[hr]&63))&1) && !((is32>>(pre[hr]&63))&1)) { emit_storereg(pre[hr],hr); } } wrote=hr; } } } } } } for(hr=0;hr=0) { int nr; if((nr=get_reg(entry,pre[hr]))>=0) { emit_mov(hr,nr); } } } } } } #define wb_invalidate wb_invalidate_arm */ // Clearing the cache is rather slow on ARM Linux, so mark the areas // that need to be cleared, and then only clear these areas once. void do_clear_cache() { int i,j; for (i=0;i<(1<<(TARGET_SIZE_2-17));i++) { u32 bitmap=needs_clear_cache[i]; if(bitmap) { u32 start,end; for(j=0;j<32;j++) { if(bitmap&(1<32M int *ptr,*ptr2; ptr=(int *)jump_table_symbols; ptr2=(int *)((void *)BASE_ADDR+(1<=-33554432&&offset<33554432) { *ptr2=0xea000000|((offset>>2)&0xffffff); // direct branch }else{ *ptr2=0xe51ff004; // ldr pc,[pc,#-4] } ptr2++; *ptr2=*ptr; ptr++; ptr2++; } // Jumping thru the trampolines created above slows things down by about 1%. // If part of the cache is beyond the 32M limit, avoid using this area // initially. It will be used later if the cache gets full. if((u32)dyna_linker-33554432>(u32)BASE_ADDR) { if((u32)dyna_linker-33554432<(u32)BASE_ADDR+(1<<(TARGET_SIZE_2-1))) { out=(u8 *)(((u32)dyna_linker-33554432)&~4095); expirep=((((int)out-BASE_ADDR)>>(TARGET_SIZE_2-16))+16384)&65535; } } #endif } yabause-0.9.15/src/sh2_dynarec/assem_x64.h000644 001750 001750 00000001374 12755623101 022232 0ustar00guillaumeguillaume000000 000000 #define HOST_REGS 8 #define HOST_CCREG 6 #define EXCLUDE_REG 4 #define SLAVERA_REG 5 //#define IMM_PREFETCH 1 #define HOST_IMM_ADDR32 1 #define INVERTED_CARRY 1 #define DESTRUCTIVE_WRITEBACK 1 #define DESTRUCTIVE_SHIFT 1 #define POINTERS_64BIT 1 #define USE_MINI_HT 1 #define BASE_ADDR 0x70000000 // Code generator target address #define TARGET_SIZE_2 25 // 2^25 = 32 megabytes #define JUMP_TABLE_SIZE 0 // Not needed for x86 /* x86-64 calling convention: func(rdi, rsi, rdx, rcx, r8, r9) {return rax;} callee-save: %rbp %rbx %r12-%r15 */ #define ARG1_REG 7 /* RDI */ #define ARG2_REG 6 /* RSI */ #define EAX 0 #define ECX 1 #define EDX 2 #define EBX 3 #define ESP 4 #define EBP 5 #define ESI 6 #define EDI 7 extern u64 memory_map[1048576]; // 64-bit yabause-0.9.15/src/sh2_dynarec/assem_x64.c000644 001750 001750 00000245144 12755623101 022232 0ustar00guillaumeguillaume000000 000000 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Yabause - assem_x64.c * * Copyright (C) 2009-2011 Ari64 * * * * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ u64 memory_map[1048576]; ALIGNED(8) u32 mini_ht_master[32][2]; ALIGNED(8) u32 mini_ht_slave[32][2]; ALIGNED(4) u8 restore_candidate[512]; int rccount; int master_reg[22]; int master_cc; // Cycle count int master_pc; // Virtual PC void * master_ip; // Translated PC int slave_reg[22]; int slave_cc; // Cycle count int slave_pc; // Virtual PC void * slave_ip; // Translated PC void FASTCALL WriteInvalidateLong(u32 addr, u32 val); void FASTCALL WriteInvalidateWord(u32 addr, u32 val); void FASTCALL WriteInvalidateByte(u32 addr, u32 val); void FASTCALL WriteInvalidateByteSwapped(u32 addr, u32 val); void jump_vaddr_eax_master(); void jump_vaddr_ecx_master(); void jump_vaddr_edx_master(); void jump_vaddr_ebx_master(); void jump_vaddr_ebp_master(); void jump_vaddr_edi_master(); void jump_vaddr_eax_slave(); void jump_vaddr_ecx_slave(); void jump_vaddr_edx_slave(); void jump_vaddr_ebx_slave(); void jump_vaddr_ebp_slave(); void jump_vaddr_edi_slave(); const pointer jump_vaddr_reg[2][8] = { { (pointer)jump_vaddr_eax_master, (pointer)jump_vaddr_ecx_master, (pointer)jump_vaddr_edx_master, (pointer)jump_vaddr_ebx_master, 0, (pointer)jump_vaddr_ebp_master, 0, (pointer)jump_vaddr_edi_master },{ (pointer)jump_vaddr_eax_slave, (pointer)jump_vaddr_ecx_slave, (pointer)jump_vaddr_edx_slave, (pointer)jump_vaddr_ebx_slave, 0, (pointer)jump_vaddr_ebp_slave, 0, (pointer)jump_vaddr_edi_slave } }; // We need these for cmovcc instructions on x86 u32 const_zero=0; u32 const_one=1; /* Linker */ void add_to_linker(int addr, int target, int ext); void set_jump_target(pointer addr,pointer target) { u8 *ptr=(u8 *)addr; if(*ptr==0x0f) { u32 *ptr2 = NULL; assert(ptr[1]>=0x80&&ptr[1]<=0x8f); ptr2=(u32 *)(ptr+2); *ptr2=target-(u32)ptr2-4; } else if(*ptr==0xe8||*ptr==0xe9) { u32 *ptr2=(u32 *)(ptr+1); *ptr2=target-(u32)ptr2-4; } else { u32 *ptr2 = NULL; assert(*ptr==0xc7); /* mov immediate (store address) */ ptr2=(u32 *)(ptr+6); *ptr2=target; } } void *kill_pointer(void *stub) { u32 i_ptr=*((u32 *)(stub+6)); *((u32 *)i_ptr)=(u32)stub-(u32)i_ptr-4; return (void *)i_ptr; } pointer get_pointer(void *stub) { pointer i_ptr=*((u32 *)(stub+6)); return *((s32 *)i_ptr)+i_ptr+4; } // Find the "clean" entry point from a "dirty" entry point // by skipping past the call to verify_code pointer get_clean_addr(pointer addr) { u8 *ptr=(u8 *)addr; if(ptr[0]==0xB8) { assert(ptr[21]==0xE8); // call instruction if(ptr[26]==0xE9) return *(s32 *)(ptr+27)+addr+31; // follow jmp else return(addr+26); } /* 64-bit source pointer */ assert(ptr[26]==0xE8); // call instruction if(ptr[31]==0xE9) return *(s32 *)(ptr+32)+addr+36; // follow jmp else return(addr+31); } int verify_dirty(pointer addr) { u8 *ptr=(u8 *)addr; if(ptr[0]==0xB8) { u32 source=*(u32 *)(ptr+1); u32 copy=*(u32 *)(ptr+6); u32 len=*(u32 *)(ptr+11); //printf("source=%x source-rdram=%x\n",source,source-(int)rdram); assert(ptr[21]==0xE8); // call instruction //printf("verify_dirty: %x %x %x\n",source,copy,len); return !memcmp((void *)source,(void *)copy,len); } assert(ptr[0]==0x48&&ptr[1]==0xB8); /* 64-bit source pointer */ { u64 source = *(u64 *)(ptr + 2); u32 copy = *(u32 *)(ptr + 11); u32 len = *(u32 *)(ptr + 16); //printf("source=%x source-rdram=%x\n",source,source-(int)rdram); assert(ptr[26] == 0xE8); // call instruction //printf("verify_dirty: %x %x %x\n",source,copy,len); return !memcmp((void *)source, (void *)copy, len); } } // This doesn't necessarily find all clean entry points, just // guarantees that it's not dirty int isclean(pointer addr) { u8 *ptr=(u8 *)addr; if(ptr[0]==0xB8) { if(ptr[0]!=0xB8) return 1; // mov imm,%eax if(ptr[5]!=0xBB) return 1; // mov imm,%ebx if(ptr[10]!=0xB9) return 1; // mov imm,%ecx if(ptr[15]!=0x41) return 1; // rex prefix if(ptr[16]!=0xBC) return 1; // mov imm,%r12d if(ptr[21]!=0xE8) return 1; // call instruction }else{ if(ptr[0]!=0x48) return 1; // rex prefix if(ptr[1]!=0xB8) return 1; // mov imm,%rax if(ptr[10]!=0xBB) return 1; // mov imm,%ebx if(ptr[15]!=0xB9) return 1; // mov imm,%ecx if(ptr[20]!=0x41) return 1; // rex prefix if(ptr[21]!=0xBC) return 1; // mov imm,%r12d if(ptr[26]!=0xE8) return 1; // call instruction } return 0; } void get_bounds(pointer addr,u32 *start,u32 *end) { u8 *ptr=(u8 *)addr; if(ptr[0]==0xB8) { u32 source=*(u32 *)(ptr+1); //u32 copy=*(u32 *)(ptr+6); u32 len=*(u32 *)(ptr+11); assert(ptr[21]==0xE8); // call instruction *start=source; *end=source+len; }else{ u64 source = 0; u32 len = 0; assert(ptr[0]==0x48&&ptr[1]==0xB8); source=*(u64 *)(ptr+2); //32 copy=*(u32 *)(ptr+11); len=*(u32 *)(ptr+16); assert(ptr[26]==0xE8); // call instruction *start=source; *end=source+len; } } /* Register allocation */ // Note: registers are allocated clean (unmodified state) // if you intend to modify the register, you must call dirty_reg(). void alloc_reg(struct regstat *cur,int i,signed char reg) { int r,hr; int preferred_reg = (reg&3)+(reg>21)*4+(reg==24)+(reg==28)+(reg==32); unsigned char hsn[MAXREG + 1] = {0}; int j = 0; if(reg==CCREG) preferred_reg=HOST_CCREG; // Don't allocate unused registers if((cur->u>>reg)&1) return; // see if it's already allocated for(hr=0;hrregmap[hr]==reg) return; } // Keep the same mapping if the register was already allocated in a loop preferred_reg = loop_reg(i,reg,preferred_reg); // Try to allocate the preferred register if(cur->regmap[preferred_reg]==-1) { cur->regmap[preferred_reg]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[preferred_reg]; if(r<64&&((cur->u>>r)&1)) { cur->regmap[preferred_reg]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]==-1) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]; if(r>=0) { if((cur->u>>r)&1) if(i==0||(unneeded_reg[i-1]>>r)&1) {cur->regmap[hr]=-1;break;} } } // Try to allocate any available register, but prefer // registers that have not been used recently. if(i>0) { for(hr=0;hrregmap[hr]==-1) { if(regs[i-1].regmap[hr]!=rs1[i-1]&®s[i-1].regmap[hr]!=rs2[i-1]&®s[i-1].regmap[hr]!=rt1[i-1]&®s[i-1].regmap[hr]!=rt2[i-1]) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]==-1) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[0]&63],hsn[cur->regmap[1]&63],hsn[cur->regmap[2]&63],hsn[cur->regmap[3]&63],hsn[cur->regmap[5]&63],hsn[cur->regmap[6]&63],hsn[cur->regmap[7]&63]); if(i>0) { // Don't evict the cycle count at entry points, otherwise the entry // stub will have to write it. if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP)) hsn[CCREG]=2; for(j=10;j>=3;j--) { // Alloc preferred register if available if(hsn[r=cur->regmap[preferred_reg]&63]==j) { for(hr=0;hrregmap[hr]&63)==r) { cur->regmap[hr]=-1; cur->dirty&=~(1<isdoingcp&=~(1<regmap[preferred_reg]=reg; return; } for(r=0;r<=MAXREG;r++) { if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<=0;j--) { for(r=0;r<=MAXREG;r++) { if(hsn[r]==j) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]==reg) return; } // Try to allocate any available register, starting with EDI, ESI, EBP... // We prefer EDI, ESI, EBP since the others are used for byte/halfword stores for(hr=HOST_REGS-1;hr>=0;hr--) { if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<=0;hr--) { r=cur->regmap[hr]; if(r>=0) { if((cur->u>>r)&1) { if(i==0||((unneeded_reg[i-1]>>r)&1)) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[0]&63],hsn[cur->regmap[1]&63],hsn[cur->regmap[2]&63],hsn[cur->regmap[3]&63],hsn[cur->regmap[5]&63],hsn[cur->regmap[6]&63],hsn[cur->regmap[7]&63]); if(i>0) { // Don't evict the cycle count at entry points, otherwise the entry // stub will have to write it. if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2; if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP)) hsn[CCREG]=2; for(j=10;j>=3;j--) { for(r=0;r<=MAXREG;r++) { if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<=0;j--) { for(r=0;r<=MAXREG;r++) { if(hsn[r]==j) { for(hr=0;hrregmap[hr]==r+64) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[hr]==r) { cur->regmap[hr]=reg; cur->dirty&=~(1<isdoingcp&=~(1<regmap[n]==reg) { dirty=(cur->dirty>>n)&1; cur->regmap[n]=-1; } } cur->regmap[hr]=reg; cur->dirty&=~(1<dirty|=dirty<isdoingcp&=~(1<7||rs>7) output_rex(1,rs>>3,0,rt>>3); output_byte(0x89); output_modrm(3,rt&7,rs&7); } void emit_mov64(int rs,int rt) { assem_debug("mov %%%s,%%%s\n",regname[rs],regname[rt]); output_rex(1,rs>>3,0,rt>>3); output_byte(0x89); output_modrm(3,rt&7,rs&7); } void emit_add(int rs1,int rs2,int rt) { if(rs1==rt) { assem_debug("add %%%s,%%%s\n",regname[rs2],regname[rs1]); output_byte(0x01); output_modrm(3,rs1,rs2); }else if(rs2==rt) { assem_debug("add %%%s,%%%s\n",regname[rs1],regname[rs2]); output_byte(0x01); output_modrm(3,rs2,rs1); }else { assem_debug("lea (%%%s,%%%s),%%%s\n",regname[rs1],regname[rs2],regname[rt]); output_byte(0x8D); if(rs1!=EBP) { output_modrm(0,4,rt); output_sib(0,rs2,rs1); }else if(rs2!=EBP) { output_modrm(0,4,rt); output_sib(0,rs1,rs2); }else /* lea 0(,%ebp,2) */{ output_modrm(0,4,rt); output_sib(1,EBP,5); output_w32(0); } } } void emit_adds(int rs1,int rs2,int rt) { emit_add(rs1,rs2,rt); } void emit_lea8(int rs1,int rt) { assem_debug("lea 0(%%%s,8),%%%s\n",regname[rs1],regname[rt]); output_byte(0x8D); output_modrm(0,4,rt); output_sib(3,rs1,5); output_w32(0); } void emit_leairrx1(int imm,int rs1,int rs2,int rt) { assem_debug("lea %x(%%%s,%%%s,1),%%%s\n",imm,regname[rs1],regname[rs2],regname[rt]); output_byte(0x8D); if(imm!=0||rs1==EBP) { output_modrm(2,4,rt); output_sib(0,rs2,rs1); output_w32(imm); }else{ output_modrm(0,4,rt); output_sib(0,rs2,rs1); } } void emit_leairrx4(int imm,int rs1,int rs2,int rt) { assem_debug("lea %x(%%%s,%%%s,4),%%%s\n",imm,regname[rs1],regname[rs2],regname[rt]); output_byte(0x8D); if(imm!=0||rs1==EBP) { output_modrm(2,4,rt); output_sib(2,rs2,rs1); output_w32(imm); }else{ output_modrm(0,4,rt); output_sib(2,rs2,rs1); } } void emit_neg(int rs, int rt) { if(rs!=rt) emit_mov(rs,rt); assem_debug("neg %%%s\n",regname[rt]); output_byte(0xF7); output_modrm(3,rt,3); } void emit_negs(int rs, int rt) { emit_neg(rs,rt); } void emit_sub(int rs1,int rs2,int rt) { if(rs1==rt) { assem_debug("sub %%%s,%%%s\n",regname[rs2],regname[rs1]); output_byte(0x29); output_modrm(3,rs1,rs2); } else if(rs2==rt) { emit_neg(rs2,rs2); emit_add(rs2,rs1,rs2); } else { emit_mov(rs1,rt); emit_sub(rt,rs2,rt); } } void emit_subs(int rs1,int rs2,int rt) { emit_sub(rs1,rs2,rt); } void emit_zeroreg(int rt) { output_byte(0x31); output_modrm(3,rt,rt); assem_debug("xor %%%s,%%%s\n",regname[rt],regname[rt]); } void emit_loadreg(int r, int hr) { int addr=(slave?(int)slave_reg:(int)master_reg)+(r<<2); if(r==CCREG) addr=slave?(int)&slave_cc:(int)&master_cc; assem_debug("mov %x+%d,%%%s\n",addr,r,regname[hr]); output_byte(0x8B); output_modrm(0,5,hr); output_w32(addr-(int)out-4); // Note: rip-relative in 64-bit mode } void emit_storereg(int r, int hr) { int addr=(slave?(int)slave_reg:(int)master_reg)+(r<<2); if(r==CCREG) addr=slave?(int)&slave_cc:(int)&master_cc; assem_debug("mov %%%s,%x+%d\n",regname[hr],addr,r); output_byte(0x89); output_modrm(0,5,hr); output_w32(addr-(int)out-4); // Note: rip-relative in 64-bit mode } void emit_test(int rs, int rt) { assem_debug("test %%%s,%%%s\n",regname[rs],regname[rt]); output_byte(0x85); output_modrm(3,rs,rt); } void emit_test64(int rs, int rt) { assem_debug("test %%%s,%%%s\n",regname[rs],regname[rt]); output_rex(1,rt>>3,0,rs>>3); output_byte(0x85); output_modrm(3,rs,rt); } void emit_testimm(int rs,int imm) { assem_debug("test $0x%x,%%%s\n",imm,regname[rs]); if(imm<128&&imm>=-128&&rs<4) { output_byte(0xF6); output_modrm(3,rs,0); output_byte(imm); } else { output_byte(0xF7); output_modrm(3,rs,0); output_w32(imm); } } void emit_not(int rs,int rt) { if(rs!=rt) emit_mov(rs,rt); assem_debug("not %%%s\n",regname[rt]); output_byte(0xF7); output_modrm(3,rt,2); } void emit_and(unsigned int rs1,unsigned int rs2,unsigned int rt) { assert(rs1<8); assert(rs2<8); assert(rt<8); if(rs1==rt) { assem_debug("and %%%s,%%%s\n",regname[rs2],regname[rt]); output_byte(0x21); output_modrm(3,rs1,rs2); } else if(rs2==rt) { assem_debug("and %%%s,%%%s\n",regname[rs1],regname[rt]); output_byte(0x21); output_modrm(3,rs2,rs1); } else { emit_mov(rs1,rt); emit_and(rt,rs2,rt); } } void emit_or(unsigned int rs1,unsigned int rs2,unsigned int rt) { assert(rs1<8); assert(rs2<8); assert(rt<8); if(rs1==rt) { assem_debug("or %%%s,%%%s\n",regname[rs2],regname[rt]); output_byte(0x09); output_modrm(3,rs1,rs2); } else if(rs2==rt) { assem_debug("or %%%s,%%%s\n",regname[rs1],regname[rt]); output_byte(0x09); output_modrm(3,rs2,rs1); } else { emit_mov(rs1,rt); emit_or(rt,rs2,rt); } } void emit_or_and_set_flags(int rs1,int rs2,int rt) { emit_or(rs1,rs2,rt); } void emit_xor(unsigned int rs1,unsigned int rs2,unsigned int rt) { assert(rs1<8); assert(rs2<8); assert(rt<8); if(rs1==rt) { assem_debug("xor %%%s,%%%s\n",regname[rs2],regname[rt]); output_byte(0x31); output_modrm(3,rs1,rs2); } else if(rs2==rt) { assem_debug("xor %%%s,%%%s\n",regname[rs1],regname[rt]); output_byte(0x31); output_modrm(3,rs2,rs1); } else { emit_mov(rs1,rt); emit_xor(rt,rs2,rt); } } void emit_movimm(int imm,unsigned int rt) { assem_debug("mov $%d,%%%s\n",imm,regname[rt]); assert(rt<16); if(rt>=8) output_rex(0,0,0,1); output_byte(0xB8+(rt&7)); output_w32(imm); } void emit_movimm64(u64 imm,unsigned int rt) { assem_debug("movq $0x%llx,%%%s\n",imm,regname[rt]); assert(rt<16); output_rex(1,0,0,rt>>3); output_byte(0xB8+(rt&7)); output_w64(imm); } void emit_addimm(int rs,int imm,int rt) { if(rs==rt) { if(imm!=0) { assem_debug("add $%d,%%%s\n",imm,regname[rt]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,0); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,0); output_w32(imm); } } } else { if(imm!=0) { assem_debug("lea %d(%%%s),%%%s\n",imm,regname[rs],regname[rt]); output_byte(0x8D); if(imm<128&&imm>=-128) { output_modrm(1,rs,rt); output_byte(imm); }else{ output_modrm(2,rs,rt); output_w32(imm); } }else{ emit_mov(rs,rt); } } } void emit_addimm64(int rs,int imm,int rt) { if(rs==rt) { if(imm!=0) { assem_debug("add $%d,%%%s\n",imm,regname[rt]); if(imm<128&&imm>=-128) { output_rex(1,0,0,rt>>3); output_byte(0x83); output_modrm(3,rt&7,0); output_byte(imm); } else { output_rex(1,0,0,rt>>3); output_byte(0x81); output_modrm(3,rt&7,0); output_w32(imm); } } } else { if(imm!=0) { assem_debug("lea %d(%%%s),%%%s\n",imm,regname[rs],regname[rt]); output_rex(1,rt>>3,0,rs>>3); output_byte(0x8D); if(imm<128&&imm>=-128) { output_modrm(1,rs&7,rt&7); output_byte(imm); }else{ output_modrm(2,rs&7,rt&7); output_w32(imm); } }else{ emit_mov(rs,rt); } } } void emit_addimm_and_set_flags(int imm,int rt) { assem_debug("add $%d,%%%s\n",imm,regname[rt]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,0); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,0); output_w32(imm); } } void emit_addimm_no_flags(int imm,int rt) { if(imm!=0) { assem_debug("lea %d(%%%s),%%%s\n",imm,regname[rt],regname[rt]); output_byte(0x8D); if(imm<128&&imm>=-128) { output_modrm(1,rt,rt); output_byte(imm); }else{ output_modrm(2,rt,rt); output_w32(imm); } } } void emit_adcimm(int imm,unsigned int rt) { assem_debug("adc $%d,%%%s\n",imm,regname[rt]); assert(rt<8); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,2); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,2); output_w32(imm); } } void emit_sbbimm(int imm,unsigned int rt) { assem_debug("sbb $%d,%%%s\n",imm,regname[rt]); assert(rt<8); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,3); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,3); output_w32(imm); } } void emit_addimm64_32(int rsh,int rsl,int imm,int rth,int rtl) { if(rsh==rth&&rsl==rtl) { assem_debug("add $%d,%%%s\n",imm,regname[rtl]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rtl,0); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rtl,0); output_w32(imm); } assem_debug("adc $%d,%%%s\n",imm>>31,regname[rth]); output_byte(0x83); output_modrm(3,rth,2); output_byte(imm>>31); } else { emit_mov(rsh,rth); emit_mov(rsl,rtl); emit_addimm64_32(rth,rtl,imm,rth,rtl); } } void emit_sbb(int rs1,int rs2) { assem_debug("sbb %%%s,%%%s\n",regname[rs1],regname[rs2]); output_byte(0x19); output_modrm(3,rs2,rs1); } void emit_andimm(int rs,int imm,int rt) { if(imm==0) { emit_zeroreg(rt); } else if(rs==rt) { assem_debug("and $%d,%%%s\n",imm,regname[rt]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,4); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,4); output_w32(imm); } } else { emit_mov(rs,rt); emit_andimm(rt,imm,rt); } } void emit_orimm(int rs,int imm,int rt) { if(rs==rt) { if(imm!=0) { assem_debug("or $%d,%%%s\n",imm,regname[rt]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,1); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,1); output_w32(imm); } } } else { emit_mov(rs,rt); emit_orimm(rt,imm,rt); } } void emit_xorimm(int rs,int imm,int rt) { if(rs==rt) { if(imm!=0) { assem_debug("xor $%d,%%%s\n",imm,regname[rt]); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rt,6); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rt,6); output_w32(imm); } } } else { emit_mov(rs,rt); emit_xorimm(rt,imm,rt); } } void emit_shlimm(int rs,unsigned int imm,int rt) { if(rs==rt) { assem_debug("shl %%%s,%d\n",regname[rt],imm); assert(imm>0); if(imm==1) output_byte(0xD1); else output_byte(0xC1); output_modrm(3,rt,4); if(imm>1) output_byte(imm); } else { emit_mov(rs,rt); emit_shlimm(rt,imm,rt); } } void emit_shlimm64(int rs,unsigned int imm,int rt) { if(rs==rt) { assem_debug("shl %%%s,%d\n",regname[rt],imm); assert(imm>0); output_rex(1,0,0,rt>>3); if(imm==1) output_byte(0xD1); else output_byte(0xC1); output_modrm(3,rt,4); if(imm>1) output_byte(imm); } else { emit_mov(rs,rt); emit_shlimm64(rt,imm,rt); } } void emit_shrimm(int rs,unsigned int imm,int rt) { if(rs==rt) { assem_debug("shr %%%s,%d\n",regname[rt],imm); assert(imm>0); if(imm==1) output_byte(0xD1); else output_byte(0xC1); output_modrm(3,rt,5); if(imm>1) output_byte(imm); } else { emit_mov(rs,rt); emit_shrimm(rt,imm,rt); } } void emit_shrimm64(int rs,unsigned int imm,int rt) { assert(rs==rt); if(rs==rt) { assem_debug("shr %%%s,%d\n",regname[rt],imm); assert(imm>0); output_rex(1,0,0,rt>>3); if(imm==1) output_byte(0xD1); else output_byte(0xC1); output_modrm(3,rt,5); if(imm>1) output_byte(imm); } else { emit_mov(rs,rt); emit_shrimm(rt,imm,rt); } } void emit_sarimm(int rs,unsigned int imm,int rt) { if(rs==rt) { assem_debug("sar %%%s,%d\n",regname[rt],imm); assert(imm>0); if(imm==1) output_byte(0xD1); else output_byte(0xC1); output_modrm(3,rt,7); if(imm>1) output_byte(imm); } else { emit_mov(rs,rt); emit_sarimm(rt,imm,rt); } } void emit_rorimm(int rs,unsigned int imm,int rt) { if(rs==rt) { assem_debug("ror %%%s,%d\n",regname[rt],imm); assert(imm>0); if(imm==1) output_byte(0xD1); else output_byte(0xC1); output_modrm(3,rt,1); if(imm>1) output_byte(imm); } else { emit_mov(rs,rt); emit_rorimm(rt,imm,rt); } } void emit_swapb(int rs,int rt) { if(rs==rt) { assem_debug("ror %%%s,8\n",regname[rt]+1); output_byte(0x66); output_byte(0xC1); output_modrm(3,rt,1); output_byte(8); } else { emit_mov(rs,rt); emit_swapb(rt,rt); } } void emit_shldimm(int rs,int rs2,unsigned int imm,int rt) { if(rs==rt) { assem_debug("shld %%%s,%%%s,%d\n",regname[rt],regname[rs2],imm); assert(imm>0); output_byte(0x0F); output_byte(0xA4); output_modrm(3,rt,rs2); output_byte(imm); } else { emit_mov(rs,rt); emit_shldimm(rt,rs2,imm,rt); } } void emit_shrdimm(int rs,int rs2,unsigned int imm,int rt) { if(rs==rt) { assem_debug("shrd %%%s,%%%s,%d\n",regname[rt],regname[rs2],imm); assert(imm>0); output_byte(0x0F); output_byte(0xAC); output_modrm(3,rt,rs2); output_byte(imm); } else { emit_mov(rs,rt); emit_shrdimm(rt,rs2,imm,rt); } } void emit_shlcl(int r) { assem_debug("shl %%%s,%%cl\n",regname[r]); output_byte(0xD3); output_modrm(3,r,4); } void emit_shrcl(int r) { assem_debug("shr %%%s,%%cl\n",regname[r]); output_byte(0xD3); output_modrm(3,r,5); } void emit_sarcl(int r) { assem_debug("sar %%%s,%%cl\n",regname[r]); output_byte(0xD3); output_modrm(3,r,7); } void emit_shldcl(int r1,int r2) { assem_debug("shld %%%s,%%%s,%%cl\n",regname[r1],regname[r2]); output_byte(0x0F); output_byte(0xA5); output_modrm(3,r1,r2); } void emit_shrdcl(int r1,int r2) { assem_debug("shrd %%%s,%%%s,%%cl\n",regname[r1],regname[r2]); output_byte(0x0F); output_byte(0xAD); output_modrm(3,r1,r2); } void emit_cmpimm(int rs,int imm) { assem_debug("cmp $%d,%%%s\n",imm,regname[rs]); if(rs>=8) output_rex(0,0,0,rs>>3); if(imm<128&&imm>=-128) { output_byte(0x83); output_modrm(3,rs&7,7); output_byte(imm); } else { output_byte(0x81); output_modrm(3,rs&7,7); output_w32(imm); } } void emit_cmovne(u32 *addr,int rt) { assem_debug("cmovne %x,%%%s",(int)addr,regname[rt]); if(addr==&const_zero) assem_debug(" [zero]\n"); else if(addr==&const_one) assem_debug(" [one]\n"); else assem_debug("\n"); output_byte(0x0F); output_byte(0x45); output_modrm(0,5,rt); output_w32((int)addr-(int)out-4); // Note: rip-relative in 64-bit mode } void emit_cmovl(u32 *addr,int rt) { assem_debug("cmovl %x,%%%s",(int)addr,regname[rt]); if(addr==&const_zero) assem_debug(" [zero]\n"); else if(addr==&const_one) assem_debug(" [one]\n"); else assem_debug("\n"); output_byte(0x0F); output_byte(0x4C); output_modrm(0,5,rt); output_w32((int)addr-(int)out-4); // Note: rip-relative in 64-bit mode } void emit_cmovs(u32 *addr,int rt) { assem_debug("cmovs %x,%%%s",(int)addr,regname[rt]); if(addr==&const_zero) assem_debug(" [zero]\n"); else if(addr==&const_one) assem_debug(" [one]\n"); else assem_debug("\n"); output_byte(0x0F); output_byte(0x48); output_modrm(0,5,rt); output_w32((int)addr-(int)out-4); // Note: rip-relative in 64-bit mode } void emit_cmovne_reg(int rs,int rt) { assem_debug("cmovne %%%s,%%%s\n",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x45); output_modrm(3,rs,rt); } void emit_cmovl_reg(int rs,int rt) { assem_debug("cmovl %%%s,%%%s\n",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x4C); output_modrm(3,rs,rt); } void emit_cmovle_reg(int rs,int rt) { assem_debug("cmovle %%%s,%%%s\n",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x4E); output_modrm(3,rs,rt); } void emit_cmovs_reg(int rs,int rt) { assem_debug("cmovs %%%s,%%%s\n",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x48); output_modrm(3,rs,rt); } void emit_cmovnc_reg(int rs,int rt) { assem_debug("cmovae %%%s,%%%s\n",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x43); output_modrm(3,rs,rt); } void emit_cmova_reg(int rs,int rt) { assem_debug("cmova %%%s,%%%s\n",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x47); output_modrm(3,rs,rt); } void emit_cmovp_reg(int rs,int rt) { assem_debug("cmovp %%%s,%%%s\n",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x4A); output_modrm(3,rs,rt); } void emit_cmovnp_reg(int rs,int rt) { assem_debug("cmovnp %%%s,%%%s\n",regname[rs],regname[rt]); output_byte(0x0F); output_byte(0x4B); output_modrm(3,rs,rt); } void emit_setl(int rt) { assem_debug("setl %%%s\n",regname[rt]); output_byte(0x0F); output_byte(0x9C); output_modrm(3,rt,2); } void emit_movzbl_reg(int rs, int rt) { if(rs<4&&rt<8) { assem_debug("movzbl %%%s,%%%s\n",regname[rs]+1,regname[rt]); output_byte(0x0F); output_byte(0xB6); output_modrm(3,rs,rt); } else { assem_debug("movzbl %%%s,%%%s\n",regname[rs]+1,regname[rt]); output_rex(0,rt>>3,0,rs>>3); output_byte(0x0F); output_byte(0xB6); output_modrm(3,rs,rt); } } void emit_movzwl_reg(int rs, int rt) { assem_debug("movzwl %%%s,%%%s\n",regname[rs]+1,regname[rt]); output_byte(0x0F); output_byte(0xB7); output_modrm(3,rs,rt); } void emit_movsbl_reg(int rs, int rt) { if(rs<4&&rt<8) { assem_debug("movsbl %%%s,%%%s\n",regname[rs]+1,regname[rt]); output_byte(0x0F); output_byte(0xBE); output_modrm(3,rs,rt); } else { assem_debug("movsbl %%%s,%%%s\n",regname[rs]+1,regname[rt]); output_rex(0,rt>>3,0,rs>>3); output_byte(0x0F); output_byte(0xBE); output_modrm(3,rs,rt); } } void emit_movswl_reg(int rs, int rt) { assem_debug("movswl %%%s,%%%s\n",regname[rs]+1,regname[rt]); output_byte(0x0F); output_byte(0xBF); output_modrm(3,rs,rt); } void emit_slti32(int rs,int imm,int rt) { if(rs!=rt) emit_zeroreg(rt); emit_cmpimm(rs,imm); if(rt<4) { emit_setl(rt); if(rs==rt) emit_movzbl_reg(rt,rt); } else { if(rs==rt) emit_movimm(0,rt); emit_cmovl(&const_one,rt); } } void emit_sltiu32(int rs,int imm,int rt) { if(rs!=rt) emit_zeroreg(rt); emit_cmpimm(rs,imm); if(rs==rt) emit_movimm(0,rt); emit_adcimm(0,rt); } void emit_slti64_32(int rsh,int rsl,int imm,int rt) { assert(rsh!=rt); emit_slti32(rsl,imm,rt); if(imm>=0) { emit_test(rsh,rsh); emit_cmovne(&const_zero,rt); emit_cmovs(&const_one,rt); } else { emit_cmpimm(rsh,-1); emit_cmovne(&const_zero,rt); emit_cmovl(&const_one,rt); } } void emit_sltiu64_32(int rsh,int rsl,int imm,int rt) { assert(rsh!=rt); emit_sltiu32(rsl,imm,rt); if(imm>=0) { emit_test(rsh,rsh); emit_cmovne(&const_zero,rt); } else { emit_cmpimm(rsh,-1); emit_cmovne(&const_one,rt); } } void emit_cmp(int rs,int rt) { assem_debug("cmp %%%s,%%%s\n",regname[rt],regname[rs]); output_byte(0x39); output_modrm(3,rs,rt); } void emit_set_gz32(int rs, int rt) { //assem_debug("set_gz32\n"); emit_cmpimm(rs,1); emit_movimm(1,rt); emit_cmovl(&const_zero,rt); } void emit_set_nz32(int rs, int rt) { //assem_debug("set_nz32\n"); emit_cmpimm(rs,1); emit_movimm(1,rt); emit_sbbimm(0,rt); } void emit_set_gz64_32(int rsh, int rsl, int rt) { //assem_debug("set_gz64\n"); emit_set_gz32(rsl,rt); emit_test(rsh,rsh); emit_cmovne(&const_one,rt); emit_cmovs(&const_zero,rt); } void emit_set_nz64_32(int rsh, int rsl, int rt) { //assem_debug("set_nz64\n"); emit_or_and_set_flags(rsh,rsl,rt); emit_cmovne(&const_one,rt); } void emit_set_if_less32(int rs1, int rs2, int rt) { //assem_debug("set if less (%%%s,%%%s),%%%s\n",regname[rs1],regname[rs2],regname[rt]); if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt); emit_cmp(rs1,rs2); if(rs1==rt||rs2==rt) emit_movimm(0,rt); emit_cmovl(&const_one,rt); } void emit_set_if_carry32(int rs1, int rs2, int rt) { //assem_debug("set if carry (%%%s,%%%s),%%%s\n",regname[rs1],regname[rs2],regname[rt]); if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt); emit_cmp(rs1,rs2); if(rs1==rt||rs2==rt) emit_movimm(0,rt); emit_adcimm(0,rt); } void emit_set_if_less64_32(int u1, int l1, int u2, int l2, int rt) { //assem_debug("set if less64 (%%%s,%%%s,%%%s,%%%s),%%%s\n",regname[u1],regname[l1],regname[u2],regname[l2],regname[rt]); assert(u1!=rt); assert(u2!=rt); emit_cmp(l1,l2); emit_mov(u1,rt); emit_sbb(u2,rt); emit_movimm(0,rt); emit_cmovl(&const_one,rt); } void emit_set_if_carry64_32(int u1, int l1, int u2, int l2, int rt) { //assem_debug("set if carry64 (%%%s,%%%s,%%%s,%%%s),%%%s\n",regname[u1],regname[l1],regname[u2],regname[l2],regname[rt]); assert(u1!=rt); assert(u2!=rt); emit_cmp(l1,l2); emit_mov(u1,rt); emit_sbb(u2,rt); emit_movimm(0,rt); emit_adcimm(0,rt); } void emit_adc(int rs,int rt) { assem_debug("adc %%%s,%%%s\n",regname[rs],regname[rt]); output_byte(0x11); output_modrm(3,rt,rs); } void emit_sh2tst(int s1, int s2, int sr, int temp) { assert(temp>=0); emit_orimm(sr,1,sr); emit_addimm(sr,-1,temp); emit_test(s1,s2); emit_cmovne_reg(temp,sr); } void emit_sh2tstimm(int s, int imm, int sr, int temp) { assert(temp>=0); emit_orimm(sr,1,sr); emit_testimm(s,imm); //emit_addimm(sr,-1,temp); assem_debug("lea -1(%%%s),%%%s\n",regname[sr],regname[temp]); output_byte(0x8D); output_modrm(1,sr,temp); output_byte(0xFF); emit_cmovne_reg(temp,sr); } void emit_cmpeq(int s1, int s2, int sr, int temp) { assert(temp>=0); emit_orimm(sr,1,sr); emit_addimm(sr,-1,temp); emit_cmp(s1,s2); emit_cmovne_reg(temp,sr); } void emit_cmpeqimm(int s, int imm, int sr, int temp) { assert(temp>=0); emit_orimm(sr,1,sr); emit_addimm(sr,-1,temp); emit_cmpimm(s,imm); emit_cmovne_reg(temp,sr); } void emit_cmpge(int s1, int s2, int sr, int temp) { assert(temp>=0); emit_orimm(sr,1,sr); emit_addimm(sr,-1,temp); emit_cmp(s2,s1); emit_cmovl_reg(temp,sr); } void emit_cmpgt(int s1, int s2, int sr, int temp) { assert(temp>=0); emit_orimm(sr,1,sr); emit_addimm(sr,-1,temp); emit_cmp(s2,s1); emit_cmovle_reg(temp,sr); } void emit_cmphi(int s1, int s2, int sr, int temp) { emit_andimm(sr,~1,sr); emit_cmp(s1,s2); emit_adcimm(0,sr); } void emit_cmphs(int s1, int s2, int sr, int temp) { emit_orimm(sr,1,sr); emit_cmp(s2,s1); emit_sbbimm(0,sr); } void emit_dt(int t, int sr) { emit_addimm(t,-2,t); emit_shrimm(sr,1,sr); emit_addimm(t,1,t); emit_adc(sr,sr); } void emit_cmppz(int s, int sr) { emit_shrimm(sr,1,sr); emit_cmpimm(s,0x80000000); emit_adc(sr,sr); } void emit_cmppl(int s, int sr, int temp) { assert(temp>=0); emit_orimm(sr,1,sr); emit_addimm(sr,-1,temp); emit_test(s,s); emit_cmovle_reg(temp,sr); } void emit_addc(int s, int t, int sr) { emit_shrimm(sr,1,sr); emit_adc(s,t); emit_adc(sr,sr); } void emit_subc(int s, int t, int sr) { emit_shrimm(sr,1,sr); emit_sbb(s,t); emit_adc(sr,sr); } void emit_shrsr(int t, int sr) { emit_shrimm(sr,1,sr); emit_shrimm(t,1,t); emit_adc(sr,sr); } void emit_sarsr(int t, int sr) { emit_shrimm(sr,1,sr); emit_sarimm(t,1,t); emit_adc(sr,sr); } void emit_shlsr(int t, int sr) { emit_shrimm(sr,1,sr); emit_shlimm(t,1,t); emit_adc(sr,sr); } void emit_rotl(int t) { assem_debug("rol %%%s\n",regname[t]); output_byte(0xD1); output_modrm(3,t,0); } void emit_rotlsr(int t, int sr) { emit_shrimm(sr,1,sr); emit_rotl(t); emit_adc(sr,sr); } void emit_rotr(int t) { assem_debug("ror %%%s\n",regname[t]); output_byte(0xD1); output_modrm(3,t,1); } void emit_rotrsr(int t, int sr) { emit_shrimm(sr,1,sr); emit_rotr(t); emit_adc(sr,sr); } void emit_rotclsr(int t, int sr) { emit_shrimm(sr,1,sr); assem_debug("rcl %%%s\n",regname[t]); output_byte(0xD1); output_modrm(3,t,2); emit_adc(sr,sr); } void emit_rotcrsr(int t, int sr) { emit_shrimm(sr,1,sr); assem_debug("rcr %%%s\n",regname[t]); output_byte(0xD1); output_modrm(3,t,3); emit_adc(sr,sr); } void emit_call(int a) { assem_debug("call %x (%x+%x)\n",a,(int)out+5,a-(int)out-5); output_byte(0xe8); output_w32(a-(int)out-4); } void emit_jmp(int a) { assem_debug("jmp %x (%x+%x)\n",a,(int)out+5,a-(int)out-5); output_byte(0xe9); output_w32(a-(int)out-4); } void emit_jne(int a) { assem_debug("jne %x\n",a); output_byte(0x0f); output_byte(0x85); output_w32(a-(int)out-4); } void emit_jeq(int a) { assem_debug("jeq %x\n",a); output_byte(0x0f); output_byte(0x84); output_w32(a-(int)out-4); } void emit_js(int a) { assem_debug("js %x\n",a); output_byte(0x0f); output_byte(0x88); output_w32(a-(int)out-4); } void emit_jns(int a) { assem_debug("jns %x\n",a); output_byte(0x0f); output_byte(0x89); output_w32(a-(int)out-4); } void emit_jl(int a) { assem_debug("jl %x\n",a); output_byte(0x0f); output_byte(0x8c); output_w32(a-(int)out-4); } void emit_jge(int a) { assem_debug("jge %x\n",a); output_byte(0x0f); output_byte(0x8d); output_w32(a-(int)out-4); } void emit_jno(int a) { assem_debug("jno %x\n",a); output_byte(0x0f); output_byte(0x81); output_w32(a-(int)out-4); } void emit_jc(int a) { assem_debug("jc %x\n",a); output_byte(0x0f); output_byte(0x82); output_w32(a-(int)out-4); } void emit_pushimm(int imm) { assem_debug("push $%x\n",imm); output_byte(0x68); output_w32(imm); } //void emit_pusha() //{ // assem_debug("pusha\n"); // output_byte(0x60); //} //void emit_popa() //{ // assem_debug("popa\n"); // output_byte(0x61); //} void emit_pushreg(unsigned int r) { assem_debug("push %%%s\n",regname[r]); assert(r<8); output_byte(0x50+r); } void emit_popreg(unsigned int r) { assem_debug("pop %%%s\n",regname[r]); assert(r<8); output_byte(0x58+r); } void emit_callreg(unsigned int r) { assem_debug("call *%%%s\n",regname[r]); assert(r<8); output_byte(0xFF); output_modrm(3,r,2); } void emit_jmpreg(unsigned int r) { assem_debug("jmp *%%%s\n",regname[r]); assert(r<8); output_byte(0xFF); output_modrm(3,r,4); } void emit_jmpmem_indexed(u32 addr,unsigned int r) { assem_debug("jmp *%x(%%%s)\n",addr,regname[r]); assert(r<8); output_byte(0xFF); output_modrm(2,r,4); output_w32(addr); } void emit_cmpstr(int s1, int s2, int sr, int temp) { // Compare s1 and s2. If any byte is equal, set T. // Calculates the xor of the strings, then checks if any byte is // zero by subtracting 1 from each byte. If there is a carry/borrow // then a byte was zero. assert(temp>=0); emit_pushreg(s2); emit_xor(s1,s2,s2); emit_shrimm(sr,1,sr); emit_mov(s2,temp); emit_addimm_and_set_flags(0-0x01010101,temp); emit_adcimm(-1,temp); emit_not(s2,s2); emit_xor(temp,s2,temp); emit_andimm(temp,0x01010101,temp); emit_addimm_and_set_flags(-1,temp); emit_adc(sr,sr); emit_popreg(s2); } void emit_negc(int rs, int rt, int sr) { assert(rs>=0&&rs<8); if(rt<0) { emit_shrimm(sr,1,sr); // Get C flag emit_jc((pointer)out+10); // 6 emit_neg(rs,rs); // 2 emit_neg(rs,rs); // 2 emit_adc(sr,sr); // Save C flag }else{ if(rs!=rt) emit_mov(rs,rt); emit_shrimm(sr,1,sr); // Get C flag emit_jc((pointer)out+9); // 6 emit_addimm(rt,-1,rt); // 3 emit_adc(sr,sr); // Save C flag emit_not(rt,rt); } } void emit_readword(u64 addr, int rt) { if(addr-(u64)out+0x7FFFFFFA>0xFFFFFFFE) { //TODO: special eax case emit_movimm64(addr,rt); assem_debug("mov (%%%s),%%%s\n",regname[rt],regname[rt]); output_byte(0x8B); if(rt!=EBP) { output_modrm(0,rt,rt); } else { output_modrm(1,rt,rt); output_byte(0); } } else { assem_debug("mov %x,%%%s\n",addr,regname[rt]); output_byte(0x8B); output_modrm(0,5,rt); output_w32(addr-(int)out-4); // Note: rip-relative in 64-bit mode } } void emit_readword_indexed(int addr, int rs, int rt) { assem_debug("mov %x+%%%s,%%%s\n",addr,regname[rs],regname[rt]); output_byte(0x8B); if(addr<128&&addr>=-128) { output_modrm(1,rs,rt); if(rs==ESP) output_sib(0,4,4); output_byte(addr); } else { output_modrm(2,rs,rt); if(rs==ESP) output_sib(0,4,4); output_w32(addr); } } void emit_readword_map(int addr, int map, int rt) { if(map<0) emit_readword(addr, rt); else { assem_debug("addr32 mov %x(,%%%s,4),%%%s\n",addr,regname[map],regname[rt]); output_byte(0x67); output_byte(0x8B); output_modrm(0,4,rt); output_sib(2,map,5); output_w32(addr); } } void emit_readword_indexed_map(int addr, int rs, int map, int rt) { assert(map>=0); if(map<0) emit_readword_indexed(addr, rs, rt); else { //assem_debug("addr32 mov %x(%%%s,%%%s,4),%%%s\n",addr,regname[rs],regname[map],regname[rt]); assem_debug("mov %x(%%%s,%%%s,4),%%%s\n",addr,regname[rs],regname[map],regname[rt]); assert(rs!=ESP); //output_byte(0x67); //addr32 output_byte(0x8B); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(2,map,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(2,map,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(2,map,rs); output_w32(addr); } } } void emit_movmem_indexedx4(int addr, int rs, int rt) { assem_debug("mov (%x,%%%s,4),%%%s\n",addr,regname[rs],regname[rt]); output_byte(0x8B); output_modrm(0,4,rt); output_sib(2,rs,5); output_w32(addr); } void emit_movmem_indexedx4_addr32(int addr, int rs, int rt) { assem_debug("addr32 mov (%x,%%%s,4),%%%s\n",addr,regname[rs],regname[rt]); output_byte(0x67); output_byte(0x8B); output_modrm(0,4,rt); output_sib(2,rs,5); output_w32(addr); } void emit_movmem_indexedx8(int addr, int rs, int rt) { assem_debug("mov (%x,%%%s,8),%%%s\n",addr,regname[rs],regname[rt]); output_byte(0x8B); output_modrm(0,4,rt); output_sib(3,rs,5); output_w32(addr); } void emit_movmem_indexedx8_64(int addr, int rs, int rt) { assem_debug("mov (%x,%%%s,8),%%%s\n",addr,regname[rs],regname[rt]); output_rex(1,0,0,rt>>3); output_byte(0x8B); output_modrm(0,4,rt); output_sib(3,rs,5); output_w32(addr); } void emit_movsbl(u64 addr, int rt) { if(addr-(u64)out+0x7FFFFFF9>0xFFFFFFFE) { emit_movimm64(addr,rt); assem_debug("movsbl (%%%s),%%%s\n",regname[rt],regname[rt]); output_byte(0x0F); output_byte(0xBE); if(rt!=EBP) { output_modrm(0,rt,rt); } else { output_modrm(1,rt,rt); output_byte(0); } } else { assem_debug("movsbl %x,%%%s\n",addr,regname[rt]); output_byte(0x0F); output_byte(0xBE); output_modrm(0,5,rt); output_w32(addr-(int)out-4); // rip-relative } } void emit_movsbl_indexed(int addr, int rs, int rt) { assem_debug("movsbl %x+%%%s,%%%s\n",addr,regname[rs],regname[rt]); output_byte(0x0F); output_byte(0xBE); output_modrm(2,rs,rt); output_w32(addr); } void emit_movsbl_map(u64 addr, int map, int rt) { if(map<0) emit_movsbl(addr, rt); else { //FIXME assem_debug("addr32 movsbl %x(,%%%s,4),%%%s\n",addr,regname[map],regname[rt]); output_byte(0x67); output_byte(0x0F); output_byte(0xBE); output_modrm(0,4,rt); output_sib(2,map,5); output_w32(addr); } } void emit_movsbl_indexed_map(int addr, int rs, int map, int rt) { if(map<0) emit_movsbl_indexed(addr, rs, rt); else { //assem_debug("addr32 movsbl %x(%%%s,%%%s,4),%%%s\n",addr,regname[rs],regname[map],regname[rt]); assem_debug("movsbl %x(%%%s,%%%s,4),%%%s\n",addr,regname[rs],regname[map],regname[rt]); assert(rs!=ESP); //output_byte(0x67); output_byte(0x0F); output_byte(0xBE); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(2,map,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(2,map,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(2,map,rs); output_w32(addr); } } } void emit_movswl(u64 addr, int rt) { if(addr-(u64)out+0x7FFFFFF9>0xFFFFFFFE) { emit_movimm64(addr,rt); assem_debug("movswl (%%%s),%%%s\n",regname[rt],regname[rt]); output_byte(0x0F); output_byte(0xBF); if(rt!=EBP) { output_modrm(0,rt,rt); } else { output_modrm(1,rt,rt); output_byte(0); } } else { assem_debug("movswl %x,%%%s\n",addr,regname[rt]); output_byte(0x0F); output_byte(0xBF); output_modrm(0,5,rt); output_w32(addr-(int)out-4); // rip-relative } } void emit_movswl_indexed(int addr, int rs, int rt) { assem_debug("movswl %x+%%%s,%%%s\n",addr,regname[rs],regname[rt]); output_byte(0x0F); output_byte(0xBF); output_modrm(2,rs,rt); output_w32(addr); } void emit_movswl_map(u64 addr, int map, int rt) { if(map<0) emit_movswl(addr, rt); else { //FIXME assem_debug("addr32 movswl %x(,%%%s,4),%%%s\n",addr,regname[map],regname[rt]); output_byte(0x67); output_byte(0x0F); output_byte(0xBF); output_modrm(0,4,rt); output_sib(2,map,5); output_w32(addr); } } void emit_movswl_indexed_map(int addr, int rs, int map, int rt) { assert(map>=0); if(map<0) emit_movswl_indexed(addr, rs, rt); else { assem_debug("movswl %x(%%%s,%%%s,4),%%%s\n",addr,regname[rs],regname[map],regname[rt]); assert(rs!=ESP); output_byte(0x0F); output_byte(0xBF); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(2,map,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(2,map,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(2,map,rs); output_w32(addr); } } } void emit_movzbl(int addr, int rt) { assem_debug("movzbl %x,%%%s\n",addr,regname[rt]); output_byte(0x0F); output_byte(0xB6); output_modrm(0,5,rt); output_w32(addr-(int)out-4); // Note: rip-relative in 64-bit mode } void emit_movzbl_indexed(int addr, int rs, int rt) { assem_debug("movzbl %x+%%%s,%%%s\n",addr,regname[rs],regname[rt]); output_byte(0x0F); output_byte(0xB6); output_modrm(2,rs,rt); output_w32(addr); } void emit_movzbl_map(int addr, int map, int rt) { if(map<0) emit_movzbl(addr, rt); else { assem_debug("addr32 movzbl %x(,%%%s,4),%%%s\n",addr,regname[map],regname[rt]); output_byte(0x67); output_byte(0x0F); output_byte(0xB6); output_modrm(0,4,rt); output_sib(2,map,5); output_w32(addr); } } void emit_movzbl_indexed_map(int addr, int rs, int map, int rt) { if(map<0) emit_movzbl_indexed(addr, rs, rt); else { assem_debug("addr32 movzbl %x(%%%s,%%%s,4),%%%s\n",addr,regname[rs],regname[map],regname[rt]); assert(rs!=ESP); output_byte(0x67); output_byte(0x0F); output_byte(0xB6); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(2,map,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(2,map,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(2,map,rs); output_w32(addr); } } } void emit_movzwl(int addr, int rt) { assem_debug("movzwl %x,%%%s\n",addr,regname[rt]); output_byte(0x0F); output_byte(0xB7); output_modrm(0,5,rt); output_w32(addr-(int)out-4); // Note: rip-relative in 64-bit mode } void emit_movzwl_indexed(int addr, int rs, int rt) { assem_debug("movzwl %x+%%%s,%%%s\n",addr,regname[rs],regname[rt]); output_byte(0x0F); output_byte(0xB7); output_modrm(2,rs,rt); output_w32(addr); } void emit_movzwl_map(int addr, int map, int rt) { if(map<0) emit_movzwl(addr, rt); else { assem_debug("addr32 movzwl %x(,%%%s,4),%%%s\n",addr,regname[map],regname[rt]); output_byte(0x67); output_byte(0x0F); output_byte(0xB7); output_modrm(0,4,rt); output_sib(2,map,5); output_w32(addr); } } void emit_movq(u64 addr, int rt) { if(addr-(u64)out+0x7FFFFFFA>0xFFFFFFFF) { assert(addr-(u64)out+0x7FFFFFFA<0x100000000); //TODO: special eax case emit_movimm64(addr,rt); //FIXME assem_debug("mov (%%%s),%%%s\n",regname[rt],regname[rt]); output_byte(0x8B); output_modrm(0,rt,rt); output_byte(0xCC);//remove } else { assem_debug("movq %llx,%%%s\n",addr,regname[rt]); output_rex(1,0,0,rt>>8); output_byte(0x8B); output_modrm(0,5,rt); output_w32(addr-(int)out-4); // Note: rip-relative in 64-bit mode } } void emit_xchg(int rs, int rt) { assem_debug("xchg %%%s,%%%s\n",regname[rs],regname[rt]); if(rs==EAX) { output_byte(0x90+rt); } else { output_byte(0x87); output_modrm(3,rs,rt); } } void emit_writeword(int rt, int addr) { assem_debug("movl %%%s,%x\n",regname[rt],addr); output_byte(0x89); output_modrm(0,5,rt); output_w32(addr-(int)out-4); // Note: rip-relative in 64-bit mode } void emit_writeword_indexed(int rt, int addr, int rs) { assem_debug("mov %%%s,%x+%%%s\n",regname[rt],addr,regname[rs]); output_byte(0x89); if(addr<128&&addr>=-128) { output_modrm(1,rs,rt); if(rs==ESP) output_sib(0,4,4); output_byte(addr); } else { output_modrm(2,rs,rt); if(rs==ESP) output_sib(0,4,4); output_w32(addr); } } #if 0 void emit_writeword_map(int rt, int addr, int map) { if(map<0) { emit_writeword(rt, addr+(int)rdram-0x80000000); } else { emit_writeword_indexed(rt, addr+(int)rdram-0x80000000, map); } } #endif void emit_writeword_indexed_map(int rt, int addr, int rs, int map, int temp) { if(map<0) emit_writeword_indexed(rt, addr, rs); else { //assem_debug("addr32 mov %%%s,%x(%%%s,%%%s,1)\n",regname[rt],addr,regname[rs],regname[map]); assem_debug("mov %%%s,%x(%%%s,%%%s,1)\n",regname[rt],addr,regname[rs],regname[map]); assert(rs!=ESP); //output_byte(0x67); output_byte(0x89); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(0,map,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(0,map,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(0,map,rs); output_w32(addr); } } } void emit_writehword(int rt, int addr) { assem_debug("movw %%%s,%x\n",regname[rt]+1,addr); output_byte(0x66); output_byte(0x89); output_modrm(0,5,rt); output_w32(addr-(int)out-4); // Note: rip-relative in 64-bit mode } void emit_writehword_indexed(int rt, int addr, int rs) { assem_debug("movw %%%s,%x+%%%s\n",regname[rt]+1,addr,regname[rs]); output_byte(0x66); output_byte(0x89); if(addr<128&&addr>=-128) { output_modrm(1,rs,rt); output_byte(addr); } else { output_modrm(2,rs,rt); output_w32(addr); } } #if 0 void emit_writehword_map(int rt, int addr, int map) { if(map<0) { emit_writehword(rt, addr+(int)rdram-0x80000000); } else { emit_writehword_indexed(rt, addr+(int)rdram-0x80000000, map); } } #endif void emit_writehword_indexed_map(int rt, int addr, int rs, int map, int temp) { if(map<0) emit_writehword_indexed(rt, addr, rs); else { assem_debug("movw %%%s,%x(%%%s,%%%s,1)\n",regname[rt]+1,addr,regname[rs],regname[map]); assert(rs!=ESP); output_byte(0x66); output_byte(0x89); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(0,map,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(0,map,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(0,map,rs); output_w32(addr); } } } void emit_writebyte(int rt, int addr) { assem_debug("movb %%%cl,%x\n",regname[rt][1],addr); if(rt>=4) output_rex(0,rt>>3,0,0); output_byte(0x88); output_modrm(0,5,rt); output_w32(addr-(int)out-4); // Note: rip-relative in 64-bit mode } void emit_writebyte_indexed(int rt, int addr, int rs) { assem_debug("movb %%%cl,%x+%%%s\n",regname[rt][1],addr,regname[rs]); if(rt>=4||rs>=8) output_rex(0,rt>>3,0,rs>>3); output_byte(0x88); if(addr<128&&addr>=-128) { output_modrm(1,rs,rt); output_byte(addr); } else { output_modrm(2,rs,rt); output_w32(addr); } } #if 0 void emit_writebyte_map(int rt, int addr, int map) { if(map<0) { emit_writebyte(rt, addr+(int)rdram-0x80000000); } else { emit_writebyte_indexed(rt, addr+(int)rdram-0x80000000, map); } } #endif void emit_writebyte_indexed_map(int rt, int addr, int rs, int map, int temp) { if(map<0) emit_writebyte_indexed(rt, addr, rs); else { assem_debug("movb %%%cl,%x(%%%s,%%%s,1)\n",regname[rt][1],addr,regname[rs],regname[map]); assert(rs!=ESP); if(rt>=4||rs>=8||map>=8) output_rex(0,rt>>3,map>>3,rs>>3); output_byte(0x88); if(addr==0&&rs!=EBP) { output_modrm(0,4,rt); output_sib(0,map,rs); } else if(addr<128&&addr>=-128) { output_modrm(1,4,rt); output_sib(0,map,rs); output_byte(addr); } else { output_modrm(2,4,rt); output_sib(0,map,rs); output_w32(addr); } } } void emit_writeword_imm(int imm, int addr) { assem_debug("movl $%x,%x\n",imm,addr); output_byte(0xC7); output_modrm(0,5,0); output_w32(addr-(int)out-8); // Note: rip-relative in 64-bit mode output_w32(imm); } void emit_writeword_imm_esp(int imm, int addr) { assem_debug("mov $%x,%x(%%esp)\n",imm,addr); assert(addr>=-128&&addr<128); output_byte(0xC7); output_modrm(!!addr,4,0); output_sib(0,4,4); if(addr) output_byte(addr); output_w32(imm); } void emit_writedword_imm32(int imm, int addr) { assem_debug("movq $%x,%x\n",imm,addr); output_rex(1,0,0,0); output_byte(0xC7); output_modrm(0,5,0); output_w32(addr-(int)out-8); // Note: rip-relative in 64-bit mode output_w32(imm); // Note: This 32-bit value will be sign extended } void emit_writebyte_imm(int imm, int addr) { assem_debug("movb $%x,%x\n",imm,addr); assert(imm>=-128&&imm<128); output_byte(0xC6); output_modrm(0,5,0); output_w32(addr-(int)out-5); // Note: rip-relative in 64-bit mode output_byte(imm); } void emit_rmw_andimm(int addr, int map, int imm) { if(map<0) { assem_debug("andb $0x%x,(%%%s)\n",imm,regname[addr]); assert(addr!=ESP); output_byte(0x80); output_modrm(0,addr,4); } else { assem_debug("andb $0x%x,(%%%s,%%%s,1)\n",imm,regname[addr],regname[map]); assert(addr!=ESP); output_byte(0x80); output_modrm(0,4,4); if(addr!=EBP) { output_sib(0,map,addr); } else { assert(addr!=map); output_sib(0,addr,map); } } output_byte(imm); } void emit_rmw_xorimm(int addr, int map, int imm) { if(map<0) { assem_debug("xorb $0x%x,(%%%s)\n",imm,regname[addr]); assert(addr!=ESP); output_byte(0x80); output_modrm(0,addr,6); } else { assem_debug("xorb $0x%x,(%%%s,%%%s,1)\n",imm,regname[addr],regname[map]); assert(addr!=ESP); output_byte(0x80); output_modrm(0,4,6); if(addr!=EBP) { output_sib(0,map,addr); } else { assert(addr!=map); output_sib(0,addr,map); } } output_byte(imm); } void emit_rmw_orimm(int addr, int map, int imm) { if(map<0) { assem_debug("orb $0x%x,(%%%s)\n",imm,regname[addr]); assert(addr!=ESP); output_byte(0x80); output_modrm(0,addr,1); } else { assem_debug("orb $0x%x,(%%%s,%%%s,1)\n",imm,regname[addr],regname[map]); assert(addr!=ESP); output_byte(0x80); output_modrm(0,4,1); if(addr!=EBP) { output_sib(0,map,addr); } else { assert(addr!=map); output_sib(0,addr,map); } } output_byte(imm); } void emit_sh2tas(int addr, int map, int sr) { emit_shrimm(sr,1,sr); if(map<0) { assem_debug("cmpb $1,(%%%s)\n",regname[addr]); assert(addr!=ESP); output_byte(0x80); output_modrm(0,addr,7); } else { assem_debug("cmpb $1,(%%%s,%%%s,1)\n",regname[addr],regname[map]); assert(addr!=ESP); output_byte(0x80); output_modrm(0,4,7); if(addr!=EBP) { output_sib(0,map,addr); } else { assert(addr!=map); output_sib(0,addr,map); } } output_byte(1); emit_adc(sr,sr); emit_rmw_orimm(addr,map,0x80); } void emit_mul(int rs) { assem_debug("mul %%%s\n",regname[rs]); output_byte(0xF7); output_modrm(3,rs,4); } void emit_imul(int rs) { assem_debug("imul %%%s\n",regname[rs]); output_byte(0xF7); output_modrm(3,rs,5); } void emit_multiply(int rs1,int rs2,int rt) { if(rs1==rt) { assem_debug("imul %%%s,%%%s\n",regname[rs2],regname[rt]); output_byte(0x0F); output_byte(0xAF); output_modrm(3,rs2,rt); } else { emit_mov(rs1,rt); emit_multiply(rt,rs2,rt); } } void emit_div(int rs) { assem_debug("div %%%s\n",regname[rs]); output_byte(0xF7); output_modrm(3,rs,6); } void emit_idiv(int rs) { assem_debug("idiv %%%s\n",regname[rs]); output_byte(0xF7); output_modrm(3,rs,7); } void emit_cdq() { assem_debug("cdq\n"); output_byte(0x99); } void emit_div0s(int s1, int s2, int sr, int temp) { emit_shlimm(sr,24,sr); emit_mov(s2,temp); assem_debug("bt %%%s,31\n",regname[s2]); output_byte(0x0f); output_byte(0xba); output_modrm(3,s2,4); output_byte(0x1f); assem_debug("rcr %%%s\n",regname[sr]); output_byte(0xD1); output_modrm(3,sr,3); emit_xor(temp,s1,temp); assem_debug("bt %%%s,31\n",regname[s1]); output_byte(0x0f); output_byte(0xba); output_modrm(3,s1,4); output_byte(0x1f); assem_debug("rcr %%%s,24\n",regname[sr]); output_byte(0xc1); output_modrm(3,sr,3); output_byte(24); assem_debug("bt %%%s,31\n",regname[temp]); output_byte(0x0f); output_byte(0xba); output_modrm(3,temp,4); output_byte(0x1f); emit_adc(sr,sr); } // Load return address void emit_load_return_address(unsigned int rt) { // (assumes this instruction will be followed by a 5-byte jmp instruction) emit_movimm((int)out+10,rt); } // Load 2 immediates optimizing for small code size void emit_mov2imm_compact(int imm1,unsigned int rt1,int imm2,unsigned int rt2) { emit_movimm(imm1,rt1); if(imm2-imm1<128&&imm2-imm1>=-128) emit_addimm(rt1,imm2-imm1,rt2); else emit_movimm(imm2,rt2); } // compare byte in memory void emit_cmpmem_imm_byte(pointer addr,int imm) { assert(imm<128&&imm>=-127); assem_debug("cmpb $%d,%x\n",imm,addr); output_byte(0x80); output_modrm(0,5,7); output_w32(addr-(int)out-5); // Note: rip-relative in 64-bit mode output_byte(imm); } // special case for checking invalid_code void emit_cmpmem_indexedsr12_imm(int addr,int r,int imm) { assert(imm<128&&imm>=-127); assert(r>=0&&r<8); emit_shrimm(r,12,r); assem_debug("cmp $%d,%x+%%%s\n",imm,addr,regname[r]); output_byte(0x80); output_modrm(2,r,7); output_w32(addr); output_byte(imm); } // special case for checking hash_table void emit_cmpmem_indexed(int addr,int rs,int rt) { assert(rs>=0&&rs<8); assert(rt>=0&&rt<8); assem_debug("cmp %x+%%%s,%%%s\n",addr,regname[rs],regname[rt]); output_byte(0x39); output_modrm(2,rs,rt); output_w32(addr); } // special case for checking memory_map in verify_mapping void emit_cmpmem(int addr,int rt) { assert(rt>=0&&rt<8); assem_debug("cmp %x,%%%s\n",addr,regname[rt]); output_byte(0x39); output_modrm(0,5,rt); output_w32((int)addr-(int)out-4); // Note: rip-relative in 64-bit mode } // Used to preload hash table entries void emit_prefetch(void *addr) { assem_debug("prefetch %x\n",(int)addr); output_byte(0x0F); output_byte(0x18); output_modrm(0,5,1); output_w32((int)addr-(int)out-4); // Note: rip-relative in 64-bit mode } /*void emit_submem(int r,int addr) { assert(r>=0&&r<8); assem_debug("sub %x,%%%s\n",addr,regname[r]); output_byte(0x2B); output_modrm(0,5,r); output_w32((int)addr); }*/ void emit_flds(int r) { assem_debug("flds (%%%s)\n",regname[r]); output_byte(0xd9); if(r!=EBP) output_modrm(0,r,0); else {output_modrm(1,EBP,0);output_byte(0);} } void emit_fldl(int r) { assem_debug("fldl (%%%s)\n",regname[r]); output_byte(0xdd); if(r!=EBP) output_modrm(0,r,0); else {output_modrm(1,EBP,0);output_byte(0);} } void emit_fucomip(unsigned int r) { assem_debug("fucomip %d\n",r); assert(r<8); output_byte(0xdf); output_byte(0xe8+r); } void emit_fchs() { assem_debug("fchs\n"); output_byte(0xd9); output_byte(0xe0); } void emit_fabs() { assem_debug("fabs\n"); output_byte(0xd9); output_byte(0xe1); } void emit_fsqrt() { assem_debug("fsqrt\n"); output_byte(0xd9); output_byte(0xfa); } void emit_fadds(int r) { assem_debug("fadds (%%%s)\n",regname[r]); output_byte(0xd8); if(r!=EBP) output_modrm(0,r,0); else {output_modrm(1,EBP,0);output_byte(0);} } void emit_faddl(int r) { assem_debug("faddl (%%%s)\n",regname[r]); output_byte(0xdc); if(r!=EBP) output_modrm(0,r,0); else {output_modrm(1,EBP,0);output_byte(0);} } void emit_fadd(int r) { assem_debug("fadd st%d\n",r); output_byte(0xd8); output_byte(0xc0+r); } void emit_fsubs(int r) { assem_debug("fsubs (%%%s)\n",regname[r]); output_byte(0xd8); if(r!=EBP) output_modrm(0,r,4); else {output_modrm(1,EBP,4);output_byte(0);} } void emit_fsubl(int r) { assem_debug("fsubl (%%%s)\n",regname[r]); output_byte(0xdc); if(r!=EBP) output_modrm(0,r,4); else {output_modrm(1,EBP,4);output_byte(0);} } void emit_fsub(int r) { assem_debug("fsub st%d\n",r); output_byte(0xd8); output_byte(0xe0+r); } void emit_fmuls(int r) { assem_debug("fmuls (%%%s)\n",regname[r]); output_byte(0xd8); if(r!=EBP) output_modrm(0,r,1); else {output_modrm(1,EBP,1);output_byte(0);} } void emit_fmull(int r) { assem_debug("fmull (%%%s)\n",regname[r]); output_byte(0xdc); if(r!=EBP) output_modrm(0,r,1); else {output_modrm(1,EBP,1);output_byte(0);} } void emit_fmul(int r) { assem_debug("fmul st%d\n",r); output_byte(0xd8); output_byte(0xc8+r); } void emit_fdivs(int r) { assem_debug("fdivs (%%%s)\n",regname[r]); output_byte(0xd8); if(r!=EBP) output_modrm(0,r,6); else {output_modrm(1,EBP,6);output_byte(0);} } void emit_fdivl(int r) { assem_debug("fdivl (%%%s)\n",regname[r]); output_byte(0xdc); if(r!=EBP) output_modrm(0,r,6); else {output_modrm(1,EBP,6);output_byte(0);} } void emit_fdiv(int r) { assem_debug("fdiv st%d\n",r); output_byte(0xd8); output_byte(0xf0+r); } void emit_fpop() { // fstp st(0) assem_debug("fpop\n"); output_byte(0xdd); output_byte(0xd8); } void emit_fildl(int r) { assem_debug("fildl (%%%s)\n",regname[r]); output_byte(0xdb); if(r!=EBP) output_modrm(0,r,0); else {output_modrm(1,EBP,0);output_byte(0);} } void emit_fildll(int r) { assem_debug("fildll (%%%s)\n",regname[r]); output_byte(0xdf); if(r!=EBP) output_modrm(0,r,5); else {output_modrm(1,EBP,5);output_byte(0);} } void emit_fistpl(int r) { assem_debug("fistpl (%%%s)\n",regname[r]); output_byte(0xdb); if(r!=EBP) output_modrm(0,r,3); else {output_modrm(1,EBP,3);output_byte(0);} } void emit_fistpll(int r) { assem_debug("fistpll (%%%s)\n",regname[r]); output_byte(0xdf); if(r!=EBP) output_modrm(0,r,7); else {output_modrm(1,EBP,7);output_byte(0);} } void emit_fstps(int r) { assem_debug("fstps (%%%s)\n",regname[r]); output_byte(0xd9); if(r!=EBP) output_modrm(0,r,3); else {output_modrm(1,EBP,3);output_byte(0);} } void emit_fstpl(int r) { assem_debug("fstpl (%%%s)\n",regname[r]); output_byte(0xdd); if(r!=EBP) output_modrm(0,r,3); else {output_modrm(1,EBP,3);output_byte(0);} } void emit_fnstcw_stack() { assem_debug("fnstcw (%%esp)\n"); output_byte(0xd9); output_modrm(0,4,7); output_sib(0,4,4); } void emit_fldcw_stack() { assem_debug("fldcw (%%esp)\n"); output_byte(0xd9); output_modrm(0,4,5); output_sib(0,4,4); } void emit_fldcw_indexed(int addr,int r) { assem_debug("fldcw %x(%%%s)\n",addr,regname[r]); output_byte(0xd9); output_modrm(0,4,5); output_sib(1,r,5); output_w32(addr); } void emit_fldcw(int addr) { assem_debug("fldcw %x\n",addr); output_byte(0xd9); output_modrm(0,5,5); output_w32(addr-(int)out-4); // Note: rip-relative in 64-bit mode } void emit_movss_load(unsigned int addr,unsigned int ssereg) { assem_debug("movss (%%%s),xmm%d\n",regname[addr],ssereg); assert(ssereg<8); output_byte(0xf3); output_byte(0x0f); output_byte(0x10); if(addr!=EBP) output_modrm(0,addr,ssereg); else {output_modrm(1,EBP,ssereg);output_byte(0);} } void emit_movsd_load(unsigned int addr,unsigned int ssereg) { assem_debug("movsd (%%%s),xmm%d\n",regname[addr],ssereg); assert(ssereg<8); output_byte(0xf2); output_byte(0x0f); output_byte(0x10); if(addr!=EBP) output_modrm(0,addr,ssereg); else {output_modrm(1,EBP,ssereg);output_byte(0);} } void emit_movd_store(unsigned int ssereg,unsigned int addr) { assem_debug("movd xmm%d,(%%%s)\n",ssereg,regname[addr]); assert(ssereg<8); output_byte(0x66); output_byte(0x0f); output_byte(0x7e); if(addr!=EBP) output_modrm(0,addr,ssereg); else {output_modrm(1,EBP,ssereg);output_byte(0);} } void emit_cvttps2dq(unsigned int ssereg1,unsigned int ssereg2) { assem_debug("cvttps2dq xmm%d,xmm%d\n",ssereg1,ssereg2); assert(ssereg1<8); assert(ssereg2<8); output_byte(0xf3); output_byte(0x0f); output_byte(0x5b); output_modrm(3,ssereg1,ssereg2); } void emit_cvttpd2dq(unsigned int ssereg1,unsigned int ssereg2) { assem_debug("cvttpd2dq xmm%d,xmm%d\n",ssereg1,ssereg2); assert(ssereg1<8); assert(ssereg2<8); output_byte(0x66); output_byte(0x0f); output_byte(0xe6); output_modrm(3,ssereg1,ssereg2); } unsigned int count_bits(u32 reglist) { int count=0; while(reglist) { count+=reglist&1; reglist>>=1; } return count; } // Save registers before function call // This code is executed infrequently so we try to minimize code size // by pushing registers onto the stack instead of writing them to their // usual locations void save_regs(u32 reglist) { int hr = 0; int count = 0; reglist&=0xC7; // only save the caller-save registers, %eax, %ecx, %edx, %esi, %edi count=count_bits(reglist); if(count) { for(hr=0;hr>hr)&1) { emit_pushreg(hr); } } } } if(slave) emit_addimm64(ESP,-(6-count)*8,ESP); // slave has master's return address on stack else emit_addimm64(ESP,-(7-count)*8,ESP); } // Restore registers after function call void restore_regs(u32 reglist) { int hr = 0; int count = 0; reglist&=0xC7; // only save the caller-save registers, %eax, %ecx, %edx, %esi, %edi count=count_bits(reglist); if(slave) emit_addimm64(ESP,(6-count)*8,ESP); else emit_addimm64(ESP,(7-count)*8,ESP); if(count) { for(hr=HOST_REGS-1;hr>=0;hr--) { if(hr!=EXCLUDE_REG) { if((reglist>>hr)&1) { emit_popreg(hr); } } } } } /* Stubs/epilogue */ void emit_extjump(pointer addr, int target) { u8 *ptr=(u8 *)addr; if(*ptr==0x0f) { assert(ptr[1]>=0x80&&ptr[1]<=0x8f); addr+=2; } else { assert(*ptr==0xe8||*ptr==0xe9); addr++; } emit_movimm(target,EAX); emit_movimm(addr,EBX); //assert(addr>=0x7000000&&addr<0x7FFFFFF); //DEBUG > #ifdef DEBUG_CYCLE_COUNT emit_readword((int)&last_count,ECX); emit_add(HOST_CCREG,ECX,HOST_CCREG); emit_readword((int)&next_interupt,ECX); emit_writeword(HOST_CCREG,(int)&Count); emit_sub(HOST_CCREG,ECX,HOST_CCREG); emit_writeword(ECX,(int)&last_count); #endif //DEBUG < emit_jmp((pointer)dyna_linker); } void do_readstub(int n) { int type = 0, i = 0, rs = 0, addr = 0, rt = 0; signed char *i_regmap = NULL; struct regstat *i_regs = NULL; u32 reglist = 0; assem_debug("do_readstub %x\n",start+stubs[n][3]*2); set_jump_target(stubs[n][1],(int)out); type=stubs[n][0]; i=stubs[n][3]; rs=stubs[n][4]; i_regs=(struct regstat *)stubs[n][5]; reglist=stubs[n][7]; i_regmap=i_regs->regmap; addr=get_reg(i_regmap,AGEN1+(i&1)); rt=get_reg(i_regmap,rt1[i]==TBIT?-1:rt1[i]); assert(rs>=0); if(addr<0) addr=rt; if(addr<0) addr=get_reg(i_regmap,-1); assert(addr>=0); save_regs(reglist); if(rs!=EDI) emit_mov(rs,EDI); if(type==LOADB_STUB) emit_xorimm(EDI,1,EDI); /* int temp; int cc=get_reg(i_regmap,CCREG); if(cc<0) { if(addr==HOST_CCREG) { cc=0;temp=1; assert(cc!=HOST_CCREG); assert(temp!=HOST_CCREG); emit_loadreg(CCREG,cc); } else { cc=HOST_CCREG; emit_loadreg(CCREG,cc); temp=!addr; } } else { temp=!addr; }*/ if(type==LOADB_STUB) emit_call((int)MappedMemoryReadByteNocache); if(type==LOADW_STUB) emit_call((int)MappedMemoryReadWordNocache); if(type==LOADL_STUB) emit_call((int)MappedMemoryReadLongNocache); if(type==LOADS_STUB) { // RTE instruction, pop PC and SR from stack int pc=get_reg(i_regmap,RTEMP); assert(pc>=0); if(rs==EAX||rs==ECX||rs==EDX||rs==ESI||rs==EDI) emit_mov(rs,12); //emit_writeword_indexed(rs,0,ESP); emit_call((int)MappedMemoryReadLongNocache); if(rs==EAX||rs==ECX||rs==EDX||rs==ESI) emit_mov(12,rs); //emit_readword_indexed(0,ESP,rs); if(pc==EDI) { emit_mov(EAX,12); //emit_writeword_indexed(EAX,0,ESP); } else { if(pc==EAX||pc==ECX||pc==EDX||pc==ESI) emit_mov(EAX,12); //emit_writeword_indexed(EAX,0,ESP); else emit_mov(EAX,pc); if(rs==EDI) { emit_mov(12,EDI); //emit_readword_indexed(0,ESP,EAX); emit_addimm(EDI,4,EDI); }else emit_addimm(rs,4,EDI); } emit_call((int)MappedMemoryReadLongNocache); assert(rt>=0); if(rt!=EAX) emit_mov(EAX,rt); if(pc==EAX||pc==ECX||pc==EDX||pc==ESI||pc==EDI) emit_mov(12,pc); //emit_readword_indexed(0,ESP,pc); } else if(type==LOADB_STUB) { if(rt>=0) emit_movsbl_reg(EAX,rt); } else if(type==LOADW_STUB) { if(rt>=0) emit_movswl_reg(EAX,rt); } else { if(rt!=EAX&&rt>=0) emit_mov(EAX,rt); } restore_regs(reglist); if(type==LOADS_STUB) emit_addimm(rs,8,rs); emit_jmp(stubs[n][2]); // return address } void inline_readstub(int type, int i, u32 addr, signed char regmap[], int target, int adj, u32 reglist) { int rt = 0; assem_debug("inline_readstub\n"); //int rs=get_reg(regmap,target); rt=get_reg(regmap,target); //if(rs<0) rs=get_reg(regmap,-1); if(rt<0) rt=get_reg(regmap,-1); assert(rt>=0); save_regs(reglist); emit_movimm(addr,EDI); if(type==LOADB_STUB) emit_call((int)MappedMemoryReadByteNocache); if(type==LOADW_STUB) emit_call((int)MappedMemoryReadWordNocache); if(type==LOADL_STUB) emit_call((int)MappedMemoryReadLongNocache); assert(type!=LOADS_STUB); if(type==LOADB_STUB) { if(rt>=0) emit_movsbl_reg(EAX,rt); } else if(type==LOADW_STUB) { if(rt>=0) emit_movswl_reg(EAX,rt); } else { if(rt!=EAX&&rt>=0) emit_mov(EAX,rt); } restore_regs(reglist); } void do_writestub(int n) { int type = 0, i = 0, rs = 0, addr = 0, rt = 0; struct regstat *i_regs = NULL; signed char *i_regmap = NULL; u32 reglist = 0; assem_debug("do_writestub %x\n",start+stubs[n][3]*2); set_jump_target(stubs[n][1],(int)out); type=stubs[n][0]; i=stubs[n][3]; rs=stubs[n][4]; i_regs=(struct regstat *)stubs[n][5]; reglist=stubs[n][7]; i_regmap=i_regs->regmap; addr=get_reg(i_regmap,AGEN1+(i&1)); rt=get_reg(i_regmap,rs1[i]); assert(rs>=0); assert(rt>=0); if(addr<0) addr=get_reg(i_regmap,-1); assert(addr>=0); save_regs(reglist); // "FASTCALL" api: address in edi, data in esi if(rs!=EDI) { if(rt==EDI) { if(rs==ESI) emit_xchg(EDI,ESI); else { emit_mov(rt,ESI); emit_mov(rs,EDI); } } else { emit_mov(rs,EDI); if(rt!=ESI) emit_mov(rt,ESI); } } else if(rt!=ESI) emit_mov(rt,ESI); //if(type==STOREB_STUB) emit_xorimm(EAX,1,EAX); // WriteInvalidateByteSwapped does this /*int temp; int cc=get_reg(i_regmap,CCREG); if(cc<0) { if(addr==HOST_CCREG) { cc=0;temp=1; assert(cc!=HOST_CCREG); assert(temp!=HOST_CCREG); emit_loadreg(CCREG,cc); } else { cc=HOST_CCREG; emit_loadreg(CCREG,cc); temp=!addr; } } else { temp=!addr; }*/ if(type==STOREB_STUB) emit_call((int)WriteInvalidateByteSwapped); if(type==STOREW_STUB) emit_call((int)WriteInvalidateWord); if(type==STOREL_STUB) emit_call((int)WriteInvalidateLong); restore_regs(reglist); emit_jmp(stubs[n][2]); // return address } void inline_writestub(int type, int i, u32 addr, signed char regmap[], int target, int adj, u32 reglist) { int rt = 0; assem_debug("inline_writestub\n"); //int rs=get_reg(regmap,-1); rt=get_reg(regmap,target); //assert(rs>=0); assert(rt>=0); save_regs(reglist); // "FASTCALL" api: address in eax, data in edx if(rt!=ESI) emit_mov(rt,ESI); emit_movimm(addr,EDI); // FIXME - should be able to move the existing value if(type==STOREB_STUB) emit_call((int)WriteInvalidateByte); if(type==STOREW_STUB) emit_call((int)WriteInvalidateWord); if(type==STOREL_STUB) emit_call((int)WriteInvalidateLong); restore_regs(reglist); } void do_rmwstub(int n) { int type = 0, i = 0, rs = 0, addr = 0; struct regstat *i_regs = NULL; u32 reglist = 0; signed char *i_regmap = NULL; assem_debug("do_rmwstub %x\n",start+stubs[n][3]*2); set_jump_target(stubs[n][1],(int)out); type=stubs[n][0]; i=stubs[n][3]; rs=stubs[n][4]; i_regs=(struct regstat *)stubs[n][5]; reglist=stubs[n][7]; i_regmap=i_regs->regmap; addr=get_reg(i_regmap,AGEN1+(i&1)); //int rt=get_reg(i_regmap,rs1[i]); assert(rs>=0); //assert(rt>=0); if(addr<0) addr=get_reg(i_regmap,-1); assert(addr>=0); save_regs(reglist); // "FASTCALL" api: address in eax, data in edx emit_xorimm(rs,1,rs); if(rs!=EDI) emit_mov(rs,EDI); if(rs==EAX||rs==ECX||rs==EDX||rs==ESI||rs==EDI) emit_mov(rs,12); //emit_writeword_indexed(rs,0,ESP); //if(i_regmap[HOST_CCREG]==CCREG) emit_storereg(CCREG,HOST_CCREG);//DEBUG /*if(i_regmap[HOST_CCREG]==CCREG) { emit_addimm(HOST_CCREG,CLOCK_DIVIDER*(stubs[n][6]),HOST_CCREG); output_byte(0x03); output_modrm(1,4,HOST_CCREG); output_sib(0,4,4); output_byte(12+16); emit_writeword(HOST_CCREG,(int)&MSH2->cycles); output_byte(0x2B); output_modrm(1,4,HOST_CCREG); output_sib(0,4,4); output_byte(12+16); emit_addimm(HOST_CCREG,-CLOCK_DIVIDER*(stubs[n][6]),HOST_CCREG); } if(i_regmap[HOST_CCREG]!=CCREG) { emit_loadreg(CCREG,ECX); emit_addimm(ECX,CLOCK_DIVIDER*(stubs[n][6]),ECX); output_byte(0x03); output_modrm(1,4,ECX); output_sib(0,4,4); output_byte(12+16); emit_writeword(ECX,(int)&MSH2->cycles); }*/ emit_call((int)MappedMemoryReadByteNocache); emit_mov(EAX,ESI); if(rs==EAX||rs==ECX||rs==EDX||rs==ESI||rs==EDI) emit_mov(12,EDI); //emit_readword_indexed(0,ESP,EAX); else emit_mov(rs,EDI); if(type==RMWA_STUB) emit_andimm(ESI,imm[i],ESI); if(type==RMWX_STUB) emit_xorimm(ESI,imm[i],ESI); if(type==RMWO_STUB) emit_orimm(ESI,imm[i],ESI); if(type==RMWT_STUB) { // TAS.B emit_mov(ESI,12); //emit_writeword_indexed(EDX,0,ESP); emit_orimm(ESI,0x80,ESI); } //emit_call((int)MappedMemoryWriteByte); emit_call((int)WriteInvalidateByte); restore_regs(reglist); if(opcode2[i]==11) { // TAS.B signed char sr; sr=get_reg(i_regs->regmap,SR); assert(sr>=0); // Liveness analysis? emit_andimm(sr,~1,sr); /*assem_debug("cmp $%d,%d+%%%s\n",1,-16,regname[ESP]); output_byte(0x80); output_modrm(1,4,7); output_sib(0,4,4); output_byte(-16); output_byte(1);*/ emit_cmpimm(12,1); emit_adcimm(0,sr); } emit_jmp(stubs[n][2]); // return address } void do_unalignedwritestub(int n) { set_jump_target(stubs[n][1],(int)out); output_byte(0xCC); emit_jmp(stubs[n][2]); // return address } void printregs(int edi,int esi,int ebp,int esp,int b,int d,int c,int a) { printf("regs: %x %x %x %x %x %x %x (%x)\n",a,b,c,d,ebp,esi,edi,(&edi)[-1]); } int do_dirty_stub(int i) { u32 alignedlen = 0; int entry = 0; assem_debug("do_dirty_stub %x\n",start+i*2); alignedlen=((((u32)source)+slen*2+2)&~2)-(u32)alignedsource; if((u64)source<=0xFFFFFFFF) emit_movimm(((u32)source)&~3,EAX); //alignedsource else emit_movimm64(((u64)source)&~3,EAX); //alignedsource emit_movimm((u32)copy,EBX); emit_movimm((((u32)source+slen*2+2)&~3)-((u32)source&~3),ECX); emit_movimm(start+i*2+slave,12); emit_call((int)&verify_code); entry=(int)out; load_regs_entry(i); if(entry==(int)out) entry=instr_addr[i]; emit_jmp(instr_addr[i]); return entry; } /* Memory Map */ int do_map_r(int s,int ar,int map,int cache,int x,int a,int shift,int c,u32 addr) { if(c) { /*if((signed int)addr>=(signed int)0xC0000000) { emit_movq((int)(memory_map+(addr>>12)),map); } else*/ return -1; // No mapping } else { if(s!=map) emit_mov(s,map); emit_shrimm(map,12,map); // Schedule this while we wait on the load if(x) emit_xorimm(s,x,ar); //if(shift>=0) emit_lea8(s,shift); //if(~a) emit_andimm(s,a,ar); emit_movmem_indexedx8_64((int)memory_map,map,map); } return map; } int do_map_r_branch(int map, int c, u32 addr, int *jaddr) { if(!c) { emit_test64(map,map); *jaddr=(int)out; emit_js(0); } return map; } void gen_tlb_addr_r(int ar, int map) { if(map>=0) { emit_leairrx4(0,ar,map,ar); } } int do_map_w(int s,int ar,int map,int cache,int x,int c,u32 addr) { if(c) { if(can_direct_write(addr)) { emit_movq((int)(memory_map+(addr>>12)),map); } else return -1; // No mapping } else { if(s!=map) emit_mov(s,map); //if(s!=ar) emit_mov(s,ar); emit_shrimm(map,12,map); // Schedule this while we wait on the load if(x) emit_xorimm(s,x,ar); emit_movmem_indexedx8_64((int)memory_map,map,map); } emit_shlimm64(map,2,map); return map; } void do_map_w_branch(int map, int c, u32 addr, int *jaddr) { if(!c||can_direct_write(addr)) { *jaddr=(int)out; emit_jc(0); } } void gen_tlb_addr_w(int ar, int map) { if(map>=0) { emit_leairrx1(0,ar,map,ar); } } // We don't need this for x86 void generate_map_const(u32 addr,int reg) { // void *mapaddr=memory_map+(addr>>12); } /* Special assem */ void do_preload_rhash(int r) { emit_movimm(0xf8,r); } void do_preload_rhtbl(int r) { // Don't need this for x86 } void do_rhash(int rs,int rh) { emit_and(rs,rh,rh); } void do_miniht_load(int ht,int rh) { // Don't need this for x86. The load and compare can be combined into // a single instruction (below) } void do_miniht_jump(int rs,int rh,int ht) { emit_cmpmem_indexed(slave?(u32)mini_ht_slave:(u32)mini_ht_master,rh,rs); emit_jne(jump_vaddr_reg[slave][rs]); emit_readword_indexed(slave?(u32)mini_ht_slave+4:(u32)mini_ht_master+4,rh,rh); emit_jmpreg(rh); } void do_miniht_insert(int return_address,int rt,int temp) { emit_movimm(return_address,rt); // PC into link register //emit_writeword_imm(return_address,(int)&mini_ht[(return_address&0xFF)>>8][0]); if(slave) emit_writeword(rt,(int)&mini_ht_slave[(return_address&0xFF)>>3][0]); else emit_writeword(rt,(int)&mini_ht_master[(return_address&0xFF)>>3][0]); add_to_linker((int)out,return_address,1); if(slave) emit_writeword_imm(0,(int)&mini_ht_slave[(return_address&0xFF)>>3][1]); else emit_writeword_imm(0,(int)&mini_ht_master[(return_address&0xFF)>>3][1]); } void wb_valid(signed char pre[],signed char entry[],u32 dirty_pre,u32 dirty,u64 u) { //if(dirty_pre==dirty) return; int hr,reg,new_hr; for(hr=0;hr>(reg&63))&1) { if(reg>=0) { if(((dirty_pre&~dirty)>>hr)&1) { if(reg>=0&® #include "sh2core.h" #include "debug.h" #include "memory.h" #include "yabause.h" #include "sh7034.h" #include "cs0.h" #include "cs1.h" #include "cs2.h" #include "scsp.h" #include "vdp1.h" #include "vdp2.h" #include "ygr.h" #include "assert.h" #include "smpc.h" #include "scu.h" // SH1/SH2 differences // SH1's mac.w operates at a smaller precision. 16x16+42 instead of 16x16+64 // SH1 is missing the following instructions: bf/s, braf, bsrf, bt/s, dmuls.l, dmulu.l, dt, mac.l, mul.l #if defined(SH2_DYNAREC) #include "sh2_dynarec/sh2_dynarec.h" #endif SH2_struct *SH1=NULL; SH2_struct *MSH2=NULL; SH2_struct *SSH2=NULL; SH2Interface_struct *SH1Core=NULL; SH2Interface_struct *SH2Core=NULL; extern SH2Interface_struct *SH2CoreList[]; void OnchipReset(SH2_struct *context); void FRTExec(SH2_struct *sh, u32 cycles); void WDTExec(SH2_struct *sh, u32 cycles); u8 SCIReceiveByte(void); void SCITransmitByte(u8); ////////////////////////////////////////////////////////////////////////////// int SH1Init(int coreid) { int i; if ((SH1 = (SH2_struct *)calloc(1, sizeof(SH2_struct))) == NULL) return -1; if (SH2TrackInfLoopInit(SH1) != 0) return -1; SH1->onchip.BCR1 = 0x0000; SH1->isslave = 0; SH1->model = SHMT_SH1; SH1->MappedMemoryReadByte = Sh1MemoryReadByte; SH1->MappedMemoryReadWord = Sh1MemoryReadWord; SH1->MappedMemoryReadLong = Sh1MemoryReadLong; SH1->MappedMemoryWriteByte = Sh1MemoryWriteByte; SH1->MappedMemoryWriteWord = Sh1MemoryWriteWord; SH1->MappedMemoryWriteLong = Sh1MemoryWriteLong; // So which core do we want? if (coreid == SH2CORE_DEFAULT) coreid = 0; // Assume we want the first one // Go through core list and find the id for (i = 0; SH2CoreList[i] != NULL; i++) { if (SH2CoreList[i]->id == coreid) { // Set to current core SH1Core = SH2CoreList[i]; break; } } if ((SH1Core == NULL) || (SH1Core->Init(SHMT_SH1, SH1, NULL) != 0)) { free(SH1); SH1 = NULL; return -1; } SH1->core = SH1Core; sh1_init_func(); return 0; } ////////////////////////////////////////////////////////////////////////////// void sh2_set_read_write_funcs(SH2_struct * sh) { if (yabsys.sh2_cache_enabled) { sh->MappedMemoryReadByte = MappedMemoryReadByteCacheEnabled; sh->MappedMemoryReadWord = MappedMemoryReadWordCacheEnabled; sh->MappedMemoryReadLong = MappedMemoryReadLongCacheEnabled; sh->MappedMemoryWriteByte = MappedMemoryWriteByteCacheEnabled; sh->MappedMemoryWriteWord = MappedMemoryWriteWordCacheEnabled; sh->MappedMemoryWriteLong = MappedMemoryWriteLongCacheEnabled; } else { sh->MappedMemoryReadByte = MappedMemoryReadByteNocache; sh->MappedMemoryReadWord = MappedMemoryReadWordNocache; sh->MappedMemoryReadLong = MappedMemoryReadLongNocache; sh->MappedMemoryWriteByte = MappedMemoryWriteByteNocache; sh->MappedMemoryWriteWord = MappedMemoryWriteWordNocache; sh->MappedMemoryWriteLong = MappedMemoryWriteLongNocache; } } int SH2Init(int coreid) { int i; // MSH2 if ((MSH2 = (SH2_struct *)calloc(1, sizeof(SH2_struct))) == NULL) return -1; if (SH2TrackInfLoopInit(MSH2) != 0) return -1; MSH2->onchip.BCR1 = 0x0000; MSH2->isslave = 0; MSH2->model = SHMT_SH2; sh2_set_read_write_funcs(MSH2); // SSH2 if ((SSH2 = (SH2_struct *)calloc(1, sizeof(SH2_struct))) == NULL) return -1; if (SH2TrackInfLoopInit(SSH2) != 0) return -1; SSH2->onchip.BCR1 = 0x8000; SSH2->isslave = 1; SSH2->model = SHMT_SH2; sh2_set_read_write_funcs(SSH2); // So which core do we want? if (coreid == SH2CORE_DEFAULT) coreid = 0; // Assume we want the first one // Go through core list and find the id for (i = 0; SH2CoreList[i] != NULL; i++) { if (SH2CoreList[i]->id == coreid) { // Set to current core SH2Core = SH2CoreList[i]; break; } } if ((SH2Core == NULL) || (SH2Core->Init(SHMT_SH2, MSH2, SSH2) != 0)) { free(MSH2); free(SSH2); MSH2 = SSH2 = NULL; return -1; } MSH2->core = SSH2->core = SH2Core; return 0; } ////////////////////////////////////////////////////////////////////////////// void SH1DeInit() { if (SH1Core) SH1Core->DeInit(); SH1Core = NULL; if (SH1) { SH2TrackInfLoopDeInit(SH1); free(SH1); } SH1 = NULL; } ////////////////////////////////////////////////////////////////////////////// void SH2DeInit() { if (SH2Core) SH2Core->DeInit(); SH2Core = NULL; if (MSH2) { SH2TrackInfLoopDeInit(MSH2); free(MSH2); } MSH2 = NULL; if (SSH2) { SH2TrackInfLoopDeInit(SSH2); free(SSH2); } SSH2 = NULL; } ////////////////////////////////////////////////////////////////////////////// void SH2Reset(SH2_struct *context) { int i; SH2Interface_struct *core=context->core; // Reset general registers for (i = 0; i < 15; i++) core->SetGPR(context, i, 0x00000000); core->SetSR(context, 0x000000F0); core->SetGBR(context, 0x00000000); core->SetVBR(context, 0x00000000); core->SetMACH(context, 0x00000000); core->SetMACL(context, 0x00000000); core->SetPR(context, 0x00000000); // Internal variables context->delay = 0x00000000; context->cycles = 0; context->isIdle = 0; context->frc.leftover = 0; context->frc.shift = 3; context->wdt.isenable = 0; context->wdt.isinterval = 1; context->wdt.shift = 1; context->wdt.leftover = 0; // Reset Interrupts memset((void *)context->interrupts, 0, sizeof(interrupt_struct) * MAX_INTERRUPTS); core->SetInterrupts(context, 0, context->interrupts); // Core specific reset core->Reset(context); // Reset Onchip modules OnchipReset(context); cache_clear(&context->onchip.cache); // Reset backtrace context->bt.numbacktrace = 0; } ////////////////////////////////////////////////////////////////////////////// void SH2PowerOn(SH2_struct *context) { SH2Interface_struct *core=context->core; u32 VBR = core->GetVBR(context); core->SetPC(context, context->MappedMemoryReadLong(context, VBR)); core->SetGPR(context, 15, context->MappedMemoryReadLong(context, VBR+4)); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL SH2Exec(SH2_struct *context, u32 cycles) { context->core->Exec(context, cycles); if(context->model == SHMT_SH1) sh1_onchip_run_cycles(cycles); else FRTExec(context, cycles); WDTExec(context, cycles); if (context->model == SHMT_SH2 && yabsys.use_sh2_dma_timing) sh2_dma_exec(context, cycles); if (UNLIKELY(context->cycles < cycles)) context->cycles = 0; else context->cycles -= cycles; } ////////////////////////////////////////////////////////////////////////////// void SH2SendInterrupt(SH2_struct *context, u8 vector, u8 level) { context->core->SendInterrupt(context, vector, level); } ////////////////////////////////////////////////////////////////////////////// void SH2NMI(SH2_struct *context) { context->onchip.ICR |= 0x8000; SH2SendInterrupt(context, 0xB, 0x10); } ////////////////////////////////////////////////////////////////////////////// void SH2Step(SH2_struct *context) { SH2Interface_struct *core=context->core; if (core) { u32 tmp = core->GetPC(context); // Execute 1 instruction SH2Exec(context, context->cycles+1); // Sometimes it doesn't always execute one instruction, // let's make sure it did if (tmp == core->GetPC(context)) SH2Exec(context, context->cycles+1); } } ////////////////////////////////////////////////////////////////////////////// int SH2StepOver(SH2_struct *context, void (*func)(void *, u32, void *)) { SH2Interface_struct *core=context->core; if (core) { u32 tmp = core->GetPC(context); u16 inst= context->MappedMemoryReadWord(context, context->regs.PC); // If instruction is jsr, bsr, or bsrf, step over it if ((inst & 0xF000) == 0xB000 || // BSR (inst & 0xF0FF) == 0x0003 || // BSRF (inst & 0xF0FF) == 0x400B) // JSR { // Set breakpoint after at PC + 4 context->stepOverOut.callBack = func; context->stepOverOut.type = SH2ST_STEPOVER; context->stepOverOut.enabled = 1; context->stepOverOut.address = context->regs.PC+4; return 1; } else { // Execute 1 instruction instead SH2Exec(context, context->cycles+1); // Sometimes it doesn't always execute one instruction, // let's make sure it did if (tmp == SH2Core->GetPC(context)) SH2Exec(context, context->cycles+1); } } return 0; } ////////////////////////////////////////////////////////////////////////////// void SH2StepOut(SH2_struct *context, void (*func)(void *, u32, void *)) { if (SH2Core) { context->stepOverOut.callBack = func; context->stepOverOut.type = SH2ST_STEPOUT; context->stepOverOut.enabled = 1; context->stepOverOut.address = 0; } } ////////////////////////////////////////////////////////////////////////////// int SH2TrackInfLoopInit(SH2_struct *context) { context->trackInfLoop.maxNum = 100; if ((context->trackInfLoop.match = calloc(context->trackInfLoop.maxNum, sizeof(tilInfo_struct))) == NULL) return -1; return 0; } ////////////////////////////////////////////////////////////////////////////// void SH2TrackInfLoopDeInit(SH2_struct *context) { if (context->trackInfLoop.match) free(context->trackInfLoop.match); } ////////////////////////////////////////////////////////////////////////////// void SH2TrackInfLoopStart(SH2_struct *context) { context->trackInfLoop.enabled = 1; } ////////////////////////////////////////////////////////////////////////////// void SH2TrackInfLoopStop(SH2_struct *context) { context->trackInfLoop.enabled = 0; } ////////////////////////////////////////////////////////////////////////////// void SH2TrackInfLoopClear(SH2_struct *context) { memset(context->trackInfLoop.match, 0, sizeof(tilInfo_struct) * context->trackInfLoop.maxNum); context->trackInfLoop.num = 0; } ////////////////////////////////////////////////////////////////////////////// void SH2GetRegisters(SH2_struct *context, sh2regs_struct * r) { if (r != NULL) { SH2Core->GetRegisters(context, r); } } ////////////////////////////////////////////////////////////////////////////// void SH2SetRegisters(SH2_struct *context, sh2regs_struct * r) { if (r != NULL) { SH2Core->SetRegisters(context, r); } } ////////////////////////////////////////////////////////////////////////////// void SH2WriteNotify(u32 start, u32 length) { if (SH2Core->WriteNotify) SH2Core->WriteNotify(start, length); } ////////////////////////////////////////////////////////////////////////////// void SH2SetBreakpointCallBack(SH2_struct *context, void (*func)(void *, u32, void *), void *userdata) { context->bp.BreakpointCallBack = func; context->bp.BreakpointUserData = userdata; } ////////////////////////////////////////////////////////////////////////////// int SH2AddCodeBreakpoint(SH2_struct *context, u32 addr) { int i; if (context->bp.numcodebreakpoints < MAX_BREAKPOINTS) { // Make sure it isn't already on the list for (i = 0; i < context->bp.numcodebreakpoints; i++) { if (addr == context->bp.codebreakpoint[i].addr) return -1; } context->bp.codebreakpoint[context->bp.numcodebreakpoints].addr = addr; context->bp.numcodebreakpoints++; return 0; } return -1; } ////////////////////////////////////////////////////////////////////////////// static void SH2SortCodeBreakpoints(SH2_struct *context) { int i, i2; u32 tmp; for (i = 0; i < (MAX_BREAKPOINTS-1); i++) { for (i2 = i+1; i2 < MAX_BREAKPOINTS; i2++) { if (context->bp.codebreakpoint[i].addr == 0xFFFFFFFF && context->bp.codebreakpoint[i2].addr != 0xFFFFFFFF) { tmp = context->bp.codebreakpoint[i].addr; context->bp.codebreakpoint[i].addr = context->bp.codebreakpoint[i2].addr; context->bp.codebreakpoint[i2].addr = tmp; } } } } ////////////////////////////////////////////////////////////////////////////// int SH2DelCodeBreakpoint(SH2_struct *context, u32 addr) { int i, i2; LOG("Deleting breakpoint %08X...\n", addr); if (context->bp.numcodebreakpoints > 0) { for (i = 0; i < context->bp.numcodebreakpoints; i++) { if (context->bp.codebreakpoint[i].addr == addr) { context->bp.codebreakpoint[i].addr = 0xFFFFFFFF; SH2SortCodeBreakpoints(context); context->bp.numcodebreakpoints--; LOG("Remaining breakpoints: \n"); for (i2 = 0; i2 < context->bp.numcodebreakpoints; i2++) { LOG("%08X", context->bp.codebreakpoint[i2].addr); } return 0; } } } LOG("Failed deleting breakpoint\n"); return -1; } ////////////////////////////////////////////////////////////////////////////// codebreakpoint_struct *SH2GetBreakpointList(SH2_struct *context) { return context->bp.codebreakpoint; } ////////////////////////////////////////////////////////////////////////////// void SH2ClearCodeBreakpoints(SH2_struct *context) { int i; for (i = 0; i < MAX_BREAKPOINTS; i++) { context->bp.codebreakpoint[i].addr = 0xFFFFFFFF; } context->bp.numcodebreakpoints = 0; } ////////////////////////////////////////////////////////////////////////////// static u8 FASTCALL SH2MemoryBreakpointReadByte(SH2_struct *sh, u32 addr) { int i; for (i = 0; i < sh->bp.nummemorybreakpoints; i++) { if (sh->bp.memorybreakpoint[i].addr == (addr & 0x0FFFFFFF)) { if (sh->bp.BreakpointCallBack && sh->bp.inbreakpoint == 0) { sh->bp.inbreakpoint = 1; sh->bp.BreakpointCallBack(sh, 0, sh->bp.BreakpointUserData); sh->bp.inbreakpoint = 0; } return sh->bp.memorybreakpoint[i].oldreadbyte(sh, addr); } } // Use the closest match if address doesn't match for (i = 0; i < sh->bp.nummemorybreakpoints; i++) { if (((sh->bp.memorybreakpoint[i].addr >> 16) & 0xFFF) == ((addr >> 16) & 0xFFF)) return sh->bp.memorybreakpoint[i].oldreadbyte(sh, addr); } return 0; } ////////////////////////////////////////////////////////////////////////////// static u16 FASTCALL SH2MemoryBreakpointReadWord(SH2_struct *sh, u32 addr) { int i; for (i = 0; i < sh->bp.nummemorybreakpoints; i++) { if (sh->bp.memorybreakpoint[i].addr == (addr & 0x0FFFFFFF)) { if (sh->bp.BreakpointCallBack && sh->bp.inbreakpoint == 0) { sh->bp.inbreakpoint = 1; sh->bp.BreakpointCallBack(sh, 0, sh->bp.BreakpointUserData); sh->bp.inbreakpoint = 0; } return sh->bp.memorybreakpoint[i].oldreadword(sh, addr); } } // Use the closest match if address doesn't match for (i = 0; i < sh->bp.nummemorybreakpoints; i++) { if (((sh->bp.memorybreakpoint[i].addr >> 16) & 0xFFF) == ((addr >> 16) & 0xFFF)) return sh->bp.memorybreakpoint[i].oldreadword(sh, addr); } return 0; } ////////////////////////////////////////////////////////////////////////////// static u32 FASTCALL SH2MemoryBreakpointReadLong(SH2_struct *sh, u32 addr) { int i; for (i = 0; i < sh->bp.nummemorybreakpoints; i++) { if (sh->bp.memorybreakpoint[i].addr == (addr & 0x0FFFFFFF)) { if (sh->bp.BreakpointCallBack && sh->bp.inbreakpoint == 0) { sh->bp.inbreakpoint = 1; sh->bp.BreakpointCallBack(sh, 0, sh->bp.BreakpointUserData); sh->bp.inbreakpoint = 0; } return sh->bp.memorybreakpoint[i].oldreadlong(sh, addr); } } // Use the closest match if address doesn't match for (i = 0; i < sh->bp.nummemorybreakpoints; i++) { if (((sh->bp.memorybreakpoint[i].addr >> 16) & 0xFFF) == ((addr >> 16) & 0xFFF)) return sh->bp.memorybreakpoint[i].oldreadlong(sh, addr); } return 0; } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL SH2MemoryBreakpointWriteByte(SH2_struct *sh, u32 addr, u8 val) { int i; for (i = 0; i < sh->bp.nummemorybreakpoints; i++) { if (sh->bp.memorybreakpoint[i].addr == (addr & 0x0FFFFFFF)) { if (sh->bp.BreakpointCallBack && sh->bp.inbreakpoint == 0) { sh->bp.inbreakpoint = 1; sh->bp.BreakpointCallBack(sh, 0, sh->bp.BreakpointUserData); sh->bp.inbreakpoint = 0; } sh->bp.memorybreakpoint[i].oldwritebyte(sh, addr, val); return; } } // Use the closest match if address doesn't match for (i = 0; i < sh->bp.nummemorybreakpoints; i++) { if (((sh->bp.memorybreakpoint[i].addr >> 16) & 0xFFF) == ((addr >> 16) & 0xFFF)) { sh->bp.memorybreakpoint[i].oldwritebyte(sh, addr, val); return; } } } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL SH2MemoryBreakpointWriteWord(SH2_struct *sh, u32 addr, u16 val) { int i; for (i = 0; i < sh->bp.nummemorybreakpoints; i++) { if (sh->bp.memorybreakpoint[i].addr == (addr & 0x0FFFFFFF)) { if (sh->bp.BreakpointCallBack && sh->bp.inbreakpoint == 0) { sh->bp.inbreakpoint = 1; sh->bp.BreakpointCallBack(sh, 0, sh->bp.BreakpointUserData); sh->bp.inbreakpoint = 0; } sh->bp.memorybreakpoint[i].oldwriteword(sh, addr, val); return; } } // Use the closest match if address doesn't match for (i = 0; i < sh->bp.nummemorybreakpoints; i++) { if (((sh->bp.memorybreakpoint[i].addr >> 16) & 0xFFF) == ((addr >> 16) & 0xFFF)) { sh->bp.memorybreakpoint[i].oldwriteword(sh, addr, val); return; } } } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL SH2MemoryBreakpointWriteLong(SH2_struct *sh, u32 addr, u32 val) { int i; for (i = 0; i < sh->bp.nummemorybreakpoints; i++) { if (sh->bp.memorybreakpoint[i].addr == (addr & 0x0FFFFFFF)) { if (sh->bp.BreakpointCallBack && sh->bp.inbreakpoint == 0) { sh->bp.inbreakpoint = 1; sh->bp.BreakpointCallBack(sh, 0, sh->bp.BreakpointUserData); sh->bp.inbreakpoint = 0; } sh->bp.memorybreakpoint[i].oldwritelong(sh, addr, val); return; } } // Use the closest match if address doesn't match for (i = 0; i < sh->bp.nummemorybreakpoints; i++) { if (((sh->bp.memorybreakpoint[i].addr >> 16) & 0xFFF) == ((addr >> 16) & 0xFFF)) { sh->bp.memorybreakpoint[i].oldwritelong(sh, addr, val); return; } } } ////////////////////////////////////////////////////////////////////////////// static int CheckForMemoryBreakpointDupes(SH2_struct *context, u32 addr, u32 flag, int *which) { int i; for (i = 0; i < context->bp.nummemorybreakpoints; i++) { if (((context->bp.memorybreakpoint[i].addr >> 16) & 0xFFF) == ((addr >> 16) & 0xFFF)) { // See it actually was using the same operation flag if (context->bp.memorybreakpoint[i].flags & flag) { *which = i; return 1; } } } return 0; } ////////////////////////////////////////////////////////////////////////////// int SH2AddMemoryBreakpoint(SH2_struct *context, u32 addr, u32 flags) { int which; int i; if (flags == 0) return -1; if (context->bp.nummemorybreakpoints < MAX_BREAKPOINTS) { // Only regular addresses are supported at this point(Sorry, no onchip!) switch (addr >> 29) { case 0x0: case 0x1: case 0x5: break; default: return -1; } addr &= 0x0FFFFFFF; // Make sure it isn't already on the list for (i = 0; i < context->bp.nummemorybreakpoints; i++) { if (addr == context->bp.memorybreakpoint[i].addr) return -1; } context->bp.memorybreakpoint[context->bp.nummemorybreakpoints].addr = addr; context->bp.memorybreakpoint[context->bp.nummemorybreakpoints].flags = flags; context->bp.memorybreakpoint[context->bp.nummemorybreakpoints].oldreadbyte = context->ReadByteList[(addr >> 16) & 0xFFF]; context->bp.memorybreakpoint[context->bp.nummemorybreakpoints].oldreadword = context->ReadWordList[(addr >> 16) & 0xFFF]; context->bp.memorybreakpoint[context->bp.nummemorybreakpoints].oldreadlong = context->ReadLongList[(addr >> 16) & 0xFFF]; context->bp.memorybreakpoint[context->bp.nummemorybreakpoints].oldwritebyte = context->WriteByteList[(addr >> 16) & 0xFFF]; context->bp.memorybreakpoint[context->bp.nummemorybreakpoints].oldwriteword = context->WriteWordList[(addr >> 16) & 0xFFF]; context->bp.memorybreakpoint[context->bp.nummemorybreakpoints].oldwritelong = context->WriteLongList[(addr >> 16) & 0xFFF]; if (flags & BREAK_BYTEREAD) { // Make sure function isn't already being breakpointed by another breakpoint if (!CheckForMemoryBreakpointDupes(context, addr, BREAK_BYTEREAD, &which)) context->ReadByteList[(addr >> 16) & 0xFFF] = &SH2MemoryBreakpointReadByte; else // fix old memory access function context->bp.memorybreakpoint[context->bp.nummemorybreakpoints].oldreadbyte = context->bp.memorybreakpoint[which].oldreadbyte; } if (flags & BREAK_WORDREAD) { // Make sure function isn't already being breakpointed by another breakpoint if (!CheckForMemoryBreakpointDupes(context, addr, BREAK_WORDREAD, &which)) context->ReadWordList[(addr >> 16) & 0xFFF] = &SH2MemoryBreakpointReadWord; else // fix old memory access function context->bp.memorybreakpoint[context->bp.nummemorybreakpoints].oldreadword = context->bp.memorybreakpoint[which].oldreadword; } if (flags & BREAK_LONGREAD) { // Make sure function isn't already being breakpointed by another breakpoint if (!CheckForMemoryBreakpointDupes(context, addr, BREAK_LONGREAD, &which)) context->ReadLongList[(addr >> 16) & 0xFFF] = &SH2MemoryBreakpointReadLong; else // fix old memory access function context->bp.memorybreakpoint[context->bp.nummemorybreakpoints].oldreadword = context->bp.memorybreakpoint[which].oldreadword; } if (flags & BREAK_BYTEWRITE) { // Make sure function isn't already being breakpointed by another breakpoint if (!CheckForMemoryBreakpointDupes(context, addr, BREAK_BYTEWRITE, &which)) context->WriteByteList[(addr >> 16) & 0xFFF] = &SH2MemoryBreakpointWriteByte; else // fix old memory access function context->bp.memorybreakpoint[context->bp.nummemorybreakpoints].oldwritebyte = context->bp.memorybreakpoint[which].oldwritebyte; } if (flags & BREAK_WORDWRITE) { // Make sure function isn't already being breakpointed by another breakpoint if (!CheckForMemoryBreakpointDupes(context, addr, BREAK_WORDWRITE, &which)) context->WriteWordList[(addr >> 16) & 0xFFF] = &SH2MemoryBreakpointWriteWord; else // fix old memory access function context->bp.memorybreakpoint[context->bp.nummemorybreakpoints].oldwriteword = context->bp.memorybreakpoint[which].oldwriteword; } if (flags & BREAK_LONGWRITE) { // Make sure function isn't already being breakpointed by another breakpoint if (!CheckForMemoryBreakpointDupes(context, addr, BREAK_LONGWRITE, &which)) context->WriteLongList[(addr >> 16) & 0xFFF] = &SH2MemoryBreakpointWriteLong; else // fix old memory access function context->bp.memorybreakpoint[context->bp.nummemorybreakpoints].oldwritelong = context->bp.memorybreakpoint[which].oldwritelong; } context->bp.nummemorybreakpoints++; return 0; } return -1; } ////////////////////////////////////////////////////////////////////////////// static void SH2SortMemoryBreakpoints(SH2_struct *context) { int i, i2; memorybreakpoint_struct tmp; for (i = 0; i < (MAX_BREAKPOINTS-1); i++) { for (i2 = i+1; i2 < MAX_BREAKPOINTS; i2++) { if (context->bp.memorybreakpoint[i].addr == 0xFFFFFFFF && context->bp.memorybreakpoint[i2].addr != 0xFFFFFFFF) { memcpy(&tmp, context->bp.memorybreakpoint+i, sizeof(memorybreakpoint_struct)); memcpy(context->bp.memorybreakpoint+i, context->bp.memorybreakpoint+i2, sizeof(memorybreakpoint_struct)); memcpy(context->bp.memorybreakpoint+i2, &tmp, sizeof(memorybreakpoint_struct)); } } } } ////////////////////////////////////////////////////////////////////////////// int SH2DelMemoryBreakpoint(SH2_struct *context, u32 addr) { int i, i2; if (context->bp.nummemorybreakpoints > 0) { for (i = 0; i < context->bp.nummemorybreakpoints; i++) { if (context->bp.memorybreakpoint[i].addr == addr) { // Remove memory access piggyback function to memory access function table // Make sure no other breakpoints need the breakpoint functions first for (i2 = 0; i2 < context->bp.nummemorybreakpoints; i2++) { if (((context->bp.memorybreakpoint[i].addr >> 16) & 0xFFF) == ((context->bp.memorybreakpoint[i2].addr >> 16) & 0xFFF) && i != i2) { // Clear the flags context->bp.memorybreakpoint[i].flags &= ~context->bp.memorybreakpoint[i2].flags; } } if (context->bp.memorybreakpoint[i].flags & BREAK_BYTEREAD) context->ReadByteList[(addr >> 16) & 0xFFF] = context->bp.memorybreakpoint[i].oldreadbyte; if (context->bp.memorybreakpoint[i].flags & BREAK_WORDREAD) context->ReadWordList[(addr >> 16) & 0xFFF] = context->bp.memorybreakpoint[i].oldreadword; if (context->bp.memorybreakpoint[i].flags & BREAK_LONGREAD) context->ReadLongList[(addr >> 16) & 0xFFF] = context->bp.memorybreakpoint[i].oldreadlong; if (context->bp.memorybreakpoint[i].flags & BREAK_BYTEWRITE) context->WriteByteList[(addr >> 16) & 0xFFF] = context->bp.memorybreakpoint[i].oldwritebyte; if (context->bp.memorybreakpoint[i].flags & BREAK_WORDWRITE) context->WriteWordList[(addr >> 16) & 0xFFF] = context->bp.memorybreakpoint[i].oldwriteword; if (context->bp.memorybreakpoint[i].flags & BREAK_LONGWRITE) context->WriteLongList[(addr >> 16) & 0xFFF] = context->bp.memorybreakpoint[i].oldwritelong; context->bp.memorybreakpoint[i].addr = 0xFFFFFFFF; SH2SortMemoryBreakpoints(context); context->bp.nummemorybreakpoints--; return 0; } } } return -1; } ////////////////////////////////////////////////////////////////////////////// memorybreakpoint_struct *SH2GetMemoryBreakpointList(SH2_struct *context) { return context->bp.memorybreakpoint; } ////////////////////////////////////////////////////////////////////////////// void SH2ClearMemoryBreakpoints(SH2_struct *context) { int i; for (i = 0; i < MAX_BREAKPOINTS; i++) { context->bp.memorybreakpoint[i].addr = 0xFFFFFFFF; context->bp.memorybreakpoint[i].flags = 0; context->bp.memorybreakpoint[i].oldreadbyte = NULL; context->bp.memorybreakpoint[i].oldreadword = NULL; context->bp.memorybreakpoint[i].oldreadlong = NULL; context->bp.memorybreakpoint[i].oldwritebyte = NULL; context->bp.memorybreakpoint[i].oldwriteword = NULL; context->bp.memorybreakpoint[i].oldwritelong = NULL; } context->bp.nummemorybreakpoints = 0; } ////////////////////////////////////////////////////////////////////////////// void SH2HandleBackTrace(SH2_struct *context) { u16 inst = context->instruction; if ((inst & 0xF000) == 0xB000 || // BSR (inst & 0xF0FF) == 0x0003 || // BSRF (inst & 0xF0FF) == 0x400B) // JSR { if (context->bt.numbacktrace < sizeof(context->bt.addr)/sizeof(u32)) { context->bt.addr[context->bt.numbacktrace] = context->regs.PC; context->bt.numbacktrace++; } } else if (inst == 0x000B) // RTS { if (context->bt.numbacktrace > 0) context->bt.numbacktrace--; } } ////////////////////////////////////////////////////////////////////////////// u32 *SH2GetBacktraceList(SH2_struct *context, int *size) { *size = context->bt.numbacktrace; return context->bt.addr; } ////////////////////////////////////////////////////////////////////////////// void SH2HandleStepOverOut(SH2_struct *context) { if (context->stepOverOut.enabled) { switch ((int)context->stepOverOut.type) { case SH2ST_STEPOVER: // Step Over if (context->regs.PC == context->stepOverOut.address) { context->stepOverOut.enabled = 0; context->stepOverOut.callBack(context, context->regs.PC, (void *)context->stepOverOut.type); } break; case SH2ST_STEPOUT: // Step Out { u16 inst; if (context->stepOverOut.levels < 0 && context->regs.PC == context->regs.PR) { context->stepOverOut.enabled = 0; context->stepOverOut.callBack(context, context->regs.PC, (void *)context->stepOverOut.type); return; } inst = context->instruction;; if ((inst & 0xF000) == 0xB000 || // BSR (inst & 0xF0FF) == 0x0003 || // BSRF (inst & 0xF0FF) == 0x400B) // JSR context->stepOverOut.levels++; else if (inst == 0x000B || // RTS inst == 0x002B) // RTE context->stepOverOut.levels--; break; } default: break; } } } ////////////////////////////////////////////////////////////////////////////// void SH2HandleTrackInfLoop(SH2_struct *context) { if (context->trackInfLoop.enabled) { // Look for specific bf/bt/bra instructions that branch to address < PC if ((context->instruction & 0x8B80) == 0x8B80 || // bf (context->instruction & 0x8F80) == 0x8F80 || // bf/s (context->instruction & 0x8980) == 0x8980 || // bt (context->instruction & 0x8D80) == 0x8D80 || // bt/s (context->instruction & 0xA800) == 0xA800) // bra { int i; // See if it's already on match list for (i = 0; i < context->trackInfLoop.num; i++) { if (context->regs.PC == context->trackInfLoop.match[i].addr) { context->trackInfLoop.match[i].count++; return; } } if (context->trackInfLoop.num >= context->trackInfLoop.maxNum) { context->trackInfLoop.match = realloc(context->trackInfLoop.match, sizeof(tilInfo_struct) * (context->trackInfLoop.maxNum * 2)); context->trackInfLoop.maxNum *= 2; } // Add new i=context->trackInfLoop.num; context->trackInfLoop.match[i].addr = context->regs.PC; context->trackInfLoop.match[i].count = 1; context->trackInfLoop.num++; } } } ////////////////////////////////////////////////////////////////////////////// // Onchip specific ////////////////////////////////////////////////////////////////////////////// void OnchipReset(SH2_struct *context) { context->onchip.SMR = 0x00; context->onchip.BRR = 0xFF; context->onchip.SCR = 0x00; context->onchip.TDR = 0xFF; context->onchip.SSR = 0x84; context->onchip.RDR = 0x00; context->onchip.TIER = 0x01; context->onchip.FTCSR = 0x00; context->onchip.FRC.all = 0x0000; context->onchip.OCRA = 0xFFFF; context->onchip.OCRB = 0xFFFF; context->onchip.TCR = 0x00; context->onchip.TOCR = 0xE0; context->onchip.FICR = 0x0000; context->onchip.IPRB = 0x0000; context->onchip.VCRA = 0x0000; context->onchip.VCRB = 0x0000; context->onchip.VCRC = 0x0000; context->onchip.VCRD = 0x0000; context->onchip.DRCR0 = 0x00; context->onchip.DRCR1 = 0x00; context->onchip.WTCSR = 0x18; context->onchip.WTCNT = 0x00; context->onchip.RSTCSR = 0x1F; context->onchip.SBYCR = 0x60; context->onchip.CCR = 0x00; context->onchip.ICR = 0x0000; context->onchip.IPRA = 0x0000; context->onchip.VCRWDT = 0x0000; context->onchip.DVCR = 0x00000000; context->onchip.VCRDIV = 0x00000000; context->onchip.BARA.all = 0x00000000; context->onchip.BAMRA.all = 0x00000000; context->onchip.BBRA = 0x0000; context->onchip.BARB.all = 0x00000000; context->onchip.BAMRB.all = 0x00000000; context->onchip.BDRB.all = 0x00000000; context->onchip.BDMRB.all = 0x00000000; context->onchip.BBRB = 0x0000; context->onchip.BRCR = 0x0000; context->onchip.CHCR0 = 0x00000000; context->onchip.CHCR1 = 0x00000000; context->onchip.DMAOR = 0x00000000; context->onchip.BCR1 &= 0x8000; // preserve MASTER bit context->onchip.BCR1 |= 0x03F0; context->onchip.BCR2 = 0x00FC; context->onchip.WCR = 0xAAFF; context->onchip.MCR = 0x0000; context->onchip.RTCSR = 0x0000; context->onchip.RTCNT = 0x0000; context->onchip.RTCOR = 0x0000; } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL OnchipReadByte(SH2_struct *sh, u32 addr) { switch(addr) { case 0x000: // LOG("Serial Mode Register read: %02X\n", sh->onchip.SMR); return sh->onchip.SMR; case 0x001: // LOG("Bit Rate Register read: %02X\n", sh->onchip.BRR); return sh->onchip.BRR; case 0x002: // LOG("Serial Control Register read: %02X\n", sh->onchip.SCR); return sh->onchip.SCR; case 0x003: // LOG("Transmit Data Register read: %02X\n", sh->onchip.TDR); return sh->onchip.TDR; case 0x004: // LOG("Serial Status Register read: %02X\n", sh->onchip.SSR); /* // if Receiver is enabled, clear SSR's TDRE bit, set SSR's RDRF and update RDR. if (sh->onchip.SCR & 0x10) { sh->onchip.RDR = SCIReceiveByte(); sh->onchip.SSR = (sh->onchip.SSR & 0x7F) | 0x40; } // if Transmitter is enabled, clear SSR's RDRF bit, and set SSR's TDRE bit. else if (sh->onchip.SCR & 0x20) { sh->onchip.SSR = (sh->onchip.SSR & 0xBF) | 0x80; } */ return sh->onchip.SSR; case 0x005: // LOG("Receive Data Register read: %02X PC = %08X\n", sh->onchip.RDR, SH2Core->GetPC(sh)); return sh->onchip.RDR; case 0x010: return sh->onchip.TIER; case 0x011: return sh->onchip.FTCSR; case 0x012: return sh->onchip.FRC.part.H; case 0x013: return sh->onchip.FRC.part.L; case 0x014: if (!(sh->onchip.TOCR & 0x10)) return sh->onchip.OCRA >> 8; else return sh->onchip.OCRB >> 8; case 0x015: if (!(sh->onchip.TOCR & 0x10)) return sh->onchip.OCRA & 0xFF; else return sh->onchip.OCRB & 0xFF; case 0x016: return sh->onchip.TCR; case 0x017: return sh->onchip.TOCR; case 0x018: return sh->onchip.FICR >> 8; case 0x019: return sh->onchip.FICR & 0xFF; case 0x060: return sh->onchip.IPRB >> 8; case 0x062: return sh->onchip.VCRA >> 8; case 0x063: return sh->onchip.VCRA & 0xFF; case 0x064: return sh->onchip.VCRB >> 8; case 0x065: return sh->onchip.VCRB & 0xFF; case 0x066: return sh->onchip.VCRC >> 8; case 0x067: return sh->onchip.VCRC & 0xFF; case 0x068: return sh->onchip.VCRD >> 8; case 0x080: return sh->onchip.WTCSR; case 0x081: return sh->onchip.WTCNT; case 0x092: return sh->onchip.CCR; case 0x0E0: return sh->onchip.ICR >> 8; case 0x0E1: return sh->onchip.ICR & 0xFF; case 0x0E2: return sh->onchip.IPRA >> 8; case 0x0E3: return sh->onchip.IPRA & 0xFF; case 0x0E4: return sh->onchip.VCRWDT >> 8; case 0x0E5: return sh->onchip.VCRWDT & 0xFF; default: LOG("Unhandled Onchip byte read %08X\n", (int)addr); break; } return 0; } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL OnchipReadWord(SH2_struct *sh, u32 addr) { switch(addr) { case 0x060: return sh->onchip.IPRB; case 0x062: return sh->onchip.VCRA; case 0x064: return sh->onchip.VCRB; case 0x066: return sh->onchip.VCRC; case 0x068: return sh->onchip.VCRD; case 0x0E0: return sh->onchip.ICR; case 0x0E2: return sh->onchip.IPRA; case 0x0E4: return sh->onchip.VCRWDT; case 0x1E2: // real BCR1 register is located at 0x1E2-0x1E3; Sega Rally OK return sh->onchip.BCR1; case 0x1E6: return sh->onchip.BCR2; case 0x1EA: return sh->onchip.WCR; case 0x1EE: return sh->onchip.MCR; case 0x1F2: return sh->onchip.RTCSR; case 0x1F6: return sh->onchip.RTCNT; case 0x1FA: return sh->onchip.RTCOR; default: LOG("Unhandled Onchip word read %08X\n", (int)addr); return 0; } return 0; } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL OnchipReadLong(SH2_struct *sh, u32 addr) { switch(addr) { case 0x100: case 0x120: return sh->onchip.DVSR; case 0x104: // DVDNT case 0x124: return sh->onchip.DVDNTL; case 0x108: case 0x128: return sh->onchip.DVCR; case 0x10C: case 0x12C: return sh->onchip.VCRDIV; case 0x110: case 0x130: return sh->onchip.DVDNTH; case 0x114: case 0x134: return sh->onchip.DVDNTL; case 0x118: // Acts as a separate register, but is set to the same value case 0x138: // as DVDNTH after division return sh->onchip.DVDNTUH; case 0x11C: // Acts as a separate register, but is set to the same value case 0x13C: // as DVDNTL after division return sh->onchip.DVDNTUL; case 0x180: return sh->onchip.SAR0; case 0x184: return sh->onchip.DAR0; case 0x188: return sh->onchip.TCR0; case 0x18C: return sh->onchip.CHCR0; case 0x190: return sh->onchip.SAR1; case 0x194: return sh->onchip.DAR1; case 0x198: return sh->onchip.TCR1; case 0x19C: return sh->onchip.CHCR1; case 0x1A0: return sh->onchip.VCRDMA0; case 0x1A8: return sh->onchip.VCRDMA1; case 0x1B0: return sh->onchip.DMAOR; case 0x1E0: return sh->onchip.BCR1; case 0x1E4: return sh->onchip.BCR2; case 0x1E8: return sh->onchip.WCR; case 0x1EC: return sh->onchip.MCR; case 0x1F0: return sh->onchip.RTCSR; case 0x1F4: return sh->onchip.RTCNT; case 0x1F8: return sh->onchip.RTCOR; default: LOG("Unhandled Onchip long read %08X\n", (int)addr); return 0; } return 0; } ////////////////////////////////////////////////////////////////////////////// void FASTCALL OnchipWriteByte(SH2_struct *sh, u32 addr, u8 val) { switch(addr) { case 0x000: // LOG("Serial Mode Register write: %02X\n", val); sh->onchip.SMR = val; return; case 0x001: // LOG("Bit Rate Register write: %02X\n", val); sh->onchip.BRR = val; return; case 0x002: // LOG("Serial Control Register write: %02X\n", val); // If Transmitter is getting disabled, set TDRE if (!(val & 0x20)) sh->onchip.SSR |= 0x80; sh->onchip.SCR = val; return; case 0x003: // LOG("Transmit Data Register write: %02X. PC = %08X\n", val, SH2Core->GetPC(sh)); sh->onchip.TDR = val; return; case 0x004: // LOG("Serial Status Register write: %02X\n", val); if (sh->onchip.SCR & 0x20) { // Transmitter Mode // If the TDRE bit cleared, let's do a transfer if (!(val & 0x80)) SCITransmitByte(sh->onchip.TDR); // Generate an interrupt if need be here } return; case 0x010: sh->onchip.TIER = (val & 0x8E) | 0x1; return; case 0x011: sh->onchip.FTCSR = (sh->onchip.FTCSR & (val & 0xFE)) | (val & 0x1); return; case 0x012: sh->onchip.FRC.part.H = val; return; case 0x013: sh->onchip.FRC.part.L = val; return; case 0x014: if (!(sh->onchip.TOCR & 0x10)) sh->onchip.OCRA = (val << 8) | (sh->onchip.OCRA & 0xFF); else sh->onchip.OCRB = (val << 8) | (sh->onchip.OCRB & 0xFF); return; case 0x015: if (!(sh->onchip.TOCR & 0x10)) sh->onchip.OCRA = (sh->onchip.OCRA & 0xFF00) | val; else sh->onchip.OCRB = (sh->onchip.OCRB & 0xFF00) | val; return; case 0x016: sh->onchip.TCR = val & 0x83; switch (val & 3) { case 0: sh->frc.shift = 3; break; case 1: sh->frc.shift = 5; break; case 2: sh->frc.shift = 7; break; case 3: LOG("FRT external input clock not implemented.\n"); break; } return; case 0x017: sh->onchip.TOCR = 0xE0 | (val & 0x13); return; case 0x060: sh->onchip.IPRB = (val << 8); return; case 0x061: return; case 0x062: sh->onchip.VCRA = ((val & 0x7F) << 8) | (sh->onchip.VCRA & 0x00FF); return; case 0x063: sh->onchip.VCRA = (sh->onchip.VCRA & 0xFF00) | (val & 0x7F); return; case 0x064: sh->onchip.VCRB = ((val & 0x7F) << 8) | (sh->onchip.VCRB & 0x00FF); return; case 0x065: sh->onchip.VCRB = (sh->onchip.VCRB & 0xFF00) | (val & 0x7F); return; case 0x066: sh->onchip.VCRC = ((val & 0x7F) << 8) | (sh->onchip.VCRC & 0x00FF); return; case 0x067: sh->onchip.VCRC = (sh->onchip.VCRC & 0xFF00) | (val & 0x7F); return; case 0x068: sh->onchip.VCRD = (val & 0x7F) << 8; return; case 0x069: return; case 0x071: sh->onchip.DRCR0 = val & 0x3; return; case 0x072: sh->onchip.DRCR1 = val & 0x3; return; case 0x091: sh->onchip.SBYCR = val & 0xDF; return; case 0x092: sh->onchip.CCR = val & 0xCF; if (val & 0x10){ cache_clear(&sh->onchip.cache); } if ( (sh->onchip.CCR & 0x01) ){ cache_enable(&sh->onchip.cache); } else{ cache_disable(&sh->onchip.cache); } return; case 0x0E0: sh->onchip.ICR = ((val & 0x1) << 8) | (sh->onchip.ICR & 0xFEFF); return; case 0x0E1: sh->onchip.ICR = (sh->onchip.ICR & 0xFFFE) | (val & 0x1); return; case 0x0E2: sh->onchip.IPRA = (val << 8) | (sh->onchip.IPRA & 0x00FF); return; case 0x0E3: sh->onchip.IPRA = (sh->onchip.IPRA & 0xFF00) | (val & 0xF0); return; case 0x0E4: sh->onchip.VCRWDT = ((val & 0x7F) << 8) | (sh->onchip.VCRWDT & 0x00FF); return; case 0x0E5: sh->onchip.VCRWDT = (sh->onchip.VCRWDT & 0xFF00) | (val & 0x7F); return; default: LOG("Unhandled Onchip byte write %08X\n", (int)addr); } } ////////////////////////////////////////////////////////////////////////////// void FASTCALL OnchipWriteWord(SH2_struct *sh, u32 addr, u16 val) { switch(addr) { case 0x060: sh->onchip.IPRB = val & 0xFF00; return; case 0x062: sh->onchip.VCRA = val & 0x7F7F; return; case 0x064: sh->onchip.VCRB = val & 0x7F7F; return; case 0x066: sh->onchip.VCRC = val & 0x7F7F; return; case 0x068: sh->onchip.VCRD = val & 0x7F7F; return; case 0x080: // This and RSTCSR have got to be the most wackiest register // mappings I've ever seen if (val >> 8 == 0xA5) { // WTCSR switch (val & 7) { case 0: sh->wdt.shift = 1; break; case 1: sh->wdt.shift = 6; break; case 2: sh->wdt.shift = 7; break; case 3: sh->wdt.shift = 8; break; case 4: sh->wdt.shift = 9; break; case 5: sh->wdt.shift = 10; break; case 6: sh->wdt.shift = 12; break; case 7: sh->wdt.shift = 13; break; } sh->wdt.isenable = (val & 0x20); sh->wdt.isinterval = (~val & 0x40); sh->onchip.WTCSR = (u8)val | 0x18; } else if (val >> 8 == 0x5A) { // WTCNT sh->onchip.WTCNT = (u8)val; } return; case 0x082: if (val == 0xA500) // clear WOVF bit sh->onchip.RSTCSR &= 0x7F; else if (val >> 8 == 0x5A) // RSTE and RSTS bits sh->onchip.RSTCSR = (sh->onchip.RSTCSR & 0x80) | (val & 0x60) | 0x1F; return; case 0x092: sh->onchip.CCR = val & 0xCF; if (val&0x10){ cache_clear( &sh->onchip.cache ); } if ((sh->onchip.CCR & 0x01)){ cache_enable(&sh->onchip.cache); } else{ cache_disable(&sh->onchip.cache); } return; case 0x0E0: sh->onchip.ICR = val & 0x0101; return; case 0x0E2: sh->onchip.IPRA = val & 0xFFF0; return; case 0x0E4: sh->onchip.VCRWDT = val & 0x7F7F; return; case 0x108: case 0x128: sh->onchip.DVCR = val & 0x3; return; case 0x148: sh->onchip.BBRA = val & 0xFF; return; case 0x178: sh->onchip.BRCR = val & 0xF4DC; return; default: LOG("Unhandled Onchip word write %08X(%04X)\n", (int)addr, val); return; } } ////////////////////////////////////////////////////////////////////////////// void FASTCALL OnchipWriteLong(SH2_struct *sh, u32 addr, u32 val) { switch (addr) { case 0x100: case 0x120: sh->onchip.DVSR = val; return; case 0x104: // 32-bit / 32-bit divide operation case 0x124: { s32 divisor = (s32) sh->onchip.DVSR; if (divisor == 0) { // Regardless of what DVDNTL is set to, the top 3 bits // are used to create the new DVDNTH value if (val & 0x80000000) { sh->onchip.DVDNTL = 0x80000000; sh->onchip.DVDNTH = 0xFFFFFFFC | ((val >> 29) & 0x3); } else { sh->onchip.DVDNTL = 0x7FFFFFFF; sh->onchip.DVDNTH = 0 | (val >> 29); } sh->onchip.DVDNTUL = sh->onchip.DVDNTL; sh->onchip.DVDNTUH = sh->onchip.DVDNTH; sh->onchip.DVCR |= 1; if (sh->onchip.DVCR & 0x2) SH2SendInterrupt(sh, sh->onchip.VCRDIV & 0x7F, (MSH2->onchip.IPRA >> 12) & 0xF); } else { s32 quotient = ((s32) val) / divisor; s32 remainder = ((s32) val) % divisor; sh->onchip.DVDNTL = quotient; sh->onchip.DVDNTUL = quotient; sh->onchip.DVDNTH = remainder; sh->onchip.DVDNTUH = remainder; } return; } case 0x108: case 0x128: sh->onchip.DVCR = val & 0x3; return; case 0x10C: case 0x12C: sh->onchip.VCRDIV = val & 0xFFFF; return; case 0x110: case 0x130: sh->onchip.DVDNTH = val; return; case 0x114: case 0x134: { // 64-bit / 32-bit divide operation s32 divisor = (s32) sh->onchip.DVSR; s64 dividend = sh->onchip.DVDNTH; dividend <<= 32; dividend |= val; if (divisor == 0) { if (sh->onchip.DVDNTH & 0x80000000) { sh->onchip.DVDNTL = 0x80000000; sh->onchip.DVDNTH = sh->onchip.DVDNTH << 3; // fix me } else { sh->onchip.DVDNTL = 0x7FFFFFFF; sh->onchip.DVDNTH = sh->onchip.DVDNTH << 3; // fix me } sh->onchip.DVDNTUL = sh->onchip.DVDNTL; sh->onchip.DVDNTUH = sh->onchip.DVDNTH; sh->onchip.DVCR |= 1; if (sh->onchip.DVCR & 0x2) SH2SendInterrupt(sh, sh->onchip.VCRDIV & 0x7F, (MSH2->onchip.IPRA >> 12) & 0xF); } else { s64 quotient = dividend / divisor; s32 remainder = dividend % divisor; if (quotient > 0x7FFFFFFF) { sh->onchip.DVCR |= 1; sh->onchip.DVDNTL = 0x7FFFFFFF; sh->onchip.DVDNTH = 0xFFFFFFFE; // fix me if (sh->onchip.DVCR & 0x2) SH2SendInterrupt(sh, sh->onchip.VCRDIV & 0x7F, (MSH2->onchip.IPRA >> 12) & 0xF); } else if ((s32)(quotient >> 32) < -1) { sh->onchip.DVCR |= 1; sh->onchip.DVDNTL = 0x80000000; sh->onchip.DVDNTH = 0xFFFFFFFE; // fix me if (sh->onchip.DVCR & 0x2) SH2SendInterrupt(sh, sh->onchip.VCRDIV & 0x7F, (MSH2->onchip.IPRA >> 12) & 0xF); } else { sh->onchip.DVDNTL = quotient; sh->onchip.DVDNTH = remainder; } sh->onchip.DVDNTUL = sh->onchip.DVDNTL; sh->onchip.DVDNTUH = sh->onchip.DVDNTH; } return; } case 0x118: case 0x138: sh->onchip.DVDNTUH = val; return; case 0x11C: case 0x13C: sh->onchip.DVDNTUL = val; return; case 0x140: sh->onchip.BARA.all = val; return; case 0x144: sh->onchip.BAMRA.all = val; return; case 0x180: sh->onchip.SAR0 = val; return; case 0x184: sh->onchip.DAR0 = val; return; case 0x188: sh->onchip.TCR0 = val & 0xFFFFFF; return; case 0x18C: sh->onchip.CHCR0 = val & 0xFFFF; // If the DMAOR DME bit is set and AE and NMIF bits are cleared, // and CHCR's DE bit is set and TE bit is cleared, // do a dma transfer if ((sh->onchip.DMAOR & 7) == 1 && (val & 0x3) == 1) { if(yabsys.use_sh2_dma_timing) sh->onchip.dma0_active = 1; else DMAExec(sh); } return; case 0x190: sh->onchip.SAR1 = val; return; case 0x194: sh->onchip.DAR1 = val; return; case 0x198: sh->onchip.TCR1 = val & 0xFFFFFF; return; case 0x19C: sh->onchip.CHCR1 = val & 0xFFFF; // If the DMAOR DME bit is set and AE and NMIF bits are cleared, // and CHCR's DE bit is set and TE bit is cleared, // do a dma transfer if ((sh->onchip.DMAOR & 7) == 1 && (val & 0x3) == 1) { if(yabsys.use_sh2_dma_timing) sh->onchip.dma1_active = 1; else DMAExec(sh); } return; case 0x1A0: sh->onchip.VCRDMA0 = val & 0xFFFF; return; case 0x1A8: sh->onchip.VCRDMA1 = val & 0xFFFF; return; case 0x1B0: sh->onchip.DMAOR = val & 0xF; // If the DMAOR DME bit is set and AE and NMIF bits are cleared, // and CHCR's DE bit is set and TE bit is cleared, // do a dma transfer if ((val & 7) == 1) { if(yabsys.use_sh2_dma_timing) { if((sh->onchip.CHCR0 & 0x3) == 1) sh->onchip.dma0_active = 1; if ((sh->onchip.CHCR1 & 0x3) == 1) sh->onchip.dma1_active = 1; } else { DMAExec(sh); } } return; case 0x1E0: sh->onchip.BCR1 &= 0x8000; sh->onchip.BCR1 |= val & 0x1FF7; return; case 0x1E4: sh->onchip.BCR2 = val & 0xFC; return; case 0x1E8: sh->onchip.WCR = val; return; case 0x1EC: sh->onchip.MCR = val & 0xFEFC; return; case 0x1F0: sh->onchip.RTCSR = val & 0xF8; return; case 0x1F8: sh->onchip.RTCOR = val & 0xFF; return; default: LOG("Unhandled Onchip long write %08X\n", (int)addr); break; } } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL AddressArrayReadLong(SH2_struct *sh, u32 addr) { if (yabsys.sh2_cache_enabled) { int way = (sh->onchip.CCR >> 6) & 3; int entry = (addr & 0x3FC) >> 4; u32 data = sh->onchip.cache.way[way][entry].tag; data |= sh->onchip.cache.lru[entry] << 4; data |= sh->onchip.cache.way[way][entry].v << 2; return data; } else return sh->AddressArray[(addr & 0x3FC) >> 2]; } ////////////////////////////////////////////////////////////////////////////// void FASTCALL AddressArrayWriteLong(SH2_struct *sh, u32 addr, u32 val) { if (yabsys.sh2_cache_enabled) { int way = (sh->onchip.CCR >> 6) & 3; int entry = (addr & 0x3FC) >> 4; sh->onchip.cache.way[way][entry].tag = addr & 0x1FFFFC00; sh->onchip.cache.way[way][entry].v = (addr >> 2) & 1; sh->onchip.cache.lru[entry] = (val >> 4) & 0x3f; } else sh->AddressArray[(addr & 0x3FC) >> 2] = val; } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL DataArrayReadByte(SH2_struct *sh, u32 addr) { if (yabsys.sh2_cache_enabled) { int way = (addr >> 10) & 3; int entry = (addr >> 4) & 0x3f; return sh->onchip.cache.way[way][entry].data[addr & 0xf]; } else return T2ReadByte(sh->DataArray, addr & 0xFFF); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL DataArrayReadWord(SH2_struct *sh, u32 addr) { if (yabsys.sh2_cache_enabled) { int way = (addr >> 10) & 3; int entry = (addr >> 4) & 0x3f; return ((u16)(sh->onchip.cache.way[way][entry].data[addr & 0xf]) << 8) | sh->onchip.cache.way[way][entry].data[(addr & 0xf) + 1]; } else return T2ReadWord(sh->DataArray, addr & 0xFFF); } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL DataArrayReadLong(SH2_struct *sh, u32 addr) { if (yabsys.sh2_cache_enabled) { int way = (addr >> 10) & 3; int entry = (addr >> 4) & 0x3f; u32 data = ((u32)(sh->onchip.cache.way[way][entry].data[addr & 0xf]) << 24) | ((u32)(sh->onchip.cache.way[way][entry].data[(addr & 0xf) + 1]) << 16) | ((u32)(sh->onchip.cache.way[way][entry].data[(addr & 0xf) + 2]) << 8) | ((u32)(sh->onchip.cache.way[way][entry].data[(addr & 0xf) + 3]) << 0); return data; } else return T2ReadLong(sh->DataArray, addr & 0xFFF); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL DataArrayWriteByte(SH2_struct *sh, u32 addr, u8 val) { if (yabsys.sh2_cache_enabled) { int way = (addr >> 10) & 3; int entry = (addr >> 4) & 0x3f; sh->onchip.cache.way[way][entry].data[addr & 0xf] = val; } else T2WriteByte(sh->DataArray, addr & 0xFFF, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL DataArrayWriteWord(SH2_struct *sh, u32 addr, u16 val) { if (yabsys.sh2_cache_enabled) { int way = (addr >> 10) & 3; int entry = (addr >> 4) & 0x3f; sh->onchip.cache.way[way][entry].data[addr & 0xf] = val >> 8; sh->onchip.cache.way[way][entry].data[(addr & 0xf) + 1] = val; } else T2WriteWord(sh->DataArray, addr & 0xFFF, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL DataArrayWriteLong(SH2_struct *sh, u32 addr, u32 val) { if (yabsys.sh2_cache_enabled) { int way = (addr >> 10) & 3; int entry = (addr >> 4) & 0x3f; sh->onchip.cache.way[way][entry].data[(addr & 0xf)] = ((val >> 24) & 0xFF); sh->onchip.cache.way[way][entry].data[(addr & 0xf) + 1] = ((val >> 16) & 0xFF); sh->onchip.cache.way[way][entry].data[(addr & 0xf) + 2] = ((val >> 8) & 0xFF); sh->onchip.cache.way[way][entry].data[(addr & 0xf) + 3] = ((val >> 0) & 0xFF); } else T2WriteLong(sh->DataArray, addr & 0xFFF, val); } ////////////////////////////////////////////////////////////////////////////// void FRTExec(SH2_struct *sh, u32 cycles) { u32 frcold; u32 frctemp; u32 mask; frcold = frctemp = (u32)sh->onchip.FRC.all; mask = (1 << sh->frc.shift) - 1; // Increment FRC frctemp += ((cycles + sh->frc.leftover) >> sh->frc.shift); sh->frc.leftover = (cycles + sh->frc.leftover) & mask; // Check to see if there is or was a Output Compare A match if (frctemp >= sh->onchip.OCRA && frcold < sh->onchip.OCRA) { // Do we need to trigger an interrupt? if (sh->onchip.TIER & 0x8) SH2SendInterrupt(sh, sh->onchip.VCRC & 0x7F, (sh->onchip.IPRB & 0xF00) >> 8); // Do we need to clear the FRC? if (sh->onchip.FTCSR & 0x1) { frctemp = 0; sh->frc.leftover = 0; } // Set OCFA flag sh->onchip.FTCSR |= 0x8; } // Check to see if there is or was a Output Compare B match if (frctemp >= sh->onchip.OCRB && frcold < sh->onchip.OCRB) { // Do we need to trigger an interrupt? if (sh->onchip.TIER & 0x4) SH2SendInterrupt(sh, sh->onchip.VCRC & 0x7F, (sh->onchip.IPRB & 0xF00) >> 8); // Set OCFB flag sh->onchip.FTCSR |= 0x4; } // If FRC overflows, set overflow flag if (frctemp > 0xFFFF) { // Do we need to trigger an interrupt? if (sh->onchip.TIER & 0x2) SH2SendInterrupt(sh, (sh->onchip.VCRD >> 8) & 0x7F, (sh->onchip.IPRB & 0xF00) >> 8); sh->onchip.FTCSR |= 2; } // Write new FRC value sh->onchip.FRC.all = frctemp; } ////////////////////////////////////////////////////////////////////////////// void WDTExec(SH2_struct *sh, u32 cycles) { u32 wdttemp; u32 mask; if (!sh->wdt.isenable || sh->onchip.WTCSR & 0x80 || sh->onchip.RSTCSR & 0x80) return; wdttemp = (u32)sh->onchip.WTCNT; mask = (1 << sh->wdt.shift) - 1; wdttemp += ((cycles + sh->wdt.leftover) >> sh->wdt.shift); sh->wdt.leftover = (cycles + sh->wdt.leftover) & mask; // Are we overflowing? if (wdttemp > 0xFF) { // Obviously depending on whether or not we're in Watchdog or Interval // Modes, they'll handle an overflow differently. if (sh->wdt.isinterval) { // Interval Timer Mode // Set OVF flag sh->onchip.WTCSR |= 0x80; // Trigger interrupt SH2SendInterrupt(sh, (sh->onchip.VCRWDT >> 8) & 0x7F, (sh->onchip.IPRA >> 4) & 0xF); } else { // Watchdog Timer Mode(untested) LOG("Watchdog timer(WDT mode) overflow not implemented\n"); } } // Write new WTCNT value sh->onchip.WTCNT = (u8)wdttemp; } ////////////////////////////////////////////////////////////////////////////// u32 sh2_dma_access(u32 addr, u32 data, int is_read, int size) { addr &= 0xfffffff; if (addr <= 0x00fffff) { //bios if (is_read) { if (size == 0) return BiosRomMemoryReadByte(addr); else if (size == 1) return BiosRomMemoryReadWord(addr); else return BiosRomMemoryReadLong(addr); } else { if (size == 0) BiosRomMemoryWriteByte(addr, data); else if (size == 1) BiosRomMemoryWriteWord(addr, data); else BiosRomMemoryWriteLong(addr, data); return 0; } } else if (addr >= 0x0100000 && addr <= 0x017ffff) { //smpc if (is_read) { if (size == 0) return SmpcReadByte(MSH2, addr); else if (size == 1) return SmpcReadWord(MSH2, addr); else return SmpcReadLong(MSH2, addr); } else { if (size == 0) SmpcWriteByte(MSH2, addr, data); else if (size == 1) SmpcWriteWord(MSH2, addr, data); else SmpcWriteLong(MSH2, addr, data); return 0; } } else if (addr >= 0x0180000 && addr <= 0x01fffff) { //backup ram if (is_read) { if (size == 0) return BupRamMemoryReadByte(addr); else if (size == 1) return BupRamMemoryReadWord(addr); else return BupRamMemoryReadLong(addr); } else { if (size == 0) BupRamMemoryWriteByte(addr, data); else if (size == 1) BupRamMemoryWriteWord(addr, data); else BupRamMemoryWriteLong(addr, data); return 0; } } else if (addr >= 0x0200000 && addr <= 0x02fffff) { //low wram if (is_read) { if (size == 0) return LowWramMemoryReadByte(addr); else if (size == 1) return LowWramMemoryReadWord(addr); else return LowWramMemoryReadLong(addr); } else { if (size == 0) LowWramMemoryWriteByte(addr, data); else if (size == 1) LowWramMemoryWriteWord(addr, data); else LowWramMemoryWriteLong(addr, data); return 0; } } else if (addr >= 0x1000000 && addr <= 0x17fffff) { //ssh2 input capture if (is_read) { if (size == 0) return UnhandledMemoryReadByte(addr); else if (size == 1) return UnhandledMemoryReadWord(addr); else return UnhandledMemoryReadLong(addr); } else { if (size == 0) UnhandledMemoryWriteByte(addr, data); else if (size == 1) SSH2InputCaptureWriteWord(MSH2, addr, data); else UnhandledMemoryWriteLong(addr, data); return 0; } } else if (addr >= 0x1800000 && addr <= 0x1ffffff) { //msh2 input capture if (is_read) { if (size == 0) return UnhandledMemoryReadByte(addr); else if (size == 1) return UnhandledMemoryReadWord(addr); else return UnhandledMemoryReadLong(addr); } else { if (size == 0) UnhandledMemoryWriteByte(addr, data); else if (size == 1) MSH2InputCaptureWriteWord(MSH2, addr, data); else UnhandledMemoryWriteLong(addr, data); return 0; } } else if (addr >= 0x2000000 && addr <= 0x3ffffff) { //cs0 if (is_read) { if(size == 0) return CartridgeArea->Cs0ReadByte(MSH2, addr); else if (size == 1) return CartridgeArea->Cs0ReadWord(MSH2, addr); else return CartridgeArea->Cs0ReadLong(MSH2, addr); } else { if(size == 0) CartridgeArea->Cs0WriteByte(MSH2, addr, data); else if (size == 1) CartridgeArea->Cs0WriteWord(MSH2, addr, data); else CartridgeArea->Cs0WriteLong(MSH2, addr, data); return 0; } } else if (addr >= 0x4000000 && addr <= 0x4ffffff) { if (is_read) { if (size == 0) return Cs1ReadByte(MSH2, addr); else if (size == 1) return Cs1ReadWord(MSH2, addr); else return Cs1ReadLong(MSH2, addr); } else { if (size == 0) Cs1WriteByte(MSH2, addr, data); else if (size == 1) Cs1WriteWord(MSH2, addr, data); else Cs1WriteLong(MSH2, addr, data); return 0; } } else if (addr >= 0x5000000 && addr <= 0x57fffff) { //dummy } else if (addr >= 0x5800000 && addr <= 0x58fffff) { //cs2 if (yabsys.use_cd_block_lle) { if (is_read) { if (size == 0) return Cs2ReadByte(MSH2, addr); else if (size == 1) return ygr_a_bus_read_word(addr); else return ygr_a_bus_read_long(addr); } else { if (size == 0) Cs2WriteByte(MSH2, addr, data); else if (size == 1) ygr_a_bus_write_word(addr, data); else ygr_a_bus_write_long(addr, data); return 0; } } else { if (is_read) { if (size == 0) return Cs2ReadByte(MSH2, addr); else if (size == 1) return Cs2ReadWord(MSH2, addr); else return Cs2ReadLong(MSH2, addr); } else { if (size == 0) Cs2WriteByte(MSH2, addr, data); else if (size == 1) Cs2WriteWord(MSH2, addr, data); else Cs2WriteLong(MSH2, addr, data); return 0; } } } else if (addr >= 0x5a00000 && addr <= 0x5afffff) { //sound ram if (is_read) { if (size == 0) return SoundRamReadByte(addr); else if (size == 1) return SoundRamReadWord(addr); else return SoundRamReadLong(addr); } else { if (size == 0) SoundRamWriteByte(addr, data); else if (size == 1) SoundRamWriteWord(addr, data); else SoundRamWriteLong(addr, data); return 0; } } else if (addr >= 0x5b00000 && addr <= 0x5bfffff) { //scsp regs if (is_read) { if (size == 0) return ScspReadByte(addr); else if (size == 1) return ScspReadWord(addr); else return ScspReadLong(addr); } else { if (size == 0) ScspWriteByte(addr, data); else if (size == 1) ScspWriteWord(addr, data); else ScspWriteLong(addr, data); return 0; } } else if (addr >= 0x5c00000 && addr <= 0x5c7ffff) { //vdp1 ram if (is_read) { if (size == 0) return Vdp1RamReadByte(addr); else if (size == 1) return Vdp1RamReadWord(addr); else return Vdp1RamReadLong(addr); } else { if (size == 0) Vdp1RamWriteByte(addr, data); else if (size == 1) Vdp1RamWriteWord(addr, data); else Vdp1RamWriteLong(addr, data); return 0; } } else if (addr >= 0x5c80000 && addr <= 0x5cfffff) { //vdp1 framebuffer if (is_read) { if (size == 0) return Vdp1FrameBufferReadByte(addr); else if (size == 1) return Vdp1FrameBufferReadWord(addr); else return Vdp1FrameBufferReadLong(addr); } else { if (size == 0) Vdp1FrameBufferWriteByte(addr, data); else if (size == 1) Vdp1FrameBufferWriteWord(addr, data); else Vdp1FrameBufferWriteLong(addr, data); return 0; } } else if (addr >= 0x5d00000 && addr <= 0x5d7ffff) { //vdp1 registers if (is_read) { if (size == 0) return Vdp1ReadByte(addr); else if (size == 1) return Vdp1ReadWord(addr); else return Vdp1ReadLong(addr); } else { if (size == 0) Vdp1WriteByte(addr, data); else if (size == 1) Vdp1WriteWord(addr, data); else Vdp1WriteLong(addr, data); return 0; } } else if (addr >= 0x5e00000 && addr <= 0x5efffff) { //vdp2 ram if (is_read) { if (size == 0) return Vdp2RamReadByte(addr); else if (size == 1) return Vdp2RamReadWord(addr); else return Vdp2RamReadLong(addr); } else { if (size == 0) Vdp2RamWriteByte(addr, data); else if (size == 1) Vdp2RamWriteWord(addr, data); else Vdp2RamWriteLong(addr, data); return 0; } } else if (addr >= 0x5f00000 && addr <= 0x5f7ffff) { //vdp2 color ram if (is_read) { if (size == 0) return Vdp2ColorRamReadByte(addr); else if (size == 1) return Vdp2ColorRamReadWord(addr); else return Vdp2ColorRamReadLong(addr); } else { if (size == 0) Vdp2ColorRamWriteByte(addr, data); else if (size == 1) Vdp2ColorRamWriteWord(addr, data); else Vdp2ColorRamWriteLong(addr, data); return 0; } } else if (addr >= 0x5f80000 && addr <= 0x5fbffff) { //vdp2 registers if (is_read) { if (size == 0) return Vdp2ReadByte(addr); else if (size == 1) return Vdp2ReadWord(addr); else return Vdp2ReadLong(addr); } else { if (size == 0) Vdp2WriteByte(addr, data); else if (size == 1) Vdp2WriteWord(addr, data); else Vdp2WriteLong(addr, data); return 0; } } else if (addr >= 0x5fe0000 && addr <= 0x5feffff) { //scu registers if (is_read) { if (size == 0) return ScuReadByte(addr); else if (size == 1) return ScuReadWord(addr); else return ScuReadLong(addr); } else { if (size == 0) ScuWriteByte(addr, data); else if (size == 1) ScuWriteWord(addr, data); else ScuWriteLong(addr, data); return 0; } } else if (addr >= 0x6000000 && addr <= 0x7ffffff) { //scu registers if (is_read) { if (size == 0) return HighWramMemoryReadByte(addr); else if (size == 1) return HighWramMemoryReadWord(addr); else return HighWramMemoryReadLong(addr); } else { if (size == 0) HighWramMemoryWriteByte(addr, data); else if (size == 1) HighWramMemoryWriteWord(addr, data); else HighWramMemoryWriteLong(addr, data); return 0; } } assert(0); return 0; } int sh2_check_wait(SH2_struct * sh, u32 addr, int size); void dma_tick(SH2_struct *sh, u32 *CHCR, u32 *SAR, u32 *DAR, u32 *TCR, u32 *VCRDMA, int * active) { int src_increment = 0; int dst_increment = 0; u8 dest_inc_mode = (*CHCR >> 14) & 3; u8 src_inc_mode = (*CHCR >> 12) & 3; u8 size = (*CHCR >> 10) & 3; int check_size = size; if (check_size > 2) check_size = 2;//size 3 is also long size writes if (sh2_check_wait(sh, *SAR, check_size)) return; if (dest_inc_mode == 1) dst_increment = 1; else if (dest_inc_mode == 2) dst_increment = -1; if (src_inc_mode == 1) src_increment = 1; else if (src_inc_mode == 2) src_increment = -1; if (size == 0) { u8 source_val = sh2_dma_access(*SAR,0,1,0); sh2_dma_access(*DAR, source_val,0,0); } else if (size == 1) { u16 source_val = sh2_dma_access(*SAR, 0, 1, 1); sh2_dma_access(*DAR, source_val, 0, 1); src_increment *= 2; dst_increment *= 2; } else if (size == 2 || size == 3) { u32 source_val = sh2_dma_access(*SAR, 0, 1, 2); sh2_dma_access(*DAR, source_val, 0, 2); src_increment *= 4; dst_increment *= 4; } if(dst_increment > 0) SH2WriteNotify(*DAR, *DAR + dst_increment); else SH2WriteNotify(*DAR + dst_increment, *DAR); *TCR = *TCR - 1; *SAR = *SAR + src_increment; *DAR = *DAR + dst_increment; if (*TCR == 0) { *active = 0; if ((*CHCR >> 2) & 1) SH2SendInterrupt(sh, *VCRDMA, (sh->onchip.IPRA & 0xF00) >> 8); *CHCR |= 0x2; } } void tick_dma0(SH2_struct *sh) { dma_tick( sh, &sh->onchip.CHCR0, &sh->onchip.SAR0, &sh->onchip.DAR0, &sh->onchip.TCR0, &sh->onchip.VCRDMA0, &sh->onchip.dma0_active); } void tick_dma1(SH2_struct *sh) { dma_tick( sh, &sh->onchip.CHCR1, &sh->onchip.SAR1, &sh->onchip.DAR1, &sh->onchip.TCR1, &sh->onchip.VCRDMA1, &sh->onchip.dma1_active);//channel 0 } void sh2_dma_exec(SH2_struct *sh, u32 cycles) { int i; if (!sh->onchip.dma0_active && !sh->onchip.dma1_active) return; for (i = 0; i < cycles; i++) { if ((sh->onchip.DMAOR >> 3) & 1)//round robin priority { //both channels are active, round robin if (sh->onchip.dma0_active && sh->onchip.dma1_active) { if (sh->onchip.dma_robin) { sh->onchip.dma_robin = 0; tick_dma0(sh); } else { tick_dma1(sh);//channel 1 } } else { //only one channel is active if (sh->onchip.dma0_active) tick_dma0(sh); if (sh->onchip.dma1_active) tick_dma1(sh); } } else { //channel 0 > channel 1 if(sh->onchip.dma0_active) tick_dma0(sh);//channel 0 else if (sh->onchip.dma1_active) tick_dma1(sh);//channel 1 } } } void DMAExec(SH2_struct *sh) { // If AE and NMIF bits are set, we can't continue if (sh->onchip.DMAOR & 0x6) return; if ( ((sh->onchip.CHCR0 & 0x3)==0x01) && ((sh->onchip.CHCR1 & 0x3)==0x01) ) { // both channel wants DMA if (sh->onchip.DMAOR & 0x8) { // round robin priority LOG("dma\t: FIXME: two channel dma - round robin priority not properly implemented\n"); DMATransfer(sh, &sh->onchip.CHCR0, &sh->onchip.SAR0, &sh->onchip.DAR0, &sh->onchip.TCR0, &sh->onchip.VCRDMA0); DMATransfer(sh, &sh->onchip.CHCR1, &sh->onchip.SAR1, &sh->onchip.DAR1, &sh->onchip.TCR1, &sh->onchip.VCRDMA1); } else { // channel 0 > channel 1 priority DMATransfer(sh, &sh->onchip.CHCR0, &sh->onchip.SAR0, &sh->onchip.DAR0, &sh->onchip.TCR0, &sh->onchip.VCRDMA0); DMATransfer(sh, &sh->onchip.CHCR1, &sh->onchip.SAR1, &sh->onchip.DAR1, &sh->onchip.TCR1, &sh->onchip.VCRDMA1); } } else { // only one channel wants DMA if (((sh->onchip.CHCR0 & 0x3) == 0x01)) { // DMA for channel 0 DMATransfer(sh, &sh->onchip.CHCR0, &sh->onchip.SAR0, &sh->onchip.DAR0, &sh->onchip.TCR0, &sh->onchip.VCRDMA0); return; } if (((sh->onchip.CHCR1 & 0x3) == 0x01)) { // DMA for channel 1 DMATransfer(sh, &sh->onchip.CHCR1, &sh->onchip.SAR1, &sh->onchip.DAR1, &sh->onchip.TCR1, &sh->onchip.VCRDMA1); return; } } } ////////////////////////////////////////////////////////////////////////////// void DMATransfer(SH2_struct *sh, u32 *CHCR, u32 *SAR, u32 *DAR, u32 *TCR, u32 *VCRDMA) { int size; u32 i, i2; if (!(*CHCR & 0x2)) { // TE is not set int srcInc; int destInc; switch(*CHCR & 0x3000) { case 0x0000: srcInc = 0; break; case 0x1000: srcInc = 1; break; case 0x2000: srcInc = -1; break; default: srcInc = 0; break; } switch(*CHCR & 0xC000) { case 0x0000: destInc = 0; break; case 0x4000: destInc = 1; break; case 0x8000: destInc = -1; break; default: destInc = 0; break; } switch (size = ((*CHCR & 0x0C00) >> 10)) { case 0: for (i = 0; i < *TCR; i++) { MappedMemoryWriteByteNocache(sh, *DAR, MappedMemoryReadByteNocache(sh, *SAR)); *SAR += srcInc; *DAR += destInc; } *TCR = 0; break; case 1: destInc *= 2; srcInc *= 2; for (i = 0; i < *TCR; i++) { MappedMemoryWriteWordNocache(sh, *DAR, MappedMemoryReadWordNocache(sh, *SAR)); *SAR += srcInc; *DAR += destInc; } *TCR = 0; break; case 2: destInc *= 4; srcInc *= 4; for (i = 0; i < *TCR; i++) { MappedMemoryWriteLongNocache(sh, *DAR, MappedMemoryReadLongNocache(sh, *SAR)); *DAR += destInc; *SAR += srcInc; } *TCR = 0; break; case 3: destInc *= 4; srcInc *= 4; for (i = 0; i < *TCR; i+=4) { for(i2 = 0; i2 < 4; i2++) { MappedMemoryWriteLongNocache(sh, *DAR, MappedMemoryReadLongNocache(sh, *SAR)); *DAR += destInc; *SAR += srcInc; } } *TCR = 0; break; } SH2WriteNotify(destInc<0?*DAR:*DAR-i*destInc,i*abs(destInc)); } if (*CHCR & 0x4) SH2SendInterrupt(sh, *VCRDMA, (sh->onchip.IPRA & 0xF00) >> 8); // Set Transfer End bit *CHCR |= 0x2; } ////////////////////////////////////////////////////////////////////////////// // Input Capture Specific ////////////////////////////////////////////////////////////////////////////// void FASTCALL MSH2InputCaptureWriteWord(SH2_struct *sh, UNUSED u32 addr, UNUSED u16 data) { // Set Input Capture Flag MSH2->onchip.FTCSR |= 0x80; // Copy FRC register to FICR MSH2->onchip.FICR = MSH2->onchip.FRC.all; // Time for an Interrupt? if (MSH2->onchip.TIER & 0x80) SH2SendInterrupt(MSH2, (MSH2->onchip.VCRC >> 8) & 0x7F, (MSH2->onchip.IPRB >> 8) & 0xF); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL SSH2InputCaptureWriteWord(SH2_struct *sh, UNUSED u32 addr, UNUSED u16 data) { // Set Input Capture Flag SSH2->onchip.FTCSR |= 0x80; // Copy FRC register to FICR SSH2->onchip.FICR = SSH2->onchip.FRC.all; // Time for an Interrupt? if (SSH2->onchip.TIER & 0x80) SH2SendInterrupt(SSH2, (SSH2->onchip.VCRC >> 8) & 0x7F, (SSH2->onchip.IPRB >> 8) & 0xF); } ////////////////////////////////////////////////////////////////////////////// // SCI Specific ////////////////////////////////////////////////////////////////////////////// u8 SCIReceiveByte(void) { return 0; } ////////////////////////////////////////////////////////////////////////////// void SCITransmitByte(UNUSED u8 val) { } ////////////////////////////////////////////////////////////////////////////// int SH2SaveState(SH2_struct *context, FILE *fp) { int offset; IOCheck_struct check = { 0, 0 }; sh2regs_struct regs; if (context->model == SHMT_SH1) { offset = StateWriteHeader(fp, "SH1 ", 1); } else if (context->model == SHMT_SH2) { // Write header if (context->isslave == 0) offset = StateWriteHeader(fp, "MSH2", 1); else { offset = StateWriteHeader(fp, "SSH2", 1); ywrite(&check, (void *)&yabsys.IsSSH2Running, 1, 1, fp); } } // Write registers SH2GetRegisters(context, ®s); ywrite(&check, (void *)®s, sizeof(sh2regs_struct), 1, fp); // Write onchip registers ywrite(&check, (void *)&context->onchip, sizeof(Onchip_struct), 1, fp); // Write internal variables // FIXME: write the clock divisor rather than the shift amount for // backward compatibility (fix this next time the save state version // is updated) context->frc.shift = 1 << context->frc.shift; ywrite(&check, (void *)&context->frc, sizeof(context->frc), 1, fp); { u32 div = context->frc.shift; context->frc.shift = 0; while ((div >>= 1) != 0) context->frc.shift++; } context->NumberOfInterrupts = SH2Core->GetInterrupts(context, context->interrupts); ywrite(&check, (void *)context->interrupts, sizeof(interrupt_struct), MAX_INTERRUPTS, fp); ywrite(&check, (void *)&context->NumberOfInterrupts, sizeof(u32), 1, fp); ywrite(&check, (void *)context->AddressArray, sizeof(u32), 0x100, fp); ywrite(&check, (void *)context->DataArray, sizeof(u8), 0x1000, fp); ywrite(&check, (void *)&context->delay, sizeof(u32), 1, fp); ywrite(&check, (void *)&context->cycles, sizeof(u32), 1, fp); ywrite(&check, (void *)&context->isslave, sizeof(u8), 1, fp); ywrite(&check, (void *)&context->isIdle, sizeof(u8), 1, fp); ywrite(&check, (void *)&context->instruction, sizeof(u16), 1, fp); return StateFinishHeader(fp, offset); } ////////////////////////////////////////////////////////////////////////////// int SH2LoadState(SH2_struct *context, FILE *fp, UNUSED int version, int size) { IOCheck_struct check = { 0, 0 }; sh2regs_struct regs; if (context->isslave == 1) yread(&check, (void *)&yabsys.IsSSH2Running, 1, 1, fp); // Read registers yread(&check, (void *)®s, sizeof(sh2regs_struct), 1, fp); SH2SetRegisters(context, ®s); // Read onchip registers yread(&check, (void *)&context->onchip, sizeof(Onchip_struct), 1, fp); // Read internal variables yread(&check, (void *)&context->frc, sizeof(context->frc), 1, fp); { // FIXME: backward compatibility hack (see SH2SaveState() comment) u32 div = context->frc.shift; context->frc.shift = 0; while ((div >>= 1) != 0) context->frc.shift++; } yread(&check, (void *)context->interrupts, sizeof(interrupt_struct), MAX_INTERRUPTS, fp); yread(&check, (void *)&context->NumberOfInterrupts, sizeof(u32), 1, fp); SH2Core->SetInterrupts(context, context->NumberOfInterrupts, context->interrupts); yread(&check, (void *)context->AddressArray, sizeof(u32), 0x100, fp); yread(&check, (void *)context->DataArray, sizeof(u8), 0x1000, fp); yread(&check, (void *)&context->delay, sizeof(u32), 1, fp); yread(&check, (void *)&context->cycles, sizeof(u32), 1, fp); yread(&check, (void *)&context->isslave, sizeof(u8), 1, fp); yread(&check, (void *)&context->isIdle, sizeof(u8), 1, fp); yread(&check, (void *)&context->instruction, sizeof(u16), 1, fp); #if defined(SH2_DYNAREC) if(SH2Core->id==2) { invalidate_all_pages(); if (context->isslave == 1) { // If the slave SH2 isn't running, make sure the dynarec stops it if(!yabsys.IsSSH2Running) SH2Core->Reset(SSH2); } } #endif return size; } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/persdljoy.h000644 001750 001750 00000001646 12755623101 020235 0ustar00guillaumeguillaume000000 000000 /* Copyright 2006 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef PERSDLJOY_H #define PERSDLJOY_H #include "peripheral.h" /** @addtogroup peripheral * @{ */ #define PERCORE_SDLJOY 3 extern PerInterface_struct PERSDLJoy; /** @} */ #endif yabause-0.9.15/src/scsp2.c000644 001750 001750 00000342515 12755623101 017252 0ustar00guillaumeguillaume000000 000000 /* src/scsp2.c: New, threadable SCSP implementation for Yabause Copyright 2004 Stephane Dallongeville Copyright 2004-2007 Theo Berkau Copyright 2006 Guillaume Duhamel Copyright 2010 Andrew Church This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "core.h" #include "debug.h" #include "error.h" #include "m68kcore.h" #include "memory.h" #include "scsp.h" #include "threads.h" #include "yabause.h" #include #include #undef round // In case math.h defines it #define round(x) ((int) (floor((x) + 0.5))) #undef ScspInit // Disable compatibility alias extern SoundInterface_struct *SNDCoreList[]; // Defined by each port /////////////////////////////////////////////////////////////////////////// // This SCSP implementation is designed to be runnable as an independent // thread, encompassing the SCSP emulation itself as well as the MC68EC000 // sound processor and the actual generation of PCM audio data. // // When running in multithreaded mode, the actual SCSP and M68K emulation // is performed via ScspThread(). This function is started as a subthread // (YAB_THREAD_SCSP), and loops over ScspDoExec() until scsp_thread_running // goes to zero, which is used as a signal for the thread to stop. // Synchronization is performed via the scsp_clock_target variable; the SCSP // thread sleeps until clock_target != clock, then calls ScspDoExec() for // (clock - clock_target) cycles. The main thread wakes up the subthread // both when clock_target is updated and when register writes, discussed // below, are submitted. // // Additionally, any register writes from outside the SCSP/M68K will be // processed synchronously in multithreaded mode, by passing the write // through a shared buffer (scsp_write_buffer_* variables). When the // thread loop detects scsp_write_buffer_size nonzero, it processes the // write before its next ScspDoExec() iteration and clears ..._size; the // main thread then waits for ..._size to return to zero before returning // from the write operation. (This will typically be no more expensive // than a pair of context switches, and it seems that SCSP register writes // from the SH-2 are uncommon.) // // The "PSP_*" macros scattered throughout the file are to support the // execution of the SCSP thread on the Media Engine CPU (ME) in the PSP. // The ME lacks cache coherence with the main CPU (SC), so special care // needs to be taken to avoid bugs arising from inconsistent cache states; // see the technical notes in README.PSP for details. These macros are all // no-ops on other platforms. //------------------------------------------------------------------------- // PSP cache management macros #ifdef PSP # include "psp/common.h" # include "psp/me.h" # include "psp/me-utility.h" # include "psp/misc.h" // psp_writeback_cache_for_scsp() declaration // Data section management (to avoid cache line collisions between CPUs) # define PSP_SECTION(name) \ __attribute__((section(".meshared.scsp." #name))) # define PSP_SECTION_START(name) \ __attribute__((section(".meshared.scsp." #name), aligned(64))) \ extern volatile char __scsp_sectstart_##name[64]; # define PSP_SECTION_END(name) \ __attribute__((section(".meshared.scsp." #name))) \ extern volatile char __scsp_sectend_##name; // Cache control # define PSP_WRITEBACK_CACHE(ptr,len) \ sceKernelDcacheWritebackRange((ptr), (len)) # define PSP_WRITEBACK_ALL() \ sceKernelDcacheWritebackAll() # define PSP_FLUSH_ALL() \ sceKernelDcacheWritebackInvalidateAll() // Uncached pointer access # define PSP_UCPTR(ptr) ((typeof(&*ptr))((uint32_t)(ptr) | 0x40000000)) // Uncached variable access (either read or write) # define PSP_UC(var) (*((typeof(&var))((uint32_t)(&var) | 0x40000000))) #else // !PSP # define PSP_SECTION(name) /*nothing*/ # define PSP_SECTION_START(name) /*nothing*/ # define PSP_SECTION_END(name) /*nothing*/ # define PSP_WRITEBACK_CACHE(ptr,len) /*nothing*/ # define PSP_WRITEBACK_ALL() /*nothing*/ # define PSP_FLUSH_ALL() /*nothing*/ # define PSP_UCPTR(ptr) ptr # define PSP_UC(var) var #endif //------------------------------------------------------------------------- // SCSP constants // SCSP hardware version (4 bits) #define SCSP_VERSION 0 // SCSP clock frequency (11.2896 MHz, or exactly 44100*256) #define SCSP_CLOCK_FREQ (44100 * 256) // SCSP output frequency #define SCSP_OUTPUT_FREQ (SCSP_CLOCK_FREQ / 256) // SCSP clock increment per 1/10 scanline #define SCSP_CLOCK_INC_NTSC (((u64)SCSP_CLOCK_FREQ<<20) * 1001 / 60000 / 263 / 10) #define SCSP_CLOCK_INC_PAL (((u64)SCSP_CLOCK_FREQ<<20) / 50 / 313 / 10) // Limit on execution time for a single thread loop (in SCSP clock cycles); // if the thread's delay exceeds this value, we stop in the main loop to // let the SCSP catch up #define SCSP_CLOCK_MAX_EXEC (SCSP_CLOCK_FREQ / 1000) // Sound RAM size #define SCSP_RAM_SIZE 0x80000 #define SCSP_RAM_MASK (SCSP_RAM_SIZE - 1) // Envelope phases #define SCSP_ENV_RELEASE 0 #define SCSP_ENV_SUSTAIN 1 #define SCSP_ENV_DECAY 2 #define SCSP_ENV_ATTACK 3 // LFO waveform types (equal to ALFOWS/PLFOWS values) #define SCSP_LFO_SAWTOOTH 0 #define SCSP_LFO_SQUARE 1 #define SCSP_LFO_TRIANGLE 2 #define SCSP_LFO_NOISE 3 // Bit sizes of fixed-point counters // Fractional part of frequency counter (determines accuracy of audio // playback frequency) #define SCSP_FREQ_LOW_BITS 10 // Integer part of envelope counter (determines resolution of attack/decay // envelope); also used to define envelope value range #define SCSP_ENV_HIGH_BITS 10 // Fractional part of envelope counter (determines accuracy of envelope timing) #define SCSP_ENV_LOW_BITS 10 // Integer part of LFO counter (determines resolution of LFO waveform); // also used to define LFO value range #define SCSP_LFO_HIGH_BITS 10 // Fractional part of LFO counter (determines accuracy of LFO frequency) #define SCSP_LFO_LOW_BITS 10 // Fractional part of TL attenuation lookup table (determines resolution of // per-voice volume control) #define SCSP_TL_BITS 10 // Envelope/waveform table data sizes and corresponding masks #define SCSP_ENV_LEN (1 << SCSP_ENV_HIGH_BITS) #define SCSP_ENV_MASK (SCSP_ENV_LEN - 1) #define SCSP_LFO_LEN (1 << SCSP_LFO_HIGH_BITS) #define SCSP_LFO_MASK (SCSP_LFO_LEN - 1) // Envelope attack/decay points (counter values) #define SCSP_ENV_ATTACK_START 0 #define SCSP_ENV_DECAY_START (SCSP_ENV_LEN << SCSP_ENV_LOW_BITS) #define SCSP_ENV_ATTACK_END (SCSP_ENV_DECAY_START - 1) #define SCSP_ENV_DECAY_END (((2 * SCSP_ENV_LEN) << SCSP_ENV_LOW_BITS) - 1) // Envelope attack/decay base times #define SCSP_ATTACK_TIME ((u32) (8 * SCSP_OUTPUT_FREQ)) #define SCSP_DECAY_TIME ((u32) (12 * SCSP_ATTACK_TIME)) // Interrupt bit numbers #define SCSP_INTERRUPT_MIDI_IN 3 // Data available in MIDI input buffer #define SCSP_INTERRUPT_DMA 4 // DMA complete #define SCSP_INTERRUPT_MANUAL 5 // 1 written to bit 5 of [MS]CIPD #define SCSP_INTERRUPT_TIMER_A 6 // Timer A reached 0xFF #define SCSP_INTERRUPT_TIMER_B 7 // Timer B reached 0xFF #define SCSP_INTERRUPT_TIMER_C 8 // Timer C reached 0xFF #define SCSP_INTERRUPT_MIDI_OUT 9 // MIDI output buffer became empty #define SCSP_INTERRUPT_SAMPLE 10 // Raised once per output sample // Interrupt target flags #define SCSP_INTTARGET_MAIN (1 << 0) // Interrupt to main CPU (SCU) #define SCSP_INTTARGET_SOUND (1 << 1) // Interrupt to sound CPU #define SCSP_INTTARGET_BOTH (SCSP_INTTARGET_MAIN | SCSP_INTTARGET_SOUND) // PCM output buffer size parameters #define SCSP_SOUND_LEN_NTSC (SCSP_OUTPUT_FREQ / 60) // Samples per frame #define SCSP_SOUND_LEN_PAL (SCSP_OUTPUT_FREQ / 50) // Reserve 10x the maximum samples per frame #define SCSP_SOUND_BUFSIZE (10 * SCSP_SOUND_LEN_PAL) // CDDA data buffer size in sectors (must be at least 3) #define CDDA_NUM_BUFFERS 3 // CDDA playback start delay in samples (see cdda_delay comments) #define CDDA_DELAY_SAMPLES 100 //------------------------------------------------------------------------- // Internal state data structures // Per-slot data structure typedef struct SlotState_struct { //////////// // Register fields // ISR $00 // [12] Write 1 to execute KEY state change u8 key; // [11] KEY state (on/off) u8 sbctl; // [10:9] Source bit control u8 ssctl; // [8:7] Sound source control u8 lpctl; // [6:5] Loop control u8 pcm8b; // [4] PCM sound format // [3:0] Start address (in bytes), high bits (19:16) // ISR $02 u32 sa; // [15:0] Start address (in bytes), low bits (15:0) // ISR $04 u16 lsa; // [15:0] Loop start address (in samples) // ISR $06 u16 lea; // [15:0] Loop end address (in samples) // ISR $08 u8 sr; // [15:11] Sustain rate u8 dr; // [10:6] Decay rate u8 eghold; // [5] Envelope hold (attack rate 0) flag u8 ar; // [4:0] Attack rate // ISR $0A u8 lpslnk; // [14] Loop start link (start decay on reaching LSA) u8 krs; // [13:10] Key rate scale u8 sl; // [9:5] Sustain level u8 rr; // [4:0] Release rate // ISR $0C u8 stwinh; // [9] Stack write inhibit flag u8 sdir; // [8] Sound direct output flag u8 tl; // [7:0] Total level // ISR $0E u8 mdl; // [15:12] Modulation level u8 mdx; // [11:6] Modulation source X u8 mdy; // [5:0] Modulation source Y // ISR $10 u8 oct; // [14:11] Octave (treated as signed -8..7) u16 fns; // [9:0] Frequency number switch // ISR $12 u8 lfore; // [15] LFO reset flag (1 = reset, 0 = count) u8 lfof; // [14:10] LFO frequency index u8 plfows; // [9:8] Pitch LFO waveform select u8 plfos; // [7:5] Pitch LFO sensitivity u8 alfows; // [4:3] Amplitude LFO waveform select u8 alfos; // [2:0] Amplitude LFO sensitivity // ISR $14 u8 isel; // [6:3] Input selector u8 imxl; // [2:0] Input mix level // ISR $16 u8 disdl; // [15:13] Direct data send level u8 dipan; // [12:8] Direct data pan position u8 efsdl; // [7:5] Effect data send level u8 efpan; // [2:0] Effect data pan position //////////// // Internal state // Audio generation routine (selected based on slot parameters) void (* FASTCALL audiogen)(struct SlotState_struct *slot, u32 len); const void *buf; // Pointer to sample data in sound RAM u32 addr_counter; // Address (playback) counter u32 addr_step; // Address counter increment u8 octave_shift; // Octave shift amount (0..15) u32 lsa_shifted; // lsa << SCSP_FREQ_LOW_BITS (for addr_counter) u32 lea_shifted; // lea << SCSP_FREQ_LOW_BITS (for addr_counter) u32 looplen_shifted;// (lea - lsa + 1) << SCSP_FREQ_LOW_BITS u32 env_phase; // Current envelope phase (attack/decay/...) s32 env_counter; // Envelope counter s32 env_step; // Envelope counter increment for current phase s32 env_target; // Envelope target value for advancing to next phase s32 env_step_a; // Envelope counter increment for attack phase s32 env_step_d; // Envelope counter increment for decay phase s32 env_step_s; // Envelope counter increment for sustain phase s32 env_step_r; // Envelope counter increment for release phase s32 last_env; // Last calculated envelope multiplier u8 krs_shift; // Shift count corresponding to KRS s32 sl_target; // Compare value corresponding to SL s32 tl_mult; // Envelope volume multiplier corresponding to TL u32 lfo_counter; // LFO counter (fixed point index into LFO waveforms) s32 lfo_step; // LFO counter increment, or -1 if in reset mode s32 *lfo_fm_wave; // LFO frequency modulation waveform pointer s32 *lfo_am_wave; // LFO amplitude modulation waveform pointer s8 lfo_fm_shift; // LFO frequency modulation strength, -1 if disabled s8 lfo_am_shift; // LFO amplitude modulation strength, -1 if disabled u8 outshift_l; // Output shift for left channel (down to 16 bits) u8 outshift_r; // Output shift for right channel (down to 16 bits) u8 imxl_shift; // Shift count for IMXL } SlotState; //------------------------------------ // Overall SCSP data structure typedef struct ScspState_struct { //////////// // Register fields // $400 u8 mem4mb; // [9] Sound RAM memory size flag (4Mbit vs. 2Mbit) u8 dac18b; // [8] DAC 18-bit output flag (ignored) u8 ver; // [7:4] Hardware version (fixed at 0) u8 mvol; // [3:0] Master volume // $402 u8 rbl; // [8:7] Ring buffer length (8192<Exec or M68KExecBP static s32 m68k_saved_cycles; // Requested minus actual cycles executed static M68KBreakpointInfo m68k_breakpoint[M68K_MAX_BREAKPOINTS]; static int m68k_num_breakpoints; static void (*M68KBreakpointCallback)(u32); static u8 m68k_in_breakpoint; //------------------------------------------------------------------------- // Local function declarations static void ScspThread(void *arg); static void ScspDoExec(u32 cycles); static u32 ScspTimerCyclesLeft(u16 timer, u8 timer_scale); static void ScspUpdateTimer(u32 samples, u16 *timer_ptr, u8 timer_scale, int interrupt); static void ScspGenerateAudio(s32 *bufL, s32 *bufR, u32 samples); static void ScspGenerateAudioForSlot(SlotState *slot, u32 samples); static void ScspGenerateAudioForCDDA(s32 *bufL, s32 *bufR, u32 samples); static u8 FASTCALL ScspReadByteDirect(u32 address); static u16 FASTCALL ScspReadWordDirect(u32 address); static void FASTCALL ScspWriteByteDirect(u32 address, u8 data); static void FASTCALL ScspWriteWordDirect(u32 address, u16 data); static u16 ScspReadMonitor(void); static void ScspDoKeyOnOff(void); static void ScspKeyOn(SlotState *slot); static void ScspKeyOff(SlotState *slot); static void ScspUpdateSlotAddress(SlotState *slot); static void ScspUpdateSlotEnv(SlotState *slot); static void ScspUpdateSlotFunc(SlotState *slot); static u16 ScspMidiIn(void); static void ScspMidiOut(u8 data); static void ScspDoDMA(void); static void ScspSyncThread(void); static void ScspRaiseInterrupt(int which, int target); static void ScspCheckInterrupts(u16 mask, int target); static void ScspClearInterrupts(u16 mask, int target); static void ScspRunM68K(u32 cycles); static s32 FASTCALL M68KExecBP(s32 cycles); static int scsp_mute_flags = 0; static int scsp_volume = 100; /////////////////////////////////////////////////////////////////////////// // Single-slot audio generation routines and corresponding table. The // table is indexed by: // scsp_audiogen_func_table[F][A][S][L][R] // ^ ^ ^ ^ ^-- Right channel on/off (on = 1) // | | | `-- Left channel on/off (on = 1) // | | `-- Sample size 16/8 bit (16 bit = 1) // | `-- Amplitude modulation on/off (on = 1) // `-- Frequency modulation on/off (on = 1) /////////////////////////////////////////////////////////////////////////// // For convenience, we use a single, parameterized macro to define every // function, with 0 or 1 in each of the F/A/S/L/R parameters; the compiler // will optimize out the disabled branches. // A couple of handy sub-macros: #define ADDRESS (addr_counter >> SCSP_FREQ_LOW_BITS) #ifdef WORDS_BIGENDIAN #define ADDRESS_8BIT (ADDRESS) #else #define ADDRESS_8BIT (ADDRESS ^ 1) #endif #define ENV_POS (env_counter >> SCSP_ENV_LOW_BITS) #define LFO_POS ((slot->lfo_counter >> SCSP_LFO_LOW_BITS) & SCSP_LFO_MASK) #define DEFINE_AUDIOGEN(tag,F,A,S,L,R) \ static void FASTCALL audiogen_##tag(SlotState *slot, u32 len) \ { \ /* Load these first to avoid having to reload them every iteration */ \ u32 addr_counter = slot->addr_counter; \ const u32 addr_step = slot->addr_step; \ u32 env_counter = slot->env_counter; \ u32 env_step = slot->env_step; \ \ u32 pos; \ for (pos = 0; pos < len; pos++) \ { \ if (L || R) /* Don't bother with calculations if it's all silent */ \ { \ /* Compute envelope/TL multiplier for waveform data */ \ s32 env = scsp_env_table[ENV_POS] * slot->tl_mult >> SCSP_TL_BITS; \ if (A) \ env -= slot->lfo_am_wave[LFO_POS] >> slot->lfo_am_shift; \ slot->last_env = env; \ \ /* Apply envelope / channel volume to waveform data and output */ \ if (LIKELY(env > 0)) \ { \ s32 out; \ if (S) \ out = (s32) ((const s16 *)slot->buf)[ADDRESS]; \ else \ out = (s32) ((const s8 *)slot->buf)[ADDRESS_8BIT] << 8; \ out *= env; \ if (L) \ scsp_bufL[pos] += out >> slot->outshift_l; \ if (R) \ scsp_bufR[pos] += out >> slot->outshift_r; \ } \ } \ \ /* Update address counter, exiting if we reach the end of the data */ \ if (F) \ { \ /* FIXME: need to handle the case where LFO data range != 1<lfo_fm_wave[LFO_POS] \ << slot->lfo_fm_shift \ >> slot->octave_shift; \ } \ addr_counter += addr_step; \ if (UNLIKELY(addr_counter > slot->lea_shifted)) \ { \ /* FIXME: reverse/alternating loops not implemented */ \ if (slot->lpctl) \ { \ addr_counter = slot->lsa_shifted \ + ((addr_counter - slot->lsa_shifted) \ % slot->looplen_shifted); \ } \ else \ { \ env_counter = SCSP_ENV_DECAY_END; \ goto done; \ } \ } \ \ /* Update envelope counter, advancing the envelope phase as needed */ \ env_counter += env_step; \ if (UNLIKELY(env_counter >= slot->env_target)) \ { \ switch (slot->env_phase) \ { \ case SCSP_ENV_ATTACK: \ env_counter = SCSP_ENV_DECAY_START; \ env_step = slot->env_step = slot->env_step_d; \ slot->env_target = slot->sl_target; \ slot->env_phase = SCSP_ENV_DECAY; \ break; \ case SCSP_ENV_DECAY: \ env_counter = slot->sl_target; \ env_step = slot->env_step = slot->env_step_s; \ slot->env_target = SCSP_ENV_DECAY_END; \ slot->env_phase = SCSP_ENV_SUSTAIN; \ break; \ default: \ env_counter = SCSP_ENV_DECAY_END; \ env_step = slot->env_step = 0; \ slot->env_target = SCSP_ENV_DECAY_END + 1; \ goto done; \ } \ } \ \ /* Update the LFO counter if either LFO waveform is in use \ * (technically, we should update whenever slot->lfore == 0, but \ * we skip the update on non-modulated channels to save time) */ \ if (F || A) \ slot->lfo_counter += slot->lfo_step; \ } \ \ done: \ slot->addr_counter = addr_counter; \ slot->env_counter = env_counter; \ } //------------------------------------------------------------------------- // Define the actual audio generation functions. For simplicity, we name // each function using the state of its parameter flags, with uppercase for // an enabled flag and lowercase for a disabled flag. We also use the null // output function for all cases where L and R are zero, to avoid // unnecessary code bloat. DEFINE_AUDIOGEN(null, 0,0,0,0,0) DEFINE_AUDIOGEN(faslR, 0,0,0,0,1) DEFINE_AUDIOGEN(fasLr, 0,0,0,1,0) DEFINE_AUDIOGEN(fasLR, 0,0,0,1,1) DEFINE_AUDIOGEN(faSlR, 0,0,1,0,1) DEFINE_AUDIOGEN(faSLr, 0,0,1,1,0) DEFINE_AUDIOGEN(faSLR, 0,0,1,1,1) DEFINE_AUDIOGEN(fAslR, 0,1,0,0,1) DEFINE_AUDIOGEN(fAsLr, 0,1,0,1,0) DEFINE_AUDIOGEN(fAsLR, 0,1,0,1,1) DEFINE_AUDIOGEN(fASlR, 0,1,1,0,1) DEFINE_AUDIOGEN(fASLr, 0,1,1,1,0) DEFINE_AUDIOGEN(fASLR, 0,1,1,1,1) DEFINE_AUDIOGEN(FaslR, 1,0,0,0,1) DEFINE_AUDIOGEN(FasLr, 1,0,0,1,0) DEFINE_AUDIOGEN(FasLR, 1,0,0,1,1) DEFINE_AUDIOGEN(FaSlR, 1,0,1,0,1) DEFINE_AUDIOGEN(FaSLr, 1,0,1,1,0) DEFINE_AUDIOGEN(FaSLR, 1,0,1,1,1) DEFINE_AUDIOGEN(FAslR, 1,1,0,0,1) DEFINE_AUDIOGEN(FAsLr, 1,1,0,1,0) DEFINE_AUDIOGEN(FAsLR, 1,1,0,1,1) DEFINE_AUDIOGEN(FASlR, 1,1,1,0,1) DEFINE_AUDIOGEN(FASLr, 1,1,1,1,0) DEFINE_AUDIOGEN(FASLR, 1,1,1,1,1) // We don't need these anymore, so get rid of them #undef ADDRESS #undef ADDRESS_8BIT #undef ENV_POS #undef LFO_POS #undef DEFINE_AUDIOGEN //------------------------------------------------------------------------- // Define the function lookup table. static void (* FASTCALL scsp_audiogen_func_table[2][2][2][2][2])(SlotState *slot, u32 len) = { { // F==0 { // A==0 {{audiogen_null, audiogen_faslR}, {audiogen_fasLr, audiogen_fasLR}}, {{audiogen_null, audiogen_faSlR}, {audiogen_faSLr, audiogen_faSLR}} }, { // A==1 {{audiogen_null, audiogen_fAslR}, {audiogen_fAsLr, audiogen_fAsLR}}, {{audiogen_null, audiogen_fASlR}, {audiogen_fASLr, audiogen_fASLR}} } }, { // F==1 { // A==0 {{audiogen_null, audiogen_FaslR}, {audiogen_FasLr, audiogen_FasLR}}, {{audiogen_null, audiogen_FaSlR}, {audiogen_FaSLr, audiogen_FaSLR}} }, { // A==1 {{audiogen_null, audiogen_FAslR}, {audiogen_FAsLr, audiogen_FAsLR}}, {{audiogen_null, audiogen_FASlR}, {audiogen_FASLr, audiogen_FASLR}} } } }; /////////////////////////////////////////////////////////////////////////// // Initialization, configuration, and cleanup routines /////////////////////////////////////////////////////////////////////////// // ScspInit: Initialize the SCSP emulation. interrupt_handler should // specify a function to handle interrupts delivered to the SCU. // Must be called after M68KInit(); returns 0 on success, -1 on failure. int ScspInit(int coreid, void (*interrupt_handler)(void)) { int i, j; double x; if ((SoundRam = T2MemoryInit(0x80000)) == NULL) return -1; // Fill in lookup tables for (i = 0; i < SCSP_ENV_LEN; i++) { // Attack Curve (x^4 ?) x = pow(((double) (SCSP_ENV_MASK - i) / SCSP_ENV_LEN), 4); x *= (double) SCSP_ENV_LEN; scsp_env_table[i] = SCSP_ENV_MASK - (s32) floor(x); // Decay curve (x = linear) scsp_env_table[i + SCSP_ENV_LEN] = SCSP_ENV_MASK - i; } for (i = 0, j = 0; i < 32; i++) { double lfo_frequency, lfo_step; // Frequency divider follows the pattern 1,2,3,4, 6,8,10,12, 16,... j += 1 << (i >> 2); // Base LFO frequency is 44100/256 or ~172.3 Hz lfo_frequency = (44100.0 / 256.0) / j; // Calculate LFO address step per output sample; we use a literal // 44100 above but OUTPUT_FREQ here in case anyone wants to try // upsampling the audio output someday lfo_step = (lfo_frequency / SCSP_OUTPUT_FREQ) * SCSP_LFO_LEN; scsp_lfo_step[31 - i] = round(lfo_step * (1 << SCSP_LFO_LOW_BITS)); } for (i = 0; i < SCSP_LFO_LEN; i++) { // Amplitude modulation uses unsigned values which are subtracted // from the base envelope value scsp_lfo_wave_amp[SCSP_LFO_SAWTOOTH][i] = i; if (i < SCSP_LFO_LEN / 2) scsp_lfo_wave_amp[SCSP_LFO_SQUARE][i] = 0; else scsp_lfo_wave_amp[SCSP_LFO_SQUARE][i] = SCSP_LFO_MASK; if (i < SCSP_LFO_LEN / 2) scsp_lfo_wave_amp[SCSP_LFO_TRIANGLE][i] = i*2; else scsp_lfo_wave_amp[SCSP_LFO_TRIANGLE][i] = SCSP_LFO_MASK - ((i - SCSP_LFO_LEN/2) * 2); scsp_lfo_wave_amp[SCSP_LFO_NOISE][i] = rand() & SCSP_LFO_MASK; // FIXME: note that the noise generator output should be independent // of LFORE/LFOF // Frequency modulation uses signed values which are added to the // address counter if (i < SCSP_LFO_LEN / 2) scsp_lfo_wave_freq[SCSP_LFO_SAWTOOTH][i] = i; else scsp_lfo_wave_freq[SCSP_LFO_SAWTOOTH][i] = i - SCSP_LFO_LEN; if (i < SCSP_LFO_LEN / 2) scsp_lfo_wave_freq[SCSP_LFO_SQUARE][i] = SCSP_LFO_MASK - SCSP_LFO_LEN/2; else scsp_lfo_wave_freq[SCSP_LFO_SQUARE][i] = 0 - SCSP_LFO_LEN/2; if (i < SCSP_LFO_LEN / 4) scsp_lfo_wave_freq[SCSP_LFO_TRIANGLE][i] = i*2; else if (i < SCSP_LFO_LEN * 3 / 4) scsp_lfo_wave_freq[SCSP_LFO_TRIANGLE][i] = SCSP_LFO_MASK - i*2; else scsp_lfo_wave_freq[SCSP_LFO_TRIANGLE][i] = i*2 - SCSP_LFO_LEN*2; scsp_lfo_wave_freq[SCSP_LFO_NOISE][i] = scsp_lfo_wave_amp[SCSP_LFO_NOISE][i] - SCSP_LFO_LEN/2; } for (i = 0; i < 4; i++) { scsp_attack_rate[i] = 0; scsp_decay_rate[i] = 0; } for (i = 0; i < 60; i++) { x = 1.0 + ((i & 3) * 0.25); // Bits 0-1: x1.00, x1.25, x1.50, x1.75 x *= 1 << (i >> 2); // Bits 2-5: shift bits (x2^0 - x2^15) x *= SCSP_ENV_LEN << SCSP_ENV_LOW_BITS; // Adjust for envelope table size scsp_attack_rate[i + 4] = round(x / SCSP_ATTACK_TIME); if (scsp_attack_rate[i + 4] == 0) scsp_attack_rate[i + 4] = 1; scsp_decay_rate[i + 4] = round(x / SCSP_DECAY_TIME); if (scsp_decay_rate[i + 4] == 0) scsp_decay_rate[i + 4] = 1; } scsp_attack_rate[63] = SCSP_ENV_ATTACK_END; scsp_decay_rate[61] = scsp_decay_rate[60]; scsp_decay_rate[62] = scsp_decay_rate[60]; scsp_decay_rate[63] = scsp_decay_rate[60]; for (i = 64; i < 78; i++) { scsp_attack_rate[i] = scsp_attack_rate[63]; scsp_decay_rate[i] = scsp_decay_rate[63]; } for (i = 0; i < 256; i++) scsp_tl_table[i] = round(pow(2.0, -(i/16.0)) * (1 << SCSP_TL_BITS)); // Initialize the SCSP state scsp_interrupt_handler = interrupt_handler; scsp_clock_inc = yabsys.IsPal ? SCSP_CLOCK_INC_PAL : SCSP_CLOCK_INC_NTSC; ScspReset(); // Note that we NEVER reset the clock counter after initialization, // because in multithreaded mode, that would cause a race condition in // which the SCSP thread runs between the two assignments and detects // clock != clock_target, causing it to execute a huge number of cycles. // (We do, however, reset the accumulated fraction of a cycle inside // ScspReset().) scsp_clock = 0; scsp_clock_target = 0; // Initialize the M68K state if (M68K->Init() != 0) return -1; M68K->SetReadB(M68KReadByte); M68K->SetReadW(M68KReadWord); M68K->SetWriteB(M68KWriteByte); M68K->SetWriteW(M68KWriteWord); M68K->SetFetch(0x000000, 0x040000, (pointer)SoundRam); M68K->SetFetch(0x040000, 0x080000, (pointer)SoundRam); M68K->SetFetch(0x080000, 0x0C0000, (pointer)SoundRam); M68K->SetFetch(0x0C0000, 0x100000, (pointer)SoundRam); m68k_running = 0; m68k_execf = M68K->Exec; m68k_saved_cycles = 0; for (i = 0; i < MAX_BREAKPOINTS; i++) m68k_breakpoint[i].addr = 0xFFFFFFFF; m68k_num_breakpoints = 0; M68KBreakpointCallback = NULL; m68k_in_breakpoint = 0; // Set up sound output scsp_sound_genpos = 0; scsp_sound_left = 0; if (ScspChangeSoundCore(coreid) < 0) return -1; // Start a subthread if requested scsp_thread_running = 0; if (yabsys.UseThreads) { scsp_thread_running = 1; // Set now so the thread doesn't quit instantly PSP_FLUSH_ALL(); if (YabThreadStart(YAB_THREAD_SCSP, ScspThread, NULL) < 0) { SCSPLOG("Failed to start SCSP thread\n"); scsp_thread_running = 0; } } // Successfully initialized! return 0; } //------------------------------------------------------------------------- // ScspReset: Reset the SCSP to its power-on state, also stopping the M68K // processor. void ScspReset(void) { int slotnum; if (scsp_thread_running) ScspSyncThread(); scsp.mem4mb = 0; scsp.dac18b = 0; scsp.ver = 0; scsp.mvol = 0; scsp.rbl = 0; scsp.rbp = 0; scsp.mofull = 0; scsp.moemp = 1; scsp.miovf = 0; scsp.mifull = 0; scsp.miemp = 1; scsp.mibuf = 0; scsp.mobuf = 0; scsp.mslc = 0; scsp.ca = 0; scsp.dmea = 0; scsp.drga = 0; scsp.dgate = 0; scsp.ddir = 0; scsp.dexe = 0; scsp.dtlg = 0; scsp.tactl = 0; scsp.tima = 0xFF00; scsp.tbctl = 0; scsp.timb = 0xFF00; scsp.tcctl = 0; scsp.timc = 0xFF00; scsp.mcieb = 0; scsp.mcipd = 0; scsp.scilv0 = 0; scsp.scilv1 = 0; scsp.scilv2 = 0; scsp.scieb = 0; scsp.scipd = 0; memset(scsp_regcache, 0, sizeof(scsp_regcache)); scsp_regcache[0x400>>1] = SCSP_VERSION << 4; memset(scsp.stack, 0, sizeof(scsp.stack)); for (slotnum = 0; slotnum < 32; slotnum++) { memset(&scsp.slot[slotnum], 0, sizeof(scsp.slot[slotnum])); scsp.slot[slotnum].env_counter = SCSP_ENV_DECAY_END; // Slot off scsp.slot[slotnum].outshift_l = 31; // Output off scsp.slot[slotnum].outshift_r = 31; scsp.slot[slotnum].audiogen = audiogen_null; } scsp.sound_ram_mask = 0x3FFFF; scsp_clock_frac = 0; scsp.sample_timer = 0; scsp_main_interrupt_pending = 0; scsp_write_buffer_size = 0; cdda_next_in = 0; cdda_next_out = 0; cdda_delay = CDDA_DELAY_SAMPLES; m68k_running = 0; if (scsp_thread_running) PSP_FLUSH_ALL(); } //------------------------------------------------------------------------- // ScspChangeSoundCore: Change the module used for sound output. Returns // 0 on success, -1 on error. int ScspChangeSoundCore(int coreid) { int i; // Make sure the old core is freed if (SNDCore) SNDCore->DeInit(); // If the default was requested, use the first core in the list if (coreid == SNDCORE_DEFAULT) SNDCore = SNDCoreList[0]; else { // Otherwise, go through core list and find the id for (i = 0; SNDCoreList[i] != NULL; i++) { if (SNDCoreList[i]->id == coreid) { // Set to current core SNDCore = SNDCoreList[i]; break; } } } if (SNDCore == NULL) { SNDCore = &SNDDummy; return -1; } if (SNDCore->Init() == -1) { // Since it failed, instead of it being fatal, we'll just use the dummy // core instead // This might be helpful though. YabSetError(YAB_ERR_CANNOTINIT, (void *)SNDCore->Name); SNDCore = &SNDDummy; } if (SNDCore) { if (scsp_mute_flags) SNDCore->MuteAudio(); else SNDCore->UnMuteAudio(); SNDCore->SetVolume(scsp_volume); } return 0; } //------------------------------------------------------------------------- // ScspChangeVideoFormat: Update SCSP parameters for a change in video // format. type is nonzero for PAL (50Hz), zero for NTSC (59.94Hz) video. // Always returns 0 for success. int ScspChangeVideoFormat(int type) { scsp_clock_inc = yabsys.IsPal ? SCSP_CLOCK_INC_PAL : SCSP_CLOCK_INC_NTSC; SNDCore->ChangeVideoFormat(type ? 50 : 60); return 0; } //------------------------------------------------------------------------- // ScspSetFrameAccurate: Set whether sound should be generated with // frame-accurate timing. void ScspSetFrameAccurate(int on) { scsp_frame_accurate = (on != 0); } //------------------------------------------------------------------------- // ScspMuteAudio, ScspUnMuteAudio: Mute or unmute the sound output. Does // not affect actual SCSP processing. void ScspMuteAudio(int flags) { scsp_mute_flags |= flags; if (SNDCore && scsp_mute_flags) SNDCore->MuteAudio(); } void ScspUnMuteAudio(int flags) { scsp_mute_flags &= ~flags; if (SNDCore && (scsp_mute_flags == 0)) SNDCore->UnMuteAudio(); } //------------------------------------------------------------------------- // ScspSetVolume: Set the sound output volume. Does not affect actual // SCSP processing. void ScspSetVolume(int volume) { scsp_volume = volume; if (SNDCore) SNDCore->SetVolume(volume); } //------------------------------------------------------------------------- // ScspDeInit: Free all resources used by the SCSP emulation. void ScspDeInit(void) { if (scsp_thread_running) { scsp_thread_running = 0; // Tell the subthread to stop YabThreadWake(YAB_THREAD_SCSP); YabThreadWait(YAB_THREAD_SCSP); } if (SNDCore) SNDCore->DeInit(); SNDCore = NULL; if (SoundRam) T2MemoryDeInit(SoundRam); SoundRam = NULL; } /////////////////////////////////////////////////////////////////////////// // Main SCSP processing routine and internal helpers /////////////////////////////////////////////////////////////////////////// // ScspExec: Main SCSP processing routine. Executes (decilines/10.0) // scanlines worth of SCSP emulation; in multithreaded mode, bumps the // clock target by the same amount of time. void ScspExec(int decilines) { u32 new_target; scsp_clock_frac += scsp_clock_inc * decilines; new_target = scsp_clock_target + (scsp_clock_frac >> 20); scsp_clock_target = new_target; scsp_clock_frac &= 0xFFFFF; if (scsp_thread_running) { #ifdef PSP if (!psp_writeback_cache_for_scsp()) PSP_UC(scsp_clock_target) = new_target; // Push just this one through #endif while (new_target - PSP_UC(scsp_clock) > SCSP_CLOCK_MAX_EXEC) { YabThreadWake(YAB_THREAD_SCSP); YabThreadYield(); } if (PSP_UC(scsp_main_interrupt_pending)) { (*scsp_interrupt_handler)(); PSP_UC(scsp_main_interrupt_pending) = 0; } } else ScspDoExec(new_target - scsp_clock); } /////////////////////////////////////////////////////////////////////////// // ScspThread: Control routine for SCSP thread. Loops over ScspDoExec() // and SCSP write buffer processing until told to stop. static void ScspThread(void *arg) { while (PSP_UC(scsp_thread_running)) { const u8 write_size = PSP_UC(scsp_write_buffer_size); u32 clock_cycles; if (write_size != 0) { const u32 address = PSP_UC(scsp_write_buffer_address); const u32 data = PSP_UC(scsp_write_buffer_data); if (write_size == 1) ScspWriteByteDirect(address, data); else if (write_size == 2) ScspWriteWordDirect(address, data); else { ScspWriteWordDirect(address, data >> 16); ScspWriteWordDirect(address+2, data & 0xFFFF); } PSP_UC(scsp_write_buffer_size) = 0; } clock_cycles = PSP_UC(scsp_clock_target) - scsp_clock; if (clock_cycles > SCSP_CLOCK_MAX_EXEC) clock_cycles = SCSP_CLOCK_MAX_EXEC; if (clock_cycles > 0) { ScspDoExec(clock_cycles); YabThreadYield(); } else YabThreadSleep(); } } /////////////////////////////////////////////////////////////////////////// // ScspDoExec: Main SCSP processing routine implementation. Runs M68K // code, updates timers, and generates samples for the given number of // SCSP clock cycles. static void ScspDoExec(u32 cycles) { #if 0 s16 stereodata16[(44100 / 60) * 16]; //11760 #endif u32 cycles_left; u32 sample_count; u32 audio_free; // If any of the timer interrupts are enabled, give the M68K a chance // to respond to them immediately, so that music doesn't slow down if // the SCSP thread gets behind and executes a lot of cycles at once. sample_count = 0; cycles_left = cycles; while (cycles_left > 0) { u32 this_samples = 0; u32 this_cycles = cycles_left; if (scsp.scieb & (1 << SCSP_INTERRUPT_TIMER_A)) this_cycles = MIN(this_cycles, ScspTimerCyclesLeft(scsp.tima, scsp.tactl)); if (scsp.scieb & (1 << SCSP_INTERRUPT_TIMER_B)) this_cycles = MIN(this_cycles, ScspTimerCyclesLeft(scsp.timb, scsp.tbctl)); if (scsp.scieb & (1 << SCSP_INTERRUPT_TIMER_C)) this_cycles = MIN(this_cycles, ScspTimerCyclesLeft(scsp.timc, scsp.tcctl)); scsp.sample_timer += this_cycles; this_samples = scsp.sample_timer >> 8; scsp.sample_timer &= 0xFF; cycles_left -= this_cycles; sample_count += this_samples; ScspRunM68K(this_cycles); ScspUpdateTimer(this_samples, &scsp.tima, scsp.tactl, SCSP_INTERRUPT_TIMER_A); ScspUpdateTimer(this_samples, &scsp.timb, scsp.tbctl, SCSP_INTERRUPT_TIMER_B); ScspUpdateTimer(this_samples, &scsp.timc, scsp.tcctl, SCSP_INTERRUPT_TIMER_C); } if (scsp_frame_accurate) { s32 *bufL, *bufR; // Update sound buffers if (scsp_sound_left + sample_count > SCSP_SOUND_BUFSIZE) { u32 overrun = (scsp_sound_left + sample_count) - SCSP_SOUND_BUFSIZE; SCSPLOG("WARNING: Sound buffer overrun, %u samples\n", (int)overrun); scsp_sound_left -= overrun; } while (sample_count > 0) { u32 this_count = sample_count; if (scsp_sound_genpos >= SCSP_SOUND_BUFSIZE) scsp_sound_genpos = 0; if (this_count > SCSP_SOUND_BUFSIZE - scsp_sound_genpos) this_count = SCSP_SOUND_BUFSIZE - scsp_sound_genpos; bufL = &scsp_buffer_L[scsp_sound_genpos]; bufR = &scsp_buffer_R[scsp_sound_genpos]; ScspGenerateAudio(bufL, bufR, this_count); scsp_sound_genpos += this_count; scsp_sound_left += this_count; sample_count -= this_count; } // Send audio to the output device if possible while (scsp_sound_left > 0 && (audio_free = SNDCore->GetAudioSpace()) > 0) { s32 out_start = (s32)scsp_sound_genpos - (s32)scsp_sound_left; if (out_start < 0) out_start += SCSP_SOUND_BUFSIZE; if (audio_free > scsp_sound_left) audio_free = scsp_sound_left; if (audio_free > SCSP_SOUND_BUFSIZE - out_start) audio_free = SCSP_SOUND_BUFSIZE - out_start; SNDCore->UpdateAudio((u32 *)&scsp_buffer_L[out_start], (u32 *)&scsp_buffer_R[out_start], audio_free); scsp_sound_left -= audio_free; #if 0 ScspConvert32uto16s(&scsp_buffer_L[out_start], &scsp_buffer_R[out_start], (s16 *)stereodata16, audio_free); DRV_AviSoundUpdate(stereodata16, audio_free); #endif } } else // !scsp_frame_accurate { if ((audio_free = SNDCore->GetAudioSpace())) { if (audio_free > SCSP_SOUND_BUFSIZE) audio_free = SCSP_SOUND_BUFSIZE; ScspGenerateAudio(scsp_buffer_L, scsp_buffer_R, audio_free); SNDCore->UpdateAudio((u32 *)scsp_buffer_L, (u32 *)scsp_buffer_R, audio_free); #if 0 ScspConvert32uto16s((s32 *)scsp_buffer_L, (s32 *)scsp_buffer_R, (s16 *)stereodata16, audio_free); DRV_AviSoundUpdate(stereodata16, audio_free); #endif } } // if (scsp_frame_accurate) // Update scsp_clock last, so the main thread can use it as a signal // that we've finished processing to this point scsp_clock += cycles; } //------------------------------------------------------------------------- // ScspTimerCyclesLeft: Return the approximate number of SCSP clock cycles // before an SCSP timer (A, B, or C) triggers an interrupt. static u32 ScspTimerCyclesLeft(u16 timer, u8 timer_scale) { return (0xFF00 - timer) << timer_scale; } //----------------------------------// // ScspUpdateTimer: Update an SCSP timer (A, B, or C) by the given number // of output samples, and raise an interrupt if the timer reaches 0xFF. static void ScspUpdateTimer(u32 samples, u16 *timer_ptr, u8 timer_scale, int interrupt) { u32 timer_new = *timer_ptr + (samples << (8 - timer_scale)); if (UNLIKELY(timer_new >= 0xFF00)) { ScspRaiseInterrupt(interrupt, SCSP_INTTARGET_BOTH); timer_new -= 0xFF00; // We won't pass 0xFF00 multiple times at once } *timer_ptr = timer_new; } //------------------------------------------------------------------------- // ScspGenerateAudio: Generate the given number of audio samples based on // the current SCSP state, and update the sound slot counters. static void ScspGenerateAudio(s32 *bufL, s32 *bufR, u32 samples) { int slotnum; u32 i; for (i = 0; i < samples; i++) bufL[i] = bufR[i] = 0; scsp_bufL = bufL; scsp_bufR = bufR; for (slotnum = 0; slotnum < 32; slotnum++) ScspGenerateAudioForSlot(&scsp.slot[slotnum], samples); if (cdda_next_out != PSP_UC(cdda_next_in) * 2352) { if (cdda_delay > 0) { if (samples > cdda_delay) { samples -= cdda_delay; cdda_delay = 0; } else { cdda_delay -= samples; samples = 0; } } if (cdda_delay == 0) ScspGenerateAudioForCDDA(bufL, bufR, samples); } if (cdda_next_out == PSP_UC(cdda_next_in) * 2352) cdda_delay = CDDA_DELAY_SAMPLES; // No data buffered, so reset delay } //----------------------------------// // ScspGenerateAudioForSlot: Generate audio samples and update counters for // a single slot. scsp_bufL and scsp_bufR are assumed to be set properly. static void ScspGenerateAudioForSlot(SlotState *slot, u32 samples) { if (slot->env_counter >= SCSP_ENV_DECAY_END) return; // No sound is currently playing (*slot->audiogen)(slot, samples); } //----------------------------------// // ScspGenerateAudioForCDDA: Generate audio samples for buffered CDDA data. static void ScspGenerateAudioForCDDA(s32 *bufL, s32 *bufR, u32 samples) { // May need to wrap around the buffer, so use nested loops while (samples > 0) { const u32 next_out = cdda_next_out; // Save volatile value locally const s32 temp = (PSP_UC(cdda_next_in) * 2352) - next_out; const u32 out_left = (temp < 0) ? sizeof(cdda_buf) - next_out : temp; const u32 this_len = (samples > out_left/4) ? out_left/4 : samples; const u8 *buf = &cdda_buf.data[next_out]; const u8 *top = buf + this_len*4; if (this_len == 0) break; // We ran out of buffered data for (; buf < top; buf += 4, bufL++, bufR++) { *bufL += (s32)(s16)((buf[1] << 8) | buf[0]); *bufR += (s32)(s16)((buf[3] << 8) | buf[2]); } if (next_out + this_len*4 >= sizeof(cdda_buf)) cdda_next_out = 0; else cdda_next_out = next_out + this_len*4; samples -= this_len; } } /////////////////////////////////////////////////////////////////////////// // SCSP register/memory access and I/O interface routines /////////////////////////////////////////////////////////////////////////// // SoundRam{Read,Write}{Byte,Word,Long}: Read or write sound RAM. // Intended for calling from external sources. u8 FASTCALL SoundRamReadByte(u32 address) { address &= scsp.sound_ram_mask; return T2ReadByte(SoundRam, address); } u16 FASTCALL SoundRamReadWord(u32 address) { address &= scsp.sound_ram_mask; return T2ReadWord(SoundRam, address); } u32 FASTCALL SoundRamReadLong(u32 address) { address &= scsp.sound_ram_mask; return T2ReadLong(SoundRam, address); } //----------------------------------// void FASTCALL SoundRamWriteByte(u32 address, u8 data) { address &= scsp.sound_ram_mask; T2WriteByte(SoundRam, address, data); M68K->WriteNotify(address, 1); } void FASTCALL SoundRamWriteWord(u32 address, u16 data) { address &= scsp.sound_ram_mask; T2WriteWord(SoundRam, address, data); M68K->WriteNotify(address, 2); } void FASTCALL SoundRamWriteLong(u32 address, u32 data) { address &= scsp.sound_ram_mask; T2WriteLong(SoundRam, address, data); M68K->WriteNotify(address, 4); } //------------------------------------------------------------------------- // Scsp{Read,Write}{Byte,Word,Long}: Read or write SCSP registers. // Intended for calling from external sources. u8 FASTCALL ScspReadByte(u32 address) { const u16 data = ScspReadWord(address & ~1); if (address & 1) return data & 0xFF; else return data >> 8; } u16 FASTCALL ScspReadWord(u32 address) { #ifdef PSP // Special handling for PSP cache management switch (address) { case 0x404: // MIDI in return 0xFF; // Not even supported, so don't bother trying case 0x408: // CA/SGC/EG return ScspReadMonitor(); default: return PSP_UC(scsp_regcache[address >> 1]); } #else return ScspReadWordDirect(address & 0xFFF); #endif } u32 FASTCALL ScspReadLong(u32 address) { return (u32)ScspReadWord(address) << 16 | ScspReadWord(address+2); } //----------------------------------// void FASTCALL ScspWriteByte(u32 address, u8 data) { if (scsp_thread_running) { PSP_UC(scsp_write_buffer_address) = address & 0xFFF; PSP_UC(scsp_write_buffer_data) = data; PSP_UC(scsp_write_buffer_size) = 1; while (PSP_UC(scsp_write_buffer_size) != 0) { YabThreadWake(YAB_THREAD_SCSP); YabThreadYield(); } return; } ScspWriteByteDirect(address & 0xFFF, data); } void FASTCALL ScspWriteWord(u32 address, u16 data) { if (scsp_thread_running) { PSP_UC(scsp_write_buffer_address) = address & 0xFFF; PSP_UC(scsp_write_buffer_data) = data; PSP_UC(scsp_write_buffer_size) = 2; while (PSP_UC(scsp_write_buffer_size) != 0) { YabThreadWake(YAB_THREAD_SCSP); YabThreadYield(); } return; } ScspWriteWordDirect(address & 0xFFF, data); } void FASTCALL ScspWriteLong(u32 address, u32 data) { if (scsp_thread_running) { PSP_UC(scsp_write_buffer_address) = address & 0xFFF; PSP_UC(scsp_write_buffer_data) = data; PSP_UC(scsp_write_buffer_size) = 4; while (PSP_UC(scsp_write_buffer_size) != 0) { YabThreadWake(YAB_THREAD_SCSP); YabThreadYield(); } return; } ScspWriteWordDirect(address & 0xFFF, data >> 16); ScspWriteWordDirect((address+2) & 0xFFF, data & 0xFFFF); } //------------------------------------------------------------------------- // ScspReceiveCDDA: Receive and buffer a sector (2352 bytes) of CDDA audio // data. Intended to be called by the CD driver when an audio sector has // been read in for playback. void ScspReceiveCDDA(const u8 *sector) { const u32 next_in = cdda_next_in; // Save volatile value locally const u32 next_next_in = (next_in + 1) % (sizeof(cdda_buf.sectors) / sizeof(cdda_buf.sectors[0])); // Make sure we have room for the new sector first const u32 next_out = PSP_UC(cdda_next_out); if (next_out > next_in * 2352 && next_out <= (next_in+1) * 2352) { SCSPLOG("WARNING: CDDA buffer overflow, discarding sector\n"); return; } memcpy(cdda_buf.sectors[next_in], sector, 2352); PSP_WRITEBACK_CACHE(cdda_buf.sectors[next_in], 2352); cdda_next_in = next_next_in; } /////////////////////////////////////////////////////////////////////////// // Miscellaneous SCSP interface routines /////////////////////////////////////////////////////////////////////////// // SoundSaveState: Save the current SCSP state to the given file. int SoundSaveState(FILE *fp) { int i; u32 temp; u8 temp8; int offset; IOCheck_struct check = { 0, 0 }; if (scsp_thread_running) ScspSyncThread(); offset = StateWriteHeader(fp, "SCSP", 2); // Save 68k registers first ywrite(&check, (void *)&m68k_running, 1, 1, fp); for (i = 0; i < 8; i++) { temp = M68K->GetDReg(i); ywrite(&check, (void *)&temp, 4, 1, fp); } for (i = 0; i < 8; i++) { temp = M68K->GetAReg(i); ywrite(&check, (void *)&temp, 4, 1, fp); } temp = M68K->GetSR(); ywrite(&check, (void *)&temp, 4, 1, fp); temp = M68K->GetPC(); ywrite(&check, (void *)&temp, 4, 1, fp); // Now for the SCSP registers ywrite(&check, (void *)scsp_regcache, 0x1000, 1, fp); // Sound RAM is important ywrite(&check, (void *)SoundRam, 0x80000, 1, fp); // Write slot internal variables for (i = 0; i < 32; i++) { ywrite(&check, (void *)&scsp.slot[i].key, 1, 1, fp); ywrite(&check, (void *)&scsp.slot[i].addr_counter, 4, 1, fp); ywrite(&check, (void *)&scsp.slot[i].env_counter, 4, 1, fp); ywrite(&check, (void *)&scsp.slot[i].env_step, 4, 1, fp); ywrite(&check, (void *)&scsp.slot[i].env_target, 4, 1, fp); ywrite(&check, (void *)&scsp.slot[i].env_phase, 4, 1, fp); // Was enxt in scsp1; we don't use it, so just derive the proper // value from env_phase if (scsp.slot[i].env_phase == SCSP_ENV_RELEASE) temp8 = 1; else if (scsp.slot[i].env_phase == SCSP_ENV_SUSTAIN) temp8 = 2; else if (scsp.slot[i].env_phase == SCSP_ENV_DECAY) temp8 = 3; else if (scsp.slot[i].env_phase == SCSP_ENV_ATTACK) temp8 = 4; else // impossible, but avoid "undefined value" warnings temp8 = 0; ywrite(&check, (void *)&temp8, 1, 1, fp); ywrite(&check, (void *)&scsp.slot[i].lfo_counter, 4, 1, fp); ywrite(&check, (void *)&scsp.slot[i].lfo_step, 4, 1, fp); } // Write main internal variables // FIXME/SCSP1: need to write a lot of these from temporary variables // to maintain save state compatibility temp = scsp.mem4mb; ywrite(&check, (void *)&temp, 4, 1, fp); temp = scsp.mvol; ywrite(&check, (void *)&temp, 4, 1, fp); temp = scsp.rbl; ywrite(&check, (void *)&temp, 4, 1, fp); ywrite(&check, (void *)&scsp.rbp, 4, 1, fp); temp = scsp.mslc; ywrite(&check, (void *)&temp, 4, 1, fp); ywrite(&check, (void *)&scsp.dmea, 4, 1, fp); temp = scsp.drga; ywrite(&check, (void *)&temp, 4, 1, fp); temp = scsp.dgate<<6 | scsp.ddir<<5 | scsp.dexe<<4; ywrite(&check, (void *)&temp, 4, 1, fp); temp = scsp.dtlg; ywrite(&check, (void *)&temp, 4, 1, fp); ywrite(&check, (void *)scsp.midi_in_buf, 1, 4, fp); ywrite(&check, (void *)scsp.midi_out_buf, 1, 4, fp); ywrite(&check, (void *)&scsp.midi_in_cnt, 1, 1, fp); ywrite(&check, (void *)&scsp.midi_out_cnt, 1, 1, fp); temp8 = scsp.mofull<<4 | scsp.moemp<<3 | scsp.miovf<<2 | scsp.mifull<<1 | scsp.miemp<<0; ywrite(&check, (void *)&temp8, 1, 1, fp); temp = scsp.tima; ywrite(&check, (void *)&temp, 4, 1, fp); temp = scsp.tactl; ywrite(&check, (void *)&temp, 4, 1, fp); temp = scsp.timb; ywrite(&check, (void *)&temp, 4, 1, fp); temp = scsp.tbctl; ywrite(&check, (void *)&temp, 4, 1, fp); temp = scsp.timc; ywrite(&check, (void *)&temp, 4, 1, fp); temp = scsp.tcctl; ywrite(&check, (void *)&temp, 4, 1, fp); temp = scsp.scieb; ywrite(&check, (void *)&temp, 4, 1, fp); temp = scsp.scipd; ywrite(&check, (void *)&temp, 4, 1, fp); temp = scsp.scilv0; ywrite(&check, (void *)&temp, 4, 1, fp); temp = scsp.scilv1; ywrite(&check, (void *)&temp, 4, 1, fp); temp = scsp.scilv2; ywrite(&check, (void *)&temp, 4, 1, fp); temp = scsp.mcieb; ywrite(&check, (void *)&temp, 4, 1, fp); temp = scsp.mcipd; ywrite(&check, (void *)&temp, 4, 1, fp); ywrite(&check, (void *)scsp.stack, 4, 32 * 2, fp); return StateFinishHeader(fp, offset); } //------------------------------------------------------------------------- // SoundLoadState: Load the current SCSP state from the given file. int SoundLoadState(FILE *fp, int version, int size) { int i, i2; u32 temp; u8 temp8; IOCheck_struct check = { 0, 0 }; if (scsp_thread_running) ScspSyncThread(); // Read 68k registers first yread(&check, (void *)&m68k_running, 1, 1, fp); for (i = 0; i < 8; i++) { yread(&check, (void *)&temp, 4, 1, fp); M68K->SetDReg(i, temp); } for (i = 0; i < 8; i++) { yread(&check, (void *)&temp, 4, 1, fp); M68K->SetAReg(i, temp); } yread(&check, (void *)&temp, 4, 1, fp); M68K->SetSR(temp); yread(&check, (void *)&temp, 4, 1, fp); M68K->SetPC(temp); // Now for the SCSP registers yread(&check, (void *)scsp_regcache, 0x1000, 1, fp); // And sound RAM yread(&check, (void *)SoundRam, 0x80000, 1, fp); // Break out slot registers into their respective fields for (i = 0; i < 32; i++) { for (i2 = 0; i2 < 0x18; i2 += 2) ScspWriteWordDirect(i<<5 | i2, scsp_regcache[(i<<5 | i2) >> 1]); // These are also called during writes, so they're not technically // necessary, but call them again anyway just to ensure everything's // up to date ScspUpdateSlotAddress(&scsp.slot[i]); ScspUpdateSlotFunc(&scsp.slot[i]); } if (version > 1) { // Read slot internal variables for (i = 0; i < 32; i++) { yread(&check, (void *)&scsp.slot[i].key, 1, 1, fp); yread(&check, (void *)&scsp.slot[i].addr_counter, 4, 1, fp); yread(&check, (void *)&scsp.slot[i].env_counter, 4, 1, fp); yread(&check, (void *)&scsp.slot[i].env_step, 4, 1, fp); yread(&check, (void *)&scsp.slot[i].env_target, 4, 1, fp); yread(&check, (void *)&scsp.slot[i].env_phase, 4, 1, fp); // Was enxt in scsp1; we don't use it, so just read and ignore yread(&check, (void *)&temp8, 1, 1, fp); yread(&check, (void *)&scsp.slot[i].lfo_counter, 4, 1, fp); yread(&check, (void *)&scsp.slot[i].lfo_step, 4, 1, fp); } // Read main internal variables yread(&check, (void *)&temp, 4, 1, fp); scsp.mem4mb = temp; // This one isn't saved in the state file (though it's not used anyway) scsp.dac18b = (scsp_regcache[0x400>>1] >> 8) & 1; yread(&check, (void *)&temp, 4, 1, fp); scsp.mvol = temp; yread(&check, (void *)&temp, 4, 1, fp); scsp.rbl = temp; yread(&check, (void *)&scsp.rbp, 4, 1, fp); yread(&check, (void *)&temp, 4, 1, fp); scsp.mslc = temp; yread(&check, (void *)&scsp.dmea, 4, 1, fp); yread(&check, (void *)&temp, 4, 1, fp); scsp.drga = temp; yread(&check, (void *)&temp, 4, 1, fp); scsp.dgate = temp>>6 & 1; scsp.ddir = temp>>5 & 1; scsp.dexe = temp>>4 & 1; yread(&check, (void *)&temp, 4, 1, fp); scsp.dtlg = temp; yread(&check, (void *)scsp.midi_in_buf, 1, 4, fp); yread(&check, (void *)scsp.midi_out_buf, 1, 4, fp); yread(&check, (void *)&scsp.midi_in_cnt, 1, 1, fp); yread(&check, (void *)&scsp.midi_out_cnt, 1, 1, fp); yread(&check, (void *)&temp8, 1, 1, fp); scsp.mofull = temp8>>4 & 1; scsp.moemp = temp8>>3 & 1; scsp.miovf = temp8>>2 & 1; scsp.mifull = temp8>>1 & 1; scsp.miemp = temp8>>0 & 1; yread(&check, (void *)&temp, 4, 1, fp); scsp.tima = temp; yread(&check, (void *)&temp, 4, 1, fp); scsp.tactl = temp; yread(&check, (void *)&temp, 4, 1, fp); scsp.timb = temp; yread(&check, (void *)&temp, 4, 1, fp); scsp.tbctl = temp; yread(&check, (void *)&temp, 4, 1, fp); scsp.timc = temp; yread(&check, (void *)&temp, 4, 1, fp); scsp.tcctl = temp; yread(&check, (void *)&temp, 4, 1, fp); scsp.scieb = temp; yread(&check, (void *)&temp, 4, 1, fp); scsp.scipd = temp; yread(&check, (void *)&temp, 4, 1, fp); scsp.scilv0 = temp; yread(&check, (void *)&temp, 4, 1, fp); scsp.scilv1 = temp; yread(&check, (void *)&temp, 4, 1, fp); scsp.scilv2 = temp; yread(&check, (void *)&temp, 4, 1, fp); scsp.mcieb = temp; yread(&check, (void *)&temp, 4, 1, fp); scsp.mcipd = temp; yread(&check, (void *)scsp.stack, 4, 32 * 2, fp); } if (scsp_thread_running) PSP_FLUSH_ALL(); return size; } //------------------------------------------------------------------------- // ScspSlotDebugStats: Generate a string describing the given slot's state // and store it in the passed-in buffer (which is assumed to be large enough // to hold the result). // Helper functions (defined below) static char *AddSoundLFO(char *outstring, const char *string, u16 level, u16 waveform); static char *AddSoundPan(char *outstring, u16 pan); static char *AddSoundLevel(char *outstring, u16 level); void ScspSlotDebugStats(u8 slotnum, char *outstring) { AddString(outstring, "Sound Source = "); switch (scsp.slot[slotnum].ssctl) { case 0: { AddString(outstring, "External DRAM data\r\n"); break; } case 1: { AddString(outstring, "Internal(Noise)\r\n"); break; } case 2: { AddString(outstring, "Internal(0's)\r\n"); break; } default: { AddString(outstring, "Invalid setting\r\n"); break; } } AddString(outstring, "Source bit = "); switch (scsp.slot[slotnum].sbctl) { case 0: { AddString(outstring, "No bit reversal\r\n"); break; } case 1: { AddString(outstring, "Reverse other bits\r\n"); break; } case 2: { AddString(outstring, "Reverse sign bit\r\n"); break; } case 3: { AddString(outstring, "Reverse sign and other bits\r\n"); break; } } // Loop Control AddString(outstring, "Loop Mode = "); switch (scsp.slot[slotnum].lpctl) { case 0: { AddString(outstring, "Off\r\n"); break; } case 1: { AddString(outstring, "Normal\r\n"); break; } case 2: { AddString(outstring, "Reverse\r\n"); break; } case 3: { AddString(outstring, "Alternating\r\n"); break; } } // PCM8B if (scsp.slot[slotnum].pcm8b) { AddString(outstring, "8-bit samples\r\n"); } else { AddString(outstring, "16-bit samples\r\n"); } AddString(outstring, "Start Address = %05lX\r\n", (unsigned long)scsp.slot[slotnum].sa); AddString(outstring, "Loop Start Address = %04X\r\n", scsp.slot[slotnum].lsa); AddString(outstring, "Loop End Address = %04X\r\n", scsp.slot[slotnum].lea); AddString(outstring, "Decay 1 Rate = %d\r\n", scsp.slot[slotnum].dr); AddString(outstring, "Decay 2 Rate = %d\r\n", scsp.slot[slotnum].sr); if (scsp.slot[slotnum].eghold) { AddString(outstring, "EG Hold Enabled\r\n"); } AddString(outstring, "Attack Rate = %d\r\n", scsp.slot[slotnum].ar); if (scsp.slot[slotnum].lpslnk) { AddString(outstring, "Loop Start Link Enabled\r\n"); } if (scsp.slot[slotnum].krs != 0) { AddString(outstring, "Key rate scaling = %d\r\n", scsp.slot[slotnum].krs); } AddString(outstring, "Decay Level = %d\r\n", scsp.slot[slotnum].sl); AddString(outstring, "Release Rate = %d\r\n", scsp.slot[slotnum].rr); if (scsp.slot[slotnum].stwinh) { AddString(outstring, "Stack Write Inhibited\r\n"); } if (scsp.slot[slotnum].sdir) { AddString(outstring, "Sound Direct Enabled\r\n"); } AddString(outstring, "Total Level = %d\r\n", scsp.slot[slotnum].tl); AddString(outstring, "Modulation Level = %d\r\n", scsp.slot[slotnum].mdl); AddString(outstring, "Modulation Input X = %d\r\n", scsp.slot[slotnum].mdx); AddString(outstring, "Modulation Input Y = %d\r\n", scsp.slot[slotnum].mdy); AddString(outstring, "Octave = %d\r\n", scsp.slot[slotnum].oct); AddString(outstring, "Frequency Number Switch = %d\r\n", scsp.slot[slotnum].fns); AddString(outstring, "LFO Reset = %s\r\n", scsp.slot[slotnum].lfore ? "TRUE" : "FALSE"); AddString(outstring, "LFO Frequency = %d\r\n", scsp.slot[slotnum].lfof); outstring = AddSoundLFO(outstring, "LFO Frequency modulation waveform =", scsp.slot[slotnum].plfos, scsp.slot[slotnum].plfows); AddString(outstring, "LFO Frequency modulation level = %d\r\n", scsp.slot[slotnum].plfos); outstring = AddSoundLFO(outstring, "LFO Amplitude modulation waveform =", scsp.slot[slotnum].alfos, scsp.slot[slotnum].alfows); AddString(outstring, "LFO Amplitude modulation level = %d\r\n", scsp.slot[slotnum].alfos); AddString(outstring, "Input mix level = "); outstring = AddSoundLevel(outstring, scsp.slot[slotnum].imxl); AddString(outstring, "Input Select = %d\r\n", scsp.slot[slotnum].isel); AddString(outstring, "Direct data send level = "); outstring = AddSoundLevel(outstring, scsp.slot[slotnum].disdl); AddString(outstring, "Direct data panpot = "); outstring = AddSoundPan(outstring, scsp.slot[slotnum].dipan); AddString(outstring, "Effect data send level = "); outstring = AddSoundLevel(outstring, scsp.slot[slotnum].efsdl); AddString(outstring, "Effect data panpot = "); outstring = AddSoundPan(outstring, scsp.slot[slotnum].efpan); } //----------------------------------// static char *AddSoundLFO(char *outstring, const char *string, u16 level, u16 waveform) { if (level > 0) { switch (waveform) { case 0: AddString(outstring, "%s Sawtooth\r\n", string); break; case 1: AddString(outstring, "%s Square\r\n", string); break; case 2: AddString(outstring, "%s Triangle\r\n", string); break; case 3: AddString(outstring, "%s Noise\r\n", string); break; } } return outstring; } //----------------------------------// static char *AddSoundPan(char *outstring, u16 pan) { if (pan == 0x0F) { AddString(outstring, "Left = -MAX dB, Right = -0 dB\r\n"); } else if (pan == 0x1F) { AddString(outstring, "Left = -0 dB, Right = -MAX dB\r\n"); } else { AddString(outstring, "Left = -%d dB, Right = -%d dB\r\n", (pan & 0xF) * 3, (pan >> 4) * 3); } return outstring; } //----------------------------------// static char *AddSoundLevel(char *outstring, u16 level) { if (level == 0) { AddString(outstring, "-MAX dB\r\n"); } else { AddString(outstring, "-%d dB\r\n", (7-level) * 6); } return outstring; } //------------------------------------------------------------------------- // ScspCommonControlRegisterDebugStats: Generate a string describing the // SCSP common state registers and store it in the passed-in buffer (which // is assumed to be large enough to hold the result). void ScspCommonControlRegisterDebugStats(char *outstring) { AddString(outstring, "Memory: %s\r\n", scsp.mem4mb ? "4 Mbit" : "2 Mbit"); AddString(outstring, "Master volume: %d\r\n", scsp.mvol); AddString(outstring, "Ring buffer length: %d\r\n", scsp.rbl); AddString(outstring, "Ring buffer address: %08lX\r\n", (unsigned long)scsp.rbp); AddString(outstring, "\r\n"); AddString(outstring, "Slot Status Registers\r\n"); AddString(outstring, "-----------------\r\n"); AddString(outstring, "Monitor slot: %d\r\n", scsp.mslc); AddString(outstring, "Call address: %d\r\n", (ScspReadWordDirect(0x408) >> 7) & 0xF); AddString(outstring, "\r\n"); AddString(outstring, "DMA Registers\r\n"); AddString(outstring, "-----------------\r\n"); AddString(outstring, "DMA memory address start: %08lX\r\n", (unsigned long)scsp.dmea); AddString(outstring, "DMA register address start: %03X\r\n", scsp.drga); AddString(outstring, "DMA Flags: %02X (%cDGATE %cDDIR %cDEXE)\r\n", scsp.dgate<<6 | scsp.ddir<<5 | scsp.dexe<<4, scsp.dgate ? '+' : '-', scsp.ddir ? '+' : '-', scsp.dexe ? '+' : '-'); AddString(outstring, "\r\n"); AddString(outstring, "Timer Registers\r\n"); AddString(outstring, "-----------------\r\n"); AddString(outstring, "Timer A counter: %02X\r\n", scsp.tima >> 8); AddString(outstring, "Timer A increment: Every %d sample(s)\r\n", 1 << scsp.tactl); AddString(outstring, "Timer B counter: %02X\r\n", scsp.timb >> 8); AddString(outstring, "Timer B increment: Every %d sample(s)\r\n", 1 << scsp.tbctl); AddString(outstring, "Timer C counter: %02X\r\n", scsp.timc >> 8); AddString(outstring, "Timer C increment: Every %d sample(s)\r\n", 1 << scsp.tcctl); AddString(outstring, "\r\n"); AddString(outstring, "Interrupt Registers\r\n"); AddString(outstring, "-----------------\r\n"); AddString(outstring, "Sound cpu interrupt pending: %04X\r\n", scsp.scipd); AddString(outstring, "Sound cpu interrupt enable: %04X\r\n", scsp.scieb); AddString(outstring, "Sound cpu interrupt level 0: %04X\r\n", scsp.scilv0); AddString(outstring, "Sound cpu interrupt level 1: %04X\r\n", scsp.scilv1); AddString(outstring, "Sound cpu interrupt level 2: %04X\r\n", scsp.scilv2); AddString(outstring, "Main cpu interrupt pending: %04X\r\n", scsp.mcipd); AddString(outstring, "Main cpu interrupt enable: %04X\r\n", scsp.mcieb); AddString(outstring, "\r\n"); } //------------------------------------------------------------------------- // ScspSlotDebugSaveRegisters: Write the values of a single slot's // registers to a file. int ScspSlotDebugSaveRegisters(u8 slotnum, const char *filename) { FILE *fp; int i; IOCheck_struct check = { 0, 0 }; if ((fp = fopen(filename, "wb")) == NULL) return -1; for (i = (slotnum * 0x20); i < ((slotnum+1) * 0x20); i += 2) { #ifdef WORDS_BIGENDIAN ywrite(&check, (void *)&scsp_regcache[i], 1, 2, fp); #else ywrite(&check, (void *)&scsp_regcache[i+1], 1, 1, fp); ywrite(&check, (void *)&scsp_regcache[i], 1, 1, fp); #endif } fclose(fp); return 0; } //------------------------------------------------------------------------- // ScspSlotDebugAudioSaveWav: Generate audio for a single slot and save it // to a WAV file. // Helper function to generate audio (defined below) static u32 ScspSlotDebugAudio(SlotState *slot, s32 *workbuf, s16 *buf, u32 len); int ScspSlotDebugAudioSaveWav(u8 slotnum, const char *filename) { typedef struct { char id[4]; u32 size; } chunk_struct; typedef struct { chunk_struct riff; char rifftype[4]; } waveheader_struct; typedef struct { chunk_struct chunk; u16 compress; u16 numchan; u32 rate; u32 bytespersec; u16 blockalign; u16 bitspersample; } fmt_struct; s32 workbuf[512*2*2]; s16 buf[512*2]; SlotState slot; FILE *fp; u32 counter = 0; waveheader_struct waveheader; fmt_struct fmt; chunk_struct data; long length; IOCheck_struct check = { 0, 0 }; if (scsp.slot[slotnum].lea == 0) return 0; if ((fp = fopen(filename, "wb")) == NULL) return -1; // Do wave header memcpy(waveheader.riff.id, "RIFF", 4); waveheader.riff.size = 0; // we'll fix this after the file is closed memcpy(waveheader.rifftype, "WAVE", 4); ywrite(&check, (void *)&waveheader, 1, sizeof(waveheader_struct), fp); // fmt chunk memcpy(fmt.chunk.id, "fmt ", 4); fmt.chunk.size = 16; // we'll fix this at the end fmt.compress = 1; // PCM fmt.numchan = 2; // Stereo fmt.rate = 44100; fmt.bitspersample = 16; fmt.blockalign = fmt.bitspersample / 8 * fmt.numchan; fmt.bytespersec = fmt.rate * fmt.blockalign; ywrite(&check, (void *)&fmt, 1, sizeof(fmt_struct), fp); // data chunk memcpy(data.id, "data", 4); data.size = 0; // we'll fix this at the end ywrite(&check, (void *)&data, 1, sizeof(chunk_struct), fp); memcpy(&slot, &scsp.slot[slotnum], sizeof(slot)); // Clear out the phase counter, etc. slot.addr_counter = 0; slot.env_counter = SCSP_ENV_ATTACK_START; slot.env_step = slot.env_step_a; slot.env_target = SCSP_ENV_ATTACK_END; slot.env_phase = SCSP_ENV_ATTACK; // Mix the audio, and then write it to the file for(;;) { if (ScspSlotDebugAudio(&slot, workbuf, buf, 512) == 0) break; counter += 512; ywrite(&check, (void *)buf, 2, 512 * 2, fp); if (slot.lpctl != 0 && counter >= (44100 * 2 * 5)) break; } length = ftell(fp); // Let's fix the riff chunk size and the data chunk size fseek(fp, sizeof(waveheader_struct)-0x8, SEEK_SET); length -= 0x4; ywrite(&check, (void *)&length, 1, 4, fp); fseek(fp, sizeof(waveheader_struct)+sizeof(fmt_struct)+0x4, SEEK_SET); length -= sizeof(waveheader_struct)+sizeof(fmt_struct); ywrite(&check, (void *)&length, 1, 4, fp); fclose(fp); return 0; } //----------------------------------// static u32 ScspSlotDebugAudio(SlotState *slot, s32 *workbuf, s16 *buf, u32 len) { s32 *bufL, *bufR; bufL = workbuf; bufR = workbuf+len; scsp_bufL = bufL; scsp_bufR = bufR; if (slot->env_counter >= SCSP_ENV_DECAY_END) return 0; // Not playing if (slot->ssctl) return 0; // not yet supported! memset(bufL, 0, sizeof(u32) * len); memset(bufR, 0, sizeof(u32) * len); ScspGenerateAudioForSlot(slot, len); ScspConvert32uto16s(bufL, bufR, buf, len); return len; } //------------------------------------------------------------------------- // ScspConvert32uto16s: Saturate two 32-bit input sample buffers to 16-bit // and interleave them into a single output buffer. void ScspConvert32uto16s(s32 *srcL, s32 *srcR, s16 *dest, u32 len) { u32 i; for (i = 0; i < len; i++, srcL++, srcR++, dest += 2) { // Left channel if (*srcL > 0x7FFF) dest[0] = 0x7FFF; else if (*srcL < -0x8000) dest[0] = -0x8000; else dest[0] = *srcL; // Right channel if (*srcR > 0x7FFF) dest[1] = 0x7FFF; else if (*srcR < -0x8000) dest[1] = -0x8000; else dest[1] = *srcR; } } /////////////////////////////////////////////////////////////////////////// // SCSP register read/write routines and internal helpers /////////////////////////////////////////////////////////////////////////// // Scsp{Read,Write}{Byte,Word}Direct: Perform an SCSP register read or // write. These are internal routines that implement the actual register // read/write logic. The address must be in the range [0,0xFFF]. static u8 FASTCALL ScspReadByteDirect(u32 address) { const u16 data = ScspReadWordDirect(address & ~1); if (address & 1) return data & 0xFF; else return data >> 8; } //----------------------------------// static u16 ScspReadMonitor(void) { u8 ca, sgc, eg; ca = (scsp.slot[scsp.mslc].addr_counter >> (SCSP_FREQ_LOW_BITS + 12)) & 0xF; switch (scsp.slot[scsp.mslc].env_phase) { case SCSP_ENV_ATTACK: sgc = 0; break; case SCSP_ENV_DECAY: sgc = 1; break; case SCSP_ENV_SUSTAIN: sgc = 2; break; case SCSP_ENV_RELEASE: sgc = 3; break; } eg = 0x1f - (scsp.slot[scsp.mslc].last_env >> 27); return (ca << 7) | (sgc << 5) | eg; } static u16 FASTCALL ScspReadWordDirect(u32 address) { switch (address) { case 0x404: // MIDI in return ScspMidiIn(); case 0x408: // CA/SGC/EG return ScspReadMonitor(); default: return PSP_UC(scsp_regcache[address >> 1]); } } //----------------------------------// static void FASTCALL ScspWriteByteDirect(u32 address, u8 data) { switch (address >> 8) { case 0x0: case 0x1: case 0x2: case 0x3: write_as_word: { // These can be treated as word writes, borrowing the missing // 8 bits from the register cache u16 word_data; if (address & 1) word_data = (PSP_UC(scsp_regcache[address >> 1]) & 0xFF00) | data; else word_data = (PSP_UC(scsp_regcache[address >> 1]) & 0x00FF) | (data << 8); ScspWriteWordDirect(address & ~1, word_data); return; } case 0x4: switch (address & 0xFF) { // FIXME: if interrupts are only triggered on 0->1 changes in // [SM]CIEB, we can skip 0x1E/0x1F/0x26/0x27 (see FIXME in // ScspWriteWordDirect()) case 0x1E: data &= 0x07; scsp.scieb = (data << 8) | (scsp.scieb & 0x00FF); ScspCheckInterrupts(0x700, SCSP_INTTARGET_SOUND); break; case 0x1F: scsp.scieb = (scsp.scieb & 0xFF00) | data; ScspCheckInterrupts(0x700, SCSP_INTTARGET_SOUND); break; case 0x20: return; // Not writable case 0x21: if (data & (1<<5)) ScspRaiseInterrupt(5, SCSP_INTTARGET_SOUND); return; // Not writable case 0x2A: data &= 0x07; scsp.mcieb = (data << 8) | (scsp.mcieb & 0x00FF); ScspCheckInterrupts(0x700, SCSP_INTTARGET_MAIN); break; case 0x2B: scsp.mcieb = (scsp.mcieb & 0xFF00) | data; ScspCheckInterrupts(0x700, SCSP_INTTARGET_MAIN); break; case 0x2C: return; // Not writable case 0x2D: if (data & (1<<5)) ScspRaiseInterrupt(5, SCSP_INTTARGET_MAIN); return; // Not writable case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2E: case 0x2F: goto write_as_word; default: goto unhandled_write; } break; default: unhandled_write: SCSPLOG("ScspWriteByteDirect(): unhandled write %02X to 0x%03X\n", data, address); break; } if (address & 1) { PSP_UC(scsp_regcache[address >> 1]) &= 0xFF00; PSP_UC(scsp_regcache[address >> 1]) |= data; } else { PSP_UC(scsp_regcache[address >> 1]) &= 0x00FF; PSP_UC(scsp_regcache[address >> 1]) |= data << 8; } } //----------------------------------// static void FASTCALL ScspWriteWordDirect(u32 address, u16 data) { switch (address >> 8) { case 0x0: case 0x1: case 0x2: case 0x3: { const int slotnum = (address & 0x3E0) >> 5; SlotState *slot = &scsp.slot[slotnum]; switch (address & 0x1F) { case 0x00: slot->key = (data >> 11) & 0x1; slot->sbctl = (data >> 9) & 0x3; slot->ssctl = (data >> 7) & 0x3; slot->lpctl = (data >> 5) & 0x3; slot->pcm8b = (data >> 4) & 0x1; slot->sa =((data >> 0) & 0xF) << 16 | (slot->sa & 0xFFFF); ScspUpdateSlotFunc(slot); if (slot->env_counter < SCSP_ENV_DECAY_END) ScspUpdateSlotAddress(slot); if (data & (1<<12)) ScspDoKeyOnOff(); data &= 0x0FFF; // Don't save KYONEX break; case 0x02: slot->sa = (slot->sa & 0xF0000) | data; if (slot->env_counter < SCSP_ENV_DECAY_END) ScspUpdateSlotAddress(slot); break; case 0x04: slot->lsa = data; if (slot->env_counter < SCSP_ENV_DECAY_END) ScspUpdateSlotAddress(slot); break; case 0x06: slot->lea = data; if (slot->env_counter < SCSP_ENV_DECAY_END) ScspUpdateSlotAddress(slot); break; case 0x08: slot->sr = (data >> 11) & 0x1F; slot->dr = (data >> 6) & 0x1F; slot->eghold = (data >> 5) & 0x1; slot->ar = (data >> 0) & 0x1F; ScspUpdateSlotEnv(slot); break; case 0x0A: data &= 0x7FFF; slot->lpslnk = (data >> 14) & 0x1; slot->krs = (data >> 10) & 0xF; slot->sl = (data >> 5) & 0x1F; slot->rr = (data >> 0) & 0x1F; if (slot->krs == 0xF) slot->krs_shift = 4; else slot->krs_shift = slot->krs >> 2; ScspUpdateSlotEnv(slot); slot->sl_target = (slot->sl << (5 + SCSP_ENV_LOW_BITS)) + SCSP_ENV_DECAY_START; break; case 0x0C: data &= 0x03FF; slot->stwinh = (data >> 9) & 0x1; slot->sdir = (data >> 8) & 0x1; slot->tl = (data >> 0) & 0xFF; slot->tl_mult = scsp_tl_table[slot->tl]; break; case 0x0E: slot->mdl = (data >> 12) & 0xF; slot->mdx = (data >> 6) & 0x3F; slot->mdy = (data >> 0) & 0x3F; break; case 0x10: data &= 0x7BFF; slot->oct = (data >> 11) & 0xF; slot->fns = (data >> 0) & 0x3FF; if (slot->oct & 8) slot->octave_shift = 23 - slot->oct; else slot->octave_shift = 7 - slot->oct; slot->addr_step = ((0x400 + slot->fns) << 7) >> slot->octave_shift; ScspUpdateSlotEnv(slot); break; case 0x12: slot->lfore = (data >> 15) & 0x1; slot->lfof = (data >> 10) & 0x1F; slot->plfows = (data >> 8) & 0x3; slot->plfos = (data >> 5) & 0x7; slot->alfows = (data >> 3) & 0x3; slot->alfos = (data >> 0) & 0x7; if (slot->lfore) { slot->lfo_step = -1; slot->lfo_counter = 0; slot->lfo_fm_shift = -1; slot->lfo_am_shift = -1; } else { slot->lfo_step = scsp_lfo_step[slot->lfof]; if (slot->plfos) slot->lfo_fm_shift = slot->plfos - 1; else slot->lfo_fm_shift = -1; if (slot->alfos) slot->lfo_am_shift = 11 - slot->alfos; else slot->lfo_am_shift = -1; } slot->lfo_fm_wave = scsp_lfo_wave_freq[slot->plfows]; slot->lfo_am_wave = scsp_lfo_wave_amp[slot->alfows]; ScspUpdateSlotFunc(slot); break; case 0x14: data &= 0x007F; slot->isel = (data >> 3) & 0xF; slot->imxl = (data >> 0) & 0x7; if (slot->imxl) slot->imxl_shift = (7 - slot->imxl) + SCSP_ENV_HIGH_BITS; else slot->imxl_shift = 31; break; case 0x16: slot->disdl = (data >> 13) & 0x7; slot->dipan = (data >> 8) & 0x1F; slot->efsdl = (data >> 5) & 0x7; slot->efpan = (data >> 0) & 0x1F; // Compute the output shift counts for the left and right // channels. If the direct sound output is muted, we assume // the data is being passed through the DSP (which we don't // currently implement) and take the effect output level // instead. Note that we lose 1 bit of resolution from the // panning parameter because we adjust the output level by // shifting (powers of two), while DIPAN/EFPAN have a // resolution of sqrt(2). if (slot->disdl) { slot->outshift_l = slot->outshift_r = (7 - slot->disdl) + SCSP_ENV_HIGH_BITS; if (slot->dipan & 0x10) // Pan left { if (slot->dipan == 0x1F) slot->outshift_r = 31; else slot->outshift_r += (slot->dipan >> 1) & 7; } else // Pan right { if (slot->dipan == 0xF) slot->outshift_l = 31; else slot->outshift_l += (slot->dipan >> 1) & 7; } } else if (slot->efsdl) { slot->outshift_l = slot->outshift_r = (7 - slot->efsdl) + SCSP_ENV_HIGH_BITS; if (slot->efpan & 0x10) // Pan left { if (slot->efpan == 0x1F) slot->outshift_r = 31; else slot->outshift_r += (slot->efpan >> 1) & 7; } else // Pan right { if (slot->efpan == 0xF) slot->outshift_l = 31; else slot->outshift_l += (slot->efpan >> 1) & 7; } } else slot->outshift_l = slot->outshift_r = 31; // Muted ScspUpdateSlotFunc(slot); break; default: goto unhandled_write; } break; } case 0x4: switch (address & 0xFF) { case 0x00: data &= 0x030F; // VER is hardwired data |= SCSP_VERSION << 4; scsp.mem4mb = (data >> 9) & 0x1; scsp.dac18b = (data >> 8) & 0x1; scsp.mvol = (data >> 0) & 0xF; if (scsp.mem4mb) M68K->SetFetch(0x000000, 0x080000, (pointer)SoundRam); else { M68K->SetFetch(0x000000, 0x040000, (pointer)SoundRam); M68K->SetFetch(0x040000, 0x080000, (pointer)SoundRam); M68K->SetFetch(0x080000, 0x0C0000, (pointer)SoundRam); M68K->SetFetch(0x0C0000, 0x100000, (pointer)SoundRam); } scsp.sound_ram_mask = scsp.mem4mb ? 0x7FFFF : 0x3FFFF; break; case 0x02: data &= 0x01FF; scsp.rbl = (data >> 7) & 0x3; scsp.rbp =((data >> 0) & 0x7F) << 13; break; case 0x04: return; // Not writable case 0x06: data &= 0x00FF; ScspMidiOut(data); break; case 0x08: data &= 0x7800; // CA/SGC/EG are not writable scsp.mslc = (data >> 11) & 0x1F; break; case 0x12: data &= 0xFFFE; scsp.dmea = (scsp.dmea & 0xF0000) | data; break; case 0x14: data &= 0xFFFE; scsp.dmea =((data >> 12) & 0xF) << 16 | (scsp.dmea & 0xFFFF); scsp.drga = (data >> 0) & 0xFFF; break; case 0x16: data &= 0x7FFE; scsp.dgate = (data >> 14) & 0x1; scsp.ddir = (data >> 13) & 0x1; scsp.dexe |= (data >> 12) & 0x1; // Writing 0 not allowed scsp.dtlg = (data >> 0) & 0xFFF; if (data & (1<<12)) ScspDoDMA(); break; case 0x18: data &= 0x07FF; scsp.tactl = (data >> 8) & 0x7; scsp.tima =((data >> 0) & 0xFF) << 8; break; case 0x1A: data &= 0x07FF; scsp.tbctl = (data >> 8) & 0x7; scsp.timb =((data >> 0) & 0xFF) << 8; break; case 0x1C: data &= 0x07FF; scsp.tcctl = (data >> 8) & 0x7; scsp.timc =((data >> 0) & 0xFF) << 8; break; case 0x1E: data &= 0x07FF; scsp.scieb = data; // FIXME: If a bit is already 1 in both SCIEB and SCIPD, // does writing another 1 here (no change) trigger another // interrupt or not? ScspCheckInterrupts(0x7FF, SCSP_INTTARGET_SOUND); break; case 0x20: if (data & (1<<5)) ScspRaiseInterrupt(5, SCSP_INTTARGET_SOUND); return; // Not writable case 0x22: ScspClearInterrupts(data, SCSP_INTTARGET_SOUND); return; // Not writable case 0x24: data &= 0x00FF; scsp.scilv0 = data; break; case 0x26: data &= 0x00FF; scsp.scilv1 = data; break; case 0x28: data &= 0x00FF; scsp.scilv2 = data; break; case 0x2A: data &= 0x07FF; scsp.mcieb = data; // FIXME: as above (SCIEB) ScspCheckInterrupts(0x7FF, SCSP_INTTARGET_MAIN); break; case 0x2C: if (data & (1<<5)) ScspRaiseInterrupt(5, SCSP_INTTARGET_MAIN); return; // Not writable case 0x2E: ScspClearInterrupts(data, SCSP_INTTARGET_MAIN); return; // Not writable default: goto unhandled_write; } break; default: unhandled_write: SCSPLOG("ScspWriteWordDirect(): unhandled write %04X to 0x%03X\n", data, address); break; } PSP_UC(scsp_regcache[address >> 1]) = data; } //------------------------------------------------------------------------- // ScspDoKeyOnOff: Apply the key-on/key-off setting for all slots. // Implements the KYONEX trigger. static void ScspDoKeyOnOff(void) { int slotnum; for (slotnum = 0; slotnum < 32; slotnum++) { if (scsp.slot[slotnum].key) ScspKeyOn(&scsp.slot[slotnum]); else ScspKeyOff(&scsp.slot[slotnum]); } } //----------------------------------// // ScspKeyOn: Execute a key-on event for a single slot. static void ScspKeyOn(SlotState *slot) { if (slot->env_phase != SCSP_ENV_RELEASE) return; // Can't key a sound that's already playing ScspUpdateSlotAddress(slot); slot->addr_counter = 0; slot->env_phase = SCSP_ENV_ATTACK; slot->env_counter = SCSP_ENV_ATTACK_START; // FIXME: should this start at the current value if the old sound is still decaying? slot->env_step = slot->env_step_a; slot->env_target = SCSP_ENV_ATTACK_END; } //----------------------------------// // ScspKeyOff: Execute a key-off event for a single slot. static void ScspKeyOff(SlotState *slot) { if (slot->env_phase == SCSP_ENV_RELEASE) return; // Can't release a sound that's already released // If we still are in attack phase at release time, convert attack to decay if (slot->env_phase == SCSP_ENV_ATTACK) slot->env_counter = SCSP_ENV_DECAY_END - slot->env_counter; slot->env_phase = SCSP_ENV_RELEASE; slot->env_step = slot->env_step_r; slot->env_target = SCSP_ENV_DECAY_END; } //------------------------------------------------------------------------- // ScspUpdateSlotAddress: Update the sample data pointer for the given // slot, bound slot->lea to the end of sound RAM, and cache the shifted // values of slot->lsa and slot->lea in slot->{lea,lsa}_shifted. static void ScspUpdateSlotAddress(SlotState *slot) { u32 max_samples; if (slot->pcm8b) slot->sa &= ~1; slot->sa &= scsp.sound_ram_mask; slot->buf = &SoundRam[slot->sa]; max_samples = scsp.sound_ram_mask - slot->sa; if (slot->pcm8b) max_samples >>= 1; if (slot->lsa > max_samples) slot->lsa = max_samples; slot->lsa_shifted = slot->lsa << SCSP_FREQ_LOW_BITS; if (slot->lea > max_samples) slot->lea = max_samples; slot->lea_shifted = ((slot->lea + 1) << SCSP_FREQ_LOW_BITS) - 1; slot->looplen_shifted = slot->lea_shifted - slot->lsa_shifted + 1; } //----------------------------------// // ScspUpdateSlotEnv: Update the envelope step values from the SR/DR/AR/RR // slot registers. slot->krs_shift and slot->octave_shift are assumed to // be up to date with respect to the KRS and OCT registers. static void ScspUpdateSlotEnv(SlotState *slot) { if (slot->sr) { const s32 *rate_table = &scsp_decay_rate[slot->sr << 1]; slot->env_step_s = rate_table[(15 - slot->octave_shift) >> slot->krs_shift]; } else slot->env_step_s = 0; if (slot->dr) { const s32 *rate_table = &scsp_decay_rate[slot->dr << 1]; slot->env_step_d = rate_table[(15 - slot->octave_shift) >> slot->krs_shift]; } else slot->env_step_d = 0; if (slot->ar) { const s32 *rate_table = &scsp_attack_rate[slot->ar << 1]; slot->env_step_a = rate_table[(15 - slot->octave_shift) >> slot->krs_shift]; } else slot->env_step_a = 0; if (slot->rr) { const s32 *rate_table = &scsp_decay_rate[slot->rr << 1]; slot->env_step_r = rate_table[(15 - slot->octave_shift) >> slot->krs_shift]; } else slot->env_step_r = 0; } //----------------------------------// // ScspUpdateSlotFunc: Update the audio generation function for the given // slot based on the slot's parameters. static void ScspUpdateSlotFunc(SlotState *slot) { if (slot->ssctl) // FIXME: noise (ssctl==1) not implemented slot->audiogen = scsp_audiogen_func_table[0][0][0][0][0]; else slot->audiogen = scsp_audiogen_func_table[slot->lfo_fm_shift >= 0] [slot->lfo_am_shift >= 0] [slot->pcm8b == 0] [slot->outshift_l != 31] [slot->outshift_r != 31]; } //------------------------------------------------------------------------- // ScspMidiIn: Handle a read from the MIDI input register ($404). Since // there is no facility for sending MIDI data (the Saturn does not have a // MIDI I/O port), most of this is essentially a giant no-op, but the logic // is included for reference. static u16 ScspMidiIn(void) { scsp.miovf = 0; scsp.mifull = 0; if (scsp.midi_in_cnt > 0) { scsp.mibuf = scsp.midi_in_buf[0]; scsp.midi_in_buf[0] = scsp.midi_in_buf[1]; scsp.midi_in_buf[1] = scsp.midi_in_buf[2]; scsp.midi_in_buf[2] = scsp.midi_in_buf[3]; scsp.midi_in_cnt--; scsp.miemp = (scsp.midi_in_cnt == 0); if (!scsp.miemp) ScspRaiseInterrupt(SCSP_INTERRUPT_MIDI_IN, SCSP_INTTARGET_BOTH); } else // scsp.midi_in_cnt == 0 scsp.mibuf = 0xFF; return scsp.mofull << 12 | scsp.moemp << 11 | scsp.miovf << 10 | scsp.mifull << 9 | scsp.miemp << 8 | scsp.mibuf << 0; } //----------------------------------// // ScspMidiOut: Handle a write to the MIDI output register ($406). static void ScspMidiOut(u8 data) { scsp.moemp = 0; if (scsp.midi_out_cnt < 4) scsp.midi_out_buf[scsp.midi_out_cnt++] = data; scsp.mofull = (scsp.midi_out_cnt >= 4); } //------------------------------------------------------------------------- // ScspDoDMA: Handle a DMA request (when 1 is written to DEXE). DMA is // processed instantaneously regardless of transfer size. static void ScspDoDMA(void) { const u32 dmea = scsp.dmea & scsp.sound_ram_mask; if (scsp.ddir) // {RAM,zero} -> registers { SCSPLOG("DMA %s RAM[$%05X] -> registers[$%03X]\n", scsp.dgate ? "clear" : "copy", dmea, scsp.drga); if (scsp.dgate) { u32 i; for (i = 0; i < scsp.dtlg; i += 2) ScspWriteWordDirect(scsp.drga + i, 0); } else { u32 i; for (i = 0; i < scsp.dtlg; i += 2) ScspWriteWordDirect(scsp.drga + i, T2ReadWord(SoundRam, dmea + i)); } } else // !scsp.ddir, i.e. registers -> RAM { SCSPLOG("DMA %s registers[$%03X] -> RAM[$%05X]\n", scsp.dgate ? "clear" : "copy", scsp.drga, dmea); if (scsp.dgate) memset(&SoundRam[dmea], 0, scsp.dtlg); else { u32 i; for (i = 0; i < scsp.dtlg; i += 2) T2WriteWord(SoundRam, dmea + i, ScspReadWordDirect(scsp.drga + i)); } M68K->WriteNotify(dmea, scsp.dtlg); } scsp.dexe = 0; PSP_UC(scsp_regcache[0x416>>1]) &= ~(1<<12); ScspRaiseInterrupt(SCSP_INTERRUPT_DMA, SCSP_INTTARGET_BOTH); } /////////////////////////////////////////////////////////////////////////// // Other SCSP internal helper routines /////////////////////////////////////////////////////////////////////////// // ScspSyncThread: Wait for the SCSP subthread to finish executing all // pending cycles. Do not call if the subthread is not running. static void ScspSyncThread(void) { PSP_FLUSH_ALL(); while (PSP_UC(scsp_clock) != scsp_clock_target) { YabThreadWake(YAB_THREAD_SCSP); YabThreadYield(); } } //------------------------------------------------------------------------- // ScspRaiseInterrupt: Raise an interrupt for the main and/or sound CPU. static void ScspRaiseInterrupt(int which, int target) { if (target & SCSP_INTTARGET_MAIN) { scsp.mcipd |= 1 << which; PSP_UC(scsp_regcache[0x42C >> 1]) = scsp.mcipd; if (scsp.mcieb & (1 << which)) { if (scsp_thread_running) PSP_UC(scsp_main_interrupt_pending) = 1; else (*scsp_interrupt_handler)(); } } if (target & SCSP_INTTARGET_SOUND) { scsp.scipd |= 1 << which; PSP_UC(scsp_regcache[0x420 >> 1]) = scsp.scipd; if (scsp.scieb & (1 << which)) { const int level_shift = (which > 7) ? 7 : which; const int level = ((scsp.scilv0 >> level_shift) & 1) << 0 | ((scsp.scilv1 >> level_shift) & 1) << 1 | ((scsp.scilv2 >> level_shift) & 1) << 2; M68K->SetIRQ(level); } } } //----------------------------------// // ScspCheckInterrupts: Check pending interrupts for the main or sound CPU // against the interrupt enable flags, and raise any interrupts which are // both enabled and pending. The mask parameter indicates which interrupts // should be checked. Implements writes to SCIEB and MCIEB. static void ScspCheckInterrupts(u16 mask, int target) { int i; for (i = 0; i < 11; i++) { if ((1<> 1]) = scsp.mcipd; } if (target & SCSP_INTTARGET_SOUND) { scsp.scipd &= ~mask; PSP_UC(scsp_regcache[0x420 >> 1]) = scsp.scipd; } } //------------------------------------------------------------------------- // ScspRunM68K: Run the M68K for the given number of cycles. static void ScspRunM68K(u32 cycles) { if (LIKELY(m68k_running)) { s32 new_cycles = m68k_saved_cycles + cycles; if (LIKELY(new_cycles > 0)) new_cycles -= (*m68k_execf)(new_cycles); m68k_saved_cycles = new_cycles; } } //----------------------------------// // M68KExecBP: Wrapper for M68K->Exec() which checks for breakpoints and // calls the breakpoint callback when one is reached. This logic is // extracted from M68KExec() to avoid unnecessary register spillage on the // fast (no-breakpoint) path. static s32 FASTCALL M68KExecBP(s32 cycles) { s32 cycles_to_exec = cycles; s32 cycles_executed = 0; int i; while (cycles_executed < cycles_to_exec) { // Make sure it isn't one of our breakpoints for (i = 0; i < m68k_num_breakpoints; i++) { if ((M68K->GetPC() == m68k_breakpoint[i].addr) && !m68k_in_breakpoint) { m68k_in_breakpoint = 1; if (M68KBreakpointCallback) M68KBreakpointCallback(m68k_breakpoint[i].addr); m68k_in_breakpoint = 0; } } // Execute instructions individually cycles_executed += M68K->Exec(1); } return cycles_executed; } /////////////////////////////////////////////////////////////////////////// // M68K management routines /////////////////////////////////////////////////////////////////////////// // M68KStart: Start the M68K processor running. void M68KStart(void) { if (scsp_thread_running) ScspSyncThread(); M68K->Reset(); m68k_saved_cycles = 0; m68k_running = 1; if (scsp_thread_running) PSP_FLUSH_ALL(); } //------------------------------------------------------------------------- // M68KStop: Halt the M68K processor. void M68KStop(void) { if (scsp_thread_running) ScspSyncThread(); m68k_running = 0; if (scsp_thread_running) PSP_FLUSH_ALL(); } //------------------------------------------------------------------------- // M68KStep: Execute a single M68K instruction. void M68KStep(void) { M68K->Exec(1); } //------------------------------------------------------------------------- // M68KWriteNotify: Notify the M68K emulator that a region of sound RAM // has been written to by an external agent. void M68KWriteNotify(u32 address, u32 size) { M68K->WriteNotify(address, size); } //------------------------------------------------------------------------- // M68KGetRegisters, M68KSetRegisters: Get or set the current values of // the M68K registers. void M68KGetRegisters(M68KRegs *regs) { int i; if (regs != NULL) { for (i = 0; i < 8; i++) { regs->D[i] = M68K->GetDReg(i); regs->A[i] = M68K->GetAReg(i); } regs->SR = M68K->GetSR(); regs->PC = M68K->GetPC(); } } void M68KSetRegisters(const M68KRegs *regs) { int i; if (regs != NULL) { for (i = 0; i < 8; i++) { M68K->SetDReg(i, regs->D[i]); M68K->SetAReg(i, regs->A[i]); } M68K->SetSR(regs->SR); M68K->SetPC(regs->PC); } } //------------------------------------------------------------------------- // M68KSetBreakpointCallback: Set a function to be called whenever an M68K // breakpoint is reached. void M68KSetBreakpointCallBack(void (*func)(u32 address)) { M68KBreakpointCallback = func; } //------------------------------------------------------------------------- // M68KAddCodeBreakpoint: Add an M68K breakpoint on the given address. // Returns 0 on success, -1 if the breakpoint table is full or there is // already a breakpoint set on the address. int M68KAddCodeBreakpoint(u32 address) { int i; if (m68k_num_breakpoints >= MAX_BREAKPOINTS) return -1; // Make sure it isn't already on the list for (i = 0; i < m68k_num_breakpoints; i++) { if (m68k_breakpoint[i].addr == address) return -1; } m68k_breakpoint[m68k_num_breakpoints].addr = address; m68k_num_breakpoints++; // Switch to the slow exec routine so we can catch the breakpoint m68k_execf = M68KExecBP; return 0; } //------------------------------------------------------------------------- // M68KDelCodeBreakpoint: Delete an M68K breakpoint on the given address. // Returns 0 on success, -1 if there was no breakpoint set on the address. int M68KDelCodeBreakpoint(u32 address) { int i; if (m68k_num_breakpoints > 0) { for (i = 0; i < m68k_num_breakpoints; i++) { if (m68k_breakpoint[i].addr == address) { // Swap with the last breakpoint in the table, so there are // no holes in the breakpoint list m68k_breakpoint[i].addr = m68k_breakpoint[m68k_num_breakpoints-1].addr; m68k_breakpoint[m68k_num_breakpoints-1].addr = 0xFFFFFFFF; m68k_num_breakpoints--; if (m68k_num_breakpoints == 0) { // Last breakpoint deleted, so go back to the fast exec routine m68k_execf = M68K->Exec; } return 0; } } } return -1; } //------------------------------------------------------------------------- // M68KGetBreakpointList: Return the array of breakpoints currently set. // The array is M68K_MAX_BREAKPOINTS elements long, and an address of // 0xFFFFFFFF indicates that no breakpoint is set in that slot. const M68KBreakpointInfo *M68KGetBreakpointList(void) { return m68k_breakpoint; } //------------------------------------------------------------------------- // M68KClearCodeBreakpoints: Clear all M68K breakpoints. void M68KClearCodeBreakpoints(void) { int i; for (i = 0; i < MAX_BREAKPOINTS; i++) m68k_breakpoint[i].addr = 0xFFFFFFFF; m68k_num_breakpoints = 0; m68k_execf = M68K->Exec; } //------------------------------------------------------------------------- // M68K{Read,Write}{Byte,Word}: Memory access routines for the M68K // emulation. Exported for use in debugging. u32 FASTCALL M68KReadByte(u32 address) { if (address < 0x100000) return T2ReadByte(SoundRam, address & scsp.sound_ram_mask); else return ScspReadByteDirect(address & 0xFFF); } u32 FASTCALL M68KReadWord(u32 address) { if (address < 0x100000) return T2ReadWord(SoundRam, address & scsp.sound_ram_mask); else return ScspReadWordDirect(address & 0xFFF); } void FASTCALL M68KWriteByte(u32 address, u32 data) { if (address < 0x100000) T2WriteByte(SoundRam, address & scsp.sound_ram_mask, data); else ScspWriteByteDirect(address & 0xFFF, data); } void FASTCALL M68KWriteWord(u32 address, u32 data) { if (address < 0x100000) T2WriteWord(SoundRam, address & scsp.sound_ram_mask, data); else ScspWriteWordDirect(address & 0xFFF, data); } /////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/dreamcast/000755 001750 001750 00000000000 12757373644 020025 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/dreamcast/CMakeLists.txt000644 001750 001750 00000001207 12755623101 022545 0ustar00guillaumeguillaume000000 000000 project(yabause-dc) if(NOT dreamcast) return() endif(NOT dreamcast) enable_language(ASM-ATT) include_directories(${PORT_INCLUDE_DIRS}) add_definitions(${PORT_CFLAGS}) set(yabause_dc_SOURCES cd.s localtime.c perdc.c viddc.c yui.c) set(yabause_dc_HEADERS localtime.h perdc.h viddc.h) link_directories(..) add_executable(yabause-dc ${yabause_dc_SOURCES}) set_target_properties(yabause-dc PROPERTIES OUTPUT_NAME yabause.elf) target_link_libraries(yabause-dc ${YABAUSE_LIBRARIES}) target_link_libraries(yabause-dc ${PORT_LIBRARIES}) target_link_libraries(yabause-dc yabause) target_link_libraries(yabause-dc m) yabause-0.9.15/src/dreamcast/perdc.h000644 001750 001750 00000001615 12755623101 021256 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef PERDC_H #define PERDC_H #include "../peripheral.h" #define PERCORE_DC 2 extern PerInterface_struct PERDC; #endif yabause-0.9.15/src/dreamcast/sh2rec/000755 001750 001750 00000000000 12757373644 021213 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/dreamcast/sh2rec/sh2rec_htab.c000644 001750 001750 00000007706 12755623101 023535 0ustar00guillaumeguillaume000000 000000 /* Copyright 2010 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include "core.h" #include "sh2core.h" #include "sh2rec.h" #include "sh2rec_htab.h" #include "sh2rec_mem.h" typedef struct htab_entry { sh2rec_block_t block; struct htab_entry *next; } htab_entry_t; /* The actual hash table. It can't be resized dynamically, and is essentially just an array of singly-linked lists. */ static htab_entry_t *table[SH2REC_HTAB_ENTRIES]; /* Internal functions */ static void htab_free_chain(htab_entry_t *ent) { htab_entry_t *i, *tmp; i = ent; while(i) { tmp = i->next; free(i->block.block); free(i); i = tmp; } } /* Hash an address into something slightly nicer to work with. The large constant in here is about 2^32 / phi (where phi is the golden ratio). Why use the golden ratio? Because its always fun to use in code. */ static inline int hash_addr(u32 addr) { return ((addr ^ 2654435761U) >> 2) & (SH2REC_HTAB_ENTRIES - 1); } /* Public functions */ void sh2rec_htab_init(void) { memset(table, 0, sizeof(htab_entry_t *) * SH2REC_HTAB_ENTRIES); } void sh2rec_htab_reset(void) { int i; for(i = 0; i < SH2REC_HTAB_ENTRIES; ++i) { if(table[i]) { htab_free_chain(table[i]); } } memset(table, 0, sizeof(htab_entry_t *) * SH2REC_HTAB_ENTRIES); } sh2rec_block_t *sh2rec_htab_lookup(u32 addr) { htab_entry_t *i = table[hash_addr(addr)]; /* Look through the chain for the entry we're after */ while(i) { if(i->block.start_pc == addr) { return &i->block; } i = i->next; } /* Didn't find it, punt. */ return NULL; } /* Create a new block assuming an old one does not exist. */ sh2rec_block_t *sh2rec_htab_block_create(u32 addr, int length) { uint8_t *ptr; htab_entry_t *ent; int index = hash_addr(addr); ptr = (uint8_t *)sh2rec_mem_alloc(length + sizeof(htab_entry_t)); #ifdef DEBUG if(!ptr) { return NULL; } #endif /* Allocate space for the block */ ent = (htab_entry_t *)ptr; ent->block.block = (u16 *)(ptr + sizeof(htab_entry_t)); /* Fill in the struct */ ent->block.start_pc = addr; ent->block.cycles = 0; ent->block.pc = addr; ent->block.length = length; ent->block.ptr = ent->block.block; /* Put the item in the list (puts it at the head of the index in the table where it would go) */ ent->next = table[index]; table[index] = ent; return &ent->block; } void sh2rec_htab_block_remove(u32 addr) { int index = hash_addr(addr); htab_entry_t *i, *tmp, *last; i = table[index]; last = NULL; /* Look through everything for the entry we're supposed to remove */ while(i) { tmp = i->next; /* Is this the entry we're looking for? */ if(i->block.start_pc == addr) { /* Unhook the entry from the list */ if(last) { last->next = tmp; } else { table[index] = tmp; } /* Free any memory used by the block */ sh2rec_mem_free(i); return; } last = i; i = tmp; } } yabause-0.9.15/src/dreamcast/sh2rec/sh2rec_mem.h000644 001750 001750 00000002575 12755623101 023401 0ustar00guillaumeguillaume000000 000000 /* Copyright 2010 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SH2REC_MEM_H #define SH2REC_MEM_H /* Initial allocation of memory: 1MB */ #define SH2REC_MEM_INITIAL (1024 * 1024) /* Size of future allocations: 256KB */ #define SH2REC_MEM_ALLOCSZ (256 * 1024) /* Maximum allocation of memory: 2MB */ #define SH2REC_MEM_MAX (2 * 1024 * 1024) /* Fudge factor... make sure at least this much is in any block above the inital request */ #define SH2REC_MEM_FUDGE 48 int sh2rec_mem_init(void); void sh2rec_mem_shutdown(void); void *sh2rec_mem_alloc(int sz); int sh2rec_mem_expand(void *block, int amt); void sh2rec_mem_free(void *block); #endif /* !SH2REC_MEM_H */ yabause-0.9.15/src/dreamcast/sh2rec/sh2rec.h000644 001750 001750 00000002737 12755623101 022543 0ustar00guillaumeguillaume000000 000000 /* Copyright 2010 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SH2REC_H #define SH2REC_H #define SH2CORE_DYNAREC 10 #define INSTRUCTION_A(x) ((x & 0xF000) >> 12) #define INSTRUCTION_B(x) ((x & 0x0F00) >> 8) #define INSTRUCTION_C(x) ((x & 0x00F0) >> 4) #define INSTRUCTION_D(x) (x & 0x000F) #define INSTRUCTION_CD(x) (x & 0x00FF) #define INSTRUCTION_BCD(x) (x & 0x0FFF) typedef struct sh2rec_block { u16 *block; u32 start_pc; int cycles; int length; u16 *ptr; u32 pc; } sh2rec_block_t; /* Recompile a single instruction */ int sh2rec_rec_inst(sh2rec_block_t *b, int isdelay); /* Recompile a block at the PC specified in the block */ int sh2rec_rec_block(sh2rec_block_t *b); extern SH2Interface_struct SH2Dynarec; #endif /* !SH2REC_H */ yabause-0.9.15/src/dreamcast/sh2rec/sh2rec_mem.c000644 001750 001750 00000013631 12755623101 023367 0ustar00guillaumeguillaume000000 000000 /* Copyright 2010 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "sh2rec_mem.h" typedef struct block_s { uint8_t *ptr; int size; struct block_s *prev; struct block_s *next; } sh2rec_mem_block; typedef struct usedblock_s { sh2rec_mem_block base; sh2rec_mem_block *freespace; } sh2rec_mem_usedblock; typedef struct allocblock_s { struct allocblock_s *next; } sh2rec_mem_allocblock; static sh2rec_mem_block *freeblocks = NULL; static sh2rec_mem_usedblock *usedblocks = NULL; static sh2rec_mem_usedblock *usedblocks_tail = NULL; static sh2rec_mem_allocblock *allocblocks = NULL; static int cur_allocation = 0; #define BSSIZE (sizeof(sh2rec_mem_allocblock) + sizeof(sh2rec_mem_block) + \ sizeof(sh2rec_mem_usedblock)) int sh2rec_mem_init(void) { sh2rec_mem_block *initblock; sh2rec_mem_allocblock *allocblock; uint8_t *block; /* Allocate our initial space for storing rec'd instructions in */ block = (uint8_t *)malloc(SH2REC_MEM_INITIAL); #ifdef DEBUG if(!block) { return -1; } #endif /* Carve our structures out of the beginning of the block */ allocblock = (sh2rec_mem_allocblock *)block; initblock = (sh2rec_mem_block *)(block + sizeof(sh2rec_mem_allocblock)); cur_allocation = SH2REC_MEM_INITIAL; /* Fill in the rest of the structs */ initblock->size = SH2REC_MEM_INITIAL - sizeof(sh2rec_mem_allocblock) - sizeof(sh2rec_mem_block); initblock->prev = NULL; initblock->next = NULL; allocblock->next = NULL; allocblocks = allocblock; /* The whole block is free, so put it in the free list */ freeblocks = initblock; return 0; } void sh2rec_mem_shutdown(void) { sh2rec_mem_allocblock *i, *tmp; /* Loop through and free any blocks we allocated */ i = allocblocks; while(i) { tmp = i->next; free(i); i = tmp; } /* Clean up the stale pointers */ allocblocks = NULL; freeblocks = NULL; usedblocks = NULL; } void *sh2rec_mem_alloc(int sz) { sh2rec_mem_block *i; sh2rec_mem_usedblock *rv; sh2rec_mem_allocblock *b; int szlook = sz + SH2REC_MEM_FUDGE + sizeof(sh2rec_mem_usedblock); uint8_t *block; /* Look for a free block of enough size */ i = freeblocks; while(i) { if(i->size >= szlook) { /* We've found a candidate, so, start working with it */ rv = (sh2rec_mem_usedblock *)i->ptr; rv->freespace = i; rv->base.ptr = i->ptr + sizeof(sh2rec_mem_usedblock); rv->base.size = sz; rv->base.prev = (sh2rec_mem_block *)usedblocks_tail; rv->base.next = NULL; /* Update the tail */ if(usedblocks_tail) { usedblocks_tail->base.next = (sh2rec_mem_block *)rv; } usedblocks_tail = rv; /* The freeblock is now smaller, so reflect that */ i->size -= sz + sizeof(sh2rec_mem_usedblock); return rv; } i = i->next; } /* We didn't find one, so allocate a new block */ block = malloc(SH2REC_MEM_ALLOCSZ); #ifdef DEBUG if(!block) { return NULL; } #endif /* Fill in the allocblock */ b = (sh2rec_mem_allocblock *)block; b->next = allocblocks; allocblocks = b; /* Now, create a freeblock, and work from that */ i = (sh2rec_mem_block *)(block + sizeof(sh2rec_mem_allocblock)); i->ptr = block + BSSIZE + sz; i->prev = NULL; i->next = freeblocks; i->size = SH2REC_MEM_ALLOCSZ - BSSIZE - sz; freeblocks = i; /* Create the usedblock */ rv = (sh2rec_mem_usedblock *)(i->ptr - sz); rv->freespace = i; rv->base.ptr = i->ptr; rv->base.size = sz; rv->base.prev = (sh2rec_mem_block *)usedblocks_tail; rv->base.next = NULL; /* Update the tail */ if(usedblocks_tail) { usedblocks_tail->base.next = (sh2rec_mem_block *)rv; } usedblocks_tail = rv; /* Keep track of our allocation */ cur_allocation += SH2REC_MEM_ALLOCSZ; return rv; } int sh2rec_mem_expand(void *block, int amt) { sh2rec_mem_usedblock *b = (sh2rec_mem_usedblock *)block; /* If the freeblock has space, allow it */ if(b->freespace->size > amt) { b->freespace->size -= amt; b->base.size += amt; b->freespace->ptr += amt; return 1; } return 0; } void sh2rec_mem_free(void *block) { sh2rec_mem_usedblock *b = (sh2rec_mem_usedblock *)block; /* Remove the usedblock from the chain */ if(b->base.next) { b->base.next->prev = b->base.prev; } if(b->base.prev) { b->base.prev->next = b->base.next; } if(b == usedblocks) { usedblocks = (sh2rec_mem_usedblock *)b->base.next; } if(b == usedblocks_tail) { usedblocks_tail = (sh2rec_mem_usedblock *)b->base.prev; } /* Treat the usedblock like its a freeblock (it is an extension of the freeblock), and just link it into the free blocks list */ b->freespace = NULL; b->base.next = freeblocks; b->base.prev = NULL; b->base.size += sizeof(sh2rec_mem_usedblock) - sizeof(sh2rec_mem_block); freeblocks = (sh2rec_mem_block *)b; } yabause-0.9.15/src/dreamcast/sh2rec/sh2rec.c000644 001750 001750 00000320767 12755623101 022544 0ustar00guillaumeguillaume000000 000000 /* Copyright 2010 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* SH2 Dynarec Core (for SH4) */ #include #include #include #include #include "sh2core.h" #include "sh2rec.h" #include "sh2rec_htab.h" #include "sh2int.h" /* Registers */ #define R0 0 #define R1 1 #define R2 2 #define R3 3 #define R4 4 #define R5 5 #define R6 6 #define R7 7 #define R8 8 #define R9 9 #define R10 10 #define R11 11 #define R12 12 #define R13 13 #define R14 14 #define R15 15 /* Control Registers (use with emitSTC/emitLDC) */ #define R_SR 0 #define R_GBR 1 #define R_VBR 2 /* System Registers (use with emitSTS/emitLDS) */ #define R_MACH 0 #define R_MACL 1 #define R_PR 2 /* ALU Ops, to be used with the emitALU function */ #define OP_ADD 0x300C #define OP_ADDC 0x300E #define OP_AND 0x2009 #define OP_EXTSB 0x600E #define OP_EXTSW 0x600F #define OP_EXTUB 0x600C #define OP_EXTUW 0x600D #define OP_NEG 0x600B #define OP_NEGC 0x600A #define OP_NOT 0x6007 #define OP_OR 0x200B #define OP_SUB 0x3008 #define OP_SUBC 0x300A #define OP_SWAPB 0x6008 #define OP_SWAPW 0x6009 #define OP_XOR 0x200A #define OP_XTRCT 0x200D /* Shift/Rotate Ops, to be used with the emitSHIFT function */ #define OP_ROTCL 0x4024 #define OP_ROTCR 0x4025 #define OP_ROTL 0x4004 #define OP_ROTR 0x4005 #define OP_SHAL 0x4020 #define OP_SHAR 0x4021 #define OP_SHLL 0x4000 #define OP_SHLR 0x4001 /* Comparison Ops, to be used with the emitALU function */ #define OP_CMPEQ 0x3000 #define OP_CMPGE 0x3003 #define OP_CMPGT 0x3007 #define OP_CMPHI 0x3006 #define OP_CMPHS 0x3002 #define OP_CMPSTR 0x200C #define OP_TST 0x2008 /* Multiplication ops, to be used with the emitALU function */ #define OP_DMULS 0x300D #define OP_DMULU 0x3005 #define OP_MULL 0x0007 #define OP_MULS 0x200F #define OP_MULU 0x200E #ifdef SH2REC__DEBUG #define EMIT_INST {\ printf("%s\n", __PRETTY_FUNCTION__); \ printf("Emitting %04x at %p\n", inst, (void *)b->ptr); \ *b->ptr++ = inst; \ } #else #define EMIT_INST *b->ptr++ = inst #endif #ifdef SH2REC__DEBUG #define EMIT_32 {\ uint32_t *__ptr = (uint32_t *)b->ptr; \ printf("%s\n", __PRETTY_FUNCTION__); \ printf("Emitting %08x at %p\n", (unsigned int)v, (void *)__ptr); \ *__ptr = v; \ b->ptr += 2; \ } #else #define EMIT_32 uint32_t *__ptr = (uint32_t *)b->ptr; *__ptr = v; b->ptr += 2 #endif static inline void emit16(sh2rec_block_t *b, uint16_t inst) { EMIT_INST; } static inline void emit32(sh2rec_block_t *b, uint32_t v) { EMIT_32; } static inline void emitMOV(sh2rec_block_t *b, int m, int n) { uint16_t inst = 0x6003 | (n << 8) | (m << 4); EMIT_INST; } static inline void emitMOVWI(sh2rec_block_t *b, int d, int n) { uint16_t inst = 0x9000 | (n << 8) | (d); EMIT_INST; } static inline void emitMOVLI(sh2rec_block_t *b, int d, int n) { uint16_t inst = 0xD000 | (n << 8) | (d); EMIT_INST; } static inline void emitMOVLS(sh2rec_block_t *b, int m, int n) { uint16_t inst = 0x2002 | (n << 8) | (m << 4); EMIT_INST; } static inline void emitMOVLL(sh2rec_block_t *b, int m, int n) { uint16_t inst = 0x6002 | (n << 8) | (m << 4); EMIT_INST; } static inline void emitMOVWM(sh2rec_block_t *b, int m, int n) { uint16_t inst = 0x2005 | (n << 8) | (m << 4); EMIT_INST; } static inline void emitMOVLM(sh2rec_block_t *b, int m, int n) { uint16_t inst = 0x2006 | (n << 8) | (m << 4); EMIT_INST; } static inline void emitMOVLP(sh2rec_block_t *b, int m, int n) { uint16_t inst = 0x6006 | (n << 8) | (m << 4); EMIT_INST; } static inline void emitMOVI(sh2rec_block_t *b, int imm, int n) { uint16_t inst = 0xE000 | (n << 8) | (imm & 0xFF); EMIT_INST; } static inline void emitMOVLL4(sh2rec_block_t *b, int m, int d, int n) { uint16_t inst = 0x5000 | (n << 8) | (m << 4) | (d); EMIT_INST; } static inline void emitMOVLS4(sh2rec_block_t *b, int m, int d, int n) { uint16_t inst = 0x1000 | (n << 8) | (m << 4) | (d); EMIT_INST; } static inline void emitMOVLLG(sh2rec_block_t *b, int imm) { uint16_t inst = 0xC600 | (imm & 0xFF); EMIT_INST; } static inline void emitMOVLSG(sh2rec_block_t *b, int imm) { uint16_t inst = 0xC200 | (imm & 0xFF); EMIT_INST; } static inline void emitMOVT(sh2rec_block_t *b, int n) { uint16_t inst = 0x0029 | (n << 8); EMIT_INST; } static inline void emitALU(sh2rec_block_t *b, int m, int n, uint16_t op) { uint16_t inst = (n << 8) | (m << 4) | op; EMIT_INST; } static inline void emitSHIFT(sh2rec_block_t *b, int n, uint16_t op) { uint16_t inst = (n << 8) | op; EMIT_INST; } static inline void emitADDI(sh2rec_block_t *b, int imm, int n) { uint16_t inst = 0x7000 | (n << 8) | (imm & 0xFF); EMIT_INST; } static inline void emitANDI(sh2rec_block_t *b, int imm) { uint16_t inst = 0xC900 | (imm & 0xFF); EMIT_INST; } static inline void emitORI(sh2rec_block_t *b, int imm) { uint16_t inst = 0xCB00 | (imm & 0xFF); EMIT_INST; } static inline void emitXORI(sh2rec_block_t *b, int imm) { uint16_t inst = 0xCA00 | (imm & 0xFF); EMIT_INST; } static inline void emitSHLL2(sh2rec_block_t *b, int n) { uint16_t inst = 0x4008 | (n << 8); EMIT_INST; } static inline void emitSHLL8(sh2rec_block_t *b, int n) { uint16_t inst = 0x4018 | (n << 8); EMIT_INST; } static inline void emitSHLL16(sh2rec_block_t *b, int n) { uint16_t inst = 0x4028 | (n << 8); EMIT_INST; } static inline void emitSHLR2(sh2rec_block_t *b, int n) { uint16_t inst = 0x4009 | (n << 8); EMIT_INST; } static inline void emitSHLR8(sh2rec_block_t *b, int n) { uint16_t inst = 0x4019 | (n << 8); EMIT_INST; } static inline void emitSHLR16(sh2rec_block_t *b, int n) { uint16_t inst = 0x4029 | (n << 8); EMIT_INST; } static inline void emitCMPIM(sh2rec_block_t *b, int imm) { uint16_t inst = 0x8800 | (imm & 0xFF); EMIT_INST; } static inline void emitCMPPL(sh2rec_block_t *b, int n) { uint16_t inst = 0x4015 | (n << 8); EMIT_INST; } static inline void emitCMPPZ(sh2rec_block_t *b, int n) { uint16_t inst = 0x4011 | (n << 8); EMIT_INST; } static inline void emitADDV(sh2rec_block_t *b, int m, int n) { uint16_t inst = 0x300F | (n << 8) | (m << 4); EMIT_INST; } static inline void emitSUBV(sh2rec_block_t *b, int m, int n) { uint16_t inst = 0x300B | (n << 8) | (m << 4); EMIT_INST; } static inline void emitLDS(sh2rec_block_t *b, int m, int sr) { uint16_t inst = 0x400A | (m << 8) | (sr << 4); EMIT_INST; } static inline void emitSTS(sh2rec_block_t *b, int sr, int n) { uint16_t inst = 0x000A | (n << 8) | (sr << 4); EMIT_INST; } static inline void emitLDC(sh2rec_block_t *b, int m, int sr) { uint16_t inst = 0x400E | (m << 8) | (sr << 4); EMIT_INST; } static inline void emitSTC(sh2rec_block_t *b, int sr, int n) { uint16_t inst = 0x0002 | (n << 8) | (sr << 4); EMIT_INST; } static inline void emitDT(sh2rec_block_t *b, int n) { uint16_t inst = 0x4010 | (n << 8); EMIT_INST; } static inline void emitTSTI(sh2rec_block_t *b, int imm) { uint16_t inst = 0xC800 | (imm & 0xFF); EMIT_INST; } static inline void emitBRA(sh2rec_block_t *b, int d) { uint16_t inst = 0xA000 | (d); EMIT_INST; } static inline void emitDIV0S(sh2rec_block_t *b, int m, int n) { uint16_t inst = 0x2007 | (n << 8) | (m << 4); EMIT_INST; } static inline void emitDIV1(sh2rec_block_t *b, int m, int n) { uint16_t inst = 0x3004 | (n << 8) | (m << 4); EMIT_INST; } static inline void emitRTS(sh2rec_block_t *b) { uint16_t inst = 0x000B; EMIT_INST; } static inline void emitNOP(sh2rec_block_t *b) { uint16_t inst = 0x0009; EMIT_INST; } static inline void emitJSR(sh2rec_block_t *b, int m) { uint16_t inst = 0x400B | (m << 8); EMIT_INST; } static inline void emitMACL(sh2rec_block_t *b, int m, int n) { uint16_t inst = 0x000F | (n << 8) | (m << 4); EMIT_INST; } static inline void emitMACW(sh2rec_block_t *b, int m, int n) { uint16_t inst = 0x400F | (n << 8) | (m << 4); EMIT_INST; } static inline void emitCLRMAC(sh2rec_block_t *b) { uint16_t inst = 0x0028; EMIT_INST; } static inline void emitBF(sh2rec_block_t *b, int disp) { uint16_t inst = 0x8B00 | (disp & 0xFF); EMIT_INST; } static inline void emitBT(sh2rec_block_t *b, int disp) { uint16_t inst = 0x8900 | (disp & 0xFF); EMIT_INST; } static inline void generateALUOP(uint16_t inst, sh2rec_block_t *b, int op) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitMOVLL4(b, R8, regm, R3); /* R3 <- sh2[Rm] */ emitALU(b, R3, R2, op); /* R2 <- R2 o R3 */ emitMOVLS4(b, R2, regn, R8); /* sh2[Rn] <- R2 */ ++b->cycles; /* 1 Cycle */ } static inline void generateSHIFT(uint16_t inst, sh2rec_block_t *b, int op) { int regn = INSTRUCTION_B(inst); emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitSHIFT(b, R0, OP_ROTCR); /* Rotate SH2's T Bit in place */ emitSHIFT(b, R2, op); /* R2 <- R2 op */ emitSHIFT(b, R0, OP_ROTCL); /* Rotate T back to SH2 reg */ emitMOVLS4(b, R2, regn, R8); /* sh2[Rn] <- R2 */ emitMOVLSG(b, 16); /* sh2[SR] <- R0 */ ++b->cycles; /* 1 Cycle */ } static inline void generateCOMP(uint16_t inst, sh2rec_block_t *b, int op) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitMOVLL4(b, R8, regm, R3); /* R3 <- sh2[Rm] */ emitSHIFT(b, R0, OP_ROTCR); /* Rotate SH2's T Bit in place */ emitALU(b, R3, R2, op); /* R2 op R3 */ emitSHIFT(b, R0, OP_ROTCL); /* Rotate T back to SH2 reg */ emitMOVLSG(b, 16); /* sh2[SR] <- R0 */ ++b->cycles; /* 1 Cycle */ } static void generateADD(uint16_t inst, sh2rec_block_t *b) { generateALUOP(inst, b, OP_ADD); b->pc += 2; } static void generateADDI(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int imm = INSTRUCTION_CD(inst); emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitADDI(b, imm, R2); /* R2 <- R2 + #imm */ emitMOVLS4(b, R2, regn, R8); /* sh2[Rn] <- R2 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateADDC(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitMOVLL4(b, R8, regm, R3); /* R3 <- sh2[Rm] */ emitSHIFT(b, R0, OP_ROTCR); /* Rotate SH2's T Bit in place */ emitALU(b, R3, R2, OP_ADDC); /* R2 = R2 + R3 + T (carry to T) */ emitSHIFT(b, R0, OP_ROTCL); /* Rotate T back to SH2 reg */ emitMOVLS4(b, R2, regn, R8); /* sh2[Rn] <- R2 */ emitMOVLSG(b, 16); /* sh2[SR] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateADDV(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitMOVLL4(b, R8, regm, R3); /* R3 <- sh2[Rm] */ emitSHIFT(b, R0, OP_ROTCR); /* Rotate SH2's T Bit in place */ emitADDV(b, R3, R2); /* R2 = R2 + R3 (overflow to T Bit) */ emitSHIFT(b, R0, OP_ROTCL); /* Rotate T back to SH2 reg */ emitMOVLS4(b, R2, regn, R8); /* sh2[Rn] <- R2 */ emitMOVLSG(b, 16); /* sh2[SR] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateAND(uint16_t inst, sh2rec_block_t *b) { generateALUOP(inst, b, OP_AND); b->pc += 2; } static void generateANDI(uint16_t inst, sh2rec_block_t *b) { int imm = INSTRUCTION_CD(inst); emitMOVLL4(b, R8, 0, R0); /* R0 <- sh2[R0] */ emitANDI(b, imm); /* R0 <- R0 & #imm */ emitMOVLS4(b, R0, 0, R8); /* sh2[R0] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateANDM(uint16_t inst, sh2rec_block_t *b) { int imm = INSTRUCTION_CD(inst); emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLLG(b, 17); /* R0 <- sh2[GBR] */ emitMOVLL4(b, R8, 0, R4); /* R4 <- sh2[R0] */ emitMOVLL4(b, R9, 0, R1); /* R1 <- MappedMemoryReadByte */ emitALU(b, R0, R4, OP_ADD); /* R4 <- R4 + R0 */ emitJSR(b, R1); /* Call MappedMemoryReadByte */ emitMOVLM(b, R4, R15); /* Push R4 on the stack (delay slot) */ emitMOVLL4(b, R9, 3, R1); /* R1 <- MappedMemoryWriteByte */ emitANDI(b, imm); /* R0 <- R0 & #imm */ emitMOVLP(b, R15, R4); /* Pop R4 off the stack */ emitJSR(b, R1); /* Call MappedMemoryWriteByte */ emitMOV(b, R0, R5); /* R5 <- R0 (delay slot) */ emitLDS(b, R10, R_PR); /* PR <- R10 */ b->cycles += 3; /* 3 Cycles */ b->pc += 2; } static void generateBF(uint16_t inst, sh2rec_block_t *b) { int disp = INSTRUCTION_CD(inst); uint32_t val = b->pc + 2; emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitMOVLI(b, 4, R2); /* R2 <- sh2[PC] + 2 */ emitSHIFT(b, R0, OP_ROTCR); /* Rotate SH2's T Bit in place */ emitMOVI(b, 0, R0); /* R0 <- 0 */ emitBT(b, 2); /* Branch around the addition if needed */ emitMOVI(b, disp, R0); /* R0 <- displacement */ emitSHIFT(b, R0, OP_SHLL); /* R0 <- R0 << 1 */ emitADDI(b, 2, R0); /* R0 <- R0 + 2 */ emitRTS(b); /* Return to sender! */ emitALU(b, R2, R0, OP_ADD); /* R0 <- R0 + R2 (delay slot) */ if(((uint32_t)b->ptr) & 0x03) emit16(b, 0); /* Padding if we need it */ emit32(b, val); /* The next PC value (if not taken) */ b->cycles += 2; /* 2 Cycles (if not taken) */ /* XXXX: Handle taken case cycle difference */ } static void generateBFS(uint16_t inst, sh2rec_block_t *b) { int disp = INSTRUCTION_CD(inst); uint32_t val = b->pc + 4; int n = (((uint32_t)b->ptr) & 0x03) ? 3 : 4; emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitMOVLI(b, n, R2); /* R2 <- sh2[PC] + 4 */ emitSHIFT(b, R0, OP_ROTCR); /* Rotate SH2's T Bit in place */ emitMOVI(b, 0, R0); /* R0 <- 0 */ emitBT(b, 1); /* Branch around the addition if needed */ emitMOVI(b, disp, R0); /* R0 <- displacement */ emitSHIFT(b, R0, OP_SHLL); /* R0 <- R0 << 1 */ if(((uint32_t)b->ptr) & 0x03) { emitBRA(b, 3); /* Branch around the constant */ emitALU(b, R2, R0, OP_ADD); /* R0 <- R0 + R2 (delay slot) */ emit16(b, 0); /* Padding since we need it */ } else { emitBRA(b, 2); /* Branch around the constant */ emitALU(b, R2, R0, OP_ADD); /* R0 <- R0 + R2 (delay slot) */ } emit32(b, val); /* The next PC value (if not taken) */ emitMOVLM(b, R0, R15); /* Push the next PC on the stack */ /* Deal with the delay slot here */ b->pc += 2; sh2rec_rec_inst(b, 1); emitRTS(b); /* Return to sender! */ emitMOVLP(b, R15, R0); /* Pop the next PC (delay slot) */ ++b->cycles; /* 1 Cycle (if not taken) */ /* XXXX: Handle taken case cycle difference */ } static void generateBRA(uint16_t inst, sh2rec_block_t *b) { int disp = INSTRUCTION_BCD(inst); int32_t val; if(disp & 0x00000800) { disp |= 0xFFFFF000; } val = b->pc + 4 + (disp << 1); emitMOVLI(b, 1, R2); /* R2 <- sh2[PC] + 4 + disp */ if(((uint32_t)b->ptr) & 0x03) { emitBRA(b, 3); /* Branch around the constant */ emitMOVLM(b, R2, R15); /* Push the next PC (delay slot) */ emit16(b, 0); /* Padding since we need it */ } else { emitBRA(b, 2); /* Branch around the constant */ emitMOVLM(b, R2, R15); /* Push the next PC (delay slot) */ } emit32(b, (uint32_t )val); /* The next PC */ /* Deal with the delay slot */ b->pc += 2; sh2rec_rec_inst(b, 1); emitRTS(b); /* Return to sender! */ emitMOVLP(b, R15, R0); /* Pop the next PC (delay slot) */ b->cycles += 2; /* 2 Cycles */ } static void generateBRAF(uint16_t inst, sh2rec_block_t *b) { int regm = INSTRUCTION_B(inst); uint32_t val = b->pc + 4; if(((uint32_t)b->ptr) & 0x03) { emitMOVLI(b, 2, R0); /* R0 <- sh2[PC] + 4 */ emitMOVLL4(b, R8, regm, R2);/* R2 <- sh2[Rm] */ emitBRA(b, 3); /* Branch around the constant */ emitALU(b, R0, R2, OP_ADD); /* R2 <- R0 + R2 (delay slot) */ emit16(b, 0); /* Padding since we need it */ } else { emitMOVLI(b, 1, R0); /* R0 <- sh2[PC] + 4 */ emitMOVLL4(b, R8, regm, R2);/* R2 <- sh2[Rm] */ emitBRA(b, 2); /* Branch around the constant */ emitALU(b, R0, R2, OP_ADD); /* R2 <- R0 + R2 (delay slot) */ } emit32(b, val); /* The value to use as the base for PC */ emitMOVLM(b, R2, R15); /* Push the next PC */ /* Deal with the delay slot */ b->pc += 2; sh2rec_rec_inst(b, 1); emitRTS(b); /* Return to sender! */ emitMOVLP(b, R15, R0); /* Pop the next PC (delay slot) */ b->cycles += 2; /* 2 Cycles */ } static void generateBSR(uint16_t inst, sh2rec_block_t *b) { int disp = INSTRUCTION_BCD(inst); int32_t val; int32_t val2 = b->pc + 4; if(disp & 0x00000800) { disp |= 0xFFFFF000; } val = b->pc + 4 + (disp << 1); if(((uint32_t)b->ptr) & 0x03) { emitMOVLI(b, 2, R2); /* R2 <- sh2[PC] + 4 + disp */ emitMOVLI(b, 2, R0); /* R0 <- sh2[PC] + 4 */ emitBRA(b, 5); /* Branch around the constant */ emitMOVLM(b, R2, R15); /* Push the next PC (delay slot) */ emit16(b, 0); /* Padding since we need it */ } else { emitMOVLI(b, 1, R2); /* R2 <- sh2[PC] + 4 + disp */ emitMOVLI(b, 2, R0); /* R0 <- sh2[PC] + 4 */ emitBRA(b, 4); /* Branch around the constant */ emitMOVLM(b, R2, R15); /* Push the next PC (delay slot) */ } emit32(b, (uint32_t)val); /* The next PC */ emit32(b, (uint32_t)val2); /* The value for PR */ emitMOVLSG(b, 21); /* sh2[PR] <- R0 */ /* Deal with the delay slot */ b->pc += 2; sh2rec_rec_inst(b, 1); emitRTS(b); /* Return to sender! */ emitMOVLP(b, R15, R0); /* Pop the next PC (delay slot) */ b->cycles += 2; /* 2 Cycles */ } static void generateBSRF(uint16_t inst, sh2rec_block_t *b) { int regm = INSTRUCTION_B(inst); uint32_t val = b->pc + 4; emitMOVLI(b, 1, R0); /* R0 <- sh2[PC] + 4 */ if(((uint32_t)b->ptr) & 0x03) { emitBRA(b, 3); /* Branch around the constant */ emitMOVLL4(b, R8, regm, R2);/* R2 <- sh2[Rm] (delay slot) */ emit16(b, 0); /* Padding since we need it */ } else { emitBRA(b, 2); /* Branch around the constant */ emitMOVLL4(b, R8, regm, R2);/* R2 <- sh2[Rm] (delay slot) */ } emit32(b, val); /* The value to put in PR */ emitALU(b, R0, R2, OP_ADD); /* R2 <- R0 + R2 (branch target) */ emitMOVLSG(b, 21); /* sh2[PR] <- R0 */ emitMOVLM(b, R2, R15); /* Push the next PC */ /* Deal with the delay slot */ b->pc += 2; sh2rec_rec_inst(b, 1); emitRTS(b); /* Return to sender! */ emitMOVLP(b, R15, R0); /* Pop the next PC (delay slot) */ b->cycles += 2; /* 2 Cycles */ } static void generateBT(uint16_t inst, sh2rec_block_t *b) { int disp = INSTRUCTION_CD(inst); uint32_t val = b->pc + 2; emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitMOVLI(b, 4, R2); /* R2 <- sh2[PC] + 4 */ emitSHIFT(b, R0, OP_ROTCR); /* Rotate SH2's T Bit in place */ emitMOVI(b, 0, R0); /* R0 <- 0 */ emitBF(b, 2); /* Branch around the addition if needed */ emitMOVI(b, disp, R0); /* R0 <- displacement */ emitSHIFT(b, R0, OP_SHLL); /* R0 <- R0 << 1 */ emitADDI(b, 2, R0); /* R0 <- R0 + 2 */ emitRTS(b); /* Return to sender! */ emitALU(b, R2, R0, OP_ADD); /* R0 <- R0 + R2 (delay slot) */ if(((uint32_t)b->ptr) & 0x03) emit16(b, 0); /* Padding if we need it */ emit32(b, val); /* The next PC value (if not taken) */ b->cycles += 2; /* 2 Cycles (if not taken) */ /* XXXX: Handle taken case cycle difference */ } static void generateBTS(uint16_t inst, sh2rec_block_t *b) { int disp = INSTRUCTION_CD(inst); uint32_t val = b->pc + 4; int n = (((uint32_t)b->ptr) & 0x03) ? 3 : 4; emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitMOVLI(b, n, R2); /* R2 <- sh2[PC] + 2 */ emitSHIFT(b, R0, OP_ROTCR); /* Rotate SH2's T Bit in place */ emitMOVI(b, 0, R0); /* R0 <- 0 */ emitBF(b, 1); /* Branch around the addition if needed */ emitMOVI(b, disp, R0); /* R0 <- displacement */ emitSHIFT(b, R0, OP_SHLL); /* R0 <- R0 << 1 */ if(((uint32_t)b->ptr) & 0x03) { emitBRA(b, 3); /* Branch around the constant */ emitALU(b, R2, R0, OP_ADD); /* R0 <- R0 + R2 (delay slot) */ emit16(b, 0); /* Padding since we need it */ } else { emitBRA(b, 2); /* Branch around the constant */ emitALU(b, R2, R0, OP_ADD); /* R0 <- R0 + R2 (delay slot) */ } emit32(b, val); /* The next PC value (if not taken) */ emitMOVLM(b, R0, R15); /* Push the next PC */ /* Deal with the delay slot */ b->pc += 2; sh2rec_rec_inst(b, 1); emitRTS(b); /* Return to sender! */ emitMOVLP(b, R15, R0); /* Pop the next PC (delay slot) */ ++b->cycles; /* 1 Cycle (if not taken) */ /* XXXX: Handle taken case cycle difference */ } static void generateCLRMAC(uint16_t inst, sh2rec_block_t *b) { emitCLRMAC(b); /* MACL/MACH <- 0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateCLRT(uint16_t inst, sh2rec_block_t *b) { emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitMOVI(b, 0xFE, R1); /* R1 <- 0xFFFFFFFE */ emitALU(b, R3, R0, OP_AND); /* Clear T bit */ emitMOVLSG(b, 16); /* sh2[SR] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateCMPEQ(uint16_t inst, sh2rec_block_t *b) { generateCOMP(inst, b, OP_CMPEQ); b->pc += 2; } static void generateCMPGE(uint16_t inst, sh2rec_block_t *b) { generateCOMP(inst, b, OP_CMPGE); b->pc += 2; } static void generateCMPGT(uint16_t inst, sh2rec_block_t *b) { generateCOMP(inst, b, OP_CMPGT); b->pc += 2; } static void generateCMPHI(uint16_t inst, sh2rec_block_t *b) { generateCOMP(inst, b, OP_CMPHI); b->pc += 2; } static void generateCMPHS(uint16_t inst, sh2rec_block_t *b) { generateCOMP(inst, b, OP_CMPHS); b->pc += 2; } static void generateCMPSTR(uint16_t inst, sh2rec_block_t *b) { generateCOMP(inst, b, OP_CMPSTR); b->pc += 2; } static void generateCMPPL(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitSHIFT(b, R0, OP_ROTCR); /* Rotate SH2's T Bit in place */ emitCMPPL(b, R2); /* cmp/pl R2 */ emitSHIFT(b, R0, OP_ROTCL); /* Rotate T back to SH2 reg */ emitMOVLSG(b, 16); /* sh2[SR] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateCMPPZ(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitSHIFT(b, R0, OP_ROTCR); /* Rotate SH2's T Bit in place */ emitCMPPZ(b, R2); /* cmp/pz R2 */ emitSHIFT(b, R0, OP_ROTCL); /* Rotate T back to SH2 reg */ emitMOVLSG(b, 16); /* sh2[SR] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateCMPIM(uint16_t inst, sh2rec_block_t *b) { int imm = INSTRUCTION_CD(inst); emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitMOV(b, R0, R2); /* R2 <- R0 */ emitMOVLL4(b, R8, 0, R0); /* R0 <- sh2[R0] */ emitSHIFT(b, R2, OP_ROTCR); /* Rotate SH2's T Bit in place */ emitCMPIM(b, imm); /* cmp/eq R0, #imm */ emitSHIFT(b, R2, OP_ROTCL); /* Rotate T back to SH2 reg */ emitMOV(b, R2, R0); /* R0 <- R2 */ emitMOVLSG(b, 16); /* sh2[SR] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateDIV0S(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitMOVI(b, 0x03, R4); /* R4 <- 0x03 */ emitANDI(b, 0xF2); /* Clear M, Q, and T */ emitMOVLL4(b, R8, regm, R3); /* R3 <- sh2[Rm] */ emitSHLL8(b, R4); /* R4 <<= 8 */ emitSHIFT(b, R0, OP_SHLR); /* Chop off the T from the SH2 reg */ emitDIV0S(b, R3, R2); /* div0s to grab the M, Q, T bits needed */ emitSTC(b, R_SR, R5); /* Save SR to R5 */ emitALU(b, R4, R5, OP_AND); /* Grab M, Q from the SR */ emitSHIFT(b, R0, OP_ROTCL); /* Rotate T back to SH2 reg */ emitALU(b, R5, R0, OP_OR); /* Save M, Q into the SH2 reg */ emitMOVLSG(b, 16); /* sh2[SR] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateDIV0U(uint16_t inst, sh2rec_block_t *b) { emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitANDI(b, 0xF2); /* Mask off M, Q, and T bits */ emitMOVLSG(b, 16); /* sh2[SR] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateDIV1(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitMOVI(b, 0x03, R4); /* R4 <- 0x03 */ emitSHLL8(b, R4); /* R4 <<= 8 */ emitMOVLL4(b, R8, regm, R3); /* R3 <- sh2[Rm] */ emitMOV(b, R4, R6); /* R6 <- R4 */ emitALU(b, R0, R6, OP_AND); /* Grab SH2 M and Q bits */ emitSHIFT(b, R0, OP_ROTCR); /* Rotate SH2's T in place */ emitSTC(b, R_SR, R5); /* Save SR to R5 */ emitALU(b, R4, R7, OP_NOT); /* Set up the mask to clear M and Q */ emitALU(b, R7, R5, OP_AND); /* Clear M, Q */ emitALU(b, R6, R5, OP_OR); /* Put SH2's M and Q in place */ emitLDC(b, R5, R_SR); /* Put the modified SR in place */ emitDIV1(b, R3, R2); /* Do the division! */ emitSTC(b, R_SR, R5); /* Save updated SR to R5 */ emitALU(b, R4, R5, OP_AND); /* Grab M and Q from the SR */ emitSHIFT(b, R0, OP_ROTCL); /* Rotate T back to SH2 reg */ emitMOVLS4(b, R2, regn, R8); /* sh2[Rn] <- R2 */ emitANDI(b, 0xF3); /* Clear M and Q from the SH2 reg */ emitALU(b, R5, R0, OP_OR); /* Save M and Q into the SH2 reg */ emitMOVLSG(b, 16); /* sh2[SR] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateDMULS(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitMOVLL4(b, R8, regm, R3); /* R3 <- sh2[Rm] */ emitALU(b, R3, R2, OP_DMULS); /* MACH/MACL <- (s32)R2 * (s32)R3 */ b->cycles += 2; /* 2 Cycles */ b->pc += 2; } static void generateDMULU(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitMOVLL4(b, R8, regm, R3); /* R3 <- sh2[Rm] */ emitALU(b, R3, R2, OP_DMULU); /* MACH/MACL <- (u32)R2 * (u32)R3 */ b->cycles += 2; /* 2 Cycles */ b->pc += 2; } static void generateDT(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitSHIFT(b, R0, OP_ROTCR); /* Rotate SH2's T Bit in place */ emitDT(b, R2); /* R2 = R2 - 1 (T Bit = non-zero) */ emitSHIFT(b, R0, OP_ROTCL); /* Rotate T back to SH2 reg */ emitMOVLS4(b, R2, regn, R8); /* sh2[Rn] <- R2 */ emitMOVLSG(b, 16); /* sh2[SR] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateEXTSB(uint16_t inst, sh2rec_block_t *b) { generateALUOP(inst, b, OP_EXTSB); b->pc += 2; } static void generateEXTSW(uint16_t inst, sh2rec_block_t *b) { generateALUOP(inst, b, OP_EXTSW); b->pc += 2; } static void generateEXTUB(uint16_t inst, sh2rec_block_t *b) { generateALUOP(inst, b, OP_EXTUB); b->pc += 2; } static void generateEXTUW(uint16_t inst, sh2rec_block_t *b) { generateALUOP(inst, b, OP_EXTUW); b->pc += 2; } static void generateJMP(uint16_t inst, sh2rec_block_t *b) { int regm = INSTRUCTION_B(inst); emitMOVLL4(b, R8, regm, R0); /* Grab the next PC value */ emitMOVLM(b, R0, R15); /* Push the next PC on the stack */ /* Deal with the delay slot */ b->pc += 2; sh2rec_rec_inst(b, 1); emitRTS(b); /* Return to sender! */ emitMOVLP(b, R15, R0); /* Pop the next PC (delay slot) */ b->cycles += 2; /* 2 Cycles */ } static void generateJSR(uint16_t inst, sh2rec_block_t *b) { int regm = INSTRUCTION_B(inst); uint32_t val = b->pc + 4; emitMOVLI(b, 1, R0); /* R0 <- sh2[PC] + 4 */ if(((uint32_t)b->ptr) & 0x03) { emitBRA(b, 3); /* Branch around the constant */ emitMOVLL4(b, R8, regm, R2);/* R2 <- sh2[Rm] (delay slot) */ emit16(b, 0); /* Padding since we need it */ } else { emitBRA(b, 2); /* Branch around the constant */ emitMOVLL4(b, R8, regm, R2);/* R2 <- sh2[Rm] (delay slot) */ } emit32(b, val); /* The value to put in PR */ emitMOVLM(b, R2, R15); /* Push the next PC */ emitMOVLSG(b, 21); /* sh2[PR] <- R0 */ /* Deal with the delay slot */ b->pc += 2; sh2rec_rec_inst(b, 1); emitRTS(b); /* Return to sender! */ emitMOVLP(b, R15, R0); /* Pop the next PC (delay slot) */ b->cycles += 2; /* 2 Cycles */ } static void generateLDCSR(uint16_t inst, sh2rec_block_t *b) { int regm = INSTRUCTION_B(inst); emitMOVWI(b, 2, R2); /* R2 <- 0x03F3 */ emitMOVLL4(b, R8, regm, R0); /* R0 <- sh2[Rm] */ emitBRA(b, 1); /* Jump beyond the constant */ emitALU(b, R2, R0, OP_AND); /* R0 <- R0 & R2 (delay slot) */ emit16(b, 0x03F3); /* 0x03F3, grabbed by the emitMOVWI */ emitMOVLSG(b, 16); /* sh2[SR] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateLDCGBR(uint16_t inst, sh2rec_block_t *b) { int regm = INSTRUCTION_B(inst); emitMOVLL4(b, R8, regm, R0); /* R0 <- sh2[Rm] */ emitMOVLSG(b, 17); /* sh2[GBR] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateLDCVBR(uint16_t inst, sh2rec_block_t *b) { int regm = INSTRUCTION_B(inst); emitMOVLL4(b, R8, regm, R0); /* R0 <- sh2[Rm] */ emitMOVLSG(b, 18); /* sh2[VBR] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateLDCMSR(uint16_t inst, sh2rec_block_t *b) { int regm = INSTRUCTION_B(inst); emitMOVLL4(b, R9, 2, R0); /* R0 <- MappedMemoryReadLong */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLL4(b, R8, regm, R4); /* R4 <- sh2[Rm] */ emitMOVI(b, 4, R1); /* R1 <- 4 */ emitALU(b, R4, R1, OP_ADD); /* R1 <- R4 + R1 */ emitJSR(b, R0); /* Call MappedMemoryReadLong */ emitMOVLS4(b, R1, regm, R8); /* sh2[Rm] <- R1 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitMOVWI(b, 2, R2); /* R2 <- 0x03F3 */ emitBRA(b, 1); /* Jump beyond the constant */ emitALU(b, R2, R0, OP_AND); /* R0 <- R0 & R2 (delay slot) */ emit16(b, 0x03F3); /* 0x03F3, grabbed by the emitMOVWI */ emitMOVLSG(b, 16); /* sh2[SR] <- R0 */ b->cycles += 3; /* 3 Cycles */ b->pc += 2; } static void generateLDCMGBR(uint16_t inst, sh2rec_block_t *b) { int regm = INSTRUCTION_B(inst); emitMOVLL4(b, R9, 2, R0); /* R0 <- MappedMemoryReadLong */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLL4(b, R8, regm, R4); /* R4 <- sh2[Rm] */ emitMOVI(b, 4, R1); /* R1 <- 4 */ emitALU(b, R4, R1, OP_ADD); /* R1 <- R4 + R1 */ emitJSR(b, R0); /* Call MappedMemoryReadLong */ emitMOVLS4(b, R1, regm, R8); /* sh2[Rm] <- R1 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitMOVLSG(b, 17); /* sh2[GBR] <- R0 */ b->cycles += 3; /* 3 Cycles */ b->pc += 2; } static void generateLDCMVBR(uint16_t inst, sh2rec_block_t *b) { int regm = INSTRUCTION_B(inst); emitMOVLL4(b, R9, 2, R0); /* R0 <- MappedMemoryReadLong */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLL4(b, R8, regm, R4); /* R4 <- sh2[Rm] */ emitMOVI(b, 4, R1); /* R1 <- 4 */ emitALU(b, R4, R1, OP_ADD); /* R1 <- R4 + R1 */ emitJSR(b, R0); /* Call MappedMemoryReadLong */ emitMOVLS4(b, R1, regm, R8); /* sh2[Rm] <- R1 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitMOVLSG(b, 18); /* sh2[VBR] <- R0 */ b->cycles += 3; /* 3 Cycles */ b->pc += 2; } static void generateLDSMACH(uint16_t inst, sh2rec_block_t *b) { int regm = INSTRUCTION_B(inst); emitMOVLL4(b, R8, regm, R0); /* R0 <- sh2[Rm] */ emitLDS(b, R0, R_MACH); /* MACH <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateLDSMACL(uint16_t inst, sh2rec_block_t *b) { int regm = INSTRUCTION_B(inst); emitMOVLL4(b, R8, regm, R0); /* R0 <- sh2[Rm] */ emitLDS(b, R0, R_MACL); /* MACL <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateLDSPR(uint16_t inst, sh2rec_block_t *b) { int regm = INSTRUCTION_B(inst); emitMOVLL4(b, R8, regm, R0); /* R0 <- sh2[Rm] */ emitMOVLSG(b, 21); /* sh2[PR] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateLDSMMACH(uint16_t inst, sh2rec_block_t *b) { int regm = INSTRUCTION_B(inst); emitMOVLL4(b, R9, 2, R0); /* R0 <- MappedMemoryReadLong */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLL4(b, R8, regm, R4); /* R4 <- sh2[Rm] */ emitMOVI(b, 4, R1); /* R1 <- 4 */ emitALU(b, R4, R1, OP_ADD); /* R1 <- R4 + R1 */ emitJSR(b, R0); /* Call MappedMemoryReadLong */ emitMOVLS4(b, R1, regm, R8); /* sh2[Rm] <- R1 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitLDS(b, R0, R_MACH); /* MACH <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateLDSMMACL(uint16_t inst, sh2rec_block_t *b) { int regm = INSTRUCTION_B(inst); emitMOVLL4(b, R9, 2, R0); /* R0 <- MappedMemoryReadLong */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLL4(b, R8, regm, R4); /* R4 <- sh2[Rm] */ emitMOVI(b, 4, R1); /* R1 <- 4 */ emitALU(b, R4, R1, OP_ADD); /* R1 <- R4 + R1 */ emitJSR(b, R0); /* Call MappedMemoryReadLong */ emitMOVLS4(b, R1, regm, R8); /* sh2[Rm] <- R1 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitLDS(b, R0, R_MACL); /* MACL <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateLDSMPR(uint16_t inst, sh2rec_block_t *b) { int regm = INSTRUCTION_B(inst); emitMOVLL4(b, R9, 2, R0); /* R0 <- MappedMemoryReadLong */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLL4(b, R8, regm, R4); /* R4 <- sh2[Rm] */ emitMOVI(b, 4, R1); /* R1 <- 4 */ emitALU(b, R4, R1, OP_ADD); /* R1 <- R4 + R1 */ emitJSR(b, R0); /* Call MappedMemoryReadLong */ emitMOVLS4(b, R1, regm, R8); /* sh2[Rm] <- R1 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitMOVLSG(b, 21); /* sh2[PR] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMACL(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLL4(b, R8, regm, R4); /* R4 <- sh2[Rm] */ emitMOVLL4(b, R9, 2, R0); /* R0 <- MappedMemoryReadLong */ emitADDI(b, 4, R4); /* R4 <- R4 + 4 */ emitMOVLS4(b, R4, regm, R8); /* sh2[Rm] <- R4 */ emitJSR(b, R0); /* Call MappedMemoryReadLong */ emitADDI(b, -4, R4); /* R4 <- R4 - 4 (delay slot) */ emitMOVLM(b, R0, R15); /* Push R0 onto the stack */ emitMOVLL4(b, R8, regn, R4); /* R4 <- sh2[Rn] */ emitMOVLL4(b, R9, 2, R0); /* R0 <- MappedMemoryReadLong */ emitADDI(b, 4, R4); /* R4 <- R4 + 4 */ emitMOVLS4(b, R4, regn, R8); /* sh2[Rn] <- R4 */ emitJSR(b, R0); /* Call MappedMemoryReadLong */ emitADDI(b, -4, R4); /* R4 <- R4 - 4 (delay slot) */ emitSTC(b, R_SR, R2); /* R2 <- SR */ emitMOVI(b, 0xFD, R3); /* R3 <- 0xFFFFFFFD */ emitMOVLM(b, R0, R15); /* Push R0 onto the stack */ emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitALU(b, R2, R3, OP_AND); /* R3 <- R2 & R3 (Mask out S Bit) */ emitANDI(b, 0x02); /* R0 <- R0 & 0x02 (S Bit) */ emitALU(b, R0, R3, OP_OR); /* R3 <- R0 | R3 (Put SH2 S Bit in) */ emitLDC(b, R3, R_SR); /* SR <- R3 */ emitMACL(b, R15, R15); /* Perform the MAC.L */ emitLDC(b, R2, R_SR); /* SR <- R2 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ b->cycles += 3; /* 3 Cycles */ b->pc += 2; } static void generateMACW(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLL4(b, R8, regm, R4); /* R4 <- sh2[Rm] */ emitMOVLL4(b, R9, 1, R0); /* R0 <- MappedMemoryReadWord */ emitADDI(b, 2, R4); /* R4 <- R4 + 2 */ emitMOVLS4(b, R4, regm, R8); /* sh2[Rm] <- R4 */ emitJSR(b, R0); /* Call MappedMemoryReadWord */ emitADDI(b, -2, R4); /* R4 <- R4 - 2 (delay slot) */ emitMOVWM(b, R0, R15); /* Push R0 onto the stack */ emitMOVLL4(b, R8, regn, R4); /* R4 <- sh2[Rn] */ emitMOVLL4(b, R9, 1, R0); /* R0 <- MappedMemoryReadWord */ emitADDI(b, 2, R4); /* R4 <- R4 + 2 */ emitMOVLS4(b, R4, regn, R8); /* sh2[Rn] <- R4 */ emitJSR(b, R0); /* Call MappedMemoryReadWord */ emitADDI(b, -2, R4); /* R4 <- R4 - 2 (delay slot) */ emitMOVWM(b, R0, R15); /* Push R0 onto the stack */ emitSTC(b, R_SR, R2); /* R2 <- SR */ emitMOVI(b, 0xFD, R3); /* R3 <- 0xFFFFFFFD */ emitMOVLM(b, R0, R15); /* Push R0 onto the stack */ emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitALU(b, R2, R3, OP_AND); /* R3 <- R2 & R3 (Mask out S Bit) */ emitANDI(b, 0x02); /* R0 <- R0 & 0x02 (S Bit) */ emitALU(b, R0, R3, OP_OR); /* R3 <- R0 | R3 (Put SH2 S Bit in) */ emitLDC(b, R3, R_SR); /* SR <- R3 */ emitMACW(b, R15, R15); /* Perform the MAC.W */ emitLDC(b, R2, R_SR); /* SR <- R2 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ b->cycles += 3; /* 3 Cycles */ b->pc += 2; } static void generateMOV(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLL4(b, R8, regm, R2); /* R2 <- sh2[Rm] */ emitMOVLS4(b, R2, regn, R8); /* sh2[Rn] <- R2 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVBS(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLL4(b, R9, 3, R0); /* R0 <- MappedMemoryWriteByte */ emitMOVLL4(b, R8, regm, R5); /* R5 <- sh2[Rm] */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitJSR(b, R0); /* Call MappedMemoryWriteByte */ emitMOVLL4(b, R8, regn, R4); /* R4 <- sh2[Rn] */ emitLDS(b, R10, R_PR); /* PR <- R10 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVWS(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLL4(b, R9, 4, R0); /* R0 <- MappedMemoryWriteWord */ emitMOVLL4(b, R8, regm, R5); /* R5 <- sh2[Rm] */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitJSR(b, R0); /* Call MappedMemoryWriteWord */ emitMOVLL4(b, R8, regn, R4); /* R4 <- sh2[Rn] */ emitLDS(b, R10, R_PR); /* PR <- R10 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVLS(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLL4(b, R9, 5, R0); /* R0 <- MappedMemoryWriteLong */ emitMOVLL4(b, R8, regm, R5); /* R5 <- sh2[Rm] */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitJSR(b, R0); /* Call MappedMemoryWriteLong */ emitMOVLL4(b, R8, regn, R4); /* R4 <- sh2[Rn] */ emitLDS(b, R10, R_PR); /* PR <- R10 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVBL(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLL4(b, R9, 0, R0); /* R0 <- MappedMemoryReadByte */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitJSR(b, R0); /* Call MappedMemoryReadByte */ emitMOVLL4(b, R8, regm, R4); /* R4 <- sh2[Rm] */ emitALU(b, R0, R0, OP_EXTSB); /* Sign extend read byte */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitMOVLS4(b, R0, regn, R8); /* sh2[Rn] <- read byte */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVWL(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLL4(b, R9, 1, R0); /* R0 <- MappedMemoryReadWord */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitJSR(b, R0); /* Call MappedMemoryReadWord */ emitMOVLL4(b, R8, regm, R4); /* R4 <- sh2[Rm] */ emitALU(b, R0, R0, OP_EXTSW); /* Sign extend read word */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitMOVLS4(b, R0, regn, R8); /* sh2[Rn] <- read word */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVLL(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLL4(b, R9, 2, R0); /* R0 <- MappedMemoryReadLong */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitJSR(b, R0); /* Call MappedMemoryReadLong */ emitMOVLL4(b, R8, regm, R4); /* R4 <- sh2[Rm] */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitMOVLS4(b, R0, regn, R8); /* sh2[Rn] <- read long */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVBM(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLL4(b, R8, regm, R5); /* R5 <- sh2[Rm] */ emitMOVLL4(b, R9, 3, R0); /* R0 <- MappedMemoryWriteByte */ emitMOVLL4(b, R8, regn, R4); /* R4 <- sh2[Rn] */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitADDI(b, -1, R4); /* R4 -= 1 */ emitJSR(b, R0); /* Call MappedMemoryWriteByte */ emitMOVLS4(b, R4, regn, R8); /* sh2[Rn] <- R4 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVWM(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLL4(b, R8, regm, R5); /* R5 <- sh2[Rm] */ emitMOVLL4(b, R9, 4, R0); /* R0 <- MappedMemoryWriteWord */ emitMOVLL4(b, R8, regn, R4); /* R4 <- sh2[Rn] */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitADDI(b, -2, R4); /* R4 -= 2 */ emitJSR(b, R0); /* Call MappedMemoryWriteWord */ emitMOVLS4(b, R4, regn, R8); /* sh2[Rn] <- R4 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVLM(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLL4(b, R8, regm, R5); /* R5 <- sh2[Rm] */ emitMOVLL4(b, R9, 5, R0); /* R0 <- MappedMemoryWriteLong */ emitMOVLL4(b, R8, regn, R4); /* R4 <- sh2[Rn] */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitADDI(b, -4, R4); /* R4 -= 4 */ emitJSR(b, R0); /* Call MappedMemoryWriteLong */ emitMOVLS4(b, R4, regn, R8); /* sh2[Rn] <- R4 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVBP(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLL4(b, R9, 0, R0); /* R0 <- MappedMemoryReadByte */ emitMOVLL4(b, R8, regm, R4); /* R4 <- sh2[Rm] */ emitMOVI(b, 1, R1); /* R1 <- 1 */ emitALU(b, R4, R1, OP_ADD); /* R1 <- R4 + R1 */ emitJSR(b, R0); /* Call MappedMemoryReadByte */ emitMOVLS4(b, R1, regm, R8); /* sh2[Rm] <- R1 */ emitALU(b, R0, R0, OP_EXTSB); /* Sign extend read byte */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitMOVLS4(b, R0, regn, R8); /* sh2[Rn] <- read byte */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVWP(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLL4(b, R9, 1, R0); /* R0 <- MappedMemoryReadWord */ emitMOVLL4(b, R8, regm, R4); /* R4 <- sh2[Rm] */ emitMOVI(b, 2, R1); /* R1 <- 2 */ emitALU(b, R4, R1, OP_ADD); /* R1 <- R4 + R1 */ emitJSR(b, R0); /* Call MappedMemoryReadWord */ emitMOVLS4(b, R1, regm, R8); /* sh2[Rm] <- R1 */ emitALU(b, R0, R0, OP_EXTSW); /* Sign extend read word */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitMOVLS4(b, R0, regn, R8); /* sh2[Rn] <- read word */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVLP(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLL4(b, R9, 2, R0); /* R0 <- MappedMemoryReadLong */ emitMOVLL4(b, R8, regm, R4); /* R4 <- sh2[Rm] */ emitMOVI(b, 4, R1); /* R1 <- 4 */ emitALU(b, R4, R1, OP_ADD); /* R1 <- R4 + R1 */ emitJSR(b, R0); /* Call MappedMemoryReadLong */ emitMOVLS4(b, R1, regm, R8); /* sh2[Rm] <- R1 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitMOVLS4(b, R0, regn, R8); /* sh2[Rn] <- read long */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVBS0(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLL4(b, R8, regm, R5); /* R5 <- sh2[Rm] */ emitMOVLL4(b, R8, 0, R1); /* R1 <- sh2[R0] */ emitMOVLL4(b, R9, 3, R0); /* R0 <- MappedMemoryWriteByte */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLL4(b, R8, regn, R4); /* R4 <- sh2[Rn] */ emitJSR(b, R0); /* Call MappedMemoryWriteByte */ emitALU(b, R1, R4, OP_ADD); /* R4 <- R4 + R1 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVWS0(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLL4(b, R8, regm, R5); /* R5 <- sh2[Rm] */ emitMOVLL4(b, R8, 0, R1); /* R1 <- sh2[R0] */ emitMOVLL4(b, R9, 4, R0); /* R0 <- MappedMemoryWriteWord */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLL4(b, R8, regn, R4); /* R4 <- sh2[Rn] */ emitJSR(b, R0); /* Call MappedMemoryWriteWord */ emitALU(b, R1, R4, OP_ADD); /* R4 <- R4 + R1 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVLS0(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLL4(b, R8, regm, R5); /* R5 <- sh2[Rm] */ emitMOVLL4(b, R8, 0, R1); /* R1 <- sh2[R0] */ emitMOVLL4(b, R9, 5, R0); /* R0 <- MappedMemoryWriteLong */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLL4(b, R8, regn, R4); /* R4 <- sh2[Rn] */ emitJSR(b, R0); /* Call MappedMemoryWriteLong */ emitALU(b, R1, R4, OP_ADD); /* R4 <- R4 + R1 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVBL0(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLL4(b, R9, 0, R0); /* R0 <- MappedMemoryReadByte */ emitMOVLL4(b, R8, regm, R4); /* R4 <- sh2[Rm] */ emitMOVLL4(b, R8, 0, R1); /* R1 <- sh2[R0] */ emitJSR(b, R0); /* Call MappedMemoryReadByte */ emitALU(b, R1, R4, OP_ADD); /* R4 <- R4 + R1 */ emitALU(b, R0, R0, OP_EXTSB); /* Sign extend read byte */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitMOVLS4(b, R0, regn, R8); /* sh2[Rn] <- read byte */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVWL0(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLL4(b, R9, 1, R0); /* R0 <- MappedMemoryReadWord */ emitMOVLL4(b, R8, regm, R4); /* R4 <- sh2[Rm] */ emitMOVLL4(b, R8, 0, R1); /* R1 <- sh2[R0] */ emitJSR(b, R0); /* Call MappedMemoryReadWord */ emitALU(b, R1, R4, OP_ADD); /* R4 <- R4 + R1 */ emitALU(b, R0, R0, OP_EXTSW); /* Sign extend read word */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitMOVLS4(b, R0, regn, R8); /* sh2[Rn] <- read word */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVLL0(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLL4(b, R9, 2, R0); /* R0 <- MappedMemoryReadLong */ emitMOVLL4(b, R8, regm, R4); /* R4 <- sh2[Rm] */ emitMOVLL4(b, R8, 0, R1); /* R1 <- sh2[R0] */ emitJSR(b, R0); /* Call MappedMemoryReadLong */ emitALU(b, R1, R4, OP_ADD); /* R4 <- R4 + R1 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitMOVLS4(b, R0, regn, R8); /* sh2[Rn] <- read long */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVI(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int imm = INSTRUCTION_CD(inst); emitMOVI(b, imm, R2); /* R2 <- #imm */ emitMOVLS4(b, R2, regn, R8); /* sh2[Rn] <- R2 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVWI(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int imm = INSTRUCTION_CD(inst); uint32_t addr = b->pc + 4 + (imm << 1); if(((uint32_t)b->ptr) & 0x03) { emitMOVLI(b, 1, R4); /* R4 <- calculated effective addr */ emitBRA(b, 2); /* Jump beyond the constant */ emitMOVLL4(b, R9, 1, R0); /* R0 <- MappedMemoryReadWord */ emit32(b, addr); /* MOV.W effective address */ } else { emitMOVLI(b, 1, R4); /* R4 <- calculated effective addr */ emitBRA(b, 3); /* Jump beyond the constant */ emitMOVLL4(b, R9, 1, R0); /* R0 <- MappedMemoryReadWord */ emit16(b, 0); /* Padding, for alignment issues */ emit32(b, addr); /* MOV.W effective address */ } emitSTS(b, R_PR, R10); /* R10 <- PR */ emitJSR(b, R0); /* Call MappedMemoryReadWord */ emitNOP(b); /* XXXX: Nothing to put here */ emitALU(b, R0, R0, OP_EXTSW); /* Sign extend read word */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitMOVLS4(b, R0, regn, R8); /* sh2[Rn] <- read word */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVLI(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int imm = INSTRUCTION_CD(inst); uint32_t addr = ((b->pc + 4) & 0xFFFFFFFC) + (imm << 2); if(((uint32_t)b->ptr) & 0x03) { emitMOVLI(b, 1, R4); /* R4 <- calculated effective addr */ emitBRA(b, 2); /* Jump beyond the constant */ emitMOVLL4(b, R9, 2, R0); /* R0 <- MappedMemoryReadLong */ emit32(b, addr); /* MOV.L effective address */ } else { emitMOVLI(b, 1, R4); /* R4 <- calculated effective addr */ emitBRA(b, 3); /* Jump beyond the constant */ emitMOVLL4(b, R9, 2, R0); /* R0 <- MappedMemoryReadLong */ emit16(b, 0); /* Padding, for alignment issues */ emit32(b, addr); /* MOV.L effective address */ } emitSTS(b, R_PR, R10); /* R10 <- PR */ emitJSR(b, R0); /* Call MappedMemoryReadLong */ emitNOP(b); /* XXXX: Nothing to put here */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitMOVLS4(b, R0, regn, R8); /* sh2[Rn] <- read long */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVBLG(uint16_t inst, sh2rec_block_t *b) { int imm = INSTRUCTION_CD(inst); emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLL4(b, R9, 0, R1); /* R1 <- MappedMemoryReadByte */ emitMOVI(b, imm, R4); /* R4 <- Displacement */ emitMOVLLG(b, 17); /* R0 <- sh2[GBR] */ emitALU(b, R4, R4, OP_EXTUB); /* Zero extend displacement */ emitJSR(b, R1); /* Call MappedMemoryReadByte */ emitALU(b, R0, R4, OP_ADD); /* R4 <- R4 + R0 */ emitALU(b, R0, R0, OP_EXTSB); /* Sign extend read byte */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitMOVLS4(b, R0, 0, R8); /* sh2[R0] <- read byte */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVWLG(uint16_t inst, sh2rec_block_t *b) { int imm = INSTRUCTION_CD(inst); emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVI(b, imm, R4); /* R4 <- Displacement */ emitMOVLL4(b, R9, 1, R1); /* R1 <- MappedMemoryReadWord */ emitALU(b, R4, R4, OP_EXTUB); /* Zero extend displacement */ emitMOVLLG(b, 17); /* R0 <- sh2[GBR] */ emitSHIFT(b, R4, OP_SHLL); /* Double displacement */ emitJSR(b, R1); /* Call MappedMemoryReadWord */ emitALU(b, R0, R4, OP_ADD); /* R4 <- R4 + R0 */ emitALU(b, R0, R0, OP_EXTSW); /* Sign extend read word */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitMOVLS4(b, R0, 0, R8); /* sh2[R0] <- read word */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVLLG(uint16_t inst, sh2rec_block_t *b) { int imm = INSTRUCTION_CD(inst); emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVI(b, imm, R4); /* R4 <- Displacement */ emitMOVLL4(b, R9, 2, R1); /* R1 <- MappedMemoryReadLong */ emitALU(b, R4, R4, OP_EXTUB); /* Zero extend displacement */ emitMOVLLG(b, 17); /* R0 <- sh2[GBR] */ emitSHLL2(b, R4); /* Quadruple displacement */ emitJSR(b, R1); /* Call MappedMemoryReadLong */ emitALU(b, R0, R4, OP_ADD); /* R4 <- R4 + R0 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitMOVLS4(b, R0, 0, R8); /* sh2[R0] <- read long */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVBSG(uint16_t inst, sh2rec_block_t *b) { int imm = INSTRUCTION_CD(inst); emitMOVLL4(b, R8, 0, R5); /* R5 <- sh2[R0] */ emitMOVLLG(b, 17); /* R0 <- sh2[GBR] */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLL4(b, R9, 3, R1); /* R1 <- MappedMemoryWriteByte */ emitMOVI(b, imm, R4); /* R4 <- Displacement */ emitALU(b, R4, R4, OP_EXTUB); /* Zero extend Displacement */ emitJSR(b, R1); /* Call MappedMemoryWriteByte */ emitALU(b, R0, R4, OP_ADD); /* R4 <- R4 + R0 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVWSG(uint16_t inst, sh2rec_block_t *b) { int imm = INSTRUCTION_CD(inst); emitMOVLL4(b, R8, 0, R5); /* R5 <- sh2[R0] */ emitMOVI(b, imm, R4); /* R4 <- Displacement */ emitMOVLLG(b, 17); /* R0 <- sh2[GBR] */ emitALU(b, R4, R4, OP_EXTUB); /* Zero extend Displacement */ emitMOVLL4(b, R9, 4, R1); /* R1 <- MappedMemoryWriteWord */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitSHIFT(b, R4, OP_SHLL); /* Double displacement */ emitJSR(b, R1); /* Call MappedMemoryWriteWord */ emitALU(b, R0, R4, OP_ADD); /* R4 <- R4 + R0 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVLSG(uint16_t inst, sh2rec_block_t *b) { int imm = INSTRUCTION_CD(inst); emitMOVLL4(b, R8, 0, R5); /* R5 <- sh2[R0] */ emitMOVI(b, imm, R4); /* R4 <- Displacement */ emitMOVLLG(b, 17); /* R0 <- sh2[GBR] */ emitALU(b, R4, R4, OP_EXTUB); /* Zero extend Displacement */ emitMOVLL4(b, R9, 5, R1); /* R1 <- MappedMemoryWriteLong */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitSHLL2(b, R4); /* Quadruple displacement */ emitJSR(b, R1); /* Call MappedMemoryWriteLong */ emitALU(b, R0, R4, OP_ADD); /* R4 <- R4 + R0 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVBS4(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_C(inst); int imm = INSTRUCTION_D(inst); emitMOVLL4(b, R8, 0, R5); /* R5 <- sh2[R0] */ emitMOVLL4(b, R9, 3, R1); /* R1 <- MappedMemoryWriteByte */ emitMOVLL4(b, R8, regn, R4); /* R4 <- sh2[Rn] */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitJSR(b, R1); /* Call MappedMemoryWriteByte */ emitADDI(b, imm, R4); /* R4 <- R4 + displacement */ emitLDS(b, R10, R_PR); /* PR <- R10 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVWS4(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_C(inst); int imm = INSTRUCTION_D(inst) << 1; emitMOVLL4(b, R8, 0, R5); /* R5 <- sh2[R0] */ emitMOVLL4(b, R9, 4, R1); /* R1 <- MappedMemoryWriteWord */ emitMOVLL4(b, R8, regn, R4); /* R4 <- sh2[Rn] */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitJSR(b, R1); /* Call MappedMemoryWriteWord */ emitADDI(b, imm, R4); /* R4 <- R4 + displacement */ emitLDS(b, R10, R_PR); /* PR <- R10 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVLS4(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); int imm = INSTRUCTION_D(inst) << 2; emitMOVLL4(b, R8, regm, R5); /* R5 <- sh2[Rm] */ emitMOVLL4(b, R9, 5, R1); /* R1 <- MappedMemoryWriteLong */ emitMOVLL4(b, R8, regn, R4); /* R4 <- sh2[Rn] */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitJSR(b, R1); /* Call MappedMemoryWriteLong */ emitADDI(b, imm, R4); /* R4 <- R4 + displacement */ emitLDS(b, R10, R_PR); /* PR <- R10 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVBL4(uint16_t inst, sh2rec_block_t *b) { int regm = INSTRUCTION_C(inst); int imm = INSTRUCTION_D(inst); emitMOVLL4(b, R8, regm, R4); /* R4 <- sh2[Rm] */ emitMOVLL4(b, R9, 0, R1); /* R1 <- MappedMemoryReadByte */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitJSR(b, R1); /* Call MappedMemoryReadByte */ emitADDI(b, imm, R4); /* R4 <- R4 + displacement */ emitALU(b, R0, R0, OP_EXTSB); /* Sign extend read byte */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitMOVLS4(b, R0, 0, R8); /* sh2[R0] <- read byte */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVWL4(uint16_t inst, sh2rec_block_t *b) { int regm = INSTRUCTION_C(inst); int imm = INSTRUCTION_D(inst) << 1; emitMOVLL4(b, R8, regm, R4); /* R4 <- sh2[Rm] */ emitMOVLL4(b, R9, 1, R1); /* R1 <- MappedMemoryReadWord */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitJSR(b, R1); /* Call MappedMemoryReadWord */ emitADDI(b, imm, R4); /* R4 <- R4 + displacement */ emitALU(b, R0, R0, OP_EXTSW); /* Sign extend read word */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitMOVLS4(b, R0, 0, R8); /* sh2[R0] <- read word */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVLL4(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); int imm = INSTRUCTION_D(inst) << 2; emitMOVLL4(b, R8, regm, R4); /* R4 <- sh2[Rm] */ emitMOVLL4(b, R9, 2, R1); /* R1 <- MappedMemoryReadLong */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitJSR(b, R1); /* Call MappedMemoryReadLong */ emitADDI(b, imm, R4); /* R4 <- R4 + displacement */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitMOVLS4(b, R0, regn, R8); /* sh2[Rn] <- read long */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVA(uint16_t inst, sh2rec_block_t *b) { int imm = INSTRUCTION_CD(inst); uint32_t addr = ((b->pc + 4) & 0xFFFFFFFC) + (imm << 2); if(((uint32_t)b->ptr) & 0x03) { emitMOVLI(b, 1, R2); /* R2 <- calculated effective addr */ emitBRA(b, 2); /* Jump beyond the constant */ emitMOVLS4(b, R2, 0, R8); /* sh2[R0] <- R2 */ emit32(b, addr); /* MOVA effective address */ } else { emitMOVLI(b, 1, R2); /* R2 <- calculated effective addr */ emitBRA(b, 3); /* Jump beyond the constant */ emitMOVLS4(b, R2, 0, R8); /* sh2[R0] <- R2 */ emit16(b, 0); /* Padding, for alignment issues */ emit32(b, addr); /* MOVA effective address */ } ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMOVT(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitANDI(b, 0x01); /* Grab T Bit */ emitMOVLS4(b, R0, regn, R8); /* sh2[Rn] <- T Bit */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMULL(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitMOVLL4(b, R8, regm, R3); /* R3 <- sh2[Rm] */ emitALU(b, R3, R2, OP_MULL); /* MACL <- R2 * R3 */ b->cycles += 2; /* 2 Cycles */ b->pc += 2; } static void generateMULS(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitMOVLL4(b, R8, regm, R3); /* R3 <- sh2[Rm] */ emitALU(b, R3, R2, OP_MULS); /* MACL <- (s16)R2 * (s16)R3 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateMULU(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitMOVLL4(b, R8, regm, R3); /* R3 <- sh2[Rm] */ emitALU(b, R3, R2, OP_MULU); /* MACL <- (u16)R2 * (u16)R3 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateNEG(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLL4(b, R8, regm, R3); /* R3 <- sh2[Rm] */ emitALU(b, R3, R2, OP_NEG); /* R2 <- 0 - R3 */ emitMOVLS4(b, R2, regn, R8); /* sh2[Rn] <- R2 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateNEGC(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitMOVLL4(b, R8, regm, R3); /* R3 <- sh2[Rm] */ emitSHIFT(b, R0, OP_ROTCR); /* Rotate SH2's T Bit in place */ emitALU(b, R3, R2, OP_NEGC); /* R2 = 0 - R3 - T (borrow to T) */ emitSHIFT(b, R0, OP_ROTCL); /* Rotate T back to SH2 reg */ emitMOVLS4(b, R2, regn, R8); /* sh2[Rn] <- R2 */ emitMOVLSG(b, 16); /* sh2[SR] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateNOP(uint16_t inst, sh2rec_block_t *b) { ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateNOT(uint16_t inst, sh2rec_block_t *b) { generateALUOP(inst, b, OP_NOT); b->pc += 2; } static void generateOR(uint16_t inst, sh2rec_block_t *b) { generateALUOP(inst, b, OP_OR); b->pc += 2; } static void generateORI(uint16_t inst, sh2rec_block_t *b) { int imm = INSTRUCTION_CD(inst); emitMOVLL4(b, R8, 0, R0); /* R0 <- sh2[R0] */ emitORI(b, imm); /* R0 <- R0 | #imm */ emitMOVLS4(b, R0, 0, R8); /* sh2[R0] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateORM(uint16_t inst, sh2rec_block_t *b) { int imm = INSTRUCTION_CD(inst); emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLLG(b, 17); /* R0 <- sh2[GBR] */ emitMOVLL4(b, R8, 0, R4); /* R4 <- sh2[R0] */ emitMOVLL4(b, R9, 0, R1); /* R1 <- MappedMemoryReadByte */ emitALU(b, R0, R4, OP_ADD); /* R4 <- R4 + R0 */ emitJSR(b, R1); /* Call MappedMemoryReadByte */ emitMOVLM(b, R4, R15); /* Push R4 on the stack (delay slot) */ emitMOVLL4(b, R9, 3, R1); /* R1 <- MappedMemoryWriteByte */ emitORI(b, imm); /* R0 <- R0 | #imm */ emitMOVLP(b, R15, R4); /* Pop R4 off the stack */ emitJSR(b, R1); /* Call MappedMemoryWriteByte */ emitMOV(b, R0, R5); /* R5 <- R0 (delay slot) */ emitLDS(b, R10, R_PR); /* PR <- R10 */ b->cycles += 3; /* 3 Cycles */ b->pc += 2; } static void generateROTCL(uint16_t inst, sh2rec_block_t *b) { generateSHIFT(inst, b, OP_ROTCL); b->pc += 2; } static void generateROTCR(uint16_t inst, sh2rec_block_t *b) { generateSHIFT(inst, b, OP_ROTCR); b->pc += 2; } static void generateROTL(uint16_t inst, sh2rec_block_t *b) { generateSHIFT(inst, b, OP_ROTL); b->pc += 2; } static void generateROTR(uint16_t inst, sh2rec_block_t *b) { generateSHIFT(inst, b, OP_ROTR); b->pc += 2; } static void generateRTE(uint16_t inst, sh2rec_block_t *b) { emitMOVLL4(b, R9, 2, R0); /* R0 <- MappedMemoryReadLong */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitJSR(b, R0); /* Call MappedMemoryReadLong */ emitMOVLL4(b, R8, 15, R4); /* R4 <- sh2[R15] (delay slot) */ emitMOVLL4(b, R9, 2, R1); /* R1 <- MappedMemoryReadLong */ emitMOVLL4(b, R8, 15, R4); /* R4 <- sh2[R15] */ emitMOVI(b, 4, R2); /* R2 <- 4 */ emitALU(b, R2, R4, OP_ADD); /* R4 <- R4 + R2 */ emitMOVLM(b, R0, R15); /* Push the next PC */ emitALU(b, R4, R2, OP_ADD); /* R2 <- R4 + R2 */ emitJSR(b, R1); /* Call MappedMemoryReadLong */ emitMOVLS4(b, R2, 15, R8); /* sh2[R15] <- R2 (delay slot) */ emitMOVWI(b, 1, R1); /* R1 <- 0x000003F3 */ emitBRA(b, 1); /* Branch around the constant */ emitALU(b, R1, R0, OP_AND); /* R0 <- R0 & R1 */ emit16(b, 0x03F3); /* Mask for SR register */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitMOVLSG(b, 16); /* sh2[SR] <- R0 */ /* Deal with the delay slot */ b->pc += 2; sh2rec_rec_inst(b, 1); emitRTS(b); /* Return to sender! */ emitMOVLP(b, R15, R0); /* Pop the next PC (delay slot) */ b->cycles += 4; /* 4 Cycles */ } static void generateRTS(uint16_t inst, sh2rec_block_t *b) { emitMOVLLG(b, 21); /* R0 <- sh2[PR] */ emitMOVLM(b, R0, R15); /* Push the PR on the stack */ /* Deal with the delay slot */ b->pc += 2; sh2rec_rec_inst(b, 1); emitRTS(b); /* Return to sender! */ emitMOVLP(b, R15, R0); /* Pop the next PC (delay slot) */ b->cycles += 2; /* 2 Cycles */ } static void generateSETT(uint16_t inst, sh2rec_block_t *b) { emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitORI(b, 0x01); /* Set T Bit */ emitMOVLSG(b, 16); /* sh2[SR] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateSHAL(uint16_t inst, sh2rec_block_t *b) { generateSHIFT(inst, b, OP_SHAL); b->pc += 2; } static void generateSHAR(uint16_t inst, sh2rec_block_t *b) { generateSHIFT(inst, b, OP_SHAR); b->pc += 2; } static void generateSHLL(uint16_t inst, sh2rec_block_t *b) { generateSHIFT(inst, b, OP_SHLL); b->pc += 2; } static void generateSHLL2(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitSHLL2(b, R2); /* R2 <- R2 << 2 */ emitMOVLS4(b, R2, regn, R8); /* sh2[Rn] <- R2 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateSHLL8(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitSHLL8(b, R2); /* R2 <- R2 << 8 */ emitMOVLS4(b, R2, regn, R8); /* sh2[Rn] <- R2 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateSHLL16(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitSHLL16(b, R2); /* R2 <- R2 << 16 */ emitMOVLS4(b, R2, regn, R8); /* sh2[Rn] <- R2 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateSHLR(uint16_t inst, sh2rec_block_t *b) { generateSHIFT(inst, b, OP_SHLR); b->pc += 2; } static void generateSHLR2(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitSHLR2(b, R2); /* R2 <- R2 >> 2 */ emitMOVLS4(b, R2, regn, R8); /* sh2[Rn] <- R2 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateSHLR8(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitSHLR8(b, R2); /* R2 <- R2 >> 8 */ emitMOVLS4(b, R2, regn, R8); /* sh2[Rn] <- R2 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateSHLR16(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitSHLR16(b, R2); /* R2 <- R2 >> 16 */ emitMOVLS4(b, R2, regn, R8); /* sh2[Rn] <- R2 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateSLEEP(uint16_t inst, sh2rec_block_t *b) { b->cycles += 3; /* 3 Cycles */ b->pc += 2; } static void generateSTCSR(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitMOVLS4(b, R0, regn, R8); /* sh2[Rn] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateSTCGBR(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitMOVLLG(b, 17); /* R0 <- sh2[GBR] */ emitMOVLS4(b, R0, regn, R8); /* sh2[Rn] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateSTCVBR(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitMOVLLG(b, 18); /* R0 <- sh2[VBR] */ emitMOVLS4(b, R0, regn, R8); /* sh2[Rn] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateSTCMSR(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitMOVLL4(b, R9, 5, R1); /* R1 <- MappedMemoryWriteLong */ emitMOVLL4(b, R8, regn, R4); /* R4 <- sh2[Rn] */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitADDI(b, -4, R4); /* R4 -= 4 */ emitMOV(b, R0, R5); /* R5 <- R0 */ emitJSR(b, R1); /* Call MappedMemoryWriteLong */ emitMOVLS4(b, R4, regn, R8); /* sh2[Rn] <- R4 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ b->cycles += 2; /* 2 Cycles */ b->pc += 2; } static void generateSTCMGBR(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitMOVLLG(b, 17); /* R0 <- sh2[GBR] */ emitMOVLL4(b, R9, 5, R1); /* R1 <- MappedMemoryWriteLong */ emitMOVLL4(b, R8, regn, R4); /* R4 <- sh2[Rn] */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitADDI(b, -4, R4); /* R4 -= 4 */ emitMOV(b, R0, R5); /* R5 <- R0 */ emitJSR(b, R1); /* Call MappedMemoryWriteLong */ emitMOVLS4(b, R4, regn, R8); /* sh2[Rn] <- R4 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ b->cycles += 2; /* 2 Cycles */ b->pc += 2; } static void generateSTCMVBR(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitMOVLLG(b, 18); /* R0 <- sh2[VBR] */ emitMOVLL4(b, R9, 5, R1); /* R1 <- MappedMemoryWriteLong */ emitMOVLL4(b, R8, regn, R4); /* R4 <- sh2[Rn] */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitADDI(b, -4, R4); /* R4 -= 4 */ emitMOV(b, R0, R5); /* R5 <- R0 */ emitJSR(b, R1); /* Call MappedMemoryWriteLong */ emitMOVLS4(b, R4, regn, R8); /* sh2[Rn] <- R4 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ b->cycles += 2; /* 2 Cycles */ b->pc += 2; } static void generateSTSMACH(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitSTS(b, R_MACH, R0); /* R0 <- MACH */ emitMOVLS4(b, R0, regn, R8); /* sh2[Rn] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateSTSMACL(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitSTS(b, R_MACL, R0); /* R0 <- MACL */ emitMOVLS4(b, R0, regn, R8); /* sh2[Rn] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateSTSPR(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitMOVLLG(b, 21); /* R0 <- sh2[PR] */ emitMOVLS4(b, R0, regn, R8); /* sh2[Rn] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateSTSMMACH(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitSTS(b, R_MACH, R5); /* R5 <- MACH */ emitMOVLL4(b, R9, 5, R1); /* R1 <- MappedMemoryWriteLong */ emitMOVLL4(b, R8, regn, R4); /* R4 <- sh2[Rn] */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitADDI(b, -4, R4); /* R4 -= 4 */ emitJSR(b, R1); /* Call MappedMemoryWriteLong */ emitMOVLS4(b, R4, regn, R8); /* sh2[Rn] <- R4 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateSTSMMACL(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitSTS(b, R_MACL, R5); /* R5 <- MACL */ emitMOVLL4(b, R9, 5, R1); /* R1 <- MappedMemoryWriteLong */ emitMOVLL4(b, R8, regn, R4); /* R4 <- sh2[Rn] */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitADDI(b, -4, R4); /* R4 -= 4 */ emitJSR(b, R1); /* Call MappedMemoryWriteLong */ emitMOVLS4(b, R4, regn, R8); /* sh2[Rn] <- R4 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateSTSMPR(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitMOVLLG(b, 21); /* R0 <- sh2[PR] */ emitMOVLL4(b, R9, 5, R1); /* R1 <- MappedMemoryWriteLong */ emitMOVLL4(b, R8, regn, R4); /* R4 <- sh2[Rn] */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitADDI(b, -4, R4); /* R4 -= 4 */ emitMOV(b, R0, R5); /* R5 <- R0 */ emitJSR(b, R1); /* Call MappedMemoryWriteLong */ emitMOVLS4(b, R4, regn, R8); /* sh2[Rn] <- R4 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateSUB(uint16_t inst, sh2rec_block_t *b) { generateALUOP(inst, b, OP_SUB); b->pc += 2; } static void generateSUBC(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitMOVLL4(b, R8, regm, R3); /* R3 <- sh2[Rm] */ emitSHIFT(b, R0, OP_ROTCR); /* Rotate SH2's T Bit in place */ emitALU(b, R3, R2, OP_SUBC); /* R2 = R2 - R3 - T (borrow to T) */ emitSHIFT(b, R0, OP_ROTCL); /* Rotate T back to SH2 reg */ emitMOVLS4(b, R2, regn, R8); /* sh2[Rn] <- R2 */ emitMOVLSG(b, 16); /* sh2[SR] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateSUBV(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); int regm = INSTRUCTION_C(inst); emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitMOVLL4(b, R8, regn, R2); /* R2 <- sh2[Rn] */ emitMOVLL4(b, R8, regm, R3); /* R3 <- sh2[Rm] */ emitSHIFT(b, R0, OP_ROTCR); /* Rotate SH2's T Bit in place */ emitSUBV(b, R3, R2); /* R2 = R2 - R3 (underflow to T Bit) */ emitSHIFT(b, R0, OP_ROTCL); /* Rotate T back to SH2 reg */ emitMOVLSG(b, 16); /* sh2[SR] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateSWAPB(uint16_t inst, sh2rec_block_t *b) { generateALUOP(inst, b, OP_SWAPB); b->pc += 2; } static void generateSWAPW(uint16_t inst, sh2rec_block_t *b) { generateALUOP(inst, b, OP_SWAPW); b->pc += 2; } static void generateTAS(uint16_t inst, sh2rec_block_t *b) { int regn = INSTRUCTION_B(inst); emitMOVLL4(b, R9, 0, R0); /* R0 <- MappedMemoryReadByte */ emitSTS(b, R_PR, R10); /* R10 <- PR */ emitJSR(b, R0); /* Call MappedMemoryReadByte */ emitMOVLL4(b, R8, regn, R4); /* R4 <- sh2[Rn] (delay slot) */ emitMOV(b, R0, R5); /* R5 <- R0 (byte read) */ emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitMOVI(b, 0x80, R2); /* R2 <- 0x80 */ emitMOVLL4(b, R8, regn, R4); /* R4 <- sh2[Rn] */ emitSHIFT(b, R0, OP_ROTCR); /* Rotate SH2's T Bit in place */ emitALU(b, R5, R5, OP_TST); /* T <- 1 if byte == 0, 0 otherwise */ emitSHIFT(b, R0, OP_ROTCL); /* Rotate T back to SH2 reg */ emitMOVLL4(b, R9, 3, R1); /* R1 <- MappedMemoryWriteByte */ emitMOVLSG(b, 16); /* sh2[SR] <- R0 */ emitJSR(b, R1); /* Call MappedMemoryWriteByte */ emitALU(b, R2, R5, OP_OR); /* R5 <- R5 | 0x80 (delay slot) */ emitLDS(b, R10, R_PR); /* PR <- R10 */ b->cycles += 4; /* 4 Cycles */ b->pc += 2; } static void generateTRAPA(uint16_t inst, sh2rec_block_t *b) { int imm = INSTRUCTION_CD(inst); int disp = (((uint32_t)(b->ptr)) & 0x03) ? 5 : 6; uint32_t val = b->pc + 2; emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLL4(b, R8, 15, R4); /* R4 <- sh2[R15] */ emitMOVLL4(b, R9, 5, R1); /* R1 <- MemoryMappedWriteLong */ emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitADDI(b, -4, R4); /* R4 <- R4 - 4 */ emitJSR(b, R1); /* Call MemoryMappedWriteLong */ emitMOV(b, R0, R5); /* R5 <- R0 (delay slot) */ emitMOVLL4(b, R8, 15, R4); /* R4 <- sh2[R15] */ emitMOVLL4(b, R9, 5, R1); /* R1 <- MemoryMappedWriteLong */ emitADDI(b, -8, R4); /* R4 <- R4 - 8 */ emitMOVLI(b, disp, R5); /* R5 <- Updated PC value (to be stacked) */ emitJSR(b, R1); /* Call MemoryMappedWriteLong */ emitMOVLS4(b, R4, 15, R8); /* sh2[R15] <- R4 (delay slot) */ emitMOVI(b, imm, R4); /* R4 <- immediate data */ emitALU(b, R4, R4, OP_EXTUB); /* Zero-extend R4 */ emitMOVLL4(b, R9, 2, R1); /* R1 <- MemoryMappedReadLong */ emitMOVLLG(b, 18); /* R0 <- sh2[VBR] */ emitSHLL2(b, R4); /* R4 <- R4 << 2 */ emitJSR(b, R1); /* Call MemoryMappedReadLong */ emitALU(b, R0, R4, OP_ADD); /* R4 <- R4 + R0 (delay slot) */ emitLDS(b, R10, R_PR); /* PR <- R10 */ emitRTS(b); /* Return to sender! */ emitNOP(b); /* XXXX: Nothing here */ if(((uint32_t)b->ptr) & 0x03) emit16(b, 0); /* Padding for the alignment */ emit32(b, val); /* The PC value to be loaded by the MOVLI */ b->cycles += 8; /* 8 Cycles */ } static void generateTST(uint16_t inst, sh2rec_block_t *b) { generateCOMP(inst, b, OP_TST); b->pc += 2; } static void generateTSTI(uint16_t inst, sh2rec_block_t *b) { int imm = INSTRUCTION_CD(inst); emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitMOV(b, R0, R2); /* R2 <- R0 */ emitMOVLL4(b, R8, 0, R0); /* R0 <- sh2[R0] */ emitSHIFT(b, R2, OP_ROTCR); /* Rotate SH2's T Bit in place */ emitTSTI(b, imm); /* tst #imm, r0 */ emitSHIFT(b, R2, OP_ROTCL); /* Rotate T back to SH2 reg */ emitMOV(b, R2, R0); /* R0 <- R2 */ emitMOVLSG(b, 16); /* sh2[SR] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateTSTM(uint16_t inst, sh2rec_block_t *b) { int imm = INSTRUCTION_CD(inst); emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLL4(b, R9, 0, R1); /* R1 <- MappedMemoryReadByte */ emitMOVLLG(b, 17); /* R0 <- sh2[GBR] */ emitMOVLL4(b, R8, 0, R4); /* R4 <- sh2[R0] */ emitJSR(b, R1); /* Call MappedMemoryReadByte */ emitALU(b, R0, R4, OP_ADD); /* R4 <- R4 + R0 (delay slot) */ emitMOV(b, R0, R5); /* R5 <- R0 (byte read) */ emitMOVI(b, imm, R3); /* R3 <- immediate value */ emitMOVLLG(b, 16); /* R0 <- sh2[SR] */ emitSHIFT(b, R0, OP_ROTCR); /* Rotate SH2's T Bit in place */ emitALU(b, R3, R5, OP_TST); /* T <- 1 if (R5 & imm) == 0, 0 otherwise */ emitSHIFT(b, R0, OP_ROTCL); /* Rotate T back to SH2 reg */ emitMOVLSG(b, 16); /* sh2[SR] <- R0 */ emitLDS(b, R10, R_PR); /* PR <- R10 */ b->cycles += 3; /* 3 Cycles */ b->pc += 2; } static void generateXOR(uint16_t inst, sh2rec_block_t *b) { generateALUOP(inst, b, OP_XOR); b->pc += 2; } static void generateXORI(uint16_t inst, sh2rec_block_t *b) { int imm = INSTRUCTION_CD(inst); emitMOVLL4(b, R8, 0, R0); /* R0 <- sh2[R0] */ emitXORI(b, imm); /* R0 <- R0 ^ #imm */ emitMOVLS4(b, R0, 0, R8); /* sh2[R0] <- R0 */ ++b->cycles; /* 1 Cycle */ b->pc += 2; } static void generateXORM(uint16_t inst, sh2rec_block_t *b) { int imm = INSTRUCTION_CD(inst); emitSTS(b, R_PR, R10); /* R10 <- PR */ emitMOVLLG(b, 17); /* R0 <- sh2[GBR] */ emitMOVLL4(b, R8, 0, R4); /* R4 <- sh2[R0] */ emitMOVLL4(b, R9, 0, R1); /* R1 <- MappedMemoryReadByte */ emitALU(b, R0, R4, OP_ADD); /* R4 <- R4 + R0 */ emitJSR(b, R1); /* Call MappedMemoryReadByte */ emitMOVLM(b, R4, R15); /* Push R4 on the stack (delay slot) */ emitMOVLL4(b, R9, 3, R1); /* R1 <- MappedMemoryWriteByte */ emitXORI(b, imm); /* R0 <- R0 ^ #imm */ emitMOVLP(b, R15, R4); /* Pop R4 off the stack */ emitJSR(b, R1); /* Call MappedMemoryWriteByte */ emitMOV(b, R0, R5); /* R5 <- R0 (delay slot) */ emitLDS(b, R10, R_PR); /* PR <- R10 */ b->cycles += 3; /* 3 Cycles */ b->pc += 2; } static void generateXTRCT(uint16_t inst, sh2rec_block_t *b) { generateALUOP(inst, b, OP_XTRCT); b->pc += 2; } int sh2rec_rec_inst(sh2rec_block_t *b, int isdelay) { uint16_t inst = MappedMemoryReadWord(b->pc); int done = 0; switch(INSTRUCTION_A(inst)) { case 0: switch(INSTRUCTION_D(inst)) { case 2: switch(INSTRUCTION_C(inst)) { case 0: generateSTCSR(inst, b); break; case 1: generateSTCGBR(inst, b); break; case 2: generateSTCVBR(inst, b); break; default: return -1; } break; case 3: switch(INSTRUCTION_C(inst)) { case 0: generateBSRF(inst, b); done = 1; break; case 2: generateBRAF(inst, b); done = 1; break; default: return -1; } break; case 4: generateMOVBS0(inst, b); break; case 5: generateMOVWS0(inst, b); break; case 6: generateMOVLS0(inst, b); break; case 7: generateMULL(inst, b); break; case 8: switch(INSTRUCTION_C(inst)) { case 0: generateCLRT(inst, b); break; case 1: generateSETT(inst, b); break; case 2: generateCLRMAC(inst, b); break; default: return -1; } break; case 9: switch(INSTRUCTION_C(inst)) { case 0: generateNOP(inst, b); break; case 1: generateDIV0U(inst, b); break; case 2: generateMOVT(inst, b); break; default: return -1; } break; case 10: switch(INSTRUCTION_C(inst)) { case 0: generateSTSMACH(inst, b); break; case 1: generateSTSMACL(inst, b); break; case 2: generateSTSPR(inst, b); break; default: return -1; } break; case 11: switch(INSTRUCTION_C(inst)) { case 0: generateRTS(inst, b); done = 1; break; case 1: generateSLEEP(inst, b); break; case 2: generateRTE(inst, b); done = 1; break; default: return -1; } break; case 12: generateMOVBL0(inst, b); break; case 13: generateMOVWL0(inst, b); break; case 14: generateMOVLL0(inst, b); break; case 15: generateMACL(inst, b); break; default: return -1; } break; case 1: generateMOVLS4(inst, b); break; case 2: switch(INSTRUCTION_D(inst)) { case 0: generateMOVBS(inst, b); break; case 1: generateMOVWS(inst, b); break; case 2: generateMOVLS(inst, b); break; case 4: generateMOVBM(inst, b); break; case 5: generateMOVWM(inst, b); break; case 6: generateMOVLM(inst, b); break; case 7: generateDIV0S(inst, b); break; case 8: generateTST(inst, b); break; case 9: generateAND(inst, b); break; case 10: generateXOR(inst, b); break; case 11: generateOR(inst, b); break; case 12: generateCMPSTR(inst, b); break; case 13: generateXTRCT(inst, b); break; case 14: generateMULU(inst, b); break; case 15: generateMULS(inst, b); break; default: return -1; } break; case 3: switch(INSTRUCTION_D(inst)) { case 0: generateCMPEQ(inst, b); break; case 2: generateCMPHS(inst, b); break; case 3: generateCMPGE(inst, b); break; case 4: generateDIV1(inst, b); break; case 5: generateDMULU(inst, b); break; case 6: generateCMPHI(inst, b); break; case 7: generateCMPGT(inst, b); break; case 8: generateSUB(inst, b); break; case 10: generateSUBC(inst, b); break; case 11: generateSUBV(inst, b); break; case 12: generateADD(inst, b); break; case 13: generateDMULS(inst, b); break; case 14: generateADDC(inst, b); break; case 15: generateADDV(inst, b); break; default: return -1; } break; case 4: switch(INSTRUCTION_D(inst)) { case 0: switch(INSTRUCTION_C(inst)) { case 0: generateSHLL(inst, b); break; case 1: generateDT(inst, b); break; case 2: generateSHAL(inst, b); break; default: return -1; } break; case 1: switch(INSTRUCTION_C(inst)) { case 0: generateSHLR(inst, b); break; case 1: generateCMPPZ(inst, b); break; case 2: generateSHAR(inst, b); break; default: return -1; } break; case 2: switch(INSTRUCTION_C(inst)) { case 0: generateSTSMMACH(inst, b); break; case 1: generateSTSMMACL(inst, b); break; case 2: generateSTSMPR(inst, b); break; default: return -1; } break; case 3: switch(INSTRUCTION_C(inst)) { case 0: generateSTCMSR(inst, b); break; case 1: generateSTCMGBR(inst, b); break; case 2: generateSTCMVBR(inst, b); break; default: return -1; } break; case 4: switch(INSTRUCTION_C(inst)) { case 0: generateROTL(inst, b); break; case 2: generateROTCL(inst, b); break; default: return -1; } break; case 5: switch(INSTRUCTION_C(inst)) { case 0: generateROTR(inst, b); break; case 1: generateCMPPL(inst, b); break; case 2: generateROTCR(inst, b); break; default: return -1; } break; case 6: switch(INSTRUCTION_C(inst)) { case 0: generateLDSMMACH(inst, b); break; case 1: generateLDSMMACL(inst, b); break; case 2: generateLDSMPR(inst, b); break; default: return -1; } break; case 7: switch(INSTRUCTION_C(inst)) { case 0: generateLDCMSR(inst, b); break; case 1: generateLDCMGBR(inst, b); break; case 2: generateLDCMVBR(inst, b); break; default: return -1; } break; case 8: switch(INSTRUCTION_C(inst)) { case 0: generateSHLL2(inst, b); break; case 1: generateSHLL8(inst, b); break; case 2: generateSHLL16(inst, b); break; default: return -1; } break; case 9: switch(INSTRUCTION_C(inst)) { case 0: generateSHLR2(inst, b); break; case 1: generateSHLR8(inst, b); break; case 2: generateSHLR16(inst, b); break; default: return -1; } break; case 10: switch(INSTRUCTION_C(inst)) { case 0: generateLDSMACH(inst, b); break; case 1: generateLDSMACL(inst, b); break; case 2: generateLDSPR(inst, b); break; default: return -1; } break; case 11: switch(INSTRUCTION_C(inst)) { case 0: generateJSR(inst, b); done = 1; break; case 1: generateTAS(inst, b); break; case 2: generateJMP(inst, b); done = 1; break; default: return -1; } break; case 14: switch(INSTRUCTION_C(inst)) { case 0: generateLDCSR(inst, b); break; case 1: generateLDCGBR(inst, b); break; case 2: generateLDCVBR(inst, b); break; default: return -1; } break; case 15: generateMACW(inst, b); break; default: return -1; } break; case 5: generateMOVLL4(inst, b); break; case 6: switch(INSTRUCTION_D(inst)) { case 0: generateMOVBL(inst, b); break; case 1: generateMOVWL(inst, b); break; case 2: generateMOVLL(inst, b); break; case 3: generateMOV(inst, b); break; case 4: generateMOVBP(inst, b); break; case 5: generateMOVWP(inst, b); break; case 6: generateMOVLP(inst, b); break; case 7: generateNOT(inst, b); break; case 8: generateSWAPB(inst, b); break; case 9: generateSWAPW(inst, b); break; case 10: generateNEGC(inst, b); break; case 11: generateNEG(inst, b); break; case 12: generateEXTUB(inst, b); break; case 13: generateEXTUW(inst, b); break; case 14: generateEXTSB(inst, b); break; case 15: generateEXTSW(inst, b); break; } break; case 7: generateADDI(inst, b); break; case 8: switch(INSTRUCTION_B(inst)) { case 0: generateMOVBS4(inst, b); break; case 1: generateMOVWS4(inst, b); break; case 4: generateMOVBL4(inst, b); break; case 5: generateMOVWL4(inst, b); break; case 8: generateCMPIM(inst, b); break; case 9: generateBT(inst, b); done = 1; break; case 11: generateBF(inst, b); done = 1; break; case 13: generateBTS(inst, b); done = 1; break; case 15: generateBFS(inst, b); done = 1; break; default: return -1; } break; case 9: generateMOVWI(inst, b); break; case 10: generateBRA(inst, b); done = 1; break; case 11: generateBSR(inst, b); done = 1; break; case 12: switch(INSTRUCTION_B(inst)) { case 0: generateMOVBSG(inst, b); break; case 1: generateMOVWSG(inst, b); break; case 2: generateMOVLSG(inst, b); break; case 3: generateTRAPA(inst, b); done = 1; break; case 4: generateMOVBLG(inst, b); break; case 5: generateMOVWLG(inst, b); break; case 6: generateMOVLLG(inst, b); break; case 7: generateMOVA(inst, b); break; case 8: generateTSTI(inst, b); break; case 9: generateANDI(inst, b); break; case 10: generateXORI(inst, b); break; case 11: generateORI(inst, b); break; case 12: generateTSTM(inst, b); break; case 13: generateANDM(inst, b); break; case 14: generateXORM(inst, b); break; case 15: generateORM(inst, b); break; } break; case 13: generateMOVLI(inst, b); break; case 14: generateMOVI(inst, b); break; default: return -1; } return done; } int sh2rec_rec_block(sh2rec_block_t *b) { int done = 0; while(!done) { done = sh2rec_rec_inst(b, 0); } /* Flush the icache, so we don't execute stale data */ icache_flush_range((uint32)b->block, ((u32)b->ptr) - ((u32)b->block)); return 0; } /* In sh2exec.s */ extern void sh2rec_exec(SH2_struct *cxt, u32 cycles); static int sh2rec_init(void) { /* Initialize anything important here */ sh2rec_htab_init(); return 0; } static void sh2rec_deinit(void) { /* Clean stuff up here */ sh2rec_htab_reset(); } static void sh2rec_reset(void) { /* Reset to a sane state */ sh2rec_htab_reset(); } /* This function borrowed from the interpreter core */ void sh2rec_check_interrupts(SH2_struct *c) { if(c->NumberOfInterrupts != 0) { if(c->interrupts[c->NumberOfInterrupts-1].level > c->regs.SR.part.I) { c->regs.R[15] -= 4; MappedMemoryWriteLong(c->regs.R[15], c->regs.SR.all); c->regs.R[15] -= 4; MappedMemoryWriteLong(c->regs.R[15], c->regs.PC); c->regs.SR.part.I = c->interrupts[c->NumberOfInterrupts - 1].level; c->regs.PC = MappedMemoryReadLong(c->regs.VBR + (c->interrupts[c->NumberOfInterrupts-1].vector << 2)); c->NumberOfInterrupts--; c->isSleeping = 0; } } } sh2rec_block_t *sh2rec_find_block(u32 pc) { sh2rec_block_t *b = sh2rec_htab_lookup(pc); if(!b) { b = sh2rec_htab_block_create(pc, 4096); sh2rec_rec_block(b); } return b; } SH2Interface_struct SH2Dynarec = { SH2CORE_DYNAREC, "SH2 -> SH4 Dynarec", sh2rec_init, /* Init */ sh2rec_deinit, /* DeInit */ sh2rec_reset, /* Reset */ sh2rec_exec, /* Exec */ SH2InterpreterGetRegisters, /* GetRegisters */ SH2InterpreterGetGPR, /* GetGPR */ SH2InterpreterGetSR, /* GetSR */ SH2InterpreterGetGBR, /* GetGBR */ SH2InterpreterGetVBR, /* GetVBR */ SH2InterpreterGetMACH, /* GetMACH */ SH2InterpreterGetMACL, /* GetMACL */ SH2InterpreterGetPR, /* GetPR */ SH2InterpreterGetPC, /* GetPC */ SH2InterpreterSetRegisters, /* SetRegisters */ SH2InterpreterSetGPR, /* SetGPR */ SH2InterpreterSetSR, /* SetSR */ SH2InterpreterSetGBR, /* SetGBR */ SH2InterpreterSetVBR, /* SetVBR */ SH2InterpreterSetMACH, /* SetMACH */ SH2InterpreterSetMACL, /* SetMACL */ SH2InterpreterSetPR, /* SetPR */ SH2InterpreterSetPC, /* SetPC */ SH2InterpreterSendInterrupt, /* SendInterrupt */ SH2InterpreterGetInterrupts, /* GetInterrupts */ SH2InterpreterSetInterrupts, /* SetInterrupts */ NULL /* WriteNotify */ }; yabause-0.9.15/src/dreamcast/sh2rec/sh2exec.s000644 001750 001750 00000011375 12755623101 022727 0ustar00guillaumeguillaume000000 000000 ! Copyright 2010 Lawrence Sebald ! ! This file is part of Yabause. ! ! Yabause 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. ! ! Yabause 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 Yabause; if not, write to the Free Software ! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ! Code for calling upon the code generated by sh2rec (SuperH). .file "sh2exec.s" .little .text .balign 8 ! void sh2rec_exec(SH2_struct *cxt, u32 cycles) ! Execute the specified number of cycles on the given SH2 context .globl _sh2rec_exec _sh2rec_exec: stc.l gbr, @-r15 ! Save call-preserved stuff sts.l mach, @-r15 ! Ditto sts.l macl, @-r15 ! Ditto mov.l r8, @-r15 ! Ditto mov r4, r8 ! Put the SH2 struct in r8 mov.l r9, @-r15 ! More call-preserved stuff add #76, r4 ! Point at MACH in the SH2 struct mov.l r10, @-r15 ! More call-preserved stuff mov.l r11, @-r15 ! Last one for now... lds.l @r4+, mach ! Load the SH2 MACH into our MACH lds.l @r4+, macl ! Ditto for MACL mov.l checkInterrupts, r0 ! We need to check for interrupts... mov.l sh2memfuncsptr, r9 ! Memory access function pointer table sts.l pr, @-r15 ! Helps to know where to go back to mov r5, r11 ! This is important enough to keep here mov.l r5, @-r15 ! Save this on the stack too mov r8, r4 ! We need the original SH2_struct back jsr @r0 ! Call sh2rec_check_interrupts ldc r8, gbr ! Put the SH2 struct in gbr (delay slot) mov.l findBlock, r1 ! Grab the sh2rec_find_block function mov.l @(88, gbr), r0 ! Grab the PC we are at .exec_loop: ! This is where the fun is! jsr @r1 ! Call sh2rec_find_block mov r0, r4 ! Move the PC to argument 1 (delay slot) mov.l @r0, r2 ! Grab where the code is mov.l @(8, r0), r1 ! Figure out the number of cycles used jsr @r2 ! Call the block sub r1, r11 ! Chop off the cycles (delay slot) cmp/pl r11 ! Are we done? mov.l findBlock, r1 ! Grab the sh2rec_find_block function bt .exec_loop ! Continue on if needed ! When we are done, we will be here. mov.l r0, @(88, gbr) ! Save the next PC value mov.l @r15+, r5 ! Pop the requested number of cycles mov r8, r4 ! Keep this for sanity for now add #84, r8 ! Point just after MACL in SH2 struct sts.l macl, @-r8 ! Store the SH2 MACL back in the struct sts.l mach, @-r8 ! Ditto for MACH lds.l @r15+, pr ! Restore stuff from the stack sub r11, r5 ! Our counter is negitive, so this works mov.l cycleOffset, r2 ! Where is the cycles member at? mov.l @r15+, r11 ! More restoring... add r2, r4 ! Point r4 at the cycles member mov.l @r15+, r10 mov.l @r15+, r9 mov.l @r15+, r8 lds.l @r15+, macl lds.l @r15+, mach mov.l r5, @r4 ! Save the cycles we spent rts ! Return to the caller ldc.l @r15+, gbr ! Last thing to restore (delay slot) .balign 4 sh2memfuncsptr: .long sh2memfuncs checkInterrupts: .long _sh2rec_check_interrupts findBlock: .long _sh2rec_find_block cycleOffset: .long 5516 .data .balign 4 sh2memfuncs: .long _MappedMemoryReadByte .long _MappedMemoryReadWord .long _MappedMemoryReadLong .long _MappedMemoryWriteByte .long _MappedMemoryWriteWord .long _MappedMemoryWriteLong yabause-0.9.15/src/dreamcast/sh2rec/sh2rec_htab.h000644 001750 001750 00000002434 12755623101 023533 0ustar00guillaumeguillaume000000 000000 /* Copyright 2010 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SH2REC_HTAB_H #define SH2REC_HTAB_H /* This MUST be set to a power of two. It is done this way to avoid using a mod operation to get the entry where the object will go, since division (and thus modulus) is quite expensive on SuperH. */ #define SH2REC_HTAB_ENTRIES 4096 void sh2rec_htab_init(void); void sh2rec_htab_reset(void); sh2rec_block_t *sh2rec_htab_lookup(u32 addr); sh2rec_block_t *sh2rec_htab_block_create(u32 addr, int length); void sh2rec_htab_block_remove(u32 addr); #endif /* !SH2REC_HTAB_H */ yabause-0.9.15/src/dreamcast/localtime.h000644 001750 001750 00000000226 12755623101 022127 0ustar00guillaumeguillaume000000 000000 /* internal_localtime_r() function declaration, included by smpc.c */ extern struct tm * internal_localtime_r(const time_t * tim_p, struct tm *res); yabause-0.9.15/src/dreamcast/yui.c000644 001750 001750 00000013216 12755623101 020762 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003 Guillaume Duhamel Copyright 2004-2010 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include "../yui.h" #include "../peripheral.h" #include "../cs0.h" #include "../m68kcore.h" #include "../m68kc68k.h" #include "perdc.h" #include "viddc.h" #include "sh2rec/sh2rec.h" SH2Interface_struct *SH2CoreList[] = { &SH2Interpreter, &SH2Dynarec, NULL }; PerInterface_struct *PERCoreList[] = { &PERDC, NULL }; CDInterface *CDCoreList[] = { &ArchCD, &DummyCD, NULL }; SoundInterface_struct *SNDCoreList[] = { &SNDDummy, NULL }; VideoInterface_struct *VIDCoreList[] = { &VIDDummy, &VIDDC, NULL }; M68K_struct * M68KCoreList[] = { &M68KDummy, &M68KC68K, #ifdef HAVE_Q68 &M68KQ68, #endif NULL }; static const char *bios = "/ram/saturn.bin"; static int emulate_bios = 0; int YuiInit(int sh2core) { yabauseinit_struct yinit; yinit.percoretype = PERCORE_DC; yinit.sh2coretype = sh2core; yinit.vidcoretype = VIDCORE_DC; yinit.m68kcoretype = M68KCORE_C68K; yinit.sndcoretype = SNDCORE_DUMMY; yinit.cdcoretype = CDCORE_ARCH; yinit.carttype = CART_NONE; yinit.regionid = REGION_AUTODETECT; yinit.biospath = emulate_bios ? NULL : bios; yinit.cdpath = NULL; yinit.buppath = NULL; yinit.mpegpath = NULL; yinit.cartpath = NULL; yinit.frameskip = 0; yinit.videoformattype = VIDEOFORMATTYPE_NTSC; yinit.clocksync = 0; yinit.basetime = 0; yinit.skip_load = 0; if(YabauseInit(&yinit) != 0) return -1; for(;;) { PERCore->HandleEvents(); } return 0; } void YuiErrorMsg(const char *error_text) { fprintf(stderr, "Error: %s\n", error_text); arch_exit(); } void YuiSwapBuffers(void) { /* Nothing here. */ } int DoGui() { struct coord { int x; int y; }; struct coord snowflakes[1024]; int i; int offset; int start_pressed = 0; int phase = 0; int core = SH2CORE_INTERPRETER; srand(time(NULL)); for(i = 0; i < 1024; ++i) { snowflakes[i].x = (rand() % 640); snowflakes[i].y = -(rand() % 480); } while(!start_pressed) { offset = 64 * 640 + 64; /* 64 pixels in from the left, 64 down */ bfont_draw_str(vram_s + offset, 640, 0, "Yabause " VERSION); offset += 640 * 128; if(phase == 0) { FILE *fp; fp = fopen("/cd/saturn.bin", "r"); if(fp) { fclose(fp); fs_copy("/cd/saturn.bin", bios); phase = 1; continue; } bfont_draw_str(vram_s + offset, 640, 0, "Please insert a CD containing the Saturn BIOS"); offset += 640 * 24; bfont_draw_str(vram_s + offset, 640, 0, "on the root of the disc, named saturn.bin."); offset += 640 * 48; bfont_draw_str(vram_s + offset, 640, 0, "Or, to use the BIOS emulation feature, insert"); offset += 640 * 24; bfont_draw_str(vram_s + offset, 640, 0, "a Sega Saturn CD and press Start."); } else { bfont_draw_str(vram_s + offset, 640, 0, "Please insert a Sega Saturn CD"); offset += 640 * 24; bfont_draw_str(vram_s + offset, 640, 0, "and press start."); } for(i = 0; i < 1024; ++i) { int dx = 1 - (rand() % 3); if(snowflakes[i].y >= 0) vram_s[640 * snowflakes[i].y + snowflakes[i].x] = 0x0000; snowflakes[i].x += dx; snowflakes[i].y += 1; if(snowflakes[i].x < 0) snowflakes[i].x = 639; else if(snowflakes[i].x > 639) snowflakes[i].x = 0; if(snowflakes[i].y > 479) snowflakes[i].y = 0; if(snowflakes[i].y >= 0) vram_s[640 * snowflakes[i].y + snowflakes[i].x] = 0xD555; } MAPLE_FOREACH_BEGIN(MAPLE_FUNC_CONTROLLER, cont_state_t, st) if(st->buttons & CONT_START) { if(phase == 0) { emulate_bios = 1; } start_pressed = 1; } if(st->buttons & CONT_Y) { core = SH2CORE_DYNAREC; if(phase == 0) { emulate_bios = 1; } start_pressed = 1; } MAPLE_FOREACH_END() vid_waitvbl(); vid_flip(1); } return core; } int main(int argc, char *argv[]) { int core; printf("...\n"); bfont_set_encoding(BFONT_CODE_ISO8859_1); core = DoGui(); YuiInit(core); return 0; } yabause-0.9.15/src/dreamcast/dreamcast.cmake000644 001750 001750 00000001315 12755623101 022752 0ustar00guillaumeguillaume000000 000000 # CMake toolchain file for building Yabause on the Dreamcast set(CMAKE_SYSTEM_NAME Generic) # Use the gnu_wrappers for the various GNU utilities set(CMAKE_C_COMPILER kos-cc) set(CMAKE_CXX_COMPILER kos-c++) set(CMAKE_ASM_COMPILER kos-as) # KOS Sets this nicely for us. set(CMAKE_FIND_ROOT_PATH $ENV{KOS_CC_BASE}) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # Set some stuff so that it doesn't complain about the lack of a normal looking # pthreads flag/library for the compiler. set(THREADS_HAVE_PTHREAD_ARG 1) set(CMAKE_HAVE_THREADS_LIBRARY 1) # Set a flag so we know we're trying to compile for Dreamcast set(dreamcast 1) yabause-0.9.15/src/dreamcast/cd.s000644 001750 001750 00000014731 12755623101 020565 0ustar00guillaumeguillaume000000 000000 ! Copyright 2008 Lawrence Sebald ! ! This file is part of Yabause. ! ! Yabause 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. ! ! Yabause 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 Yabause; if not, write to the Free Software ! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ! Ok, so this is the start of me assemblerizing different parts of the core ! of the Dreamcast port of Yabause. I picked the CD core since its one of the ! parts of the emulator that is least likely to change in the future ! (hopefully anyway), and its somewhat simple to start with. .file "cd.s" .little .text .align 2 ! static int DCCDInit(const char *cdrom_name) ! Initialize the GD drive to read 2352 byte sectors. DCCDInit: sts.l pr, @-r15 .do_reinit: mov.l .cdrom_exec_cmd, r0 mov #0, r5 jsr @r0 mov #24, r4 ! CMD_INIT cmp/eq #1, r0 ! ERR_NO_DISC bt .init_return_success cmp/eq #3, r0 ! ERR_SYS bt .init_return_error mov.l .gdc_syscall_vector, r1 mova .DCCDInitParams, r0 mov #10, r7 mov.l @r1, r1 mov r0, r4 mov #0, r6 jsr @r1 mov #0, r5 lds.l @r15+, pr rts nop .init_return_success: lds.l @r15+, pr rts mov #0, r0 .init_return_error: lds.l @r15+, pr rts mov #-1, r0 .align 4 .cdrom_exec_cmd: .long _cdrom_exec_cmd .DCCDInitParams: .long 0 ! 0 = set .long 4096 ! Magic value for RAW sector reads .long 0x0400 ! Ditto .long 2352 ! Sector Size? (Maybe not for RAW though?) ! static int DCCDGetStatus(void) ! Execute the BIOS syscall of the Dreamcast to get the GD drive status, ! translating that into the format expected by the core of Yabause. DCCDGetStatus: sts.l pr, @-r15 .status_startgame: mov.l .gdc_syscall_vector, r1 mova .get_status_scratchpad, r0 mov #4, r7 mov.l @r1, r1 mov #0, r5 mov r0, r4 jsr @r1 mov #0, r6 cmp/eq #2, r0 ! 2 = Disc change error bt .status_reinit cmp/eq #0, r0 bf .status_error .status_endgame: ! status in 1st entry in scratchpad mova .get_status_scratchpad, r0 mov #0x07, r2 mov.l @r0, r1 mova .get_status_return_value, r0 and r2, r1 add r1, r0 lds.l @r15+, pr rts mov.b @r0, r0 .status_reinit: mov.l .get_status_init_func, r0 jsr @r0 mov #0, r4 cmp/eq #0, r0 bt .status_startgame .status_error: lds.l @r15+, pr rts mov #2, r0 .align 4 .gdc_syscall_vector: .long 0x8c0000bc .get_status_scratchpad: .long 0 .long 0 .get_status_return_value: .byte 0, 1, 1, 0, 0, 0, 3, 2 .get_status_init_func: .long DCCDInit ! static int DCCDDeInit(void) ! Deinitialize the CD Drive of the Dreamcast (i.e., undo the odd ! initialization stuff that the code does for Yabause). DCCDDeInit: mov.l .cdrom_reinit, r0 sts.l pr, @-r15 jsr @r0 nop lds.l @r15+, pr rts nop ! Leave the return value from cdrom_reinit as the return here. ! static int DCCDReadSectorFAD(u32 FAD, void *buffer) ! Read a single 2352 byte sector from the given position on the disc. DCCDReadSectorFAD: sts.l pr, @-r15 mov r4, r2 mov.l r4, @-r15 mov r5, r4 mov.l .cdrom_read_sectors, r0 mov.l r5, @-r15 mov r2, r5 .read_sector_start: jsr @r0 mov #1, r6 cmp/eq #2, r0 bt .read_reinit cmp/eq #0, r0 add #8, r15 bf/s .read_error lds.l @r15+, pr rts mov #1, r0 .read_reinit: mov.l .DCCDInit, r0 jsr @r0 mov #0, r4 cmp/eq #0, r0 mov.l @r15, r4 mov.l .cdrom_read_sectors, r0 bt/s .read_sector_start mov.l @(4, r15), r5 add #8, r15 .read_error: rts mov #0, r0 ! static int DCCDReadAheadFAD(u32 FAD) ! No-op (for the moment). DCCDReadAheadFAD: rts nop ! static s32 DCCDReadTOC(u32 *TOC); ! Read the TOC of the CD inserted in the drive. ! Amusingly enough, I just realized that the format that Yabause expects ! and what the Dreamcast spews out are exactly the same. Go figure! DCCDReadTOC: sts.l pr, @-r15 mov.l .cdrom_read_toc, r0 mov.l r4, @-r15 .readtoc_start: jsr @r0 mov #0, r5 cmp/eq #2, r0 bt .readtoc_reinit cmp/eq #0, r0 add #4, r15 bf/s .readtoc_error mov #0xCC, r0 lds.l @r15+, pr extu.b r0, r0 rts shll r0 .readtoc_reinit: mov.l .DCCDInit, r0 jsr @r0 mov #0, r4 cmp/eq #0, r0 mov.l @r15, r4 bt/s .readtoc_start mov.l .cdrom_read_toc, r0 add #4, r15 .readtoc_error: rts mov #0, r0 .align 4 .cdrom_reinit: .long _cdrom_reinit .cdrom_read_sectors: .long _cdrom_read_sectors .DCCDInit: .long DCCDInit .cdrom_read_toc: .long _cdrom_read_toc .section .rodata .align 2 .CDInterfaceName: .string "Dreamcast CD Drive" .data .align 4 .globl _ArchCD .size _ArchCD, 32 _ArchCD: .long 2 .long .CDInterfaceName .long DCCDInit .long DCCDDeInit .long DCCDGetStatus .long DCCDReadTOC .long DCCDReadSectorFAD .long DCCDReadAheadFAD yabause-0.9.15/src/dreamcast/viddc.h000644 001750 001750 00000001610 12755623101 021245 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef VIDDC_H #define VIDDC_H #include "../vdp1.h" #define VIDCORE_DC 3 extern VideoInterface_struct VIDDC; #endif yabause-0.9.15/src/dreamcast/viddc.c000644 001750 001750 00000241072 12755623101 021250 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2006 Guillaume Duhamel Copyright 2004-2009 Lawrence Sebald Copyright 2004-2006 Theo Berkau Copyright 2006 Fabien Coulon This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "viddc.h" #include "../debug.h" #include "../vdp2.h" #include #include #include #include #include #include #include #include #define SAT2YAB1(temp) ((temp & 0x8000) | (temp & 0x1F) << 10 | \ (temp & 0x3E0) | (temp & 0x7C00) >> 10) #define SAT2YAB32(alpha, temp) (alpha << 24 | (temp & 0x1F) << 3 | \ (temp & 0x3E0) << 6 | (temp & 0x7C00) << 9) #define SAT2YAB2(dot1, dot2) ((dot1 & 0xF8) << 7 | (dot2 & 0xF800) >> 6 | \ (dot2 & 0x00F8) >> 3 | 0x8000) #define SAT2YAB2_32(alpha, dot1, dot2) (alpha << 24 | ((dot1 & 0xFF) << 16) | \ (dot2 & 0xFF00) | (dot2 & 0xFF)) #define COLOR_ADDt32(b) (b > 0xFF ? 0xFF : (b < 0 ? 0 : b)) #define COLOR_ADDb32(b1,b2) COLOR_ADDt32((signed) (b1) + (b2)) #define COLOR_ADD32(l,r,g,b) COLOR_ADDb32((l & 0xFF), r) | \ (COLOR_ADDb32((l >> 8) & 0xFF, g) << 8) | \ (COLOR_ADDb32((l >> 16) & 0xFF, b) << 16) | \ (l & 0xFF000000) #define COLOR_ADDt(b) (b > 0xF8 ? 0xF8 : (b < 0x08 ? 0 : b)) #define COLOR_ADDb(b1,b2) COLOR_ADDt((signed) (b1) + (b2)) #define COLOR_ADD(l,r,g,b) ((COLOR_ADDb((l >> 7) & 0xF8, \ r) & 0xF8) << 7) | \ ((COLOR_ADDb((l >> 2) & 0xF8, \ g) & 0xF8) << 2) | \ ((COLOR_ADDb((l << 3) & 0xF8, \ b) & 0xF8) >> 3) | \ (l & 0x8000) static pvr_init_params_t pvr_params = { /* Enable Opaque, Translucent, and Punch-Thru polygons with binsize 16 */ { PVR_BINSIZE_16, PVR_BINSIZE_0, PVR_BINSIZE_16, PVR_BINSIZE_0, PVR_BINSIZE_16 }, /* 512KB Vertex Buffer */ 512 * 1024, /* DMA Enabled */ 1, /* FSAA Disabled */ 0 }; struct sprite_info { uint32 pvr_base; uint32 vdp1_base; float uf, vf; int w, h; }; typedef struct { int cellw, cellh; int flipfunction; int priority; int mapwh; int planew, planeh; int pagewh; int patternwh; int patterndatasize; int specialfunction; u32 addr, charaddr, paladdr; int colornumber; int isbitmap; u16 supplementdata; int auxmode; int enable; int x, y; int alpha; int coloroffset; int transparencyenable; int specialprimode; s32 cor; s32 cog; s32 cob; float coordincx, coordincy; void (* PlaneAddr)(void *, int); u16 (* PostPixelFetchCalc)(void *, u16); int patternpixelwh; int draww; int drawh; } vdp2draw_struct; static struct sprite_info cur_spr; static struct sprite_info cache[1024]; int cached_spr = 0; /* Polygon Headers */ static pvr_sprite_hdr_t op_poly_hdr; static pvr_sprite_hdr_t tr_poly_hdr; static pvr_sprite_hdr_t tr_sprite_hdr; static pvr_sprite_hdr_t pt_sprite_hdr; /* DMA Vertex Buffers 256KB Each */ static uint8 vbuf_opaque[1024 * 256] __attribute__((aligned(32))); static uint8 vbuf_translucent[1024 * 256] __attribute__((aligned(32))); static uint8 vbuf_punchthru[1024 * 256] __attribute__((aligned(32))); /* VDP2 Framebuffer */ static uint16 *vdp2_fb; static int vdp2_fbnum = 0; static uint16 vdp2_fbs[2][512 * 256] __attribute__((aligned(32))); static uint8 vdp2_prio[352][240]; static semaphore_t dmadone = SEM_INITIALIZER(1); static pvr_ptr_t vdp2_tex; static uint32 cur_vdp2; /* Priority levels, sprites drawn last get drawn on top */ static float priority_levels[8]; /* Texture space for VDP1 sprites */ static pvr_ptr_t tex_space; static uint32 cur_addr; /* Misc parameters */ static int vdp1cor = 0; static int vdp1cog = 0; static int vdp1cob = 0; static int nbg0priority = 0; static int nbg1priority = 0; static int nbg2priority = 0; static int nbg3priority = 0; static int rbg0priority = 0; static int vdp2width = 320; static int vdp2height = 224; /* Frame counter */ static time_t lastup; static int framecount; static int power_of_two(int num) { int ret = 8; while(ret < num) ret <<= 1; return ret; } static inline void vdp2putpixel(s32 x, s32 y, u16 color, int priority) { vdp2_fb[(y * 512) + x] = color; vdp2_prio[x][y] = (uint8) priority; } static u32 Vdp2ColorRamGetColor32(u32 colorindex, int alpha) { switch(Vdp2Internal.ColorMode) { case 0: case 1: { u32 tmp; colorindex <<= 1; tmp = T2ReadWord(Vdp2ColorRam, colorindex & 0xFFF); return SAT2YAB32(alpha, tmp); } case 2: { u32 tmp1, tmp2; colorindex <<= 2; colorindex &= 0xFFF; tmp1 = T2ReadWord(Vdp2ColorRam, colorindex); tmp2 = T2ReadWord(Vdp2ColorRam, colorindex+2); return SAT2YAB2_32(alpha, tmp1, tmp2); } default: break; } return 0; } static uint16 Vdp2ColorRamGetColor(u32 colorindex) { u16 tmp; switch(Vdp2Internal.ColorMode) { case 0: case 1: { colorindex <<= 1; tmp = T2ReadWord(Vdp2ColorRam, colorindex & 0xFFF); return SAT2YAB1(tmp) | 0x8000; } case 2: { u16 tmp2; colorindex <<= 2; colorindex &= 0xFFF; tmp = T2ReadWord(Vdp2ColorRam, colorindex); tmp2 = T2ReadWord(Vdp2ColorRam, colorindex+2); return SAT2YAB2(tmp, tmp2) | 0x8000; } default: break; } return 0; } static int Vdp1ReadTexture(vdp1cmd_struct *cmd, pvr_sprite_hdr_t *hdr) { u32 charAddr = cmd->CMDSRCA << 3; uint16 dot, dot2; int queuepos = 0; uint32 *store_queue; uint32 cur_base; u8 SPD = ((cmd->CMDPMOD & 0x40) != 0); int k; int wi = power_of_two(cur_spr.w); int he = power_of_two(cur_spr.h); for(k = 0; k < cached_spr; ++k) { if(cache[k].vdp1_base == charAddr) { if(cache[k].w == cur_spr.w && cache[k].h == cur_spr.h) { cur_base = cache[k].pvr_base; goto fillHeader; } } } cur_base = cur_addr; /* Set up both Store Queues for transfer to VRAM */ QACR0 = 0x00000004; QACR1 = 0x00000004; switch((cmd->CMDPMOD >> 3) & 0x07) { case 0: { // 4 bpp Bank mode u16 temp; u32 colorBank = cmd->CMDCOLR; u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4; int i, j; for(i = 0; i < cur_spr.h; ++i) { store_queue = (uint32 *) (0xE0000000 | (cur_addr & 0x03FFFFE0)); for(j = 0; j < cur_spr.w; j += 2) { dot = T1ReadByte(Vdp1Ram, charAddr & 0x7FFFF); if(((dot & 0xF) == 0) && !SPD) dot2 = 0; else { temp = Vdp2ColorRamGetColor(((dot & 0x0F) | colorBank) + colorOffset); dot2 = COLOR_ADD(temp, vdp1cor, vdp1cog, vdp1cob); } if(((dot >> 4) == 0) && !SPD) dot = 0; else { temp = Vdp2ColorRamGetColor(((dot >> 4) | colorBank) + colorOffset); dot = COLOR_ADD(temp, vdp1cor, vdp1cog, vdp1cob); } ++charAddr; store_queue[queuepos++] = dot | (dot2 << 16); if(queuepos == 8) { asm("pref @%0" : : "r"(store_queue)); queuepos = 0; store_queue += 8; } } if(queuepos) { asm("pref @%0" : : "r"(store_queue)); queuepos = 0; } cur_addr += wi * 2; } break; } case 1: { // 4 bpp LUT mode u16 temp; u32 colorLut = cmd->CMDCOLR * 8; int i, j; for(i = 0; i < cur_spr.h; ++i) { store_queue = (uint32 *) (0xE0000000 | (cur_addr & 0x03FFFFE0)); for(j = 0; j < cur_spr.w; j += 2) { dot = T1ReadByte(Vdp1Ram, charAddr & 0x7FFFF); if(((dot & 0xF) == 0) && !SPD) dot2 = 0; else { temp = T1ReadWord(Vdp1Ram, ((dot & 0xF) * 2 + colorLut) & 0x7FFFF); if(temp & 0x8000) dot2 = COLOR_ADD(SAT2YAB1(temp), vdp1cor, vdp1cog, vdp1cob); else dot2 = COLOR_ADD(Vdp2ColorRamGetColor(temp), vdp1cor, vdp1cog, vdp1cob); } if(((dot >> 4) == 0) && !SPD) dot = 0; else { temp = T1ReadWord(Vdp1Ram, ((dot >> 4) * 2 + colorLut) & 0x7FFFF); if (temp & 0x8000) dot = COLOR_ADD(SAT2YAB1(temp), vdp1cor, vdp1cog, vdp1cob); else dot = COLOR_ADD(Vdp2ColorRamGetColor(temp), vdp1cor, vdp1cog, vdp1cob); } ++charAddr; store_queue[queuepos++] = dot | (dot2 << 16); if(queuepos == 8) { asm("pref @%0" : : "r"(store_queue)); queuepos = 0; store_queue += 8; } } if(queuepos) { asm("pref @%0" : : "r"(store_queue)); queuepos = 0; } cur_addr += wi * 2; } break; } case 2: { // 8 bpp (64 color) Bank mode int i, j; u32 colorBank = cmd->CMDCOLR; u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4; u16 temp; for(i = 0; i < cur_spr.h; ++i) { store_queue = (uint32 *) (0xE0000000 | (cur_addr & 0x03FFFFE0)); for(j = 0; j < cur_spr.w; j += 2) { dot = T1ReadByte(Vdp1Ram, charAddr & 0x7FFFF) & 0x3F; dot2 = T1ReadByte(Vdp1Ram, (charAddr + 1) & 0x7FFFF) & 0x3F; charAddr = charAddr + 2; if(dot || SPD) { temp = Vdp2ColorRamGetColor((dot | colorBank) + colorOffset); dot = COLOR_ADD(temp, vdp1cor, vdp1cog, vdp1cob); } if(dot2 || SPD) { temp = Vdp2ColorRamGetColor((dot2 | colorBank) + colorOffset); dot2 = COLOR_ADD(temp, vdp1cor, vdp1cog, vdp1cob); } store_queue[queuepos++] = dot | (dot2 << 16); if(queuepos == 8) { asm("pref @%0" : : "r"(store_queue)); queuepos = 0; store_queue += 8; } } if(queuepos) { asm("pref @%0" : : "r"(store_queue)); queuepos = 0; } cur_addr += wi * 2; } break; } case 3: { // 8 bpp (128 color) Bank mode int i, j; u32 colorBank = cmd->CMDCOLR; u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4; u16 temp; for(i = 0; i < cur_spr.h; ++i) { store_queue = (uint32 *) (0xE0000000 | (cur_addr & 0x03FFFFE0)); for(j = 0; j < cur_spr.w; j += 2) { dot = T1ReadByte(Vdp1Ram, charAddr & 0x7FFFF) & 0x7F; dot2 = T1ReadByte(Vdp1Ram, (charAddr + 1) & 0x7FFFF) & 0x7F; charAddr = charAddr + 2; if(dot || SPD) { temp = Vdp2ColorRamGetColor((dot | colorBank) + colorOffset); dot = COLOR_ADD(temp, vdp1cor, vdp1cog, vdp1cob); } if(dot2 || SPD) { temp = Vdp2ColorRamGetColor((dot2 | colorBank) + colorOffset); dot2 = COLOR_ADD(temp, vdp1cor, vdp1cog, vdp1cob); } store_queue[queuepos++] = dot | (dot2 << 16); if(queuepos == 8) { asm("pref @%0" : : "r"(store_queue)); queuepos = 0; store_queue += 8; } } if(queuepos) { asm("pref @%0" : : "r"(store_queue)); queuepos = 0; } cur_addr += wi * 2; } break; } case 4: { // 8 bpp (256 color) Bank mode int i, j; u32 colorBank = cmd->CMDCOLR; u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4; u16 temp; for(i = 0; i < cur_spr.h; ++i) { store_queue = (uint32 *) (0xE0000000 | (cur_addr & 0x03FFFFE0)); for(j = 0; j < cur_spr.w; j += 2) { dot = T1ReadByte(Vdp1Ram, charAddr & 0x7FFFF); dot2 = T1ReadByte(Vdp1Ram, (charAddr + 1) & 0x7FFFF); charAddr = charAddr + 2; if(dot || SPD) { temp = Vdp2ColorRamGetColor((dot | colorBank) + colorOffset); dot = COLOR_ADD(temp, vdp1cor, vdp1cog, vdp1cob); } if(dot2 || SPD) { temp = Vdp2ColorRamGetColor((dot2 | colorBank) + colorOffset); dot2 = COLOR_ADD(temp, vdp1cor, vdp1cog, vdp1cob); } store_queue[queuepos++] = dot | (dot2 << 16); if(queuepos == 8) { asm("pref @%0" : : "r"(store_queue)); queuepos = 0; store_queue += 8; } } if(queuepos) { asm("pref @%0" : : "r"(store_queue)); queuepos = 0; } cur_addr += wi * 2; } break; } case 5: { // 16 bpp Bank mode int i, j; for(i = 0; i < cur_spr.h; ++i) { store_queue = (uint32 *) (0xE0000000 | (cur_addr & 0x03FFFFE0)); for(j = 0; j < cur_spr.w; j += 2) { dot = T1ReadWord(Vdp1Ram, charAddr & 0x7FFFF); dot2 = T1ReadWord(Vdp1Ram, (charAddr + 2) & 0x7FFFF); charAddr = charAddr + 4; if(dot || SPD) dot = COLOR_ADD(SAT2YAB1(dot), vdp1cor, vdp1cog, vdp1cob); if(dot2 || SPD) dot2 = COLOR_ADD(SAT2YAB1(dot2), vdp1cor, vdp1cog, vdp1cob); store_queue[queuepos++] = dot | (dot2 << 16); if(queuepos == 8) { asm("pref @%0" : : "r"(store_queue)); queuepos = 0; store_queue += 8; } } if(queuepos) { asm("pref @%0" : : "r"(store_queue)); queuepos = 0; } cur_addr += wi * 2; } break; } default: VDP1LOG("Unimplemented sprite color mode: %X\n", (cmd->CMDPMOD >> 3) & 0x7); return 0; } if(cached_spr < 1023) { cache[cached_spr].vdp1_base = cmd->CMDSRCA << 3; cache[cached_spr].pvr_base = cur_base; cache[cached_spr].w = cur_spr.w; cache[cached_spr].h = cur_spr.h; cached_spr++; } fillHeader: cur_spr.uf = (float) cur_spr.w / wi; cur_spr.vf = (float) cur_spr.h / he; hdr->mode2 &= (~(PVR_TA_PM2_USIZE_MASK | PVR_TA_PM2_VSIZE_MASK)); switch (wi) { case 8: break; case 16: hdr->mode2 |= (1 << PVR_TA_PM2_USIZE_SHIFT); break; case 32: hdr->mode2 |= (2 << PVR_TA_PM2_USIZE_SHIFT); break; case 64: hdr->mode2 |= (3 << PVR_TA_PM2_USIZE_SHIFT); break; case 128: hdr->mode2 |= (4 << PVR_TA_PM2_USIZE_SHIFT); break; case 256: hdr->mode2 |= (5 << PVR_TA_PM2_USIZE_SHIFT); break; case 512: hdr->mode2 |= (6 << PVR_TA_PM2_USIZE_SHIFT); break; case 1024: hdr->mode2 |= (7 << PVR_TA_PM2_USIZE_SHIFT); break; default: assert_msg(0, "Invalid texture U size"); break; } switch (he) { case 8: break; case 16: hdr->mode2 |= (1 << PVR_TA_PM2_VSIZE_SHIFT); break; case 32: hdr->mode2 |= (2 << PVR_TA_PM2_VSIZE_SHIFT); break; case 64: hdr->mode2 |= (3 << PVR_TA_PM2_VSIZE_SHIFT); break; case 128: hdr->mode2 |= (4 << PVR_TA_PM2_VSIZE_SHIFT); break; case 256: hdr->mode2 |= (5 << PVR_TA_PM2_VSIZE_SHIFT); break; case 512: hdr->mode2 |= (6 << PVR_TA_PM2_VSIZE_SHIFT); break; case 1024: hdr->mode2 |= (7 << PVR_TA_PM2_VSIZE_SHIFT); break; default: assert_msg(0, "Invalid texture V size"); break; } hdr->mode3 = ((cur_base & 0x00FFFFF8) >> 3) | (PVR_TXRFMT_NONTWIDDLED); /* Make sure everything is aligned nicely... */ cur_addr = (cur_addr & 0x03FFFFE0) + 0x20; return 1; } static u8 Vdp1ReadPriority(vdp1cmd_struct *cmd) { u8 SPCLMD = Vdp2Regs->SPCTL; u8 sprite_register; u8 *sprprilist = (u8 *)&Vdp2Regs->PRISA; if ((SPCLMD & 0x20) && (cmd->CMDCOLR & 0x8000)) { // RGB data, use register 0 return Vdp2Regs->PRISA & 0x07; } else { u8 sprite_type = SPCLMD & 0x0F; switch(sprite_type) { case 0: sprite_register = ((cmd->CMDCOLR & 0x8000) | (~cmd->CMDCOLR & 0x4000)) >> 14; return sprprilist[sprite_register ^ 1] & 0x07; break; case 1: sprite_register = ((cmd->CMDCOLR & 0xC000) | (~cmd->CMDCOLR & 0x2000)) >> 13; return sprprilist[sprite_register ^ 1] & 0x07; break; case 3: sprite_register = ((cmd->CMDCOLR & 0x4000) | (~cmd->CMDCOLR & 0x2000)) >> 13; return sprprilist[sprite_register ^ 1] & 0x07; break; case 4: sprite_register = ((cmd->CMDCOLR & 0x4000) | (~cmd->CMDCOLR & 0x2000)) >> 13; return sprprilist[sprite_register ^ 1] & 0x07; break; case 5: sprite_register = ((cmd->CMDCOLR & 0x6000) | (~cmd->CMDCOLR & 0x1000)) >> 12; return sprprilist[sprite_register ^ 1] & 0x07; break; case 6: sprite_register = ((cmd->CMDCOLR & 0x6000) | (~cmd->CMDCOLR & 0x1000)) >> 12; return sprprilist[sprite_register ^ 1] & 0x07; break; case 7: sprite_register = ((cmd->CMDCOLR & 0x6000) | (~cmd->CMDCOLR & 0x1000)) >> 12; return sprprilist[sprite_register ^ 1] & 0x07; break; default: VDP1LOG("sprite type %d not implemented\n", sprite_type); return 0x07; break; } } } /* This has all been imported from the vidsoft.c file. It will be updated, hopefully (roughly) synchronized with updates to it */ ////////////////////////////////////////////////////////////////////////////// typedef struct { int xstart, ystart; int xend, yend; int pixeloffset; int lineincrement; } clipping_struct; static void inline HandleClipping(vdp2draw_struct *info, clipping_struct *clip) { clip->pixeloffset=0; clip->lineincrement=0; // Handle clipping(both window and screen clipping) if (info->x < 0) { clip->xstart = 0; clip->xend = (info->x+info->cellw); clip->pixeloffset = 0 - info->x; clip->lineincrement = 0 - info->x; } else { clip->xstart = info->x; if ((info->x+info->cellw) > vdp2width) { clip->xend = vdp2width; clip->lineincrement = (info->x+info->cellw) - vdp2width; } else clip->xend = (info->x+info->cellw); } if (info->y < 0) { clip->ystart = 0; clip->yend = (info->y+info->cellh); clip->pixeloffset = (info->cellw * (0 - info->y)) + clip->pixeloffset; } else { clip->ystart = info->y; if ((info->y+info->cellh) >= vdp2height) clip->yend = vdp2height; else clip->yend = (info->y+info->cellh); } } ////////////////////////////////////////////////////////////////////////////// void Vdp2DrawScrollBitmap(vdp2draw_struct *info) { int i, i2; clipping_struct clip; HandleClipping(info, &clip); switch (info->colornumber) { case 0: // 4 BPP(16 colors) // fix me printf("vdp2 bitmap 4 bpp draw\n"); return; case 1: // 8 BPP(256 colors) info->charaddr += clip.pixeloffset; for (i = clip.ystart; i < clip.yend; i++) { for (i2 = clip.xstart; i2 < clip.xend; i2++) { u16 color = T1ReadByte(Vdp2Ram, info->charaddr); info->charaddr++; if (color == 0 && info->transparencyenable) { vdp2putpixel(i2, i, 0, info->priority); } else { color = Vdp2ColorRamGetColor(info->coloroffset + (info->paladdr | color)); vdp2putpixel(i2, i, info->PostPixelFetchCalc(info, color) | 0x8000, info->priority); } } info->charaddr += clip.lineincrement; } return; case 2: printf("vdp2 bitmap 16bpp palette draw\n"); break; case 3: // 15 BPP clip.pixeloffset *= 2; clip.lineincrement *= 2; info->charaddr += clip.pixeloffset; for (i = clip.ystart; i < clip.yend; i++) { for (i2 = clip.xstart; i2 < clip.xend; i2++) { u16 color = T1ReadWord(Vdp2Ram, info->charaddr); info->charaddr += 2; if ((color & 0x8000) == 0 && info->transparencyenable) vdp2_fb[(i * vdp2width) + i2] = 0; else vdp2_fb[(i * vdp2width) + i2] = info->PostPixelFetchCalc(info, SAT2YAB1(color)) | 0x8000; vdp2_prio[i][i2] = info->priority; } info->charaddr += clip.lineincrement; } return; case 4: // 24 BPP clip.pixeloffset *= 4; clip.lineincrement *= 4; info->charaddr += clip.pixeloffset; for (i = clip.ystart; i < clip.yend; i++) { for (i2 = clip.xstart; i2 < clip.xend; i2++) { u32 color = T1ReadLong(Vdp2Ram, info->charaddr); info->charaddr += 4; if ((color & 0x80000000) == 0 && info->transparencyenable) vdp2putpixel(i2, i, 0, info->priority); else { u16 dot = ((color & 0xF80000) >> 19 | (color & 0x00F800) >> 6 | (color & 0x0000F8) << 7 | 0x8000); vdp2putpixel(i2, i, info->PostPixelFetchCalc(info, dot), info->priority); } } info->charaddr += clip.lineincrement; } return; default: break; } } ////////////////////////////////////////////////////////////////////////////// #define Vdp2DrawCell4bpp(mask, shift) \ if ((dot & mask) == 0 && info->transparencyenable) { \ vdp2putpixel(i2, i, 0, info->priority); \ } \ else \ { \ color = Vdp2ColorRamGetColor(info->coloroffset + (info->paladdr | ((dot & mask) >> shift))); \ vdp2putpixel(i2, i, info->PostPixelFetchCalc(info, color), info->priority); \ } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawCell(vdp2draw_struct *info) { u32 color; int i, i2; clipping_struct clip; u32 newcharaddr; HandleClipping(info, &clip); if (info->flipfunction & 0x1) { // Horizontal flip } if (info->flipfunction & 0x2) { // Vertical flip // clip.pixeloffset = (info.w * info.h) - clip.pixeloffset; // clip.lineincrement = 0 - clip.lineincrement; } switch(info->colornumber) { case 0: // 4 BPP if ((clip.lineincrement | clip.pixeloffset) == 0) { for (i = clip.ystart; i < clip.yend; i++) { u32 dot; u16 color; i2 = clip.xstart; // Fetch Pixel 1/2/3/4/5/6/7/8 dot = T1ReadLong(Vdp2Ram, info->charaddr); info->charaddr+=4; // Draw 8 Pixels Vdp2DrawCell4bpp(0xF0000000, 28) i2++; Vdp2DrawCell4bpp(0x0F000000, 24) i2++; Vdp2DrawCell4bpp(0x00F00000, 20) i2++; Vdp2DrawCell4bpp(0x000F0000, 16) i2++; Vdp2DrawCell4bpp(0x0000F000, 12) i2++; Vdp2DrawCell4bpp(0x00000F00, 8) i2++; Vdp2DrawCell4bpp(0x000000F0, 4) i2++; Vdp2DrawCell4bpp(0x0000000F, 0) i2++; } } else { u8 dot; newcharaddr = info->charaddr + ((info->cellw * info->cellh) >> 1); info->charaddr <<= 1; info->charaddr += clip.pixeloffset; for (i = clip.ystart; i < clip.yend; i++) { dot = T1ReadByte(Vdp2Ram, info->charaddr >> 1); info->charaddr++; for (i2 = clip.xstart; i2 < clip.xend; i2++) { u32 color; // Draw two pixels if(info->charaddr & 0x1) { Vdp2DrawCell4bpp(0xF0, 4) info->charaddr++; } else { Vdp2DrawCell4bpp(0x0F, 0) dot = T1ReadByte(Vdp2Ram, info->charaddr >> 1); info->charaddr++; } } info->charaddr += clip.lineincrement; } info->charaddr = newcharaddr; } break; case 1: // 8 BPP newcharaddr = info->charaddr + (info->cellw * info->cellh); info->charaddr += clip.pixeloffset; for (i = clip.ystart; i < clip.yend; i++) { for (i2 = clip.xstart; i2 < clip.xend; i2++) { u16 color = T1ReadByte(Vdp2Ram, info->charaddr); info->charaddr++; if (color == 0 && info->transparencyenable) { vdp2putpixel(i2, i, 0, info->priority); } else { color = Vdp2ColorRamGetColor(info->coloroffset + (info->paladdr | color)); vdp2putpixel(i2, i, info->PostPixelFetchCalc(info, color), info->priority); } } info->charaddr += clip.lineincrement; } info->charaddr = newcharaddr; break; case 2: // 16 BPP(palette) printf("vdp2 cell draw 16bpp palette\n"); break; case 3: // 16 BPP(RGB) printf("vdp2 cell draw 16bpp\n"); break; case 4: // 32 BPP newcharaddr = info->charaddr + (info->cellw * info->cellh); info->charaddr += clip.pixeloffset; for (i = clip.ystart; i < clip.yend; i++) { for (i2 = clip.xstart; i2 < clip.xend; i2++) { u16 dot1, dot2; dot1 = T1ReadWord(Vdp2Ram, info->charaddr & 0x7FFFF); info->charaddr += 2; dot2 = T1ReadWord(Vdp2Ram, info->charaddr & 0x7FFFF); info->charaddr += 2; if (!(dot1 & 0x8000) && info->transparencyenable) continue; color = SAT2YAB2(dot1, dot2); vdp2putpixel(i2, i, info->PostPixelFetchCalc(info, color), info->priority); } info->charaddr += clip.lineincrement; } info->charaddr = newcharaddr; break; } } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawPattern(vdp2draw_struct *info) { // if (info->specialprimode == 1) // tile.priority = (info->priority & 0xFFFFFFFE) | info->specialfunction; // else // tile.priority = info->priority; switch(info->patternwh) { case 1: Vdp2DrawCell(info); info->x += 8; info->y += 8; break; case 2: Vdp2DrawCell(info); info->x += 8; Vdp2DrawCell(info); info->x -= 8; info->y += 8; Vdp2DrawCell(info); info->x += 8; Vdp2DrawCell(info); info->x += 8; info->y += 8; break; } } ////////////////////////////////////////////////////////////////////////////// static void Vdp2PatternAddr(vdp2draw_struct *info) { switch(info->patterndatasize) { case 1: { u16 tmp = T1ReadWord(Vdp2Ram, info->addr); info->addr += 2; info->specialfunction = (info->supplementdata >> 9) & 0x1; switch(info->colornumber) { case 0: // in 16 colors info->paladdr = ((tmp & 0xF000) >> 8) | ((info->supplementdata & 0xE0) << 3); break; default: // not in 16 colors info->paladdr = (tmp & 0x7000) >> 4; break; } switch(info->auxmode) { case 0: info->flipfunction = (tmp & 0xC00) >> 10; switch(info->patternwh) { case 1: info->charaddr = (tmp & 0x3FF) | ((info->supplementdata & 0x1F) << 10); break; case 2: info->charaddr = ((tmp & 0x3FF) << 2) | (info->supplementdata & 0x3) | ((info->supplementdata & 0x1C) << 10); break; } break; case 1: info->flipfunction = 0; switch(info->patternwh) { case 1: info->charaddr = (tmp & 0xFFF) | ((info->supplementdata & 0x1C) << 10); break; case 2: info->charaddr = ((tmp & 0xFFF) << 2) | (info->supplementdata & 0x3) | ((info->supplementdata & 0x10) << 10); break; } break; } break; } case 2: { u16 tmp1 = T1ReadWord(Vdp2Ram, info->addr); u16 tmp2 = T1ReadWord(Vdp2Ram, info->addr+2); info->addr += 4; info->charaddr = tmp2 & 0x7FFF; info->flipfunction = (tmp1 & 0xC000) >> 14; info->paladdr = (tmp1 & 0x7F) << 4; info->specialfunction = (tmp1 & 0x2000) >> 13; break; } } if (!(Vdp2Regs->VRSIZE & 0x8000)) info->charaddr &= 0x3FFF; info->charaddr *= 0x20; // selon Runik } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawPage(vdp2draw_struct *info) { int X, Y; int i, j; X = info->x; for(i = 0;i < info->pagewh;i++) { Y = info->y; info->x = X; for(j = 0;j < info->pagewh;j++) { info->y = Y; if ((info->x >= -info->patternpixelwh) && (info->y >= -info->patternpixelwh) && (info->x <= info->draww) && (info->y <= info->drawh)) { Vdp2PatternAddr(info); Vdp2DrawPattern(info); } else { info->addr += info->patterndatasize * 2; info->x += info->patternpixelwh; info->y += info->patternpixelwh; } } } } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawPlane(vdp2draw_struct *info) { int X, Y; int i, j; X = info->x; for(i = 0;i < info->planeh;i++) { Y = info->y; info->x = X; for(j = 0;j < info->planew;j++) { info->y = Y; Vdp2DrawPage(info); } } } ////////////////////////////////////////////////////////////////////////////// static void Vdp2DrawMap(vdp2draw_struct *info) { int i, j; int X, Y; u32 lastplane; X = info->x; lastplane=0xFFFFFFFF; info->patternpixelwh = 8 * info->patternwh; info->draww = (int)((float)vdp2width / info->coordincx); info->drawh = (int)((float)vdp2height / info->coordincy); for(i = 0;i < info->mapwh;i++) { Y = info->y; info->x = X; for(j = 0;j < info->mapwh;j++) { info->y = Y; info->PlaneAddr(info, info->mapwh * i + j); if (info->addr != lastplane) { Vdp2DrawPlane(info); lastplane = info->addr; } } } } static int VIDDCInit(void) { pvr_sprite_cxt_t op_poly_cxt, tr_poly_cxt; pvr_sprite_cxt_t pt_sprite_cxt, tr_sprite_cxt; vid_set_mode(DM_320x240, PM_RGB565); if(pvr_init(&pvr_params)) { fprintf(stderr, "VIDDCInit() - error initializing PVR\n"); return -1; } pvr_set_vertbuf(PVR_LIST_OP_POLY, vbuf_opaque, 1024 * 256); pvr_set_vertbuf(PVR_LIST_TR_POLY, vbuf_translucent, 1024 * 256); pvr_set_vertbuf(PVR_LIST_PT_POLY, vbuf_punchthru, 1024 * 256); tex_space = pvr_mem_malloc(1024 * 1024 * 2); vdp2_tex = pvr_mem_malloc(512 * 256 * 4 * 2); cur_addr = (uint32)tex_space; printf("PVR Memory Available: %lu\n", pvr_mem_available()); sq_set(tex_space, 0xFF, 1024 * 1024 * 2); pvr_sprite_cxt_col(&op_poly_cxt, PVR_LIST_OP_POLY); pvr_sprite_cxt_col(&tr_poly_cxt, PVR_LIST_TR_POLY); op_poly_cxt.gen.culling = PVR_CULLING_NONE; tr_poly_cxt.gen.culling = PVR_CULLING_NONE; pvr_sprite_compile(&op_poly_hdr, &op_poly_cxt); pvr_sprite_compile(&tr_poly_hdr, &tr_poly_cxt); pvr_sprite_cxt_txr(&tr_sprite_cxt, PVR_LIST_TR_POLY, PVR_TXRFMT_ARGB1555 | PVR_TXRFMT_NONTWIDDLED, 1024, 1024, tex_space, PVR_FILTER_NONE); pvr_sprite_cxt_txr(&pt_sprite_cxt, PVR_LIST_PT_POLY, PVR_TXRFMT_ARGB1555 | PVR_TXRFMT_NONTWIDDLED, 1024, 1024, tex_space, PVR_FILTER_NONE); pt_sprite_cxt.gen.culling = PVR_CULLING_NONE; tr_sprite_cxt.gen.culling = PVR_CULLING_NONE; pvr_sprite_compile(&tr_sprite_hdr, &tr_sprite_cxt); pvr_sprite_compile(&pt_sprite_hdr, &pt_sprite_cxt); tr_sprite_hdr.argb = PVR_PACK_COLOR(0.5f, 1.0f, 1.0f, 1.0f); priority_levels[0] = 0.0f; priority_levels[1] = 1.0f; priority_levels[2] = 2.0f; priority_levels[3] = 3.0f; priority_levels[4] = 4.0f; priority_levels[5] = 5.0f; priority_levels[6] = 6.0f; priority_levels[7] = 7.0f; framecount = 0; lastup = time(NULL); return 0; } static void VIDDCDeInit(void) { pvr_set_vertbuf(PVR_LIST_OP_POLY, NULL, 0); pvr_set_vertbuf(PVR_LIST_TR_POLY, NULL, 0); pvr_set_vertbuf(PVR_LIST_PT_POLY, NULL, 0); pvr_mem_free(tex_space); sem_destroy(&dmadone); pvr_shutdown(); vid_set_mode(DM_640x480, PM_RGB565); } static void VIDDCResize(unsigned int w, unsigned int h, int unused) { } static int VIDDCIsFullscreen(void) { return 1; } static int VIDDCVdp1Reset(void) { return 0; } static void VIDDCVdp1DrawStart(void) { if(Vdp2Regs->CLOFEN & 0x40) { // color offset enable if(Vdp2Regs->CLOFSL & 0x40) { // color offset B vdp1cor = Vdp2Regs->COBR & 0xFF; if(Vdp2Regs->COBR & 0x100) vdp1cor |= 0xFFFFFF00; vdp1cog = Vdp2Regs->COBG & 0xFF; if(Vdp2Regs->COBG & 0x100) vdp1cog |= 0xFFFFFF00; vdp1cob = Vdp2Regs->COBB & 0xFF; if(Vdp2Regs->COBB & 0x100) vdp1cob |= 0xFFFFFF00; } else { // color offset A vdp1cor = Vdp2Regs->COAR & 0xFF; if(Vdp2Regs->COAR & 0x100) vdp1cor |= 0xFFFFFF00; vdp1cog = Vdp2Regs->COAG & 0xFF; if(Vdp2Regs->COAG & 0x100) vdp1cog |= 0xFFFFFF00; vdp1cob = Vdp2Regs->COAB & 0xFF; if(Vdp2Regs->COAB & 0x100) vdp1cob |= 0xFFFFFF00; } } else // color offset disable vdp1cor = vdp1cog = vdp1cob = 0; } static void VIDDCVdp1DrawEnd(void) { cached_spr = 0; priority_levels[0] = 0.0f; priority_levels[1] = 1.0f; priority_levels[2] = 2.0f; priority_levels[3] = 3.0f; priority_levels[4] = 4.0f; priority_levels[5] = 5.0f; priority_levels[6] = 6.0f; priority_levels[7] = 7.0f; } static void VIDDCVdp1NormalSpriteDraw(void) { int x, y, num; u8 z; vdp1cmd_struct cmd; pvr_sprite_txr_t sprite; pvr_list_t list; Vdp1ReadCommand(&cmd, Vdp1Regs->addr); x = Vdp1Regs->localX + cmd.CMDXA; y = Vdp1Regs->localY + cmd.CMDYA; cur_spr.w = ((cmd.CMDSIZE >> 8) & 0x3F) << 3; cur_spr.h = cmd.CMDSIZE & 0xFF; if ((cmd.CMDPMOD & 0x07) == 0x03) { list = PVR_LIST_TR_POLY; num = Vdp1ReadTexture(&cmd, &tr_sprite_hdr); if(num == 0) return; else pvr_list_prim(PVR_LIST_TR_POLY, &tr_sprite_hdr, sizeof(pvr_sprite_hdr_t)); } else { num = Vdp1ReadTexture(&cmd, &pt_sprite_hdr); list = PVR_LIST_PT_POLY; if(num == 0) return; else pvr_list_prim(PVR_LIST_PT_POLY, &pt_sprite_hdr, sizeof(pvr_sprite_hdr_t)); } z = Vdp1ReadPriority(&cmd); sprite.flags = PVR_CMD_VERTEX_EOL; sprite.ax = x; sprite.ay = y; sprite.az = priority_levels[z]; sprite.bx = x + cur_spr.w; sprite.by = y; sprite.bz = priority_levels[z]; sprite.cx = x + cur_spr.w; sprite.cy = y + cur_spr.h; sprite.cz = priority_levels[z]; sprite.dx = x; sprite.dy = y + cur_spr.h; sprite.auv = PVR_PACK_16BIT_UV(((cmd.CMDCTRL & 0x0010) ? cur_spr.uf : 0.0f), ((cmd.CMDCTRL & 0x0020) ? cur_spr.vf : 0.0f)); sprite.buv = PVR_PACK_16BIT_UV(((cmd.CMDCTRL & 0x0010) ? 0.0f : cur_spr.uf), ((cmd.CMDCTRL & 0x0020) ? cur_spr.vf : 0.0f)); sprite.cuv = PVR_PACK_16BIT_UV(((cmd.CMDCTRL & 0x0010) ? 0.0f : cur_spr.uf), ((cmd.CMDCTRL & 0x0020) ? 0.0f : cur_spr.vf)); pvr_list_prim(list, &sprite, sizeof(sprite)); priority_levels[z] += 0.000001f; } static void VIDDCVdp1ScaledSpriteDraw(void) { vdp1cmd_struct cmd; s16 rw = 0, rh = 0; s16 x, y; u8 z; pvr_sprite_txr_t sprite; pvr_list_t list; int num; Vdp1ReadCommand(&cmd, Vdp1Regs->addr); x = cmd.CMDXA + Vdp1Regs->localX; y = cmd.CMDYA + Vdp1Regs->localY; cur_spr.w = ((cmd.CMDSIZE >> 8) & 0x3F) * 8; cur_spr.h = cmd.CMDSIZE & 0xFF; if((cmd.CMDPMOD & 0x07) == 0x03) { list = PVR_LIST_TR_POLY; num = Vdp1ReadTexture(&cmd, &tr_sprite_hdr); if(num == 0) return; else pvr_list_prim(PVR_LIST_TR_POLY, &tr_sprite_hdr, sizeof(pvr_sprite_hdr_t)); } else { num = Vdp1ReadTexture(&cmd, &pt_sprite_hdr); list = PVR_LIST_PT_POLY; if(num == 0) return; else pvr_list_prim(PVR_LIST_PT_POLY, &pt_sprite_hdr, sizeof(pvr_sprite_hdr_t)); } // Setup Zoom Point switch ((cmd.CMDCTRL & 0xF00) >> 8) { case 0x0: // Only two coordinates rw = cmd.CMDXC - x + Vdp1Regs->localX + 1; rh = cmd.CMDYC - y + Vdp1Regs->localY + 1; break; case 0x5: // Upper-left rw = cmd.CMDXB + 1; rh = cmd.CMDYB + 1; break; case 0x6: // Upper-Center rw = cmd.CMDXB; rh = cmd.CMDYB; x = x - rw / 2; ++rw; ++rh; break; case 0x7: // Upper-Right rw = cmd.CMDXB; rh = cmd.CMDYB; x = x - rw; ++rw; ++rh; break; case 0x9: // Center-left rw = cmd.CMDXB; rh = cmd.CMDYB; y = y - rh / 2; ++rw; ++rh; break; case 0xA: // Center-center rw = cmd.CMDXB; rh = cmd.CMDYB; x = x - rw / 2; y = y - rh / 2; ++rw; ++rh; break; case 0xB: // Center-right rw = cmd.CMDXB; rh = cmd.CMDYB; x = x - rw; y = y - rh / 2; ++rw; ++rh; break; case 0xD: // Lower-left rw = cmd.CMDXB; rh = cmd.CMDYB; y = y - rh; ++rw; ++rh; break; case 0xE: // Lower-center rw = cmd.CMDXB; rh = cmd.CMDYB; x = x - rw / 2; y = y - rh; ++rw; ++rh; break; case 0xF: // Lower-right rw = cmd.CMDXB; rh = cmd.CMDYB; x = x - rw; y = y - rh; ++rw; ++rh; break; default: break; } z = Vdp1ReadPriority(&cmd); sprite.flags = PVR_CMD_VERTEX_EOL; sprite.ax = x; sprite.ay = y; sprite.az = priority_levels[z]; sprite.bx = x + rw; sprite.by = y; sprite.bz = priority_levels[z]; sprite.cx = x + rw; sprite.cy = y + rh; sprite.cz = priority_levels[z]; sprite.dx = x; sprite.dy = y + rh; sprite.auv = PVR_PACK_16BIT_UV(((cmd.CMDCTRL & 0x0010) ? cur_spr.uf : 0.0f), ((cmd.CMDCTRL & 0x0020) ? cur_spr.vf : 0.0f)); sprite.buv = PVR_PACK_16BIT_UV(((cmd.CMDCTRL & 0x0010) ? 0.0f : cur_spr.uf), ((cmd.CMDCTRL & 0x0020) ? cur_spr.vf : 0.0f)); sprite.cuv = PVR_PACK_16BIT_UV(((cmd.CMDCTRL & 0x0010) ? 0.0f : cur_spr.uf), ((cmd.CMDCTRL & 0x0020) ? 0.0f : cur_spr.vf)); pvr_list_prim(list, &sprite, sizeof(sprite)); priority_levels[z] += 0.000001f; } static void VIDDCVdp1DistortedSpriteDraw(void) { vdp1cmd_struct cmd; u8 z; pvr_sprite_txr_t sprite; pvr_list_t list; int num; Vdp1ReadCommand(&cmd, Vdp1Regs->addr); cur_spr.w = ((cmd.CMDSIZE >> 8) & 0x3F) * 8; cur_spr.h = cmd.CMDSIZE & 0xFF; if((cmd.CMDPMOD & 0x7) == 0x3) { list = PVR_LIST_TR_POLY; num = Vdp1ReadTexture(&cmd, &tr_sprite_hdr); if(num == 0) return; else pvr_list_prim(PVR_LIST_TR_POLY, &tr_sprite_hdr, sizeof(pvr_sprite_hdr_t)); } else { num = Vdp1ReadTexture(&cmd, &pt_sprite_hdr); list = PVR_LIST_PT_POLY; if(num == 0) return; else pvr_list_prim(PVR_LIST_PT_POLY, &pt_sprite_hdr, sizeof(pvr_sprite_hdr_t)); } z = Vdp1ReadPriority(&cmd); sprite.flags = PVR_CMD_VERTEX_EOL; sprite.ax = cmd.CMDXA + Vdp1Regs->localX; sprite.ay = cmd.CMDYA + Vdp1Regs->localY; sprite.az = priority_levels[z]; sprite.bx = cmd.CMDXB + Vdp1Regs->localX + 1; sprite.by = cmd.CMDYB + Vdp1Regs->localY; sprite.bz = priority_levels[z]; sprite.cx = cmd.CMDXC + Vdp1Regs->localX + 1; sprite.cy = cmd.CMDYC + Vdp1Regs->localY + 1; sprite.cz = priority_levels[z]; sprite.dx = cmd.CMDXD + Vdp1Regs->localX; sprite.dy = cmd.CMDYD + Vdp1Regs->localY + 1; sprite.auv = PVR_PACK_16BIT_UV(((cmd.CMDCTRL & 0x0010) ? cur_spr.uf : 0.0f), ((cmd.CMDCTRL & 0x0020) ? cur_spr.vf : 0.0f)); sprite.buv = PVR_PACK_16BIT_UV(((cmd.CMDCTRL & 0x0010) ? 0.0f : cur_spr.uf), ((cmd.CMDCTRL & 0x0020) ? cur_spr.vf : 0.0f)); sprite.cuv = PVR_PACK_16BIT_UV(((cmd.CMDCTRL & 0x0010) ? 0.0f : cur_spr.uf), ((cmd.CMDCTRL & 0x0020) ? 0.0f : cur_spr.vf)); pvr_list_prim(list, &sprite, sizeof(sprite)); priority_levels[z] += 0.000001f; } static void VIDDCVdp1PolygonDraw(void) { s16 X[4]; s16 Y[4]; u16 color; u16 CMDPMOD; u8 alpha, z; pvr_list_t list; pvr_sprite_col_t spr; pvr_sprite_hdr_t *hdr; X[0] = Vdp1Regs->localX + T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x0C); Y[0] = Vdp1Regs->localY + T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x0E); X[1] = Vdp1Regs->localX + T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x10); Y[1] = Vdp1Regs->localY + T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x12); X[2] = Vdp1Regs->localX + T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x14); Y[2] = Vdp1Regs->localY + T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x16); X[3] = Vdp1Regs->localX + T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x18); Y[3] = Vdp1Regs->localY + T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x1A); color = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x06); CMDPMOD = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x04); /* Don't bother rendering completely transparent polygons */ if((!(color & 0x8000) && !(CMDPMOD & 0x0040)) || !color) { return; } if((CMDPMOD & 0x0007) == 0x0003) { alpha = 0x80; list = PVR_LIST_TR_POLY; hdr = &tr_poly_hdr; } else { alpha = 0xFF; list = PVR_LIST_OP_POLY; hdr = &op_poly_hdr; } if(color & 0x8000) { hdr->argb = COLOR_ADD32(SAT2YAB32(alpha, color), vdp1cor, vdp1cog, vdp1cob); } else { hdr->argb = COLOR_ADD32(Vdp2ColorRamGetColor32(color, alpha), vdp1cor, vdp1cog, vdp1cob); } pvr_list_prim(list, hdr, sizeof(pvr_sprite_hdr_t)); z = Vdp2Regs->PRISA & 0x07; spr.flags = PVR_CMD_VERTEX_EOL; spr.d1 = spr.d2 = spr.d3 = spr.d4 = 0; spr.az = spr.bz = spr.cz = priority_levels[z]; spr.ax = X[0]; spr.ay = Y[0]; spr.bx = X[1]; spr.by = Y[1]; spr.cx = X[2]; spr.cy = Y[2]; spr.dx = X[3]; spr.dy = Y[3]; pvr_list_prim(list, &spr, sizeof(pvr_sprite_col_t)); priority_levels[z] += 0.000001f; } static void VIDDCVdp1PolylineDraw(void) { } static void VIDDCVdp1LineDraw(void) { } static void VIDDCVdp1UserClipping(void) { Vdp1Regs->userclipX1 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x0C); Vdp1Regs->userclipY1 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x0E); Vdp1Regs->userclipX2 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x14); Vdp1Regs->userclipY2 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x16); } static void VIDDCVdp1SystemClipping(void) { Vdp1Regs->systemclipX1 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x0C); Vdp1Regs->systemclipY1 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x0E); Vdp1Regs->systemclipX2 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x14); Vdp1Regs->systemclipY2 = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x16); } static void VIDDCVdp1LocalCoordinate(void) { Vdp1Regs->localX = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x0C); Vdp1Regs->localY = T1ReadWord(Vdp1Ram, Vdp1Regs->addr + 0x0E); } ////////////////////////////////////////////////////////////////////////////// static u16 DoNothing(void *info, u16 pixel) { return pixel; } ////////////////////////////////////////////////////////////////////////////// static u16 DoColorOffset(void *info, u16 pixel) { return COLOR_ADD(pixel, ((vdp2draw_struct *)info)->cor, ((vdp2draw_struct *)info)->cog, ((vdp2draw_struct *)info)->cob); } ////////////////////////////////////////////////////////////////////////////// static u16 DoColorCalc(void *info, u16 pixel) { // should be doing color calculation here return pixel; } ////////////////////////////////////////////////////////////////////////////// static u16 DoColorCalcWithColorOffset(void *info, u16 pixel) { // should be doing color calculation here return COLOR_ADD(pixel, ((vdp2draw_struct *)info)->cor, ((vdp2draw_struct *)info)->cog, ((vdp2draw_struct *)info)->cob); } static void Vdp2DrawBackScreen() { u32 scrAddr; u16 dot; pvr_sprite_col_t spr; if(Vdp2Regs->VRSIZE & 0x8000) scrAddr = (((Vdp2Regs->BKTAU & 0x07) << 16) | Vdp2Regs->BKTAL) << 1; else scrAddr = (((Vdp2Regs->BKTAU & 0x03) << 16) | Vdp2Regs->BKTAL) << 1; if(Vdp2Regs->BKTAU & 0x8000) { int i; for(i = 0; i < vdp2height; ++i) { dot = T1ReadWord(Vdp2Ram, scrAddr); scrAddr += 2; op_poly_hdr.argb = SAT2YAB32(0xFF, dot); pvr_list_prim(PVR_LIST_OP_POLY, &op_poly_hdr, sizeof(pvr_sprite_hdr_t)); spr.flags = PVR_CMD_VERTEX_EOL; spr.ax = 0.0f; spr.ay = i + 1; spr.az = 0.1f; spr.bx = 0.0f; spr.by = i; spr.bz = 0.1f; spr.cx = vdp2width; spr.cy = i; spr.cz = 0.1f; spr.dx = vdp2width; spr.dy = i + 1; spr.d1 = spr.d2 = spr.d3 = spr.d4 = 0; pvr_list_prim(PVR_LIST_OP_POLY, &spr, sizeof(pvr_sprite_col_t)); } } else { dot = T1ReadWord(Vdp2Ram, scrAddr); op_poly_hdr.argb = SAT2YAB32(0xFF, dot); pvr_list_prim(PVR_LIST_OP_POLY, &op_poly_hdr, sizeof(pvr_sprite_hdr_t)); spr.flags = PVR_CMD_VERTEX_EOL; spr.ax = 0.0f; spr.ay = vdp2height; spr.az = 0.1f; spr.bx = 0.0f; spr.by = 0.0f; spr.bz = 0.1f; spr.cx = vdp2width; spr.cy = 0.0f; spr.cz = 0.1f; spr.dx = vdp2width; spr.dy = vdp2height; spr.d1 = spr.d2 = spr.d3 = spr.d4 = 0; pvr_list_prim(PVR_LIST_OP_POLY, &spr, sizeof(pvr_sprite_col_t)); } } static void Vdp2DrawLineColorScreen() { } ////////////////////////////////////////////////////////////////////////////// static void Vdp2NBG0PlaneAddr(vdp2draw_struct *info, int i) { u32 offset = (Vdp2Regs->MPOFN & 0x7) << 6; u32 tmp=0; int deca; int multi; switch(i) { case 0: tmp = offset | (Vdp2Regs->MPABN0 & 0xFF); break; case 1: tmp = offset | (Vdp2Regs->MPABN0 >> 8); break; case 2: tmp = offset | (Vdp2Regs->MPCDN0 & 0xFF); break; case 3: tmp = offset | (Vdp2Regs->MPCDN0 >> 8); break; } deca = info->planeh + info->planew - 2; multi = info->planeh * info->planew; //if (Vdp2Regs->VRSIZE & 0x8000) //{ if (info->patterndatasize == 1) { if (info->patternwh == 1) info->addr = ((tmp & 0x3F) >> deca) * (multi * 0x2000); else info->addr = (tmp >> deca) * (multi * 0x800); } else { if (info->patternwh == 1) info->addr = ((tmp & 0x1F) >> deca) * (multi * 0x4000); else info->addr = ((tmp & 0x7F) >> deca) * (multi * 0x1000); } /*} else { if (info->patterndatasize == 1) { if (info->patternwh == 1) info->addr = ((tmp & 0x1F) >> deca) * (multi * 0x2000); else info->addr = ((tmp & 0x7F) >> deca) * (multi * 0x800); } else { if (info->patternwh == 1) info->addr = ((tmp & 0xF) >> deca) * (multi * 0x4000); else info->addr = ((tmp & 0x3F) >> deca) * (multi * 0x1000); } }*/ } ////////////////////////////////////////////////////////////////////////////// static int Vdp2DrawNBG0(void) { vdp2draw_struct info; /* FIXME should start by checking if it's a normal * or rotate scroll screen */ info.enable = Vdp2Regs->BGON & 0x1; if (!(info.enable & Vdp2External.disptoggle)) return 0; info.transparencyenable = !(Vdp2Regs->BGON & 0x100); info.specialprimode = Vdp2Regs->SFPRMD & 0x3; info.colornumber = (Vdp2Regs->CHCTLA & 0x70) >> 4; if((info.isbitmap = Vdp2Regs->CHCTLA & 0x2) != 0) { // Bitmap Mode switch((Vdp2Regs->CHCTLA & 0xC) >> 2) { case 0: info.cellw = 512; info.cellh = 256; break; case 1: info.cellw = 512; info.cellh = 512; break; case 2: info.cellw = 1024; info.cellh = 256; break; case 3: info.cellw = 1024; info.cellh = 512; break; } info.x = - ((Vdp2Regs->SCXIN0 & 0x7FF) % info.cellw); info.y = - ((Vdp2Regs->SCYIN0 & 0x7FF) % info.cellh); info.charaddr = (Vdp2Regs->MPOFN & 0x7) * 0x20000; info.paladdr = (Vdp2Regs->BMPNA & 0x7) << 8; info.flipfunction = 0; info.specialfunction = 0; } else { // Tile Mode info.mapwh = 2; switch(Vdp2Regs->PLSZ & 0x3) { case 0: info.planew = info.planeh = 1; break; case 1: info.planew = 2; info.planeh = 1; break; case 3: info.planew = info.planeh = 2; break; default: // Not sure what 0x2 does info.planew = info.planeh = 1; break; } info.x = - ((Vdp2Regs->SCXIN0 & 0x7FF) % (512 * info.planew)); info.y = - ((Vdp2Regs->SCYIN0 & 0x7FF) % (512 * info.planeh)); if(Vdp2Regs->PNCN0 & 0x8000) info.patterndatasize = 1; else info.patterndatasize = 2; if(Vdp2Regs->CHCTLA & 0x1) info.patternwh = 2; else info.patternwh = 1; info.pagewh = 64/info.patternwh; info.cellw = info.cellh = 8; info.supplementdata = Vdp2Regs->PNCN0 & 0x3FF; info.auxmode = (Vdp2Regs->PNCN0 & 0x4000) >> 14; } if (Vdp2Regs->CCCTL & 0x1) info.alpha = ((~Vdp2Regs->CCRNA & 0x1F) << 3) + 0x7; else info.alpha = 0xFF; info.coloroffset = (Vdp2Regs->CRAOFA & 0x7) << 8; if (Vdp2Regs->CLOFEN & 0x1) { // color offset enable if (Vdp2Regs->CLOFSL & 0x1) { // color offset B info.cor = Vdp2Regs->COBR & 0xFF; if (Vdp2Regs->COBR & 0x100) info.cor |= 0xFFFFFF00; info.cog = Vdp2Regs->COBG & 0xFF; if (Vdp2Regs->COBG & 0x100) info.cog |= 0xFFFFFF00; info.cob = Vdp2Regs->COBB & 0xFF; if (Vdp2Regs->COBB & 0x100) info.cob |= 0xFFFFFF00; } else { // color offset A info.cor = Vdp2Regs->COAR & 0xFF; if (Vdp2Regs->COAR & 0x100) info.cor |= 0xFFFFFF00; info.cog = Vdp2Regs->COAG & 0xFF; if (Vdp2Regs->COAG & 0x100) info.cog |= 0xFFFFFF00; info.cob = Vdp2Regs->COAB & 0xFF; if (Vdp2Regs->COAB & 0x100) info.cob |= 0xFFFFFF00; } if (Vdp2Regs->CCCTL & 0x1) info.PostPixelFetchCalc = &DoColorCalcWithColorOffset; else info.PostPixelFetchCalc = &DoColorOffset; } else // color offset disable { if (Vdp2Regs->CCCTL & 0x1) info.PostPixelFetchCalc = &DoColorCalc; else info.PostPixelFetchCalc = &DoNothing; } info.coordincx = (float) 65536 / (Vdp2Regs->ZMXN0.all & 0x7FF00); info.coordincy = (float) 65536 / (Vdp2Regs->ZMYN0.all & 0x7FF00); info.priority = nbg0priority; info.PlaneAddr = (void (*)(void *, int))&Vdp2NBG0PlaneAddr; if (info.isbitmap) Vdp2DrawScrollBitmap(&info); else Vdp2DrawMap(&info); return 1; } ////////////////////////////////////////////////////////////////////////////// static void Vdp2NBG1PlaneAddr(vdp2draw_struct *info, int i) { u32 offset = (Vdp2Regs->MPOFN & 0x70) << 2; u32 tmp=0; int deca; int multi; switch(i) { case 0: tmp = offset | (Vdp2Regs->MPABN1 & 0xFF); break; case 1: tmp = offset | (Vdp2Regs->MPABN1 >> 8); break; case 2: tmp = offset | (Vdp2Regs->MPCDN1 & 0xFF); break; case 3: tmp = offset | (Vdp2Regs->MPCDN1 >> 8); break; } deca = info->planeh + info->planew - 2; multi = info->planeh * info->planew; //if (Vdp2Regs->VRSIZE & 0x8000) //{ if (info->patterndatasize == 1) { if (info->patternwh == 1) info->addr = ((tmp & 0x3F) >> deca) * (multi * 0x2000); else info->addr = (tmp >> deca) * (multi * 0x800); } else { if (info->patternwh == 1) info->addr = ((tmp & 0x1F) >> deca) * (multi * 0x4000); else info->addr = ((tmp & 0x7F) >> deca) * (multi * 0x1000); } /*} else { if (info->patterndatasize == 1) { if (info->patternwh == 1) info->addr = ((tmp & 0x1F) >> deca) * (multi * 0x2000); else info->addr = ((tmp & 0x7F) >> deca) * (multi * 0x800); } else { if (info->patternwh == 1) info->addr = ((tmp & 0xF) >> deca) * (multi * 0x4000); else info->addr = ((tmp & 0x3F) >> deca) * (multi * 0x1000); } }*/ } ////////////////////////////////////////////////////////////////////////////// static int Vdp2DrawNBG1(void) { vdp2draw_struct info; info.enable = Vdp2Regs->BGON & 0x2; if (!(info.enable & Vdp2External.disptoggle)) return 0; info.transparencyenable = !(Vdp2Regs->BGON & 0x200); info.specialprimode = (Vdp2Regs->SFPRMD >> 2) & 0x3; info.colornumber = (Vdp2Regs->CHCTLA & 0x3000) >> 12; if((info.isbitmap = Vdp2Regs->CHCTLA & 0x200) != 0) { switch((Vdp2Regs->CHCTLA & 0xC00) >> 10) { case 0: info.cellw = 512; info.cellh = 256; break; case 1: info.cellw = 512; info.cellh = 512; break; case 2: info.cellw = 1024; info.cellh = 256; break; case 3: info.cellw = 1024; info.cellh = 512; break; } info.x = - ((Vdp2Regs->SCXIN1 & 0x7FF) % info.cellw); info.y = - ((Vdp2Regs->SCYIN1 & 0x7FF) % info.cellh); info.charaddr = ((Vdp2Regs->MPOFN & 0x70) >> 4) * 0x20000; info.paladdr = Vdp2Regs->BMPNA & 0x700; info.flipfunction = 0; info.specialfunction = 0; } else { info.mapwh = 2; switch((Vdp2Regs->PLSZ & 0xC) >> 2) { case 0: info.planew = info.planeh = 1; break; case 1: info.planew = 2; info.planeh = 1; break; case 3: info.planew = info.planeh = 2; break; default: // Not sure what 0x2 does info.planew = info.planeh = 1; break; } info.x = - ((Vdp2Regs->SCXIN1 & 0x7FF) % (512 * info.planew)); info.y = - ((Vdp2Regs->SCYIN1 & 0x7FF) % (512 * info.planeh)); if(Vdp2Regs->PNCN1 & 0x8000) info.patterndatasize = 1; else info.patterndatasize = 2; if(Vdp2Regs->CHCTLA & 0x100) info.patternwh = 2; else info.patternwh = 1; info.pagewh = 64/info.patternwh; info.cellw = info.cellh = 8; info.supplementdata = Vdp2Regs->PNCN1 & 0x3FF; info.auxmode = (Vdp2Regs->PNCN1 & 0x4000) >> 14; } if (Vdp2Regs->CCCTL & 0x2) info.alpha = ((~Vdp2Regs->CCRNA & 0x1F00) >> 5) + 0x7; else info.alpha = 0xFF; info.coloroffset = (Vdp2Regs->CRAOFA & 0x70) << 4; if (Vdp2Regs->CLOFEN & 0x2) { // color offset enable if (Vdp2Regs->CLOFSL & 0x2) { // color offset B info.cor = Vdp2Regs->COBR & 0xFF; if (Vdp2Regs->COBR & 0x100) info.cor |= 0xFFFFFF00; info.cog = Vdp2Regs->COBG & 0xFF; if (Vdp2Regs->COBG & 0x100) info.cog |= 0xFFFFFF00; info.cob = Vdp2Regs->COBB & 0xFF; if (Vdp2Regs->COBB & 0x100) info.cob |= 0xFFFFFF00; } else { // color offset A info.cor = Vdp2Regs->COAR & 0xFF; if (Vdp2Regs->COAR & 0x100) info.cor |= 0xFFFFFF00; info.cog = Vdp2Regs->COAG & 0xFF; if (Vdp2Regs->COAG & 0x100) info.cog |= 0xFFFFFF00; info.cob = Vdp2Regs->COAB & 0xFF; if (Vdp2Regs->COAB & 0x100) info.cob |= 0xFFFFFF00; } if (Vdp2Regs->CCCTL & 0x2) info.PostPixelFetchCalc = &DoColorCalcWithColorOffset; else info.PostPixelFetchCalc = &DoColorOffset; } else // color offset disable { if (Vdp2Regs->CCCTL & 0x2) info.PostPixelFetchCalc = &DoColorCalc; else info.PostPixelFetchCalc = &DoNothing; } info.coordincx = (float) 65536 / (Vdp2Regs->ZMXN1.all & 0x7FF00); info.coordincy = (float) 65536 / (Vdp2Regs->ZMXN1.all & 0x7FF00); info.priority = nbg1priority; info.PlaneAddr = (void (*)(void *, int))&Vdp2NBG1PlaneAddr; if (info.isbitmap) { Vdp2DrawScrollBitmap(&info); /* // Handle Scroll Wrapping(Let's see if we even need do to it to begin // with) if (info.x < (vdp2width - info.cellw)) { info.vertices[0] = (info.x+info.cellw) * info.coordincx; info.vertices[2] = (info.x + (info.cellw<<1)) * info.coordincx; info.vertices[4] = (info.x + (info.cellw<<1)) * info.coordincx; info.vertices[6] = (info.x+info.cellw) * info.coordincx; YglCachedQuad((YglSprite *)&info, tmp); if (info.y < (vdp2height - info.cellh)) { info.vertices[1] = (info.y+info.cellh) * info.coordincy; info.vertices[3] = (info.y + (info.cellh<<1)) * info.coordincy; info.vertices[5] = (info.y + (info.cellh<<1)) * info.coordincy; info.vertices[7] = (info.y+info.cellh) * info.coordincy; YglCachedQuad((YglSprite *)&info, tmp); } } else if (info.y < (vdp2height - info.cellh)) { info.vertices[1] = (info.y+info.cellh) * info.coordincy; info.vertices[3] = (info.y + (info.cellh<<1)) * info.coordincy; info.vertices[5] = (info.y + (info.cellh<<1)) * info.coordincy; info.vertices[7] = (info.y+info.cellh) * info.coordincy; YglCachedQuad((YglSprite *)&info, tmp); } */ } else Vdp2DrawMap(&info); return 1; } ////////////////////////////////////////////////////////////////////////////// static void Vdp2NBG2PlaneAddr(vdp2draw_struct *info, int i) { u32 offset = (Vdp2Regs->MPOFN & 0x700) >> 2; u32 tmp=0; int deca; int multi; switch(i) { case 0: tmp = offset | (Vdp2Regs->MPABN2 & 0xFF); break; case 1: tmp = offset | (Vdp2Regs->MPABN2 >> 8); break; case 2: tmp = offset | (Vdp2Regs->MPCDN2 & 0xFF); break; case 3: tmp = offset | (Vdp2Regs->MPCDN2 >> 8); break; } deca = info->planeh + info->planew - 2; multi = info->planeh * info->planew; //if (Vdp2Regs->VRSIZE & 0x8000) //{ if (info->patterndatasize == 1) { if (info->patternwh == 1) info->addr = ((tmp & 0x3F) >> deca) * (multi * 0x2000); else info->addr = (tmp >> deca) * (multi * 0x800); } else { if (info->patternwh == 1) info->addr = ((tmp & 0x1F) >> deca) * (multi * 0x4000); else info->addr = ((tmp & 0x7F) >> deca) * (multi * 0x1000); } /*} else { if (info->patterndatasize == 1) { if (info->patternwh == 1) info->addr = ((tmp & 0x1F) >> deca) * (multi * 0x2000); else info->addr = ((tmp & 0x7F) >> deca) * (multi * 0x800); } else { if (info->patternwh == 1) info->addr = ((tmp & 0xF) >> deca) * (multi * 0x4000); else info->addr = ((tmp & 0x3F) >> deca) * (multi * 0x1000); } }*/ } ////////////////////////////////////////////////////////////////////////////// static int Vdp2DrawNBG2(void) { vdp2draw_struct info; info.enable = Vdp2Regs->BGON & 0x4; if (!(info.enable & Vdp2External.disptoggle)) return 0; info.transparencyenable = !(Vdp2Regs->BGON & 0x400); info.specialprimode = (Vdp2Regs->SFPRMD >> 4) & 0x3; info.colornumber = (Vdp2Regs->CHCTLB & 0x2) >> 1; info.mapwh = 2; switch((Vdp2Regs->PLSZ & 0x30) >> 4) { case 0: info.planew = info.planeh = 1; break; case 1: info.planew = 2; info.planeh = 1; break; case 3: info.planew = info.planeh = 2; break; default: // Not sure what 0x2 does info.planew = info.planeh = 1; break; } info.x = - ((Vdp2Regs->SCXN2 & 0x7FF) % (512 * info.planew)); info.y = - ((Vdp2Regs->SCYN2 & 0x7FF) % (512 * info.planeh)); if(Vdp2Regs->PNCN2 & 0x8000) info.patterndatasize = 1; else info.patterndatasize = 2; if(Vdp2Regs->CHCTLB & 0x1) info.patternwh = 2; else info.patternwh = 1; info.pagewh = 64/info.patternwh; info.cellw = info.cellh = 8; info.supplementdata = Vdp2Regs->PNCN2 & 0x3FF; info.auxmode = (Vdp2Regs->PNCN2 & 0x4000) >> 14; if (Vdp2Regs->CCCTL & 0x4) info.alpha = ((~Vdp2Regs->CCRNB & 0x1F) << 3) + 0x7; else info.alpha = 0xFF; info.coloroffset = Vdp2Regs->CRAOFA & 0x700; if (Vdp2Regs->CLOFEN & 0x4) { // color offset enable if (Vdp2Regs->CLOFSL & 0x4) { // color offset B info.cor = Vdp2Regs->COBR & 0xFF; if (Vdp2Regs->COBR & 0x100) info.cor |= 0xFFFFFF00; info.cog = Vdp2Regs->COBG & 0xFF; if (Vdp2Regs->COBG & 0x100) info.cog |= 0xFFFFFF00; info.cob = Vdp2Regs->COBB & 0xFF; if (Vdp2Regs->COBB & 0x100) info.cob |= 0xFFFFFF00; } else { // color offset A info.cor = Vdp2Regs->COAR & 0xFF; if (Vdp2Regs->COAR & 0x100) info.cor |= 0xFFFFFF00; info.cog = Vdp2Regs->COAG & 0xFF; if (Vdp2Regs->COAG & 0x100) info.cog |= 0xFFFFFF00; info.cob = Vdp2Regs->COAB & 0xFF; if (Vdp2Regs->COAB & 0x100) info.cob |= 0xFFFFFF00; } if (Vdp2Regs->CCCTL & 0x4) info.PostPixelFetchCalc = &DoColorCalcWithColorOffset; else info.PostPixelFetchCalc = &DoColorOffset; } else // color offset disable { if (Vdp2Regs->CCCTL & 0x4) info.PostPixelFetchCalc = &DoColorCalc; else info.PostPixelFetchCalc = &DoNothing; } info.coordincx = info.coordincy = 1; info.priority = nbg2priority; info.PlaneAddr = (void (*)(void *, int))&Vdp2NBG2PlaneAddr; Vdp2DrawMap(&info); return 1; } ////////////////////////////////////////////////////////////////////////////// static void Vdp2NBG3PlaneAddr(vdp2draw_struct *info, int i) { u32 offset = (Vdp2Regs->MPOFN & 0x7000) >> 6; u32 tmp=0; int deca; int multi; switch(i) { case 0: tmp = offset | (Vdp2Regs->MPABN3 & 0xFF); break; case 1: tmp = offset | (Vdp2Regs->MPABN3 >> 8); break; case 2: tmp = offset | (Vdp2Regs->MPCDN3 & 0xFF); break; case 3: tmp = offset | (Vdp2Regs->MPCDN3 >> 8); break; } deca = info->planeh + info->planew - 2; multi = info->planeh * info->planew; //if (Vdp2Regs->VRSIZE & 0x8000) { if (info->patterndatasize == 1) { if (info->patternwh == 1) info->addr = ((tmp & 0x3F) >> deca) * (multi * 0x2000); else info->addr = (tmp >> deca) * (multi * 0x800); } else { if (info->patternwh == 1) info->addr = ((tmp & 0x1F) >> deca) * (multi * 0x4000); else info->addr = ((tmp & 0x7F) >> deca) * (multi * 0x1000); } /*} else { if (info->patterndatasize == 1) { if (info->patternwh == 1) info->addr = ((tmp & 0x1F) >> deca) * (multi * 0x2000); else info->addr = ((tmp & 0x7F) >> deca) * (multi * 0x800); } else { if (info->patternwh == 1) info->addr = ((tmp & 0xF) >> deca) * (multi * 0x4000); else info->addr = ((tmp & 0x3F) >> deca) * (multi * 0x1000); } }*/ } ////////////////////////////////////////////////////////////////////////////// static int Vdp2DrawNBG3(void) { vdp2draw_struct info; info.enable = Vdp2Regs->BGON & 0x8; if (!(info.enable & Vdp2External.disptoggle)) return 0; info.transparencyenable = !(Vdp2Regs->BGON & 0x800); info.specialprimode = (Vdp2Regs->SFPRMD >> 6) & 0x3; info.colornumber = (Vdp2Regs->CHCTLB & 0x20) >> 5; info.mapwh = 2; switch((Vdp2Regs->PLSZ & 0xC0) >> 6) { case 0: info.planew = info.planeh = 1; break; case 1: info.planew = 2; info.planeh = 1; break; case 3: info.planew = info.planeh = 2; break; default: // Not sure what 0x2 does info.planew = info.planeh = 1; break; } info.x = - ((Vdp2Regs->SCXN3 & 0x7FF) % (512 * info.planew)); info.y = - ((Vdp2Regs->SCYN3 & 0x7FF) % (512 * info.planeh)); if(Vdp2Regs->PNCN3 & 0x8000) info.patterndatasize = 1; else info.patterndatasize = 2; if(Vdp2Regs->CHCTLB & 0x10) info.patternwh = 2; else info.patternwh = 1; info.pagewh = 64/info.patternwh; info.cellw = info.cellh = 8; info.supplementdata = Vdp2Regs->PNCN3 & 0x3FF; info.auxmode = (Vdp2Regs->PNCN3 & 0x4000) >> 14; if (Vdp2Regs->CCCTL & 0x8) info.alpha = ((~Vdp2Regs->CCRNB & 0x1F00) >> 5) + 0x7; else info.alpha = 0xFF; info.coloroffset = (Vdp2Regs->CRAOFA & 0x7000) >> 4; if (Vdp2Regs->CLOFEN & 0x8) { // color offset enable if (Vdp2Regs->CLOFSL & 0x8) { // color offset B info.cor = Vdp2Regs->COBR & 0xFF; if (Vdp2Regs->COBR & 0x100) info.cor |= 0xFFFFFF00; info.cog = Vdp2Regs->COBG & 0xFF; if (Vdp2Regs->COBG & 0x100) info.cog |= 0xFFFFFF00; info.cob = Vdp2Regs->COBB & 0xFF; if (Vdp2Regs->COBB & 0x100) info.cob |= 0xFFFFFF00; } else { // color offset A info.cor = Vdp2Regs->COAR & 0xFF; if (Vdp2Regs->COAR & 0x100) info.cor |= 0xFFFFFF00; info.cog = Vdp2Regs->COAG & 0xFF; if (Vdp2Regs->COAG & 0x100) info.cog |= 0xFFFFFF00; info.cob = Vdp2Regs->COAB & 0xFF; if (Vdp2Regs->COAB & 0x100) info.cob |= 0xFFFFFF00; } if (Vdp2Regs->CCCTL & 0x8) info.PostPixelFetchCalc = &DoColorCalcWithColorOffset; else info.PostPixelFetchCalc = &DoColorOffset; } else // color offset disable { if (Vdp2Regs->CCCTL & 0x8) info.PostPixelFetchCalc = &DoColorCalc; else info.PostPixelFetchCalc = &DoNothing; } info.coordincx = info.coordincy = 1; info.priority = nbg3priority; info.PlaneAddr = (void (*)(void *, int))&Vdp2NBG3PlaneAddr; Vdp2DrawMap(&info); return 1; } static int VIDDCVdp2Reset(void) { return 0; } static void VIDDCVdp2DrawStart(void) { cur_addr = (uint32) tex_space; cur_vdp2 = (uint32) vdp2_tex; pvr_wait_ready(); pvr_scene_begin(); Vdp2DrawBackScreen(); Vdp2DrawLineColorScreen(); } static void VIDDCVdp2DrawEnd(void) { /* Make sure we don't have any texture dma still going on... */ sem_wait(&dmadone); sem_signal(&dmadone); pvr_scene_finish(); ++framecount; if(lastup + 10 <= time(NULL)) { printf("%d frames in %d seconds FPS: %f\n", framecount, time(NULL) - lastup, ((float)(framecount)) / (time(NULL) - lastup)); framecount = 0; lastup = time(NULL); } } static void dma_callback(ptr_t data __attribute__((unused))) { sem_signal(&dmadone); } static void Vdp2Draw(int priority) { pvr_sprite_txr_t sprite; pt_sprite_hdr.mode2 &= (~(PVR_TA_PM2_USIZE_MASK | PVR_TA_PM2_VSIZE_MASK)); pt_sprite_hdr.mode2 |= (6 << PVR_TA_PM2_USIZE_SHIFT) | (5 << PVR_TA_PM2_VSIZE_SHIFT); pt_sprite_hdr.mode3 = ((cur_vdp2 & 0x00FFFFF8) >> 3) | (PVR_TXRFMT_NONTWIDDLED); pvr_list_prim(PVR_LIST_PT_POLY, &pt_sprite_hdr, sizeof(pvr_sprite_hdr_t)); sprite.flags = PVR_CMD_VERTEX_EOL; sprite.ax = 0; sprite.ay = 0; sprite.az = priority_levels[priority]; sprite.bx = vdp2width; sprite.by = 0; sprite.bz = priority_levels[priority]; sprite.cx = vdp2width; sprite.cy = vdp2height; sprite.cz = priority_levels[priority]; sprite.dx = 0; sprite.dy = vdp2height; sprite.auv = PVR_PACK_16BIT_UV(0.0f, 0.0f); sprite.buv = PVR_PACK_16BIT_UV(vdp2width / 512.0f, 0.0f); sprite.cuv = PVR_PACK_16BIT_UV(vdp2width / 512.0f, vdp2height / 256.0f); pvr_list_prim(PVR_LIST_PT_POLY, &sprite, sizeof(pvr_sprite_txr_t)); priority_levels[priority] += 0.000001f; } static void VIDDCVdp2SetResolution(u16 TVMD) { int w = 0, h = 0; switch(TVMD & 0x03) { case 0: w = 320; break; case 1: w = 352; break; case 2: w = 640; break; case 3: w = 704; break; } switch((TVMD >> 4) & 0x03) { case 0: h = 224; break; case 1: h = 240; break; case 2: h = 256; break; } switch((TVMD >> 6) & 0x03) { case 2: case 3: h <<= 1; default: break; } vdp2width = w; vdp2height = h; if(w > 352 || h > 256) { printf("Unsupported resolution set %d x %d\n", w, h); printf("Bailing out!\n"); exit(-1); } } static void VIDDCVdp2SetPriorityNBG0(int priority) { nbg0priority = priority; } static void VIDDCVdp2SetPriorityNBG1(int priority) { nbg1priority = priority; } static void VIDDCVdp2SetPriorityNBG2(int priority) { nbg2priority = priority; } static void VIDDCVdp2SetPriorityNBG3(int priority) { nbg3priority = priority; } static void VIDDCVdp2SetPriorityRBG0(int priority) { rbg0priority = priority; } static void VIDDCVdp2DrawScreens(void) { int i; VIDDCVdp2SetResolution(Vdp2Regs->TVMD); VIDDCVdp2SetPriorityNBG0(Vdp2Regs->PRINA & 0x7); VIDDCVdp2SetPriorityNBG1((Vdp2Regs->PRINA >> 8) & 0x7); VIDDCVdp2SetPriorityNBG2(Vdp2Regs->PRINB & 0x7); VIDDCVdp2SetPriorityNBG3((Vdp2Regs->PRINB >> 8) & 0x7); VIDDCVdp2SetPriorityRBG0(Vdp2Regs->PRIR & 0x7); vdp2_fb = vdp2_fbs[0]; vdp2_fbnum = 0; for(i = 1; i < 8; i++) { if(nbg3priority == i) { if(Vdp2DrawNBG3()) { dcache_flush_range((ptr_t)(vdp2_fb), 512 * 256 * 2); sem_wait(&dmadone); pvr_txr_load_dma(vdp2_fb, (pvr_ptr_t) cur_vdp2, 512 * 256 * 2, 0, dma_callback, 0); Vdp2Draw(i); cur_vdp2 += 512 * 256 * 2; vdp2_fbnum ^= 1; vdp2_fb = vdp2_fbs[vdp2_fbnum]; } } if(nbg2priority == i) { if(Vdp2DrawNBG2()) { dcache_flush_range((ptr_t)(vdp2_fb), 512 * 256 * 2); sem_wait(&dmadone); pvr_txr_load_dma(vdp2_fb, (pvr_ptr_t) cur_vdp2, 512 * 256 * 2, 0, dma_callback, 0); Vdp2Draw(i); cur_vdp2 += 512 * 256 * 2; vdp2_fbnum ^= 1; vdp2_fb = vdp2_fbs[vdp2_fbnum]; } } if(nbg1priority == i) { if(Vdp2DrawNBG1()) { dcache_flush_range((ptr_t)(vdp2_fb), 512 * 256 * 2); sem_wait(&dmadone); pvr_txr_load_dma(vdp2_fb, (pvr_ptr_t) cur_vdp2, 512 * 256 * 2, 0, dma_callback, 0); Vdp2Draw(i); cur_vdp2 += 512 * 256 * 2; vdp2_fbnum ^= 1; vdp2_fb = vdp2_fbs[vdp2_fbnum]; } } if(nbg0priority == i) { if(Vdp2DrawNBG0()) { dcache_flush_range((ptr_t)(vdp2_fb), 512 * 256 * 2); sem_wait(&dmadone); pvr_txr_load_dma(vdp2_fb, (pvr_ptr_t) cur_vdp2, 512 * 256 * 2, 0, dma_callback, 0); Vdp2Draw(i); cur_vdp2 += 512 * 256 * 2; vdp2_fbnum ^= 1; vdp2_fb = vdp2_fbs[vdp2_fbnum]; } } // if (rbg0priority == i) // Vdp2DrawRBG0(); } } VideoInterface_struct VIDDC = { VIDCORE_DC, "Dreamcast PVR Video Interface", VIDDCInit, VIDDCDeInit, VIDDCResize, VIDDCIsFullscreen, VIDDCVdp1Reset, VIDDCVdp1DrawStart, VIDDCVdp1DrawEnd, VIDDCVdp1NormalSpriteDraw, VIDDCVdp1ScaledSpriteDraw, VIDDCVdp1DistortedSpriteDraw, VIDDCVdp1PolygonDraw, VIDDCVdp1PolylineDraw, VIDDCVdp1LineDraw, VIDDCVdp1UserClipping, VIDDCVdp1SystemClipping, VIDDCVdp1LocalCoordinate, NULL, VIDDCVdp2Reset, VIDDCVdp2DrawStart, VIDDCVdp2DrawEnd, VIDDCVdp2DrawScreens }; yabause-0.9.15/src/dreamcast/localtime.c000644 001750 001750 00000004510 12755623101 022122 0ustar00guillaumeguillaume000000 000000 /* * localtime_r.c * Original Author: Adapted from tzcode maintained by Arthur David Olson. * * Converts the calendar time pointed to by tim_p into a broken-down time * expressed as local time. Returns a pointer to a structure containing the * broken-down time. */ /* This file was taken from newlib , it's a * modified version of Arthur David Olsons localtime.c from tzcode which * is under Public Domain */ #include #include #include "localtime.h" #define SECSPERMIN 60L #define MINSPERHOUR 60L #define HOURSPERDAY 24L #define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) #define SECSPERDAY (SECSPERHOUR * HOURSPERDAY) #define DAYSPERWEEK 7 #define MONSPERYEAR 12 #define YEAR_BASE 1900 #define EPOCH_YEAR 1970 #define EPOCH_WDAY 4 #define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) static const int mon_lengths[2][MONSPERYEAR] = { {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} } ; static const int year_lengths[2] = { 365, 366 } ; struct tm * internal_localtime_r(const time_t * tim_p, struct tm *res) { long days, rem; int y; int yleap; const int *ip; days = ((long) *tim_p) / SECSPERDAY; rem = ((long) *tim_p) % SECSPERDAY; while (rem < 0) { rem += SECSPERDAY; --days; } while (rem >= SECSPERDAY) { rem -= SECSPERDAY; ++days; } /* compute hour, min, and sec */ res->tm_hour = (int) (rem / SECSPERHOUR); rem %= SECSPERHOUR; res->tm_min = (int) (rem / SECSPERMIN); res->tm_sec = (int) (rem % SECSPERMIN); /* compute day of week */ if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0) res->tm_wday += DAYSPERWEEK; /* compute year & day of year */ y = EPOCH_YEAR; if (days >= 0) { for (;;) { yleap = isleap(y); if (days < year_lengths[yleap]) break; y++; days -= year_lengths[yleap]; } } else { do { --y; yleap = isleap(y); days += year_lengths[yleap]; } while (days < 0); } res->tm_year = y - YEAR_BASE; res->tm_yday = days; ip = mon_lengths[yleap]; for (res->tm_mon = 0; days >= ip[res->tm_mon]; ++res->tm_mon) days -= ip[res->tm_mon]; res->tm_mday = days + 1; /* set daylight saving time flag */ res->tm_isdst = -1; return (res); } yabause-0.9.15/src/dreamcast/perdc.c000644 001750 001750 00000007337 12755623101 021260 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005-2008 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "perdc.h" #include "../yabause.h" #include "../yui.h" #include "../vdp2.h" #include #include int PERDCInit(void); void PERDCDeInit(void); int PERDCHandleEvents(void); void PERDCNothing(void); u32 PERDCScan(u32 flags); void PERDCKeyName(u32 key, char *name, int size); static PerPad_struct *pad1; PerInterface_struct PERDC = { PERCORE_DC, "Dreamcast Input Interface", PERDCInit, PERDCDeInit, PERDCHandleEvents, PERDCScan, 0, PERDCNothing, PERDCKeyName }; int PERDCInit(void) { PerPortReset(); pad1 = PerPadAdd(&PORTDATA1); return 0; } void PERDCDeInit(void) { } int PERDCHandleEvents(void) { maple_device_t *dev; dev = maple_enum_type(0, MAPLE_FUNC_CONTROLLER); if(dev != NULL) { cont_state_t *state = (cont_state_t *) maple_dev_status(dev); if(state != NULL) { if(state->buttons & CONT_DPAD_UP) *pad1->padbits &= 0xEF; else *pad1->padbits |= 0x10; if(state->buttons & CONT_DPAD_DOWN) *pad1->padbits &= 0xDF; else *pad1->padbits |= 0x20; if(state->buttons & CONT_DPAD_RIGHT) *pad1->padbits &= 0x7F; else *pad1->padbits |= 0x80; if(state->buttons & CONT_DPAD_LEFT) *pad1->padbits &= 0xBF; else *pad1->padbits |= 0x40; if(state->buttons & CONT_START) *pad1->padbits &= 0xF7; else *pad1->padbits |= 0x08; if(state->buttons & CONT_A) *pad1->padbits &= 0xFB; else *pad1->padbits |= 0x04; if(state->buttons & CONT_B) *pad1->padbits &= 0xFE; else *pad1->padbits |= 0x01; if(state->buttons & CONT_X) *(pad1->padbits + 1) &= 0xBF; else *(pad1->padbits + 1) |= 0x40; if(state->buttons & CONT_Y) *(pad1->padbits + 1) &= 0xDF; else *(pad1->padbits + 1) |= 0x20; if(state->rtrig > 20) *(pad1->padbits + 1) &= 0x7F; else *(pad1->padbits + 1) |= 0x80; if(state->ltrig > 20) *(pad1->padbits + 1) &= 0xF7; else *(pad1->padbits + 1) |= 0x08; if(state->joyx > 20) *pad1->padbits &= 0xFD; else *pad1->padbits |= 0x02; if(state->joyy > 20) *(pad1->padbits + 1) &= 0xEF; else *(pad1->padbits + 1) |= 0x10; } } YabauseExec(); return 0; } void PERDCNothing(void) { /* Nothing */ } u32 PERDCScan(u32 flags) { /* Nothing */ return 0; } void PERDCKeyName(u32 key, char *name, int size) { snprintf(name, size, "%x", (unsigned int)key); } yabause-0.9.15/src/gameshw/000755 001750 001750 00000000000 12757373644 017515 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/gameshw/dsplist.txt000644 001750 001750 00000002235 12755623101 021722 0ustar00guillaumeguillaume000000 000000 Games using SCU dsp -------------------- Battle Monsters Blazing Tornado Blue Chicago Blues - J.B.Harold Blue Seed Bubble Symphony Capcom Generations 1 Capcom Generations 4 Cotton Boomerang Crimewave Daisuki Dark Savior Dead or Alive Don Pachi Doom Dragon Ball Z Shinbuthoden DX Jinsei Game - The Game of Life Fatal Fury 3 Find Love 2 ?Gal Panic SS Galaxy Force 2(sega ages) Grandia Grandia: Digital Museum GT24 Guardian Force Guyferd Jissen Pachinko Hisshouhou! Twin Lunar 2: Eternal Blue Mega Man X4 Momotaroudouchuuki Nadesico Mighty Hits Planet Joker Psychic Killer Taromaru Real Bout FF Real Bout FF Special Samurai Shodown RPG Sega Ages Memorial Selection - Vol. 1 ?Shining Force 3 Scenario 1 Shining Force 3 Scenario 2 Shining Force 3 Scenario 3 Sky Target Slam Dunk - I love Basketball (heavy usage) Slayers Royal Sonic R Stakes Winner SS Steeldom ?Street Fighter Collection Disc 1 Super Real Mahjong P7 Sword & Sorcery Tenga Seiha ?Tengai Makyou Dai Yon no Mokujiroku - The Apocalypse IV Toshinden Ura The Yakuyaken Special ?Thunderforce Gold Pack 1 Victory Boxing Virtua Racing Virtua Fighter Remix Winter Heat Wonder 3 Worms Yellow Brick Road Zero4 Champ DooZy-J Type-R yabause-0.9.15/src/sh2cache.c000644 001750 001750 00000057160 12755623101 017677 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005 Guillaume Duhamel Copyright 2016 Shinya Miyamoto This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file sh2cache.c \brief SH2 internal cache operations FIL0016332.PDF section 8 */ #ifdef PSP # include #endif #include #include #include #include #include "memory.h" #include "yabause.h" #include "sh2cache.h" #include "sh2core.h" #include "vdp2.h" #include "vdp1.h" #include "assert.h" #include "scsp.h" #include "scu.h" #include "ygr.h" #include "cs1.h" #include "cs0.h" #include "smpc.h" #include "cs2.h" #define AREA_MASK (0xE0000000) #define TAG_MASK (0x1FFFFC00) #define ENTRY_MASK (0x000003F0) #define ENTRY_SHIFT (4) #define LINE_MASK (0x0000000F) #define CACHE_USE ((0x00)<<29) #define CACHE_THROUGH ((0x01)<<29) #define CACHE_PURGE ((0x02)<<29) #define CACHE_ADDRES_ARRAY ((0x03)<<29) #define CACHE_DATA_ARRAY ((0x06)<<29) #define CACHE_IO ((0x07)<<29) void cache_clear(cache_enty * ca){ int entry = 0; ca->enable = 0; for (entry = 0; entry < 64; entry++){ int way = 0; ca->lru[entry] = 0; for (way = 0; way < 4; way++) { int i = 0; ca->way[way][entry].tag = 0; for (i = 0; i < 16; i++) ca->way[way][entry].data[i] = 0; ca->way[way][entry].v = 0; } } return; } void cache_enable(cache_enty * ca){ //cache enable does not clear the cache ca->enable = 1; } void cache_disable(cache_enty * ca){ ca->enable = 0; } //lru is updated //when cache hit occurs during a read //when cache hit occurs during a write //when replacement occurs after a cache miss static INLINE void update_lru(int way, u32*lru) { if (way == 3) { *lru = *lru | 0xb;//set bits 3, 1, 0 return; } else if (way == 2) { *lru = *lru & 0x3E;//set bit 0 to 0 *lru = *lru | 0x14;//set bits 4 and 2 return; } else if (way == 1) { *lru = *lru | (1 << 5);//set bit 5 *lru = *lru & 0x39;//unset bits 2 and 1 return; } else { *lru = *lru & 0x7;//unset bits 5,4,3 return; } //should not happen } static INLINE int select_way_to_replace(SH2_struct *sh, u32 lru) { if (sh->onchip.CCR & (1 << 3))//2-way mode { if ((lru & 1) == 1) return 2; else return 3; } else { if ((lru & 0x38) == 0x38)//bits 5, 4, 3 must be 1 return 0; else if ((lru & 0x26) == 0x6)//bit 5 must be zero. bits 2 and 1 must be 1 return 1; else if ((lru & 0x15) == 1)//bits 4, 2 must be zero. bit 0 must be 1 return 2; else if ((lru & 0xB) == 0)//bits 3, 1, 0 must be zero return 3; } //should not happen return 0; } //values are from console measurements and have extra delays included //delay 0 if the measured cycles are 7 or less, otherwise subtract 7 #define ADJUST_CYCLES(n) (n <= 7 ? 0 : (n - 7)) int get_cache_through_timing_read_byte_word(u32 addr) { addr = (addr >> 16) & 0xFFF; if (addr <= 0x00f)//bios return ADJUST_CYCLES(15); else if (addr >= 0x010 && addr <= 0x017)//smpc return ADJUST_CYCLES(15); else if (addr >= 0x018 && addr <= 0x01f)//bup return ADJUST_CYCLES(1); else if (addr >= 0x020 && addr <= 0x02f)//lwram return ADJUST_CYCLES(14); //ignore input capture else if (addr >= 0x200 && addr <= 0x3ff)//cs0 return ADJUST_CYCLES(1); else if (addr >= 0x400 && addr <= 0x4ff)//cs1 return ADJUST_CYCLES(1); else if (addr >= 0x580 && addr <= 0x58f)//cs2 return ADJUST_CYCLES(24); else if (addr >= 0x5a0 && addr <= 0x5af)//sound ram return ADJUST_CYCLES(53); else if (addr >= 0x5b0 && addr <= 0x5bf)//scsp regs return ADJUST_CYCLES(52); else if (addr >= 0x5c0 && addr <= 0x5c7)//vdp1 ram return ADJUST_CYCLES(51); else if (addr >= 0x5c8 && addr <= 0x5cf)//vdp1 fb return ADJUST_CYCLES(51); else if (addr >= 0x5d0 && addr <= 0x5d7)//vdp1 regs return ADJUST_CYCLES(35); else if (addr >= 0x5e0 && addr <= 0x5ef)//vdp2 ram return ADJUST_CYCLES(44); else if (addr >= 0x5f0 && addr <= 0x5f7)//vdp2 color return ADJUST_CYCLES(44); else if (addr >= 0x5f8 && addr <= 0x5fb)//vdp2 regs return ADJUST_CYCLES(44); else if (addr >= 0x5fe && addr <= 0x5fe)//scu return ADJUST_CYCLES(14); else if (addr >= 0x600 && addr <= 0x7ff)//hwram return ADJUST_CYCLES(14); return 0; } int get_cache_through_timing_read_long(u32 addr) { addr = (addr >> 16) & 0xFFF; if (addr <= 0x00f)//bios return ADJUST_CYCLES(23); else if (addr >= 0x010 && addr <= 0x017)//smpc return ADJUST_CYCLES(23); else if (addr >= 0x018 && addr <= 0x01f)//bup return ADJUST_CYCLES(1); else if (addr >= 0x020 && addr <= 0x02f)//lwram return ADJUST_CYCLES(21); //ignore input capture else if (addr >= 0x200 && addr <= 0x3ff)//cs0 return ADJUST_CYCLES(1); else if (addr >= 0x400 && addr <= 0x4ff)//cs1 return ADJUST_CYCLES(1); else if (addr >= 0x580 && addr <= 0x58f)//cs2 return ADJUST_CYCLES(24); else if (addr >= 0x5a0 && addr <= 0x5af)//sound ram return ADJUST_CYCLES(53); else if (addr >= 0x5b0 && addr <= 0x5bf)//scsp regs return ADJUST_CYCLES(52); else if (addr >= 0x5c0 && addr <= 0x5c7)//vdp1 ram return ADJUST_CYCLES(51); else if (addr >= 0x5c8 && addr <= 0x5cf)//vdp1 fb return ADJUST_CYCLES(51); else if (addr >= 0x5d0 && addr <= 0x5d7)//vdp1 regs return ADJUST_CYCLES(35); else if (addr >= 0x5e0 && addr <= 0x5ef)//vdp2 ram return ADJUST_CYCLES(44); else if (addr >= 0x5f0 && addr <= 0x5f7)//vdp2 color return ADJUST_CYCLES(44); else if (addr >= 0x5f8 && addr <= 0x5fb)//vdp2 regs return ADJUST_CYCLES(44); else if (addr >= 0x5fe && addr <= 0x5fe)//scu return ADJUST_CYCLES(14); else if (addr >= 0x600 && addr <= 0x7ff)//hwram return ADJUST_CYCLES(14); return 0; } int get_cache_through_timing_write_byte_word(u32 addr) { addr = (addr >> 16) & 0xFFF; if (addr <= 0x00f)//bios return ADJUST_CYCLES(8); else if (addr >= 0x010 && addr <= 0x017)//smpc return ADJUST_CYCLES(8); else if (addr >= 0x018 && addr <= 0x01f)//bup return ADJUST_CYCLES(1); else if (addr >= 0x020 && addr <= 0x02f)//lwram return ADJUST_CYCLES(7); //ignore input capture else if (addr >= 0x200 && addr <= 0x3ff)//cs0 return ADJUST_CYCLES(1); else if (addr >= 0x400 && addr <= 0x4ff)//cs1 return ADJUST_CYCLES(1); else if (addr >= 0x580 && addr <= 0x58f)//cs2 return ADJUST_CYCLES(7); else if (addr >= 0x5a0 && addr <= 0x5af)//sound ram return ADJUST_CYCLES(19); else if (addr >= 0x5b0 && addr <= 0x5bf)//scsp regs return ADJUST_CYCLES(19); else if (addr >= 0x5c0 && addr <= 0x5c7)//vdp1 ram return ADJUST_CYCLES(11); else if (addr >= 0x5c8 && addr <= 0x5cf)//vdp1 fb return ADJUST_CYCLES(11); else if (addr >= 0x5d0 && addr <= 0x5d7)//vdp1 regs return ADJUST_CYCLES(11); else if (addr >= 0x5e0 && addr <= 0x5ef)//vdp2 ram return ADJUST_CYCLES(7); else if (addr >= 0x5f0 && addr <= 0x5f7)//vdp2 color return ADJUST_CYCLES(8); else if (addr >= 0x5f8 && addr <= 0x5fb)//vdp2 regs return ADJUST_CYCLES(7); else if (addr >= 0x5fe && addr <= 0x5fe)//scu return ADJUST_CYCLES(7); else if (addr >= 0x600 && addr <= 0x7ff)//hwram return ADJUST_CYCLES(7); return 0; } int get_cache_through_timing_write_long(u32 addr) { addr = (addr >> 16) & 0xFFF; if (addr <= 0x00f)//bios return ADJUST_CYCLES(16); else if (addr >= 0x010 && addr <= 0x017)//smpc return ADJUST_CYCLES(16); else if (addr >= 0x018 && addr <= 0x01f)//bup return ADJUST_CYCLES(1); else if (addr >= 0x020 && addr <= 0x02f)//lwram return ADJUST_CYCLES(14); //ignore input capture else if (addr >= 0x200 && addr <= 0x3ff)//cs0 return ADJUST_CYCLES(1); else if (addr >= 0x400 && addr <= 0x4ff)//cs1 return ADJUST_CYCLES(1); else if (addr >= 0x580 && addr <= 0x58f)//cs2 return ADJUST_CYCLES(14); else if (addr >= 0x5a0 && addr <= 0x5af)//sound ram return ADJUST_CYCLES(33); else if (addr >= 0x5b0 && addr <= 0x5bf)//scsp regs return ADJUST_CYCLES(32); else if (addr >= 0x5c0 && addr <= 0x5c7)//vdp1 ram return ADJUST_CYCLES(12); else if (addr >= 0x5c8 && addr <= 0x5cf)//vdp1 fb return ADJUST_CYCLES(12); else if (addr >= 0x5d0 && addr <= 0x5d7)//vdp1 regs return ADJUST_CYCLES(11); else if (addr >= 0x5e0 && addr <= 0x5ef)//vdp2 ram return ADJUST_CYCLES(7); else if (addr >= 0x5f0 && addr <= 0x5f7)//vdp2 color return ADJUST_CYCLES(8); else if (addr >= 0x5f8 && addr <= 0x5fb)//vdp2 regs return ADJUST_CYCLES(7); else if (addr >= 0x5fe && addr <= 0x5fe)//scu return ADJUST_CYCLES(7); else if (addr >= 0x600 && addr <= 0x7ff)//hwram return ADJUST_CYCLES(7); return 0; } void cache_memory_write_b(SH2_struct *sh, cache_enty * ca, u32 addr, u8 val){ switch (addr & AREA_MASK){ case CACHE_USE: { u32 tagaddr = 0; u32 entry = 0; if (ca->enable == 0){ MappedMemoryWriteByteNocache(sh, addr, val); return; } tagaddr = (addr & TAG_MASK); entry = (addr & ENTRY_MASK) >> ENTRY_SHIFT; if (ca->way[0][entry].v && ca->way[0][entry].tag == tagaddr){ ca->way[0][entry].data[addr&LINE_MASK] = val; update_lru(0, &ca->lru[entry]); } else if (ca->way[1][entry].v && ca->way[1][entry].tag == tagaddr){ ca->way[1][entry].data[addr&LINE_MASK] = val; update_lru(1, &ca->lru[entry]); } else if (ca->way[2][entry].v && ca->way[2][entry].tag == tagaddr){ ca->way[2][entry].data[addr&LINE_MASK] = val; update_lru(2, &ca->lru[entry]); } else if (ca->way[3][entry].v && ca->way[3][entry].tag == tagaddr){ ca->way[3][entry].data[addr&LINE_MASK] = val; update_lru(3, &ca->lru[entry]); } MappedMemoryWriteByteNocache(sh, addr, val); } break; case CACHE_THROUGH: sh->cycles += get_cache_through_timing_write_byte_word(addr); MappedMemoryWriteByteNocache(sh, addr, val); break; default: MappedMemoryWriteByteNocache(sh, addr, val); break; } } void cache_memory_write_w(SH2_struct *sh, cache_enty * ca, u32 addr, u16 val){ switch (addr & AREA_MASK){ case CACHE_USE: { u32 tagaddr = 0; u32 entry = 0; if (ca->enable == 0){ MappedMemoryWriteWordNocache(sh, addr, val); return; } tagaddr = (addr & TAG_MASK); entry = (addr & ENTRY_MASK) >> ENTRY_SHIFT; if (ca->way[0][entry].v && ca->way[0][entry].tag == tagaddr){ ca->way[0][entry].data[addr&LINE_MASK] = val >> 8; ca->way[0][entry].data[(addr&LINE_MASK) + 1] = val; update_lru(0, &ca->lru[entry]); } else if (ca->way[1][entry].v && ca->way[1][entry].tag == tagaddr){ ca->way[1][entry].data[addr&LINE_MASK] = val >> 8; ca->way[1][entry].data[(addr&LINE_MASK) + 1] = val; update_lru(1, &ca->lru[entry]); } else if (ca->way[2][entry].v && ca->way[2][entry].tag == tagaddr){ ca->way[2][entry].data[addr&LINE_MASK] = val >> 8; ca->way[2][entry].data[(addr&LINE_MASK) + 1] = val; update_lru(2, &ca->lru[entry]); } else if (ca->way[3][entry].v && ca->way[3][entry].tag == tagaddr){ ca->way[3][entry].data[addr&LINE_MASK] = val >> 8; ca->way[3][entry].data[(addr&LINE_MASK) + 1] = val; update_lru(3, &ca->lru[entry]); } // write through MappedMemoryWriteWordNocache(sh, addr, val); } break; case CACHE_THROUGH: sh->cycles += get_cache_through_timing_write_byte_word(addr); MappedMemoryWriteWordNocache(sh, addr, val); break; default: MappedMemoryWriteWordNocache(sh, addr, val); break; } } void cache_memory_write_l(SH2_struct *sh, cache_enty * ca, u32 addr, u32 val){ switch (addr & AREA_MASK){ case CACHE_PURGE://associative purge { int i; u32 tagaddr = (addr & TAG_MASK); u32 entry = (addr & ENTRY_MASK) >> ENTRY_SHIFT; for (i = 0; i < 3; i++) { if (ca->way[i][entry].tag == tagaddr) { //only v bit is changed, the rest of the data remains ca->way[i][entry].v = 0; break; } } } break; case CACHE_USE: { u32 tagaddr = 0; u32 entry = 0; if (ca->enable == 0){ MappedMemoryWriteLongNocache(sh, addr, val); return; } tagaddr = (addr & TAG_MASK); entry = (addr & ENTRY_MASK) >> ENTRY_SHIFT; if (ca->way[0][entry].v && ca->way[0][entry].tag == tagaddr){ ca->way[0][entry].data[(addr&LINE_MASK)] = ((val >> 24) & 0xFF); ca->way[0][entry].data[(addr&LINE_MASK) + 1] = ((val >> 16) & 0xFF); ca->way[0][entry].data[(addr&LINE_MASK) + 2] = ((val >> 8) & 0xFF); ca->way[0][entry].data[(addr&LINE_MASK) + 3] = ((val >> 0) & 0xFF); update_lru(0, &ca->lru[entry]); } else if (ca->way[1][entry].v && ca->way[1][entry].tag == tagaddr){ ca->way[1][entry].data[(addr&LINE_MASK)] = ((val >> 24) & 0xFF); ca->way[1][entry].data[(addr&LINE_MASK) + 1] = ((val >> 16) & 0xFF); ca->way[1][entry].data[(addr&LINE_MASK) + 2] = ((val >> 8) & 0xFF); ca->way[1][entry].data[(addr&LINE_MASK) + 3] = ((val >> 0) & 0xFF); update_lru(1, &ca->lru[entry]); } else if (ca->way[2][entry].v && ca->way[2][entry].tag == tagaddr){ ca->way[2][entry].data[(addr&LINE_MASK)] = ((val >> 24) & 0xFF); ca->way[2][entry].data[(addr&LINE_MASK) + 1] = ((val >> 16) & 0xFF); ca->way[2][entry].data[(addr&LINE_MASK) + 2] = ((val >> 8) & 0xFF); ca->way[2][entry].data[(addr&LINE_MASK) + 3] = ((val >> 0) & 0xFF); update_lru(2, &ca->lru[entry]); } else if (ca->way[3][entry].v && ca->way[3][entry].tag == tagaddr){ ca->way[3][entry].data[(addr&LINE_MASK)] = ((val >> 24) & 0xFF); ca->way[3][entry].data[(addr&LINE_MASK) + 1] = ((val >> 16) & 0xFF); ca->way[3][entry].data[(addr&LINE_MASK) + 2] = ((val >> 8) & 0xFF); ca->way[3][entry].data[(addr&LINE_MASK) + 3] = ((val >> 0) & 0xFF); update_lru(3, &ca->lru[entry]); } // write through MappedMemoryWriteLongNocache(sh, addr, val); } break; case CACHE_THROUGH: sh->cycles += get_cache_through_timing_write_long(addr); MappedMemoryWriteLongNocache(sh, addr, val); break; default: MappedMemoryWriteLongNocache(sh, addr, val); break; } } u32 sh2_cache_refill_read(SH2_struct *sh, u32 addr) { addr &= 0xfffffff; if (addr <= 0x00fffff) { //bios return BiosRomMemoryReadLong(addr); } else if (addr >= 0x0100000 && addr <= 0x017ffff) { //smpc return SmpcReadLong(MSH2, addr); } else if (addr >= 0x0180000 && addr <= 0x01fffff) { //backup ram return BupRamMemoryReadLong(addr); } else if (addr >= 0x0200000 && addr <= 0x02fffff) { //low wram return LowWramMemoryReadLong(addr); } else if (addr >= 0x1000000 && addr <= 0x17fffff) { //ssh2 input capture return UnhandledMemoryReadLong(addr); } else if (addr >= 0x1800000 && addr <= 0x1ffffff) { //msh2 input capture return UnhandledMemoryReadLong(addr); } else if (addr >= 0x2000000 && addr <= 0x3ffffff) { //cs0 return CartridgeArea->Cs0ReadLong(MSH2, addr); } else if (addr >= 0x4000000 && addr <= 0x4ffffff) { return Cs1ReadLong(MSH2, addr); } else if (addr >= 0x5000000 && addr <= 0x57fffff) { //dummy } else if (addr >= 0x5800000 && addr <= 0x58fffff) { //cs2 if (yabsys.use_cd_block_lle) { return ygr_a_bus_read_long(addr); } else { return Cs2ReadLong(MSH2, addr); } } else if (addr >= 0x5a00000 && addr <= 0x5afffff) { //sound ram return SoundRamReadLong(addr); } else if (addr >= 0x5b00000 && addr <= 0x5bfffff) { //scsp regs return ScspReadLong(addr); } else if (addr >= 0x5c00000 && addr <= 0x5c7ffff) { //vdp1 ram return Vdp1RamReadLong(addr); } else if (addr >= 0x5c80000 && addr <= 0x5cfffff) { //vdp1 framebuffer return Vdp1FrameBufferReadLong(addr); } else if (addr >= 0x5d00000 && addr <= 0x5d7ffff) { //vdp1 registers return Vdp1ReadLong(addr); } else if (addr >= 0x5e00000 && addr <= 0x5efffff) { //vdp2 ram return Vdp2RamReadLong(addr); } else if (addr >= 0x5f00000 && addr <= 0x5f7ffff) { //vdp2 color ram return Vdp2ColorRamReadLong(addr); } else if (addr >= 0x5f80000 && addr <= 0x5fbffff) { //vdp2 registers return Vdp2ReadLong(addr); } else if (addr >= 0x5fe0000 && addr <= 0x5feffff) { //scu registers return ScuReadLong(addr); } else if (addr >= 0x6000000 && addr <= 0x7ffffff) { //high wram return HighWramMemoryReadLong(addr); } return 0; } void sh2_refill_cache(SH2_struct *sh, cache_enty * ca, int lruway, u32 entry, u32 addr) { int i; sh->cycles += 4; for (i = 0; i < 16; i += 4) { u32 val = sh2_cache_refill_read(sh, (addr & 0xFFFFFFF0) + i); ca->way[lruway][entry].data[i + 0] = (val >> 24) & 0xff; ca->way[lruway][entry].data[i + 1] = (val >> 16) & 0xff; ca->way[lruway][entry].data[i + 2] = (val >> 8) & 0xff; ca->way[lruway][entry].data[i + 3] = (val >> 0) & 0xff; } } u8 cache_memory_read_b(SH2_struct *sh, cache_enty * ca, u32 addr){ switch (addr & AREA_MASK){ case CACHE_USE: { u32 tagaddr = 0; u32 entry = 0; int i = 0; int lruway = 0; if (ca->enable == 0){ return MappedMemoryReadByteNocache(sh, addr); } tagaddr = (addr & TAG_MASK); entry = (addr & ENTRY_MASK) >> ENTRY_SHIFT; if (ca->way[0][entry].v && ca->way[0][entry].tag == tagaddr){ update_lru(0, &ca->lru[entry]); return ca->way[0][entry].data[addr&LINE_MASK]; } else if (ca->way[1][entry].v && ca->way[1][entry].tag == tagaddr){ update_lru(1, &ca->lru[entry]); return ca->way[1][entry].data[addr&LINE_MASK]; } else if (ca->way[2][entry].v && ca->way[2][entry].tag == tagaddr){ update_lru(2, &ca->lru[entry]); return ca->way[2][entry].data[addr&LINE_MASK]; } else if (ca->way[3][entry].v && ca->way[3][entry].tag == tagaddr){ update_lru(3, &ca->lru[entry]); return ca->way[3][entry].data[addr&LINE_MASK]; } // cache miss lruway = select_way_to_replace(sh, ca->lru[entry]); update_lru(lruway, &ca->lru[entry]); ca->way[lruway][entry].tag = tagaddr; sh2_refill_cache(sh, ca, lruway, entry, addr); ca->way[lruway][entry].v = 1; //becomes valid return ca->way[lruway][entry].data[addr&LINE_MASK]; } break; case CACHE_THROUGH: sh->cycles += get_cache_through_timing_read_byte_word(addr); return MappedMemoryReadByteNocache(sh, addr); break; default: return MappedMemoryReadByteNocache(sh, addr); break; } return 0; } u16 cache_memory_read_w(SH2_struct *sh, cache_enty * ca, u32 addr){ switch (addr & AREA_MASK){ case CACHE_USE: { u32 tagaddr = 0; u32 entry = 0; int i = 0; int lruway = 0; if (ca->enable == 0){ return MappedMemoryReadWordNocache(sh, addr); } tagaddr = (addr & TAG_MASK); entry = (addr & ENTRY_MASK) >> ENTRY_SHIFT; if (ca->way[0][entry].v && ca->way[0][entry].tag == tagaddr){ update_lru(0, &ca->lru[entry]); return ((u16)(ca->way[0][entry].data[addr&LINE_MASK]) << 8) | ca->way[0][entry].data[(addr&LINE_MASK) + 1]; } else if (ca->way[1][entry].v && ca->way[1][entry].tag == tagaddr){ update_lru(1, &ca->lru[entry]); return ((u16)(ca->way[1][entry].data[addr&LINE_MASK]) << 8) | ca->way[1][entry].data[(addr&LINE_MASK) + 1]; } else if (ca->way[2][entry].v && ca->way[2][entry].tag == tagaddr){ update_lru(2, &ca->lru[entry]); return ((u16)(ca->way[2][entry].data[addr&LINE_MASK]) << 8) | ca->way[2][entry].data[(addr&LINE_MASK) + 1]; } else if (ca->way[3][entry].v && ca->way[3][entry].tag == tagaddr){ update_lru(3, &ca->lru[entry]); return ((u16)(ca->way[3][entry].data[addr&LINE_MASK]) << 8) | ca->way[3][entry].data[(addr&LINE_MASK) + 1]; } // cache miss lruway = select_way_to_replace(sh, ca->lru[entry]); update_lru(lruway, &ca->lru[entry]); ca->way[lruway][entry].tag = tagaddr; sh2_refill_cache(sh, ca, lruway, entry, addr); ca->way[lruway][entry].v = 1; //becomes valid return ((u16)(ca->way[lruway][entry].data[addr&LINE_MASK]) << 8) | ca->way[lruway][entry].data[(addr&LINE_MASK) + 1]; } break; case CACHE_THROUGH: sh->cycles += get_cache_through_timing_read_byte_word(addr); return MappedMemoryReadWordNocache(sh, addr); break; default: return MappedMemoryReadWordNocache(sh, addr); break; } return 0; } u32 cache_memory_read_l(SH2_struct *sh, cache_enty * ca, u32 addr){ switch (addr & AREA_MASK){ case CACHE_USE: { u32 tagaddr = 0; u32 entry = 0; int i = 0; int lruway = 0; if (ca->enable == 0){ return MappedMemoryReadLongNocache(sh, addr); } tagaddr = (addr & TAG_MASK); entry = (addr & ENTRY_MASK) >> ENTRY_SHIFT; if (ca->way[0][entry].v && ca->way[0][entry].tag == tagaddr){ update_lru(0, &ca->lru[entry]); return ((u32)(ca->way[0][entry].data[addr&LINE_MASK]) << 24) | ((u32)(ca->way[0][entry].data[(addr&LINE_MASK) + 1]) << 16) | ((u32)(ca->way[0][entry].data[(addr&LINE_MASK) + 2]) << 8) | ((u32)(ca->way[0][entry].data[(addr&LINE_MASK) + 3]) << 0); } else if (ca->way[1][entry].v && ca->way[1][entry].tag == tagaddr){ update_lru(1, &ca->lru[entry]); return ((u32)(ca->way[1][entry].data[addr&LINE_MASK]) << 24) | ((u32)(ca->way[1][entry].data[(addr&LINE_MASK) + 1]) << 16) | ((u32)(ca->way[1][entry].data[(addr&LINE_MASK) + 2]) << 8) | ((u32)(ca->way[1][entry].data[(addr&LINE_MASK) + 3]) << 0); } else if (ca->way[2][entry].v && ca->way[2][entry].tag == tagaddr){ update_lru(2, &ca->lru[entry]); return ((u32)(ca->way[2][entry].data[addr&LINE_MASK]) << 24) | ((u32)(ca->way[2][entry].data[(addr&LINE_MASK) + 1]) << 16) | ((u32)(ca->way[2][entry].data[(addr&LINE_MASK) + 2]) << 8) | ((u32)(ca->way[2][entry].data[(addr&LINE_MASK) + 3]) << 0); } else if (ca->way[3][entry].v && ca->way[3][entry].tag == tagaddr){ update_lru(3, &ca->lru[entry]); return ((u32)(ca->way[3][entry].data[addr&LINE_MASK]) << 24) | ((u32)(ca->way[3][entry].data[(addr&LINE_MASK) + 1]) << 16) | ((u32)(ca->way[3][entry].data[(addr&LINE_MASK) + 2]) << 8) | ((u32)(ca->way[3][entry].data[(addr&LINE_MASK) + 3]) << 0); } // cache miss lruway = select_way_to_replace(sh, ca->lru[entry]); update_lru(lruway, &ca->lru[entry]); ca->way[lruway][entry].tag = tagaddr; sh2_refill_cache(sh, ca, lruway, entry, addr); ca->way[lruway][entry].v = 1; //becomes valid return ((u32)(ca->way[lruway][entry].data[addr&LINE_MASK]) << 24) | ((u32)(ca->way[lruway][entry].data[(addr&LINE_MASK) + 1]) << 16) | ((u32)(ca->way[lruway][entry].data[(addr&LINE_MASK) + 2]) << 8) | ((u32)(ca->way[lruway][entry].data[(addr&LINE_MASK) + 3]) << 0); } break; case CACHE_THROUGH: sh->cycles += get_cache_through_timing_read_long(addr); return MappedMemoryReadLongNocache(sh, addr); break; default: return MappedMemoryReadLongNocache(sh, addr); break; } return 0; } yabause-0.9.15/src/debug.h000644 001750 001750 00000005261 12755623101 017305 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005-2006 Guillaume Duhamel Copyright 2005 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef DEBUG_H #define DEBUG_H #include "core.h" #include typedef enum { DEBUG_STRING, DEBUG_STREAM , DEBUG_STDOUT, DEBUG_STDERR, DEBUG_CALLBACK } DebugOutType; typedef struct { DebugOutType output_type; union { FILE * stream; char * string; void (*callback) (char*); } output; char * name; } Debug; Debug * DebugInit(const char *, DebugOutType, char *); void DebugDeInit(Debug *); void DebugChangeOutput(Debug *, DebugOutType, char *); void DebugPrintf(Debug *, const char *, u32, const char *, ...); extern Debug * MainLog; void LogStart(void); void LogStop(void); void LogChangeOutput(DebugOutType t, char * s); #ifdef DEBUG #define LOG(...) DebugPrintf(MainLog, __FILE__, __LINE__, __VA_ARGS__) #else #define LOG(...) #endif #ifdef CDDEBUG #define CDLOG(...) DebugPrintf(MainLog, __FILE__, __LINE__, __VA_ARGS__) #else #define CDLOG(...) #endif #ifdef NETLINK_DEBUG #define NETLINK_LOG(...) DebugPrintf(MainLog, __FILE__, __LINE__, __VA_ARGS__) #else #define NETLINK_LOG(...) #endif #ifdef SCSP_DEBUG #define SCSPLOG(...) DebugPrintf(MainLog, __FILE__, __LINE__, __VA_ARGS__) #else #define SCSPLOG(...) #endif #ifdef SCSPDSP_DEBUG #define SCSPDSPLOG(...) DebugPrintf(MainLog, __FILE__, __LINE__, __VA_ARGS__) #else #define SCSPDSPLOG(...) #endif #ifdef VDP1_DEBUG #define VDP1LOG(...) DebugPrintf(MainLog, __FILE__, __LINE__, __VA_ARGS__) #else #define VDP1LOG(...) #endif #ifdef VDP2_DEBUG #define VDP2LOG(...) DebugPrintf(MainLog, __FILE__, __LINE__, __VA_ARGS__) #else #define VDP2LOG(...) #endif #ifdef SMPC_DEBUG #define SMPCLOG(...) DebugPrintf(MainLog, __FILE__, __LINE__, __VA_ARGS__) #else #define SMPCLOG(...) #endif #ifdef YGL_DEBUG #define YGLLOG(...) DebugPrintf(MainLog, __FILE__, __LINE__, __VA_ARGS__) #else #define YGLLOG(...) #endif #endif yabause-0.9.15/src/error.h000644 001750 001750 00000002547 12755623101 017354 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005-2006 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef ERROR_H #define ERROR_H #define YAB_ERR_UNKNOWN 0 #define YAB_ERR_FILENOTFOUND 1 #define YAB_ERR_MEMORYALLOC 2 #define YAB_ERR_FILEREAD 3 #define YAB_ERR_FILEWRITE 4 #define YAB_ERR_CANNOTINIT 5 #define YAB_ERR_SH2INVALIDOPCODE 6 #define YAB_ERR_SH2READ 7 #define YAB_ERR_SH2WRITE 8 #define YAB_ERR_SDL 9 #define YAB_ERR_OTHER 10 void YabSetError(int type, const void *extra); void YabErrorMsg(const char * format, ...); #endif yabause-0.9.15/src/scr-x.c000644 001750 001750 00000006332 12755623101 017246 0ustar00guillaumeguillaume000000 000000 /* Copyright 2013 Theo Berkau Copyright 2013 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "screen.h" #include #include #include typedef struct { Display *dpy; XRRScreenSize *xrrs; int num_sizes; int current_size; short * rates; int num_rates; int current_rate; } X11ResolutionList; static XRRScreenConfiguration *x11Conf = NULL; static short x11OriginalRate; static SizeID x11OriginalSizeId; static Rotation x11OriginalRotation; ResolutionList ScreenGetResolutions() { X11ResolutionList * list; list = malloc(sizeof(X11ResolutionList)); list->dpy = XOpenDisplay(NULL); list->xrrs = XRRSizes(list->dpy, 0, &list->num_sizes); list->rates = XRRRates(list->dpy, 0, 0, &list->num_rates); list->current_size = 0; list->current_rate = 0; return list; } int ScreenNextResolution(ResolutionList rl, supportedRes_struct * res) { X11ResolutionList * list = rl; if (list->current_rate < list->num_rates) { res->index = list->current_size; res->width = list->xrrs[list->current_size].width; res->height = list->xrrs[list->current_size].height; res->freq = list->rates[list->current_rate]; res->bpp = 0; list->current_rate++; return 0; } list->current_size++; if (list->current_size < list->num_sizes) { list->rates = XRRRates(list->dpy, 0, list->current_size, &list->num_rates); list->current_rate = 0; return ScreenNextResolution(list, res); } XCloseDisplay(list->dpy); free(list); return 1; } void ScreenChangeResolution(supportedRes_struct * res) { Display *dpy; Window root; // Open X11 connection dpy = XOpenDisplay(NULL); root = RootWindow(dpy, 0); if (x11Conf != NULL) XRRFreeScreenConfigInfo(x11Conf); // Save original settings x11Conf = XRRGetScreenInfo(dpy, root); x11OriginalRate = XRRConfigCurrentRate(x11Conf); x11OriginalSizeId = XRRConfigCurrentConfiguration(x11Conf, &x11OriginalRotation); // Change resolution XRRSetScreenConfigAndRate(dpy, x11Conf, root, res->index, RR_Rotate_0, res->freq, CurrentTime); // Close connection XCloseDisplay(dpy); } void ScreenRestoreResolution() { Display *dpy; Window root; if (x11Conf == NULL) return; // Open X11 connection dpy = XOpenDisplay(NULL); root = RootWindow(dpy, 0); XRRSetScreenConfigAndRate(dpy, x11Conf, root, x11OriginalSizeId, x11OriginalRotation, x11OriginalRate, CurrentTime); // Close connection XCloseDisplay(dpy); } yabause-0.9.15/src/musashi/000755 001750 001750 00000000000 12757373644 017533 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/musashi/CMakeLists.txt000644 001750 001750 00000000735 12755623101 022260 0ustar00guillaumeguillaume000000 000000 project(m68kmake) cmake_minimum_required(VERSION 2.6) add_executable(m68kmake m68kmake.c) if (MSVC) add_definitions(-D_CRT_SECURE_NO_WARNINGS) endif (MSVC) add_custom_command(OUTPUT m68kops.h COMMAND m68kmake ${CMAKE_CURRENT_BINARY_DIR}/ ${CMAKE_CURRENT_SOURCE_DIR}/m68k_in.c DEPENDS m68kmake.c COMMENT "Generating musashi 68k core" VERBATIM) add_custom_target(musashi ALL DEPENDS m68kops.h) yabause-0.9.15/src/musashi/m68k_in.c000644 001750 001750 00000671227 12755623101 021151 0ustar00guillaumeguillaume000000 000000 /* must fix: callm chk */ /* ======================================================================== */ /* ========================= LICENSING & COPYRIGHT ======================== */ /* ======================================================================== */ /* * MUSASHI * Version 3.4 * * A portable Motorola M680x0 processor emulation engine. * Copyright 1998-2001 Karl Stenerud. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* Special thanks to Bart Trzynadlowski for his insight into the * undocumented features of this chip: * * http://dynarec.com/~bart/files/68knotes.txt */ /* Input file for m68kmake * ----------------------- * * All sections begin with 80 X's in a row followed by an end-of-line * sequence. * After this, m68kmake will expect to find one of the following section * identifiers: * M68KMAKE_PROTOTYPE_HEADER - header for opcode handler prototypes * M68KMAKE_PROTOTYPE_FOOTER - footer for opcode handler prototypes * M68KMAKE_TABLE_HEADER - header for opcode handler jumptable * M68KMAKE_TABLE_FOOTER - footer for opcode handler jumptable * M68KMAKE_TABLE_BODY - the table itself * M68KMAKE_OPCODE_HANDLER_HEADER - header for opcode handler implementation * M68KMAKE_OPCODE_HANDLER_FOOTER - footer for opcode handler implementation * M68KMAKE_OPCODE_HANDLER_BODY - body section for opcode handler implementation * * NOTE: M68KMAKE_OPCODE_HANDLER_BODY must be last in the file and * M68KMAKE_TABLE_BODY must be second last in the file. * * The M68KMAKE_OPHANDLER_BODY section contains the opcode handler * primitives themselves. Each opcode handler begins with: * M68KMAKE_OP(A, B, C, D) * * where A is the opcode handler name, B is the size of the operation, * C denotes any special processing mode, and D denotes a specific * addressing mode. * For C and D where nothing is specified, use "." * * Example: * M68KMAKE_OP(abcd, 8, rr, .) abcd, size 8, register to register, default EA * M68KMAKE_OP(abcd, 8, mm, ax7) abcd, size 8, memory to memory, register X is A7 * M68KMAKE_OP(tst, 16, ., pcix) tst, size 16, PCIX addressing * * All opcode handler primitives end with a closing curly brace "}" at column 1 * * NOTE: Do not place a M68KMAKE_OP() directive inside the opcode handler, * and do not put a closing curly brace at column 1 unless it is * marking the end of the handler! * * Inside the handler, m68kmake will recognize M68KMAKE_GET_OPER_xx_xx, * M68KMAKE_GET_EA_xx_xx, and M68KMAKE_CC directives, and create multiple * opcode handlers to handle variations in the opcode handler. * Note: M68KMAKE_CC will only be interpreted in condition code opcodes. * As well, M68KMAKE_GET_EA_xx_xx and M68KMAKE_GET_OPER_xx_xx will only * be interpreted on instructions where the corresponding table entry * specifies multiple effective addressing modes. * Example: * clr 32 . . 0100001010...... A+-DXWL... U U U 12 6 4 * * This table entry says that the clr.l opcde has 7 variations (A+-DXWL). * It is run in user or supervisor mode for all CPUs, and uses 12 cycles for * 68000, 6 cycles for 68010, and 4 cycles for 68020. */ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX M68KMAKE_PROTOTYPE_HEADER #ifndef M68KOPS__HEADER #define M68KOPS__HEADER /* ======================================================================== */ /* ============================ OPCODE HANDLERS =========================== */ /* ======================================================================== */ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX M68KMAKE_PROTOTYPE_FOOTER /* Build the opcode handler table */ void m68ki_build_opcode_table(void); extern void (*m68ki_instruction_jump_table[0x10000])(void); /* opcode handler jump table */ extern unsigned char m68ki_cycles[][0x10000]; /* ======================================================================== */ /* ============================== END OF FILE ============================= */ /* ======================================================================== */ #endif /* M68KOPS__HEADER */ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX M68KMAKE_TABLE_HEADER /* ======================================================================== */ /* ========================= OPCODE TABLE BUILDER ========================= */ /* ======================================================================== */ #include "m68kops.h" #define NUM_CPU_TYPES 3 void (*m68ki_instruction_jump_table[0x10000])(void); /* opcode handler jump table */ unsigned char m68ki_cycles[NUM_CPU_TYPES][0x10000]; /* Cycles used by CPU type */ /* This is used to generate the opcode handler jump table */ typedef struct { void (*opcode_handler)(void); /* handler function */ unsigned int mask; /* mask on opcode */ unsigned int match; /* what to match after masking */ unsigned char cycles[NUM_CPU_TYPES]; /* cycles each cpu type takes */ } opcode_handler_struct; /* Opcode handler table */ static opcode_handler_struct m68k_opcode_handler_table[] = { /* function mask match 000 010 020 */ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX M68KMAKE_TABLE_FOOTER {0, 0, 0, {0, 0, 0}} }; /* Build the opcode handler jump table */ void m68ki_build_opcode_table(void) { opcode_handler_struct *ostruct; int cycle_cost; int instr; int i; int j; int k; for(i = 0; i < 0x10000; i++) { /* default to illegal */ m68ki_instruction_jump_table[i] = m68k_op_illegal; for(k=0;kmask != 0xff00) { for(i = 0;i < 0x10000;i++) { if((i & ostruct->mask) == ostruct->match) { m68ki_instruction_jump_table[i] = ostruct->opcode_handler; for(k=0;kcycles[k]; } } ostruct++; } while(ostruct->mask == 0xff00) { for(i = 0;i <= 0xff;i++) { m68ki_instruction_jump_table[ostruct->match | i] = ostruct->opcode_handler; for(k=0;kmatch | i] = ostruct->cycles[k]; } ostruct++; } while(ostruct->mask == 0xf1f8) { for(i = 0;i < 8;i++) { for(j = 0;j < 8;j++) { instr = ostruct->match | (i << 9) | j; m68ki_instruction_jump_table[instr] = ostruct->opcode_handler; for(k=0;kcycles[k]; // For all shift operations with known shift distance (encoded in instruction word) if((instr & 0xf000) == 0xe000 && (!(instr & 0x20))) { // On the 68000 and 68010 shift distance affect execution time. // Add the cycle cost of shifting; 2 times the shift distance cycle_cost = ((((i-1)&7)+1)<<1); m68ki_cycles[0][instr] += cycle_cost; m68ki_cycles[1][instr] += cycle_cost; // On the 68020 shift distance does not affect execution time m68ki_cycles[2][instr] += 0; } } } ostruct++; } while(ostruct->mask == 0xfff0) { for(i = 0;i <= 0x0f;i++) { m68ki_instruction_jump_table[ostruct->match | i] = ostruct->opcode_handler; for(k=0;kmatch | i] = ostruct->cycles[k]; } ostruct++; } while(ostruct->mask == 0xf1ff) { for(i = 0;i <= 0x07;i++) { m68ki_instruction_jump_table[ostruct->match | (i << 9)] = ostruct->opcode_handler; for(k=0;kmatch | (i << 9)] = ostruct->cycles[k]; } ostruct++; } while(ostruct->mask == 0xfff8) { for(i = 0;i <= 0x07;i++) { m68ki_instruction_jump_table[ostruct->match | i] = ostruct->opcode_handler; for(k=0;kmatch | i] = ostruct->cycles[k]; } ostruct++; } while(ostruct->mask == 0xffff) { m68ki_instruction_jump_table[ostruct->match] = ostruct->opcode_handler; for(k=0;kmatch] = ostruct->cycles[k]; ostruct++; } } /* ======================================================================== */ /* ============================== END OF FILE ============================= */ /* ======================================================================== */ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX M68KMAKE_OPCODE_HANDLER_HEADER #include "m68kcpu.h" /* ======================================================================== */ /* ========================= INSTRUCTION HANDLERS ========================= */ /* ======================================================================== */ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX M68KMAKE_OPCODE_HANDLER_FOOTER /* ======================================================================== */ /* ============================== END OF FILE ============================= */ /* ======================================================================== */ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX M68KMAKE_TABLE_BODY The following table is arranged as follows: name: Opcode mnemonic size: Operation size spec proc: Special processing mode: .: normal s: static operand r: register operand rr: register to register mm: memory to memory er: effective address to register re: register to effective address dd: data register to data register da: data register to address register aa: address register to address register cr: control register to register rc: register to control register toc: to condition code register tos: to status register tou: to user stack pointer frc: from condition code register frs: from status register fru: from user stack pointer * for move.x, the special processing mode is a specific destination effective addressing mode. spec ea: Specific effective addressing mode: .: normal i: immediate d: data register a: address register ai: address register indirect pi: address register indirect with postincrement pd: address register indirect with predecrement di: address register indirect with displacement ix: address register indirect with index aw: absolute word address al: absolute long address pcdi: program counter relative with displacement pcix: program counter relative with index a7: register specified in instruction is A7 ax7: register field X of instruction is A7 ay7: register field Y of instruction is A7 axy7: register fields X and Y of instruction are A7 bit pattern: Pattern to recognize this opcode. "." means don't care. allowed ea: List of allowed addressing modes: .: not present A: address register indirect +: ARI (address register indirect) with postincrement -: ARI with predecrement D: ARI with displacement X: ARI with index W: absolute word address L: absolute long address d: program counter indirect with displacement x: program counter indirect with index I: immediate mode: CPU operating mode for each cpu type. U = user or supervisor, S = supervisor only, "." = opcode not present. cpu cycles: Base number of cycles required to execute this opcode on the specified CPU type. Use "." if CPU does not have this opcode. spec spec allowed ea mode cpu cycles name size proc ea bit pattern A+-DXWLdxI 0 1 2 000 010 020 comments ====== ==== ==== ==== ================ ========== = = = === === === ============= M68KMAKE_TABLE_START 1010 0 . . 1010............ .......... U U U 4 4 4 1111 0 . . 1111............ .......... U U U 4 4 4 abcd 8 rr . 1100...100000... .......... U U U 6 6 4 abcd 8 mm ax7 1100111100001... .......... U U U 18 18 16 abcd 8 mm ay7 1100...100001111 .......... U U U 18 18 16 abcd 8 mm axy7 1100111100001111 .......... U U U 18 18 16 abcd 8 mm . 1100...100001... .......... U U U 18 18 16 add 8 er d 1101...000000... .......... U U U 4 4 2 add 8 er . 1101...000...... A+-DXWLdxI U U U 4 4 2 add 16 er d 1101...001000... .......... U U U 4 4 2 add 16 er a 1101...001001... .......... U U U 4 4 2 add 16 er . 1101...001...... A+-DXWLdxI U U U 4 4 2 add 32 er d 1101...010000... .......... U U U 6 6 2 add 32 er a 1101...010001... .......... U U U 6 6 2 add 32 er . 1101...010...... A+-DXWLdxI U U U 6 6 2 add 8 re . 1101...100...... A+-DXWL... U U U 8 8 4 add 16 re . 1101...101...... A+-DXWL... U U U 8 8 4 add 32 re . 1101...110...... A+-DXWL... U U U 12 12 4 adda 16 . d 1101...011000... .......... U U U 8 8 2 adda 16 . a 1101...011001... .......... U U U 8 8 2 adda 16 . . 1101...011...... A+-DXWLdxI U U U 8 8 2 adda 32 . d 1101...111000... .......... U U U 6 6 2 adda 32 . a 1101...111001... .......... U U U 6 6 2 adda 32 . . 1101...111...... A+-DXWLdxI U U U 6 6 2 addi 8 . d 0000011000000... .......... U U U 8 8 2 addi 8 . . 0000011000...... A+-DXWL... U U U 12 12 4 addi 16 . d 0000011001000... .......... U U U 8 8 2 addi 16 . . 0000011001...... A+-DXWL... U U U 12 12 4 addi 32 . d 0000011010000... .......... U U U 16 14 2 addi 32 . . 0000011010...... A+-DXWL... U U U 20 20 4 addq 8 . d 0101...000000... .......... U U U 4 4 2 addq 8 . . 0101...000...... A+-DXWL... U U U 8 8 4 addq 16 . d 0101...001000... .......... U U U 4 4 2 addq 16 . a 0101...001001... .......... U U U 4 4 2 addq 16 . . 0101...001...... A+-DXWL... U U U 8 8 4 addq 32 . d 0101...010000... .......... U U U 8 8 2 addq 32 . a 0101...010001... .......... U U U 8 8 2 addq 32 . . 0101...010...... A+-DXWL... U U U 12 12 4 addx 8 rr . 1101...100000... .......... U U U 4 4 2 addx 16 rr . 1101...101000... .......... U U U 4 4 2 addx 32 rr . 1101...110000... .......... U U U 8 6 2 addx 8 mm ax7 1101111100001... .......... U U U 18 18 12 addx 8 mm ay7 1101...100001111 .......... U U U 18 18 12 addx 8 mm axy7 1101111100001111 .......... U U U 18 18 12 addx 8 mm . 1101...100001... .......... U U U 18 18 12 addx 16 mm . 1101...101001... .......... U U U 18 18 12 addx 32 mm . 1101...110001... .......... U U U 30 30 12 and 8 er d 1100...000000... .......... U U U 4 4 2 and 8 er . 1100...000...... A+-DXWLdxI U U U 4 4 2 and 16 er d 1100...001000... .......... U U U 4 4 2 and 16 er . 1100...001...... A+-DXWLdxI U U U 4 4 2 and 32 er d 1100...010000... .......... U U U 6 6 2 and 32 er . 1100...010...... A+-DXWLdxI U U U 6 6 2 and 8 re . 1100...100...... A+-DXWL... U U U 8 8 4 and 16 re . 1100...101...... A+-DXWL... U U U 8 8 4 and 32 re . 1100...110...... A+-DXWL... U U U 12 12 4 andi 16 toc . 0000001000111100 .......... U U U 20 16 12 andi 16 tos . 0000001001111100 .......... S S S 20 16 12 andi 8 . d 0000001000000... .......... U U U 8 8 2 andi 8 . . 0000001000...... A+-DXWL... U U U 12 12 4 andi 16 . d 0000001001000... .......... U U U 8 8 2 andi 16 . . 0000001001...... A+-DXWL... U U U 12 12 4 andi 32 . d 0000001010000... .......... U U U 14 14 2 andi 32 . . 0000001010...... A+-DXWL... U U U 20 20 4 asr 8 s . 1110...000000... .......... U U U 6 6 6 asr 16 s . 1110...001000... .......... U U U 6 6 6 asr 32 s . 1110...010000... .......... U U U 8 8 6 asr 8 r . 1110...000100... .......... U U U 6 6 6 asr 16 r . 1110...001100... .......... U U U 6 6 6 asr 32 r . 1110...010100... .......... U U U 8 8 6 asr 16 . . 1110000011...... A+-DXWL... U U U 8 8 5 asl 8 s . 1110...100000... .......... U U U 6 6 8 asl 16 s . 1110...101000... .......... U U U 6 6 8 asl 32 s . 1110...110000... .......... U U U 8 8 8 asl 8 r . 1110...100100... .......... U U U 6 6 8 asl 16 r . 1110...101100... .......... U U U 6 6 8 asl 32 r . 1110...110100... .......... U U U 8 8 8 asl 16 . . 1110000111...... A+-DXWL... U U U 8 8 6 bcc 8 . . 0110............ .......... U U U 10 10 6 bcc 16 . . 0110....00000000 .......... U U U 10 10 6 bcc 32 . . 0110....11111111 .......... . . U . . 6 bchg 8 r . 0000...101...... A+-DXWL... U U U 8 8 4 bchg 32 r d 0000...101000... .......... U U U 8 8 4 bchg 8 s . 0000100001...... A+-DXWL... U U U 12 12 4 bchg 32 s d 0000100001000... .......... U U U 12 12 4 bclr 8 r . 0000...110...... A+-DXWL... U U U 8 10 4 bclr 32 r d 0000...110000... .......... U U U 10 10 4 bclr 8 s . 0000100010...... A+-DXWL... U U U 12 12 4 bclr 32 s d 0000100010000... .......... U U U 14 14 4 bfchg 32 . d 1110101011000... .......... . . U . . 12 timing not quite correct bfchg 32 . . 1110101011...... A..DXWL... . . U . . 20 bfclr 32 . d 1110110011000... .......... . . U . . 12 bfclr 32 . . 1110110011...... A..DXWL... . . U . . 20 bfexts 32 . d 1110101111000... .......... . . U . . 8 bfexts 32 . . 1110101111...... A..DXWLdx. . . U . . 15 bfextu 32 . d 1110100111000... .......... . . U . . 8 bfextu 32 . . 1110100111...... A..DXWLdx. . . U . . 15 bfffo 32 . d 1110110111000... .......... . . U . . 18 bfffo 32 . . 1110110111...... A..DXWLdx. . . U . . 28 bfins 32 . d 1110111111000... .......... . . U . . 10 bfins 32 . . 1110111111...... A..DXWL... . . U . . 17 bfset 32 . d 1110111011000... .......... . . U . . 12 bfset 32 . . 1110111011...... A..DXWL... . . U . . 20 bftst 32 . d 1110100011000... .......... . . U . . 6 bftst 32 . . 1110100011...... A..DXWLdx. . . U . . 13 bkpt 0 . . 0100100001001... .......... . U U . 10 10 bra 8 . . 01100000........ .......... U U U 10 10 10 bra 16 . . 0110000000000000 .......... U U U 10 10 10 bra 32 . . 0110000011111111 .......... U U U . . 10 bset 32 r d 0000...111000... .......... U U U 8 8 4 bset 8 r . 0000...111...... A+-DXWL... U U U 8 8 4 bset 8 s . 0000100011...... A+-DXWL... U U U 12 12 4 bset 32 s d 0000100011000... .......... U U U 12 12 4 bsr 8 . . 01100001........ .......... U U U 18 18 7 bsr 16 . . 0110000100000000 .......... U U U 18 18 7 bsr 32 . . 0110000111111111 .......... . . U . . 7 btst 8 r . 0000...100...... A+-DXWLdxI U U U 4 4 4 btst 32 r d 0000...100000... .......... U U U 6 6 4 btst 8 s . 0000100000...... A+-DXWLdx. U U U 8 8 4 btst 32 s d 0000100000000... .......... U U U 10 10 4 callm 32 . . 0000011011...... A..DXWLdx. . . U . . 60 not properly emulated cas 8 . . 0000101011...... A+-DXWL... . . U . . 12 cas 16 . . 0000110011...... A+-DXWL... . . U . . 12 cas 32 . . 0000111011...... A+-DXWL... . . U . . 12 cas2 16 . . 0000110011111100 .......... . . U . . 12 cas2 32 . . 0000111011111100 .......... . . U . . 12 chk 16 . d 0100...110000... .......... U U U 10 8 8 chk 16 . . 0100...110...... A+-DXWLdxI U U U 10 8 8 chk 32 . d 0100...100000... .......... . . U . . 8 chk 32 . . 0100...100...... A+-DXWLdxI . . U . . 8 chk2cmp2 8 . pcdi 0000000011111010 .......... . . U . . 23 chk2cmp2 8 . pcix 0000000011111011 .......... . . U . . 23 chk2cmp2 8 . . 0000000011...... A..DXWL... . . U . . 18 chk2cmp2 16 . pcdi 0000001011111010 .......... . . U . . 23 chk2cmp2 16 . pcix 0000001011111011 .......... . . U . . 23 chk2cmp2 16 . . 0000001011...... A..DXWL... . . U . . 18 chk2cmp2 32 . pcdi 0000010011111010 .......... . . U . . 23 chk2cmp2 32 . pcix 0000010011111011 .......... . . U . . 23 chk2cmp2 32 . . 0000010011...... A..DXWL... . . U . . 18 clr 8 . d 0100001000000... .......... U U U 4 4 2 clr 8 . . 0100001000...... A+-DXWL... U U U 8 4 4 clr 16 . d 0100001001000... .......... U U U 4 4 2 clr 16 . . 0100001001...... A+-DXWL... U U U 8 4 4 clr 32 . d 0100001010000... .......... U U U 6 6 2 clr 32 . . 0100001010...... A+-DXWL... U U U 12 6 4 cmp 8 . d 1011...000000... .......... U U U 4 4 2 cmp 8 . . 1011...000...... A+-DXWLdxI U U U 4 4 2 cmp 16 . d 1011...001000... .......... U U U 4 4 2 cmp 16 . a 1011...001001... .......... U U U 4 4 2 cmp 16 . . 1011...001...... A+-DXWLdxI U U U 4 4 2 cmp 32 . d 1011...010000... .......... U U U 6 6 2 cmp 32 . a 1011...010001... .......... U U U 6 6 2 cmp 32 . . 1011...010...... A+-DXWLdxI U U U 6 6 2 cmpa 16 . d 1011...011000... .......... U U U 6 6 4 cmpa 16 . a 1011...011001... .......... U U U 6 6 4 cmpa 16 . . 1011...011...... A+-DXWLdxI U U U 6 6 4 cmpa 32 . d 1011...111000... .......... U U U 6 6 4 cmpa 32 . a 1011...111001... .......... U U U 6 6 4 cmpa 32 . . 1011...111...... A+-DXWLdxI U U U 6 6 4 cmpi 8 . d 0000110000000... .......... U U U 8 8 2 cmpi 8 . . 0000110000...... A+-DXWL... U U U 8 8 2 cmpi 8 . pcdi 0000110000111010 .......... . . U . . 7 cmpi 8 . pcix 0000110000111011 .......... . . U . . 9 cmpi 16 . d 0000110001000... .......... U U U 8 8 2 cmpi 16 . . 0000110001...... A+-DXWL... U U U 8 8 2 cmpi 16 . pcdi 0000110001111010 .......... . . U . . 7 cmpi 16 . pcix 0000110001111011 .......... . . U . . 9 cmpi 32 . d 0000110010000... .......... U U U 14 12 2 cmpi 32 . . 0000110010...... A+-DXWL... U U U 12 12 2 cmpi 32 . pcdi 0000110010111010 .......... . . U . . 7 cmpi 32 . pcix 0000110010111011 .......... . . U . . 9 cmpm 8 . ax7 1011111100001... .......... U U U 12 12 9 cmpm 8 . ay7 1011...100001111 .......... U U U 12 12 9 cmpm 8 . axy7 1011111100001111 .......... U U U 12 12 9 cmpm 8 . . 1011...100001... .......... U U U 12 12 9 cmpm 16 . . 1011...101001... .......... U U U 12 12 9 cmpm 32 . . 1011...110001... .......... U U U 20 20 9 cpbcc 32 . . 1111...01....... .......... . . U . . 4 unemulated cpdbcc 32 . . 1111...001001... .......... . . U . . 4 unemulated cpgen 32 . . 1111...000...... .......... . . U . . 4 unemulated cpscc 32 . . 1111...001...... .......... . . U . . 4 unemulated cptrapcc 32 . . 1111...001111... .......... . . U . . 4 unemulated dbt 16 . . 0101000011001... .......... U U U 12 12 6 dbf 16 . . 0101000111001... .......... U U U 12 12 6 dbcc 16 . . 0101....11001... .......... U U U 12 12 6 divs 16 . d 1000...111000... .......... U U U 158 122 56 divs 16 . . 1000...111...... A+-DXWLdxI U U U 158 122 56 divu 16 . d 1000...011000... .......... U U U 140 108 44 divu 16 . . 1000...011...... A+-DXWLdxI U U U 140 108 44 divl 32 . d 0100110001000... .......... . . U . . 84 divl 32 . . 0100110001...... A+-DXWLdxI . . U . . 84 eor 8 . d 1011...100000... .......... U U U 4 4 2 eor 8 . . 1011...100...... A+-DXWL... U U U 8 8 4 eor 16 . d 1011...101000... .......... U U U 4 4 2 eor 16 . . 1011...101...... A+-DXWL... U U U 8 8 4 eor 32 . d 1011...110000... .......... U U U 8 6 2 eor 32 . . 1011...110...... A+-DXWL... U U U 12 12 4 eori 16 toc . 0000101000111100 .......... U U U 20 16 12 eori 16 tos . 0000101001111100 .......... S S S 20 16 12 eori 8 . d 0000101000000... .......... U U U 8 8 2 eori 8 . . 0000101000...... A+-DXWL... U U U 12 12 4 eori 16 . d 0000101001000... .......... U U U 8 8 2 eori 16 . . 0000101001...... A+-DXWL... U U U 12 12 4 eori 32 . d 0000101010000... .......... U U U 16 14 2 eori 32 . . 0000101010...... A+-DXWL... U U U 20 20 4 exg 32 dd . 1100...101000... .......... U U U 6 6 2 exg 32 aa . 1100...101001... .......... U U U 6 6 2 exg 32 da . 1100...110001... .......... U U U 6 6 2 ext 16 . . 0100100010000... .......... U U U 4 4 4 ext 32 . . 0100100011000... .......... U U U 4 4 4 extb 32 . . 0100100111000... .......... . . U . . 4 illegal 0 . . 0100101011111100 .......... U U U 4 4 4 jmp 32 . . 0100111011...... A..DXWLdx. U U U 4 4 0 jsr 32 . . 0100111010...... A..DXWLdx. U U U 12 12 0 lea 32 . . 0100...111...... A..DXWLdx. U U U 0 0 2 link 16 . a7 0100111001010111 .......... U U U 16 16 5 link 16 . . 0100111001010... .......... U U U 16 16 5 link 32 . a7 0100100000001111 .......... . . U . . 6 link 32 . . 0100100000001... .......... . . U . . 6 lsr 8 s . 1110...000001... .......... U U U 6 6 4 lsr 16 s . 1110...001001... .......... U U U 6 6 4 lsr 32 s . 1110...010001... .......... U U U 8 8 4 lsr 8 r . 1110...000101... .......... U U U 6 6 6 lsr 16 r . 1110...001101... .......... U U U 6 6 6 lsr 32 r . 1110...010101... .......... U U U 8 8 6 lsr 16 . . 1110001011...... A+-DXWL... U U U 8 8 5 lsl 8 s . 1110...100001... .......... U U U 6 6 4 lsl 16 s . 1110...101001... .......... U U U 6 6 4 lsl 32 s . 1110...110001... .......... U U U 8 8 4 lsl 8 r . 1110...100101... .......... U U U 6 6 6 lsl 16 r . 1110...101101... .......... U U U 6 6 6 lsl 32 r . 1110...110101... .......... U U U 8 8 6 lsl 16 . . 1110001111...... A+-DXWL... U U U 8 8 5 move 8 d d 0001...000000... .......... U U U 4 4 2 move 8 d . 0001...000...... A+-DXWLdxI U U U 4 4 2 move 8 ai d 0001...010000... .......... U U U 8 8 4 move 8 ai . 0001...010...... A+-DXWLdxI U U U 8 8 4 move 8 pi d 0001...011000... .......... U U U 8 8 4 move 8 pi . 0001...011...... A+-DXWLdxI U U U 8 8 4 move 8 pi7 d 0001111011000... .......... U U U 8 8 4 move 8 pi7 . 0001111011...... A+-DXWLdxI U U U 8 8 4 move 8 pd d 0001...100000... .......... U U U 8 8 5 move 8 pd . 0001...100...... A+-DXWLdxI U U U 8 8 5 move 8 pd7 d 0001111100000... .......... U U U 8 8 5 move 8 pd7 . 0001111100...... A+-DXWLdxI U U U 8 8 5 move 8 di d 0001...101000... .......... U U U 12 12 5 move 8 di . 0001...101...... A+-DXWLdxI U U U 12 12 5 move 8 ix d 0001...110000... .......... U U U 14 14 7 move 8 ix . 0001...110...... A+-DXWLdxI U U U 14 14 7 move 8 aw d 0001000111000... .......... U U U 12 12 4 move 8 aw . 0001000111...... A+-DXWLdxI U U U 12 12 4 move 8 al d 0001001111000... .......... U U U 16 16 6 move 8 al . 0001001111...... A+-DXWLdxI U U U 16 16 6 move 16 d d 0011...000000... .......... U U U 4 4 2 move 16 d a 0011...000001... .......... U U U 4 4 2 move 16 d . 0011...000...... A+-DXWLdxI U U U 4 4 2 move 16 ai d 0011...010000... .......... U U U 8 8 4 move 16 ai a 0011...010001... .......... U U U 8 8 4 move 16 ai . 0011...010...... A+-DXWLdxI U U U 8 8 4 move 16 pi d 0011...011000... .......... U U U 8 8 4 move 16 pi a 0011...011001... .......... U U U 8 8 4 move 16 pi . 0011...011...... A+-DXWLdxI U U U 8 8 4 move 16 pd d 0011...100000... .......... U U U 8 8 5 move 16 pd a 0011...100001... .......... U U U 8 8 5 move 16 pd . 0011...100...... A+-DXWLdxI U U U 8 8 5 move 16 di d 0011...101000... .......... U U U 12 12 5 move 16 di a 0011...101001... .......... U U U 12 12 5 move 16 di . 0011...101...... A+-DXWLdxI U U U 12 12 5 move 16 ix d 0011...110000... .......... U U U 14 14 7 move 16 ix a 0011...110001... .......... U U U 14 14 7 move 16 ix . 0011...110...... A+-DXWLdxI U U U 14 14 7 move 16 aw d 0011000111000... .......... U U U 12 12 4 move 16 aw a 0011000111001... .......... U U U 12 12 4 move 16 aw . 0011000111...... A+-DXWLdxI U U U 12 12 4 move 16 al d 0011001111000... .......... U U U 16 16 6 move 16 al a 0011001111001... .......... U U U 16 16 6 move 16 al . 0011001111...... A+-DXWLdxI U U U 16 16 6 move 32 d d 0010...000000... .......... U U U 4 4 2 move 32 d a 0010...000001... .......... U U U 4 4 2 move 32 d . 0010...000...... A+-DXWLdxI U U U 4 4 2 move 32 ai d 0010...010000... .......... U U U 12 12 4 move 32 ai a 0010...010001... .......... U U U 12 12 4 move 32 ai . 0010...010...... A+-DXWLdxI U U U 12 12 4 move 32 pi d 0010...011000... .......... U U U 12 12 4 move 32 pi a 0010...011001... .......... U U U 12 12 4 move 32 pi . 0010...011...... A+-DXWLdxI U U U 12 12 4 move 32 pd d 0010...100000... .......... U U U 12 14 5 move 32 pd a 0010...100001... .......... U U U 12 14 5 move 32 pd . 0010...100...... A+-DXWLdxI U U U 12 14 5 move 32 di d 0010...101000... .......... U U U 16 16 5 move 32 di a 0010...101001... .......... U U U 16 16 5 move 32 di . 0010...101...... A+-DXWLdxI U U U 16 16 5 move 32 ix d 0010...110000... .......... U U U 18 18 7 move 32 ix a 0010...110001... .......... U U U 18 18 7 move 32 ix . 0010...110...... A+-DXWLdxI U U U 18 18 7 move 32 aw d 0010000111000... .......... U U U 16 16 4 move 32 aw a 0010000111001... .......... U U U 16 16 4 move 32 aw . 0010000111...... A+-DXWLdxI U U U 16 16 4 move 32 al d 0010001111000... .......... U U U 20 20 6 move 32 al a 0010001111001... .......... U U U 20 20 6 move 32 al . 0010001111...... A+-DXWLdxI U U U 20 20 6 movea 16 . d 0011...001000... .......... U U U 4 4 2 movea 16 . a 0011...001001... .......... U U U 4 4 2 movea 16 . . 0011...001...... A+-DXWLdxI U U U 4 4 2 movea 32 . d 0010...001000... .......... U U U 4 4 2 movea 32 . a 0010...001001... .......... U U U 4 4 2 movea 32 . . 0010...001...... A+-DXWLdxI U U U 4 4 2 move 16 frc d 0100001011000... .......... . U U . 4 4 move 16 frc . 0100001011...... A+-DXWL... . U U . 8 4 move 16 toc d 0100010011000... .......... U U U 12 12 4 move 16 toc . 0100010011...... A+-DXWLdxI U U U 12 12 4 move 16 frs d 0100000011000... .......... U S S 6 4 8 U only for 000 move 16 frs . 0100000011...... A+-DXWL... U S S 8 8 8 U only for 000 move 16 tos d 0100011011000... .......... S S S 12 12 8 move 16 tos . 0100011011...... A+-DXWLdxI S S S 12 12 8 move 32 fru . 0100111001101... .......... S S S 4 6 2 move 32 tou . 0100111001100... .......... S S S 4 6 2 movec 32 cr . 0100111001111010 .......... . S S . 12 6 movec 32 rc . 0100111001111011 .......... . S S . 10 12 movem 16 re pd 0100100010100... .......... U U U 8 8 4 movem 16 re . 0100100010...... A..DXWL... U U U 4 4 4 cycles for hypothetical d addressing mode (020 unverified) movem 32 re pd 0100100011100... .......... U U U 8 8 4 movem 32 re . 0100100011...... A..DXWL... U U U 0 0 4 cycles for hypothetical d addressing mode (020 unverified) movem 16 er pi 0100110010011... .......... U U U 12 12 8 movem 16 er pcdi 0100110010111010 .......... U U U 16 16 9 movem 16 er pcix 0100110010111011 .......... U U U 18 18 11 movem 16 er . 0100110010...... A..DXWL... U U U 8 8 8 cycles for hypothetical d addressing mode (020 unverified) movem 32 er pi 0100110011011... .......... U U U 12 12 8 movem 32 er pcdi 0100110011111010 .......... U U U 16 16 9 movem 32 er pcix 0100110011111011 .......... U U U 18 18 11 movem 32 er . 0100110011...... A..DXWL... U U U 4 4 8 cycles for hypothetical d addressing mode (020 unverified) movep 16 er . 0000...100001... .......... U U U 16 16 12 movep 32 er . 0000...101001... .......... U U U 24 24 18 movep 16 re . 0000...110001... .......... U U U 16 16 11 movep 32 re . 0000...111001... .......... U U U 24 24 17 moveq 32 . . 0111...0........ .......... U U U 4 4 2 moves 8 . . 0000111000...... A+-DXWL... . S S . 14 5 moves 16 . . 0000111001...... A+-DXWL... . S S . 14 5 moves 32 . . 0000111010...... A+-DXWL... . S S . 16 5 muls 16 . d 1100...111000... .......... U U U 54 32 27 muls 16 . . 1100...111...... A+-DXWLdxI U U U 54 32 27 mulu 16 . d 1100...011000... .......... U U U 54 30 27 mulu 16 . . 1100...011...... A+-DXWLdxI U U U 54 30 27 mull 32 . d 0100110000000... .......... . . U . . 43 mull 32 . . 0100110000...... A+-DXWLdxI . . U . . 43 nbcd 8 . d 0100100000000... .......... U U U 6 6 6 nbcd 8 . . 0100100000...... A+-DXWL... U U U 8 8 6 neg 8 . d 0100010000000... .......... U U U 4 4 2 neg 8 . . 0100010000...... A+-DXWL... U U U 8 8 4 neg 16 . d 0100010001000... .......... U U U 4 4 2 neg 16 . . 0100010001...... A+-DXWL... U U U 8 8 4 neg 32 . d 0100010010000... .......... U U U 6 6 2 neg 32 . . 0100010010...... A+-DXWL... U U U 12 12 4 negx 8 . d 0100000000000... .......... U U U 4 4 2 negx 8 . . 0100000000...... A+-DXWL... U U U 8 8 4 negx 16 . d 0100000001000... .......... U U U 4 4 2 negx 16 . . 0100000001...... A+-DXWL... U U U 8 8 4 negx 32 . d 0100000010000... .......... U U U 6 6 2 negx 32 . . 0100000010...... A+-DXWL... U U U 12 12 4 nop 0 . . 0100111001110001 .......... U U U 4 4 2 not 8 . d 0100011000000... .......... U U U 4 4 2 not 8 . . 0100011000...... A+-DXWL... U U U 8 8 4 not 16 . d 0100011001000... .......... U U U 4 4 2 not 16 . . 0100011001...... A+-DXWL... U U U 8 8 4 not 32 . d 0100011010000... .......... U U U 6 6 2 not 32 . . 0100011010...... A+-DXWL... U U U 12 12 4 or 8 er d 1000...000000... .......... U U U 4 4 2 or 8 er . 1000...000...... A+-DXWLdxI U U U 4 4 2 or 16 er d 1000...001000... .......... U U U 4 4 2 or 16 er . 1000...001...... A+-DXWLdxI U U U 4 4 2 or 32 er d 1000...010000... .......... U U U 6 6 2 or 32 er . 1000...010...... A+-DXWLdxI U U U 6 6 2 or 8 re . 1000...100...... A+-DXWL... U U U 8 8 4 or 16 re . 1000...101...... A+-DXWL... U U U 8 8 4 or 32 re . 1000...110...... A+-DXWL... U U U 12 12 4 ori 16 toc . 0000000000111100 .......... U U U 20 16 12 ori 16 tos . 0000000001111100 .......... S S S 20 16 12 ori 8 . d 0000000000000... .......... U U U 8 8 2 ori 8 . . 0000000000...... A+-DXWL... U U U 12 12 4 ori 16 . d 0000000001000... .......... U U U 8 8 2 ori 16 . . 0000000001...... A+-DXWL... U U U 12 12 4 ori 32 . d 0000000010000... .......... U U U 16 14 2 ori 32 . . 0000000010...... A+-DXWL... U U U 20 20 4 pack 16 rr . 1000...101000... .......... . . U . . 6 pack 16 mm ax7 1000111101001... .......... . . U . . 13 pack 16 mm ay7 1000...101001111 .......... . . U . . 13 pack 16 mm axy7 1000111101001111 .......... . . U . . 13 pack 16 mm . 1000...101001... .......... . . U . . 13 pea 32 . . 0100100001...... A..DXWLdx. U U U 6 6 5 reset 0 . . 0100111001110000 .......... S S S 0 0 0 ror 8 s . 1110...000011... .......... U U U 6 6 8 ror 16 s . 1110...001011... .......... U U U 6 6 8 ror 32 s . 1110...010011... .......... U U U 8 8 8 ror 8 r . 1110...000111... .......... U U U 6 6 8 ror 16 r . 1110...001111... .......... U U U 6 6 8 ror 32 r . 1110...010111... .......... U U U 8 8 8 ror 16 . . 1110011011...... A+-DXWL... U U U 8 8 7 rol 8 s . 1110...100011... .......... U U U 6 6 8 rol 16 s . 1110...101011... .......... U U U 6 6 8 rol 32 s . 1110...110011... .......... U U U 8 8 8 rol 8 r . 1110...100111... .......... U U U 6 6 8 rol 16 r . 1110...101111... .......... U U U 6 6 8 rol 32 r . 1110...110111... .......... U U U 8 8 8 rol 16 . . 1110011111...... A+-DXWL... U U U 8 8 7 roxr 8 s . 1110...000010... .......... U U U 6 6 12 roxr 16 s . 1110...001010... .......... U U U 6 6 12 roxr 32 s . 1110...010010... .......... U U U 8 8 12 roxr 8 r . 1110...000110... .......... U U U 6 6 12 roxr 16 r . 1110...001110... .......... U U U 6 6 12 roxr 32 r . 1110...010110... .......... U U U 8 8 12 roxr 16 . . 1110010011...... A+-DXWL... U U U 8 8 5 roxl 8 s . 1110...100010... .......... U U U 6 6 12 roxl 16 s . 1110...101010... .......... U U U 6 6 12 roxl 32 s . 1110...110010... .......... U U U 8 8 12 roxl 8 r . 1110...100110... .......... U U U 6 6 12 roxl 16 r . 1110...101110... .......... U U U 6 6 12 roxl 32 r . 1110...110110... .......... U U U 8 8 12 roxl 16 . . 1110010111...... A+-DXWL... U U U 8 8 5 rtd 32 . . 0100111001110100 .......... . U U . 16 10 rte 32 . . 0100111001110011 .......... S S S 20 24 20 bus fault not emulated rtm 32 . . 000001101100.... .......... . . U . . 19 not properly emulated rtr 32 . . 0100111001110111 .......... U U U 20 20 14 rts 32 . . 0100111001110101 .......... U U U 16 16 10 sbcd 8 rr . 1000...100000... .......... U U U 6 6 4 sbcd 8 mm ax7 1000111100001... .......... U U U 18 18 16 sbcd 8 mm ay7 1000...100001111 .......... U U U 18 18 16 sbcd 8 mm axy7 1000111100001111 .......... U U U 18 18 16 sbcd 8 mm . 1000...100001... .......... U U U 18 18 16 st 8 . d 0101000011000... .......... U U U 6 4 4 st 8 . . 0101000011...... A+-DXWL... U U U 8 8 6 sf 8 . d 0101000111000... .......... U U U 4 4 4 sf 8 . . 0101000111...... A+-DXWL... U U U 8 8 6 scc 8 . d 0101....11000... .......... U U U 4 4 4 scc 8 . . 0101....11...... A+-DXWL... U U U 8 8 6 stop 0 . . 0100111001110010 .......... S S S 4 4 8 sub 8 er d 1001...000000... .......... U U U 4 4 2 sub 8 er . 1001...000...... A+-DXWLdxI U U U 4 4 2 sub 16 er d 1001...001000... .......... U U U 4 4 2 sub 16 er a 1001...001001... .......... U U U 4 4 2 sub 16 er . 1001...001...... A+-DXWLdxI U U U 4 4 2 sub 32 er d 1001...010000... .......... U U U 6 6 2 sub 32 er a 1001...010001... .......... U U U 6 6 2 sub 32 er . 1001...010...... A+-DXWLdxI U U U 6 6 2 sub 8 re . 1001...100...... A+-DXWL... U U U 8 8 4 sub 16 re . 1001...101...... A+-DXWL... U U U 8 8 4 sub 32 re . 1001...110...... A+-DXWL... U U U 12 12 4 suba 16 . d 1001...011000... .......... U U U 8 8 2 suba 16 . a 1001...011001... .......... U U U 8 8 2 suba 16 . . 1001...011...... A+-DXWLdxI U U U 8 8 2 suba 32 . d 1001...111000... .......... U U U 6 6 2 suba 32 . a 1001...111001... .......... U U U 6 6 2 suba 32 . . 1001...111...... A+-DXWLdxI U U U 6 6 2 subi 8 . d 0000010000000... .......... U U U 8 8 2 subi 8 . . 0000010000...... A+-DXWL... U U U 12 12 4 subi 16 . d 0000010001000... .......... U U U 8 8 2 subi 16 . . 0000010001...... A+-DXWL... U U U 12 12 4 subi 32 . d 0000010010000... .......... U U U 16 14 2 subi 32 . . 0000010010...... A+-DXWL... U U U 20 20 4 subq 8 . d 0101...100000... .......... U U U 4 4 2 subq 8 . . 0101...100...... A+-DXWL... U U U 8 8 4 subq 16 . d 0101...101000... .......... U U U 4 4 2 subq 16 . a 0101...101001... .......... U U U 8 4 2 subq 16 . . 0101...101...... A+-DXWL... U U U 8 8 4 subq 32 . d 0101...110000... .......... U U U 8 8 2 subq 32 . a 0101...110001... .......... U U U 8 8 2 subq 32 . . 0101...110...... A+-DXWL... U U U 12 12 4 subx 8 rr . 1001...100000... .......... U U U 4 4 2 subx 16 rr . 1001...101000... .......... U U U 4 4 2 subx 32 rr . 1001...110000... .......... U U U 8 6 2 subx 8 mm ax7 1001111100001... .......... U U U 18 18 12 subx 8 mm ay7 1001...100001111 .......... U U U 18 18 12 subx 8 mm axy7 1001111100001111 .......... U U U 18 18 12 subx 8 mm . 1001...100001... .......... U U U 18 18 12 subx 16 mm . 1001...101001... .......... U U U 18 18 12 subx 32 mm . 1001...110001... .......... U U U 30 30 12 swap 32 . . 0100100001000... .......... U U U 4 4 4 tas 8 . d 0100101011000... .......... U U U 4 4 4 tas 8 . . 0100101011...... A+-DXWL... U U U 14 14 12 trap 0 . . 010011100100.... .......... U U U 4 4 4 trapt 0 . . 0101000011111100 .......... . . U . . 4 trapt 16 . . 0101000011111010 .......... . . U . . 6 trapt 32 . . 0101000011111011 .......... . . U . . 8 trapf 0 . . 0101000111111100 .......... . . U . . 4 trapf 16 . . 0101000111111010 .......... . . U . . 6 trapf 32 . . 0101000111111011 .......... . . U . . 8 trapcc 0 . . 0101....11111100 .......... . . U . . 4 trapcc 16 . . 0101....11111010 .......... . . U . . 6 trapcc 32 . . 0101....11111011 .......... . . U . . 8 trapv 0 . . 0100111001110110 .......... U U U 4 4 4 tst 8 . d 0100101000000... .......... U U U 4 4 2 tst 8 . . 0100101000...... A+-DXWL... U U U 4 4 2 tst 8 . pcdi 0100101000111010 .......... . . U . . 7 tst 8 . pcix 0100101000111011 .......... . . U . . 9 tst 8 . i 0100101000111100 .......... . . U . . 6 tst 16 . d 0100101001000... .......... U U U 4 4 2 tst 16 . a 0100101001001... .......... . . U . . 2 tst 16 . . 0100101001...... A+-DXWL... U U U 4 4 2 tst 16 . pcdi 0100101001111010 .......... . . U . . 7 tst 16 . pcix 0100101001111011 .......... . . U . . 9 tst 16 . i 0100101001111100 .......... . . U . . 6 tst 32 . d 0100101010000... .......... U U U 4 4 2 tst 32 . a 0100101010001... .......... . . U . . 2 tst 32 . . 0100101010...... A+-DXWL... U U U 4 4 2 tst 32 . pcdi 0100101010111010 .......... . . U . . 7 tst 32 . pcix 0100101010111011 .......... . . U . . 9 tst 32 . i 0100101010111100 .......... . . U . . 6 unlk 32 . a7 0100111001011111 .......... U U U 12 12 6 unlk 32 . . 0100111001011... .......... U U U 12 12 6 unpk 16 rr . 1000...110000... .......... . . U . . 8 unpk 16 mm ax7 1000111110001... .......... . . U . . 13 unpk 16 mm ay7 1000...110001111 .......... . . U . . 13 unpk 16 mm axy7 1000111110001111 .......... . . U . . 13 unpk 16 mm . 1000...110001... .......... . . U . . 13 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX M68KMAKE_OPCODE_HANDLER_BODY M68KMAKE_OP(1010, 0, ., .) { m68ki_exception_1010(); } M68KMAKE_OP(1111, 0, ., .) { m68ki_exception_1111(); } M68KMAKE_OP(abcd, 8, rr, .) { uint* r_dst = &DX; uint src = DY; uint dst = *r_dst; uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(); FLAG_V = ~res; /* Undefined V behavior */ if(res > 9) res += 6; res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); FLAG_X = FLAG_C = (res > 0x99) << 8; if(FLAG_C) res -= 0xa0; FLAG_V &= res; /* Undefined V behavior part II */ FLAG_N = NFLAG_8(res); /* Undefined N behavior */ res = MASK_OUT_ABOVE_8(res); FLAG_Z |= res; *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; } M68KMAKE_OP(abcd, 8, mm, ax7) { uint src = OPER_AY_PD_8(); uint ea = EA_A7_PD_8(); uint dst = m68ki_read_8(ea); uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(); FLAG_V = ~res; /* Undefined V behavior */ if(res > 9) res += 6; res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); FLAG_X = FLAG_C = (res > 0x99) << 8; if(FLAG_C) res -= 0xa0; FLAG_V &= res; /* Undefined V behavior part II */ FLAG_N = NFLAG_8(res); /* Undefined N behavior */ res = MASK_OUT_ABOVE_8(res); FLAG_Z |= res; m68ki_write_8(ea, res); } M68KMAKE_OP(abcd, 8, mm, ay7) { uint src = OPER_A7_PD_8(); uint ea = EA_AX_PD_8(); uint dst = m68ki_read_8(ea); uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(); FLAG_V = ~res; /* Undefined V behavior */ if(res > 9) res += 6; res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); FLAG_X = FLAG_C = (res > 0x99) << 8; if(FLAG_C) res -= 0xa0; FLAG_V &= res; /* Undefined V behavior part II */ FLAG_N = NFLAG_8(res); /* Undefined N behavior */ res = MASK_OUT_ABOVE_8(res); FLAG_Z |= res; m68ki_write_8(ea, res); } M68KMAKE_OP(abcd, 8, mm, axy7) { uint src = OPER_A7_PD_8(); uint ea = EA_A7_PD_8(); uint dst = m68ki_read_8(ea); uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(); FLAG_V = ~res; /* Undefined V behavior */ if(res > 9) res += 6; res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); FLAG_X = FLAG_C = (res > 0x99) << 8; if(FLAG_C) res -= 0xa0; FLAG_V &= res; /* Undefined V behavior part II */ FLAG_N = NFLAG_8(res); /* Undefined N behavior */ res = MASK_OUT_ABOVE_8(res); FLAG_Z |= res; m68ki_write_8(ea, res); } M68KMAKE_OP(abcd, 8, mm, .) { uint src = OPER_AY_PD_8(); uint ea = EA_AX_PD_8(); uint dst = m68ki_read_8(ea); uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1(); FLAG_V = ~res; /* Undefined V behavior */ if(res > 9) res += 6; res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst); FLAG_X = FLAG_C = (res > 0x99) << 8; if(FLAG_C) res -= 0xa0; FLAG_V &= res; /* Undefined V behavior part II */ FLAG_N = NFLAG_8(res); /* Undefined N behavior */ res = MASK_OUT_ABOVE_8(res); FLAG_Z |= res; m68ki_write_8(ea, res); } M68KMAKE_OP(add, 8, er, d) { uint* r_dst = &DX; uint src = MASK_OUT_ABOVE_8(DY); uint dst = MASK_OUT_ABOVE_8(*r_dst); uint res = src + dst; FLAG_N = NFLAG_8(res); FLAG_V = VFLAG_ADD_8(src, dst, res); FLAG_X = FLAG_C = CFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; } M68KMAKE_OP(add, 8, er, .) { uint* r_dst = &DX; uint src = M68KMAKE_GET_OPER_AY_8; uint dst = MASK_OUT_ABOVE_8(*r_dst); uint res = src + dst; FLAG_N = NFLAG_8(res); FLAG_V = VFLAG_ADD_8(src, dst, res); FLAG_X = FLAG_C = CFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; } M68KMAKE_OP(add, 16, er, d) { uint* r_dst = &DX; uint src = MASK_OUT_ABOVE_16(DY); uint dst = MASK_OUT_ABOVE_16(*r_dst); uint res = src + dst; FLAG_N = NFLAG_16(res); FLAG_V = VFLAG_ADD_16(src, dst, res); FLAG_X = FLAG_C = CFLAG_16(res); FLAG_Z = MASK_OUT_ABOVE_16(res); *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; } M68KMAKE_OP(add, 16, er, a) { uint* r_dst = &DX; uint src = MASK_OUT_ABOVE_16(AY); uint dst = MASK_OUT_ABOVE_16(*r_dst); uint res = src + dst; FLAG_N = NFLAG_16(res); FLAG_V = VFLAG_ADD_16(src, dst, res); FLAG_X = FLAG_C = CFLAG_16(res); FLAG_Z = MASK_OUT_ABOVE_16(res); *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; } M68KMAKE_OP(add, 16, er, .) { uint* r_dst = &DX; uint src = M68KMAKE_GET_OPER_AY_16; uint dst = MASK_OUT_ABOVE_16(*r_dst); uint res = src + dst; FLAG_N = NFLAG_16(res); FLAG_V = VFLAG_ADD_16(src, dst, res); FLAG_X = FLAG_C = CFLAG_16(res); FLAG_Z = MASK_OUT_ABOVE_16(res); *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; } M68KMAKE_OP(add, 32, er, d) { uint* r_dst = &DX; uint src = DY; uint dst = *r_dst; uint res = src + dst; FLAG_N = NFLAG_32(res); FLAG_V = VFLAG_ADD_32(src, dst, res); FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); FLAG_Z = MASK_OUT_ABOVE_32(res); *r_dst = FLAG_Z; } M68KMAKE_OP(add, 32, er, a) { uint* r_dst = &DX; uint src = AY; uint dst = *r_dst; uint res = src + dst; FLAG_N = NFLAG_32(res); FLAG_V = VFLAG_ADD_32(src, dst, res); FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); FLAG_Z = MASK_OUT_ABOVE_32(res); *r_dst = FLAG_Z; } M68KMAKE_OP(add, 32, er, .) { uint* r_dst = &DX; uint src = M68KMAKE_GET_OPER_AY_32; uint dst = *r_dst; uint res = src + dst; FLAG_N = NFLAG_32(res); FLAG_V = VFLAG_ADD_32(src, dst, res); FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); FLAG_Z = MASK_OUT_ABOVE_32(res); *r_dst = FLAG_Z; } M68KMAKE_OP(add, 8, re, .) { uint ea = M68KMAKE_GET_EA_AY_8; uint src = MASK_OUT_ABOVE_8(DX); uint dst = m68ki_read_8(ea); uint res = src + dst; FLAG_N = NFLAG_8(res); FLAG_V = VFLAG_ADD_8(src, dst, res); FLAG_X = FLAG_C = CFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); m68ki_write_8(ea, FLAG_Z); } M68KMAKE_OP(add, 16, re, .) { uint ea = M68KMAKE_GET_EA_AY_16; uint src = MASK_OUT_ABOVE_16(DX); uint dst = m68ki_read_16(ea); uint res = src + dst; FLAG_N = NFLAG_16(res); FLAG_V = VFLAG_ADD_16(src, dst, res); FLAG_X = FLAG_C = CFLAG_16(res); FLAG_Z = MASK_OUT_ABOVE_16(res); m68ki_write_16(ea, FLAG_Z); } M68KMAKE_OP(add, 32, re, .) { uint ea = M68KMAKE_GET_EA_AY_32; uint src = DX; uint dst = m68ki_read_32(ea); uint res = src + dst; FLAG_N = NFLAG_32(res); FLAG_V = VFLAG_ADD_32(src, dst, res); FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); FLAG_Z = MASK_OUT_ABOVE_32(res); m68ki_write_32(ea, FLAG_Z); } M68KMAKE_OP(adda, 16, ., d) { uint* r_dst = &AX; *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(DY)); } M68KMAKE_OP(adda, 16, ., a) { uint* r_dst = &AX; *r_dst = MASK_OUT_ABOVE_32(*r_dst + MAKE_INT_16(AY)); } M68KMAKE_OP(adda, 16, ., .) { signed short src = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16); uint* r_dst = &AX; *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); } M68KMAKE_OP(adda, 32, ., d) { uint* r_dst = &AX; *r_dst = MASK_OUT_ABOVE_32(*r_dst + DY); } M68KMAKE_OP(adda, 32, ., a) { uint* r_dst = &AX; *r_dst = MASK_OUT_ABOVE_32(*r_dst + AY); } M68KMAKE_OP(adda, 32, ., .) { uint src = M68KMAKE_GET_OPER_AY_32; uint* r_dst = &AX; *r_dst = MASK_OUT_ABOVE_32(*r_dst + src); } M68KMAKE_OP(addi, 8, ., d) { uint* r_dst = &DY; uint src = OPER_I_8(); uint dst = MASK_OUT_ABOVE_8(*r_dst); uint res = src + dst; FLAG_N = NFLAG_8(res); FLAG_V = VFLAG_ADD_8(src, dst, res); FLAG_X = FLAG_C = CFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; } M68KMAKE_OP(addi, 8, ., .) { uint src = OPER_I_8(); uint ea = M68KMAKE_GET_EA_AY_8; uint dst = m68ki_read_8(ea); uint res = src + dst; FLAG_N = NFLAG_8(res); FLAG_V = VFLAG_ADD_8(src, dst, res); FLAG_X = FLAG_C = CFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); m68ki_write_8(ea, FLAG_Z); } M68KMAKE_OP(addi, 16, ., d) { uint* r_dst = &DY; uint src = OPER_I_16(); uint dst = MASK_OUT_ABOVE_16(*r_dst); uint res = src + dst; FLAG_N = NFLAG_16(res); FLAG_V = VFLAG_ADD_16(src, dst, res); FLAG_X = FLAG_C = CFLAG_16(res); FLAG_Z = MASK_OUT_ABOVE_16(res); *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; } M68KMAKE_OP(addi, 16, ., .) { uint src = OPER_I_16(); uint ea = M68KMAKE_GET_EA_AY_16; uint dst = m68ki_read_16(ea); uint res = src + dst; FLAG_N = NFLAG_16(res); FLAG_V = VFLAG_ADD_16(src, dst, res); FLAG_X = FLAG_C = CFLAG_16(res); FLAG_Z = MASK_OUT_ABOVE_16(res); m68ki_write_16(ea, FLAG_Z); } M68KMAKE_OP(addi, 32, ., d) { uint* r_dst = &DY; uint src = OPER_I_32(); uint dst = *r_dst; uint res = src + dst; FLAG_N = NFLAG_32(res); FLAG_V = VFLAG_ADD_32(src, dst, res); FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); FLAG_Z = MASK_OUT_ABOVE_32(res); *r_dst = FLAG_Z; } M68KMAKE_OP(addi, 32, ., .) { uint src = OPER_I_32(); uint ea = M68KMAKE_GET_EA_AY_32; uint dst = m68ki_read_32(ea); uint res = src + dst; FLAG_N = NFLAG_32(res); FLAG_V = VFLAG_ADD_32(src, dst, res); FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); FLAG_Z = MASK_OUT_ABOVE_32(res); m68ki_write_32(ea, FLAG_Z); } M68KMAKE_OP(addq, 8, ., d) { uint* r_dst = &DY; uint src = (((REG_IR >> 9) - 1) & 7) + 1; uint dst = MASK_OUT_ABOVE_8(*r_dst); uint res = src + dst; FLAG_N = NFLAG_8(res); FLAG_V = VFLAG_ADD_8(src, dst, res); FLAG_X = FLAG_C = CFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; } M68KMAKE_OP(addq, 8, ., .) { uint src = (((REG_IR >> 9) - 1) & 7) + 1; uint ea = M68KMAKE_GET_EA_AY_8; uint dst = m68ki_read_8(ea); uint res = src + dst; FLAG_N = NFLAG_8(res); FLAG_V = VFLAG_ADD_8(src, dst, res); FLAG_X = FLAG_C = CFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); m68ki_write_8(ea, FLAG_Z); } M68KMAKE_OP(addq, 16, ., d) { uint* r_dst = &DY; uint src = (((REG_IR >> 9) - 1) & 7) + 1; uint dst = MASK_OUT_ABOVE_16(*r_dst); uint res = src + dst; FLAG_N = NFLAG_16(res); FLAG_V = VFLAG_ADD_16(src, dst, res); FLAG_X = FLAG_C = CFLAG_16(res); FLAG_Z = MASK_OUT_ABOVE_16(res); *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; } M68KMAKE_OP(addq, 16, ., a) { uint* r_dst = &AY; *r_dst = MASK_OUT_ABOVE_32(*r_dst + (((REG_IR >> 9) - 1) & 7) + 1); } M68KMAKE_OP(addq, 16, ., .) { uint src = (((REG_IR >> 9) - 1) & 7) + 1; uint ea = M68KMAKE_GET_EA_AY_16; uint dst = m68ki_read_16(ea); uint res = src + dst; FLAG_N = NFLAG_16(res); FLAG_V = VFLAG_ADD_16(src, dst, res); FLAG_X = FLAG_C = CFLAG_16(res); FLAG_Z = MASK_OUT_ABOVE_16(res); m68ki_write_16(ea, FLAG_Z); } M68KMAKE_OP(addq, 32, ., d) { uint* r_dst = &DY; uint src = (((REG_IR >> 9) - 1) & 7) + 1; uint dst = *r_dst; uint res = src + dst; FLAG_N = NFLAG_32(res); FLAG_V = VFLAG_ADD_32(src, dst, res); FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); FLAG_Z = MASK_OUT_ABOVE_32(res); *r_dst = FLAG_Z; } M68KMAKE_OP(addq, 32, ., a) { uint* r_dst = &AY; *r_dst = MASK_OUT_ABOVE_32(*r_dst + (((REG_IR >> 9) - 1) & 7) + 1); } M68KMAKE_OP(addq, 32, ., .) { uint src = (((REG_IR >> 9) - 1) & 7) + 1; uint ea = M68KMAKE_GET_EA_AY_32; uint dst = m68ki_read_32(ea); uint res = src + dst; FLAG_N = NFLAG_32(res); FLAG_V = VFLAG_ADD_32(src, dst, res); FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); FLAG_Z = MASK_OUT_ABOVE_32(res); m68ki_write_32(ea, FLAG_Z); } M68KMAKE_OP(addx, 8, rr, .) { uint* r_dst = &DX; uint src = MASK_OUT_ABOVE_8(DY); uint dst = MASK_OUT_ABOVE_8(*r_dst); uint res = src + dst + XFLAG_AS_1(); FLAG_N = NFLAG_8(res); FLAG_V = VFLAG_ADD_8(src, dst, res); FLAG_X = FLAG_C = CFLAG_8(res); res = MASK_OUT_ABOVE_8(res); FLAG_Z |= res; *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; } M68KMAKE_OP(addx, 16, rr, .) { uint* r_dst = &DX; uint src = MASK_OUT_ABOVE_16(DY); uint dst = MASK_OUT_ABOVE_16(*r_dst); uint res = src + dst + XFLAG_AS_1(); FLAG_N = NFLAG_16(res); FLAG_V = VFLAG_ADD_16(src, dst, res); FLAG_X = FLAG_C = CFLAG_16(res); res = MASK_OUT_ABOVE_16(res); FLAG_Z |= res; *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; } M68KMAKE_OP(addx, 32, rr, .) { uint* r_dst = &DX; uint src = DY; uint dst = *r_dst; uint res = src + dst + XFLAG_AS_1(); FLAG_N = NFLAG_32(res); FLAG_V = VFLAG_ADD_32(src, dst, res); FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); res = MASK_OUT_ABOVE_32(res); FLAG_Z |= res; *r_dst = res; } M68KMAKE_OP(addx, 8, mm, ax7) { uint src = OPER_AY_PD_8(); uint ea = EA_A7_PD_8(); uint dst = m68ki_read_8(ea); uint res = src + dst + XFLAG_AS_1(); FLAG_N = NFLAG_8(res); FLAG_V = VFLAG_ADD_8(src, dst, res); FLAG_X = FLAG_C = CFLAG_8(res); res = MASK_OUT_ABOVE_8(res); FLAG_Z |= res; m68ki_write_8(ea, res); } M68KMAKE_OP(addx, 8, mm, ay7) { uint src = OPER_A7_PD_8(); uint ea = EA_AX_PD_8(); uint dst = m68ki_read_8(ea); uint res = src + dst + XFLAG_AS_1(); FLAG_N = NFLAG_8(res); FLAG_V = VFLAG_ADD_8(src, dst, res); FLAG_X = FLAG_C = CFLAG_8(res); res = MASK_OUT_ABOVE_8(res); FLAG_Z |= res; m68ki_write_8(ea, res); } M68KMAKE_OP(addx, 8, mm, axy7) { uint src = OPER_A7_PD_8(); uint ea = EA_A7_PD_8(); uint dst = m68ki_read_8(ea); uint res = src + dst + XFLAG_AS_1(); FLAG_N = NFLAG_8(res); FLAG_V = VFLAG_ADD_8(src, dst, res); FLAG_X = FLAG_C = CFLAG_8(res); res = MASK_OUT_ABOVE_8(res); FLAG_Z |= res; m68ki_write_8(ea, res); } M68KMAKE_OP(addx, 8, mm, .) { uint src = OPER_AY_PD_8(); uint ea = EA_AX_PD_8(); uint dst = m68ki_read_8(ea); uint res = src + dst + XFLAG_AS_1(); FLAG_N = NFLAG_8(res); FLAG_V = VFLAG_ADD_8(src, dst, res); FLAG_X = FLAG_C = CFLAG_8(res); res = MASK_OUT_ABOVE_8(res); FLAG_Z |= res; m68ki_write_8(ea, res); } M68KMAKE_OP(addx, 16, mm, .) { uint src = OPER_AY_PD_16(); uint ea = EA_AX_PD_16(); uint dst = m68ki_read_16(ea); uint res = src + dst + XFLAG_AS_1(); FLAG_N = NFLAG_16(res); FLAG_V = VFLAG_ADD_16(src, dst, res); FLAG_X = FLAG_C = CFLAG_16(res); res = MASK_OUT_ABOVE_16(res); FLAG_Z |= res; m68ki_write_16(ea, res); } M68KMAKE_OP(addx, 32, mm, .) { uint src = OPER_AY_PD_32(); uint ea = EA_AX_PD_32(); uint dst = m68ki_read_32(ea); uint res = src + dst + XFLAG_AS_1(); FLAG_N = NFLAG_32(res); FLAG_V = VFLAG_ADD_32(src, dst, res); FLAG_X = FLAG_C = CFLAG_ADD_32(src, dst, res); res = MASK_OUT_ABOVE_32(res); FLAG_Z |= res; m68ki_write_32(ea, res); } M68KMAKE_OP(and, 8, er, d) { FLAG_Z = MASK_OUT_ABOVE_8(DX &= (DY | 0xffffff00)); FLAG_N = NFLAG_8(FLAG_Z); FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(and, 8, er, .) { FLAG_Z = MASK_OUT_ABOVE_8(DX &= (M68KMAKE_GET_OPER_AY_8 | 0xffffff00)); FLAG_N = NFLAG_8(FLAG_Z); FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(and, 16, er, d) { FLAG_Z = MASK_OUT_ABOVE_16(DX &= (DY | 0xffff0000)); FLAG_N = NFLAG_16(FLAG_Z); FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(and, 16, er, .) { FLAG_Z = MASK_OUT_ABOVE_16(DX &= (M68KMAKE_GET_OPER_AY_16 | 0xffff0000)); FLAG_N = NFLAG_16(FLAG_Z); FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(and, 32, er, d) { FLAG_Z = DX &= DY; FLAG_N = NFLAG_32(FLAG_Z); FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(and, 32, er, .) { FLAG_Z = DX &= M68KMAKE_GET_OPER_AY_32; FLAG_N = NFLAG_32(FLAG_Z); FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(and, 8, re, .) { uint ea = M68KMAKE_GET_EA_AY_8; uint res = DX & m68ki_read_8(ea); FLAG_N = NFLAG_8(res); FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; FLAG_Z = MASK_OUT_ABOVE_8(res); m68ki_write_8(ea, FLAG_Z); } M68KMAKE_OP(and, 16, re, .) { uint ea = M68KMAKE_GET_EA_AY_16; uint res = DX & m68ki_read_16(ea); FLAG_N = NFLAG_16(res); FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; FLAG_Z = MASK_OUT_ABOVE_16(res); m68ki_write_16(ea, FLAG_Z); } M68KMAKE_OP(and, 32, re, .) { uint ea = M68KMAKE_GET_EA_AY_32; uint res = DX & m68ki_read_32(ea); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; m68ki_write_32(ea, res); } M68KMAKE_OP(andi, 8, ., d) { FLAG_Z = MASK_OUT_ABOVE_8(DY &= (OPER_I_8() | 0xffffff00)); FLAG_N = NFLAG_8(FLAG_Z); FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(andi, 8, ., .) { uint src = OPER_I_8(); uint ea = M68KMAKE_GET_EA_AY_8; uint res = src & m68ki_read_8(ea); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; m68ki_write_8(ea, res); } M68KMAKE_OP(andi, 16, ., d) { FLAG_Z = MASK_OUT_ABOVE_16(DY &= (OPER_I_16() | 0xffff0000)); FLAG_N = NFLAG_16(FLAG_Z); FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(andi, 16, ., .) { uint src = OPER_I_16(); uint ea = M68KMAKE_GET_EA_AY_16; uint res = src & m68ki_read_16(ea); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; m68ki_write_16(ea, res); } M68KMAKE_OP(andi, 32, ., d) { FLAG_Z = DY &= (OPER_I_32()); FLAG_N = NFLAG_32(FLAG_Z); FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(andi, 32, ., .) { uint src = OPER_I_32(); uint ea = M68KMAKE_GET_EA_AY_32; uint res = src & m68ki_read_32(ea); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; m68ki_write_32(ea, res); } M68KMAKE_OP(andi, 16, toc, .) { m68ki_set_ccr(m68ki_get_ccr() & OPER_I_16()); } M68KMAKE_OP(andi, 16, tos, .) { if(FLAG_S) { uint src = OPER_I_16(); m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ m68ki_set_sr(m68ki_get_sr() & src); return; } m68ki_exception_privilege_violation(); } M68KMAKE_OP(asr, 8, s, .) { uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint src = MASK_OUT_ABOVE_8(*r_dst); uint res = src >> shift; if(GET_MSB_8(src)) res |= m68ki_shift_8_table[shift]; *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_X = FLAG_C = src << (9-shift); } M68KMAKE_OP(asr, 16, s, .) { uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint src = MASK_OUT_ABOVE_16(*r_dst); uint res = src >> shift; if(GET_MSB_16(src)) res |= m68ki_shift_16_table[shift]; *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_X = FLAG_C = src << (9-shift); } M68KMAKE_OP(asr, 32, s, .) { uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint src = *r_dst; uint res = src >> shift; if(GET_MSB_32(src)) res |= m68ki_shift_32_table[shift]; *r_dst = res; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_X = FLAG_C = src << (9-shift); } M68KMAKE_OP(asr, 8, r, .) { uint* r_dst = &DY; uint shift = DX & 0x3f; uint src = MASK_OUT_ABOVE_8(*r_dst); uint res = src >> shift; if(shift != 0) { USE_CYCLES(shift<> shift; if(shift != 0) { USE_CYCLES(shift<> (shift - 1))<<8; FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; return; } if(GET_MSB_16(src)) { *r_dst |= 0xffff; FLAG_C = CFLAG_SET; FLAG_X = XFLAG_SET; FLAG_N = NFLAG_SET; FLAG_Z = ZFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; return; } *r_dst &= 0xffff0000; FLAG_C = CFLAG_CLEAR; FLAG_X = XFLAG_CLEAR; FLAG_N = NFLAG_CLEAR; FLAG_Z = ZFLAG_SET; FLAG_V = VFLAG_CLEAR; return; } FLAG_C = CFLAG_CLEAR; FLAG_N = NFLAG_16(src); FLAG_Z = src; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(asr, 32, r, .) { uint* r_dst = &DY; uint shift = DX & 0x3f; uint src = *r_dst; uint res = src >> shift; if(shift != 0) { USE_CYCLES(shift<> (shift - 1))<<8; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; return; } if(GET_MSB_32(src)) { *r_dst = 0xffffffff; FLAG_C = CFLAG_SET; FLAG_X = XFLAG_SET; FLAG_N = NFLAG_SET; FLAG_Z = ZFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; return; } *r_dst = 0; FLAG_C = CFLAG_CLEAR; FLAG_X = XFLAG_CLEAR; FLAG_N = NFLAG_CLEAR; FLAG_Z = ZFLAG_SET; FLAG_V = VFLAG_CLEAR; return; } FLAG_C = CFLAG_CLEAR; FLAG_N = NFLAG_32(src); FLAG_Z = src; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(asr, 16, ., .) { uint ea = M68KMAKE_GET_EA_AY_16; uint src = m68ki_read_16(ea); uint res = src >> 1; if(GET_MSB_16(src)) res |= 0x8000; m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = FLAG_X = src << 8; } M68KMAKE_OP(asl, 8, s, .) { uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint src = MASK_OUT_ABOVE_8(*r_dst); uint res = MASK_OUT_ABOVE_8(src << shift); *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; FLAG_X = FLAG_C = src << shift; FLAG_N = NFLAG_8(res); FLAG_Z = res; src &= m68ki_shift_8_table[shift + 1]; FLAG_V = (!(src == 0 || (src == m68ki_shift_8_table[shift + 1] && shift < 8)))<<7; } M68KMAKE_OP(asl, 16, s, .) { uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint src = MASK_OUT_ABOVE_16(*r_dst); uint res = MASK_OUT_ABOVE_16(src << shift); *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_X = FLAG_C = src >> (8-shift); src &= m68ki_shift_16_table[shift + 1]; FLAG_V = (!(src == 0 || src == m68ki_shift_16_table[shift + 1]))<<7; } M68KMAKE_OP(asl, 32, s, .) { uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint src = *r_dst; uint res = MASK_OUT_ABOVE_32(src << shift); *r_dst = res; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_X = FLAG_C = src >> (24-shift); src &= m68ki_shift_32_table[shift + 1]; FLAG_V = (!(src == 0 || src == m68ki_shift_32_table[shift + 1]))<<7; } M68KMAKE_OP(asl, 8, r, .) { uint* r_dst = &DY; uint shift = DX & 0x3f; uint src = MASK_OUT_ABOVE_8(*r_dst); uint res = MASK_OUT_ABOVE_8(src << shift); if(shift != 0) { USE_CYCLES(shift<> 8; FLAG_N = NFLAG_16(res); FLAG_Z = res; src &= m68ki_shift_16_table[shift + 1]; FLAG_V = (!(src == 0 || src == m68ki_shift_16_table[shift + 1]))<<7; return; } *r_dst &= 0xffff0000; FLAG_X = FLAG_C = ((shift == 16 ? src & 1 : 0))<<8; FLAG_N = NFLAG_CLEAR; FLAG_Z = ZFLAG_SET; FLAG_V = (!(src == 0))<<7; return; } FLAG_C = CFLAG_CLEAR; FLAG_N = NFLAG_16(src); FLAG_Z = src; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(asl, 32, r, .) { uint* r_dst = &DY; uint shift = DX & 0x3f; uint src = *r_dst; uint res = MASK_OUT_ABOVE_32(src << shift); if(shift != 0) { USE_CYCLES(shift<> (32 - shift)) << 8; FLAG_N = NFLAG_32(res); FLAG_Z = res; src &= m68ki_shift_32_table[shift + 1]; FLAG_V = (!(src == 0 || src == m68ki_shift_32_table[shift + 1]))<<7; return; } *r_dst = 0; FLAG_X = FLAG_C = ((shift == 32 ? src & 1 : 0))<<8; FLAG_N = NFLAG_CLEAR; FLAG_Z = ZFLAG_SET; FLAG_V = (!(src == 0))<<7; return; } FLAG_C = CFLAG_CLEAR; FLAG_N = NFLAG_32(src); FLAG_Z = src; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(asl, 16, ., .) { uint ea = M68KMAKE_GET_EA_AY_16; uint src = m68ki_read_16(ea); uint res = MASK_OUT_ABOVE_16(src << 1); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_X = FLAG_C = src >> 7; src &= 0xc000; FLAG_V = (!(src == 0 || src == 0xc000))<<7; } M68KMAKE_OP(bcc, 8, ., .) { if(M68KMAKE_CC) { m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); return; } USE_CYCLES(CYC_BCC_NOTAKE_B); } M68KMAKE_OP(bcc, 16, ., .) { if(M68KMAKE_CC) { uint offset = OPER_I_16(); REG_PC -= 2; m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ m68ki_branch_16(offset); return; } REG_PC += 2; USE_CYCLES(CYC_BCC_NOTAKE_W); } M68KMAKE_OP(bcc, 32, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { if(M68KMAKE_CC) { uint offset = OPER_I_32(); REG_PC -= 4; m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ m68ki_branch_32(offset); return; } REG_PC += 4; return; } m68ki_exception_illegal(); } M68KMAKE_OP(bchg, 32, r, d) { uint* r_dst = &DY; uint mask = 1 << (DX & 0x1f); FLAG_Z = *r_dst & mask; *r_dst ^= mask; } M68KMAKE_OP(bchg, 8, r, .) { uint ea = M68KMAKE_GET_EA_AY_8; uint src = m68ki_read_8(ea); uint mask = 1 << (DX & 7); FLAG_Z = src & mask; m68ki_write_8(ea, src ^ mask); } M68KMAKE_OP(bchg, 32, s, d) { uint* r_dst = &DY; uint mask = 1 << (OPER_I_8() & 0x1f); FLAG_Z = *r_dst & mask; *r_dst ^= mask; } M68KMAKE_OP(bchg, 8, s, .) { uint mask = 1 << (OPER_I_8() & 7); uint ea = M68KMAKE_GET_EA_AY_8; uint src = m68ki_read_8(ea); FLAG_Z = src & mask; m68ki_write_8(ea, src ^ mask); } M68KMAKE_OP(bclr, 32, r, d) { uint* r_dst = &DY; uint mask = 1 << (DX & 0x1f); FLAG_Z = *r_dst & mask; *r_dst &= ~mask; } M68KMAKE_OP(bclr, 8, r, .) { uint ea = M68KMAKE_GET_EA_AY_8; uint src = m68ki_read_8(ea); uint mask = 1 << (DX & 7); FLAG_Z = src & mask; m68ki_write_8(ea, src & ~mask); } M68KMAKE_OP(bclr, 32, s, d) { uint* r_dst = &DY; uint mask = 1 << (OPER_I_8() & 0x1f); FLAG_Z = *r_dst & mask; *r_dst &= ~mask; } M68KMAKE_OP(bclr, 8, s, .) { uint mask = 1 << (OPER_I_8() & 7); uint ea = M68KMAKE_GET_EA_AY_8; uint src = m68ki_read_8(ea); FLAG_Z = src & mask; m68ki_write_8(ea, src & ~mask); } M68KMAKE_OP(bfchg, 32, ., d) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint offset = (word2>>6)&31; uint width = word2; uint* data = &DY; uint64 mask; if(BIT_B(word2)) offset = REG_D[offset&7]; if(BIT_5(word2)) width = REG_D[width&7]; offset &= 31; width = ((width-1) & 31) + 1; mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); mask = ROR_32(mask, offset); FLAG_N = NFLAG_32(*data<>6)&31; uint width = word2; uint mask_base; uint data_long; uint mask_long; uint data_byte = 0; uint mask_byte = 0; uint ea = M68KMAKE_GET_EA_AY_8; if(BIT_B(word2)) offset = MAKE_INT_32(REG_D[offset&7]); if(BIT_5(word2)) width = REG_D[width&7]; /* Offset is signed so we have to use ugly math =( */ ea += offset / 8; offset %= 8; if(offset < 0) { offset += 8; ea--; } width = ((width-1) & 31) + 1; mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); mask_long = mask_base >> offset; data_long = m68ki_read_32(ea); FLAG_N = NFLAG_32(data_long << offset); FLAG_Z = data_long & mask_long; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; m68ki_write_32(ea, data_long ^ mask_long); if((width + offset) > 32) { mask_byte = MASK_OUT_ABOVE_8(mask_base); data_byte = m68ki_read_8(ea+4); FLAG_Z |= (data_byte & mask_byte); m68ki_write_8(ea+4, data_byte ^ mask_byte); } return; } m68ki_exception_illegal(); } M68KMAKE_OP(bfclr, 32, ., d) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint offset = (word2>>6)&31; uint width = word2; uint* data = &DY; uint64 mask; if(BIT_B(word2)) offset = REG_D[offset&7]; if(BIT_5(word2)) width = REG_D[width&7]; offset &= 31; width = ((width-1) & 31) + 1; mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); mask = ROR_32(mask, offset); FLAG_N = NFLAG_32(*data<>6)&31; uint width = word2; uint mask_base; uint data_long; uint mask_long; uint data_byte = 0; uint mask_byte = 0; uint ea = M68KMAKE_GET_EA_AY_8; if(BIT_B(word2)) offset = MAKE_INT_32(REG_D[offset&7]); if(BIT_5(word2)) width = REG_D[width&7]; /* Offset is signed so we have to use ugly math =( */ ea += offset / 8; offset %= 8; if(offset < 0) { offset += 8; ea--; } width = ((width-1) & 31) + 1; mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); mask_long = mask_base >> offset; data_long = m68ki_read_32(ea); FLAG_N = NFLAG_32(data_long << offset); FLAG_Z = data_long & mask_long; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; m68ki_write_32(ea, data_long & ~mask_long); if((width + offset) > 32) { mask_byte = MASK_OUT_ABOVE_8(mask_base); data_byte = m68ki_read_8(ea+4); FLAG_Z |= (data_byte & mask_byte); m68ki_write_8(ea+4, data_byte & ~mask_byte); } return; } m68ki_exception_illegal(); } M68KMAKE_OP(bfexts, 32, ., d) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint offset = (word2>>6)&31; uint width = word2; uint64 data = DY; if(BIT_B(word2)) offset = REG_D[offset&7]; if(BIT_5(word2)) width = REG_D[width&7]; offset &= 31; width = ((width-1) & 31) + 1; data = ROL_32(data, offset); FLAG_N = NFLAG_32(data); data = MAKE_INT_32(data) >> (32 - width); FLAG_Z = data; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; REG_D[(word2>>12)&7] = data; return; } m68ki_exception_illegal(); } M68KMAKE_OP(bfexts, 32, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); sint offset = (word2>>6)&31; uint width = word2; uint data; uint ea = M68KMAKE_GET_EA_AY_8; if(BIT_B(word2)) offset = MAKE_INT_32(REG_D[offset&7]); if(BIT_5(word2)) width = REG_D[width&7]; /* Offset is signed so we have to use ugly math =( */ ea += offset / 8; offset %= 8; if(offset < 0) { offset += 8; ea--; } width = ((width-1) & 31) + 1; data = m68ki_read_32(ea); data = MASK_OUT_ABOVE_32(data< 32) data |= (m68ki_read_8(ea+4) << offset) >> 8; FLAG_N = NFLAG_32(data); data = MAKE_INT_32(data) >> (32 - width); FLAG_Z = data; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; REG_D[(word2 >> 12) & 7] = data; return; } m68ki_exception_illegal(); } M68KMAKE_OP(bfextu, 32, ., d) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint offset = (word2>>6)&31; uint width = word2; uint64 data = DY; if(BIT_B(word2)) offset = REG_D[offset&7]; if(BIT_5(word2)) width = REG_D[width&7]; offset &= 31; width = ((width-1) & 31) + 1; data = ROL_32(data, offset); FLAG_N = NFLAG_32(data); data >>= 32 - width; FLAG_Z = data; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; REG_D[(word2>>12)&7] = data; return; } m68ki_exception_illegal(); } M68KMAKE_OP(bfextu, 32, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); sint offset = (word2>>6)&31; uint width = word2; uint data; uint ea = M68KMAKE_GET_EA_AY_8; if(BIT_B(word2)) offset = MAKE_INT_32(REG_D[offset&7]); if(BIT_5(word2)) width = REG_D[width&7]; /* Offset is signed so we have to use ugly math =( */ ea += offset / 8; offset %= 8; if(offset < 0) { offset += 8; ea--; } width = ((width-1) & 31) + 1; data = m68ki_read_32(ea); data = MASK_OUT_ABOVE_32(data< 32) data |= (m68ki_read_8(ea+4) << offset) >> 8; FLAG_N = NFLAG_32(data); data >>= (32 - width); FLAG_Z = data; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; REG_D[(word2 >> 12) & 7] = data; return; } m68ki_exception_illegal(); } M68KMAKE_OP(bfffo, 32, ., d) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint offset = (word2>>6)&31; uint width = word2; uint64 data = DY; uint bit; if(BIT_B(word2)) offset = REG_D[offset&7]; if(BIT_5(word2)) width = REG_D[width&7]; offset &= 31; width = ((width-1) & 31) + 1; data = ROL_32(data, offset); FLAG_N = NFLAG_32(data); data >>= 32 - width; FLAG_Z = data; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1) offset++; REG_D[(word2>>12)&7] = offset; return; } m68ki_exception_illegal(); } M68KMAKE_OP(bfffo, 32, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); sint offset = (word2>>6)&31; sint local_offset; uint width = word2; uint data; uint bit; uint ea = M68KMAKE_GET_EA_AY_8; if(BIT_B(word2)) offset = MAKE_INT_32(REG_D[offset&7]); if(BIT_5(word2)) width = REG_D[width&7]; /* Offset is signed so we have to use ugly math =( */ ea += offset / 8; local_offset = offset % 8; if(local_offset < 0) { local_offset += 8; ea--; } width = ((width-1) & 31) + 1; data = m68ki_read_32(ea); data = MASK_OUT_ABOVE_32(data< 32) data |= (m68ki_read_8(ea+4) << local_offset) >> 8; FLAG_N = NFLAG_32(data); data >>= (32 - width); FLAG_Z = data; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; for(bit = 1<<(width-1);bit && !(data & bit);bit>>= 1) offset++; REG_D[(word2>>12)&7] = offset; return; } m68ki_exception_illegal(); } M68KMAKE_OP(bfins, 32, ., d) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint offset = (word2>>6)&31; uint width = word2; uint* data = &DY; uint64 mask; uint64 insert = REG_D[(word2>>12)&7]; if(BIT_B(word2)) offset = REG_D[offset&7]; if(BIT_5(word2)) width = REG_D[width&7]; offset &= 31; width = ((width-1) & 31) + 1; mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); mask = ROR_32(mask, offset); insert = MASK_OUT_ABOVE_32(insert << (32 - width)); FLAG_N = NFLAG_32(insert); FLAG_Z = insert; insert = ROR_32(insert, offset); FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; *data &= ~mask; *data |= insert; return; } m68ki_exception_illegal(); } M68KMAKE_OP(bfins, 32, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); sint offset = (word2>>6)&31; uint width = word2; uint insert_base = REG_D[(word2>>12)&7]; uint insert_long; uint insert_byte; uint mask_base; uint data_long; uint mask_long; uint data_byte = 0; uint mask_byte = 0; uint ea = M68KMAKE_GET_EA_AY_8; if(BIT_B(word2)) offset = MAKE_INT_32(REG_D[offset&7]); if(BIT_5(word2)) width = REG_D[width&7]; /* Offset is signed so we have to use ugly math =( */ ea += offset / 8; offset %= 8; if(offset < 0) { offset += 8; ea--; } width = ((width-1) & 31) + 1; mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); mask_long = mask_base >> offset; insert_base = MASK_OUT_ABOVE_32(insert_base << (32 - width)); FLAG_N = NFLAG_32(insert_base); FLAG_Z = insert_base; insert_long = insert_base >> offset; data_long = m68ki_read_32(ea); FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; m68ki_write_32(ea, (data_long & ~mask_long) | insert_long); if((width + offset) > 32) { mask_byte = MASK_OUT_ABOVE_8(mask_base); insert_byte = MASK_OUT_ABOVE_8(insert_base); data_byte = m68ki_read_8(ea+4); FLAG_Z |= (data_byte & mask_byte); m68ki_write_8(ea+4, (data_byte & ~mask_byte) | insert_byte); } return; } m68ki_exception_illegal(); } M68KMAKE_OP(bfset, 32, ., d) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint offset = (word2>>6)&31; uint width = word2; uint* data = &DY; uint64 mask; if(BIT_B(word2)) offset = REG_D[offset&7]; if(BIT_5(word2)) width = REG_D[width&7]; offset &= 31; width = ((width-1) & 31) + 1; mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); mask = ROR_32(mask, offset); FLAG_N = NFLAG_32(*data<>6)&31; uint width = word2; uint mask_base; uint data_long; uint mask_long; uint data_byte = 0; uint mask_byte = 0; uint ea = M68KMAKE_GET_EA_AY_8; if(BIT_B(word2)) offset = MAKE_INT_32(REG_D[offset&7]); if(BIT_5(word2)) width = REG_D[width&7]; /* Offset is signed so we have to use ugly math =( */ ea += offset / 8; offset %= 8; if(offset < 0) { offset += 8; ea--; } width = ((width-1) & 31) + 1; mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); mask_long = mask_base >> offset; data_long = m68ki_read_32(ea); FLAG_N = NFLAG_32(data_long << offset); FLAG_Z = data_long & mask_long; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; m68ki_write_32(ea, data_long | mask_long); if((width + offset) > 32) { mask_byte = MASK_OUT_ABOVE_8(mask_base); data_byte = m68ki_read_8(ea+4); FLAG_Z |= (data_byte & mask_byte); m68ki_write_8(ea+4, data_byte | mask_byte); } return; } m68ki_exception_illegal(); } M68KMAKE_OP(bftst, 32, ., d) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint offset = (word2>>6)&31; uint width = word2; uint* data = &DY; uint64 mask; if(BIT_B(word2)) offset = REG_D[offset&7]; if(BIT_5(word2)) width = REG_D[width&7]; offset &= 31; width = ((width-1) & 31) + 1; mask = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); mask = ROR_32(mask, offset); FLAG_N = NFLAG_32(*data<>6)&31; uint width = word2; uint mask_base; uint data_long; uint mask_long; uint data_byte = 0; uint mask_byte = 0; uint ea = M68KMAKE_GET_EA_AY_8; if(BIT_B(word2)) offset = MAKE_INT_32(REG_D[offset&7]); if(BIT_5(word2)) width = REG_D[width&7]; /* Offset is signed so we have to use ugly math =( */ ea += offset / 8; offset %= 8; if(offset < 0) { offset += 8; ea--; } width = ((width-1) & 31) + 1; mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width)); mask_long = mask_base >> offset; data_long = m68ki_read_32(ea); FLAG_N = ((data_long & (0x80000000 >> offset))<>24; FLAG_Z = data_long & mask_long; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; if((width + offset) > 32) { mask_byte = MASK_OUT_ABOVE_8(mask_base); data_byte = m68ki_read_8(ea+4); FLAG_Z |= (data_byte & mask_byte); } return; } m68ki_exception_illegal(); } M68KMAKE_OP(bkpt, 0, ., .) { if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) { m68ki_bkpt_ack(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE) ? REG_IR & 7 : 0); /* auto-disable (see m68kcpu.h) */ } m68ki_exception_illegal(); } M68KMAKE_OP(bra, 8, ., .) { m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); if(REG_PC == REG_PPC) USE_ALL_CYCLES(); } M68KMAKE_OP(bra, 16, ., .) { uint offset = OPER_I_16(); REG_PC -= 2; m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ m68ki_branch_16(offset); if(REG_PC == REG_PPC) USE_ALL_CYCLES(); } M68KMAKE_OP(bra, 32, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint offset = OPER_I_32(); REG_PC -= 4; m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ m68ki_branch_32(offset); if(REG_PC == REG_PPC) USE_ALL_CYCLES(); return; } m68ki_exception_illegal(); } M68KMAKE_OP(bset, 32, r, d) { uint* r_dst = &DY; uint mask = 1 << (DX & 0x1f); FLAG_Z = *r_dst & mask; *r_dst |= mask; } M68KMAKE_OP(bset, 8, r, .) { uint ea = M68KMAKE_GET_EA_AY_8; uint src = m68ki_read_8(ea); uint mask = 1 << (DX & 7); FLAG_Z = src & mask; m68ki_write_8(ea, src | mask); } M68KMAKE_OP(bset, 32, s, d) { uint* r_dst = &DY; uint mask = 1 << (OPER_I_8() & 0x1f); FLAG_Z = *r_dst & mask; *r_dst |= mask; } M68KMAKE_OP(bset, 8, s, .) { uint mask = 1 << (OPER_I_8() & 7); uint ea = M68KMAKE_GET_EA_AY_8; uint src = m68ki_read_8(ea); FLAG_Z = src & mask; m68ki_write_8(ea, src | mask); } M68KMAKE_OP(bsr, 8, ., .) { m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ m68ki_push_32(REG_PC); m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR)); } M68KMAKE_OP(bsr, 16, ., .) { uint offset = OPER_I_16(); m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ m68ki_push_32(REG_PC); REG_PC -= 2; m68ki_branch_16(offset); } M68KMAKE_OP(bsr, 32, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint offset = OPER_I_32(); m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ m68ki_push_32(REG_PC); REG_PC -= 4; m68ki_branch_32(offset); return; } m68ki_exception_illegal(); } M68KMAKE_OP(btst, 32, r, d) { FLAG_Z = DY & (1 << (DX & 0x1f)); } M68KMAKE_OP(btst, 8, r, .) { FLAG_Z = M68KMAKE_GET_OPER_AY_8 & (1 << (DX & 7)); } M68KMAKE_OP(btst, 32, s, d) { FLAG_Z = DY & (1 << (OPER_I_8() & 0x1f)); } M68KMAKE_OP(btst, 8, s, .) { uint bit = OPER_I_8() & 7; FLAG_Z = M68KMAKE_GET_OPER_AY_8 & (1 << bit); } M68KMAKE_OP(callm, 32, ., .) { /* note: watch out for pcrelative modes */ if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) { uint ea = M68KMAKE_GET_EA_AY_32; m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ REG_PC += 2; (void)ea; /* just to avoid an 'unused variable' warning */ M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); return; } m68ki_exception_illegal(); } M68KMAKE_OP(cas, 8, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint ea = M68KMAKE_GET_EA_AY_8; uint dest = m68ki_read_8(ea); uint* compare = ®_D[word2 & 7]; uint res = dest - MASK_OUT_ABOVE_8(*compare); m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ FLAG_N = NFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); FLAG_V = VFLAG_SUB_8(*compare, dest, res); FLAG_C = CFLAG_8(res); if(COND_NE()) *compare = MASK_OUT_BELOW_8(*compare) | dest; else { USE_CYCLES(3); m68ki_write_8(ea, MASK_OUT_ABOVE_8(REG_D[(word2 >> 6) & 7])); } return; } m68ki_exception_illegal(); } M68KMAKE_OP(cas, 16, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint ea = M68KMAKE_GET_EA_AY_16; uint dest = m68ki_read_16(ea); uint* compare = ®_D[word2 & 7]; uint res = dest - MASK_OUT_ABOVE_16(*compare); m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ FLAG_N = NFLAG_16(res); FLAG_Z = MASK_OUT_ABOVE_16(res); FLAG_V = VFLAG_SUB_16(*compare, dest, res); FLAG_C = CFLAG_16(res); if(COND_NE()) *compare = MASK_OUT_BELOW_16(*compare) | dest; else { USE_CYCLES(3); m68ki_write_16(ea, MASK_OUT_ABOVE_16(REG_D[(word2 >> 6) & 7])); } return; } m68ki_exception_illegal(); } M68KMAKE_OP(cas, 32, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint ea = M68KMAKE_GET_EA_AY_32; uint dest = m68ki_read_32(ea); uint* compare = ®_D[word2 & 7]; uint res = dest - *compare; m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ FLAG_N = NFLAG_32(res); FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_V = VFLAG_SUB_32(*compare, dest, res); FLAG_C = CFLAG_SUB_32(*compare, dest, res); if(COND_NE()) *compare = dest; else { USE_CYCLES(3); m68ki_write_32(ea, REG_D[(word2 >> 6) & 7]); } return; } m68ki_exception_illegal(); } M68KMAKE_OP(cas2, 16, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_32(); uint* compare1 = ®_D[(word2 >> 16) & 7]; uint ea1 = REG_DA[(word2 >> 28) & 15]; uint dest1 = m68ki_read_16(ea1); uint res1 = dest1 - MASK_OUT_ABOVE_16(*compare1); uint* compare2 = ®_D[word2 & 7]; uint ea2 = REG_DA[(word2 >> 12) & 15]; uint dest2 = m68ki_read_16(ea2); uint res2; m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ FLAG_N = NFLAG_16(res1); FLAG_Z = MASK_OUT_ABOVE_16(res1); FLAG_V = VFLAG_SUB_16(*compare1, dest1, res1); FLAG_C = CFLAG_16(res1); if(COND_EQ()) { res2 = dest2 - MASK_OUT_ABOVE_16(*compare2); FLAG_N = NFLAG_16(res2); FLAG_Z = MASK_OUT_ABOVE_16(res2); FLAG_V = VFLAG_SUB_16(*compare2, dest2, res2); FLAG_C = CFLAG_16(res2); if(COND_EQ()) { USE_CYCLES(3); m68ki_write_16(ea1, REG_D[(word2 >> 22) & 7]); m68ki_write_16(ea2, REG_D[(word2 >> 6) & 7]); return; } } *compare1 = BIT_1F(word2) ? MAKE_INT_16(dest1) : MASK_OUT_BELOW_16(*compare1) | dest1; *compare2 = BIT_F(word2) ? MAKE_INT_16(dest2) : MASK_OUT_BELOW_16(*compare2) | dest2; return; } m68ki_exception_illegal(); } M68KMAKE_OP(cas2, 32, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_32(); uint* compare1 = ®_D[(word2 >> 16) & 7]; uint ea1 = REG_DA[(word2 >> 28) & 15]; uint dest1 = m68ki_read_32(ea1); uint res1 = dest1 - *compare1; uint* compare2 = ®_D[word2 & 7]; uint ea2 = REG_DA[(word2 >> 12) & 15]; uint dest2 = m68ki_read_32(ea2); uint res2; m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ FLAG_N = NFLAG_32(res1); FLAG_Z = MASK_OUT_ABOVE_32(res1); FLAG_V = VFLAG_SUB_32(*compare1, dest1, res1); FLAG_C = CFLAG_SUB_32(*compare1, dest1, res1); if(COND_EQ()) { res2 = dest2 - *compare2; FLAG_N = NFLAG_32(res2); FLAG_Z = MASK_OUT_ABOVE_32(res2); FLAG_V = VFLAG_SUB_32(*compare2, dest2, res2); FLAG_C = CFLAG_SUB_32(*compare2, dest2, res2); if(COND_EQ()) { USE_CYCLES(3); m68ki_write_32(ea1, REG_D[(word2 >> 22) & 7]); m68ki_write_32(ea2, REG_D[(word2 >> 6) & 7]); return; } } *compare1 = dest1; *compare2 = dest2; return; } m68ki_exception_illegal(); } M68KMAKE_OP(chk, 16, ., d) { sint src = MAKE_INT_16(DX); sint bound = MAKE_INT_16(DY); FLAG_Z = ZFLAG_16(src); /* Undocumented */ FLAG_V = VFLAG_CLEAR; /* Undocumented */ FLAG_C = CFLAG_CLEAR; /* Undocumented */ if(src >= 0 && src <= bound) { return; } FLAG_N = (src < 0)<<7; m68ki_exception_trap(EXCEPTION_CHK); } M68KMAKE_OP(chk, 16, ., .) { sint src = MAKE_INT_16(DX); sint bound = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16); FLAG_Z = ZFLAG_16(src); /* Undocumented */ FLAG_V = VFLAG_CLEAR; /* Undocumented */ FLAG_C = CFLAG_CLEAR; /* Undocumented */ if(src >= 0 && src <= bound) { return; } FLAG_N = (src < 0)<<7; m68ki_exception_trap(EXCEPTION_CHK); } M68KMAKE_OP(chk, 32, ., d) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { sint src = MAKE_INT_32(DX); sint bound = MAKE_INT_32(DY); FLAG_Z = ZFLAG_32(src); /* Undocumented */ FLAG_V = VFLAG_CLEAR; /* Undocumented */ FLAG_C = CFLAG_CLEAR; /* Undocumented */ if(src >= 0 && src <= bound) { return; } FLAG_N = (src < 0)<<7; m68ki_exception_trap(EXCEPTION_CHK); return; } m68ki_exception_illegal(); } M68KMAKE_OP(chk, 32, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { sint src = MAKE_INT_32(DX); sint bound = MAKE_INT_32(M68KMAKE_GET_OPER_AY_32); FLAG_Z = ZFLAG_32(src); /* Undocumented */ FLAG_V = VFLAG_CLEAR; /* Undocumented */ FLAG_C = CFLAG_CLEAR; /* Undocumented */ if(src >= 0 && src <= bound) { return; } FLAG_N = (src < 0)<<7; m68ki_exception_trap(EXCEPTION_CHK); return; } m68ki_exception_illegal(); } M68KMAKE_OP(chk2cmp2, 8, ., pcdi) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint compare = REG_DA[(word2 >> 12) & 15]&0xff; uint ea = EA_PCDI_8(); uint lower_bound = m68ki_read_pcrel_8(ea); uint upper_bound = m68ki_read_pcrel_8(ea + 1); if(!BIT_F(word2)) FLAG_C = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); else FLAG_C = compare - lower_bound; FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); if(COND_CS()) { if(BIT_B(word2)) m68ki_exception_trap(EXCEPTION_CHK); return; } FLAG_C = upper_bound - compare; if(COND_CS() && BIT_B(word2)) m68ki_exception_trap(EXCEPTION_CHK); return; } m68ki_exception_illegal(); } M68KMAKE_OP(chk2cmp2, 8, ., pcix) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint compare = REG_DA[(word2 >> 12) & 15]&0xff; uint ea = EA_PCIX_8(); uint lower_bound = m68ki_read_pcrel_8(ea); uint upper_bound = m68ki_read_pcrel_8(ea + 1); if(!BIT_F(word2)) FLAG_C = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); else FLAG_C = compare - lower_bound; FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); if(COND_CS()) { if(BIT_B(word2)) m68ki_exception_trap(EXCEPTION_CHK); return; } FLAG_C = upper_bound - compare; if(COND_CS() && BIT_B(word2)) m68ki_exception_trap(EXCEPTION_CHK); return; } m68ki_exception_illegal(); } M68KMAKE_OP(chk2cmp2, 8, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint compare = REG_DA[(word2 >> 12) & 15]&0xff; uint ea = M68KMAKE_GET_EA_AY_8; uint lower_bound = m68ki_read_8(ea); uint upper_bound = m68ki_read_8(ea + 1); if(!BIT_F(word2)) FLAG_C = MAKE_INT_8(compare) - MAKE_INT_8(lower_bound); else FLAG_C = compare - lower_bound; FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); if(COND_CS()) { if(BIT_B(word2)) m68ki_exception_trap(EXCEPTION_CHK); return; } FLAG_C = upper_bound - compare; if(COND_CS() && BIT_B(word2)) m68ki_exception_trap(EXCEPTION_CHK); return; } m68ki_exception_illegal(); } M68KMAKE_OP(chk2cmp2, 16, ., pcdi) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint compare = REG_DA[(word2 >> 12) & 15]&0xffff; uint ea = EA_PCDI_16(); uint lower_bound = m68ki_read_pcrel_16(ea); uint upper_bound = m68ki_read_pcrel_16(ea + 2); if(!BIT_F(word2)) FLAG_C = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); else FLAG_C = compare - lower_bound; FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); FLAG_C = CFLAG_16(FLAG_C); if(COND_CS()) { if(BIT_B(word2)) m68ki_exception_trap(EXCEPTION_CHK); return; } if(!BIT_F(word2)) FLAG_C = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); else FLAG_C = upper_bound - compare; FLAG_C = CFLAG_16(FLAG_C); if(COND_CS() && BIT_B(word2)) m68ki_exception_trap(EXCEPTION_CHK); return; } m68ki_exception_illegal(); } M68KMAKE_OP(chk2cmp2, 16, ., pcix) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint compare = REG_DA[(word2 >> 12) & 15]&0xffff; uint ea = EA_PCIX_16(); uint lower_bound = m68ki_read_pcrel_16(ea); uint upper_bound = m68ki_read_pcrel_16(ea + 2); if(!BIT_F(word2)) FLAG_C = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); else FLAG_C = compare - lower_bound; FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); FLAG_C = CFLAG_16(FLAG_C); if(COND_CS()) { if(BIT_B(word2)) m68ki_exception_trap(EXCEPTION_CHK); return; } if(!BIT_F(word2)) FLAG_C = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); else FLAG_C = upper_bound - compare; FLAG_C = CFLAG_16(FLAG_C); if(COND_CS() && BIT_B(word2)) m68ki_exception_trap(EXCEPTION_CHK); return; } m68ki_exception_illegal(); } M68KMAKE_OP(chk2cmp2, 16, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint compare = REG_DA[(word2 >> 12) & 15]&0xffff; uint ea = M68KMAKE_GET_EA_AY_16; uint lower_bound = m68ki_read_16(ea); uint upper_bound = m68ki_read_16(ea + 2); if(!BIT_F(word2)) FLAG_C = MAKE_INT_16(compare) - MAKE_INT_16(lower_bound); else FLAG_C = compare - lower_bound; FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); FLAG_C = CFLAG_16(FLAG_C); if(COND_CS()) { if(BIT_B(word2)) m68ki_exception_trap(EXCEPTION_CHK); return; } if(!BIT_F(word2)) FLAG_C = MAKE_INT_16(upper_bound) - MAKE_INT_16(compare); else FLAG_C = upper_bound - compare; FLAG_C = CFLAG_16(FLAG_C); if(COND_CS() && BIT_B(word2)) m68ki_exception_trap(EXCEPTION_CHK); return; } m68ki_exception_illegal(); } M68KMAKE_OP(chk2cmp2, 32, ., pcdi) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint compare = REG_DA[(word2 >> 12) & 15]; uint ea = EA_PCDI_32(); uint lower_bound = m68ki_read_pcrel_32(ea); uint upper_bound = m68ki_read_pcrel_32(ea + 4); FLAG_C = compare - lower_bound; FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); FLAG_C = CFLAG_SUB_32(lower_bound, compare, FLAG_C); if(COND_CS()) { if(BIT_B(word2)) m68ki_exception_trap(EXCEPTION_CHK); return; } FLAG_C = upper_bound - compare; FLAG_C = CFLAG_SUB_32(compare, upper_bound, FLAG_C); if(COND_CS() && BIT_B(word2)) m68ki_exception_trap(EXCEPTION_CHK); return; } m68ki_exception_illegal(); } M68KMAKE_OP(chk2cmp2, 32, ., pcix) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint compare = REG_DA[(word2 >> 12) & 15]; uint ea = EA_PCIX_32(); uint lower_bound = m68ki_read_pcrel_32(ea); uint upper_bound = m68ki_read_pcrel_32(ea + 4); FLAG_C = compare - lower_bound; FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); FLAG_C = CFLAG_SUB_32(lower_bound, compare, FLAG_C); if(COND_CS()) { if(BIT_B(word2)) m68ki_exception_trap(EXCEPTION_CHK); return; } FLAG_C = upper_bound - compare; FLAG_C = CFLAG_SUB_32(compare, upper_bound, FLAG_C); if(COND_CS() && BIT_B(word2)) m68ki_exception_trap(EXCEPTION_CHK); return; } m68ki_exception_illegal(); } M68KMAKE_OP(chk2cmp2, 32, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint compare = REG_DA[(word2 >> 12) & 15]; uint ea = M68KMAKE_GET_EA_AY_32; uint lower_bound = m68ki_read_32(ea); uint upper_bound = m68ki_read_32(ea + 4); FLAG_C = compare - lower_bound; FLAG_Z = !((upper_bound==compare) | (lower_bound==compare)); FLAG_C = CFLAG_SUB_32(lower_bound, compare, FLAG_C); if(COND_CS()) { if(BIT_B(word2)) m68ki_exception_trap(EXCEPTION_CHK); return; } FLAG_C = upper_bound - compare; FLAG_C = CFLAG_SUB_32(compare, upper_bound, FLAG_C); if(COND_CS() && BIT_B(word2)) m68ki_exception_trap(EXCEPTION_CHK); return; } m68ki_exception_illegal(); } M68KMAKE_OP(clr, 8, ., d) { DY &= 0xffffff00; FLAG_N = NFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; FLAG_Z = ZFLAG_SET; } M68KMAKE_OP(clr, 8, ., .) { m68ki_write_8(M68KMAKE_GET_EA_AY_8, 0); FLAG_N = NFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; FLAG_Z = ZFLAG_SET; } M68KMAKE_OP(clr, 16, ., d) { DY &= 0xffff0000; FLAG_N = NFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; FLAG_Z = ZFLAG_SET; } M68KMAKE_OP(clr, 16, ., .) { m68ki_write_16(M68KMAKE_GET_EA_AY_16, 0); FLAG_N = NFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; FLAG_Z = ZFLAG_SET; } M68KMAKE_OP(clr, 32, ., d) { DY = 0; FLAG_N = NFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; FLAG_Z = ZFLAG_SET; } M68KMAKE_OP(clr, 32, ., .) { m68ki_write_32(M68KMAKE_GET_EA_AY_32, 0); FLAG_N = NFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; FLAG_Z = ZFLAG_SET; } M68KMAKE_OP(cmp, 8, ., d) { uint src = MASK_OUT_ABOVE_8(DY); uint dst = MASK_OUT_ABOVE_8(DX); uint res = dst - src; FLAG_N = NFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); FLAG_V = VFLAG_SUB_8(src, dst, res); FLAG_C = CFLAG_8(res); } M68KMAKE_OP(cmp, 8, ., .) { uint src = M68KMAKE_GET_OPER_AY_8; uint dst = MASK_OUT_ABOVE_8(DX); uint res = dst - src; FLAG_N = NFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); FLAG_V = VFLAG_SUB_8(src, dst, res); FLAG_C = CFLAG_8(res); } M68KMAKE_OP(cmp, 16, ., d) { uint src = MASK_OUT_ABOVE_16(DY); uint dst = MASK_OUT_ABOVE_16(DX); uint res = dst - src; FLAG_N = NFLAG_16(res); FLAG_Z = MASK_OUT_ABOVE_16(res); FLAG_V = VFLAG_SUB_16(src, dst, res); FLAG_C = CFLAG_16(res); } M68KMAKE_OP(cmp, 16, ., a) { uint src = MASK_OUT_ABOVE_16(AY); uint dst = MASK_OUT_ABOVE_16(DX); uint res = dst - src; FLAG_N = NFLAG_16(res); FLAG_Z = MASK_OUT_ABOVE_16(res); FLAG_V = VFLAG_SUB_16(src, dst, res); FLAG_C = CFLAG_16(res); } M68KMAKE_OP(cmp, 16, ., .) { uint src = M68KMAKE_GET_OPER_AY_16; uint dst = MASK_OUT_ABOVE_16(DX); uint res = dst - src; FLAG_N = NFLAG_16(res); FLAG_Z = MASK_OUT_ABOVE_16(res); FLAG_V = VFLAG_SUB_16(src, dst, res); FLAG_C = CFLAG_16(res); } M68KMAKE_OP(cmp, 32, ., d) { uint src = DY; uint dst = DX; uint res = dst - src; FLAG_N = NFLAG_32(res); FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_V = VFLAG_SUB_32(src, dst, res); FLAG_C = CFLAG_SUB_32(src, dst, res); } M68KMAKE_OP(cmp, 32, ., a) { uint src = AY; uint dst = DX; uint res = dst - src; FLAG_N = NFLAG_32(res); FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_V = VFLAG_SUB_32(src, dst, res); FLAG_C = CFLAG_SUB_32(src, dst, res); } M68KMAKE_OP(cmp, 32, ., .) { uint src = M68KMAKE_GET_OPER_AY_32; uint dst = DX; uint res = dst - src; FLAG_N = NFLAG_32(res); FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_V = VFLAG_SUB_32(src, dst, res); FLAG_C = CFLAG_SUB_32(src, dst, res); } M68KMAKE_OP(cmpa, 16, ., d) { uint src = MAKE_INT_16(DY); uint dst = AX; uint res = dst - src; FLAG_N = NFLAG_32(res); FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_V = VFLAG_SUB_32(src, dst, res); FLAG_C = CFLAG_SUB_32(src, dst, res); } M68KMAKE_OP(cmpa, 16, ., a) { uint src = MAKE_INT_16(AY); uint dst = AX; uint res = dst - src; FLAG_N = NFLAG_32(res); FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_V = VFLAG_SUB_32(src, dst, res); FLAG_C = CFLAG_SUB_32(src, dst, res); } M68KMAKE_OP(cmpa, 16, ., .) { uint src = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16); uint dst = AX; uint res = dst - src; FLAG_N = NFLAG_32(res); FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_V = VFLAG_SUB_32(src, dst, res); FLAG_C = CFLAG_SUB_32(src, dst, res); } M68KMAKE_OP(cmpa, 32, ., d) { uint src = DY; uint dst = AX; uint res = dst - src; FLAG_N = NFLAG_32(res); FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_V = VFLAG_SUB_32(src, dst, res); FLAG_C = CFLAG_SUB_32(src, dst, res); } M68KMAKE_OP(cmpa, 32, ., a) { uint src = AY; uint dst = AX; uint res = dst - src; FLAG_N = NFLAG_32(res); FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_V = VFLAG_SUB_32(src, dst, res); FLAG_C = CFLAG_SUB_32(src, dst, res); } M68KMAKE_OP(cmpa, 32, ., .) { uint src = M68KMAKE_GET_OPER_AY_32; uint dst = AX; uint res = dst - src; FLAG_N = NFLAG_32(res); FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_V = VFLAG_SUB_32(src, dst, res); FLAG_C = CFLAG_SUB_32(src, dst, res); } M68KMAKE_OP(cmpi, 8, ., d) { uint src = OPER_I_8(); uint dst = MASK_OUT_ABOVE_8(DY); uint res = dst - src; FLAG_N = NFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); FLAG_V = VFLAG_SUB_8(src, dst, res); FLAG_C = CFLAG_8(res); } M68KMAKE_OP(cmpi, 8, ., .) { uint src = OPER_I_8(); uint dst = M68KMAKE_GET_OPER_AY_8; uint res = dst - src; FLAG_N = NFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); FLAG_V = VFLAG_SUB_8(src, dst, res); FLAG_C = CFLAG_8(res); } M68KMAKE_OP(cmpi, 8, ., pcdi) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint src = OPER_I_8(); uint dst = OPER_PCDI_8(); uint res = dst - src; FLAG_N = NFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); FLAG_V = VFLAG_SUB_8(src, dst, res); FLAG_C = CFLAG_8(res); return; } m68ki_exception_illegal(); } M68KMAKE_OP(cmpi, 8, ., pcix) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint src = OPER_I_8(); uint dst = OPER_PCIX_8(); uint res = dst - src; FLAG_N = NFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); FLAG_V = VFLAG_SUB_8(src, dst, res); FLAG_C = CFLAG_8(res); return; } m68ki_exception_illegal(); } M68KMAKE_OP(cmpi, 16, ., d) { uint src = OPER_I_16(); uint dst = MASK_OUT_ABOVE_16(DY); uint res = dst - src; FLAG_N = NFLAG_16(res); FLAG_Z = MASK_OUT_ABOVE_16(res); FLAG_V = VFLAG_SUB_16(src, dst, res); FLAG_C = CFLAG_16(res); } M68KMAKE_OP(cmpi, 16, ., .) { uint src = OPER_I_16(); uint dst = M68KMAKE_GET_OPER_AY_16; uint res = dst - src; FLAG_N = NFLAG_16(res); FLAG_Z = MASK_OUT_ABOVE_16(res); FLAG_V = VFLAG_SUB_16(src, dst, res); FLAG_C = CFLAG_16(res); } M68KMAKE_OP(cmpi, 16, ., pcdi) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint src = OPER_I_16(); uint dst = OPER_PCDI_16(); uint res = dst - src; FLAG_N = NFLAG_16(res); FLAG_Z = MASK_OUT_ABOVE_16(res); FLAG_V = VFLAG_SUB_16(src, dst, res); FLAG_C = CFLAG_16(res); return; } m68ki_exception_illegal(); } M68KMAKE_OP(cmpi, 16, ., pcix) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint src = OPER_I_16(); uint dst = OPER_PCIX_16(); uint res = dst - src; FLAG_N = NFLAG_16(res); FLAG_Z = MASK_OUT_ABOVE_16(res); FLAG_V = VFLAG_SUB_16(src, dst, res); FLAG_C = CFLAG_16(res); return; } m68ki_exception_illegal(); } M68KMAKE_OP(cmpi, 32, ., d) { uint src = OPER_I_32(); uint dst = DY; uint res = dst - src; FLAG_N = NFLAG_32(res); FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_V = VFLAG_SUB_32(src, dst, res); FLAG_C = CFLAG_SUB_32(src, dst, res); } M68KMAKE_OP(cmpi, 32, ., .) { uint src = OPER_I_32(); uint dst = M68KMAKE_GET_OPER_AY_32; uint res = dst - src; FLAG_N = NFLAG_32(res); FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_V = VFLAG_SUB_32(src, dst, res); FLAG_C = CFLAG_SUB_32(src, dst, res); } M68KMAKE_OP(cmpi, 32, ., pcdi) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint src = OPER_I_32(); uint dst = OPER_PCDI_32(); uint res = dst - src; FLAG_N = NFLAG_32(res); FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_V = VFLAG_SUB_32(src, dst, res); FLAG_C = CFLAG_SUB_32(src, dst, res); return; } m68ki_exception_illegal(); } M68KMAKE_OP(cmpi, 32, ., pcix) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint src = OPER_I_32(); uint dst = OPER_PCIX_32(); uint res = dst - src; FLAG_N = NFLAG_32(res); FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_V = VFLAG_SUB_32(src, dst, res); FLAG_C = CFLAG_SUB_32(src, dst, res); return; } m68ki_exception_illegal(); } M68KMAKE_OP(cmpm, 8, ., ax7) { uint src = OPER_AY_PI_8(); uint dst = OPER_A7_PI_8(); uint res = dst - src; FLAG_N = NFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); FLAG_V = VFLAG_SUB_8(src, dst, res); FLAG_C = CFLAG_8(res); } M68KMAKE_OP(cmpm, 8, ., ay7) { uint src = OPER_A7_PI_8(); uint dst = OPER_AX_PI_8(); uint res = dst - src; FLAG_N = NFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); FLAG_V = VFLAG_SUB_8(src, dst, res); FLAG_C = CFLAG_8(res); } M68KMAKE_OP(cmpm, 8, ., axy7) { uint src = OPER_A7_PI_8(); uint dst = OPER_A7_PI_8(); uint res = dst - src; FLAG_N = NFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); FLAG_V = VFLAG_SUB_8(src, dst, res); FLAG_C = CFLAG_8(res); } M68KMAKE_OP(cmpm, 8, ., .) { uint src = OPER_AY_PI_8(); uint dst = OPER_AX_PI_8(); uint res = dst - src; FLAG_N = NFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); FLAG_V = VFLAG_SUB_8(src, dst, res); FLAG_C = CFLAG_8(res); } M68KMAKE_OP(cmpm, 16, ., .) { uint src = OPER_AY_PI_16(); uint dst = OPER_AX_PI_16(); uint res = dst - src; FLAG_N = NFLAG_16(res); FLAG_Z = MASK_OUT_ABOVE_16(res); FLAG_V = VFLAG_SUB_16(src, dst, res); FLAG_C = CFLAG_16(res); } M68KMAKE_OP(cmpm, 32, ., .) { uint src = OPER_AY_PI_32(); uint dst = OPER_AX_PI_32(); uint res = dst - src; FLAG_N = NFLAG_32(res); FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_V = VFLAG_SUB_32(src, dst, res); FLAG_C = CFLAG_SUB_32(src, dst, res); } M68KMAKE_OP(cpbcc, 32, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); return; } m68ki_exception_1111(); } M68KMAKE_OP(cpdbcc, 32, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); return; } m68ki_exception_1111(); } M68KMAKE_OP(cpgen, 32, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); return; } m68ki_exception_1111(); } M68KMAKE_OP(cpscc, 32, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); return; } m68ki_exception_1111(); } M68KMAKE_OP(cptrapcc, 32, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); return; } m68ki_exception_1111(); } M68KMAKE_OP(dbt, 16, ., .) { REG_PC += 2; } M68KMAKE_OP(dbf, 16, ., .) { uint* r_dst = &DY; uint res = MASK_OUT_ABOVE_16(*r_dst - 1); *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; if(res != 0xffff) { uint offset = OPER_I_16(); REG_PC -= 2; m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ m68ki_branch_16(offset); USE_CYCLES(CYC_DBCC_F_NOEXP); return; } REG_PC += 2; USE_CYCLES(CYC_DBCC_F_EXP); } M68KMAKE_OP(dbcc, 16, ., .) { if(M68KMAKE_NOT_CC) { uint* r_dst = &DY; uint res = MASK_OUT_ABOVE_16(*r_dst - 1); *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; if(res != 0xffff) { uint offset = OPER_I_16(); REG_PC -= 2; m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ m68ki_branch_16(offset); USE_CYCLES(CYC_DBCC_F_NOEXP); return; } REG_PC += 2; USE_CYCLES(CYC_DBCC_F_EXP); return; } REG_PC += 2; } M68KMAKE_OP(divs, 16, ., d) { uint* r_dst = &DX; sint src = MAKE_INT_16(DY); sint quotient; sint remainder; if(src != 0) { if((uint32)*r_dst == 0x80000000 && src == -1) { FLAG_Z = 0; FLAG_N = NFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; *r_dst = 0; return; } quotient = MAKE_INT_32(*r_dst) / src; remainder = MAKE_INT_32(*r_dst) % src; if(quotient == MAKE_INT_16(quotient)) { FLAG_Z = quotient; FLAG_N = NFLAG_16(quotient); FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); return; } FLAG_V = VFLAG_SET; return; } m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); } M68KMAKE_OP(divs, 16, ., .) { uint* r_dst = &DX; sint src = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16); sint quotient; sint remainder; if(src != 0) { if((uint32)*r_dst == 0x80000000 && src == -1) { FLAG_Z = 0; FLAG_N = NFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; *r_dst = 0; return; } quotient = MAKE_INT_32(*r_dst) / src; remainder = MAKE_INT_32(*r_dst) % src; if(quotient == MAKE_INT_16(quotient)) { FLAG_Z = quotient; FLAG_N = NFLAG_16(quotient); FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); return; } FLAG_V = VFLAG_SET; return; } m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); } M68KMAKE_OP(divu, 16, ., d) { uint* r_dst = &DX; uint src = MASK_OUT_ABOVE_16(DY); if(src != 0) { uint quotient = *r_dst / src; uint remainder = *r_dst % src; if(quotient < 0x10000) { FLAG_Z = quotient; FLAG_N = NFLAG_16(quotient); FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); return; } FLAG_V = VFLAG_SET; return; } m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); } M68KMAKE_OP(divu, 16, ., .) { uint* r_dst = &DX; uint src = M68KMAKE_GET_OPER_AY_16; if(src != 0) { uint quotient = *r_dst / src; uint remainder = *r_dst % src; if(quotient < 0x10000) { FLAG_Z = quotient; FLAG_N = NFLAG_16(quotient); FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; *r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16)); return; } FLAG_V = VFLAG_SET; return; } m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); } M68KMAKE_OP(divl, 32, ., d) { #if M68K_USE_64_BIT if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint64 divisor = DY; uint64 dividend = 0; uint64 quotient = 0; uint64 remainder = 0; if(divisor != 0) { if(BIT_A(word2)) /* 64 bit */ { dividend = REG_D[word2 & 7]; dividend <<= 32; dividend |= REG_D[(word2 >> 12) & 7]; if(BIT_B(word2)) /* signed */ { quotient = (uint64)((sint64)dividend / (sint64)((sint32)divisor)); remainder = (uint64)((sint64)dividend % (sint64)((sint32)divisor)); if((sint64)quotient != (sint64)((sint32)quotient)) { FLAG_V = VFLAG_SET; return; } } else /* unsigned */ { quotient = dividend / divisor; if(quotient > 0xffffffff) { FLAG_V = VFLAG_SET; return; } remainder = dividend % divisor; } } else /* 32 bit */ { dividend = REG_D[(word2 >> 12) & 7]; if(BIT_B(word2)) /* signed */ { quotient = (uint64)((sint64)((sint32)dividend) / (sint64)((sint32)divisor)); remainder = (uint64)((sint64)((sint32)dividend) % (sint64)((sint32)divisor)); } else /* unsigned */ { quotient = dividend / divisor; remainder = dividend % divisor; } } REG_D[word2 & 7] = remainder; REG_D[(word2 >> 12) & 7] = quotient; FLAG_N = NFLAG_32(quotient); FLAG_Z = quotient; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; return; } m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); return; } m68ki_exception_illegal(); #else if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint divisor = DY; uint dividend_hi = REG_D[word2 & 7]; uint dividend_lo = REG_D[(word2 >> 12) & 7]; uint quotient = 0; uint remainder = 0; uint dividend_neg = 0; uint divisor_neg = 0; sint i; uint overflow; if(divisor != 0) { /* quad / long : long quotient, long remainder */ if(BIT_A(word2)) { if(BIT_B(word2)) /* signed */ { /* special case in signed divide */ if(dividend_hi == 0 && dividend_lo == 0x80000000 && divisor == 0xffffffff) { REG_D[word2 & 7] = 0; REG_D[(word2 >> 12) & 7] = 0x80000000; FLAG_N = NFLAG_SET; FLAG_Z = ZFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; return; } if(GET_MSB_32(dividend_hi)) { dividend_neg = 1; dividend_hi = (uint)MASK_OUT_ABOVE_32((-(sint)dividend_hi) - (dividend_lo != 0)); dividend_lo = (uint)MASK_OUT_ABOVE_32(-(sint)dividend_lo); } if(GET_MSB_32(divisor)) { divisor_neg = 1; divisor = (uint)MASK_OUT_ABOVE_32(-(sint)divisor); } } /* if the upper long is greater than the divisor, we're overflowing. */ if(dividend_hi >= divisor) { FLAG_V = VFLAG_SET; return; } for(i = 31; i >= 0; i--) { quotient <<= 1; remainder = (remainder << 1) + ((dividend_hi >> i) & 1); if(remainder >= divisor) { remainder -= divisor; quotient++; } } for(i = 31; i >= 0; i--) { quotient <<= 1; overflow = GET_MSB_32(remainder); remainder = (remainder << 1) + ((dividend_lo >> i) & 1); if(remainder >= divisor || overflow) { remainder -= divisor; quotient++; } } if(BIT_B(word2)) /* signed */ { if(quotient > 0x7fffffff) { FLAG_V = VFLAG_SET; return; } if(dividend_neg) { remainder = (uint)MASK_OUT_ABOVE_32(-(sint)remainder); quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); } if(divisor_neg) quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); } REG_D[word2 & 7] = remainder; REG_D[(word2 >> 12) & 7] = quotient; FLAG_N = NFLAG_32(quotient); FLAG_Z = quotient; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; return; } /* long / long: long quotient, maybe long remainder */ if(BIT_B(word2)) /* signed */ { /* Special case in divide */ if(dividend_lo == 0x80000000 && divisor == 0xffffffff) { FLAG_N = NFLAG_SET; FLAG_Z = ZFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; REG_D[(word2 >> 12) & 7] = 0x80000000; REG_D[word2 & 7] = 0; return; } REG_D[word2 & 7] = MAKE_INT_32(dividend_lo) % MAKE_INT_32(divisor); quotient = REG_D[(word2 >> 12) & 7] = MAKE_INT_32(dividend_lo) / MAKE_INT_32(divisor); } else { REG_D[word2 & 7] = MASK_OUT_ABOVE_32(dividend_lo) % MASK_OUT_ABOVE_32(divisor); quotient = REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(dividend_lo) / MASK_OUT_ABOVE_32(divisor); } FLAG_N = NFLAG_32(quotient); FLAG_Z = quotient; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; return; } m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); return; } m68ki_exception_illegal(); #endif } M68KMAKE_OP(divl, 32, ., .) { #if M68K_USE_64_BIT if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint64 divisor = M68KMAKE_GET_OPER_AY_32; uint64 dividend = 0; uint64 quotient = 0; uint64 remainder = 0; if(divisor != 0) { if(BIT_A(word2)) /* 64 bit */ { dividend = REG_D[word2 & 7]; dividend <<= 32; dividend |= REG_D[(word2 >> 12) & 7]; if(BIT_B(word2)) /* signed */ { quotient = (uint64)((sint64)dividend / (sint64)((sint32)divisor)); remainder = (uint64)((sint64)dividend % (sint64)((sint32)divisor)); if((sint64)quotient != (sint64)((sint32)quotient)) { FLAG_V = VFLAG_SET; return; } } else /* unsigned */ { quotient = dividend / divisor; if(quotient > 0xffffffff) { FLAG_V = VFLAG_SET; return; } remainder = dividend % divisor; } } else /* 32 bit */ { dividend = REG_D[(word2 >> 12) & 7]; if(BIT_B(word2)) /* signed */ { quotient = (uint64)((sint64)((sint32)dividend) / (sint64)((sint32)divisor)); remainder = (uint64)((sint64)((sint32)dividend) % (sint64)((sint32)divisor)); } else /* unsigned */ { quotient = dividend / divisor; remainder = dividend % divisor; } } REG_D[word2 & 7] = remainder; REG_D[(word2 >> 12) & 7] = quotient; FLAG_N = NFLAG_32(quotient); FLAG_Z = quotient; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; return; } m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); return; } m68ki_exception_illegal(); #else if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint divisor = M68KMAKE_GET_OPER_AY_32; uint dividend_hi = REG_D[word2 & 7]; uint dividend_lo = REG_D[(word2 >> 12) & 7]; uint quotient = 0; uint remainder = 0; uint dividend_neg = 0; uint divisor_neg = 0; sint i; uint overflow; if(divisor != 0) { /* quad / long : long quotient, long remainder */ if(BIT_A(word2)) { if(BIT_B(word2)) /* signed */ { /* special case in signed divide */ if(dividend_hi == 0 && dividend_lo == 0x80000000 && divisor == 0xffffffff) { REG_D[word2 & 7] = 0; REG_D[(word2 >> 12) & 7] = 0x80000000; FLAG_N = NFLAG_SET; FLAG_Z = ZFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; return; } if(GET_MSB_32(dividend_hi)) { dividend_neg = 1; dividend_hi = (uint)MASK_OUT_ABOVE_32((-(sint)dividend_hi) - (dividend_lo != 0)); dividend_lo = (uint)MASK_OUT_ABOVE_32(-(sint)dividend_lo); } if(GET_MSB_32(divisor)) { divisor_neg = 1; divisor = (uint)MASK_OUT_ABOVE_32(-(sint)divisor); } } /* if the upper long is greater than the divisor, we're overflowing. */ if(dividend_hi >= divisor) { FLAG_V = VFLAG_SET; return; } for(i = 31; i >= 0; i--) { quotient <<= 1; remainder = (remainder << 1) + ((dividend_hi >> i) & 1); if(remainder >= divisor) { remainder -= divisor; quotient++; } } for(i = 31; i >= 0; i--) { quotient <<= 1; overflow = GET_MSB_32(remainder); remainder = (remainder << 1) + ((dividend_lo >> i) & 1); if(remainder >= divisor || overflow) { remainder -= divisor; quotient++; } } if(BIT_B(word2)) /* signed */ { if(quotient > 0x7fffffff) { FLAG_V = VFLAG_SET; return; } if(dividend_neg) { remainder = (uint)MASK_OUT_ABOVE_32(-(sint)remainder); quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); } if(divisor_neg) quotient = (uint)MASK_OUT_ABOVE_32(-(sint)quotient); } REG_D[word2 & 7] = remainder; REG_D[(word2 >> 12) & 7] = quotient; FLAG_N = NFLAG_32(quotient); FLAG_Z = quotient; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; return; } /* long / long: long quotient, maybe long remainder */ if(BIT_B(word2)) /* signed */ { /* Special case in divide */ if(dividend_lo == 0x80000000 && divisor == 0xffffffff) { FLAG_N = NFLAG_SET; FLAG_Z = ZFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; REG_D[(word2 >> 12) & 7] = 0x80000000; REG_D[word2 & 7] = 0; return; } REG_D[word2 & 7] = MAKE_INT_32(dividend_lo) % MAKE_INT_32(divisor); quotient = REG_D[(word2 >> 12) & 7] = MAKE_INT_32(dividend_lo) / MAKE_INT_32(divisor); } else { REG_D[word2 & 7] = MASK_OUT_ABOVE_32(dividend_lo) % MASK_OUT_ABOVE_32(divisor); quotient = REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(dividend_lo) / MASK_OUT_ABOVE_32(divisor); } FLAG_N = NFLAG_32(quotient); FLAG_Z = quotient; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; return; } m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE); return; } m68ki_exception_illegal(); #endif } M68KMAKE_OP(eor, 8, ., d) { uint res = MASK_OUT_ABOVE_8(DY ^= MASK_OUT_ABOVE_8(DX)); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(eor, 8, ., .) { uint ea = M68KMAKE_GET_EA_AY_8; uint res = MASK_OUT_ABOVE_8(DX ^ m68ki_read_8(ea)); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(eor, 16, ., d) { uint res = MASK_OUT_ABOVE_16(DY ^= MASK_OUT_ABOVE_16(DX)); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(eor, 16, ., .) { uint ea = M68KMAKE_GET_EA_AY_16; uint res = MASK_OUT_ABOVE_16(DX ^ m68ki_read_16(ea)); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(eor, 32, ., d) { uint res = DY ^= DX; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(eor, 32, ., .) { uint ea = M68KMAKE_GET_EA_AY_32; uint res = DX ^ m68ki_read_32(ea); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(eori, 8, ., d) { uint res = MASK_OUT_ABOVE_8(DY ^= OPER_I_8()); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(eori, 8, ., .) { uint src = OPER_I_8(); uint ea = M68KMAKE_GET_EA_AY_8; uint res = src ^ m68ki_read_8(ea); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(eori, 16, ., d) { uint res = MASK_OUT_ABOVE_16(DY ^= OPER_I_16()); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(eori, 16, ., .) { uint src = OPER_I_16(); uint ea = M68KMAKE_GET_EA_AY_16; uint res = src ^ m68ki_read_16(ea); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(eori, 32, ., d) { uint res = DY ^= OPER_I_32(); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(eori, 32, ., .) { uint src = OPER_I_32(); uint ea = M68KMAKE_GET_EA_AY_32; uint res = src ^ m68ki_read_32(ea); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(eori, 16, toc, .) { m68ki_set_ccr(m68ki_get_ccr() ^ OPER_I_16()); } M68KMAKE_OP(eori, 16, tos, .) { if(FLAG_S) { uint src = OPER_I_16(); m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ m68ki_set_sr(m68ki_get_sr() ^ src); return; } m68ki_exception_privilege_violation(); } M68KMAKE_OP(exg, 32, dd, .) { uint* reg_a = &DX; uint* reg_b = &DY; uint tmp = *reg_a; *reg_a = *reg_b; *reg_b = tmp; } M68KMAKE_OP(exg, 32, aa, .) { uint* reg_a = &AX; uint* reg_b = &AY; uint tmp = *reg_a; *reg_a = *reg_b; *reg_b = tmp; } M68KMAKE_OP(exg, 32, da, .) { uint* reg_a = &DX; uint* reg_b = &AY; uint tmp = *reg_a; *reg_a = *reg_b; *reg_b = tmp; } M68KMAKE_OP(ext, 16, ., .) { uint* r_dst = &DY; *r_dst = MASK_OUT_BELOW_16(*r_dst) | MASK_OUT_ABOVE_8(*r_dst) | (GET_MSB_8(*r_dst) ? 0xff00 : 0); FLAG_N = NFLAG_16(*r_dst); FLAG_Z = MASK_OUT_ABOVE_16(*r_dst); FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(ext, 32, ., .) { uint* r_dst = &DY; *r_dst = MASK_OUT_ABOVE_16(*r_dst) | (GET_MSB_16(*r_dst) ? 0xffff0000 : 0); FLAG_N = NFLAG_32(*r_dst); FLAG_Z = *r_dst; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(extb, 32, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint* r_dst = &DY; *r_dst = MASK_OUT_ABOVE_8(*r_dst) | (GET_MSB_8(*r_dst) ? 0xffffff00 : 0); FLAG_N = NFLAG_32(*r_dst); FLAG_Z = *r_dst; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; return; } m68ki_exception_illegal(); } M68KMAKE_OP(illegal, 0, ., .) { m68ki_exception_illegal(); } M68KMAKE_OP(jmp, 32, ., .) { m68ki_jump(M68KMAKE_GET_EA_AY_32); m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ if(REG_PC == REG_PPC) USE_ALL_CYCLES(); } M68KMAKE_OP(jsr, 32, ., .) { uint ea = M68KMAKE_GET_EA_AY_32; m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ m68ki_push_32(REG_PC); m68ki_jump(ea); } M68KMAKE_OP(lea, 32, ., .) { AX = M68KMAKE_GET_EA_AY_32; } M68KMAKE_OP(link, 16, ., a7) { REG_A[7] -= 4; m68ki_write_32(REG_A[7], REG_A[7]); REG_A[7] = MASK_OUT_ABOVE_32(REG_A[7] + MAKE_INT_16(OPER_I_16())); } M68KMAKE_OP(link, 16, ., .) { uint* r_dst = &AY; m68ki_push_32(*r_dst); *r_dst = REG_A[7]; REG_A[7] = MASK_OUT_ABOVE_32(REG_A[7] + MAKE_INT_16(OPER_I_16())); } M68KMAKE_OP(link, 32, ., a7) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { REG_A[7] -= 4; m68ki_write_32(REG_A[7], REG_A[7]); REG_A[7] = MASK_OUT_ABOVE_32(REG_A[7] + OPER_I_32()); return; } m68ki_exception_illegal(); } M68KMAKE_OP(link, 32, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint* r_dst = &AY; m68ki_push_32(*r_dst); *r_dst = REG_A[7]; REG_A[7] = MASK_OUT_ABOVE_32(REG_A[7] + OPER_I_32()); return; } m68ki_exception_illegal(); } M68KMAKE_OP(lsr, 8, s, .) { uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint src = MASK_OUT_ABOVE_8(*r_dst); uint res = src >> shift; *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; FLAG_N = NFLAG_CLEAR; FLAG_Z = res; FLAG_X = FLAG_C = src << (9-shift); FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(lsr, 16, s, .) { uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint src = MASK_OUT_ABOVE_16(*r_dst); uint res = src >> shift; *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; FLAG_N = NFLAG_CLEAR; FLAG_Z = res; FLAG_X = FLAG_C = src << (9-shift); FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(lsr, 32, s, .) { uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint src = *r_dst; uint res = src >> shift; *r_dst = res; FLAG_N = NFLAG_CLEAR; FLAG_Z = res; FLAG_X = FLAG_C = src << (9-shift); FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(lsr, 8, r, .) { uint* r_dst = &DY; uint shift = DX & 0x3f; uint src = MASK_OUT_ABOVE_8(*r_dst); uint res = src >> shift; if(shift != 0) { USE_CYCLES(shift<> shift; if(shift != 0) { USE_CYCLES(shift<> (shift - 1))<<8; FLAG_N = NFLAG_CLEAR; FLAG_Z = res; FLAG_V = VFLAG_CLEAR; return; } *r_dst &= 0xffff0000; FLAG_X = XFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; FLAG_N = NFLAG_CLEAR; FLAG_Z = ZFLAG_SET; FLAG_V = VFLAG_CLEAR; return; } FLAG_C = CFLAG_CLEAR; FLAG_N = NFLAG_16(src); FLAG_Z = src; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(lsr, 32, r, .) { uint* r_dst = &DY; uint shift = DX & 0x3f; uint src = *r_dst; uint res = src >> shift; if(shift != 0) { USE_CYCLES(shift<> (shift - 1))<<8; FLAG_N = NFLAG_CLEAR; FLAG_Z = res; FLAG_V = VFLAG_CLEAR; return; } *r_dst = 0; FLAG_X = FLAG_C = (shift == 32 ? GET_MSB_32(src)>>23 : 0); FLAG_N = NFLAG_CLEAR; FLAG_Z = ZFLAG_SET; FLAG_V = VFLAG_CLEAR; return; } FLAG_C = CFLAG_CLEAR; FLAG_N = NFLAG_32(src); FLAG_Z = src; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(lsr, 16, ., .) { uint ea = M68KMAKE_GET_EA_AY_16; uint src = m68ki_read_16(ea); uint res = src >> 1; m68ki_write_16(ea, res); FLAG_N = NFLAG_CLEAR; FLAG_Z = res; FLAG_C = FLAG_X = src << 8; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(lsl, 8, s, .) { uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint src = MASK_OUT_ABOVE_8(*r_dst); uint res = MASK_OUT_ABOVE_8(src << shift); *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_X = FLAG_C = src << shift; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(lsl, 16, s, .) { uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint src = MASK_OUT_ABOVE_16(*r_dst); uint res = MASK_OUT_ABOVE_16(src << shift); *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_X = FLAG_C = src >> (8-shift); FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(lsl, 32, s, .) { uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint src = *r_dst; uint res = MASK_OUT_ABOVE_32(src << shift); *r_dst = res; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_X = FLAG_C = src >> (24-shift); FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(lsl, 8, r, .) { uint* r_dst = &DY; uint shift = DX & 0x3f; uint src = MASK_OUT_ABOVE_8(*r_dst); uint res = MASK_OUT_ABOVE_8(src << shift); if(shift != 0) { USE_CYCLES(shift<> 8; FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; return; } *r_dst &= 0xffff0000; FLAG_X = XFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; FLAG_N = NFLAG_CLEAR; FLAG_Z = ZFLAG_SET; FLAG_V = VFLAG_CLEAR; return; } FLAG_C = CFLAG_CLEAR; FLAG_N = NFLAG_16(src); FLAG_Z = src; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(lsl, 32, r, .) { uint* r_dst = &DY; uint shift = DX & 0x3f; uint src = *r_dst; uint res = MASK_OUT_ABOVE_32(src << shift); if(shift != 0) { USE_CYCLES(shift<> (32 - shift)) << 8; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; return; } *r_dst = 0; FLAG_X = FLAG_C = ((shift == 32 ? src & 1 : 0))<<8; FLAG_N = NFLAG_CLEAR; FLAG_Z = ZFLAG_SET; FLAG_V = VFLAG_CLEAR; return; } FLAG_C = CFLAG_CLEAR; FLAG_N = NFLAG_32(src); FLAG_Z = src; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(lsl, 16, ., .) { uint ea = M68KMAKE_GET_EA_AY_16; uint src = m68ki_read_16(ea); uint res = MASK_OUT_ABOVE_16(src << 1); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_X = FLAG_C = src >> 7; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(move, 8, d, d) { uint res = MASK_OUT_ABOVE_8(DY); uint* r_dst = &DX; *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 8, d, .) { uint res = M68KMAKE_GET_OPER_AY_8; uint* r_dst = &DX; *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 8, ai, d) { uint res = MASK_OUT_ABOVE_8(DY); uint ea = EA_AX_AI_8(); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 8, ai, .) { uint res = M68KMAKE_GET_OPER_AY_8; uint ea = EA_AX_AI_8(); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 8, pi7, d) { uint res = MASK_OUT_ABOVE_8(DY); uint ea = EA_A7_PI_8(); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 8, pi, d) { uint res = MASK_OUT_ABOVE_8(DY); uint ea = EA_AX_PI_8(); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 8, pi7, .) { uint res = M68KMAKE_GET_OPER_AY_8; uint ea = EA_A7_PI_8(); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 8, pi, .) { uint res = M68KMAKE_GET_OPER_AY_8; uint ea = EA_AX_PI_8(); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 8, pd7, d) { uint res = MASK_OUT_ABOVE_8(DY); uint ea = EA_A7_PD_8(); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 8, pd, d) { uint res = MASK_OUT_ABOVE_8(DY); uint ea = EA_AX_PD_8(); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 8, pd7, .) { uint res = M68KMAKE_GET_OPER_AY_8; uint ea = EA_A7_PD_8(); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 8, pd, .) { uint res = M68KMAKE_GET_OPER_AY_8; uint ea = EA_AX_PD_8(); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 8, di, d) { uint res = MASK_OUT_ABOVE_8(DY); uint ea = EA_AX_DI_8(); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 8, di, .) { uint res = M68KMAKE_GET_OPER_AY_8; uint ea = EA_AX_DI_8(); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 8, ix, d) { uint res = MASK_OUT_ABOVE_8(DY); uint ea = EA_AX_IX_8(); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 8, ix, .) { uint res = M68KMAKE_GET_OPER_AY_8; uint ea = EA_AX_IX_8(); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 8, aw, d) { uint res = MASK_OUT_ABOVE_8(DY); uint ea = EA_AW_8(); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 8, aw, .) { uint res = M68KMAKE_GET_OPER_AY_8; uint ea = EA_AW_8(); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 8, al, d) { uint res = MASK_OUT_ABOVE_8(DY); uint ea = EA_AL_8(); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 8, al, .) { uint res = M68KMAKE_GET_OPER_AY_8; uint ea = EA_AL_8(); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, d, d) { uint res = MASK_OUT_ABOVE_16(DY); uint* r_dst = &DX; *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, d, a) { uint res = MASK_OUT_ABOVE_16(AY); uint* r_dst = &DX; *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, d, .) { uint res = M68KMAKE_GET_OPER_AY_16; uint* r_dst = &DX; *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, ai, d) { uint res = MASK_OUT_ABOVE_16(DY); uint ea = EA_AX_AI_16(); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, ai, a) { uint res = MASK_OUT_ABOVE_16(AY); uint ea = EA_AX_AI_16(); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, ai, .) { uint res = M68KMAKE_GET_OPER_AY_16; uint ea = EA_AX_AI_16(); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, pi, d) { uint res = MASK_OUT_ABOVE_16(DY); uint ea = EA_AX_PI_16(); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, pi, a) { uint res = MASK_OUT_ABOVE_16(AY); uint ea = EA_AX_PI_16(); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, pi, .) { uint res = M68KMAKE_GET_OPER_AY_16; uint ea = EA_AX_PI_16(); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, pd, d) { uint res = MASK_OUT_ABOVE_16(DY); uint ea = EA_AX_PD_16(); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, pd, a) { uint res = MASK_OUT_ABOVE_16(AY); uint ea = EA_AX_PD_16(); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, pd, .) { uint res = M68KMAKE_GET_OPER_AY_16; uint ea = EA_AX_PD_16(); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, di, d) { uint res = MASK_OUT_ABOVE_16(DY); uint ea = EA_AX_DI_16(); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, di, a) { uint res = MASK_OUT_ABOVE_16(AY); uint ea = EA_AX_DI_16(); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, di, .) { uint res = M68KMAKE_GET_OPER_AY_16; uint ea = EA_AX_DI_16(); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, ix, d) { uint res = MASK_OUT_ABOVE_16(DY); uint ea = EA_AX_IX_16(); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, ix, a) { uint res = MASK_OUT_ABOVE_16(AY); uint ea = EA_AX_IX_16(); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, ix, .) { uint res = M68KMAKE_GET_OPER_AY_16; uint ea = EA_AX_IX_16(); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, aw, d) { uint res = MASK_OUT_ABOVE_16(DY); uint ea = EA_AW_16(); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, aw, a) { uint res = MASK_OUT_ABOVE_16(AY); uint ea = EA_AW_16(); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, aw, .) { uint res = M68KMAKE_GET_OPER_AY_16; uint ea = EA_AW_16(); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, al, d) { uint res = MASK_OUT_ABOVE_16(DY); uint ea = EA_AL_16(); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, al, a) { uint res = MASK_OUT_ABOVE_16(AY); uint ea = EA_AL_16(); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 16, al, .) { uint res = M68KMAKE_GET_OPER_AY_16; uint ea = EA_AL_16(); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, d, d) { uint res = DY; uint* r_dst = &DX; *r_dst = res; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, d, a) { uint res = AY; uint* r_dst = &DX; *r_dst = res; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, d, .) { uint res = M68KMAKE_GET_OPER_AY_32; uint* r_dst = &DX; *r_dst = res; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, ai, d) { uint res = DY; uint ea = EA_AX_AI_32(); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, ai, a) { uint res = AY; uint ea = EA_AX_AI_32(); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, ai, .) { uint res = M68KMAKE_GET_OPER_AY_32; uint ea = EA_AX_AI_32(); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, pi, d) { uint res = DY; uint ea = EA_AX_PI_32(); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, pi, a) { uint res = AY; uint ea = EA_AX_PI_32(); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, pi, .) { uint res = M68KMAKE_GET_OPER_AY_32; uint ea = EA_AX_PI_32(); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, pd, d) { uint res = DY; uint ea = EA_AX_PD_32(); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, pd, a) { uint res = AY; uint ea = EA_AX_PD_32(); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, pd, .) { uint res = M68KMAKE_GET_OPER_AY_32; uint ea = EA_AX_PD_32(); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, di, d) { uint res = DY; uint ea = EA_AX_DI_32(); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, di, a) { uint res = AY; uint ea = EA_AX_DI_32(); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, di, .) { uint res = M68KMAKE_GET_OPER_AY_32; uint ea = EA_AX_DI_32(); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, ix, d) { uint res = DY; uint ea = EA_AX_IX_32(); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, ix, a) { uint res = AY; uint ea = EA_AX_IX_32(); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, ix, .) { uint res = M68KMAKE_GET_OPER_AY_32; uint ea = EA_AX_IX_32(); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, aw, d) { uint res = DY; uint ea = EA_AW_32(); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, aw, a) { uint res = AY; uint ea = EA_AW_32(); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, aw, .) { uint res = M68KMAKE_GET_OPER_AY_32; uint ea = EA_AW_32(); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, al, d) { uint res = DY; uint ea = EA_AL_32(); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, al, a) { uint res = AY; uint ea = EA_AL_32(); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(move, 32, al, .) { uint res = M68KMAKE_GET_OPER_AY_32; uint ea = EA_AL_32(); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(movea, 16, ., d) { AX = MAKE_INT_16(DY); } M68KMAKE_OP(movea, 16, ., a) { AX = MAKE_INT_16(AY); } M68KMAKE_OP(movea, 16, ., .) { AX = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16); } M68KMAKE_OP(movea, 32, ., d) { AX = DY; } M68KMAKE_OP(movea, 32, ., a) { AX = AY; } M68KMAKE_OP(movea, 32, ., .) { AX = M68KMAKE_GET_OPER_AY_32; } M68KMAKE_OP(move, 16, frc, d) { if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) { DY = MASK_OUT_BELOW_16(DY) | m68ki_get_ccr(); return; } m68ki_exception_illegal(); } M68KMAKE_OP(move, 16, frc, .) { if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) { m68ki_write_16(M68KMAKE_GET_EA_AY_16, m68ki_get_ccr()); return; } m68ki_exception_illegal(); } M68KMAKE_OP(move, 16, toc, d) { m68ki_set_ccr(DY); } M68KMAKE_OP(move, 16, toc, .) { m68ki_set_ccr(M68KMAKE_GET_OPER_AY_16); } M68KMAKE_OP(move, 16, frs, d) { if(CPU_TYPE_IS_000(CPU_TYPE) || FLAG_S) /* NS990408 */ { DY = MASK_OUT_BELOW_16(DY) | m68ki_get_sr(); return; } m68ki_exception_privilege_violation(); } M68KMAKE_OP(move, 16, frs, .) { if(CPU_TYPE_IS_000(CPU_TYPE) || FLAG_S) /* NS990408 */ { uint ea = M68KMAKE_GET_EA_AY_16; m68ki_write_16(ea, m68ki_get_sr()); return; } m68ki_exception_privilege_violation(); } M68KMAKE_OP(move, 16, tos, d) { if(FLAG_S) { m68ki_set_sr(DY); return; } m68ki_exception_privilege_violation(); } M68KMAKE_OP(move, 16, tos, .) { if(FLAG_S) { uint new_sr = M68KMAKE_GET_OPER_AY_16; m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ m68ki_set_sr(new_sr); return; } m68ki_exception_privilege_violation(); } M68KMAKE_OP(move, 32, fru, .) { if(FLAG_S) { AY = REG_USP; return; } m68ki_exception_privilege_violation(); } M68KMAKE_OP(move, 32, tou, .) { if(FLAG_S) { m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ REG_USP = AY; return; } m68ki_exception_privilege_violation(); } M68KMAKE_OP(movec, 32, cr, .) { if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) { if(FLAG_S) { uint word2 = OPER_I_16(); m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ switch (word2 & 0xfff) { case 0x000: /* SFC */ REG_DA[(word2 >> 12) & 15] = REG_SFC; return; case 0x001: /* DFC */ REG_DA[(word2 >> 12) & 15] = REG_DFC; return; case 0x002: /* CACR */ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { REG_DA[(word2 >> 12) & 15] = REG_CACR; return; } return; case 0x800: /* USP */ REG_DA[(word2 >> 12) & 15] = REG_USP; return; case 0x801: /* VBR */ REG_DA[(word2 >> 12) & 15] = REG_VBR; return; case 0x802: /* CAAR */ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { REG_DA[(word2 >> 12) & 15] = REG_CAAR; return; } m68ki_exception_illegal(); break; case 0x803: /* MSP */ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { REG_DA[(word2 >> 12) & 15] = FLAG_M ? REG_SP : REG_MSP; return; } m68ki_exception_illegal(); return; case 0x804: /* ISP */ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { REG_DA[(word2 >> 12) & 15] = FLAG_M ? REG_ISP : REG_SP; return; } m68ki_exception_illegal(); return; default: m68ki_exception_illegal(); return; } } m68ki_exception_privilege_violation(); return; } m68ki_exception_illegal(); } M68KMAKE_OP(movec, 32, rc, .) { if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) { if(FLAG_S) { uint word2 = OPER_I_16(); m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ switch (word2 & 0xfff) { case 0x000: /* SFC */ REG_SFC = REG_DA[(word2 >> 12) & 15] & 7; return; case 0x001: /* DFC */ REG_DFC = REG_DA[(word2 >> 12) & 15] & 7; return; case 0x002: /* CACR */ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { REG_CACR = REG_DA[(word2 >> 12) & 15]; return; } m68ki_exception_illegal(); return; case 0x800: /* USP */ REG_USP = REG_DA[(word2 >> 12) & 15]; return; case 0x801: /* VBR */ REG_VBR = REG_DA[(word2 >> 12) & 15]; return; case 0x802: /* CAAR */ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { REG_CAAR = REG_DA[(word2 >> 12) & 15]; return; } m68ki_exception_illegal(); return; case 0x803: /* MSP */ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { /* we are in supervisor mode so just check for M flag */ if(!FLAG_M) { REG_MSP = REG_DA[(word2 >> 12) & 15]; return; } REG_SP = REG_DA[(word2 >> 12) & 15]; return; } m68ki_exception_illegal(); return; case 0x804: /* ISP */ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { if(!FLAG_M) { REG_SP = REG_DA[(word2 >> 12) & 15]; return; } REG_ISP = REG_DA[(word2 >> 12) & 15]; return; } m68ki_exception_illegal(); return; default: m68ki_exception_illegal(); return; } } m68ki_exception_privilege_violation(); return; } m68ki_exception_illegal(); } M68KMAKE_OP(movem, 16, re, pd) { uint i = 0; uint register_list = OPER_I_16(); uint ea = AY; uint count = 0; for(; i < 16; i++) if(register_list & (1 << i)) { ea -= 2; m68ki_write_16(ea, MASK_OUT_ABOVE_16(REG_DA[15-i])); count++; } AY = ea; USE_CYCLES(count<> 8)); m68ki_write_8(ea += 2, MASK_OUT_ABOVE_8(src)); } M68KMAKE_OP(movep, 32, re, .) { uint ea = EA_AY_DI_32(); uint src = DX; m68ki_write_8(ea, MASK_OUT_ABOVE_8(src >> 24)); m68ki_write_8(ea += 2, MASK_OUT_ABOVE_8(src >> 16)); m68ki_write_8(ea += 2, MASK_OUT_ABOVE_8(src >> 8)); m68ki_write_8(ea += 2, MASK_OUT_ABOVE_8(src)); } M68KMAKE_OP(movep, 16, er, .) { uint ea = EA_AY_DI_16(); uint* r_dst = &DX; *r_dst = MASK_OUT_BELOW_16(*r_dst) | ((m68ki_read_8(ea) << 8) + m68ki_read_8(ea + 2)); } M68KMAKE_OP(movep, 32, er, .) { uint ea = EA_AY_DI_32(); DX = (m68ki_read_8(ea) << 24) + (m68ki_read_8(ea + 2) << 16) + (m68ki_read_8(ea + 4) << 8) + m68ki_read_8(ea + 6); } M68KMAKE_OP(moves, 8, ., .) { if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) { if(FLAG_S) { uint word2 = OPER_I_16(); uint ea = M68KMAKE_GET_EA_AY_8; m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ if(BIT_B(word2)) /* Register to memory */ { m68ki_write_8_fc(ea, REG_DFC, MASK_OUT_ABOVE_8(REG_DA[(word2 >> 12) & 15])); return; } if(BIT_F(word2)) /* Memory to address register */ { REG_A[(word2 >> 12) & 7] = MAKE_INT_8(m68ki_read_8_fc(ea, REG_SFC)); if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) USE_CYCLES(2); return; } /* Memory to data register */ REG_D[(word2 >> 12) & 7] = MASK_OUT_BELOW_8(REG_D[(word2 >> 12) & 7]) | m68ki_read_8_fc(ea, REG_SFC); if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) USE_CYCLES(2); return; } m68ki_exception_privilege_violation(); return; } m68ki_exception_illegal(); } M68KMAKE_OP(moves, 16, ., .) { if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) { if(FLAG_S) { uint word2 = OPER_I_16(); uint ea = M68KMAKE_GET_EA_AY_16; m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ if(BIT_B(word2)) /* Register to memory */ { m68ki_write_16_fc(ea, REG_DFC, MASK_OUT_ABOVE_16(REG_DA[(word2 >> 12) & 15])); return; } if(BIT_F(word2)) /* Memory to address register */ { REG_A[(word2 >> 12) & 7] = MAKE_INT_16(m68ki_read_16_fc(ea, REG_SFC)); if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) USE_CYCLES(2); return; } /* Memory to data register */ REG_D[(word2 >> 12) & 7] = MASK_OUT_BELOW_16(REG_D[(word2 >> 12) & 7]) | m68ki_read_16_fc(ea, REG_SFC); if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) USE_CYCLES(2); return; } m68ki_exception_privilege_violation(); return; } m68ki_exception_illegal(); } M68KMAKE_OP(moves, 32, ., .) { if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) { if(FLAG_S) { uint word2 = OPER_I_16(); uint ea = M68KMAKE_GET_EA_AY_32; m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ if(BIT_B(word2)) /* Register to memory */ { m68ki_write_32_fc(ea, REG_DFC, REG_DA[(word2 >> 12) & 15]); if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) USE_CYCLES(2); return; } /* Memory to register */ REG_DA[(word2 >> 12) & 15] = m68ki_read_32_fc(ea, REG_SFC); if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) USE_CYCLES(2); return; } m68ki_exception_privilege_violation(); return; } m68ki_exception_illegal(); } M68KMAKE_OP(moveq, 32, ., .) { uint res = DX = MAKE_INT_8(MASK_OUT_ABOVE_8(REG_IR)); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(muls, 16, ., d) { uint* r_dst = &DX; uint res = MASK_OUT_ABOVE_32(MAKE_INT_16(DY) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); *r_dst = res; FLAG_Z = res; FLAG_N = NFLAG_32(res); FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(muls, 16, ., .) { uint* r_dst = &DX; uint res = MASK_OUT_ABOVE_32(MAKE_INT_16(M68KMAKE_GET_OPER_AY_16) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst))); *r_dst = res; FLAG_Z = res; FLAG_N = NFLAG_32(res); FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(mulu, 16, ., d) { uint* r_dst = &DX; uint res = MASK_OUT_ABOVE_16(DY) * MASK_OUT_ABOVE_16(*r_dst); *r_dst = res; FLAG_Z = res; FLAG_N = NFLAG_32(res); FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(mulu, 16, ., .) { uint* r_dst = &DX; uint res = M68KMAKE_GET_OPER_AY_16 * MASK_OUT_ABOVE_16(*r_dst); *r_dst = res; FLAG_Z = res; FLAG_N = NFLAG_32(res); FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(mull, 32, ., d) { #if M68K_USE_64_BIT if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint64 src = DY; uint64 dst = REG_D[(word2 >> 12) & 7]; uint64 res; FLAG_C = CFLAG_CLEAR; if(BIT_B(word2)) /* signed */ { res = (sint64)((sint32)src) * (sint64)((sint32)dst); if(!BIT_A(word2)) { FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_N = NFLAG_32(res); FLAG_V = ((sint64)res != (sint32)res)<<7; REG_D[(word2 >> 12) & 7] = FLAG_Z; return; } FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); FLAG_N = NFLAG_64(res); FLAG_V = VFLAG_CLEAR; REG_D[word2 & 7] = (res >> 32); REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); return; } res = src * dst; if(!BIT_A(word2)) { FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_N = NFLAG_32(res); FLAG_V = (res > 0xffffffff)<<7; REG_D[(word2 >> 12) & 7] = FLAG_Z; return; } FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); FLAG_N = NFLAG_64(res); FLAG_V = VFLAG_CLEAR; REG_D[word2 & 7] = (res >> 32); REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); return; } m68ki_exception_illegal(); #else if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint src = DY; uint dst = REG_D[(word2 >> 12) & 7]; uint neg = GET_MSB_32(src ^ dst); uint src1; uint src2; uint dst1; uint dst2; uint r1; uint r2; uint r3; uint r4; uint lo; uint hi; FLAG_C = CFLAG_CLEAR; if(BIT_B(word2)) /* signed */ { if(GET_MSB_32(src)) src = (uint)MASK_OUT_ABOVE_32(-(sint)src); if(GET_MSB_32(dst)) dst = (uint)MASK_OUT_ABOVE_32(-(sint)dst); } src1 = MASK_OUT_ABOVE_16(src); src2 = src>>16; dst1 = MASK_OUT_ABOVE_16(dst); dst2 = dst>>16; r1 = src1 * dst1; r2 = src1 * dst2; r3 = src2 * dst1; r4 = src2 * dst2; lo = r1 + (MASK_OUT_ABOVE_16(r2)<<16) + (MASK_OUT_ABOVE_16(r3)<<16); hi = r4 + (r2>>16) + (r3>>16) + (((r1>>16) + MASK_OUT_ABOVE_16(r2) + MASK_OUT_ABOVE_16(r3)) >> 16); if(BIT_B(word2) && neg) { hi = (uint)MASK_OUT_ABOVE_32((-(sint)hi) - (lo != 0)); lo = (uint)MASK_OUT_ABOVE_32(-(sint)lo); } if(BIT_A(word2)) { REG_D[word2 & 7] = hi; REG_D[(word2 >> 12) & 7] = lo; FLAG_N = NFLAG_32(hi); FLAG_Z = hi | lo; FLAG_V = VFLAG_CLEAR; return; } REG_D[(word2 >> 12) & 7] = lo; FLAG_N = NFLAG_32(lo); FLAG_Z = lo; if(BIT_B(word2)) FLAG_V = (!((GET_MSB_32(lo) && hi == 0xffffffff) || (!GET_MSB_32(lo) && !hi)))<<7; else FLAG_V = (hi != 0) << 7; return; } m68ki_exception_illegal(); #endif } M68KMAKE_OP(mull, 32, ., .) { #if M68K_USE_64_BIT if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint64 src = M68KMAKE_GET_OPER_AY_32; uint64 dst = REG_D[(word2 >> 12) & 7]; uint64 res; FLAG_C = CFLAG_CLEAR; if(BIT_B(word2)) /* signed */ { res = (sint64)((sint32)src) * (sint64)((sint32)dst); if(!BIT_A(word2)) { FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_N = NFLAG_32(res); FLAG_V = ((sint64)res != (sint32)res)<<7; REG_D[(word2 >> 12) & 7] = FLAG_Z; return; } FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); FLAG_N = NFLAG_64(res); FLAG_V = VFLAG_CLEAR; REG_D[word2 & 7] = (res >> 32); REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); return; } res = src * dst; if(!BIT_A(word2)) { FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_N = NFLAG_32(res); FLAG_V = (res > 0xffffffff)<<7; REG_D[(word2 >> 12) & 7] = FLAG_Z; return; } FLAG_Z = MASK_OUT_ABOVE_32(res) | (res>>32); FLAG_N = NFLAG_64(res); FLAG_V = VFLAG_CLEAR; REG_D[word2 & 7] = (res >> 32); REG_D[(word2 >> 12) & 7] = MASK_OUT_ABOVE_32(res); return; } m68ki_exception_illegal(); #else if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint word2 = OPER_I_16(); uint src = M68KMAKE_GET_OPER_AY_32; uint dst = REG_D[(word2 >> 12) & 7]; uint neg = GET_MSB_32(src ^ dst); uint src1; uint src2; uint dst1; uint dst2; uint r1; uint r2; uint r3; uint r4; uint lo; uint hi; FLAG_C = CFLAG_CLEAR; if(BIT_B(word2)) /* signed */ { if(GET_MSB_32(src)) src = (uint)MASK_OUT_ABOVE_32(-(sint)src); if(GET_MSB_32(dst)) dst = (uint)MASK_OUT_ABOVE_32(-(sint)dst); } src1 = MASK_OUT_ABOVE_16(src); src2 = src>>16; dst1 = MASK_OUT_ABOVE_16(dst); dst2 = dst>>16; r1 = src1 * dst1; r2 = src1 * dst2; r3 = src2 * dst1; r4 = src2 * dst2; lo = r1 + (MASK_OUT_ABOVE_16(r2)<<16) + (MASK_OUT_ABOVE_16(r3)<<16); hi = r4 + (r2>>16) + (r3>>16) + (((r1>>16) + MASK_OUT_ABOVE_16(r2) + MASK_OUT_ABOVE_16(r3)) >> 16); if(BIT_B(word2) && neg) { hi = (uint)MASK_OUT_ABOVE_32((-(sint)hi) - (lo != 0)); lo = (uint)MASK_OUT_ABOVE_32(-(sint)lo); } if(BIT_A(word2)) { REG_D[word2 & 7] = hi; REG_D[(word2 >> 12) & 7] = lo; FLAG_N = NFLAG_32(hi); FLAG_Z = hi | lo; FLAG_V = VFLAG_CLEAR; return; } REG_D[(word2 >> 12) & 7] = lo; FLAG_N = NFLAG_32(lo); FLAG_Z = lo; if(BIT_B(word2)) FLAG_V = (!((GET_MSB_32(lo) && hi == 0xffffffff) || (!GET_MSB_32(lo) && !hi)))<<7; else FLAG_V = (hi != 0) << 7; return; } m68ki_exception_illegal(); #endif } M68KMAKE_OP(nbcd, 8, ., d) { uint* r_dst = &DY; uint dst = *r_dst; uint res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1()); if(res != 0x9a) { FLAG_V = ~res; /* Undefined V behavior */ if((res & 0x0f) == 0xa) res = (res & 0xf0) + 0x10; res = MASK_OUT_ABOVE_8(res); FLAG_V &= res; /* Undefined V behavior part II */ *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; FLAG_Z |= res; FLAG_C = CFLAG_SET; FLAG_X = XFLAG_SET; } else { FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; FLAG_X = XFLAG_CLEAR; } FLAG_N = NFLAG_8(res); /* Undefined N behavior */ } M68KMAKE_OP(nbcd, 8, ., .) { uint ea = M68KMAKE_GET_EA_AY_8; uint dst = m68ki_read_8(ea); uint res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1()); if(res != 0x9a) { FLAG_V = ~res; /* Undefined V behavior */ if((res & 0x0f) == 0xa) res = (res & 0xf0) + 0x10; res = MASK_OUT_ABOVE_8(res); FLAG_V &= res; /* Undefined V behavior part II */ m68ki_write_8(ea, MASK_OUT_ABOVE_8(res)); FLAG_Z |= res; FLAG_C = CFLAG_SET; FLAG_X = XFLAG_SET; } else { FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; FLAG_X = XFLAG_CLEAR; } FLAG_N = NFLAG_8(res); /* Undefined N behavior */ } M68KMAKE_OP(neg, 8, ., d) { uint* r_dst = &DY; uint res = 0 - MASK_OUT_ABOVE_8(*r_dst); FLAG_N = NFLAG_8(res); FLAG_C = FLAG_X = CFLAG_8(res); FLAG_V = *r_dst & res; FLAG_Z = MASK_OUT_ABOVE_8(res); *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; } M68KMAKE_OP(neg, 8, ., .) { uint ea = M68KMAKE_GET_EA_AY_8; uint src = m68ki_read_8(ea); uint res = 0 - src; FLAG_N = NFLAG_8(res); FLAG_C = FLAG_X = CFLAG_8(res); FLAG_V = src & res; FLAG_Z = MASK_OUT_ABOVE_8(res); m68ki_write_8(ea, FLAG_Z); } M68KMAKE_OP(neg, 16, ., d) { uint* r_dst = &DY; uint res = 0 - MASK_OUT_ABOVE_16(*r_dst); FLAG_N = NFLAG_16(res); FLAG_C = FLAG_X = CFLAG_16(res); FLAG_V = (*r_dst & res)>>8; FLAG_Z = MASK_OUT_ABOVE_16(res); *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; } M68KMAKE_OP(neg, 16, ., .) { uint ea = M68KMAKE_GET_EA_AY_16; uint src = m68ki_read_16(ea); uint res = 0 - src; FLAG_N = NFLAG_16(res); FLAG_C = FLAG_X = CFLAG_16(res); FLAG_V = (src & res)>>8; FLAG_Z = MASK_OUT_ABOVE_16(res); m68ki_write_16(ea, FLAG_Z); } M68KMAKE_OP(neg, 32, ., d) { uint* r_dst = &DY; uint res = 0 - *r_dst; FLAG_N = NFLAG_32(res); FLAG_C = FLAG_X = CFLAG_SUB_32(*r_dst, 0, res); FLAG_V = (*r_dst & res)>>24; FLAG_Z = MASK_OUT_ABOVE_32(res); *r_dst = FLAG_Z; } M68KMAKE_OP(neg, 32, ., .) { uint ea = M68KMAKE_GET_EA_AY_32; uint src = m68ki_read_32(ea); uint res = 0 - src; FLAG_N = NFLAG_32(res); FLAG_C = FLAG_X = CFLAG_SUB_32(src, 0, res); FLAG_V = (src & res)>>24; FLAG_Z = MASK_OUT_ABOVE_32(res); m68ki_write_32(ea, FLAG_Z); } M68KMAKE_OP(negx, 8, ., d) { uint* r_dst = &DY; uint res = 0 - MASK_OUT_ABOVE_8(*r_dst) - XFLAG_AS_1(); FLAG_N = NFLAG_8(res); FLAG_X = FLAG_C = CFLAG_8(res); FLAG_V = *r_dst & res; res = MASK_OUT_ABOVE_8(res); FLAG_Z |= res; *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; } M68KMAKE_OP(negx, 8, ., .) { uint ea = M68KMAKE_GET_EA_AY_8; uint src = m68ki_read_8(ea); uint res = 0 - src - XFLAG_AS_1(); FLAG_N = NFLAG_8(res); FLAG_X = FLAG_C = CFLAG_8(res); FLAG_V = src & res; res = MASK_OUT_ABOVE_8(res); FLAG_Z |= res; m68ki_write_8(ea, res); } M68KMAKE_OP(negx, 16, ., d) { uint* r_dst = &DY; uint res = 0 - MASK_OUT_ABOVE_16(*r_dst) - XFLAG_AS_1(); FLAG_N = NFLAG_16(res); FLAG_X = FLAG_C = CFLAG_16(res); FLAG_V = (*r_dst & res)>>8; res = MASK_OUT_ABOVE_16(res); FLAG_Z |= res; *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; } M68KMAKE_OP(negx, 16, ., .) { uint ea = M68KMAKE_GET_EA_AY_16; uint src = m68ki_read_16(ea); uint res = 0 - MASK_OUT_ABOVE_16(src) - XFLAG_AS_1(); FLAG_N = NFLAG_16(res); FLAG_X = FLAG_C = CFLAG_16(res); FLAG_V = (src & res)>>8; res = MASK_OUT_ABOVE_16(res); FLAG_Z |= res; m68ki_write_16(ea, res); } M68KMAKE_OP(negx, 32, ., d) { uint* r_dst = &DY; uint res = 0 - MASK_OUT_ABOVE_32(*r_dst) - XFLAG_AS_1(); FLAG_N = NFLAG_32(res); FLAG_X = FLAG_C = CFLAG_SUB_32(*r_dst, 0, res); FLAG_V = (*r_dst & res)>>24; res = MASK_OUT_ABOVE_32(res); FLAG_Z |= res; *r_dst = res; } M68KMAKE_OP(negx, 32, ., .) { uint ea = M68KMAKE_GET_EA_AY_32; uint src = m68ki_read_32(ea); uint res = 0 - MASK_OUT_ABOVE_32(src) - XFLAG_AS_1(); FLAG_N = NFLAG_32(res); FLAG_X = FLAG_C = CFLAG_SUB_32(src, 0, res); FLAG_V = (src & res)>>24; res = MASK_OUT_ABOVE_32(res); FLAG_Z |= res; m68ki_write_32(ea, res); } M68KMAKE_OP(nop, 0, ., .) { m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ } M68KMAKE_OP(not, 8, ., d) { uint* r_dst = &DY; uint res = MASK_OUT_ABOVE_8(~*r_dst); *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(not, 8, ., .) { uint ea = M68KMAKE_GET_EA_AY_8; uint res = MASK_OUT_ABOVE_8(~m68ki_read_8(ea)); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(not, 16, ., d) { uint* r_dst = &DY; uint res = MASK_OUT_ABOVE_16(~*r_dst); *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(not, 16, ., .) { uint ea = M68KMAKE_GET_EA_AY_16; uint res = MASK_OUT_ABOVE_16(~m68ki_read_16(ea)); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(not, 32, ., d) { uint* r_dst = &DY; uint res = *r_dst = MASK_OUT_ABOVE_32(~*r_dst); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(not, 32, ., .) { uint ea = M68KMAKE_GET_EA_AY_32; uint res = MASK_OUT_ABOVE_32(~m68ki_read_32(ea)); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(or, 8, er, d) { uint res = MASK_OUT_ABOVE_8((DX |= MASK_OUT_ABOVE_8(DY))); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(or, 8, er, .) { uint res = MASK_OUT_ABOVE_8((DX |= M68KMAKE_GET_OPER_AY_8)); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(or, 16, er, d) { uint res = MASK_OUT_ABOVE_16((DX |= MASK_OUT_ABOVE_16(DY))); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(or, 16, er, .) { uint res = MASK_OUT_ABOVE_16((DX |= M68KMAKE_GET_OPER_AY_16)); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(or, 32, er, d) { uint res = DX |= DY; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(or, 32, er, .) { uint res = DX |= M68KMAKE_GET_OPER_AY_32; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(or, 8, re, .) { uint ea = M68KMAKE_GET_EA_AY_8; uint res = MASK_OUT_ABOVE_8(DX | m68ki_read_8(ea)); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(or, 16, re, .) { uint ea = M68KMAKE_GET_EA_AY_16; uint res = MASK_OUT_ABOVE_16(DX | m68ki_read_16(ea)); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(or, 32, re, .) { uint ea = M68KMAKE_GET_EA_AY_32; uint res = DX | m68ki_read_32(ea); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(ori, 8, ., d) { uint res = MASK_OUT_ABOVE_8((DY |= OPER_I_8())); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(ori, 8, ., .) { uint src = OPER_I_8(); uint ea = M68KMAKE_GET_EA_AY_8; uint res = MASK_OUT_ABOVE_8(src | m68ki_read_8(ea)); m68ki_write_8(ea, res); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(ori, 16, ., d) { uint res = MASK_OUT_ABOVE_16(DY |= OPER_I_16()); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(ori, 16, ., .) { uint src = OPER_I_16(); uint ea = M68KMAKE_GET_EA_AY_16; uint res = MASK_OUT_ABOVE_16(src | m68ki_read_16(ea)); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(ori, 32, ., d) { uint res = DY |= OPER_I_32(); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(ori, 32, ., .) { uint src = OPER_I_32(); uint ea = M68KMAKE_GET_EA_AY_32; uint res = src | m68ki_read_32(ea); m68ki_write_32(ea, res); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(ori, 16, toc, .) { m68ki_set_ccr(m68ki_get_ccr() | OPER_I_16()); } M68KMAKE_OP(ori, 16, tos, .) { if(FLAG_S) { uint src = OPER_I_16(); m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ m68ki_set_sr(m68ki_get_sr() | src); return; } m68ki_exception_privilege_violation(); } M68KMAKE_OP(pack, 16, rr, .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { /* Note: DX and DY are reversed in Motorola's docs */ uint src = DY + OPER_I_16(); uint* r_dst = &DX; *r_dst = MASK_OUT_BELOW_8(*r_dst) | ((src >> 4) & 0x00f0) | (src & 0x000f); return; } m68ki_exception_illegal(); } M68KMAKE_OP(pack, 16, mm, ax7) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { /* Note: AX and AY are reversed in Motorola's docs */ uint ea_src = EA_AY_PD_8(); uint src = m68ki_read_8(ea_src); ea_src = EA_AY_PD_8(); src = ((src << 8) | m68ki_read_8(ea_src)) + OPER_I_16(); m68ki_write_8(EA_A7_PD_8(), ((src >> 4) & 0x00f0) | (src & 0x000f)); return; } m68ki_exception_illegal(); } M68KMAKE_OP(pack, 16, mm, ay7) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { /* Note: AX and AY are reversed in Motorola's docs */ uint ea_src = EA_A7_PD_8(); uint src = m68ki_read_8(ea_src); ea_src = EA_A7_PD_8(); src = ((src << 8) | m68ki_read_8(ea_src)) + OPER_I_16(); m68ki_write_8(EA_AX_PD_8(), ((src >> 4) & 0x00f0) | (src & 0x000f)); return; } m68ki_exception_illegal(); } M68KMAKE_OP(pack, 16, mm, axy7) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint ea_src = EA_A7_PD_8(); uint src = m68ki_read_8(ea_src); ea_src = EA_A7_PD_8(); src = ((src << 8) | m68ki_read_8(ea_src)) + OPER_I_16(); m68ki_write_8(EA_A7_PD_8(), ((src >> 4) & 0x00f0) | (src & 0x000f)); return; } m68ki_exception_illegal(); } M68KMAKE_OP(pack, 16, mm, .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { /* Note: AX and AY are reversed in Motorola's docs */ uint ea_src = EA_AY_PD_8(); uint src = m68ki_read_8(ea_src); ea_src = EA_AY_PD_8(); src = ((src << 8) | m68ki_read_8(ea_src)) + OPER_I_16(); m68ki_write_8(EA_AX_PD_8(), ((src >> 4) & 0x00f0) | (src & 0x000f)); return; } m68ki_exception_illegal(); } M68KMAKE_OP(pea, 32, ., .) { uint ea = M68KMAKE_GET_EA_AY_32; m68ki_push_32(ea); } M68KMAKE_OP(reset, 0, ., .) { if(FLAG_S) { m68ki_output_reset(); /* auto-disable (see m68kcpu.h) */ USE_CYCLES(CYC_RESET); return; } m68ki_exception_privilege_violation(); } M68KMAKE_OP(ror, 8, s, .) { uint* r_dst = &DY; uint orig_shift = (((REG_IR >> 9) - 1) & 7) + 1; uint shift = orig_shift & 7; uint src = MASK_OUT_ABOVE_8(*r_dst); uint res = ROR_8(src, shift); *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_C = src << (9-orig_shift); FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(ror, 16, s, .) { uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint src = MASK_OUT_ABOVE_16(*r_dst); uint res = ROR_16(src, shift); *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_C = src << (9-shift); FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(ror, 32, s, .) { uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint64 src = *r_dst; uint res = ROR_32(src, shift); *r_dst = res; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_C = src << (9-shift); FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(ror, 8, r, .) { uint* r_dst = &DY; uint orig_shift = DX & 0x3f; uint shift = orig_shift & 7; uint src = MASK_OUT_ABOVE_8(*r_dst); uint res = ROR_8(src, shift); if(orig_shift != 0) { USE_CYCLES(orig_shift<> ((shift - 1) & 15)) << 8; FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; return; } FLAG_C = CFLAG_CLEAR; FLAG_N = NFLAG_16(src); FLAG_Z = src; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(ror, 32, r, .) { uint* r_dst = &DY; uint orig_shift = DX & 0x3f; uint shift = orig_shift & 31; uint64 src = *r_dst; uint res = ROR_32(src, shift); if(orig_shift != 0) { USE_CYCLES(orig_shift<> ((shift - 1) & 31)) << 8; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; return; } FLAG_C = CFLAG_CLEAR; FLAG_N = NFLAG_32(src); FLAG_Z = src; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(ror, 16, ., .) { uint ea = M68KMAKE_GET_EA_AY_16; uint src = m68ki_read_16(ea); uint res = ROR_16(src, 1); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_C = src << 8; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(rol, 8, s, .) { uint* r_dst = &DY; uint orig_shift = (((REG_IR >> 9) - 1) & 7) + 1; uint shift = orig_shift & 7; uint src = MASK_OUT_ABOVE_8(*r_dst); uint res = ROL_8(src, shift); *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_C = src << orig_shift; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(rol, 16, s, .) { uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint src = MASK_OUT_ABOVE_16(*r_dst); uint res = ROL_16(src, shift); *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_C = src >> (8-shift); FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(rol, 32, s, .) { uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint64 src = *r_dst; uint res = ROL_32(src, shift); *r_dst = res; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_C = src >> (24-shift); FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(rol, 8, r, .) { uint* r_dst = &DY; uint orig_shift = DX & 0x3f; uint shift = orig_shift & 7; uint src = MASK_OUT_ABOVE_8(*r_dst); uint res = ROL_8(src, shift); if(orig_shift != 0) { USE_CYCLES(orig_shift<> 8; FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; return; } FLAG_C = (src & 1)<<8; FLAG_N = NFLAG_16(src); FLAG_Z = src; FLAG_V = VFLAG_CLEAR; return; } FLAG_C = CFLAG_CLEAR; FLAG_N = NFLAG_16(src); FLAG_Z = src; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(rol, 32, r, .) { uint* r_dst = &DY; uint orig_shift = DX & 0x3f; uint shift = orig_shift & 31; uint64 src = *r_dst; uint res = ROL_32(src, shift); if(orig_shift != 0) { USE_CYCLES(orig_shift<> (32 - shift)) << 8; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; return; } FLAG_C = CFLAG_CLEAR; FLAG_N = NFLAG_32(src); FLAG_Z = src; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(rol, 16, ., .) { uint ea = M68KMAKE_GET_EA_AY_16; uint src = m68ki_read_16(ea); uint res = MASK_OUT_ABOVE_16(ROL_16(src, 1)); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_C = src >> 7; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(roxr, 8, s, .) { uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint src = MASK_OUT_ABOVE_8(*r_dst); uint res = ROR_9(src | (XFLAG_AS_1() << 8), shift); FLAG_C = FLAG_X = res; res = MASK_OUT_ABOVE_8(res); *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(roxr, 16, s, .) { uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint src = MASK_OUT_ABOVE_16(*r_dst); uint res = ROR_17(src | (XFLAG_AS_1() << 16), shift); FLAG_C = FLAG_X = res >> 8; res = MASK_OUT_ABOVE_16(res); *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(roxr, 32, s, .) { #if M68K_USE_64_BIT uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint64 src = *r_dst; uint64 res = src | (((uint64)XFLAG_AS_1()) << 32); res = ROR_33_64(res, shift); FLAG_C = FLAG_X = res >> 24; res = MASK_OUT_ABOVE_32(res); *r_dst = res; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; #else uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint src = *r_dst; uint res = MASK_OUT_ABOVE_32((ROR_33(src, shift) & ~(1 << (32 - shift))) | (XFLAG_AS_1() << (32 - shift))); uint new_x_flag = src & (1 << (shift - 1)); *r_dst = res; FLAG_C = FLAG_X = (new_x_flag != 0)<<8; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; #endif } M68KMAKE_OP(roxr, 8, r, .) { uint* r_dst = &DY; uint orig_shift = DX & 0x3f; if(orig_shift != 0) { uint shift = orig_shift % 9; uint src = MASK_OUT_ABOVE_8(*r_dst); uint res = ROR_9(src | (XFLAG_AS_1() << 8), shift); USE_CYCLES(orig_shift<> 8; res = MASK_OUT_ABOVE_16(res); *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; return; } FLAG_C = FLAG_X; FLAG_N = NFLAG_16(*r_dst); FLAG_Z = MASK_OUT_ABOVE_16(*r_dst); FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(roxr, 32, r, .) { #if M68K_USE_64_BIT uint* r_dst = &DY; uint orig_shift = DX & 0x3f; if(orig_shift != 0) { uint shift = orig_shift % 33; uint64 src = *r_dst; uint64 res = src | (((uint64)XFLAG_AS_1()) << 32); res = ROR_33_64(res, shift); USE_CYCLES(orig_shift<> 24; res = MASK_OUT_ABOVE_32(res); *r_dst = res; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; return; } FLAG_C = FLAG_X; FLAG_N = NFLAG_32(*r_dst); FLAG_Z = *r_dst; FLAG_V = VFLAG_CLEAR; #else uint* r_dst = &DY; uint orig_shift = DX & 0x3f; uint shift = orig_shift % 33; uint src = *r_dst; uint res = MASK_OUT_ABOVE_32((ROR_33(src, shift) & ~(1 << (32 - shift))) | (XFLAG_AS_1() << (32 - shift))); uint new_x_flag = src & (1 << (shift - 1)); if(orig_shift != 0) USE_CYCLES(orig_shift<> 8; res = MASK_OUT_ABOVE_16(res); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(roxl, 8, s, .) { uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint src = MASK_OUT_ABOVE_8(*r_dst); uint res = ROL_9(src | (XFLAG_AS_1() << 8), shift); FLAG_C = FLAG_X = res; res = MASK_OUT_ABOVE_8(res); *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(roxl, 16, s, .) { uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint src = MASK_OUT_ABOVE_16(*r_dst); uint res = ROL_17(src | (XFLAG_AS_1() << 16), shift); FLAG_C = FLAG_X = res >> 8; res = MASK_OUT_ABOVE_16(res); *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(roxl, 32, s, .) { #if M68K_USE_64_BIT uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint64 src = *r_dst; uint64 res = src | (((uint64)XFLAG_AS_1()) << 32); res = ROL_33_64(res, shift); FLAG_C = FLAG_X = res >> 24; res = MASK_OUT_ABOVE_32(res); *r_dst = res; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; #else uint* r_dst = &DY; uint shift = (((REG_IR >> 9) - 1) & 7) + 1; uint src = *r_dst; uint res = MASK_OUT_ABOVE_32((ROL_33(src, shift) & ~(1 << (shift - 1))) | (XFLAG_AS_1() << (shift - 1))); uint new_x_flag = src & (1 << (32 - shift)); *r_dst = res; FLAG_C = FLAG_X = (new_x_flag != 0)<<8; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; #endif } M68KMAKE_OP(roxl, 8, r, .) { uint* r_dst = &DY; uint orig_shift = DX & 0x3f; if(orig_shift != 0) { uint shift = orig_shift % 9; uint src = MASK_OUT_ABOVE_8(*r_dst); uint res = ROL_9(src | (XFLAG_AS_1() << 8), shift); USE_CYCLES(orig_shift<> 8; res = MASK_OUT_ABOVE_16(res); *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; return; } FLAG_C = FLAG_X; FLAG_N = NFLAG_16(*r_dst); FLAG_Z = MASK_OUT_ABOVE_16(*r_dst); FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(roxl, 32, r, .) { #if M68K_USE_64_BIT uint* r_dst = &DY; uint orig_shift = DX & 0x3f; if(orig_shift != 0) { uint shift = orig_shift % 33; uint64 src = *r_dst; uint64 res = src | (((uint64)XFLAG_AS_1()) << 32); res = ROL_33_64(res, shift); USE_CYCLES(orig_shift<> 24; res = MASK_OUT_ABOVE_32(res); *r_dst = res; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; return; } FLAG_C = FLAG_X; FLAG_N = NFLAG_32(*r_dst); FLAG_Z = *r_dst; FLAG_V = VFLAG_CLEAR; #else uint* r_dst = &DY; uint orig_shift = DX & 0x3f; uint shift = orig_shift % 33; uint src = *r_dst; uint res = MASK_OUT_ABOVE_32((ROL_33(src, shift) & ~(1 << (shift - 1))) | (XFLAG_AS_1() << (shift - 1))); uint new_x_flag = src & (1 << (32 - shift)); if(orig_shift != 0) USE_CYCLES(orig_shift<> 8; res = MASK_OUT_ABOVE_16(res); m68ki_write_16(ea, res); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(rtd, 32, ., .) { if(CPU_TYPE_IS_010_PLUS(CPU_TYPE)) { uint new_pc = m68ki_pull_32(); m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ REG_A[7] = MASK_OUT_ABOVE_32(REG_A[7] + MAKE_INT_16(OPER_I_16())); m68ki_jump(new_pc); return; } m68ki_exception_illegal(); } M68KMAKE_OP(rte, 32, ., .) { if(FLAG_S) { uint new_sr; uint new_pc; uint format_word; m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ if(CPU_TYPE_IS_000(CPU_TYPE)) { new_sr = m68ki_pull_16(); new_pc = m68ki_pull_32(); m68ki_jump(new_pc); m68ki_set_sr(new_sr); CPU_INSTR_MODE = INSTRUCTION_YES; CPU_RUN_MODE = RUN_MODE_NORMAL; return; } if(CPU_TYPE_IS_010(CPU_TYPE)) { format_word = m68ki_read_16(REG_A[7]+6) >> 12; if(format_word == 0) { new_sr = m68ki_pull_16(); new_pc = m68ki_pull_32(); m68ki_fake_pull_16(); /* format word */ m68ki_jump(new_pc); m68ki_set_sr(new_sr); CPU_INSTR_MODE = INSTRUCTION_YES; CPU_RUN_MODE = RUN_MODE_NORMAL; return; } CPU_INSTR_MODE = INSTRUCTION_YES; CPU_RUN_MODE = RUN_MODE_NORMAL; /* Not handling bus fault (9) */ m68ki_exception_format_error(); return; } /* Otherwise it's 020 */ rte_loop: format_word = m68ki_read_16(REG_A[7]+6) >> 12; switch(format_word) { case 0: /* Normal */ new_sr = m68ki_pull_16(); new_pc = m68ki_pull_32(); m68ki_fake_pull_16(); /* format word */ m68ki_jump(new_pc); m68ki_set_sr(new_sr); CPU_INSTR_MODE = INSTRUCTION_YES; CPU_RUN_MODE = RUN_MODE_NORMAL; return; case 1: /* Throwaway */ new_sr = m68ki_pull_16(); m68ki_fake_pull_32(); /* program counter */ m68ki_fake_pull_16(); /* format word */ m68ki_set_sr_noint(new_sr); goto rte_loop; case 2: /* Trap */ new_sr = m68ki_pull_16(); new_pc = m68ki_pull_32(); m68ki_fake_pull_16(); /* format word */ m68ki_fake_pull_32(); /* address */ m68ki_jump(new_pc); m68ki_set_sr(new_sr); CPU_INSTR_MODE = INSTRUCTION_YES; CPU_RUN_MODE = RUN_MODE_NORMAL; return; } /* Not handling long or short bus fault */ CPU_INSTR_MODE = INSTRUCTION_YES; CPU_RUN_MODE = RUN_MODE_NORMAL; m68ki_exception_format_error(); return; } m68ki_exception_privilege_violation(); } M68KMAKE_OP(rtm, 32, ., .) { if(CPU_TYPE_IS_020_VARIANT(CPU_TYPE)) { m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: called unimplemented instruction %04x (%s)\n", m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC - 2), REG_IR, m68k_disassemble_quick(ADDRESS_68K(REG_PC - 2)))); return; } m68ki_exception_illegal(); } M68KMAKE_OP(rtr, 32, ., .) { m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ m68ki_set_ccr(m68ki_pull_16()); m68ki_jump(m68ki_pull_32()); } M68KMAKE_OP(rts, 32, ., .) { m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ m68ki_jump(m68ki_pull_32()); } M68KMAKE_OP(sbcd, 8, rr, .) { uint* r_dst = &DX; uint src = DY; uint dst = *r_dst; uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(); FLAG_V = ~res; /* Undefined V behavior */ if(res > 9) res -= 6; res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); FLAG_X = FLAG_C = (res > 0x99) << 8; if(FLAG_C) res += 0xa0; res = MASK_OUT_ABOVE_8(res); FLAG_V &= res; /* Undefined V behavior part II */ FLAG_N = NFLAG_8(res); /* Undefined N behavior */ FLAG_Z |= res; *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; } M68KMAKE_OP(sbcd, 8, mm, ax7) { uint src = OPER_AY_PD_8(); uint ea = EA_A7_PD_8(); uint dst = m68ki_read_8(ea); uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(); FLAG_V = ~res; /* Undefined V behavior */ if(res > 9) res -= 6; res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); FLAG_X = FLAG_C = (res > 0x99) << 8; if(FLAG_C) res += 0xa0; res = MASK_OUT_ABOVE_8(res); FLAG_V &= res; /* Undefined V behavior part II */ FLAG_N = NFLAG_8(res); /* Undefined N behavior */ FLAG_Z |= res; m68ki_write_8(ea, res); } M68KMAKE_OP(sbcd, 8, mm, ay7) { uint src = OPER_A7_PD_8(); uint ea = EA_AX_PD_8(); uint dst = m68ki_read_8(ea); uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(); FLAG_V = ~res; /* Undefined V behavior */ if(res > 9) res -= 6; res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); FLAG_X = FLAG_C = (res > 0x99) << 8; if(FLAG_C) res += 0xa0; res = MASK_OUT_ABOVE_8(res); FLAG_V &= res; /* Undefined V behavior part II */ FLAG_N = NFLAG_8(res); /* Undefined N behavior */ FLAG_Z |= res; m68ki_write_8(ea, res); } M68KMAKE_OP(sbcd, 8, mm, axy7) { uint src = OPER_A7_PD_8(); uint ea = EA_A7_PD_8(); uint dst = m68ki_read_8(ea); uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(); FLAG_V = ~res; /* Undefined V behavior */ if(res > 9) res -= 6; res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); FLAG_X = FLAG_C = (res > 0x99) << 8; if(FLAG_C) res += 0xa0; res = MASK_OUT_ABOVE_8(res); FLAG_V &= res; /* Undefined V behavior part II */ FLAG_N = NFLAG_8(res); /* Undefined N behavior */ FLAG_Z |= res; m68ki_write_8(ea, res); } M68KMAKE_OP(sbcd, 8, mm, .) { uint src = OPER_AY_PD_8(); uint ea = EA_AX_PD_8(); uint dst = m68ki_read_8(ea); uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1(); FLAG_V = ~res; /* Undefined V behavior */ if(res > 9) res -= 6; res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src); FLAG_X = FLAG_C = (res > 0x99) << 8; if(FLAG_C) res += 0xa0; res = MASK_OUT_ABOVE_8(res); FLAG_V &= res; /* Undefined V behavior part II */ FLAG_N = NFLAG_8(res); /* Undefined N behavior */ FLAG_Z |= res; m68ki_write_8(ea, res); } M68KMAKE_OP(st, 8, ., d) { DY |= 0xff; } M68KMAKE_OP(st, 8, ., .) { m68ki_write_8(M68KMAKE_GET_EA_AY_8, 0xff); } M68KMAKE_OP(sf, 8, ., d) { DY &= 0xffffff00; } M68KMAKE_OP(sf, 8, ., .) { m68ki_write_8(M68KMAKE_GET_EA_AY_8, 0); } M68KMAKE_OP(scc, 8, ., d) { if(M68KMAKE_CC) { DY |= 0xff; USE_CYCLES(CYC_SCC_R_TRUE); return; } DY &= 0xffffff00; } M68KMAKE_OP(scc, 8, ., .) { m68ki_write_8(M68KMAKE_GET_EA_AY_8, M68KMAKE_CC ? 0xff : 0); } M68KMAKE_OP(stop, 0, ., .) { if(FLAG_S) { uint new_sr = OPER_I_16(); m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */ CPU_STOPPED |= STOP_LEVEL_STOP; m68ki_set_sr(new_sr); m68ki_remaining_cycles = 0; return; } m68ki_exception_privilege_violation(); } M68KMAKE_OP(sub, 8, er, d) { uint* r_dst = &DX; uint src = MASK_OUT_ABOVE_8(DY); uint dst = MASK_OUT_ABOVE_8(*r_dst); uint res = dst - src; FLAG_N = NFLAG_8(res); FLAG_X = FLAG_C = CFLAG_8(res); FLAG_V = VFLAG_SUB_8(src, dst, res); FLAG_Z = MASK_OUT_ABOVE_8(res); *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; } M68KMAKE_OP(sub, 8, er, .) { uint* r_dst = &DX; uint src = M68KMAKE_GET_OPER_AY_8; uint dst = MASK_OUT_ABOVE_8(*r_dst); uint res = dst - src; FLAG_N = NFLAG_8(res); FLAG_X = FLAG_C = CFLAG_8(res); FLAG_V = VFLAG_SUB_8(src, dst, res); FLAG_Z = MASK_OUT_ABOVE_8(res); *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; } M68KMAKE_OP(sub, 16, er, d) { uint* r_dst = &DX; uint src = MASK_OUT_ABOVE_16(DY); uint dst = MASK_OUT_ABOVE_16(*r_dst); uint res = dst - src; FLAG_N = NFLAG_16(res); FLAG_X = FLAG_C = CFLAG_16(res); FLAG_V = VFLAG_SUB_16(src, dst, res); FLAG_Z = MASK_OUT_ABOVE_16(res); *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; } M68KMAKE_OP(sub, 16, er, a) { uint* r_dst = &DX; uint src = MASK_OUT_ABOVE_16(AY); uint dst = MASK_OUT_ABOVE_16(*r_dst); uint res = dst - src; FLAG_N = NFLAG_16(res); FLAG_X = FLAG_C = CFLAG_16(res); FLAG_V = VFLAG_SUB_16(src, dst, res); FLAG_Z = MASK_OUT_ABOVE_16(res); *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; } M68KMAKE_OP(sub, 16, er, .) { uint* r_dst = &DX; uint src = M68KMAKE_GET_OPER_AY_16; uint dst = MASK_OUT_ABOVE_16(*r_dst); uint res = dst - src; FLAG_N = NFLAG_16(res); FLAG_X = FLAG_C = CFLAG_16(res); FLAG_V = VFLAG_SUB_16(src, dst, res); FLAG_Z = MASK_OUT_ABOVE_16(res); *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; } M68KMAKE_OP(sub, 32, er, d) { uint* r_dst = &DX; uint src = DY; uint dst = *r_dst; uint res = dst - src; FLAG_N = NFLAG_32(res); FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); FLAG_V = VFLAG_SUB_32(src, dst, res); FLAG_Z = MASK_OUT_ABOVE_32(res); *r_dst = FLAG_Z; } M68KMAKE_OP(sub, 32, er, a) { uint* r_dst = &DX; uint src = AY; uint dst = *r_dst; uint res = dst - src; FLAG_N = NFLAG_32(res); FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); FLAG_V = VFLAG_SUB_32(src, dst, res); FLAG_Z = MASK_OUT_ABOVE_32(res); *r_dst = FLAG_Z; } M68KMAKE_OP(sub, 32, er, .) { uint* r_dst = &DX; uint src = M68KMAKE_GET_OPER_AY_32; uint dst = *r_dst; uint res = dst - src; FLAG_N = NFLAG_32(res); FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); FLAG_V = VFLAG_SUB_32(src, dst, res); FLAG_Z = MASK_OUT_ABOVE_32(res); *r_dst = FLAG_Z; } M68KMAKE_OP(sub, 8, re, .) { uint ea = M68KMAKE_GET_EA_AY_8; uint src = MASK_OUT_ABOVE_8(DX); uint dst = m68ki_read_8(ea); uint res = dst - src; FLAG_N = NFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); FLAG_X = FLAG_C = CFLAG_8(res); FLAG_V = VFLAG_SUB_8(src, dst, res); m68ki_write_8(ea, FLAG_Z); } M68KMAKE_OP(sub, 16, re, .) { uint ea = M68KMAKE_GET_EA_AY_16; uint src = MASK_OUT_ABOVE_16(DX); uint dst = m68ki_read_16(ea); uint res = dst - src; FLAG_N = NFLAG_16(res); FLAG_Z = MASK_OUT_ABOVE_16(res); FLAG_X = FLAG_C = CFLAG_16(res); FLAG_V = VFLAG_SUB_16(src, dst, res); m68ki_write_16(ea, FLAG_Z); } M68KMAKE_OP(sub, 32, re, .) { uint ea = M68KMAKE_GET_EA_AY_32; uint src = DX; uint dst = m68ki_read_32(ea); uint res = dst - src; FLAG_N = NFLAG_32(res); FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); FLAG_V = VFLAG_SUB_32(src, dst, res); m68ki_write_32(ea, FLAG_Z); } M68KMAKE_OP(suba, 16, ., d) { uint* r_dst = &AX; *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(DY)); } M68KMAKE_OP(suba, 16, ., a) { uint* r_dst = &AX; *r_dst = MASK_OUT_ABOVE_32(*r_dst - MAKE_INT_16(AY)); } M68KMAKE_OP(suba, 16, ., .) { signed short src = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16); uint* r_dst = &AX; *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); } M68KMAKE_OP(suba, 32, ., d) { uint* r_dst = &AX; *r_dst = MASK_OUT_ABOVE_32(*r_dst - DY); } M68KMAKE_OP(suba, 32, ., a) { uint* r_dst = &AX; *r_dst = MASK_OUT_ABOVE_32(*r_dst - AY); } M68KMAKE_OP(suba, 32, ., .) { uint src = M68KMAKE_GET_OPER_AY_32; uint* r_dst = &AX; *r_dst = MASK_OUT_ABOVE_32(*r_dst - src); } M68KMAKE_OP(subi, 8, ., d) { uint* r_dst = &DY; uint src = OPER_I_8(); uint dst = MASK_OUT_ABOVE_8(*r_dst); uint res = dst - src; FLAG_N = NFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); FLAG_X = FLAG_C = CFLAG_8(res); FLAG_V = VFLAG_SUB_8(src, dst, res); *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; } M68KMAKE_OP(subi, 8, ., .) { uint src = OPER_I_8(); uint ea = M68KMAKE_GET_EA_AY_8; uint dst = m68ki_read_8(ea); uint res = dst - src; FLAG_N = NFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); FLAG_X = FLAG_C = CFLAG_8(res); FLAG_V = VFLAG_SUB_8(src, dst, res); m68ki_write_8(ea, FLAG_Z); } M68KMAKE_OP(subi, 16, ., d) { uint* r_dst = &DY; uint src = OPER_I_16(); uint dst = MASK_OUT_ABOVE_16(*r_dst); uint res = dst - src; FLAG_N = NFLAG_16(res); FLAG_Z = MASK_OUT_ABOVE_16(res); FLAG_X = FLAG_C = CFLAG_16(res); FLAG_V = VFLAG_SUB_16(src, dst, res); *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; } M68KMAKE_OP(subi, 16, ., .) { uint src = OPER_I_16(); uint ea = M68KMAKE_GET_EA_AY_16; uint dst = m68ki_read_16(ea); uint res = dst - src; FLAG_N = NFLAG_16(res); FLAG_Z = MASK_OUT_ABOVE_16(res); FLAG_X = FLAG_C = CFLAG_16(res); FLAG_V = VFLAG_SUB_16(src, dst, res); m68ki_write_16(ea, FLAG_Z); } M68KMAKE_OP(subi, 32, ., d) { uint* r_dst = &DY; uint src = OPER_I_32(); uint dst = *r_dst; uint res = dst - src; FLAG_N = NFLAG_32(res); FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); FLAG_V = VFLAG_SUB_32(src, dst, res); *r_dst = FLAG_Z; } M68KMAKE_OP(subi, 32, ., .) { uint src = OPER_I_32(); uint ea = M68KMAKE_GET_EA_AY_32; uint dst = m68ki_read_32(ea); uint res = dst - src; FLAG_N = NFLAG_32(res); FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); FLAG_V = VFLAG_SUB_32(src, dst, res); m68ki_write_32(ea, FLAG_Z); } M68KMAKE_OP(subq, 8, ., d) { uint* r_dst = &DY; uint src = (((REG_IR >> 9) - 1) & 7) + 1; uint dst = MASK_OUT_ABOVE_8(*r_dst); uint res = dst - src; FLAG_N = NFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); FLAG_X = FLAG_C = CFLAG_8(res); FLAG_V = VFLAG_SUB_8(src, dst, res); *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; } M68KMAKE_OP(subq, 8, ., .) { uint src = (((REG_IR >> 9) - 1) & 7) + 1; uint ea = M68KMAKE_GET_EA_AY_8; uint dst = m68ki_read_8(ea); uint res = dst - src; FLAG_N = NFLAG_8(res); FLAG_Z = MASK_OUT_ABOVE_8(res); FLAG_X = FLAG_C = CFLAG_8(res); FLAG_V = VFLAG_SUB_8(src, dst, res); m68ki_write_8(ea, FLAG_Z); } M68KMAKE_OP(subq, 16, ., d) { uint* r_dst = &DY; uint src = (((REG_IR >> 9) - 1) & 7) + 1; uint dst = MASK_OUT_ABOVE_16(*r_dst); uint res = dst - src; FLAG_N = NFLAG_16(res); FLAG_Z = MASK_OUT_ABOVE_16(res); FLAG_X = FLAG_C = CFLAG_16(res); FLAG_V = VFLAG_SUB_16(src, dst, res); *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; } M68KMAKE_OP(subq, 16, ., a) { uint* r_dst = &AY; *r_dst = MASK_OUT_ABOVE_32(*r_dst - ((((REG_IR >> 9) - 1) & 7) + 1)); } M68KMAKE_OP(subq, 16, ., .) { uint src = (((REG_IR >> 9) - 1) & 7) + 1; uint ea = M68KMAKE_GET_EA_AY_16; uint dst = m68ki_read_16(ea); uint res = dst - src; FLAG_N = NFLAG_16(res); FLAG_Z = MASK_OUT_ABOVE_16(res); FLAG_X = FLAG_C = CFLAG_16(res); FLAG_V = VFLAG_SUB_16(src, dst, res); m68ki_write_16(ea, FLAG_Z); } M68KMAKE_OP(subq, 32, ., d) { uint* r_dst = &DY; uint src = (((REG_IR >> 9) - 1) & 7) + 1; uint dst = *r_dst; uint res = dst - src; FLAG_N = NFLAG_32(res); FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); FLAG_V = VFLAG_SUB_32(src, dst, res); *r_dst = FLAG_Z; } M68KMAKE_OP(subq, 32, ., a) { uint* r_dst = &AY; *r_dst = MASK_OUT_ABOVE_32(*r_dst - ((((REG_IR >> 9) - 1) & 7) + 1)); } M68KMAKE_OP(subq, 32, ., .) { uint src = (((REG_IR >> 9) - 1) & 7) + 1; uint ea = M68KMAKE_GET_EA_AY_32; uint dst = m68ki_read_32(ea); uint res = dst - src; FLAG_N = NFLAG_32(res); FLAG_Z = MASK_OUT_ABOVE_32(res); FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); FLAG_V = VFLAG_SUB_32(src, dst, res); m68ki_write_32(ea, FLAG_Z); } M68KMAKE_OP(subx, 8, rr, .) { uint* r_dst = &DX; uint src = MASK_OUT_ABOVE_8(DY); uint dst = MASK_OUT_ABOVE_8(*r_dst); uint res = dst - src - XFLAG_AS_1(); FLAG_N = NFLAG_8(res); FLAG_X = FLAG_C = CFLAG_8(res); FLAG_V = VFLAG_SUB_8(src, dst, res); res = MASK_OUT_ABOVE_8(res); FLAG_Z |= res; *r_dst = MASK_OUT_BELOW_8(*r_dst) | res; } M68KMAKE_OP(subx, 16, rr, .) { uint* r_dst = &DX; uint src = MASK_OUT_ABOVE_16(DY); uint dst = MASK_OUT_ABOVE_16(*r_dst); uint res = dst - src - XFLAG_AS_1(); FLAG_N = NFLAG_16(res); FLAG_X = FLAG_C = CFLAG_16(res); FLAG_V = VFLAG_SUB_16(src, dst, res); res = MASK_OUT_ABOVE_16(res); FLAG_Z |= res; *r_dst = MASK_OUT_BELOW_16(*r_dst) | res; } M68KMAKE_OP(subx, 32, rr, .) { uint* r_dst = &DX; uint src = DY; uint dst = *r_dst; uint res = dst - src - XFLAG_AS_1(); FLAG_N = NFLAG_32(res); FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); FLAG_V = VFLAG_SUB_32(src, dst, res); res = MASK_OUT_ABOVE_32(res); FLAG_Z |= res; *r_dst = res; } M68KMAKE_OP(subx, 8, mm, ax7) { uint src = OPER_AY_PD_8(); uint ea = EA_A7_PD_8(); uint dst = m68ki_read_8(ea); uint res = dst - src - XFLAG_AS_1(); FLAG_N = NFLAG_8(res); FLAG_X = FLAG_C = CFLAG_8(res); FLAG_V = VFLAG_SUB_8(src, dst, res); res = MASK_OUT_ABOVE_8(res); FLAG_Z |= res; m68ki_write_8(ea, res); } M68KMAKE_OP(subx, 8, mm, ay7) { uint src = OPER_A7_PD_8(); uint ea = EA_AX_PD_8(); uint dst = m68ki_read_8(ea); uint res = dst - src - XFLAG_AS_1(); FLAG_N = NFLAG_8(res); FLAG_X = FLAG_C = CFLAG_8(res); FLAG_V = VFLAG_SUB_8(src, dst, res); res = MASK_OUT_ABOVE_8(res); FLAG_Z |= res; m68ki_write_8(ea, res); } M68KMAKE_OP(subx, 8, mm, axy7) { uint src = OPER_A7_PD_8(); uint ea = EA_A7_PD_8(); uint dst = m68ki_read_8(ea); uint res = dst - src - XFLAG_AS_1(); FLAG_N = NFLAG_8(res); FLAG_X = FLAG_C = CFLAG_8(res); FLAG_V = VFLAG_SUB_8(src, dst, res); res = MASK_OUT_ABOVE_8(res); FLAG_Z |= res; m68ki_write_8(ea, res); } M68KMAKE_OP(subx, 8, mm, .) { uint src = OPER_AY_PD_8(); uint ea = EA_AX_PD_8(); uint dst = m68ki_read_8(ea); uint res = dst - src - XFLAG_AS_1(); FLAG_N = NFLAG_8(res); FLAG_X = FLAG_C = CFLAG_8(res); FLAG_V = VFLAG_SUB_8(src, dst, res); res = MASK_OUT_ABOVE_8(res); FLAG_Z |= res; m68ki_write_8(ea, res); } M68KMAKE_OP(subx, 16, mm, .) { uint src = OPER_AY_PD_16(); uint ea = EA_AX_PD_16(); uint dst = m68ki_read_16(ea); uint res = dst - src - XFLAG_AS_1(); FLAG_N = NFLAG_16(res); FLAG_X = FLAG_C = CFLAG_16(res); FLAG_V = VFLAG_SUB_16(src, dst, res); res = MASK_OUT_ABOVE_16(res); FLAG_Z |= res; m68ki_write_16(ea, res); } M68KMAKE_OP(subx, 32, mm, .) { uint src = OPER_AY_PD_32(); uint ea = EA_AX_PD_32(); uint dst = m68ki_read_32(ea); uint res = dst - src - XFLAG_AS_1(); FLAG_N = NFLAG_32(res); FLAG_X = FLAG_C = CFLAG_SUB_32(src, dst, res); FLAG_V = VFLAG_SUB_32(src, dst, res); res = MASK_OUT_ABOVE_32(res); FLAG_Z |= res; m68ki_write_32(ea, res); } M68KMAKE_OP(swap, 32, ., .) { uint* r_dst = &DY; FLAG_Z = MASK_OUT_ABOVE_32(*r_dst<<16); *r_dst = (*r_dst>>16) | FLAG_Z; FLAG_Z = *r_dst; FLAG_N = NFLAG_32(*r_dst); FLAG_C = CFLAG_CLEAR; FLAG_V = VFLAG_CLEAR; } M68KMAKE_OP(tas, 8, ., d) { uint* r_dst = &DY; FLAG_Z = MASK_OUT_ABOVE_8(*r_dst); FLAG_N = NFLAG_8(*r_dst); FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; *r_dst |= 0x80; } M68KMAKE_OP(tas, 8, ., .) { uint ea = M68KMAKE_GET_EA_AY_8; uint dst = m68ki_read_8(ea); FLAG_Z = dst; FLAG_N = NFLAG_8(dst); FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; m68ki_write_8(ea, dst | 0x80); } M68KMAKE_OP(trap, 0, ., .) { /* Trap#n stacks exception frame type 0 */ m68ki_exception_trapN(EXCEPTION_TRAP_BASE + (REG_IR & 0xf)); /* HJB 990403 */ } M68KMAKE_OP(trapt, 0, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ return; } m68ki_exception_illegal(); } M68KMAKE_OP(trapt, 16, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ return; } m68ki_exception_illegal(); } M68KMAKE_OP(trapt, 32, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ return; } m68ki_exception_illegal(); } M68KMAKE_OP(trapf, 0, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { return; } m68ki_exception_illegal(); } M68KMAKE_OP(trapf, 16, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { REG_PC += 2; return; } m68ki_exception_illegal(); } M68KMAKE_OP(trapf, 32, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { REG_PC += 4; return; } m68ki_exception_illegal(); } M68KMAKE_OP(trapcc, 0, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { if(M68KMAKE_CC) m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ return; } m68ki_exception_illegal(); } M68KMAKE_OP(trapcc, 16, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { if(M68KMAKE_CC) { m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ return; } REG_PC += 2; return; } m68ki_exception_illegal(); } M68KMAKE_OP(trapcc, 32, ., .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { if(M68KMAKE_CC) { m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ return; } REG_PC += 4; return; } m68ki_exception_illegal(); } M68KMAKE_OP(trapv, 0, ., .) { if(COND_VC()) { return; } m68ki_exception_trap(EXCEPTION_TRAPV); /* HJB 990403 */ } M68KMAKE_OP(tst, 8, ., d) { uint res = MASK_OUT_ABOVE_8(DY); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(tst, 8, ., .) { uint res = M68KMAKE_GET_OPER_AY_8; FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(tst, 8, ., pcdi) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint res = OPER_PCDI_8(); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; return; } m68ki_exception_illegal(); } M68KMAKE_OP(tst, 8, ., pcix) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint res = OPER_PCIX_8(); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; return; } m68ki_exception_illegal(); } M68KMAKE_OP(tst, 8, ., i) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint res = OPER_I_8(); FLAG_N = NFLAG_8(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; return; } m68ki_exception_illegal(); } M68KMAKE_OP(tst, 16, ., d) { uint res = MASK_OUT_ABOVE_16(DY); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(tst, 16, ., a) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint res = MAKE_INT_16(AY); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; return; } m68ki_exception_illegal(); } M68KMAKE_OP(tst, 16, ., .) { uint res = M68KMAKE_GET_OPER_AY_16; FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(tst, 16, ., pcdi) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint res = OPER_PCDI_16(); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; return; } m68ki_exception_illegal(); } M68KMAKE_OP(tst, 16, ., pcix) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint res = OPER_PCIX_16(); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; return; } m68ki_exception_illegal(); } M68KMAKE_OP(tst, 16, ., i) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint res = OPER_I_16(); FLAG_N = NFLAG_16(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; return; } m68ki_exception_illegal(); } M68KMAKE_OP(tst, 32, ., d) { uint res = DY; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(tst, 32, ., a) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint res = AY; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; return; } m68ki_exception_illegal(); } M68KMAKE_OP(tst, 32, ., .) { uint res = M68KMAKE_GET_OPER_AY_32; FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; } M68KMAKE_OP(tst, 32, ., pcdi) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint res = OPER_PCDI_32(); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; return; } m68ki_exception_illegal(); } M68KMAKE_OP(tst, 32, ., pcix) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint res = OPER_PCIX_32(); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; return; } m68ki_exception_illegal(); } M68KMAKE_OP(tst, 32, ., i) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint res = OPER_I_32(); FLAG_N = NFLAG_32(res); FLAG_Z = res; FLAG_V = VFLAG_CLEAR; FLAG_C = CFLAG_CLEAR; return; } m68ki_exception_illegal(); } M68KMAKE_OP(unlk, 32, ., a7) { REG_A[7] = m68ki_read_32(REG_A[7]); } M68KMAKE_OP(unlk, 32, ., .) { uint* r_dst = &AY; REG_A[7] = *r_dst; *r_dst = m68ki_pull_32(); } M68KMAKE_OP(unpk, 16, rr, .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { /* Note: DX and DY are reversed in Motorola's docs */ uint src = DY; uint* r_dst = &DX; *r_dst = MASK_OUT_BELOW_16(*r_dst) | (((((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16()) & 0xffff); return; } m68ki_exception_illegal(); } M68KMAKE_OP(unpk, 16, mm, ax7) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { /* Note: AX and AY are reversed in Motorola's docs */ uint src = OPER_AY_PD_8(); uint ea_dst; src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16(); ea_dst = EA_A7_PD_8(); m68ki_write_8(ea_dst, (src >> 8) & 0xff); ea_dst = EA_A7_PD_8(); m68ki_write_8(ea_dst, src & 0xff); return; } m68ki_exception_illegal(); } M68KMAKE_OP(unpk, 16, mm, ay7) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { /* Note: AX and AY are reversed in Motorola's docs */ uint src = OPER_A7_PD_8(); uint ea_dst; src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16(); ea_dst = EA_AX_PD_8(); m68ki_write_8(ea_dst, (src >> 8) & 0xff); ea_dst = EA_AX_PD_8(); m68ki_write_8(ea_dst, src & 0xff); return; } m68ki_exception_illegal(); } M68KMAKE_OP(unpk, 16, mm, axy7) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { uint src = OPER_A7_PD_8(); uint ea_dst; src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16(); ea_dst = EA_A7_PD_8(); m68ki_write_8(ea_dst, (src >> 8) & 0xff); ea_dst = EA_A7_PD_8(); m68ki_write_8(ea_dst, src & 0xff); return; } m68ki_exception_illegal(); } M68KMAKE_OP(unpk, 16, mm, .) { if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { /* Note: AX and AY are reversed in Motorola's docs */ uint src = OPER_AY_PD_8(); uint ea_dst; src = (((src << 4) & 0x0f00) | (src & 0x000f)) + OPER_I_16(); ea_dst = EA_AX_PD_8(); m68ki_write_8(ea_dst, (src >> 8) & 0xff); ea_dst = EA_AX_PD_8(); m68ki_write_8(ea_dst, src & 0xff); return; } m68ki_exception_illegal(); } XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX M68KMAKE_END yabause-0.9.15/src/musashi/m68kcpu.h000644 001750 001750 00000173316 12755623101 021174 0ustar00guillaumeguillaume000000 000000 /* ======================================================================== */ /* ========================= LICENSING & COPYRIGHT ======================== */ /* ======================================================================== */ /* * MUSASHI * Version 3.4 * * A portable Motorola M680x0 processor emulation engine. * Copyright 1998-2001 Karl Stenerud. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef M68KCPU__HEADER #define M68KCPU__HEADER #include "m68k.h" #include #if M68K_EMULATE_ADDRESS_ERROR #include #endif /* M68K_EMULATE_ADDRESS_ERROR */ /* ======================================================================== */ /* ==================== ARCHITECTURE-DEPENDANT DEFINES ==================== */ /* ======================================================================== */ /* Check for > 32bit sizes */ #if UINT_MAX > 0xffffffff #define M68K_INT_GT_32_BIT 1 #else #define M68K_INT_GT_32_BIT 0 #endif /* Data types used in this emulation core */ #undef sint8 #undef sint16 #undef sint32 #undef sint64 #undef uint8 #undef uint16 #undef uint32 #undef uint64 #undef sint #undef uint #define sint8 signed char /* ASG: changed from char to signed char */ #define sint16 signed short #define sint32 signed long #define uint8 unsigned char #define uint16 unsigned short #define uint32 unsigned long /* signed and unsigned int must be at least 32 bits wide */ #define sint signed int #define uint unsigned int #if M68K_USE_64_BIT #define sint64 signed long long #define uint64 unsigned long long #else #define sint64 sint32 #define uint64 uint32 #endif /* M68K_USE_64_BIT */ /* Allow for architectures that don't have 8-bit sizes */ #if UCHAR_MAX == 0xff #define MAKE_INT_8(A) (sint8)(A) #else #undef sint8 #define sint8 signed int #undef uint8 #define uint8 unsigned int INLINE sint MAKE_INT_8(uint value) { return (value & 0x80) ? value | ~0xff : value & 0xff; } #endif /* UCHAR_MAX == 0xff */ /* Allow for architectures that don't have 16-bit sizes */ #if USHRT_MAX == 0xffff #define MAKE_INT_16(A) (sint16)(A) #else #undef sint16 #define sint16 signed int #undef uint16 #define uint16 unsigned int INLINE sint MAKE_INT_16(uint value) { return (value & 0x8000) ? value | ~0xffff : value & 0xffff; } #endif /* USHRT_MAX == 0xffff */ /* Allow for architectures that don't have 32-bit sizes */ #if ULONG_MAX == 0xffffffff #define MAKE_INT_32(A) (sint32)(A) #else #undef sint32 #define sint32 signed int #undef uint32 #define uint32 unsigned int INLINE sint MAKE_INT_32(uint value) { return (value & 0x80000000) ? value | ~0xffffffff : value & 0xffffffff; } #endif /* ULONG_MAX == 0xffffffff */ /* ======================================================================== */ /* ============================ GENERAL DEFINES =========================== */ /* ======================================================================== */ /* Exception Vectors handled by emulation */ #define EXCEPTION_BUS_ERROR 2 /* This one is not emulated! */ #define EXCEPTION_ADDRESS_ERROR 3 /* This one is partially emulated (doesn't stack a proper frame yet) */ #define EXCEPTION_ILLEGAL_INSTRUCTION 4 #define EXCEPTION_ZERO_DIVIDE 5 #define EXCEPTION_CHK 6 #define EXCEPTION_TRAPV 7 #define EXCEPTION_PRIVILEGE_VIOLATION 8 #define EXCEPTION_TRACE 9 #define EXCEPTION_1010 10 #define EXCEPTION_1111 11 #define EXCEPTION_FORMAT_ERROR 14 #define EXCEPTION_UNINITIALIZED_INTERRUPT 15 #define EXCEPTION_SPURIOUS_INTERRUPT 24 #define EXCEPTION_INTERRUPT_AUTOVECTOR 24 #define EXCEPTION_TRAP_BASE 32 /* Function codes set by CPU during data/address bus activity */ #define FUNCTION_CODE_USER_DATA 1 #define FUNCTION_CODE_USER_PROGRAM 2 #define FUNCTION_CODE_SUPERVISOR_DATA 5 #define FUNCTION_CODE_SUPERVISOR_PROGRAM 6 #define FUNCTION_CODE_CPU_SPACE 7 /* CPU types for deciding what to emulate */ #define CPU_TYPE_000 1 #define CPU_TYPE_010 2 #define CPU_TYPE_EC020 4 #define CPU_TYPE_020 8 /* Different ways to stop the CPU */ #define STOP_LEVEL_STOP 1 #define STOP_LEVEL_HALT 2 /* Used for 68000 address error processing */ #define INSTRUCTION_YES 0 #define INSTRUCTION_NO 0x08 #define MODE_READ 0x10 #define MODE_WRITE 0 #define RUN_MODE_NORMAL 0 #define RUN_MODE_BERR_AERR_RESET 1 #ifndef NULL #define NULL ((void*)0) #endif /* ======================================================================== */ /* ================================ MACROS ================================ */ /* ======================================================================== */ /* ---------------------------- General Macros ---------------------------- */ /* Bit Isolation Macros */ #define BIT_0(A) ((A) & 0x00000001) #define BIT_1(A) ((A) & 0x00000002) #define BIT_2(A) ((A) & 0x00000004) #define BIT_3(A) ((A) & 0x00000008) #define BIT_4(A) ((A) & 0x00000010) #define BIT_5(A) ((A) & 0x00000020) #define BIT_6(A) ((A) & 0x00000040) #define BIT_7(A) ((A) & 0x00000080) #define BIT_8(A) ((A) & 0x00000100) #define BIT_9(A) ((A) & 0x00000200) #define BIT_A(A) ((A) & 0x00000400) #define BIT_B(A) ((A) & 0x00000800) #define BIT_C(A) ((A) & 0x00001000) #define BIT_D(A) ((A) & 0x00002000) #define BIT_E(A) ((A) & 0x00004000) #define BIT_F(A) ((A) & 0x00008000) #define BIT_10(A) ((A) & 0x00010000) #define BIT_11(A) ((A) & 0x00020000) #define BIT_12(A) ((A) & 0x00040000) #define BIT_13(A) ((A) & 0x00080000) #define BIT_14(A) ((A) & 0x00100000) #define BIT_15(A) ((A) & 0x00200000) #define BIT_16(A) ((A) & 0x00400000) #define BIT_17(A) ((A) & 0x00800000) #define BIT_18(A) ((A) & 0x01000000) #define BIT_19(A) ((A) & 0x02000000) #define BIT_1A(A) ((A) & 0x04000000) #define BIT_1B(A) ((A) & 0x08000000) #define BIT_1C(A) ((A) & 0x10000000) #define BIT_1D(A) ((A) & 0x20000000) #define BIT_1E(A) ((A) & 0x40000000) #define BIT_1F(A) ((A) & 0x80000000) /* Get the most significant bit for specific sizes */ #define GET_MSB_8(A) ((A) & 0x80) #define GET_MSB_9(A) ((A) & 0x100) #define GET_MSB_16(A) ((A) & 0x8000) #define GET_MSB_17(A) ((A) & 0x10000) #define GET_MSB_32(A) ((A) & 0x80000000) #if M68K_USE_64_BIT #define GET_MSB_33(A) ((A) & 0x100000000) #endif /* M68K_USE_64_BIT */ /* Isolate nibbles */ #define LOW_NIBBLE(A) ((A) & 0x0f) #define HIGH_NIBBLE(A) ((A) & 0xf0) /* These are used to isolate 8, 16, and 32 bit sizes */ #define MASK_OUT_ABOVE_2(A) ((A) & 3) #define MASK_OUT_ABOVE_8(A) ((A) & 0xff) #define MASK_OUT_ABOVE_16(A) ((A) & 0xffff) #define MASK_OUT_BELOW_2(A) ((A) & ~3) #define MASK_OUT_BELOW_8(A) ((A) & ~0xff) #define MASK_OUT_BELOW_16(A) ((A) & ~0xffff) /* No need to mask if we are 32 bit */ #if M68K_INT_GT_32_BIT || M68K_USE_64_BIT #define MASK_OUT_ABOVE_32(A) ((A) & 0xffffffff) #define MASK_OUT_BELOW_32(A) ((A) & ~0xffffffff) #else #define MASK_OUT_ABOVE_32(A) (A) #define MASK_OUT_BELOW_32(A) 0 #endif /* M68K_INT_GT_32_BIT || M68K_USE_64_BIT */ /* Simulate address lines of 68k family */ #define ADDRESS_68K(A) ((A)&CPU_ADDRESS_MASK) /* Shift & Rotate Macros. */ #define LSL(A, C) ((A) << (C)) #define LSR(A, C) ((A) >> (C)) /* Some > 32-bit optimizations */ #if M68K_INT_GT_32_BIT /* Shift left and right */ #define LSR_32(A, C) ((A) >> (C)) #define LSL_32(A, C) ((A) << (C)) #else /* We have to do this because the morons at ANSI decided that shifts * by >= data size are undefined. */ #define LSR_32(A, C) ((C) < 32 ? (A) >> (C) : 0) #define LSL_32(A, C) ((C) < 32 ? (A) << (C) : 0) #endif /* M68K_INT_GT_32_BIT */ #if M68K_USE_64_BIT #define LSL_32_64(A, C) ((A) << (C)) #define LSR_32_64(A, C) ((A) >> (C)) #define ROL_33_64(A, C) (LSL_32_64(A, C) | LSR_32_64(A, 33-(C))) #define ROR_33_64(A, C) (LSR_32_64(A, C) | LSL_32_64(A, 33-(C))) #endif /* M68K_USE_64_BIT */ #define ROL_8(A, C) MASK_OUT_ABOVE_8(LSL(A, C) | LSR(A, 8-(C))) #define ROL_9(A, C) (LSL(A, C) | LSR(A, 9-(C))) #define ROL_16(A, C) MASK_OUT_ABOVE_16(LSL(A, C) | LSR(A, 16-(C))) #define ROL_17(A, C) (LSL(A, C) | LSR(A, 17-(C))) #define ROL_32(A, C) MASK_OUT_ABOVE_32(LSL_32(A, C) | LSR_32(A, 32-(C))) #define ROL_33(A, C) (LSL_32(A, C) | LSR_32(A, 33-(C))) #define ROR_8(A, C) MASK_OUT_ABOVE_8(LSR(A, C) | LSL(A, 8-(C))) #define ROR_9(A, C) (LSR(A, C) | LSL(A, 9-(C))) #define ROR_16(A, C) MASK_OUT_ABOVE_16(LSR(A, C) | LSL(A, 16-(C))) #define ROR_17(A, C) (LSR(A, C) | LSL(A, 17-(C))) #define ROR_32(A, C) MASK_OUT_ABOVE_32(LSR_32(A, C) | LSL_32(A, 32-(C))) #define ROR_33(A, C) (LSR_32(A, C) | LSL_32(A, 33-(C))) /* ------------------------------ CPU Access ------------------------------ */ /* Access the CPU registers */ #define CPU_TYPE m68ki_cpu.cpu_type #define REG_DA m68ki_cpu.dar /* easy access to data and address regs */ #define REG_D m68ki_cpu.dar #define REG_A (m68ki_cpu.dar+8) #define REG_PPC m68ki_cpu.ppc #define REG_PC m68ki_cpu.pc #define REG_SP_BASE m68ki_cpu.sp #define REG_USP m68ki_cpu.sp[0] #define REG_ISP m68ki_cpu.sp[4] #define REG_MSP m68ki_cpu.sp[6] #define REG_SP m68ki_cpu.dar[15] #define REG_VBR m68ki_cpu.vbr #define REG_SFC m68ki_cpu.sfc #define REG_DFC m68ki_cpu.dfc #define REG_CACR m68ki_cpu.cacr #define REG_CAAR m68ki_cpu.caar #define REG_IR m68ki_cpu.ir #define FLAG_T1 m68ki_cpu.t1_flag #define FLAG_T0 m68ki_cpu.t0_flag #define FLAG_S m68ki_cpu.s_flag #define FLAG_M m68ki_cpu.m_flag #define FLAG_X m68ki_cpu.x_flag #define FLAG_N m68ki_cpu.n_flag #define FLAG_Z m68ki_cpu.not_z_flag #define FLAG_V m68ki_cpu.v_flag #define FLAG_C m68ki_cpu.c_flag #define FLAG_INT_MASK m68ki_cpu.int_mask #define CPU_INT_LEVEL m68ki_cpu.int_level /* ASG: changed from CPU_INTS_PENDING */ #define CPU_INT_CYCLES m68ki_cpu.int_cycles /* ASG */ #define CPU_STOPPED m68ki_cpu.stopped #define CPU_PREF_ADDR m68ki_cpu.pref_addr #define CPU_PREF_DATA m68ki_cpu.pref_data #define CPU_ADDRESS_MASK m68ki_cpu.address_mask #define CPU_SR_MASK m68ki_cpu.sr_mask #define CPU_INSTR_MODE m68ki_cpu.instr_mode #define CPU_RUN_MODE m68ki_cpu.run_mode #define CYC_INSTRUCTION m68ki_cpu.cyc_instruction #define CYC_EXCEPTION m68ki_cpu.cyc_exception #define CYC_BCC_NOTAKE_B m68ki_cpu.cyc_bcc_notake_b #define CYC_BCC_NOTAKE_W m68ki_cpu.cyc_bcc_notake_w #define CYC_DBCC_F_NOEXP m68ki_cpu.cyc_dbcc_f_noexp #define CYC_DBCC_F_EXP m68ki_cpu.cyc_dbcc_f_exp #define CYC_SCC_R_TRUE m68ki_cpu.cyc_scc_r_true #define CYC_MOVEM_W m68ki_cpu.cyc_movem_w #define CYC_MOVEM_L m68ki_cpu.cyc_movem_l #define CYC_SHIFT m68ki_cpu.cyc_shift #define CYC_RESET m68ki_cpu.cyc_reset #define CALLBACK_INT_ACK m68ki_cpu.int_ack_callback #define CALLBACK_BKPT_ACK m68ki_cpu.bkpt_ack_callback #define CALLBACK_RESET_INSTR m68ki_cpu.reset_instr_callback #define CALLBACK_PC_CHANGED m68ki_cpu.pc_changed_callback #define CALLBACK_SET_FC m68ki_cpu.set_fc_callback #define CALLBACK_INSTR_HOOK m68ki_cpu.instr_hook_callback /* ----------------------------- Configuration ---------------------------- */ /* These defines are dependant on the configuration defines in m68kconf.h */ /* Disable certain comparisons if we're not using all CPU types */ #if M68K_EMULATE_020 #define CPU_TYPE_IS_020_PLUS(A) ((A) & CPU_TYPE_020) #define CPU_TYPE_IS_020_LESS(A) 1 #else #define CPU_TYPE_IS_020_PLUS(A) 0 #define CPU_TYPE_IS_020_LESS(A) 1 #endif #if M68K_EMULATE_EC020 #define CPU_TYPE_IS_EC020_PLUS(A) ((A) & (CPU_TYPE_EC020 | CPU_TYPE_020)) #define CPU_TYPE_IS_EC020_LESS(A) ((A) & (CPU_TYPE_000 | CPU_TYPE_010 | CPU_TYPE_EC020)) #else #define CPU_TYPE_IS_EC020_PLUS(A) CPU_TYPE_IS_020_PLUS(A) #define CPU_TYPE_IS_EC020_LESS(A) CPU_TYPE_IS_020_LESS(A) #endif #if M68K_EMULATE_010 #define CPU_TYPE_IS_010(A) ((A) == CPU_TYPE_010) #define CPU_TYPE_IS_010_PLUS(A) ((A) & (CPU_TYPE_010 | CPU_TYPE_EC020 | CPU_TYPE_020)) #define CPU_TYPE_IS_010_LESS(A) ((A) & (CPU_TYPE_000 | CPU_TYPE_010)) #else #define CPU_TYPE_IS_010(A) 0 #define CPU_TYPE_IS_010_PLUS(A) CPU_TYPE_IS_EC020_PLUS(A) #define CPU_TYPE_IS_010_LESS(A) CPU_TYPE_IS_EC020_LESS(A) #endif #if M68K_EMULATE_020 || M68K_EMULATE_EC020 #define CPU_TYPE_IS_020_VARIANT(A) ((A) & (CPU_TYPE_EC020 | CPU_TYPE_020)) #else #define CPU_TYPE_IS_020_VARIANT(A) 0 #endif #if M68K_EMULATE_020 || M68K_EMULATE_EC020 || M68K_EMULATE_010 #define CPU_TYPE_IS_000(A) ((A) == CPU_TYPE_000) #else #define CPU_TYPE_IS_000(A) 1 #endif #if !M68K_SEPARATE_READS #define m68k_read_immediate_16(A) m68ki_read_program_16(A) #define m68k_read_immediate_32(A) m68ki_read_program_32(A) #define m68k_read_pcrelative_8(A) m68ki_read_program_8(A) #define m68k_read_pcrelative_16(A) m68ki_read_program_16(A) #define m68k_read_pcrelative_32(A) m68ki_read_program_32(A) #endif /* M68K_SEPARATE_READS */ /* Enable or disable callback functions */ #if M68K_EMULATE_INT_ACK #if M68K_EMULATE_INT_ACK == OPT_SPECIFY_HANDLER #define m68ki_int_ack(A) M68K_INT_ACK_CALLBACK(A) #else #define m68ki_int_ack(A) CALLBACK_INT_ACK(A) #endif #else /* Default action is to used autovector mode, which is most common */ #define m68ki_int_ack(A) M68K_INT_ACK_AUTOVECTOR #endif /* M68K_EMULATE_INT_ACK */ #if M68K_EMULATE_BKPT_ACK #if M68K_EMULATE_BKPT_ACK == OPT_SPECIFY_HANDLER #define m68ki_bkpt_ack(A) M68K_BKPT_ACK_CALLBACK(A) #else #define m68ki_bkpt_ack(A) CALLBACK_BKPT_ACK(A) #endif #else #define m68ki_bkpt_ack(A) #endif /* M68K_EMULATE_BKPT_ACK */ #if M68K_EMULATE_RESET #if M68K_EMULATE_RESET == OPT_SPECIFY_HANDLER #define m68ki_output_reset() M68K_RESET_CALLBACK() #else #define m68ki_output_reset() CALLBACK_RESET_INSTR() #endif #else #define m68ki_output_reset() #endif /* M68K_EMULATE_RESET */ #if M68K_INSTRUCTION_HOOK #if M68K_INSTRUCTION_HOOK == OPT_SPECIFY_HANDLER #define m68ki_instr_hook() M68K_INSTRUCTION_CALLBACK() #else #define m68ki_instr_hook() CALLBACK_INSTR_HOOK() #endif #else #define m68ki_instr_hook() #endif /* M68K_INSTRUCTION_HOOK */ #if M68K_MONITOR_PC #if M68K_MONITOR_PC == OPT_SPECIFY_HANDLER #define m68ki_pc_changed(A) M68K_SET_PC_CALLBACK(ADDRESS_68K(A)) #else #define m68ki_pc_changed(A) CALLBACK_PC_CHANGED(ADDRESS_68K(A)) #endif #else #define m68ki_pc_changed(A) #endif /* M68K_MONITOR_PC */ /* Enable or disable function code emulation */ #if M68K_EMULATE_FC #if M68K_EMULATE_FC == OPT_SPECIFY_HANDLER #define m68ki_set_fc(A) M68K_SET_FC_CALLBACK(A) #else #define m68ki_set_fc(A) CALLBACK_SET_FC(A) #endif #define m68ki_use_data_space() m68ki_address_space = FUNCTION_CODE_USER_DATA #define m68ki_use_program_space() m68ki_address_space = FUNCTION_CODE_USER_PROGRAM #define m68ki_get_address_space() m68ki_address_space #else #define m68ki_set_fc(A) #define m68ki_use_data_space() #define m68ki_use_program_space() #define m68ki_get_address_space() FUNCTION_CODE_USER_DATA #endif /* M68K_EMULATE_FC */ /* Enable or disable trace emulation */ #if M68K_EMULATE_TRACE /* Initiates trace checking before each instruction (t1) */ #define m68ki_trace_t1() m68ki_tracing = FLAG_T1 /* adds t0 to trace checking if we encounter change of flow */ #define m68ki_trace_t0() m68ki_tracing |= FLAG_T0 /* Clear all tracing */ #define m68ki_clear_trace() m68ki_tracing = 0 /* Cause a trace exception if we are tracing */ #define m68ki_exception_if_trace() if(m68ki_tracing) m68ki_exception_trace() #else #define m68ki_trace_t1() #define m68ki_trace_t0() #define m68ki_clear_trace() #define m68ki_exception_if_trace() #endif /* M68K_EMULATE_TRACE */ /* Address error */ #if M68K_EMULATE_ADDRESS_ERROR #include extern jmp_buf m68ki_aerr_trap; #define m68ki_set_address_error_trap() \ if(setjmp(m68ki_aerr_trap) != 0) \ { \ m68ki_exception_address_error(); \ if(CPU_STOPPED) \ { \ SET_CYCLES(0); \ CPU_INT_CYCLES = 0; \ return m68ki_initial_cycles; \ } \ } #define m68ki_check_address_error(ADDR, WRITE_MODE, FC) \ if((ADDR)&1) \ { \ m68ki_aerr_address = ADDR; \ m68ki_aerr_write_mode = WRITE_MODE; \ m68ki_aerr_fc = FC; \ longjmp(m68ki_aerr_trap, 1); \ } #else #define m68ki_set_address_error_trap() #define m68ki_check_address_error(ADDR, WRITE_MODE, FC) #endif /* M68K_ADDRESS_ERROR */ /* Logging */ #if M68K_LOG_ENABLE #include extern FILE* M68K_LOG_FILEHANDLE extern char* m68ki_cpu_names[]; #define M68K_DO_LOG(A) if(M68K_LOG_FILEHANDLE) fprintf A #if M68K_LOG_1010_1111 #define M68K_DO_LOG_EMU(A) if(M68K_LOG_FILEHANDLE) fprintf A #else #define M68K_DO_LOG_EMU(A) #endif #else #define M68K_DO_LOG(A) #define M68K_DO_LOG_EMU(A) #endif /* -------------------------- EA / Operand Access ------------------------- */ /* * The general instruction format follows this pattern: * .... XXX. .... .YYY * where XXX is register X and YYY is register Y */ /* Data Register Isolation */ #define DX (REG_D[(REG_IR >> 9) & 7]) #define DY (REG_D[REG_IR & 7]) /* Address Register Isolation */ #define AX (REG_A[(REG_IR >> 9) & 7]) #define AY (REG_A[REG_IR & 7]) /* Effective Address Calculations */ #define EA_AY_AI_8() AY /* address register indirect */ #define EA_AY_AI_16() EA_AY_AI_8() #define EA_AY_AI_32() EA_AY_AI_8() #define EA_AY_PI_8() (AY++) /* postincrement (size = byte) */ #define EA_AY_PI_16() ((AY+=2)-2) /* postincrement (size = word) */ #define EA_AY_PI_32() ((AY+=4)-4) /* postincrement (size = long) */ #define EA_AY_PD_8() (--AY) /* predecrement (size = byte) */ #define EA_AY_PD_16() (AY-=2) /* predecrement (size = word) */ #define EA_AY_PD_32() (AY-=4) /* predecrement (size = long) */ #define EA_AY_DI_8() (AY+MAKE_INT_16(m68ki_read_imm_16())) /* displacement */ #define EA_AY_DI_16() EA_AY_DI_8() #define EA_AY_DI_32() EA_AY_DI_8() #define EA_AY_IX_8() m68ki_get_ea_ix(AY) /* indirect + index */ #define EA_AY_IX_16() EA_AY_IX_8() #define EA_AY_IX_32() EA_AY_IX_8() #define EA_AX_AI_8() AX #define EA_AX_AI_16() EA_AX_AI_8() #define EA_AX_AI_32() EA_AX_AI_8() #define EA_AX_PI_8() (AX++) #define EA_AX_PI_16() ((AX+=2)-2) #define EA_AX_PI_32() ((AX+=4)-4) #define EA_AX_PD_8() (--AX) #define EA_AX_PD_16() (AX-=2) #define EA_AX_PD_32() (AX-=4) #define EA_AX_DI_8() (AX+MAKE_INT_16(m68ki_read_imm_16())) #define EA_AX_DI_16() EA_AX_DI_8() #define EA_AX_DI_32() EA_AX_DI_8() #define EA_AX_IX_8() m68ki_get_ea_ix(AX) #define EA_AX_IX_16() EA_AX_IX_8() #define EA_AX_IX_32() EA_AX_IX_8() #define EA_A7_PI_8() ((REG_A[7]+=2)-2) #define EA_A7_PD_8() (REG_A[7]-=2) #define EA_AW_8() MAKE_INT_16(m68ki_read_imm_16()) /* absolute word */ #define EA_AW_16() EA_AW_8() #define EA_AW_32() EA_AW_8() #define EA_AL_8() m68ki_read_imm_32() /* absolute long */ #define EA_AL_16() EA_AL_8() #define EA_AL_32() EA_AL_8() #define EA_PCDI_8() m68ki_get_ea_pcdi() /* pc indirect + displacement */ #define EA_PCDI_16() EA_PCDI_8() #define EA_PCDI_32() EA_PCDI_8() #define EA_PCIX_8() m68ki_get_ea_pcix() /* pc indirect + index */ #define EA_PCIX_16() EA_PCIX_8() #define EA_PCIX_32() EA_PCIX_8() #define OPER_I_8() m68ki_read_imm_8() #define OPER_I_16() m68ki_read_imm_16() #define OPER_I_32() m68ki_read_imm_32() /* --------------------------- Status Register ---------------------------- */ /* Flag Calculation Macros */ #define CFLAG_8(A) (A) #define CFLAG_16(A) ((A)>>8) #if M68K_INT_GT_32_BIT #define CFLAG_ADD_32(S, D, R) ((R)>>24) #define CFLAG_SUB_32(S, D, R) ((R)>>24) #else #define CFLAG_ADD_32(S, D, R) (((S & D) | (~R & (S | D)))>>23) #define CFLAG_SUB_32(S, D, R) (((S & R) | (~D & (S | R)))>>23) #endif /* M68K_INT_GT_32_BIT */ #define VFLAG_ADD_8(S, D, R) ((S^R) & (D^R)) #define VFLAG_ADD_16(S, D, R) (((S^R) & (D^R))>>8) #define VFLAG_ADD_32(S, D, R) (((S^R) & (D^R))>>24) #define VFLAG_SUB_8(S, D, R) ((S^D) & (R^D)) #define VFLAG_SUB_16(S, D, R) (((S^D) & (R^D))>>8) #define VFLAG_SUB_32(S, D, R) (((S^D) & (R^D))>>24) #define NFLAG_8(A) (A) #define NFLAG_16(A) ((A)>>8) #define NFLAG_32(A) ((A)>>24) #define NFLAG_64(A) ((A)>>56) #define ZFLAG_8(A) MASK_OUT_ABOVE_8(A) #define ZFLAG_16(A) MASK_OUT_ABOVE_16(A) #define ZFLAG_32(A) MASK_OUT_ABOVE_32(A) /* Flag values */ #define NFLAG_SET 0x80 #define NFLAG_CLEAR 0 #define CFLAG_SET 0x100 #define CFLAG_CLEAR 0 #define XFLAG_SET 0x100 #define XFLAG_CLEAR 0 #define VFLAG_SET 0x80 #define VFLAG_CLEAR 0 #define ZFLAG_SET 0 #define ZFLAG_CLEAR 0xffffffff #define SFLAG_SET 4 #define SFLAG_CLEAR 0 #define MFLAG_SET 2 #define MFLAG_CLEAR 0 /* Turn flag values into 1 or 0 */ #define XFLAG_AS_1() ((FLAG_X>>8)&1) #define NFLAG_AS_1() ((FLAG_N>>7)&1) #define VFLAG_AS_1() ((FLAG_V>>7)&1) #define ZFLAG_AS_1() (!FLAG_Z) #define CFLAG_AS_1() ((FLAG_C>>8)&1) /* Conditions */ #define COND_CS() (FLAG_C&0x100) #define COND_CC() (!COND_CS()) #define COND_VS() (FLAG_V&0x80) #define COND_VC() (!COND_VS()) #define COND_NE() FLAG_Z #define COND_EQ() (!COND_NE()) #define COND_MI() (FLAG_N&0x80) #define COND_PL() (!COND_MI()) #define COND_LT() ((FLAG_N^FLAG_V)&0x80) #define COND_GE() (!COND_LT()) #define COND_HI() (COND_CC() && COND_NE()) #define COND_LS() (COND_CS() || COND_EQ()) #define COND_GT() (COND_GE() && COND_NE()) #define COND_LE() (COND_LT() || COND_EQ()) /* Reversed conditions */ #define COND_NOT_CS() COND_CC() #define COND_NOT_CC() COND_CS() #define COND_NOT_VS() COND_VC() #define COND_NOT_VC() COND_VS() #define COND_NOT_NE() COND_EQ() #define COND_NOT_EQ() COND_NE() #define COND_NOT_MI() COND_PL() #define COND_NOT_PL() COND_MI() #define COND_NOT_LT() COND_GE() #define COND_NOT_GE() COND_LT() #define COND_NOT_HI() COND_LS() #define COND_NOT_LS() COND_HI() #define COND_NOT_GT() COND_LE() #define COND_NOT_LE() COND_GT() /* Not real conditions, but here for convenience */ #define COND_XS() (FLAG_X&0x100) #define COND_XC() (!COND_XS) /* Get the condition code register */ #define m68ki_get_ccr() ((COND_XS() >> 4) | \ (COND_MI() >> 4) | \ (COND_EQ() << 2) | \ (COND_VS() >> 6) | \ (COND_CS() >> 8)) /* Get the status register */ #define m68ki_get_sr() ( FLAG_T1 | \ FLAG_T0 | \ (FLAG_S << 11) | \ (FLAG_M << 11) | \ FLAG_INT_MASK | \ m68ki_get_ccr()) /* ---------------------------- Cycle Counting ---------------------------- */ #define ADD_CYCLES(A) m68ki_remaining_cycles += (A) #define USE_CYCLES(A) m68ki_remaining_cycles -= (A) #define SET_CYCLES(A) m68ki_remaining_cycles = A #define GET_CYCLES() m68ki_remaining_cycles #define USE_ALL_CYCLES() m68ki_remaining_cycles %= CYC_INSTRUCTION[REG_IR] /* ----------------------------- Read / Write ----------------------------- */ /* Read from the current address space */ #define m68ki_read_8(A) m68ki_read_8_fc (A, FLAG_S | m68ki_get_address_space()) #define m68ki_read_16(A) m68ki_read_16_fc(A, FLAG_S | m68ki_get_address_space()) #define m68ki_read_32(A) m68ki_read_32_fc(A, FLAG_S | m68ki_get_address_space()) /* Write to the current data space */ #define m68ki_write_8(A, V) m68ki_write_8_fc (A, FLAG_S | FUNCTION_CODE_USER_DATA, V) #define m68ki_write_16(A, V) m68ki_write_16_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA, V) #define m68ki_write_32(A, V) m68ki_write_32_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA, V) #if M68K_SIMULATE_PD_WRITES #define m68ki_write_32_pd(A, V) m68ki_write_32_pd_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA, V) #else #define m68ki_write_32_pd(A, V) m68ki_write_32_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA, V) #endif /* map read immediate 8 to read immediate 16 */ #define m68ki_read_imm_8() MASK_OUT_ABOVE_8(m68ki_read_imm_16()) /* Map PC-relative reads */ #define m68ki_read_pcrel_8(A) m68k_read_pcrelative_8(A) #define m68ki_read_pcrel_16(A) m68k_read_pcrelative_16(A) #define m68ki_read_pcrel_32(A) m68k_read_pcrelative_32(A) /* Read from the program space */ #define m68ki_read_program_8(A) m68ki_read_8_fc(A, FLAG_S | FUNCTION_CODE_USER_PROGRAM) #define m68ki_read_program_16(A) m68ki_read_16_fc(A, FLAG_S | FUNCTION_CODE_USER_PROGRAM) #define m68ki_read_program_32(A) m68ki_read_32_fc(A, FLAG_S | FUNCTION_CODE_USER_PROGRAM) /* Read from the data space */ #define m68ki_read_data_8(A) m68ki_read_8_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA) #define m68ki_read_data_16(A) m68ki_read_16_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA) #define m68ki_read_data_32(A) m68ki_read_32_fc(A, FLAG_S | FUNCTION_CODE_USER_DATA) /* ======================================================================== */ /* =============================== PROTOTYPES ============================= */ /* ======================================================================== */ typedef struct { uint cpu_type; /* CPU Type: 68000, 68010, 68EC020, or 68020 */ uint dar[16]; /* Data and Address Registers */ uint ppc; /* Previous program counter */ uint pc; /* Program Counter */ uint sp[7]; /* User, Interrupt, and Master Stack Pointers */ uint vbr; /* Vector Base Register (m68010+) */ uint sfc; /* Source Function Code Register (m68010+) */ uint dfc; /* Destination Function Code Register (m68010+) */ uint cacr; /* Cache Control Register (m68020, unemulated) */ uint caar; /* Cache Address Register (m68020, unemulated) */ uint ir; /* Instruction Register */ uint t1_flag; /* Trace 1 */ uint t0_flag; /* Trace 0 */ uint s_flag; /* Supervisor */ uint m_flag; /* Master/Interrupt state */ uint x_flag; /* Extend */ uint n_flag; /* Negative */ uint not_z_flag; /* Zero, inverted for speedups */ uint v_flag; /* Overflow */ uint c_flag; /* Carry */ uint int_mask; /* I0-I2 */ uint int_level; /* State of interrupt pins IPL0-IPL2 -- ASG: changed from ints_pending */ uint int_cycles; /* ASG: extra cycles from generated interrupts */ uint stopped; /* Stopped state */ uint pref_addr; /* Last prefetch address */ uint pref_data; /* Data in the prefetch queue */ uint address_mask; /* Available address pins */ uint sr_mask; /* Implemented status register bits */ uint instr_mode; /* Stores whether we are in instruction mode or group 0/1 exception mode */ uint run_mode; /* Stores whether we are processing a reset, bus error, address error, or something else */ /* Clocks required for instructions / exceptions */ uint cyc_bcc_notake_b; uint cyc_bcc_notake_w; uint cyc_dbcc_f_noexp; uint cyc_dbcc_f_exp; uint cyc_scc_r_true; uint cyc_movem_w; uint cyc_movem_l; uint cyc_shift; uint cyc_reset; uint8* cyc_instruction; uint8* cyc_exception; /* Callbacks to host */ int (*int_ack_callback)(int int_line); /* Interrupt Acknowledge */ void (*bkpt_ack_callback)(unsigned int data); /* Breakpoint Acknowledge */ void (*reset_instr_callback)(void); /* Called when a RESET instruction is encountered */ void (*pc_changed_callback)(unsigned int new_pc); /* Called when the PC changes by a large amount */ void (*set_fc_callback)(unsigned int new_fc); /* Called when the CPU function code changes */ void (*instr_hook_callback)(void); /* Called every instruction cycle prior to execution */ } m68ki_cpu_core; extern m68ki_cpu_core m68ki_cpu; extern sint m68ki_remaining_cycles; extern uint m68ki_tracing; extern uint8 m68ki_shift_8_table[]; extern uint16 m68ki_shift_16_table[]; extern uint m68ki_shift_32_table[]; extern uint8 m68ki_exception_cycle_table[][256]; extern uint m68ki_address_space; extern uint8 m68ki_ea_idx_cycle_table[]; extern uint m68ki_aerr_address; extern uint m68ki_aerr_write_mode; extern uint m68ki_aerr_fc; /* Read data immediately after the program counter */ INLINE uint m68ki_read_imm_16(void); INLINE uint m68ki_read_imm_32(void); /* Read data with specific function code */ INLINE uint m68ki_read_8_fc (uint address, uint fc); INLINE uint m68ki_read_16_fc (uint address, uint fc); INLINE uint m68ki_read_32_fc (uint address, uint fc); /* Write data with specific function code */ INLINE void m68ki_write_8_fc (uint address, uint fc, uint value); INLINE void m68ki_write_16_fc(uint address, uint fc, uint value); INLINE void m68ki_write_32_fc(uint address, uint fc, uint value); #if M68K_SIMULATE_PD_WRITES INLINE void m68ki_write_32_pd_fc(uint address, uint fc, uint value); #endif /* M68K_SIMULATE_PD_WRITES */ /* Indexed and PC-relative ea fetching */ INLINE uint m68ki_get_ea_pcdi(void); INLINE uint m68ki_get_ea_pcix(void); INLINE uint m68ki_get_ea_ix(uint An); /* Operand fetching */ INLINE uint OPER_AY_AI_8(void); INLINE uint OPER_AY_AI_16(void); INLINE uint OPER_AY_AI_32(void); INLINE uint OPER_AY_PI_8(void); INLINE uint OPER_AY_PI_16(void); INLINE uint OPER_AY_PI_32(void); INLINE uint OPER_AY_PD_8(void); INLINE uint OPER_AY_PD_16(void); INLINE uint OPER_AY_PD_32(void); INLINE uint OPER_AY_DI_8(void); INLINE uint OPER_AY_DI_16(void); INLINE uint OPER_AY_DI_32(void); INLINE uint OPER_AY_IX_8(void); INLINE uint OPER_AY_IX_16(void); INLINE uint OPER_AY_IX_32(void); INLINE uint OPER_AX_AI_8(void); INLINE uint OPER_AX_AI_16(void); INLINE uint OPER_AX_AI_32(void); INLINE uint OPER_AX_PI_8(void); INLINE uint OPER_AX_PI_16(void); INLINE uint OPER_AX_PI_32(void); INLINE uint OPER_AX_PD_8(void); INLINE uint OPER_AX_PD_16(void); INLINE uint OPER_AX_PD_32(void); INLINE uint OPER_AX_DI_8(void); INLINE uint OPER_AX_DI_16(void); INLINE uint OPER_AX_DI_32(void); INLINE uint OPER_AX_IX_8(void); INLINE uint OPER_AX_IX_16(void); INLINE uint OPER_AX_IX_32(void); INLINE uint OPER_A7_PI_8(void); INLINE uint OPER_A7_PD_8(void); INLINE uint OPER_AW_8(void); INLINE uint OPER_AW_16(void); INLINE uint OPER_AW_32(void); INLINE uint OPER_AL_8(void); INLINE uint OPER_AL_16(void); INLINE uint OPER_AL_32(void); INLINE uint OPER_PCDI_8(void); INLINE uint OPER_PCDI_16(void); INLINE uint OPER_PCDI_32(void); INLINE uint OPER_PCIX_8(void); INLINE uint OPER_PCIX_16(void); INLINE uint OPER_PCIX_32(void); /* Stack operations */ INLINE void m68ki_push_16(uint value); INLINE void m68ki_push_32(uint value); INLINE uint m68ki_pull_16(void); INLINE uint m68ki_pull_32(void); /* Program flow operations */ INLINE void m68ki_jump(uint new_pc); INLINE void m68ki_jump_vector(uint vector); INLINE void m68ki_branch_8(uint offset); INLINE void m68ki_branch_16(uint offset); INLINE void m68ki_branch_32(uint offset); /* Status register operations. */ INLINE void m68ki_set_s_flag(uint value); /* Only bit 2 of value should be set (i.e. 4 or 0) */ INLINE void m68ki_set_sm_flag(uint value); /* only bits 1 and 2 of value should be set */ INLINE void m68ki_set_ccr(uint value); /* set the condition code register */ INLINE void m68ki_set_sr(uint value); /* set the status register */ INLINE void m68ki_set_sr_noint(uint value); /* set the status register */ /* Exception processing */ INLINE uint m68ki_init_exception(void); /* Initial exception processing */ INLINE void m68ki_stack_frame_3word(uint pc, uint sr); /* Stack various frame types */ INLINE void m68ki_stack_frame_buserr(uint sr); INLINE void m68ki_stack_frame_0000(uint pc, uint sr, uint vector); INLINE void m68ki_stack_frame_0001(uint pc, uint sr, uint vector); INLINE void m68ki_stack_frame_0010(uint sr, uint vector); INLINE void m68ki_stack_frame_1000(uint pc, uint sr, uint vector); INLINE void m68ki_stack_frame_1010(uint sr, uint vector, uint pc); INLINE void m68ki_stack_frame_1011(uint sr, uint vector, uint pc); INLINE void m68ki_exception_trap(uint vector); INLINE void m68ki_exception_trapN(uint vector); INLINE void m68ki_exception_trace(void); INLINE void m68ki_exception_privilege_violation(void); INLINE void m68ki_exception_1010(void); INLINE void m68ki_exception_1111(void); INLINE void m68ki_exception_illegal(void); INLINE void m68ki_exception_format_error(void); INLINE void m68ki_exception_address_error(void); INLINE void m68ki_exception_interrupt(uint int_level); INLINE void m68ki_check_interrupts(void); /* ASG: check for interrupts */ /* quick disassembly (used for logging) */ char* m68ki_disassemble_quick(unsigned int pc, unsigned int cpu_type); /* ======================================================================== */ /* =========================== UTILITY FUNCTIONS ========================== */ /* ======================================================================== */ /* ---------------------------- Read Immediate ---------------------------- */ /* Handles all immediate reads, does address error check, function code setting, * and prefetching if they are enabled in m68kconf.h */ INLINE uint m68ki_read_imm_16(void) { m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */ m68ki_check_address_error(REG_PC, MODE_READ, FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */ #if M68K_EMULATE_PREFETCH if(MASK_OUT_BELOW_2(REG_PC) != CPU_PREF_ADDR) { CPU_PREF_ADDR = MASK_OUT_BELOW_2(REG_PC); CPU_PREF_DATA = m68k_read_immediate_32(ADDRESS_68K(CPU_PREF_ADDR)); } REG_PC += 2; return MASK_OUT_ABOVE_16(CPU_PREF_DATA >> ((2-((REG_PC-2)&2))<<3)); #else REG_PC += 2; return m68k_read_immediate_16(ADDRESS_68K(REG_PC-2)); #endif /* M68K_EMULATE_PREFETCH */ } INLINE uint m68ki_read_imm_32(void) { #if M68K_EMULATE_PREFETCH uint temp_val; m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */ m68ki_check_address_error(REG_PC, MODE_READ, FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */ if(MASK_OUT_BELOW_2(REG_PC) != CPU_PREF_ADDR) { CPU_PREF_ADDR = MASK_OUT_BELOW_2(REG_PC); CPU_PREF_DATA = m68k_read_immediate_32(ADDRESS_68K(CPU_PREF_ADDR)); } temp_val = CPU_PREF_DATA; REG_PC += 2; if(MASK_OUT_BELOW_2(REG_PC) != CPU_PREF_ADDR) { CPU_PREF_ADDR = MASK_OUT_BELOW_2(REG_PC); CPU_PREF_DATA = m68k_read_immediate_32(ADDRESS_68K(CPU_PREF_ADDR)); temp_val = MASK_OUT_ABOVE_32((temp_val << 16) | (CPU_PREF_DATA >> 16)); } REG_PC += 2; return temp_val; #else m68ki_set_fc(FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */ m68ki_check_address_error(REG_PC, MODE_READ, FLAG_S | FUNCTION_CODE_USER_PROGRAM); /* auto-disable (see m68kcpu.h) */ REG_PC += 4; return m68k_read_immediate_32(ADDRESS_68K(REG_PC-4)); #endif /* M68K_EMULATE_PREFETCH */ } /* ------------------------- Top level read/write ------------------------- */ /* Handles all memory accesses (except for immediate reads if they are * configured to use separate functions in m68kconf.h). * All memory accesses must go through these top level functions. * These functions will also check for address error and set the function * code if they are enabled in m68kconf.h. */ INLINE uint m68ki_read_8_fc(uint address, uint fc) { m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */ return m68k_read_memory_8(ADDRESS_68K(address)); } INLINE uint m68ki_read_16_fc(uint address, uint fc) { m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */ m68ki_check_address_error(address, MODE_READ, fc); /* auto-disable (see m68kcpu.h) */ return m68k_read_memory_16(ADDRESS_68K(address)); } INLINE uint m68ki_read_32_fc(uint address, uint fc) { m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */ m68ki_check_address_error(address, MODE_READ, fc); /* auto-disable (see m68kcpu.h) */ return m68k_read_memory_32(ADDRESS_68K(address)); } INLINE void m68ki_write_8_fc(uint address, uint fc, uint value) { m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */ m68k_write_memory_8(ADDRESS_68K(address), value); } INLINE void m68ki_write_16_fc(uint address, uint fc, uint value) { m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */ m68ki_check_address_error(address, MODE_WRITE, fc); /* auto-disable (see m68kcpu.h) */ m68k_write_memory_16(ADDRESS_68K(address), value); } INLINE void m68ki_write_32_fc(uint address, uint fc, uint value) { m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */ m68ki_check_address_error(address, MODE_WRITE, fc); /* auto-disable (see m68kcpu.h) */ m68k_write_memory_32(ADDRESS_68K(address), value); } #if M68K_SIMULATE_PD_WRITES INLINE void m68ki_write_32_pd_fc(uint address, uint fc, uint value) { m68ki_set_fc(fc); /* auto-disable (see m68kcpu.h) */ m68ki_check_address_error(address, MODE_WRITE, fc); /* auto-disable (see m68kcpu.h) */ m68k_write_memory_32_pd(ADDRESS_68K(address), value); } #endif /* --------------------- Effective Address Calculation -------------------- */ /* The program counter relative addressing modes cause operands to be * retrieved from program space, not data space. */ INLINE uint m68ki_get_ea_pcdi(void) { uint old_pc = REG_PC; m68ki_use_program_space(); /* auto-disable */ return old_pc + MAKE_INT_16(m68ki_read_imm_16()); } INLINE uint m68ki_get_ea_pcix(void) { m68ki_use_program_space(); /* auto-disable */ return m68ki_get_ea_ix(REG_PC); } /* Indexed addressing modes are encoded as follows: * * Base instruction format: * F E D C B A 9 8 7 6 | 5 4 3 | 2 1 0 * x x x x x x x x x x | 1 1 0 | BASE REGISTER (An) * * Base instruction format for destination EA in move instructions: * F E D C | B A 9 | 8 7 6 | 5 4 3 2 1 0 * x x x x | BASE REG | 1 1 0 | X X X X X X (An) * * Brief extension format: * F | E D C | B | A 9 | 8 | 7 6 5 4 3 2 1 0 * D/A | REGISTER | W/L | SCALE | 0 | DISPLACEMENT * * Full extension format: * F E D C B A 9 8 7 6 5 4 3 2 1 0 * D/A | REGISTER | W/L | SCALE | 1 | BS | IS | BD SIZE | 0 | I/IS * BASE DISPLACEMENT (0, 16, 32 bit) (bd) * OUTER DISPLACEMENT (0, 16, 32 bit) (od) * * D/A: 0 = Dn, 1 = An (Xn) * W/L: 0 = W (sign extend), 1 = L (.SIZE) * SCALE: 00=1, 01=2, 10=4, 11=8 (*SCALE) * BS: 0=add base reg, 1=suppress base reg (An suppressed) * IS: 0=add index, 1=suppress index (Xn suppressed) * BD SIZE: 00=reserved, 01=NULL, 10=Word, 11=Long (size of bd) * * IS I/IS Operation * 0 000 No Memory Indirect * 0 001 indir prex with null outer * 0 010 indir prex with word outer * 0 011 indir prex with long outer * 0 100 reserved * 0 101 indir postx with null outer * 0 110 indir postx with word outer * 0 111 indir postx with long outer * 1 000 no memory indirect * 1 001 mem indir with null outer * 1 010 mem indir with word outer * 1 011 mem indir with long outer * 1 100-111 reserved */ INLINE uint m68ki_get_ea_ix(uint An) { /* An = base register */ uint extension = m68ki_read_imm_16(); uint Xn = 0; /* Index register */ uint bd = 0; /* Base Displacement */ uint od = 0; /* Outer Displacement */ if(CPU_TYPE_IS_010_LESS(CPU_TYPE)) { /* Calculate index */ Xn = REG_DA[extension>>12]; /* Xn */ if(!BIT_B(extension)) /* W/L */ Xn = MAKE_INT_16(Xn); /* Add base register and displacement and return */ return An + Xn + MAKE_INT_8(extension); } /* Brief extension format */ if(!BIT_8(extension)) { /* Calculate index */ Xn = REG_DA[extension>>12]; /* Xn */ if(!BIT_B(extension)) /* W/L */ Xn = MAKE_INT_16(Xn); /* Add scale if proper CPU type */ if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) Xn <<= (extension>>9) & 3; /* SCALE */ /* Add base register and displacement and return */ return An + Xn + MAKE_INT_8(extension); } /* Full extension format */ USE_CYCLES(m68ki_ea_idx_cycle_table[extension&0x3f]); /* Check if base register is present */ if(BIT_7(extension)) /* BS */ An = 0; /* An */ /* Check if index is present */ if(!BIT_6(extension)) /* IS */ { Xn = REG_DA[extension>>12]; /* Xn */ if(!BIT_B(extension)) /* W/L */ Xn = MAKE_INT_16(Xn); Xn <<= (extension>>9) & 3; /* SCALE */ } /* Check if base displacement is present */ if(BIT_5(extension)) /* BD SIZE */ bd = BIT_4(extension) ? m68ki_read_imm_32() : MAKE_INT_16(m68ki_read_imm_16()); /* If no indirect action, we are done */ if(!(extension&7)) /* No Memory Indirect */ return An + bd + Xn; /* Check if outer displacement is present */ if(BIT_1(extension)) /* I/IS: od */ od = BIT_0(extension) ? m68ki_read_imm_32() : MAKE_INT_16(m68ki_read_imm_16()); /* Postindex */ if(BIT_2(extension)) /* I/IS: 0 = preindex, 1 = postindex */ return m68ki_read_32(An + bd) + Xn + od; /* Preindex */ return m68ki_read_32(An + bd + Xn) + od; } /* Fetch operands */ INLINE uint OPER_AY_AI_8(void) {uint ea = EA_AY_AI_8(); return m68ki_read_8(ea); } INLINE uint OPER_AY_AI_16(void) {uint ea = EA_AY_AI_16(); return m68ki_read_16(ea);} INLINE uint OPER_AY_AI_32(void) {uint ea = EA_AY_AI_32(); return m68ki_read_32(ea);} INLINE uint OPER_AY_PI_8(void) {uint ea = EA_AY_PI_8(); return m68ki_read_8(ea); } INLINE uint OPER_AY_PI_16(void) {uint ea = EA_AY_PI_16(); return m68ki_read_16(ea);} INLINE uint OPER_AY_PI_32(void) {uint ea = EA_AY_PI_32(); return m68ki_read_32(ea);} INLINE uint OPER_AY_PD_8(void) {uint ea = EA_AY_PD_8(); return m68ki_read_8(ea); } INLINE uint OPER_AY_PD_16(void) {uint ea = EA_AY_PD_16(); return m68ki_read_16(ea);} INLINE uint OPER_AY_PD_32(void) {uint ea = EA_AY_PD_32(); return m68ki_read_32(ea);} INLINE uint OPER_AY_DI_8(void) {uint ea = EA_AY_DI_8(); return m68ki_read_8(ea); } INLINE uint OPER_AY_DI_16(void) {uint ea = EA_AY_DI_16(); return m68ki_read_16(ea);} INLINE uint OPER_AY_DI_32(void) {uint ea = EA_AY_DI_32(); return m68ki_read_32(ea);} INLINE uint OPER_AY_IX_8(void) {uint ea = EA_AY_IX_8(); return m68ki_read_8(ea); } INLINE uint OPER_AY_IX_16(void) {uint ea = EA_AY_IX_16(); return m68ki_read_16(ea);} INLINE uint OPER_AY_IX_32(void) {uint ea = EA_AY_IX_32(); return m68ki_read_32(ea);} INLINE uint OPER_AX_AI_8(void) {uint ea = EA_AX_AI_8(); return m68ki_read_8(ea); } INLINE uint OPER_AX_AI_16(void) {uint ea = EA_AX_AI_16(); return m68ki_read_16(ea);} INLINE uint OPER_AX_AI_32(void) {uint ea = EA_AX_AI_32(); return m68ki_read_32(ea);} INLINE uint OPER_AX_PI_8(void) {uint ea = EA_AX_PI_8(); return m68ki_read_8(ea); } INLINE uint OPER_AX_PI_16(void) {uint ea = EA_AX_PI_16(); return m68ki_read_16(ea);} INLINE uint OPER_AX_PI_32(void) {uint ea = EA_AX_PI_32(); return m68ki_read_32(ea);} INLINE uint OPER_AX_PD_8(void) {uint ea = EA_AX_PD_8(); return m68ki_read_8(ea); } INLINE uint OPER_AX_PD_16(void) {uint ea = EA_AX_PD_16(); return m68ki_read_16(ea);} INLINE uint OPER_AX_PD_32(void) {uint ea = EA_AX_PD_32(); return m68ki_read_32(ea);} INLINE uint OPER_AX_DI_8(void) {uint ea = EA_AX_DI_8(); return m68ki_read_8(ea); } INLINE uint OPER_AX_DI_16(void) {uint ea = EA_AX_DI_16(); return m68ki_read_16(ea);} INLINE uint OPER_AX_DI_32(void) {uint ea = EA_AX_DI_32(); return m68ki_read_32(ea);} INLINE uint OPER_AX_IX_8(void) {uint ea = EA_AX_IX_8(); return m68ki_read_8(ea); } INLINE uint OPER_AX_IX_16(void) {uint ea = EA_AX_IX_16(); return m68ki_read_16(ea);} INLINE uint OPER_AX_IX_32(void) {uint ea = EA_AX_IX_32(); return m68ki_read_32(ea);} INLINE uint OPER_A7_PI_8(void) {uint ea = EA_A7_PI_8(); return m68ki_read_8(ea); } INLINE uint OPER_A7_PD_8(void) {uint ea = EA_A7_PD_8(); return m68ki_read_8(ea); } INLINE uint OPER_AW_8(void) {uint ea = EA_AW_8(); return m68ki_read_8(ea); } INLINE uint OPER_AW_16(void) {uint ea = EA_AW_16(); return m68ki_read_16(ea);} INLINE uint OPER_AW_32(void) {uint ea = EA_AW_32(); return m68ki_read_32(ea);} INLINE uint OPER_AL_8(void) {uint ea = EA_AL_8(); return m68ki_read_8(ea); } INLINE uint OPER_AL_16(void) {uint ea = EA_AL_16(); return m68ki_read_16(ea);} INLINE uint OPER_AL_32(void) {uint ea = EA_AL_32(); return m68ki_read_32(ea);} INLINE uint OPER_PCDI_8(void) {uint ea = EA_PCDI_8(); return m68ki_read_pcrel_8(ea); } INLINE uint OPER_PCDI_16(void) {uint ea = EA_PCDI_16(); return m68ki_read_pcrel_16(ea);} INLINE uint OPER_PCDI_32(void) {uint ea = EA_PCDI_32(); return m68ki_read_pcrel_32(ea);} INLINE uint OPER_PCIX_8(void) {uint ea = EA_PCIX_8(); return m68ki_read_pcrel_8(ea); } INLINE uint OPER_PCIX_16(void) {uint ea = EA_PCIX_16(); return m68ki_read_pcrel_16(ea);} INLINE uint OPER_PCIX_32(void) {uint ea = EA_PCIX_32(); return m68ki_read_pcrel_32(ea);} /* ---------------------------- Stack Functions --------------------------- */ /* Push/pull data from the stack */ INLINE void m68ki_push_16(uint value) { REG_SP = MASK_OUT_ABOVE_32(REG_SP - 2); m68ki_write_16(REG_SP, value); } INLINE void m68ki_push_32(uint value) { REG_SP = MASK_OUT_ABOVE_32(REG_SP - 4); m68ki_write_32(REG_SP, value); } INLINE uint m68ki_pull_16(void) { REG_SP = MASK_OUT_ABOVE_32(REG_SP + 2); return m68ki_read_16(REG_SP-2); } INLINE uint m68ki_pull_32(void) { REG_SP = MASK_OUT_ABOVE_32(REG_SP + 4); return m68ki_read_32(REG_SP-4); } /* Increment/decrement the stack as if doing a push/pull but * don't do any memory access. */ INLINE void m68ki_fake_push_16(void) { REG_SP = MASK_OUT_ABOVE_32(REG_SP - 2); } INLINE void m68ki_fake_push_32(void) { REG_SP = MASK_OUT_ABOVE_32(REG_SP - 4); } INLINE void m68ki_fake_pull_16(void) { REG_SP = MASK_OUT_ABOVE_32(REG_SP + 2); } INLINE void m68ki_fake_pull_32(void) { REG_SP = MASK_OUT_ABOVE_32(REG_SP + 4); } /* ----------------------------- Program Flow ----------------------------- */ /* Jump to a new program location or vector. * These functions will also call the pc_changed callback if it was enabled * in m68kconf.h. */ INLINE void m68ki_jump(uint new_pc) { REG_PC = new_pc; m68ki_pc_changed(REG_PC); } INLINE void m68ki_jump_vector(uint vector) { REG_PC = (vector<<2) + REG_VBR; REG_PC = m68ki_read_data_32(REG_PC); m68ki_pc_changed(REG_PC); } /* Branch to a new memory location. * The 32-bit branch will call pc_changed if it was enabled in m68kconf.h. * So far I've found no problems with not calling pc_changed for 8 or 16 * bit branches. */ INLINE void m68ki_branch_8(uint offset) { REG_PC += MAKE_INT_8(offset); } INLINE void m68ki_branch_16(uint offset) { REG_PC += MAKE_INT_16(offset); } INLINE void m68ki_branch_32(uint offset) { REG_PC += offset; m68ki_pc_changed(REG_PC); } /* ---------------------------- Status Register --------------------------- */ /* Set the S flag and change the active stack pointer. * Note that value MUST be 4 or 0. */ INLINE void m68ki_set_s_flag(uint value) { /* Backup the old stack pointer */ REG_SP_BASE[FLAG_S | ((FLAG_S>>1) & FLAG_M)] = REG_SP; /* Set the S flag */ FLAG_S = value; /* Set the new stack pointer */ REG_SP = REG_SP_BASE[FLAG_S | ((FLAG_S>>1) & FLAG_M)]; } /* Set the S and M flags and change the active stack pointer. * Note that value MUST be 0, 2, 4, or 6 (bit2 = S, bit1 = M). */ INLINE void m68ki_set_sm_flag(uint value) { /* Backup the old stack pointer */ REG_SP_BASE[FLAG_S | ((FLAG_S>>1) & FLAG_M)] = REG_SP; /* Set the S and M flags */ FLAG_S = value & SFLAG_SET; FLAG_M = value & MFLAG_SET; /* Set the new stack pointer */ REG_SP = REG_SP_BASE[FLAG_S | ((FLAG_S>>1) & FLAG_M)]; } /* Set the S and M flags. Don't touch the stack pointer. */ INLINE void m68ki_set_sm_flag_nosp(uint value) { /* Set the S and M flags */ FLAG_S = value & SFLAG_SET; FLAG_M = value & MFLAG_SET; } /* Set the condition code register */ INLINE void m68ki_set_ccr(uint value) { FLAG_X = BIT_4(value) << 4; FLAG_N = BIT_3(value) << 4; FLAG_Z = !BIT_2(value); FLAG_V = BIT_1(value) << 6; FLAG_C = BIT_0(value) << 8; } /* Set the status register but don't check for interrupts */ INLINE void m68ki_set_sr_noint(uint value) { /* Mask out the "unimplemented" bits */ value &= CPU_SR_MASK; /* Now set the status register */ FLAG_T1 = BIT_F(value); FLAG_T0 = BIT_E(value); FLAG_INT_MASK = value & 0x0700; m68ki_set_ccr(value); m68ki_set_sm_flag((value >> 11) & 6); } /* Set the status register but don't check for interrupts nor * change the stack pointer */ INLINE void m68ki_set_sr_noint_nosp(uint value) { /* Mask out the "unimplemented" bits */ value &= CPU_SR_MASK; /* Now set the status register */ FLAG_T1 = BIT_F(value); FLAG_T0 = BIT_E(value); FLAG_INT_MASK = value & 0x0700; m68ki_set_ccr(value); m68ki_set_sm_flag_nosp((value >> 11) & 6); } /* Set the status register and check for interrupts */ INLINE void m68ki_set_sr(uint value) { m68ki_set_sr_noint(value); m68ki_check_interrupts(); } /* ------------------------- Exception Processing ------------------------- */ /* Initiate exception processing */ INLINE uint m68ki_init_exception(void) { /* Save the old status register */ uint sr = m68ki_get_sr(); /* Turn off trace flag, clear pending traces */ FLAG_T1 = FLAG_T0 = 0; m68ki_clear_trace(); /* Enter supervisor mode */ m68ki_set_s_flag(SFLAG_SET); return sr; } /* 3 word stack frame (68000 only) */ INLINE void m68ki_stack_frame_3word(uint pc, uint sr) { m68ki_push_32(pc); m68ki_push_16(sr); } /* Format 0 stack frame. * This is the standard stack frame for 68010+. */ INLINE void m68ki_stack_frame_0000(uint pc, uint sr, uint vector) { /* Stack a 3-word frame if we are 68000 */ if(CPU_TYPE == CPU_TYPE_000) { m68ki_stack_frame_3word(pc, sr); return; } m68ki_push_16(vector<<2); m68ki_push_32(pc); m68ki_push_16(sr); } /* Format 1 stack frame (68020). * For 68020, this is the 4 word throwaway frame. */ INLINE void m68ki_stack_frame_0001(uint pc, uint sr, uint vector) { m68ki_push_16(0x1000 | (vector<<2)); m68ki_push_32(pc); m68ki_push_16(sr); } /* Format 2 stack frame. * This is used only by 68020 for trap exceptions. */ INLINE void m68ki_stack_frame_0010(uint sr, uint vector) { m68ki_push_32(REG_PPC); m68ki_push_16(0x2000 | (vector<<2)); m68ki_push_32(REG_PC); m68ki_push_16(sr); } /* Bus error stack frame (68000 only). */ INLINE void m68ki_stack_frame_buserr(uint sr) { m68ki_push_32(REG_PC); m68ki_push_16(sr); m68ki_push_16(REG_IR); m68ki_push_32(m68ki_aerr_address); /* access address */ /* 0 0 0 0 0 0 0 0 0 0 0 R/W I/N FC * R/W 0 = write, 1 = read * I/N 0 = instruction, 1 = not * FC 3-bit function code */ m68ki_push_16(m68ki_aerr_write_mode | CPU_INSTR_MODE | m68ki_aerr_fc); } /* Format 8 stack frame (68010). * 68010 only. This is the 29 word bus/address error frame. */ INLINE void m68ki_stack_frame_1000(uint pc, uint sr, uint vector) { /* VERSION * NUMBER * INTERNAL INFORMATION, 16 WORDS */ m68ki_fake_push_32(); m68ki_fake_push_32(); m68ki_fake_push_32(); m68ki_fake_push_32(); m68ki_fake_push_32(); m68ki_fake_push_32(); m68ki_fake_push_32(); m68ki_fake_push_32(); /* INSTRUCTION INPUT BUFFER */ m68ki_push_16(0); /* UNUSED, RESERVED (not written) */ m68ki_fake_push_16(); /* DATA INPUT BUFFER */ m68ki_push_16(0); /* UNUSED, RESERVED (not written) */ m68ki_fake_push_16(); /* DATA OUTPUT BUFFER */ m68ki_push_16(0); /* UNUSED, RESERVED (not written) */ m68ki_fake_push_16(); /* FAULT ADDRESS */ m68ki_push_32(0); /* SPECIAL STATUS WORD */ m68ki_push_16(0); /* 1000, VECTOR OFFSET */ m68ki_push_16(0x8000 | (vector<<2)); /* PROGRAM COUNTER */ m68ki_push_32(pc); /* STATUS REGISTER */ m68ki_push_16(sr); } /* Format A stack frame (short bus fault). * This is used only by 68020 for bus fault and address error * if the error happens at an instruction boundary. * PC stacked is address of next instruction. */ INLINE void m68ki_stack_frame_1010(uint sr, uint vector, uint pc) { /* INTERNAL REGISTER */ m68ki_push_16(0); /* INTERNAL REGISTER */ m68ki_push_16(0); /* DATA OUTPUT BUFFER (2 words) */ m68ki_push_32(0); /* INTERNAL REGISTER */ m68ki_push_16(0); /* INTERNAL REGISTER */ m68ki_push_16(0); /* DATA CYCLE FAULT ADDRESS (2 words) */ m68ki_push_32(0); /* INSTRUCTION PIPE STAGE B */ m68ki_push_16(0); /* INSTRUCTION PIPE STAGE C */ m68ki_push_16(0); /* SPECIAL STATUS REGISTER */ m68ki_push_16(0); /* INTERNAL REGISTER */ m68ki_push_16(0); /* 1010, VECTOR OFFSET */ m68ki_push_16(0xa000 | (vector<<2)); /* PROGRAM COUNTER */ m68ki_push_32(pc); /* STATUS REGISTER */ m68ki_push_16(sr); } /* Format B stack frame (long bus fault). * This is used only by 68020 for bus fault and address error * if the error happens during instruction execution. * PC stacked is address of instruction in progress. */ INLINE void m68ki_stack_frame_1011(uint sr, uint vector, uint pc) { /* INTERNAL REGISTERS (18 words) */ m68ki_push_32(0); m68ki_push_32(0); m68ki_push_32(0); m68ki_push_32(0); m68ki_push_32(0); m68ki_push_32(0); m68ki_push_32(0); m68ki_push_32(0); m68ki_push_32(0); /* VERSION# (4 bits), INTERNAL INFORMATION */ m68ki_push_16(0); /* INTERNAL REGISTERS (3 words) */ m68ki_push_32(0); m68ki_push_16(0); /* DATA INTPUT BUFFER (2 words) */ m68ki_push_32(0); /* INTERNAL REGISTERS (2 words) */ m68ki_push_32(0); /* STAGE B ADDRESS (2 words) */ m68ki_push_32(0); /* INTERNAL REGISTER (4 words) */ m68ki_push_32(0); m68ki_push_32(0); /* DATA OUTPUT BUFFER (2 words) */ m68ki_push_32(0); /* INTERNAL REGISTER */ m68ki_push_16(0); /* INTERNAL REGISTER */ m68ki_push_16(0); /* DATA CYCLE FAULT ADDRESS (2 words) */ m68ki_push_32(0); /* INSTRUCTION PIPE STAGE B */ m68ki_push_16(0); /* INSTRUCTION PIPE STAGE C */ m68ki_push_16(0); /* SPECIAL STATUS REGISTER */ m68ki_push_16(0); /* INTERNAL REGISTER */ m68ki_push_16(0); /* 1011, VECTOR OFFSET */ m68ki_push_16(0xb000 | (vector<<2)); /* PROGRAM COUNTER */ m68ki_push_32(pc); /* STATUS REGISTER */ m68ki_push_16(sr); } /* Used for Group 2 exceptions. * These stack a type 2 frame on the 020. */ INLINE void m68ki_exception_trap(uint vector) { uint sr = m68ki_init_exception(); if(CPU_TYPE_IS_010_LESS(CPU_TYPE)) m68ki_stack_frame_0000(REG_PC, sr, vector); else m68ki_stack_frame_0010(sr, vector); m68ki_jump_vector(vector); /* Use up some clock cycles */ USE_CYCLES(CYC_EXCEPTION[vector]); } /* Trap#n stacks a 0 frame but behaves like group2 otherwise */ INLINE void m68ki_exception_trapN(uint vector) { uint sr = m68ki_init_exception(); m68ki_stack_frame_0000(REG_PC, sr, vector); m68ki_jump_vector(vector); /* Use up some clock cycles */ USE_CYCLES(CYC_EXCEPTION[vector]); } /* Exception for trace mode */ INLINE void m68ki_exception_trace(void) { uint sr = m68ki_init_exception(); if(CPU_TYPE_IS_010_LESS(CPU_TYPE)) { #if M68K_EMULATE_ADDRESS_ERROR == OPT_ON if(CPU_TYPE_IS_000(CPU_TYPE)) { CPU_INSTR_MODE = INSTRUCTION_NO; } #endif /* M68K_EMULATE_ADDRESS_ERROR */ m68ki_stack_frame_0000(REG_PC, sr, EXCEPTION_TRACE); } else m68ki_stack_frame_0010(sr, EXCEPTION_TRACE); m68ki_jump_vector(EXCEPTION_TRACE); /* Trace nullifies a STOP instruction */ CPU_STOPPED &= ~STOP_LEVEL_STOP; /* Use up some clock cycles */ USE_CYCLES(CYC_EXCEPTION[EXCEPTION_TRACE]); } /* Exception for privilege violation */ INLINE void m68ki_exception_privilege_violation(void) { uint sr = m68ki_init_exception(); #if M68K_EMULATE_ADDRESS_ERROR == OPT_ON if(CPU_TYPE_IS_000(CPU_TYPE)) { CPU_INSTR_MODE = INSTRUCTION_NO; } #endif /* M68K_EMULATE_ADDRESS_ERROR */ m68ki_stack_frame_0000(REG_PPC, sr, EXCEPTION_PRIVILEGE_VIOLATION); m68ki_jump_vector(EXCEPTION_PRIVILEGE_VIOLATION); /* Use up some clock cycles and undo the instruction's cycles */ USE_CYCLES(CYC_EXCEPTION[EXCEPTION_PRIVILEGE_VIOLATION] - CYC_INSTRUCTION[REG_IR]); } /* Exception for A-Line instructions */ INLINE void m68ki_exception_1010(void) { uint sr; #if M68K_LOG_1010_1111 == OPT_ON M68K_DO_LOG_EMU((M68K_LOG_FILEHANDLE "%s at %08x: called 1010 instruction %04x (%s)\n", m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PPC), REG_IR, m68ki_disassemble_quick(ADDRESS_68K(REG_PPC)))); #endif sr = m68ki_init_exception(); m68ki_stack_frame_0000(REG_PPC, sr, EXCEPTION_1010); m68ki_jump_vector(EXCEPTION_1010); /* Use up some clock cycles and undo the instruction's cycles */ USE_CYCLES(CYC_EXCEPTION[EXCEPTION_1010] - CYC_INSTRUCTION[REG_IR]); } /* Exception for F-Line instructions */ INLINE void m68ki_exception_1111(void) { uint sr; #if M68K_LOG_1010_1111 == OPT_ON M68K_DO_LOG_EMU((M68K_LOG_FILEHANDLE "%s at %08x: called 1111 instruction %04x (%s)\n", m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PPC), REG_IR, m68ki_disassemble_quick(ADDRESS_68K(REG_PPC)))); #endif sr = m68ki_init_exception(); m68ki_stack_frame_0000(REG_PPC, sr, EXCEPTION_1111); m68ki_jump_vector(EXCEPTION_1111); /* Use up some clock cycles and undo the instruction's cycles */ USE_CYCLES(CYC_EXCEPTION[EXCEPTION_1111] - CYC_INSTRUCTION[REG_IR]); } /* Exception for illegal instructions */ INLINE void m68ki_exception_illegal(void) { uint sr; M68K_DO_LOG((M68K_LOG_FILEHANDLE "%s at %08x: illegal instruction %04x (%s)\n", m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PPC), REG_IR, m68ki_disassemble_quick(ADDRESS_68K(REG_PPC)))); sr = m68ki_init_exception(); #if M68K_EMULATE_ADDRESS_ERROR == OPT_ON if(CPU_TYPE_IS_000(CPU_TYPE)) { CPU_INSTR_MODE = INSTRUCTION_NO; } #endif /* M68K_EMULATE_ADDRESS_ERROR */ m68ki_stack_frame_0000(REG_PPC, sr, EXCEPTION_ILLEGAL_INSTRUCTION); m68ki_jump_vector(EXCEPTION_ILLEGAL_INSTRUCTION); /* Use up some clock cycles and undo the instruction's cycles */ USE_CYCLES(CYC_EXCEPTION[EXCEPTION_ILLEGAL_INSTRUCTION] - CYC_INSTRUCTION[REG_IR]); } /* Exception for format errror in RTE */ INLINE void m68ki_exception_format_error(void) { uint sr = m68ki_init_exception(); m68ki_stack_frame_0000(REG_PC, sr, EXCEPTION_FORMAT_ERROR); m68ki_jump_vector(EXCEPTION_FORMAT_ERROR); /* Use up some clock cycles and undo the instruction's cycles */ USE_CYCLES(CYC_EXCEPTION[EXCEPTION_FORMAT_ERROR] - CYC_INSTRUCTION[REG_IR]); } /* Exception for address error */ INLINE void m68ki_exception_address_error(void) { uint sr = m68ki_init_exception(); /* If we were processing a bus error, address error, or reset, * this is a catastrophic failure. * Halt the CPU */ if(CPU_RUN_MODE == RUN_MODE_BERR_AERR_RESET) { m68k_read_memory_8(0x00ffff01); CPU_STOPPED = STOP_LEVEL_HALT; return; } CPU_RUN_MODE = RUN_MODE_BERR_AERR_RESET; /* Note: This is implemented for 68000 only! */ m68ki_stack_frame_buserr(sr); m68ki_jump_vector(EXCEPTION_ADDRESS_ERROR); /* Use up some clock cycles and undo the instruction's cycles */ USE_CYCLES(CYC_EXCEPTION[EXCEPTION_ADDRESS_ERROR] - CYC_INSTRUCTION[REG_IR]); } /* Service an interrupt request and start exception processing */ INLINE void m68ki_exception_interrupt(uint int_level) { uint vector; uint sr; uint new_pc; #if M68K_EMULATE_ADDRESS_ERROR == OPT_ON if(CPU_TYPE_IS_000(CPU_TYPE)) { CPU_INSTR_MODE = INSTRUCTION_NO; } #endif /* M68K_EMULATE_ADDRESS_ERROR */ /* Turn off the stopped state */ CPU_STOPPED &= ~STOP_LEVEL_STOP; /* If we are halted, don't do anything */ if(CPU_STOPPED) return; /* Acknowledge the interrupt */ vector = m68ki_int_ack(int_level); /* Get the interrupt vector */ if(vector == M68K_INT_ACK_AUTOVECTOR) /* Use the autovectors. This is the most commonly used implementation */ vector = EXCEPTION_INTERRUPT_AUTOVECTOR+int_level; else if(vector == M68K_INT_ACK_SPURIOUS) /* Called if no devices respond to the interrupt acknowledge */ vector = EXCEPTION_SPURIOUS_INTERRUPT; else if(vector > 255) { M68K_DO_LOG_EMU((M68K_LOG_FILEHANDLE "%s at %08x: Interrupt acknowledge returned invalid vector $%x\n", m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC), vector)); return; } /* Start exception processing */ sr = m68ki_init_exception(); /* Set the interrupt mask to the level of the one being serviced */ FLAG_INT_MASK = int_level<<8; /* Get the new PC */ new_pc = m68ki_read_data_32((vector<<2) + REG_VBR); /* If vector is uninitialized, call the uninitialized interrupt vector */ if(new_pc == 0) new_pc = m68ki_read_data_32((EXCEPTION_UNINITIALIZED_INTERRUPT<<2) + REG_VBR); /* Generate a stack frame */ m68ki_stack_frame_0000(REG_PC, sr, vector); if(FLAG_M && CPU_TYPE_IS_EC020_PLUS(CPU_TYPE)) { /* Create throwaway frame */ m68ki_set_sm_flag(FLAG_S); /* clear M */ sr |= 0x2000; /* Same as SR in master stack frame except S is forced high */ m68ki_stack_frame_0001(REG_PC, sr, vector); } m68ki_jump(new_pc); /* Defer cycle counting until later */ CPU_INT_CYCLES += CYC_EXCEPTION[vector]; #if !M68K_EMULATE_INT_ACK /* Automatically clear IRQ if we are not using an acknowledge scheme */ CPU_INT_LEVEL = 0; #endif /* M68K_EMULATE_INT_ACK */ } /* ASG: Check for interrupts */ INLINE void m68ki_check_interrupts(void) { if(CPU_INT_LEVEL > FLAG_INT_MASK) m68ki_exception_interrupt(CPU_INT_LEVEL>>8); } /* ======================================================================== */ /* ============================== END OF FILE ============================= */ /* ======================================================================== */ #endif /* M68KCPU__HEADER */ yabause-0.9.15/src/musashi/readme.txt000644 001750 001750 00000024466 12755623101 021525 0ustar00guillaumeguillaume000000 000000 MUSASHI ======= Version 3.4 A portable Motorola M680x0 processor emulation engine. Copyright 1998-2002 Karl Stenerud. All rights reserved. INTRODUCTION: ------------ Musashi is a Motorola 68000, 68010, 68EC020, and 68020 emulator written in C. This emulator was written with two goals in mind: portability and speed. The emulator is written to ANSI C89 specifications. It also uses inline functions, which are C9X compliant. It has been successfully running in the MAME project (www.mame.net) for years and so has had time to mature. LICENSE AND COPYRIGHT: --------------------- Copyright © 1998-2001 Karl Stenerud Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. AVAILABILITY: ------------ The latest version of this code can be obtained at: https://github.com/kstenerud/Musashi CONTACTING THE AUTHOR: --------------------- I can be reached at kstenerud@gmail.com BASIC CONFIGURATION: ------------------- The basic configuration will give you a standard 68000 that has sufficient functionality to work in a primitive environment. This setup assumes that you only have 1 device interrupting it, that the device will always request an autovectored interrupt, and it will always clear the interrupt before the interrupt service routine finishes (but could possibly re-assert the interrupt). You will have only one address space, no tracing, and no instruction prefetch. To implement the basic configuration: - Open m68kconf.h and verify that the settings for INLINE will work with your compiler. (Currently set to "static __inline__", which works in gcc 2.9. For C9X compliance, it should be "inline") - In your host program, implement the following functions: unsigned int m68k_read_memory_8(unsigned int address); unsigned int m68k_read_memory_16(unsigned int address); unsigned int m68k_read_memory_32(unsigned int address); void m68k_write_memory_8(unsigned int address, unsigned int value); void m68k_write_memory_16(unsigned int address, unsigned int value); void m68k_write_memory_32(unsigned int address, unsigned int value); - In your host program, be sure to call m68k_pulse_reset() once before calling any of the other functions as this initializes the core. - Use m68k_execute() to execute instructions and m68k_set_irq() to cause an interrupt. ADDING PROPER INTERRUPT HANDLING: -------------------------------- The interrupt handling in the basic configuration doesn't emulate the interrupt acknowledge phase of the CPU and automatically clears an interrupt request during interrupt processing. While this works for most systems, you may need more accurate interrupt handling. To add proper interrupt handling: - In m68kconf.h, set M68K_EMULATE_INT_ACK to OPT_SPECIFY_HANDLER - In m68kconf.h, set M68K_INT_ACK_CALLBACK(A) to your interrupt acknowledge routine - Your interrupt acknowledge routine must return an interrupt vector, M68K_INT_ACK_AUTOVECTOR, or M68K_INT_ACK_SPURIOUS. most m68k implementations just use autovectored interrupts. - When the interrupting device is satisfied, you must call m68k_set_irq(0) to remove the interrupt request. MULTIPLE INTERRUPTS: ------------------- The above system will work if you have only one device interrupting the CPU, but if you have more than one device, you must do a bit more. To add multiple interrupts: - You must make an interrupt arbitration device that will take the highest priority interrupt and encode it onto the IRQ pins on the CPU. - The interrupt arbitration device should use m68k_set_irq() to set the highest pending interrupt, or 0 for no interrupts pending. SEPARATE IMMEDIATE READS: ------------------------ You can write faster memory access functions if you know whether you are fetching from ROM or RAM. Immediate reads are always from the program space (Always in ROM unless it is running self-modifying code). To enable separate immediate reads: - In m68kconf.h, turn on M68K_SEPARATE_READ_IMM. - In your host program, implement the following functions: unsigned int m68k_read_immediate_16(unsigned int address); unsigned int m68k_read_immediate_32(unsigned int address); - If you need to know the current PC (for banking and such), set M68K_MONITOR_PC to OPT_SPECIFY_HANDLER, and set M68K_SET_PC_CALLBACK(A) to your routine. ADDRESS SPACES: -------------- Most systems will only implement one address space, placing ROM at the lower addresses and RAM at the higher. However, there is the possibility that a system will implement ROM and RAM in the same address range, but in different address spaces. In this case, you might get away with assuming that immediate reads are in the program space and all other reads are in the data space, if it weren't for the fact that the exception vectors are fetched from the data space. As a result, anyone implementing this kind of system will have to copy the vector table from ROM to RAM using pc-relative instructions. This makes things bad for emulation, because this means that a non-immediate read is not necessarily in the data space. The m68k deals with this by encoding the requested address space on the function code pins: FC Address Space 210 ------------------ --- USER DATA 001 USER PROGRAM 010 SUPERVISOR DATA 101 SUPERVISOR PROGRAM 110 CPU SPACE 111 <-- not emulated in this core since we emulate interrupt acknowledge in another way. To emulate the function code pins: - In m68kconf.h, set M68K_EMULATE_FC to OPT_SPECIFY_HANDLER and set M68K_SET_FC_CALLBACK(A) to your function code handler function. - Your function code handler should select the proper address space for subsequent calls to m68k_read_xx (and m68k_write_xx for 68010+). Note: immediate reads are always done from program space, so technically you don't need to implement the separate immediate reads, although you could gain more speed improvements leaving them in and doing some clever programming. USING DIFFERENT CPU TYPES: ------------------------- The default is to enable only the 68000 cpu type. To change this, change the settings for M68K_EMULATE_010 etc in m68kconf.h. To set the CPU type you want to use: - Make sure it is enabled in m68kconf.h. Current switches are: M68K_EMULATE_010 M68K_EMULATE_EC020 M68K_EMULATE_020 - In your host program, call m68k_set_cpu_type() and then call m68k_pulse_reset(). Valid CPU types are: M68K_CPU_TYPE_68000, M68K_CPU_TYPE_68010, M68K_CPU_TYPE_68EC020, M68K_CPU_TYPE_68020 CLOCK FREQUENCY: --------------- In order to emulate the correct clock frequency, you will have to calculate how long it takes the emulation to execute a certain number of "cycles" and vary your calls to m68k_execute() accordingly. As well, it is a good idea to take away the CPU's timeslice when it writes to a memory-mapped port in order to give the device it wrote to a chance to react. You can use the functions m68k_cycles_run(), m68k_cycles_remaining(), m68k_modify_timeslice(), and m68k_end_timeslice() to do this. Try to use large cycle values in your calls to m68k_execute() since it will increase throughput. You can always take away the timeslice later. MORE CORRECT EMULATION: ---------------------- You may need to enable these in order to properly emulate some of the more obscure functions of the m68k: - M68K_EMULATE_BKPT_ACK causes the CPU to call a breakpoint handler on a BKPT instruction - M68K_EMULATE_TRACE causes the CPU to generate trace exceptions when the trace bits are set - M68K_EMULATE_RESET causes the CPU to call a reset handler on a RESET instruction. - M68K_EMULATE_PREFETCH emulates the 4-word instruction prefetch that is part of the 68000/68010 (needed for Amiga emulation). NOTE: if the CPU fetches a word or longword at an odd address when this option is on, it will yield unpredictable results, which is why a real 68000 will generate an address error exception. - M68K_EMULATE_ADDRESS_ERROR will cause the CPU to generate address error exceptions if it attempts to read a word or longword at an odd address. - call m68k_pulse_halt() to emulate the HALT pin. CONVENIENCE FUNCTIONS: --------------------- These are in here for programmer convenience: - M68K_INSTRUCTION_HOOK lets you call a handler before each instruction. - M68K_LOG_ENABLE and M68K_LOG_1010_1111 lets you log illegal and A/F-line instructions. MULTIPLE CPU EMULATION: ---------------------- The default is to use only one CPU. To use more than one CPU in this core, there are some things to keep in mind: - To have different cpus call different functions, use OPT_ON instead of OPT_SPECIFY_HANDLER, and use the m68k_set_xxx_callback() functions to set your callback handlers on a per-cpu basis. - Be sure to call set_cpu_type() for each CPU you use. - Use m68k_set_context() and m68k_get_context() to switch to another CPU. LOAD AND SAVE CPU CONTEXTS FROM DISK: ------------------------------------ You can use them68k_load_context() and m68k_save_context() functions to load and save the CPU state to disk. GET/SET INFORMATION FROM THE CPU: -------------------------------- You can use m68k_get_reg() and m68k_set_reg() to gain access to the internals of the CPU. EXAMPLE: ------- The subdir example contains a full example (currently DOS only). yabause-0.9.15/src/musashi/m68kconf.h000644 001750 001750 00000016010 12755623101 021315 0ustar00guillaumeguillaume000000 000000 /* ======================================================================== */ /* ========================= LICENSING & COPYRIGHT ======================== */ /* ======================================================================== */ /* * MUSASHI * Version 3.4 * * A portable Motorola M680x0 processor emulation engine. * Copyright 1998-2001 Karl Stenerud. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef M68KCONF__HEADER #define M68KCONF__HEADER /* Configuration switches. * Use OPT_SPECIFY_HANDLER for configuration options that allow callbacks. * OPT_SPECIFY_HANDLER causes the core to link directly to the function * or macro you specify, rather than using callback functions whose pointer * must be passed in using m68k_set_xxx_callback(). */ #define OPT_OFF 0 #define OPT_ON 1 #define OPT_SPECIFY_HANDLER 2 /* ======================================================================== */ /* ============================== MAME STUFF ============================== */ /* ======================================================================== */ /* If you're compiling this for MAME, only change M68K_COMPILE_FOR_MAME * to OPT_ON and use m68kmame.h to configure the 68k core. */ #ifndef M68K_COMPILE_FOR_MAME #define M68K_COMPILE_FOR_MAME OPT_OFF #endif /* M68K_COMPILE_FOR_MAME */ #if M68K_COMPILE_FOR_MAME == OPT_OFF /* ======================================================================== */ /* ============================= CONFIGURATION ============================ */ /* ======================================================================== */ /* Turn ON if you want to use the following M68K variants */ #define M68K_EMULATE_010 OPT_OFF #define M68K_EMULATE_EC020 OPT_OFF #define M68K_EMULATE_020 OPT_OFF /* If ON, the CPU will call m68k_read_immediate_xx() for immediate addressing * and m68k_read_pcrelative_xx() for PC-relative addressing. * If off, all read requests from the CPU will be redirected to m68k_read_xx() */ #define M68K_SEPARATE_READS OPT_OFF /* If ON, the CPU will call m68k_write_32_pd() when it executes move.l with a * predecrement destination EA mode instead of m68k_write_32(). * To simulate real 68k behavior, m68k_write_32_pd() must first write the high * word to [address+2], and then write the low word to [address]. */ #define M68K_SIMULATE_PD_WRITES OPT_OFF /* If ON, CPU will call the interrupt acknowledge callback when it services an * interrupt. * If off, all interrupts will be autovectored and all interrupt requests will * auto-clear when the interrupt is serviced. */ #define M68K_EMULATE_INT_ACK OPT_OFF #define M68K_INT_ACK_CALLBACK(A) your_int_ack_handler_function(A) /* If ON, CPU will call the breakpoint acknowledge callback when it encounters * a breakpoint instruction and it is running a 68010+. */ #define M68K_EMULATE_BKPT_ACK OPT_OFF #define M68K_BKPT_ACK_CALLBACK() your_bkpt_ack_handler_function() /* If ON, the CPU will monitor the trace flags and take trace exceptions */ #define M68K_EMULATE_TRACE OPT_OFF /* If ON, CPU will call the output reset callback when it encounters a reset * instruction. */ #define M68K_EMULATE_RESET OPT_ON #define M68K_RESET_CALLBACK() your_reset_handler_function() /* If ON, CPU will call the set fc callback on every memory access to * differentiate between user/supervisor, program/data access like a real * 68000 would. This should be enabled and the callback should be set if you * want to properly emulate the m68010 or higher. (moves uses function codes * to read/write data from different address spaces) */ #define M68K_EMULATE_FC OPT_OFF #define M68K_SET_FC_CALLBACK(A) your_set_fc_handler_function(A) /* If ON, CPU will call the pc changed callback when it changes the PC by a * large value. This allows host programs to be nicer when it comes to * fetching immediate data and instructions on a banked memory system. */ #define M68K_MONITOR_PC OPT_OFF #define M68K_SET_PC_CALLBACK(A) your_pc_changed_handler_function(A) /* If ON, CPU will call the instruction hook callback before every * instruction. */ #define M68K_INSTRUCTION_HOOK OPT_OFF #define M68K_INSTRUCTION_CALLBACK() your_instruction_hook_function() /* If ON, the CPU will emulate the 4-byte prefetch queue of a real 68000 */ #define M68K_EMULATE_PREFETCH OPT_OFF /* If ON, the CPU will generate address error exceptions if it tries to * access a word or longword at an odd address. * NOTE: This is only emulated properly for 68000 mode. */ #define M68K_EMULATE_ADDRESS_ERROR OPT_OFF /* Turn ON to enable logging of illegal instruction calls. * M68K_LOG_FILEHANDLE must be #defined to a stdio file stream. * Turn on M68K_LOG_1010_1111 to log all 1010 and 1111 calls. */ #define M68K_LOG_ENABLE OPT_OFF #define M68K_LOG_1010_1111 OPT_OFF #define M68K_LOG_FILEHANDLE some_file_handle /* ----------------------------- COMPATIBILITY ---------------------------- */ /* The following options set optimizations that violate the current ANSI * standard, but will be compliant under the forthcoming C9X standard. */ /* If ON, the enulation core will use 64-bit integers to speed up some * operations. */ #define M68K_USE_64_BIT OPT_OFF /* Set to your compiler's static inline keyword to enable it, or * set it to blank to disable it. * If you define INLINE in the makefile, it will override this value. * NOTE: not enabling inline functions will SEVERELY slow down emulation. */ #ifndef INLINE #ifdef _MSC_VER #define INLINE _inline #else #define INLINE static inline #endif #endif /* INLINE */ #endif /* M68K_COMPILE_FOR_MAME */ /* ======================================================================== */ /* ============================== END OF FILE ============================= */ /* ======================================================================== */ #endif /* M68KCONF__HEADER */ yabause-0.9.15/src/musashi/m68kdasm.c000644 001750 001750 00000275727 12755623101 021335 0ustar00guillaumeguillaume000000 000000 /* ======================================================================== */ /* ========================= LICENSING & COPYRIGHT ======================== */ /* ======================================================================== */ /* * MUSASHI * Version 3.4 * * A portable Motorola M680x0 processor emulation engine. * Copyright 1998-2001 Karl Stenerud. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* ======================================================================== */ /* ================================ INCLUDES ============================== */ /* ======================================================================== */ #include #include #include #include "m68k.h" #ifndef DECL_SPEC #define DECL_SPEC #endif /* ======================================================================== */ /* ============================ GENERAL DEFINES =========================== */ /* ======================================================================== */ /* unsigned int and int must be at least 32 bits wide */ #undef uint #define uint unsigned int /* Bit Isolation Functions */ #define BIT_0(A) ((A) & 0x00000001) #define BIT_1(A) ((A) & 0x00000002) #define BIT_2(A) ((A) & 0x00000004) #define BIT_3(A) ((A) & 0x00000008) #define BIT_4(A) ((A) & 0x00000010) #define BIT_5(A) ((A) & 0x00000020) #define BIT_6(A) ((A) & 0x00000040) #define BIT_7(A) ((A) & 0x00000080) #define BIT_8(A) ((A) & 0x00000100) #define BIT_9(A) ((A) & 0x00000200) #define BIT_A(A) ((A) & 0x00000400) #define BIT_B(A) ((A) & 0x00000800) #define BIT_C(A) ((A) & 0x00001000) #define BIT_D(A) ((A) & 0x00002000) #define BIT_E(A) ((A) & 0x00004000) #define BIT_F(A) ((A) & 0x00008000) #define BIT_10(A) ((A) & 0x00010000) #define BIT_11(A) ((A) & 0x00020000) #define BIT_12(A) ((A) & 0x00040000) #define BIT_13(A) ((A) & 0x00080000) #define BIT_14(A) ((A) & 0x00100000) #define BIT_15(A) ((A) & 0x00200000) #define BIT_16(A) ((A) & 0x00400000) #define BIT_17(A) ((A) & 0x00800000) #define BIT_18(A) ((A) & 0x01000000) #define BIT_19(A) ((A) & 0x02000000) #define BIT_1A(A) ((A) & 0x04000000) #define BIT_1B(A) ((A) & 0x08000000) #define BIT_1C(A) ((A) & 0x10000000) #define BIT_1D(A) ((A) & 0x20000000) #define BIT_1E(A) ((A) & 0x40000000) #define BIT_1F(A) ((A) & 0x80000000) /* These are the CPU types understood by this disassembler */ #define TYPE_68000 1 #define TYPE_68010 2 #define TYPE_68020 4 #define TYPE_68030 8 #define TYPE_68040 16 #define M68000_ONLY TYPE_68000 #define M68010_ONLY TYPE_68010 #define M68010_LESS (TYPE_68000 | TYPE_68010) #define M68010_PLUS (TYPE_68010 | TYPE_68020 | TYPE_68030 | TYPE_68040) #define M68020_ONLY TYPE_68020 #define M68020_LESS (TYPE_68010 | TYPE_68020) #define M68020_PLUS (TYPE_68020 | TYPE_68030 | TYPE_68040) #define M68030_ONLY TYPE_68030 #define M68030_LESS (TYPE_68010 | TYPE_68020 | TYPE_68030) #define M68030_PLUS (TYPE_68030 | TYPE_68040) #define M68040_PLUS TYPE_68040 /* Extension word formats */ #define EXT_8BIT_DISPLACEMENT(A) ((A)&0xff) #define EXT_FULL(A) BIT_8(A) #define EXT_EFFECTIVE_ZERO(A) (((A)&0xe4) == 0xc4 || ((A)&0xe2) == 0xc0) #define EXT_BASE_REGISTER_PRESENT(A) (!BIT_7(A)) #define EXT_INDEX_REGISTER_PRESENT(A) (!BIT_6(A)) #define EXT_INDEX_REGISTER(A) (((A)>>12)&7) #define EXT_INDEX_PRE_POST(A) (EXT_INDEX_PRESENT(A) && (A)&3) #define EXT_INDEX_PRE(A) (EXT_INDEX_PRESENT(A) && ((A)&7) < 4 && ((A)&7) != 0) #define EXT_INDEX_POST(A) (EXT_INDEX_PRESENT(A) && ((A)&7) > 4) #define EXT_INDEX_SCALE(A) (((A)>>9)&3) #define EXT_INDEX_LONG(A) BIT_B(A) #define EXT_INDEX_AR(A) BIT_F(A) #define EXT_BASE_DISPLACEMENT_PRESENT(A) (((A)&0x30) > 0x10) #define EXT_BASE_DISPLACEMENT_WORD(A) (((A)&0x30) == 0x20) #define EXT_BASE_DISPLACEMENT_LONG(A) (((A)&0x30) == 0x30) #define EXT_OUTER_DISPLACEMENT_PRESENT(A) (((A)&3) > 1 && ((A)&0x47) < 0x44) #define EXT_OUTER_DISPLACEMENT_WORD(A) (((A)&3) == 2 && ((A)&0x47) < 0x44) #define EXT_OUTER_DISPLACEMENT_LONG(A) (((A)&3) == 3 && ((A)&0x47) < 0x44) /* ======================================================================== */ /* =============================== PROTOTYPES ============================= */ /* ======================================================================== */ /* Read data at the PC and increment PC */ uint read_imm_8(void); uint read_imm_16(void); uint read_imm_32(void); /* Read data at the PC but don't imcrement the PC */ uint peek_imm_8(void); uint peek_imm_16(void); uint peek_imm_32(void); /* make signed integers 100% portably */ static int make_int_8(int value); static int make_int_16(int value); /* make a string of a hex value */ static char* make_signed_hex_str_8(uint val); static char* make_signed_hex_str_16(uint val); static char* make_signed_hex_str_32(uint val); /* make string of ea mode */ static char* get_ea_mode_str(uint instruction, uint size); char* get_ea_mode_str_8(uint instruction); char* get_ea_mode_str_16(uint instruction); char* get_ea_mode_str_32(uint instruction); /* make string of immediate value */ static char* get_imm_str_s(uint size); static char* get_imm_str_u(uint size); char* get_imm_str_s8(void); char* get_imm_str_s16(void); char* get_imm_str_s32(void); /* Stuff to build the opcode handler jump table */ static void build_opcode_table(void); static int valid_ea(uint opcode, uint mask); static int DECL_SPEC compare_nof_true_bits(const void *aptr, const void *bptr); /* used to build opcode handler jump table */ typedef struct { void (*opcode_handler)(void); /* handler function */ uint mask; /* mask on opcode */ uint match; /* what to match after masking */ uint ea_mask; /* what ea modes are allowed */ } opcode_struct; /* ======================================================================== */ /* ================================= DATA ================================= */ /* ======================================================================== */ /* Opcode handler jump table */ static void (*g_instruction_table[0x10000])(void); /* Flag if disassembler initialized */ static int g_initialized = 0; /* Address mask to simulate address lines */ static unsigned int g_address_mask = 0xffffffff; static char g_dasm_str[100]; /* string to hold disassembly */ static char g_helper_str[100]; /* string to hold helpful info */ static uint g_cpu_pc; /* program counter */ static uint g_cpu_ir; /* instruction register */ static uint g_cpu_type; /* used by ops like asr, ror, addq, etc */ static uint g_3bit_qdata_table[8] = {8, 1, 2, 3, 4, 5, 6, 7}; static uint g_5bit_data_table[32] = { 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }; static char* g_cc[16] = {"t", "f", "hi", "ls", "cc", "cs", "ne", "eq", "vc", "vs", "pl", "mi", "ge", "lt", "gt", "le"}; static char* g_cpcc[64] = {/* 000 001 010 011 100 101 110 111 */ "f", "eq", "ogt", "oge", "olt", "ole", "ogl", "or", /* 000 */ "un", "ueq", "ugt", "uge", "ult", "ule", "ne", "t", /* 001 */ "sf", "seq", "gt", "ge", "lt", "le", "gl" "gle", /* 010 */ "ngle", "ngl", "nle", "nlt", "nge", "ngt", "sne", "st", /* 011 */ "?", "?", "?", "?", "?", "?", "?", "?", /* 100 */ "?", "?", "?", "?", "?", "?", "?", "?", /* 101 */ "?", "?", "?", "?", "?", "?", "?", "?", /* 110 */ "?", "?", "?", "?", "?", "?", "?", "?" /* 111 */ }; /* ======================================================================== */ /* =========================== UTILITY FUNCTIONS ========================== */ /* ======================================================================== */ #define LIMIT_CPU_TYPES(ALLOWED_CPU_TYPES) \ if(!(g_cpu_type & ALLOWED_CPU_TYPES)) \ { \ d68000_illegal(); \ return; \ } #define read_imm_8() (m68k_read_disassembler_16(((g_cpu_pc+=2)-2)&g_address_mask)&0xff) #define read_imm_16() m68k_read_disassembler_16(((g_cpu_pc+=2)-2)&g_address_mask) #define read_imm_32() m68k_read_disassembler_32(((g_cpu_pc+=4)-4)&g_address_mask) #define peek_imm_8() (m68k_read_disassembler_16(g_cpu_pc & g_address_mask)&0xff) #define peek_imm_16() m68k_read_disassembler_16(g_cpu_pc & g_address_mask) #define peek_imm_32() m68k_read_disassembler_32(g_cpu_pc & g_address_mask) /* Fake a split interface */ #define get_ea_mode_str_8(instruction) get_ea_mode_str(instruction, 0) #define get_ea_mode_str_16(instruction) get_ea_mode_str(instruction, 1) #define get_ea_mode_str_32(instruction) get_ea_mode_str(instruction, 2) #define get_imm_str_s8() get_imm_str_s(0) #define get_imm_str_s16() get_imm_str_s(1) #define get_imm_str_s32() get_imm_str_s(2) #define get_imm_str_u8() get_imm_str_u(0) #define get_imm_str_u16() get_imm_str_u(1) #define get_imm_str_u32() get_imm_str_u(2) /* 100% portable signed int generators */ static int make_int_8(int value) { return (value & 0x80) ? value | ~0xff : value & 0xff; } static int make_int_16(int value) { return (value & 0x8000) ? value | ~0xffff : value & 0xffff; } /* Get string representation of hex values */ static char* make_signed_hex_str_8(uint val) { static char str[20]; val &= 0xff; if(val == 0x80) sprintf(str, "-$80"); else if(val & 0x80) sprintf(str, "-$%x", (0-val) & 0x7f); else sprintf(str, "$%x", val & 0x7f); return str; } static char* make_signed_hex_str_16(uint val) { static char str[20]; val &= 0xffff; if(val == 0x8000) sprintf(str, "-$8000"); else if(val & 0x8000) sprintf(str, "-$%x", (0-val) & 0x7fff); else sprintf(str, "$%x", val & 0x7fff); return str; } static char* make_signed_hex_str_32(uint val) { static char str[20]; val &= 0xffffffff; if(val == 0x80000000) sprintf(str, "-$80000000"); else if(val & 0x80000000) sprintf(str, "-$%x", (0-val) & 0x7fffffff); else sprintf(str, "$%x", val & 0x7fffffff); return str; } /* make string of immediate value */ static char* get_imm_str_s(uint size) { static char str[15]; if(size == 0) sprintf(str, "#%s", make_signed_hex_str_8(read_imm_8())); else if(size == 1) sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16())); else sprintf(str, "#%s", make_signed_hex_str_32(read_imm_32())); return str; } static char* get_imm_str_u(uint size) { static char str[15]; if(size == 0) sprintf(str, "#$%x", read_imm_8() & 0xff); else if(size == 1) sprintf(str, "#$%x", read_imm_16() & 0xffff); else sprintf(str, "#$%x", read_imm_32() & 0xffffffff); return str; } /* Make string of effective address mode */ static char* get_ea_mode_str(uint instruction, uint size) { static char b1[64]; static char b2[64]; static char* mode = b2; uint extension; uint base; uint outer; char base_reg[4]; char index_reg[8]; uint preindex; uint postindex; uint comma = 0; uint temp_value; /* Switch buffers so we don't clobber on a double-call to this function */ mode = mode == b1 ? b2 : b1; switch(instruction & 0x3f) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: /* data register direct */ sprintf(mode, "D%d", instruction&7); break; case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: /* address register direct */ sprintf(mode, "A%d", instruction&7); break; case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: /* address register indirect */ sprintf(mode, "(A%d)", instruction&7); break; case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: /* address register indirect with postincrement */ sprintf(mode, "(A%d)+", instruction&7); break; case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: /* address register indirect with predecrement */ sprintf(mode, "-(A%d)", instruction&7); break; case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: /* address register indirect with displacement*/ sprintf(mode, "(%s,A%d)", make_signed_hex_str_16(read_imm_16()), instruction&7); break; case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: /* address register indirect with index */ extension = read_imm_16(); if(EXT_FULL(extension)) { if(EXT_EFFECTIVE_ZERO(extension)) { strcpy(mode, "0"); break; } base = EXT_BASE_DISPLACEMENT_PRESENT(extension) ? (EXT_BASE_DISPLACEMENT_LONG(extension) ? read_imm_32() : read_imm_16()) : 0; outer = EXT_OUTER_DISPLACEMENT_PRESENT(extension) ? (EXT_OUTER_DISPLACEMENT_LONG(extension) ? read_imm_32() : read_imm_16()) : 0; if(EXT_BASE_REGISTER_PRESENT(extension)) sprintf(base_reg, "A%d", instruction&7); else *base_reg = 0; if(EXT_INDEX_REGISTER_PRESENT(extension)) { sprintf(index_reg, "%c%d.%c", EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w'); if(EXT_INDEX_SCALE(extension)) sprintf(index_reg+strlen(index_reg), "*%d", 1 << EXT_INDEX_SCALE(extension)); } else *index_reg = 0; preindex = (extension&7) > 0 && (extension&7) < 4; postindex = (extension&7) > 4; strcpy(mode, "("); if(preindex || postindex) strcat(mode, "["); if(base) { strcat(mode, make_signed_hex_str_16(base)); comma = 1; } if(*base_reg) { if(comma) strcat(mode, ","); strcat(mode, base_reg); comma = 1; } if(postindex) { strcat(mode, "]"); comma = 1; } if(*index_reg) { if(comma) strcat(mode, ","); strcat(mode, index_reg); comma = 1; } if(preindex) { strcat(mode, "]"); comma = 1; } if(outer) { if(comma) strcat(mode, ","); strcat(mode, make_signed_hex_str_16(outer)); } strcat(mode, ")"); break; } if(EXT_8BIT_DISPLACEMENT(extension) == 0) sprintf(mode, "(A%d,%c%d.%c", instruction&7, EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w'); else sprintf(mode, "(%s,A%d,%c%d.%c", make_signed_hex_str_8(extension), instruction&7, EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w'); if(EXT_INDEX_SCALE(extension)) sprintf(mode+strlen(mode), "*%d", 1 << EXT_INDEX_SCALE(extension)); strcat(mode, ")"); break; case 0x38: /* absolute short address */ sprintf(mode, "$%x.w", read_imm_16()); break; case 0x39: /* absolute long address */ sprintf(mode, "$%x.l", read_imm_32()); break; case 0x3a: /* program counter with displacement */ temp_value = read_imm_16(); sprintf(mode, "(%s,PC)", make_signed_hex_str_16(temp_value)); sprintf(g_helper_str, "; ($%x)", (make_int_16(temp_value) + g_cpu_pc-2) & 0xffffffff); break; case 0x3b: /* program counter with index */ extension = read_imm_16(); if(EXT_FULL(extension)) { if(EXT_EFFECTIVE_ZERO(extension)) { strcpy(mode, "0"); break; } base = EXT_BASE_DISPLACEMENT_PRESENT(extension) ? (EXT_BASE_DISPLACEMENT_LONG(extension) ? read_imm_32() : read_imm_16()) : 0; outer = EXT_OUTER_DISPLACEMENT_PRESENT(extension) ? (EXT_OUTER_DISPLACEMENT_LONG(extension) ? read_imm_32() : read_imm_16()) : 0; if(EXT_BASE_REGISTER_PRESENT(extension)) strcpy(base_reg, "PC"); else *base_reg = 0; if(EXT_INDEX_REGISTER_PRESENT(extension)) { sprintf(index_reg, "%c%d.%c", EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w'); if(EXT_INDEX_SCALE(extension)) sprintf(index_reg+strlen(index_reg), "*%d", 1 << EXT_INDEX_SCALE(extension)); } else *index_reg = 0; preindex = (extension&7) > 0 && (extension&7) < 4; postindex = (extension&7) > 4; strcpy(mode, "("); if(preindex || postindex) strcat(mode, "["); if(base) { strcat(mode, make_signed_hex_str_16(base)); comma = 1; } if(*base_reg) { if(comma) strcat(mode, ","); strcat(mode, base_reg); comma = 1; } if(postindex) { strcat(mode, "]"); comma = 1; } if(*index_reg) { if(comma) strcat(mode, ","); strcat(mode, index_reg); comma = 1; } if(preindex) { strcat(mode, "]"); comma = 1; } if(outer) { if(comma) strcat(mode, ","); strcat(mode, make_signed_hex_str_16(outer)); } strcat(mode, ")"); break; } if(EXT_8BIT_DISPLACEMENT(extension) == 0) sprintf(mode, "(PC,%c%d.%c", EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w'); else sprintf(mode, "(%s,PC,%c%d.%c", make_signed_hex_str_8(extension), EXT_INDEX_AR(extension) ? 'A' : 'D', EXT_INDEX_REGISTER(extension), EXT_INDEX_LONG(extension) ? 'l' : 'w'); if(EXT_INDEX_SCALE(extension)) sprintf(mode+strlen(mode), "*%d", 1 << EXT_INDEX_SCALE(extension)); strcat(mode, ")"); break; case 0x3c: /* Immediate */ sprintf(mode, "%s", get_imm_str_u(size)); break; default: sprintf(mode, "INVALID %x", instruction & 0x3f); } return mode; } /* ======================================================================== */ /* ========================= INSTRUCTION HANDLERS ========================= */ /* ======================================================================== */ /* Instruction handler function names follow this convention: * * d68000_NAME_EXTENSIONS(void) * where NAME is the name of the opcode it handles and EXTENSIONS are any * extensions for special instances of that opcode. * * Examples: * d68000_add_er_8(): add opcode, from effective address to register, * size = byte * * d68000_asr_s_8(): arithmetic shift right, static count, size = byte * * * Common extensions: * 8 : size = byte * 16 : size = word * 32 : size = long * rr : register to register * mm : memory to memory * r : register * s : static * er : effective address -> register * re : register -> effective address * ea : using effective address mode of operation * d : data register direct * a : address register direct * ai : address register indirect * pi : address register indirect with postincrement * pd : address register indirect with predecrement * di : address register indirect with displacement * ix : address register indirect with index * aw : absolute word * al : absolute long */ static void d68000_illegal(void) { sprintf(g_dasm_str, "dc.w $%04x; ILLEGAL", g_cpu_ir); } static void d68000_1010(void) { sprintf(g_dasm_str, "dc.w $%04x; opcode 1010", g_cpu_ir); } static void d68000_1111(void) { sprintf(g_dasm_str, "dc.w $%04x; opcode 1111", g_cpu_ir); } static void d68000_abcd_rr(void) { sprintf(g_dasm_str, "abcd D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); } static void d68000_abcd_mm(void) { sprintf(g_dasm_str, "abcd -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); } static void d68000_add_er_8(void) { sprintf(g_dasm_str, "add.b %s, D%d", get_ea_mode_str_8(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_add_er_16(void) { sprintf(g_dasm_str, "add.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_add_er_32(void) { sprintf(g_dasm_str, "add.l %s, D%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_add_re_8(void) { sprintf(g_dasm_str, "add.b D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); } static void d68000_add_re_16(void) { sprintf(g_dasm_str, "add.w D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_16(g_cpu_ir)); } static void d68000_add_re_32(void) { sprintf(g_dasm_str, "add.l D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_32(g_cpu_ir)); } static void d68000_adda_16(void) { sprintf(g_dasm_str, "adda.w %s, A%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_adda_32(void) { sprintf(g_dasm_str, "adda.l %s, A%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_addi_8(void) { char* str = get_imm_str_s8(); sprintf(g_dasm_str, "addi.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); } static void d68000_addi_16(void) { char* str = get_imm_str_s16(); sprintf(g_dasm_str, "addi.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir)); } static void d68000_addi_32(void) { char* str = get_imm_str_s32(); sprintf(g_dasm_str, "addi.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir)); } static void d68000_addq_8(void) { sprintf(g_dasm_str, "addq.b #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_8(g_cpu_ir)); } static void d68000_addq_16(void) { sprintf(g_dasm_str, "addq.w #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_16(g_cpu_ir)); } static void d68000_addq_32(void) { sprintf(g_dasm_str, "addq.l #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_32(g_cpu_ir)); } static void d68000_addx_rr_8(void) { sprintf(g_dasm_str, "addx.b D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); } static void d68000_addx_rr_16(void) { sprintf(g_dasm_str, "addx.w D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); } static void d68000_addx_rr_32(void) { sprintf(g_dasm_str, "addx.l D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); } static void d68000_addx_mm_8(void) { sprintf(g_dasm_str, "addx.b -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); } static void d68000_addx_mm_16(void) { sprintf(g_dasm_str, "addx.w -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); } static void d68000_addx_mm_32(void) { sprintf(g_dasm_str, "addx.l -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); } static void d68000_and_er_8(void) { sprintf(g_dasm_str, "and.b %s, D%d", get_ea_mode_str_8(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_and_er_16(void) { sprintf(g_dasm_str, "and.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_and_er_32(void) { sprintf(g_dasm_str, "and.l %s, D%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_and_re_8(void) { sprintf(g_dasm_str, "and.b D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); } static void d68000_and_re_16(void) { sprintf(g_dasm_str, "and.w D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_16(g_cpu_ir)); } static void d68000_and_re_32(void) { sprintf(g_dasm_str, "and.l D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_32(g_cpu_ir)); } static void d68000_andi_8(void) { char* str = get_imm_str_u8(); sprintf(g_dasm_str, "andi.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); } static void d68000_andi_16(void) { char* str = get_imm_str_u16(); sprintf(g_dasm_str, "andi.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir)); } static void d68000_andi_32(void) { char* str = get_imm_str_u32(); sprintf(g_dasm_str, "andi.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir)); } static void d68000_andi_to_ccr(void) { sprintf(g_dasm_str, "andi %s, CCR", get_imm_str_u8()); } static void d68000_andi_to_sr(void) { sprintf(g_dasm_str, "andi %s, SR", get_imm_str_u16()); } static void d68000_asr_s_8(void) { sprintf(g_dasm_str, "asr.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_asr_s_16(void) { sprintf(g_dasm_str, "asr.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_asr_s_32(void) { sprintf(g_dasm_str, "asr.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_asr_r_8(void) { sprintf(g_dasm_str, "asr.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_asr_r_16(void) { sprintf(g_dasm_str, "asr.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_asr_r_32(void) { sprintf(g_dasm_str, "asr.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_asr_ea(void) { sprintf(g_dasm_str, "asr.w %s", get_ea_mode_str_16(g_cpu_ir)); } static void d68000_asl_s_8(void) { sprintf(g_dasm_str, "asl.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_asl_s_16(void) { sprintf(g_dasm_str, "asl.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_asl_s_32(void) { sprintf(g_dasm_str, "asl.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_asl_r_8(void) { sprintf(g_dasm_str, "asl.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_asl_r_16(void) { sprintf(g_dasm_str, "asl.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_asl_r_32(void) { sprintf(g_dasm_str, "asl.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_asl_ea(void) { sprintf(g_dasm_str, "asl.w %s", get_ea_mode_str_16(g_cpu_ir)); } static void d68000_bcc_8(void) { uint temp_pc = g_cpu_pc; sprintf(g_dasm_str, "b%-2s %x", g_cc[(g_cpu_ir>>8)&0xf], temp_pc + make_int_8(g_cpu_ir)); } static void d68000_bcc_16(void) { uint temp_pc = g_cpu_pc; sprintf(g_dasm_str, "b%-2s %x", g_cc[(g_cpu_ir>>8)&0xf], temp_pc + make_int_16(read_imm_16())); } static void d68020_bcc_32(void) { uint temp_pc = g_cpu_pc; LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "b%-2s %x; (2+)", g_cc[(g_cpu_ir>>8)&0xf], temp_pc + read_imm_32()); } static void d68000_bchg_r(void) { sprintf(g_dasm_str, "bchg D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); } static void d68000_bchg_s(void) { char* str = get_imm_str_u8(); sprintf(g_dasm_str, "bchg %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); } static void d68000_bclr_r(void) { sprintf(g_dasm_str, "bclr D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); } static void d68000_bclr_s(void) { char* str = get_imm_str_u8(); sprintf(g_dasm_str, "bclr %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); } static void d68010_bkpt(void) { LIMIT_CPU_TYPES(M68010_PLUS); sprintf(g_dasm_str, "bkpt #%d; (1+)", g_cpu_ir&7); } static void d68020_bfchg(void) { uint extension; char offset[3]; char width[3]; LIMIT_CPU_TYPES(M68020_PLUS); extension = read_imm_16(); if(BIT_B(extension)) sprintf(offset, "D%d", (extension>>6)&7); else sprintf(offset, "%d", (extension>>6)&31); if(BIT_5(extension)) sprintf(width, "D%d", extension&7); else sprintf(width, "%d", g_5bit_data_table[extension&31]); sprintf(g_dasm_str, "bfchg %s {%s:%s}; (2+)", get_ea_mode_str_8(g_cpu_ir), offset, width); } static void d68020_bfclr(void) { uint extension; char offset[3]; char width[3]; LIMIT_CPU_TYPES(M68020_PLUS); extension = read_imm_16(); if(BIT_B(extension)) sprintf(offset, "D%d", (extension>>6)&7); else sprintf(offset, "%d", (extension>>6)&31); if(BIT_5(extension)) sprintf(width, "D%d", extension&7); else sprintf(width, "%d", g_5bit_data_table[extension&31]); sprintf(g_dasm_str, "bfclr %s {%s:%s}; (2+)", get_ea_mode_str_8(g_cpu_ir), offset, width); } static void d68020_bfexts(void) { uint extension; char offset[3]; char width[3]; LIMIT_CPU_TYPES(M68020_PLUS); extension = read_imm_16(); if(BIT_B(extension)) sprintf(offset, "D%d", (extension>>6)&7); else sprintf(offset, "%d", (extension>>6)&31); if(BIT_5(extension)) sprintf(width, "D%d", extension&7); else sprintf(width, "%d", g_5bit_data_table[extension&31]); sprintf(g_dasm_str, "bfexts %s {%s:%s}, D%d; (2+)", get_ea_mode_str_8(g_cpu_ir), offset, width, (extension>>12)&7); } static void d68020_bfextu(void) { uint extension; char offset[3]; char width[3]; LIMIT_CPU_TYPES(M68020_PLUS); extension = read_imm_16(); if(BIT_B(extension)) sprintf(offset, "D%d", (extension>>6)&7); else sprintf(offset, "%d", (extension>>6)&31); if(BIT_5(extension)) sprintf(width, "D%d", extension&7); else sprintf(width, "%d", g_5bit_data_table[extension&31]); sprintf(g_dasm_str, "bfextu %s {%s:%s}, D%d; (2+)", get_ea_mode_str_8(g_cpu_ir), offset, width, (extension>>12)&7); } static void d68020_bfffo(void) { uint extension; char offset[3]; char width[3]; LIMIT_CPU_TYPES(M68020_PLUS); extension = read_imm_16(); if(BIT_B(extension)) sprintf(offset, "D%d", (extension>>6)&7); else sprintf(offset, "%d", (extension>>6)&31); if(BIT_5(extension)) sprintf(width, "D%d", extension&7); else sprintf(width, "%d", g_5bit_data_table[extension&31]); sprintf(g_dasm_str, "bfffo %s {%s:%s}, D%d; (2+)", get_ea_mode_str_8(g_cpu_ir), offset, width, (extension>>12)&7); } static void d68020_bfins(void) { uint extension; char offset[3]; char width[3]; LIMIT_CPU_TYPES(M68020_PLUS); extension = read_imm_16(); if(BIT_B(extension)) sprintf(offset, "D%d", (extension>>6)&7); else sprintf(offset, "%d", (extension>>6)&31); if(BIT_5(extension)) sprintf(width, "D%d", extension&7); else sprintf(width, "%d", g_5bit_data_table[extension&31]); sprintf(g_dasm_str, "bfins D%d, %s {%s:%s}; (2+)", (extension>>12)&7, get_ea_mode_str_8(g_cpu_ir), offset, width); } static void d68020_bfset(void) { uint extension; char offset[3]; char width[3]; LIMIT_CPU_TYPES(M68020_PLUS); extension = read_imm_16(); if(BIT_B(extension)) sprintf(offset, "D%d", (extension>>6)&7); else sprintf(offset, "%d", (extension>>6)&31); if(BIT_5(extension)) sprintf(width, "D%d", extension&7); else sprintf(width, "%d", g_5bit_data_table[extension&31]); sprintf(g_dasm_str, "bfset %s {%s:%s}; (2+)", get_ea_mode_str_8(g_cpu_ir), offset, width); } static void d68020_bftst(void) { uint extension; char offset[3]; char width[3]; LIMIT_CPU_TYPES(M68020_PLUS); extension = read_imm_16(); if(BIT_B(extension)) sprintf(offset, "D%d", (extension>>6)&7); else sprintf(offset, "%d", (extension>>6)&31); if(BIT_5(extension)) sprintf(width, "D%d", extension&7); else sprintf(width, "%d", g_5bit_data_table[extension&31]); sprintf(g_dasm_str, "bftst %s {%s:%s}; (2+)", get_ea_mode_str_8(g_cpu_ir), offset, width); } static void d68000_bra_8(void) { uint temp_pc = g_cpu_pc; sprintf(g_dasm_str, "bra %x", temp_pc + make_int_8(g_cpu_ir)); } static void d68000_bra_16(void) { uint temp_pc = g_cpu_pc; sprintf(g_dasm_str, "bra %x", temp_pc + make_int_16(read_imm_16())); } static void d68020_bra_32(void) { uint temp_pc = g_cpu_pc; LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "bra %x; (2+)", temp_pc + read_imm_32()); } static void d68000_bset_r(void) { sprintf(g_dasm_str, "bset D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); } static void d68000_bset_s(void) { char* str = get_imm_str_u8(); sprintf(g_dasm_str, "bset %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); } static void d68000_bsr_8(void) { uint temp_pc = g_cpu_pc; sprintf(g_dasm_str, "bsr %x", temp_pc + make_int_8(g_cpu_ir)); } static void d68000_bsr_16(void) { uint temp_pc = g_cpu_pc; sprintf(g_dasm_str, "bsr %x", temp_pc + make_int_16(read_imm_16())); } static void d68020_bsr_32(void) { uint temp_pc = g_cpu_pc; LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "bsr %x; (2+)", temp_pc + peek_imm_32()); } static void d68000_btst_r(void) { sprintf(g_dasm_str, "btst D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); } static void d68000_btst_s(void) { char* str = get_imm_str_u8(); sprintf(g_dasm_str, "btst %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); } static void d68020_callm(void) { char* str; LIMIT_CPU_TYPES(M68020_ONLY); str = get_imm_str_u8(); sprintf(g_dasm_str, "callm %s, %s; (2)", str, get_ea_mode_str_8(g_cpu_ir)); } static void d68020_cas_8(void) { uint extension; LIMIT_CPU_TYPES(M68020_PLUS); extension = read_imm_16(); sprintf(g_dasm_str, "cas.b D%d, D%d, %s; (2+)", extension&7, (extension>>6)&7, get_ea_mode_str_8(g_cpu_ir)); } static void d68020_cas_16(void) { uint extension; LIMIT_CPU_TYPES(M68020_PLUS); extension = read_imm_16(); sprintf(g_dasm_str, "cas.w D%d, D%d, %s; (2+)", extension&7, (extension>>6)&7, get_ea_mode_str_16(g_cpu_ir)); } static void d68020_cas_32(void) { uint extension; LIMIT_CPU_TYPES(M68020_PLUS); extension = read_imm_16(); sprintf(g_dasm_str, "cas.l D%d, D%d, %s; (2+)", extension&7, (extension>>6)&7, get_ea_mode_str_32(g_cpu_ir)); } static void d68020_cas2_16(void) { /* CAS2 Dc1:Dc2,Du1:Dc2:(Rn1):(Rn2) f e d c b a 9 8 7 6 5 4 3 2 1 0 DARn1 0 0 0 Du1 0 0 0 Dc1 DARn2 0 0 0 Du2 0 0 0 Dc2 */ uint extension; LIMIT_CPU_TYPES(M68020_PLUS); extension = read_imm_32(); sprintf(g_dasm_str, "cas2.w D%d:D%d, D%d:D%d, (%c%d):(%c%d); (2+)", (extension>>16)&7, extension&7, (extension>>22)&7, (extension>>6)&7, BIT_1F(extension) ? 'A' : 'D', (extension>>28)&7, BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); } static void d68020_cas2_32(void) { uint extension; LIMIT_CPU_TYPES(M68020_PLUS); extension = read_imm_32(); sprintf(g_dasm_str, "cas2.l D%d:D%d, D%d:D%d, (%c%d):(%c%d); (2+)", (extension>>16)&7, extension&7, (extension>>22)&7, (extension>>6)&7, BIT_1F(extension) ? 'A' : 'D', (extension>>28)&7, BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); } static void d68000_chk_16(void) { sprintf(g_dasm_str, "chk.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68020_chk_32(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "chk.l %s, D%d; (2+)", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68020_chk2_cmp2_8(void) { uint extension; LIMIT_CPU_TYPES(M68020_PLUS); extension = read_imm_16(); sprintf(g_dasm_str, "%s.b %s, %c%d; (2+)", BIT_B(extension) ? "chk2" : "cmp2", get_ea_mode_str_8(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); } static void d68020_chk2_cmp2_16(void) { uint extension; LIMIT_CPU_TYPES(M68020_PLUS); extension = read_imm_16(); sprintf(g_dasm_str, "%s.w %s, %c%d; (2+)", BIT_B(extension) ? "chk2" : "cmp2", get_ea_mode_str_16(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); } static void d68020_chk2_cmp2_32(void) { uint extension; LIMIT_CPU_TYPES(M68020_PLUS); extension = read_imm_16(); sprintf(g_dasm_str, "%s.l %s, %c%d; (2+)", BIT_B(extension) ? "chk2" : "cmp2", get_ea_mode_str_32(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); } static void d68040_cinv(void) { LIMIT_CPU_TYPES(M68040_PLUS); switch((g_cpu_ir>>3)&3) { case 0: sprintf(g_dasm_str, "cinv (illegal scope); (4)"); break; case 1: sprintf(g_dasm_str, "cinvl %d, (A%d); (4)", (g_cpu_ir>>6)&3, g_cpu_ir&7); break; case 2: sprintf(g_dasm_str, "cinvp %d, (A%d); (4)", (g_cpu_ir>>6)&3, g_cpu_ir&7); break; case 3: sprintf(g_dasm_str, "cinva %d; (4)", (g_cpu_ir>>6)&3); break; } } static void d68000_clr_8(void) { sprintf(g_dasm_str, "clr.b %s", get_ea_mode_str_8(g_cpu_ir)); } static void d68000_clr_16(void) { sprintf(g_dasm_str, "clr.w %s", get_ea_mode_str_16(g_cpu_ir)); } static void d68000_clr_32(void) { sprintf(g_dasm_str, "clr.l %s", get_ea_mode_str_32(g_cpu_ir)); } static void d68000_cmp_8(void) { sprintf(g_dasm_str, "cmp.b %s, D%d", get_ea_mode_str_8(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_cmp_16(void) { sprintf(g_dasm_str, "cmp.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_cmp_32(void) { sprintf(g_dasm_str, "cmp.l %s, D%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_cmpa_16(void) { sprintf(g_dasm_str, "cmpa.w %s, A%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_cmpa_32(void) { sprintf(g_dasm_str, "cmpa.l %s, A%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_cmpi_8(void) { char* str = get_imm_str_s8(); sprintf(g_dasm_str, "cmpi.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); } static void d68020_cmpi_pcdi_8(void) { char* str; LIMIT_CPU_TYPES(M68010_PLUS); str = get_imm_str_s8(); sprintf(g_dasm_str, "cmpi.b %s, %s; (2+)", str, get_ea_mode_str_8(g_cpu_ir)); } static void d68020_cmpi_pcix_8(void) { char* str; LIMIT_CPU_TYPES(M68010_PLUS); str = get_imm_str_s8(); sprintf(g_dasm_str, "cmpi.b %s, %s; (2+)", str, get_ea_mode_str_8(g_cpu_ir)); } static void d68000_cmpi_16(void) { char* str; str = get_imm_str_s16(); sprintf(g_dasm_str, "cmpi.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir)); } static void d68020_cmpi_pcdi_16(void) { char* str; LIMIT_CPU_TYPES(M68010_PLUS); str = get_imm_str_s16(); sprintf(g_dasm_str, "cmpi.w %s, %s; (2+)", str, get_ea_mode_str_16(g_cpu_ir)); } static void d68020_cmpi_pcix_16(void) { char* str; LIMIT_CPU_TYPES(M68010_PLUS); str = get_imm_str_s16(); sprintf(g_dasm_str, "cmpi.w %s, %s; (2+)", str, get_ea_mode_str_16(g_cpu_ir)); } static void d68000_cmpi_32(void) { char* str; str = get_imm_str_s32(); sprintf(g_dasm_str, "cmpi.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir)); } static void d68020_cmpi_pcdi_32(void) { char* str; LIMIT_CPU_TYPES(M68010_PLUS); str = get_imm_str_s32(); sprintf(g_dasm_str, "cmpi.l %s, %s; (2+)", str, get_ea_mode_str_32(g_cpu_ir)); } static void d68020_cmpi_pcix_32(void) { char* str; LIMIT_CPU_TYPES(M68010_PLUS); str = get_imm_str_s32(); sprintf(g_dasm_str, "cmpi.l %s, %s; (2+)", str, get_ea_mode_str_32(g_cpu_ir)); } static void d68000_cmpm_8(void) { sprintf(g_dasm_str, "cmpm.b (A%d)+, (A%d)+", g_cpu_ir&7, (g_cpu_ir>>9)&7); } static void d68000_cmpm_16(void) { sprintf(g_dasm_str, "cmpm.w (A%d)+, (A%d)+", g_cpu_ir&7, (g_cpu_ir>>9)&7); } static void d68000_cmpm_32(void) { sprintf(g_dasm_str, "cmpm.l (A%d)+, (A%d)+", g_cpu_ir&7, (g_cpu_ir>>9)&7); } static void d68020_cpbcc_16(void) { uint extension; uint new_pc = g_cpu_pc; LIMIT_CPU_TYPES(M68020_PLUS); extension = read_imm_16(); new_pc += make_int_16(peek_imm_16()); sprintf(g_dasm_str, "%db%-4s %s; %x (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[g_cpu_ir&0x3f], get_imm_str_s16(), new_pc, extension); } static void d68020_cpbcc_32(void) { uint extension; uint new_pc = g_cpu_pc; LIMIT_CPU_TYPES(M68020_PLUS); extension = read_imm_16(); new_pc += peek_imm_32(); sprintf(g_dasm_str, "%db%-4s %s; %x (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[g_cpu_ir&0x3f], get_imm_str_s16(), new_pc, extension); } static void d68020_cpdbcc(void) { uint extension1; uint extension2; uint new_pc = g_cpu_pc; LIMIT_CPU_TYPES(M68020_PLUS); extension1 = read_imm_16(); extension2 = read_imm_16(); new_pc += make_int_16(peek_imm_16()); sprintf(g_dasm_str, "%ddb%-4s D%d,%s; %x (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[extension1&0x3f], g_cpu_ir&7, get_imm_str_s16(), new_pc, extension2); } static void d68020_cpgen(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "%dgen %s; (2-3)", (g_cpu_ir>>9)&7, get_imm_str_u32()); } static void d68020_cprestore(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "%drestore %s; (2-3)", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); } static void d68020_cpsave(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "%dsave %s; (2-3)", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); } static void d68020_cpscc(void) { uint extension1; uint extension2; LIMIT_CPU_TYPES(M68020_PLUS); extension1 = read_imm_16(); extension2 = read_imm_16(); sprintf(g_dasm_str, "%ds%-4s %s; (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[extension1&0x3f], get_ea_mode_str_8(g_cpu_ir), extension2); } static void d68020_cptrapcc_0(void) { uint extension1; uint extension2; LIMIT_CPU_TYPES(M68020_PLUS); extension1 = read_imm_16(); extension2 = read_imm_16(); sprintf(g_dasm_str, "%dtrap%-4s; (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[extension1&0x3f], extension2); } static void d68020_cptrapcc_16(void) { uint extension1; uint extension2; LIMIT_CPU_TYPES(M68020_PLUS); extension1 = read_imm_16(); extension2 = read_imm_16(); sprintf(g_dasm_str, "%dtrap%-4s %s; (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[extension1&0x3f], get_imm_str_u16(), extension2); } static void d68020_cptrapcc_32(void) { uint extension1; uint extension2; LIMIT_CPU_TYPES(M68020_PLUS); extension1 = read_imm_16(); extension2 = read_imm_16(); sprintf(g_dasm_str, "%dtrap%-4s %s; (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[extension1&0x3f], get_imm_str_u32(), extension2); } static void d68040_cpush(void) { LIMIT_CPU_TYPES(M68040_PLUS); switch((g_cpu_ir>>3)&3) { case 0: sprintf(g_dasm_str, "cpush (illegal scope); (4)"); break; case 1: sprintf(g_dasm_str, "cpushl %d, (A%d); (4)", (g_cpu_ir>>6)&3, g_cpu_ir&7); break; case 2: sprintf(g_dasm_str, "cpushp %d, (A%d); (4)", (g_cpu_ir>>6)&3, g_cpu_ir&7); break; case 3: sprintf(g_dasm_str, "cpusha %d; (4)", (g_cpu_ir>>6)&3); break; } } static void d68000_dbra(void) { uint temp_pc = g_cpu_pc; sprintf(g_dasm_str, "dbra D%d, %x", g_cpu_ir & 7, temp_pc + make_int_16(read_imm_16())); } static void d68000_dbcc(void) { uint temp_pc = g_cpu_pc; sprintf(g_dasm_str, "db%-2s D%d, %x", g_cc[(g_cpu_ir>>8)&0xf], g_cpu_ir & 7, temp_pc + make_int_16(read_imm_16())); } static void d68000_divs(void) { sprintf(g_dasm_str, "divs.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_divu(void) { sprintf(g_dasm_str, "divu.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68020_divl(void) { uint extension; LIMIT_CPU_TYPES(M68020_PLUS); extension = read_imm_16(); if(BIT_A(extension)) sprintf(g_dasm_str, "div%c.l %s, D%d:D%d; (2+)", BIT_B(extension) ? 's' : 'u', get_ea_mode_str_32(g_cpu_ir), extension&7, (extension>>12)&7); else if((extension&7) == ((extension>>12)&7)) sprintf(g_dasm_str, "div%c.l %s, D%d; (2+)", BIT_B(extension) ? 's' : 'u', get_ea_mode_str_32(g_cpu_ir), (extension>>12)&7); else sprintf(g_dasm_str, "div%cl.l %s, D%d:D%d; (2+)", BIT_B(extension) ? 's' : 'u', get_ea_mode_str_32(g_cpu_ir), extension&7, (extension>>12)&7); } static void d68000_eor_8(void) { sprintf(g_dasm_str, "eor.b D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); } static void d68000_eor_16(void) { sprintf(g_dasm_str, "eor.w D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_16(g_cpu_ir)); } static void d68000_eor_32(void) { sprintf(g_dasm_str, "eor.l D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_32(g_cpu_ir)); } static void d68000_eori_8(void) { char* str = get_imm_str_u8(); sprintf(g_dasm_str, "eori.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); } static void d68000_eori_16(void) { char* str = get_imm_str_u16(); sprintf(g_dasm_str, "eori.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir)); } static void d68000_eori_32(void) { char* str = get_imm_str_u32(); sprintf(g_dasm_str, "eori.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir)); } static void d68000_eori_to_ccr(void) { sprintf(g_dasm_str, "eori %s, CCR", get_imm_str_u8()); } static void d68000_eori_to_sr(void) { sprintf(g_dasm_str, "eori %s, SR", get_imm_str_u16()); } static void d68000_exg_dd(void) { sprintf(g_dasm_str, "exg D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_exg_aa(void) { sprintf(g_dasm_str, "exg A%d, A%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_exg_da(void) { sprintf(g_dasm_str, "exg D%d, A%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_ext_16(void) { sprintf(g_dasm_str, "ext.w D%d", g_cpu_ir&7); } static void d68000_ext_32(void) { sprintf(g_dasm_str, "ext.l D%d", g_cpu_ir&7); } static void d68020_extb_32(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "extb.l D%d; (2+)", g_cpu_ir&7); } static void d68000_jmp(void) { sprintf(g_dasm_str, "jmp %s", get_ea_mode_str_32(g_cpu_ir)); } static void d68000_jsr(void) { sprintf(g_dasm_str, "jsr %s", get_ea_mode_str_32(g_cpu_ir)); } static void d68000_lea(void) { sprintf(g_dasm_str, "lea %s, A%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_link_16(void) { sprintf(g_dasm_str, "link A%d, %s", g_cpu_ir&7, get_imm_str_s16()); } static void d68020_link_32(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "link A%d, %s; (2+)", g_cpu_ir&7, get_imm_str_s32()); } static void d68000_lsr_s_8(void) { sprintf(g_dasm_str, "lsr.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_lsr_s_16(void) { sprintf(g_dasm_str, "lsr.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_lsr_s_32(void) { sprintf(g_dasm_str, "lsr.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_lsr_r_8(void) { sprintf(g_dasm_str, "lsr.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_lsr_r_16(void) { sprintf(g_dasm_str, "lsr.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_lsr_r_32(void) { sprintf(g_dasm_str, "lsr.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_lsr_ea(void) { sprintf(g_dasm_str, "lsr.w %s", get_ea_mode_str_32(g_cpu_ir)); } static void d68000_lsl_s_8(void) { sprintf(g_dasm_str, "lsl.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_lsl_s_16(void) { sprintf(g_dasm_str, "lsl.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_lsl_s_32(void) { sprintf(g_dasm_str, "lsl.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_lsl_r_8(void) { sprintf(g_dasm_str, "lsl.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_lsl_r_16(void) { sprintf(g_dasm_str, "lsl.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_lsl_r_32(void) { sprintf(g_dasm_str, "lsl.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_lsl_ea(void) { sprintf(g_dasm_str, "lsl.w %s", get_ea_mode_str_32(g_cpu_ir)); } static void d68000_move_8(void) { char* str = get_ea_mode_str_8(g_cpu_ir); sprintf(g_dasm_str, "move.b %s, %s", str, get_ea_mode_str_8(((g_cpu_ir>>9) & 7) | ((g_cpu_ir>>3) & 0x38))); } static void d68000_move_16(void) { char* str = get_ea_mode_str_16(g_cpu_ir); sprintf(g_dasm_str, "move.w %s, %s", str, get_ea_mode_str_16(((g_cpu_ir>>9) & 7) | ((g_cpu_ir>>3) & 0x38))); } static void d68000_move_32(void) { char* str = get_ea_mode_str_32(g_cpu_ir); sprintf(g_dasm_str, "move.l %s, %s", str, get_ea_mode_str_32(((g_cpu_ir>>9) & 7) | ((g_cpu_ir>>3) & 0x38))); } static void d68000_movea_16(void) { sprintf(g_dasm_str, "movea.w %s, A%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_movea_32(void) { sprintf(g_dasm_str, "movea.l %s, A%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_move_to_ccr(void) { sprintf(g_dasm_str, "move %s, CCR", get_ea_mode_str_8(g_cpu_ir)); } static void d68010_move_fr_ccr(void) { LIMIT_CPU_TYPES(M68010_PLUS); sprintf(g_dasm_str, "move CCR, %s; (1+)", get_ea_mode_str_8(g_cpu_ir)); } static void d68000_move_fr_sr(void) { sprintf(g_dasm_str, "move SR, %s", get_ea_mode_str_16(g_cpu_ir)); } static void d68000_move_to_sr(void) { sprintf(g_dasm_str, "move %s, SR", get_ea_mode_str_16(g_cpu_ir)); } static void d68000_move_fr_usp(void) { sprintf(g_dasm_str, "move USP, A%d", g_cpu_ir&7); } static void d68000_move_to_usp(void) { sprintf(g_dasm_str, "move A%d, USP", g_cpu_ir&7); } static void d68010_movec(void) { uint extension; char* reg_name; char* processor; LIMIT_CPU_TYPES(M68010_PLUS); extension = read_imm_16(); switch(extension & 0xfff) { case 0x000: reg_name = "SFC"; processor = "1+"; break; case 0x001: reg_name = "DFC"; processor = "1+"; break; case 0x800: reg_name = "USP"; processor = "1+"; break; case 0x801: reg_name = "VBR"; processor = "1+"; break; case 0x002: reg_name = "CACR"; processor = "2+"; break; case 0x802: reg_name = "CAAR"; processor = "2,3"; break; case 0x803: reg_name = "MSP"; processor = "2+"; break; case 0x804: reg_name = "ISP"; processor = "2+"; break; case 0x003: reg_name = "TC"; processor = "4+"; break; case 0x004: reg_name = "ITT0"; processor = "4+"; break; case 0x005: reg_name = "ITT1"; processor = "4+"; break; case 0x006: reg_name = "DTT0"; processor = "4+"; break; case 0x007: reg_name = "DTT1"; processor = "4+"; break; case 0x805: reg_name = "MMUSR"; processor = "4+"; break; case 0x806: reg_name = "URP"; processor = "4+"; break; case 0x807: reg_name = "SRP"; processor = "4+"; break; default: reg_name = make_signed_hex_str_16(extension & 0xfff); processor = "?"; } if(BIT_1(g_cpu_ir)) sprintf(g_dasm_str, "movec %c%d, %s; (%s)", BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, reg_name, processor); else sprintf(g_dasm_str, "movec %s, %c%d; (%s)", reg_name, BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, processor); } static void d68000_movem_pd_16(void) { uint data = read_imm_16(); char buffer[40]; uint first; uint run_length; uint i; buffer[0] = 0; for(i=0;i<8;i++) { if(data&(1<<(15-i))) { first = i; run_length = 0; while(i<7 && (data&(1<<(15-(i+1))))) { i++; run_length++; } if(buffer[0] != 0) strcat(buffer, "/"); sprintf(buffer+strlen(buffer), "D%d", first); if(run_length > 0) sprintf(buffer+strlen(buffer), "-D%d", first + run_length); } } for(i=0;i<8;i++) { if(data&(1<<(7-i))) { first = i; run_length = 0; while(i<7 && (data&(1<<(7-(i+1))))) { i++; run_length++; } if(buffer[0] != 0) strcat(buffer, "/"); sprintf(buffer+strlen(buffer), "A%d", first); if(run_length > 0) sprintf(buffer+strlen(buffer), "-A%d", first + run_length); } } sprintf(g_dasm_str, "movem.w %s, %s", buffer, get_ea_mode_str_16(g_cpu_ir)); } static void d68000_movem_pd_32(void) { uint data = read_imm_16(); char buffer[40]; uint first; uint run_length; uint i; buffer[0] = 0; for(i=0;i<8;i++) { if(data&(1<<(15-i))) { first = i; run_length = 0; while(i<7 && (data&(1<<(15-(i+1))))) { i++; run_length++; } if(buffer[0] != 0) strcat(buffer, "/"); sprintf(buffer+strlen(buffer), "D%d", first); if(run_length > 0) sprintf(buffer+strlen(buffer), "-D%d", first + run_length); } } for(i=0;i<8;i++) { if(data&(1<<(7-i))) { first = i; run_length = 0; while(i<7 && (data&(1<<(7-(i+1))))) { i++; run_length++; } if(buffer[0] != 0) strcat(buffer, "/"); sprintf(buffer+strlen(buffer), "A%d", first); if(run_length > 0) sprintf(buffer+strlen(buffer), "-A%d", first + run_length); } } sprintf(g_dasm_str, "movem.l %s, %s", buffer, get_ea_mode_str_32(g_cpu_ir)); } static void d68000_movem_er_16(void) { uint data = read_imm_16(); char buffer[40]; uint first; uint run_length; uint i; buffer[0] = 0; for(i=0;i<8;i++) { if(data&(1< 0) sprintf(buffer+strlen(buffer), "-D%d", first + run_length); } } for(i=0;i<8;i++) { if(data&(1<<(i+8))) { first = i; run_length = 0; while(i<7 && (data&(1<<(i+8+1)))) { i++; run_length++; } if(buffer[0] != 0) strcat(buffer, "/"); sprintf(buffer+strlen(buffer), "A%d", first); if(run_length > 0) sprintf(buffer+strlen(buffer), "-A%d", first + run_length); } } sprintf(g_dasm_str, "movem.w %s, %s", get_ea_mode_str_16(g_cpu_ir), buffer); } static void d68000_movem_er_32(void) { uint data = read_imm_16(); char buffer[40]; uint first; uint run_length; uint i; buffer[0] = 0; for(i=0;i<8;i++) { if(data&(1< 0) sprintf(buffer+strlen(buffer), "-D%d", first + run_length); } } for(i=0;i<8;i++) { if(data&(1<<(i+8))) { first = i; run_length = 0; while(i<7 && (data&(1<<(i+8+1)))) { i++; run_length++; } if(buffer[0] != 0) strcat(buffer, "/"); sprintf(buffer+strlen(buffer), "A%d", first); if(run_length > 0) sprintf(buffer+strlen(buffer), "-A%d", first + run_length); } } sprintf(g_dasm_str, "movem.l %s, %s", get_ea_mode_str_32(g_cpu_ir), buffer); } static void d68000_movem_re_16(void) { uint data = read_imm_16(); char buffer[40]; uint first; uint run_length; uint i; buffer[0] = 0; for(i=0;i<8;i++) { if(data&(1< 0) sprintf(buffer+strlen(buffer), "-D%d", first + run_length); } } for(i=0;i<8;i++) { if(data&(1<<(i+8))) { first = i; run_length = 0; while(i<7 && (data&(1<<(i+8+1)))) { i++; run_length++; } if(buffer[0] != 0) strcat(buffer, "/"); sprintf(buffer+strlen(buffer), "A%d", first); if(run_length > 0) sprintf(buffer+strlen(buffer), "-A%d", first + run_length); } } sprintf(g_dasm_str, "movem.w %s, %s", buffer, get_ea_mode_str_16(g_cpu_ir)); } static void d68000_movem_re_32(void) { uint data = read_imm_16(); char buffer[40]; uint first; uint run_length; uint i; buffer[0] = 0; for(i=0;i<8;i++) { if(data&(1< 0) sprintf(buffer+strlen(buffer), "-D%d", first + run_length); } } for(i=0;i<8;i++) { if(data&(1<<(i+8))) { first = i; run_length = 0; while(i<7 && (data&(1<<(i+8+1)))) { i++; run_length++; } if(buffer[0] != 0) strcat(buffer, "/"); sprintf(buffer+strlen(buffer), "A%d", first); if(run_length > 0) sprintf(buffer+strlen(buffer), "-A%d", first + run_length); } } sprintf(g_dasm_str, "movem.l %s, %s", buffer, get_ea_mode_str_32(g_cpu_ir)); } static void d68000_movep_re_16(void) { sprintf(g_dasm_str, "movep.w D%d, ($%x,A%d)", (g_cpu_ir>>9)&7, read_imm_16(), g_cpu_ir&7); } static void d68000_movep_re_32(void) { sprintf(g_dasm_str, "movep.l D%d, ($%x,A%d)", (g_cpu_ir>>9)&7, read_imm_16(), g_cpu_ir&7); } static void d68000_movep_er_16(void) { sprintf(g_dasm_str, "movep.w ($%x,A%d), D%d", read_imm_16(), g_cpu_ir&7, (g_cpu_ir>>9)&7); } static void d68000_movep_er_32(void) { sprintf(g_dasm_str, "movep.l ($%x,A%d), D%d", read_imm_16(), g_cpu_ir&7, (g_cpu_ir>>9)&7); } static void d68010_moves_8(void) { uint extension; LIMIT_CPU_TYPES(M68010_PLUS); extension = read_imm_16(); if(BIT_B(extension)) sprintf(g_dasm_str, "moves.b %c%d, %s; (1+)", BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, get_ea_mode_str_8(g_cpu_ir)); else sprintf(g_dasm_str, "moves.b %s, %c%d; (1+)", get_ea_mode_str_8(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); } static void d68010_moves_16(void) { uint extension; LIMIT_CPU_TYPES(M68010_PLUS); extension = read_imm_16(); if(BIT_B(extension)) sprintf(g_dasm_str, "moves.w %c%d, %s; (1+)", BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, get_ea_mode_str_16(g_cpu_ir)); else sprintf(g_dasm_str, "moves.w %s, %c%d; (1+)", get_ea_mode_str_16(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); } static void d68010_moves_32(void) { uint extension; LIMIT_CPU_TYPES(M68010_PLUS); extension = read_imm_16(); if(BIT_B(extension)) sprintf(g_dasm_str, "moves.l %c%d, %s; (1+)", BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, get_ea_mode_str_32(g_cpu_ir)); else sprintf(g_dasm_str, "moves.l %s, %c%d; (1+)", get_ea_mode_str_32(g_cpu_ir), BIT_F(extension) ? 'A' : 'D', (extension>>12)&7); } static void d68000_moveq(void) { sprintf(g_dasm_str, "moveq #%s, D%d", make_signed_hex_str_8(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68040_move16_pi_pi(void) { LIMIT_CPU_TYPES(M68040_PLUS); sprintf(g_dasm_str, "move16 (A%d)+, (A%d)+; (4)", g_cpu_ir&7, (read_imm_16()>>12)&7); } static void d68040_move16_pi_al(void) { LIMIT_CPU_TYPES(M68040_PLUS); sprintf(g_dasm_str, "move16 (A%d)+, %s; (4)", g_cpu_ir&7, get_imm_str_u32()); } static void d68040_move16_al_pi(void) { LIMIT_CPU_TYPES(M68040_PLUS); sprintf(g_dasm_str, "move16 %s, (A%d)+; (4)", get_imm_str_u32(), g_cpu_ir&7); } static void d68040_move16_ai_al(void) { LIMIT_CPU_TYPES(M68040_PLUS); sprintf(g_dasm_str, "move16 (A%d), %s; (4)", g_cpu_ir&7, get_imm_str_u32()); } static void d68040_move16_al_ai(void) { LIMIT_CPU_TYPES(M68040_PLUS); sprintf(g_dasm_str, "move16 %s, (A%d); (4)", get_imm_str_u32(), g_cpu_ir&7); } static void d68000_muls(void) { sprintf(g_dasm_str, "muls.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_mulu(void) { sprintf(g_dasm_str, "mulu.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68020_mull(void) { uint extension; LIMIT_CPU_TYPES(M68020_PLUS); extension = read_imm_16(); if(BIT_A(extension)) sprintf(g_dasm_str, "mul%c.l %s, D%d:D%d; (2+)", BIT_B(extension) ? 's' : 'u', get_ea_mode_str_32(g_cpu_ir), extension&7, (extension>>12)&7); else sprintf(g_dasm_str, "mul%c.l %s, D%d; (2+)", BIT_B(extension) ? 's' : 'u', get_ea_mode_str_32(g_cpu_ir), (extension>>12)&7); } static void d68000_nbcd(void) { sprintf(g_dasm_str, "nbcd %s", get_ea_mode_str_8(g_cpu_ir)); } static void d68000_neg_8(void) { sprintf(g_dasm_str, "neg.b %s", get_ea_mode_str_8(g_cpu_ir)); } static void d68000_neg_16(void) { sprintf(g_dasm_str, "neg.w %s", get_ea_mode_str_16(g_cpu_ir)); } static void d68000_neg_32(void) { sprintf(g_dasm_str, "neg.l %s", get_ea_mode_str_32(g_cpu_ir)); } static void d68000_negx_8(void) { sprintf(g_dasm_str, "negx.b %s", get_ea_mode_str_8(g_cpu_ir)); } static void d68000_negx_16(void) { sprintf(g_dasm_str, "negx.w %s", get_ea_mode_str_16(g_cpu_ir)); } static void d68000_negx_32(void) { sprintf(g_dasm_str, "negx.l %s", get_ea_mode_str_32(g_cpu_ir)); } static void d68000_nop(void) { sprintf(g_dasm_str, "nop"); } static void d68000_not_8(void) { sprintf(g_dasm_str, "not.b %s", get_ea_mode_str_8(g_cpu_ir)); } static void d68000_not_16(void) { sprintf(g_dasm_str, "not.w %s", get_ea_mode_str_16(g_cpu_ir)); } static void d68000_not_32(void) { sprintf(g_dasm_str, "not.l %s", get_ea_mode_str_32(g_cpu_ir)); } static void d68000_or_er_8(void) { sprintf(g_dasm_str, "or.b %s, D%d", get_ea_mode_str_8(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_or_er_16(void) { sprintf(g_dasm_str, "or.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_or_er_32(void) { sprintf(g_dasm_str, "or.l %s, D%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_or_re_8(void) { sprintf(g_dasm_str, "or.b D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); } static void d68000_or_re_16(void) { sprintf(g_dasm_str, "or.w D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_16(g_cpu_ir)); } static void d68000_or_re_32(void) { sprintf(g_dasm_str, "or.l D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_32(g_cpu_ir)); } static void d68000_ori_8(void) { char* str = get_imm_str_u8(); sprintf(g_dasm_str, "ori.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); } static void d68000_ori_16(void) { char* str = get_imm_str_u16(); sprintf(g_dasm_str, "ori.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir)); } static void d68000_ori_32(void) { char* str = get_imm_str_u32(); sprintf(g_dasm_str, "ori.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir)); } static void d68000_ori_to_ccr(void) { sprintf(g_dasm_str, "ori %s, CCR", get_imm_str_u8()); } static void d68000_ori_to_sr(void) { sprintf(g_dasm_str, "ori %s, SR", get_imm_str_u16()); } static void d68020_pack_rr(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "pack D%d, D%d, %s; (2+)", g_cpu_ir&7, (g_cpu_ir>>9)&7, get_imm_str_u16()); } static void d68020_pack_mm(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "pack -(A%d), -(A%d), %s; (2+)", g_cpu_ir&7, (g_cpu_ir>>9)&7, get_imm_str_u16()); } static void d68000_pea(void) { sprintf(g_dasm_str, "pea %s", get_ea_mode_str_32(g_cpu_ir)); } static void d68000_reset(void) { sprintf(g_dasm_str, "reset"); } static void d68000_ror_s_8(void) { sprintf(g_dasm_str, "ror.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_ror_s_16(void) { sprintf(g_dasm_str, "ror.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7],g_cpu_ir&7); } static void d68000_ror_s_32(void) { sprintf(g_dasm_str, "ror.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_ror_r_8(void) { sprintf(g_dasm_str, "ror.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_ror_r_16(void) { sprintf(g_dasm_str, "ror.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_ror_r_32(void) { sprintf(g_dasm_str, "ror.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_ror_ea(void) { sprintf(g_dasm_str, "ror.w %s", get_ea_mode_str_32(g_cpu_ir)); } static void d68000_rol_s_8(void) { sprintf(g_dasm_str, "rol.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_rol_s_16(void) { sprintf(g_dasm_str, "rol.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_rol_s_32(void) { sprintf(g_dasm_str, "rol.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_rol_r_8(void) { sprintf(g_dasm_str, "rol.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_rol_r_16(void) { sprintf(g_dasm_str, "rol.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_rol_r_32(void) { sprintf(g_dasm_str, "rol.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_rol_ea(void) { sprintf(g_dasm_str, "rol.w %s", get_ea_mode_str_32(g_cpu_ir)); } static void d68000_roxr_s_8(void) { sprintf(g_dasm_str, "roxr.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_roxr_s_16(void) { sprintf(g_dasm_str, "roxr.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_roxr_s_32(void) { sprintf(g_dasm_str, "roxr.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_roxr_r_8(void) { sprintf(g_dasm_str, "roxr.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_roxr_r_16(void) { sprintf(g_dasm_str, "roxr.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_roxr_r_32(void) { sprintf(g_dasm_str, "roxr.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_roxr_ea(void) { sprintf(g_dasm_str, "roxr.w %s", get_ea_mode_str_32(g_cpu_ir)); } static void d68000_roxl_s_8(void) { sprintf(g_dasm_str, "roxl.b #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_roxl_s_16(void) { sprintf(g_dasm_str, "roxl.w #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_roxl_s_32(void) { sprintf(g_dasm_str, "roxl.l #%d, D%d", g_3bit_qdata_table[(g_cpu_ir>>9)&7], g_cpu_ir&7); } static void d68000_roxl_r_8(void) { sprintf(g_dasm_str, "roxl.b D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_roxl_r_16(void) { sprintf(g_dasm_str, "roxl.w D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_roxl_r_32(void) { sprintf(g_dasm_str, "roxl.l D%d, D%d", (g_cpu_ir>>9)&7, g_cpu_ir&7); } static void d68000_roxl_ea(void) { sprintf(g_dasm_str, "roxl.w %s", get_ea_mode_str_32(g_cpu_ir)); } static void d68010_rtd(void) { LIMIT_CPU_TYPES(M68010_PLUS); sprintf(g_dasm_str, "rtd %s; (1+)", get_imm_str_s16()); } static void d68000_rte(void) { sprintf(g_dasm_str, "rte"); } static void d68020_rtm(void) { LIMIT_CPU_TYPES(M68020_ONLY); sprintf(g_dasm_str, "rtm %c%d; (2+)", BIT_3(g_cpu_ir) ? 'A' : 'D', g_cpu_ir&7); } static void d68000_rtr(void) { sprintf(g_dasm_str, "rtr"); } static void d68000_rts(void) { sprintf(g_dasm_str, "rts"); } static void d68000_sbcd_rr(void) { sprintf(g_dasm_str, "sbcd D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); } static void d68000_sbcd_mm(void) { sprintf(g_dasm_str, "sbcd -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); } static void d68000_scc(void) { sprintf(g_dasm_str, "s%-2s %s", g_cc[(g_cpu_ir>>8)&0xf], get_ea_mode_str_8(g_cpu_ir)); } static void d68000_stop(void) { sprintf(g_dasm_str, "stop %s", get_imm_str_s16()); } static void d68000_sub_er_8(void) { sprintf(g_dasm_str, "sub.b %s, D%d", get_ea_mode_str_8(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_sub_er_16(void) { sprintf(g_dasm_str, "sub.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_sub_er_32(void) { sprintf(g_dasm_str, "sub.l %s, D%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_sub_re_8(void) { sprintf(g_dasm_str, "sub.b D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); } static void d68000_sub_re_16(void) { sprintf(g_dasm_str, "sub.w D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_16(g_cpu_ir)); } static void d68000_sub_re_32(void) { sprintf(g_dasm_str, "sub.l D%d, %s", (g_cpu_ir>>9)&7, get_ea_mode_str_32(g_cpu_ir)); } static void d68000_suba_16(void) { sprintf(g_dasm_str, "suba.w %s, A%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_suba_32(void) { sprintf(g_dasm_str, "suba.l %s, A%d", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7); } static void d68000_subi_8(void) { char* str = get_imm_str_s8(); sprintf(g_dasm_str, "subi.b %s, %s", str, get_ea_mode_str_8(g_cpu_ir)); } static void d68000_subi_16(void) { char* str = get_imm_str_s16(); sprintf(g_dasm_str, "subi.w %s, %s", str, get_ea_mode_str_16(g_cpu_ir)); } static void d68000_subi_32(void) { char* str = get_imm_str_s32(); sprintf(g_dasm_str, "subi.l %s, %s", str, get_ea_mode_str_32(g_cpu_ir)); } static void d68000_subq_8(void) { sprintf(g_dasm_str, "subq.b #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_8(g_cpu_ir)); } static void d68000_subq_16(void) { sprintf(g_dasm_str, "subq.w #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_16(g_cpu_ir)); } static void d68000_subq_32(void) { sprintf(g_dasm_str, "subq.l #%d, %s", g_3bit_qdata_table[(g_cpu_ir>>9)&7], get_ea_mode_str_32(g_cpu_ir)); } static void d68000_subx_rr_8(void) { sprintf(g_dasm_str, "subx.b D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); } static void d68000_subx_rr_16(void) { sprintf(g_dasm_str, "subx.w D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); } static void d68000_subx_rr_32(void) { sprintf(g_dasm_str, "subx.l D%d, D%d", g_cpu_ir&7, (g_cpu_ir>>9)&7); } static void d68000_subx_mm_8(void) { sprintf(g_dasm_str, "subx.b -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); } static void d68000_subx_mm_16(void) { sprintf(g_dasm_str, "subx.w -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); } static void d68000_subx_mm_32(void) { sprintf(g_dasm_str, "subx.l -(A%d), -(A%d)", g_cpu_ir&7, (g_cpu_ir>>9)&7); } static void d68000_swap(void) { sprintf(g_dasm_str, "swap D%d", g_cpu_ir&7); } static void d68000_tas(void) { sprintf(g_dasm_str, "tas %s", get_ea_mode_str_8(g_cpu_ir)); } static void d68000_trap(void) { sprintf(g_dasm_str, "trap #$%x", g_cpu_ir&0xf); } static void d68020_trapcc_0(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "trap%-2s; (2+)", g_cc[(g_cpu_ir>>8)&0xf]); } static void d68020_trapcc_16(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "trap%-2s %s; (2+)", g_cc[(g_cpu_ir>>8)&0xf], get_imm_str_u16()); } static void d68020_trapcc_32(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "trap%-2s %s; (2+)", g_cc[(g_cpu_ir>>8)&0xf], get_imm_str_u32()); } static void d68000_trapv(void) { sprintf(g_dasm_str, "trapv"); } static void d68000_tst_8(void) { sprintf(g_dasm_str, "tst.b %s", get_ea_mode_str_8(g_cpu_ir)); } static void d68020_tst_pcdi_8(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "tst.b %s; (2+)", get_ea_mode_str_8(g_cpu_ir)); } static void d68020_tst_pcix_8(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "tst.b %s; (2+)", get_ea_mode_str_8(g_cpu_ir)); } static void d68020_tst_i_8(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "tst.b %s; (2+)", get_ea_mode_str_8(g_cpu_ir)); } static void d68000_tst_16(void) { sprintf(g_dasm_str, "tst.w %s", get_ea_mode_str_16(g_cpu_ir)); } static void d68020_tst_a_16(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "tst.w %s; (2+)", get_ea_mode_str_16(g_cpu_ir)); } static void d68020_tst_pcdi_16(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "tst.w %s; (2+)", get_ea_mode_str_16(g_cpu_ir)); } static void d68020_tst_pcix_16(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "tst.w %s; (2+)", get_ea_mode_str_16(g_cpu_ir)); } static void d68020_tst_i_16(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "tst.w %s; (2+)", get_ea_mode_str_16(g_cpu_ir)); } static void d68000_tst_32(void) { sprintf(g_dasm_str, "tst.l %s", get_ea_mode_str_32(g_cpu_ir)); } static void d68020_tst_a_32(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "tst.l %s; (2+)", get_ea_mode_str_32(g_cpu_ir)); } static void d68020_tst_pcdi_32(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "tst.l %s; (2+)", get_ea_mode_str_32(g_cpu_ir)); } static void d68020_tst_pcix_32(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "tst.l %s; (2+)", get_ea_mode_str_32(g_cpu_ir)); } static void d68020_tst_i_32(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "tst.l %s; (2+)", get_ea_mode_str_32(g_cpu_ir)); } static void d68000_unlk(void) { sprintf(g_dasm_str, "unlk A%d", g_cpu_ir&7); } static void d68020_unpk_rr(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "unpk D%d, D%d, %s; (2+)", g_cpu_ir&7, (g_cpu_ir>>9)&7, get_imm_str_u16()); } static void d68020_unpk_mm(void) { LIMIT_CPU_TYPES(M68020_PLUS); sprintf(g_dasm_str, "unpk -(A%d), -(A%d), %s; (2+)", g_cpu_ir&7, (g_cpu_ir>>9)&7, get_imm_str_u16()); } /* ======================================================================== */ /* ======================= INSTRUCTION TABLE BUILDER ====================== */ /* ======================================================================== */ /* EA Masks: 800 = data register direct 400 = address register direct 200 = address register indirect 100 = ARI postincrement 80 = ARI pre-decrement 40 = ARI displacement 20 = ARI index 10 = absolute short 8 = absolute long 4 = immediate / sr 2 = pc displacement 1 = pc idx */ static opcode_struct g_opcode_info[] = { /* opcode handler mask match ea mask */ {d68000_1010 , 0xf000, 0xa000, 0x000}, {d68000_1111 , 0xf000, 0xf000, 0x000}, {d68000_abcd_rr , 0xf1f8, 0xc100, 0x000}, {d68000_abcd_mm , 0xf1f8, 0xc108, 0x000}, {d68000_add_er_8 , 0xf1c0, 0xd000, 0xbff}, {d68000_add_er_16 , 0xf1c0, 0xd040, 0xfff}, {d68000_add_er_32 , 0xf1c0, 0xd080, 0xfff}, {d68000_add_re_8 , 0xf1c0, 0xd100, 0x3f8}, {d68000_add_re_16 , 0xf1c0, 0xd140, 0x3f8}, {d68000_add_re_32 , 0xf1c0, 0xd180, 0x3f8}, {d68000_adda_16 , 0xf1c0, 0xd0c0, 0xfff}, {d68000_adda_32 , 0xf1c0, 0xd1c0, 0xfff}, {d68000_addi_8 , 0xffc0, 0x0600, 0xbf8}, {d68000_addi_16 , 0xffc0, 0x0640, 0xbf8}, {d68000_addi_32 , 0xffc0, 0x0680, 0xbf8}, {d68000_addq_8 , 0xf1c0, 0x5000, 0xbf8}, {d68000_addq_16 , 0xf1c0, 0x5040, 0xff8}, {d68000_addq_32 , 0xf1c0, 0x5080, 0xff8}, {d68000_addx_rr_8 , 0xf1f8, 0xd100, 0x000}, {d68000_addx_rr_16 , 0xf1f8, 0xd140, 0x000}, {d68000_addx_rr_32 , 0xf1f8, 0xd180, 0x000}, {d68000_addx_mm_8 , 0xf1f8, 0xd108, 0x000}, {d68000_addx_mm_16 , 0xf1f8, 0xd148, 0x000}, {d68000_addx_mm_32 , 0xf1f8, 0xd188, 0x000}, {d68000_and_er_8 , 0xf1c0, 0xc000, 0xbff}, {d68000_and_er_16 , 0xf1c0, 0xc040, 0xbff}, {d68000_and_er_32 , 0xf1c0, 0xc080, 0xbff}, {d68000_and_re_8 , 0xf1c0, 0xc100, 0x3f8}, {d68000_and_re_16 , 0xf1c0, 0xc140, 0x3f8}, {d68000_and_re_32 , 0xf1c0, 0xc180, 0x3f8}, {d68000_andi_to_ccr , 0xffff, 0x023c, 0x000}, {d68000_andi_to_sr , 0xffff, 0x027c, 0x000}, {d68000_andi_8 , 0xffc0, 0x0200, 0xbf8}, {d68000_andi_16 , 0xffc0, 0x0240, 0xbf8}, {d68000_andi_32 , 0xffc0, 0x0280, 0xbf8}, {d68000_asr_s_8 , 0xf1f8, 0xe000, 0x000}, {d68000_asr_s_16 , 0xf1f8, 0xe040, 0x000}, {d68000_asr_s_32 , 0xf1f8, 0xe080, 0x000}, {d68000_asr_r_8 , 0xf1f8, 0xe020, 0x000}, {d68000_asr_r_16 , 0xf1f8, 0xe060, 0x000}, {d68000_asr_r_32 , 0xf1f8, 0xe0a0, 0x000}, {d68000_asr_ea , 0xffc0, 0xe0c0, 0x3f8}, {d68000_asl_s_8 , 0xf1f8, 0xe100, 0x000}, {d68000_asl_s_16 , 0xf1f8, 0xe140, 0x000}, {d68000_asl_s_32 , 0xf1f8, 0xe180, 0x000}, {d68000_asl_r_8 , 0xf1f8, 0xe120, 0x000}, {d68000_asl_r_16 , 0xf1f8, 0xe160, 0x000}, {d68000_asl_r_32 , 0xf1f8, 0xe1a0, 0x000}, {d68000_asl_ea , 0xffc0, 0xe1c0, 0x3f8}, {d68000_bcc_8 , 0xf000, 0x6000, 0x000}, {d68000_bcc_16 , 0xf0ff, 0x6000, 0x000}, {d68020_bcc_32 , 0xf0ff, 0x60ff, 0x000}, {d68000_bchg_r , 0xf1c0, 0x0140, 0xbf8}, {d68000_bchg_s , 0xffc0, 0x0840, 0xbf8}, {d68000_bclr_r , 0xf1c0, 0x0180, 0xbf8}, {d68000_bclr_s , 0xffc0, 0x0880, 0xbf8}, {d68020_bfchg , 0xffc0, 0xeac0, 0xa78}, {d68020_bfclr , 0xffc0, 0xecc0, 0xa78}, {d68020_bfexts , 0xffc0, 0xebc0, 0xa7b}, {d68020_bfextu , 0xffc0, 0xe9c0, 0xa7b}, {d68020_bfffo , 0xffc0, 0xedc0, 0xa7b}, {d68020_bfins , 0xffc0, 0xefc0, 0xa78}, {d68020_bfset , 0xffc0, 0xeec0, 0xa78}, {d68020_bftst , 0xffc0, 0xe8c0, 0xa7b}, {d68010_bkpt , 0xfff8, 0x4848, 0x000}, {d68000_bra_8 , 0xff00, 0x6000, 0x000}, {d68000_bra_16 , 0xffff, 0x6000, 0x000}, {d68020_bra_32 , 0xffff, 0x60ff, 0x000}, {d68000_bset_r , 0xf1c0, 0x01c0, 0xbf8}, {d68000_bset_s , 0xffc0, 0x08c0, 0xbf8}, {d68000_bsr_8 , 0xff00, 0x6100, 0x000}, {d68000_bsr_16 , 0xffff, 0x6100, 0x000}, {d68020_bsr_32 , 0xffff, 0x61ff, 0x000}, {d68000_btst_r , 0xf1c0, 0x0100, 0xbff}, {d68000_btst_s , 0xffc0, 0x0800, 0xbfb}, {d68020_callm , 0xffc0, 0x06c0, 0x27b}, {d68020_cas_8 , 0xffc0, 0x0ac0, 0x3f8}, {d68020_cas_16 , 0xffc0, 0x0cc0, 0x3f8}, {d68020_cas_32 , 0xffc0, 0x0ec0, 0x3f8}, {d68020_cas2_16 , 0xffff, 0x0cfc, 0x000}, {d68020_cas2_32 , 0xffff, 0x0efc, 0x000}, {d68000_chk_16 , 0xf1c0, 0x4180, 0xbff}, {d68020_chk_32 , 0xf1c0, 0x4100, 0xbff}, {d68020_chk2_cmp2_8 , 0xffc0, 0x00c0, 0x27b}, {d68020_chk2_cmp2_16 , 0xffc0, 0x02c0, 0x27b}, {d68020_chk2_cmp2_32 , 0xffc0, 0x04c0, 0x27b}, {d68040_cinv , 0xff20, 0xf400, 0x000}, {d68000_clr_8 , 0xffc0, 0x4200, 0xbf8}, {d68000_clr_16 , 0xffc0, 0x4240, 0xbf8}, {d68000_clr_32 , 0xffc0, 0x4280, 0xbf8}, {d68000_cmp_8 , 0xf1c0, 0xb000, 0xbff}, {d68000_cmp_16 , 0xf1c0, 0xb040, 0xfff}, {d68000_cmp_32 , 0xf1c0, 0xb080, 0xfff}, {d68000_cmpa_16 , 0xf1c0, 0xb0c0, 0xfff}, {d68000_cmpa_32 , 0xf1c0, 0xb1c0, 0xfff}, {d68000_cmpi_8 , 0xffc0, 0x0c00, 0xbf8}, {d68020_cmpi_pcdi_8 , 0xffff, 0x0c3a, 0x000}, {d68020_cmpi_pcix_8 , 0xffff, 0x0c3b, 0x000}, {d68000_cmpi_16 , 0xffc0, 0x0c40, 0xbf8}, {d68020_cmpi_pcdi_16 , 0xffff, 0x0c7a, 0x000}, {d68020_cmpi_pcix_16 , 0xffff, 0x0c7b, 0x000}, {d68000_cmpi_32 , 0xffc0, 0x0c80, 0xbf8}, {d68020_cmpi_pcdi_32 , 0xffff, 0x0cba, 0x000}, {d68020_cmpi_pcix_32 , 0xffff, 0x0cbb, 0x000}, {d68000_cmpm_8 , 0xf1f8, 0xb108, 0x000}, {d68000_cmpm_16 , 0xf1f8, 0xb148, 0x000}, {d68000_cmpm_32 , 0xf1f8, 0xb188, 0x000}, {d68020_cpbcc_16 , 0xf1c0, 0xf080, 0x000}, {d68020_cpbcc_32 , 0xf1c0, 0xf0c0, 0x000}, {d68020_cpdbcc , 0xf1f8, 0xf048, 0x000}, {d68020_cpgen , 0xf1c0, 0xf000, 0x000}, {d68020_cprestore , 0xf1c0, 0xf140, 0x37f}, {d68020_cpsave , 0xf1c0, 0xf100, 0x2f8}, {d68020_cpscc , 0xf1c0, 0xf040, 0xbf8}, {d68020_cptrapcc_0 , 0xf1ff, 0xf07c, 0x000}, {d68020_cptrapcc_16 , 0xf1ff, 0xf07a, 0x000}, {d68020_cptrapcc_32 , 0xf1ff, 0xf07b, 0x000}, {d68040_cpush , 0xff20, 0xf420, 0x000}, {d68000_dbcc , 0xf0f8, 0x50c8, 0x000}, {d68000_dbra , 0xfff8, 0x51c8, 0x000}, {d68000_divs , 0xf1c0, 0x81c0, 0xbff}, {d68000_divu , 0xf1c0, 0x80c0, 0xbff}, {d68020_divl , 0xffc0, 0x4c40, 0xbff}, {d68000_eor_8 , 0xf1c0, 0xb100, 0xbf8}, {d68000_eor_16 , 0xf1c0, 0xb140, 0xbf8}, {d68000_eor_32 , 0xf1c0, 0xb180, 0xbf8}, {d68000_eori_to_ccr , 0xffff, 0x0a3c, 0x000}, {d68000_eori_to_sr , 0xffff, 0x0a7c, 0x000}, {d68000_eori_8 , 0xffc0, 0x0a00, 0xbf8}, {d68000_eori_16 , 0xffc0, 0x0a40, 0xbf8}, {d68000_eori_32 , 0xffc0, 0x0a80, 0xbf8}, {d68000_exg_dd , 0xf1f8, 0xc140, 0x000}, {d68000_exg_aa , 0xf1f8, 0xc148, 0x000}, {d68000_exg_da , 0xf1f8, 0xc188, 0x000}, {d68020_extb_32 , 0xfff8, 0x49c0, 0x000}, {d68000_ext_16 , 0xfff8, 0x4880, 0x000}, {d68000_ext_32 , 0xfff8, 0x48c0, 0x000}, {d68000_illegal , 0xffff, 0x4afc, 0x000}, {d68000_jmp , 0xffc0, 0x4ec0, 0x27b}, {d68000_jsr , 0xffc0, 0x4e80, 0x27b}, {d68000_lea , 0xf1c0, 0x41c0, 0x27b}, {d68000_link_16 , 0xfff8, 0x4e50, 0x000}, {d68020_link_32 , 0xfff8, 0x4808, 0x000}, {d68000_lsr_s_8 , 0xf1f8, 0xe008, 0x000}, {d68000_lsr_s_16 , 0xf1f8, 0xe048, 0x000}, {d68000_lsr_s_32 , 0xf1f8, 0xe088, 0x000}, {d68000_lsr_r_8 , 0xf1f8, 0xe028, 0x000}, {d68000_lsr_r_16 , 0xf1f8, 0xe068, 0x000}, {d68000_lsr_r_32 , 0xf1f8, 0xe0a8, 0x000}, {d68000_lsr_ea , 0xffc0, 0xe2c0, 0x3f8}, {d68000_lsl_s_8 , 0xf1f8, 0xe108, 0x000}, {d68000_lsl_s_16 , 0xf1f8, 0xe148, 0x000}, {d68000_lsl_s_32 , 0xf1f8, 0xe188, 0x000}, {d68000_lsl_r_8 , 0xf1f8, 0xe128, 0x000}, {d68000_lsl_r_16 , 0xf1f8, 0xe168, 0x000}, {d68000_lsl_r_32 , 0xf1f8, 0xe1a8, 0x000}, {d68000_lsl_ea , 0xffc0, 0xe3c0, 0x3f8}, {d68000_move_8 , 0xf000, 0x1000, 0xbff}, {d68000_move_16 , 0xf000, 0x3000, 0xfff}, {d68000_move_32 , 0xf000, 0x2000, 0xfff}, {d68000_movea_16 , 0xf1c0, 0x3040, 0xfff}, {d68000_movea_32 , 0xf1c0, 0x2040, 0xfff}, {d68000_move_to_ccr , 0xffc0, 0x44c0, 0xbff}, {d68010_move_fr_ccr , 0xffc0, 0x42c0, 0xbf8}, {d68000_move_to_sr , 0xffc0, 0x46c0, 0xbff}, {d68000_move_fr_sr , 0xffc0, 0x40c0, 0xbf8}, {d68000_move_to_usp , 0xfff8, 0x4e60, 0x000}, {d68000_move_fr_usp , 0xfff8, 0x4e68, 0x000}, {d68010_movec , 0xfffe, 0x4e7a, 0x000}, {d68000_movem_pd_16 , 0xfff8, 0x48a0, 0x000}, {d68000_movem_pd_32 , 0xfff8, 0x48e0, 0x000}, {d68000_movem_re_16 , 0xffc0, 0x4880, 0x2f8}, {d68000_movem_re_32 , 0xffc0, 0x48c0, 0x2f8}, {d68000_movem_er_16 , 0xffc0, 0x4c80, 0x37b}, {d68000_movem_er_32 , 0xffc0, 0x4cc0, 0x37b}, {d68000_movep_er_16 , 0xf1f8, 0x0108, 0x000}, {d68000_movep_er_32 , 0xf1f8, 0x0148, 0x000}, {d68000_movep_re_16 , 0xf1f8, 0x0188, 0x000}, {d68000_movep_re_32 , 0xf1f8, 0x01c8, 0x000}, {d68010_moves_8 , 0xffc0, 0x0e00, 0x3f8}, {d68010_moves_16 , 0xffc0, 0x0e40, 0x3f8}, {d68010_moves_32 , 0xffc0, 0x0e80, 0x3f8}, {d68000_moveq , 0xf100, 0x7000, 0x000}, {d68040_move16_pi_pi , 0xfff8, 0xf620, 0x000}, {d68040_move16_pi_al , 0xfff8, 0xf600, 0x000}, {d68040_move16_al_pi , 0xfff8, 0xf608, 0x000}, {d68040_move16_ai_al , 0xfff8, 0xf610, 0x000}, {d68040_move16_al_ai , 0xfff8, 0xf618, 0x000}, {d68000_muls , 0xf1c0, 0xc1c0, 0xbff}, {d68000_mulu , 0xf1c0, 0xc0c0, 0xbff}, {d68020_mull , 0xffc0, 0x4c00, 0xbff}, {d68000_nbcd , 0xffc0, 0x4800, 0xbf8}, {d68000_neg_8 , 0xffc0, 0x4400, 0xbf8}, {d68000_neg_16 , 0xffc0, 0x4440, 0xbf8}, {d68000_neg_32 , 0xffc0, 0x4480, 0xbf8}, {d68000_negx_8 , 0xffc0, 0x4000, 0xbf8}, {d68000_negx_16 , 0xffc0, 0x4040, 0xbf8}, {d68000_negx_32 , 0xffc0, 0x4080, 0xbf8}, {d68000_nop , 0xffff, 0x4e71, 0x000}, {d68000_not_8 , 0xffc0, 0x4600, 0xbf8}, {d68000_not_16 , 0xffc0, 0x4640, 0xbf8}, {d68000_not_32 , 0xffc0, 0x4680, 0xbf8}, {d68000_or_er_8 , 0xf1c0, 0x8000, 0xbff}, {d68000_or_er_16 , 0xf1c0, 0x8040, 0xbff}, {d68000_or_er_32 , 0xf1c0, 0x8080, 0xbff}, {d68000_or_re_8 , 0xf1c0, 0x8100, 0x3f8}, {d68000_or_re_16 , 0xf1c0, 0x8140, 0x3f8}, {d68000_or_re_32 , 0xf1c0, 0x8180, 0x3f8}, {d68000_ori_to_ccr , 0xffff, 0x003c, 0x000}, {d68000_ori_to_sr , 0xffff, 0x007c, 0x000}, {d68000_ori_8 , 0xffc0, 0x0000, 0xbf8}, {d68000_ori_16 , 0xffc0, 0x0040, 0xbf8}, {d68000_ori_32 , 0xffc0, 0x0080, 0xbf8}, {d68020_pack_rr , 0xf1f8, 0x8140, 0x000}, {d68020_pack_mm , 0xf1f8, 0x8148, 0x000}, {d68000_pea , 0xffc0, 0x4840, 0x27b}, {d68000_reset , 0xffff, 0x4e70, 0x000}, {d68000_ror_s_8 , 0xf1f8, 0xe018, 0x000}, {d68000_ror_s_16 , 0xf1f8, 0xe058, 0x000}, {d68000_ror_s_32 , 0xf1f8, 0xe098, 0x000}, {d68000_ror_r_8 , 0xf1f8, 0xe038, 0x000}, {d68000_ror_r_16 , 0xf1f8, 0xe078, 0x000}, {d68000_ror_r_32 , 0xf1f8, 0xe0b8, 0x000}, {d68000_ror_ea , 0xffc0, 0xe6c0, 0x3f8}, {d68000_rol_s_8 , 0xf1f8, 0xe118, 0x000}, {d68000_rol_s_16 , 0xf1f8, 0xe158, 0x000}, {d68000_rol_s_32 , 0xf1f8, 0xe198, 0x000}, {d68000_rol_r_8 , 0xf1f8, 0xe138, 0x000}, {d68000_rol_r_16 , 0xf1f8, 0xe178, 0x000}, {d68000_rol_r_32 , 0xf1f8, 0xe1b8, 0x000}, {d68000_rol_ea , 0xffc0, 0xe7c0, 0x3f8}, {d68000_roxr_s_8 , 0xf1f8, 0xe010, 0x000}, {d68000_roxr_s_16 , 0xf1f8, 0xe050, 0x000}, {d68000_roxr_s_32 , 0xf1f8, 0xe090, 0x000}, {d68000_roxr_r_8 , 0xf1f8, 0xe030, 0x000}, {d68000_roxr_r_16 , 0xf1f8, 0xe070, 0x000}, {d68000_roxr_r_32 , 0xf1f8, 0xe0b0, 0x000}, {d68000_roxr_ea , 0xffc0, 0xe4c0, 0x3f8}, {d68000_roxl_s_8 , 0xf1f8, 0xe110, 0x000}, {d68000_roxl_s_16 , 0xf1f8, 0xe150, 0x000}, {d68000_roxl_s_32 , 0xf1f8, 0xe190, 0x000}, {d68000_roxl_r_8 , 0xf1f8, 0xe130, 0x000}, {d68000_roxl_r_16 , 0xf1f8, 0xe170, 0x000}, {d68000_roxl_r_32 , 0xf1f8, 0xe1b0, 0x000}, {d68000_roxl_ea , 0xffc0, 0xe5c0, 0x3f8}, {d68010_rtd , 0xffff, 0x4e74, 0x000}, {d68000_rte , 0xffff, 0x4e73, 0x000}, {d68020_rtm , 0xfff0, 0x06c0, 0x000}, {d68000_rtr , 0xffff, 0x4e77, 0x000}, {d68000_rts , 0xffff, 0x4e75, 0x000}, {d68000_sbcd_rr , 0xf1f8, 0x8100, 0x000}, {d68000_sbcd_mm , 0xf1f8, 0x8108, 0x000}, {d68000_scc , 0xf0c0, 0x50c0, 0xbf8}, {d68000_stop , 0xffff, 0x4e72, 0x000}, {d68000_sub_er_8 , 0xf1c0, 0x9000, 0xbff}, {d68000_sub_er_16 , 0xf1c0, 0x9040, 0xfff}, {d68000_sub_er_32 , 0xf1c0, 0x9080, 0xfff}, {d68000_sub_re_8 , 0xf1c0, 0x9100, 0x3f8}, {d68000_sub_re_16 , 0xf1c0, 0x9140, 0x3f8}, {d68000_sub_re_32 , 0xf1c0, 0x9180, 0x3f8}, {d68000_suba_16 , 0xf1c0, 0x90c0, 0xfff}, {d68000_suba_32 , 0xf1c0, 0x91c0, 0xfff}, {d68000_subi_8 , 0xffc0, 0x0400, 0xbf8}, {d68000_subi_16 , 0xffc0, 0x0440, 0xbf8}, {d68000_subi_32 , 0xffc0, 0x0480, 0xbf8}, {d68000_subq_8 , 0xf1c0, 0x5100, 0xbf8}, {d68000_subq_16 , 0xf1c0, 0x5140, 0xff8}, {d68000_subq_32 , 0xf1c0, 0x5180, 0xff8}, {d68000_subx_rr_8 , 0xf1f8, 0x9100, 0x000}, {d68000_subx_rr_16 , 0xf1f8, 0x9140, 0x000}, {d68000_subx_rr_32 , 0xf1f8, 0x9180, 0x000}, {d68000_subx_mm_8 , 0xf1f8, 0x9108, 0x000}, {d68000_subx_mm_16 , 0xf1f8, 0x9148, 0x000}, {d68000_subx_mm_32 , 0xf1f8, 0x9188, 0x000}, {d68000_swap , 0xfff8, 0x4840, 0x000}, {d68000_tas , 0xffc0, 0x4ac0, 0xbf8}, {d68000_trap , 0xfff0, 0x4e40, 0x000}, {d68020_trapcc_0 , 0xf0ff, 0x50fc, 0x000}, {d68020_trapcc_16 , 0xf0ff, 0x50fa, 0x000}, {d68020_trapcc_32 , 0xf0ff, 0x50fb, 0x000}, {d68000_trapv , 0xffff, 0x4e76, 0x000}, {d68000_tst_8 , 0xffc0, 0x4a00, 0xbf8}, {d68020_tst_pcdi_8 , 0xffff, 0x4a3a, 0x000}, {d68020_tst_pcix_8 , 0xffff, 0x4a3b, 0x000}, {d68020_tst_i_8 , 0xffff, 0x4a3c, 0x000}, {d68000_tst_16 , 0xffc0, 0x4a40, 0xbf8}, {d68020_tst_a_16 , 0xfff8, 0x4a48, 0x000}, {d68020_tst_pcdi_16 , 0xffff, 0x4a7a, 0x000}, {d68020_tst_pcix_16 , 0xffff, 0x4a7b, 0x000}, {d68020_tst_i_16 , 0xffff, 0x4a7c, 0x000}, {d68000_tst_32 , 0xffc0, 0x4a80, 0xbf8}, {d68020_tst_a_32 , 0xfff8, 0x4a88, 0x000}, {d68020_tst_pcdi_32 , 0xffff, 0x4aba, 0x000}, {d68020_tst_pcix_32 , 0xffff, 0x4abb, 0x000}, {d68020_tst_i_32 , 0xffff, 0x4abc, 0x000}, {d68000_unlk , 0xfff8, 0x4e58, 0x000}, {d68020_unpk_rr , 0xf1f8, 0x8180, 0x000}, {d68020_unpk_mm , 0xf1f8, 0x8188, 0x000}, {0, 0, 0, 0} }; /* Check if opcode is using a valid ea mode */ static int valid_ea(uint opcode, uint mask) { if(mask == 0) return 1; switch(opcode & 0x3f) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: return (mask & 0x800) != 0; case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: return (mask & 0x400) != 0; case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: return (mask & 0x200) != 0; case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: return (mask & 0x100) != 0; case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: return (mask & 0x080) != 0; case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: return (mask & 0x040) != 0; case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: return (mask & 0x020) != 0; case 0x38: return (mask & 0x010) != 0; case 0x39: return (mask & 0x008) != 0; case 0x3a: return (mask & 0x002) != 0; case 0x3b: return (mask & 0x001) != 0; case 0x3c: return (mask & 0x004) != 0; } return 0; } /* Used by qsort */ static int DECL_SPEC compare_nof_true_bits(const void *aptr, const void *bptr) { uint a = ((const opcode_struct*)aptr)->mask; uint b = ((const opcode_struct*)bptr)->mask; a = ((a & 0xAAAA) >> 1) + (a & 0x5555); a = ((a & 0xCCCC) >> 2) + (a & 0x3333); a = ((a & 0xF0F0) >> 4) + (a & 0x0F0F); a = ((a & 0xFF00) >> 8) + (a & 0x00FF); b = ((b & 0xAAAA) >> 1) + (b & 0x5555); b = ((b & 0xCCCC) >> 2) + (b & 0x3333); b = ((b & 0xF0F0) >> 4) + (b & 0x0F0F); b = ((b & 0xFF00) >> 8) + (b & 0x00FF); return b - a; /* reversed to get greatest to least sorting */ } /* build the opcode handler jump table */ static void build_opcode_table(void) { uint i; uint opcode; opcode_struct* ostruct; uint opcode_info_length = 0; for(ostruct = g_opcode_info;ostruct->opcode_handler != 0;ostruct++) opcode_info_length++; qsort((void *)g_opcode_info, opcode_info_length, sizeof(g_opcode_info[0]), compare_nof_true_bits); for(i=0;i<0x10000;i++) { g_instruction_table[i] = d68000_illegal; /* default to illegal */ opcode = i; /* search through opcode info for a match */ for(ostruct = g_opcode_info;ostruct->opcode_handler != 0;ostruct++) { /* match opcode mask and allowed ea modes */ if((opcode & ostruct->mask) == ostruct->match) { /* Handle destination ea for move instructions */ if((ostruct->opcode_handler == d68000_move_8 || ostruct->opcode_handler == d68000_move_16 || ostruct->opcode_handler == d68000_move_32) && !valid_ea(((opcode>>9)&7) | ((opcode>>3)&0x38), 0xbf8)) continue; if(valid_ea(opcode, ostruct->ea_mask)) { g_instruction_table[i] = ostruct->opcode_handler; break; } } } } } /* ======================================================================== */ /* ================================= API ================================== */ /* ======================================================================== */ /* Disasemble one instruction at pc and store in str_buff */ unsigned int m68k_disassemble(char* str_buff, unsigned int pc, unsigned int cpu_type) { if(!g_initialized) { build_opcode_table(); g_initialized = 1; } switch(cpu_type) { case M68K_CPU_TYPE_68000: g_cpu_type = TYPE_68000; g_address_mask = 0x00ffffff; break; case M68K_CPU_TYPE_68010: g_cpu_type = TYPE_68010; g_address_mask = 0x00ffffff; break; case M68K_CPU_TYPE_68EC020: g_cpu_type = TYPE_68020; g_address_mask = 0x00ffffff; break; case M68K_CPU_TYPE_68020: g_cpu_type = TYPE_68020; g_address_mask = 0xffffffff; break; case M68K_CPU_TYPE_68030: g_cpu_type = TYPE_68030; g_address_mask = 0xffffffff; break; case M68K_CPU_TYPE_68040: g_cpu_type = TYPE_68040; g_address_mask = 0xffffffff; break; default: return 0; } g_cpu_pc = pc; g_helper_str[0] = 0; g_cpu_ir = read_imm_16(); g_instruction_table[g_cpu_ir](); sprintf(str_buff, "%s%s", g_dasm_str, g_helper_str); return g_cpu_pc - pc; } char* m68ki_disassemble_quick(unsigned int pc, unsigned int cpu_type) { static char buff[100]; buff[0] = 0; m68k_disassemble(buff, pc, cpu_type); return buff; } /* Check if the instruction is a valid one */ unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cpu_type) { if(!g_initialized) { build_opcode_table(); g_initialized = 1; } instruction &= 0xffff; if(g_instruction_table[instruction] == d68000_illegal) return 0; switch(cpu_type) { case M68K_CPU_TYPE_68000: if(g_instruction_table[instruction] == d68010_bkpt) return 0; if(g_instruction_table[instruction] == d68010_move_fr_ccr) return 0; if(g_instruction_table[instruction] == d68010_movec) return 0; if(g_instruction_table[instruction] == d68010_moves_8) return 0; if(g_instruction_table[instruction] == d68010_moves_16) return 0; if(g_instruction_table[instruction] == d68010_moves_32) return 0; if(g_instruction_table[instruction] == d68010_rtd) return 0; case M68K_CPU_TYPE_68010: if(g_instruction_table[instruction] == d68020_bcc_32) return 0; if(g_instruction_table[instruction] == d68020_bfchg) return 0; if(g_instruction_table[instruction] == d68020_bfclr) return 0; if(g_instruction_table[instruction] == d68020_bfexts) return 0; if(g_instruction_table[instruction] == d68020_bfextu) return 0; if(g_instruction_table[instruction] == d68020_bfffo) return 0; if(g_instruction_table[instruction] == d68020_bfins) return 0; if(g_instruction_table[instruction] == d68020_bfset) return 0; if(g_instruction_table[instruction] == d68020_bftst) return 0; if(g_instruction_table[instruction] == d68020_bra_32) return 0; if(g_instruction_table[instruction] == d68020_bsr_32) return 0; if(g_instruction_table[instruction] == d68020_callm) return 0; if(g_instruction_table[instruction] == d68020_cas_8) return 0; if(g_instruction_table[instruction] == d68020_cas_16) return 0; if(g_instruction_table[instruction] == d68020_cas_32) return 0; if(g_instruction_table[instruction] == d68020_cas2_16) return 0; if(g_instruction_table[instruction] == d68020_cas2_32) return 0; if(g_instruction_table[instruction] == d68020_chk_32) return 0; if(g_instruction_table[instruction] == d68020_chk2_cmp2_8) return 0; if(g_instruction_table[instruction] == d68020_chk2_cmp2_16) return 0; if(g_instruction_table[instruction] == d68020_chk2_cmp2_32) return 0; if(g_instruction_table[instruction] == d68020_cmpi_pcdi_8) return 0; if(g_instruction_table[instruction] == d68020_cmpi_pcix_8) return 0; if(g_instruction_table[instruction] == d68020_cmpi_pcdi_16) return 0; if(g_instruction_table[instruction] == d68020_cmpi_pcix_16) return 0; if(g_instruction_table[instruction] == d68020_cmpi_pcdi_32) return 0; if(g_instruction_table[instruction] == d68020_cmpi_pcix_32) return 0; if(g_instruction_table[instruction] == d68020_cpbcc_16) return 0; if(g_instruction_table[instruction] == d68020_cpbcc_32) return 0; if(g_instruction_table[instruction] == d68020_cpdbcc) return 0; if(g_instruction_table[instruction] == d68020_cpgen) return 0; if(g_instruction_table[instruction] == d68020_cprestore) return 0; if(g_instruction_table[instruction] == d68020_cpsave) return 0; if(g_instruction_table[instruction] == d68020_cpscc) return 0; if(g_instruction_table[instruction] == d68020_cptrapcc_0) return 0; if(g_instruction_table[instruction] == d68020_cptrapcc_16) return 0; if(g_instruction_table[instruction] == d68020_cptrapcc_32) return 0; if(g_instruction_table[instruction] == d68020_divl) return 0; if(g_instruction_table[instruction] == d68020_extb_32) return 0; if(g_instruction_table[instruction] == d68020_link_32) return 0; if(g_instruction_table[instruction] == d68020_mull) return 0; if(g_instruction_table[instruction] == d68020_pack_rr) return 0; if(g_instruction_table[instruction] == d68020_pack_mm) return 0; if(g_instruction_table[instruction] == d68020_rtm) return 0; if(g_instruction_table[instruction] == d68020_trapcc_0) return 0; if(g_instruction_table[instruction] == d68020_trapcc_16) return 0; if(g_instruction_table[instruction] == d68020_trapcc_32) return 0; if(g_instruction_table[instruction] == d68020_tst_pcdi_8) return 0; if(g_instruction_table[instruction] == d68020_tst_pcix_8) return 0; if(g_instruction_table[instruction] == d68020_tst_i_8) return 0; if(g_instruction_table[instruction] == d68020_tst_a_16) return 0; if(g_instruction_table[instruction] == d68020_tst_pcdi_16) return 0; if(g_instruction_table[instruction] == d68020_tst_pcix_16) return 0; if(g_instruction_table[instruction] == d68020_tst_i_16) return 0; if(g_instruction_table[instruction] == d68020_tst_a_32) return 0; if(g_instruction_table[instruction] == d68020_tst_pcdi_32) return 0; if(g_instruction_table[instruction] == d68020_tst_pcix_32) return 0; if(g_instruction_table[instruction] == d68020_tst_i_32) return 0; if(g_instruction_table[instruction] == d68020_unpk_rr) return 0; if(g_instruction_table[instruction] == d68020_unpk_mm) return 0; case M68K_CPU_TYPE_68EC020: case M68K_CPU_TYPE_68020: case M68K_CPU_TYPE_68030: if(g_instruction_table[instruction] == d68040_cinv) return 0; if(g_instruction_table[instruction] == d68040_cpush) return 0; if(g_instruction_table[instruction] == d68040_move16_pi_pi) return 0; if(g_instruction_table[instruction] == d68040_move16_pi_al) return 0; if(g_instruction_table[instruction] == d68040_move16_al_pi) return 0; if(g_instruction_table[instruction] == d68040_move16_ai_al) return 0; if(g_instruction_table[instruction] == d68040_move16_al_ai) return 0; } if(cpu_type != M68K_CPU_TYPE_68020 && cpu_type != M68K_CPU_TYPE_68EC020 && (g_instruction_table[instruction] == d68020_callm || g_instruction_table[instruction] == d68020_rtm)) return 0; return 1; } /* ======================================================================== */ /* ============================== END OF FILE ============================= */ /* ======================================================================== */ yabause-0.9.15/src/musashi/m68k.h000644 001750 001750 00000033060 12755623101 020453 0ustar00guillaumeguillaume000000 000000 /* ======================================================================== */ /* ========================= LICENSING & COPYRIGHT ======================== */ /* ======================================================================== */ /* * MUSASHI * Version 3.4 * * A portable Motorola M680x0 processor emulation engine. * Copyright 1998-2001 Karl Stenerud. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef M68K__HEADER #define M68K__HEADER /* ======================================================================== */ /* ============================= CONFIGURATION ============================ */ /* ======================================================================== */ /* Import the configuration for this build */ #include "m68kconf.h" /* ======================================================================== */ /* ============================ GENERAL DEFINES =========================== */ /* ======================================================================== */ /* There are 7 levels of interrupt to the 68K. * A transition from < 7 to 7 will cause a non-maskable interrupt (NMI). */ #define M68K_IRQ_NONE 0 #define M68K_IRQ_1 1 #define M68K_IRQ_2 2 #define M68K_IRQ_3 3 #define M68K_IRQ_4 4 #define M68K_IRQ_5 5 #define M68K_IRQ_6 6 #define M68K_IRQ_7 7 /* Special interrupt acknowledge values. * Use these as special returns from the interrupt acknowledge callback * (specified later in this header). */ /* Causes an interrupt autovector (0x18 + interrupt level) to be taken. * This happens in a real 68K if VPA or AVEC is asserted during an interrupt * acknowledge cycle instead of DTACK. */ #define M68K_INT_ACK_AUTOVECTOR 0xffffffff /* Causes the spurious interrupt vector (0x18) to be taken * This happens in a real 68K if BERR is asserted during the interrupt * acknowledge cycle (i.e. no devices responded to the acknowledge). */ #define M68K_INT_ACK_SPURIOUS 0xfffffffe /* CPU types for use in m68k_set_cpu_type() */ enum { M68K_CPU_TYPE_INVALID, M68K_CPU_TYPE_68000, M68K_CPU_TYPE_68010, M68K_CPU_TYPE_68EC020, M68K_CPU_TYPE_68020, M68K_CPU_TYPE_68030, /* Supported by disassembler ONLY */ M68K_CPU_TYPE_68040 /* Supported by disassembler ONLY */ }; /* Registers used by m68k_get_reg() and m68k_set_reg() */ typedef enum { /* Real registers */ M68K_REG_D0, /* Data registers */ M68K_REG_D1, M68K_REG_D2, M68K_REG_D3, M68K_REG_D4, M68K_REG_D5, M68K_REG_D6, M68K_REG_D7, M68K_REG_A0, /* Address registers */ M68K_REG_A1, M68K_REG_A2, M68K_REG_A3, M68K_REG_A4, M68K_REG_A5, M68K_REG_A6, M68K_REG_A7, M68K_REG_PC, /* Program Counter */ M68K_REG_SR, /* Status Register */ M68K_REG_SP, /* The current Stack Pointer (located in A7) */ M68K_REG_USP, /* User Stack Pointer */ M68K_REG_ISP, /* Interrupt Stack Pointer */ M68K_REG_MSP, /* Master Stack Pointer */ M68K_REG_SFC, /* Source Function Code */ M68K_REG_DFC, /* Destination Function Code */ M68K_REG_VBR, /* Vector Base Register */ M68K_REG_CACR, /* Cache Control Register */ M68K_REG_CAAR, /* Cache Address Register */ /* Assumed registers */ /* These are cheat registers which emulate the 1-longword prefetch * present in the 68000 and 68010. */ M68K_REG_PREF_ADDR, /* Last prefetch address */ M68K_REG_PREF_DATA, /* Last prefetch data */ /* Convenience registers */ M68K_REG_PPC, /* Previous value in the program counter */ M68K_REG_IR, /* Instruction register */ M68K_REG_CPU_TYPE /* Type of CPU being run */ } m68k_register_t; /* ======================================================================== */ /* ====================== FUNCTIONS CALLED BY THE CPU ===================== */ /* ======================================================================== */ /* You will have to implement these functions */ /* read/write functions called by the CPU to access memory. * while values used are 32 bits, only the appropriate number * of bits are relevant (i.e. in write_memory_8, only the lower 8 bits * of value should be written to memory). * * NOTE: I have separated the immediate and PC-relative memory fetches * from the other memory fetches because some systems require * differentiation between PROGRAM and DATA fetches (usually * for security setups such as encryption). * This separation can either be achieved by setting * M68K_SEPARATE_READS in m68kconf.h and defining * the read functions, or by setting M68K_EMULATE_FC and * making a function code callback function. * Using the callback offers better emulation coverage * because you can also monitor whether the CPU is in SYSTEM or * USER mode, but it is also slower. */ /* Read from anywhere */ unsigned int m68k_read_memory_8(unsigned int address); unsigned int m68k_read_memory_16(unsigned int address); unsigned int m68k_read_memory_32(unsigned int address); /* Read data immediately following the PC */ unsigned int m68k_read_immediate_16(unsigned int address); unsigned int m68k_read_immediate_32(unsigned int address); /* Read data relative to the PC */ unsigned int m68k_read_pcrelative_8(unsigned int address); unsigned int m68k_read_pcrelative_16(unsigned int address); unsigned int m68k_read_pcrelative_32(unsigned int address); /* Memory access for the disassembler */ unsigned int m68k_read_disassembler_8 (unsigned int address); unsigned int m68k_read_disassembler_16 (unsigned int address); unsigned int m68k_read_disassembler_32 (unsigned int address); /* Write to anywhere */ void m68k_write_memory_8(unsigned int address, unsigned int value); void m68k_write_memory_16(unsigned int address, unsigned int value); void m68k_write_memory_32(unsigned int address, unsigned int value); /* Special call to simulate undocumented 68k behavior when move.l with a * predecrement destination mode is executed. * To simulate real 68k behavior, first write the high word to * [address+2], and then write the low word to [address]. * * Enable this functionality with M68K_SIMULATE_PD_WRITES in m68kconf.h. */ void m68k_write_memory_32_pd(unsigned int address, unsigned int value); /* ======================================================================== */ /* ============================== CALLBACKS =============================== */ /* ======================================================================== */ /* These functions allow you to set callbacks to the host when specific events * occur. Note that you must enable the corresponding value in m68kconf.h * in order for these to do anything useful. * Note: I have defined default callbacks which are used if you have enabled * the corresponding #define in m68kconf.h but either haven't assigned a * callback or have assigned a callback of NULL. */ /* Set the callback for an interrupt acknowledge. * You must enable M68K_EMULATE_INT_ACK in m68kconf.h. * The CPU will call the callback with the interrupt level being acknowledged. * The host program must return either a vector from 0x02-0xff, or one of the * special interrupt acknowledge values specified earlier in this header. * If this is not implemented, the CPU will always assume an autovectored * interrupt, and will automatically clear the interrupt request when it * services the interrupt. * Default behavior: return M68K_INT_ACK_AUTOVECTOR. */ void m68k_set_int_ack_callback(int (*callback)(int int_level)); /* Set the callback for a breakpoint acknowledge (68010+). * You must enable M68K_EMULATE_BKPT_ACK in m68kconf.h. * The CPU will call the callback with whatever was in the data field of the * BKPT instruction for 68020+, or 0 for 68010. * Default behavior: do nothing. */ void m68k_set_bkpt_ack_callback(void (*callback)(unsigned int data)); /* Set the callback for the RESET instruction. * You must enable M68K_EMULATE_RESET in m68kconf.h. * The CPU calls this callback every time it encounters a RESET instruction. * Default behavior: do nothing. */ void m68k_set_reset_instr_callback(void (*callback)(void)); /* Set the callback for informing of a large PC change. * You must enable M68K_MONITOR_PC in m68kconf.h. * The CPU calls this callback with the new PC value every time the PC changes * by a large value (currently set for changes by longwords). * Default behavior: do nothing. */ void m68k_set_pc_changed_callback(void (*callback)(unsigned int new_pc)); /* Set the callback for CPU function code changes. * You must enable M68K_EMULATE_FC in m68kconf.h. * The CPU calls this callback with the function code before every memory * access to set the CPU's function code according to what kind of memory * access it is (supervisor/user, program/data and such). * Default behavior: do nothing. */ void m68k_set_fc_callback(void (*callback)(unsigned int new_fc)); /* Set a callback for the instruction cycle of the CPU. * You must enable M68K_INSTRUCTION_HOOK in m68kconf.h. * The CPU calls this callback just before fetching the opcode in the * instruction cycle. * Default behavior: do nothing. */ void m68k_set_instr_hook_callback(void (*callback)(void)); /* ======================================================================== */ /* ====================== FUNCTIONS TO ACCESS THE CPU ===================== */ /* ======================================================================== */ /* Use this function to set the CPU type you want to emulate. * Currently supported types are: M68K_CPU_TYPE_68000, M68K_CPU_TYPE_68010, * M68K_CPU_TYPE_EC020, and M68K_CPU_TYPE_68020. */ void m68k_set_cpu_type(unsigned int cpu_type); /* Do whatever initialisations the core requires. Should be called * at least once at init time. */ void m68k_init(void); /* Pulse the RESET pin on the CPU. * You *MUST* reset the CPU at least once to initialize the emulation * Note: If you didn't call m68k_set_cpu_type() before resetting * the CPU for the first time, the CPU will be set to * M68K_CPU_TYPE_68000. */ void m68k_pulse_reset(void); /* execute num_cycles worth of instructions. returns number of cycles used */ int m68k_execute(int num_cycles); /* These functions let you read/write/modify the number of cycles left to run * while m68k_execute() is running. * These are useful if the 68k accesses a memory-mapped port on another device * that requires immediate processing by another CPU. */ int m68k_cycles_run(void); /* Number of cycles run so far */ int m68k_cycles_remaining(void); /* Number of cycles left */ void m68k_modify_timeslice(int cycles); /* Modify cycles left */ void m68k_end_timeslice(void); /* End timeslice now */ /* Set the IPL0-IPL2 pins on the CPU (IRQ). * A transition from < 7 to 7 will cause a non-maskable interrupt (NMI). * Setting IRQ to 0 will clear an interrupt request. */ void m68k_set_irq(unsigned int int_level); /* Halt the CPU as if you pulsed the HALT pin. */ void m68k_pulse_halt(void); /* Context switching to allow multiple CPUs */ /* Get the size of the cpu context in bytes */ unsigned int m68k_context_size(void); /* Get a cpu context */ unsigned int m68k_get_context(void* dst); /* set the current cpu context */ void m68k_set_context(void* dst); /* Register the CPU state information */ void m68k_state_register(const char *type); /* Peek at the internals of a CPU context. This can either be a context * retrieved using m68k_get_context() or the currently running context. * If context is NULL, the currently running CPU context will be used. */ unsigned int m68k_get_reg(void* context, m68k_register_t reg); /* Poke values into the internals of the currently running CPU context */ void m68k_set_reg(m68k_register_t reg, unsigned int value); /* Check if an instruction is valid for the specified CPU type */ unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cpu_type); /* Disassemble 1 instruction using the epecified CPU type at pc. Stores * disassembly in str_buff and returns the size of the instruction in bytes. */ unsigned int m68k_disassemble(char* str_buff, unsigned int pc, unsigned int cpu_type); /* ======================================================================== */ /* ============================== MAME STUFF ============================== */ /* ======================================================================== */ #if M68K_COMPILE_FOR_MAME == OPT_ON #include "m68kmame.h" #endif /* M68K_COMPILE_FOR_MAME */ /* ======================================================================== */ /* ============================== END OF FILE ============================= */ /* ======================================================================== */ #endif /* M68K__HEADER */ yabause-0.9.15/src/musashi/m68kmake.c000644 001750 001750 00000130143 12755623101 021304 0ustar00guillaumeguillaume000000 000000 /* ======================================================================== */ /* ========================= LICENSING & COPYRIGHT ======================== */ /* ======================================================================== */ /* * MUSASHI * Version 3.4 * * A portable Motorola M680x0 processor emulation engine. * Copyright 1998-2001 Karl Stenerud. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* ======================================================================== */ /* ============================ CODE GENERATOR ============================ */ /* ======================================================================== */ /* * This is the code generator program which will generate the opcode table * and the final opcode handlers. * * It requires an input file to function (default m68k_in.c), but you can * specify your own like so: * * m68kmake * * where output path is the path where the output files should be placed, and * input file is the file to use for input. * * If you modify the input file greatly from its released form, you may have * to tweak the configuration section a bit since I'm using static allocation * to keep things simple. * * * TODO: - build a better code generator for the move instruction. * - Add callm and rtm instructions * - Fix RTE to handle other format words * - Add address error (and bus error?) handling */ char* g_version = "3.3"; /* ======================================================================== */ /* =============================== INCLUDES =============================== */ /* ======================================================================== */ #include #include #include #include #include /* ======================================================================== */ /* ============================= CONFIGURATION ============================ */ /* ======================================================================== */ #define M68K_MAX_PATH 1024 #define M68K_MAX_DIR 1024 #define NUM_CPUS 3 /* 000, 010, 020 */ #define MAX_LINE_LENGTH 200 /* length of 1 line */ #define MAX_BODY_LENGTH 300 /* Number of lines in 1 function */ #define MAX_REPLACE_LENGTH 30 /* Max number of replace strings */ #define MAX_INSERT_LENGTH 5000 /* Max size of insert piece */ #define MAX_NAME_LENGTH 30 /* Max length of ophandler name */ #define MAX_SPEC_PROC_LENGTH 4 /* Max length of special processing str */ #define MAX_SPEC_EA_LENGTH 5 /* Max length of specified EA str */ #define EA_ALLOWED_LENGTH 11 /* Max length of ea allowed str */ #define MAX_OPCODE_INPUT_TABLE_LENGTH 1000 /* Max length of opcode handler tbl */ #define MAX_OPCODE_OUTPUT_TABLE_LENGTH 3000 /* Max length of opcode handler tbl */ /* Default filenames */ #define FILENAME_INPUT "m68k_in.c" #define FILENAME_PROTOTYPE "m68kops.h" #define FILENAME_TABLE "m68kops.c" #define FILENAME_OPS_AC "m68kopac.c" #define FILENAME_OPS_DM "m68kopdm.c" #define FILENAME_OPS_NZ "m68kopnz.c" /* Identifier sequences recognized by this program */ #define ID_INPUT_SEPARATOR "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" #define ID_BASE "M68KMAKE" #define ID_PROTOTYPE_HEADER ID_BASE "_PROTOTYPE_HEADER" #define ID_PROTOTYPE_FOOTER ID_BASE "_PROTOTYPE_FOOTER" #define ID_TABLE_HEADER ID_BASE "_TABLE_HEADER" #define ID_TABLE_FOOTER ID_BASE "_TABLE_FOOTER" #define ID_TABLE_BODY ID_BASE "_TABLE_BODY" #define ID_TABLE_START ID_BASE "_TABLE_START" #define ID_OPHANDLER_HEADER ID_BASE "_OPCODE_HANDLER_HEADER" #define ID_OPHANDLER_FOOTER ID_BASE "_OPCODE_HANDLER_FOOTER" #define ID_OPHANDLER_BODY ID_BASE "_OPCODE_HANDLER_BODY" #define ID_END ID_BASE "_END" #define ID_OPHANDLER_NAME ID_BASE "_OP" #define ID_OPHANDLER_EA_AY_8 ID_BASE "_GET_EA_AY_8" #define ID_OPHANDLER_EA_AY_16 ID_BASE "_GET_EA_AY_16" #define ID_OPHANDLER_EA_AY_32 ID_BASE "_GET_EA_AY_32" #define ID_OPHANDLER_OPER_AY_8 ID_BASE "_GET_OPER_AY_8" #define ID_OPHANDLER_OPER_AY_16 ID_BASE "_GET_OPER_AY_16" #define ID_OPHANDLER_OPER_AY_32 ID_BASE "_GET_OPER_AY_32" #define ID_OPHANDLER_CC ID_BASE "_CC" #define ID_OPHANDLER_NOT_CC ID_BASE "_NOT_CC" #ifndef DECL_SPEC #define DECL_SPEC #endif /* DECL_SPEC */ /* ======================================================================== */ /* ============================== PROTOTYPES ============================== */ /* ======================================================================== */ #define CPU_TYPE_000 0 #define CPU_TYPE_010 1 #define CPU_TYPE_020 2 #define UNSPECIFIED "." #define UNSPECIFIED_CH '.' #define HAS_NO_EA_MODE(A) (strcmp(A, "..........") == 0) #define HAS_EA_AI(A) ((A)[0] == 'A') #define HAS_EA_PI(A) ((A)[1] == '+') #define HAS_EA_PD(A) ((A)[2] == '-') #define HAS_EA_DI(A) ((A)[3] == 'D') #define HAS_EA_IX(A) ((A)[4] == 'X') #define HAS_EA_AW(A) ((A)[5] == 'W') #define HAS_EA_AL(A) ((A)[6] == 'L') #define HAS_EA_PCDI(A) ((A)[7] == 'd') #define HAS_EA_PCIX(A) ((A)[8] == 'x') #define HAS_EA_I(A) ((A)[9] == 'I') enum { EA_MODE_NONE, /* No special addressing mode */ EA_MODE_AI, /* Address register indirect */ EA_MODE_PI, /* Address register indirect with postincrement */ EA_MODE_PI7, /* Address register 7 indirect with postincrement */ EA_MODE_PD, /* Address register indirect with predecrement */ EA_MODE_PD7, /* Address register 7 indirect with predecrement */ EA_MODE_DI, /* Address register indirect with displacement */ EA_MODE_IX, /* Address register indirect with index */ EA_MODE_AW, /* Absolute word */ EA_MODE_AL, /* Absolute long */ EA_MODE_PCDI, /* Program counter indirect with displacement */ EA_MODE_PCIX, /* Program counter indirect with index */ EA_MODE_I /* Immediate */ }; /* Everything we need to know about an opcode */ typedef struct { char name[MAX_NAME_LENGTH]; /* opcode handler name */ unsigned char size; /* Size of operation */ char spec_proc[MAX_SPEC_PROC_LENGTH]; /* Special processing mode */ char spec_ea[MAX_SPEC_EA_LENGTH]; /* Specified effective addressing mode */ unsigned char bits; /* Number of significant bits (used for sorting the table) */ unsigned short op_mask; /* Mask to apply for matching an opcode to a handler */ unsigned short op_match; /* Value to match after masking */ char ea_allowed[EA_ALLOWED_LENGTH]; /* Effective addressing modes allowed */ char cpu_mode[NUM_CPUS]; /* User or supervisor mode */ char cpus[NUM_CPUS+1]; /* Allowed CPUs */ unsigned char cycles[NUM_CPUS]; /* cycles for 000, 010, 020 */ } opcode_struct; /* All modifications necessary for a specific EA mode of an instruction */ typedef struct { char* fname_add; char* ea_add; unsigned int mask_add; unsigned int match_add; } ea_info_struct; /* Holds the body of a function */ typedef struct { char body[MAX_BODY_LENGTH][MAX_LINE_LENGTH+1]; int length; } body_struct; /* Holds a sequence of search / replace strings */ typedef struct { char replace[MAX_REPLACE_LENGTH][2][MAX_LINE_LENGTH+1]; int length; } replace_struct; /* Function Prototypes */ void error_exit(char* fmt, ...); void perror_exit(char* fmt, ...); size_t check_strsncpy(char* dst, char* src, int maxlength); size_t check_atoi(char* str, int *result); size_t skip_spaces(char* str); int num_bits(int value); int atoh(char* buff); int fgetline(char* buff, int nchars, FILE* file); int get_oper_cycles(opcode_struct* op, int ea_mode, int cpu_type); opcode_struct* find_opcode(char* name, int size, char* spec_proc, char* spec_ea); opcode_struct* find_illegal_opcode(void); int extract_opcode_info(char* src, char* name, int* size, char* spec_proc, char* spec_ea); void add_replace_string(replace_struct* replace, char* search_str, char* replace_str); void write_body(FILE* filep, body_struct* body, replace_struct* replace); void get_base_name(char* base_name, opcode_struct* op); void write_prototype(FILE* filep, char* base_name); void write_function_name(FILE* filep, char* base_name); void add_opcode_output_table_entry(opcode_struct* op, char* name); static int DECL_SPEC compare_nof_true_bits(const void* aptr, const void* bptr); void print_opcode_output_table(FILE* filep); void write_table_entry(FILE* filep, opcode_struct* op); void set_opcode_struct(opcode_struct* src, opcode_struct* dst, int ea_mode); void generate_opcode_handler(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* opinfo, int ea_mode); void generate_opcode_ea_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op); void generate_opcode_cc_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op_in, int offset); void process_opcode_handlers(void); void populate_table(void); void read_insert(char* insert); /* ======================================================================== */ /* ================================= DATA ================================= */ /* ======================================================================== */ /* Name of the input file */ char g_input_filename[M68K_MAX_PATH] = FILENAME_INPUT; /* File handles */ FILE* g_input_file = NULL; FILE* g_prototype_file = NULL; FILE* g_table_file = NULL; FILE* g_ops_ac_file = NULL; FILE* g_ops_dm_file = NULL; FILE* g_ops_nz_file = NULL; int g_num_functions = 0; /* Number of functions processed */ int g_num_primitives = 0; /* Number of function primitives read */ int g_line_number = 1; /* Current line number */ /* Opcode handler table */ opcode_struct g_opcode_input_table[MAX_OPCODE_INPUT_TABLE_LENGTH]; opcode_struct g_opcode_output_table[MAX_OPCODE_OUTPUT_TABLE_LENGTH]; int g_opcode_output_table_length = 0; ea_info_struct g_ea_info_table[13] = {/* fname ea mask match */ {"", "", 0x00, 0x00}, /* EA_MODE_NONE */ {"ai", "AY_AI", 0x38, 0x10}, /* EA_MODE_AI */ {"pi", "AY_PI", 0x38, 0x18}, /* EA_MODE_PI */ {"pi7", "A7_PI", 0x3f, 0x1f}, /* EA_MODE_PI7 */ {"pd", "AY_PD", 0x38, 0x20}, /* EA_MODE_PD */ {"pd7", "A7_PD", 0x3f, 0x27}, /* EA_MODE_PD7 */ {"di", "AY_DI", 0x38, 0x28}, /* EA_MODE_DI */ {"ix", "AY_IX", 0x38, 0x30}, /* EA_MODE_IX */ {"aw", "AW", 0x3f, 0x38}, /* EA_MODE_AW */ {"al", "AL", 0x3f, 0x39}, /* EA_MODE_AL */ {"pcdi", "PCDI", 0x3f, 0x3a}, /* EA_MODE_PCDI */ {"pcix", "PCIX", 0x3f, 0x3b}, /* EA_MODE_PCIX */ {"i", "I", 0x3f, 0x3c}, /* EA_MODE_I */ }; char* g_cc_table[16][2] = { { "t", "T"}, /* 0000 */ { "f", "F"}, /* 0001 */ {"hi", "HI"}, /* 0010 */ {"ls", "LS"}, /* 0011 */ {"cc", "CC"}, /* 0100 */ {"cs", "CS"}, /* 0101 */ {"ne", "NE"}, /* 0110 */ {"eq", "EQ"}, /* 0111 */ {"vc", "VC"}, /* 1000 */ {"vs", "VS"}, /* 1001 */ {"pl", "PL"}, /* 1010 */ {"mi", "MI"}, /* 1011 */ {"ge", "GE"}, /* 1100 */ {"lt", "LT"}, /* 1101 */ {"gt", "GT"}, /* 1110 */ {"le", "LE"}, /* 1111 */ }; /* size to index translator (0 -> 0, 8 and 16 -> 1, 32 -> 2) */ int g_size_select_table[33] = { 0, /* unsized */ 0, 0, 0, 0, 0, 0, 0, 1, /* 8 */ 0, 0, 0, 0, 0, 0, 0, 1, /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 /* 32 */ }; /* Extra cycles required for certain EA modes */ int g_ea_cycle_table[13][NUM_CPUS][3] = {/* 000 010 020 */ {{ 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}}, /* EA_MODE_NONE */ {{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}}, /* EA_MODE_AI */ {{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}}, /* EA_MODE_PI */ {{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}}, /* EA_MODE_PI7 */ {{ 0, 6, 10}, { 0, 6, 10}, { 0, 5, 5}}, /* EA_MODE_PD */ {{ 0, 6, 10}, { 0, 6, 10}, { 0, 5, 5}}, /* EA_MODE_PD7 */ {{ 0, 8, 12}, { 0, 8, 12}, { 0, 5, 5}}, /* EA_MODE_DI */ {{ 0, 10, 14}, { 0, 10, 14}, { 0, 7, 7}}, /* EA_MODE_IX */ {{ 0, 8, 12}, { 0, 8, 12}, { 0, 4, 4}}, /* EA_MODE_AW */ {{ 0, 12, 16}, { 0, 12, 16}, { 0, 4, 4}}, /* EA_MODE_AL */ {{ 0, 8, 12}, { 0, 8, 12}, { 0, 5, 5}}, /* EA_MODE_PCDI */ {{ 0, 10, 14}, { 0, 10, 14}, { 0, 7, 7}}, /* EA_MODE_PCIX */ {{ 0, 4, 8}, { 0, 4, 8}, { 0, 2, 4}}, /* EA_MODE_I */ }; /* Extra cycles for JMP instruction (000, 010) */ int g_jmp_cycle_table[13] = { 0, /* EA_MODE_NONE */ 4, /* EA_MODE_AI */ 0, /* EA_MODE_PI */ 0, /* EA_MODE_PI7 */ 0, /* EA_MODE_PD */ 0, /* EA_MODE_PD7 */ 6, /* EA_MODE_DI */ 10, /* EA_MODE_IX */ 6, /* EA_MODE_AW */ 8, /* EA_MODE_AL */ 6, /* EA_MODE_PCDI */ 10, /* EA_MODE_PCIX */ 0, /* EA_MODE_I */ }; /* Extra cycles for JSR instruction (000, 010) */ int g_jsr_cycle_table[13] = { 0, /* EA_MODE_NONE */ 4, /* EA_MODE_AI */ 0, /* EA_MODE_PI */ 0, /* EA_MODE_PI7 */ 0, /* EA_MODE_PD */ 0, /* EA_MODE_PD7 */ 6, /* EA_MODE_DI */ 10, /* EA_MODE_IX */ 6, /* EA_MODE_AW */ 8, /* EA_MODE_AL */ 6, /* EA_MODE_PCDI */ 10, /* EA_MODE_PCIX */ 0, /* EA_MODE_I */ }; /* Extra cycles for LEA instruction (000, 010) */ int g_lea_cycle_table[13] = { 0, /* EA_MODE_NONE */ 4, /* EA_MODE_AI */ 0, /* EA_MODE_PI */ 0, /* EA_MODE_PI7 */ 0, /* EA_MODE_PD */ 0, /* EA_MODE_PD7 */ 8, /* EA_MODE_DI */ 12, /* EA_MODE_IX */ 8, /* EA_MODE_AW */ 12, /* EA_MODE_AL */ 8, /* EA_MODE_PCDI */ 12, /* EA_MODE_PCIX */ 0, /* EA_MODE_I */ }; /* Extra cycles for PEA instruction (000, 010) */ int g_pea_cycle_table[13] = { 0, /* EA_MODE_NONE */ 6, /* EA_MODE_AI */ 0, /* EA_MODE_PI */ 0, /* EA_MODE_PI7 */ 0, /* EA_MODE_PD */ 0, /* EA_MODE_PD7 */ 10, /* EA_MODE_DI */ 14, /* EA_MODE_IX */ 10, /* EA_MODE_AW */ 14, /* EA_MODE_AL */ 10, /* EA_MODE_PCDI */ 14, /* EA_MODE_PCIX */ 0, /* EA_MODE_I */ }; /* Extra cycles for MOVES instruction (010) */ int g_moves_cycle_table[13][3] = { { 0, 0, 0}, /* EA_MODE_NONE */ { 0, 4, 6}, /* EA_MODE_AI */ { 0, 4, 6}, /* EA_MODE_PI */ { 0, 4, 6}, /* EA_MODE_PI7 */ { 0, 6, 12}, /* EA_MODE_PD */ { 0, 6, 12}, /* EA_MODE_PD7 */ { 0, 12, 16}, /* EA_MODE_DI */ { 0, 16, 20}, /* EA_MODE_IX */ { 0, 12, 16}, /* EA_MODE_AW */ { 0, 16, 20}, /* EA_MODE_AL */ { 0, 0, 0}, /* EA_MODE_PCDI */ { 0, 0, 0}, /* EA_MODE_PCIX */ { 0, 0, 0}, /* EA_MODE_I */ }; /* Extra cycles for CLR instruction (010) */ int g_clr_cycle_table[13][3] = { { 0, 0, 0}, /* EA_MODE_NONE */ { 0, 4, 6}, /* EA_MODE_AI */ { 0, 4, 6}, /* EA_MODE_PI */ { 0, 4, 6}, /* EA_MODE_PI7 */ { 0, 6, 8}, /* EA_MODE_PD */ { 0, 6, 8}, /* EA_MODE_PD7 */ { 0, 8, 10}, /* EA_MODE_DI */ { 0, 10, 14}, /* EA_MODE_IX */ { 0, 8, 10}, /* EA_MODE_AW */ { 0, 10, 14}, /* EA_MODE_AL */ { 0, 0, 0}, /* EA_MODE_PCDI */ { 0, 0, 0}, /* EA_MODE_PCIX */ { 0, 0, 0}, /* EA_MODE_I */ }; /* ======================================================================== */ /* =========================== UTILITY FUNCTIONS ========================== */ /* ======================================================================== */ /* Print an error message and exit with status error */ void error_exit(char* fmt, ...) { va_list args; fprintf(stderr, "In %s, near or on line %d:\n\t", g_input_filename, g_line_number); va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); fprintf(stderr, "\n"); if(g_prototype_file) fclose(g_prototype_file); if(g_table_file) fclose(g_table_file); if(g_ops_ac_file) fclose(g_ops_ac_file); if(g_ops_dm_file) fclose(g_ops_dm_file); if(g_ops_nz_file) fclose(g_ops_nz_file); if(g_input_file) fclose(g_input_file); exit(EXIT_FAILURE); } /* Print an error message, call perror(), and exit with status error */ void perror_exit(char* fmt, ...) { va_list args; va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); perror(""); if(g_prototype_file) fclose(g_prototype_file); if(g_table_file) fclose(g_table_file); if(g_ops_ac_file) fclose(g_ops_ac_file); if(g_ops_dm_file) fclose(g_ops_dm_file); if(g_ops_nz_file) fclose(g_ops_nz_file); if(g_input_file) fclose(g_input_file); exit(EXIT_FAILURE); } /* copy until 0 or space and exit with error if we read too far */ size_t check_strsncpy(char* dst, char* src, int maxlength) { char* p = dst; while(*src && *src != ' ') { *p++ = *src++; if(p - dst > maxlength) error_exit("Field too long"); } *p = 0; return p - dst; } /* copy until 0 or specified character and exit with error if we read too far */ size_t check_strcncpy(char* dst, char* src, char delim, int maxlength) { char* p = dst; while(*src && *src != delim) { *p++ = *src++; if(p - dst > maxlength) error_exit("Field too long"); } *p = 0; return p - dst; } /* convert ascii to integer and exit with error if we find invalid data */ size_t check_atoi(char* str, int *result) { int accum = 0; char* p = str; while(*p >= '0' && *p <= '9') { accum *= 10; accum += *p++ - '0'; } if(*p != ' ' && *p != 0) error_exit("Malformed integer value (%c)", *p); *result = accum; return p - str; } /* Skip past spaces in a string */ size_t skip_spaces(char* str) { char* p = str; while(*p == ' ') p++; return p - str; } /* Count the number of set bits in a value */ int num_bits(int value) { value = ((value & 0xaaaa) >> 1) + (value & 0x5555); value = ((value & 0xcccc) >> 2) + (value & 0x3333); value = ((value & 0xf0f0) >> 4) + (value & 0x0f0f); value = ((value & 0xff00) >> 8) + (value & 0x00ff); return value; } /* Convert a hex value written in ASCII */ int atoh(char* buff) { int accum = 0; for(;;buff++) { if(*buff >= '0' && *buff <= '9') { accum <<= 4; accum += *buff - '0'; } else if(*buff >= 'a' && *buff <= 'f') { accum <<= 4; accum += *buff - 'a' + 10; } else break; } return accum; } /* Get a line of text from a file, discarding any end-of-line characters */ int fgetline(char* buff, int nchars, FILE* file) { int length; if(fgets(buff, nchars, file) == NULL) return -1; if(buff[0] == '\r') memcpy(buff, buff + 1, nchars - 1); length = (int)strlen(buff); while(length && (buff[length-1] == '\r' || buff[length-1] == '\n')) length--; buff[length] = 0; g_line_number++; return length; } /* ======================================================================== */ /* =========================== HELPER FUNCTIONS =========================== */ /* ======================================================================== */ /* Calculate the number of cycles an opcode requires */ int get_oper_cycles(opcode_struct* op, int ea_mode, int cpu_type) { int size = g_size_select_table[op->size]; if(op->cpus[cpu_type] == '.') return 0; if(cpu_type < CPU_TYPE_020) { if(cpu_type == CPU_TYPE_010) { if(strcmp(op->name, "moves") == 0) return op->cycles[cpu_type] + g_moves_cycle_table[ea_mode][size]; if(strcmp(op->name, "clr") == 0) return op->cycles[cpu_type] + g_clr_cycle_table[ea_mode][size]; } /* ASG: added these cases -- immediate modes take 2 extra cycles here */ if(cpu_type == CPU_TYPE_000 && ea_mode == EA_MODE_I && ((strcmp(op->name, "add") == 0 && strcmp(op->spec_proc, "er") == 0) || strcmp(op->name, "adda") == 0 || (strcmp(op->name, "and") == 0 && strcmp(op->spec_proc, "er") == 0) || (strcmp(op->name, "or") == 0 && strcmp(op->spec_proc, "er") == 0) || (strcmp(op->name, "sub") == 0 && strcmp(op->spec_proc, "er") == 0) || strcmp(op->name, "suba") == 0)) return op->cycles[cpu_type] + g_ea_cycle_table[ea_mode][cpu_type][size] + 2; if(strcmp(op->name, "jmp") == 0) return op->cycles[cpu_type] + g_jmp_cycle_table[ea_mode]; if(strcmp(op->name, "jsr") == 0) return op->cycles[cpu_type] + g_jsr_cycle_table[ea_mode]; if(strcmp(op->name, "lea") == 0) return op->cycles[cpu_type] + g_lea_cycle_table[ea_mode]; if(strcmp(op->name, "pea") == 0) return op->cycles[cpu_type] + g_pea_cycle_table[ea_mode]; } return op->cycles[cpu_type] + g_ea_cycle_table[ea_mode][cpu_type][size]; } /* Find an opcode in the opcode handler list */ opcode_struct* find_opcode(char* name, int size, char* spec_proc, char* spec_ea) { opcode_struct* op; for(op = g_opcode_input_table; strlen(op->name) != 0;op++) { if( strcmp(name, op->name) == 0 && (size == op->size) && strcmp(spec_proc, op->spec_proc) == 0 && strcmp(spec_ea, op->spec_ea) == 0) return op; } return NULL; } /* Specifically find the illegal opcode in the list */ opcode_struct* find_illegal_opcode(void) { opcode_struct* op; for(op = g_opcode_input_table;strlen(op->name) != 0;op++) { if(strcmp(op->name, "illegal") == 0) return op; } return NULL; } /* Parse an opcode handler name */ int extract_opcode_info(char* src, char* name, int* size, char* spec_proc, char* spec_ea) { char* ptr = strstr(src, ID_OPHANDLER_NAME); if(ptr == NULL) return 0; ptr += strlen(ID_OPHANDLER_NAME) + 1; ptr += check_strcncpy(name, ptr, ',', MAX_NAME_LENGTH); if(*ptr != ',') return 0; ptr++; ptr += skip_spaces(ptr); *size = atoi(ptr); ptr = strstr(ptr, ","); if(ptr == NULL) return 0; ptr++; ptr += skip_spaces(ptr); ptr += check_strcncpy(spec_proc, ptr, ',', MAX_SPEC_PROC_LENGTH); if(*ptr != ',') return 0; ptr++; ptr += skip_spaces(ptr); ptr += check_strcncpy(spec_ea, ptr, ')', MAX_SPEC_EA_LENGTH); if(*ptr != ')') return 0; ptr++; ptr += skip_spaces(ptr); return 1; } /* Add a search/replace pair to a replace structure */ void add_replace_string(replace_struct* replace, char* search_str, char* replace_str) { size_t search_str_len = strlen(search_str); size_t replace_str_len = strlen(replace_str); if(search_str_len >= 201) error_exit("search_str was too long"); if (replace_str_len >= 201) error_exit("replace_str was too long"); if(replace->length >= MAX_REPLACE_LENGTH) error_exit("overflow in replace structure"); strcpy(replace->replace[replace->length][0], search_str); strcpy(replace->replace[replace->length++][1], replace_str); } /* Write a function body while replacing any selected strings */ void write_body(FILE* filep, body_struct* body, replace_struct* replace) { int i; int j; char* ptr; char output[MAX_LINE_LENGTH+1]; char temp_buff[MAX_LINE_LENGTH+1]; int found; for(i=0;ilength;i++) { strcpy(output, body->body[i]); /* Check for the base directive header */ if(strstr(output, ID_BASE) != NULL) { /* Search for any text we need to replace */ found = 0; for(j=0;jlength;j++) { ptr = strstr(output, replace->replace[j][0]); if(ptr) { size_t replace_len = strlen(ptr + strlen(replace->replace[j][0])); if(replace_len >= 201) error_exit("write_body: replace_len was too long"); /* We found something to replace */ found = 1; strcpy(temp_buff, ptr+strlen(replace->replace[j][0])); strcpy(ptr, replace->replace[j][1]); strcat(ptr, temp_buff); } } /* Found a directive with no matching replace string */ if(!found) error_exit("Unknown " ID_BASE " directive"); } fprintf(filep, "%s\n", output); } fprintf(filep, "\n\n"); } /* Generate a base function name from an opcode struct */ void get_base_name(char* base_name, opcode_struct* op) { sprintf(base_name, "m68k_op_%s", op->name); if(op->size > 0) sprintf(base_name+strlen(base_name), "_%d", op->size); if(strcmp(op->spec_proc, UNSPECIFIED) != 0) sprintf(base_name+strlen(base_name), "_%s", op->spec_proc); if(strcmp(op->spec_ea, UNSPECIFIED) != 0) sprintf(base_name+strlen(base_name), "_%s", op->spec_ea); } /* Write the prototype of an opcode handler function */ void write_prototype(FILE* filep, char* base_name) { fprintf(filep, "void %s(void);\n", base_name); } /* Write the name of an opcode handler function */ void write_function_name(FILE* filep, char* base_name) { fprintf(filep, "void %s(void)\n", base_name); } void add_opcode_output_table_entry(opcode_struct* op, char* name) { opcode_struct* ptr; size_t name_len = strlen(name); if(name_len >= 30) error_exit("Opcode output name too long"); if(g_opcode_output_table_length >= MAX_OPCODE_OUTPUT_TABLE_LENGTH) error_exit("Opcode output table overflow"); ptr = g_opcode_output_table + g_opcode_output_table_length++; *ptr = *op; strcpy(ptr->name, name); ptr->bits = num_bits(ptr->op_mask); } /* * Comparison function for qsort() * For entries with an equal number of set bits in * the mask compare the match values */ static int DECL_SPEC compare_nof_true_bits(const void* aptr, const void* bptr) { const opcode_struct *a = aptr, *b = bptr; if(a->bits != b->bits) return a->bits - b->bits; if(a->op_mask != b->op_mask) return a->op_mask - b->op_mask; return a->op_match - b->op_match; } void print_opcode_output_table(FILE* filep) { int i; qsort((void *)g_opcode_output_table, g_opcode_output_table_length, sizeof(g_opcode_output_table[0]), compare_nof_true_bits); for(i=0;iname, op->op_mask, op->op_match); for(i=0;icycles[i]); if(i < NUM_CPUS-1) fprintf(filep, ", "); } fprintf(filep, "}},\n"); } /* Fill out an opcode struct with a specific addressing mode of the source opcode struct */ void set_opcode_struct(opcode_struct* src, opcode_struct* dst, int ea_mode) { int i; *dst = *src; for(i=0;icycles[i] = get_oper_cycles(dst, ea_mode, i); if(strcmp(dst->spec_ea, UNSPECIFIED) == 0 && ea_mode != EA_MODE_NONE) sprintf(dst->spec_ea, "%s", g_ea_info_table[ea_mode].fname_add); dst->op_mask |= g_ea_info_table[ea_mode].mask_add; dst->op_match |= g_ea_info_table[ea_mode].match_add; } /* Generate a final opcode handler from the provided data */ void generate_opcode_handler(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* opinfo, int ea_mode) { char str[MAX_LINE_LENGTH+1]; opcode_struct* op = malloc(sizeof(opcode_struct)); /* Set the opcode structure and write the tables, prototypes, etc */ set_opcode_struct(opinfo, op, ea_mode); get_base_name(str, op); write_prototype(g_prototype_file, str); add_opcode_output_table_entry(op, str); write_function_name(filep, str); /* Add any replace strings needed */ if(ea_mode != EA_MODE_NONE) { sprintf(str, "EA_%s_8()", g_ea_info_table[ea_mode].ea_add); add_replace_string(replace, ID_OPHANDLER_EA_AY_8, str); sprintf(str, "EA_%s_16()", g_ea_info_table[ea_mode].ea_add); add_replace_string(replace, ID_OPHANDLER_EA_AY_16, str); sprintf(str, "EA_%s_32()", g_ea_info_table[ea_mode].ea_add); add_replace_string(replace, ID_OPHANDLER_EA_AY_32, str); sprintf(str, "OPER_%s_8()", g_ea_info_table[ea_mode].ea_add); add_replace_string(replace, ID_OPHANDLER_OPER_AY_8, str); sprintf(str, "OPER_%s_16()", g_ea_info_table[ea_mode].ea_add); add_replace_string(replace, ID_OPHANDLER_OPER_AY_16, str); sprintf(str, "OPER_%s_32()", g_ea_info_table[ea_mode].ea_add); add_replace_string(replace, ID_OPHANDLER_OPER_AY_32, str); } /* Now write the function body with the selected replace strings */ write_body(filep, body, replace); g_num_functions++; free(op); } /* Generate opcode variants based on available addressing modes */ void generate_opcode_ea_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op) { int old_length = replace->length; /* No ea modes available for this opcode */ if(HAS_NO_EA_MODE(op->ea_allowed)) { generate_opcode_handler(filep, body, replace, op, EA_MODE_NONE); return; } /* Check for and create specific opcodes for each available addressing mode */ if(HAS_EA_AI(op->ea_allowed)) generate_opcode_handler(filep, body, replace, op, EA_MODE_AI); replace->length = old_length; if(HAS_EA_PI(op->ea_allowed)) { generate_opcode_handler(filep, body, replace, op, EA_MODE_PI); replace->length = old_length; if(op->size == 8) generate_opcode_handler(filep, body, replace, op, EA_MODE_PI7); } replace->length = old_length; if(HAS_EA_PD(op->ea_allowed)) { generate_opcode_handler(filep, body, replace, op, EA_MODE_PD); replace->length = old_length; if(op->size == 8) generate_opcode_handler(filep, body, replace, op, EA_MODE_PD7); } replace->length = old_length; if(HAS_EA_DI(op->ea_allowed)) generate_opcode_handler(filep, body, replace, op, EA_MODE_DI); replace->length = old_length; if(HAS_EA_IX(op->ea_allowed)) generate_opcode_handler(filep, body, replace, op, EA_MODE_IX); replace->length = old_length; if(HAS_EA_AW(op->ea_allowed)) generate_opcode_handler(filep, body, replace, op, EA_MODE_AW); replace->length = old_length; if(HAS_EA_AL(op->ea_allowed)) generate_opcode_handler(filep, body, replace, op, EA_MODE_AL); replace->length = old_length; if(HAS_EA_PCDI(op->ea_allowed)) generate_opcode_handler(filep, body, replace, op, EA_MODE_PCDI); replace->length = old_length; if(HAS_EA_PCIX(op->ea_allowed)) generate_opcode_handler(filep, body, replace, op, EA_MODE_PCIX); replace->length = old_length; if(HAS_EA_I(op->ea_allowed)) generate_opcode_handler(filep, body, replace, op, EA_MODE_I); replace->length = old_length; } /* Generate variants of condition code opcodes */ void generate_opcode_cc_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op_in, int offset) { char repl[20]; char replnot[20]; int i; int old_length = replace->length; opcode_struct* op = malloc(sizeof(opcode_struct)); *op = *op_in; op->op_mask |= 0x0f00; /* Do all condition codes except t and f */ for(i=2;i<16;i++) { /* Add replace strings for this condition code */ sprintf(repl, "COND_%s()", g_cc_table[i][1]); sprintf(replnot, "COND_NOT_%s()", g_cc_table[i][1]); add_replace_string(replace, ID_OPHANDLER_CC, repl); add_replace_string(replace, ID_OPHANDLER_NOT_CC, replnot); /* Set the new opcode info */ strcpy(op->name+offset, g_cc_table[i][0]); op->op_match = (op->op_match & 0xf0ff) | (i<<8); /* Generate all opcode variants for this modified opcode */ generate_opcode_ea_variants(filep, body, replace, op); /* Remove the above replace strings */ replace->length = old_length; } free(op); } /* Process the opcode handlers section of the input file */ void process_opcode_handlers(void) { FILE* input_file = g_input_file; FILE* output_file; char func_name[MAX_LINE_LENGTH+1]; char oper_name[MAX_LINE_LENGTH+1]; int oper_size; char oper_spec_proc[MAX_LINE_LENGTH+1]; char oper_spec_ea[MAX_LINE_LENGTH+1]; opcode_struct* opinfo; replace_struct* replace = malloc(sizeof(replace_struct)); body_struct* body = malloc(sizeof(body_struct)); output_file = g_ops_ac_file; for(;;) { /* Find the first line of the function */ func_name[0] = 0; while(strstr(func_name, ID_OPHANDLER_NAME) == NULL) { if(strcmp(func_name, ID_INPUT_SEPARATOR) == 0) { free(replace); free(body); return; /* all done */ } if(fgetline(func_name, MAX_LINE_LENGTH, input_file) < 0) error_exit("Premature end of file when getting function name"); } /* Get the rest of the function */ for(body->length=0;;body->length++) { if(body->length > MAX_BODY_LENGTH) error_exit("Function too long"); if(fgetline(body->body[body->length], MAX_LINE_LENGTH, input_file) < 0) error_exit("Premature end of file when getting function body"); if(body->body[body->length][0] == '}') { body->length++; break; } } g_num_primitives++; /* Extract the function name information */ if(!extract_opcode_info(func_name, oper_name, &oper_size, oper_spec_proc, oper_spec_ea)) error_exit("Invalid " ID_OPHANDLER_NAME " format"); /* Find the corresponding table entry */ opinfo = find_opcode(oper_name, oper_size, oper_spec_proc, oper_spec_ea); if(opinfo == NULL) error_exit("Unable to find matching table entry for %s", func_name); /* Change output files if we pass 'c' or 'n' */ if(output_file == g_ops_ac_file && oper_name[0] > 'c') output_file = g_ops_dm_file; else if(output_file == g_ops_dm_file && oper_name[0] > 'm') output_file = g_ops_nz_file; replace->length = 0; /* Generate opcode variants */ if(strcmp(opinfo->name, "bcc") == 0 || strcmp(opinfo->name, "scc") == 0) generate_opcode_cc_variants(output_file, body, replace, opinfo, 1); else if(strcmp(opinfo->name, "dbcc") == 0) generate_opcode_cc_variants(output_file, body, replace, opinfo, 2); else if(strcmp(opinfo->name, "trapcc") == 0) generate_opcode_cc_variants(output_file, body, replace, opinfo, 4); else generate_opcode_ea_variants(output_file, body, replace, opinfo); } free(replace); free(body); } /* Populate the opcode handler table from the input file */ void populate_table(void) { char* ptr; char bitpattern[17]; opcode_struct* op; char buff[MAX_LINE_LENGTH]; int i; int temp; buff[0] = 0; /* Find the start of the table */ while(strcmp(buff, ID_TABLE_START) != 0) if(fgetline(buff, MAX_LINE_LENGTH, g_input_file) < 0) error_exit("Premature EOF while reading table"); /* Process the entire table */ for(op = g_opcode_input_table;;op++) { if(fgetline(buff, MAX_LINE_LENGTH, g_input_file) < 0) error_exit("Premature EOF while reading table"); if(strlen(buff) == 0) continue; /* We finish when we find an input separator */ if(strcmp(buff, ID_INPUT_SEPARATOR) == 0) break; /* Extract the info from the table */ ptr = buff; /* Name */ ptr += skip_spaces(ptr); ptr += check_strsncpy(op->name, ptr, MAX_NAME_LENGTH); /* Size */ ptr += skip_spaces(ptr); ptr += check_atoi(ptr, &temp); op->size = (unsigned char)temp; /* Special processing */ ptr += skip_spaces(ptr); ptr += check_strsncpy(op->spec_proc, ptr, MAX_SPEC_PROC_LENGTH); /* Specified EA Mode */ ptr += skip_spaces(ptr); ptr += check_strsncpy(op->spec_ea, ptr, MAX_SPEC_EA_LENGTH); /* Bit Pattern (more processing later) */ ptr += skip_spaces(ptr); ptr += check_strsncpy(bitpattern, ptr, 17); /* Allowed Addressing Mode List */ ptr += skip_spaces(ptr); ptr += check_strsncpy(op->ea_allowed, ptr, EA_ALLOWED_LENGTH); /* CPU operating mode (U = user or supervisor, S = supervisor only */ ptr += skip_spaces(ptr); for(i=0;icpu_mode[i] = *ptr++; ptr += skip_spaces(ptr); } /* Allowed CPUs for this instruction */ for(i=0;icpus[i] = UNSPECIFIED_CH; op->cycles[i] = 0; ptr++; } else { op->cpus[i] = '0' + i; ptr += check_atoi(ptr, &temp); op->cycles[i] = (unsigned char)temp; } } /* generate mask and match from bitpattern */ op->op_mask = 0; op->op_match = 0; for(i=0;i<16;i++) { op->op_mask |= (bitpattern[i] != '.') << (15-i); op->op_match |= (bitpattern[i] == '1') << (15-i); } } /* Terminate the list */ op->name[0] = 0; } /* Read a header or footer insert from the input file */ void read_insert(char* insert) { char* ptr = insert; char* overflow = insert + MAX_INSERT_LENGTH - MAX_LINE_LENGTH; int length; char* first_blank = NULL; first_blank = NULL; /* Skip any leading blank lines */ for(length = 0;length == 0;length = fgetline(ptr, MAX_LINE_LENGTH, g_input_file)) if(ptr >= overflow) error_exit("Buffer overflow reading inserts"); if(length < 0) error_exit("Premature EOF while reading inserts"); /* Advance and append newline */ ptr += length; strcpy(ptr++, "\n"); /* Read until next separator */ for(;;) { /* Read a new line */ if(ptr >= overflow) error_exit("Buffer overflow reading inserts"); if((length = fgetline(ptr, MAX_LINE_LENGTH, g_input_file)) < 0) error_exit("Premature EOF while reading inserts"); /* Stop if we read a separator */ if(strcmp(ptr, ID_INPUT_SEPARATOR) == 0) break; /* keep track in case there are trailing blanks */ if(length == 0) { if(first_blank == NULL) first_blank = ptr; } else first_blank = NULL; /* Advance and append newline */ ptr += length; strcpy(ptr++, "\n"); } /* kill any trailing blank lines */ if(first_blank) ptr = first_blank; *ptr++ = 0; } /* ======================================================================== */ /* ============================= MAIN FUNCTION ============================ */ /* ======================================================================== */ int main(int argc, char **argv) { /* File stuff */ char output_path[M68K_MAX_DIR] = ""; char filename[M68K_MAX_PATH]; /* Section identifier */ char section_id[MAX_LINE_LENGTH+1]; /* Inserts */ char temp_insert[MAX_INSERT_LENGTH+1]; char prototype_footer_insert[MAX_INSERT_LENGTH+1]; char table_footer_insert[MAX_INSERT_LENGTH+1]; char ophandler_footer_insert[MAX_INSERT_LENGTH+1]; /* Flags if we've processed certain parts already */ int prototype_header_read = 0; int prototype_footer_read = 0; int table_header_read = 0; int table_footer_read = 0; int ophandler_header_read = 0; int ophandler_footer_read = 0; int table_body_read = 0; int ophandler_body_read = 0; printf("\n\t\tMusashi v%s 68000, 68010, 68EC020, 68020 emulator\n", g_version); printf("\t\tCopyright 1998-2000 Karl Stenerud (karl@mame.net)\n\n"); /* Check if output path and source for the input file are given */ if(argc > 1) { char *ptr; size_t argv_len = strlen(argv[1]); if(argv_len >= 1024) perror_exit("Argument was too long (%s)\n", argv[1]); strcpy(output_path, argv[1]); for(ptr = strchr(output_path, '\\'); ptr; ptr = strchr(ptr, '\\')) *ptr = '/'; if(output_path[strlen(output_path)-1] != '/') strcat(output_path, "/"); if (argc > 2) { if (strlen(argv[2]) >= 1024) perror_exit("Argument 2 was too long (%s)\n", argv[2]); strcpy(g_input_filename, argv[2]); } } /* Open the files we need */ sprintf(filename, "%s%s", output_path, FILENAME_PROTOTYPE); if((g_prototype_file = fopen(filename, "wt")) == NULL) perror_exit("Unable to create prototype file (%s)\n", filename); sprintf(filename, "%s%s", output_path, FILENAME_TABLE); if((g_table_file = fopen(filename, "wt")) == NULL) perror_exit("Unable to create table file (%s)\n", filename); sprintf(filename, "%s%s", output_path, FILENAME_OPS_AC); if((g_ops_ac_file = fopen(filename, "wt")) == NULL) perror_exit("Unable to create ops ac file (%s)\n", filename); sprintf(filename, "%s%s", output_path, FILENAME_OPS_DM); if((g_ops_dm_file = fopen(filename, "wt")) == NULL) perror_exit("Unable to create ops dm file (%s)\n", filename); sprintf(filename, "%s%s", output_path, FILENAME_OPS_NZ); if((g_ops_nz_file = fopen(filename, "wt")) == NULL) perror_exit("Unable to create ops nz file (%s)\n", filename); if((g_input_file=fopen(g_input_filename, "rt")) == NULL) perror_exit("can't open %s for input", g_input_filename); /* Get to the first section of the input file */ section_id[0] = 0; while(strcmp(section_id, ID_INPUT_SEPARATOR) != 0) if(fgetline(section_id, MAX_LINE_LENGTH, g_input_file) < 0) error_exit("Premature EOF while reading input file"); /* Now process all sections */ for(;;) { if(fgetline(section_id, MAX_LINE_LENGTH, g_input_file) < 0) error_exit("Premature EOF while reading input file"); if(strcmp(section_id, ID_PROTOTYPE_HEADER) == 0) { if(prototype_header_read) error_exit("Duplicate prototype header"); read_insert(temp_insert); fprintf(g_prototype_file, "%s\n\n", temp_insert); prototype_header_read = 1; } else if(strcmp(section_id, ID_TABLE_HEADER) == 0) { if(table_header_read) error_exit("Duplicate table header"); read_insert(temp_insert); fprintf(g_table_file, "%s", temp_insert); table_header_read = 1; } else if(strcmp(section_id, ID_OPHANDLER_HEADER) == 0) { if(ophandler_header_read) error_exit("Duplicate opcode handler header"); read_insert(temp_insert); fprintf(g_ops_ac_file, "%s\n\n", temp_insert); fprintf(g_ops_dm_file, "%s\n\n", temp_insert); fprintf(g_ops_nz_file, "%s\n\n", temp_insert); ophandler_header_read = 1; } else if(strcmp(section_id, ID_PROTOTYPE_FOOTER) == 0) { if(prototype_footer_read) error_exit("Duplicate prototype footer"); read_insert(prototype_footer_insert); prototype_footer_read = 1; } else if(strcmp(section_id, ID_TABLE_FOOTER) == 0) { if(table_footer_read) error_exit("Duplicate table footer"); read_insert(table_footer_insert); table_footer_read = 1; } else if(strcmp(section_id, ID_OPHANDLER_FOOTER) == 0) { if(ophandler_footer_read) error_exit("Duplicate opcode handler footer"); read_insert(ophandler_footer_insert); ophandler_footer_read = 1; } else if(strcmp(section_id, ID_TABLE_BODY) == 0) { if(!prototype_header_read) error_exit("Table body encountered before prototype header"); if(!table_header_read) error_exit("Table body encountered before table header"); if(!ophandler_header_read) error_exit("Table body encountered before opcode handler header"); if(table_body_read) error_exit("Duplicate table body"); populate_table(); table_body_read = 1; } else if(strcmp(section_id, ID_OPHANDLER_BODY) == 0) { if(!prototype_header_read) error_exit("Opcode handlers encountered before prototype header"); if(!table_header_read) error_exit("Opcode handlers encountered before table header"); if(!ophandler_header_read) error_exit("Opcode handlers encountered before opcode handler header"); if(!table_body_read) error_exit("Opcode handlers encountered before table body"); if(ophandler_body_read) error_exit("Duplicate opcode handler section"); process_opcode_handlers(); ophandler_body_read = 1; } else if(strcmp(section_id, ID_END) == 0) { /* End of input file. Do a sanity check and then write footers */ if(!prototype_header_read) error_exit("Missing prototype header"); if(!prototype_footer_read) error_exit("Missing prototype footer"); if(!table_header_read) error_exit("Missing table header"); if(!table_footer_read) error_exit("Missing table footer"); if(!table_body_read) error_exit("Missing table body"); if(!ophandler_header_read) error_exit("Missing opcode handler header"); if(!ophandler_footer_read) error_exit("Missing opcode handler footer"); if(!ophandler_body_read) error_exit("Missing opcode handler body"); print_opcode_output_table(g_table_file); fprintf(g_prototype_file, "%s\n\n", prototype_footer_insert); fprintf(g_table_file, "%s\n\n", table_footer_insert); fprintf(g_ops_ac_file, "%s\n\n", ophandler_footer_insert); fprintf(g_ops_dm_file, "%s\n\n", ophandler_footer_insert); fprintf(g_ops_nz_file, "%s\n\n", ophandler_footer_insert); break; } else { error_exit("Unknown section identifier: %s", section_id); } } /* Close all files and exit */ fclose(g_prototype_file); fclose(g_table_file); fclose(g_ops_ac_file); fclose(g_ops_dm_file); fclose(g_ops_nz_file); fclose(g_input_file); printf("Generated %d opcode handlers from %d primitives\n", g_num_functions, g_num_primitives); return 0; } /* ======================================================================== */ /* ============================== END OF FILE ============================= */ /* ======================================================================== */ yabause-0.9.15/src/musashi/m68kcpu.c000644 001750 001750 00000110117 12755623101 021155 0ustar00guillaumeguillaume000000 000000 /* ======================================================================== */ /* ========================= LICENSING & COPYRIGHT ======================== */ /* ======================================================================== */ /* * MUSASHI * Version 3.4 * * A portable Motorola M680x0 processor emulation engine. * Copyright 1998-2001 Karl Stenerud. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* ======================================================================== */ /* ================================= NOTES ================================ */ /* ======================================================================== */ /* ======================================================================== */ /* ================================ INCLUDES ============================== */ /* ======================================================================== */ #include "m68kops.h" #include "m68kcpu.h" /* ======================================================================== */ /* ================================= DATA ================================= */ /* ======================================================================== */ int m68ki_initial_cycles; int m68ki_remaining_cycles = 0; /* Number of clocks remaining */ uint m68ki_tracing = 0; uint m68ki_address_space; #ifdef M68K_LOG_ENABLE char* m68ki_cpu_names[9] = { "Invalid CPU", "M68000", "M68010", "Invalid CPU", "M68EC020", "Invalid CPU", "Invalid CPU", "Invalid CPU", "M68020" }; #endif /* M68K_LOG_ENABLE */ /* The CPU core */ m68ki_cpu_core m68ki_cpu = {0}; #if M68K_EMULATE_ADDRESS_ERROR jmp_buf m68ki_aerr_trap; #endif /* M68K_EMULATE_ADDRESS_ERROR */ uint m68ki_aerr_address; uint m68ki_aerr_write_mode; uint m68ki_aerr_fc; /* Used by shift & rotate instructions */ uint8 m68ki_shift_8_table[65] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; uint16 m68ki_shift_16_table[65] = { 0x0000, 0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }; uint m68ki_shift_32_table[65] = { 0x00000000, 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000, 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; /* Number of clock cycles to use for exception processing. * I used 4 for any vectors that are undocumented for processing times. */ uint8 m68ki_exception_cycle_table[3][256] = { { /* 000 */ 4, /* 0: Reset - Initial Stack Pointer */ 4, /* 1: Reset - Initial Program Counter */ 50, /* 2: Bus Error (unemulated) */ 50, /* 3: Address Error (unemulated) */ 34, /* 4: Illegal Instruction */ 38, /* 5: Divide by Zero -- ASG: changed from 42 */ 40, /* 6: CHK -- ASG: chanaged from 44 */ 34, /* 7: TRAPV */ 34, /* 8: Privilege Violation */ 34, /* 9: Trace */ 4, /* 10: 1010 */ 4, /* 11: 1111 */ 4, /* 12: RESERVED */ 4, /* 13: Coprocessor Protocol Violation (unemulated) */ 4, /* 14: Format Error */ 44, /* 15: Uninitialized Interrupt */ 4, /* 16: RESERVED */ 4, /* 17: RESERVED */ 4, /* 18: RESERVED */ 4, /* 19: RESERVED */ 4, /* 20: RESERVED */ 4, /* 21: RESERVED */ 4, /* 22: RESERVED */ 4, /* 23: RESERVED */ 44, /* 24: Spurious Interrupt */ 44, /* 25: Level 1 Interrupt Autovector */ 44, /* 26: Level 2 Interrupt Autovector */ 44, /* 27: Level 3 Interrupt Autovector */ 44, /* 28: Level 4 Interrupt Autovector */ 44, /* 29: Level 5 Interrupt Autovector */ 44, /* 30: Level 6 Interrupt Autovector */ 44, /* 31: Level 7 Interrupt Autovector */ 34, /* 32: TRAP #0 -- ASG: chanaged from 38 */ 34, /* 33: TRAP #1 */ 34, /* 34: TRAP #2 */ 34, /* 35: TRAP #3 */ 34, /* 36: TRAP #4 */ 34, /* 37: TRAP #5 */ 34, /* 38: TRAP #6 */ 34, /* 39: TRAP #7 */ 34, /* 40: TRAP #8 */ 34, /* 41: TRAP #9 */ 34, /* 42: TRAP #10 */ 34, /* 43: TRAP #11 */ 34, /* 44: TRAP #12 */ 34, /* 45: TRAP #13 */ 34, /* 46: TRAP #14 */ 34, /* 47: TRAP #15 */ 4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */ 4, /* 49: FP Inexact Result (unemulated) */ 4, /* 50: FP Divide by Zero (unemulated) */ 4, /* 51: FP Underflow (unemulated) */ 4, /* 52: FP Operand Error (unemulated) */ 4, /* 53: FP Overflow (unemulated) */ 4, /* 54: FP Signaling NAN (unemulated) */ 4, /* 55: FP Unimplemented Data Type (unemulated) */ 4, /* 56: MMU Configuration Error (unemulated) */ 4, /* 57: MMU Illegal Operation Error (unemulated) */ 4, /* 58: MMU Access Level Violation Error (unemulated) */ 4, /* 59: RESERVED */ 4, /* 60: RESERVED */ 4, /* 61: RESERVED */ 4, /* 62: RESERVED */ 4, /* 63: RESERVED */ /* 64-255: User Defined */ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 }, { /* 010 */ 4, /* 0: Reset - Initial Stack Pointer */ 4, /* 1: Reset - Initial Program Counter */ 126, /* 2: Bus Error (unemulated) */ 126, /* 3: Address Error (unemulated) */ 38, /* 4: Illegal Instruction */ 44, /* 5: Divide by Zero */ 44, /* 6: CHK */ 34, /* 7: TRAPV */ 38, /* 8: Privilege Violation */ 38, /* 9: Trace */ 4, /* 10: 1010 */ 4, /* 11: 1111 */ 4, /* 12: RESERVED */ 4, /* 13: Coprocessor Protocol Violation (unemulated) */ 4, /* 14: Format Error */ 44, /* 15: Uninitialized Interrupt */ 4, /* 16: RESERVED */ 4, /* 17: RESERVED */ 4, /* 18: RESERVED */ 4, /* 19: RESERVED */ 4, /* 20: RESERVED */ 4, /* 21: RESERVED */ 4, /* 22: RESERVED */ 4, /* 23: RESERVED */ 46, /* 24: Spurious Interrupt */ 46, /* 25: Level 1 Interrupt Autovector */ 46, /* 26: Level 2 Interrupt Autovector */ 46, /* 27: Level 3 Interrupt Autovector */ 46, /* 28: Level 4 Interrupt Autovector */ 46, /* 29: Level 5 Interrupt Autovector */ 46, /* 30: Level 6 Interrupt Autovector */ 46, /* 31: Level 7 Interrupt Autovector */ 38, /* 32: TRAP #0 */ 38, /* 33: TRAP #1 */ 38, /* 34: TRAP #2 */ 38, /* 35: TRAP #3 */ 38, /* 36: TRAP #4 */ 38, /* 37: TRAP #5 */ 38, /* 38: TRAP #6 */ 38, /* 39: TRAP #7 */ 38, /* 40: TRAP #8 */ 38, /* 41: TRAP #9 */ 38, /* 42: TRAP #10 */ 38, /* 43: TRAP #11 */ 38, /* 44: TRAP #12 */ 38, /* 45: TRAP #13 */ 38, /* 46: TRAP #14 */ 38, /* 47: TRAP #15 */ 4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */ 4, /* 49: FP Inexact Result (unemulated) */ 4, /* 50: FP Divide by Zero (unemulated) */ 4, /* 51: FP Underflow (unemulated) */ 4, /* 52: FP Operand Error (unemulated) */ 4, /* 53: FP Overflow (unemulated) */ 4, /* 54: FP Signaling NAN (unemulated) */ 4, /* 55: FP Unimplemented Data Type (unemulated) */ 4, /* 56: MMU Configuration Error (unemulated) */ 4, /* 57: MMU Illegal Operation Error (unemulated) */ 4, /* 58: MMU Access Level Violation Error (unemulated) */ 4, /* 59: RESERVED */ 4, /* 60: RESERVED */ 4, /* 61: RESERVED */ 4, /* 62: RESERVED */ 4, /* 63: RESERVED */ /* 64-255: User Defined */ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 }, { /* 020 */ 4, /* 0: Reset - Initial Stack Pointer */ 4, /* 1: Reset - Initial Program Counter */ 50, /* 2: Bus Error (unemulated) */ 50, /* 3: Address Error (unemulated) */ 20, /* 4: Illegal Instruction */ 38, /* 5: Divide by Zero */ 40, /* 6: CHK */ 20, /* 7: TRAPV */ 34, /* 8: Privilege Violation */ 25, /* 9: Trace */ 20, /* 10: 1010 */ 20, /* 11: 1111 */ 4, /* 12: RESERVED */ 4, /* 13: Coprocessor Protocol Violation (unemulated) */ 4, /* 14: Format Error */ 30, /* 15: Uninitialized Interrupt */ 4, /* 16: RESERVED */ 4, /* 17: RESERVED */ 4, /* 18: RESERVED */ 4, /* 19: RESERVED */ 4, /* 20: RESERVED */ 4, /* 21: RESERVED */ 4, /* 22: RESERVED */ 4, /* 23: RESERVED */ 30, /* 24: Spurious Interrupt */ 30, /* 25: Level 1 Interrupt Autovector */ 30, /* 26: Level 2 Interrupt Autovector */ 30, /* 27: Level 3 Interrupt Autovector */ 30, /* 28: Level 4 Interrupt Autovector */ 30, /* 29: Level 5 Interrupt Autovector */ 30, /* 30: Level 6 Interrupt Autovector */ 30, /* 31: Level 7 Interrupt Autovector */ 20, /* 32: TRAP #0 */ 20, /* 33: TRAP #1 */ 20, /* 34: TRAP #2 */ 20, /* 35: TRAP #3 */ 20, /* 36: TRAP #4 */ 20, /* 37: TRAP #5 */ 20, /* 38: TRAP #6 */ 20, /* 39: TRAP #7 */ 20, /* 40: TRAP #8 */ 20, /* 41: TRAP #9 */ 20, /* 42: TRAP #10 */ 20, /* 43: TRAP #11 */ 20, /* 44: TRAP #12 */ 20, /* 45: TRAP #13 */ 20, /* 46: TRAP #14 */ 20, /* 47: TRAP #15 */ 4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */ 4, /* 49: FP Inexact Result (unemulated) */ 4, /* 50: FP Divide by Zero (unemulated) */ 4, /* 51: FP Underflow (unemulated) */ 4, /* 52: FP Operand Error (unemulated) */ 4, /* 53: FP Overflow (unemulated) */ 4, /* 54: FP Signaling NAN (unemulated) */ 4, /* 55: FP Unimplemented Data Type (unemulated) */ 4, /* 56: MMU Configuration Error (unemulated) */ 4, /* 57: MMU Illegal Operation Error (unemulated) */ 4, /* 58: MMU Access Level Violation Error (unemulated) */ 4, /* 59: RESERVED */ 4, /* 60: RESERVED */ 4, /* 61: RESERVED */ 4, /* 62: RESERVED */ 4, /* 63: RESERVED */ /* 64-255: User Defined */ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 } }; uint8 m68ki_ea_idx_cycle_table[64] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ..01.000 no memory indirect, base NULL */ 5, /* ..01..01 memory indirect, base NULL, outer NULL */ 7, /* ..01..10 memory indirect, base NULL, outer 16 */ 7, /* ..01..11 memory indirect, base NULL, outer 32 */ 0, 5, 7, 7, 0, 5, 7, 7, 0, 5, 7, 7, 2, /* ..10.000 no memory indirect, base 16 */ 7, /* ..10..01 memory indirect, base 16, outer NULL */ 9, /* ..10..10 memory indirect, base 16, outer 16 */ 9, /* ..10..11 memory indirect, base 16, outer 32 */ 0, 7, 9, 9, 0, 7, 9, 9, 0, 7, 9, 9, 6, /* ..11.000 no memory indirect, base 32 */ 11, /* ..11..01 memory indirect, base 32, outer NULL */ 13, /* ..11..10 memory indirect, base 32, outer 16 */ 13, /* ..11..11 memory indirect, base 32, outer 32 */ 0, 11, 13, 13, 0, 11, 13, 13, 0, 11, 13, 13 }; /* ======================================================================== */ /* =============================== CALLBACKS ============================== */ /* ======================================================================== */ /* Default callbacks used if the callback hasn't been set yet, or if the * callback is set to NULL */ /* Interrupt acknowledge */ static int default_int_ack_callback_data; static int default_int_ack_callback(int int_level) { default_int_ack_callback_data = int_level; CPU_INT_LEVEL = 0; return M68K_INT_ACK_AUTOVECTOR; } /* Breakpoint acknowledge */ static unsigned int default_bkpt_ack_callback_data; static void default_bkpt_ack_callback(unsigned int data) { default_bkpt_ack_callback_data = data; } /* Called when a reset instruction is executed */ static void default_reset_instr_callback(void) { } /* Called when the program counter changed by a large value */ static unsigned int default_pc_changed_callback_data; static void default_pc_changed_callback(unsigned int new_pc) { default_pc_changed_callback_data = new_pc; } /* Called every time there's bus activity (read/write to/from memory */ static unsigned int default_set_fc_callback_data; static void default_set_fc_callback(unsigned int new_fc) { default_set_fc_callback_data = new_fc; } /* Called every instruction cycle prior to execution */ static void default_instr_hook_callback(void) { } #if M68K_EMULATE_ADDRESS_ERROR #include jmp_buf m68ki_aerr_trap; #endif /* M68K_EMULATE_ADDRESS_ERROR */ /* ======================================================================== */ /* ================================= API ================================== */ /* ======================================================================== */ /* Access the internals of the CPU */ unsigned int m68k_get_reg(void* context, m68k_register_t regnum) { m68ki_cpu_core* cpu = context != NULL ?(m68ki_cpu_core*)context : &m68ki_cpu; switch(regnum) { case M68K_REG_D0: return cpu->dar[0]; case M68K_REG_D1: return cpu->dar[1]; case M68K_REG_D2: return cpu->dar[2]; case M68K_REG_D3: return cpu->dar[3]; case M68K_REG_D4: return cpu->dar[4]; case M68K_REG_D5: return cpu->dar[5]; case M68K_REG_D6: return cpu->dar[6]; case M68K_REG_D7: return cpu->dar[7]; case M68K_REG_A0: return cpu->dar[8]; case M68K_REG_A1: return cpu->dar[9]; case M68K_REG_A2: return cpu->dar[10]; case M68K_REG_A3: return cpu->dar[11]; case M68K_REG_A4: return cpu->dar[12]; case M68K_REG_A5: return cpu->dar[13]; case M68K_REG_A6: return cpu->dar[14]; case M68K_REG_A7: return cpu->dar[15]; case M68K_REG_PC: return MASK_OUT_ABOVE_32(cpu->pc); case M68K_REG_SR: return cpu->t1_flag | cpu->t0_flag | (cpu->s_flag << 11) | (cpu->m_flag << 11) | cpu->int_mask | ((cpu->x_flag & XFLAG_SET) >> 4) | ((cpu->n_flag & NFLAG_SET) >> 4) | ((!cpu->not_z_flag) << 2) | ((cpu->v_flag & VFLAG_SET) >> 6) | ((cpu->c_flag & CFLAG_SET) >> 8); case M68K_REG_SP: return cpu->dar[15]; case M68K_REG_USP: return cpu->s_flag ? cpu->sp[0] : cpu->dar[15]; case M68K_REG_ISP: return cpu->s_flag && !cpu->m_flag ? cpu->dar[15] : cpu->sp[4]; case M68K_REG_MSP: return cpu->s_flag && cpu->m_flag ? cpu->dar[15] : cpu->sp[6]; case M68K_REG_SFC: return cpu->sfc; case M68K_REG_DFC: return cpu->dfc; case M68K_REG_VBR: return cpu->vbr; case M68K_REG_CACR: return cpu->cacr; case M68K_REG_CAAR: return cpu->caar; case M68K_REG_PREF_ADDR: return cpu->pref_addr; case M68K_REG_PREF_DATA: return cpu->pref_data; case M68K_REG_PPC: return MASK_OUT_ABOVE_32(cpu->ppc); case M68K_REG_IR: return cpu->ir; case M68K_REG_CPU_TYPE: switch(cpu->cpu_type) { case CPU_TYPE_000: return (unsigned int)M68K_CPU_TYPE_68000; case CPU_TYPE_010: return (unsigned int)M68K_CPU_TYPE_68010; case CPU_TYPE_EC020: return (unsigned int)M68K_CPU_TYPE_68EC020; case CPU_TYPE_020: return (unsigned int)M68K_CPU_TYPE_68020; } return M68K_CPU_TYPE_INVALID; default: return 0; } return 0; } void m68k_set_reg(m68k_register_t regnum, unsigned int value) { switch(regnum) { case M68K_REG_D0: REG_D[0] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_D1: REG_D[1] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_D2: REG_D[2] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_D3: REG_D[3] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_D4: REG_D[4] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_D5: REG_D[5] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_D6: REG_D[6] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_D7: REG_D[7] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_A0: REG_A[0] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_A1: REG_A[1] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_A2: REG_A[2] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_A3: REG_A[3] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_A4: REG_A[4] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_A5: REG_A[5] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_A6: REG_A[6] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_A7: REG_A[7] = MASK_OUT_ABOVE_32(value); return; case M68K_REG_PC: m68ki_jump(MASK_OUT_ABOVE_32(value)); return; case M68K_REG_SR: m68ki_set_sr(value); return; case M68K_REG_SP: REG_SP = MASK_OUT_ABOVE_32(value); return; case M68K_REG_USP: if(FLAG_S) REG_USP = MASK_OUT_ABOVE_32(value); else REG_SP = MASK_OUT_ABOVE_32(value); return; case M68K_REG_ISP: if(FLAG_S && !FLAG_M) REG_SP = MASK_OUT_ABOVE_32(value); else REG_ISP = MASK_OUT_ABOVE_32(value); return; case M68K_REG_MSP: if(FLAG_S && FLAG_M) REG_SP = MASK_OUT_ABOVE_32(value); else REG_MSP = MASK_OUT_ABOVE_32(value); return; case M68K_REG_VBR: REG_VBR = MASK_OUT_ABOVE_32(value); return; case M68K_REG_SFC: REG_SFC = value & 7; return; case M68K_REG_DFC: REG_DFC = value & 7; return; case M68K_REG_CACR: REG_CACR = MASK_OUT_ABOVE_32(value); return; case M68K_REG_CAAR: REG_CAAR = MASK_OUT_ABOVE_32(value); return; case M68K_REG_PPC: REG_PPC = MASK_OUT_ABOVE_32(value); return; case M68K_REG_IR: REG_IR = MASK_OUT_ABOVE_16(value); return; case M68K_REG_CPU_TYPE: m68k_set_cpu_type(value); return; default: return; } } /* Set the callbacks */ void m68k_set_int_ack_callback(int (*callback)(int int_level)) { CALLBACK_INT_ACK = callback ? callback : default_int_ack_callback; } void m68k_set_bkpt_ack_callback(void (*callback)(unsigned int data)) { CALLBACK_BKPT_ACK = callback ? callback : default_bkpt_ack_callback; } void m68k_set_reset_instr_callback(void (*callback)(void)) { CALLBACK_RESET_INSTR = callback ? callback : default_reset_instr_callback; } void m68k_set_pc_changed_callback(void (*callback)(unsigned int new_pc)) { CALLBACK_PC_CHANGED = callback ? callback : default_pc_changed_callback; } void m68k_set_fc_callback(void (*callback)(unsigned int new_fc)) { CALLBACK_SET_FC = callback ? callback : default_set_fc_callback; } void m68k_set_instr_hook_callback(void (*callback)(void)) { CALLBACK_INSTR_HOOK = callback ? callback : default_instr_hook_callback; } /* Set the CPU type. */ void m68k_set_cpu_type(unsigned int cpu_type) { switch(cpu_type) { case M68K_CPU_TYPE_68000: CPU_TYPE = CPU_TYPE_000; CPU_ADDRESS_MASK = 0x00ffffff; CPU_SR_MASK = 0xa71f; /* T1 -- S -- -- I2 I1 I0 -- -- -- X N Z V C */ CYC_INSTRUCTION = m68ki_cycles[0]; CYC_EXCEPTION = m68ki_exception_cycle_table[0]; CYC_BCC_NOTAKE_B = -2; CYC_BCC_NOTAKE_W = 2; CYC_DBCC_F_NOEXP = -2; CYC_DBCC_F_EXP = 2; CYC_SCC_R_TRUE = 2; CYC_MOVEM_W = 2; CYC_MOVEM_L = 3; CYC_SHIFT = 1; CYC_RESET = 132; return; case M68K_CPU_TYPE_68010: CPU_TYPE = CPU_TYPE_010; CPU_ADDRESS_MASK = 0x00ffffff; CPU_SR_MASK = 0xa71f; /* T1 -- S -- -- I2 I1 I0 -- -- -- X N Z V C */ CYC_INSTRUCTION = m68ki_cycles[1]; CYC_EXCEPTION = m68ki_exception_cycle_table[1]; CYC_BCC_NOTAKE_B = -4; CYC_BCC_NOTAKE_W = 0; CYC_DBCC_F_NOEXP = 0; CYC_DBCC_F_EXP = 6; CYC_SCC_R_TRUE = 0; CYC_MOVEM_W = 2; CYC_MOVEM_L = 3; CYC_SHIFT = 1; CYC_RESET = 130; return; case M68K_CPU_TYPE_68EC020: CPU_TYPE = CPU_TYPE_EC020; CPU_ADDRESS_MASK = 0x00ffffff; CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */ CYC_INSTRUCTION = m68ki_cycles[2]; CYC_EXCEPTION = m68ki_exception_cycle_table[2]; CYC_BCC_NOTAKE_B = -2; CYC_BCC_NOTAKE_W = 0; CYC_DBCC_F_NOEXP = 0; CYC_DBCC_F_EXP = 4; CYC_SCC_R_TRUE = 0; CYC_MOVEM_W = 2; CYC_MOVEM_L = 2; CYC_SHIFT = 0; CYC_RESET = 518; return; case M68K_CPU_TYPE_68020: CPU_TYPE = CPU_TYPE_020; CPU_ADDRESS_MASK = 0xffffffff; CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */ CYC_INSTRUCTION = m68ki_cycles[2]; CYC_EXCEPTION = m68ki_exception_cycle_table[2]; CYC_BCC_NOTAKE_B = -2; CYC_BCC_NOTAKE_W = 0; CYC_DBCC_F_NOEXP = 0; CYC_DBCC_F_EXP = 4; CYC_SCC_R_TRUE = 0; CYC_MOVEM_W = 2; CYC_MOVEM_L = 2; CYC_SHIFT = 0; CYC_RESET = 518; return; } } /* Execute some instructions until we use up num_cycles clock cycles */ /* ASG: removed per-instruction interrupt checks */ int m68k_execute(int num_cycles) { /* Make sure we're not stopped */ if(!CPU_STOPPED) { /* Set our pool of clock cycles available */ SET_CYCLES(num_cycles); m68ki_initial_cycles = num_cycles; /* ASG: update cycles */ USE_CYCLES(CPU_INT_CYCLES); CPU_INT_CYCLES = 0; /* Return point if we had an address error */ m68ki_set_address_error_trap(); /* auto-disable (see m68kcpu.h) */ /* Main loop. Keep going until we run out of clock cycles */ do { /* Set tracing accodring to T1. (T0 is done inside instruction) */ m68ki_trace_t1(); /* auto-disable (see m68kcpu.h) */ /* Set the address space for reads */ m68ki_use_data_space(); /* auto-disable (see m68kcpu.h) */ /* Call external hook to peek at CPU */ m68ki_instr_hook(); /* auto-disable (see m68kcpu.h) */ /* Record previous program counter */ REG_PPC = REG_PC; /* Read an instruction and call its handler */ REG_IR = m68ki_read_imm_16(); m68ki_instruction_jump_table[REG_IR](); USE_CYCLES(CYC_INSTRUCTION[REG_IR]); /* Trace m68k_exception, if necessary */ m68ki_exception_if_trace(); /* auto-disable (see m68kcpu.h) */ } while(GET_CYCLES() > 0); /* set previous PC to current PC for the next entry into the loop */ REG_PPC = REG_PC; /* ASG: update cycles */ USE_CYCLES(CPU_INT_CYCLES); CPU_INT_CYCLES = 0; /* return how many clocks we used */ return m68ki_initial_cycles - GET_CYCLES(); } /* We get here if the CPU is stopped or halted */ SET_CYCLES(0); CPU_INT_CYCLES = 0; return num_cycles; } int m68k_cycles_run(void) { return m68ki_initial_cycles - GET_CYCLES(); } int m68k_cycles_remaining(void) { return GET_CYCLES(); } /* Change the timeslice */ void m68k_modify_timeslice(int cycles) { m68ki_initial_cycles += cycles; ADD_CYCLES(cycles); } void m68k_end_timeslice(void) { m68ki_initial_cycles = GET_CYCLES(); SET_CYCLES(0); } /* ASG: rewrote so that the int_level is a mask of the IPL0/IPL1/IPL2 bits */ /* KS: Modified so that IPL* bits match with mask positions in the SR * and cleaned out remenants of the interrupt controller. */ void m68k_set_irq(unsigned int int_level) { uint old_level = CPU_INT_LEVEL; CPU_INT_LEVEL = int_level << 8; /* A transition from < 7 to 7 always interrupts (NMI) */ /* Note: Level 7 can also level trigger like a normal IRQ */ if(old_level != 0x0700 && CPU_INT_LEVEL == 0x0700) m68ki_exception_interrupt(7); /* Edge triggered level 7 (NMI) */ else m68ki_check_interrupts(); /* Level triggered (IRQ) */ } void m68k_init(void) { static uint emulation_initialized = 0; /* The first call to this function initializes the opcode handler jump table */ if(!emulation_initialized) { m68ki_build_opcode_table(); emulation_initialized = 1; } m68k_set_int_ack_callback(NULL); m68k_set_bkpt_ack_callback(NULL); m68k_set_reset_instr_callback(NULL); m68k_set_pc_changed_callback(NULL); m68k_set_fc_callback(NULL); m68k_set_instr_hook_callback(NULL); } /* Pulse the RESET line on the CPU */ void m68k_pulse_reset(void) { /* Clear all stop levels and eat up all remaining cycles */ CPU_STOPPED = 0; SET_CYCLES(0); CPU_RUN_MODE = RUN_MODE_BERR_AERR_RESET; CPU_INSTR_MODE = INSTRUCTION_YES; /* Turn off tracing */ FLAG_T1 = FLAG_T0 = 0; m68ki_clear_trace(); /* Interrupt mask to level 7 */ FLAG_INT_MASK = 0x0700; /* Reset VBR */ REG_VBR = 0; /* Go to supervisor mode */ m68ki_set_sm_flag(SFLAG_SET | MFLAG_CLEAR); /* Invalidate the prefetch queue */ #if M68K_EMULATE_PREFETCH /* Set to arbitrary number since our first fetch is from 0 */ CPU_PREF_ADDR = 0x1000; #endif /* M68K_EMULATE_PREFETCH */ /* Read the initial stack pointer and program counter */ m68ki_jump(0); REG_SP = m68ki_read_imm_32(); REG_PC = m68ki_read_imm_32(); m68ki_jump(REG_PC); CPU_RUN_MODE = RUN_MODE_NORMAL; } /* Pulse the HALT line on the CPU */ void m68k_pulse_halt(void) { CPU_STOPPED |= STOP_LEVEL_HALT; } /* Get and set the current CPU context */ /* This is to allow for multiple CPUs */ unsigned int m68k_context_size() { return sizeof(m68ki_cpu_core); } unsigned int m68k_get_context(void* dst) { if(dst) *(m68ki_cpu_core*)dst = m68ki_cpu; return sizeof(m68ki_cpu_core); } void m68k_set_context(void* src) { if(src) m68ki_cpu = *(m68ki_cpu_core*)src; } /* ======================================================================== */ /* ============================== MAME STUFF ============================== */ /* ======================================================================== */ #if M68K_COMPILE_FOR_MAME == OPT_ON #include "state.h" static struct { UINT16 sr; int stopped; int halted; } m68k_substate; static void m68k_prepare_substate(void) { m68k_substate.sr = m68ki_get_sr(); m68k_substate.stopped = (CPU_STOPPED & STOP_LEVEL_STOP) != 0; m68k_substate.halted = (CPU_STOPPED & STOP_LEVEL_HALT) != 0; } static void m68k_post_load(void) { m68ki_set_sr_noint_nosp(m68k_substate.sr); CPU_STOPPED = m68k_substate.stopped ? STOP_LEVEL_STOP : 0 | m68k_substate.halted ? STOP_LEVEL_HALT : 0; m68ki_jump(REG_PC); } void m68k_state_register(const char *type) { int cpu = cpu_getactivecpu(); state_save_register_UINT32(type, cpu, "D" , REG_D, 8); state_save_register_UINT32(type, cpu, "A" , REG_A, 8); state_save_register_UINT32(type, cpu, "PPC" , ®_PPC, 1); state_save_register_UINT32(type, cpu, "PC" , ®_PC, 1); state_save_register_UINT32(type, cpu, "USP" , ®_USP, 1); state_save_register_UINT32(type, cpu, "ISP" , ®_ISP, 1); state_save_register_UINT32(type, cpu, "MSP" , ®_MSP, 1); state_save_register_UINT32(type, cpu, "VBR" , ®_VBR, 1); state_save_register_UINT32(type, cpu, "SFC" , ®_SFC, 1); state_save_register_UINT32(type, cpu, "DFC" , ®_DFC, 1); state_save_register_UINT32(type, cpu, "CACR" , ®_CACR, 1); state_save_register_UINT32(type, cpu, "CAAR" , ®_CAAR, 1); state_save_register_UINT16(type, cpu, "SR" , &m68k_substate.sr, 1); state_save_register_UINT32(type, cpu, "INT_LEVEL" , &CPU_INT_LEVEL, 1); state_save_register_UINT32(type, cpu, "INT_CYCLES", &CPU_INT_CYCLES, 1); state_save_register_int (type, cpu, "STOPPED" , &m68k_substate.stopped); state_save_register_int (type, cpu, "HALTED" , &m68k_substate.halted); state_save_register_UINT32(type, cpu, "PREF_ADDR" , &CPU_PREF_ADDR, 1); state_save_register_UINT32(type, cpu, "PREF_DATA" , &CPU_PREF_DATA, 1); state_save_register_func_presave(m68k_prepare_substate); state_save_register_func_postload(m68k_post_load); } #endif /* M68K_COMPILE_FOR_MAME */ /* ======================================================================== */ /* ============================== END OF FILE ============================= */ /* ======================================================================== */ yabause-0.9.15/src/screen.h000644 001750 001750 00000002261 12755623101 017473 0ustar00guillaumeguillaume000000 000000 /* Copyright 2013 Theo Berkau Copyright 2013 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SCREEN_H #define SCREEN_H typedef struct { int index; int width; int height; int bpp; int freq; } supportedRes_struct; typedef void * ResolutionList; ResolutionList ScreenGetResolutions(); int ScreenNextResolution(ResolutionList rl, supportedRes_struct * res); void ScreenChangeResolution(supportedRes_struct * res); void ScreenRestoreResolution(); #endif yabause-0.9.15/src/logo.bmp000644 001750 001750 00000006066 12755623101 017512 0ustar00guillaumeguillaume000000 000000 BM6 6(    ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŽŽŽŽŽŽŽŽãßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÆÀ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  STRQ 6 ÆÀ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿúûýøùýŒ„ˆ|}¾„€·vp«\WœB:A ÇÀÀÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðòúÏÖ勤⇘×r‡ÐlÎlÎtˆÑˆ™×¦°ÞÂÃßϾ˥“•o^^ÑËËÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿäèöœªÞVnÇ0Nº'F·'F·'F·'F·'F·'F·'F·'F·,J¹B]Àp„Ïž«ÜÑÖêûûþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýþþ¼ÆéSlÆ'F·'F·'F·'F·-K¹8U½>Z¿=Y¾7T¼-K¹'F·'F·'F·'F·'F·D_ÁzÓÐ×ïñóùÃÉàš¾‰“¹²¹Òíïöÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ²½å9U½'F·'F·§9›/„Tb™íïöÿÿÿüýþƒ•Ö'F·(G·‹œØ÷øüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÖ‡{ÛÜ‘„Þ˜}a^˜ŒŒáãî»Åä5M£$C®(G·(G·'F¶&D³:œ-|³ºÓÿÿÿéìø`wÊ)G¸VnÇìïùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿà“†åšŒæœŽåšŒL&"& ËÆÉ¡¬×%@¤8UÀB_ÈB_È5S¾(G¸#@ª0†~вÿÿÿÞãôYqÈ(G·ŽŸÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ螑ð©›î¦˜N)%ýÀ¡­Ö*E§VrÒ|‘ârŠßNhÎ,Kº$A¯2Šx„®ÿÿÿàäõg|Ì'F·˜¦ÝÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŽK&"ö°¡ù´¥ö°¡‚RJTAA½Åã5L¦ZtÒÎÖö¨·íSmÒ-L¼#A­1ˆž¦Çÿÿÿîðù‘¡Ú.L¹}ÔþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÆÀ¿°shð©›ù´¥ÿ¼­ù´¥í¦™<‡’fw¸8SµyŽÛo†Û@\Æ(G· <¡8L’ÛßîÿÿÿûûþºÄèKdÃE`Áàäõÿÿÿÿÿÿÿÿÿÿÿÿñïï8"!xE>嚌ö°¡ù´¥ö°¡î¦˜¤i_*±¶ÏJ^«)E«/Kµ(F° <¡/E–¨²Óüüþþþÿÿÿÿçë÷‚”Õ.L¹ŸÚþþÿÿÿÿÿÿÿÿÿÿ€qqN#Ö†yà“†èž‘î¦˜ð©›î¦˜èž‘à“†]0+SACÌÒê|ŒÃLa«G]©k|·¹Áßö÷ûÿÿÿýþþÿÿÿûûþÕÛñlÎ:W½ºÄèÿÿÿÿÿÿÆÀ¿£YPÏ}q؉}à“†Øƒ³ujâ˜Šà“†Ø‰}Çwl7šðòùâæôáåóîðøüýþÿÿÿÿÿÿøùýÿÿÿÿÿÿóõûÃËëh~ÍE`ÁÊÑíñïï8"!e,&½f[ÇrgÏ}q]0+;Í€sÏ}qÇrg‰E>*ãßßþþÿÿÿÿÿÿÿþþÿýþþûûþñóúÿÿÿÿÿÿþþÿ÷øüÐÖïr†ÐºÄè€qqB«NEµZP½f[ƒE>*UBA[,'Åod½f[µZPNUBAÿÿÿÿÿÿÿÿÿüýþûûþ÷øüðòúÿÿÿÿÿÿÿÿÿþþÿúûýÕÛñýÀ€-&£C:«NE±WM5ª Ÿãßß™NE³XN«NE@70 ›ÿÿÿÿÿÿûûþûûþøùýñóúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêêî8#)R“.&š8/¡A8W UBAÿÿÿÿÿÿ€qqH¨JA¡A8š8/l *ãßßüýþûûþüüþùúýòôûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€rq8…‹$’,%*#ÓÏÏÿÿÿÿÿÿñïï*k% ˜4,’,%‹$A SACõöüüüþýþþüüþüüþÿÿÿÿÿÿÿÿÿÿÿÿ¸°¯g  „‰!> €qqóõûèë÷üýþÿÿÿª Ÿ/ Œ' ‰!„z +´­¯÷øüûûþüüþÿÿÿÿÿÿÿÿÿÿÿÿñïï*Oy z ~ T *ñïïÖÜñ€’Õ”¤Û°¼åÒÙðSACI ‚~ z O*ççìûûþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿcQQ8y y y u +³¬°óõûßãôÑØð½Æé¦³áª¶ã¿¿Ìny y y 8`QUÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¸°¯%33333UBAÿÿÿüýþüýþþþÿýþþûûþôöûîðùm`f33333%¸°¯ÿÿÿÿÿÿÿÿÿñïï*ãßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿýþþíëî)*ñïïÿÿÿÿÿÿãß߯À¿ÆÀ¿ÆÀ¿ÆÀ¿ÆÀ¿ÆÀ¿ÆÀ¿ÆÀ¿ÔÏÏÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÔÏÏÆÀ¿ÆÀ¿ÆÀ¿ÆÀ¿ÆÀ¿ÆÀ¿ÆÀ¿ÆÀ¿ãßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿyabause-0.9.15/src/osdcore.h000644 001750 001750 00000004107 12755623101 017653 0ustar00guillaumeguillaume000000 000000 /* Copyright 2012 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef OSDCORE_H #define OSDCORE_H #include "core.h" #define OSDCORE_DUMMY 0 #define OSDCORE_GLUT 1 #define OSDCORE_SOFT 2 #ifdef HAVE_LIBGLUT #define OSDCORE_DEFAULT OSDCORE_GLUT #else #define OSDCORE_DEFAULT OSDCORE_SOFT #endif #define OSDMSG_FPS 0 #define OSDMSG_STATUS 1 #define OSDMSG_DEBUG 2 #define OSDMSG_COUNT 3 typedef struct { int type; char * message; int timetolive; int timeleft; int hidden; } OSDMessage_struct; typedef struct { int id; const char *Name; int (*Init)(void); void (*DeInit)(void); void (*Reset)(void); void (*DisplayMessage)(OSDMessage_struct * message, pixel_t * buffer, int w, int h); int (*UseBuffer)(void); } OSD_struct; int OSDInit(int coreid); int OSDChangeCore(int coreid); void OSDPushMessage(int msgtype, int ttl, const char * message, ...); int OSDDisplayMessages(pixel_t * buffer, int w, int h); void OSDToggle(int what); int OSDIsVisible(int what); void OSDSetVisible(int what, int visible); int OSDUseBuffer(void); extern OSD_struct OSDDummy; #ifdef HAVE_LIBGLUT extern OSD_struct OSDGlut; #endif extern OSD_struct OSDSoft; /* defined for backward compatibility (used to be in vdp2.h) */ void ToggleFPS(void); int GetOSDToggle(void); void SetOSDToggle(int toggle); void DisplayMessage(const char* str); #endif yabause-0.9.15/src/snddx.c000644 001750 001750 00000032435 12755623101 017335 0ustar00guillaumeguillaume000000 000000 /* Copyright (C) 2005-2007 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file snddx.c \brief Direct X sound interface. */ #include #include #include #include "debug.h" #include "dx.h" #include "scsp.h" #include "snddx.h" #include "error.h" int SNDDXInit(void); void SNDDXDeInit(void); int SNDDXReset(void); int SNDDXChangeVideoFormat(int vertfreq); void SNDDXUpdateAudio(u32 *leftchanbuffer, u32 *rightchanbuffer, u32 num_samples); u32 SNDDXGetAudioSpace(void); void SNDDXMuteAudio(void); void SNDDXUnMuteAudio(void); void SNDDXSetVolume(int volume); #ifdef USE_SCSPMIDI int SNDDXMidiInit(int inport, int outport); void SNDDXMidiDeInit(); int SNDDXMidiChangePorts(int inport, int outport); u8 SNDDXMidiIn(int *isdata); int SNDDXMidiOut(u8 data); #endif SoundInterface_struct SNDDIRECTX = { SNDCORE_DIRECTX, "DirectX Sound Interface", SNDDXInit, SNDDXDeInit, SNDDXReset, SNDDXChangeVideoFormat, SNDDXUpdateAudio, SNDDXGetAudioSpace, SNDDXMuteAudio, SNDDXUnMuteAudio, SNDDXSetVolume, #ifdef USE_SCSPMIDI SNDDXMidiChangePorts, SNDDXMidiIn, SNDDXMidiOut #endif }; LPDIRECTSOUND8 lpDS8; LPDIRECTSOUNDBUFFER lpDSB, lpDSB2; #define NUMSOUNDBLOCKS 4 static u16 *stereodata16; static u32 soundlen; static u32 soundoffset=0; static u32 soundbufsize; static LONG soundvolume; static int issoundmuted; HWND DXGetWindow (); HMIDIIN indevice=NULL; HMIDIOUT outdevice=NULL; static CRITICAL_SECTION dxmidi_cs; ////////////////////////////////////////////////////////////////////////////// int SNDDXInit(void) { DSBUFFERDESC dsbdesc; WAVEFORMATEX wfx; HRESULT ret; char tempstr[512]; if ((ret = DirectSoundCreate8(NULL, &lpDS8, NULL)) != DS_OK) { sprintf(tempstr, "Sound. DirectSound8Create error: %s - %s", DXGetErrorString8(ret), DXGetErrorDescription8(ret)); YabSetError(YAB_ERR_CANNOTINIT, tempstr); return -1; } if ((ret = IDirectSound8_SetCooperativeLevel(lpDS8, DXGetWindow(), DSSCL_PRIORITY)) != DS_OK) { sprintf(tempstr, "Sound. IDirectSound8_SetCooperativeLevel error: %s - %s", DXGetErrorString8(ret), DXGetErrorDescription8(ret)); YabSetError(YAB_ERR_CANNOTINIT, tempstr); return -1; } memset(&dsbdesc, 0, sizeof(dsbdesc)); dsbdesc.dwSize = sizeof(DSBUFFERDESC); dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER; dsbdesc.dwBufferBytes = 0; dsbdesc.lpwfxFormat = NULL; if ((ret = IDirectSound8_CreateSoundBuffer(lpDS8, &dsbdesc, &lpDSB, NULL)) != DS_OK) { sprintf(tempstr, "Sound. Error when creating primary sound buffer: %s - %s", DXGetErrorString8(ret), DXGetErrorDescription8(ret)); YabSetError(YAB_ERR_CANNOTINIT, tempstr); return -1; } soundlen = 44100 / 60; // 60 for NTSC or 50 for PAL. Initially assume it's going to be NTSC. soundbufsize = soundlen * NUMSOUNDBLOCKS * 2 * 2; memset(&wfx, 0, sizeof(wfx)); wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nChannels = 2; wfx.nSamplesPerSec = 44100; wfx.wBitsPerSample = 16; wfx.nBlockAlign = (wfx.wBitsPerSample / 8) * wfx.nChannels; wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; if ((ret = IDirectSoundBuffer8_SetFormat(lpDSB, &wfx)) != DS_OK) { sprintf(tempstr, "Sound. IDirectSoundBuffer8_SetFormat error: %s - %s", DXGetErrorString8(ret), DXGetErrorDescription8(ret)); YabSetError(YAB_ERR_CANNOTINIT, tempstr); return -1; } memset(&dsbdesc, 0, sizeof(dsbdesc)); dsbdesc.dwSize = sizeof(DSBUFFERDESC); dsbdesc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_STICKYFOCUS | DSBCAPS_CTRLVOLUME | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCHARDWARE; dsbdesc.dwBufferBytes = soundbufsize; dsbdesc.lpwfxFormat = &wfx; if ((ret = IDirectSound8_CreateSoundBuffer(lpDS8, &dsbdesc, &lpDSB2, NULL)) != DS_OK) { if (ret == DSERR_CONTROLUNAVAIL || ret == DSERR_INVALIDCALL || ret == E_FAIL || ret == E_NOTIMPL) { // Try using a software buffer instead dsbdesc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_STICKYFOCUS | DSBCAPS_CTRLVOLUME | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCSOFTWARE; if ((ret = IDirectSound8_CreateSoundBuffer(lpDS8, &dsbdesc, &lpDSB2, NULL)) != DS_OK) { sprintf(tempstr, "Sound. Error when creating secondary sound buffer: %s - %s", DXGetErrorString8(ret), DXGetErrorDescription8(ret)); YabSetError(YAB_ERR_CANNOTINIT, tempstr); return -1; } } else { sprintf(tempstr, "Sound. Error when creating secondary sound buffer: %s - %s", DXGetErrorString8(ret), DXGetErrorDescription8(ret)); YabSetError(YAB_ERR_CANNOTINIT, tempstr); return -1; } } IDirectSoundBuffer8_Play(lpDSB2, 0, 0, DSBPLAY_LOOPING); if ((stereodata16 = (u16 *)malloc(soundbufsize)) == NULL) return -1; memset(stereodata16, 0, soundbufsize); soundvolume = DSBVOLUME_MAX; issoundmuted = 0; #ifdef USE_SCSPMIDI SNDDXMidiInit (-1, -1); #endif return 0; } ////////////////////////////////////////////////////////////////////////////// void SNDDXDeInit(void) { DWORD status=0; #ifdef USE_SCSPMIDI SNDDXMidiDeInit(); #endif if (lpDSB2) { IDirectSoundBuffer8_GetStatus(lpDSB2, &status); if(status == DSBSTATUS_PLAYING) IDirectSoundBuffer8_Stop(lpDSB2); IDirectSoundBuffer8_Release(lpDSB2); lpDSB2 = NULL; } if (lpDSB) { IDirectSoundBuffer8_Release(lpDSB); lpDSB = NULL; } if (lpDS8) { IDirectSound8_Release(lpDS8); lpDS8 = NULL; } } ////////////////////////////////////////////////////////////////////////////// int SNDDXReset(void) { return 0; } ////////////////////////////////////////////////////////////////////////////// int SNDDXChangeVideoFormat(int vertfreq) { soundlen = 44100 / vertfreq; soundbufsize = soundlen * NUMSOUNDBLOCKS * 2 * 2; if (stereodata16) free(stereodata16); if ((stereodata16 = (u16 *)malloc(soundbufsize)) == NULL) return -1; memset(stereodata16, 0, soundbufsize); return 0; } ////////////////////////////////////////////////////////////////////////////// void SNDDXUpdateAudio(u32 *leftchanbuffer, u32 *rightchanbuffer, u32 num_samples) { LPVOID buffer1; LPVOID buffer2; DWORD buffer1_size, buffer2_size; DWORD status; IDirectSoundBuffer8_GetStatus(lpDSB2, &status); if (status & DSBSTATUS_BUFFERLOST) return; // fix me IDirectSoundBuffer8_Lock(lpDSB2, soundoffset, num_samples * sizeof(s16) * 2, &buffer1, &buffer1_size, &buffer2, &buffer2_size, 0); ScspConvert32uto16s((s32 *)leftchanbuffer, (s32 *)rightchanbuffer, (s16 *)stereodata16, num_samples); memcpy(buffer1, stereodata16, buffer1_size); if (buffer2) memcpy(buffer2, ((u8 *)stereodata16)+buffer1_size, buffer2_size); soundoffset += buffer1_size + buffer2_size; soundoffset %= soundbufsize; IDirectSoundBuffer8_Unlock(lpDSB2, buffer1, buffer1_size, buffer2, buffer2_size); } ////////////////////////////////////////////////////////////////////////////// u32 SNDDXGetAudioSpace(void) { DWORD playcursor, writecursor; u32 freespace=0; if (IDirectSoundBuffer8_GetCurrentPosition (lpDSB2, &playcursor, &writecursor) != DS_OK) return 0; if (soundoffset > playcursor) freespace = soundbufsize - soundoffset + playcursor; else freespace = playcursor - soundoffset; // if (freespace > 512) return (freespace / 2 / 2); // else // return 0; } ////////////////////////////////////////////////////////////////////////////// void SNDDXMuteAudio(void) { issoundmuted = 1; IDirectSoundBuffer8_SetVolume (lpDSB2, DSBVOLUME_MIN); } ////////////////////////////////////////////////////////////////////////////// void SNDDXUnMuteAudio(void) { issoundmuted = 0; IDirectSoundBuffer8_SetVolume (lpDSB2, soundvolume); } ////////////////////////////////////////////////////////////////////////////// void SNDDXSetVolume(int volume) { // Convert linear volume to logarithmic volume if (volume == 0) soundvolume = DSBVOLUME_MIN; else soundvolume = (LONG)(log10((double)volume / 100.0) * 2000.0); if (!issoundmuted) IDirectSoundBuffer8_SetVolume (lpDSB2, soundvolume); } ////////////////////////////////////////////////////////////////////////////// volatile u8 midi_in_buf[512]; volatile int midi_in_cnt=0; void CALLBACK midiincallback( HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { switch (wMsg) { case MIM_OPEN: // Open/Close device case MIM_CLOSE: break; case MIM_DATA: { u8 status=dwParam1; // status byte if ((status & 0xF0) == 0xF0) break; EnterCriticalSection (&dxmidi_cs); midi_in_buf[midi_in_cnt++] = status; switch((status & 0xF0) >> 4) { case 0x8: // Note Off/On(2 bytes) case 0x9: case 0xA: // Polyphonic Aftertouch(2 bytes) case 0xB: // Control/Mode Change(2 bytes) case 0xE: // Pitch Bend(2 bytes) midi_in_buf[midi_in_cnt++] = dwParam1 >> 8; midi_in_buf[midi_in_cnt++] = dwParam1 >> 16; break; case 0xC: // Program Change(1 byte) case 0xD: // Channel Aftertouch(1 byte) midi_in_buf[midi_in_cnt++] = dwParam1 >> 8; break; default: break; } LeaveCriticalSection(&dxmidi_cs); break; } default: //LOG("wMsg = Unsupport/unknown\n"); break; } } ////////////////////////////////////////////////////////////////////////////// #ifdef USE_SCSPMIDI int SNDDXMidiInit (int inport, int outport) { MMRESULT flag; if (inport < 0) inport = 0; if (outport < 0) outport = 0; InitializeCriticalSection(&dxmidi_cs); // open midi in port flag = midiInOpen(&indevice, inport, (DWORD_PTR)midiincallback, 0, CALLBACK_FUNCTION); if (flag != MMSYSERR_NOERROR) { YabSetError (YAB_ERR_CANNOTINIT, (void *)"MIDI Input"); return -1; } midiInStart(indevice); // open midi out port flag = midiOutOpen(&outdevice, outport, 0, 0, CALLBACK_NULL); if (flag != MMSYSERR_NOERROR) { YabSetError (YAB_ERR_CANNOTINIT, (void *)"MIDI Output"); return -1; } return 0; } ////////////////////////////////////////////////////////////////////////////// void SNDDXMidiDeInit () { // Remove any data in MIDI device and close the MIDI ports if (indevice) { midiInStop(indevice); midiInClose(indevice); indevice = NULL; DeleteCriticalSection(&dxmidi_cs); } if (outdevice) { midiOutReset(outdevice); midiOutClose(outdevice); outdevice = NULL; } } ////////////////////////////////////////////////////////////////////////////// int SNDDXMidiChangePorts(int inport, int outport) { SNDDXMidiDeInit(); return SNDDXMidiInit(inport, outport); } ////////////////////////////////////////////////////////////////////////////// u8 SNDDXMidiIn(int *isdata) { if (midi_in_cnt) { int i; u8 data; *isdata = 1; EnterCriticalSection (&dxmidi_cs); data = midi_in_buf[0]; midi_in_cnt--; for (i = 0; i < midi_in_cnt; i++) midi_in_buf[i] = midi_in_buf[i+1]; LeaveCriticalSection (&dxmidi_cs); return data; } else { *isdata = 0; return 0; } } ////////////////////////////////////////////////////////////////////////////// int SNDDXMidiOut(u8 data) { static u8 buf[32]; static int cnt=0; if (outdevice) { buf[cnt] = data; cnt++; switch((buf[0] & 0xF0) >> 4) { case 0x8: // Note Off/On(2 bytes) case 0x9: case 0xA: // Polyphonic Aftertouch(2 bytes) case 0xB: // Control/Mode Change(2 bytes) case 0xE: // Pitch Bend(2 bytes) if (cnt == 3) { midiOutShortMsg(outdevice, buf[0] | (buf[1] << 8) | (buf[2] << 16)); cnt = 0; } break; case 0xC: // Program Change(1 byte) case 0xD: // Channel Aftertouch(1 byte) if (cnt == 2) { midiOutShortMsg(outdevice, buf[0] | (buf[1] << 8)); cnt = 0; } break; default: //LOG("Unsupported midi command %02X\n", buf[0]); break; } } return 1; } #endif ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/cd-macosx.c000644 001750 001750 00000013561 12755623101 020072 0ustar00guillaumeguillaume000000 000000 /* Copyright 2004-2005 Lucas Newman Copyright 2004-2005 Theo Berkau Copyright 2005 Weston Yager Copyright 2006-2008 Guillaume Duhamel Copyright 2010 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cdbase.h" static int MacOSXCDInit(const char *); static void MacOSXCDDeInit(void); static int MacOSXCDGetStatus(void); static s32 MacOSXCDReadTOC(u32 *); static int MacOSXCDReadSectorFAD(u32, void *); static void MacOSXCDReadAheadFAD(u32); CDInterface ArchCD = { CDCORE_ARCH, "MacOSX CD Drive", MacOSXCDInit, MacOSXCDDeInit, MacOSXCDGetStatus, MacOSXCDReadTOC, MacOSXCDReadSectorFAD, MacOSXCDReadAheadFAD, }; static int hCDROM; static int MacOSXCDInit(const char * useless_for_now) { CFMutableDictionaryRef classesToMatch; io_iterator_t mediaIterator; io_object_t media; char cdrom_name[ MAXPATHLEN ]; classesToMatch = IOServiceMatching(kIOCDMediaClass); CFDictionarySetValue(classesToMatch, CFSTR(kIOMediaEjectableKey), kCFBooleanTrue); IOServiceGetMatchingServices(kIOMasterPortDefault, classesToMatch, &mediaIterator); media = IOIteratorNext(mediaIterator); if(media) { CFTypeRef path; path = IORegistryEntryCreateCFProperty(media, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0); if (path) { size_t length; strcpy(cdrom_name, _PATH_DEV); strcat(cdrom_name, "r"); length = strlen(cdrom_name); CFStringGetCString(path, cdrom_name + length, MAXPATHLEN - length, kCFStringEncodingUTF8); CFRelease(path); } IOObjectRelease(media); } if ((hCDROM = open(cdrom_name, O_RDONLY)) == -1) { return -1; } return 0; } static void MacOSXCDDeInit(void) { if (hCDROM != -1) { close(hCDROM); } } static CDTOC * GetTOCFromCDPath(void) { CFMutableDictionaryRef classesToMatch; io_iterator_t mediaIterator; io_object_t media; CDTOC * TOC = NULL; classesToMatch = IOServiceMatching(kIOCDMediaClass); CFDictionarySetValue(classesToMatch, CFSTR(kIOMediaEjectableKey), kCFBooleanTrue); IOServiceGetMatchingServices(kIOMasterPortDefault, classesToMatch, &mediaIterator); media = IOIteratorNext(mediaIterator); if(media) { CFDataRef TOCData = IORegistryEntryCreateCFProperty(media, CFSTR(kIOCDMediaTOCKey), kCFAllocatorDefault, 0); TOC = malloc(CFDataGetLength(TOCData)); CFDataGetBytes(TOCData,CFRangeMake(0,CFDataGetLength(TOCData)),(UInt8 *)TOC); CFRelease(TOCData); IOObjectRelease(media); } return TOC; } static s32 MacOSXCDReadTOC(u32 *TOC) { int add150 = 150, tracks = 0; u_char track; int i, fad = 0; CDTOC *cdTOC = GetTOCFromCDPath(); CDTOCDescriptor *pTrackDescriptors; pTrackDescriptors = cdTOC->descriptors; memset(TOC, 0xFF, 0xCC * 2); /* Convert TOC to Saturn format */ for( i = 3; i < CDTOCGetDescriptorCount(cdTOC); i++ ) { track = pTrackDescriptors[i].point; fad = CDConvertMSFToLBA(pTrackDescriptors[i].p) + add150; if ((track > 99) || (track < 1)) continue; TOC[i-3] = (pTrackDescriptors[i].control << 28 | pTrackDescriptors[i].adr << 24 | fad); tracks++; } /* First */ TOC[99] = pTrackDescriptors[0].control << 28 | pTrackDescriptors[0].adr << 24 | 1 << 16; /* Last */ TOC[100] = pTrackDescriptors[1].control << 28 | pTrackDescriptors[1].adr << 24 | tracks << 16; /* Leadout */ TOC[101] = pTrackDescriptors[2].control << 28 | pTrackDescriptors[2].adr << 24 | CDConvertMSFToLBA(pTrackDescriptors[2].p) + add150; //free(cdTOC); Looks like this is not need, will look into that. return (0xCC * 2); } static int MacOSXCDGetStatus(void) { // 0 - CD Present, disc spinning // 1 - CD Present, disc not spinning // 2 - CD not present // 3 - Tray open // see ../windows/cd.cc for more info //Return that disc is present and spinning. 2 and 3 can't happen in the mac port, i don't understand what "not spinning" is supposed to say return 0; } static int MacOSXCDReadSectorFAD(u32 FAD, void *buffer) { const int blockSize = 2352; #ifdef CRAB_REWRITE const int cacheBlocks = 32; static u8 cache[blockSize * cacheBlocks]; static u32 cacheFAD = 0xFFFFFF00; #endif if (hCDROM != -1) { #ifdef CRAB_REWRITE /* See if the block we are looking for is in the cache already... */ if(FAD < cacheFAD || FAD >= cacheFAD + cacheBlocks) { /* Cache miss, read some blocks from the cd, then we'll hit the cache below. */ if(!pread(hCDROM, cache, blockSize * cacheBlocks, (FAD - 150) * blockSize)) { return 0; } cacheFAD = FAD; } /* Cache hit, copy the block out. */ memcpy(buffer, cache + (blockSize * (FAD - cacheFAD)), blockSize); return 1; #else if (pread(hCDROM, buffer, blockSize, (FAD - 150) * blockSize)) return true; #endif } return false; } static void MacOSXCDReadAheadFAD(UNUSED u32 FAD) { // No-op } yabause-0.9.15/src/sock-linux.c000644 001750 001750 00000007713 12755623101 020312 0ustar00guillaumeguillaume000000 000000 /* Copyright 2013 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "core.h" #include "sock.h" #include "debug.h" #include #include #include #include #include #include static fd_set read_fds; static fd_set write_fds; ////////////////////////////////////////////////////////////////////////////// int YabSockInit() { return 0; } int YabSockDeInit() { return 0; } int YabSockConnectSocket(const char *ip, int port, YabSock *sock) { struct addrinfo *result = NULL, hints; char port_str[256]; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; sprintf(port_str, "%d", port); if (getaddrinfo(ip, port_str, &hints, &result) != 0) { perror("getaddrinfo"); return -1; } // Create a Socket if ((sock[0] = socket(result->ai_family, result->ai_socktype, result->ai_protocol)) == -1) { freeaddrinfo(result); perror("socket"); return -1; } // Connect to the socket if (connect(sock[0], result->ai_addr, (int)result->ai_addrlen) == -1) { perror("connect"); freeaddrinfo(result); close(sock[0]); return -1; } freeaddrinfo(result); return 0; } int YabSockListenSocket(int port, YabSock *sock) { struct sockaddr_in addr; char opt = 1; sock[0] = socket(AF_INET, SOCK_STREAM, 0); if (setsockopt(sock[0], SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)) == -1) { perror("setsockopt"); return -1; } memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(port); if (bind(sock[0], (struct sockaddr *) &addr, sizeof(addr)) == -1) { fprintf(stderr, "Can't bind to port %d: %s\n", port, strerror(errno)); return -1; } if (listen(sock[0], 3) == -1) { perror("listen"); return -1; } return 0; } int YabSockCloseSocket(YabSock sock) { return close(sock); } int YabSockSelect(YabSock sock, int check_read, int check_write ) { fd_set *read_fds_ptr; fd_set *write_fds_ptr; struct timeval tv; int ret; FD_ZERO(&read_fds); FD_ZERO(&write_fds); // Let's see if we can even connect at this point if (check_read) { FD_SET(sock, &read_fds); read_fds_ptr = &read_fds; } else read_fds_ptr = NULL; if (check_write) { FD_SET(sock, &write_fds); write_fds_ptr = &write_fds; } else write_fds_ptr = NULL; tv.tv_sec = 0; tv.tv_usec = 0; if ((ret=select(sock+1, read_fds_ptr, write_fds_ptr, NULL, &tv)) < 1) { LOG("select: %d\n", ret); return -1; } return 0; } int YabSockIsReadSet(YabSock sock) { return FD_ISSET(sock, &read_fds); } int YabSockIsWriteSet(YabSock sock) { return FD_ISSET(sock, &write_fds); } YabSock YabSockAccept(YabSock sock) { return accept(sock,NULL,NULL); } int YabSockSend(YabSock sock, const void *buf, int len, int flags) { return send(sock, buf, len, flags); } int YabSockReceive(YabSock sock, void *buf, int len, int flags) { return recv(sock, buf, len, flags); } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/gdb/000755 001750 001750 00000000000 12757373644 016616 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/gdb/packet.h000644 001750 001750 00000000560 12755623101 020217 0ustar00guillaumeguillaume000000 000000 #ifndef GDB_PACKET_H #define GDB_PACKET_H #include "../core.h" #include typedef struct _gdb_client gdb_client; typedef struct { char buffer[2048]; size_t buflen; u8 bufsum; char checksum[2]; size_t cslen; int state; gdb_client * client; } gdb_packet; void gdb_packet_read(gdb_packet * packet, char * buffer, size_t got); #endif yabause-0.9.15/src/gdb/client.h000644 001750 001750 00000000771 12755623101 020232 0ustar00guillaumeguillaume000000 000000 #ifndef GDB_CLIENT_H #define GDB_CLIENT_H #include "packet.h" #include "../sh2core.h" #include "../sock.h" #include "../threads.h" struct _gdb_client { SH2_struct * context; YabSock sock; }; void gdb_client_received(gdb_client * client, gdb_packet * packet); void gdb_client_error(gdb_client * client); void gdb_client_send(gdb_client * client, const char * message, int msglen); void gdb_client_break(gdb_client * client); void gdb_client_lock(void *context, u32 addr, void * userdata); #endif yabause-0.9.15/src/gdb/stub.c000644 001750 001750 00000003057 12755623101 017724 0ustar00guillaumeguillaume000000 000000 #include "stub.h" #include "client.h" #include "../sh2core.h" #include "../threads.h" #include "../sock.h" #include #include #include /*! \file stub.c \brief GDB stub interface. */ typedef struct { SH2_struct * context; YabSock server; } gdb_stub; static void gdb_stub_client(void * data) { gdb_client * client = data; char buffer[1024]; size_t got; gdb_packet packet; packet.state = 0; packet.client = client; while(-1 != (got = YabSockReceive(client->sock, buffer, 1024, 0))) { gdb_packet_read(&packet, buffer, got); } } static void gdb_stub_listener(void * data) { gdb_stub * stub = data; YabSock sock; while(1) { gdb_client * client; sock = YabSockAccept(stub->server); if (sock == -1) { perror("accept"); return; } client = malloc(sizeof(gdb_client)); client->context = stub->context; client->sock = sock; SH2SetBreakpointCallBack(stub->context, gdb_client_lock, client); YabThreadStart(YAB_THREAD_GDBSTUBCLIENT, gdb_stub_client, client); } } int GdbStubInit(SH2_struct * context, int port) { int opt = 1; YabSock server; gdb_stub * stub; int ret; YabSockInit(); if ((ret = YabSockListenSocket(port, &server)) != 0) return ret; stub = malloc(sizeof(gdb_stub)); stub->context = context; stub->server = server; YabThreadStart(YAB_THREAD_GDBSTUBLISTENER, gdb_stub_listener, stub); return 0; } int GdbStubDeInit() { YabSockDeInit(); return 0; } yabause-0.9.15/src/gdb/packet.c000644 001750 001750 00000002540 12755623101 020212 0ustar00guillaumeguillaume000000 000000 #include "packet.h" #include "client.h" /*! \file packet.c \brief GDB stub packet function. */ void gdb_packet_read(gdb_packet * packet, char * buffer, size_t got) { size_t i; char c; for(i = 0;i < got;i++) { c = buffer[i]; switch(packet->state) { case 0: if ('$' == c) { packet->state = 1; packet->buflen = 0; packet->bufsum = 0; } else if (3 == c) gdb_client_break(packet->client); break; case 1: if ('#' == c) { packet->state = 2; packet->cslen = 0; } else { packet->buffer[packet->buflen++] = c; packet->bufsum += c; } break; case 2: packet->checksum[packet->cslen++] = c; if (2 == packet->cslen) { int checksum; sscanf(packet->checksum, "%2x", &checksum); packet->buffer[packet->buflen] = '\0'; if (packet->bufsum == checksum) gdb_client_received(packet->client, packet); else gdb_client_error(packet->client); packet->state = 0; } break; } } } yabause-0.9.15/src/gdb/client.c000644 001750 001750 00000011163 12755623101 020222 0ustar00guillaumeguillaume000000 000000 /*! \file client.c \brief GDB stub client functions. */ #include "client.h" #include "../sh2core.h" #include void gdb_client_unlock(gdb_client * client) { YabThreadWake(YAB_THREAD_GDBSTUBCLIENT); } void gdb_client_step(gdb_client * client) { SH2BreakNow(client->context); gdb_client_unlock(client); } void gdb_client_received(gdb_client * client, gdb_packet * packet) { char ack = '+'; printf("packet received: %s\n", packet->buffer); YabSockSend(client->sock, &ack, 1, 0); if (packet->buffer[0] == '?') gdb_client_break(client); else if (packet->buffer[0] == 'c') gdb_client_unlock(client); else if (packet->buffer[0] == 'g') { int i; char buffer[184+1]; for(i = 0;i < 16;i++) sprintf(buffer + 8 * i, "%08x", client->context->regs.R[i]); sprintf(buffer + 8 * 16, "%08x", client->context->regs.PC); sprintf(buffer + 8 * 17, "%08x", client->context->regs.PR); sprintf(buffer + 8 * 18, "%08x", client->context->regs.GBR); sprintf(buffer + 8 * 19, "%08x", client->context->regs.VBR); sprintf(buffer + 8 * 20, "%08x", client->context->regs.MACH); sprintf(buffer + 8 * 21, "%08x", client->context->regs.MACL); sprintf(buffer + 8 * 22, "%08x", client->context->regs.SR); gdb_client_send(client, buffer, 184); } else if (packet->buffer[0] == 'H') gdb_client_send(client, "OK", 2); else if (packet->buffer[0] == 'q') { if (!strncmp(packet->buffer, "qSupported", 10)) gdb_client_send(client, "PacketSize=1024", 15); else if (packet->buffer[1] == 'C') gdb_client_send(client, "", 0); else if (!strncmp(packet->buffer, "qAttached", 9)) gdb_client_send(client, "0", 1); else if (!strncmp(packet->buffer, "qTStatus", 8)) gdb_client_send(client, "T0", 2); else if (!strncmp(packet->buffer, "qTfP", 8)) gdb_client_send(client, "", 0); else if (!strncmp(packet->buffer, "qTfV", 8)) gdb_client_send(client, "", 0); else if (!strncmp(packet->buffer, "qTsP", 8)) gdb_client_send(client, "", 0); } else if (packet->buffer[0] == 'm') { u32 addr; int len, i; char * buffer; char * pos; sscanf(packet->buffer, "m%x,%d", &addr, &len); buffer = malloc(2 * len); pos = buffer; i = 0; while(i < len / 4) { u32 val = MappedMemoryReadLongNocache(client->context, addr + 4 * i); sprintf(pos, "%08x", val); i += 1; pos += 8; } switch(len % 4) { case 2: { u16 val = MappedMemoryReadWordNocache(client->context, addr + 4 * i); sprintf(pos, "%04x", val); break; } case 1: { u8 val = MappedMemoryReadByteNocache(client->context, addr + 4 * i); sprintf(pos, "%02x", val); break; } } gdb_client_send(client, buffer, 2 * len); free(buffer); } else if (packet->buffer[0] == 'v') { if (!strncmp(packet->buffer, "vCont?", 6)) gdb_client_send(client, "", 0); } else if (packet->buffer[0] == 's') gdb_client_step(client); else if (packet->buffer[0] == 'Z') /* insert breakpoint */ { if (packet->buffer[1] == '0') /* code breakpoint */ { u32 addr; int dummy; sscanf(packet->buffer, "Z0,%x,%d", &addr, &dummy); SH2AddCodeBreakpoint(client->context, addr); } gdb_client_send(client, "OK", 2); } else if (packet->buffer[0] == 'z') /* remove breakpoint */ { if (packet->buffer[1] == '0') /* code breakpoint */ { u32 addr; int dummy; sscanf(packet->buffer, "Z0,%x,%d", &addr, &dummy); SH2DelCodeBreakpoint(client->context, addr); } gdb_client_send(client, "OK", 2); } } void gdb_client_send(gdb_client * client, const char * message, int msglen) { char * buffer; u8 checksum = 0; int i; for(i = 0;i < msglen;i++) checksum += message[i]; buffer = malloc(msglen + 5); buffer[0] = '$'; memcpy(buffer + 1, message, msglen); buffer[msglen + 1] = '#'; sprintf(buffer + msglen + 2, "%02x", checksum); buffer[msglen + 4] = '\0'; YabSockSend(client->sock, buffer, msglen + 4, 0); printf("sent: %s\n", buffer); free(buffer); } void gdb_client_error(gdb_client * client) { } void gdb_client_lock(void *context, u32 addr, void * userdata) { gdb_client * client = userdata; gdb_client_send(client, "S05", 3); YabThreadRemoteSleep(YAB_THREAD_GDBSTUBCLIENT); } void gdb_client_break(gdb_client * client) { SH2BreakNow(client->context); } yabause-0.9.15/src/gdb/stub.h000644 001750 001750 00000000216 12755623101 017723 0ustar00guillaumeguillaume000000 000000 #ifndef GDB_STUB_H #define GDB_STUB_H #include "../sh2core.h" int GdbStubInit(SH2_struct * context, int port); int GdbStubDeInit(); #endif yabause-0.9.15/src/vdp2.h000644 001750 001750 00000024223 12755623101 017071 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2005 Guillaume Duhamel Copyright 2004-2006 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef VDP2_H #define VDP2_H #include "memory.h" /* This include is not *needed*, it's here to avoid breaking ports */ #include "osdcore.h" extern u8 * Vdp2Ram; extern u8 * Vdp2ColorRam; u8 FASTCALL Vdp2RamReadByte(u32); u16 FASTCALL Vdp2RamReadWord(u32); u32 FASTCALL Vdp2RamReadLong(u32); void FASTCALL Vdp2RamWriteByte(u32, u8); void FASTCALL Vdp2RamWriteWord(u32, u16); void FASTCALL Vdp2RamWriteLong(u32, u32); u8 FASTCALL Vdp2ColorRamReadByte(u32); u16 FASTCALL Vdp2ColorRamReadWord(u32); u32 FASTCALL Vdp2ColorRamReadLong(u32); void FASTCALL Vdp2ColorRamWriteByte(u32, u8); void FASTCALL Vdp2ColorRamWriteWord(u32, u16); void FASTCALL Vdp2ColorRamWriteLong(u32, u32); u8 FASTCALL Sh2Vdp2RamReadByte(SH2_struct *, u32); u16 FASTCALL Sh2Vdp2RamReadWord(SH2_struct *, u32); u32 FASTCALL Sh2Vdp2RamReadLong(SH2_struct *, u32); void FASTCALL Sh2Vdp2RamWriteByte(SH2_struct *, u32, u8); void FASTCALL Sh2Vdp2RamWriteWord(SH2_struct *, u32, u16); void FASTCALL Sh2Vdp2RamWriteLong(SH2_struct *, u32, u32); u8 FASTCALL Sh2Vdp2ColorRamReadByte(SH2_struct *, u32); u16 FASTCALL Sh2Vdp2ColorRamReadWord(SH2_struct *, u32); u32 FASTCALL Sh2Vdp2ColorRamReadLong(SH2_struct *, u32); void FASTCALL Sh2Vdp2ColorRamWriteByte(SH2_struct *, u32, u8); void FASTCALL Sh2Vdp2ColorRamWriteWord(SH2_struct *, u32, u16); void FASTCALL Sh2Vdp2ColorRamWriteLong(SH2_struct *, u32, u32); typedef struct { u16 TVMD; // 0x25F80000 u16 EXTEN; // 0x25F80002 u16 TVSTAT; // 0x25F80004 u16 VRSIZE; // 0x25F80006 u16 HCNT; // 0x25F80008 u16 VCNT; // 0x25F8000A u16 RAMCTL; // 0x25F8000E u16 CYCA0L; // 0x25F80010 u16 CYCA0U; // 0x25F80012 u16 CYCA1L; // 0x25F80014 u16 CYCA1U; // 0x25F80016 u16 CYCB0L; // 0x25F80018 u16 CYCB0U; // 0x25F8001A u16 CYCB1L; // 0x25F8001C u16 CYCB1U; // 0x25F8001E u16 BGON; // 0x25F80020 u16 MZCTL; // 0x25F80022 u16 SFSEL; // 0x25F80024 u16 SFCODE; // 0x25F80026 u16 CHCTLA; // 0x25F80028 u16 CHCTLB; // 0x25F8002A u16 BMPNA; // 0x25F8002C u16 BMPNB; // 0x25F8002E u16 PNCN0; // 0x25F80030 u16 PNCN1; // 0x25F80032 u16 PNCN2; // 0x25F80034 u16 PNCN3; // 0x25F80036 u16 PNCR; // 0x25F80038 u16 PLSZ; // 0x25F8003A u16 MPOFN; // 0x25F8003C u16 MPOFR; // 0x25F8003E u16 MPABN0; // 0x25F80040 u16 MPCDN0; // 0x25F80042 u16 MPABN1; // 0x25F80044 u16 MPCDN1; // 0x25F80046 u16 MPABN2; // 0x25F80048 u16 MPCDN2; // 0x25F8004A u16 MPABN3; // 0x25F8004C u16 MPCDN3; // 0x25F8004E u16 MPABRA; // 0x25F80050 u16 MPCDRA; // 0x25F80052 u16 MPEFRA; // 0x25F80054 u16 MPGHRA; // 0x25F80056 u16 MPIJRA; // 0x25F80058 u16 MPKLRA; // 0x25F8005A u16 MPMNRA; // 0x25F8005C u16 MPOPRA; // 0x25F8005E u16 MPABRB; // 0x25F80060 u16 MPCDRB; // 0x25F80062 u16 MPEFRB; // 0x25F80064 u16 MPGHRB; // 0x25F80066 u16 MPIJRB; // 0x25F80068 u16 MPKLRB; // 0x25F8006A u16 MPMNRB; // 0x25F8006C u16 MPOPRB; // 0x25F8006E u16 SCXIN0; // 0x25F80070 u16 SCXDN0; // 0x25F80072 u16 SCYIN0; // 0x25F80074 u16 SCYDN0; // 0x25F80076 #ifdef WORDS_BIGENDIAN union { struct { u32 I:16; // 0x25F80078 u32 D:16; // 0x25F8007A } part; u32 all; } ZMXN0; union { struct { u32 I:16; // 0x25F8007C u32 D:16; // 0x25F8007E } part; u32 all; } ZMYN0; #else union { struct { u32 D:16; // 0x25F8007A u32 I:16; // 0x25F80078 } part; u32 all; } ZMXN0; union { struct { u32 D:16; // 0x25F8007E u32 I:16; // 0x25F8007C } part; u32 all; } ZMYN0; #endif u16 SCXIN1; // 0x25F80080 u16 SCXDN1; // 0x25F80082 u16 SCYIN1; // 0x25F80084 u16 SCYDN1; // 0x25F80086 #ifdef WORDS_BIGENDIAN union { struct { u32 I:16; // 0x25F80088 u32 D:16; // 0x25F8008A } part; u32 all; } ZMXN1; union { struct { u32 I:16; // 0x25F8008C u32 D:16; // 0x25F8008E } part; u32 all; } ZMYN1; #else union { struct { u32 D:16; // 0x25F8008A u32 I:16; // 0x25F80088 } part; u32 all; } ZMXN1; union { struct { u32 D:16; // 0x25F8008E u32 I:16; // 0x25F8008C } part; u32 all; } ZMYN1; #endif u16 SCXN2; // 0x25F80090 u16 SCYN2; // 0x25F80092 u16 SCXN3; // 0x25F80094 u16 SCYN3; // 0x25F80096 u16 ZMCTL; // 0x25F80098 u16 SCRCTL; // 0x25F8009A #ifdef WORDS_BIGENDIAN union { struct { u32 U:16; // 0x25F8009C u32 L:16; // 0x25F8009E } part; u32 all; } VCSTA; union { struct { u32 U:16; // 0x25F800A0 u32 L:16; // 0x25F800A2 } part; u32 all; } LSTA0; union { struct { u32 U:16; // 0x25F800A4 u32 L:16; // 0x25F800A6 } part; u32 all; } LSTA1; union { struct { u32 U:16; // 0x25F800A8 u32 L:16; // 0x25F800AA } part; u32 all; } LCTA; #else union { struct { u32 L:16; // 0x25F8009E u32 U:16; // 0x25F8009C } part; u32 all; } VCSTA; union { struct { u32 L:16; // 0x25F800A2 u32 U:16; // 0x25F800A0 } part; u32 all; } LSTA0; union { struct { u32 L:16; // 0x25F800A6 u32 U:16; // 0x25F800A4 } part; u32 all; } LSTA1; union { struct { u32 L:16; // 0x25F800AA u32 U:16; // 0x25F800A8 } part; u32 all; } LCTA; #endif u16 BKTAU; // 0x25F800AC u16 BKTAL; // 0x25F800AE u16 RPMD; // 0x25F800B0 u16 RPRCTL; // 0x25F800B2 u16 KTCTL; // 0x25F800B4 u16 KTAOF; // 0x25F800B6 u16 OVPNRA; // 0x25F800B8 u16 OVPNRB; // 0x25F800BA #ifdef WORDS_BIGENDIAN union { struct { u32 U:16; // 0x25F800BC u32 L:16; // 0x25F800BE } part; u32 all; } RPTA; #else union { struct { u32 L:16; // 0x25F800BE u32 U:16; // 0x25F800BC } part; u32 all; } RPTA; #endif u16 WPSX0; // 0x25F800C0 u16 WPSY0; // 0x25F800C2 u16 WPEX0; // 0x25F800C4 u16 WPEY0; // 0x25F800C6 u16 WPSX1; // 0x25F800C8 u16 WPSY1; // 0x25F800CA u16 WPEX1; // 0x25F800CC u16 WPEY1; // 0x25F800CE u16 WCTLA; // 0x25F800D0 u16 WCTLB; // 0x25F800D2 u16 WCTLC; // 0x25F800D4 u16 WCTLD; // 0x25F800D6 #ifdef WORDS_BIGENDIAN union { struct { u32 U:16; // 0x25F800D8 u32 L:16; // 0x25F800DA } part; u32 all; } LWTA0; union { struct { u32 U:16; // 0x25F800DC u32 L:16; // 0x25F800DE } part; u32 all; } LWTA1; #else union { struct { u32 L:16; // 0x25F800D8 u32 U:16; // 0x25F800DA } part; u32 all; } LWTA0; union { struct { u32 L:16; // 0x25F800DC u32 U:16; // 0x25F800DE } part; u32 all; } LWTA1; #endif u16 SPCTL; // 0x25F800E0 u16 SDCTL; // 0x25F800E2 u16 CRAOFA; // 0x25F800E4 u16 CRAOFB; // 0x25F800E6 u16 LNCLEN; // 0x25F800E8 u16 SFPRMD; // 0x25F800EA u16 CCCTL; // 0x25F800EC u16 SFCCMD; // 0x25F800EE u16 PRISA; // 0x25F800F0 u16 PRISB; // 0x25F800F2 u16 PRISC; // 0x25F800F4 u16 PRISD; // 0x25F800F6 u16 PRINA; // 0x25F800F8 u16 PRINB; // 0x25F800FA u16 PRIR; // 0x25F800FC u16 CCRSA; // 0x25F80100 u16 CCRSB; // 0x25F80102 u16 CCRSC; // 0x25F80104 u16 CCRSD; // 0x25F80106 u16 CCRNA; // 0x25F80108 u16 CCRNB; // 0x25F8010A u16 CCRR; // 0x25F8010C u16 CCRLB; // 0x25F8010E u16 CLOFEN; // 0x25F80110 u16 CLOFSL; // 0x25F80112 u16 COAR; // 0x25F80114 u16 COAG; // 0x25F80116 u16 COAB; // 0x25F80118 u16 COBR; // 0x25F8011A u16 COBG; // 0x25F8011C u16 COBB; // 0x25F8011E } Vdp2; extern Vdp2 * Vdp2Regs; typedef struct { int ColorMode; } Vdp2Internal_struct; extern Vdp2Internal_struct Vdp2Internal; extern u64 lastticks; extern int vdp2_is_odd_frame; extern Vdp2 Vdp2Lines[270]; struct CellScrollData { u32 data[88];//(352/8) * 2 screens }; extern struct CellScrollData cell_scroll_data[270]; // struct for Vdp2 part that shouldn't be saved typedef struct { int disptoggle; } Vdp2External_struct; extern Vdp2External_struct Vdp2External; int Vdp2Init(void); void Vdp2DeInit(void); void Vdp2Reset(void); void Vdp2VBlankIN(void); void Vdp2HBlankIN(void); void Vdp2HBlankOUT(void); void Vdp2VBlankOUT(void); void Vdp2SendExternalLatch(int hcnt, int vcnt); void SpeedThrottleEnable(void); void SpeedThrottleDisable(void); u8 FASTCALL Vdp2ReadByte(u32); u16 FASTCALL Vdp2ReadWord(u32); u32 FASTCALL Vdp2ReadLong(u32); void FASTCALL Vdp2WriteByte(u32, u8); void FASTCALL Vdp2WriteWord(u32, u16); void FASTCALL Vdp2WriteLong(u32, u32); u8 FASTCALL Sh2Vdp2ReadByte(SH2_struct *, u32); u16 FASTCALL Sh2Vdp2ReadWord(SH2_struct *, u32); u32 FASTCALL Sh2Vdp2ReadLong(SH2_struct *, u32); void FASTCALL Sh2Vdp2WriteByte(SH2_struct *, u32, u8); void FASTCALL Sh2Vdp2WriteWord(SH2_struct *, u32, u16); void FASTCALL Sh2Vdp2WriteLong(SH2_struct *, u32, u32); int Vdp2SaveState(FILE *fp); int Vdp2LoadState(FILE *fp, int version, int size); void ToggleNBG0(void); void ToggleNBG1(void); void ToggleNBG2(void); void ToggleNBG3(void); void ToggleRBG0(void); void ToggleFullScreen(void); void EnableAutoFrameSkip(void); void DisableAutoFrameSkip(void); Vdp2 * Vdp2RestoreRegs(int line, Vdp2* lines); #endif yabause-0.9.15/src/sock-windows.c000644 001750 001750 00000010662 12755623101 020642 0ustar00guillaumeguillaume000000 000000 /* Copyright 2013 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file sock-windows.c \brief Windows port's socket interface */ #include "core.h" #include "sock.h" #include "debug.h" #ifdef __MINGW32__ // I blame mingw for this #define _WIN32_WINNT 0x501 #endif #include #include static fd_set read_fds; static fd_set write_fds; ////////////////////////////////////////////////////////////////////////////// int YabSockInit() { WSADATA wsaData; if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) return -1; return 0; } int YabSockDeInit() { WSACleanup(); return 0; } int YabSockConnectSocket(const char *ip, int port, YabSock *sock) { struct addrinfo *result = NULL, hints; char port_str[256]; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; sprintf(port_str, "%d", port); if (getaddrinfo(ip, port_str, &hints, &result) != 0) { perror("getaddrinfo"); return -1; } // Create a Socket if ((sock[0] = socket(result->ai_family, result->ai_socktype, result->ai_protocol)) == -1) { freeaddrinfo(result); perror("socket"); return -1; } // Connect to the socket if (connect(sock[0], result->ai_addr, (int)result->ai_addrlen) == -1) { perror("connect"); freeaddrinfo(result); closesocket(sock[0]); return -1; } freeaddrinfo(result); return 0; } int YabSockListenSocket(int port, YabSock *sock) { struct sockaddr_in addr; char opt = 1; sock[0] = socket(AF_INET, SOCK_STREAM, 0); if (setsockopt(sock[0], SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)) == -1) { perror("setsockopt"); return -1; } memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(port); if (bind(sock[0], (struct sockaddr *) &addr, sizeof(addr)) == -1) { fprintf(stderr, "Can't bind to port %d: %s\n", port, strerror(errno)); return -1; } if (listen(sock[0], 3) == -1) { perror("listen"); return -1; } return 0; } int YabSockCloseSocket(YabSock sock) { return closesocket(sock); } int YabSockSelect(YabSock sock, int check_read, int check_write ) { fd_set *read_fds_ptr; fd_set *write_fds_ptr; struct timeval tv; int ret; FD_ZERO(&read_fds); FD_ZERO(&write_fds); // Let's see if we can even connect at this point if (check_read) { FD_SET(sock, &read_fds); read_fds_ptr = &read_fds; } else read_fds_ptr = NULL; if (check_write) { FD_SET(sock, &write_fds); write_fds_ptr = &write_fds; } else write_fds_ptr = NULL; tv.tv_sec = 0; tv.tv_usec = 0; if ((ret=select(sock+1, read_fds_ptr, write_fds_ptr, NULL, &tv)) < 1) { if (ret == SOCKET_ERROR) LOG("select: err code %d\n", WSAGetLastError()); else LOG("select: %d\n", ret); return -1; } return 0; } int YabSockIsReadSet(YabSock sock) { return FD_ISSET(sock, &read_fds); } int YabSockIsWriteSet(YabSock sock) { return FD_ISSET(sock, &write_fds); } YabSock YabSockAccept(YabSock sock) { return accept(sock,NULL,NULL); } int YabSockSend(YabSock sock, const void *buf, int len, int flags) { return send(sock, buf, len, flags); } int YabSockReceive(YabSock sock, void *buf, int len, int flags) { return recv(sock, buf, len, flags); } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/gameinfo.c000644 001750 001750 00000006500 12755623101 017774 0ustar00guillaumeguillaume000000 000000 /* Copyright 2016 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "gameinfo.h" #include "cdbase.h" #include "cs2.h" extern ip_struct * cdip; int GameInfoFromPath(const char * filename, GameInfo * info) { if (cdip != NULL) return 0; Cs2Init(0, CDCORE_ISO, filename, NULL, NULL, NULL); Cs2GetIP(1); memcpy(info, cdip, sizeof(GameInfo)); Cs2DeInit(); return 1; } int LoadStateSlotScreenshotStream(FILE * fp, int * outputwidth, int * outputheight, u32 ** buffer) { int version, chunksize; int totalsize; size_t fread_result = 0; fseek(fp, 0x14, SEEK_SET); if (StateCheckRetrieveHeader(fp, "CART", &version, &chunksize) != 0) return -1; fseek(fp, chunksize, SEEK_CUR); if (StateCheckRetrieveHeader(fp, "CS2 ", &version, &chunksize) != 0) return -1; fseek(fp, chunksize, SEEK_CUR); if (StateCheckRetrieveHeader(fp, "MSH2", &version, &chunksize) != 0) return -1; fseek(fp, chunksize, SEEK_CUR); if (StateCheckRetrieveHeader(fp, "SSH2", &version, &chunksize) != 0) return -1; fseek(fp, chunksize, SEEK_CUR); if (StateCheckRetrieveHeader(fp, "SCSP", &version, &chunksize) != 0) return -1; fseek(fp, chunksize, SEEK_CUR); if (StateCheckRetrieveHeader(fp, "SCU ", &version, &chunksize) != 0) return -1; fseek(fp, chunksize, SEEK_CUR); if (StateCheckRetrieveHeader(fp, "SMPC", &version, &chunksize) != 0) return -1; fseek(fp, chunksize, SEEK_CUR); if (StateCheckRetrieveHeader(fp, "VDP1", &version, &chunksize) != 0) return -1; fseek(fp, chunksize, SEEK_CUR); if (StateCheckRetrieveHeader(fp, "VDP2", &version, &chunksize) != 0) return -1; fseek(fp, chunksize, SEEK_CUR); if (StateCheckRetrieveHeader(fp, "OTHR", &version, &chunksize) != 0) return -1; fseek(fp, 0x210000, SEEK_CUR); fseek(fp, sizeof(int) * 9, SEEK_CUR); fread_result = fread((void *) outputwidth, sizeof(int), 1, fp); fread_result = fread((void *) outputheight, sizeof(int), 1, fp); totalsize = *outputwidth * *outputheight * sizeof(u32); *buffer = malloc(totalsize); fread_result = fread(*buffer, totalsize, 1, fp); return 0; } int LoadStateSlotScreenshot(const char * dirpath, const char * itemnum, int slot, int * outputwidth, int * outputheight, u32 ** buffer) { char filename[512]; FILE * fp; int status; sprintf(filename, "%s/%s_%03d.yss", dirpath, itemnum, slot); fp = fopen(filename, "r"); if (fp == NULL) return -1; status = LoadStateSlotScreenshotStream(fp, outputwidth, outputheight, buffer); fclose(fp); return status; } yabause-0.9.15/src/yglshaderes.c000755 001750 001750 00000155726 12755623101 020543 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005-2006 Guillaume Duhamel Copyright 2005-2006 Theo Berkau Copyright 2011-2015 Shinya Miyamoto(devmiyax) This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_LIBGL //#ifdef __ANDROID__ #include #include #include "ygl.h" #include "yui.h" #include "vidshared.h" extern float vdp1wratio; extern float vdp1hratio; extern int GlHeight; extern int GlWidth; static void Ygl_printShaderError( GLuint shader ) { GLsizei bufSize; glGetShaderiv(shader, GL_INFO_LOG_LENGTH , &bufSize); if (bufSize > 1) { GLchar *infoLog; infoLog = (GLchar *)malloc(bufSize); if (infoLog != NULL) { GLsizei length; glGetShaderInfoLog(shader, bufSize, &length, infoLog); YGLLOG("Shaderlog:\n%s\n", infoLog); free(infoLog); } } } static GLuint _prgid[PG_MAX] ={0}; /*------------------------------------------------------------------------------------ * Normal Draw * ----------------------------------------------------------------------------------*/ const GLchar Yglprg_normal_v[] = #if defined(_OGLES3_) "#version 300 es \n" #else "#version 330 \n" #endif "uniform mat4 u_mvpMatrix; \n" "uniform mat4 u_texMatrix; \n" "layout (location = 0) in vec4 a_position; \n" "layout (location = 1) in vec4 a_texcoord; \n" "out highp vec4 v_texcoord; \n" "void main() \n" "{ \n" " gl_Position = a_position*u_mvpMatrix; \n" " v_texcoord = a_texcoord/*u_texMatrix*/; \n" " v_texcoord.s = v_texcoord.s; ///2048.0; \n" " v_texcoord.t = v_texcoord.t; ///1024.0; \n" "} "; const GLchar * pYglprg_normal_v[] = {Yglprg_normal_v, NULL}; const GLchar Yglprg_normal_f[] = #if defined(_OGLES3_) "#version 300 es \n" #else "#version 330 \n" #endif "precision highp float; \n" "in highp vec4 v_texcoord; \n" "uniform vec4 u_color_offset; \n" "uniform sampler2D s_texture; \n" "out vec4 fragColor; \n" "void main() \n" "{ \n" " ivec2 addr; \n" " addr.x = int(v_texcoord.x); \n" " addr.y = int(v_texcoord.y); \n" " vec4 txcol = texelFetch( s_texture, addr,0 ); \n" " if(txcol.a > 0.0)\n " " fragColor = clamp(txcol+u_color_offset,vec4(0.0),vec4(1.0));\n " " else \n " " discard;\n " "} \n"; const GLchar * pYglprg_normal_f[] = {Yglprg_normal_f, NULL}; static int id_normal_s_texture = -1; int Ygl_uniformNormal(void * p ) { YglProgram * prg; prg = p; glEnableVertexAttribArray(prg->vertexp); glEnableVertexAttribArray(prg->texcoordp); glUniform1i(id_normal_s_texture, 0); glUniform4fv(prg->color_offset,1,prg->color_offset_val); return 0; } int Ygl_cleanupNormal(void * p ) { YglProgram * prg; prg = p; return 0; } int ShaderDrawTest() { GLuint vertexp = glGetAttribLocation(_prgid[PG_NORMAL],(const GLchar *)"a_position"); GLuint texcoordp = glGetAttribLocation(_prgid[PG_NORMAL],(const GLchar *)"a_texcoord"); GLuint mtxModelView = glGetUniformLocation(_prgid[PG_NORMAL],(const GLchar *)"u_mvpMatrix"); GLuint mtxTexture = glGetUniformLocation(_prgid[PG_NORMAL],(const GLchar *)"u_texMatrix"); GLfloat vec[]={ 0.0f,0.0f,-0.5f, 100.0f, 0.0f,-0.5f,100.0f,100.0f,-0.5f, 0.0f,0.0f,-0.5f, 100.0f,100.0f,-0.5f, 0.0f,100.0f,-0.5f }; /* GLfloat vec[]={ 0.0f,0.0f,-0.5f, -1.0f,1.0f,-0.5f, 1.0f,1.0f,-0.5f, 0.0f,0.0f,-0.5f, -1.0f,-1.0f,-0.5f, 1.0f,-1.0f,-0.5f, }; */ GLfloat tex[]={ 0.0f,0.0f, 2048.0f,0.0f,2048.0f,1024.0f,0.0f,0.0f,2048.0f,1024.0f,0.0f,1024.0f }; // GLfloat tex[]={ 0.0f,0.0f,1.0f,0.0f,1.0f,1.0f, // 0.0f,0.0f,1.0f,1.0f,0.0f,1.0f }; YglMatrix mtx; YglMatrix mtxt; GLuint id = glGetUniformLocation(_prgid[PG_NORMAL], (const GLchar *)"s_texture"); YglLoadIdentity(&mtx); YglLoadIdentity(&mtxt); YglOrtho(&mtx,0.0f,100.0f,100.0f,0.0f,1.0f,0.0f); glUseProgram(_prgid[PG_NORMAL]); glUniform1i(id, 0); glEnableVertexAttribArray(vertexp); glEnableVertexAttribArray(texcoordp); glUniformMatrix4fv( mtxModelView, 1, GL_FALSE, (GLfloat*) &_Ygl->mtxModelView/*mtx*/.m[0][0] ); glVertexAttribPointer(vertexp,3, GL_FLOAT,GL_FALSE, 0, (const GLvoid*) vec ); glVertexAttribPointer(texcoordp,2, GL_FLOAT,GL_FALSE, 0, (const GLvoid*)tex ); glDrawArrays(GL_TRIANGLES, 0, 6); return 0; } /*------------------------------------------------------------------------------------ * Window Operation * ----------------------------------------------------------------------------------*/ const GLchar Yglprg_window_v[] = #if defined(_OGLES3_) "#version 300 es \n" #else "#version 330 \n" #endif "uniform mat4 u_mvpMatrix; \n" "layout (location = 0) in vec4 a_position; \n" "void main() \n" "{ \n" " gl_Position = a_position*u_mvpMatrix; \n" "} "; const GLchar * pYglprg_window_v[] = {Yglprg_window_v, NULL}; const GLchar Yglprg_window_f[] = #if defined(_OGLES3_) "#version 300 es \n" #else "#version 330 \n" #endif "precision highp float; \n" "out vec4 fragColor; \n" "void main() \n" "{ \n" " fragColor = vec4( 1.0,1.0,1.0,1.0 );\n" "} \n"; const GLchar * pYglprg_window_f[] = {Yglprg_window_f, NULL}; int Ygl_uniformWindow(void * p ) { YglProgram * prg; prg = p; glUseProgram(prg->prgid ); glUniform1i(prg->tex0, 0); glEnableVertexAttribArray(0); glDisableVertexAttribArray(1); glDisableVertexAttribArray(2); return 0; } int Ygl_cleanupWindow(void * p ) { YglProgram * prg; prg = p; return 0; } /*------------------------------------------------------------------------------------ * VDP1 Normal Draw * ----------------------------------------------------------------------------------*/ const GLchar Yglprg_vdp1_normal_v[] = #if defined(_OGLES3_) "#version 300 es \n" #else "#version 330 \n" #endif "uniform mat4 u_mvpMatrix; \n" "layout (location = 0) in vec4 a_position; \n" "layout (location = 1) in vec4 a_texcoord; \n" "out vec4 v_texcoord; \n" "void main() \n" "{ \n" " gl_Position = a_position*u_mvpMatrix; \n" " v_texcoord = a_texcoord; \n" " v_texcoord.s = v_texcoord.s/2048.0; \n" " v_texcoord.t = v_texcoord.t/1024.0; \n" "} "; const GLchar * pYglprg_vdp1_normal_v[] = {Yglprg_vdp1_normal_v, NULL}; const GLchar Yglprg_vpd1_normal_f[] = #if defined(_OGLES3_) "#version 300 es \n" #else "#version 330 \n" #endif "precision highp float; \n" "in vec4 v_texcoord; \n" "uniform sampler2D s_texture; \n" "out vec4 fragColor; \n" "void main() \n" "{ \n" " vec2 addr = v_texcoord.st; \n" " addr.s = addr.s / (v_texcoord.q); \n" " addr.t = addr.t / (v_texcoord.q); \n" " vec4 FragColor = texture( s_texture, addr ); \n" " /*if( FragColor.a == 0.0 ) discard;*/ \n" " fragColor = FragColor;\n " "} \n"; const GLchar * pYglprg_vdp1_normal_f[] = {Yglprg_vpd1_normal_f, NULL}; static int id_vdp1_normal_s_texture = -1; int Ygl_uniformVdp1Normal(void * p ) { YglProgram * prg; prg = p; glEnableVertexAttribArray(prg->vertexp); glEnableVertexAttribArray(prg->texcoordp); glUniform1i(id_vdp1_normal_s_texture, 0); return 0; } int Ygl_cleanupVdp1Normal(void * p ) { YglProgram * prg; prg = p; return 0; } /*------------------------------------------------------------------------------------ * VDP1 GlowShading Operation * ----------------------------------------------------------------------------------*/ const GLchar Yglprg_vdp1_gouraudshading_v[] = #if defined(_OGLES3_) "#version 300 es \n" #else "#version 330 \n" #endif "uniform mat4 u_mvpMatrix; \n" "uniform mat4 u_texMatrix; \n" "layout (location = 0) in vec4 a_position; \n" "layout (location = 1) in vec4 a_texcoord; \n" "layout (location = 2) in vec4 a_grcolor; \n" "out vec4 v_texcoord; \n" "out vec4 v_vtxcolor; \n" "void main() { \n" " v_vtxcolor = a_grcolor; \n" " v_texcoord = a_texcoord/*u_texMatrix*/; \n" " v_texcoord.s = v_texcoord.s/2048.0; \n" " v_texcoord.t = v_texcoord.t/1024.0; \n" " gl_Position = a_position*u_mvpMatrix; \n" "}\n"; const GLchar * pYglprg_vdp1_gouraudshading_v[] = {Yglprg_vdp1_gouraudshading_v, NULL}; const GLchar Yglprg_vdp1_gouraudshading_f[] = #if defined(_OGLES3_) "#version 300 es \n" #else "#version 330 \n" #endif "precision highp float; \n" "uniform sampler2D u_sprite; \n" "in vec4 v_texcoord; \n" "in vec4 v_vtxcolor; \n" "out vec4 fragColor; \n" "void main() { \n" " vec2 addr = v_texcoord.st; \n" " addr.s = addr.s / (v_texcoord.q); \n" " addr.t = addr.t / (v_texcoord.q); \n" " vec4 spriteColor = texture(u_sprite,addr); \n" " if( spriteColor.a == 0.0 ) discard; \n" " fragColor = spriteColor; \n" " fragColor = clamp(spriteColor+v_vtxcolor,vec4(0.0),vec4(1.0)); \n" " fragColor.a = spriteColor.a; \n" "}\n"; const GLchar * pYglprg_vdp1_gouraudshading_f[] = {Yglprg_vdp1_gouraudshading_f, NULL}; static int id_vdp1_normal_s_sprite = -1; int Ygl_uniformGlowShading(void * p ) { YglProgram * prg; prg = p; glEnableVertexAttribArray(prg->vertexp); glEnableVertexAttribArray(prg->texcoordp); glUniform1i(id_vdp1_normal_s_sprite, 0); if( prg->vertexAttribute != NULL ) { glEnableVertexAttribArray(prg->vaid); } return 0; } int Ygl_cleanupGlowShading(void * p ) { YglProgram * prg; prg = p; glDisableVertexAttribArray(prg->vaid); return 0; } /*------------------------------------------------------------------------------------ * VDP1 GlowShading and Half Trans Operation * ----------------------------------------------------------------------------------*/ static int id_sprite; static int id_fbo; static int id_fbowidth; static int id_fboheight; const GLchar Yglprg_vdp1_gouraudshading_hf_v[] = #if defined(_OGLES3_) "#version 300 es \n" #else "#version 330 \n" #endif "uniform mat4 u_mvpMatrix; \n" "uniform mat4 u_texMatrix; \n" "layout (location = 0) in vec4 a_position; \n" "layout (location = 1) in vec4 a_texcoord; \n" "layout (location = 2) in vec4 a_grcolor; \n" "out vec4 v_texcoord; \n" "out vec4 v_vtxcolor; \n" "void main() { \n" " v_vtxcolor = a_grcolor; \n" " v_texcoord = a_texcoord/*u_texMatrix*/; \n" " v_texcoord.s = v_texcoord.s/2048.0; \n" " v_texcoord.t = v_texcoord.t/1024.0; \n" " gl_Position = a_position*u_mvpMatrix; \n" "}\n"; const GLchar * pYglprg_vdp1_gouraudshading_hf_v[] = {Yglprg_vdp1_gouraudshading_hf_v, NULL}; const GLchar Yglprg_vdp1_gouraudshading_hf_f[] = #if defined(_OGLES3_) "#version 300 es \n" #else "#version 330 \n" #endif "precision highp float; \n" "uniform sampler2D u_sprite; \n" "uniform sampler2D u_fbo; \n" "uniform int u_fbowidth; \n" "uniform int u_fbohegiht; \n" "in vec4 v_texcoord; \n" "in vec4 v_vtxcolor; \n" "out vec4 fragColor; \n " "void main() { \n" " vec2 addr = v_texcoord.st; \n" " vec2 faddr = vec2( gl_FragCoord.x/float(u_fbowidth), gl_FragCoord.y/float(u_fbohegiht)); \n" " addr.s = addr.s / (v_texcoord.q); \n" " addr.t = addr.t / (v_texcoord.q); \n" " vec4 spriteColor = texture(u_sprite,addr); \n" " if( spriteColor.a == 0.0 ) discard; \n" " vec4 fboColor = texture(u_fbo,faddr); \n" " spriteColor += vec4(v_vtxcolor.r,v_vtxcolor.g,v_vtxcolor.b,0.0); \n" " if( fboColor.a > 0.0 && spriteColor.a > 0.0 ) \n" " { \n" " fragColor = spriteColor*0.5 + fboColor*0.5; \n" " fragColor.a = fboColor.a; \n" " }else{ \n" " fragColor = spriteColor; \n" " } \n" "}\n"; const GLchar * pYglprg_vdp1_gouraudshading_hf_f[] = {Yglprg_vdp1_gouraudshading_hf_f, NULL}; int Ygl_uniformGlowShadingHalfTrans(void * p ) { YglProgram * prg; prg = p; glEnableVertexAttribArray(prg->vertexp); glEnableVertexAttribArray(prg->texcoordp); if( prg->vertexAttribute != NULL ) { glEnableVertexAttribArray(prg->vaid); } glUniform1i(id_sprite, 0); glUniform1i(id_fbo, 1); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D,_Ygl->vdp1FrameBuff[_Ygl->drawframe]); glUniform1i(id_fbowidth, GlWidth); glUniform1i(id_fboheight, GlHeight); glActiveTexture(GL_TEXTURE0); #if !defined(_OGLES3_) glTextureBarrierNV(); #endif return 0; } int Ygl_cleanupGlowShadingHalfTrans(void * p ) { YglProgram * prg; prg = p; glDisableVertexAttribArray(prg->vaid); return 0; } /*------------------------------------------------------------------------------------ * VDP1 Half Trans Operation * ----------------------------------------------------------------------------------*/ static int id_hf_sprite; static int id_hf_fbo; static int id_hf_fbowidth; static int id_hf_fboheight; const GLchar Yglprg_vdp1_halftrans_v[] = #if defined(_OGLES3_) "#version 300 es \n" #else "#version 330 \n" #endif "uniform mat4 u_mvpMatrix; \n" "layout (location = 0) in vec4 a_position; \n" "layout (location = 1) in vec4 a_texcoord; \n" "layout (location = 2) in vec4 a_grcolor; \n" "out vec4 v_texcoord; \n" "out vec4 v_vtxcolor; \n" "void main() { \n" " v_vtxcolor = a_grcolor; \n" " v_texcoord = a_texcoord/*u_texMatrix*/; \n" " v_texcoord.s = v_texcoord.s/2048.0; \n" " v_texcoord.t = v_texcoord.t/1024.0; \n" " gl_Position = a_position*u_mvpMatrix; \n" "}\n"; const GLchar * pYglprg_vdp1_halftrans_v[] = {Yglprg_vdp1_halftrans_v, NULL}; const GLchar Yglprg_vdp1_halftrans_f[] = #if defined(_OGLES3_) "#version 300 es \n" #else "#version 330 \n" #endif "precision highp float; \n" "uniform sampler2D u_sprite; \n" "uniform sampler2D u_fbo; \n" "uniform int u_fbowidth; \n" "uniform int u_fbohegiht; \n" "in vec4 v_texcoord; \n" "out vec4 fragColor; \n " "void main() { \n" " vec2 addr = v_texcoord.st; \n" " vec2 faddr = vec2( gl_FragCoord.x/float(u_fbowidth), gl_FragCoord.y/float(u_fbohegiht)); \n" " addr.s = addr.s / (v_texcoord.q); \n" " addr.t = addr.t / (v_texcoord.q); \n" " vec4 spriteColor = texture(u_sprite,addr); \n" " if( spriteColor.a == 0.0 ) discard; \n" " vec4 fboColor = texture(u_fbo,faddr); \n" " if( fboColor.a > 0.0 && spriteColor.a > 0.0 ) \n" " { \n" " fragColor = spriteColor*0.5 + fboColor*0.5; \n" " fragColor.a = fboColor.a; \n" " }else{ \n" " fragColor = spriteColor; \n" " } \n" "}\n"; const GLchar * pYglprg_vdp1_halftrans_f[] = {Yglprg_vdp1_halftrans_f, NULL}; int Ygl_uniformHalfTrans(void * p ) { YglProgram * prg; prg = p; glEnableVertexAttribArray(prg->vertexp); glEnableVertexAttribArray(prg->texcoordp); glUniform1i(id_hf_sprite, 0); glUniform1i(id_hf_fbo, 1); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D,_Ygl->vdp1FrameBuff[_Ygl->drawframe]); glUniform1i(id_hf_fbowidth, GlWidth); glUniform1i(id_hf_fboheight, GlHeight); glActiveTexture(GL_TEXTURE0); #if !defined(_OGLES3_) glTextureBarrierNV(); #endif return 0; } int Ygl_cleanupHalfTrans(void * p ) { YglProgram * prg; prg = p; return 0; } /*------------------------------------------------------------------------------------ * VDP1 UserClip Operation * ----------------------------------------------------------------------------------*/ int Ygl_uniformStartUserClip(void * p ) { YglProgram * prg; prg = p; glEnableVertexAttribArray(0); glDisableVertexAttribArray(1); if( prg->ux1 != -1 ) { GLint vertices[12]; glColorMask( GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE ); glStencilMask(0xffffffff); glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS,0x1,0x01); glStencilOp(GL_REPLACE,GL_REPLACE,GL_REPLACE); //glDisable(GL_TEXTURE_2D); // render vertices[0] = (int)((float)prg->ux1 * vdp1wratio); vertices[1] = (int)((float)prg->uy1 * vdp1hratio); vertices[2] = (int)((float)(prg->ux2+1) * vdp1wratio); vertices[3] = (int)((float)prg->uy1 * vdp1hratio); vertices[4] = (int)((float)(prg->ux2+1) * vdp1wratio); vertices[5] = (int)((float)(prg->uy2+1) * vdp1hratio); vertices[6] = (int)((float)prg->ux1 * vdp1wratio); vertices[7] = (int)((float)prg->uy1 * vdp1hratio); vertices[8] = (int)((float)(prg->ux2+1) * vdp1wratio); vertices[9] = (int)((float)(prg->uy2+1) * vdp1hratio); vertices[10] = (int)((float)prg->ux1 * vdp1wratio); vertices[11] = (int)((float)(prg->uy2+1) * vdp1hratio); glUniformMatrix4fv( prg->mtxModelView, 1, GL_FALSE, (GLfloat*) &_Ygl->mtxModelView.m[0][0] ); glVertexAttribPointer(prg->vertexp,2, GL_INT,GL_FALSE, 0, (GLvoid*)vertices ); glDrawArrays(GL_TRIANGLES, 0, 6); glColorMask( GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE ); glStencilFunc(GL_ALWAYS,0,0x0); glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP); glDisable(GL_STENCIL_TEST); } glEnable(GL_STENCIL_TEST); glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP); if( prg->uClipMode == 0x02 ) { glStencilFunc(GL_EQUAL,0x1,0xFF); }else if( prg->uClipMode == 0x03 ) { glStencilFunc(GL_EQUAL,0x0,0xFF); }else{ glStencilFunc(GL_ALWAYS,0,0xFF); } glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); //glDisable(GL_STENCIL_TEST); return 0; } int Ygl_cleanupStartUserClip(void * p ){return 0;} int Ygl_uniformEndUserClip(void * p ) { YglProgram * prg; prg = p; glDisable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS,0,0xFF); return 0; } int Ygl_cleanupEndUserClip(void * p ){return 0;} int Ygl_uniformStartVDP2Window(void * p ) { YglProgram * prg; prg = p; glEnable(GL_STENCIL_TEST); glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP); //glEnableVertexAttribArray(0); //glDisableVertexAttribArray(1); if( prg->bwin0 && !prg->bwin1 ) { if( prg->logwin0 ) { glStencilFunc(GL_EQUAL,0x01,0x01); }else{ glStencilFunc(GL_NOTEQUAL,0x01,0x01); } }else if( !prg->bwin0 && prg->bwin1 ) { if( prg->logwin1 ) { glStencilFunc(GL_EQUAL,0x02,0x02); }else{ glStencilFunc(GL_NOTEQUAL,0x02,0x02); } }else if( prg->bwin0 && prg->bwin1 ) { // and if( prg->winmode == 0x0 ) { if (prg->logwin0 == 1 && prg->logwin0 == 1){ glStencilFunc(GL_EQUAL, 0x03, 0x03); } else if (prg->logwin0 == 0 && prg->logwin0 == 0){ glStencilFunc(GL_NOTEQUAL, 0x03, 0x03); }else{ glStencilFunc(GL_ALWAYS, 0, 0xFF); } // OR }else if( prg->winmode == 0x01 ) { if (prg->logwin0 == 1 && prg->logwin0 == 1){ glStencilFunc(GL_LEQUAL, 0x01, 0x03); } else if (prg->logwin0 == 0 && prg->logwin0 == 0){ glStencilFunc(GL_GREATER, 0x01, 0x03); } else{ glStencilFunc(GL_ALWAYS, 0, 0xFF); } } } return 0; } int Ygl_cleanupStartVDP2Window(void * p ){return 0;} int Ygl_uniformEndVDP2Window(void * p ) { YglProgram * prg; prg = p; glDisable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS,0,0xFF); return 0; } int Ygl_cleanupEndVDP2Window(void * p ){return 0;} /*------------------------------------------------------------------------------------ * VDP2 Draw Frame buffer Operation * ----------------------------------------------------------------------------------*/ static int idvdp1FrameBuffer; static int idfrom; static int idto; static int idcoloroffset; const GLchar Yglprg_vdp1_drawfb_v[] = #if defined(_OGLES3_) "#version 300 es \n" #else "#version 330 \n" #endif "uniform mat4 u_mvpMatrix; \n" "layout (location = 0) in vec4 a_position; \n" "layout (location = 1) in vec2 a_texcoord; \n" "out vec2 v_texcoord; \n" "void main() { \n" " v_texcoord = a_texcoord; \n" " gl_Position = a_position*u_mvpMatrix; \n" "}\n"; const GLchar * pYglprg_vdp2_drawfb_v[] = {Yglprg_vdp1_drawfb_v, NULL}; const GLchar Yglprg_vdp2_drawfb_f[] = #if defined(_OGLES3_) "#version 300 es \n" #else "#version 330 \n" #endif "precision highp float;\n" "in vec2 v_texcoord;\n" "uniform sampler2D s_vdp1FrameBuffer;\n" "uniform float u_from;\n" "uniform float u_to;\n" "uniform vec4 u_coloroffset;\n" "out vec4 fragColor;\n" "void main()\n" "{\n" " vec2 addr = v_texcoord;\n" " highp vec4 fbColor = texture(s_vdp1FrameBuffer,addr);\n" " int additional = int(fbColor.a * 255.0);\n" " highp float alpha = float((additional/8)*8)/255.0;\n" " highp float depth = (float(additional&0x07)/10.0) + 0.05;\n" " if( depth < u_from || depth > u_to ){ discard;return;}\n" " if( alpha > 0.0){\n" " fragColor = fbColor;\n" " fragColor += u_coloroffset; \n" " fragColor.a = alpha + 7.0/255.0;\n" " gl_FragDepth = (depth+1.0)/2.0;\n" " } else { \n" " discard;\n" " }\n" "}\n"; const GLchar * pYglprg_vdp2_drawfb_f[] = {Yglprg_vdp2_drawfb_f, NULL}; void Ygl_uniformVDP2DrawFramebuffer( void * p, float from, float to , float * offsetcol ) { YglProgram * prg; prg = p; glUseProgram(_prgid[PG_VDP2_DRAWFRAMEBUFF]); glUniform1i(idvdp1FrameBuffer, 0); glActiveTexture(GL_TEXTURE0); glUniform1f(idfrom,from); glUniform1f(idto,to); glUniform4fv(idcoloroffset,1,offsetcol); glEnableVertexAttribArray(prg->vertexp); glEnableVertexAttribArray(prg->texcoordp); _Ygl->renderfb.mtxModelView = glGetUniformLocation(_prgid[PG_VDP2_DRAWFRAMEBUFF], (const GLchar *)"u_mvpMatrix"); } /*------------------------------------------------------------------------------------ * VDP2 Draw Frame buffer Operation( with Line color insert ) * ----------------------------------------------------------------------------------*/ static int idvdp1FrameBuffer_linecolor; static int idfrom_linecolor; static int idto_linecolor; static int idcoloroffset_linecolor; static int id_fblinecol_s_line; static int id_fblinecol_emu_height; static int id_fblinecol_vheight; const GLchar * pYglprg_vdp2_drawfb_linecolor_v[] = { Yglprg_vdp1_drawfb_v, NULL }; const GLchar Yglprg_vdp2_drawfb_linecolor_f[] = #if defined(_OGLES3_) "#version 300 es \n" #else "#version 330 \n" #endif "precision highp float; \n" "in vec2 v_texcoord; \n" "uniform sampler2D s_vdp1FrameBuffer; \n" "uniform float u_from; \n" "uniform float u_to; \n" "uniform vec4 u_coloroffset; \n" "uniform float u_emu_height; \n" "uniform sampler2D s_line; \n" "uniform float u_vheight; \n" "out vec4 fragColor; \n" "void main() \n" "{ \n" " vec2 addr = v_texcoord; \n" " highp vec4 fbColor = texture(s_vdp1FrameBuffer,addr); \n" " int additional = int(fbColor.a * 255.0); \n" " highp float alpha = float((additional/8)*8)/255.0; \n" " highp float depth = (float(additional&0x07)/10.0) + 0.05; \n" " if( depth < u_from || depth > u_to ){ discard;return;} \n" " ivec2 linepos; \n " " linepos.y = 0; \n " " linepos.x = int((u_vheight - gl_FragCoord.y) * u_emu_height);\n" " vec4 lncol = texelFetch( s_line, linepos,0 ); \n" " if( alpha > 0.0){ \n" " fragColor = fbColor; \n" " fragColor += u_coloroffset; \n" " fragColor += lncol; \n" " fragColor.a = 1.0; \n" " gl_FragDepth = (depth+1.0)/2.0;\n" " } else { \n" " discard;\n" " }\n" "} \n"; const GLchar * pYglprg_vdp2_drawfb_linecolor_f[] = { Yglprg_vdp2_drawfb_linecolor_f, NULL }; void Ygl_uniformVDP2DrawFramebuffer_linecolor(void * p, float from, float to, float * offsetcol) { YglProgram * prg; prg = p; glUseProgram(_prgid[PG_VDP2_DRAWFRAMEBUFF_LINECOLOR]); glUniform1i(idvdp1FrameBuffer_linecolor, 0); glActiveTexture(GL_TEXTURE0); glUniform1f(idfrom_linecolor, from); glUniform1f(idto_linecolor, to); glUniform4fv(idcoloroffset_linecolor, 1, offsetcol); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glUniform1i(id_fblinecol_s_line, 1); glUniform1f(id_fblinecol_emu_height, (float)_Ygl->rheight/(float)_Ygl->height); glUniform1f(id_fblinecol_vheight, (float)_Ygl->height); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, _Ygl->lincolor_tex); glActiveTexture(GL_TEXTURE0); glDisable(GL_BLEND); _Ygl->renderfb.mtxModelView = glGetUniformLocation(_prgid[PG_VDP2_DRAWFRAMEBUFF_LINECOLOR], (const GLchar *)"u_mvpMatrix"); } const GLchar Yglprg_vdp2_drawfb_addcolor_f[] = #if defined(_OGLES3_) "#version 300 es \n" #else "#version 330 \n" #endif "precision highp float;\n" "in vec2 v_texcoord;\n" "uniform sampler2D s_vdp1FrameBuffer;\n" "uniform float u_from;\n" "uniform float u_to;\n" "uniform vec4 u_coloroffset;\n" "out vec4 fragColor;\n" "void main()\n" "{\n" " vec2 addr = v_texcoord;\n" " highp vec4 fbColor = texture(s_vdp1FrameBuffer,addr);\n" " int additional = int(fbColor.a * 255.0);\n" " highp float alpha = float((additional/8)*8)/255.0;\n" " highp float depth = (float(additional&0x07)/10.0) + 0.05;\n" " if( depth < u_from || depth > u_to ){ discard;return;}\n" " if( alpha <= 0.0){\n" " discard;\n" " }else if( alpha >= 0.75){\n" " fragColor = fbColor;\n" " fragColor += u_coloroffset; \n" " fragColor.a = 0.0;\n" " gl_FragDepth = (depth+1.0)/2.0;\n" " }else{\n" " fragColor = fbColor;\n" " fragColor += u_coloroffset;\n" " fragColor.a = 1.0;\n" " gl_FragDepth = (depth+1.0)/2.0;\n" " }\n " "}\n"; const GLchar * pYglprg_vdp2_drawfb_addcolor_f[] = { Yglprg_vdp2_drawfb_addcolor_f, NULL }; /*------------------------------------------------------------------------------------ * VDP2 Draw Frame buffer Operation( with add color operation ) * ----------------------------------------------------------------------------------*/ static int idvdp1FrameBuffer_addcolor; static int idfrom_addcolor; static int idto_addcolor; static int idcoloroffset_addcolor; int Ygl_uniformVDP2DrawFramebuffer_addcolor(void * p, float from, float to, float * offsetcol) { YglProgram * prg; prg = p; glUseProgram(_prgid[PG_VDP2_DRAWFRAMEBUFF_ADDCOLOR]); glUniform1i(idvdp1FrameBuffer_addcolor, 0); glActiveTexture(GL_TEXTURE0); glUniform1f(idfrom_addcolor, from); glUniform1f(idto_addcolor, to); glUniform4fv(idcoloroffset_addcolor, 1, offsetcol); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); _Ygl->renderfb.mtxModelView = glGetUniformLocation(_prgid[PG_VDP2_DRAWFRAMEBUFF_ADDCOLOR], (const GLchar *)"u_mvpMatrix"); glBlendFunc(GL_ONE, GL_SRC_ALPHA); return 0; } int Ygl_cleanupVDP2DrawFramebuffer_addcolor(void * p){ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); return 0; } /*------------------------------------------------------------------------------------ * VDP2 Add Blend operaiotn * ----------------------------------------------------------------------------------*/ int Ygl_uniformAddBlend(void * p ) { glBlendFunc(GL_ONE,GL_ONE); return 0; } int Ygl_cleanupAddBlend(void * p ) { glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); return 0; } /*------------------------------------------------------------------------------------ * 11.3 Line Color Insertion * ----------------------------------------------------------------------------------*/ const GLchar * pYglprg_linecol_v[] = { Yglprg_normal_v, NULL }; const GLchar Yglprg_linecol_f[] = #if defined(_OGLES3_) "#version 300 es \n" #else "#version 330 \n" #endif "precision highp float; \n" "in highp vec4 v_texcoord; \n" "uniform vec4 u_color_offset; \n" "uniform float u_emu_height; \n" "uniform float u_vheight; \n" "uniform sampler2D s_texture; \n" "uniform sampler2D s_line; \n" "out vec4 fragColor; \n" "void main() \n" "{ \n" " ivec2 addr; \n" " addr.x = int(v_texcoord.x); \n" " addr.y = int(v_texcoord.y); \n" " ivec2 linepos; \n " " linepos.y = 0; \n " " linepos.x = int( (u_vheight-gl_FragCoord.y) * u_emu_height);\n" " vec4 txcol = texelFetch( s_texture, addr,0 ); \n" " vec4 lncol = texelFetch( s_line, linepos,0 ); \n" " if(txcol.a > 0.0){\n " " fragColor = txcol+u_color_offset+lncol;\n " " fragColor.a = 1.0;\n " " }else{ \n " " discard;\n " " } \n" "} \n"; const GLchar * pYglprg_linecol_f[] = { Yglprg_linecol_f, NULL }; static int id_linecol_s_texture = -1; static int id_linecol_s_line = -1; static int id_linecol_color_offset = -1; static int id_linecol_emu_height = -1; static int id_linecol_vheight = -1; int Ygl_uniformLinecolorInsert(void * p) { YglProgram * prg; prg = p; glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glUniform1i(id_linecol_s_texture, 0); glUniform1i(id_linecol_s_line, 1); glUniform4fv(id_linecol_color_offset, 1, prg->color_offset_val); glUniform1f(id_linecol_emu_height, (float)_Ygl->rheight / (float)_Ygl->height); glUniform1f(id_linecol_vheight, (float)_Ygl->height); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, _Ygl->lincolor_tex); glActiveTexture(GL_TEXTURE0); glDisable(GL_BLEND); return 0; } int Ygl_cleanupLinecolorInsert(void * p) { YglProgram * prg; prg = p; glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); glEnable(GL_BLEND); return 0; } int YglGetProgramId( int prg ) { return _prgid[prg]; } int YglInitShader( int id, const GLchar * vertex[], const GLchar * frag[] ) { GLint compiled,linked; GLuint vshader; GLuint fshader; _prgid[id] = glCreateProgram(); if (_prgid[id] == 0 ) return -1; vshader = glCreateShader(GL_VERTEX_SHADER); fshader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(vshader, 1, vertex, NULL); glCompileShader(vshader); glGetShaderiv(vshader, GL_COMPILE_STATUS, &compiled); if (compiled == GL_FALSE) { YGLLOG( "Compile error in vertex shader.\n"); Ygl_printShaderError(vshader); _prgid[id] = 0; return -1; } glShaderSource(fshader, 1,frag, NULL); glCompileShader(fshader); glGetShaderiv(fshader, GL_COMPILE_STATUS, &compiled); if (compiled == GL_FALSE) { YGLLOG( "Compile error in fragment shader.\n"); Ygl_printShaderError(fshader); _prgid[id] = 0; return -1; } glAttachShader(_prgid[id], vshader); glAttachShader(_prgid[id], fshader); glLinkProgram(_prgid[id]); glGetProgramiv(_prgid[id], GL_LINK_STATUS, &linked); if (linked == GL_FALSE) { YGLLOG("Link error..\n"); Ygl_printShaderError(_prgid[id]); _prgid[id] = 0; return -1; } return 0; } int YglProgramInit() { YGLLOG("PG_NORMAL\n"); // if( YglInitShader( PG_NORMAL, pYglprg_normal_v, pYglprg_normal_f ) != 0 ) return -1; id_normal_s_texture = glGetUniformLocation(_prgid[PG_NORMAL], (const GLchar *)"s_texture"); // _prgid[PG_VFP1_ENDUSERCLIP] = _prgid[PG_NORMAL]; _prgid[PG_VDP2_ADDBLEND] = _prgid[PG_NORMAL]; YGLLOG("PG_VDP1_NORMAL\n"); // if( YglInitShader( PG_VDP1_NORMAL, pYglprg_vdp1_normal_v, pYglprg_vdp1_normal_f ) != 0 ) return -1; id_vdp1_normal_s_texture = glGetUniformLocation(_prgid[PG_VDP1_NORMAL], (const GLchar *)"s_texture"); YGLLOG("PG_VFP1_GOURAUDSAHDING\n"); // if( YglInitShader( PG_VFP1_GOURAUDSAHDING, pYglprg_vdp1_gouraudshading_v, pYglprg_vdp1_gouraudshading_f ) != 0 ) return -1; id_vdp1_normal_s_sprite = glGetUniformLocation(_prgid[PG_VFP1_GOURAUDSAHDING], (const GLchar *)"u_sprite"); YGLLOG("PG_VDP2_DRAWFRAMEBUFF --START--\n"); // if( YglInitShader( PG_VDP2_DRAWFRAMEBUFF, pYglprg_vdp2_drawfb_v, pYglprg_vdp2_drawfb_f ) != 0 ) return -1; YGLLOG("PG_VDP2_DRAWFRAMEBUFF --END--\n"); idvdp1FrameBuffer = glGetUniformLocation(_prgid[PG_VDP2_DRAWFRAMEBUFF], (const GLchar *)"s_vdp1FrameBuffer"); idfrom = glGetUniformLocation(_prgid[PG_VDP2_DRAWFRAMEBUFF], (const GLchar *)"u_from"); idto = glGetUniformLocation(_prgid[PG_VDP2_DRAWFRAMEBUFF], (const GLchar *)"u_to"); idcoloroffset = glGetUniformLocation(_prgid[PG_VDP2_DRAWFRAMEBUFF], (const GLchar *)"u_coloroffset"); _Ygl->renderfb.prgid=_prgid[PG_VDP2_DRAWFRAMEBUFF]; _Ygl->renderfb.setupUniform = Ygl_uniformNormal; _Ygl->renderfb.cleanupUniform = Ygl_cleanupNormal; _Ygl->renderfb.vertexp = glGetAttribLocation(_prgid[PG_VDP2_DRAWFRAMEBUFF],(const GLchar *)"a_position"); _Ygl->renderfb.texcoordp = glGetAttribLocation(_prgid[PG_VDP2_DRAWFRAMEBUFF],(const GLchar *)"a_texcoord"); _Ygl->renderfb.mtxModelView = glGetUniformLocation(_prgid[PG_VDP2_DRAWFRAMEBUFF],(const GLchar *)"u_mvpMatrix"); YGLLOG("PG_VFP1_HALFTRANS\n"); // if( YglInitShader( PG_VFP1_HALFTRANS, pYglprg_vdp1_halftrans_v, pYglprg_vdp1_halftrans_f ) != 0 ) return -1; id_hf_sprite = glGetUniformLocation(_prgid[PG_VFP1_HALFTRANS], (const GLchar *)"u_sprite"); id_hf_fbo = glGetUniformLocation(_prgid[PG_VFP1_HALFTRANS], (const GLchar *)"u_fbo"); id_hf_fbowidth = glGetUniformLocation(_prgid[PG_VFP1_HALFTRANS], (const GLchar *)"u_fbowidth"); id_hf_fboheight = glGetUniformLocation(_prgid[PG_VFP1_HALFTRANS], (const GLchar *)"u_fbohegiht"); YGLLOG("PG_VFP1_GOURAUDSAHDING_HALFTRANS\n"); if( YglInitShader( PG_VFP1_GOURAUDSAHDING_HALFTRANS, pYglprg_vdp1_gouraudshading_hf_v, pYglprg_vdp1_gouraudshading_hf_f ) != 0 ) return -1; id_sprite = glGetUniformLocation(_prgid[PG_VFP1_GOURAUDSAHDING_HALFTRANS], (const GLchar *)"u_sprite"); id_fbo = glGetUniformLocation(_prgid[PG_VFP1_GOURAUDSAHDING_HALFTRANS], (const GLchar *)"u_fbo"); id_fbowidth = glGetUniformLocation(_prgid[PG_VFP1_GOURAUDSAHDING_HALFTRANS], (const GLchar *)"u_fbowidth"); id_fboheight = glGetUniformLocation(_prgid[PG_VFP1_GOURAUDSAHDING_HALFTRANS], (const GLchar *)"u_fbohegiht"); YGLLOG("PG_WINDOW\n"); // if( YglInitShader( PG_WINDOW, pYglprg_window_v, pYglprg_window_f ) != 0 ) return -1; _Ygl->windowpg.prgid=_prgid[PG_WINDOW]; _Ygl->windowpg.setupUniform = Ygl_uniformNormal; _Ygl->windowpg.cleanupUniform = Ygl_cleanupNormal; _Ygl->windowpg.vertexp = glGetAttribLocation(_prgid[PG_WINDOW],(const GLchar *)"a_position"); _Ygl->windowpg.mtxModelView = glGetUniformLocation(_prgid[PG_WINDOW],(const GLchar *)"u_mvpMatrix"); _prgid[PG_VFP1_STARTUSERCLIP] = _prgid[PG_WINDOW]; YGLLOG("PG_LINECOLOR_INSERT\n"); // if (YglInitShader(PG_LINECOLOR_INSERT, pYglprg_linecol_v, pYglprg_linecol_f) != 0) return -1; id_linecol_s_texture = glGetUniformLocation(_prgid[PG_LINECOLOR_INSERT], (const GLchar *)"s_texture"); id_linecol_s_line = glGetUniformLocation(_prgid[PG_LINECOLOR_INSERT], (const GLchar *)"s_line"); id_linecol_color_offset = glGetUniformLocation(_prgid[PG_LINECOLOR_INSERT], (const GLchar *)"u_color_offset"); id_linecol_emu_height = glGetUniformLocation(_prgid[PG_LINECOLOR_INSERT], (const GLchar *)"u_emu_height"); id_linecol_vheight = glGetUniformLocation(_prgid[PG_LINECOLOR_INSERT], (const GLchar *)"u_vheight"); // if (YglInitShader(PG_VDP2_DRAWFRAMEBUFF_LINECOLOR, pYglprg_vdp2_drawfb_linecolor_v, pYglprg_vdp2_drawfb_linecolor_f) != 0) return -1; idvdp1FrameBuffer_linecolor = glGetUniformLocation(_prgid[PG_VDP2_DRAWFRAMEBUFF_LINECOLOR], (const GLchar *)"s_vdp1FrameBuffer");; idfrom_linecolor = glGetUniformLocation(_prgid[PG_VDP2_DRAWFRAMEBUFF_LINECOLOR], (const GLchar *)"u_from"); idto_linecolor = glGetUniformLocation(_prgid[PG_VDP2_DRAWFRAMEBUFF_LINECOLOR], (const GLchar *)"u_to"); idcoloroffset_linecolor = glGetUniformLocation(_prgid[PG_VDP2_DRAWFRAMEBUFF_LINECOLOR], (const GLchar *)"u_coloroffset"); id_fblinecol_s_line = glGetUniformLocation(_prgid[PG_VDP2_DRAWFRAMEBUFF_LINECOLOR], (const GLchar *)"s_line"); id_fblinecol_emu_height = glGetUniformLocation(_prgid[PG_VDP2_DRAWFRAMEBUFF_LINECOLOR], (const GLchar *)"u_emu_height"); id_fblinecol_vheight = glGetUniformLocation(_prgid[PG_LINECOLOR_INSERT], (const GLchar *)"u_vheight"); // if (YglInitShader(PG_VDP2_DRAWFRAMEBUFF_ADDCOLOR, pYglprg_vdp2_drawfb_v, pYglprg_vdp2_drawfb_addcolor_f) != 0) return -1; idvdp1FrameBuffer_addcolor = glGetUniformLocation(_prgid[PG_VDP2_DRAWFRAMEBUFF_ADDCOLOR], (const GLchar *)"s_vdp1FrameBuffer");; idfrom_addcolor = glGetUniformLocation(_prgid[PG_VDP2_DRAWFRAMEBUFF_ADDCOLOR], (const GLchar *)"u_from"); idto_addcolor = glGetUniformLocation(_prgid[PG_VDP2_DRAWFRAMEBUFF_ADDCOLOR], (const GLchar *)"u_to"); idcoloroffset_addcolor = glGetUniformLocation(_prgid[PG_VDP2_DRAWFRAMEBUFF_ADDCOLOR], (const GLchar *)"u_coloroffset"); return 0; } int YglProgramChange( YglLevel * level, int prgid ) { YglProgram* tmp; YglProgram* current; #if USEVBO int maxsize; #endif level->prgcurrent++; if( level->prgcurrent >= level->prgcount) { level->prgcount++; tmp = (YglProgram*)malloc(sizeof(YglProgram)*level->prgcount); if( tmp == NULL ) return -1; memset(tmp,0,sizeof(YglProgram)*level->prgcount); memcpy(tmp,level->prg,sizeof(YglProgram)*(level->prgcount-1)); level->prg = tmp; level->prg[level->prgcurrent].currentQuad = 0; #if USEVBO level->prg[level->prgcurrent].maxQuad = 14692; maxsize = level->prg[level->prgcurrent].maxQuad; if( YglGetVertexBuffer(maxsize, (void**)&level->prg[level->prgcurrent].quads, (void**)&level->prg[level->prgcurrent].textcoords, (void**)&level->prg[level->prgcurrent].vertexAttribute ) != 0 ) { return -1; } if( level->prg[level->prgcurrent].quads == 0 ) { int a=0; } #else level->prg[level->prgcurrent].maxQuad = 12*64; if ((level->prg[level->prgcurrent].quads = (float *) malloc(level->prg[level->prgcurrent].maxQuad * sizeof(float))) == NULL) return -1; if ((level->prg[level->prgcurrent].textcoords = (float *) malloc(level->prg[level->prgcurrent].maxQuad * sizeof(float) * 2)) == NULL) return -1; if ((level->prg[level->prgcurrent].vertexAttribute = (float *) malloc(level->prg[level->prgcurrent].maxQuad * sizeof(float)*2)) == NULL) return -1; #endif } current = &level->prg[level->prgcurrent]; level->prg[level->prgcurrent].prgid=prgid; level->prg[level->prgcurrent].prg=_prgid[prgid]; level->prg[level->prgcurrent].vaid = 0; if( prgid == PG_NORMAL ) { current->setupUniform = Ygl_uniformNormal; current->cleanupUniform = Ygl_cleanupNormal; current->vertexp = 0; current->texcoordp = 1; current->mtxModelView = glGetUniformLocation(_prgid[PG_NORMAL],(const GLchar *)"u_mvpMatrix"); current->mtxTexture = glGetUniformLocation(_prgid[PG_NORMAL],(const GLchar *)"u_texMatrix"); current->color_offset = glGetUniformLocation(_prgid[PG_NORMAL], (const GLchar *)"u_color_offset"); current->tex0 = glGetUniformLocation(_prgid[PG_NORMAL], (const GLchar *)"s_texture"); }else if( prgid == PG_VDP1_NORMAL ) { current->setupUniform = Ygl_uniformVdp1Normal; current->cleanupUniform = Ygl_cleanupVdp1Normal; current->vertexp = 0; current->texcoordp = 1; current->mtxModelView = glGetUniformLocation(_prgid[PG_VDP1_NORMAL],(const GLchar *)"u_mvpMatrix"); current->mtxTexture = glGetUniformLocation(_prgid[PG_VDP1_NORMAL],(const GLchar *)"u_texMatrix"); current->tex0 = glGetUniformLocation(_prgid[PG_VDP1_NORMAL], (const GLchar *)"s_texture"); }else if( prgid == PG_VFP1_GOURAUDSAHDING ) { level->prg[level->prgcurrent].setupUniform = Ygl_uniformGlowShading; level->prg[level->prgcurrent].cleanupUniform = Ygl_cleanupGlowShading; current->vertexp = 0; current->texcoordp = 1; level->prg[level->prgcurrent].vaid = 2; current->mtxModelView = glGetUniformLocation(_prgid[PG_VFP1_GOURAUDSAHDING],(const GLchar *)"u_mvpMatrix"); current->mtxTexture = glGetUniformLocation(_prgid[PG_VFP1_GOURAUDSAHDING],(const GLchar *)"u_texMatrix"); current->tex0 = glGetUniformLocation(_prgid[PG_VFP1_GOURAUDSAHDING], (const GLchar *)"s_texture"); } else if( prgid == PG_VFP1_STARTUSERCLIP ) { level->prg[level->prgcurrent].setupUniform = Ygl_uniformStartUserClip; level->prg[level->prgcurrent].cleanupUniform = Ygl_cleanupStartUserClip; current->vertexp = 0; current->texcoordp = -1; current->mtxModelView = glGetUniformLocation(_prgid[PG_WINDOW],(const GLchar *)"u_mvpMatrix"); current->mtxTexture = -1; //glGetUniformLocation(_prgid[PG_NORMAL],(const GLchar *)"u_texMatrix"); } else if( prgid == PG_VFP1_ENDUSERCLIP ) { level->prg[level->prgcurrent].setupUniform = Ygl_uniformEndUserClip; level->prg[level->prgcurrent].cleanupUniform = Ygl_cleanupEndUserClip; current->vertexp = 0; current->texcoordp = 1; current->mtxModelView = glGetUniformLocation(_prgid[PG_NORMAL],(const GLchar *)"u_mvpMatrix"); current->mtxTexture = glGetUniformLocation(_prgid[PG_NORMAL],(const GLchar *)"u_texMatrix"); current->tex0 = glGetUniformLocation(_prgid[PG_NORMAL], (const GLchar *)"s_texture"); } else if( prgid == PG_VFP1_HALFTRANS ) { level->prg[level->prgcurrent].setupUniform = Ygl_uniformHalfTrans; level->prg[level->prgcurrent].cleanupUniform = Ygl_cleanupHalfTrans; current->vertexp = 0; current->texcoordp = 1; current->mtxModelView = glGetUniformLocation(_prgid[PG_VFP1_HALFTRANS],(const GLchar *)"u_mvpMatrix"); current->mtxTexture = glGetUniformLocation(_prgid[PG_VFP1_HALFTRANS],(const GLchar *)"u_texMatrix"); } else if( prgid == PG_VFP1_GOURAUDSAHDING_HALFTRANS ) { level->prg[level->prgcurrent].setupUniform = Ygl_uniformGlowShadingHalfTrans; level->prg[level->prgcurrent].cleanupUniform = Ygl_cleanupGlowShadingHalfTrans; current->vertexp = 0; current->texcoordp = 1; level->prg[level->prgcurrent].vaid = 2; current->mtxModelView = glGetUniformLocation(_prgid[PG_VFP1_GOURAUDSAHDING_HALFTRANS],(const GLchar *)"u_mvpMatrix"); current->mtxTexture = glGetUniformLocation(_prgid[PG_VFP1_GOURAUDSAHDING_HALFTRANS],(const GLchar *)"u_texMatrix"); }else if( prgid == PG_VDP2_ADDBLEND ) { level->prg[level->prgcurrent].setupUniform = Ygl_uniformAddBlend; level->prg[level->prgcurrent].cleanupUniform = Ygl_cleanupAddBlend; current->vertexp = 0; current->texcoordp = 1; current->mtxModelView = glGetUniformLocation(_prgid[PG_NORMAL],(const GLchar *)"u_mvpMatrix"); current->mtxTexture = glGetUniformLocation(_prgid[PG_NORMAL],(const GLchar *)"u_texMatrix"); }else if( prgid == PG_VDP2_STARTWINDOW ) { level->prg[level->prgcurrent].setupUniform = Ygl_uniformStartVDP2Window; level->prg[level->prgcurrent].cleanupUniform = Ygl_cleanupStartVDP2Window; current->vertexp = 0; current->texcoordp = -1; current->mtxModelView = glGetUniformLocation(_prgid[PG_NORMAL],(const GLchar *)"u_mvpMatrix"); current->mtxTexture = glGetUniformLocation(_prgid[PG_NORMAL],(const GLchar *)"u_texMatrix"); } else if (prgid == PG_VDP2_ENDWINDOW) { level->prg[level->prgcurrent].setupUniform = Ygl_uniformEndVDP2Window; level->prg[level->prgcurrent].cleanupUniform = Ygl_cleanupEndVDP2Window; current->vertexp = 0; current->texcoordp = 1; current->mtxModelView = glGetUniformLocation(_prgid[PG_NORMAL], (const GLchar *)"u_mvpMatrix"); current->mtxTexture = glGetUniformLocation(_prgid[PG_NORMAL], (const GLchar *)"u_texMatrix"); } else if (prgid == PG_LINECOLOR_INSERT) { current->setupUniform = Ygl_uniformLinecolorInsert; current->cleanupUniform = Ygl_cleanupLinecolorInsert; current->vertexp = 0; current->texcoordp = 1; current->mtxModelView = glGetUniformLocation(_prgid[PG_LINECOLOR_INSERT], (const GLchar *)"u_mvpMatrix"); current->mtxTexture = glGetUniformLocation(_prgid[PG_LINECOLOR_INSERT], (const GLchar *)"u_texMatrix"); current->color_offset = glGetUniformLocation(_prgid[PG_LINECOLOR_INSERT], (const GLchar *)"u_color_offset"); current->tex0 = glGetUniformLocation(_prgid[PG_LINECOLOR_INSERT], (const GLchar *)"s_texture"); }else{ level->prg[level->prgcurrent].setupUniform = NULL; level->prg[level->prgcurrent].cleanupUniform = NULL; } return 0; } static int blit_prg = -1; static int u_w; static int u_h; static const char vblit_img[] = #if defined (_OGLES3_) "#version 300 es \n" #else "#version 330 \n" #endif "layout (location = 0) in vec2 a_Position; \n" "layout (location = 1) in vec2 a_Uv; \n" "uniform float u_w; \n" "uniform float u_h; \n" "out vec2 v_Uv; \n" "void main() \n" "{ \n" " gl_Position = vec4((a_Position.x*u_w)-1.0, (a_Position.y*u_h)-1.0, 0.0, 1.0); \n" " v_Uv = a_Uv; \n" "}"; static const char fblit_img[] = #if defined (_OGLES3_) "#version 300 es \n" #else "#version 330 \n" #endif "precision mediump float; \n" "uniform sampler2D u_Src; \n" "in vec2 v_Uv; \n" "out vec4 fragColor; \n" "void main () \n" "{ \n" " vec4 src = texture2D( u_Src, v_Uv ); \n" " fragColor = src; \n" "}\n"; int YglBlitFramebuffer(u32 srcTexture, u32 targetFbo, float w, float h) { float vb[] = { 0, 0, 2.0, 0.0, 2.0, 2.0, 0, 2.0, }; float tb[] = { 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0 }; glBindFramebuffer(GL_FRAMEBUFFER, targetFbo); if (blit_prg == -1){ GLuint vshader; GLuint fshader; GLint compiled, linked; const GLchar * vblit_img_v[] = { vblit_img, NULL }; const GLchar * fblit_img_v[] = { fblit_img, NULL }; blit_prg = glCreateProgram(); if (blit_prg == 0) return -1; glUseProgram(blit_prg); vshader = glCreateShader(GL_VERTEX_SHADER); fshader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(vshader, 1, vblit_img_v, NULL); glCompileShader(vshader); glGetShaderiv(vshader, GL_COMPILE_STATUS, &compiled); if (compiled == GL_FALSE) { YGLLOG("Compile error in vertex shader.\n"); Ygl_printShaderError(vshader); blit_prg = -1; return -1; } glShaderSource(fshader, 1, fblit_img_v, NULL); glCompileShader(fshader); glGetShaderiv(fshader, GL_COMPILE_STATUS, &compiled); if (compiled == GL_FALSE) { YGLLOG("Compile error in fragment shader.\n"); Ygl_printShaderError(fshader); blit_prg = -1; return -1; } glAttachShader(blit_prg, vshader); glAttachShader(blit_prg, fshader); glLinkProgram(blit_prg); glGetProgramiv(blit_prg, GL_LINK_STATUS, &linked); if (linked == GL_FALSE) { YGLLOG("Link error..\n"); Ygl_printShaderError(blit_prg); blit_prg = -1; return -1; } glUniform1i(glGetUniformLocation(blit_prg, "u_Src"), 0); u_w = glGetUniformLocation(blit_prg, "u_w"); u_h = glGetUniformLocation(blit_prg, "u_h"); } else{ glUseProgram(blit_prg); } glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vb); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, tb); glUniform1f(u_w, w); glUniform1f(u_h, h); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, srcTexture); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); // Clean up glActiveTexture(GL_TEXTURE0); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glBindFramebuffer(GL_FRAMEBUFFER, 0); glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); return 0; } #endif yabause-0.9.15/src/runner/000755 001750 001750 00000000000 12757373644 017373 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/runner/CMakeLists.txt000644 001750 001750 00000000740 12755623101 022114 0ustar00guillaumeguillaume000000 000000 project(yabause-runner) cmake_minimum_required(VERSION 2.8) yab_port_start() if ((NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/lodepng/lodepng.h") OR (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/lodepng/lodepng.cpp")) return() endif() include_directories(${PORT_INCLUDE_DIRS}) find_package(Threads) add_executable(yabause-runner yui.cpp) target_link_libraries(yabause-runner yabause ${YABAUSE_LIBRARIES} ${PORT_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) yab_port_success(yabause-runner)yabause-0.9.15/src/runner/yui.cpp000644 001750 001750 00000072532 12757373537 020717 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003 Guillaume Duhamel Copyright 2004-2010 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include extern "C" { #include "../yui.h" #include "../peripheral.h" #include "../cs0.h" #include "../m68kcore.h" #include "../m68kc68k.h" #include "../vidsoft.h" #include "../vdp2.h" #include "../titan/titan.h" #ifdef _MSC_VER #include #endif extern u8 *vdp1backframebuffer; } #include "lodepng/lodepng.h" #include "lodepng/lodepng.cpp" #include #include #include #include #include #define AUTO_TEST_SELECT_ADDRESS 0x7F000 #define AUTO_TEST_STATUS_ADDRESS 0x7F004 #define AUTO_TEST_MESSAGE_ADDRESS 0x7F008 #define AUTO_TEST_MESSAGE_SENT 1 #define AUTO_TEST_MESSAGE_RECEIVED 2 #define VDP2_VRAM 0x25E00000 extern "C" { SH2Interface_struct *SH2CoreList[] = { &SH2Interpreter, NULL }; PerInterface_struct *PERCoreList[] = { &PERDummy, NULL }; CDInterface *CDCoreList[] = { &DummyCD, &ISOCD, NULL }; SoundInterface_struct *SNDCoreList[] = { &SNDDummy, NULL }; VideoInterface_struct *VIDCoreList[] = { &VIDSoft, &VIDDummy, NULL }; M68K_struct * M68KCoreList[] = { &M68KDummy, #ifdef HAVE_C68K &M68KC68K, #endif #ifdef HAVE_Q68 &M68KQ68, #endif NULL }; } struct ConsoleColor { char ansi[12]; int windows; }; struct ConsoleColor text_red = { "\033[22;31m",4 }; struct ConsoleColor text_green = { "\033[22;32m", 2 }; struct ConsoleColor text_white = { "\033[01;37m", 7 }; void set_color(struct ConsoleColor color) { #ifndef _MSC_VER printf("%s", color.ansi); #else HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(hConsole, (WORD)color.windows); #endif } static const char *bios = ""; static int emulate_bios = 0; void YuiErrorMsg(const char *error_text) { printf("\n\nError: %s\n", error_text); printf(" "); } void YuiSwapBuffers(void) { } //add tests that currently don't work in yabause here const char* tests_expected_to_fail[] = { //slave sh2 "SCU Mask Cache Quirk", "Slave VBlank", //scu interrupt "Timer 1 Interrupt", "Pad Interrupt", "Illegal DMA Interrupt", //scu dma "Misaligned DMA transfer", "Indirect DMA transfer", //scu dsp "DSP Execution", "MVI Imm, [d]", "DSP Timing", "Clipping test", NULL }; void read_second_part(char*source, char*dest) { int pos = (int)strlen(source) + 1; sprintf(dest, "%s", Vdp2Ram + AUTO_TEST_MESSAGE_ADDRESS + pos); } void print_basic(char*message) { read_second_part(message, message); printf("%s\n", message); } int find_test_expected_to_fail(char* test_name) { int j = 0; for (j = 0; tests_expected_to_fail[j] != NULL; j++) { if (!strcmp(test_name, tests_expected_to_fail[j])) { return 1; } } return 0; } std::string make_screenshot_filename(std::string test_name, std::string path, int preset) { char preset_str[64] = { 0 }; sprintf(preset_str, "%d", preset); return path + test_name + " " + preset_str + ".png"; } bool do_pixel_test(int x, int y, u32 test_color, u32 correct_color) { if (test_color != correct_color) { set_color(text_red); printf("\nTest color was 0x%08x at x=%d y=%d. 0x%08x was expected.\n", test_color, x, y, correct_color); set_color(text_white); return false; } return true; } bool handle_screenshot(bool write_images, std::string test_name, std::string path, int preset, pixel_t * runner_dispbuffer) { std::string screenshot_filename = make_screenshot_filename(test_name, path, preset); if (write_images) { int width = 0, height = 0; TitanGetResolution(&width, &height); TitanRender(runner_dispbuffer); unsigned error = lodepng::encode(screenshot_filename, (unsigned char*)runner_dispbuffer, width, height); if (error) { printf("error %u: %s\n", error, lodepng_error_text(error)); return false; } else { printf("%s written.\n", screenshot_filename.c_str()); } } else { std::vector correct_image; std::vector correct_image_u32; unsigned correct_width, correct_height; unsigned error = lodepng::decode(correct_image, correct_width, correct_height, screenshot_filename); if (error) { printf("error %u: %s\n", error, lodepng_error_text(error)); return false; } int test_width = 0, test_height = 0; TitanGetResolution(&test_width, &test_height); TitanRender(runner_dispbuffer); bool check_failed = false; if (test_width != correct_width) { printf("Vdp2 width was %d. %d was expected.\n", test_width, correct_width); } if (test_height != correct_height) { printf("Vdp2 height was %d. %d was expected.\n", test_height, correct_height); } correct_image_u32.resize(correct_width*correct_height); int j = 0; for (unsigned int i = 0; i < correct_width*correct_height * 4; i += 4) { correct_image_u32[j] = (correct_image[i + 3] << 24) | (correct_image[i + 2] << 16) | (correct_image[i + 1] << 8) | correct_image[i + 0]; j++; } for (unsigned int y = 0; y < correct_height; y++) { for (unsigned int x = 0; x < correct_width; x++) { u32 correct_color = correct_image_u32[(y * correct_width) + x]; u32 test_color = runner_dispbuffer[(y * correct_width) + x]; bool result = do_pixel_test(x, y, test_color, correct_color); if (!result) return false; } } if (!check_failed) { return true; } } return false; } bool handle_framebuffer(char * stored_test_name, std::string framebuffer_path) { std::string filename = framebuffer_path + stored_test_name + ".bin"; u16 correct_framebuffer[0x20000]; u16 correct_framebuffer_swapped[0x20000]; unsigned int width = 320; unsigned int height = 224; FILE * fp = fopen(filename.c_str(), "rb"); fread(correct_framebuffer, sizeof(u16), 0x20000, fp); fclose(fp); for (int i = 0; i < 0x20000; i++) { correct_framebuffer_swapped[i] = ((correct_framebuffer[i] & 0xff) << 8) | ((correct_framebuffer[i] >> 8) & 0xff); } for (unsigned y = 0; y < height; y++) { for (unsigned x = 0; x < height; x++) { int pos = ((y * 320) + x) * 2; u16 correct_pixel = correct_framebuffer_swapped[((y * 320) + x)]; u16 yabause_pixel = (vdp1backframebuffer[pos+1] << 8) | (vdp1backframebuffer[pos] & 0xff); bool result = do_pixel_test(x, y, yabause_pixel, correct_pixel); if (!result) return false; } } return true; } int go_to_next_test(int ¤t_test, std::string filename, yabauseinit_struct yinit) { current_test++; YabauseDeInit(); if (YabauseInit(&yinit) != 0) return -1; MappedMemoryLoadExec(filename.c_str(), 0); MappedMemoryWriteByteNocache(MSH2, VDP2_VRAM + AUTO_TEST_SELECT_ADDRESS, current_test); return 1; } struct Stats { int regressions; int total_tests; int tests_passed; int expected_failures; struct { int matches; int diffs; int total; }screenshot; }; void do_test_pass(struct Stats & stats, const char * message) { //test was passed set_color(text_green); printf("%s\n", message); set_color(text_white); } void do_test_fail(struct Stats & stats, char* stored_test_name) { //test failed set_color(text_red); if (find_test_expected_to_fail(stored_test_name)) { //test is not a regression printf("FAIL"); set_color(text_green); printf(" (Not a regression)\n"); stats.expected_failures++; } else { //test is a regression printf("FAIL\n"); stats.regressions++; } set_color(text_white); } void do_regression_color(int regressions) { if (regressions > 0) set_color(text_red); else set_color(text_green); } std::string int_to_string(const int input) { std::stringstream s; s << input; return s.str(); } int string_to_int(const std::string input) { int i; std::stringstream s(input); s >> i; return i; } namespace game_testing { struct GameData { std::string name; std::string path; std::vector screenshot_frames; std::vector start_press_frames; }; std::vector game_data; std::string get_screenshot_filename(const std::string current_game, const std::string output_path, int frame_count, bool is_failure) { if(!is_failure) return output_path + current_game + " " + int_to_string(frame_count) + ".png"; else return output_path + current_game + " " + int_to_string(frame_count) + " FAIL" + ".png"; } void lodepng_print_error(unsigned error) { std::cout << "Lodepng error " << error << " " << lodepng_error_text(error) << std::endl; } bool take_screenshot(std::string screenshot_filename, pixel_t * runner_dispbuffer) { int width = 0, height = 0; TitanGetResolution(&width, &height); TitanRender(runner_dispbuffer); unsigned error = lodepng::encode(screenshot_filename, (unsigned char*)runner_dispbuffer, width, height); if (error) { lodepng_print_error(error); return false; } else { std::cout << screenshot_filename << " written." << std::endl; } return true; } bool check_width_height(unsigned correct_width, unsigned correct_height, int test_width, int test_height) { if (test_width != correct_width) { printf("Width was %d. %d was expected.\n", test_width, correct_width); return false; } if (test_height != correct_height) { printf("Height was %d. %d was expected.\n", test_height, correct_height); return false; } return true; } void byte_swap_image( std::vector &correct_image_u32, const std::vector correct_image, const unsigned correct_width, const unsigned correct_height) { int j = 0; for (unsigned int i = 0; i < correct_width*correct_height * 4; i += 4) { correct_image_u32[j] = (correct_image[i + 3] << 24) | (correct_image[i + 2] << 16) | (correct_image[i + 1] << 8) | correct_image[i + 0]; j++; } } bool compare_all_pixels( const std::vector correct_image_u32, const unsigned correct_width, const unsigned correct_height, pixel_t * runner_dispbuffer) { for (unsigned int y = 0; y < correct_height; y++) { for (unsigned int x = 0; x < correct_width; x++) { u32 correct_color = correct_image_u32[(y * correct_width) + x]; u32 test_color = runner_dispbuffer[(y * correct_width) + x]; bool result = do_pixel_test(x, y, test_color, correct_color); if (!result) return false; } } return true; } bool check_screenshot(std::string screenshot_filename, pixel_t * runner_dispbuffer) { std::vector correct_image; std::vector correct_image_u32; unsigned correct_width, correct_height; unsigned error = lodepng::decode(correct_image, correct_width, correct_height, screenshot_filename); if (error) { lodepng_print_error(error); return false; } int test_width = 0, test_height = 0; TitanGetResolution(&test_width, &test_height); TitanRender(runner_dispbuffer); bool check_failed = false; if (!check_width_height(correct_width, correct_height, test_width, test_height)) return false; correct_image_u32.resize(correct_width*correct_height); byte_swap_image(correct_image_u32, correct_image, correct_width, correct_height); if (!compare_all_pixels(correct_image_u32, correct_width, correct_height, runner_dispbuffer)) { return false; } return true; } int init_game(std::string full_path) { yabauseinit_struct yinit = { 0 }; yinit.percoretype = PERCORE_DUMMY; yinit.sh2coretype = SH2CORE_INTERPRETER; yinit.vidcoretype = VIDCORE_SOFT; yinit.m68kcoretype = M68KCORE_C68K; yinit.sndcoretype = SNDCORE_DUMMY; yinit.cdcoretype = CDCORE_ISO; yinit.carttype = CART_NONE; yinit.regionid = REGION_AUTODETECT; yinit.biospath = emulate_bios ? NULL : bios; yinit.cdpath = full_path.c_str(); yinit.buppath = NULL; yinit.mpegpath = NULL; yinit.cartpath = NULL; yinit.frameskip = 0; yinit.videoformattype = VIDEOFORMATTYPE_NTSC; yinit.clocksync = 0; yinit.basetime = 0; yinit.skip_load = 0; yinit.numthreads = 0; yinit.usethreads = 0; YabauseDeInit(); if (YabauseInit(&yinit) != 0) return -1; return 1; } bool load_game_paths(std::string path_filename) { std::ifstream file(path_filename.c_str()); for(int i = 0; i < game_data.size(); i++) { std::string str; if (std::getline(file, str)) { if (game_data.at(i).name == str)//key match { if (std::getline(file, str)) { game_data.at(i).path = str; } else { std::cout << game_data.at(i).name << " didn't have a matching path" << std::endl; return false; } } else { std::cout << "Keys didn't match while loading game paths." << std::endl; std::cout << "Expected: " << game_data.at(i).name << "Found: " << str << std::endl; return false; } } } return true; } std::vector tokenize(std::string input) { std::vector results; char * token = NULL; token = strtok((char*)input.c_str(), " "); results.push_back(std::string(token)); while (token != NULL) { token = strtok(NULL, " "); if (token != NULL) results.push_back(std::string(token)); } return results; } std::vector string_vector_to_int(std::vector input) { std::vector results; for (int i = 0; i < input.size(); i++) { std::string str = input.at(i); results.push_back(string_to_int(str)); } return results; } bool load_game_data(std::string game_data_filename) { std::ifstream file(game_data_filename.c_str()); std::string str; GameData current; for (;;) { if (std::getline(file, str)) { current.name = str; if (std::getline(file, str)) { std::vector screen_vec = tokenize(str); current.screenshot_frames = string_vector_to_int(screen_vec); if (std::getline(file, str)) { std::vector start_vec = tokenize(str); if (start_vec.size() > 0 && start_vec.at(0)[0] != 'n')//check for null current.start_press_frames = string_vector_to_int(start_vec); } else { std::cout << current.name << " didn't have a any start press frames." << std::endl; return false; } } else { std::cout << current.name << " didn't have a any screenshot frames." << std::endl; return false; } game_data.push_back(current); } else break;//finished with the file } return true; } int start(const std::string screenshot_path, const std::string path_filename, std::string game_data_filename, std::string failures_path, bool check_images) { std::cout << "Game testing" << std::endl; if (!load_game_data(game_data_filename)) { std::cout << "Failed to load game paths." << std::endl; return false; } if (!load_game_paths(path_filename)) { std::cout << "Failed to load game paths." << std::endl; return false; } //for (auto current_game_data : game_data) for(int i = 0; i < game_data.size(); i++) { pixel_t * runner_dispbuffer = (pixel_t*)calloc(1, sizeof(pixel_t) * 704 * 512); if (!init_game(game_data.at(i).path)) { std::cout << "Couldn't init game" << std::endl; return 0; } if(check_images) std::cout << "Testing " << game_data.at(i).name << "..." << std::endl; else std::cout << "Generating images for " << game_data.at(i).name << "..." << std::endl; int frame_count = 0; int frame_pos = 0; PerPortReset(); PerPad_struct* pad1 = PerPadAdd(&PORTDATA1); for (;;) { //handle start presses if (game_data.at(i).start_press_frames.size() > 0) { if (frame_count == game_data.at(i).start_press_frames.at(0)) { *pad1->padbits &= 0xF7;//press start game_data.at(i).start_press_frames.erase(game_data.at(i).start_press_frames.begin() + 0); } else *pad1->padbits |= 0x08;//undo press } else *pad1->padbits |= 0x08;//undo press PERCore->HandleEvents(); if (frame_pos >= game_data.at(i).screenshot_frames.size()) break; if (frame_count == game_data.at(i).screenshot_frames.at(frame_pos)) { if (check_images) { std::string screenshot_filename = get_screenshot_filename(game_data.at(i).name, screenshot_path, frame_count, false); if (!check_screenshot(screenshot_filename, runner_dispbuffer)) { std::cout << "Frame " << frame_count << ": FAIL " << std::endl; std::string screenshot_filename_fail = get_screenshot_filename(game_data.at(i).name, failures_path, frame_count, true); take_screenshot(screenshot_filename_fail, runner_dispbuffer);//take a picture of the failure } else { std::cout << "Frame " << frame_count << ": PASS " << std::endl; } } else { std::string screenshot_filename = get_screenshot_filename(game_data.at(i).name, screenshot_path, frame_count, false); take_screenshot(screenshot_filename, runner_dispbuffer); } frame_pos++; } frame_count++; } if (runner_dispbuffer) free(runner_dispbuffer); } return 1; } } namespace yabauseut { int start(std::string yabause_ut_filename, std::string screenshot_path, std::string framebuffer_path, bool check) { struct Stats stats = { 0 }; yabauseinit_struct yinit = { 0 }; int current_test = 0; char stored_test_name[256] = { 0 }; printf("Running tests...\n\n"); yinit.percoretype = PERCORE_DUMMY; yinit.sh2coretype = SH2CORE_INTERPRETER; yinit.vidcoretype = VIDCORE_SOFT; yinit.m68kcoretype = M68KCORE_DUMMY; yinit.sndcoretype = SNDCORE_DUMMY; yinit.cdcoretype = CDCORE_DUMMY; yinit.carttype = CART_NONE; yinit.regionid = REGION_AUTODETECT; yinit.biospath = emulate_bios ? NULL : bios; yinit.cdpath = NULL; yinit.buppath = NULL; yinit.mpegpath = NULL; yinit.cartpath = NULL; yinit.frameskip = 0; yinit.videoformattype = VIDEOFORMATTYPE_NTSC; yinit.clocksync = 0; yinit.basetime = 0; yinit.skip_load = 1; if (YabauseInit(&yinit) != 0) return -1; MappedMemoryLoadExec(yabause_ut_filename.c_str(), 0); MappedMemoryWriteByteNocache(MSH2, VDP2_VRAM + AUTO_TEST_SELECT_ADDRESS, current_test); bool write_images = false; std::string screenshot_filename = ""; int screenshot_preset = 0; bool is_screenshot = false; pixel_t * runner_dispbuffer = (pixel_t*)calloc(1, sizeof(pixel_t) * 704 * 512); for (;;) { int status = 0; //emulate a frame PERCore->HandleEvents(); status = MappedMemoryReadByteNocache(MSH2, VDP2_VRAM + AUTO_TEST_STATUS_ADDRESS); if (status == AUTO_TEST_MESSAGE_SENT) { char message[256] = { 0 }; sprintf(message, "%s", Vdp2Ram + AUTO_TEST_MESSAGE_ADDRESS); if (!strcmp(message, "DEBUG_MESSAGE")) { //print a debug message print_basic(message); } else if (!strcmp(message, "SCREENSHOT")) { stats.screenshot.total++; if (handle_screenshot(write_images, stored_test_name, screenshot_path, screenshot_preset, runner_dispbuffer)) { //screenshot matches if (!write_images) { printf("Preset %-25d ", screenshot_preset); do_test_pass(stats, "Match"); stats.screenshot.matches++; } } else { //doesn't match if (!write_images) { stats.screenshot.diffs++; } } screenshot_preset++; } else if (std::string(message) == "FRAMEBUFFER") { bool result = handle_framebuffer(stored_test_name, framebuffer_path); if (!result) do_test_fail(stats, stored_test_name); stats.total_tests++; } else if (!strcmp(message, "SECTION_START")) { //print the name of the test section print_basic(message); if (std::string(message) == "Vdp2 screenshot tests") { is_screenshot = true; } } else if (!strcmp(message, "SECTION_END")) { //all sub-tests finished, proceed to next main test printf("\n"); YabauseDeInit(); if (YabauseInit(&yinit) != 0) return -1; MappedMemoryLoadExec(yabause_ut_filename.c_str() , 0); MappedMemoryWriteByteNocache(MSH2, VDP2_VRAM + AUTO_TEST_SELECT_ADDRESS, current_test); go_to_next_test(current_test, yabause_ut_filename, yinit); is_screenshot = false; } else if (!strcmp(message, "SUB_TEST_START")) { //keep the test name for checking if it is a regression or not read_second_part(message, stored_test_name); screenshot_preset = 0; if (is_screenshot) printf("\n"); if (!write_images) { if (is_screenshot) { printf("%-32s \n", stored_test_name); } else { printf("%-32s ", stored_test_name); } } if (is_screenshot) { screenshot_filename = make_screenshot_filename(stored_test_name, screenshot_path, screenshot_preset); } } else if (!strcmp(message, "RESULT")) { char result_prefix[64] = { 0 }; read_second_part(message, message); strncpy(result_prefix, message, 4); if (!strcmp(result_prefix, "PASS")) { do_test_pass(stats, "PASS"); stats.tests_passed++; } else if (!strcmp(result_prefix, "FAIL")) { do_test_fail(stats, stored_test_name); } else { printf("Unrecognized result prefix: %s\n", result_prefix); } stats.total_tests++; } else if (!strcmp(message, "ALL_FINISHED")) { //print stats and exit do_regression_color(stats.regressions); printf("%d of %d tests passed. %d regressions. %d failures that are not regressions. \n", stats.tests_passed, stats.total_tests, stats.regressions, stats.expected_failures); do_regression_color(stats.screenshot.diffs); printf("%d of %d screenshots matched. %d did not match. \n", stats.screenshot.matches, stats.screenshot.total, stats.screenshot.diffs); set_color(text_white); break; } else { printf("Unrecognized message type: %s\n", message); } MappedMemoryWriteByteNocache(MSH2, VDP2_VRAM + AUTO_TEST_STATUS_ADDRESS, AUTO_TEST_MESSAGE_RECEIVED); } } return stats.regressions || stats.screenshot.diffs; } } //usage //no spaces in paths allowed, include final / on directories //yabause game check game_data_file path_file screenshot_path fail_path //yabause game dump game_data_file path_file output_path //yabause yabauseut check yabause_ut_binary_path screenshot_path framebuffer_path //yabause yabauseut dump yabause_ut_binary_path output_path int main(int argc, char *argv[]) { int i = 0; std::vector args; while (argv[i] != NULL) { args.push_back(argv[i++]); } if (args.size() < 4) { std::cout << "Not enough command line arguments." << std::endl; return false; } if (args.size() > 7) { std::cout << "Too many command line arguments." << std::endl; std::cout << "Paths cannot have spaces." << std::endl; return false; } if (args.at(1) == "game") { //game mode if (args.at(2) == "check") { //verify images if (args.size() < 7) { std::cout << "Not enough arguments for game checking mode." << std::endl; return false; } std::string game_data_path = args.at(3); std::string path_file = args.at(4); std::string screenshot_path = args.at(5); std::string fail_path = args.at(6); return game_testing::start( screenshot_path, path_file, game_data_path, fail_path, true); } else if (args.at(2) == "dump") { //dump images if (args.size() < 6) { std::cout << "Not enough arguments for game dumping mode." << std::endl; return false; } std::string game_data_path = args.at(3); std::string path_file = args.at(4); std::string screenshot_path = args.at(5); std::string dummy; return game_testing::start( screenshot_path, path_file, game_data_path, dummy, false); } else { std::cout << "Unknown check/dump argment." << std::endl; return false; } } else if (args.at(1) == "yabauseut") { //yabauseut mode if (args.at(2) == "check") { //verify images if (args.size() < 6) { std::cout << "Not enough arguments for yabauseut checking mode." << std::endl; return false; } std::string yabause_ut_filename = args.at(3); std::string screenshot_path = args.at(4); std::string framebuffer_path = args.at(5); return yabauseut::start(yabause_ut_filename, screenshot_path, framebuffer_path, true); } else if (args.at(2) == "dump") { //dump images if (args.size() < 5) { std::cout << "Not enough arguments for yabauseut dumping mode." << std::endl; return false; } std::string yabause_ut_filename = args.at(3); std::string output_path = args.at(4); std::string dummy; return yabauseut::start(yabause_ut_filename, output_path, dummy, true); } else { std::cout << "Unknown check/dump argment." << std::endl; return false; } } else { std::cout << "Unknown mode argument." << std::endl; return false; } }yabause-0.9.15/src/sndsdl.c000755 001750 001750 00000016403 12755623101 017504 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005-2006 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file sndsdl.c \brief SDL sound interface. */ #ifdef HAVE_LIBSDL #include #if defined(__APPLE__) || defined(GEKKO) #ifdef HAVE_LIBSDL2 #include #else #include #endif #else #include "SDL.h" #endif #include "error.h" #include "scsp.h" #include "sndsdl.h" #include "debug.h" static int SNDSDLInit(void); static void SNDSDLDeInit(void); static int SNDSDLReset(void); static int SNDSDLChangeVideoFormat(int vertfreq); static void sdlConvert32uto16s(s32 *srcL, s32 *srcR, s16 *dst, u32 len); static void SNDSDLUpdateAudio(u32 *leftchanbuffer, u32 *rightchanbuffer, u32 num_samples); static u32 SNDSDLGetAudioSpace(void); static void SNDSDLMuteAudio(void); static void SNDSDLUnMuteAudio(void); static void SNDSDLSetVolume(int volume); #ifdef USE_SCSPMIDI int SNDSDLMidiChangePorts(int inport, int outport); u8 SNDSDLMidiIn(int *isdata); int SNDSDLMidiOut(u8 data); #endif SoundInterface_struct SNDSDL = { SNDCORE_SDL, "SDL Sound Interface", SNDSDLInit, SNDSDLDeInit, SNDSDLReset, SNDSDLChangeVideoFormat, SNDSDLUpdateAudio, SNDSDLGetAudioSpace, SNDSDLMuteAudio, SNDSDLUnMuteAudio, SNDSDLSetVolume, #ifdef USE_SCSPMIDI SNDSDLMidiChangePorts, SNDSDLMidiIn, SNDSDLMidiOut #endif }; #define NUMSOUNDBLOCKS 4 static u16 *stereodata16; static u32 soundoffset; static volatile u32 soundpos; static u32 soundlen; static u32 soundbufsize; static SDL_AudioSpec audiofmt; static u8 soundvolume; static int muted = 0; ////////////////////////////////////////////////////////////////////////////// static void MixAudio(UNUSED void *userdata, Uint8 *stream, int len) { int i; Uint8* soundbuf = (Uint8*)stereodata16; // original code for (i = 0; i < len; i++) { if (soundpos >= soundbufsize) soundpos = 0; stream[i] = muted ? audiofmt.silence : soundbuf[soundpos]; soundpos++; } } ////////////////////////////////////////////////////////////////////////////// static int SNDSDLInit(void) { //samples should be a power of 2 according to SDL-doc //so normalize it to the nearest power of 2 here u32 normSamples = 512; #if defined (_MSC_VER) && SDL_VERSION_ATLEAST(2,0,0) SDL_SetMainReady(); #endif SDL_InitSubSystem(SDL_INIT_AUDIO); // if (SDL_InitSubSystem(SDL_INIT_AUDIO) != 0); // return -1; audiofmt.freq = 44100; audiofmt.format = AUDIO_S16SYS; audiofmt.channels = 2; audiofmt.samples = (audiofmt.freq / 60) * 2; audiofmt.callback = MixAudio; audiofmt.userdata = NULL; while (normSamples < audiofmt.samples) normSamples <<= 1; audiofmt.samples = normSamples; soundlen = audiofmt.freq / 60; // 60 for NTSC or 50 for PAL. Initially assume it's going to be NTSC. soundbufsize = soundlen * NUMSOUNDBLOCKS * 2 * 2; soundvolume = SDL_MIX_MAXVOLUME; if (SDL_OpenAudio(&audiofmt, NULL) != 0) { YabSetError(YAB_ERR_SDL, (void *)SDL_GetError()); return -1; } if ((stereodata16 = (u16 *)malloc(soundbufsize)) == NULL) return -1; memset(stereodata16, 0, soundbufsize); soundpos = 0; SDL_PauseAudio(0); return 0; } ////////////////////////////////////////////////////////////////////////////// static void SNDSDLDeInit(void) { SDL_CloseAudio(); if (stereodata16) free(stereodata16); } ////////////////////////////////////////////////////////////////////////////// static int SNDSDLReset(void) { return 0; } ////////////////////////////////////////////////////////////////////////////// static int SNDSDLChangeVideoFormat(int vertfreq) { soundlen = audiofmt.freq / vertfreq; soundbufsize = soundlen * NUMSOUNDBLOCKS * 2 * 2; if (stereodata16) free(stereodata16); if ((stereodata16 = (u16 *)malloc(soundbufsize)) == NULL) return -1; memset(stereodata16, 0, soundbufsize); return 0; } ////////////////////////////////////////////////////////////////////////////// static void sdlConvert32uto16s(s32 *srcL, s32 *srcR, s16 *dst, u32 len) { u32 i; for (i = 0; i < len; i++) { // Left Channel *srcL = ( *srcL *soundvolume ) /SDL_MIX_MAXVOLUME; if (*srcL > 0x7FFF) *dst = 0x7FFF; else if (*srcL < -0x8000) *dst = -0x8000; else *dst = *srcL; srcL++; dst++; // Right Channel *srcR = ( *srcR *soundvolume ) /SDL_MIX_MAXVOLUME; if (*srcR > 0x7FFF) *dst = 0x7FFF; else if (*srcR < -0x8000) *dst = -0x8000; else *dst = *srcR; srcR++; dst++; } } static void SNDSDLUpdateAudio(u32 *leftchanbuffer, u32 *rightchanbuffer, u32 num_samples) { u32 copy1size=0, copy2size=0; SDL_LockAudio(); if ((soundbufsize - soundoffset) < (num_samples * sizeof(s16) * 2)) { copy1size = (soundbufsize - soundoffset); copy2size = (num_samples * sizeof(s16) * 2) - copy1size; } else { copy1size = (num_samples * sizeof(s16) * 2); copy2size = 0; } sdlConvert32uto16s((s32 *)leftchanbuffer, (s32 *)rightchanbuffer, (s16 *)(((u8 *)stereodata16)+soundoffset), copy1size / sizeof(s16) / 2); if (copy2size) sdlConvert32uto16s((s32 *)leftchanbuffer + (copy1size / sizeof(s16) / 2), (s32 *)rightchanbuffer + (copy1size / sizeof(s16) / 2), (s16 *)stereodata16, copy2size / sizeof(s16) / 2); soundoffset += copy1size + copy2size; soundoffset %= soundbufsize; SDL_UnlockAudio(); } ////////////////////////////////////////////////////////////////////////////// static u32 SNDSDLGetAudioSpace(void) { u32 freespace=0; if (soundoffset > soundpos) freespace = soundbufsize - soundoffset + soundpos; else freespace = soundpos - soundoffset; return (freespace / sizeof(s16) / 2); } ////////////////////////////////////////////////////////////////////////////// static void SNDSDLMuteAudio(void) { muted = 1; } ////////////////////////////////////////////////////////////////////////////// static void SNDSDLUnMuteAudio(void) { muted = 0; } ////////////////////////////////////////////////////////////////////////////// static void SNDSDLSetVolume(int volume) { soundvolume = ( (double)SDL_MIX_MAXVOLUME /(double)100 ) *volume; } ////////////////////////////////////////////////////////////////////////////// #ifdef USE_SCSPMIDI int SNDSDLMidiChangePorts(int inport, int outport) { return 0; } ////////////////////////////////////////////////////////////////////////////// u8 SNDSDLMidiIn(int *isdata) { *isdata = 0; return 0; } ////////////////////////////////////////////////////////////////////////////// int SNDSDLMidiOut(u8 data) { return 1; } ////////////////////////////////////////////////////////////////////////////// #endif #endif yabause-0.9.15/src/tsunami/000755 001750 001750 00000000000 12757373644 017542 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/tsunami/Tsunami.h000644 001750 001750 00000021623 12755623101 021317 0ustar00guillaumeguillaume000000 000000 /* ================================================================================ */ /* */ /* ` ` ` */ /* ...... ` ` ` ` ` */ /* ,/////\\\\\ ` ` ` */ /* ,/// `\\\\ ` ` */ /* ,//// , `\\\ */ /* ,/// / ,,`, `\\\\ ` */ /* /// /,,/ ,`,` ` ```` ` */ /* /,, /,/ /,`/ `/`` */ /* \__..._//, ___________ .__ ` */ /* /////// /,..\__ ___/_______ __ ____ _____ _____ |__| */ /* // ,,,, | | / ___/ | \/ \\__ \ / \| | */ /* \_____...., | | \___ \| | / | \/ __ \| Y Y \ | */ /* |____|/____ >____/|___| (____ /__|_| /__| ` */ /* \/ \/ \/ \/ */ /* */ /* ================================================================================ */ /* Tsunami.h Defines the public interface to Tsunami */ /* The MIT License (MIT) Copyright (c) 2014 James A. McCombe Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once /* ================================================================================ */ /* Master enable switch */ /* By disabling here, Tsunami disappears from your software entirely through empty stub macros replacing the real Tsunami APIs */ #ifndef TSUNAMI_ENABLE #define TSUNAMI_ENABLE 1 #endif /* ================================================================================ */ /* Required includes */ #include "TsunamiPrivate.h" /* Constants */ #define TSUNAMI_DEFAULT_LOGSIZE (1 * 1024 * 1024) #ifdef __cplusplus extern "C" { #endif #if TSUNAMI_ENABLE /* ================================================================================ */ /* Public Tsunami API */ /* ================================================================================ */ /* TsunamiInitialise(): Initialises Tsunami's internal context. This must be called before everything else and would typically be placed at the earliest reasonable place in your client application */ void TsunamiInitialise(void); /* TsunamiStartTimeline(): Tsunami allows for multiple "timelines", each time line containing the change in values of variables in your client application over time. This function creates a new timeline If this is called and an existing timeline with the same name is found, that previous timeline will be flushed its VCD file and new empty timeline started with the same name. */ void TsunamiStartTimeline(const char *timeline_name, /* NULL terminate timeline name */ const char *filename, /* Full path to write output VCD file to */ uint32_t log_size_bytes); /* Size in bytes of the internal circular buffer used to log value changes within Tsunami. Use TSUNAMI_DEFAULT_LOGSIZE if you don't care. */ /* TsunamiFlushTimeline(): This causes a timeline to write its internal circular buffer to the file specified on the call to TsunamiStartTimeline(). The timeline remains active after this call. This must be called at least once otherwise the output VCD file will remain empty. You can call this multiple times if you want your application to provide updates to the VCD file over time. */ void TsunamiFlushTimeline(const char *timeline_name); /* TsunamiAdvanceTimeline(): This advances a timeline to the next time increment. When using this function, the time increment doesn't correspond to real-time. */ void TsunamiAdvanceTimeline(const char *timeline_name); /* TsunamiUpdateTimelineToRealtime(): This advances a timeline to the current real-time in microseconds since the timeline was started. This can be useful when using Tsunami for real-time analysis and debugging. */ void TsunamiUpdateTimelineToRealtime(const char *timeline_name); /* ================================================================================ */ /* Timeline value setting macros. These macros update the current value of a named entry in a timeline. These macros have several common arguments: _value_ : 32-bit integer value in your client application. _timeline_name_ : Name of the timeline this value should be recoreded into. _value_name_format : Name of the value. This can use printf() style format strings and be followed by an optional variable length argument list. TsunamiSetValue(): This sets the current value of a named entry in the timeline. The entry will retain this value forever onwards until its changed. TsunamiIncrementValue(): This adds "_increment_" to the existing value of the named entry in the timeline. The entry will retain its value forever onwards until its changed. TsunamiPulseValue(): This sets the current value of a named entry in the timeline. The entry will have this value only for the current time step and will be reset to 0 afterwards. This is useful to indicate that a value exists only the current time step, i.e. perhaps a boolean value indicating that an event occured on that particular timestep. TsunamiSetRange(): This creates a single value in the VCD file with value "_range_". It is useful as a presentation tool in the waveform viewer when viewing signals as analogue curves. This causes the waveform viewer to set the Y axis scale the curve between 0 and "_range_" which can help with certain visualisations. */ #if _WIN32 #define TsunamiSetValue(_value_, _size_, _timeline_name_, _value_name_format_, ...) \ TsunamiSetValue_Base_Internal(0, 0, 0, _value_, _size_, _timeline_name_, _value_name_format_, __VA_ARGS__) #define TsunamiIncrementValue(_increment_, _timeline_name_, _value_name_format_, ...) \ TsunamiSetValue_Base_Internal(1, 0, 0, _increment_, _timeline_name_, _value_name_format_, __VA_ARGS__) #define TsunamiPulseValue(_value_, _size_, _timeline_name_, _value_name_format_, ...) \ TsunamiSetValue_Base_Internal(0, 1, 0, _value_, _size_, _timeline_name_, _value_name_format_, __VA_ARGS__) #define TsunamiSetRange(_range_, _timeline_name_, _value_name_format_, ...) \ TsunamiSetValue_Base_Internal(0, 0, 1, _range_, _timeline_name_, _value_name_format_, __VA_ARGS__) #else #define TsunamiSetValue(_value_, _size_, _timeline_name_, _value_name_format_, args...) \ TsunamiSetValue_Base_Internal(0, 0, 0, _value_, _size_, _timeline_name_, _value_name_format_, ##args) #define TsunamiIncrementValue(_increment_, _timeline_name_, _value_name_format_, args...) \ TsunamiSetValue_Base_Internal(1, 0, 0, _increment_, _timeline_name_, _value_name_format_, ##args) #define TsunamiPulseValue(_value_, _size_, _timeline_name_, _value_name_format_, args...) \ TsunamiSetValue_Base_Internal(0, 1, 0, _value_, _size_, _timeline_name_, _value_name_format_, ##args) #define TsunamiSetRange(_range_, _timeline_name_, _value_name_format_, args...) \ TsunamiSetValue_Base_Internal(0, 0, 1, _range_, _timeline_name_, _value_name_format_, ##args) #endif /* ================================================================================ */ #endif /* TSUNAMI_ENABLE */ #ifdef __cplusplus } #endif yabause-0.9.15/src/tsunami/TsunamiPrivate.h000644 001750 001750 00000012413 12755623101 022647 0ustar00guillaumeguillaume000000 000000 /* TsunamiPrivate.h */ /* The MIT License (MIT) Copyright (c) 2014 James A. McCombe Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #if TSUNAMI_ENABLE /* Required includes */ #include #include #include /* Structure - Internal representation of a variable/signal */ typedef struct _TsunamiVariable { char *full_name; char *node_name; uint32_t full_name_len; uint32_t node_name_len; char uid [16]; int size; uint32_t is_defined; uint32_t is_pulse; uint64_t last_value; uint64_t range; /* Maximum this value can be. If present, this is placed at the end of the trace to allow tools to draw analogue graphs will proper scale. */ struct _TsunamiVariable *next; /* Sibling link */ struct _TsunamiVariable *head; /* Children head */ struct _TsunamiVariable *list_next; /* Overall flat list next pointer */ } TsunamiVariable; /* Structure - Timeline */ typedef struct _TsunamiTimeline TsunamiTimeline; #ifdef __cplusplus extern "C" { #endif /* ================================================================================ */ /* Tsunami Internal APIs */ TsunamiTimeline *TsunamiFindTimeline_Internal(const char *timeline_name); TsunamiVariable *TsunamiFindVariable_Internal(TsunamiTimeline *timeline, const char *name); void TsunamiSetValue_Internal(TsunamiTimeline *timeline, TsunamiVariable *var, uint64_t value); void TsunamiSetRange_Internal(TsunamiTimeline *timeline, TsunamiVariable *var, uint64_t range); #define TsunamiSetValue_Base_Internal2(_inc_, _pulse_, _setrange_, _value_, _size_, _timeline_name_, _variable_name_) \ { \ static TsunamiTimeline *timeline = NULL; \ static TsunamiVariable *var = NULL; \ if (!timeline) \ timeline = TsunamiFindTimeline_Internal((_timeline_name_)); \ if (!timeline) { \ printf("TSUNAMI: Attempted to set value on unknown timeline \"%s\"\n", _timeline_name_); \ } else { \ if (!var) \ var = TsunamiFindVariable_Internal(timeline, (_variable_name_)); \ if (strcmp((_variable_name_), var->full_name)) \ var = TsunamiFindVariable_Internal(timeline, (_variable_name_)); \ if (_inc_) \ TsunamiSetValue_Internal(timeline, var, (var->last_value + (_value_))); \ else if (_setrange_) \ TsunamiSetRange_Internal(timeline, var, (_value_)); \ else { \ TsunamiSetValue_Internal(timeline, var, (uint64_t) (_value_)); \ var->is_pulse = (_pulse_); \ var->size = (_size_); \ } \ } \ } #if _WIN32 #define TsunamiSetValue_Base_Internal(_inc_, _pulse_, _setrange_, _value_, _size_, _timeline_name_, _value_format_, ...) \ { \ static char variable_name [1024]; \ sprintf(variable_name, (_value_format_), __VA_ARGS__); \ TsunamiSetValue_Base_Internal2(_inc_, _pulse_, _setrange_, _value_, _size_, _timeline_name_, variable_name); \ } #else #define TsunamiSetValue_Base_Internal(_inc_, _pulse_, _setrange_, _value_, _size_, _timeline_name_, _value_format_, args...) \ { \ static char variable_name [1024]; \ sprintf(variable_name, (_value_format_), ##args); \ TsunamiSetValue_Base_Internal2(_inc_, _pulse_, _setrange_, _value_, _size_, _timeline_name_, variable_name); \ } #endif /* ================================================================================ */ #ifdef __cplusplus } #endif #else /* TSUNAMI_ENABLE */ #define TsunamiInitialise() ((void)0) #define TsunamiStartTimeline(_t_, _f_, _l_) ((void)0) #define TsunamiFlushTimeline(_t_) ((void)0) #define TsunamiAdvanceTimeline(_t_) ((void)0) #define TsunamiUpdateTimelineToRealtime(_t_) ((void)0) #define TsunamiSetValue(_v_, _t_, _vf_, ...) ((void)0) #define TsunamiIncrementValue(_i_, _t_, _vf_, ...) ((void)0) #define TsunamiPulseValue(_v_, _t_, _vf_, ...) ((void)0) #define TsunamiSetRange(_r_, _t_, _vf_, ...) ((void)0) #endif yabause-0.9.15/src/tsunami/LICENSE000644 001750 001750 00000002072 12755623101 020530 0ustar00guillaumeguillaume000000 000000 The MIT License (MIT) Copyright (c) 2014 James A. McCombe Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.yabause-0.9.15/src/tsunami/Tsunami.c000644 001750 001750 00000043646 12755623101 021323 0ustar00guillaumeguillaume000000 000000 /* Tsunami.c */ /* The MIT License (MIT) Copyright (c) 2014 James A. McCombe Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #if _WIN32 #include #else #include #endif #if _WIN32 #else #include #endif #include "Tsunami.h" #if TSUNAMI_ENABLE /* ================================================================================ */ /* Tsunami Internal Logging */ /* Tsunami maintains a compact internal log of the value changes over time in memory. It stores this in a circular buffer of a user-defined size. This allows for a fixed sliding window of time to be captured. Once the application finishes the timeline, it will dump this internal buffer to a VCD file on disk so that the data can be viewed using external tools. */ typedef enum _TsunamiLogEntryType { TsunamiLogEntryType_NewTime = 0, TsunamiLogEntryType_ChangeValue, } TsunamiLogEntryType; typedef struct _TsunamiLogEntry { TsunamiLogEntryType type; union { struct { uint64_t time; } new_time; struct { TsunamiVariable *var; uint64_t value; } change_value; }; } TsunamiLogEntry; /* ================================================================================ */ /* ================================================================================ */ /* Structure - A Tsunami "timeline" context. */ struct _TsunamiTimeline { char *name; /* Name of the timeline */ char *filename; /* VCD filename to write the timeline to on Finish() */ struct { TsunamiLogEntry *entry; /* Log storage buffer */ uint32_t entry_alloc_count; /* Number of log entries allocated */ uint32_t entry_start_index; /* Start of circular buffer */ uint32_t entry_last_index; /* End of the circular buffer */ uint32_t entry_count; /* Number of active entries */ } log; TsunamiVariable var_root; /* Variables - This is a hierarchy of nodes */ uint64_t starting_usec; /* Microseconds at timeline start */ uint64_t clk; /* Current time slice */ uint32_t next_uid; /* Variable unique ID allocator */ struct _TsunamiTimeline *next; /* Next timeline */ }; /* ================================================================================ */ /* ================================================================================ */ /* Structure - Overall Tsunami context */ typedef struct _TsunamiContext { TsunamiTimeline *timeline_head; uint32_t timeline_count; #if _WIN32 #else pthread_mutex_t mutex; /* TODO: Make this platform specific */ #endif } TsunamiContext; /* Globally defined Tsunami context */ TsunamiContext _tsunami_context; static uint32_t _tsunami_context_is_initialised = 0; /* ================================================================================ */ /* ================================================================================ */ TsunamiLogEntry *TsunamiGetLogWritePtrAndAdvance(TsunamiTimeline *timeline) { TsunamiLogEntry *entry = (timeline->log.entry + timeline->log.entry_last_index); timeline->log.entry_last_index = ((timeline->log.entry_last_index + 1) % timeline->log.entry_alloc_count); if (timeline->log.entry_count == timeline->log.entry_alloc_count) timeline->log.entry_start_index = ((timeline->log.entry_start_index + 1) % timeline->log.entry_alloc_count); else timeline->log.entry_count ++; return entry; } void TsunamiDumpSignals_Traverse(FILE *output_vcd_file, TsunamiTimeline *timeline, TsunamiVariable *var, uint32_t depth) { uint32_t i; while (var) { for (i = 0; i < depth; i ++) fprintf(output_vcd_file, " "); if (var->head) { fprintf(output_vcd_file, "$scope module %s $end\n", var->node_name); } else { fprintf(output_vcd_file, "$var wire %i %s %s [%d:0] $end\n", var->size, var->uid, var->node_name, var->size); } if (var->head) { TsunamiDumpSignals_Traverse(output_vcd_file, timeline, var->head, (depth + 1)); for (i = 0; i < depth; i ++) fprintf(output_vcd_file, " "); fprintf(output_vcd_file, "$upscope $end\n"); } var = var->next; } } void TsunamiDumpRanges_Traverse(FILE *output_vcd_file, TsunamiTimeline *timeline, TsunamiVariable *var, uint32_t depth) { while (var) { if ((!var->head) && (var->range)) { uint32_t i; fprintf(output_vcd_file, "#%llu\n", (unsigned long long) timeline->clk); fprintf(output_vcd_file, "b"); for (i = 0; i < 32; i ++) fprintf(output_vcd_file, "%c", (int) ('0' + ((var->range >> (63 - i)) & 0x1))); fprintf(output_vcd_file, " %s\n", var->uid); } else { TsunamiDumpRanges_Traverse(output_vcd_file, timeline, var->head, (depth + 1)); } var = var->next; } } TsunamiTimeline *TsunamiFindTimeline_Internal(const char *timeline_name) { TsunamiContext *ctx = &_tsunami_context; TsunamiTimeline *timeline = ctx->timeline_head; while (timeline) { if (!strcmp(timeline_name, timeline->name)) return timeline; timeline = timeline->next; } return NULL; } void TsunamiLock_Internal(TsunamiContext *ctx) { #if _WIN32 #else pthread_mutex_lock(&ctx->mutex); #endif } void TsunamiUnlock_Internal(TsunamiContext *ctx) { #if _WIN32 #else pthread_mutex_unlock(&ctx->mutex); #endif } uint64_t TsunamiGetMicroseconds(void) { #if _WIN32 LARGE_INTEGER current; LARGE_INTEGER freq; QueryPerformanceFrequency(&freq); QueryPerformanceCounter(¤t); current.QuadPart *= 1000000; current.QuadPart /= freq.QuadPart; return (uint64_t)current.QuadPart; #else struct timeval t; gettimeofday(&t, NULL); return ((t.tv_sec * 1000000) + t.tv_usec); #endif } void TsunamiTerminateSignalHandler(int signal) { TsunamiContext *ctx = &_tsunami_context; TsunamiTimeline *timeline = ctx->timeline_head; printf("TSUNAMI: Caught signal, flushing all outstanding timelines...\n"); /* Finish all outstanding timelines */ while (timeline) { TsunamiFlushTimeline(timeline->name); timeline = timeline->next; } exit(1); } void TsunamiInitialise(void) { if (!_tsunami_context_is_initialised) { TsunamiContext *ctx = &_tsunami_context; memset(ctx, 0, sizeof(TsunamiContext)); /* Create mutex */ #if _WIN32 #else pthread_mutex_init(&ctx->mutex, NULL); #endif /* Install signal handlers for abnormal application termination */ //signal(SIGHUP, &TsunamiTerminateSignalHandler); //signal(SIGILL, &TsunamiTerminateSignalHandler); signal(SIGABRT, &TsunamiTerminateSignalHandler); signal(SIGFPE, &TsunamiTerminateSignalHandler); //signal(SIGKILL, &TsunamiTerminateSignalHandler); //signal(SIGBUS, &TsunamiTerminateSignalHandler); signal(SIGSEGV, &TsunamiTerminateSignalHandler); signal(SIGTERM, &TsunamiTerminateSignalHandler); signal(SIGINT, &TsunamiTerminateSignalHandler); _tsunami_context_is_initialised = 1; printf("TSUNAMI: Initialised and installed termination signal handlers\n"); } } void TsunamiStartTimeline(const char *timeline_name, const char *filename, uint32_t log_size_bytes) { TsunamiContext *ctx = &_tsunami_context; TsunamiLock_Internal(ctx); { TsunamiTimeline *timeline = TsunamiFindTimeline_Internal(timeline_name); if (timeline) { printf("TSUNAMI: Found existing timeline for \"%s\", flushing its contents and restarting it from scratch\n", timeline_name); TsunamiUnlock_Internal(ctx); TsunamiFlushTimeline(timeline_name); TsunamiLock_Internal(ctx); timeline = NULL; } printf("TSUNAMI: Starting timeline \"%s\", logging into %u byte buffer to be written to VCD file \"%s\"\n", timeline_name, (unsigned int) log_size_bytes, filename); /* Create a new timeline */ timeline = ((TsunamiTimeline *) calloc(sizeof(TsunamiTimeline), 1)); timeline->name = ((char *) malloc(sizeof(char) * (strlen(timeline_name) + 1))); strcpy(timeline->name, timeline_name); timeline->filename = ((char *) malloc(sizeof(char) * (strlen(filename) + 1))); strcpy(timeline->filename, filename); /* Add it to the linked list of timelines */ if (!ctx->timeline_count) { ctx->timeline_head = timeline; } else { timeline->next = ctx->timeline_head; ctx->timeline_head = timeline; } ctx->timeline_count ++; /* Setup the timeline */ timeline->log.entry_alloc_count = (log_size_bytes / sizeof(TsunamiLogEntry)); timeline->log.entry = ((TsunamiLogEntry *) calloc(sizeof(TsunamiLogEntry), timeline->log.entry_alloc_count)); /* Put in a zero timestamp into the change log to start off */ { TsunamiLogEntry *entry = TsunamiGetLogWritePtrAndAdvance(timeline); entry->type = TsunamiLogEntryType_NewTime; entry->new_time.time = 0; } /* Record start microseconds for timeline (used for real-time mode) */ timeline->starting_usec = TsunamiGetMicroseconds(); } TsunamiUnlock_Internal(ctx); } void TsunamiFlushTimeline(const char *timeline_name) { TsunamiContext *ctx = &_tsunami_context; TsunamiLock_Internal(ctx); { TsunamiTimeline *timeline = TsunamiFindTimeline_Internal(timeline_name); if (!timeline) { printf("TSUNAMI: Attempted to flush unknown timeline \"%s\"\n", timeline_name); } else { FILE *output_vcd_file = fopen(timeline->filename, "wb"); if (output_vcd_file) { /* Write a simple timeline */ fprintf(output_vcd_file, "$timescale 1us $end\n"); /* Dump signal hierarchy */ TsunamiDumpSignals_Traverse(output_vcd_file, timeline, timeline->var_root.head, 0); /* Dump change deltas */ { TsunamiLogEntry *entry; uint32_t i, j, k; uint32_t found_first_time = 0; for (i = 0, j = timeline->log.entry_start_index; i < timeline->log.entry_count; i ++) { entry = (timeline->log.entry + j); /* The first entry in the file should be a time stamp so wait for it */ if (!found_first_time && (entry->type != TsunamiLogEntryType_NewTime)) goto skip; switch (entry->type) { case TsunamiLogEntryType_NewTime: fprintf(output_vcd_file, "#%llu\n", (unsigned long long) entry->new_time.time); found_first_time = 1; break; case TsunamiLogEntryType_ChangeValue: fprintf(output_vcd_file, "b"); for (k = 0; k < entry->change_value.var->size; k ++) fprintf(output_vcd_file, "%c", (int) ('0' + ((entry->change_value.value >> ((entry->change_value.var->size -1) - k)) & 0x1))); fprintf(output_vcd_file, " %s\n", entry->change_value.var->uid); break; } skip: j = ((j + 1) % timeline->log.entry_alloc_count); } } /* Dump ranges (for signals which have ranges set) */ TsunamiDumpRanges_Traverse(output_vcd_file, timeline, timeline->var_root.head, 0); fclose(output_vcd_file); printf("TSUNAMI: Flushed timeline \"%s\" and written to VCD file \"%s\"\n", timeline_name, timeline->filename); } else { printf("TSUNAMI: Failed to open VCD file \"%s\" for writing\n", timeline->filename); } } } TsunamiUnlock_Internal(ctx); } void TsunamiAdvanceTimeline_Internal(TsunamiTimeline *timeline) { TsunamiLogEntry *entry = TsunamiGetLogWritePtrAndAdvance(timeline); /* Write a new time token into the log */ entry->type = TsunamiLogEntryType_NewTime; entry->new_time.time = timeline->clk; /* Reset pulse variables */ { TsunamiVariable *var = timeline->var_root.list_next; while (var) { if (var->is_pulse) { TsunamiSetValue_Internal(timeline, var, 0); var->last_value = 0; } var = var->list_next; } } } void TsunamiAdvanceTimeline(const char *timeline_name) { TsunamiTimeline *timeline = TsunamiFindTimeline_Internal(timeline_name); if (!timeline) { printf("TSUNAMI: Attempted to flush unknown timeline \"%s\"\n", timeline_name); return; } /* Advance clock */ timeline->clk ++; TsunamiAdvanceTimeline_Internal(timeline); } void TsunamiUpdateTimelineToRealtime(const char *timeline_name) { TsunamiTimeline *timeline = TsunamiFindTimeline_Internal(timeline_name); if (!timeline) { printf("TSUNAMI: Attempted to flush unknown timeline \"%s\"\n", timeline_name); return; } /* Set the clock to real-time microseconds since timeline start-up */ timeline->clk = (TsunamiGetMicroseconds() - timeline->starting_usec); TsunamiAdvanceTimeline_Internal(timeline); } TsunamiVariable *TsunamiFindVariable_Traverse_Internal(TsunamiTimeline *timeline, const char *name, uint32_t name_len, TsunamiVariable *parent_var) { TsunamiVariable *var; uint32_t i, len; /* A NULL var suggests starting traversal at root */ if (!parent_var) parent_var = &timeline->var_root; /* Extract the name of this scope */ len = name_len; for (i = 0; i < len; i ++) { if (name[i] == '.') break; } len = i; /* Search this level for a matching scope name */ var = parent_var->head; while (var) { if (var->node_name_len == len) { if (!strncmp(name, var->node_name, len)) break; } var = var->next; } /* If we failed to find a match at this level, return NULL since this variable doesn't exist in the tree */ if (!var) return NULL; /* Descend another level if needed */ if (var->head) return TsunamiFindVariable_Traverse_Internal(timeline, (name + len + 1), (name_len - len - 1), var); return var; } TsunamiVariable *TsunamiAddVariable_Internal(TsunamiTimeline *timeline, const char *full_name, uint32_t full_name_len, const char *name, uint32_t name_len, TsunamiVariable *parent_var) { TsunamiVariable *var; uint32_t i, node_name_len, is_leaf = 0; uint32_t uid; /* A NULL var suggests starting traversal at root */ if (!parent_var) parent_var = &timeline->var_root; /* Extract the name of this scope */ node_name_len = name_len; for (i = 0; i < node_name_len; i ++) { if (name[i] == '.') break; } if (i == node_name_len) is_leaf = 1; node_name_len = i; /* Search this level for a matching scope name */ var = parent_var->head; while (var) { if (var->node_name_len == node_name_len) { if (!strncmp(name, var->node_name, node_name_len)) break; } var = var->next; } /* If we failed to find a match at this level, create this scope and continue descent */ if (!var) { /* Create a new variable */ var = ((TsunamiVariable *) calloc(sizeof(TsunamiVariable), 1)); /* Assign node name of this scope */ var->node_name = ((char *) calloc(sizeof(char), (node_name_len + 1))); strncpy(var->node_name, name, node_name_len); var->node_name_len = node_name_len; /* If its a leaf, assign the actual attributes of the variable */ if (is_leaf) { /* Assign full name */ var->full_name = ((char *) calloc(sizeof(char), (full_name_len + 1))); strncpy(var->full_name, full_name, full_name_len); var->full_name_len = full_name_len; /* Assign the type of the signal and initialise the "last" value */ var->last_value = 0; /* Generate a new UID */ uid = timeline->next_uid ++; /* Convert the UID into an ASCII string (upto 5 chars long) */ for (i = 0; i < 5; i ++) { var->uid[i] = ((uid >> (i * 5) & 0x1f)); if ((i > 0) && (!var->uid[i])) break; var->uid[i] += 65; } var->uid[i] = 0; } /* Add to linked list */ var->next = parent_var->head; parent_var->head = var; if (timeline->var_root.list_next) var->list_next = timeline->var_root.list_next; timeline->var_root.list_next = var; } /* Descend another level if needed */ if (!is_leaf) return TsunamiAddVariable_Internal(timeline, full_name, full_name_len, (name + node_name_len + 1), (name_len - node_name_len - 1), var); return var; } TsunamiVariable *TsunamiFindVariable_Internal(TsunamiTimeline *timeline, const char *name) { TsunamiVariable *var = NULL; uint32_t name_len; /* Find variable */ name_len = (uint32_t) strlen(name); var = TsunamiFindVariable_Traverse_Internal(timeline, name, name_len, NULL); /* Create a new variable, if existing one was not found */ if (!var) var = TsunamiAddVariable_Internal(timeline, name, name_len, name, name_len, NULL); return var; } void TsunamiSetValue_Internal(TsunamiTimeline *timeline, TsunamiVariable *var, uint64_t value) { /* Only write the variable if the data has changed for this signal */ if ((var->last_value != value) || (!var->is_defined)) { TsunamiLogEntry *entry = TsunamiGetLogWritePtrAndAdvance(timeline); entry->type = TsunamiLogEntryType_ChangeValue; entry->change_value.var = var; entry->change_value.value = value; var->last_value = value; var->is_defined = 1; } } void TsunamiSetRange_Internal(TsunamiTimeline *timeline, TsunamiVariable *var, uint64_t range) { var->range = range; } #endif /* TSUNAMI_ENABLE */ yabause-0.9.15/src/tsunami/README.md000644 001750 001750 00000000470 12755623101 021002 0ustar00guillaumeguillaume000000 000000 Tsunami ======= Tsunami is a visualisation tool for software state machines over time. It enables hardware wave viewing software to be easily attached to your software to open up a new type of temporal visualisation for certain types of software problems. Read the github Wiki for more detailed information. yabause-0.9.15/src/tsunami/yab_tsunami.c000644 001750 001750 00000003107 12755623101 022202 0ustar00guillaumeguillaume000000 000000 /* Copyright 2016 James Laird-Wah This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file yab_tsunami.c \brief Yabause Tsunami library integration */ #include "Tsunami.h" #define TSUNAMI_FILENAME "c:/yabause/cdb.vcd" void tsunami_init(void) { TsunamiInitialise(); TsunamiStartTimeline("CDB", TSUNAMI_FILENAME, 1048576 * 512); } void tsunami_log_value(char * name, int value, int size) { TsunamiUpdateTimelineToRealtime("CDB"); TsunamiSetValue(value, size, "CDB", "root.%s", name); } void tsunami_log_pulse(char * name, int value) { TsunamiUpdateTimelineToRealtime("CDB"); TsunamiPulseValue(value, 1, "CDB", "root.%s", name); } void tsunami_flush() { TsunamiFlushTimeline("CDB"); } void tsunami_init_dummy(void) { } void tsunami_log_value_dummy(char * name, int value, int size) { } void tsunami_log_pulse_dummy(char * name, int value) { } void tsunami_flush_dummy() {}yabause-0.9.15/src/tsunami/yab_tsunami.h000644 001750 001750 00000002651 12755623101 022212 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2005 Guillaume Duhamel Copyright 2005 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef YAB_TSUNAMI_H #define YAB_TSUNAMI_H //#define ENABLE_TSUNAMI void tsunami_init_dummy(void); void tsunami_log_value_dummy(char * name, int value, int size); void tsunami_log_pulse_dummy(char * name, int value); void tsunami_flush_dummy(); #ifdef ENABLE_TSUNAMI void tsunami_init(void); void tsunami_log_value(char * name, int value, int size); void tsunami_log_pulse(char * name, int value); void tsunami_flush(); #else #define tsunami_init tsunami_init_dummy #define tsunami_log_value tsunami_log_value_dummy #define tsunami_log_pulse tsunami_log_pulse_dummy #define tsunami_flush tsunami_flush_dummy #endif #endif yabause-0.9.15/src/yabause.h000644 001750 001750 00000006325 12757373537 017673 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2005 Guillaume Duhamel Copyright 2004-2006 Theo Berkau Copyright 2006 Anders Montonen This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef YABAUSE_H #define YABAUSE_H #include "core.h" #include "sh2core.h" typedef struct { int percoretype; int sh1coretype; int sh2coretype; int vidcoretype; int sndcoretype; int m68kcoretype; int cdcoretype; int carttype; u8 regionid; const char *biospath; const char *cdpath; const char *ssfpath; const char *buppath; const char *mpegpath; const char *cartpath; const char *modemip; const char *modemport; const char *sh1rompath; int videoformattype; int frameskip; int clocksync; // 1 = sync internal clock to emulation, 0 = realtime clock u32 basetime; // Initial time in clocksync mode (0 = start w/ system time) int usethreads; int numthreads; int osdcoretype; int skip_load;//skip loading in YabauseInit so tests can be run without a bios int play_ssf; int use_new_scsp; int use_cd_block_lle; int use_sh2_dma_timing; int use_scu_dma_timing; int sh2_cache_enabled; } yabauseinit_struct; #define CLKTYPE_26MHZ 0 #define CLKTYPE_28MHZ 1 #define VIDEOFORMATTYPE_NTSC 0 #define VIDEOFORMATTYPE_PAL 1 #ifndef NO_CLI void print_usage(const char *program_name); #endif void YabauseChangeTiming(int freqtype); int YabauseInit(yabauseinit_struct *init); void YabFlushBackups(void); void YabauseDeInit(void); void YabauseSetDecilineMode(int on); void YabauseResetNoLoad(void); void YabauseReset(void); void YabauseResetButton(void); int YabauseExec(void); void YabauseStartSlave(void); void YabauseStopSlave(void); u64 YabauseGetTicks(void); void YabauseSetVideoFormat(int type); void YabauseSpeedySetup(void); int YabauseQuickLoadGame(void); #define YABSYS_TIMING_BITS 20 #define YABSYS_TIMING_MASK ((1 << YABSYS_TIMING_BITS) - 1) typedef struct { int DecilineMode; int DecilineCount; int LineCount; int VBlankLineCount; int MaxLineCount; u32 DecilineStop; // Fixed point u32 SH2CycleFrac; // Fixed point u32 DecilineUsec; // Fixed point u32 UsecFrac; // Fixed point int CurSH2FreqType; int IsPal; u8 UseThreads; int NumThreads; u8 IsSSH2Running; u64 OneFrameTime; u64 tickfreq; int emulatebios; int usequickload; int playing_ssf; int use_cd_block_lle; int use_sh2_dma_timing; int use_scu_dma_timing; int sh2_cache_enabled; } yabsys_struct; extern yabsys_struct yabsys; int YabauseEmulate(void); #endif yabause-0.9.15/src/permacjoy.h000644 001750 001750 00000001655 12755623101 020213 0ustar00guillaumeguillaume000000 000000 /* Copyright 2009 Lawrence Sebald This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef PERMACJOY_H #define PERMACJOY_H #include "peripheral.h" #define PERCORE_MACJOY 5 extern PerInterface_struct PERMacJoy; #endif /* !PERMACJOY_H */ yabause-0.9.15/src/memory.c000644 001750 001750 00000157213 12755623101 017527 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005 Guillaume Duhamel Copyright 2005-2006 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file memory.c \brief Memory access functions. */ #ifdef PSP // see FIXME in T1MemoryInit() # include #endif #include #include #include #include #include "memory.h" #include "coffelf.h" #include "cs0.h" #include "cs1.h" #include "cs2.h" #include "debug.h" #include "error.h" #include "sh2core.h" #include "scsp.h" #include "scu.h" #include "smpc.h" #include "vdp1.h" #include "vdp2.h" #include "yabause.h" #include "yui.h" #include "movie.h" #include "sh7034.h" #include "ygr.h" #ifdef HAVE_LIBGL #define USE_OPENGL #endif #ifdef USE_OPENGL #include "ygl.h" #endif #include "vidsoft.h" #include "vidogl.h" #ifdef SH2_TRACE #include "sh2trace.h" #endif ////////////////////////////////////////////////////////////////////////////// u8 *SH1Rom; u8 *SH1Dram; u8 *SH1MpegRom; u8 *HighWram; u8 *LowWram; u8 *BiosRom; u8 *BupRam; /* This flag is set to 1 on every write to backup RAM. Ports can freely * check or clear this flag to determine when backup RAM has been written, * e.g. for implementing autosave of backup RAM. */ u8 BupRamWritten; ////////////////////////////////////////////////////////////////////////////// u8 * T1MemoryInit(u32 size) { #ifdef PSP // FIXME: could be ported to all arches, but requires stdint.h // for uintptr_t u8 * base; u8 * mem; if ((base = calloc((size * sizeof(u8)) + sizeof(u8 *) + 64, 1)) == NULL) return NULL; mem = base + sizeof(u8 *); mem = mem + (64 - ((uintptr_t) mem & 63)); *(u8 **)(mem - sizeof(u8 *)) = base; // Save base pointer below memory block return mem; #else return calloc(size, sizeof(u8)); #endif } ////////////////////////////////////////////////////////////////////////////// void T1MemoryDeInit(u8 * mem) { #ifdef PSP if (mem) free(*(u8 **)(mem - sizeof(u8 *))); #else free(mem); #endif } ////////////////////////////////////////////////////////////////////////////// T3Memory * T3MemoryInit(u32 size) { T3Memory * mem; if ((mem = (T3Memory *) calloc(1, sizeof(T3Memory))) == NULL) return NULL; if ((mem->base_mem = (u8 *) calloc(size, sizeof(u8))) == NULL) { free(mem); return NULL; } mem->mem = mem->base_mem + size; return mem; } ////////////////////////////////////////////////////////////////////////////// void T3MemoryDeInit(T3Memory * mem) { free(mem->base_mem); free(mem); } ////////////////////////////////////////////////////////////////////////////// Dummy * DummyInit(UNUSED u32 s) { return NULL; } ////////////////////////////////////////////////////////////////////////////// void DummyDeInit(UNUSED Dummy * d) { } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL UnhandledMemoryReadByte(USED_IF_DEBUG u32 addr) { LOG("Unhandled byte read %08X\n", (unsigned int)addr); return 0; } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL UnhandledMemoryReadWord(USED_IF_DEBUG u32 addr) { LOG("Unhandled word read %08X\n", (unsigned int)addr); return 0; } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL UnhandledMemoryReadLong(USED_IF_DEBUG u32 addr) { LOG("Unhandled long read %08X\n", (unsigned int)addr); return 0; } ////////////////////////////////////////////////////////////////////////////// void FASTCALL UnhandledMemoryWriteByte(USED_IF_DEBUG u32 addr, UNUSED u8 val) { LOG("Unhandled byte write %08X\n", (unsigned int)addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL UnhandledMemoryWriteWord(USED_IF_DEBUG u32 addr, UNUSED u16 val) { LOG("Unhandled word write %08X\n", (unsigned int)addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL UnhandledMemoryWriteLong(USED_IF_DEBUG u32 addr, UNUSED u32 val) { LOG("Unhandled long write %08X\n", (unsigned int)addr); } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL HighWramMemoryReadByte(u32 addr) { return T2ReadByte(HighWram, addr & 0xFFFFF); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL HighWramMemoryReadWord(u32 addr) { return T2ReadWord(HighWram, addr & 0xFFFFF); } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL HighWramMemoryReadLong(u32 addr) { return T2ReadLong(HighWram, addr & 0xFFFFF); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL HighWramMemoryWriteByte(u32 addr, u8 val) { T2WriteByte(HighWram, addr & 0xFFFFF, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL HighWramMemoryWriteWord(u32 addr, u16 val) { T2WriteWord(HighWram, addr & 0xFFFFF, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL HighWramMemoryWriteLong(u32 addr, u32 val) { T2WriteLong(HighWram, addr & 0xFFFFF, val); } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL LowWramMemoryReadByte(u32 addr) { return T2ReadByte(LowWram, addr & 0xFFFFF); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL LowWramMemoryReadWord(u32 addr) { return T2ReadWord(LowWram, addr & 0xFFFFF); } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL LowWramMemoryReadLong(u32 addr) { return T2ReadLong(LowWram, addr & 0xFFFFF); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL LowWramMemoryWriteByte(u32 addr, u8 val) { T2WriteByte(LowWram, addr & 0xFFFFF, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL LowWramMemoryWriteWord(u32 addr, u16 val) { T2WriteWord(LowWram, addr & 0xFFFFF, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL LowWramMemoryWriteLong(u32 addr, u32 val) { T2WriteLong(LowWram, addr & 0xFFFFF, val); } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL BiosRomMemoryReadByte(u32 addr) { return T2ReadByte(BiosRom, addr & 0x7FFFF); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL BiosRomMemoryReadWord(u32 addr) { return T2ReadWord(BiosRom, addr & 0x7FFFF); } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL BiosRomMemoryReadLong(u32 addr) { return T2ReadLong(BiosRom, addr & 0x7FFFF); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL BiosRomMemoryWriteByte(UNUSED u32 addr, UNUSED u8 val) { // read-only } ////////////////////////////////////////////////////////////////////////////// void FASTCALL BiosRomMemoryWriteWord(UNUSED u32 addr, UNUSED u16 val) { // read-only } ////////////////////////////////////////////////////////////////////////////// void FASTCALL BiosRomMemoryWriteLong(UNUSED u32 addr, UNUSED u32 val) { // read-only } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL BupRamMemoryReadByte(u32 addr) { return T1ReadByte(BupRam, addr & 0xFFFF); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL BupRamMemoryReadWord(USED_IF_DEBUG u32 addr) { LOG("bup\t: BackupRam read word - %08X\n", addr); return 0; } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL BupRamMemoryReadLong(USED_IF_DEBUG u32 addr) { LOG("bup\t: BackupRam read long - %08X\n", addr); return 0; } ////////////////////////////////////////////////////////////////////////////// void FASTCALL BupRamMemoryWriteByte(u32 addr, u8 val) { T1WriteByte(BupRam, (addr & 0xFFFF) | 0x1, val); BupRamWritten = 1; } ////////////////////////////////////////////////////////////////////////////// void FASTCALL BupRamMemoryWriteWord(USED_IF_DEBUG u32 addr, UNUSED u16 val) { LOG("bup\t: BackupRam write word - %08X\n", addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL BupRamMemoryWriteLong(USED_IF_DEBUG u32 addr, UNUSED u32 val) { LOG("bup\t: BackupRam write long - %08X\n", addr); } ////////////////////////////////////////////////////////////////////////////// //sh2 specific functions static u8 FASTCALL Sh2UnhandledMemoryReadByte(UNUSED SH2_struct *sh, USED_IF_DEBUG u32 addr) { LOG("Unhandled byte read %08X\n", (unsigned int)addr); return 0; } ////////////////////////////////////////////////////////////////////////////// static u16 FASTCALL Sh2UnhandledMemoryReadWord(UNUSED SH2_struct *sh, USED_IF_DEBUG u32 addr) { LOG("Unhandled word read %08X\n", (unsigned int)addr); return 0; } ////////////////////////////////////////////////////////////////////////////// static u32 FASTCALL Sh2UnhandledMemoryReadLong(UNUSED SH2_struct *sh, USED_IF_DEBUG u32 addr) { LOG("Unhandled long read %08X\n", (unsigned int)addr); return 0; } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL Sh2UnhandledMemoryWriteByte(UNUSED SH2_struct *sh, USED_IF_DEBUG u32 addr, UNUSED u8 val) { LOG("Unhandled byte write %08X\n", (unsigned int)addr); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL Sh2UnhandledMemoryWriteWord(UNUSED SH2_struct *sh, USED_IF_DEBUG u32 addr, UNUSED u16 val) { LOG("Unhandled word write %08X\n", (unsigned int)addr); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL Sh2UnhandledMemoryWriteLong(UNUSED SH2_struct *sh, USED_IF_DEBUG u32 addr, UNUSED u32 val) { LOG("Unhandled long write %08X\n", (unsigned int)addr); } ////////////////////////////////////////////////////////////////////////////// static u8 FASTCALL Sh2HighWramMemoryReadByte(SH2_struct *sh, u32 addr) { return HighWramMemoryReadByte(addr); } ////////////////////////////////////////////////////////////////////////////// static u16 FASTCALL Sh2HighWramMemoryReadWord(SH2_struct *sh, u32 addr) { return HighWramMemoryReadWord(addr); } ////////////////////////////////////////////////////////////////////////////// static u32 FASTCALL Sh2HighWramMemoryReadLong(SH2_struct *sh, u32 addr) { return HighWramMemoryReadLong(addr); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL Sh2HighWramMemoryWriteByte(SH2_struct *sh, u32 addr, u8 val) { HighWramMemoryWriteByte(addr, val); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL Sh2HighWramMemoryWriteWord(SH2_struct *sh, u32 addr, u16 val) { HighWramMemoryWriteWord(addr, val); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL Sh2HighWramMemoryWriteLong(SH2_struct *sh, u32 addr, u32 val) { HighWramMemoryWriteLong(addr, val); } ////////////////////////////////////////////////////////////////////////////// static u8 FASTCALL Sh2LowWramMemoryReadByte(SH2_struct *sh, u32 addr) { return LowWramMemoryReadByte(addr); } ////////////////////////////////////////////////////////////////////////////// static u16 FASTCALL Sh2LowWramMemoryReadWord(SH2_struct *sh, u32 addr) { return LowWramMemoryReadWord(addr); } ////////////////////////////////////////////////////////////////////////////// static u32 FASTCALL Sh2LowWramMemoryReadLong(SH2_struct *sh, u32 addr) { return LowWramMemoryReadLong(addr); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL Sh2LowWramMemoryWriteByte(SH2_struct *sh, u32 addr, u8 val) { LowWramMemoryWriteByte(addr, val); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL Sh2LowWramMemoryWriteWord(SH2_struct *sh, u32 addr, u16 val) { LowWramMemoryWriteWord(addr, val); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL Sh2LowWramMemoryWriteLong(SH2_struct *sh, u32 addr, u32 val) { LowWramMemoryWriteLong(addr, val); } ////////////////////////////////////////////////////////////////////////////// static u8 FASTCALL Sh2BiosRomMemoryReadByte(SH2_struct *sh, u32 addr) { return BiosRomMemoryReadByte(addr); } ////////////////////////////////////////////////////////////////////////////// static u16 FASTCALL Sh2BiosRomMemoryReadWord(SH2_struct *sh, u32 addr) { return BiosRomMemoryReadWord(addr); } ////////////////////////////////////////////////////////////////////////////// static u32 FASTCALL Sh2BiosRomMemoryReadLong(SH2_struct *sh, u32 addr) { return BiosRomMemoryReadLong(addr); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL Sh2BiosRomMemoryWriteByte(UNUSED SH2_struct *sh, UNUSED u32 addr, UNUSED u8 val) { // read-only } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL Sh2BiosRomMemoryWriteWord(UNUSED SH2_struct *sh, UNUSED u32 addr, UNUSED u16 val) { // read-only } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL Sh2BiosRomMemoryWriteLong(UNUSED SH2_struct *sh, UNUSED u32 addr, UNUSED u32 val) { // read-only } ////////////////////////////////////////////////////////////////////////////// static u8 FASTCALL Sh2BupRamMemoryReadByte(SH2_struct *sh, u32 addr) { return BupRamMemoryReadByte(addr); } ////////////////////////////////////////////////////////////////////////////// static u16 FASTCALL Sh2BupRamMemoryReadWord(UNUSED SH2_struct *sh, USED_IF_DEBUG u32 addr) { return BupRamMemoryReadWord(addr);; } ////////////////////////////////////////////////////////////////////////////// static u32 FASTCALL Sh2BupRamMemoryReadLong(UNUSED SH2_struct *sh, USED_IF_DEBUG u32 addr) { return BupRamMemoryReadLong(addr); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL Sh2BupRamMemoryWriteByte(SH2_struct *sh, u32 addr, u8 val) { BupRamMemoryWriteByte(addr, val); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL Sh2BupRamMemoryWriteWord(UNUSED SH2_struct *sh, USED_IF_DEBUG u32 addr, UNUSED u16 val) { BupRamMemoryWriteWord(addr, val); } ////////////////////////////////////////////////////////////////////////////// static void FASTCALL Sh2BupRamMemoryWriteLong(UNUSED SH2_struct *sh, USED_IF_DEBUG u32 addr, UNUSED u32 val) { BupRamMemoryWriteLong(addr, val); } ////////////////////////////////////////////////////////////////////////////// static void FillMemoryArea(SH2_struct *sh, unsigned short start, unsigned short end, readbytefunc r8func, readwordfunc r16func, readlongfunc r32func, writebytefunc w8func, writewordfunc w16func, writelongfunc w32func) { int i; for (i=start; i < (end+1); i++) { sh->ReadByteList[i] = r8func; sh->ReadWordList[i] = r16func; sh->ReadLongList[i] = r32func; sh->WriteByteList[i] = w8func; sh->WriteWordList[i] = w16func; sh->WriteLongList[i] = w32func; } } ////////////////////////////////////////////////////////////////////////////// void MappedMemoryInit(SH2_struct *msh2, SH2_struct *ssh2, SH2_struct *sh1) { SH2_struct *sh2[2] = { msh2, ssh2 }; int i; // MSH2/SSH2 for (i = 0; i < 2; i++) { // Initialize everything to unhandled to begin with FillMemoryArea(sh2[i], 0x000, 0xFFF, &Sh2UnhandledMemoryReadByte, &Sh2UnhandledMemoryReadWord, &Sh2UnhandledMemoryReadLong, &Sh2UnhandledMemoryWriteByte, &Sh2UnhandledMemoryWriteWord, &Sh2UnhandledMemoryWriteLong); // Fill the rest FillMemoryArea(sh2[i], 0x000, 0x00F, &Sh2BiosRomMemoryReadByte, &Sh2BiosRomMemoryReadWord, &Sh2BiosRomMemoryReadLong, &Sh2BiosRomMemoryWriteByte, &Sh2BiosRomMemoryWriteWord, &Sh2BiosRomMemoryWriteLong); FillMemoryArea(sh2[i], 0x010, 0x017, &SmpcReadByte, &SmpcReadWord, &SmpcReadLong, &SmpcWriteByte, &SmpcWriteWord, &SmpcWriteLong); FillMemoryArea(sh2[i], 0x018, 0x01F, &Sh2BupRamMemoryReadByte, &Sh2BupRamMemoryReadWord, &Sh2BupRamMemoryReadLong, &Sh2BupRamMemoryWriteByte, &Sh2BupRamMemoryWriteWord, &Sh2BupRamMemoryWriteLong); FillMemoryArea(sh2[i], 0x020, 0x02F, &Sh2LowWramMemoryReadByte, &Sh2LowWramMemoryReadWord, &Sh2LowWramMemoryReadLong, &Sh2LowWramMemoryWriteByte, &Sh2LowWramMemoryWriteWord, &Sh2LowWramMemoryWriteLong); FillMemoryArea(sh2[i], 0x100, 0x17F, &Sh2UnhandledMemoryReadByte, &Sh2UnhandledMemoryReadWord, &Sh2UnhandledMemoryReadLong, &Sh2UnhandledMemoryWriteByte, &SSH2InputCaptureWriteWord, &Sh2UnhandledMemoryWriteLong); FillMemoryArea(sh2[i], 0x180, 0x1FF, &Sh2UnhandledMemoryReadByte, &Sh2UnhandledMemoryReadWord, &Sh2UnhandledMemoryReadLong, &Sh2UnhandledMemoryWriteByte, &MSH2InputCaptureWriteWord, &Sh2UnhandledMemoryWriteLong); FillMemoryArea(sh2[i], 0x200, 0x3FF, CartridgeArea->Cs0ReadByte, CartridgeArea->Cs0ReadWord, CartridgeArea->Cs0ReadLong, CartridgeArea->Cs0WriteByte, CartridgeArea->Cs0WriteWord, CartridgeArea->Cs0WriteLong); FillMemoryArea(sh2[i], 0x400, 0x4FF, &Cs1ReadByte, &Cs1ReadWord, &Cs1ReadLong, &Cs1WriteByte, &Cs1WriteWord, &Cs1WriteLong); if (yabsys.use_cd_block_lle) { FillMemoryArea(sh2[i], 0x580, 0x58F, &Cs2ReadByte, &sh2_ygr_a_bus_read_word, &sh2_ygr_a_bus_read_long, &Cs2WriteByte, &sh2_ygr_a_bus_write_word, &sh2_ygr_a_bus_write_long); } else { FillMemoryArea(sh2[i], 0x580, 0x58F, &Cs2ReadByte, &Cs2ReadWord, &Cs2ReadLong, &Cs2WriteByte, &Cs2WriteWord, &Cs2WriteLong); } FillMemoryArea(sh2[i], 0x5A0, 0x5AF, &Sh2SoundRamReadByte, &Sh2SoundRamReadWord, &Sh2SoundRamReadLong, &Sh2SoundRamWriteByte, &Sh2SoundRamWriteWord, &Sh2SoundRamWriteLong); FillMemoryArea(sh2[i], 0x5B0, 0x5BF, &Sh2ScspReadByte, &Sh2ScspReadWord, &Sh2ScspReadLong, &Sh2ScspWriteByte, &Sh2ScspWriteWord, &Sh2ScspWriteLong); FillMemoryArea(sh2[i], 0x5C0, 0x5C7, &Sh2Vdp1RamReadByte, &Sh2Vdp1RamReadWord, &Sh2Vdp1RamReadLong, &Sh2Vdp1RamWriteByte, &Sh2Vdp1RamWriteWord, &Sh2Vdp1RamWriteLong); FillMemoryArea(sh2[i], 0x5C8, 0x5CF, &Sh2Vdp1FrameBufferReadByte, &Sh2Vdp1FrameBufferReadWord, &Sh2Vdp1FrameBufferReadLong, &Sh2Vdp1FrameBufferWriteByte, &Sh2Vdp1FrameBufferWriteWord, &Sh2Vdp1FrameBufferWriteLong); FillMemoryArea(sh2[i], 0x5D0, 0x5D7, &Sh2Vdp1ReadByte, &Sh2Vdp1ReadWord, &Sh2Vdp1ReadLong, &Sh2Vdp1WriteByte, &Sh2Vdp1WriteWord, &Sh2Vdp1WriteLong); FillMemoryArea(sh2[i], 0x5E0, 0x5EF, &Sh2Vdp2RamReadByte, &Sh2Vdp2RamReadWord, &Sh2Vdp2RamReadLong, &Sh2Vdp2RamWriteByte, &Sh2Vdp2RamWriteWord, &Sh2Vdp2RamWriteLong); FillMemoryArea(sh2[i], 0x5F0, 0x5F7, &Sh2Vdp2ColorRamReadByte, &Sh2Vdp2ColorRamReadWord, &Sh2Vdp2ColorRamReadLong, &Sh2Vdp2ColorRamWriteByte, &Sh2Vdp2ColorRamWriteWord, &Sh2Vdp2ColorRamWriteLong); FillMemoryArea(sh2[i], 0x5F8, 0x5FB, &Sh2Vdp2ReadByte, &Sh2Vdp2ReadWord, &Sh2Vdp2ReadLong, &Sh2Vdp2WriteByte, &Sh2Vdp2WriteWord, &Sh2Vdp2WriteLong); FillMemoryArea(sh2[i], 0x5FE, 0x5FE, &Sh2ScuReadByte, &Sh2ScuReadWord, &Sh2ScuReadLong, &Sh2ScuWriteByte, &Sh2ScuWriteWord, &Sh2ScuWriteLong); FillMemoryArea(sh2[i], 0x600, 0x7FF, &Sh2HighWramMemoryReadByte, &Sh2HighWramMemoryReadWord, &Sh2HighWramMemoryReadLong, &Sh2HighWramMemoryWriteByte, &Sh2HighWramMemoryWriteWord, &Sh2HighWramMemoryWriteLong); } if (yabsys.use_cd_block_lle) { // SH1 FillMemoryArea(sh1, 0x000, 0xFFF, &Sh2UnhandledMemoryReadByte, &Sh2UnhandledMemoryReadWord, &Sh2UnhandledMemoryReadLong, &Sh2UnhandledMemoryWriteByte, &Sh2UnhandledMemoryWriteWord, &Sh2UnhandledMemoryWriteLong); } } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL MappedMemoryReadByteCacheEnabled(SH2_struct *sh, u32 addr) { return cache_memory_read_b(sh, &sh->onchip.cache, addr); } u8 FASTCALL MappedMemoryReadByteNocache(SH2_struct *sh, u32 addr) { switch (addr >> 29) { case 0x0: case 0x1: case 0x5: { // Cache/Non-Cached return sh->ReadByteList[(addr >> 16) & 0xFFF](sh, addr); } /* case 0x2: { // Purge Area break; } */ case 0x4: case 0x6: // Data Array return DataArrayReadByte(sh, addr); case 0x7: { if (addr >= 0xFFFFFE00) { // Onchip modules addr &= 0x1FF; return OnchipReadByte(sh, addr); } else if (addr >= 0xFFFF8000 && addr < 0xFFFFC000) { // ??? } else { // Garbage data } break; } default: { return Sh2UnhandledMemoryReadByte(sh, addr); } } return 0; } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL MappedMemoryReadWordCacheEnabled(SH2_struct *sh, u32 addr) { return cache_memory_read_w(sh, &sh->onchip.cache, addr); } u16 FASTCALL MappedMemoryReadWordNocache(SH2_struct *sh, u32 addr) { switch (addr >> 29) { case 0x0: case 0x1: case 0x5: { // Cache/Non-Cached return sh->ReadWordList[(addr >> 16) & 0xFFF](sh, addr); } /* case 0x2: { // Purge Area break; } */ case 0x4: case 0x6: // Data Array return DataArrayReadWord(sh, addr); case 0x7: { if (addr >= 0xFFFFFE00) { // Onchip modules addr &= 0x1FF; return OnchipReadWord(sh, addr); } else if (addr >= 0xFFFF8000 && addr < 0xFFFFC000) { // ??? } else { // Garbage data } break; } default: { return Sh2UnhandledMemoryReadWord(sh, addr); } } return 0; } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL MappedMemoryReadLongCacheEnabled(SH2_struct *sh, u32 addr) { return cache_memory_read_l(sh, &sh->onchip.cache, addr); } u32 FASTCALL MappedMemoryReadLongNocache(SH2_struct *sh, u32 addr) { switch (addr >> 29) { case 0x0: case 0x1: case 0x5: { // Cache/Non-Cached return sh->ReadLongList[(addr >> 16) & 0xFFF](sh, addr); } /* case 0x2: { // Purge Area break; } */ case 0x3: { // Address Array return AddressArrayReadLong(sh, addr); } case 0x4: case 0x6: // Data Array return DataArrayReadLong(sh, addr); case 0x7: { if (addr >= 0xFFFFFE00) { // Onchip modules addr &= 0x1FF; return OnchipReadLong(sh, addr); } else if (addr >= 0xFFFF8000 && addr < 0xFFFFC000) { // ??? } else { // Garbage data } break; } default: { return Sh2UnhandledMemoryReadLong(sh, addr); } } return 0; } ////////////////////////////////////////////////////////////////////////////// void FASTCALL MappedMemoryWriteByteCacheEnabled(SH2_struct *sh, u32 addr, u8 val) { #ifdef SH2_TRACE sh2_trace_writeb(addr, val); #endif cache_memory_write_b(sh, &sh->onchip.cache, addr, val); } void FASTCALL MappedMemoryWriteByteNocache(SH2_struct *sh, u32 addr, u8 val) { #ifdef SH2_TRACE sh2_trace_writeb(addr, val); #endif switch (addr >> 29) { case 0x0: case 0x1: case 0x5: { // Cache/Non-Cached sh->WriteByteList[(addr >> 16) & 0xFFF](sh, addr, val); return; } /* case 0x2: { // Purge Area return; } */ case 0x4: case 0x6: // Data Array DataArrayWriteByte(sh, addr, val); return; case 0x7: { if (addr >= 0xFFFFFE00) { // Onchip modules addr &= 0x1FF; OnchipWriteByte(sh, addr, val); return; } else if (addr >= 0xFFFF8000 && addr < 0xFFFFC000) { // ??? } else { // Garbage data } return; } default: { Sh2UnhandledMemoryWriteByte(sh, addr, val); return; } } } ////////////////////////////////////////////////////////////////////////////// void FASTCALL MappedMemoryWriteWordCacheEnabled(SH2_struct *sh, u32 addr, u16 val) { #ifdef SH2_TRACE sh2_trace_writew(addr, val); #endif cache_memory_write_w(sh, &sh->onchip.cache, addr, val); } void FASTCALL MappedMemoryWriteWordNocache(SH2_struct *sh, u32 addr, u16 val) { #ifdef SH2_TRACE sh2_trace_writew(addr, val); #endif switch (addr >> 29) { case 0x0: case 0x1: case 0x5: { // Cache/Non-Cached sh->WriteWordList[(addr >> 16) & 0xFFF](sh, addr, val); return; } /* case 0x2: { // Purge Area return; } */ case 0x4: case 0x6: // Data Array DataArrayWriteWord(sh, addr, val); return; case 0x7: { if (addr >= 0xFFFFFE00) { // Onchip modules addr &= 0x1FF; OnchipWriteWord(sh, addr, val); return; } else if (addr >= 0xFFFF8000 && addr < 0xFFFFC000) { // ??? } else { // Garbage data } return; } default: { Sh2UnhandledMemoryWriteWord(sh, addr, val); return; } } } ////////////////////////////////////////////////////////////////////////////// void FASTCALL MappedMemoryWriteLongCacheEnabled(SH2_struct *sh, u32 addr, u32 val) { #ifdef SH2_TRACE sh2_trace_writel(addr, val); #endif cache_memory_write_l(sh, &sh->onchip.cache, addr, val); } void FASTCALL MappedMemoryWriteLongNocache(SH2_struct *sh, u32 addr, u32 val) { #ifdef SH2_TRACE sh2_trace_writel(addr, val); #endif switch (addr >> 29) { case 0x0: case 0x1: case 0x5: { // Cache/Non-Cached sh->WriteLongList[(addr >> 16) & 0xFFF](sh, addr, val); return; } case 0x2: { // Purge Area return; } case 0x3: { // Address Array AddressArrayWriteLong(sh, addr, val); return; } case 0x4: case 0x6: // Data Array DataArrayWriteLong(sh, addr, val); return; case 0x7: { if (addr >= 0xFFFFFE00) { // Onchip modules addr &= 0x1FF; OnchipWriteLong(sh, addr, val); return; } else if (addr >= 0xFFFF8000 && addr < 0xFFFFC000) { // ??? } else { // Garbage data } return; } default: { Sh2UnhandledMemoryWriteLong(sh, addr, val); return; } } } ////////////////////////////////////////////////////////////////////////////// int MappedMemoryLoad(SH2_struct *sh, const char *filename, u32 addr) { FILE *fp; long filesize; u8 *buffer; u32 i; size_t num_read = 0; if (!filename) return -1; if ((fp = fopen(filename, "rb")) == NULL) return -1; // Calculate file size fseek(fp, 0, SEEK_END); filesize = ftell(fp); if (filesize <= 0) { YabSetError(YAB_ERR_FILEREAD, filename); fclose(fp); return -1;//error } fseek(fp, 0, SEEK_SET); if ((buffer = (u8 *)malloc(filesize)) == NULL) { fclose(fp); return -2; } num_read = fread((void *)buffer, 1, filesize, fp); fclose(fp); for (i = 0; i < filesize; i++) MappedMemoryWriteByteNocache(sh, addr+i, buffer[i]); free(buffer); return 0; } ////////////////////////////////////////////////////////////////////////////// int MappedMemorySave(SH2_struct *sh, const char *filename, u32 addr, u32 size) { FILE *fp; u8 *buffer; u32 i; if (!filename) return -1; if ((fp = fopen(filename, "wb")) == NULL) return -1; if ((buffer = (u8 *)malloc(size)) == NULL) { fclose(fp); return -2; } for (i = 0; i < size; i++) buffer[i] = MappedMemoryReadByteNocache(sh, addr+i); fwrite((void *)buffer, 1, size, fp); fclose(fp); free(buffer); return 0; } ////////////////////////////////////////////////////////////////////////////// void MappedMemoryLoadExec(const char *filename, u32 pc) { char *p; size_t i; if ((p = strrchr(filename, '.'))) { p = strdup(p); for (i = 0; i < strlen(p); i++) p[i] = toupper(p[i]); if (strcmp(p, ".COF") == 0 || strcmp(p, ".COFF") == 0) { MappedMemoryLoadCoff(filename); free(p); return; } else if(strcmp(p, ".ELF") == 0) { MappedMemoryLoadElf(filename); free(p); return; } free(p); } YabauseResetNoLoad(); // Setup the vector table area, etc. YabauseSpeedySetup(); MappedMemoryLoad(MSH2, filename, pc); SH2GetRegisters(MSH2, &MSH2->regs); MSH2->regs.PC = pc; SH2SetRegisters(MSH2, &MSH2->regs); } ////////////////////////////////////////////////////////////////////////////// int LoadSH1Rom(const char *filename) { return T123Load(SH1Rom, 0x10000, 2, filename); } ////////////////////////////////////////////////////////////////////////////// int LoadMpegRom(const char *filename) { return T123Load(SH1MpegRom, 0x80000, 2, filename); } ////////////////////////////////////////////////////////////////////////////// int LoadBios(const char *filename) { return T123Load(BiosRom, 0x80000, 2, filename); } ////////////////////////////////////////////////////////////////////////////// int LoadBackupRam(const char *filename) { return T123Load(BupRam, 0x10000, 1, filename); } ////////////////////////////////////////////////////////////////////////////// void FormatBackupRam(void *mem, u32 size) { int i, i2; u32 i3; u8 header[32] = { 0xFF, 'B', 0xFF, 'a', 0xFF, 'c', 0xFF, 'k', 0xFF, 'U', 0xFF, 'p', 0xFF, 'R', 0xFF, 'a', 0xFF, 'm', 0xFF, ' ', 0xFF, 'F', 0xFF, 'o', 0xFF, 'r', 0xFF, 'm', 0xFF, 'a', 0xFF, 't' }; // Fill in header for(i2 = 0; i2 < 4; i2++) for(i = 0; i < 32; i++) T1WriteByte(mem, (i2 * 32) + i, header[i]); // Clear the rest for(i3 = 0x80; i3 < size; i3+=2) { T1WriteByte(mem, i3, 0xFF); T1WriteByte(mem, i3+1, 0x00); } } ////////////////////////////////////////////////////////////////////////////// int YabSaveStateBuffer(void ** buffer, size_t * size) { FILE * fp; int status; size_t num_read = 0; if (buffer != NULL) *buffer = NULL; *size = 0; fp = tmpfile(); status = YabSaveStateStream(fp); if (status != 0) { fclose(fp); return status; } fseek(fp, 0, SEEK_END); *size = ftell(fp); fseek(fp, 0, SEEK_SET); if (buffer != NULL) { *buffer = malloc(*size); num_read = fread(*buffer, 1, *size, fp); } fclose(fp); return 0; } ////////////////////////////////////////////////////////////////////////////// int YabSaveState(const char *filename) { FILE *fp; int status; //use a second set of savestates for movies filename = MakeMovieStateName(filename); if (!filename) return -1; if ((fp = fopen(filename, "wb")) == NULL) return -1; status = YabSaveStateStream(fp); fclose(fp); return status; } ////////////////////////////////////////////////////////////////////////////// // FIXME: Here's a (possibly incomplete) list of data that should be added // to the next version of the save state file: // yabsys.DecilineStop (new format) // yabsys.SH2CycleFrac (new field) // yabsys.DecilineUSed (new field) // yabsys.UsecFrac (new field) // [scsp2.c] It would be nice to redo the format entirely because so // many fields have changed format/size from the old scsp.c // [scsp2.c] scsp_clock, scsp_clock_frac, ScspState.sample_timer (timing) // [scsp2.c] cdda_buf, cdda_next_in, cdda_next_out (CDDA buffer) // [sh2core.c] frc.div changed to frc.shift // [sh2core.c] wdt probably needs to be written as well int YabSaveStateStream(FILE *fp) { u32 i; int offset; IOCheck_struct check; u8 *buf; int totalsize; int outputwidth; int outputheight; int movieposition; int temp; u32 temp32; check.done = 0; check.size = 0; // Write signature fprintf(fp, "YSS"); // Write endianness byte #ifdef WORDS_BIGENDIAN fputc(0x00, fp); #else fputc(0x01, fp); #endif // Write version(fix me) i = 2; ywrite(&check, (void *)&i, sizeof(i), 1, fp); // Skip the next 4 bytes for now i = 0; ywrite(&check, (void *)&i, sizeof(i), 1, fp); //write frame number ywrite(&check, (void *)&framecounter, 4, 1, fp); //this will be updated with the movie position later ywrite(&check, (void *)&framecounter, 4, 1, fp); // Go through each area and write each state i += CartSaveState(fp); i += Cs2SaveState(fp); i += SH2SaveState(MSH2, fp); i += SH2SaveState(SSH2, fp); i += SoundSaveState(fp); i += ScuSaveState(fp); i += SmpcSaveState(fp); i += Vdp1SaveState(fp); i += Vdp2SaveState(fp); offset = StateWriteHeader(fp, "OTHR", 1); // Other data ywrite(&check, (void *)BupRam, 0x10000, 1, fp); // do we really want to save this? ywrite(&check, (void *)HighWram, 0x100000, 1, fp); ywrite(&check, (void *)LowWram, 0x100000, 1, fp); ywrite(&check, (void *)&yabsys.DecilineCount, sizeof(int), 1, fp); ywrite(&check, (void *)&yabsys.LineCount, sizeof(int), 1, fp); ywrite(&check, (void *)&yabsys.VBlankLineCount, sizeof(int), 1, fp); ywrite(&check, (void *)&yabsys.MaxLineCount, sizeof(int), 1, fp); temp = yabsys.DecilineStop >> YABSYS_TIMING_BITS; ywrite(&check, (void *)&temp, sizeof(int), 1, fp); temp = (yabsys.CurSH2FreqType == CLKTYPE_26MHZ) ? 268 : 286; ywrite(&check, (void *)&temp, sizeof(int), 1, fp); temp32 = (yabsys.UsecFrac * temp / 10) >> YABSYS_TIMING_BITS; ywrite(&check, (void *)&temp32, sizeof(u32), 1, fp); ywrite(&check, (void *)&yabsys.CurSH2FreqType, sizeof(int), 1, fp); ywrite(&check, (void *)&yabsys.IsPal, sizeof(int), 1, fp); VIDCore->GetGlSize(&outputwidth, &outputheight); totalsize=outputwidth * outputheight * sizeof(u32); if ((buf = (u8 *)malloc(totalsize)) == NULL) { return -2; } YuiSwapBuffers(); #ifdef USE_OPENGL glPixelZoom(1,1); glReadBuffer(GL_BACK); glReadPixels(0, 0, outputwidth, outputheight, GL_RGBA, GL_UNSIGNED_BYTE, buf); #else memcpy(buf, dispbuffer, totalsize); #endif YuiSwapBuffers(); ywrite(&check, (void *)&outputwidth, sizeof(outputwidth), 1, fp); ywrite(&check, (void *)&outputheight, sizeof(outputheight), 1, fp); ywrite(&check, (void *)buf, totalsize, 1, fp); movieposition=ftell(fp); //write the movie to the end of the savestate SaveMovieInState(fp, check); i += StateFinishHeader(fp, offset); // Go back and update size fseek(fp, 8, SEEK_SET); ywrite(&check, (void *)&i, sizeof(i), 1, fp); fseek(fp, 16, SEEK_SET); ywrite(&check, (void *)&movieposition, sizeof(movieposition), 1, fp); free(buf); OSDPushMessage(OSDMSG_STATUS, 150, "STATE SAVED"); return 0; } ////////////////////////////////////////////////////////////////////////////// int YabLoadStateBuffer(const void * buffer, size_t size) { FILE * fp; int status; fp = tmpfile(); fwrite(buffer, 1, size, fp); fseek(fp, 0, SEEK_SET); status = YabLoadStateStream(fp); fclose(fp); return status; } ////////////////////////////////////////////////////////////////////////////// int YabLoadState(const char *filename) { FILE *fp; int status; filename = MakeMovieStateName(filename); if (!filename) return -1; if ((fp = fopen(filename, "rb")) == NULL) return -1; status = YabLoadStateStream(fp); fclose(fp); return status; } ////////////////////////////////////////////////////////////////////////////// int YabLoadStateStream(FILE *fp) { char id[3]; u8 endian; int headerversion, version, size, chunksize, headersize; IOCheck_struct check; u8* buf; int totalsize; int outputwidth; int outputheight; int curroutputwidth; int curroutputheight; int movieposition; int temp; u32 temp32; int test_endian; headersize = 0xC; check.done = 0; check.size = 0; // Read signature yread(&check, (void *)id, 1, 3, fp); if (strncmp(id, "YSS", 3) != 0) { return -2; } // Read header yread(&check, (void *)&endian, 1, 1, fp); yread(&check, (void *)&headerversion, 4, 1, fp); yread(&check, (void *)&size, 4, 1, fp); switch(headerversion) { case 1: /* This is the "original" version of the format */ break; case 2: /* version 2 adds video recording */ yread(&check, (void *)&framecounter, 4, 1, fp); movieposition=ftell(fp); yread(&check, (void *)&movieposition, 4, 1, fp); headersize = 0x14; break; default: /* we're trying to open a save state using a future version * of the YSS format, that won't work, sorry :) */ return -3; break; } #ifdef WORDS_BIGENDIAN test_endian = endian == 1; #else test_endian = endian == 0; #endif if (test_endian) { // should setup reading so it's byte-swapped YabSetError(YAB_ERR_OTHER, (void *)"Load State byteswapping not supported"); return -3; } // Make sure size variable matches actual size minus header fseek(fp, 0, SEEK_END); if (size != (ftell(fp) - headersize)) { return -2; } fseek(fp, headersize, SEEK_SET); // Verify version here ScspMuteAudio(SCSP_MUTE_SYSTEM); if (StateCheckRetrieveHeader(fp, "CART", &version, &chunksize) != 0) { // Revert back to old state here ScspUnMuteAudio(SCSP_MUTE_SYSTEM); return -3; } CartLoadState(fp, version, chunksize); if (StateCheckRetrieveHeader(fp, "CS2 ", &version, &chunksize) != 0) { // Revert back to old state here ScspUnMuteAudio(SCSP_MUTE_SYSTEM); return -3; } Cs2LoadState(fp, version, chunksize); if (StateCheckRetrieveHeader(fp, "MSH2", &version, &chunksize) != 0) { // Revert back to old state here ScspUnMuteAudio(SCSP_MUTE_SYSTEM); return -3; } SH2LoadState(MSH2, fp, version, chunksize); if (StateCheckRetrieveHeader(fp, "SSH2", &version, &chunksize) != 0) { // Revert back to old state here ScspUnMuteAudio(SCSP_MUTE_SYSTEM); return -3; } SH2LoadState(SSH2, fp, version, chunksize); if (StateCheckRetrieveHeader(fp, "SCSP", &version, &chunksize) != 0) { // Revert back to old state here ScspUnMuteAudio(SCSP_MUTE_SYSTEM); return -3; } SoundLoadState(fp, version, chunksize); if (StateCheckRetrieveHeader(fp, "SCU ", &version, &chunksize) != 0) { // Revert back to old state here ScspUnMuteAudio(SCSP_MUTE_SYSTEM); return -3; } ScuLoadState(fp, version, chunksize); if (StateCheckRetrieveHeader(fp, "SMPC", &version, &chunksize) != 0) { // Revert back to old state here ScspUnMuteAudio(SCSP_MUTE_SYSTEM); return -3; } SmpcLoadState(fp, version, chunksize); if (StateCheckRetrieveHeader(fp, "VDP1", &version, &chunksize) != 0) { // Revert back to old state here ScspUnMuteAudio(SCSP_MUTE_SYSTEM); return -3; } Vdp1LoadState(fp, version, chunksize); if (StateCheckRetrieveHeader(fp, "VDP2", &version, &chunksize) != 0) { // Revert back to old state here ScspUnMuteAudio(SCSP_MUTE_SYSTEM); return -3; } Vdp2LoadState(fp, version, chunksize); if (StateCheckRetrieveHeader(fp, "OTHR", &version, &chunksize) != 0) { // Revert back to old state here ScspUnMuteAudio(SCSP_MUTE_SYSTEM); return -3; } // Other data yread(&check, (void *)BupRam, 0x10000, 1, fp); yread(&check, (void *)HighWram, 0x100000, 1, fp); yread(&check, (void *)LowWram, 0x100000, 1, fp); yread(&check, (void *)&yabsys.DecilineCount, sizeof(int), 1, fp); yread(&check, (void *)&yabsys.LineCount, sizeof(int), 1, fp); yread(&check, (void *)&yabsys.VBlankLineCount, sizeof(int), 1, fp); yread(&check, (void *)&yabsys.MaxLineCount, sizeof(int), 1, fp); yread(&check, (void *)&temp, sizeof(int), 1, fp); yread(&check, (void *)&temp, sizeof(int), 1, fp); yread(&check, (void *)&temp32, sizeof(u32), 1, fp); yread(&check, (void *)&yabsys.CurSH2FreqType, sizeof(int), 1, fp); yread(&check, (void *)&yabsys.IsPal, sizeof(int), 1, fp); YabauseChangeTiming(yabsys.CurSH2FreqType); yabsys.UsecFrac = (temp32 << YABSYS_TIMING_BITS) * temp / 10; if (headerversion > 1) { yread(&check, (void *)&outputwidth, sizeof(outputwidth), 1, fp); yread(&check, (void *)&outputheight, sizeof(outputheight), 1, fp); totalsize=outputwidth * outputheight * sizeof(u32); if ((buf = (u8 *)malloc(totalsize)) == NULL) { return -2; } yread(&check, (void *)buf, totalsize, 1, fp); YuiSwapBuffers(); #ifdef USE_OPENGL if(VIDCore->id == VIDCORE_SOFT) glRasterPos2i(0, outputheight); if(VIDCore->id == VIDCORE_OGL) glRasterPos2i(0, outputheight/2); #endif VIDCore->GetGlSize(&curroutputwidth, &curroutputheight); #ifdef USE_OPENGL glPixelZoom((float)curroutputwidth / (float)outputwidth, ((float)curroutputheight / (float)outputheight)); glDrawPixels(outputwidth, outputheight, GL_RGBA, GL_UNSIGNED_BYTE, buf); #endif YuiSwapBuffers(); free(buf); fseek(fp, movieposition, SEEK_SET); MovieReadState(fp); } ScspUnMuteAudio(SCSP_MUTE_SYSTEM); OSDPushMessage(OSDMSG_STATUS, 150, "STATE LOADED"); return 0; } ////////////////////////////////////////////////////////////////////////////// int YabSaveStateSlot(const char *dirpath, u8 slot) { char filename[512]; if (cdip == NULL) return -1; #ifdef WIN32 sprintf(filename, "%s\\%s_%03d.yss", dirpath, cdip->itemnum, slot); #else sprintf(filename, "%s/%s_%03d.yss", dirpath, cdip->itemnum, slot); #endif return YabSaveState(filename); } ////////////////////////////////////////////////////////////////////////////// int YabLoadStateSlot(const char *dirpath, u8 slot) { char filename[512]; if (cdip == NULL) return -1; #ifdef WIN32 sprintf(filename, "%s\\%s_%03d.yss", dirpath, cdip->itemnum, slot); #else sprintf(filename, "%s/%s_%03d.yss", dirpath, cdip->itemnum, slot); #endif return YabLoadState(filename); } ////////////////////////////////////////////////////////////////////////////// static int MappedMemoryAddMatch(u32 addr, u32 val, int searchtype, result_struct *result, u32 *numresults) { result[numresults[0]].addr = addr; result[numresults[0]].val = val; numresults[0]++; return 0; } ////////////////////////////////////////////////////////////////////////////// static INLINE int SearchIncrementAndCheckBounds(result_struct *prevresults, u32 *maxresults, u32 numresults, u32 *i, u32 inc, u32 *newaddr, u32 endaddr) { if (prevresults) { if (i[0] >= maxresults[0]) { maxresults[0] = numresults; return 1; } newaddr[0] = prevresults[i[0]].addr; i[0]++; } else { newaddr[0] = inc; if (newaddr[0] > endaddr || numresults >= maxresults[0]) { maxresults[0] = numresults; return 1; } } return 0; } ////////////////////////////////////////////////////////////////////////////// static int SearchString(u32 startaddr, u32 endaddr, int searchtype, const char *searchstr, result_struct *results, u32 *maxresults) { u8 *buf=NULL; u32 *buf32=NULL; u32 buflen=0; u32 counter; u32 addr; u32 numresults=0; buflen=(u32)strlen(searchstr); if ((buf32=(u32 *)malloc(buflen*sizeof(u32))) == NULL) return 0; buf = (u8 *)buf32; // Copy string to buffer switch (searchtype & 0x70) { case SEARCHSTRING: strcpy((char *)buf, searchstr); break; case SEARCHREL8BIT: case SEARCHREL16BIT: { char *text; char *searchtext=strdup(searchstr); // Calculate buffer length and read values into table buflen = 0; for (text=strtok((char *)searchtext, " ,"); text != NULL; text=strtok(NULL, " ,")) { buf32[buflen] = strtoul(text, NULL, 0); buflen++; } free(searchtext); break; } } addr = startaddr; counter = 0; for (;;) { // Fetch byte/word/etc. switch (searchtype & 0x70) { case SEARCHSTRING: { u8 val = MappedMemoryReadByteNocache(MSH2, addr); addr++; if (val == buf[counter]) { counter++; if (counter == buflen) MappedMemoryAddMatch(addr-buflen, val, searchtype, results, &numresults); } else counter = 0; break; } case SEARCHREL8BIT: { int diff; u32 j; u8 val2; u8 val = MappedMemoryReadByteNocache(MSH2, addr); for (j = 1; j < buflen; j++) { // grab the next value val2 = MappedMemoryReadByteNocache(MSH2, addr+j); // figure out the diff diff = (int)val2 - (int)val; // see if there's a match if (((int)buf32[j] - (int)buf32[j-1]) != diff) break; if (j == (buflen - 1)) MappedMemoryAddMatch(addr, val, searchtype, results, &numresults); val = val2; } addr++; break; } case SEARCHREL16BIT: { int diff; u32 j; u16 val2; u16 val = MappedMemoryReadWordNocache(MSH2, addr); for (j = 1; j < buflen; j++) { // grab the next value val2 = MappedMemoryReadWordNocache(MSH2, addr+(j*2)); // figure out the diff diff = (int)val2 - (int)val; // see if there's a match if (((int)buf32[j] - (int)buf32[j-1]) != diff) break; if (j == (buflen - 1)) MappedMemoryAddMatch(addr, val, searchtype, results, &numresults); val = val2; } addr+=2; break; } } if (addr > endaddr || numresults >= maxresults[0]) break; } free(buf); maxresults[0] = numresults; return 1; } ////////////////////////////////////////////////////////////////////////////// result_struct *MappedMemorySearch(u32 startaddr, u32 endaddr, int searchtype, const char *searchstr, result_struct *prevresults, u32 *maxresults) { u32 i=0; result_struct *results; u32 numresults=0; unsigned long searchval = 0; int issigned=0; u32 addr; if ((results = (result_struct *)malloc(sizeof(result_struct) * maxresults[0])) == NULL) return NULL; switch (searchtype & 0x70) { case SEARCHSTRING: case SEARCHREL8BIT: case SEARCHREL16BIT: { // String/8-bit relative/16-bit relative search(not supported, yet) if (SearchString(startaddr, endaddr, searchtype, searchstr, results, maxresults) == 0) { maxresults[0] = 0; free(results); return NULL; } return results; } case SEARCHHEX: sscanf(searchstr, "%08lx", &searchval); break; case SEARCHUNSIGNED: searchval = (unsigned long)strtoul(searchstr, NULL, 10); issigned = 0; break; case SEARCHSIGNED: searchval = (unsigned long)strtol(searchstr, NULL, 10); issigned = 1; break; } if (prevresults) { addr = prevresults[i].addr; i++; } else addr = startaddr; // Regular value search for (;;) { u32 val=0; u32 newaddr; // Fetch byte/word/etc. switch (searchtype & 0x3) { case SEARCHBYTE: val = MappedMemoryReadByteNocache(MSH2, addr); // sign extend if neccessary if (issigned) val = (s8)val; if (SearchIncrementAndCheckBounds(prevresults, maxresults, numresults, &i, addr+1, &newaddr, endaddr)) return results; break; case SEARCHWORD: val = MappedMemoryReadWordNocache(MSH2, addr); // sign extend if neccessary if (issigned) val = (s16)val; if (SearchIncrementAndCheckBounds(prevresults, maxresults, numresults, &i, addr+2, &newaddr, endaddr)) return results; break; case SEARCHLONG: val = MappedMemoryReadLongNocache(MSH2, addr); if (SearchIncrementAndCheckBounds(prevresults, maxresults, numresults, &i, addr+4, &newaddr, endaddr)) return results; break; default: maxresults[0] = 0; if (results) free(results); return NULL; } // Do a comparison switch (searchtype & 0xC) { case SEARCHEXACT: if (val == searchval) MappedMemoryAddMatch(addr, val, searchtype, results, &numresults); break; case SEARCHLESSTHAN: if ((!issigned && val < searchval) || (issigned && (signed)val < (signed)searchval)) MappedMemoryAddMatch(addr, val, searchtype, results, &numresults); break; case SEARCHGREATERTHAN: if ((!issigned && val > searchval) || (issigned && (signed)val > (signed)searchval)) MappedMemoryAddMatch(addr, val, searchtype, results, &numresults); break; default: maxresults[0] = 0; if (results) free(results); return NULL; } addr = newaddr; } maxresults[0] = numresults; return results; } yabause-0.9.15/src/fakeddk.h000644 001750 001750 00000004202 12755623101 017602 0ustar00guillaumeguillaume000000 000000 /* * This file is not copyrighted, it comes from: * ntddcdrm.h and ntddstor.h from w32api package * ntddscsi.h from w64 mingw-runtime package * * Those three files are in the public domain. */ #define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM #define MAXIMUM_NUMBER_TRACKS 100 #define SCSI_IOCTL_DATA_IN 1 #define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER #define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE(IOCTL_SCSI_BASE,0x0405,METHOD_BUFFERED,FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define IOCTL_CDROM_READ_TOC \ CTL_CODE(IOCTL_CDROM_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS) #define IOCTL_CDROM_READ_TOC_EX \ CTL_CODE(IOCTL_CDROM_BASE, 0x0015, METHOD_BUFFERED, FILE_READ_ACCESS) typedef struct _TRACK_DATA { UCHAR Reserved; UCHAR Control : 4; UCHAR Adr : 4; UCHAR TrackNumber; UCHAR Reserved1; UCHAR Address[4]; } TRACK_DATA, *PTRACK_DATA; typedef struct _CDROM_TOC { UCHAR Length[2]; UCHAR FirstTrack; UCHAR LastTrack; TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS]; } CDROM_TOC, *PCDROM_TOC; typedef struct _SCSI_PASS_THROUGH_DIRECT { USHORT Length; UCHAR ScsiStatus; UCHAR PathId; UCHAR TargetId; UCHAR Lun; UCHAR CdbLength; UCHAR SenseInfoLength; UCHAR DataIn; ULONG DataTransferLength; ULONG TimeOutValue; PVOID DataBuffer; ULONG SenseInfoOffset; UCHAR Cdb[16]; }SCSI_PASS_THROUGH_DIRECT,*PSCSI_PASS_THROUGH_DIRECT; #define CDROM_READ_TOC_EX_FORMAT_FULL_TOC 0x02 typedef struct _CDROM_READ_TOC_EX { UCHAR Format : 4; UCHAR Reserved1 : 3; UCHAR Msf : 1; UCHAR SessionTrack; UCHAR Reserved2; UCHAR Reserved3; } CDROM_READ_TOC_EX, *PCDROM_READ_TOC_EX; typedef struct _CDROM_TOC_FULL_TOC_DATA_BLOCK { UCHAR SessionNumber; UCHAR Control : 4; UCHAR Adr : 4; UCHAR Reserved1; UCHAR Point; UCHAR MsfExtra[3]; UCHAR Zero; UCHAR Msf[3]; } CDROM_TOC_FULL_TOC_DATA_BLOCK, *PCDROM_TOC_FULL_TOC_DATA_BLOCK; typedef struct _CDROM_TOC_FULL_TOC_DATA { UCHAR Length[2]; UCHAR FirstCompleteSession; UCHAR LastCompleteSession; CDROM_TOC_FULL_TOC_DATA_BLOCK Descriptors[0]; } CDROM_TOC_FULL_TOC_DATA, *PCDROM_TOC_FULL_TOC_DATA; yabause-0.9.15/src/yui.h000644 001750 001750 00000016625 12755623101 017033 0ustar00guillaumeguillaume000000 000000 /* Copyright 2004-2005 Guillaume Duhamel Copyright 2004-2006 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef YUI_H #define YUI_H #include "cdbase.h" #include "sh2core.h" #include "sh2int.h" #include "scsp.h" #include "smpc.h" #include "vdp1.h" #include "yabause.h" /* If Yabause encounters any fatal errors, it sends the error text to this function */ void YuiErrorMsg(const char *string); /* Tells the yui to exchange front and back video buffers. This may end up being moved to the Video Core. */ void YuiSwapBuffers(void); ////////////////////////////////////////////////////////////////////////////// // Helper functions(you can use these in your own port) ////////////////////////////////////////////////////////////////////////////// /* int MappedMemoryLoad(const char *filename, u32 addr); Loads the specified file(filename) to specified address(addr). Returns zero on success, less than zero if an error has occured. Note: Some areas in memory are read-only and won't acknowledge any writes. */ /* int MappedMemorySave(const char *filename, u32 addr, u32 size); Saves data from specified address(addr) by specified amount of bytes(size) to specified file(filename). Returns zero on success, less than zero if an error has occured. Note: Some areas in memory are write-only and will only return zero on reads. */ /* void MappedMemoryLoadExec(const char *filename, u32 pc); Loads the specified file(filename) to specified address(pc) and sets Master SH2 to execute from there. Note: Some areas in memory are read-only and won't acknowledge any writes. */ /* void FormatBackupRam(void *mem, u32 size); Formats the specified Backup Ram memory area(mem) of specified size(size). */ /* void SH2Disasm(u32 v_addr, u16 op, int mode, char *string); Generates a disassembled instruction into specified string(string) based on specified address(v_addr) and specified opcode(op). mode should always be 0. */ /* void SH2Step(SH2_struct *context); For the specified SH2 context(context), it executes 1 instruction. context should be either MSH2 or SSH2. */ /* void SH2GetRegisters(SH2_struct *context, sh2regs_struct * r); For the specified SH2 context(context), copies the current registers into the specified structure(r). context should be either MSH2 or SSH2. */ /* void SH2SetRegisters(SH2_struct *context, sh2regs_struct * r); For the specified SH2 context(context), copies the specified structure(r) to the current registers. context should be either MSH2 or SSH2. */ /* void SH2SetBreakpointCallBack(SH2_struct *context, void (*func)(void *, u32, void *), void *userdata); For the specified SH2 context(context), it sets the breakpoint handler function(func). context should be either MSH2 or SSH2. */ /* int SH2AddCodeBreakpoint(SH2_struct *context, u32 addr); For the specified SH2 context(context), it adds a code breakpoint for specified address(addr). context should be either MSH2 or SSH2. Returns zero on success, or less than zero if an error has occured(such as the breakpoint list being full) */ /* int SH2DelCodeBreakpoint(SH2_struct *context, u32 addr); For the specified SH2 context(context), it deletes a code breakpoint for specified address(addr). context should be either MSH2 or SSH2. Returns zero on success, or less than zero if an error has occured. */ /* codebreakpoint_struct *SH2GetBreakpointList(SH2_struct *context); For the specified SH2 context(context), it returns a pointer to the code breakpoint list for the processor. context should be either MSH2 or SSH2. */ /* void SH2ClearCodeBreakpoints(SH2_struct *context); For the specified SH2 context(context), it deletes every code breakpoint entry. context should be either MSH2 or SSH2. */ /* u32 M68KDisasm(u32 addr, char *outstring); Generates a disassembled instruction into specified string(string) based on instruction stored at specified address(addr). Returns address of next instruction. */ /* void M68KStep(); Executes 1 68k instruction. */ /* void M68KGetRegisters(m68kregs_struct *regs); Copies the current 68k registers into the specified structure(regs). */ /* void M68KSetRegisters(m68kregs_struct *regs); Copies the specified structure(regs) to the current 68k registers. */ /* void M68KSetBreakpointCallBack(void (*func)(u32)); It sets the breakpoint handler function(func) for the 68k. */ /* int M68KAddCodeBreakpoint(u32 addr); It adds a 68K code breakpoint for specified address(addr). Returns zero on success, or less than zero if an error has occured(such as the breakpoint list being full) */ /* int M68KDelCodeBreakpoint(u32 addr); It deletes a 68k code breakpoint for specified address(addr). Returns zero on success, or less than zero if an error has occured. */ /* m68kcodebreakpoint_struct *M68KGetBreakpointList(); It returns a pointer to the code breakpoint list for the 68k. */ /* void M68KClearCodeBreakpoints(); It deletes every code breakpoint entry for the 68k. */ /* void ScuDspDisasm(u8 addr, char *outstring); Generates a disassembled instruction into specified string(string) based on instruction stored at specified address(addr). */ /* void ScuDspStep(void); Executes 1 SCU DSP step */ /* void ScuDspGetRegisters(scudspregs_struct *regs); Copies the current SCU DSP registers into the specified structure(regs). */ /* void ScuDspSetRegisters(scudspregs_struct *regs); Copies the specified structure(regs) to the current SCU DSP registers. */ /* void ScuDspSetBreakpointCallBack(void (*func)(u32)); It sets the breakpoint handler function(func) for the SCU DSP. */ /* int ScuDspAddCodeBreakpoint(u32 addr); It adds a SCU DSP code breakpoint for specified address(addr). Returns zero on success, or less than zero if an error has occured(such as the breakpoint list being full) */ /* int ScuDspDelCodeBreakpoint(u32 addr); It deletes a SCU DSP code breakpoint for specified address(addr). Returns zero on success, or less than zero if an error has occured. */ /* scucodebreakpoint_struct *ScuDspGetBreakpointList(); It returns a pointer to the code breakpoint list for the SCU DSP. */ /* void ScuDspClearCodeBreakpoints(); It deletes every code breakpoint entry for the SCU DSP. */ /* void Vdp2DebugStatsRBG0(char *outstring, int *isenabled); void Vdp2DebugStatsNBG0(char *outstring, int *isenabled); void Vdp2DebugStatsNBG1(char *outstring, int *isenabled); void Vdp2DebugStatsNBG2(char *outstring, int *isenabled); void Vdp2DebugStatsNBG3(char *outstring, int *isenabled); Fills a specified string pointer(outstring) with debug information for the specified screen. It also fills a variable(isenabled) with the screen's current status */ #endif yabause-0.9.15/src/vdp1.c000644 001750 001750 00000134433 12755623101 017070 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2005 Guillaume Duhamel Copyright 2004 Lawrence Sebald Copyright 2004-2006 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file vdp1.c \brief VDP1 emulation functions. */ #include #include "vdp1.h" #include "debug.h" #include "scu.h" #include "vdp2.h" #include "vidsoft.h" #include "threads.h" #include "sh2core.h" u8 * Vdp1Ram; u8 * Vdp1FrameBuffer; VideoInterface_struct *VIDCore=NULL; extern VideoInterface_struct *VIDCoreList[]; ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL Vdp1RamReadByte(u32 addr) { addr &= 0x7FFFF; return T1ReadByte(Vdp1Ram, addr); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL Vdp1RamReadWord(u32 addr) { addr &= 0x7FFFF; return T1ReadWord(Vdp1Ram, addr); } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL Vdp1RamReadLong(u32 addr) { addr &= 0x7FFFF; return T1ReadLong(Vdp1Ram, addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp1RamWriteByte(u32 addr, u8 val) { addr &= 0x7FFFF; T1WriteByte(Vdp1Ram, addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp1RamWriteWord(u32 addr, u16 val) { addr &= 0x7FFFF; T1WriteWord(Vdp1Ram, addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp1RamWriteLong(u32 addr, u32 val) { addr &= 0x7FFFF; T1WriteLong(Vdp1Ram, addr, val); } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL Vdp1FrameBufferReadByte(u32 addr) { addr &= 0x3FFFF; if (VIDCore->Vdp1ReadFrameBuffer){ u8 val; VIDCore->Vdp1ReadFrameBuffer(0, addr, &val); return val; } return T1ReadByte(Vdp1FrameBuffer, addr); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL Vdp1FrameBufferReadWord(u32 addr) { addr &= 0x3FFFF; if (VIDCore->Vdp1ReadFrameBuffer){ u16 val; VIDCore->Vdp1ReadFrameBuffer(1, addr, &val); return val; } return T1ReadWord(Vdp1FrameBuffer, addr); } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL Vdp1FrameBufferReadLong(u32 addr) { addr &= 0x3FFFF; if (VIDCore->Vdp1ReadFrameBuffer){ u32 val; VIDCore->Vdp1ReadFrameBuffer(2, addr, &val); return val; } return T1ReadLong(Vdp1FrameBuffer, addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp1FrameBufferWriteByte(u32 addr, u8 val) { addr &= 0x3FFFF; if (VIDCore->Vdp1WriteFrameBuffer) { VIDCore->Vdp1WriteFrameBuffer(0, addr, val); return; } T1WriteByte(Vdp1FrameBuffer, addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp1FrameBufferWriteWord(u32 addr, u16 val) { addr &= 0x3FFFF; if (VIDCore->Vdp1WriteFrameBuffer) { VIDCore->Vdp1WriteFrameBuffer(1, addr, val); return; } T1WriteWord(Vdp1FrameBuffer, addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp1FrameBufferWriteLong(u32 addr, u32 val) { addr &= 0x3FFFF; if (VIDCore->Vdp1WriteFrameBuffer) { VIDCore->Vdp1WriteFrameBuffer(2, addr, val); return; } T1WriteLong(Vdp1FrameBuffer, addr, val); } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL Sh2Vdp1RamReadByte(SH2_struct *sh, u32 addr) { return Vdp1RamReadByte(addr); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL Sh2Vdp1RamReadWord(SH2_struct *sh, u32 addr) { return Vdp1RamReadWord(addr); } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL Sh2Vdp1RamReadLong(SH2_struct *sh, u32 addr) { return Vdp1RamReadLong(addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2Vdp1RamWriteByte(SH2_struct *sh, u32 addr, u8 val) { Vdp1RamWriteByte(addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2Vdp1RamWriteWord(SH2_struct *sh, u32 addr, u16 val) { Vdp1RamWriteWord(addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2Vdp1RamWriteLong(SH2_struct *sh, u32 addr, u32 val) { Vdp1RamWriteLong(addr, val); } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL Sh2Vdp1FrameBufferReadByte(SH2_struct *sh, u32 addr) { return Vdp1FrameBufferReadByte(addr); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL Sh2Vdp1FrameBufferReadWord(SH2_struct *sh, u32 addr) { return Vdp1FrameBufferReadWord(addr); } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL Sh2Vdp1FrameBufferReadLong(SH2_struct *sh, u32 addr) { return Vdp1FrameBufferReadLong(addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2Vdp1FrameBufferWriteByte(SH2_struct *sh, u32 addr, u8 val) { Vdp1FrameBufferWriteByte(addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2Vdp1FrameBufferWriteWord(SH2_struct *sh, u32 addr, u16 val) { Vdp1FrameBufferWriteWord(addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2Vdp1FrameBufferWriteLong(SH2_struct *sh, u32 addr, u32 val) { Vdp1FrameBufferWriteLong(addr, val); } ////////////////////////////////////////////////////////////////////////////// Vdp1 * Vdp1Regs; Vdp1External_struct Vdp1External; ////////////////////////////////////////////////////////////////////////////// int Vdp1Init(void) { if ((Vdp1Regs = (Vdp1 *) malloc(sizeof(Vdp1))) == NULL) return -1; if ((Vdp1Ram = T1MemoryInit(0x80000)) == NULL) return -1; // Allocate enough memory for two frames if ((Vdp1FrameBuffer = T1MemoryInit(0x80000)) == NULL) return -1; Vdp1External.disptoggle = 1; return 0; } ////////////////////////////////////////////////////////////////////////////// void Vdp1DeInit(void) { if (Vdp1Regs) free(Vdp1Regs); Vdp1Regs = NULL; if (Vdp1Ram) T1MemoryDeInit(Vdp1Ram); Vdp1Ram = NULL; if (Vdp1FrameBuffer) T1MemoryDeInit(Vdp1FrameBuffer); Vdp1FrameBuffer = NULL; } ////////////////////////////////////////////////////////////////////////////// int VideoInit(int coreid) { return VideoChangeCore(coreid); } ////////////////////////////////////////////////////////////////////////////// int VideoChangeCore(int coreid) { int i; // Make sure the old core is freed VideoDeInit(); // So which core do we want? if (coreid == VIDCORE_DEFAULT) coreid = 0; // Assume we want the first one // Go through core list and find the id for (i = 0; VIDCoreList[i] != NULL; i++) { if (VIDCoreList[i]->id == coreid) { // Set to current core VIDCore = VIDCoreList[i]; break; } } if (VIDCore == NULL) return -1; if (VIDCore->Init() != 0) return -1; // Reset resolution/priority variables if (Vdp2Regs) { VIDCore->Vdp1Reset(); } return 0; } ////////////////////////////////////////////////////////////////////////////// void VideoDeInit(void) { if (VIDCore) VIDCore->DeInit(); VIDCore = NULL; } ////////////////////////////////////////////////////////////////////////////// void Vdp1Reset(void) { Vdp1Regs->PTMR = 0; Vdp1Regs->MODR = 0x1000; // VDP1 Version 1 VIDCore->Vdp1Reset(); } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL Vdp1ReadByte(u32 addr) { addr &= 0xFF; LOG("trying to byte-read a Vdp1 register\n"); return 0; } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL Vdp1ReadWord(u32 addr) { addr &= 0xFF; switch(addr) { case 0x10: LOG("Read EDSR %X\n", Vdp1Regs->EDSR ); return Vdp1Regs->EDSR; case 0x12: return Vdp1Regs->LOPR; case 0x14: return Vdp1Regs->COPR; case 0x16: return 0x1000 | ((Vdp1Regs->PTMR & 2) << 7) | ((Vdp1Regs->FBCR & 0x1E) << 3) | (Vdp1Regs->TVMR & 0xF); default: LOG("trying to read a Vdp1 write-only register\n"); } return 0; } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL Vdp1ReadLong(u32 addr) { addr &= 0xFF; LOG("trying to long-read a Vdp1 register - %08X\n", addr); return 0; } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp1WriteByte(u32 addr, UNUSED u8 val) { addr &= 0xFF; LOG("trying to byte-write a Vdp1 register - %08X\n", addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp1WriteWord(u32 addr, u16 val) { addr &= 0xFF; switch(addr) { case 0x0: Vdp1Regs->TVMR = val; break; case 0x2: Vdp1Regs->FBCR = val; if ((Vdp1Regs->FBCR & 3) == 3) { Vdp1External.manualchange = 1; } else if ((Vdp1Regs->FBCR & 3) == 2) Vdp1External.manualerase = 1; break; case 0x4: Vdp1Regs->COPR = 0; Vdp1Regs->PTMR = val; if (val == 1) Vdp1Draw(); break; case 0x6: Vdp1Regs->EWDR = val; break; case 0x8: Vdp1Regs->EWLR = val; break; case 0xA: Vdp1Regs->EWRR = val; break; case 0xC: Vdp1Regs->ENDR = val; break; default: LOG("trying to write a Vdp1 read-only register - %08X\n", addr); } } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp1WriteLong(u32 addr, UNUSED u32 val) { addr &= 0xFF; LOG("trying to long-write a Vdp1 register - %08X\n", addr); } ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL Sh2Vdp1ReadByte(SH2_struct *sh, u32 addr) { return Vdp1ReadByte(addr); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL Sh2Vdp1ReadWord(SH2_struct *sh, u32 addr) { return Vdp1ReadWord(addr); } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL Sh2Vdp1ReadLong(SH2_struct *sh, u32 addr) { return Vdp1ReadLong(addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2Vdp1WriteByte(SH2_struct *sh, u32 addr, UNUSED u8 val) { Vdp1WriteByte(addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2Vdp1WriteWord(SH2_struct *sh, u32 addr, u16 val) { Vdp1WriteWord(addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Sh2Vdp1WriteLong(SH2_struct *sh, u32 addr, UNUSED u32 val) { Vdp1WriteLong(addr, val); } ////////////////////////////////////////////////////////////////////////////// void Vdp1DrawCommands(u8 * ram, Vdp1 * regs, u8* back_framebuffer) { u16 command = T1ReadWord(ram, regs->addr); u32 commandCounter = 0; u32 returnAddr = 0xffffffff; while (!(command & 0x8000) && commandCounter < 2000) { // fix me // First, process the command if (!(command & 0x4000)) { // if (!skip) switch (command & 0x000F) { case 0: // normal sprite draw VIDCore->Vdp1NormalSpriteDraw(ram, regs, back_framebuffer); break; case 1: // scaled sprite draw VIDCore->Vdp1ScaledSpriteDraw(ram, regs, back_framebuffer); break; case 2: // distorted sprite draw case 3: /* this one should be invalid, but some games (Hardcore 4x4 for instance) use it instead of 2 */ VIDCore->Vdp1DistortedSpriteDraw(ram, regs, back_framebuffer); break; case 4: // polygon draw VIDCore->Vdp1PolygonDraw(ram, regs, back_framebuffer); break; case 5: // polyline draw case 7: // undocumented mirror VIDCore->Vdp1PolylineDraw(ram, regs, back_framebuffer); break; case 6: // line draw VIDCore->Vdp1LineDraw(ram, regs, back_framebuffer); break; case 8: // user clipping coordinates case 11: // undocumented mirror VIDCore->Vdp1UserClipping(ram, regs); break; case 9: // system clipping coordinates VIDCore->Vdp1SystemClipping(ram, regs); break; case 10: // local coordinate VIDCore->Vdp1LocalCoordinate(ram, regs); break; default: // Abort VDP1LOG("vdp1\t: Bad command: %x\n", command); regs->EDSR |= 2; VIDCore->Vdp1DrawEnd(); regs->LOPR = regs->addr >> 3; regs->COPR = regs->addr >> 3; return; } } // Next, determine where to go next switch ((command & 0x3000) >> 12) { case 0: // NEXT, jump to following table regs->addr += 0x20; break; case 1: // ASSIGN, jump to CMDLINK regs->addr = T1ReadWord(ram, regs->addr + 2) * 8; break; case 2: // CALL, call a subroutine if (returnAddr == 0xFFFFFFFF) returnAddr = regs->addr + 0x20; regs->addr = T1ReadWord(ram, regs->addr + 2) * 8; break; case 3: // RETURN, return from subroutine if (returnAddr != 0xFFFFFFFF) { regs->addr = returnAddr; returnAddr = 0xFFFFFFFF; } else regs->addr += 0x20; break; } command = T1ReadWord(ram, regs->addr); commandCounter++; } } //ensure that registers are set correctly void Vdp1FakeDrawCommands(u8 * ram, Vdp1 * regs) { u16 command = T1ReadWord(ram, regs->addr); u32 commandCounter = 0; u32 returnAddr = 0xffffffff; while (!(command & 0x8000) && commandCounter < 2000) { // fix me // First, process the command if (!(command & 0x4000)) { // if (!skip) switch (command & 0x000F) { case 0: // normal sprite draw case 1: // scaled sprite draw case 2: // distorted sprite draw case 3: /* this one should be invalid, but some games (Hardcore 4x4 for instance) use it instead of 2 */ case 4: // polygon draw case 5: // polyline draw case 6: // line draw case 7: // undocumented polyline draw mirror break; case 8: // user clipping coordinates case 11: // undocumented mirror VIDCore->Vdp1UserClipping(ram, regs); break; case 9: // system clipping coordinates VIDCore->Vdp1SystemClipping(ram, regs); break; case 10: // local coordinate VIDCore->Vdp1LocalCoordinate(ram, regs); break; default: // Abort VDP1LOG("vdp1\t: Bad command: %x\n", command); regs->EDSR |= 2; VIDCore->Vdp1DrawEnd(); regs->LOPR = regs->addr >> 3; regs->COPR = regs->addr >> 3; return; } } // Next, determine where to go next switch ((command & 0x3000) >> 12) { case 0: // NEXT, jump to following table regs->addr += 0x20; break; case 1: // ASSIGN, jump to CMDLINK regs->addr = T1ReadWord(ram, regs->addr + 2) * 8; break; case 2: // CALL, call a subroutine if (returnAddr == 0xFFFFFFFF) returnAddr = regs->addr + 0x20; regs->addr = T1ReadWord(ram, regs->addr + 2) * 8; break; case 3: // RETURN, return from subroutine if (returnAddr != 0xFFFFFFFF) { regs->addr = returnAddr; returnAddr = 0xFFFFFFFF; } else regs->addr += 0x20; break; } command = T1ReadWord(ram, regs->addr); commandCounter++; } } void Vdp1Draw(void) { if (!Vdp1External.disptoggle) { Vdp1NoDraw(); return; } Vdp1Regs->addr = 0; // beginning of a frame // BEF <- CEF // CEF <- 0 Vdp1Regs->EDSR >>= 1; /* this should be done after a frame change or a plot trigger */ Vdp1Regs->COPR = 0; VIDCore->Vdp1DrawStart(); // we set two bits to 1 Vdp1Regs->EDSR |= 2; Vdp1Regs->COPR = Vdp1Regs->addr >> 3; ScuSendDrawEnd(); VIDCore->Vdp1DrawEnd(); } ////////////////////////////////////////////////////////////////////////////// void Vdp1NoDraw(void) { // beginning of a frame (ST-013-R3-061694 page 53) // BEF <- CEF // CEF <- 0 Vdp1Regs->EDSR >>= 1; /* this should be done after a frame change or a plot trigger */ Vdp1Regs->COPR = 0; Vdp1FakeDrawCommands(Vdp1Ram, Vdp1Regs); // we set two bits to 1 Vdp1Regs->EDSR |= 2; ScuSendDrawEnd(); Vdp1External.manualchange = 0; } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp1ReadCommand(vdp1cmd_struct *cmd, u32 addr, u8* ram) { cmd->CMDCTRL = T1ReadWord(ram, addr); cmd->CMDLINK = T1ReadWord(ram, addr + 0x2); cmd->CMDPMOD = T1ReadWord(ram, addr + 0x4); cmd->CMDCOLR = T1ReadWord(ram, addr + 0x6); cmd->CMDSRCA = T1ReadWord(ram, addr + 0x8); cmd->CMDSIZE = T1ReadWord(ram, addr + 0xA); cmd->CMDXA = T1ReadWord(ram, addr + 0xC); cmd->CMDYA = T1ReadWord(ram, addr + 0xE); cmd->CMDXB = T1ReadWord(ram, addr + 0x10); cmd->CMDYB = T1ReadWord(ram, addr + 0x12); cmd->CMDXC = T1ReadWord(ram, addr + 0x14); cmd->CMDYC = T1ReadWord(ram, addr + 0x16); cmd->CMDXD = T1ReadWord(ram, addr + 0x18); cmd->CMDYD = T1ReadWord(ram, addr + 0x1A); cmd->CMDGRDA = T1ReadWord(ram, addr + 0x1C); } ////////////////////////////////////////////////////////////////////////////// int Vdp1SaveState(FILE *fp) { int offset; IOCheck_struct check = { 0, 0 }; #ifdef IMPROVED_SAVESTATES int i = 0; u8 back_framebuffer[0x40000] = { 0 }; #endif offset = StateWriteHeader(fp, "VDP1", 1); // Write registers ywrite(&check, (void *)Vdp1Regs, sizeof(Vdp1), 1, fp); // Write VDP1 ram ywrite(&check, (void *)Vdp1Ram, 0x80000, 1, fp); #ifdef IMPROVED_SAVESTATES for (i = 0; i < 0x40000; i++) back_framebuffer[i] = Vdp1FrameBufferReadByte(i); ywrite(&check, (void *)back_framebuffer, 0x40000, 1, fp); #endif return StateFinishHeader(fp, offset); } ////////////////////////////////////////////////////////////////////////////// int Vdp1LoadState(FILE *fp, UNUSED int version, int size) { IOCheck_struct check = { 0, 0 }; #ifdef IMPROVED_SAVESTATES int i = 0; u8 back_framebuffer[0x40000] = { 0 }; #endif // Read registers yread(&check, (void *)Vdp1Regs, sizeof(Vdp1), 1, fp); // Read VDP1 ram yread(&check, (void *)Vdp1Ram, 0x80000, 1, fp); #ifdef IMPROVED_SAVESTATES yread(&check, (void *)back_framebuffer, 0x40000, 1, fp); for (i = 0; i < 0x40000; i++) Vdp1FrameBufferWriteByte(i, back_framebuffer[i]); #endif return size; } ////////////////////////////////////////////////////////////////////////////// static u32 Vdp1DebugGetCommandNumberAddr(u32 number) { u32 addr = 0; u32 returnAddr = 0xFFFFFFFF; u32 commandCounter = 0; u16 command; command = T1ReadWord(Vdp1Ram, addr); while (!(command & 0x8000) && commandCounter != number) { // Make sure we're still dealing with a valid command if ((command & 0x000C) == 0x000C) // Invalid, abort return 0xFFFFFFFF; // Determine where to go next switch ((command & 0x3000) >> 12) { case 0: // NEXT, jump to following table addr += 0x20; break; case 1: // ASSIGN, jump to CMDLINK addr = T1ReadWord(Vdp1Ram, addr + 2) * 8; break; case 2: // CALL, call a subroutine if (returnAddr == 0xFFFFFFFF) returnAddr = addr + 0x20; addr = T1ReadWord(Vdp1Ram, addr + 2) * 8; break; case 3: // RETURN, return from subroutine if (returnAddr != 0xFFFFFFFF) { addr = returnAddr; returnAddr = 0xFFFFFFFF; } else addr += 0x20; break; } if (addr > 0x7FFE0) return 0xFFFFFFFF; command = T1ReadWord(Vdp1Ram, addr); commandCounter++; } if (commandCounter == number) return addr; else return 0xFFFFFFFF; } ////////////////////////////////////////////////////////////////////////////// char *Vdp1DebugGetCommandNumberName(u32 number) { u32 addr; u16 command; if ((addr = Vdp1DebugGetCommandNumberAddr(number)) != 0xFFFFFFFF) { command = T1ReadWord(Vdp1Ram, addr); if (command & 0x8000) return "Draw End"; // Figure out command name switch (command & 0x000F) { case 0: return "Normal Sprite"; case 1: return "Scaled Sprite"; case 2: return "Distorted Sprite"; case 3: return "Distorted Sprite *"; case 4: return "Polygon"; case 5: return "Polyline"; case 6: return "Line"; case 7: return "Polyline *"; case 8: return "User Clipping Coordinates"; case 9: return "System Clipping Coordinates"; case 10: return "Local Coordinates"; case 11: return "User Clipping Coordinates *"; default: return "Bad command"; } } else return NULL; } ////////////////////////////////////////////////////////////////////////////// void Vdp1DebugCommand(u32 number, char *outstring) { u16 command; vdp1cmd_struct cmd; u32 addr; if ((addr = Vdp1DebugGetCommandNumberAddr(number)) == 0xFFFFFFFF) return; command = T1ReadWord(Vdp1Ram, addr); if (command & 0x8000) { // Draw End outstring[0] = 0x00; return; } if (command & 0x4000) { AddString(outstring, "Command is skipped\r\n"); return; } Vdp1ReadCommand(&cmd, addr, Vdp1Ram); switch (cmd.CMDCTRL & 0x000F) { case 0: AddString(outstring, "Normal Sprite\r\n"); AddString(outstring, "x = %d, y = %d\r\n", cmd.CMDXA, cmd.CMDYA); break; case 1: AddString(outstring, "Scaled Sprite\r\n"); AddString(outstring, "Zoom Point: "); switch ((cmd.CMDCTRL >> 8) & 0xF) { case 0x0: AddString(outstring, "Only two coordinates\r\n"); break; case 0x5: AddString(outstring, "Upper-left\r\n"); break; case 0x6: AddString(outstring, "Upper-center\r\n"); break; case 0x7: AddString(outstring, "Upper-right\r\n"); break; case 0x9: AddString(outstring, "Center-left\r\n"); break; case 0xA: AddString(outstring, "Center-center\r\n"); break; case 0xB: AddString(outstring, "Center-right\r\n"); break; case 0xC: AddString(outstring, "Lower-left\r\n"); break; case 0xE: AddString(outstring, "Lower-center\r\n"); break; case 0xF: AddString(outstring, "Lower-right\r\n"); break; default: break; } if (((cmd.CMDCTRL >> 8) & 0xF) == 0) { AddString(outstring, "xa = %d, ya = %d, xc = %d, yc = %d\r\n", cmd.CMDXA, cmd.CMDYA, cmd.CMDXC, cmd.CMDYC); } else { AddString(outstring, "xa = %d, ya = %d, xb = %d, yb = %d\r\n", cmd.CMDXA, cmd.CMDYA, cmd.CMDXB, cmd.CMDYB); } break; case 2: AddString(outstring, "Distorted Sprite\r\n"); AddString(outstring, "x1 = %d, y1 = %d, x2 = %d, y2 = %d\r\n", cmd.CMDXA, cmd.CMDYA, cmd.CMDXB, cmd.CMDYB); AddString(outstring, "x3 = %d, y3 = %d, x4 = %d, y4 = %d\r\n", cmd.CMDXC, cmd.CMDYC, cmd.CMDXD, cmd.CMDYD); break; case 3: AddString(outstring, "Distorted Sprite *\r\n"); AddString(outstring, "x1 = %d, y1 = %d, x2 = %d, y2 = %d\r\n", cmd.CMDXA, cmd.CMDYA, cmd.CMDXB, cmd.CMDYB); AddString(outstring, "x3 = %d, y3 = %d, x4 = %d, y4 = %d\r\n", cmd.CMDXC, cmd.CMDYC, cmd.CMDXD, cmd.CMDYD); break; case 4: AddString(outstring, "Polygon\r\n"); AddString(outstring, "x1 = %d, y1 = %d, x2 = %d, y2 = %d\r\n", cmd.CMDXA, cmd.CMDYA, cmd.CMDXB, cmd.CMDYB); AddString(outstring, "x3 = %d, y3 = %d, x4 = %d, y4 = %d\r\n", cmd.CMDXC, cmd.CMDYC, cmd.CMDXD, cmd.CMDYD); break; case 5: AddString(outstring, "Polyline\r\n"); AddString(outstring, "x1 = %d, y1 = %d, x2 = %d, y2 = %d\r\n", cmd.CMDXA, cmd.CMDYA, cmd.CMDXB, cmd.CMDYB); AddString(outstring, "x3 = %d, y3 = %d, x4 = %d, y4 = %d\r\n", cmd.CMDXC, cmd.CMDYC, cmd.CMDXD, cmd.CMDYD); break; case 6: AddString(outstring, "Line\r\n"); AddString(outstring, "x1 = %d, y1 = %d, x2 = %d, y2 = %d\r\n", cmd.CMDXA, cmd.CMDYA, cmd.CMDXB, cmd.CMDYB); break; case 7: AddString(outstring, "Polyline *\r\n"); AddString(outstring, "x1 = %d, y1 = %d, x2 = %d, y2 = %d\r\n", cmd.CMDXA, cmd.CMDYA, cmd.CMDXB, cmd.CMDYB); AddString(outstring, "x3 = %d, y3 = %d, x4 = %d, y4 = %d\r\n", cmd.CMDXC, cmd.CMDYC, cmd.CMDXD, cmd.CMDYD); break; case 8: AddString(outstring, "User Clipping\r\n"); AddString(outstring, "x1 = %d, y1 = %d, x2 = %d, y2 = %d\r\n", cmd.CMDXA, cmd.CMDYA, cmd.CMDXC, cmd.CMDYC); break; case 9: AddString(outstring, "System Clipping\r\n"); AddString(outstring, "x1 = 0, y1 = 0, x2 = %d, y2 = %d\r\n", cmd.CMDXC, cmd.CMDYC); break; case 10: AddString(outstring, "Local Coordinates\r\n"); AddString(outstring, "x = %d, y = %d\r\n", cmd.CMDXA, cmd.CMDYA); break; default: AddString(outstring, "Invalid command\r\n"); return; } // Only Sprite commands use CMDSRCA, CMDSIZE if (!(cmd.CMDCTRL & 0x000C)) { AddString(outstring, "Texture address = %08X\r\n", ((unsigned int)cmd.CMDSRCA) << 3); AddString(outstring, "Texture width = %d, height = %d\r\n", (cmd.CMDSIZE & 0x3F00) >> 5, cmd.CMDSIZE & 0xFF); AddString(outstring, "Texture read direction: "); switch ((cmd.CMDCTRL >> 4) & 0x3) { case 0: AddString(outstring, "Normal\r\n"); break; case 1: AddString(outstring, "Reversed horizontal\r\n"); break; case 2: AddString(outstring, "Reversed vertical\r\n"); break; case 3: AddString(outstring, "Reversed horizontal and vertical\r\n"); break; default: break; } } // Only draw commands use CMDPMOD if (!(cmd.CMDCTRL & 0x0008)) { if (cmd.CMDPMOD & 0x8000) { AddString(outstring, "MSB set\r\n"); } if (cmd.CMDPMOD & 0x1000) { AddString(outstring, "High Speed Shrink Enabled\r\n"); } if (!(cmd.CMDPMOD & 0x0800)) { AddString(outstring, "Pre-clipping Enabled\r\n"); } if (cmd.CMDPMOD & 0x0400) { AddString(outstring, "User Clipping Enabled\r\n"); AddString(outstring, "Clipping Mode = %d\r\n", (cmd.CMDPMOD >> 9) & 0x1); } if (cmd.CMDPMOD & 0x0100) { AddString(outstring, "Mesh Enabled\r\n"); } if (!(cmd.CMDPMOD & 0x0080)) { AddString(outstring, "End Code Enabled\r\n"); } if (!(cmd.CMDPMOD & 0x0040)) { AddString(outstring, "Transparent Pixel Enabled\r\n"); } AddString(outstring, "Color mode: "); switch ((cmd.CMDPMOD >> 3) & 0x7) { case 0: AddString(outstring, "4 BPP(16 color bank)\r\n"); AddString(outstring, "Color bank: %08X\r\n", (cmd.CMDCOLR << 3)); break; case 1: AddString(outstring, "4 BPP(16 color LUT)\r\n"); AddString(outstring, "Color lookup table: %08X\r\n", (cmd.CMDCOLR << 3)); break; case 2: AddString(outstring, "8 BPP(64 color bank)\r\n"); AddString(outstring, "Color bank: %08X\r\n", (cmd.CMDCOLR << 3)); break; case 3: AddString(outstring, "8 BPP(128 color bank)\r\n"); AddString(outstring, "Color bank: %08X\r\n", (cmd.CMDCOLR << 3)); break; case 4: AddString(outstring, "8 BPP(256 color bank)\r\n"); AddString(outstring, "Color bank: %08X\r\n", (cmd.CMDCOLR << 3)); break; case 5: AddString(outstring, "15 BPP(RGB)\r\n"); // Only non-textured commands if (cmd.CMDCTRL & 0x0004) { AddString(outstring, "Non-textured color: %04X\r\n", cmd.CMDCOLR); } break; default: break; } AddString(outstring, "Color Calc. mode: "); switch (cmd.CMDPMOD & 0x7) { case 0: AddString(outstring, "Replace\r\n"); break; case 1: AddString(outstring, "Cannot overwrite/Shadow\r\n"); break; case 2: AddString(outstring, "Half-luminance\r\n"); break; case 3: AddString(outstring, "Replace/Half-transparent\r\n"); break; case 4: AddString(outstring, "Gouraud Shading\r\n"); AddString(outstring, "Gouraud Shading Table = %08X\r\n", ((unsigned int)cmd.CMDGRDA) << 3); break; case 6: AddString(outstring, "Gouraud Shading + Half-luminance\r\n"); AddString(outstring, "Gouraud Shading Table = %08X\r\n", ((unsigned int)cmd.CMDGRDA) << 3); break; case 7: AddString(outstring, "Gouraud Shading/Gouraud Shading + Half-transparent\r\n"); AddString(outstring, "Gouraud Shading Table = %08X\r\n", ((unsigned int)cmd.CMDGRDA) << 3); break; default: break; } } } ////////////////////////////////////////////////////////////////////////////// #if defined WORDS_BIGENDIAN #define SAT2YAB1(alpha,temp) (alpha | (temp & 0x7C00) << 1 | (temp & 0x3E0) << 14 | (temp & 0x1F) << 27) #else #define SAT2YAB1(alpha,temp) (alpha << 24 | (temp & 0x1F) << 3 | (temp & 0x3E0) << 6 | (temp & 0x7C00) << 9) #endif #if defined WORDS_BIGENDIAN #define SAT2YAB2(alpha,dot1,dot2) (((dot2 & 0xFF) << 24) | ((dot2 & 0xFF00) << 8) | ((dot1 & 0xFF) << 8) | alpha) #else #define SAT2YAB2(alpha,dot1,dot2) (alpha << 24 | ((dot1 & 0xFF) << 16) | (dot2 & 0xFF00) | (dot2 & 0xFF)) #endif static u32 ColorRamGetColor(u32 colorindex) { switch(Vdp2Internal.ColorMode) { case 0: case 1: { u32 tmp; colorindex <<= 1; tmp = T2ReadWord(Vdp2ColorRam, colorindex & 0xFFF); return SAT2YAB1(0xFF, tmp); } case 2: { u32 tmp1, tmp2; colorindex <<= 2; colorindex &= 0xFFF; tmp1 = T2ReadWord(Vdp2ColorRam, colorindex); tmp2 = T2ReadWord(Vdp2ColorRam, colorindex+2); return SAT2YAB2(0xFF, tmp1, tmp2); } default: break; } return 0; } ////////////////////////////////////////////////////////////////////////////// static INLINE int CheckEndcode(int dot, int endcode, int *code) { if (dot == endcode) { code[0]++; if (code[0] == 2) { code[0] = 0; return 2; } return 1; } return 0; } ////////////////////////////////////////////////////////////////////////////// static INLINE int DoEndcode(int count, u32 *charAddr, u32 **textdata, int width, int xoff, int oddpixel, int pixelsize) { if (count > 1) { float divisor = (float)(8 / pixelsize); if(divisor != 0) charAddr[0] += (int)((float)(width - xoff + oddpixel) / divisor); memset(textdata[0], 0, sizeof(u32) * (width - xoff)); textdata[0] += (width - xoff); return 1; } else *textdata[0]++ = 0; return 0; } ////////////////////////////////////////////////////////////////////////////// u32 *Vdp1DebugTexture(u32 number, int *w, int *h) { u16 command; vdp1cmd_struct cmd; u32 addr; u32 *texture; u32 charAddr; u32 dot; u8 SPD; u32 alpha; u32 *textdata; int isendcode=0; int code=0; int ret; if ((addr = Vdp1DebugGetCommandNumberAddr(number)) == 0xFFFFFFFF) return NULL; command = T1ReadWord(Vdp1Ram, addr); if (command & 0x8000) // Draw End return NULL; if (command & 0x4000) // Command Skipped return NULL; Vdp1ReadCommand(&cmd, addr, Vdp1Ram); switch (cmd.CMDCTRL & 0x000F) { case 0: // Normal Sprite case 1: // Scaled Sprite case 2: // Distorted Sprite case 3: // Distorted Sprite * w[0] = (cmd.CMDSIZE & 0x3F00) >> 5; h[0] = cmd.CMDSIZE & 0xFF; if ((texture = (u32 *)malloc(sizeof(u32) * w[0] * h[0])) == NULL) return NULL; if (!(cmd.CMDPMOD & 0x80)) { isendcode = 1; code = 0; } else isendcode = 0; break; case 4: // Polygon case 5: // Polyline case 6: // Line case 7: // Polyline * // Do 1x1 pixel w[0] = 1; h[0] = 1; if ((texture = (u32 *)malloc(sizeof(u32))) == NULL) return NULL; if (cmd.CMDCOLR & 0x8000) texture[0] = SAT2YAB1(0xFF, cmd.CMDCOLR); else texture[0] = ColorRamGetColor(cmd.CMDCOLR); return texture; case 8: // User Clipping case 9: // System Clipping case 10: // Local Coordinates case 11: // User Clipping * return NULL; default: // Invalid command return NULL; } charAddr = cmd.CMDSRCA * 8; SPD = ((cmd.CMDPMOD & 0x40) != 0); alpha = 0xFF; textdata = texture; switch((cmd.CMDPMOD >> 3) & 0x7) { case 0: { // 4 bpp Bank mode u32 colorBank = cmd.CMDCOLR; u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4; u16 i; for(i = 0;i < h[0];i++) { u16 j; j = 0; while(j < w[0]) { dot = T1ReadByte(Vdp1Ram, charAddr & 0x7FFFF); // Pixel 1 if (isendcode && (ret = CheckEndcode(dot >> 4, 0xF, &code)) > 0) { if (DoEndcode(ret, &charAddr, &textdata, w[0], j, 0, 4)) break; } else { if (((dot >> 4) == 0) && !SPD) *textdata++ = 0; else *textdata++ = ColorRamGetColor(((dot >> 4) | colorBank) + colorOffset); } j += 1; // Pixel 2 if (isendcode && (ret = CheckEndcode(dot & 0xF, 0xF, &code)) > 0) { if (DoEndcode(ret, &charAddr, &textdata, w[0], j, 1, 4)) break; } else { if (((dot & 0xF) == 0) && !SPD) *textdata++ = 0; else *textdata++ = ColorRamGetColor(((dot & 0xF) | colorBank) + colorOffset); } j += 1; charAddr += 1; } } break; } case 1: { // 4 bpp LUT mode u32 temp; u32 colorLut = cmd.CMDCOLR * 8; u16 i; for(i = 0;i < h[0];i++) { u16 j; j = 0; while(j < w[0]) { dot = T1ReadByte(Vdp1Ram, charAddr & 0x7FFFF); if (isendcode && (ret = CheckEndcode(dot >> 4, 0xF, &code)) > 0) { if (DoEndcode(ret, &charAddr, &textdata, w[0], j, 0, 4)) break; } else { if (((dot >> 4) == 0) && !SPD) *textdata++ = 0; else { temp = T1ReadWord(Vdp1Ram, ((dot >> 4) * 2 + colorLut) & 0x7FFFF); if (temp & 0x8000) *textdata++ = SAT2YAB1(0xFF, temp); else *textdata++ = ColorRamGetColor(temp); } } j += 1; if (isendcode && (ret = CheckEndcode(dot & 0xF, 0xF, &code)) > 0) { if (DoEndcode(ret, &charAddr, &textdata, w[0], j, 1, 4)) break; } else { if (((dot & 0xF) == 0) && !SPD) *textdata++ = 0; else { temp = T1ReadWord(Vdp1Ram, ((dot & 0xF) * 2 + colorLut) & 0x7FFFF); if (temp & 0x8000) *textdata++ = SAT2YAB1(0xFF, temp); else *textdata++ = ColorRamGetColor(temp); } } j += 1; charAddr += 1; } } break; } case 2: { // 8 bpp(64 color) Bank mode u32 colorBank = cmd.CMDCOLR; u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4; u16 i, j; for(i = 0;i < h[0];i++) { for(j = 0;j < w[0];j++) { dot = T1ReadByte(Vdp1Ram, charAddr & 0x7FFFF) & 0x3F; charAddr++; if ((dot == 0) && !SPD) *textdata++ = 0; else *textdata++ = ColorRamGetColor((dot | colorBank) + colorOffset); } } break; } case 3: { // 8 bpp(128 color) Bank mode u32 colorBank = cmd.CMDCOLR; u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4; u16 i, j; for(i = 0;i < h[0];i++) { for(j = 0;j < w[0];j++) { dot = T1ReadByte(Vdp1Ram, charAddr & 0x7FFFF) & 0x7F; charAddr++; if ((dot == 0) && !SPD) *textdata++ = 0; else *textdata++ = ColorRamGetColor((dot | colorBank) + colorOffset); } } break; } case 4: { // 8 bpp(256 color) Bank mode u32 colorBank = cmd.CMDCOLR; u32 colorOffset = (Vdp2Regs->CRAOFB & 0x70) << 4; u16 i, j; for(i = 0;i < h[0];i++) { for(j = 0;j < w[0];j++) { dot = T1ReadByte(Vdp1Ram, charAddr & 0x7FFFF); charAddr++; if ((dot == 0) && !SPD) *textdata++ = 0; else *textdata++ = ColorRamGetColor((dot | colorBank) + colorOffset); } } break; } case 5: { // 16 bpp Bank mode u16 i, j; for(i = 0;i < h[0];i++) { for(j = 0;j < w[0];j++) { dot = T1ReadWord(Vdp1Ram, charAddr & 0x7FFFF); if (isendcode && (ret = CheckEndcode(dot, 0x7FFF, &code)) > 0) { if (DoEndcode(ret, &charAddr, &textdata, w[0], j, 0, 16)) break; } else { //if (!(dot & 0x8000) && (Vdp2Regs->SPCTL & 0x20)) printf("mixed mode\n"); if (!(dot & 0x8000) && !SPD) *textdata++ = 0; else *textdata++ = SAT2YAB1(0xFF, dot); } charAddr += 2; } } break; } default: break; } return texture; } ////////////////////////////////////////////////////////////////////////////// void ToggleVDP1(void) { Vdp1External.disptoggle ^= 1; } ////////////////////////////////////////////////////////////////////////////// // Dummy Video Interface ////////////////////////////////////////////////////////////////////////////// int VIDDummyInit(void); void VIDDummyDeInit(void); void VIDDummyResize(unsigned int, unsigned int, int); int VIDDummyIsFullscreen(void); int VIDDummyVdp1Reset(void); void VIDDummyVdp1DrawStart(void); void VIDDummyVdp1DrawEnd(void); void VIDDummyVdp1NormalSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDDummyVdp1ScaledSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDDummyVdp1DistortedSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDDummyVdp1PolygonDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDDummyVdp1PolylineDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDDummyVdp1LineDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer); void VIDDummyVdp1UserClipping(u8 * ram, Vdp1 * regs); void VIDDummyVdp1SystemClipping(u8 * ram, Vdp1 * regs); void VIDDummyVdp1LocalCoordinate(u8 * ram, Vdp1 * regs); int VIDDummyVdp2Reset(void); void VIDDummyVdp2DrawStart(void); void VIDDummyVdp2DrawEnd(void); void VIDDummyVdp2DrawScreens(void); void VIDDummyGetGlSize(int *width, int *height); void VIDDummVdp1ReadFrameBuffer(u32 type, u32 addr, void * out); void VIDDummVdp1WriteFrameBuffer(u32 type, u32 addr, u32 val); void VIDDummyGetNativeResolution(int *width, int * height, int *interlace); void VIDDummyVdp2DispOff(void); VideoInterface_struct VIDDummy = { VIDCORE_DUMMY, "Dummy Video Interface", VIDDummyInit, VIDDummyDeInit, VIDDummyResize, VIDDummyIsFullscreen, VIDDummyVdp1Reset, VIDDummyVdp1DrawStart, VIDDummyVdp1DrawEnd, VIDDummyVdp1NormalSpriteDraw, VIDDummyVdp1ScaledSpriteDraw, VIDDummyVdp1DistortedSpriteDraw, VIDDummyVdp1PolygonDraw, VIDDummyVdp1PolylineDraw, VIDDummyVdp1LineDraw, VIDDummyVdp1UserClipping, VIDDummyVdp1SystemClipping, VIDDummyVdp1LocalCoordinate, VIDDummVdp1ReadFrameBuffer, VIDDummVdp1WriteFrameBuffer, VIDDummyVdp2Reset, VIDDummyVdp2DrawStart, VIDDummyVdp2DrawEnd, VIDDummyVdp2DrawScreens, VIDDummyGetGlSize, VIDDummyGetNativeResolution, VIDDummyVdp2DispOff, }; ////////////////////////////////////////////////////////////////////////////// int VIDDummyInit(void) { return 0; } ////////////////////////////////////////////////////////////////////////////// void VIDDummyDeInit(void) { } ////////////////////////////////////////////////////////////////////////////// void VIDDummyResize(UNUSED unsigned int i, UNUSED unsigned int j, UNUSED int on) { } ////////////////////////////////////////////////////////////////////////////// int VIDDummyIsFullscreen(void) { return 0; } ////////////////////////////////////////////////////////////////////////////// int VIDDummyVdp1Reset(void) { return 0; } ////////////////////////////////////////////////////////////////////////////// void VIDDummyVdp1DrawStart(void) { } ////////////////////////////////////////////////////////////////////////////// void VIDDummyVdp1DrawEnd(void) { } ////////////////////////////////////////////////////////////////////////////// void VIDDummyVdp1NormalSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer) { } ////////////////////////////////////////////////////////////////////////////// void VIDDummyVdp1ScaledSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer) { } ////////////////////////////////////////////////////////////////////////////// void VIDDummyVdp1DistortedSpriteDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer) { } ////////////////////////////////////////////////////////////////////////////// void VIDDummyVdp1PolygonDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer) { } ////////////////////////////////////////////////////////////////////////////// void VIDDummyVdp1PolylineDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer) { } ////////////////////////////////////////////////////////////////////////////// void VIDDummyVdp1LineDraw(u8 * ram, Vdp1 * regs, u8* back_framebuffer) { } ////////////////////////////////////////////////////////////////////////////// void VIDDummyVdp1UserClipping(u8 * ram, Vdp1 * regs) { } ////////////////////////////////////////////////////////////////////////////// void VIDDummyVdp1SystemClipping(u8 * ram, Vdp1 * regs) { } ////////////////////////////////////////////////////////////////////////////// void VIDDummyVdp1LocalCoordinate(u8 * ram, Vdp1 * regs) { } ////////////////////////////////////////////////////////////////////////////// int VIDDummyVdp2Reset(void) { return 0; } ////////////////////////////////////////////////////////////////////////////// void VIDDummyVdp2DrawStart(void) { } ////////////////////////////////////////////////////////////////////////////// void VIDDummyVdp2DrawEnd(void) { } ////////////////////////////////////////////////////////////////////////////// void VIDDummyVdp2DrawScreens(void) { } ////////////////////////////////////////////////////////////////////////////// void VIDDummyGetGlSize(int *width, int *height) { *width = 0; *height = 0; } ////////////////////////////////////////////////////////////////////////////// void VIDDummVdp1ReadFrameBuffer(u32 type, u32 addr, void * out) { } ////////////////////////////////////////////////////////////////////////////// void VIDDummVdp1WriteFrameBuffer(u32 type, u32 addr, u32 val) { } ////////////////////////////////////////////////////////////////////////////// void VIDDummyGetNativeResolution(int *width, int * height, int * interlace) { *width = 0; *height = 0; *interlace = 0; } ////////////////////////////////////////////////////////////////////////////// void VIDDummyVdp2DispOff(void) { }yabause-0.9.15/src/macjoy.h000644 001750 001750 00000006431 12755623101 017501 0ustar00guillaumeguillaume000000 000000 /* This file was imported form CrabEmu ( http://crabemu.sourceforge.net/ ) -- A Sega Master System emulator for Mac OS X (among other targets). The rest of the file is left intact from CrabEmu to make things easier if this were to be upgraded in the future. */ /* This file is part of CrabEmu. Copyright (C) 2008 Lawrence Sebald CrabEmu is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. CrabEmu 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 CrabEmu; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef JOYSTICK_H #define JOYSTICK_H #include /* Values for the joy_elemdata_t type element. */ #define JOY_TYPE_NOT_APPLICABLE 0 #define JOY_TYPE_X_AXIS 1 #define JOY_TYPE_Y_AXIS 2 #define JOY_TYPE_Z_AXIS 3 #define JOY_TYPE_X2_AXIS 4 #define JOY_TYPE_Y2_AXIS 5 #define JOY_TYPE_Z2_AXIS 6 /* Structure for holding basic information about each element. */ typedef struct joy_elemdata_s { IOHIDElementCookie cookie; int type; int number; int min; int max; } joy_elemdata_t; /* Structure for holding information about each joystick connected. */ typedef struct joydata_s { IOHIDDeviceInterface **iface; int open; int buttons_count; int axes_count; int hats_count; joy_elemdata_t *buttons; joy_elemdata_t *axes; joy_elemdata_t *hats; char name[256]; } joydata_t; /* Values for hat switches. ORed together and returned from joy_read_hat. */ #define JOY_HAT_CENTER 0 #define JOY_HAT_UP (1 << 0) #define JOY_HAT_DOWN (1 << 1) #define JOY_HAT_RIGHT (1 << 2) #define JOY_HAT_LEFT (1 << 3) /* Scan the system for any joysticks connected. */ int joy_scan_joysticks(void); /* Clean up any data allocated by the program for joysticks. */ void joy_release_joysticks(void); /* Get the joystick at a given index in our list of joysticks. */ joydata_t *joy_get_joystick(int index); /* Grab the device for exclusive use by this program. The device must be closed properly (with the joy_close_joystick function, or you may need to unplug/replug the joystick to get it to work again). */ int joy_open_joystick(joydata_t *joy); /* Close the device and return its resources to the system. */ int joy_close_joystick(joydata_t *joy); /* Read a given element from the joystick. The joystick must be open for this function to actually do anything useful. */ int joy_read_element(joydata_t *joy, joy_elemdata_t *elem); /* Read the value of a given button. Returns -1 on failure. */ int joy_read_button(joydata_t *joy, int num); /* Read the value of a given axis. Returns 0 on failure (or if the axis reports that its value is 0). */ int joy_read_axis(joydata_t *joy, int index); /* Read the value of a given hat. Returns -1 on failure. */ int joy_read_hat(joydata_t *joy, int index); #endif /* !JOYSTICK_H */ yabause-0.9.15/src/mpeg_card.c000644 001750 001750 00000035041 12755623101 020132 0ustar00guillaumeguillaume000000 000000 /* Copyright 2014-2016 James Laird-Wah Copyright 2004-2006, 2013 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file mpeg_card.c \brief Mpeg card implementation */ #include "core.h" #include "sh7034.h" #include "debug.h" #include "assert.h" #include "error.h" #include "assert.h" #include "vidshared.h" #include "titan/titan.h" ///////////////////////////////////////////////////////////////////// #ifdef HAVE_MPEG #include #include #include #include #define BUFFER_SIZE 4096 struct YabCodec { AVCodec *codec; AVCodecContext *context; AVFrame *frame; AVPacket packet; struct SwsContext *sws_context; int is_audio; u8 buffer[BUFFER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE]; FILE * file; }; struct YabMpegState { struct YabCodec video; struct YabCodec audio; int inited; }yab_mpeg = {0}; void yab_mpeg_do_frame(struct YabCodec * c); void yab_mpeg_init(); void yab_mpeg_play_file(struct YabCodec * c, char * filename); u32 pixels[704*480] = {0}; u8* out_buf[4]; int out_linesize[4]; extern pixel_t *dispbuffer; void ScspReceiveMpeg (const u8 *samples, int len); #endif void TitanPutPixel(int priority, s32 x, s32 y, u32 color, int linescreen, vdp2draw_struct* info); ///////////////////////////////////////////////////////////////////// void mpeg_reg_debug_print(); //a100000 //write //FEDC BA98 7654 3210 //.ccc .yyy iiii h.d. //d : 0 == display on, 1 == display off //h : 0 == HD, 1 == standard def (mpeg set mode) //i : interpolation (set to opposite of command, 0xf - command_value) //y : y gain //c : c gain //read //FEDC BA98 7654 3210 //.... ...o .... fpdc // c == video decoding // d == display // p == pause // f == freeze // o == output prep complete //a100002 //FEDC BA98 7654 3210 //.... .... .... .ooo //.... .... .ppp ppp. //o : display window offset x (not sure how many bits) //p: display window pos x (seems to occupy the same bits, modal?) (not sure how many bits) //a100004 //FEDC BA98 7654 3210 //.... .... .... .ooo //.... .... .ppp ppp. //o : display window offset y //p: display window pos y //a100006 //when writing //FEDC BA98 7654 3210 //.... ..xx xxxx xxx. //x : frame buffer window pos x (not sure how many bits total) //a100008 //FEDC BA98 7654 3210 //.... ..yy yyyy yyy. //y : frame buffer window pos y //a10000e //FEDC BA98 7654 3210 //.... .... .... xxxx //x : zoom rate x (not sure how many bits total) //a100010 //FEDC BA98 7654 3210 //.... .... .... yyyy //y : zoom rate y (not sure how many bits total) //a100012 //FEDC BA98 7654 3210 //cccc cccc cccc cccc //c : border color (rgb555?) //a100014 //FEDC BA98 7654 3210 //.... .... .s.. fpot //t : 0 == decode timing mode is host, 1 == decode timing mode is vsync //o : 0 == output to host, 1 == output to vdp2 //p : seems pause related. writing 0 in cr2 of set decoding method sets it to 0 //f : seems freeze related. write 0 in cr4 of set decoding method to set it to 0 //s : 0 == still picture, 1 == video (mpeg set mode) //a10001c //FEDC BA98 7654 3210 //hhhh wwww ..b. .... //b : blur on/off (todo recheck) //w : mosaic width 0xf == off, 0-9 settings //h : mosaic height 0xf == off, 0-9 settings //a100022 //FEDC BA98 7654 3210 //fff. .... .... .... //f : frame type (sent in status info) // 1 : i frame // 2 : p frame // 3 : b frame // 4 : d frame //a10003e //FEDC BA98 7654 3210 //..i. .... .... .... // i : 0 == not interlaced 1 == interlaced struct MpegCard { u16 reg_00; u16 window_offset_x;//0x02 u16 window_offset_y;//0x04 u16 window_size_x;//0x06 u16 window_size_y;//0x08 u16 framebuffer_x;//0x0a u16 framebuffer_y;//0x0c u16 zoom_x;//0x0e u16 zoom_y;//0x10 u16 border_color;//0x12 u16 reg_14; u16 reg_18; u16 reg_1a; u16 mosaic_blur;//0x1c u16 reg_1e; u16 reg_20; u16 reg_22; u16 reg_32; u16 reg_34; u16 reg_3e; u16 reg_80000; u16 reg_80008; u16 ram[0x40000]; u32 ram_ptr; }mpeg_card; #define RAM_MASK 0x3ffff u32 mpeg_framebuffer[704 * 480] = { 0 }; void mpeg_card_write_word(u32 addr, u16 data) { if ((addr & 0xfffff) != 0x34 && (addr & 0xfffff) != 0x36) { // CDLOG("mpeg lsi ww %08x, %04x\n", addr, data); //mpeg_reg_debug_print(); } switch (addr & 0xfffff) { case 0: mpeg_card.reg_00 = data; return; case 2: mpeg_card.window_offset_x = data; return; case 4: mpeg_card.window_offset_y = data; return; case 6: mpeg_card.window_size_x = data; return; case 8: mpeg_card.window_size_y = data; return; case 0xa: mpeg_card.framebuffer_x = data; return; case 0xc: mpeg_card.framebuffer_y = data; return; case 0xe: mpeg_card.zoom_x = data; return; case 0x10: mpeg_card.zoom_y = data; return; case 0x12: mpeg_card.border_color = data; return; case 0x14: mpeg_card.reg_14 = data; return; case 0x18: mpeg_card.reg_18 = data; return; case 0x1a: mpeg_card.reg_1a = data; return; case 0x1c: mpeg_card.mosaic_blur = data; return; case 0x1e: mpeg_card.reg_1e = data; return; case 0x20: mpeg_card.reg_20 = data; return; case 0x22: mpeg_card.reg_22 = data; return; case 0x30: mpeg_card.ram_ptr = data << 2; return; case 0x32: mpeg_card.reg_32 = data; return; case 0x34: mpeg_card.reg_34 = data; return; case 0x36: mpeg_card.ram_ptr &= RAM_MASK; mpeg_card.ram[mpeg_card.ram_ptr++] = data; return; case 0x3e: mpeg_card.reg_3e = data; return; case 0x80000: mpeg_card.reg_80000 = data; return; case 0x80008: mpeg_card.reg_80008 = data; return; } assert(0); } u16 mpeg_card_read_word(u32 addr) { // if ((addr & 0xfffff) != 0x34 && (addr & 0xfffff) != 0x36) // CDLOG("mpeg lsi rw %08x %08x\n", addr, SH1->regs.PC); switch (addr & 0xfffff) { case 0: //0x10 needs to be clear for the video interrupt to set mpcm //get status wants 1 << 8 set, to clear "output prep" bit in mpeg video status //get interrupt wants 1 << 13 set, to clear "sequence end detected" interrupt bit return (mpeg_card.reg_00 & ~0x10) | (1 << 8) | (1 << 13); case 2: return mpeg_card.window_offset_x;//probably not right case 0x34: return 1;//return mpeg_card.reg_34 | 5;//first bit is always set? case 0x36: mpeg_card.ram_ptr &= RAM_MASK; return mpeg_card.ram[mpeg_card.ram_ptr++]; case 0x80000: return mpeg_card.reg_80000; case 0x80008: return mpeg_card.reg_80008; } // assert(0); return 0; } void set_mpeg_audio_data_transfer_irq() { sh1_assert_tioca(0); } void set_mpeg_video_data_transfer_irq() { sh1_assert_tioca(1); } void set_mpeg_audio_irq() { sh1_assert_tioca(2); } const u16 mosaic_masks[] = { 0xfffe,//0 0xfffc,//1 0xfff8,//2 0xfff0,//3 0xffe0,//4 0xffc0,//5 0xff80,//6 0xff00,//7 0xfe00,//8 0xfc00,//9 0xf800,//a 0xf000,//b 0xe000,//c 0xc000,//d 0x8000,//e 0xffff,//f (off) }; void mpeg_render() { int x = 0; int y = 0; vdp2draw_struct info = { 0 }; int priority = (Vdp2Regs->PRINA >> 8) & 7; //offset from a center value or fixed point? int window_x_offset = (mpeg_card.window_offset_x - 0x96) >> 1; int window_y_offset = (mpeg_card.window_offset_y - 0x26) >> 1; int framebuffer_x_offset = mpeg_card.framebuffer_x >> 1; int framebuffer_y_offset = mpeg_card.framebuffer_y >> 1; //start framebuffer pos from offset float fb_x = framebuffer_x_offset; float fb_y = framebuffer_y_offset; int window_last_x = window_x_offset + (mpeg_card.window_size_x >> 1); int window_last_y = window_y_offset + (mpeg_card.window_size_y >> 1); //zoom float fb_x_inc = 1; float fb_y_inc = 1; int mosaic_x = (mpeg_card.mosaic_blur >> 8) & 0xf; int mosaic_y = (mpeg_card.mosaic_blur >> 12) & 0xf; info.titan_which_layer = TITAN_NBG1; if (window_x_offset < 0) window_x_offset = 0; if (window_y_offset < 0) window_y_offset = 0; for (y = window_y_offset; y < window_last_y; y++)//in output coordinates { fb_x = framebuffer_x_offset; for (x = window_x_offset; x < window_last_x; x++) { u32 pixel = 0; int x_val = ((int)fb_x) & mosaic_masks[mosaic_x]; int y_val = ((int)fb_y) & mosaic_masks[mosaic_y]; u32 offset = (y_val * 704) + x_val; if (offset < (704 * 480)) { pixel = mpeg_framebuffer[offset]; if(x < 704 && y < 480) TitanPutPixel(priority, x, y, pixel, 0, &info); } fb_x+= fb_x_inc; } fb_y+= fb_y_inc; } } void set_mpeg_video_irq() { sh1_assert_tiocb(2); #ifdef HAVE_MPEG yab_mpeg_do_frame(&yab_mpeg.video); yab_mpeg_do_frame(&yab_mpeg.audio); #else if(Vdp2Regs->EXTEN & 1)//exbg enabled mpeg_render(); #endif } void mpeg_card_set_all_irqs() { set_mpeg_audio_data_transfer_irq(); set_mpeg_video_data_transfer_irq(); //triggers jump to null pointer, get hardware info shows mpeg present without it //set_mpeg_audio_irq(); set_mpeg_video_irq(); } void mpeg_card_init() { int x = 0; int y = 0; memset(&mpeg_card, 0, sizeof(struct MpegCard)); memset(&mpeg_framebuffer, 0, sizeof(u32) * 704*480); for (y = 0; y < 480; y++) { for (x = 0; x < 704; x++) { mpeg_framebuffer[(y * 704) + x] = 0xff00ff00;//green } } for (y = 0; y < 240; y++) { for (x = 8; x < 320; x++) { mpeg_framebuffer[(y * 704) + x] = 0xff0000ff;//red } } mpeg_card.reg_34 = 1; #ifdef HAVE_MPEG yab_mpeg_init(); #endif } void mpeg_reg_debug_print() { if((mpeg_card.reg_00 >> 1) & 1) CDLOG("Display disabled\n"); else CDLOG("Display enabled\n"); CDLOG("Interpolation %01X\n", 0xf - ((mpeg_card.reg_00 >> 4) & 0xf)); CDLOG("Window x %d\n", mpeg_card.window_size_x >> 1); CDLOG("Window y %d\n", mpeg_card.window_size_y >> 1); CDLOG("Mosaic x %d\n", (mpeg_card.mosaic_blur >> 8) & 0xf); CDLOG("Mosaic y %d\n", (mpeg_card.mosaic_blur >> 12) & 0xf); if ((mpeg_card.mosaic_blur >> 5) & 1) CDLOG("Blur disabled\n"); else CDLOG("Blur enabled\n"); } ///////////////////////////////////////////////////////////////////// #ifdef HAVE_MPEG void yab_mpeg_init_codec(struct YabCodec * c, int type) { c->codec = avcodec_find_decoder(type); if(!c->codec) { YabErrorMsg("couldn't find decoder"); return; } c->context = avcodec_alloc_context3(c->codec); if(!c->context) { YabErrorMsg("couldn't allocate context"); return; } if (avcodec_open2(c->context, c->codec, NULL) < 0) { YabErrorMsg("couldn't open codec"); return; } av_init_packet(&c->packet); c->packet.data = c->buffer; } void yab_mpeg_deinit_codec(struct YabCodec * c) { avcodec_close(c->context); } void yab_mpeg_init() { int ret = 0; av_register_all(); memset(&yab_mpeg,0,sizeof(struct YabMpegState)); yab_mpeg_init_codec(&yab_mpeg.video,AV_CODEC_ID_MPEG1VIDEO); yab_mpeg_init_codec(&yab_mpeg.audio,AV_CODEC_ID_MP2); yab_mpeg_play_file(&yab_mpeg.video, "/home/d/yab-f/yabause/yabauseut/src/buildcd/M2TEST/MOVIE.m1v"); yab_mpeg_play_file(&yab_mpeg.audio, "/home/d/yab-f/yabause/yabauseut/src/buildcd/M2TEST/MOVIE.MP2"); yab_mpeg.audio.is_audio = 1; yab_mpeg.inited = 1; yab_mpeg.audio.context->channels = 2; yab_mpeg.audio.context->sample_rate = 44100; ret = av_image_alloc(out_buf,out_linesize, 320, 240,PIX_FMT_RGB32, 1); if(!ret) assert(0); } void write_frame_to_video_buffer(struct YabCodec * c) { int x = 0, y = 0; int out_width = 320; int out_height = 240; int mpeg_width = c->frame->linesize[0]; u8 * mpeg_buf = c->frame->data[0]; //convert yuv to rgb with sws if(!c->sws_context) { c->sws_context = sws_getContext( //source width, height, format c->context->width, c->context->height, c->context->pix_fmt, //dest width, height, format out_width, out_height, PIX_FMT_RGB32, //flags SWS_BILINEAR, //source/dest filters NULL, NULL, //param NULL ); } sws_scale( c->sws_context, (u8 const * const *)c->frame->data, c->frame->linesize, 0, c->context->height, out_buf, out_linesize); memcpy(pixels, out_buf[0], 320*240*4); for(y = 0; y < out_height; y++) { for(x = 0; x < out_width; x++) { dispbuffer[(y*out_width) + x] = pixels[(y * mpeg_width) + x]; } } } void write_sound(struct YabCodec * c) { int size = av_get_bytes_per_sample(c->context->sample_fmt); ScspReceiveMpeg(c->frame->data[0],size); } void yab_mpeg_do_frame(struct YabCodec * c) { int got_frame = 0; int num_tries = 0; if(!yab_mpeg.inited) { yab_mpeg_init(); } c->packet.size = fread(c->buffer, 1, BUFFER_SIZE, c->file); while(c->packet.size > 0) { int length = 0; if(!c->frame) { c->frame = av_frame_alloc(); if(!c->frame) { YabErrorMsg("couldn't allocate frame"); return; } } if(!c->is_audio) length = avcodec_decode_video2(c->context, c->frame, &got_frame, &c->packet); else length = avcodec_decode_audio4(c->context, c->frame, &got_frame, &c->packet); if(length < 0) { return; } if(num_tries > 8) { return; } if(got_frame) { if(!c->is_audio) write_frame_to_video_buffer(c); else write_sound(c); break; } num_tries++; } } void yab_mpeg_do_video_frame() { yab_mpeg_do_frame(&yab_mpeg.video); yab_mpeg_do_frame(&yab_mpeg.audio); } void yab_mpeg_play_file(struct YabCodec * c, char * filename) { c->file = fopen(filename, "rb"); if(!c->file) { YabErrorMsg("couldn't open file"); assert(0); return; } } #endif yabause-0.9.15/src/perlinuxjoy.c000644 001750 001750 00000013434 12755623101 020603 0ustar00guillaumeguillaume000000 000000 /* Copyright 2009 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "debug.h" #include "perlinuxjoy.h" #include #include #include #include #include int PERLinuxJoyInit(void); void PERLinuxJoyDeInit(void); int PERLinuxJoyHandleEvents(void); u32 PERLinuxJoyScan(u32 flags); void PERLinuxJoyFlush(void); void PERLinuxKeyName(u32 key, char * name, int size); PerInterface_struct PERLinuxJoy = { PERCORE_LINUXJOY, "Linux Joystick Interface", PERLinuxJoyInit, PERLinuxJoyDeInit, PERLinuxJoyHandleEvents, PERLinuxJoyScan, 1, PERLinuxJoyFlush, PERLinuxKeyName }; typedef struct { int fd; int * axis; int axiscount; } perlinuxjoy_struct; static perlinuxjoy_struct * joysticks = NULL; static int joycount = 0; #define PACKEVENT(evt) ((evt.value < 0 ? 0x10000 : 0) | (evt.type << 8) | (evt.number)) #define THRESHOLD 1000 #define MAXAXIS 256 ////////////////////////////////////////////////////////////////////////////// static void LinuxJoyInit(perlinuxjoy_struct * joystick, const char * path) { int i; int fd; int axisinit[MAXAXIS]; struct js_event evt; size_t num_read; joystick->fd = open(path, O_RDONLY | O_NONBLOCK); if (joystick->fd == -1) return; joystick->axiscount = 0; while ((num_read = read(joystick->fd, &evt, sizeof(struct js_event))) > 0) { if (evt.type == (JS_EVENT_AXIS | JS_EVENT_INIT)) { axisinit[evt.number] = evt.value; if (evt.number + 1 > joystick->axiscount) { joystick->axiscount = evt.number + 1; } } } if (joystick->axiscount > MAXAXIS) joystick->axiscount = MAXAXIS; joystick->axis = malloc(sizeof(int) * joystick->axiscount); for(i = 0;i < joystick->axiscount;i++) { joystick->axis[i] = axisinit[i]; } } static void LinuxJoyDeInit(perlinuxjoy_struct * joystick) { if (joystick->fd == -1) return; close(joystick->fd); free(joystick->axis); } static void LinuxJoyHandleEvents(perlinuxjoy_struct * joystick) { struct js_event evt; size_t num_read; if (joystick->fd == -1) return; while ((num_read = read(joystick->fd, &evt, sizeof(struct js_event))) > 0) { if (evt.type == JS_EVENT_AXIS) { int initvalue; int disp; u8 axis = evt.number; if (axis >= joystick->axiscount) return; initvalue = joystick->axis[axis]; disp = abs(initvalue - evt.value); if (disp < THRESHOLD) evt.value = 0; else if (evt.value < initvalue) evt.value = -1; else evt.value = 1; } if (evt.value != 0) { PerKeyDown(PACKEVENT(evt)); } else { PerKeyUp(PACKEVENT(evt)); PerKeyUp(0x10000 | PACKEVENT(evt)); } } } static int LinuxJoyScan(perlinuxjoy_struct * joystick) { struct js_event evt; size_t num_read; if (joystick->fd == -1) return 0; if ((num_read = read(joystick->fd, &evt, sizeof(struct js_event))) <= 0) return 0; if (evt.type == JS_EVENT_AXIS) { int initvalue; int disp; u8 axis = evt.number; if (axis >= joystick->axiscount) return 0; initvalue = joystick->axis[axis]; disp = abs(initvalue - evt.value); if (disp < THRESHOLD) return 0; else if (evt.value < initvalue) evt.value = -1; else evt.value = 1; } return PACKEVENT(evt); } static void LinuxJoyFlush(perlinuxjoy_struct * joystick) { struct js_event evt; size_t num_read; if (joystick->fd == -1) return; while ((num_read = read(joystick->fd, &evt, sizeof(struct js_event))) > 0); } ////////////////////////////////////////////////////////////////////////////// int PERLinuxJoyInit(void) { int i; int fd; glob_t globbuf; glob("/dev/input/js*", 0, NULL, &globbuf); joycount = globbuf.gl_pathc; joysticks = malloc(sizeof(perlinuxjoy_struct) * joycount); for(i = 0;i < globbuf.gl_pathc;i++) LinuxJoyInit(joysticks + i, globbuf.gl_pathv[i]); globfree(&globbuf); return 0; } ////////////////////////////////////////////////////////////////////////////// void PERLinuxJoyDeInit(void) { int i; for(i = 0;i < joycount;i++) LinuxJoyDeInit(joysticks + i); free(joysticks); } ////////////////////////////////////////////////////////////////////////////// int PERLinuxJoyHandleEvents(void) { int i; for(i = 0;i < joycount;i++) LinuxJoyHandleEvents(joysticks + i); // execute yabause if ( YabauseExec() != 0 ) { return -1; } // return success return 0; } ////////////////////////////////////////////////////////////////////////////// u32 PERLinuxJoyScan(u32 flags) { int i; for(i = 0;i < joycount;i++) { int ret = LinuxJoyScan(joysticks + i); if (ret != 0) return ret; } return 0; } ////////////////////////////////////////////////////////////////////////////// void PERLinuxJoyFlush(void) { int i; for (i = 0;i < joycount;i++) LinuxJoyFlush(joysticks + i); } ////////////////////////////////////////////////////////////////////////////// void PERLinuxKeyName(u32 key, char * name, UNUSED int size) { sprintf(name, "%x", (int)key); } yabause-0.9.15/src/thr-linux.c000644 001750 001750 00000005522 12755623101 020144 0ustar00guillaumeguillaume000000 000000 /* src/thr-linux.c: Thread functions for Linux Copyright 2010 Andrew Church This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "core.h" #include "threads.h" #include #include #include #include ////////////////////////////////////////////////////////////////////////////// // Thread handles for each Yabause subthread static pthread_t thread_handle[YAB_NUM_THREADS]; ////////////////////////////////////////////////////////////////////////////// static void dummy_sighandler(int signum_unused) {} // For thread sleep/wake int YabThreadStart(unsigned int id, void (*func)(void *), void *arg) { // Set up a dummy signal handler for SIGUSR1 so we can return from pause() // in YabThreadSleep() static const struct sigaction sa = {.sa_handler = dummy_sighandler}; if (sigaction(SIGUSR1, &sa, NULL) != 0) { perror("sigaction(SIGUSR1)"); return -1; } if (thread_handle[id]) { fprintf(stderr, "YabThreadStart: thread %u is already started!\n", id); return -1; } if ((errno = pthread_create(&thread_handle[id], NULL, (void *)func, arg)) != 0) { perror("pthread_create"); return -1; } return 0; } ////////////////////////////////////////////////////////////////////////////// void YabThreadWait(unsigned int id) { if (!thread_handle[id]) return; // Thread wasn't running in the first place pthread_join(thread_handle[id], NULL); thread_handle[id] = 0; } ////////////////////////////////////////////////////////////////////////////// void YabThreadYield(void) { sched_yield(); } ////////////////////////////////////////////////////////////////////////////// void YabThreadSleep(void) { pause(); } ////////////////////////////////////////////////////////////////////////////// void YabThreadRemoteSleep(unsigned int id) { } ////////////////////////////////////////////////////////////////////////////// void YabThreadWake(unsigned int id) { if (!thread_handle[id]) return; // Thread isn't running pthread_kill(thread_handle[id], SIGUSR1); } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/sh2trace.c000644 001750 001750 00000017713 12755623101 017732 0ustar00guillaumeguillaume000000 000000 /* src/sh2trace.c: SH-2 tracing code for debugging Copyright 2009 Andrew Church This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file sh2trace.c \brief SH2 execution tracing. */ #include #include "sh2core.h" #include "sh2d.h" #include "sh2trace.h" /*************************************************************************/ /* Define BINARY_LOG to log traces in a binary format (faster than text) */ //#define BINARY_LOG /* Define GZIP_LOG to compress log as it's created */ #ifdef __linux__ # define GZIP_LOG #endif /* Define ECHO_TO_STDERR to log traces to stderr as well as logfile * (ignored in BINARY_LOG mode) */ // #define ECHO_TO_STDERR /*----------------------------------*/ static const u64 trace_start = 000000000ULL; // First cycle to trace static const u64 trace_stop = 2800000000ULL; // Last cycle to trace + 1 /*----------------------------------*/ static int is_ins_enabled = 0; static FILE *logfile; // Trace log file static u64 cycle_accum = 0; // Global cycle accumulator static u64 current_cycles = 0; // Cycle count on last call to sh2_trace() /*************************************************************************/ void SH2SetInsTracing(int enable) { is_ins_enabled = enable; } FASTCALL u64 sh2_cycle_count(void) { return current_cycles; } /*-----------------------------------------------------------------------*/ FASTCALL void sh2_trace_add_cycles(s32 cycles) { cycle_accum += cycles; } /*-----------------------------------------------------------------------*/ FASTCALL void sh2_trace_writeb(u32 address, u32 value) { #ifdef BINARY_LOG struct { u16 id; // 1 = byte store u16 pad1; u32 address; u32 value; u32 pad2; } buf; #endif if (logfile) { value &= 0xFF; #ifdef BINARY_LOG buf.id = 1; buf.pad1 = 0; buf.address = address; buf.value = value; buf.pad2 = 0; fwrite(&buf, sizeof(buf), 1, logfile); #else fprintf(logfile, "WRITEB %08X <- %02X\n", (int)address, (int)value); # ifdef ECHO_TO_STDERR fprintf(stderr, "WRITEB %08X <- %02X\n", (int)address, (int)value); # endif #endif } } FASTCALL void sh2_trace_writew(u32 address, u32 value) { #ifdef BINARY_LOG struct { u16 id; // 2 = word store u16 pad1; u32 address; u32 value; u32 pad2; } buf; #endif if (logfile) { value &= 0xFFFF; #ifdef BINARY_LOG buf.id = 2; buf.pad1 = 0; buf.address = address; buf.value = value; buf.pad2 = 0; fwrite(&buf, sizeof(buf), 1, logfile); #else fprintf(logfile, "WRITEW %08X <- %04X\n", (int)address, (int)value); # ifdef ECHO_TO_STDERR fprintf(stderr, "WRITEW %08X <- %04X\n", (int)address, (int)value); # endif #endif } } FASTCALL void sh2_trace_writel(u32 address, u32 value) { if (logfile) { #ifdef BINARY_LOG struct { u16 id; // 4 = long store u16 pad1; u32 address; u32 value; u32 pad2; } buf; buf.id = 4; buf.pad1 = 0; buf.address = address; buf.value = value; buf.pad2 = 0; fwrite(&buf, sizeof(buf), 1, logfile); #else fprintf(logfile, "WRITEL %08X <- %08X\n", (int)address, (int)value); # ifdef ECHO_TO_STDERR fprintf(stderr, "WRITEL %08X <- %08X\n", (int)address, (int)value); # endif #endif } } /*-----------------------------------------------------------------------*/ #ifndef BINARY_LOG static INLINE void HEXIT(char * const ptr, u32 val, int ndigits) { while (ndigits-- > 0) { const int digit = val & 0xF; val >>= 4; ptr[ndigits] = (digit>9 ? digit+7+'0' : digit+'0'); } } #endif FASTCALL void sh2_trace(SH2_struct *state, u32 address) { if (!is_ins_enabled) return; current_cycles = cycle_accum + state->cycles; if (current_cycles < trace_start) { /* Before first instruction: do nothing */ } else if (current_cycles >= trace_stop) { /* After last instruction: close log file if it's open */ if (logfile) { #ifdef GZIP_LOG pclose(logfile); #else fclose(logfile); #endif logfile = NULL; } } else { u16 opcode; #ifdef BINARY_LOG struct { u16 id; // 1/2/4 = store; 0x80 = MSH2 insn; 0x81 = SSH2 insn u16 opcode; u32 regs[23]; u64 cycles; u32 pad[2]; } buf; #else char buf[100]; /* This looks ugly, but it's faster than fprintf() in this case */ static char regbuf[] = " R0: XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX\n R8: XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX\n PR: XXXXXXXX SR: XXX MAC: XXXXXXXX/XXXXXXXX GBR: XXXXXXXX VBR: XXXXXXXX\n"; int i; #endif if (!logfile) { const char *filename = "sh2.log"; #ifdef GZIP_LOG char cmdbuf[100]; snprintf(cmdbuf, sizeof(cmdbuf), "gzip -3 >'%s'.gz", filename); logfile = popen(cmdbuf, "w"); #else logfile = fopen(filename, "w"); #endif if (!logfile) { return; } setvbuf(logfile, NULL, _IOFBF, 65536); } opcode = MappedMemoryReadWordNocache(state, address); #ifdef BINARY_LOG buf.id = state==SSH2 ? 0x81 : 0x80; buf.opcode = opcode; /* sh2int leaves the branch target in regs.PC during a delay slot, * so insert the proper PC manually */ SH2GetRegisters(state, (sh2regs_struct *)buf.regs); buf.regs[22] = address; buf.cycles = current_cycles; buf.pad[0] = 0; buf.pad[1] = 0; fwrite(&buf, sizeof(buf), 1, logfile); #else // !BINARY_LOG SH2GetRegisters(state, &state->regs); SH2Disasm(address, opcode, 0, &state->regs, buf); fprintf(logfile, "[%c] %08X: %04X %-44s [%12llu]\n", state==SSH2 ? 'S' : 'M', (int)address, (int)opcode, buf+12, (unsigned long long)current_cycles); #ifdef ECHO_TO_STDERR fprintf(stderr, "[%c] %08X: %04X %-44s [%12llu]\n", state==SSH2 ? 'S' : 'M', (int)address, (int)opcode, buf+12, (unsigned long long)current_cycles); #endif for (i = 0; i < 16; i++) { HEXIT(i>=8 ? ®buf[12+i*9] : ®buf[6+i*9], state->regs.R[i], 8); } HEXIT(®buf[162], state->regs.PR, 8); HEXIT(®buf[176], state->regs.SR.all, 3); HEXIT(®buf[186], state->regs.MACH, 8); HEXIT(®buf[195], state->regs.MACL, 8); HEXIT(®buf[210], state->regs.GBR, 8); HEXIT(®buf[225], state->regs.VBR, 8); fwrite(regbuf, sizeof(regbuf)-1, 1, logfile); #ifdef ECHO_TO_STDERR fwrite(regbuf, sizeof(regbuf)-1, 1, stderr); #endif #endif // BINARY_LOG } // current_cycles >= trace_start && current_cycles < trace_stop } /*************************************************************************/ /* * Local variables: * c-file-style: "stroustrup" * c-file-offsets: ((case-label . *) (statement-case-intro . *)) * indent-tabs-mode: nil * End: * * vim: expandtab shiftwidth=4: */ yabause-0.9.15/src/sh2int.h000644 001750 001750 00000006157 12755623101 017433 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2005 Guillaume Duhamel Copyright 2004-2005 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SH2INT_H #define SH2INT_H #define SH2CORE_INTERPRETER 0 #define SH2CORE_DEBUGINTERPRETER 1 #define INSTRUCTION_A(x) ((x & 0xF000) >> 12) #define INSTRUCTION_B(x) ((x & 0x0F00) >> 8) #define INSTRUCTION_C(x) ((x & 0x00F0) >> 4) #define INSTRUCTION_D(x) (x & 0x000F) #define INSTRUCTION_CD(x) (x & 0x00FF) #define INSTRUCTION_BCD(x) (x & 0x0FFF) int SH2InterpreterInit(enum SHMODELTYPE model, SH2_struct *msh, SH2_struct *ssh); int SH2DebugInterpreterInit(enum SHMODELTYPE model, SH2_struct *msh, SH2_struct *ssh); void SH2InterpreterDeInit(void); void SH2InterpreterReset(SH2_struct *context); void FASTCALL SH2InterpreterExec(SH2_struct *context, u32 cycles); void FASTCALL SH2DebugInterpreterExec(SH2_struct *context, u32 cycles); void SH2InterpreterGetRegisters(SH2_struct *context, sh2regs_struct *regs); u32 SH2InterpreterGetGPR(SH2_struct *context, int num); u32 SH2InterpreterGetSR(SH2_struct *context); u32 SH2InterpreterGetGBR(SH2_struct *context); u32 SH2InterpreterGetVBR(SH2_struct *context); u32 SH2InterpreterGetMACH(SH2_struct *context); u32 SH2InterpreterGetMACL(SH2_struct *context); u32 SH2InterpreterGetPR(SH2_struct *context); u32 SH2InterpreterGetPC(SH2_struct *context); void SH2InterpreterSetRegisters(SH2_struct *context, const sh2regs_struct *regs); void SH2InterpreterSetGPR(SH2_struct *context, int num, u32 value); void SH2InterpreterSetSR(SH2_struct *context, u32 value); void SH2InterpreterSetGBR(SH2_struct *context, u32 value); void SH2InterpreterSetVBR(SH2_struct *context, u32 value); void SH2InterpreterSetMACH(SH2_struct *context, u32 value); void SH2InterpreterSetMACL(SH2_struct *context, u32 value); void SH2InterpreterSetPR(SH2_struct *context, u32 value); void SH2InterpreterSetPC(SH2_struct *context, u32 value); void SH2InterpreterSendInterrupt(SH2_struct *context, u8 level, u8 vector); int SH2InterpreterGetInterrupts(SH2_struct *context, interrupt_struct interrupts[MAX_INTERRUPTS]); void SH2InterpreterSetInterrupts(SH2_struct *context, int num_interrupts, const interrupt_struct interrupts[MAX_INTERRUPTS]); extern SH2Interface_struct SH2Interpreter; extern SH2Interface_struct SH2DebugInterpreter; typedef u32 (FASTCALL *fetchfunc)(SH2_struct *, u32); typedef void (FASTCALL *opcodefunc)(SH2_struct *); #endif yabause-0.9.15/src/cs1.c000644 001750 001750 00000005150 12755623101 016675 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2005 Guillaume Duhamel Copyright 2005 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file cs1.c \brief A-Bus CS1 emulation functions. */ #include #include "cs1.h" #include "cs0.h" ////////////////////////////////////////////////////////////////////////////// u8 FASTCALL Cs1ReadByte(SH2_struct *sh, u32 addr) { addr &= 0xFFFFFF; if (addr == 0xFFFFFF) return CartridgeArea->cartid; return CartridgeArea->Cs1ReadByte(sh, addr); } ////////////////////////////////////////////////////////////////////////////// u16 FASTCALL Cs1ReadWord(SH2_struct *sh, u32 addr) { addr &= 0xFFFFFF; if (addr == 0xFFFFFE) return (0xFF00 | CartridgeArea->cartid); return CartridgeArea->Cs1ReadWord(sh, addr); } ////////////////////////////////////////////////////////////////////////////// u32 FASTCALL Cs1ReadLong(SH2_struct *sh, u32 addr) { addr &= 0xFFFFFF; if (addr == 0xFFFFFC) return (0xFF00FF00 | (CartridgeArea->cartid << 16) | CartridgeArea->cartid); return CartridgeArea->Cs1ReadLong(sh, addr); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Cs1WriteByte(SH2_struct *sh, u32 addr, u8 val) { addr &= 0xFFFFFF; if (addr == 0xFFFFFF) return; CartridgeArea->Cs1WriteByte(sh, addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Cs1WriteWord(SH2_struct *sh, u32 addr, u16 val) { addr &= 0xFFFFFF; if (addr == 0xFFFFFE) return; CartridgeArea->Cs1WriteWord(sh, addr, val); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Cs1WriteLong(SH2_struct *sh, u32 addr, u32 val) { addr &= 0xFFFFFF; if (addr == 0xFFFFFC) return; CartridgeArea->Cs1WriteLong(sh, addr, val); } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/m68kd.c000644 001750 001750 00000105275 12755623101 017151 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file m68kd.c \brief 68000 disassembler function. */ #include "core.h" #include "m68kd.h" #include "scsp.h" // for c68k_word_read() typedef struct { u16 mask; u16 inst; const char *name; int (*disasm)(u32, u16, char *); } m68kdis_struct; ////////////////////////////////////////////////////////////////////////////// static int setsizestr(u16 size, char *outstring) { switch (size & 0x3) { case 0x1: return sprintf(outstring, ".b "); case 0x3: return sprintf(outstring, ".w "); case 0x2: return sprintf(outstring, ".l "); default: return sprintf(outstring, " "); } } ////////////////////////////////////////////////////////////////////////////// static int setsizestr2(u16 size, char *outstring) { switch (size & 0x3) { case 0x0: return sprintf(outstring, ".b "); case 0x1: return sprintf(outstring, ".w "); case 0x2: return sprintf(outstring, ".l "); default: return sprintf(outstring, " "); } } ////////////////////////////////////////////////////////////////////////////// static int setimmstr(u32 addr, u16 size, int *addsize, char *outstring) { switch (size & 0x3) { case 0x0: *addsize+=2; return sprintf(outstring, "#0x%X", (unsigned int)(c68k_word_read(addr) & 0xFF)); case 0x1: *addsize+=2; return sprintf(outstring, "#0x%X", (unsigned int)c68k_word_read(addr)); case 0x2: *addsize+=4; return sprintf(outstring, "#0x%X", (unsigned int)((c68k_word_read(addr) << 16) | c68k_word_read(addr+2))); default: return 0; } } ////////////////////////////////////////////////////////////////////////////// static int seteafieldstr(u32 addr, u16 modereg, int *addsize, char *outstring) { switch ((modereg >> 3) & 0x7) { case 0x0: // Dn return sprintf(outstring, "d%d", modereg & 0x7); case 0x1: // An return sprintf(outstring, "a%d", modereg & 0x7); case 0x2: // (An) return sprintf(outstring, "(a%d)", modereg & 0x7); case 0x3: // (An)+ return sprintf(outstring, "(a%d)+", modereg & 0x7); case 0x4: // -(An) return sprintf(outstring, "-(a%d)", modereg & 0x7); case 0x5: // (d16, An) *addsize += 2; return sprintf(outstring, "0x%X(a%d)", (unsigned int)c68k_word_read(addr), modereg & 0x7); case 0x6: // (d8,An,Xn) // fix me *addsize += 2; return sprintf(outstring, "0x%X(a%d, Xn)", (unsigned int)(c68k_word_read(addr) & 0xFF), modereg & 0x7); case 0x7: switch (modereg & 0x7) { case 0x0: // (xxx).W *addsize += 2; // fix me? return sprintf(outstring, "(0x%X).w", (unsigned int)c68k_word_read(addr)); case 0x1: // (xxx).L *addsize += 4; // fix me? return sprintf(outstring, "(0x%X).l", (unsigned int)((c68k_word_read(addr) << 16) | c68k_word_read(addr+2))); case 0x4: // # *addsize += 2; // fix me? return sprintf(outstring, "#0x%X", (unsigned int)c68k_word_read(addr)); case 0x2: // (d16,PC) *addsize += 2; return sprintf(outstring, "0x%X(PC)", (unsigned int)c68k_word_read(addr)); case 0x3: // (d8,PC,Xn) // fix me return 0; default: break; } default: break; } return 0; } ////////////////////////////////////////////////////////////////////////////// static int setcondstr(u16 cond, char *outstring) { switch (cond & 0xF) { case 0x0: // True return sprintf(outstring, "t "); case 0x1: // False return sprintf(outstring, "f "); case 0x2: // High return sprintf(outstring, "hi"); case 0x3: // Low or Same return sprintf(outstring, "ls"); case 0x4: // Carry Clear return sprintf(outstring, "cc"); case 0x5: // Carry Set return sprintf(outstring, "cs"); case 0x6: // Not Equal return sprintf(outstring, "ne"); case 0x7: // Equal return sprintf(outstring, "eq"); case 0x8: // Overflow Clear return sprintf(outstring, "vc"); case 0x9: // Overflow Set return sprintf(outstring, "vs"); case 0xA: // Plus return sprintf(outstring, "pl"); case 0xB: // Minus return sprintf(outstring, "mi"); case 0xC: // Greater or Equal return sprintf(outstring, "ge"); case 0xD: // Less Than return sprintf(outstring, "lt"); case 0xE: // Greater Than return sprintf(outstring, "gt"); case 0xF: // Less or Equal return sprintf(outstring, "le"); default: break; } return 0; } ////////////////////////////////////////////////////////////////////////////// static int setbranchdispstr(u32 addr, u16 op, int *addsize, char *outstring) { if ((op & 0xFF) == 0xFF) { // 32-bit displacement *addsize += 4; return sprintf(outstring, ".l %X", (unsigned int)(addr + ((c68k_word_read(addr) << 16) | c68k_word_read(addr+2)))); } else if ((op & 0xFF) == 0x00) { // 16-bit displacement *addsize += 2; return sprintf(outstring, ".w %X", (unsigned int)((s32)addr + (s32)(s16)c68k_word_read(addr))); } // 8-bit displacement return sprintf(outstring, ".s %X", (unsigned int)((s32)addr + (s32)(s8)(op & 0xFF))); } ////////////////////////////////////////////////////////////////////////////// static int disabcd(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "abcd"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disadd(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "add"); outstring += setsizestr2(op >> 6, outstring); outstring += sprintf(outstring, " "); if (op & 0x100) { // Dn, outstring += sprintf(outstring, "d%d, ", (op >> 9) & 7); seteafieldstr(addr+size, op, &size, outstring); } else { // , Dn outstring += seteafieldstr(addr+size, op, &size, outstring); sprintf(outstring, ", d%d", (op >> 9) & 7); } return size; } ////////////////////////////////////////////////////////////////////////////// static int disadda(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "adda"); if ((op & 0x1C0) == 0xC0) outstring += sprintf(outstring, ".w "); else outstring += sprintf(outstring, ".l "); outstring += seteafieldstr(addr+size, op, &size, outstring); outstring += sprintf(outstring, ", a%d", (op >> 9) & 0x7); return size; } ////////////////////////////////////////////////////////////////////////////// static int disaddi(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "addi"); outstring += setsizestr2(op >> 6, outstring); outstring += setimmstr(addr+size, op >> 6, &size, outstring); outstring += sprintf(outstring, ", "); seteafieldstr(addr+size, op, &size, outstring); return size; } ////////////////////////////////////////////////////////////////////////////// static int disaddq(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "addq"); outstring += setsizestr2(op >> 6, outstring); outstring += sprintf(outstring, " "); outstring += sprintf(outstring, "#%d, ", (op >> 9) & 7); // fix me seteafieldstr(addr+size, op, &size, outstring); return size; } ////////////////////////////////////////////////////////////////////////////// static int disaddx(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "addx"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disand(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "and"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disandi(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "andi"); outstring += setsizestr2(op >> 6, outstring); outstring += sprintf(outstring, " "); outstring += setimmstr(addr+size, op >> 6, &size, outstring); outstring += sprintf(outstring, ", "); seteafieldstr(addr+size, op, &size, outstring); return size; } ////////////////////////////////////////////////////////////////////////////// static int disanditoccr(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "andi to CCR"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disasl(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "asl"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disasr(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "asr"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disbcc(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "b"); outstring += setcondstr(op >> 8, outstring); setbranchdispstr(addr+size, op, &size, outstring); return size; } ////////////////////////////////////////////////////////////////////////////// static int disbkpt(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "bkpt"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disbra(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "bra"); setbranchdispstr(addr+size, op, &size, outstring); return size; } ////////////////////////////////////////////////////////////////////////////// static int disbchg(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "bchg"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disbclrd(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "bclr"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disbclrs(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "bclr "); outstring += setimmstr(addr+size, 0, &size, outstring); outstring += sprintf(outstring, ", "); seteafieldstr(addr+size, op, &size, outstring); return size; } ////////////////////////////////////////////////////////////////////////////// static int disbsetd(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "bset"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disbsets(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "bset "); outstring += setimmstr(addr+size, 0, &size, outstring); outstring += sprintf(outstring, ", "); seteafieldstr(addr+size, op, &size, outstring); return size; } ////////////////////////////////////////////////////////////////////////////// static int disbtstd(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "btst"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disbtsts(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "btst "); outstring += setimmstr(addr+size, 0, &size, outstring); outstring += sprintf(outstring, ", "); seteafieldstr(addr+size, op, &size, outstring); return size; } ////////////////////////////////////////////////////////////////////////////// static int disbsr(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "bsr"); setbranchdispstr(addr+size, op, &size, outstring); return size; } ////////////////////////////////////////////////////////////////////////////// static int dischk(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "chk"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disclr(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "clr"); outstring += setsizestr2((op >> 6), outstring); outstring += sprintf(outstring, " "); seteafieldstr(addr+size, op, &size, outstring); return size; } ////////////////////////////////////////////////////////////////////////////// static int disdbcc(u32 addr, u16 op, char *outstring) { outstring += sprintf(outstring, "db"); outstring += setcondstr(op >> 8, outstring); outstring += sprintf(outstring, " "); sprintf(outstring, " d%d, %X", op & 0x7, (unsigned int)((s32)addr+2+(s32)(s16)c68k_word_read(addr+2))); return 4; } ////////////////////////////////////////////////////////////////////////////// static int discmpb(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "cmp.b "); outstring += seteafieldstr(addr+size, op, &size, outstring); outstring += sprintf(outstring, ", d%d", (op >> 9) & 0x7); return size; } ////////////////////////////////////////////////////////////////////////////// static int discmpw(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "cmp.w "); outstring += seteafieldstr(addr+size, op, &size, outstring); outstring += sprintf(outstring, ", d%d", (op >> 9) & 0x7); return size; } ////////////////////////////////////////////////////////////////////////////// static int discmpl(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "cmp.l "); outstring += seteafieldstr(addr+size, op, &size, outstring); outstring += sprintf(outstring, ", d%d", (op >> 9) & 0x7); return size; } ////////////////////////////////////////////////////////////////////////////// static int discmpaw(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "cmpa.w"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int discmpal(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "cmpa.l"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int discmpi(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "cmpi"); outstring += setsizestr2((op >> 6), outstring); outstring += sprintf(outstring, " "); outstring += setimmstr(addr+size, op >> 6, &size, outstring); outstring += sprintf(outstring, ", "); seteafieldstr(addr+size, op, &size, outstring); return size; } ////////////////////////////////////////////////////////////////////////////// static int disdivs(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "divs.w"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disdivu(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "divu.w"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int discmpm(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "cmpm"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int diseorb(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "eor.b"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int diseorw(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "eor.w"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int diseorl(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "eor.l"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int diseori(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "eori"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int diseoritoccr(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "eori to ccr"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disexg(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "exg"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disext(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "ext"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disillegal(UNUSED u32 addr, UNUSED u16 op, char *outstring) { sprintf(outstring, "illegal"); return 2; } ////////////////////////////////////////////////////////////////////////////// static int disjmp(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "jmp "); seteafieldstr(addr+size, op, &size, outstring); return size; } ////////////////////////////////////////////////////////////////////////////// static int disjsr(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "jsr "); seteafieldstr(addr+size, op, &size, outstring); return size; } ////////////////////////////////////////////////////////////////////////////// static int dislea(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "lea "); outstring += seteafieldstr(addr+size, op, &size, outstring); outstring += sprintf(outstring, ", a%d", (op >> 9) & 0x7); return size; } ////////////////////////////////////////////////////////////////////////////// static int dislink(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "link"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int dislsl(UNUSED u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "lsl"); outstring += setsizestr2(op >> 6, outstring); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int dislsr(UNUSED u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "lsr"); outstring += setsizestr2(op >> 6, outstring); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int dismove(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "move"); outstring += setsizestr((op >> 12), outstring); outstring += sprintf(outstring, " "); outstring += seteafieldstr(addr+size, op, &size, outstring); outstring += sprintf(outstring, ", "); seteafieldstr(addr+size, ((op >> 3) & 0x38) | ((op >> 9) & 0x7), &size, outstring); return size; } ////////////////////////////////////////////////////////////////////////////// static int dismovea(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "movea"); outstring += setsizestr((op >> 12), outstring); outstring += seteafieldstr(addr+size, op, &size, outstring); outstring += sprintf(outstring, ", a%d", (op >> 9) & 0x7); return size; } ////////////////////////////////////////////////////////////////////////////// static int dismovetoccr(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "move to ccr"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int dismovefromsr(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "move from sr"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int dismovetosr(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "move "); outstring += seteafieldstr(addr+size, op, &size, outstring); sprintf(outstring, ", sr"); return size; } ////////////////////////////////////////////////////////////////////////////// static int dismovem(UNUSED u32 addr, UNUSED u16 op, char *outstring) { outstring += sprintf(outstring, "movem"); // fix me return 4; } ////////////////////////////////////////////////////////////////////////////// static int dismovep(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "movep"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int dismoveq(UNUSED u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "moveq #0x%X, d%d", op & 0xFF, (op >> 9) & 0x7); return size; } ////////////////////////////////////////////////////////////////////////////// static int dismuls(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "muls"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int dismulu(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "mulu"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disnbcd(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "nbcd"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disneg(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "neg"); outstring += setsizestr2((op >> 6), outstring); outstring += sprintf(outstring, " "); seteafieldstr(addr+size, op, &size, outstring); return size; } ////////////////////////////////////////////////////////////////////////////// static int disnegx(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "negx"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disnop(UNUSED u32 addr, UNUSED u16 op, char *outstring) { sprintf(outstring, "nop"); return 2; } ////////////////////////////////////////////////////////////////////////////// static int disnot(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "not"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disor(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "ori to CCR"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disori(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "ori"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disoritoccr(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "ori to CCR"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int dispea(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "pea"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disrol(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "rol"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disror(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "ror"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disroxl(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "roxl"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disroxr(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "roxr"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disrtr(UNUSED u32 addr, UNUSED u16 op, char *outstring) { sprintf(outstring, "rtr"); return 2; } ////////////////////////////////////////////////////////////////////////////// static int disrts(UNUSED u32 addr, UNUSED u16 op, char *outstring) { sprintf(outstring, "rts"); return 2; } ////////////////////////////////////////////////////////////////////////////// static int dissbcd(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "sbcd"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disscc(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "scc"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int dissub(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "sub"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int dissuba(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "suba"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int dissubi(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "subi"); outstring += setsizestr2(op >> 6, outstring); outstring += sprintf(outstring, " "); outstring += setimmstr(addr+size, op >> 6, &size, outstring); outstring += sprintf(outstring, ", "); seteafieldstr(addr+size, op, &size, outstring); return size; } ////////////////////////////////////////////////////////////////////////////// static int dissubq(u32 addr, u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "subq"); outstring += setsizestr2(op >> 6, outstring); outstring += sprintf(outstring, " #%d, ", (op >> 9) & 7); // fix me seteafieldstr(addr+size, op, &size, outstring); return size; } ////////////////////////////////////////////////////////////////////////////// static int dissubx(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "subx"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disswap(UNUSED u32 addr, u16 op, char *outstring) { sprintf(outstring, "swap d%d", op & 0x7); return 2; } ////////////////////////////////////////////////////////////////////////////// static int distas(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "tas"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int distrap(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "trap"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int distrapv(UNUSED u32 addr, UNUSED u16 op, char *outstring) { sprintf(outstring, "trapv"); return 2; } ////////////////////////////////////////////////////////////////////////////// static int distst(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "tst"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static int disunlk(UNUSED u32 addr, UNUSED u16 op, char *outstring) { int size=2; outstring += sprintf(outstring, "unlk"); // fix me return size; } ////////////////////////////////////////////////////////////////////////////// static m68kdis_struct instruction[] = { { 0xFFFF, 0x023C, "andi #??, CCR", disanditoccr }, { 0xFFFF, 0x0A3C, "eori #??, CCR", diseoritoccr }, { 0xFFFF, 0x4AFC, "illegal", disillegal }, { 0xFFFF, 0x4E71, "nop", disnop }, { 0xFFFF, 0x003C, "ori #??, CCR", disoritoccr }, { 0xFFFF, 0x4E77, "rtr", disrtr }, { 0xFFFF, 0x4E75, "rts", disrts }, { 0xFFFF, 0x4E76, "trapv", distrapv }, { 0xFFF8, 0x4848, "bkpt", disbkpt }, { 0xFFF8, 0x4E50, "link", dislink }, { 0xFFF8, 0x4840, "swap", disswap }, { 0xFFF8, 0x4E58, "unlk", disunlk }, { 0xFFF0, 0x4E40, "trap", distrap }, { 0xF1F8, 0xD100, "addx.b", disaddx }, { 0xF1F8, 0xD140, "addx.w", disaddx }, { 0xF1F8, 0xD180, "addx.l", disaddx }, { 0xF1F8, 0xB108, "cmpm.b", discmpm }, { 0xF1F8, 0xB148, "cmpm.w", discmpm }, { 0xF1F8, 0xB188, "cmpm.l", discmpm }, { 0xFFC0, 0xE1C0, "asl", disasl }, { 0xFFC0, 0xE0C0, "asr", disasr }, { 0xFFC0, 0x0880, "bclr", disbclrs }, { 0xFFC0, 0x08C0, "bset", disbsets }, { 0xFFC0, 0x0800, "btst", disbtsts }, { 0xFFC0, 0x4EC0, "jmp", disjmp }, { 0xFFC0, 0x4E80, "jsr", disjsr }, { 0xFFC0, 0x44C0, "move ??, CCR", dismovetoccr }, { 0xFFC0, 0x40C0, "move SR, ??", dismovefromsr }, { 0xFFC0, 0x46C0, "move ??, SR", dismovetosr }, { 0xFFC0, 0x4800, "nbcd", disnbcd }, { 0xFFC0, 0x4840, "pea", dispea }, { 0xFFC0, 0x4AC0, "tas", distas }, { 0xFE38, 0x4800, "ext", disext }, { 0xF1F0, 0xC100, "abcd", disabcd }, { 0xF1F0, 0x8100, "sbcd", dissbcd }, { 0xF0F8, 0x50C8, "dbcc", disdbcc }, { 0xFB80, 0x4880, "movem", dismovem }, { 0xFF00, 0x0600, "addi", disaddi }, { 0xFF00, 0x0200, "andi", disandi }, { 0xFF00, 0x6000, "bra", disbra }, { 0xFF00, 0x6100, "bsr", disbsr }, { 0xFF00, 0x4200, "clr", disclr }, { 0xFF00, 0x0C00, "cmpi", discmpi }, { 0xFF00, 0x0A00, "eori", diseori }, { 0xFF00, 0x4400, "neg", disneg }, { 0xFF00, 0x4000, "negx", disnegx }, { 0xFF00, 0x4600, "not", disnot }, { 0xFF00, 0x0000, "ori", disori }, { 0xFF00, 0x0400, "subi", dissubi }, { 0xFF00, 0x4A00, "tst", distst }, { 0xF118, 0xE108, "lsl", dislsl }, { 0xF118, 0xE008, "lsr", dislsr }, { 0xF118, 0xE118, "rol", disrol }, { 0xF118, 0xE018, "ror", disror }, { 0xF118, 0xE110, "roxl", disroxl }, { 0xF118, 0xE010, "roxr", disroxr }, { 0xF1C0, 0xD0C0, "adda.w", disadda }, { 0xF1C0, 0xD1C0, "adda.l", disadda }, { 0xF1C0, 0x0140, "bchg", disbchg }, { 0xF1C0, 0x0180, "bclr", disbclrd }, { 0xF1C0, 0x01C0, "bset", disbsetd }, { 0xF1C0, 0x0100, "btst", disbtstd }, { 0xF1C0, 0xB000, "cmp.b", discmpb }, { 0xF1C0, 0xB040, "cmp.w", discmpw }, { 0xF1C0, 0xB080, "cmp.l", discmpl }, { 0xF1C0, 0xB0C0, "cmpa.w", discmpaw }, { 0xF1C0, 0xB1C0, "cmpa.l", discmpal }, { 0xF1C0, 0x81C0, "divs.w", disdivs }, { 0xF1C0, 0x80C0, "divu.w", disdivu }, { 0xF1C0, 0xB100, "eor.b", diseorb }, { 0xF1C0, 0xB140, "eor.w", diseorw }, { 0xF1C0, 0xB180, "eor.l", diseorl }, { 0xF1C0, 0x41C0, "lea", dislea }, { 0xF1C0, 0xC1C0, "muls", dismuls }, { 0xF1C0, 0xC0C0, "mulu", dismulu }, { 0xF130, 0x9100, "subx", dissubx }, { 0xF038, 0x0008, "movep", dismovep }, { 0xF0C0, 0x50C0, "scc", disscc }, { 0xC1C0, 0x0040, "movea", dismovea }, { 0xF040, 0x4000, "chk", dischk }, { 0xF100, 0x5000, "addq", disaddq }, { 0xF100, 0xC100, "exg", disexg }, { 0xF100, 0x7000, "moveq", dismoveq }, { 0xF100, 0x5100, "subq", dissubq }, { 0xF000, 0xD000, "add", disadd }, // fix me { 0xF000, 0xC000, "and", disand }, { 0xF000, 0x6000, "bcc", disbcc }, { 0xF000, 0x8000, "or", disor }, { 0xF000, 0x9000, "sub", dissub }, // fix me { 0xF000, 0x9000, "suba", dissuba }, // fix me { 0xC000, 0x0000, "move", dismove }, { 0x0000, 0x0000, NULL, NULL } }; ////////////////////////////////////////////////////////////////////////////// u32 M68KDisasm(u32 addr, char *outstring) { int i; outstring += sprintf(outstring, "%05X: ", (unsigned int)addr); for (i = 0; instruction[i].name != NULL; i++) { u16 op = (u16)c68k_word_read(addr); if ((op & instruction[i].mask) == instruction[i].inst) { addr += instruction[i].disasm(addr, op, outstring); return addr; } } sprintf(outstring, "unknown"); return (addr+2); } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/osdcore.c000644 001750 001750 00000017740 12755623101 017655 0ustar00guillaumeguillaume000000 000000 /* Copyright 2012 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file osdcore.c \brief OSD dummy, glut, and software interfaces. */ #include "osdcore.h" #include "vdp1.h" #include "font.h" #include "titan/titan.h" #include #include #ifndef YAB_PORT_OSD /* Heya fellow port developper :) If you're reading this, that may be because you want to use your own OSD core in your port and you're about to do it here... Don't. Please define the CPP constant YAB_PORT_OSD and define your own list of OSD cores in your port. This definition was added here to avoid breaking "everything" when we the new OSD system was added. */ OSD_struct *OSDCoreList[] = { &OSDDummy, #ifdef HAVE_LIBGLUT &OSDGlut, #endif #ifndef _arch_dreamcast &OSDSoft, #endif NULL }; #else extern OSD_struct * OSDCoreList[]; #endif static OSD_struct * OSD = NULL; static OSDMessage_struct osdmessages[OSDMSG_COUNT]; int OSDInit(int coreid) { int i; for (i = 0; OSDCoreList[i] != NULL; i++) { if (OSDCoreList[i]->id == coreid) { OSD = OSDCoreList[i]; break; } } if (OSD == NULL) return -1; if (OSD->Init() != 0) return -1; memset(osdmessages, 0, sizeof(osdmessages)); osdmessages[OSDMSG_FPS].hidden = 1; osdmessages[OSDMSG_DEBUG].hidden = 1; return 0; } void OSDDeInit() { if (OSD) OSD->DeInit(); OSD = NULL; } int OSDChangeCore(int coreid) { int preservefps, fpshidden, dbghidden; preservefps = (OSD != NULL); fpshidden = osdmessages[OSDMSG_FPS].hidden; dbghidden = osdmessages[OSDMSG_DEBUG].hidden; OSDDeInit(); OSDInit(coreid); if (preservefps) { osdmessages[OSDMSG_FPS].hidden = fpshidden; osdmessages[OSDMSG_DEBUG].hidden = dbghidden; } return 0; } void OSDPushMessage(int msgtype, int ttl, const char * format, ...) { va_list arglist; char message[1024]; if (ttl == 0) return; va_start(arglist, format); vsprintf(message, format, arglist); va_end(arglist); osdmessages[msgtype].type = msgtype; osdmessages[msgtype].message = strdup(message); osdmessages[msgtype].timetolive = ttl; osdmessages[msgtype].timeleft = ttl; } int OSDDisplayMessages(pixel_t * buffer, int w, int h) { int i = 0; int somethingnew = 0; if (OSD == NULL) return somethingnew; for(i = 0;i < OSDMSG_COUNT;i++) if (osdmessages[i].timeleft > 0) { if (osdmessages[i].hidden == 0) { somethingnew = 1; OSD->DisplayMessage(osdmessages + i, buffer, w, h); } osdmessages[i].timeleft--; if (osdmessages[i].timeleft == 0) free(osdmessages[i].message); } return somethingnew; } void OSDToggle(int what) { if ((what < 0) || (what >= OSDMSG_COUNT)) return; osdmessages[what].hidden = 1 - osdmessages[what].hidden; } int OSDIsVisible(int what) { if ((what < 0) || (what >= OSDMSG_COUNT)) return -1; return 1 - osdmessages[what].hidden; } void OSDSetVisible(int what, int visible) { if ((what < 0) || (what >= OSDMSG_COUNT)) return; visible = visible == 0 ? 0 : 1; osdmessages[what].hidden = 1 - visible; } int OSDUseBuffer(void) { if (OSD == NULL) return 0; return OSD->UseBuffer(); } void ToggleFPS() { OSDToggle(OSDMSG_FPS); } int GetOSDToggle(void) { return OSDIsVisible(OSDMSG_FPS); } void SetOSDToggle(int toggle) { OSDSetVisible(OSDMSG_FPS, toggle); } void DisplayMessage(const char* str) { OSDPushMessage(OSDMSG_STATUS, 120, str); } static int OSDDummyInit(void); static void OSDDummyDeInit(void); static void OSDDummyReset(void); static void OSDDummyDisplayMessage(OSDMessage_struct * message, pixel_t * buffer, int w, int h); static int OSDDummyUseBuffer(void); OSD_struct OSDDummy = { OSDCORE_DUMMY, "Dummy OSD Interface", OSDDummyInit, OSDDummyDeInit, OSDDummyReset, OSDDummyDisplayMessage, OSDDummyUseBuffer, }; int OSDDummyInit(void) { return 0; } void OSDDummyDeInit(void) { } void OSDDummyReset(void) { } void OSDDummyDisplayMessage(OSDMessage_struct * message, pixel_t * buffer, int w, int h) { } int OSDDummyUseBuffer(void) { return 0; } #ifdef HAVE_LIBGLUT #ifdef __APPLE__ #include #else #include #endif static int OSDGlutInit(void); static void OSDGlutDeInit(void); static void OSDGlutReset(void); static void OSDGlutDisplayMessage(OSDMessage_struct * message, pixel_t * buffer, int w, int h); static int OSDGlutUseBuffer(void); OSD_struct OSDGlut = { OSDCORE_GLUT, "Glut OSD Interface", OSDGlutInit, OSDGlutDeInit, OSDGlutReset, OSDGlutDisplayMessage, OSDGlutUseBuffer }; int OSDGlutInit(void) { int fake_argc = 1; char * fake_argv[] = { "yabause" }; static int glutinited = 0; if (!glutinited) { glutInit(&fake_argc, fake_argv); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_STENCIL); glutinited = 1; } return 0; } void OSDGlutDeInit(void) { } void OSDGlutReset(void) { } void OSDGlutDisplayMessage(OSDMessage_struct * message, pixel_t * buffer, int w, int h) { int LeftX=9; int Width=500; int TxtY=11; int Height=13; int i, msglength; int vidwidth, vidheight; VIDCore->GetGlSize(&vidwidth, &vidheight); Width = vidwidth - 2 * LeftX; switch(message->type) { case OSDMSG_STATUS: TxtY = vidheight - (Height + TxtY); break; } msglength = strlen(message->message); glBegin(GL_POLYGON); glColor3f(0, 0, 0); glVertex2i(LeftX, TxtY); glVertex2i(LeftX + Width, TxtY); glVertex2i(LeftX + Width, TxtY + Height); glVertex2i(LeftX, TxtY + Height); glEnd(); glColor3f(1.0f, 1.0f, 1.0f); glRasterPos2i(10, TxtY + 11); for (i = 0; i < msglength; i++) { glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, message->message[i]); } glColor3f(1, 1, 1); } int OSDGlutUseBuffer(void) { return 0; } #endif #ifndef _arch_dreamcast static int OSDSoftInit(void); static void OSDSoftDeInit(void); static void OSDSoftReset(void); static void OSDSoftDisplayMessage(OSDMessage_struct * message, pixel_t * buffer, int w, int h); static int OSDSoftUseBuffer(void); OSD_struct OSDSoft = { OSDCORE_SOFT, "Software OSD Interface", OSDSoftInit, OSDSoftDeInit, OSDSoftReset, OSDSoftDisplayMessage, OSDSoftUseBuffer }; int OSDSoftInit(void) { return 0; } void OSDSoftDeInit(void) { } void OSDSoftReset(void) { } void OSDSoftDisplayMessage(OSDMessage_struct * message, pixel_t * buffer, int w, int h) { int i; char * c; int loffset = 0; if (buffer == NULL) return; switch (message->type) { case OSDMSG_STATUS: loffset = h - 48; break; } c = message->message; i = 0; while(*c) { if (*c >= 47) { int first_line, l, p; first_line = *c * 10; for(l = 0;l < 10;l++) { for(p = 0;p < 9;p++) { if (font[first_line + l][p] == '.') TitanWriteColor(buffer, w, (i * 8) + 20 + p, loffset + l + 20, 0xFF000000); else if (font[first_line + l][p] == '#') TitanWriteColor(buffer, w, (i * 8) + 20 + p, loffset + l + 20, 0xFFFFFFFF); } } } c++; i++; } } int OSDSoftUseBuffer(void) { return 1; } #endif /* !_arch_dreamcast */ yabause-0.9.15/src/sh2d.h000644 001750 001750 00000001633 12755623101 017056 0ustar00guillaumeguillaume000000 000000 /* Copyright 2004 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SH2D_H #define SH2D_H #include "core.h" void SH2Disasm(u32 v_addr, u16 op, int mode, sh2regs_struct *r, char *string); #endif yabause-0.9.15/src/debug.c000644 001750 001750 00000011051 12755623101 017272 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005 Guillaume Duhamel Copyright 2006 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file debug.c \brief Debug logging functions. */ #include "debug.h" #include #include #include ////////////////////////////////////////////////////////////////////////////// Debug * DebugInit(const char * n, DebugOutType t, char * s) { Debug * d; if ((d = (Debug *) malloc(sizeof(Debug))) == NULL) return NULL; d->output_type = t; if ((d->name = strdup(n)) == NULL) { free(d); return NULL; } switch(t) { case DEBUG_STREAM: d->output.stream = fopen(s, "w"); break; case DEBUG_STRING: d->output.string = s; break; case DEBUG_STDOUT: d->output.stream = stdout; break; case DEBUG_STDERR: d->output.stream = stderr; break; case DEBUG_CALLBACK: d->output.callback = (void (*) (char*))s; break; } return d; } ////////////////////////////////////////////////////////////////////////////// void DebugDeInit(Debug * d) { if (d == NULL) return; switch(d->output_type) { case DEBUG_STREAM: if (d->output.stream) fclose(d->output.stream); break; case DEBUG_STRING: case DEBUG_STDOUT: case DEBUG_STDERR: case DEBUG_CALLBACK: break; } if (d->name) free(d->name); free(d); } ////////////////////////////////////////////////////////////////////////////// void DebugChangeOutput(Debug * d, DebugOutType t, char * s) { if (t != d->output_type) { if (d->output_type == DEBUG_STREAM) { if (d->output.stream) fclose(d->output.stream); } d->output_type = t; } switch(t) { case DEBUG_STREAM: d->output.stream = fopen(s, "w"); break; case DEBUG_STRING: d->output.string = s; break; case DEBUG_CALLBACK: d->output.callback = (void (*) (char*))s; break; case DEBUG_STDOUT: d->output.stream = stdout; break; case DEBUG_STDERR: d->output.stream = stderr; break; } } ////////////////////////////////////////////////////////////////////////////// void DebugPrintf(Debug * d, const char * file, u32 line, const char * format, ...) { va_list l; static char strtmp[512]; static int strhash; if (d == NULL) return; va_start(l, format); switch(d->output_type) { case DEBUG_STDOUT: case DEBUG_STDERR: case DEBUG_STREAM: if (d->output.stream == NULL) break; fprintf(d->output.stream, "%s (%s:%ld): ", d->name, file, (long)line); vfprintf(d->output.stream, format, l); break; case DEBUG_STRING: { int i; if (d->output.string == NULL) break; i = sprintf(d->output.string, "%s (%s:%ld): ", d->name, file, (long)line); vsprintf(d->output.string + i, format, l); } break; case DEBUG_CALLBACK: { int i; int strnewhash = 0; i = sprintf(strtmp, "%s (%s:%ld): ", d->name, file, (long)line); i += vsprintf(strtmp + i, format, l); for ( ; i>0 ; i-- ) strnewhash += (int)(strtmp[i]); if ( strnewhash != strhash ) d->output.callback( strtmp ); strhash = strnewhash; } break; } va_end(l); } ////////////////////////////////////////////////////////////////////////////// Debug * MainLog; ////////////////////////////////////////////////////////////////////////////// void LogStart(void) { MainLog = DebugInit("main", DEBUG_STDOUT, NULL); // MainLog = DebugInit("main", DEBUG_STREAM, "stdout.txt"); } ////////////////////////////////////////////////////////////////////////////// void LogStop(void) { DebugDeInit(MainLog); MainLog = NULL; } ////////////////////////////////////////////////////////////////////////////// void LogChangeOutput(DebugOutType t, char * s) { DebugChangeOutput( MainLog, t, s ); } yabause-0.9.15/src/vidshared.c000644 001750 001750 00000046140 12755623101 020164 0ustar00guillaumeguillaume000000 000000 /* Copyright 2003-2006 Guillaume Duhamel Copyright 2004-2007 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file vidshared.c \brief Functions shared between opengl and software video renderers. */ #include "ygl.h" #include "vidshared.h" #include "vdp2.h" #include "debug.h" ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp2NBG0PlaneAddr(vdp2draw_struct *info, int i, Vdp2* regs) { u32 offset = (regs->MPOFN & 0x7) << 6; u32 tmp=0; switch(i) { case 0: tmp = offset | (regs->MPABN0 & 0xFF); break; case 1: tmp = offset | (regs->MPABN0 >> 8); break; case 2: tmp = offset | (regs->MPCDN0 & 0xFF); break; case 3: tmp = offset | (regs->MPCDN0 >> 8); break; } CalcPlaneAddr(info, tmp); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp2NBG1PlaneAddr(vdp2draw_struct *info, int i, Vdp2* regs) { u32 offset = (regs->MPOFN & 0x70) << 2; u32 tmp=0; switch(i) { case 0: tmp = offset | (regs->MPABN1 & 0xFF); break; case 1: tmp = offset | (regs->MPABN1 >> 8); break; case 2: tmp = offset | (regs->MPCDN1 & 0xFF); break; case 3: tmp = offset | (regs->MPCDN1 >> 8); break; } CalcPlaneAddr(info, tmp); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp2NBG2PlaneAddr(vdp2draw_struct *info, int i, Vdp2* regs) { u32 offset = (regs->MPOFN & 0x700) >> 2; u32 tmp=0; switch(i) { case 0: tmp = offset | (regs->MPABN2 & 0xFF); break; case 1: tmp = offset | (regs->MPABN2 >> 8); break; case 2: tmp = offset | (regs->MPCDN2 & 0xFF); break; case 3: tmp = offset | (regs->MPCDN2 >> 8); break; } CalcPlaneAddr(info, tmp); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp2NBG3PlaneAddr(vdp2draw_struct *info, int i, Vdp2* regs) { u32 offset = (regs->MPOFN & 0x7000) >> 6; u32 tmp=0; switch(i) { case 0: tmp = offset | (regs->MPABN3 & 0xFF); break; case 1: tmp = offset | (regs->MPABN3 >> 8); break; case 2: tmp = offset | (regs->MPCDN3 & 0xFF); break; case 3: tmp = offset | (regs->MPCDN3 >> 8); break; } CalcPlaneAddr(info, tmp); } ////////////////////////////////////////////////////////////////////////////// void Vdp2ReadRotationTable(int which, vdp2rotationparameter_struct *parameter, Vdp2* regs, u8* ram) { s32 i; u32 addr; addr = regs->RPTA.all << 1; if (which == 0) { // Rotation Parameter A addr &= 0x000FFF7C; parameter->coefenab = regs->KTCTL & 0x1; parameter->screenover = (regs->PLSZ >> 10) & 0x3; } else { // Rotation Parameter B addr = (addr & 0x000FFFFC) | 0x00000080; parameter->coefenab = regs->KTCTL & 0x100; parameter->screenover = (regs->PLSZ >> 14) & 0x3; } i = T1ReadLong(ram, addr); parameter->Xst = (float) (signed) ((i & 0x1FFFFFC0) | (i & 0x10000000 ? 0xF0000000 : 0x00000000)) / 65536; addr += 4; i = T1ReadLong(ram, addr); parameter->Yst = (float) (signed) ((i & 0x1FFFFFC0) | (i & 0x10000000 ? 0xF0000000 : 0x00000000)) / 65536; addr += 4; i = T1ReadLong(ram, addr); parameter->Zst = (float) (signed) ((i & 0x1FFFFFC0) | (i & 0x10000000 ? 0xF0000000 : 0x00000000)) / 65536; addr += 4; i = T1ReadLong(ram, addr); parameter->deltaXst = (float) (signed) ((i & 0x0007FFC0) | (i & 0x00040000 ? 0xFFFC0000 : 0x00000000)) / 65536; addr += 4; i = T1ReadLong(ram, addr); parameter->deltaYst = (float) (signed) ((i & 0x0007FFC0) | (i & 0x00040000 ? 0xFFFC0000 : 0x00000000)) / 65536; addr += 4; i = T1ReadLong(ram, addr); parameter->deltaX = (float) (signed) ((i & 0x0007FFC0) | (i & 0x00040000 ? 0xFFFC0000 : 0x00000000)) / 65536; addr += 4; i = T1ReadLong(ram, addr); parameter->deltaY = (float) (signed) ((i & 0x0007FFC0) | (i & 0x00040000 ? 0xFFFC0000 : 0x00000000)) / 65536; addr += 4; i = T1ReadLong(ram, addr); parameter->A = (float) (signed) ((i & 0x000FFFC0) | (i & 0x00080000 ? 0xFFF80000 : 0x00000000)) / 65536; addr += 4; i = T1ReadLong(ram, addr); parameter->B = (float) (signed) ((i & 0x000FFFC0) | ((i & 0x00080000) ? 0xFFF80000 : 0x00000000)) / 65536; addr += 4; i = T1ReadLong(ram, addr); parameter->C = (float) (signed) ((i & 0x000FFFC0) | (i & 0x00080000 ? 0xFFF80000 : 0x00000000)) / 65536; addr += 4; i = T1ReadLong(ram, addr); parameter->D = (float) (signed) ((i & 0x000FFFC0) | (i & 0x00080000 ? 0xFFF80000 : 0x00000000)) / 65536; addr += 4; i = T1ReadLong(ram, addr); parameter->E = (float) (signed) ((i & 0x000FFFC0) | (i & 0x00080000 ? 0xFFF80000 : 0x00000000)) / 65536; addr += 4; i = T1ReadLong(ram, addr); parameter->F = (float) (signed) ((i & 0x000FFFC0) | (i & 0x00080000 ? 0xFFF80000 : 0x00000000)) / 65536; addr += 4; i = T1ReadWord(ram, addr); parameter->Px = (float) (signed) ((i & 0x3FFF) | (i & 0x2000 ? 0xFFF80000 : 0x00000000)); addr += 2; i = T1ReadWord(ram, addr); parameter->Py = (float) (signed) ((i & 0x3FFF) | (i & 0x2000 ? 0xFFF80000 : 0x00000000)); addr += 2; i = T1ReadWord(ram, addr); parameter->Pz = (float) (signed) ((i & 0x3FFF) | (i & 0x2000 ? 0xFFF80000 : 0x00000000)); addr += 4; i = T1ReadWord(ram, addr); parameter->Cx = (float) (signed) ((i & 0x3FFF) | (i & 0x2000 ? 0xFFF80000 : 0x00000000)); addr += 2; i = T1ReadWord(ram, addr); parameter->Cy = (float) (signed) ((i & 0x3FFF) | (i & 0x2000 ? 0xFFF80000 : 0x00000000)); addr += 2; i = T1ReadWord(ram, addr); parameter->Cz = (float) (signed) ((i & 0x3FFF) | (i & 0x2000 ? 0xFFF80000 : 0x00000000)); addr += 4; i = T1ReadLong(ram, addr); parameter->Mx = (float) (signed) ((i & 0x3FFFFFC0) | (i & 0x20000000 ? 0xE0000000 : 0x00000000)) / 65536; addr += 4; i = T1ReadLong(ram, addr); parameter->My = (float) (signed) ((i & 0x3FFFFFC0) | (i & 0x20000000 ? 0xE0000000 : 0x00000000)) / 65536; addr += 4; i = T1ReadLong(ram, addr); parameter->kx = (float) (signed) ((i & 0x00FFFFFF) | (i & 0x00800000 ? 0xFF800000 : 0x00000000)) / 65536; addr += 4; i = T1ReadLong(ram, addr); parameter->ky = (float) (signed) ((i & 0x00FFFFFF) | (i & 0x00800000 ? 0xFF800000 : 0x00000000)) / 65536; addr += 4; if (parameter->coefenab) { // Read in coefficient values i = T1ReadLong(ram, addr); parameter->KAst = (float)(unsigned)(i & 0xFFFFFFC0) / 65536; addr += 4; i = T1ReadLong(ram, addr); parameter->deltaKAst = (float) (signed) ((i & 0x03FFFFC0) | (i & 0x02000000 ? 0xFE000000 : 0x00000000)) / 65536; addr += 4; i = T1ReadLong(ram, addr); parameter->deltaKAx = (float) (signed) ((i & 0x03FFFFC0) | (i & 0x02000000 ? 0xFE000000 : 0x00000000)) / 65536; addr += 4; if (which == 0) { parameter->coefdatasize = (regs->KTCTL & 0x2 ? 2 : 4); parameter->coeftbladdr = ((regs->KTAOF & 0x7) * 0x10000 + (int)(parameter->KAst)) * parameter->coefdatasize; parameter->coefmode = (regs->KTCTL >> 2) & 0x3; } else { parameter->coefdatasize = (regs->KTCTL & 0x200 ? 2 : 4); parameter->coeftbladdr = (((regs->KTAOF >> 8) & 0x7) * 0x10000 + (int)(parameter->KAst)) * parameter->coefdatasize; parameter->coefmode = (regs->KTCTL >> 10) & 0x3; } } VDP2LOG("Xst: %f, Yst: %f, Zst: %f, deltaXst: %f deltaYst: %f deltaX: %f\n" "deltaY: %f A: %f B: %f C: %f D: %f E: %f F: %f Px: %f Py: %f Pz: %f\n" "Cx: %f Cy: %f Cz: %f Mx: %f My: %f kx: %f ky: %f KAst: %f\n" "deltaKAst: %f deltaKAx: %f kadr %08X\n", parameter->Xst, parameter->Yst, parameter->Zst, parameter->deltaXst, parameter->deltaYst, parameter->deltaX, parameter->deltaY, parameter->A, parameter->B, parameter->C, parameter->D, parameter->E, parameter->F, parameter->Px, parameter->Py, parameter->Pz, parameter->Cx, parameter->Cy, parameter->Cz, parameter->Mx, parameter->My, parameter->kx, parameter->ky, parameter->KAst, parameter->deltaKAst, parameter->deltaKAx,parameter->coeftbladdr); } ////////////////////////////////////////////////////////////////////////////// void Vdp2ReadRotationTableFP(int which, vdp2rotationparameterfp_struct *parameter, Vdp2* regs, u8 * ram) { s32 i; u32 addr; addr = regs->RPTA.all << 1; if (which == 0) { // Rotation Parameter A addr &= 0x000FFF7C; parameter->coefenab = regs->KTCTL & 0x1; parameter->screenover = (regs->PLSZ >> 10) & 0x3; } else { // Rotation Parameter B addr = (addr & 0x000FFFFC) | 0x00000080; parameter->coefenab = regs->KTCTL & 0x100; parameter->screenover = (regs->PLSZ >> 14) & 0x3; } i = T1ReadLong(ram, addr); parameter->Xst = (signed) ((i & 0x1FFFFFC0) | (i & 0x10000000 ? 0xF0000000 : 0x00000000)); addr += 4; i = T1ReadLong(ram, addr); parameter->Yst = (signed) ((i & 0x1FFFFFC0) | (i & 0x10000000 ? 0xF0000000 : 0x00000000)); addr += 4; i = T1ReadLong(ram, addr); parameter->Zst = (signed) ((i & 0x1FFFFFC0) | (i & 0x10000000 ? 0xF0000000 : 0x00000000)); addr += 4; i = T1ReadLong(ram, addr); parameter->deltaXst = (signed) ((i & 0x0007FFC0) | (i & 0x00040000 ? 0xFFFC0000 : 0x00000000)); addr += 4; i = T1ReadLong(ram, addr); parameter->deltaYst = (signed) ((i & 0x0007FFC0) | (i & 0x00040000 ? 0xFFFC0000 : 0x00000000)); addr += 4; i = T1ReadLong(ram, addr); parameter->deltaX = (signed) ((i & 0x0007FFC0) | (i & 0x00040000 ? 0xFFFC0000 : 0x00000000)); addr += 4; i = T1ReadLong(ram, addr); parameter->deltaY = (signed) ((i & 0x0007FFC0) | (i & 0x00040000 ? 0xFFFC0000 : 0x00000000)); addr += 4; i = T1ReadLong(ram, addr); parameter->A = (signed) ((i & 0x000FFFC0) | (i & 0x00080000 ? 0xFFF80000 : 0x00000000)); addr += 4; i = T1ReadLong(ram, addr); parameter->B = (signed) ((i & 0x000FFFC0) | ((i & 0x00080000) ? 0xFFF80000 : 0x00000000)); addr += 4; i = T1ReadLong(ram, addr); parameter->C = (signed) ((i & 0x000FFFC0) | (i & 0x00080000 ? 0xFFF80000 : 0x00000000)); addr += 4; i = T1ReadLong(ram, addr); parameter->D = (signed) ((i & 0x000FFFC0) | (i & 0x00080000 ? 0xFFF80000 : 0x00000000)); addr += 4; i = T1ReadLong(ram, addr); parameter->E = (signed) ((i & 0x000FFFC0) | (i & 0x00080000 ? 0xFFF80000 : 0x00000000)); addr += 4; i = T1ReadLong(ram, addr); parameter->F = (signed) ((i & 0x000FFFC0) | (i & 0x00080000 ? 0xFFF80000 : 0x00000000)); addr += 4; i = T1ReadWord(ram, addr); parameter->Px = tofixed((signed) ((i & 0x3FFF) | (i & 0x2000 ? 0xFFF80000 : 0x00000000))); addr += 2; i = T1ReadWord(ram, addr); parameter->Py = tofixed((signed) ((i & 0x3FFF) | (i & 0x2000 ? 0xFFF80000 : 0x00000000))); addr += 2; i = T1ReadWord(ram, addr); parameter->Pz = tofixed((signed) ((i & 0x3FFF) | (i & 0x2000 ? 0xFFF80000 : 0x00000000))); addr += 4; i = T1ReadWord(ram, addr); parameter->Cx = tofixed((signed) ((i & 0x3FFF) | (i & 0x2000 ? 0xFFF80000 : 0x00000000))); addr += 2; i = T1ReadWord(ram, addr); parameter->Cy = tofixed((signed) ((i & 0x3FFF) | (i & 0x2000 ? 0xFFF80000 : 0x00000000))); addr += 2; i = T1ReadWord(ram, addr); parameter->Cz = tofixed((signed) ((i & 0x3FFF) | (i & 0x2000 ? 0xFFF80000 : 0x00000000))); addr += 4; i = T1ReadLong(ram, addr); parameter->Mx = (signed) ((i & 0x3FFFFFC0) | (i & 0x20000000 ? 0xE0000000 : 0x00000000)); addr += 4; i = T1ReadLong(ram, addr); parameter->My = (signed) ((i & 0x3FFFFFC0) | (i & 0x20000000 ? 0xE0000000 : 0x00000000)); addr += 4; i = T1ReadLong(ram, addr); parameter->kx = (signed) ((i & 0x00FFFFFF) | (i & 0x00800000 ? 0xFF800000 : 0x00000000)); addr += 4; i = T1ReadLong(ram, addr); parameter->ky = (signed) ((i & 0x00FFFFFF) | (i & 0x00800000 ? 0xFF800000 : 0x00000000)); addr += 4; if (parameter->coefenab) { // Read in coefficient values i = T1ReadLong(ram, addr); parameter->KAst = (unsigned)(i & 0xFFFFFFC0); addr += 4; i = T1ReadLong(ram, addr); parameter->deltaKAst = (signed) ((i & 0x03FFFFC0) | (i & 0x02000000 ? 0xFE000000 : 0x00000000)); addr += 4; i = T1ReadLong(ram, addr); parameter->deltaKAx = (signed) ((i & 0x03FFFFC0) | (i & 0x02000000 ? 0xFE000000 : 0x00000000)); addr += 4; if (which == 0) { parameter->coefdatasize = (regs->KTCTL & 0x2 ? 2 : 4); parameter->coeftbladdr = ((regs->KTAOF & 0x7) * 0x10000 + touint(parameter->KAst)) * parameter->coefdatasize; parameter->coefmode = (regs->KTCTL >> 2) & 0x3; } else { parameter->coefdatasize = (regs->KTCTL & 0x200 ? 2 : 4); parameter->coeftbladdr = (((regs->KTAOF >> 8) & 0x7) * 0x10000 + touint(parameter->KAst)) * parameter->coefdatasize; parameter->coefmode = (regs->KTCTL >> 10) & 0x3; } } VDP2LOG("Xst: %f, Yst: %f, Zst: %f, deltaXst: %f deltaYst: %f deltaX: %f\n" "deltaY: %f A: %f B: %f C: %f D: %f E: %f F: %f Px: %f Py: %f Pz: %f\n" "Cx: %f Cy: %f Cz: %f Mx: %f My: %f kx: %f ky: %f KAst: %f\n" "deltaKAst: %f deltaKAx: %f\n", tofloat(parameter->Xst), tofloat(parameter->Yst), tofloat(parameter->Zst), tofloat(parameter->deltaXst), tofloat(parameter->deltaYst), tofloat(parameter->deltaX), tofloat(parameter->deltaY), tofloat(parameter->A), tofloat(parameter->B), tofloat(parameter->C), tofloat(parameter->D), tofloat(parameter->E), tofloat(parameter->F), tofloat(parameter->Px), tofloat(parameter->Py), tofloat(parameter->Pz), tofloat(parameter->Cx), tofloat(parameter->Cy), tofloat(parameter->Cz), tofloat(parameter->Mx), tofloat(parameter->My), tofloat(parameter->kx), tofloat(parameter->ky), tofloat(parameter->KAst), tofloat(parameter->deltaKAst), tofloat(parameter->deltaKAx)); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp2ParameterAPlaneAddr(vdp2draw_struct *info, int i, Vdp2* regs) { u32 offset = (regs->MPOFR & 0x7) << 6; u32 tmp=0; switch(i) { case 0: tmp = offset | (regs->MPABRA & 0xFF); break; case 1: tmp = offset | (regs->MPABRA >> 8); break; case 2: tmp = offset | (regs->MPCDRA & 0xFF); break; case 3: tmp = offset | (regs->MPCDRA >> 8); break; case 4: tmp = offset | (regs->MPEFRA & 0xFF); break; case 5: tmp = offset | (regs->MPEFRA >> 8); break; case 6: tmp = offset | (regs->MPGHRA & 0xFF); break; case 7: tmp = offset | (regs->MPGHRA >> 8); break; case 8: tmp = offset | (regs->MPIJRA & 0xFF); break; case 9: tmp = offset | (regs->MPIJRA >> 8); break; case 10: tmp = offset | (regs->MPKLRA & 0xFF); break; case 11: tmp = offset | (regs->MPKLRA >> 8); break; case 12: tmp = offset | (regs->MPMNRA & 0xFF); break; case 13: tmp = offset | (regs->MPMNRA >> 8); break; case 14: tmp = offset | (regs->MPOPRA & 0xFF); break; case 15: tmp = offset | (regs->MPOPRA >> 8); break; } CalcPlaneAddr(info, tmp); } ////////////////////////////////////////////////////////////////////////////// void FASTCALL Vdp2ParameterBPlaneAddr(vdp2draw_struct *info, int i, Vdp2* regs) { u32 offset = (regs->MPOFR & 0x70) << 2; u32 tmp=0; // Parameter B switch(i) { case 0: tmp = offset | (regs->MPABRB & 0xFF); break; case 1: tmp = offset | (regs->MPABRB >> 8); break; case 2: tmp = offset | (regs->MPCDRB & 0xFF); break; case 3: tmp = offset | (regs->MPCDRB >> 8); break; case 4: tmp = offset | (regs->MPEFRB & 0xFF); break; case 5: tmp = offset | (regs->MPEFRB >> 8); break; case 6: tmp = offset | (regs->MPGHRB & 0xFF); break; case 7: tmp = offset | (regs->MPGHRB >> 8); break; case 8: tmp = offset | (regs->MPIJRB & 0xFF); break; case 9: tmp = offset | (regs->MPIJRB >> 8); break; case 10: tmp = offset | (regs->MPKLRB & 0xFF); break; case 11: tmp = offset | (regs->MPKLRB >> 8); break; case 12: tmp = offset | (regs->MPMNRB & 0xFF); break; case 13: tmp = offset | (regs->MPMNRB >> 8); break; case 14: tmp = offset | (regs->MPOPRB & 0xFF); break; case 15: tmp = offset | (regs->MPOPRB >> 8); break; } CalcPlaneAddr(info, tmp); } ////////////////////////////////////////////////////////////////////////////// float Vdp2ReadCoefficientMode0_2(vdp2rotationparameter_struct *parameter, u32 addr, u8 * ram) { s32 i; if (parameter->coefdatasize == 2) { addr &= 0x7FFFE; i = T1ReadWord(ram, addr); parameter->msb = (i >> 15) & 0x1; return (float) (signed) ((i & 0x7FFF) | (i & 0x4000 ? 0xFFFFC000 : 0x00000000)) / 1024; } else { addr &= 0x7FFFC; i = T1ReadLong(ram, addr); parameter->msb = (i >> 31) & 0x1; return (float) (signed) ((i & 0x00FFFFFF) | (i & 0x00800000 ? 0xFF800000 : 0x00000000)) / 65536; } } ////////////////////////////////////////////////////////////////////////////// fixed32 Vdp2ReadCoefficientMode0_2FP(vdp2rotationparameterfp_struct *parameter, u32 addr, u8* ram) { s32 i; if (parameter->coefdatasize == 2) { addr &= 0x7FFFE; i = T1ReadWord(ram, addr); parameter->msb = (i >> 15) & 0x1; return (signed) ((i & 0x7FFF) | (i & 0x4000 ? 0xFFFFC000 : 0x00000000)) * 64; } else { addr &= 0x7FFFC; i = T1ReadLong(ram, addr); parameter->linescreen = (i >> 24) & 0x7F; parameter->msb = (i >> 31) & 0x1; return (signed) ((i & 0x00FFFFFF) | (i & 0x00800000 ? 0xFF800000 : 0x00000000)); } } ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/sh2iasm.c000644 001750 001750 00000114375 12755623101 017567 0ustar00guillaumeguillaume000000 000000 /* Code originally from Sega Saturn DeBuGgEr Written by TyRaNiD. Released under Public Domain. */ /*! \file sh2iasm.c \brief SH2 inline assembler. */ #include #include #include #include #include "sh-opc.h" #ifdef __cplusplus extern "C" { #endif sh_opcode_info sh_table[] = { /* 0111nnnni8*1.... add #, */{"add",{A_IMM,A_REG_N},{HEX_7,REG_N,IMM_8}}, /* 0011nnnnmmmm1100 add , */{"add",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_C}}, /* 0011nnnnmmmm1110 addc ,*/{"addc",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_E}}, /* 0011nnnnmmmm1111 addv ,*/{"addv",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_F}}, /* 11001001i8*1.... and #,R0 */{"and",{A_IMM,A_R0},{HEX_C,HEX_9,IMM_8}}, /* 0010nnnnmmmm1001 and , */{"and",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_9}}, /* 11001101i8*1.... and.b #,@(R0,GBR)*/{"and.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_D,IMM_8}}, /* 1010i12......... bra */{"bra",{A_BDISP12},{HEX_A,BRANCH_12}}, /* 1011i12......... bsr */{"bsr",{A_BDISP12},{HEX_B,BRANCH_12}}, /* 10001001i8p1.... bt */{"bt",{A_BDISP8},{HEX_8,HEX_9,BRANCH_8}}, /* 10001011i8p1.... bf */{"bf",{A_BDISP8},{HEX_8,HEX_B,BRANCH_8}}, /* 10001101i8p1.... bt.s */{"bt.s",{A_BDISP8},{HEX_8,HEX_D,BRANCH_8}}, /* 10001101i8p1.... bt/s */{"bt/s",{A_BDISP8},{HEX_8,HEX_D,BRANCH_8}}, /* 10001111i8p1.... bf.s */{"bf.s",{A_BDISP8},{HEX_8,HEX_F,BRANCH_8}}, /* 10001111i8p1.... bf/s */{"bf/s",{A_BDISP8},{HEX_8,HEX_F,BRANCH_8}}, /* 0000000000101000 clrmac */{"clrmac",{0},{HEX_0,HEX_0,HEX_2,HEX_8}}, /* 0000000001001000 clrs */{"clrs",{0},{HEX_0,HEX_0,HEX_4,HEX_8}}, /* 0000000000001000 clrt */{"clrt",{0},{HEX_0,HEX_0,HEX_0,HEX_8}}, /* 10001000i8*1.... cmp/eq #,R0 */{"cmp/eq",{A_IMM,A_R0},{HEX_8,HEX_8,IMM_8}}, /* 0011nnnnmmmm0000 cmp/eq ,*/{"cmp/eq",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_0}}, /* 0011nnnnmmmm0011 cmp/ge ,*/{"cmp/ge",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_3}}, /* 0011nnnnmmmm0111 cmp/gt ,*/{"cmp/gt",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_7}}, /* 0011nnnnmmmm0110 cmp/hi ,*/{"cmp/hi",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_6}}, /* 0011nnnnmmmm0010 cmp/hs ,*/{"cmp/hs",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_2}}, /* 0100nnnn00010101 cmp/pl */{"cmp/pl",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_5}}, /* 0100nnnn00010001 cmp/pz */{"cmp/pz",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_1}}, /* 0010nnnnmmmm1100 cmp/str ,*/{"cmp/str",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_C}}, /* 0010nnnnmmmm0111 div0s ,*/{"div0s",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_7}}, /* 0000000000011001 div0u */{"div0u",{0},{HEX_0,HEX_0,HEX_1,HEX_9}}, /* 0011nnnnmmmm0100 div1 ,*/{"div1",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_4}}, /* 0110nnnnmmmm1110 exts.b ,*/{"exts.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_E}}, /* 0110nnnnmmmm1111 exts.w ,*/{"exts.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_F}}, /* 0110nnnnmmmm1100 extu.b ,*/{"extu.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_C}}, /* 0110nnnnmmmm1101 extu.w ,*/{"extu.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_D}}, /* 0100nnnn00101011 jmp @ */{"jmp",{A_IND_N},{HEX_4,REG_N,HEX_2,HEX_B}}, /* 0100nnnn00001011 jsr @ */{"jsr",{A_IND_N},{HEX_4,REG_N,HEX_0,HEX_B}}, /* 0100nnnn00001110 ldc ,SR */{"ldc",{A_REG_N,A_SR},{HEX_4,REG_N,HEX_0,HEX_E}}, /* 0100nnnn00011110 ldc ,GBR */{"ldc",{A_REG_N,A_GBR},{HEX_4,REG_N,HEX_1,HEX_E}}, /* 0100nnnn00101110 ldc ,VBR */{"ldc",{A_REG_N,A_VBR},{HEX_4,REG_N,HEX_2,HEX_E}}, /* 0100nnnn00111110 ldc ,SSR */{"ldc",{A_REG_N,A_SSR},{HEX_4,REG_N,HEX_3,HEX_E}}, /* 0100nnnn01001110 ldc ,SPC */{"ldc",{A_REG_N,A_SPC},{HEX_4,REG_N,HEX_4,HEX_E}}, /* 0100nnnn01111110 ldc ,DBR */{"ldc",{A_REG_N,A_DBR},{HEX_4,REG_N,HEX_7,HEX_E}}, /* 0100nnnn1xxx1110 ldc ,Rn_BANK */{"ldc",{A_REG_N,A_REG_B},{HEX_4,REG_N,REG_B,HEX_E}}, /* 0100nnnn00000111 ldc.l @+,SR */{"ldc.l",{A_INC_N,A_SR},{HEX_4,REG_N,HEX_0,HEX_7}}, /* 0100nnnn00010111 ldc.l @+,GBR */{"ldc.l",{A_INC_N,A_GBR},{HEX_4,REG_N,HEX_1,HEX_7}}, /* 0100nnnn00100111 ldc.l @+,VBR */{"ldc.l",{A_INC_N,A_VBR},{HEX_4,REG_N,HEX_2,HEX_7}}, /* 0100nnnn00110111 ldc.l @+,SSR */{"ldc.l",{A_INC_N,A_SSR},{HEX_4,REG_N,HEX_3,HEX_7}}, /* 0100nnnn01000111 ldc.l @+,SPC */{"ldc.l",{A_INC_N,A_SPC},{HEX_4,REG_N,HEX_4,HEX_7}}, /* 0100nnnn01110111 ldc.l @+,DBR */{"ldc.l",{A_INC_N,A_DBR},{HEX_4,REG_N,HEX_7,HEX_7}}, /* 0100nnnn1xxx0111 ldc.l ,Rn_BANK */{"ldc.l",{A_INC_N,A_REG_B},{HEX_4,REG_N,REG_B,HEX_7}}, /* 0100nnnn00001010 lds ,MACH */{"lds",{A_REG_N,A_MACH},{HEX_4,REG_N,HEX_0,HEX_A}}, /* 0100nnnn00011010 lds ,MACL */{"lds",{A_REG_N,A_MACL},{HEX_4,REG_N,HEX_1,HEX_A}}, /* 0100nnnn00101010 lds ,PR */{"lds",{A_REG_N,A_PR},{HEX_4,REG_N,HEX_2,HEX_A}}, /* 0100nnnn01011010 lds ,FPUL */{"lds",{A_REG_M,FPUL_N},{HEX_4,REG_M,HEX_5,HEX_A}}, /* 0100nnnn01101010 lds ,FPSCR */{"lds",{A_REG_M,FPSCR_N},{HEX_4,REG_M,HEX_6,HEX_A}}, /* 0100nnnn00000110 lds.l @+,MACH*/{"lds.l",{A_INC_N,A_MACH},{HEX_4,REG_N,HEX_0,HEX_6}}, /* 0100nnnn00010110 lds.l @+,MACL*/{"lds.l",{A_INC_N,A_MACL},{HEX_4,REG_N,HEX_1,HEX_6}}, /* 0100nnnn00100110 lds.l @+,PR */{"lds.l",{A_INC_N,A_PR},{HEX_4,REG_N,HEX_2,HEX_6}}, /* 0100nnnn01010110 lds.l @+,FPUL*/{"lds.l",{A_INC_M,FPUL_N},{HEX_4,REG_M,HEX_5,HEX_6}}, /* 0100nnnn01100110 lds.l @+,FPSCR*/{"lds.l",{A_INC_M,FPSCR_N},{HEX_4,REG_M,HEX_6,HEX_6}}, /* 0000000000111000 ldtlb */{"ldtlb",{0},{HEX_0,HEX_0,HEX_3,HEX_8}}, /* 0100nnnnmmmm1111 mac.w @+,@+*/{"mac.w",{A_INC_M,A_INC_N},{HEX_4,REG_N,REG_M,HEX_F}}, /* 1110nnnni8*1.... mov #, */{"mov",{A_IMM,A_REG_N},{HEX_E,REG_N,IMM_8}}, /* 0110nnnnmmmm0011 mov , */{"mov",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_3}}, /* 0000nnnnmmmm0100 mov.b ,@(R0,)*/{"mov.b",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_4}}, /* 0010nnnnmmmm0100 mov.b ,@-*/{"mov.b",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_4}}, /* 0010nnnnmmmm0000 mov.b ,@*/{"mov.b",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_0}}, /* 10000100mmmmi4*1 mov.b @(,),R0*/{"mov.b",{A_DISP_REG_M,A_R0},{HEX_8,HEX_4,REG_M,IMM_4}}, /* 11000100i8*1.... mov.b @(,GBR),R0*/{"mov.b",{A_DISP_GBR,A_R0},{HEX_C,HEX_4,IMM_8}}, /* 0000nnnnmmmm1100 mov.b @(R0,),*/{"mov.b",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_C}}, /* 0110nnnnmmmm0100 mov.b @+,*/{"mov.b",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_4}}, /* 0110nnnnmmmm0000 mov.b @,*/{"mov.b",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_0}}, /* 10000000mmmmi4*1 mov.b R0,@(,)*/{"mov.b",{A_R0,A_DISP_REG_M},{HEX_8,HEX_0,REG_M,IMM_4}}, /* 11000000i8*1.... mov.b R0,@(,GBR)*/{"mov.b",{A_R0,A_DISP_GBR},{HEX_C,HEX_0,IMM_8}}, /* 0001nnnnmmmmi4*4 mov.l ,@(,)*/{"mov.l",{ A_REG_M,A_DISP_REG_N},{HEX_1,REG_N,REG_M,IMM_4BY4}}, /* 0000nnnnmmmm0110 mov.l ,@(R0,)*/{"mov.l",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_6}}, /* 0010nnnnmmmm0110 mov.l ,@-*/{"mov.l",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_6}}, /* 0010nnnnmmmm0010 mov.l ,@*/{"mov.l",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_2}}, /* 0101nnnnmmmmi4*4 mov.l @(,),*/{"mov.l",{A_DISP_REG_M,A_REG_N},{HEX_5,REG_N,REG_M,IMM_4BY4}}, /* 11000110i8*4.... mov.l @(,GBR),R0*/{"mov.l",{A_DISP_GBR,A_R0},{HEX_C,HEX_6,IMM_8BY4}}, /* 1101nnnni8p4.... mov.l @(,PC),*/{"mov.l",{A_DISP_PC,A_REG_N},{HEX_D,REG_N,PCRELIMM_8BY4}}, /* 0000nnnnmmmm1110 mov.l @(R0,),*/{"mov.l",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_E}}, /* 0110nnnnmmmm0110 mov.l @+,*/{"mov.l",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_6}}, /* 0110nnnnmmmm0010 mov.l @,*/{"mov.l",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_2}}, /* 11000010i8*4.... mov.l R0,@(,GBR)*/{"mov.l",{A_R0,A_DISP_GBR},{HEX_C,HEX_2,IMM_8BY4}}, /* 0000nnnnmmmm0101 mov.w ,@(R0,)*/{"mov.w",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_5}}, /* 0010nnnnmmmm0101 mov.w ,@-*/{"mov.w",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_5}}, /* 0010nnnnmmmm0001 mov.w ,@*/{"mov.w",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_1}}, /* 10000101mmmmi4*2 mov.w @(,),R0*/{"mov.w",{A_DISP_REG_M,A_R0},{HEX_8,HEX_5,REG_M,IMM_4BY2}}, /* 11000101i8*2.... mov.w @(,GBR),R0*/{"mov.w",{A_DISP_GBR,A_R0},{HEX_C,HEX_5,IMM_8BY2}}, /* 1001nnnni8p2.... mov.w @(,PC),*/{"mov.w",{A_DISP_PC,A_REG_N},{HEX_9,REG_N,PCRELIMM_8BY2}}, /* 0000nnnnmmmm1101 mov.w @(R0,),*/{"mov.w",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_D}}, /* 0110nnnnmmmm0101 mov.w @+,*/{"mov.w",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_5}}, /* 0110nnnnmmmm0001 mov.w @,*/{"mov.w",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_1}}, /* 10000001mmmmi4*2 mov.w R0,@(,)*/{"mov.w",{A_R0,A_DISP_REG_M},{HEX_8,HEX_1,REG_M,IMM_4BY2}}, /* 11000001i8*2.... mov.w R0,@(,GBR)*/{"mov.w",{A_R0,A_DISP_GBR},{HEX_C,HEX_1,IMM_8BY2}}, /* 11000111i8p4.... mova @(,PC),R0*/{"mova",{A_DISP_PC,A_R0},{HEX_C,HEX_7,PCRELIMM_8BY4}}, /* 0000nnnn11000011 movca.l R0,@ */{"movca.l",{A_R0,A_IND_N},{HEX_0,REG_N,HEX_C,HEX_3}}, /* 0000nnnn00101001 movt */{"movt",{A_REG_N},{HEX_0,REG_N,HEX_2,HEX_9}}, /* 0010nnnnmmmm1111 muls ,*/{"muls",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_F}}, /* 0000nnnnmmmm0111 mul.l ,*/{"mul.l",{ A_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_7}}, /* 0010nnnnmmmm1110 mulu ,*/{"mulu",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_E}}, /* 0110nnnnmmmm1011 neg , */{"neg",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_B}}, /* 0110nnnnmmmm1010 negc ,*/{"negc",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_A}}, /* 0000000000001001 nop */{"nop",{0},{HEX_0,HEX_0,HEX_0,HEX_9}}, /* 0110nnnnmmmm0111 not , */{"not",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_7}}, /* 0000nnnn10010011 ocbi @ */{"ocbi",{A_IND_N},{HEX_0,REG_N,HEX_9,HEX_3}}, /* 0000nnnn10100011 ocbp @ */{"ocbp",{A_IND_N},{HEX_0,REG_N,HEX_A,HEX_3}}, /* 0000nnnn10110011 ocbwb @ */{"ocbwb",{A_IND_N},{HEX_0,REG_N,HEX_B,HEX_3}}, /* 11001011i8*1.... or #,R0 */{"or",{A_IMM,A_R0},{HEX_C,HEX_B,IMM_8}}, /* 0010nnnnmmmm1011 or , */{"or",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_B}}, /* 11001111i8*1.... or.b #,@(R0,GBR)*/{"or.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_F,IMM_8}}, /* 0000nnnn10000011 pref @ */{"pref",{A_IND_N},{HEX_0,REG_N,HEX_8,HEX_3}}, /* 0100nnnn00100100 rotcl */{"rotcl",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_4}}, /* 0100nnnn00100101 rotcr */{"rotcr",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_5}}, /* 0100nnnn00000100 rotl */{"rotl",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_4}}, /* 0100nnnn00000101 rotr */{"rotr",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_5}}, /* 0000000000101011 rte */{"rte",{0},{HEX_0,HEX_0,HEX_2,HEX_B}}, /* 0000000000001011 rts */{"rts",{0},{HEX_0,HEX_0,HEX_0,HEX_B}}, /* 0000000001011000 sets */{"sets",{0},{HEX_0,HEX_0,HEX_5,HEX_8}}, /* 0000000000011000 sett */{"sett",{0},{HEX_0,HEX_0,HEX_1,HEX_8}}, /* 0100nnnnmmmm1100 shad ,*/{"shad",{ A_REG_M,A_REG_N},{HEX_4,REG_N,REG_M,HEX_C}}, /* 0100nnnnmmmm1101 shld ,*/{"shld",{ A_REG_M,A_REG_N},{HEX_4,REG_N,REG_M,HEX_D}}, /* 0100nnnn00100000 shal */{"shal",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_0}}, /* 0100nnnn00100001 shar */{"shar",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_1}}, /* 0100nnnn00000000 shll */{"shll",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_0}}, /* 0100nnnn00101000 shll16 */{"shll16",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_8}}, /* 0100nnnn00001000 shll2 */{"shll2",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_8}}, /* 0100nnnn00011000 shll8 */{"shll8",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_8}}, /* 0100nnnn00000001 shlr */{"shlr",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_1}}, /* 0100nnnn00101001 shlr16 */{"shlr16",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_9}}, /* 0100nnnn00001001 shlr2 */{"shlr2",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_9}}, /* 0100nnnn00011001 shlr8 */{"shlr8",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_9}}, /* 0000000000011011 sleep */{"sleep",{0},{HEX_0,HEX_0,HEX_1,HEX_B}}, /* 0000nnnn00000010 stc SR, */{"stc",{A_SR,A_REG_N},{HEX_0,REG_N,HEX_0,HEX_2}}, /* 0000nnnn00010010 stc GBR, */{"stc",{A_GBR,A_REG_N},{HEX_0,REG_N,HEX_1,HEX_2}}, /* 0000nnnn00100010 stc VBR, */{"stc",{A_VBR,A_REG_N},{HEX_0,REG_N,HEX_2,HEX_2}}, /* 0000nnnn00110010 stc SSR, */{"stc",{A_SSR,A_REG_N},{HEX_0,REG_N,HEX_3,HEX_2}}, /* 0000nnnn01000010 stc SPC, */{"stc",{A_SPC,A_REG_N},{HEX_0,REG_N,HEX_4,HEX_2}}, /* 0000nnnn01100010 stc SGR, */{"stc",{A_SGR,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_2}}, /* 0000nnnn01110010 stc DBR, */{"stc",{A_DBR,A_REG_N},{HEX_0,REG_N,HEX_7,HEX_2}}, /* 0000nnnn1xxx0012 stc Rn_BANK, */{"stc",{A_REG_B,A_REG_N},{HEX_0,REG_N,REG_B,HEX_2}}, /* 0100nnnn00000011 stc.l SR,@- */{"stc.l",{A_SR,A_DEC_N},{HEX_4,REG_N,HEX_0,HEX_3}}, /* 0100nnnn00010011 stc.l GBR,@- */{"stc.l",{A_GBR,A_DEC_N},{HEX_4,REG_N,HEX_1,HEX_3}}, /* 0100nnnn00100011 stc.l VBR,@- */{"stc.l",{A_VBR,A_DEC_N},{HEX_4,REG_N,HEX_2,HEX_3}}, /* 0100nnnn00110011 stc.l SSR,@- */{"stc.l",{A_SSR,A_DEC_N},{HEX_4,REG_N,HEX_3,HEX_3}}, /* 0100nnnn01000011 stc.l SPC,@- */{"stc.l",{A_SPC,A_DEC_N},{HEX_4,REG_N,HEX_4,HEX_3}}, /* 0100nnnn01100011 stc.l SGR,@- */{"stc.l",{A_SGR,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_3}}, /* 0100nnnn01110011 stc.l DBR,@- */{"stc.l",{A_DBR,A_DEC_N},{HEX_4,REG_N,HEX_7,HEX_3}}, /* 0100nnnn1xxx0012 stc.l Rn_BANK,@- */{"stc.l",{A_REG_B,A_DEC_N},{HEX_4,REG_N,REG_B,HEX_3}}, /* 0000nnnn00001010 sts MACH, */{"sts",{A_MACH,A_REG_N},{HEX_0,REG_N,HEX_0,HEX_A}}, /* 0000nnnn00011010 sts MACL, */{"sts",{A_MACL,A_REG_N},{HEX_0,REG_N,HEX_1,HEX_A}}, /* 0000nnnn00101010 sts PR, */{"sts",{A_PR,A_REG_N},{HEX_0,REG_N,HEX_2,HEX_A}}, /* 0000nnnn01011010 sts FPUL, */{"sts",{FPUL_M,A_REG_N},{HEX_0,REG_N,HEX_5,HEX_A}}, /* 0000nnnn01101010 sts FPSCR, */{"sts",{FPSCR_M,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_A}}, /* 0100nnnn00000010 sts.l MACH,@-*/{"sts.l",{A_MACH,A_DEC_N},{HEX_4,REG_N,HEX_0,HEX_2}}, /* 0100nnnn00010010 sts.l MACL,@-*/{"sts.l",{A_MACL,A_DEC_N},{HEX_4,REG_N,HEX_1,HEX_2}}, /* 0100nnnn00100010 sts.l PR,@- */{"sts.l",{A_PR,A_DEC_N},{HEX_4,REG_N,HEX_2,HEX_2}}, /* 0100nnnn01010010 sts.l FPUL,@-*/{"sts.l",{FPUL_M,A_DEC_N},{HEX_4,REG_N,HEX_5,HEX_2}}, /* 0100nnnn01100010 sts.l FPSCR,@-*/{"sts.l",{FPSCR_M,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_2}}, /* 0011nnnnmmmm1000 sub , */{"sub",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_8}}, /* 0011nnnnmmmm1010 subc ,*/{"subc",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_A}}, /* 0011nnnnmmmm1011 subv ,*/{"subv",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_B}}, /* 0110nnnnmmmm1000 swap.b ,*/{"swap.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_8}}, /* 0110nnnnmmmm1001 swap.w ,*/{"swap.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_9}}, /* 0100nnnn00011011 tas.b @ */{"tas.b",{A_IND_N},{HEX_4,REG_N,HEX_1,HEX_B}}, /* 11000011i8*1.... trapa # */{"trapa",{A_IMM},{HEX_C,HEX_3,IMM_8}}, /* 11001000i8*1.... tst #,R0 */{"tst",{A_IMM,A_R0},{HEX_C,HEX_8,IMM_8}}, /* 0010nnnnmmmm1000 tst , */{"tst",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_8}}, /* 11001100i8*1.... tst.b #,@(R0,GBR)*/{"tst.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_C,IMM_8}}, /* 11001010i8*1.... xor #,R0 */{"xor",{A_IMM,A_R0},{HEX_C,HEX_A,IMM_8}}, /* 0010nnnnmmmm1010 xor , */{"xor",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_A}}, /* 11001110i8*1.... xor.b #,@(R0,GBR)*/{"xor.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_E,IMM_8}}, /* 0010nnnnmmmm1101 xtrct ,*/{"xtrct",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_D}}, /* 0000nnnnmmmm0111 mul.l ,*/{"mul.l",{ A_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_7}}, /* 0100nnnn00010000 dt */{"dt",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_0}}, /* 0011nnnnmmmm1101 dmuls.l ,*/{"dmuls.l",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_D}}, /* 0011nnnnmmmm0101 dmulu.l ,*/{"dmulu.l",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_5}}, /* 0000nnnnmmmm1111 mac.l @+,@+*/{"mac.l",{A_INC_M,A_INC_N},{HEX_0,REG_N,REG_M,HEX_F}}, /* 0000nnnn00100011 braf */{"braf",{A_REG_N},{HEX_0,REG_N,HEX_2,HEX_3}}, /* 0000nnnn00000011 bsrf */{"bsrf",{A_REG_N},{HEX_0,REG_N,HEX_0,HEX_3}}, /* 1111nnnn01011101 fabs */{"fabs",{FD_REG_N},{HEX_F,REG_N,HEX_5,HEX_D}}, /* 1111nnnnmmmm0000 fadd ,*/{"fadd",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_0}}, /* 1111nnn0mmm00000 fadd ,*/{"fadd",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_0}}, /* 1111nnnnmmmm0100 fcmp/eq ,*/{"fcmp/eq",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_4}}, /* 1111nnn0mmm00100 fcmp/eq ,*/{"fcmp/eq",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_4}}, /* 1111nnnnmmmm0101 fcmp/gt ,*/{"fcmp/gt",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_5}}, /* 1111nnn0mmm00101 fcmp/gt ,*/{"fcmp/gt",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_5}}, /* 1111nnn010111101 fcnvds ,FPUL*/{"fcnvds",{D_REG_N,FPUL_M},{HEX_F,REG_N,HEX_B,HEX_D}}, /* 1111nnn010101101 fcnvsd FPUL,*/{"fcnvsd",{FPUL_M,D_REG_N},{HEX_F,REG_N,HEX_A,HEX_D}}, /* 1111nnnnmmmm0011 fdiv ,*/{"fdiv",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_3}}, /* 1111nnn0mmm00011 fdiv ,*/{"fdiv",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_3}}, /* 1111nnmm11101101 fipr ,*/{"fipr",{V_REG_M,V_REG_N},{HEX_F,REG_NM,HEX_E,HEX_D}}, /* 1111nnnn10001101 fldi0 */{"fldi0",{F_REG_N},{HEX_F,REG_N,HEX_8,HEX_D}}, /* 1111nnnn10011101 fldi1 */{"fldi1",{F_REG_N},{HEX_F,REG_N,HEX_9,HEX_D}}, /* 1111nnnn00011101 flds ,FPUL*/{"flds",{F_REG_N,FPUL_M},{HEX_F,REG_N,HEX_1,HEX_D}}, /* 1111nnnn00101101 float FPUL,*/{"float",{FPUL_M,FD_REG_N},{HEX_F,REG_N,HEX_2,HEX_D}}, /* 1111nnnnmmmm1110 fmac FR0,,*/{"fmac",{F_FR0,F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_E}}, /* 1111nnnnmmmm1100 fmov ,*/{"fmov",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_C}}, /* 1111nnnnmmmm1100 fmov ,*/{"fmov",{DX_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_C}}, /* 1111nnnnmmmm1000 fmov @,*/{"fmov",{A_IND_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_8}}, /* 1111nnnnmmmm1000 fmov @,*/{"fmov",{A_IND_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_8}}, /* 1111nnnnmmmm1010 fmov ,@*/{"fmov",{F_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}}, /* 1111nnnnmmmm1010 fmov ,@*/{"fmov",{DX_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}}, /* 1111nnnnmmmm1001 fmov @+,*/{"fmov",{A_INC_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_9}}, /* 1111nnnnmmmm1001 fmov @+,*/{"fmov",{A_INC_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_9}}, /* 1111nnnnmmmm1011 fmov ,@-*/{"fmov",{F_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}}, /* 1111nnnnmmmm1011 fmov ,@-*/{"fmov",{DX_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}}, /* 1111nnnnmmmm0110 fmov @(R0,),*/{"fmov",{A_IND_R0_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_6}}, /* 1111nnnnmmmm0110 fmov @(R0,),*/{"fmov",{A_IND_R0_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_6}}, /* 1111nnnnmmmm0111 fmov ,@(R0,)*/{"fmov",{F_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}}, /* 1111nnnnmmmm0111 fmov ,@(R0,)*/{"fmov",{DX_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}}, /* 1111nnnnmmmm1000 fmov.d @,*/{"fmov.d",{A_IND_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_8}}, /* 1111nnnnmmmm1010 fmov.d ,@*/{"fmov.d",{DX_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}}, /* 1111nnnnmmmm1001 fmov.d @+,*/{"fmov.d",{A_INC_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_9}}, /* 1111nnnnmmmm1011 fmov.d ,@-*/{"fmov.d",{DX_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}}, /* 1111nnnnmmmm0110 fmov.d @(R0,),*/{"fmov.d",{A_IND_R0_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_6}}, /* 1111nnnnmmmm0111 fmov.d ,@(R0,)*/{"fmov.d",{DX_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}}, /* 1111nnnnmmmm1000 fmov.s @,*/{"fmov.s",{A_IND_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_8}}, /* 1111nnnnmmmm1010 fmov.s ,@*/{"fmov.s",{F_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}}, /* 1111nnnnmmmm1001 fmov.s @+,*/{"fmov.s",{A_INC_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_9}}, /* 1111nnnnmmmm1011 fmov.s ,@-*/{"fmov.s",{F_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}}, /* 1111nnnnmmmm0110 fmov.s @(R0,),*/{"fmov.s",{A_IND_R0_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_6}}, /* 1111nnnnmmmm0111 fmov.s ,@(R0,)*/{"fmov.s",{F_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}}, /* 1111nnnnmmmm0010 fmul ,*/{"fmul",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_2}}, /* 1111nnn0mmm00010 fmul ,*/{"fmul",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_2}}, /* 1111nnnn01001101 fneg */{"fneg",{FD_REG_N},{HEX_F,REG_N,HEX_4,HEX_D}}, /* 1111101111111101 frchg */{"frchg",{0},{HEX_F,HEX_B,HEX_F,HEX_D}}, /* 1111001111111101 fschg */{"fschg",{0},{HEX_F,HEX_3,HEX_F,HEX_D}}, /* 1111nnnn01101101 fsqrt */{"fsqrt",{FD_REG_N},{HEX_F,REG_N,HEX_6,HEX_D}}, /* 1111nnnn00001101 fsts FPUL,*/{"fsts",{FPUL_M,F_REG_N},{HEX_F,REG_N,HEX_0,HEX_D}}, /* 1111nnnnmmmm0001 fsub ,*/{"fsub",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_1}}, /* 1111nnn0mmm00001 fsub ,*/{"fsub",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_1}}, /* 1111nnnn00111101 ftrc ,FPUL*/{"ftrc",{FD_REG_N,FPUL_M},{HEX_F,REG_N,HEX_3,HEX_D}}, /* 1111nn0111111101 ftrv XMTRX_M4,*/{"ftrv",{XMTRX_M4,V_REG_N},{HEX_F,REG_NM,HEX_F,HEX_D}}, { 0 } }; typedef struct { int type; int reg; } sh_operand_info; // Operand structure void asm_bad(const char *str, char *err_msg) // Displays an error message { sprintf(err_msg, "ERROR : %s", str); } /* try and parse a reg name, returns number of chars consumed */ int parse_reg (const char *src, int *mode, int *reg) // Ripped out of the gas asm { /* We use !isalnum for the next character after the register name, to make sure that we won't accidentally recognize a symbol name such as 'sram' as being a reference to the register 'sr'. */ if (src[0] == 'r') { if (src[1] == '1') { if (src[2] >= '0' && src[2] <= '5' && ! isalnum (src[3])) { *mode = A_REG_N; *reg = 10 + src[2] - '0'; return 3; } } if (src[1] >= '0' && src[1] <= '9' && ! isalnum (src[2])) { *mode = A_REG_N; *reg = (src[1] - '0'); return 2; } } if (src[0] == 's' && src[1] == 'r' && ! isalnum (src[2])) { *mode = A_SR; return 2; } if (src[0] == 's' && src[1] == 'p' && ! isalnum (src[2])) { *mode = A_REG_N; *reg = 15; return 2; } if (src[0] == 'p' && src[1] == 'r' && ! isalnum (src[2])) { *mode = A_PR; return 2; } if (src[0] == 'p' && src[1] == 'c' && ! isalnum (src[2])) { *mode = A_DISP_PC; return 2; } if (src[0] == 'g' && src[1] == 'b' && src[2] == 'r' && ! isalnum (src[3])) { *mode = A_GBR; return 3; } if (src[0] == 'v' && src[1] == 'b' && src[2] == 'r' && ! isalnum (src[3])) { *mode = A_VBR; return 3; } if (src[0] == 'm' && src[1] == 'a' && src[2] == 'c' && ! isalnum (src[4])) { if (src[3] == 'l') { *mode = A_MACL; return 4; } if (src[3] == 'h') { *mode = A_MACH; return 4; } } return 0; } int strip_opname(const char *str,char *name) // Strip out the opcode name and return in *name { int pos; pos = 0; while((str[pos] != 32) && (str[pos] != 0)) { name[pos] = str[pos]; pos++; } name[pos] = 0; return pos; } int strip_arg(const char *str,char *arg) // Strip out next arg in the string { int pos; pos = 0; if(str[0] == '@') { if(str[1] == '(') { if(str[2] != 0) { do { arg[pos] = str[pos]; pos++; } while((str[pos-1] != ')') && (str[pos] != 0)); } } else while((str[pos] != ',') && (str[pos] != 0)) { arg[pos] = str[pos]; pos++; } } else while((str[pos] != ',') && (str[pos] != 0)) { arg[pos] = str[pos]; pos++; } arg[pos] = 0; return pos; } int parse_at(const char *arg,sh_operand_info *op, char *err_msg) // Parse pointer arguement and return a operand info struct { int mode; int len; if(arg[0] == 0) return 0; if(*arg == '-') { arg++; len = parse_reg(arg,&mode,&(op->reg)); if(len == 0) { asm_bad("Cant find arg", err_msg); return 0; } if(mode != A_REG_N) { asm_bad("Invalid reg after @-", err_msg); return 0; } else { op->type = A_DEC_N; } } else if(*arg == '(') { arg++; len = parse_reg(arg,&mode,&(op->reg)); if((len > 0) && (mode == A_REG_N)) { arg+=len; if(op->reg != 0) { asm_bad("Must be @(R0,...)", err_msg); return 0; } if(arg[0] == ',') arg++; len = parse_reg(arg,&mode,&(op->reg)); arg += len; if(mode == A_GBR) { op->type = A_R0_GBR; } else if (mode == A_REG_N) { op->type = A_IND_R0_REG_N; } else { asm_bad("Syntax error in @(R0,...)", err_msg); return 0; } } else { while((*(arg-1) != ',') && (*arg != 0)) arg++; len = parse_reg(arg,&mode,&(op->reg)); arg+=len; if(len) { if(mode == A_REG_N) { op->type = A_DISP_REG_N; } else if (mode == A_GBR) { op->type = A_DISP_GBR; } else if (mode == A_DISP_PC) { op->type = A_DISP_PC; } else { asm_bad("Bad syntax in @(disp,[Rn,GBR,PC])", err_msg); return 0; } } else { asm_bad("Bad syntax in @(disp,[Rn,GBR,PC])", err_msg); return 0; } } if(*arg != ')') { asm_bad("Expected a )", err_msg); return 0; } } else { arg += parse_reg(arg,&mode,&(op->reg)); if(mode != A_REG_N) { asm_bad("Invalid register after @", err_msg); return 0; } if(arg[0] == '+') { op->type = A_INC_N; } else { op->type = A_IND_N; } } return 1; } int parse_arg(const char *arg,sh_operand_info *op, char *err_msg) // Parse arg and return a filled operand struct { int len,mode; if(arg[0] == 0) { op->type = 0; op->reg = 0; return 1; } if(*arg == '@') { arg++; return parse_at(arg,op, err_msg); } if(*arg == '#') { op->type = A_IMM; return 1; } len = parse_reg(arg,&mode,&(op->reg)); if(len) { op->type = mode; return 1; } else { op->type = A_BDISP12; return 1; } return 0; } int fix_arg(int type,sh_operand_info *arg) // Checks the arg with the opcode type and see if its matchable // Returns 1 if possible to match and 0 if not { if((type == A_DEC_M) && (arg->type == A_DEC_N)) return 1; if((type == A_DISP_REG_M) && (arg->type == A_DISP_REG_N)) return 1; if((type == A_INC_M) && (arg->type == A_INC_N)) return 1; if((type == A_IND_M) && (arg->type == A_IND_N)) return 1; if((type == A_IND_R0_REG_M) && (arg->type == A_IND_R0_REG_N)) return 1; if((type == A_REG_M) && (arg->type == A_REG_N)) return 1; if((type == A_BDISP8) && (arg->type == A_BDISP12)) return 1; if((type == A_R0) && (arg->type == A_REG_N) && (arg->reg == 0)) return 1; return 0; } int search_op(const char *name,sh_operand_info *arg1,sh_operand_info *arg2,sh_opcode_info *op) // Search for a matching opcode and fix args if necessary { int loop = 0; sh_operand_info arg1back,arg2back; arg1back = *arg1; arg2back = *arg2; while(strcmp(sh_table[loop].name,"ftrv")) { if(!strcmp(sh_table[loop].name,name)) { if(sh_table[loop].arg[0] != 0) { if(fix_arg(sh_table[loop].arg[0],arg1)) arg1->type = sh_table[loop].arg[0]; } if(sh_table[loop].arg[1] != 0) { if(fix_arg(sh_table[loop].arg[1],arg2)) arg2->type = sh_table[loop].arg[1]; } if((arg1->type == sh_table[loop].arg[0]) && (arg2->type == sh_table[loop].arg[1])) { *op = sh_table[loop]; return 1; } } *arg1 = arg1back; *arg2 = arg2back; loop++; } return 0; } void insert(unsigned int *opcode,int value,int pos) // Insert a nibble into the supplied word { *opcode |= ((value & 0xF) << (12 - (pos * 4))); } unsigned long build_bytes(sh_opcode_info op,sh_operand_info a1, sh_operand_info a2,sh_operand_info disp) // Now we know the opcode then build its bytes. Returns opcode if valid // and 0 if not. { int loop; int i; unsigned int opcode; loop = 0; opcode = 0; while(loop < 4) { i = op.nibbles[loop]; if(i < 16) { insert(&opcode,i,loop); loop++; } else { switch(i) { case REG_M : if(a1.type == REG_M) insert(&opcode,a1.reg,loop); else insert(&opcode,a2.reg,loop); break; case REG_N : if(a1.type == REG_N) insert(&opcode,a1.reg,loop); else insert(&opcode,a2.reg,loop); break; case DISP_4 : case IMM_4 : insert(&opcode,disp.reg&0xF,loop); break; case IMM_4BY2: disp.reg >>= 1; insert(&opcode,disp.reg&0xF,loop); break; case IMM_4BY4: disp.reg >>= 2; insert(&opcode,disp.reg&0xF,loop); break; case BRANCH_12: insert(&opcode,(disp.reg >> 8) & 0xF,loop); insert(&opcode,(disp.reg >> 4) & 0xF,loop+1); insert(&opcode,disp.reg & 0xF,loop+2); loop += 2; break; case DISP_8 : case IMM_8 : case BRANCH_8 : insert(&opcode,(disp.reg >> 4) & 0xF,loop); insert(&opcode,disp.reg & 0xF,loop+1); loop += 1; break; case PCRELIMM_8BY2: case IMM_8BY2 : disp.reg >>= 1; insert(&opcode,(disp.reg >> 4) & 0xF,loop); insert(&opcode,disp.reg & 0xF,loop+1); loop += 1; break; case PCRELIMM_8BY4: case IMM_8BY4 : disp.reg >>= 2; insert(&opcode,(disp.reg >> 4) & 0xF,loop); insert(&opcode,disp.reg & 0xF,loop+1); loop += 1; break; } loop++; } } return opcode; } int rebuild_args(const char *arg1,const char *arg2,sh_operand_info *a1, sh_operand_info *a2,sh_operand_info *disp) // Rebuild args into the maximum 3 args for building. // Redefine type values to nibble equivalents and extract imm values. // returns 1 on error { char s1[30],s2[30]; char *bp; if (strlen(arg1) >= 30 || strlen(arg2) >= 30) return 1;//error strcpy(s1,arg1); strcpy(s2,arg2); bp = NULL; switch(a1->type) { case A_IND_R0_REG_M: case A_DEC_M: case A_INC_M: case A_IND_M: case A_REG_M: a1->type = REG_M; break; case A_IND_R0_REG_N: case A_DEC_N: case A_INC_N: case A_IND_N: case A_REG_N: a1->type = REG_N; break; case A_DISP_PC: disp->reg = strtol(&s1[2],&bp,16); disp->type = PCRELIMM; break; case A_DISP_GBR:disp->reg = strtol(&s1[2],&bp,16); disp->type = IMM; break; case A_DISP_REG_M: disp->reg = strtol(&s1[2],&bp,16); disp->type = IMM; a1->type = REG_M; break; case A_DISP_REG_N: disp->reg = strtol(&s1[2],&bp,16); disp->type = IMM; a1->type = REG_N; break; case A_IMM : disp->reg = strtol(&s1[1],&bp,16); disp->type = IMM; break; case A_BDISP12 : case A_BDISP8 : disp->reg = strtol(s1,&bp,16); disp->type = IMM; break; } switch(a2->type) { case A_IND_R0_REG_M: case A_DEC_M: case A_INC_M: case A_IND_M: case A_REG_M: a2->type = REG_M; break; case A_IND_R0_REG_N: case A_DEC_N: case A_INC_N: case A_IND_N: case A_REG_N: a2->type = REG_N; break; case A_DISP_PC: disp->reg = strtol(&s2[2],&bp,16); disp->type = PCRELIMM; break; case A_DISP_GBR:disp->reg = strtol(&s2[2],&bp,16); disp->type = IMM; break; case A_DISP_REG_M: disp->reg = strtol(&s2[2],&bp,16); disp->type = IMM; a2->type = REG_M; break; case A_DISP_REG_N: disp->reg = strtol(&s2[2],&bp,16); disp->type = IMM; a2->type = REG_N; break; case A_IMM : disp->reg = strtol(&s2[1],&bp,16); disp->type = IMM; break; case A_BDISP12 : case A_BDISP8 : disp->reg = strtol(s2,&bp,16); disp->type = IMM; break; } return 0; } int sh2iasm(char *str, char *err_msg) // Function to do all the work { char name[30]; char arg1[30]; char arg2[30]; char *p; int loop; int oplen,arg1len,arg2len; sh_operand_info arg1info,arg2info,disp; sh_opcode_info opcode; arg1info.type = 0; arg1info.reg = 0; arg2info.type = 0; arg2info.reg = 0; //gets(str); p = str; while(*p == ' ') p++; if((oplen = strip_opname(p,name)) == 0) { asm_bad("No opcode", err_msg); return 0; } p += oplen; while(*p == ' ') p++; arg1len = strip_arg(p,arg1); p += arg1len; while(*p == ' ') p++; if(*p == ',') p++; while(*p == ' ') p++; arg2len = strip_arg(p,arg2); for(loop = 0;name[loop] != 0;loop++) { name[loop] = tolower(name[loop]); } for(loop = 0;arg1[loop] != 0;loop++) arg1[loop] = tolower(arg1[loop]); for(loop = 0;arg2[loop] != 0;loop++) arg2[loop] = tolower(arg2[loop]); if(!parse_arg(arg1,&arg1info,err_msg)) { if(arg1[0] != 0) asm_bad("Arg 1", err_msg); return 0; } if(!parse_arg(arg2,&arg2info,err_msg)) { if(arg2[0] != 0) asm_bad("Arg 2", err_msg); return 0; } if(!search_op(name,&arg1info,&arg2info,&opcode)) { asm_bad("Invalid opcode. Likely doesn't exist or format is wrong\n", err_msg); return 0; } loop = 0; rebuild_args(arg1,arg2,&arg1info,&arg2info,&disp); return build_bytes(opcode,arg1info,arg2info,disp); } #ifdef __cplusplus } #endif yabause-0.9.15/src/peripheral.h000644 001750 001750 00000017420 12757373537 020373 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005 Guillaume Duhamel Copyright 2005-2006, 2013 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef PERIPHERAL_H #define PERIPHERAL_H #include "core.h" #include "smpc.h" #include "yabause.h" /** @defgroup peripheral Peripheral * * @brief This module provides two kind of functions * - peripheral core management functions * - controller ports management functions * * @{ */ #define PERPAD 0x02 #define PERWHEEL 0x13 #define PERMISSIONSTICK 0x15 #define PER3DPAD 0x16 #define PERTWINSTICKS 0x19//double mission sticks use same id #define PERGUN 0x25 #define PERKEYBOARD 0x34 #define PERMOUSE 0xE3 #define PERCORE_DEFAULT -1 #define PERCORE_DUMMY 0 extern PortData_struct PORTDATA1; extern PortData_struct PORTDATA2; #define PERSF_ALL (0xFFFFFFFF) #define PERSF_KEY (1 << 0) #define PERSF_BUTTON (1 << 1) #define PERSF_HAT (1 << 2) #define PERSF_AXIS (1 << 3) #define PERSF_MOUSEMOVE (1 << 4) typedef struct { int id; const char * Name; int (*Init)(void); void (*DeInit)(void); int (*HandleEvents)(void); u32 (*Scan)(u32 flags); int canScan; void (*Flush)(void); void (*KeyName)(u32 key, char * name, int size); } PerInterface_struct; /** @brief Pointer to the current peripheral core. * * You should not set this manually but use * PerInit() and PerDeInit() instead. */ extern PerInterface_struct * PERCore; extern PerInterface_struct PERDummy; /** * @brief Init a peripheral core * * Searches through the PERCoreList array for the given coreid. * If found, PERCore is set to the address of that core and * the core's Init function is called. * * @param coreid the peripheral core to be used * @return 0 if core has been inited, -1 otherwise */ int PerInit(int coreid); /** * @brief De-init a peripheral core * * Calls the core's DeInit callback and set PERCore to NULL. */ void PerDeInit(void); /** @brief Adds a peripheral * * You shouldn't directly use this function but * PerPadAdd() or PerMouseAdd() instead. */ void * PerAddPeripheral(PortData_struct *port, int perid); int PerGetId(void * peripheral); void PerPortReset(void); /** * Iterate the list of peripherals connected to a port * and flush them if necesseray. This is needed for mouses. */ void PerFlush(PortData_struct * port); void PerKeyDown(u32 key); void PerKeyUp(u32 key); void PerSetKey(u32 key, u8 name, void * controller); void PerAxisValue(u32 key, u8 val); void PerAxisMove(u32 key, s32 dispx, s32 dispy); /** @defgroup pad Pad * * @{ */ #define PERPAD_UP 0 #define PERPAD_RIGHT 1 #define PERPAD_DOWN 2 #define PERPAD_LEFT 3 #define PERPAD_RIGHT_TRIGGER 4 #define PERPAD_LEFT_TRIGGER 5 #define PERPAD_START 6 #define PERPAD_A 7 #define PERPAD_B 8 #define PERPAD_C 9 #define PERPAD_X 10 #define PERPAD_Y 11 #define PERPAD_Z 12 extern const char * PerPadNames[14]; typedef struct { u8 perid; u8 padbits[2]; } PerPad_struct; /** @brief Adds a pad to one of the controller ports. * * @param port can be either &PORTDATA1 or &PORTDATA2 * @return pointer to a PerPad_struct or NULL if it fails * */ PerPad_struct * PerPadAdd(PortData_struct * port); void PerPadUpPressed(PerPad_struct * pad); void PerPadUpReleased(PerPad_struct * pad); void PerPadDownPressed(PerPad_struct * pad); void PerPadDownReleased(PerPad_struct * pad); void PerPadRightPressed(PerPad_struct * pad); void PerPadRightReleased(PerPad_struct * pad); void PerPadLeftPressed(PerPad_struct * pad); void PerPadLeftReleased(PerPad_struct * pad); void PerPadStartPressed(PerPad_struct * pad); void PerPadStartReleased(PerPad_struct * pad); void PerPadAPressed(PerPad_struct * pad); void PerPadAReleased(PerPad_struct * pad); void PerPadBPressed(PerPad_struct * pad); void PerPadBReleased(PerPad_struct * pad); void PerPadCPressed(PerPad_struct * pad); void PerPadCReleased(PerPad_struct * pad); void PerPadXPressed(PerPad_struct * pad); void PerPadXReleased(PerPad_struct * pad); void PerPadYPressed(PerPad_struct * pad); void PerPadYReleased(PerPad_struct * pad); void PerPadZPressed(PerPad_struct * pad); void PerPadZReleased(PerPad_struct * pad); void PerPadRTriggerPressed(PerPad_struct * pad); void PerPadRTriggerReleased(PerPad_struct * pad); void PerPadLTriggerPressed(PerPad_struct * pad); void PerPadLTriggerReleased(PerPad_struct * pad); /** @} */ /** @defgroup mouse Mouse * * @{ * */ #define PERMOUSE_LEFT 13 #define PERMOUSE_MIDDLE 14 #define PERMOUSE_RIGHT 15 #define PERMOUSE_START 16 #define PERMOUSE_AXIS 17 extern const char * PerMouseNames[5]; typedef struct { u8 perid; u8 mousebits[3]; } PerMouse_struct; /** @brief Adds a mouse to one of the controller ports. * * @param port can be either &PORTDATA1 or &PORTDATA2 * @return pointer to a PerMouse_struct or NULL if it fails * */ PerMouse_struct * PerMouseAdd(PortData_struct * port); void PerMouseLeftPressed(PerMouse_struct * mouse); void PerMouseLeftReleased(PerMouse_struct * mouse); void PerMouseMiddlePressed(PerMouse_struct * mouse); void PerMouseMiddleReleased(PerMouse_struct * mouse); void PerMouseRightPressed(PerMouse_struct * mouse); void PerMouseRightReleased(PerMouse_struct * mouse); void PerMouseStartPressed(PerMouse_struct * mouse); void PerMouseStartReleased(PerMouse_struct * mouse); void PerMouseMove(PerMouse_struct * mouse, s32 dispx, s32 dispy); /** @} */ /** @defgroup 3danalog 3DAnalog * * @{ * */ #define PERANALOG_AXIS1 18 #define PERANALOG_AXIS2 19 #define PERANALOG_AXIS3 20 #define PERANALOG_AXIS4 21 #define PERANALOG_AXIS5 22 #define PERANALOG_AXIS6 23 #define PERANALOG_AXIS7 24 typedef struct { u8 perid; u8 analogbits[9]; } PerAnalog_struct; /** @brief Adds a Analog control pad to one of the controller ports. * * @param port can be either &PORTDATA1 or &PORTDATA2 * @return pointer to a Per3DAnalog_struct or NULL if it fails * */ PerAnalog_struct * PerWheelAdd(PortData_struct * port); PerAnalog_struct * PerMissionStickAdd(PortData_struct * port); PerAnalog_struct * Per3DPadAdd(PortData_struct * port); PerAnalog_struct * PerTwinSticksAdd(PortData_struct * port); void PerAxis1Value(PerAnalog_struct * analog, u32 val); void PerAxis2Value(PerAnalog_struct * analog, u32 val); void PerAxis3Value(PerAnalog_struct * analog, u32 val); void PerAxis4Value(PerAnalog_struct * analog, u32 val); void PerAxis5Value(PerAnalog_struct * analog, u32 val); void PerAxis6Value(PerAnalog_struct * analog, u32 val); void PerAxis7Value(PerAnalog_struct * analog, u32 val); /** @} */ /** @defgroup gun Gun * * @{ * */ #define PERGUN_TRIGGER 25 #define PERGUN_START 27 #define PERGUN_AXIS 28 typedef struct { u8 perid; u8 gunbits[5]; } PerGun_struct; /** @brief Adds a Gun to one of the controller ports up to a maximum of one per port. * * @param port can be either &PORTDATA1 or &PORTDATA2 * @return pointer to a PerGun_struct or NULL if it fails * */ PerGun_struct * PerGunAdd(PortData_struct * port); void PerGunTriggerPressed(PerGun_struct * gun); void PerGunTriggerReleased(PerGun_struct * gun); void PerGunStartPressed(PerGun_struct * gun); void PerGunStartReleased(PerGun_struct * gun); void PerGunMove(PerGun_struct * gun, s32 dispx, s32 dispy); /** @} */ /** @} */ #endif yabause-0.9.15/src/snddummy.c000644 001750 001750 00000010242 12755623101 020045 0ustar00guillaumeguillaume000000 000000 /* Copyright 2004 Stephane Dallongeville Copyright 2004-2007 Theo Berkau Copyright 2006 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*! \file snddummy.c \brief Dummy sound interface. */ #include "scsp.h" ////////////////////////////////////////////////////////////////////////////// // Dummy Sound Interface ////////////////////////////////////////////////////////////////////////////// static int SNDDummyInit(void); static void SNDDummyDeInit(void); static int SNDDummyReset(void); static int SNDDummyChangeVideoFormat(int vertfreq); static void SNDDummyUpdateAudio(u32 *leftchanbuffer, u32 *rightchanbuffer, u32 num_samples); static u32 SNDDummyGetAudioSpace(void); static void SNDDummyMuteAudio(void); static void SNDDummyUnMuteAudio(void); static void SNDDummySetVolume(int volume); #ifdef USE_SCSPMIDI int SNDDummyMidiChangePorts(int inport, int outport); u8 SNDDummyMidiIn(int *isdata); int SNDDummyMidiOut(u8 data); #endif SoundInterface_struct SNDDummy = { SNDCORE_DUMMY, "Dummy Sound Interface", SNDDummyInit, SNDDummyDeInit, SNDDummyReset, SNDDummyChangeVideoFormat, SNDDummyUpdateAudio, SNDDummyGetAudioSpace, SNDDummyMuteAudio, SNDDummyUnMuteAudio, SNDDummySetVolume, #ifdef USE_SCSPMIDI SNDDummyMidiChangePorts, SNDDummyMidiIn, SNDDummyMidiOut #endif }; ////////////////////////////////////////////////////////////////////////////// static int SNDDummyInit(void) { return 0; } ////////////////////////////////////////////////////////////////////////////// static void SNDDummyDeInit(void) { } ////////////////////////////////////////////////////////////////////////////// static int SNDDummyReset(void) { return 0; } ////////////////////////////////////////////////////////////////////////////// static int SNDDummyChangeVideoFormat(UNUSED int vertfreq) { return 0; } ////////////////////////////////////////////////////////////////////////////// static void SNDDummyUpdateAudio(UNUSED u32 *leftchanbuffer, UNUSED u32 *rightchanbuffer, UNUSED u32 num_samples) { } ////////////////////////////////////////////////////////////////////////////// static u32 SNDDummyGetAudioSpace(void) { /* A "hack" to get dummy sound core working enough * so videos are not "freezing". Values have been * found by experiments... I don't have a clue why * they are working ^^; */ static int i = 0; i++; if (i == 55) { i = 0; return 85; } else { return 0; } } ////////////////////////////////////////////////////////////////////////////// void SNDDummyMuteAudio() { } ////////////////////////////////////////////////////////////////////////////// void SNDDummyUnMuteAudio() { } ////////////////////////////////////////////////////////////////////////////// void SNDDummySetVolume(UNUSED int volume) { } ////////////////////////////////////////////////////////////////////////////// #ifdef USE_SCSPMIDI int SNDDummyMidiChangePorts(int inport, int outport) { return 0; } ////////////////////////////////////////////////////////////////////////////// u8 SNDDummyMidiIn(int *isdata) { *isdata = 0; /* Called when SCSP wants more MIDI data. Set isdata to 1 if there's data to return */ return 0; } ////////////////////////////////////////////////////////////////////////////// int SNDDummyMidiOut(u8 data) { /* Called when SCSP wants to send out MIDI data. num is the number of bytes in buffer. Return 1 if data used, or 0 if not */ return 1; } #endif ////////////////////////////////////////////////////////////////////////////// yabause-0.9.15/src/coffelf.h000644 001750 001750 00000001631 12755623101 017620 0ustar00guillaumeguillaume000000 000000 /* Copyright 2007 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef COFFELF_H #define COFFELF_H int MappedMemoryLoadCoff(const char *filename); int MappedMemoryLoadElf(const char *filename); #endif yabause-0.9.15/src/yglcache.c000644 001750 001750 00000005727 12755623101 020000 0ustar00guillaumeguillaume000000 000000 /* Copyright 2005-2006 Guillaume Duhamel * Copyright 2005-2006 Theo Berkau * Copyright 2011-2015 Shinya Miyamoto(devmiyax) This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_LIBGL #include "ygl.h" #include "yui.h" #include "vidshared.h" #define HASHSIZE (0xFFFF) typedef struct _YglCacheHash { u32 addr; float x; float y; struct _YglCacheHash * next; } YglCacheHash; YglCacheHash *HashTable[HASHSIZE] = { 0 }; YglCacheHash CashLink[HASHSIZE*2] = { 0 }; u32 CashLink_index = 0; static int YglgetHash(u32 addr) { return ((addr>>4) & HASHSIZE); } static YglCacheHash * YglgetNewCash() { YglCacheHash * rtn; if (CashLink_index >= HASHSIZE*2){ printf("not enough cash"); return NULL; } rtn = &CashLink[CashLink_index]; CashLink_index++; return rtn; } int YglIsCached(u32 addr, YglCache * c ) { u32 hashkey; hashkey = YglgetHash(addr); /* get hash */ if (HashTable[hashkey] == NULL) { /* Empty Hash */ return 0; /* Not Found */ } else { /* needs liner search */ YglCacheHash *at = HashTable[hashkey]; while (at != NULL) { if (at->addr == addr) { /* Find! */ c->x = at->x; c->y = at->y; return 1; } at = at->next; } return 0; /* Not found */ } return 1; } ////////////////////////////////////////////////////////////////////////////// void YglCacheAdd(u32 addr, YglCache * c) { u32 hashkey; YglCacheHash *add; hashkey = YglgetHash(addr); if (HashTable[hashkey] == NULL){ add = YglgetNewCash(); add->addr = addr; add->x = c->x; add->y = c->y; add->next = NULL; HashTable[hashkey] = add; } else{ YglCacheHash *at = HashTable[hashkey]; while (at != NULL) { if (at->addr == addr ) { at->addr = addr; at->x = c->x; at->y = c->y; return; } at = at->next; } add = YglgetNewCash(); add->addr = addr; add->x = c->x; add->y = c->y; add->next = HashTable[hashkey]; HashTable[hashkey] = add; } } ////////////////////////////////////////////////////////////////////////////// void YglCacheReset(void) { memset(HashTable, 0, sizeof(HashTable)); CashLink_index = 0; } ////////////////////////////////////////////////////////////////////////////// #endif yabause-0.9.15/src/gameinfo.h000644 001750 001750 00000003027 12755623101 020002 0ustar00guillaumeguillaume000000 000000 /* Copyright 2016 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef GAMESINFO_H #define GAMESINFO_H #include "core.h" typedef struct _GameInfo GameInfo; struct _GameInfo { char system[17]; char company[17]; char itemnum[11]; char version[7]; char date[11]; char cdinfo[9]; char region[11]; char peripheral[17]; char gamename[113]; }; /* Copy part of cdip information info GameInfo. This function only works if the emulator is not running, ie: not between YabauseInit and YabauseDeInit. */ int GameInfoFromPath(const char * filename, GameInfo * info); int LoadStateSlotScreenshotStream(FILE * fp, int * outputwidth, int * outputheight, u32 ** buffer); int LoadStateSlotScreenshot(const char * dirpath, const char * itemnum, int slot, int * outputwidth, int * outputheight, u32 ** buffer); #endif yabause-0.9.15/src/android/000755 001750 001750 00000000000 12757373644 017502 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/android/CMakeLists.txt000644 001750 001750 00000015575 12757373537 022260 0ustar00guillaumeguillaume000000 000000 find_program(NDK_BUILD ndk-build) if(NOT NDK_BUILD) message(FATAL_ERROR "ndk build not found, bye") endif() find_program(SDK_ANDROID android) if(NOT SDK_ANDROID) message(FATAL_ERROR "sdk android tool not found, bye") endif() find_program(ANT NAMES ant ant.bat) if(NOT ANT) message(FATAL_ERROR "ant not found, bye") endif() if (NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) set(yabause_android_SHADOW build.xml project.properties jni/yui.c jni/miniegl.h jni/sndaudiotrack.c jni/sndaudiotrack.h jni/sndopensl.c jni/sndopensl.h src/org/yabause/android/Cartridge.java src/org/yabause/android/GameInfo.java src/org/yabause/android/GameInfoManager.java src/org/yabause/android/GameList.java src/org/yabause/android/GameListAdapter.java src/org/yabause/android/Home.java src/org/yabause/android/PadEvent.java src/org/yabause/android/PadManager.java src/org/yabause/android/PadManagerV8.java src/org/yabause/android/PadManagerV16.java src/org/yabause/android/SaveList.java src/org/yabause/android/SaveListAdapter.java src/org/yabause/android/SaveListModeListener.java src/org/yabause/android/Yabause.java src/org/yabause/android/YabauseAudio.java src/org/yabause/android/YabauseView.java src/org/yabause/android/YabausePad.java src/org/yabause/android/YabauseSettings.java src/org/yabause/android/YabauseStorage.java res/drawable-hdpi/icon.png res/drawable-ldpi/icon.png res/drawable-mdpi/icon.png res/drawable-xhdpi/banner.png res/layout/game_item.xml res/layout/home.xml res/layout/main.xml res/layout/save_item.xml res/layout-v11/save_item.xml res/layout/save_list.xml res/menu/save_list.xml res/values/strings.xml res/xml/preferences.xml ) foreach(item IN LISTS yabause_android_SHADOW) message(STATUS ${item}) add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${item}" COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/${item}" "${CMAKE_CURRENT_BINARY_DIR}/${item}" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${item}" ) endforeach() endif() set(YABAUSE_JNI_SRC "sndaudiotrack.c") if (YAB_WANT_OPENSL) set(YABAUSE_JNI_SRC "${YABAUSE_JNI_SRC} sndopensl.c") set(YABAUSE_JNI_LIB "-lOpenSLES") endif() if (YAB_USE_SSF) set(YABAUSE_JNI_LIB "${YABAUSE_JNI_LIB} -lz") endif() set(YABAUSE_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..") configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/jni/Android.mk.in ${CMAKE_CURRENT_BINARY_DIR}/jni/Android.mk @ONLY ) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/AndroidManifest.xml.in ${CMAKE_CURRENT_BINARY_DIR}/AndroidManifest.xml @ONLY ) add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/local.properties" COMMAND ${SDK_ANDROID} update project -p "${CMAKE_CURRENT_BINARY_DIR}" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/AndroidManifest.xml" "${CMAKE_CURRENT_BINARY_DIR}/build.xml" "${CMAKE_CURRENT_BINARY_DIR}/project.properties" "${CMAKE_CURRENT_BINARY_DIR}/jni/Android.mk" ) add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/jni/libyabause.a" COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/../libyabause.a ${CMAKE_CURRENT_BINARY_DIR}/jni/libyabause.a DEPENDS yabause "${CMAKE_CURRENT_BINARY_DIR}/../config.h" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/local.properties" ) add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/libs/armeabi/libyabause.so" COMMAND "${NDK_BUILD}" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/jni/libyabause.a" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/jni/yui.c" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/jni/miniegl.h" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/jni/sndaudiotrack.c" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/jni/sndaudiotrack.h" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/jni/sndopensl.c" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/jni/sndopensl.h" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) set(yabause_android_RES "${CMAKE_CURRENT_BINARY_DIR}/res/drawable-hdpi/icon.png" "${CMAKE_CURRENT_BINARY_DIR}/res/drawable-ldpi/icon.png" "${CMAKE_CURRENT_BINARY_DIR}/res/drawable-mdpi/icon.png" "${CMAKE_CURRENT_BINARY_DIR}/res/drawable-xhdpi/banner.png" "${CMAKE_CURRENT_BINARY_DIR}/res/layout/game_item.xml" "${CMAKE_CURRENT_BINARY_DIR}/res/layout/home.xml" "${CMAKE_CURRENT_BINARY_DIR}/res/layout/main.xml" "${CMAKE_CURRENT_BINARY_DIR}/res/layout/save_item.xml" "${CMAKE_CURRENT_BINARY_DIR}/res/layout-v11/save_item.xml" "${CMAKE_CURRENT_BINARY_DIR}/res/layout/save_list.xml" "${CMAKE_CURRENT_BINARY_DIR}/res/menu/save_list.xml" "${CMAKE_CURRENT_BINARY_DIR}/res/values/strings.xml" "${CMAKE_CURRENT_BINARY_DIR}/res/xml/preferences.xml" ) set(yabause_android_SRC "${CMAKE_CURRENT_BINARY_DIR}/src/org/yabause/android/Cartridge.java" "${CMAKE_CURRENT_BINARY_DIR}/src/org/yabause/android/GameInfo.java" "${CMAKE_CURRENT_BINARY_DIR}/src/org/yabause/android/GameInfoManager.java" "${CMAKE_CURRENT_BINARY_DIR}/src/org/yabause/android/GameList.java" "${CMAKE_CURRENT_BINARY_DIR}/src/org/yabause/android/GameListAdapter.java" "${CMAKE_CURRENT_BINARY_DIR}/src/org/yabause/android/Home.java" "${CMAKE_CURRENT_BINARY_DIR}/src/org/yabause/android/PadEvent.java" "${CMAKE_CURRENT_BINARY_DIR}/src/org/yabause/android/PadManager.java" "${CMAKE_CURRENT_BINARY_DIR}/src/org/yabause/android/PadManagerV8.java" "${CMAKE_CURRENT_BINARY_DIR}/src/org/yabause/android/PadManagerV16.java" "${CMAKE_CURRENT_BINARY_DIR}/src/org/yabause/android/SaveList.java" "${CMAKE_CURRENT_BINARY_DIR}/src/org/yabause/android/SaveListAdapter.java" "${CMAKE_CURRENT_BINARY_DIR}/src/org/yabause/android/SaveListModeListener.java" "${CMAKE_CURRENT_BINARY_DIR}/src/org/yabause/android/Yabause.java" "${CMAKE_CURRENT_BINARY_DIR}/src/org/yabause/android/YabauseAudio.java" "${CMAKE_CURRENT_BINARY_DIR}/src/org/yabause/android/YabauseView.java" "${CMAKE_CURRENT_BINARY_DIR}/src/org/yabause/android/YabausePad.java" "${CMAKE_CURRENT_BINARY_DIR}/src/org/yabause/android/YabauseSettings.java" "${CMAKE_CURRENT_BINARY_DIR}/src/org/yabause/android/YabauseStorage.java" ) add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/bin/Yabause-debug.apk" COMMAND "${ANT}" ARGS "debug" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/libs/armeabi/libyabause.so" DEPENDS ${yabause_android_SRC} DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/AndroidManifest.xml" DEPENDS ${yabause_android_RES} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/bin/Yabause-release-unsigned.apk" COMMAND "${ANT}" ARGS "release" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/libs/armeabi/libyabause.so" DEPENDS ${yabause_android_SRC} DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/AndroidManifest.xml" DEPENDS ${yabause_android_RES} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) if(CMAKE_BUILD_TYPE STREQUAL "Release") add_custom_target(yabause-android ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/bin/Yabause-release-unsigned.apk") else() add_custom_target(yabause-android ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/bin/Yabause-debug.apk") endif() yabause-0.9.15/src/android/AndroidManifest.xml.in000644 001750 001750 00000004111 12757373537 023676 0ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/android/src/000755 001750 001750 00000000000 12757373644 020271 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/android/src/org/000755 001750 001750 00000000000 12757373644 021060 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/android/src/org/yabause/000755 001750 001750 00000000000 12757373644 022511 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/android/src/org/yabause/android/000755 001750 001750 00000000000 12757373644 024131 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/android/src/org/yabause/android/SaveList.java000644 001750 001750 00000010040 12755623101 026501 0ustar00guillaumeguillaume000000 000000 /* Copyright 2016 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package org.yabause.android; import java.util.TreeSet; import android.app.Activity; import android.content.Intent; import android.os.Build; import android.os.Bundle; import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; import android.view.MenuItem; import android.view.MenuInflater; import android.view.View; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.GridView; import org.yabause.android.SaveListAdapter; import org.yabause.android.SaveListModeListener; import org.yabause.android.Yabause; public class SaveList extends Activity implements OnItemClickListener { private static final String TAG = "Yabause"; private String game; private SaveListAdapter adapter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent intent = getIntent(); game = intent.getStringExtra("org.yabause.android.FileName"); SaveListAdapter adapter = new SaveListAdapter(this, game); this.adapter = adapter; setContentView(R.layout.save_list); GridView listView = (GridView) findViewById(R.id.save_listview); listView.setAdapter(this.adapter); listView.setOnItemClickListener(this); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { listView.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE_MODAL); listView.setMultiChoiceModeListener(new SaveListModeListener(adapter)); } else { registerForContextMenu(listView); } } public void onItemClick(AdapterView l, View v, int position, long id) { Integer slot = (Integer) l.getItemAtPosition(position); Intent intent = new Intent(this, Yabause.class); intent.putExtra("org.yabause.android.FileName", game); intent.putExtra("org.yabause.android.Slot", slot); startActivity(intent); } public void onStartWithAutosave(View view) { Intent intent = new Intent(this, Yabause.class); intent.putExtra("org.yabause.android.FileName", game); intent.putExtra("org.yabause.android.Slot", adapter.getEmptySlot()); startActivity(intent); } public void onStartWithoutAutosave(View view) { Intent intent = new Intent(this, Yabause.class); intent.putExtra("org.yabause.android.FileName", game); startActivity(intent); } // Compatibility for Android < 3 @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.save_list, menu); } @Override public boolean onContextItemSelected(MenuItem item) { AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); switch (item.getItemId()) { case R.id.delete_save: adapter.deleteSlot((int) info.id); return true; default: return super.onContextItemSelected(item); } } } yabause-0.9.15/src/android/src/org/yabause/android/SaveListModeListener.java000644 001750 001750 00000006115 12757373537 031045 0ustar00guillaumeguillaume000000 000000 /* Copyright 2016 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package org.yabause.android; import java.util.TreeSet; import android.util.Log; import android.view.ActionMode; import android.view.Menu; import android.view.MenuItem; import android.view.MenuInflater; import android.widget.AbsListView.MultiChoiceModeListener; import org.yabause.android.SaveListAdapter; public class SaveListModeListener implements MultiChoiceModeListener { private SaveListAdapter adapter; private TreeSet selection; SaveListModeListener(SaveListAdapter adapter) { this.adapter = adapter; } @Override public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { // Here you can do something when items are selected/de-selected, // such as update the title in the CAB if (checked) { selection.add(new Long(id)); } else { selection.remove(new Long(id)); } mode.setTitle("" + selection.size()); } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { // Respond to clicks on the actions in the CAB switch (item.getItemId()) { case R.id.delete_save: int[] slots = new int[selection.size()]; int i = 0; for(long slot : selection) { slots[i++] = (int) slot; } adapter.deleteSlots(slots); mode.finish(); // Action picked, so close the CAB return true; default: return false; } } @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { // Inflate the menu for the CAB MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(R.menu.save_list, menu); selection = new TreeSet(); return true; } @Override public void onDestroyActionMode(ActionMode mode) { // Here you can make any necessary updates to the activity when // the CAB is removed. By default, selected items are deselected/unchecked. } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { // Here you can perform updates to the CAB due to // an invalidate() request return false; } } yabause-0.9.15/src/android/src/org/yabause/android/GameInfo.java000644 001750 001750 00000005352 12755623101 026446 0ustar00guillaumeguillaume000000 000000 /* Copyright 2016 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package org.yabause.android; import java.text.SimpleDateFormat; import java.text.DateFormat; import java.text.ParseException; import java.util.Date; import java.util.Locale; class GameInfo { private String system; private String company; private String itemnum; private String version; private String date; private String cdinfo; private String region; private String peripheral; private String gamename; public GameInfo(String system, String company, String itemnum, String version, String date, String cdinfo, String region, String peripheral, String gamename) { this.system = system; this.company = company; this.itemnum = itemnum; this.version = version; this.date = date; this.cdinfo = cdinfo; this.region = region; this.peripheral = peripheral; this.gamename = gamename; } public String getSystem() { return this.system; } public String getCompany() { return this.company; } public String getItemnum() { return this.itemnum; } public String getVersion() { return this.version; } public String getDate() { return this.date; } public String getCdinfo() { return this.cdinfo; } public String getRegion() { return this.region; } public String getPeripheral() { return this.peripheral; } public String getGamename() { return this.gamename; } public String getName() { return this.gamename.replaceAll("\\s+", " "); } public String getHumanDate() { try { SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy", Locale.US); DateFormat df = DateFormat.getDateInstance(); Date date = sdf.parse(this.date); return df.format(date); } catch(ParseException exc) { return this.date; } } } yabause-0.9.15/src/android/src/org/yabause/android/YabauseView.java000644 001750 001750 00000012421 12757373537 027221 0ustar00guillaumeguillaume000000 000000 /* Copyright 2011-2013 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package org.yabause.android; import java.lang.Runnable; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLContext; import javax.microedition.khronos.egl.EGLDisplay; import javax.microedition.khronos.egl.EGLSurface; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; import android.view.View; class YabauseView extends SurfaceView implements Callback { private static String TAG = "YabauseView"; private static final boolean DEBUG = false; private EGLContext mEglContext; private EGLDisplay mEglDisplay; private EGLSurface mEglSurface; private EGLConfig mEglConfig; public YabauseView(Context context, AttributeSet attrs) { super(context,attrs); init(); } public YabauseView(Context context) { super(context); init(); } private void init() { getHolder().addCallback(this); getHolder().setType(SurfaceHolder.SURFACE_TYPE_GPU); } private boolean initGLES(){ EGL10 egl = (EGL10)EGLContext.getEGL(); mEglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); if( mEglDisplay == EGL10.EGL_NO_DISPLAY ){ Log.e(TAG, "Fail to get Display"); return false; } int[] version = new int[2]; if( !egl.eglInitialize(mEglDisplay, version) ){ Log.e(TAG, "Fail to eglInitialize"); return false; } int[] configSpec = { EGL10.EGL_NONE }; EGLConfig[] configs = new EGLConfig[1]; int[] numConfigs = new int[1]; if( !egl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, numConfigs) ){ Log.e(TAG, "Fail to Choose Config"); return false; } mEglConfig = configs[0]; mEglContext = egl.eglCreateContext(mEglDisplay, mEglConfig, EGL10.EGL_NO_CONTEXT, null); if( mEglContext == EGL10.EGL_NO_CONTEXT ){ Log.e(TAG, "Fail to Create OpenGL Context"); return false; } return true; } private boolean createSurface(){ EGL10 egl = (EGL10)EGLContext.getEGL(); mEglSurface = egl.eglCreateWindowSurface(mEglDisplay, mEglConfig, getHolder(), null); if( mEglSurface == EGL10.EGL_NO_SURFACE ){ return false; } return true; } private void endGLES(){ EGL10 egl = (EGL10)EGLContext.getEGL(); if( mEglSurface != null){ egl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); egl.eglDestroySurface(mEglDisplay, mEglSurface); mEglSurface = null; } if( mEglContext != null ){ egl.eglDestroyContext(mEglDisplay, mEglContext); mEglContext = null; } if( mEglDisplay != null){ egl.eglTerminate(mEglDisplay); mEglDisplay = null; } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { EGL10 egl = (EGL10)EGLContext.getEGL(); YabauseRunnable.lockGL(); egl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext); YabauseRunnable.initViewport(); YabauseRunnable.unlockGL(); } @Override public void surfaceCreated(SurfaceHolder holder) { initGLES(); if( !createSurface() ){ Log.e(TAG, "Fail to Create Surface"); return ; } } @Override public void surfaceDestroyed(SurfaceHolder holder) { endGLES(); YabauseRunnable.cleanup(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int specw = MeasureSpec.getSize(widthMeasureSpec); int spech = MeasureSpec.getSize(heightMeasureSpec); float specratio = (float) specw / spech; int saturnw = 320; int saturnh = 224; float saturnratio = (float) saturnw / saturnh; float revratio = (float) saturnh / saturnw; if (specratio > saturnratio) { setMeasuredDimension((int) (spech * saturnratio), spech); } else { setMeasuredDimension(specw, (int) (specw * revratio)); } } } yabause-0.9.15/src/android/src/org/yabause/android/PadEvent.java000644 001750 001750 00000003143 12755623101 026463 0ustar00guillaumeguillaume000000 000000 /* Copyright 2013 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package org.yabause.android; class PadEvent { final static int BUTTON_UP = 0; final static int BUTTON_RIGHT = 1; final static int BUTTON_DOWN = 2; final static int BUTTON_LEFT = 3; final static int BUTTON_RIGHT_TRIGGER = 4; final static int BUTTON_LEFT_TRIGGER = 5; final static int BUTTON_START = 6; final static int BUTTON_A = 7; final static int BUTTON_B = 8; final static int BUTTON_C = 9; final static int BUTTON_X = 10; final static int BUTTON_Y = 11; final static int BUTTON_Z = 12; final static int BUTTON_LAST = 13; private int action; private int key; PadEvent(int action, int key) { this.action = action; this.key = key; } public int getAction() { return this.action; } public int getKey() { return this.key; } } yabause-0.9.15/src/android/src/org/yabause/android/YabauseAudio.java000644 001750 001750 00000005157 12755623101 027337 0ustar00guillaumeguillaume000000 000000 /* Copyright 2013 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package org.yabause.android; import android.app.Activity; import android.media.AudioManager; public class YabauseAudio implements AudioManager.OnAudioFocusChangeListener { public final int SYSTEM = 1; public final int USER = 2; private Activity activity; private int muteFlags; private boolean muted; YabauseAudio(Activity activity) { this.activity = activity; activity.setVolumeControlStream(AudioManager.STREAM_MUSIC); this.muteFlags = 0; this.muted = false; } public void mute(int flags) { muted = true; muteFlags |= flags; AudioManager am = (AudioManager) activity.getSystemService(Activity.AUDIO_SERVICE); am.abandonAudioFocus(this); YabauseRunnable.setVolume(0); } public void unmute(int flags) { muteFlags &= ~flags; if (0 == muteFlags) { muted = false; AudioManager am = (AudioManager) activity.getSystemService(Activity.AUDIO_SERVICE); int result = am.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { YabauseRunnable.setVolume(0); } else { YabauseRunnable.setVolume(100); } } } @Override public void onAudioFocusChange(int focusChange) { if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) { mute(SYSTEM); } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) { YabauseRunnable.setVolume(50); } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { if (muted) unmute(SYSTEM); else YabauseRunnable.setVolume(100); } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) { mute(SYSTEM); } } } yabause-0.9.15/src/android/src/org/yabause/android/PadManagerV8.java000644 001750 001750 00000000637 12755623101 027177 0ustar00guillaumeguillaume000000 000000 package org.yabause.android; import android.view.KeyEvent; import org.yabause.android.PadEvent; import org.yabause.android.PadManager; class PadManagerV8 extends PadManager { public boolean hasPad() { return false; } public PadEvent onKeyDown(int keyCode, KeyEvent event) { return null; } public PadEvent onKeyUp(int keyCode, KeyEvent event) { return null; } } yabause-0.9.15/src/android/src/org/yabause/android/GameListAdapter.java000644 001750 001750 00000005672 12755623101 027774 0ustar00guillaumeguillaume000000 000000 /* Copyright 2015 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package org.yabause.android; import android.content.Context; import android.database.DataSetObserver; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ListAdapter; import android.widget.TextView; import org.yabause.android.YabauseStorage; import org.yabause.android.GameInfoManager; class GameListAdapter implements ListAdapter { private YabauseStorage storage; private String[] gamefiles; private Context context; private GameInfoManager gim; GameListAdapter(Context ctx) { storage = YabauseStorage.getStorage(); gamefiles = storage.getGameFiles(); context = ctx; gim = new GameInfoManager(ctx); } public int getCount() { return gamefiles.length; } public Object getItem(int position) { return gamefiles[position]; } public long getItemId(int position) { return position; } public int getItemViewType(int position) { return 0; } public View getView(int position, View convertView, ViewGroup parent) { View layout; TextView name; if (convertView != null) { layout = convertView; } else { LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE ); layout = inflater.inflate(R.layout.game_item, parent, false); } name = (TextView) layout.findViewById(R.id.game_name); GameInfo gi = gim.gameInfo(gamefiles[position]); if (gi == null) { name.setText(gamefiles[position]); } else { name.setText(gi.getName()); } return layout; } public int getViewTypeCount() { return 1; } public boolean hasStableIds() { return false; } public boolean isEmpty() { return getCount() == 0; } public void registerDataSetObserver(DataSetObserver observer) { } public void unregisterDataSetObserver(DataSetObserver observer) { } public boolean areAllItemsEnabled() { return true; } public boolean isEnabled(int position) { return true; } } yabause-0.9.15/src/android/src/org/yabause/android/GameList.java000644 001750 001750 00000003250 12755623101 026461 0ustar00guillaumeguillaume000000 000000 /* Copyright 2015 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package org.yabause.android; import android.app.ListActivity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.ListView; import org.yabause.android.GameListAdapter; import org.yabause.android.SaveList; public class GameList extends ListActivity { private static final String TAG = "Yabause"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GameListAdapter adapter = new GameListAdapter(this); setListAdapter(adapter); } @Override public void onListItemClick(ListView l, View v, int position, long id) { String string = (String) l.getItemAtPosition(position); Intent intent = new Intent(this, SaveList.class); intent.putExtra("org.yabause.android.FileName", string); startActivity(intent); } } yabause-0.9.15/src/android/src/org/yabause/android/PadManagerV16.java000644 001750 001750 00000007436 12757373537 027303 0ustar00guillaumeguillaume000000 000000 package org.yabause.android; import android.util.Log; import android.view.InputDevice; import android.view.KeyEvent; import java.util.ArrayList; import org.yabause.android.PadEvent; import org.yabause.android.PadManager; class PadManagerV16 extends PadManager { private ArrayList deviceIds; PadManagerV16() { deviceIds = new ArrayList(); int[] ids = InputDevice.getDeviceIds(); for (int deviceId : ids) { InputDevice dev = InputDevice.getDevice(deviceId); int sources = dev.getSources(); if (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) || ((sources & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK)) { if (!deviceIds.contains(deviceId)) { deviceIds.add(deviceId); } } } } public boolean hasPad() { return deviceIds.size() > 0; } public PadEvent onKeyDown(int keyCode, KeyEvent event) { PadEvent pe = null; if (((event.getSource() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) || ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK)) { if (event.getRepeatCount() == 0) { switch(keyCode) { case KeyEvent.KEYCODE_DPAD_UP: pe = new PadEvent(0, pe.BUTTON_UP); break; case KeyEvent.KEYCODE_DPAD_RIGHT: pe = new PadEvent(0, pe.BUTTON_RIGHT); break; case KeyEvent.KEYCODE_DPAD_DOWN: pe = new PadEvent(0, pe.BUTTON_DOWN); break; case KeyEvent.KEYCODE_DPAD_LEFT: pe = new PadEvent(0, pe.BUTTON_LEFT); break; case KeyEvent.KEYCODE_BUTTON_L1: pe = new PadEvent(0, pe.BUTTON_START); break; case KeyEvent.KEYCODE_BUTTON_A: pe = new PadEvent(0, pe.BUTTON_A); break; case KeyEvent.KEYCODE_BUTTON_B: pe = new PadEvent(0, pe.BUTTON_B); break; } } } return pe; } public PadEvent onKeyUp(int keyCode, KeyEvent event) { PadEvent pe = null; if (((event.getSource() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) || ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK)) { if (event.getRepeatCount() == 0) { switch(keyCode) { case KeyEvent.KEYCODE_DPAD_UP: pe = new PadEvent(1, pe.BUTTON_UP); break; case KeyEvent.KEYCODE_DPAD_RIGHT: pe = new PadEvent(1, pe.BUTTON_RIGHT); break; case KeyEvent.KEYCODE_DPAD_DOWN: pe = new PadEvent(1, pe.BUTTON_DOWN); break; case KeyEvent.KEYCODE_DPAD_LEFT: pe = new PadEvent(1, pe.BUTTON_LEFT); break; case KeyEvent.KEYCODE_BUTTON_L1: pe = new PadEvent(1, pe.BUTTON_START); break; case KeyEvent.KEYCODE_BUTTON_A: pe = new PadEvent(1, pe.BUTTON_A); break; case KeyEvent.KEYCODE_BUTTON_B: pe = new PadEvent(1, pe.BUTTON_B); break; } } } return pe; } } yabause-0.9.15/src/android/src/org/yabause/android/PadManager.java000644 001750 001750 00000001174 12755623101 026756 0ustar00guillaumeguillaume000000 000000 package org.yabause.android; import android.os.Build; import android.view.KeyEvent; import org.yabause.android.PadEvent; import org.yabause.android.PadManagerV8; import org.yabause.android.PadManagerV16; abstract class PadManager { public abstract boolean hasPad(); public abstract PadEvent onKeyDown(int keyCode, KeyEvent event); public abstract PadEvent onKeyUp(int keyCode, KeyEvent event); static PadManager getPadManager() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { return new PadManagerV16(); } else { return new PadManagerV8(); } } } yabause-0.9.15/src/android/src/org/yabause/android/YabauseStorage.java000644 001750 001750 00000007145 12755623101 027701 0ustar00guillaumeguillaume000000 000000 package org.yabause.android; import java.io.File; import java.io.FilenameFilter; import android.os.Environment; import android.util.Log; class BiosFilter implements FilenameFilter { public boolean accept(File dir, String filename) { if (filename.endsWith(".bin")) return true; if (filename.endsWith(".rom")) return true; return false; } } class GameFilter implements FilenameFilter { public boolean accept(File dir, String filename) { if (filename.endsWith(".bin")) return true; if (filename.endsWith(".cue")) return true; if (filename.endsWith(".iso")) return true; if (filename.endsWith(".mds")) return true; return false; } } class MemoryFilter implements FilenameFilter { public boolean accept(File dir, String filename) { if (filename.endsWith(".ram")) return true; return false; } } class SaveFilter implements FilenameFilter { public boolean accept(File dir, String filename) { if (filename.endsWith(".yss")) return true; return false; } } class GameSavesFilter implements FilenameFilter { private String itemnum; GameSavesFilter(String itemnum) { super(); this.itemnum = itemnum; } public boolean accept(File dir, String filename) { if (filename.startsWith(this.itemnum) && filename.endsWith(".yss")) return true; return false; } } public class YabauseStorage { static private YabauseStorage instance = null; private File bios; private File games; private File memory; private File cartridge; private File saves; private YabauseStorage() { File yabroot = new File(Environment.getExternalStorageDirectory(), "yabause"); if (! yabroot.exists()) yabroot.mkdir(); bios = new File(yabroot, "bios"); if (! bios.exists()) bios.mkdir(); games = new File(yabroot, "games"); if (! games.exists()) games.mkdir(); memory = new File(yabroot, "memory"); if (! memory.exists()) memory.mkdir(); cartridge = new File(yabroot, "cartridge"); if (! cartridge.exists()) cartridge.mkdir(); saves = new File(yabroot, "saves"); if (! saves.exists()) saves.mkdir(); } static public YabauseStorage getStorage() { if (instance == null) { instance = new YabauseStorage(); } return instance; } public String[] getBiosFiles() { String[] biosfiles = bios.list(new BiosFilter()); return biosfiles; } public String getBiosPath(String biosfile) { return bios + File.separator + biosfile; } public String[] getGameFiles() { String[] gamefiles = games.list(new GameFilter()); return gamefiles; } public String getGamePath(String gamefile) { return games + File.separator + gamefile; } public String[] getMemoryFiles() { String[] memoryfiles = memory.list(new MemoryFilter()); return memoryfiles; } public String getMemoryPath(String memoryfile) { return memory + File.separator + memoryfile; } public String getCartridgePath(String cartridgefile) { return cartridge + File.separator + cartridgefile; } public String getSavesPath() { return saves.getPath(); } public String[] getGameSaves(String itemnum) { return saves.list(new GameSavesFilter(itemnum)); } public void deleteGameSaves(String[] gamesaves) { for(String save : gamesaves) { File f = new File(saves.getPath() + File.separator + save); f.delete(); } } } yabause-0.9.15/src/android/src/org/yabause/android/GameInfoManager.java000644 001750 001750 00000007614 12755623101 027744 0ustar00guillaumeguillaume000000 000000 /* Copyright 2016 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package org.yabause.android; import org.yabause.android.GameInfo; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import java.util.HashMap; class GameInfoOpenHelper extends SQLiteOpenHelper { private static final int DATABASE_VERSION = 1; private static final String GAMEINFO_TABLE_NAME = "gameinfo"; private static final String GAMEINFO_TABLE_CREATE = "CREATE TABLE " + GAMEINFO_TABLE_NAME + " (" + "path TEXT PRIMARY KEY, " + "system TEXT, " + "company TEXT, " + "itemnum TEXT, " + "version TEXT, " + "date TEXT, " + "cdinfo TEXT, " + "region TEXT, " + "peripheral TEXT, " + "gamename TEXT);"; GameInfoOpenHelper(Context context) { super(context, "gameinfo", null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(GAMEINFO_TABLE_CREATE); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } } class GameInfoManager { private GameInfoOpenHelper opener; private HashMap games; public GameInfoManager(Context ctx) { opener = new GameInfoOpenHelper(ctx); games = new HashMap(); SQLiteDatabase db = opener.getReadableDatabase(); Cursor cur = db.rawQuery("SELECT path, system, company, itemnum, version, date, cdinfo, region, peripheral, gamename FROM gameinfo", null); while(cur.moveToNext()) { String path = cur.getString(0); GameInfo gi = new GameInfo(cur.getString(1), cur.getString(2), cur.getString(3), cur.getString(4), cur.getString(5), cur.getString(6), cur.getString(7), cur.getString(8), cur.getString(9)); games.put(path, gi); } cur.close(); opener.close(); } public GameInfo gameInfo(String name) { String path = YabauseStorage.getStorage().getGamePath(name); GameInfo gi = games.get(path); if (gi == null) { gi = YabauseRunnable.gameInfo(path); if (gi != null) { SQLiteDatabase db = opener.getWritableDatabase(); ContentValues cv = new ContentValues(); cv.put("path", path); cv.put("system", gi.getSystem()); cv.put("company", gi.getCompany()); cv.put("itemnum", gi.getItemnum()); cv.put("version", gi.getVersion()); cv.put("date", gi.getDate()); cv.put("cdinfo", gi.getCdinfo()); cv.put("region", gi.getRegion()); cv.put("peripheral", gi.getPeripheral()); cv.put("gamename", gi.getGamename()); db.insert("gameinfo", null, cv); opener.close(); games.put(path, gi); } } return gi; } } yabause-0.9.15/src/android/src/org/yabause/android/Home.java000644 001750 001750 00000003034 12755623101 025644 0ustar00guillaumeguillaume000000 000000 /* Copyright 2015 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package org.yabause.android; import android.app.Activity; import android.content.Intent; import android.view.View; import android.os.Bundle; import org.yabause.android.GameList; public class Home extends Activity { private static final String TAG = "Yabause"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.home); } public void onLoadGame(View view) { Intent intent = new Intent(this, GameList.class); startActivity(intent); } public void onSettings(View view) { Intent intent = new Intent(this, YabauseSettings.class); startActivity(intent); } static { System.loadLibrary("yabause"); } } yabause-0.9.15/src/android/src/org/yabause/android/YabauseSettings.java000644 001750 001750 00000007532 12755623101 030075 0ustar00guillaumeguillaume000000 000000 /* Copyright 2013 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package org.yabause.android; import java.util.ArrayList; import java.util.List; import android.os.Bundle; import android.preference.ListPreference; import android.preference.PreferenceActivity; import android.content.SharedPreferences; public class YabauseSettings extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); YabauseStorage storage = YabauseStorage.getStorage(); /* bios */ ListPreference p = (ListPreference) getPreferenceManager().findPreference("pref_bios"); List labels = new ArrayList(); List values = new ArrayList(); CharSequence[] biosfiles = storage.getBiosFiles(); labels.add("built-in bios"); values.add(""); if ((biosfiles != null) && (biosfiles.length > 0)) { for(CharSequence bios : biosfiles) { labels.add(bios); values.add(bios); } CharSequence[] entries = new CharSequence[labels.size()]; labels.toArray(entries); CharSequence[] entryValues = new CharSequence[values.size()]; values.toArray(entryValues); p.setEntries(entries); p.setEntryValues(entryValues); p.setSummary(p.getEntry()); } else { p.setEnabled(false); p.setSummary("built-in bios"); } /* cartridge */ ListPreference cart = (ListPreference) getPreferenceManager().findPreference("pref_cart"); List cartlabels = new ArrayList(); List cartvalues = new ArrayList(); for(int carttype = 0;carttype < Cartridge.getTypeCount();carttype++) { cartlabels.add(Cartridge.getName(carttype)); cartvalues.add(Integer.toString(carttype)); } CharSequence[] cartentries = new CharSequence[cartlabels.size()]; cartlabels.toArray(cartentries); CharSequence[] cartentryValues = new CharSequence[cartvalues.size()]; cartvalues.toArray(cartentryValues); cart.setEntries(cartentries); cart.setEntryValues(cartentryValues); cart.setSummary(cart.getEntry()); } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (key.equals("pref_bios") || key.equals("pref_cart")) { ListPreference pref = (ListPreference) findPreference(key); pref.setSummary(pref.getEntry()); } } @Override protected void onResume() { super.onResume(); getPreferenceScreen().getSharedPreferences() .registerOnSharedPreferenceChangeListener(this); } @Override protected void onPause() { super.onPause(); getPreferenceScreen().getSharedPreferences() .unregisterOnSharedPreferenceChangeListener(this); } } yabause-0.9.15/src/android/src/org/yabause/android/SaveListAdapter.java000644 001750 001750 00000012332 12757373537 030031 0ustar00guillaumeguillaume000000 000000 /* Copyright 2016 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package org.yabause.android; import android.content.Context; import android.database.DataSetObserver; import android.graphics.Bitmap; import android.os.FileObserver; import android.os.Handler; import android.os.Message; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import org.yabause.android.YabauseStorage; import org.yabause.android.GameInfoManager; import java.util.TreeSet; class SavesHandler extends Handler { private SaveListAdapter adapter; SavesHandler(SaveListAdapter adapter) { this.adapter = adapter; } public void handleMessage(Message msg) { adapter.loadSlots(true); } } class SavesObserver extends FileObserver { private SavesHandler handler; SavesObserver(String path, SavesHandler handler) { super(path, FileObserver.DELETE | FileObserver.CLOSE_WRITE); this.handler = handler; } @Override public void onEvent(int event, String path) { handler.sendEmptyMessage(0); } } class SaveListAdapter extends BaseAdapter { private YabauseStorage storage; private Context context; private int[] slots; private int emptyslot; private String itemnum; private SavesHandler handler; private SavesObserver observer; SaveListAdapter(Context ctx, String game) { storage = YabauseStorage.getStorage(); GameInfoManager gim = new GameInfoManager(ctx); GameInfo gi = gim.gameInfo(game); itemnum = gi.getItemnum(); loadSlots(false); context = ctx; handler = new SavesHandler(this); observer = new SavesObserver(storage.getSavesPath(), handler); observer.startWatching(); } public int getCount() { return slots.length; } public Object getItem(int position) { return slots[position]; } public long getItemId(int position) { return slots[position]; } public int getItemViewType(int position) { return 0; } public View getView(int position, View convertView, ViewGroup parent) { View layout; TextView name; ImageView screenshot; if (convertView != null) { layout = convertView; } else { LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE ); layout = inflater.inflate(R.layout.save_item, parent, false); } name = (TextView) layout.findViewById(R.id.save_name); name.setText("Slot " + slots[position]); screenshot = (ImageView) layout.findViewById(R.id.save_screenshot); Bitmap.Config conf = Bitmap.Config.ARGB_8888; Bitmap bitmap = Bitmap.createBitmap(320, 224, conf); YabauseRunnable.stateSlotScreenshot(storage.getSavesPath(), itemnum, slots[position], bitmap); screenshot.setImageBitmap(bitmap); return layout; } public int getViewTypeCount() { return 1; } public boolean hasStableIds() { return false; } public boolean isEmpty() { return false; } public boolean areAllItemsEnabled() { return true; } public boolean isEnabled(int position) { return true; } public int getEmptySlot() { return emptyslot; } public void deleteSlot(int slot) { String[] saves = new String[1]; saves[0] = String.format("%s_%03d.yss", itemnum, slot); storage.deleteGameSaves(saves); } public void deleteSlots(int[] slots) { String[] saves = new String[slots.length]; int i = 0; for(int slot : slots) { saves[i++] = String.format("%s_%03d.yss", itemnum, slot); } storage.deleteGameSaves(saves); } public void loadSlots(boolean notify) { String[] savefiles = storage.getGameSaves(itemnum); TreeSet slotset = new TreeSet(); for(String file : savefiles) { int slot = Integer.parseInt(file.substring(itemnum.length() + 1, file.length() - ".yss".length())); slotset.add(slot); } emptyslot = 0; while(slotset.contains(emptyslot)) emptyslot++; slots = new int[slotset.size()]; int i = 0; for(int slot : slotset) { slots[i] = slot; i++; } if (notify) { notifyDataSetChanged(); } } } yabause-0.9.15/src/android/src/org/yabause/android/YabausePad.java000644 001750 001750 00000017045 12757373537 027022 0ustar00guillaumeguillaume000000 000000 /* Copyright 2013 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package org.yabause.android; import android.view.MotionEvent; import android.view.KeyEvent; import android.view.View.OnTouchListener; import android.view.View; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import java.util.HashMap; import org.yabause.android.PadEvent; class PadButton { protected Rect rect; PadButton() { rect = new Rect(); } public void updateRect(int x1, int y1, int x2, int y2) { rect.set(x1, y1, x2, y2); } public boolean contains(int x, int y) { return rect.contains(x, y); } public void draw(Canvas canvas, Paint back, Paint front) { } } class DPadButton extends PadButton { public void draw(Canvas canvas, Paint back, Paint front) { canvas.drawRect(rect, back); } } class StartButton extends PadButton { public void draw(Canvas canvas, Paint back, Paint front) { canvas.drawOval(new RectF(rect), back); } } class ActionButton extends PadButton { private int width; private String text; private int textsize; ActionButton(String t) { super(); text = t; } public void draw(Canvas canvas, Paint back, Paint front) { int textsize = (int) (((float) rect.width() / 3) * 4); canvas.drawCircle(rect.centerX(), rect.centerY(), rect.width(), back); front.setTextSize(textsize); front.setTextAlign(Paint.Align.CENTER); canvas.drawText(text, rect.centerX(), rect.centerY() + (rect.width() / 2), front); } } interface OnPadListener { public abstract boolean onPad(PadEvent event); } class YabausePad extends View implements OnTouchListener { private PadButton buttons[]; private OnPadListener listener = null; private HashMap active; public YabausePad(Context context) { super(context); init(); } public YabausePad(Context context, AttributeSet attrs) { super(context, attrs); init(); } public YabausePad(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { setOnTouchListener(this); buttons = new PadButton[PadEvent.BUTTON_LAST]; buttons[PadEvent.BUTTON_UP] = new DPadButton(); buttons[PadEvent.BUTTON_RIGHT] = new DPadButton(); buttons[PadEvent.BUTTON_DOWN] = new DPadButton(); buttons[PadEvent.BUTTON_LEFT] = new DPadButton(); buttons[PadEvent.BUTTON_RIGHT_TRIGGER] = new PadButton(); buttons[PadEvent.BUTTON_LEFT_TRIGGER] = new PadButton(); buttons[PadEvent.BUTTON_START] = new StartButton(); buttons[PadEvent.BUTTON_A] = new ActionButton("A"); buttons[PadEvent.BUTTON_B] = new ActionButton("B"); buttons[PadEvent.BUTTON_C] = new ActionButton("C"); buttons[PadEvent.BUTTON_X] = new ActionButton("X"); buttons[PadEvent.BUTTON_Y] = new ActionButton("Y"); buttons[PadEvent.BUTTON_Z] = new ActionButton("Z"); active = new HashMap(); } @Override public void onDraw(Canvas canvas) { Paint paint = new Paint(); paint.setARGB(0x80, 0x80, 0x80, 0x80); Paint apaint = new Paint(); apaint.setARGB(0x80, 0xFF, 0x00, 0x00); Paint tpaint = new Paint(); tpaint.setARGB(0x80, 0xFF, 0xFF, 0xFF); for(int i = 0;i < PadEvent.BUTTON_LAST;i++) { Paint p = active.containsValue(i) ? apaint : paint; buttons[i].draw(canvas, p, tpaint); } } public void setOnPadListener(OnPadListener listener) { this.listener = listener; } public boolean onTouch(View v, MotionEvent event) { int action = event.getActionMasked(); int index = event.getActionIndex(); int posx = (int) event.getX(index); int posy = (int) event.getY(index); PadEvent pe = null; if ((action == event.ACTION_DOWN) || (action == event.ACTION_POINTER_DOWN)) { for(int i = 0;i < PadEvent.BUTTON_LAST;i++) { if (buttons[i].contains(posx, posy)) { active.put(index, i); pe = new PadEvent(0, i); } } } if (((action == event.ACTION_UP) || (action == event.ACTION_POINTER_UP)) && active.containsKey(index)) { int i = active.remove(index); pe = new PadEvent(1, i); } if ((listener != null) && (pe != null)) { invalidate(); listener.onPad(pe); return true; } return false; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); float xu = (float) getWidth() / 160; float yu = (float) getHeight() / 160; buttons[PadEvent.BUTTON_UP].updateRect((int) (20 * xu), (int) (getHeight() - 70 * yu), (int) (28 * xu), (int) (getHeight() - 50 * yu)); buttons[PadEvent.BUTTON_RIGHT].updateRect((int) (30 * xu), (int) (getHeight() - 47 * yu), (int) (42 * xu), (int) (getHeight() - 33 * yu)); buttons[PadEvent.BUTTON_DOWN].updateRect((int) (20 * xu), (int) (getHeight() - 30 * yu), (int) (28 * xu), (int) (getHeight() - 10 * yu)); buttons[PadEvent.BUTTON_LEFT].updateRect((int) (6 * xu), (int) (getHeight() - 47 * yu), (int) (18 * xu), (int) (getHeight() - 33 * yu)); buttons[PadEvent.BUTTON_START].updateRect((int) (getWidth() / 2 - (8 * xu)), (int) (getHeight() - 20 * yu), (int) (getWidth() / 2 + 8 * xu), (int) (getHeight() - 5 * yu)); buttons[PadEvent.BUTTON_A].updateRect((int) (getWidth() - 46 * xu), (int) (getHeight() - 24 * yu), (int) (getWidth() - 38 * xu), (int) (getHeight() - 9 * yu)); buttons[PadEvent.BUTTON_B].updateRect((int) (getWidth() - 31 * xu), (int) (getHeight() - 41 * yu), (int) (getWidth() - 23 * xu), (int) (getHeight() - 26 * yu)); buttons[PadEvent.BUTTON_C].updateRect((int) (getWidth() - 14 * xu), (int) (getHeight() - 51 * yu), (int) (getWidth() - 6 * xu), (int) (getHeight() - 36 * yu)); buttons[PadEvent.BUTTON_X].updateRect((int) (getWidth() - 55 * xu), (int) (getHeight() - 46 * yu), (int) (getWidth() - 49 * xu), (int) (getHeight() - 34 * yu)); buttons[PadEvent.BUTTON_Y].updateRect((int) (getWidth() - 40 * xu), (int) (getHeight() - 63 * yu), (int) (getWidth() - 34 * xu), (int) (getHeight() - 51 * yu)); buttons[PadEvent.BUTTON_Z].updateRect((int) (getWidth() - 23 * xu), (int) (getHeight() - 73 * yu), (int) (getWidth() - 17 * xu), (int) (getHeight() - 61 * yu)); setMeasuredDimension(width, height); } } yabause-0.9.15/src/android/src/org/yabause/android/Cartridge.java000644 001750 001750 00000004355 12755623101 026667 0ustar00guillaumeguillaume000000 000000 package org.yabause.android; public class Cartridge { final static int CART_NONE = 0; final static int CART_PAR = 1; final static int CART_BACKUPRAM4MBIT = 2; final static int CART_BACKUPRAM8MBIT = 3; final static int CART_BACKUPRAM16MBIT = 4; final static int CART_BACKUPRAM32MBIT = 5; final static int CART_DRAM8MBIT = 6; final static int CART_DRAM32MBIT = 7; final static int CART_NETLINK = 8; final static int CART_ROM16MBIT = 9; static public String getName(int cartridgetype) { switch(cartridgetype) { case CART_NONE: return "None"; case CART_PAR: return "Pro Action Replay"; case CART_BACKUPRAM4MBIT: return "4 Mbit Backup Ram"; case CART_BACKUPRAM8MBIT: return "8 Mbit Backup Ram"; case CART_BACKUPRAM16MBIT: return "16 Mbit Backup Ram"; case CART_BACKUPRAM32MBIT: return "32 Mbit Backup Ram"; case CART_DRAM8MBIT: return "8 Mbit Dram"; case CART_DRAM32MBIT: return "32 Mbit Dram"; case CART_NETLINK: return "Netlink"; case CART_ROM16MBIT: return "16 Mbit ROM"; } return null; } static public String getDefaultFilename(int cartridgetype) { switch(cartridgetype) { case CART_NONE: return "none.ram"; case CART_PAR: return "par.ram"; case CART_BACKUPRAM4MBIT: return "backup4.ram"; case CART_BACKUPRAM8MBIT: return "backup8.ram"; case CART_BACKUPRAM16MBIT: return "backup16.ram"; case CART_BACKUPRAM32MBIT: return "backup32.ram"; case CART_DRAM8MBIT: return "dram8.ram"; case CART_DRAM32MBIT: return "dram32.ram"; case CART_NETLINK: return "netlink.ram"; case CART_ROM16MBIT: return "rom16.ram"; } return null; } static public int getTypeCount() { return 10; } } yabause-0.9.15/src/android/src/org/yabause/android/Yabause.java000644 001750 001750 00000024161 12757373537 026372 0ustar00guillaumeguillaume000000 000000 /* Copyright 2011-2013 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package org.yabause.android; import java.lang.Runnable; import java.io.File; import java.io.FileOutputStream; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.MenuInflater; import android.view.KeyEvent; import android.app.Dialog; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.content.DialogInterface; import android.content.Intent; import android.content.ContentValues; import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.view.View; import android.graphics.Bitmap; import android.os.Environment; import android.provider.MediaStore; import android.net.Uri; import org.yabause.android.GameInfo; class InputHandler extends Handler { private YabauseRunnable yr; public InputHandler(YabauseRunnable yr) { this.yr = yr; } public void handleMessage(Message msg) { Log.v("Yabause", "received message: " + msg.arg1 + " " + msg.arg2); if (msg.arg1 == 0) { yr.press(msg.arg2); } else if (msg.arg1 == 1) { yr.release(msg.arg2); } } } class YabauseRunnable implements Runnable { public static native int init(Yabause yabause); public static native void deinit(); public static native void exec(); public static native void press(int key); public static native void release(int key); public static native int initViewport(); public static native int cleanup(); public static native int drawScreen(); public static native int lockGL(); public static native int unlockGL(); public static native void enableFPS(int enable); public static native void enableFrameskip(int enable); public static native void setVolume(int volume); public static native void screenshot(Bitmap bitmap); public static native GameInfo gameInfo(String path); public static native void stateSlotScreenshot(String dirpath, String itemnum, int slot, Bitmap bitmap); private boolean inited; private boolean paused; public InputHandler handler; public YabauseRunnable(Yabause yabause) { handler = new InputHandler(this); int ok = init(yabause); Log.v("Yabause", "init = " + ok); inited = (ok == 0); } public void pause() { Log.v("Yabause", "pause... should really pause emulation now..."); paused = true; } public void resume() { Log.v("Yabause", "resuming emulation..."); paused = false; handler.post(this); } public void destroy() { Log.v("Yabause", "destroying yabause..."); inited = false; deinit(); } public void run() { if (inited && (! paused)) { exec(); handler.post(this); } } public boolean paused() { return paused; } } class YabauseHandler extends Handler { private Yabause yabause; public YabauseHandler(Yabause yabause) { this.yabause = yabause; } public void handleMessage(Message msg) { yabause.showDialog(msg.what, msg.getData()); } } public class Yabause extends Activity implements OnPadListener { private static final String TAG = "Yabause"; private YabauseRunnable yabauseThread; private YabauseHandler handler; private YabauseAudio audio; private String biospath; private String gamepath; private int saveslot; private int carttype; private PadManager padm; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); hideSystemUI(); setContentView(R.layout.main); audio = new YabauseAudio(this); PreferenceManager.setDefaultValues(this, R.xml.preferences, false); readPreferences(); Intent intent = getIntent(); String game = intent.getStringExtra("org.yabause.android.FileName"); if (game.length() > 0) { YabauseStorage storage = YabauseStorage.getStorage(); gamepath = storage.getGamePath(game); } else gamepath = ""; saveslot = intent.getIntExtra("org.yabause.android.Slot", -1); handler = new YabauseHandler(this); yabauseThread = new YabauseRunnable(this); padm = PadManager.getPadManager(); YabausePad pad = (YabausePad) findViewById(R.id.yabause_pad); pad.setOnPadListener(this); if (padm.hasPad()) { pad.setVisibility(View.INVISIBLE); } } @Override public void onPause() { super.onPause(); Log.v(TAG, "pause... should pause emulation..."); yabauseThread.pause(); audio.mute(audio.SYSTEM); } @Override public void onResume() { super.onResume(); Log.v(TAG, "resume... should resume emulation..."); readPreferences(); audio.unmute(audio.SYSTEM); yabauseThread.resume(); } @Override public void onDestroy() { super.onDestroy(); Log.v(TAG, "this is the end..."); yabauseThread.destroy(); } @Override public Dialog onCreateDialog(int id, Bundle args) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage(args.getString("message")) .setCancelable(false) .setNegativeButton("Exit", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { Yabause.this.finish(); } }) .setPositiveButton("Ignore", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); AlertDialog alert = builder.create(); return alert; } @Override public boolean onPad(PadEvent event) { Message message = handler.obtainMessage(); message.arg1 = event.getAction(); message.arg2 = event.getKey(); yabauseThread.handler.sendMessage(message); return true; } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { PadEvent pe = padm.onKeyDown(keyCode, event); if (pe != null) { this.onPad(pe); return true; } return super.onKeyDown(keyCode, event); } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { PadEvent pe = padm.onKeyUp(keyCode, event); if (pe != null) { this.onPad(pe); return true; } return super.onKeyUp(keyCode, event); } private void hideSystemUI() { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY ); } } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { hideSystemUI(); } } private void errorMsg(String msg) { Message message = handler.obtainMessage(); Bundle bundle = new Bundle(); bundle.putString("message", msg); message.setData(bundle); handler.sendMessage(message); } private void readPreferences() { SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); boolean fps = sharedPref.getBoolean("pref_fps", false); yabauseThread.enableFPS(fps ? 1 : 0); boolean frameskip = sharedPref.getBoolean("pref_frameskip", false); yabauseThread.enableFrameskip(frameskip ? 1 : 0); boolean audioout = sharedPref.getBoolean("pref_audio", true); if (audioout) { audio.unmute(audio.USER); } else { audio.mute(audio.USER); } String bios = sharedPref.getString("pref_bios", ""); if (bios.length() > 0) { YabauseStorage storage = YabauseStorage.getStorage(); biospath = storage.getBiosPath(bios); } else biospath = ""; String cart = sharedPref.getString("pref_cart", ""); if (cart.length() > 0) { Integer i = new Integer(cart); carttype = i.intValue(); } else carttype = -1; } public String getBiosPath() { return biospath; } public String getGamePath() { return gamepath; } public String getMemoryPath() { return YabauseStorage.getStorage().getMemoryPath("memory.ram"); } public int getCartridgeType() { return carttype; } public String getCartridgePath() { return YabauseStorage.getStorage().getCartridgePath(Cartridge.getDefaultFilename(carttype)); } public String getSavesPath() { return YabauseStorage.getStorage().getSavesPath(); } public int getSaveSlot() { return saveslot; } } yabause-0.9.15/src/android/project.properties000644 001750 001750 00000000551 12757373537 023270 0ustar00guillaumeguillaume000000 000000 # This file is automatically generated by Android Tools. # Do not modify this file -- YOUR CHANGES WILL BE ERASED! # # This file must be checked in Version Control Systems. # # To customize properties used by the Ant build system use, # "ant.properties", and override values to adapt the script to your # project structure. # Project target. target=android-21 yabause-0.9.15/src/android/jni/000755 001750 001750 00000000000 12757373644 020262 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/android/jni/miniegl.h000644 001750 001750 00000003024 12755623101 022036 0ustar00guillaumeguillaume000000 000000 #ifndef _MINIEGL_ #define _MINIEGL_ typedef int EGLint; typedef unsigned int EGLBoolean; typedef unsigned int EGLenum; typedef void *EGLConfig; typedef void *EGLContext; typedef void *EGLDisplay; typedef void *EGLSurface; typedef void *EGLClientBuffer; /* EGL aliases */ #define EGL_FALSE 0 #define EGL_TRUE 1 /* Out-of-band handle values */ #define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0) #define EGL_NO_CONTEXT ((EGLContext)0) #define EGL_NO_DISPLAY ((EGLDisplay)0) #define EGL_NO_SURFACE ((EGLSurface)0) /* GetCurrentSurface targets */ #define EGL_DRAW 0x3059 #define EGL_READ 0x305A /* QuerySurface / SurfaceAttrib / CreatePbufferSurface targets */ #define EGL_HEIGHT 0x3056 #define EGL_WIDTH 0x3057 /* QueryString targets */ #define EGL_VENDOR 0x3053 #define EGL_VERSION 0x3054 #define EGL_EXTENSIONS 0x3055 #define EGL_CLIENT_APIS 0x308D EGLContext (*eglGetCurrentContext)(void); EGLSurface (*eglGetCurrentSurface)(EGLint readdraw); EGLDisplay (*eglGetCurrentDisplay)(void); EGLBoolean (*eglQuerySurface)(EGLDisplay dpy, EGLSurface surface,EGLint attribute, EGLint *value); EGLBoolean (*eglSwapInterval)(EGLDisplay dpy, EGLint interval); EGLBoolean (*eglMakeCurrent)(EGLDisplay dpy, EGLSurface draw,EGLSurface read, EGLContext ctx); EGLBoolean (*eglSwapBuffers)(EGLDisplay dpy, EGLSurface surface); const char * (*eglQueryString)(EGLDisplay dpy, EGLint name); EGLint (*eglGetError)(void); #endif // _MINIEGL_yabause-0.9.15/src/android/jni/yui.c000644 001750 001750 00000044447 12757373537 021252 0ustar00guillaumeguillaume000000 000000 /* Copyright 2011 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "../../config.h" #include "yabause.h" #include "scsp.h" #include "vidsoft.h" #include "peripheral.h" #include "m68kcore.h" #include "sh2core.h" #include "sh2int.h" #include "cdbase.h" #include "cs2.h" #include "debug.h" #include "osdcore.h" #include "gameinfo.h" #include #include #define _ANDROID_2_2_ #ifdef _ANDROID_2_2_ #include "miniegl.h" #else #include #endif #include #include #include #include "sndaudiotrack.h" #ifdef HAVE_OPENSL #include "sndopensl.h" #endif JavaVM * yvm; static jobject yabause; static char mpegpath[256] = "\0"; static char cartpath[256] = "\0"; EGLDisplay g_Display = EGL_NO_DISPLAY; EGLSurface g_Surface = EGL_NO_SURFACE; EGLContext g_Context = EGL_NO_CONTEXT; GLuint g_FrameBuffer = 0; GLuint g_VertexBuffer = 0; int g_buf_width = -1; int g_buf_height = -1; pthread_mutex_t g_mtxGlLock = PTHREAD_MUTEX_INITIALIZER; float vertices [] = { 0, 0, 0, 0, 320, 0, 0, 0, 320, 224, 0, 0, 0, 224, 0, 0 }; int g_swapped; M68K_struct * M68KCoreList[] = { &M68KDummy, #ifdef HAVE_C68K &M68KC68K, #endif #ifdef HAVE_Q68 &M68KQ68, #endif #ifdef HAVE_MUSASHI &M68KMusashi, #endif NULL }; SH2Interface_struct *SH2CoreList[] = { &SH2Interpreter, &SH2DebugInterpreter, #ifdef SH2_DYNAREC &SH2Dynarec, #endif NULL }; PerInterface_struct *PERCoreList[] = { &PERDummy, NULL }; CDInterface *CDCoreList[] = { &DummyCD, &ISOCD, NULL }; SoundInterface_struct *SNDCoreList[] = { &SNDDummy, &SNDAudioTrack, #ifdef HAVE_OPENSL &SNDOpenSL, #endif NULL }; VideoInterface_struct *VIDCoreList[] = { &VIDDummy, &VIDSoft, NULL }; #define LOG_TAG "yabause" /* Override printf for debug*/ int yprintf( const char * fmt, ... ) { va_list ap; va_start(ap, fmt); int result = __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, fmt, ap); va_end(ap); return result; } const char * GetBiosPath() { jclass yclass; jmethodID getBiosPath; jstring message; jboolean dummy; JNIEnv * env; if ((*yvm)->GetEnv(yvm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) return NULL; yclass = (*env)->GetObjectClass(env, yabause); getBiosPath = (*env)->GetMethodID(env, yclass, "getBiosPath", "()Ljava/lang/String;"); message = (*env)->CallObjectMethod(env, yabause, getBiosPath); if ((*env)->GetStringLength(env, message) == 0) return NULL; else return (*env)->GetStringUTFChars(env, message, &dummy); } const char * GetGamePath() { jclass yclass; jmethodID getGamePath; jstring message; jboolean dummy; JNIEnv * env; if ((*yvm)->GetEnv(yvm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) return NULL; yclass = (*env)->GetObjectClass(env, yabause); getGamePath = (*env)->GetMethodID(env, yclass, "getGamePath", "()Ljava/lang/String;"); message = (*env)->CallObjectMethod(env, yabause, getGamePath); if ((*env)->GetStringLength(env, message) == 0) return NULL; else return (*env)->GetStringUTFChars(env, message, &dummy); } const char * GetMemoryPath() { jclass yclass; jmethodID getMemoryPath; jstring message; jboolean dummy; JNIEnv * env; if ((*yvm)->GetEnv(yvm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) return NULL; yclass = (*env)->GetObjectClass(env, yabause); getMemoryPath = (*env)->GetMethodID(env, yclass, "getMemoryPath", "()Ljava/lang/String;"); message = (*env)->CallObjectMethod(env, yabause, getMemoryPath); if ((*env)->GetStringLength(env, message) == 0) return NULL; else return (*env)->GetStringUTFChars(env, message, &dummy); } int GetCartridgeType() { jclass yclass; jmethodID getCartridgeType; JNIEnv * env; if ((*yvm)->GetEnv(yvm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) return -1; yclass = (*env)->GetObjectClass(env, yabause); getCartridgeType = (*env)->GetMethodID(env, yclass, "getCartridgeType", "()I"); return (*env)->CallIntMethod(env, yabause, getCartridgeType); } const char * GetCartridgePath() { jclass yclass; jmethodID getCartridgePath; jstring message; jboolean dummy; JNIEnv * env; if ((*yvm)->GetEnv(yvm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) return NULL; yclass = (*env)->GetObjectClass(env, yabause); getCartridgePath = (*env)->GetMethodID(env, yclass, "getCartridgePath", "()Ljava/lang/String;"); message = (*env)->CallObjectMethod(env, yabause, getCartridgePath); if ((*env)->GetStringLength(env, message) == 0) return NULL; else return (*env)->GetStringUTFChars(env, message, &dummy); } const char * GetSavesPath() { jclass yclass; jmethodID getSavesPath; jstring message; jboolean dummy; JNIEnv * env; if ((*yvm)->GetEnv(yvm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) return NULL; yclass = (*env)->GetObjectClass(env, yabause); getSavesPath = (*env)->GetMethodID(env, yclass, "getSavesPath", "()Ljava/lang/String;"); message = (*env)->CallObjectMethod(env, yabause, getSavesPath); if ((*env)->GetStringLength(env, message) == 0) return NULL; else return (*env)->GetStringUTFChars(env, message, &dummy); } int GetSaveSlot() { jclass yclass; jmethodID getSaveSlot; JNIEnv * env; if ((*yvm)->GetEnv(yvm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) return -1; yclass = (*env)->GetObjectClass(env, yabause); getSaveSlot = (*env)->GetMethodID(env, yclass, "getSaveSlot", "()I"); return (*env)->CallIntMethod(env, yabause, getSaveSlot); } void YuiErrorMsg(const char *string) { jclass yclass; jmethodID errorMsg; jstring message; JNIEnv * env; if ((*yvm)->GetEnv(yvm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) return; yclass = (*env)->GetObjectClass(env, yabause); errorMsg = (*env)->GetMethodID(env, yclass, "errorMsg", "(Ljava/lang/String;)V"); message = (*env)->NewStringUTF(env, string); (*env)->CallVoidMethod(env, yabause, errorMsg, message); } void YuiSwapBuffers(void) { int buf_width, buf_height; int error; g_swapped = 1; pthread_mutex_lock(&g_mtxGlLock); if( g_Display == EGL_NO_DISPLAY ) { pthread_mutex_unlock(&g_mtxGlLock); return; } if( eglMakeCurrent(g_Display,g_Surface,g_Surface,g_Context) == EGL_FALSE ) { yprintf( "eglMakeCurrent fail %04x",eglGetError()); pthread_mutex_unlock(&g_mtxGlLock); return; } { int swidth, sheight; eglQuerySurface(g_Display, g_Surface, EGL_WIDTH, &swidth); eglQuerySurface(g_Display, g_Surface, EGL_HEIGHT, &sheight); glViewport(0,0,swidth,sheight); } glClearColor( 0.0f,0.0f,0.0f,1.0f); glClear(GL_COLOR_BUFFER_BIT); if( g_FrameBuffer == 0 ) { glEnable(GL_TEXTURE_2D); glGenTextures(1,&g_FrameBuffer); glBindTexture(GL_TEXTURE_2D, g_FrameBuffer); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); error = glGetError(); if( error != GL_NO_ERROR ) { yprintf("gl error %d", error ); return; } }else{ glBindTexture(GL_TEXTURE_2D, g_FrameBuffer); } VIDCore->GetGlSize(&buf_width, &buf_height); glTexSubImage2D(GL_TEXTURE_2D, 0,0,0,buf_width,buf_height,GL_RGBA,GL_UNSIGNED_BYTE,dispbuffer); if( g_VertexBuffer == 0 ) { glGenBuffers(1, &g_VertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, g_VertexBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices),vertices,GL_STATIC_DRAW); error = glGetError(); if( error != GL_NO_ERROR ) { yprintf("gl error %d", error ); return; } }else{ glBindBuffer(GL_ARRAY_BUFFER, g_VertexBuffer); } if( buf_width != g_buf_width || buf_height != g_buf_height ) { vertices[6]=vertices[10]=(float)buf_width/1024.f; vertices[11]=vertices[15]=(float)buf_height/1024.f; glBufferData(GL_ARRAY_BUFFER, sizeof(vertices),vertices,GL_STATIC_DRAW); glVertexPointer(2, GL_FLOAT, sizeof(float)*4, 0); glTexCoordPointer(2, GL_FLOAT, sizeof(float)*4, (void*)(sizeof(float)*2)); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); g_buf_width = buf_width; g_buf_height = buf_height; } glDrawArrays(GL_TRIANGLE_FAN, 0, 4); eglSwapBuffers(g_Display,g_Surface); pthread_mutex_unlock(&g_mtxGlLock); } int Java_org_yabause_android_YabauseRunnable_initViewport() { int error; char * buf; g_Display = eglGetCurrentDisplay(); g_Surface = eglGetCurrentSurface(EGL_READ); g_Context = eglGetCurrentContext(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrthof(0, 320, 224, 0, 1, 0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glDisable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); yprintf(glGetString(GL_VENDOR)); yprintf(glGetString(GL_RENDERER)); yprintf(glGetString(GL_VERSION)); yprintf(glGetString(GL_EXTENSIONS)); yprintf(eglQueryString(g_Display,EGL_EXTENSIONS)); eglSwapInterval(g_Display,0); eglMakeCurrent(g_Display,EGL_NO_SURFACE,EGL_NO_SURFACE,EGL_NO_CONTEXT); return 0; } int Java_org_yabause_android_YabauseRunnable_cleanup() { g_FrameBuffer = 0; g_VertexBuffer = 0; g_buf_width = -1; g_buf_height = -1; } #ifdef _ANDROID_2_2_ int initEGLFunc() { void * handle; char *error; handle = dlopen("libEGL.so",RTLD_LAZY); if( handle == NULL ) { yprintf(dlerror()); return -1; } eglGetCurrentDisplay = dlsym(handle, "eglGetCurrentDisplay"); if( eglGetCurrentDisplay == NULL){ yprintf(dlerror()); return -1; } eglGetCurrentSurface = dlsym(handle, "eglGetCurrentSurface"); if( eglGetCurrentSurface == NULL){ yprintf(dlerror()); return -1; } eglGetCurrentContext = dlsym(handle, "eglGetCurrentContext"); if( eglGetCurrentContext == NULL){ yprintf(dlerror()); return -1; } eglQuerySurface = dlsym(handle, "eglQuerySurface"); if( eglQuerySurface == NULL){ yprintf(dlerror()); return -1; } eglSwapInterval = dlsym(handle, "eglSwapInterval"); if( eglSwapInterval == NULL){ yprintf(dlerror()); return -1; } eglMakeCurrent = dlsym(handle, "eglMakeCurrent"); if( eglMakeCurrent == NULL){ yprintf(dlerror()); return -1; } eglSwapBuffers = dlsym(handle, "eglSwapBuffers"); if( eglSwapBuffers == NULL){ yprintf(dlerror()); return -1; } eglQueryString = dlsym(handle, "eglQueryString"); if( eglQueryString == NULL){ yprintf(dlerror()); return -1; } eglGetError = dlsym(handle, "eglGetError"); if( eglGetError == NULL){ yprintf(dlerror()); return -1; } return 0; } #else int initEGLFunc() { return 0; } #endif int Java_org_yabause_android_YabauseRunnable_lockGL() { pthread_mutex_lock(&g_mtxGlLock); } int Java_org_yabause_android_YabauseRunnable_unlockGL() { pthread_mutex_unlock(&g_mtxGlLock); } jint Java_org_yabause_android_YabauseRunnable_init( JNIEnv* env, jobject obj, jobject yab ) { yabauseinit_struct yinit; int res; void * padbits; if( initEGLFunc() == -1 ) return -1; yabause = (*env)->NewGlobalRef(env, yab); memset(&yinit, 0, sizeof(yabauseinit_struct)); yinit.m68kcoretype = M68KCORE_C68K; yinit.percoretype = PERCORE_DUMMY; #ifdef SH2_DYNAREC yinit.sh2coretype = 2; #else yinit.sh2coretype = SH2CORE_DEFAULT; #endif yinit.vidcoretype = VIDCORE_SOFT; #ifdef HAVE_OPENSL yinit.sndcoretype = SNDCORE_OPENSL; #else yinit.sndcoretype = SNDCORE_AUDIOTRACK; #endif yinit.cdcoretype = CDCORE_ISO; yinit.carttype = GetCartridgeType(); yinit.regionid = 0; yinit.biospath = GetBiosPath(); yinit.cdpath = GetGamePath(); yinit.buppath = GetMemoryPath(); yinit.mpegpath = mpegpath; yinit.cartpath = GetCartridgePath(); yinit.videoformattype = VIDEOFORMATTYPE_NTSC; yinit.frameskip = 0; yinit.skip_load = 0; res = YabauseInit(&yinit); { int slot = GetSaveSlot(); if (slot != -1) { const char * dirpath = GetSavesPath(); YabLoadStateSlot(dirpath, slot); } } OSDChangeCore(OSDCORE_SOFT); PerPortReset(); padbits = PerPadAdd(&PORTDATA1); PerSetKey(PERPAD_UP, PERPAD_UP, padbits); PerSetKey(PERPAD_RIGHT, PERPAD_RIGHT, padbits); PerSetKey(PERPAD_DOWN, PERPAD_DOWN, padbits); PerSetKey(PERPAD_LEFT, PERPAD_LEFT, padbits); PerSetKey(PERPAD_START, PERPAD_START, padbits); PerSetKey(PERPAD_A, PERPAD_A, padbits); PerSetKey(PERPAD_B, PERPAD_B, padbits); PerSetKey(PERPAD_C, PERPAD_C, padbits); PerSetKey(PERPAD_X, PERPAD_X, padbits); PerSetKey(PERPAD_Y, PERPAD_Y, padbits); PerSetKey(PERPAD_Z, PERPAD_Z, padbits); return res; } void Java_org_yabause_android_YabauseRunnable_deinit( JNIEnv* env ) { int slot = GetSaveSlot(); if (slot != -1) { const char * dirpath = GetSavesPath(); SetOSDToggle(0); DisableAutoFrameSkip(); g_swapped = 0; while(! g_swapped) YabauseExec(); YabSaveStateSlot(dirpath, slot); } YabauseDeInit(); } void Java_org_yabause_android_YabauseRunnable_exec( JNIEnv* env ) { YabauseExec(); } void Java_org_yabause_android_YabauseRunnable_press( JNIEnv* env, jobject obj, jint key ) { PerKeyDown(key); } void Java_org_yabause_android_YabauseRunnable_release( JNIEnv* env, jobject obj, jint key ) { PerKeyUp(key); } void Java_org_yabause_android_YabauseRunnable_enableFPS( JNIEnv* env, jobject obj, jint enable ) { SetOSDToggle(enable); } void Java_org_yabause_android_YabauseRunnable_enableFrameskip( JNIEnv* env, jobject obj, jint enable ) { if (enable) EnableAutoFrameSkip(); else DisableAutoFrameSkip(); } void Java_org_yabause_android_YabauseRunnable_setVolume( JNIEnv* env, jobject obj, jint volume ) { if (0 == volume) ScspMuteAudio(SCSP_MUTE_USER); else { ScspUnMuteAudio(SCSP_MUTE_USER); ScspSetVolume(volume); } } void Java_org_yabause_android_YabauseRunnable_screenshot( JNIEnv* env, jobject obj, jobject bitmap ) { u32 * buffer; AndroidBitmapInfo info; void * pixels; int x, y; AndroidBitmap_getInfo(env, bitmap, &info); AndroidBitmap_lockPixels(env, bitmap, &pixels); buffer = dispbuffer; for(y = 0;y < info.height;y++) { for(x = 0;x < info.width;x++) { *((uint32_t *) pixels + x) = *(buffer + x); } pixels += info.stride; buffer += g_buf_width; } AndroidBitmap_unlockPixels(env, bitmap); } jobject Java_org_yabause_android_YabauseRunnable_gameInfo( JNIEnv* env, jobject obj, jobject path ) { jmethodID cons; jboolean dummy; jclass c; jstring system, company, itemnum, version, date, cdinfo, region, peripheral, gamename; GameInfo info; const char * filename = (*env)->GetStringUTFChars(env, path, &dummy); if (! GameInfoFromPath(filename, &info)) { return NULL; } c = (*env)->FindClass(env, "org/yabause/android/GameInfo"); cons = (*env)->GetMethodID(env, c, "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); system = (*env)->NewStringUTF(env, info.system); company = (*env)->NewStringUTF(env, info.company); itemnum = (*env)->NewStringUTF(env, info.itemnum); version = (*env)->NewStringUTF(env, info.version); date = (*env)->NewStringUTF(env, info.date); cdinfo = (*env)->NewStringUTF(env, info.cdinfo); region = (*env)->NewStringUTF(env, info.region); peripheral = (*env)->NewStringUTF(env, info.peripheral); gamename = (*env)->NewStringUTF(env, info.gamename); return (*env)->NewObject(env, c, cons, system, company, itemnum, version, date, cdinfo, region, peripheral, gamename); } void Java_org_yabause_android_YabauseRunnable_stateSlotScreenshot( JNIEnv* env, jobject obj, jobject dirpath, jobject itemnum, int slot, jobject bitmap ) { int outputwidth, outputheight; u32 * buffer, * cur; AndroidBitmapInfo info; void * pixels; int x, y; jboolean dummy; const char * dp = (*env)->GetStringUTFChars(env, dirpath, &dummy); const char * in = (*env)->GetStringUTFChars(env, itemnum, &dummy); if (0 != LoadStateSlotScreenshot(dp, in, slot, &outputwidth, &outputheight, &buffer)) return; AndroidBitmap_getInfo(env, bitmap, &info); AndroidBitmap_lockPixels(env, bitmap, &pixels); cur = buffer; for(y = 0;y < info.height;y++) { for(x = 0;x < info.width;x++) { *((uint32_t *) pixels + x) = *(cur + x); } pixels += info.stride; cur += outputwidth; } free(buffer); AndroidBitmap_unlockPixels(env, bitmap); } void log_callback(char * message) { __android_log_print(ANDROID_LOG_INFO, "yabause", "%s", message); } jint JNI_OnLoad(JavaVM * vm, void * reserved) { JNIEnv * env; if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) return -1; yvm = vm; LogStart(); LogChangeOutput(DEBUG_CALLBACK, (char *) log_callback); return JNI_VERSION_1_6; } yabause-0.9.15/src/android/jni/sndaudiotrack.c000644 001750 001750 00000014347 12755623101 023252 0ustar00guillaumeguillaume000000 000000 /* Copyright 2012 Guillaume Duhamel Copyright 2005-2006 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "sndaudiotrack.h" #include "debug.h" static int SNDAudioTrackInit(void); static void SNDAudioTrackDeInit(void); static int SNDAudioTrackReset(void); static int SNDAudioTrackChangeVideoFormat(int vertfreq); static void SNDAudioTrackUpdateAudio(u32 *leftchanbuffer, u32 *rightchanbuffer, u32 num_samples); static u32 SNDAudioTrackGetAudioSpace(void); static void SNDAudioTrackMuteAudio(void); static void SNDAudioTrackUnMuteAudio(void); static void SNDAudioTrackSetVolume(int volume); SoundInterface_struct SNDAudioTrack = { SNDCORE_AUDIOTRACK, "Audio Track Sound Interface", SNDAudioTrackInit, SNDAudioTrackDeInit, SNDAudioTrackReset, SNDAudioTrackChangeVideoFormat, SNDAudioTrackUpdateAudio, SNDAudioTrackGetAudioSpace, SNDAudioTrackMuteAudio, SNDAudioTrackUnMuteAudio, SNDAudioTrackSetVolume }; extern JavaVM * yvm; jobject gtrack = NULL; jclass cAudioTrack = NULL; jmethodID mWrite = NULL; int mbufferSizeInBytes; static u16 *stereodata16; static u8 soundvolume; static u8 soundmaxvolume; static u8 soundbufsize; static int soundoffset; static int muted; ////////////////////////////////////////////////////////////////////////////// static int SNDAudioTrackInit(void) { int sampleRateInHz = 44100; int channelConfig = 12; //AudioFormat.CHANNEL_OUT_STEREO int audioFormat = 2; //AudioFormat.ENCODING_PCM_16BIT JNIEnv * env; jobject mtrack = NULL; jmethodID mPlay = NULL; jmethodID mGetMinBufferSize = NULL; jmethodID mAudioTrack = NULL; if ((*yvm)->GetEnv(yvm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) return -1; cAudioTrack = (*env)->FindClass(env, "android/media/AudioTrack"); cAudioTrack = (jclass) (*env)->NewGlobalRef(env, cAudioTrack); mAudioTrack = (*env)->GetMethodID(env, cAudioTrack, "", "(IIIIII)V"); mWrite = (*env)->GetMethodID(env, cAudioTrack, "write", "([BII)I"); mPlay = (*env)->GetMethodID(env, cAudioTrack, "play", "()V"); mGetMinBufferSize = (*env)->GetStaticMethodID(env, cAudioTrack, "getMinBufferSize", "(III)I"); mbufferSizeInBytes = (*env)->CallStaticIntMethod(env, cAudioTrack, mGetMinBufferSize, sampleRateInHz, channelConfig, audioFormat); mtrack = (*env)->NewObject(env, cAudioTrack, mAudioTrack, 3 /* STREAM_MUSIC */, sampleRateInHz, channelConfig, audioFormat, mbufferSizeInBytes, 1 /* MODE_STREAM */); gtrack = (*env)->NewGlobalRef(env, mtrack); (*env)->CallNonvirtualVoidMethod(env, gtrack, cAudioTrack, mPlay); if ((stereodata16 = (u16 *)malloc(2 * mbufferSizeInBytes)) == NULL) return -1; memset(stereodata16, 0, soundbufsize); soundvolume = 100; soundmaxvolume = 100; soundbufsize = 85; soundoffset = 0; muted = 0; return 0; } ////////////////////////////////////////////////////////////////////////////// static void SNDAudioTrackDeInit(void) { JNIEnv * env; if ((*yvm)->GetEnv(yvm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) return; free(stereodata16); stereodata16 = NULL; (*env)->DeleteGlobalRef(env, gtrack); } ////////////////////////////////////////////////////////////////////////////// static int SNDAudioTrackReset(void) { return 0; } ////////////////////////////////////////////////////////////////////////////// static int SNDAudioTrackChangeVideoFormat(int vertfreq) { return 0; } ////////////////////////////////////////////////////////////////////////////// static void sdlConvert32uto16s(s32 *srcL, s32 *srcR, s16 *dst, u32 len) { u32 i; for (i = 0; i < len; i++) { // Left Channel *srcL = ( *srcL *soundvolume ) / soundmaxvolume; if (*srcL > 0x7FFF) *dst = 0x7FFF; else if (*srcL < -0x8000) *dst = -0x8000; else *dst = *srcL; srcL++; dst++; // Right Channel *srcR = ( *srcR *soundvolume ) / soundmaxvolume; if (*srcR > 0x7FFF) *dst = 0x7FFF; else if (*srcR < -0x8000) *dst = -0x8000; else *dst = *srcR; srcR++; dst++; } } static void SNDAudioTrackUpdateAudio(u32 *leftchanbuffer, u32 *rightchanbuffer, u32 num_samples) { u32 copy1size=0; copy1size = (num_samples * sizeof(s16) * 2); sdlConvert32uto16s((s32 *)leftchanbuffer, (s32 *)rightchanbuffer, (s16 *)(((u8 *)stereodata16)+soundoffset), copy1size / sizeof(s16) / 2); soundoffset += copy1size; if (soundoffset > mbufferSizeInBytes) { if (! muted) { JNIEnv * env; jbyteArray array; if ((*yvm)->GetEnv(yvm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) return; array = (*env)->NewByteArray(env, soundoffset); if(array) { (*env)->SetByteArrayRegion(env, array, 0, soundoffset, (u8 *) stereodata16); } (*env)->CallNonvirtualIntMethod(env, gtrack, cAudioTrack, mWrite, array, 0, soundoffset); } soundoffset = 0; } } ////////////////////////////////////////////////////////////////////////////// static u32 SNDAudioTrackGetAudioSpace(void) { static int i = 0; i++; if (i == 55) { i = 0; return mbufferSizeInBytes; } else { return 0; } } ////////////////////////////////////////////////////////////////////////////// static void SNDAudioTrackMuteAudio(void) { muted = 1; } ////////////////////////////////////////////////////////////////////////////// static void SNDAudioTrackUnMuteAudio(void) { muted = 0; } ////////////////////////////////////////////////////////////////////////////// static void SNDAudioTrackSetVolume(int volume) { soundvolume = volume; } yabause-0.9.15/src/android/jni/sndaudiotrack.h000644 001750 001750 00000001647 12755623101 023256 0ustar00guillaumeguillaume000000 000000 /* Copyright 2012 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SNDAUDIOTRACK_H #define SNDAUDIOTRACK_H #define SNDCORE_AUDIOTRACK 4 #include "scsp.h" extern SoundInterface_struct SNDAudioTrack; #endif yabause-0.9.15/src/android/jni/sndopensl.h000644 001750 001750 00000001627 12755623101 022426 0ustar00guillaumeguillaume000000 000000 /* Copyright 2012 Guillaume Duhamel This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SNDOPENSL_H #define SNDOPENSL_H #define SNDCORE_OPENSL 5 #include "scsp.h" extern SoundInterface_struct SNDOpenSL; #endif yabause-0.9.15/src/android/jni/Android.mk.in000644 001750 001750 00000000660 12755623101 022562 0ustar00guillaumeguillaume000000 000000 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := yabause LOCAL_SRC_FILES := yui.c @YABAUSE_JNI_SRC@ LOCAL_STATIC_LIBRARIES := yabause-prebuilt LOCAL_LDLIBS := -llog -ljnigraphics -lGLESv1_CM @YABAUSE_JNI_LIB@ include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := yabause-prebuilt LOCAL_SRC_FILES := libyabause.a LOCAL_EXPORT_C_INCLUDES := @YABAUSE_INCLUDE_DIR@ include $(PREBUILT_STATIC_LIBRARY) yabause-0.9.15/src/android/jni/sndopensl.c000644 001750 001750 00000025304 12755623101 022417 0ustar00guillaumeguillaume000000 000000 /* Copyright 2012 Guillaume Duhamel Copyright 2005-2006 Theo Berkau This file is part of Yabause. Yabause 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. Yabause 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 Yabause; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "sndopensl.h" // for native audio #include #include // for native asset manager #include #include #include #include "debug.h" static int SNDOpenSLInit(void); static void SNDOpenSLDeInit(void); static int SNDOpenSLReset(void); static int SNDOpenSLChangeVideoFormat(int vertfreq); static void SNDOpenSLUpdateAudio(u32 *leftchanbuffer, u32 *rightchanbuffer, u32 num_samples); static u32 SNDOpenSLGetAudioSpace(void); static void SNDOpenSLMuteAudio(void); static void SNDOpenSLUnMuteAudio(void); static void SNDOpenSLSetVolume(int volume); SoundInterface_struct SNDOpenSL = { SNDCORE_OPENSL, "OpenSL Sound Interface", SNDOpenSLInit, SNDOpenSLDeInit, SNDOpenSLReset, SNDOpenSLChangeVideoFormat, SNDOpenSLUpdateAudio, SNDOpenSLGetAudioSpace, SNDOpenSLMuteAudio, SNDOpenSLUnMuteAudio, SNDOpenSLSetVolume }; extern JavaVM * yvm; // engine interfaces static SLObjectItf engineObject = NULL; static SLEngineItf engineEngine; // output mix interfaces static SLObjectItf outputMixObject = NULL; static SLEnvironmentalReverbItf outputMixEnvironmentalReverb = NULL; // buffer queue player interfaces static SLObjectItf bqPlayerObject = NULL; static SLPlayItf bqPlayerPlay; static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue; static SLEffectSendItf bqPlayerEffectSend; static SLMuteSoloItf bqPlayerMuteSolo; static SLVolumeItf bqPlayerVolume; // pointer and size of the next player buffer to enqueue, and number of remaining buffers static short *nextBuffer; static unsigned nextSize; static int nextCount; int mbufferSizeInBytes; #define MAX_BUFFER_CNT (2) static u16 *stereodata16[MAX_BUFFER_CNT]; static int currentpos = 0; static int soundbufsize=0; static int soundoffset[MAX_BUFFER_CNT]={0}; static u8 soundvolume; static u8 soundmaxvolume; #define MAX_QUEUE (32) static int queue_head = 0; static int queue_tail = 0; static int index_queue[MAX_QUEUE]={0}; static int muted; void push_index( int index ) { index_queue[queue_tail] = index; queue_tail++; if( queue_tail >= MAX_QUEUE ) queue_tail = 0; } int pop_index() { int val = index_queue[queue_head]; queue_head++; if( queue_head >= MAX_QUEUE ) queue_head = 0; return val; } // this callback handler is called every time a buffer finishes playing void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) { assert(bq == bqPlayerBufferQueue); assert(NULL == context); int playpos = pop_index(); //printf("bqPlayerCallback %d,%d",playpos,soundoffset[playpos]); soundoffset[playpos] = 0; } ////////////////////////////////////////////////////////////////////////////// static int SNDOpenSLInit(void) { int i; // configure audio source SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 2, SL_SAMPLINGRATE_44_1, SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16, (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT), SL_BYTEORDER_LITTLEENDIAN}; SLDataSource audioSrc = {&loc_bufq, &format_pcm}; SLresult result; // create engine result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); assert(SL_RESULT_SUCCESS == result); // realize the engine result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); assert(SL_RESULT_SUCCESS == result); // get the engine interface, which is needed in order to create other objects result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); assert(SL_RESULT_SUCCESS == result); // create output mix, with environmental reverb specified as a non-required interface const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB}; const SLboolean req[1] = {SL_BOOLEAN_FALSE}; result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req); assert(SL_RESULT_SUCCESS == result); // realize the output mix result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); assert(SL_RESULT_SUCCESS == result); // configure audio sink SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject}; SLDataSink audioSnk = {&loc_outmix, NULL}; // create audio player const SLInterfaceID aids[3] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND, /*SL_IID_MUTESOLO,*/ SL_IID_VOLUME}; const SLboolean areq[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE,/*SL_BOOLEAN_TRUE,*/ SL_BOOLEAN_TRUE}; result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 3, aids, areq); assert(SL_RESULT_SUCCESS == result); // realize the player result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE); assert(SL_RESULT_SUCCESS == result); // get the play interface result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay); assert(SL_RESULT_SUCCESS == result); // get the buffer queue interface result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE, &bqPlayerBufferQueue); assert(SL_RESULT_SUCCESS == result); // register callback on the buffer queue result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL); assert(SL_RESULT_SUCCESS == result); // get the effect send interface result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_EFFECTSEND, &bqPlayerEffectSend); assert(SL_RESULT_SUCCESS == result); #if 0 // mute/solo is not supported for sources that are known to be mono, as this is // get the mute/solo interface result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_MUTESOLO, &bqPlayerMuteSolo); assert(SL_RESULT_SUCCESS == result); #endif // get the volume interface result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume); assert(SL_RESULT_SUCCESS == result); InitSoundBuff(); // set the player's state to playing result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING); assert(SL_RESULT_SUCCESS == result); muted = 0; return 0; } int InitSoundBuff() { int i; // 5msec( 2byte * 44100Hz * 0.005 ) mbufferSizeInBytes = 2940*4; //2 * 44100 * 2 *0.016; soundbufsize = mbufferSizeInBytes*2; for( i=0; i< MAX_BUFFER_CNT; i++ ) { if ((stereodata16[i] = (u16 *)malloc(soundbufsize)) == NULL) return -1; memset(stereodata16[i], 0, soundbufsize); soundoffset[i] = 0; } soundvolume = 100; soundmaxvolume = 100; printf("InitSoundBuff %d,%d\n",mbufferSizeInBytes,soundbufsize); printf("SNDOpenSLInit %08x,%08X,%08x,%08x",stereodata16[0],(int)(stereodata16[0]) + soundbufsize, stereodata16[1],(int)(stereodata16[1]) + soundbufsize); return 0; } ////////////////////////////////////////////////////////////////////////////// static void SNDOpenSLDeInit(void) { int i; JNIEnv * env; for( i=0; i< MAX_BUFFER_CNT; i++ ) { free(stereodata16[i]); stereodata16[i] = NULL; } } ////////////////////////////////////////////////////////////////////////////// static int SNDOpenSLReset(void) { return 0; } ////////////////////////////////////////////////////////////////////////////// static int SNDOpenSLChangeVideoFormat(int vertfreq) { return 0; } ////////////////////////////////////////////////////////////////////////////// static void sdlConvert32uto16s(s32 *srcL, s32 *srcR, s16 *dst, u32 len) { u32 i; for (i = 0; i < len; i++) { // Left Channel *srcL = ( *srcL *soundvolume ) / soundmaxvolume; if (*srcL > 0x7FFF) *dst = 0x7FFF; else if (*srcL < -0x8000) *dst = -0x8000; else *dst = *srcL; srcL++; dst++; // Right Channel *srcR = ( *srcR *soundvolume ) / soundmaxvolume; if (*srcR > 0x7FFF) *dst = 0x7FFF; else if (*srcR < -0x8000) *dst = -0x8000; else *dst = *srcR; srcR++; dst++; } } static void SNDOpenSLUpdateAudio(u32 *leftchanbuffer, u32 *rightchanbuffer, u32 num_samples) { // return; u32 copy1size=0; int nextpos; copy1size = (num_samples * sizeof(s16) * 2); //printf("SNDOpenSLUpdateAudio %08X,%08X,%08X",currentpos,soundoffset[currentpos],copy1size); sdlConvert32uto16s((s32 *)leftchanbuffer, (s32 *)rightchanbuffer, (s16 *)(((u8 *)stereodata16[currentpos])+soundoffset[currentpos] ), copy1size / sizeof(s16) / 2); soundoffset[currentpos] += copy1size; if (soundoffset[currentpos] >= mbufferSizeInBytes) { if (!muted) { // here we only enqueue one buffer because it is a long clip, // but for streaming playback we would typically enqueue at least 2 buffers to start SLresult result; push_index(currentpos); result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, stereodata16[currentpos], soundoffset[currentpos]); if (SL_RESULT_SUCCESS != result) { printf("Fail to Add queue"); return; } } nextpos = currentpos+1; if( nextpos >= MAX_BUFFER_CNT ) { nextpos = 0; } currentpos = nextpos; } } ////////////////////////////////////////////////////////////////////////////// static u32 SNDOpenSLGetAudioSpace(void) { // printf("SNDOpenSLGetAudioSpace %d,%d",soundoffset,mbufferSizeInBytes); int val = (mbufferSizeInBytes-soundoffset[currentpos]); if( val < 0 ) return 0; return val; } ////////////////////////////////////////////////////////////////////////////// static void SNDOpenSLMuteAudio(void) { muted = 1; } ////////////////////////////////////////////////////////////////////////////// static void SNDOpenSLUnMuteAudio(void) { muted = 0; } ////////////////////////////////////////////////////////////////////////////// static void SNDOpenSLSetVolume(int volume) { } yabause-0.9.15/src/android/build.xml000644 001750 001750 00000006402 12757373537 021326 0ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/android/android-windows.cmake000644 001750 001750 00000001623 12755623101 023576 0ustar00guillaumeguillaume000000 000000 SET(CMAKE_SYSTEM_NAME Linux) SET(CMAKE_SYSTEM_VERSION 1) SET(CMAKE_C_COMPILER "C:/android-ndk-r8e/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/arm-linux-androideabi-gcc.exe") SET(CMAKE_CXX_COMPILER "C:/android-ndk-r8e/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/arm-linux-androideabi-g++.exe") SET(CMAKE_ASM-ATT_COMPILER "C:/android-ndk-r8e/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/arm-linux-androideabi-as.exe") SET(CMAKE_FIND_ROOT_PATH "C:/android-ndk-r8e/platforms/android-8/arch-arm/usr") set(CMAKE_C_FLAGS "--sysroot=C:/android-ndk-r8e/platforms/android-8/arch-arm" CACHE STRING "GCC flags" FORCE) set(CMAKE_CXX_FLAGS "--sysroot=C:/android-ndk-r8e/platforms/android-8/arch-arm" CACHE STRING "G++ flags" FORCE) SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) SET(ANDROID ON) yabause-0.9.15/src/android/res/000755 001750 001750 00000000000 12757373644 020273 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/android/res/layout/000755 001750 001750 00000000000 12757373644 021610 5ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/android/res/layout/save_item.xml000644 001750 001750 00000001635 12757373537 024314 0ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/android/res/layout/game_item.xml000644 001750 001750 00000001264 12757373537 024265 0ustar00guillaumeguillaume000000 000000 yabause-0.9.15/src/android/res/layout/save_list.xml000644 001750 001750 00000002150 12755623101 024301 0ustar00guillaumeguillaume000000 000000