#include "atari5200.h" #include #include "memory.h" #include "cpu.h" #include "atari.h" #include "pokey.h" #include "rom.h" #include "antic.h" #include "gtia.h" #include "colours.h" #include "emuapi.h" #if HAS_SND #include "pokeysnd.h" #endif // Controllers typedef struct { // All values are 1 or 0, or perhaps not... int left; int right; int up; int down; unsigned char analog_h; unsigned char analog_v; int trig; int side_button; // These may be set to 1. The core handles clearing them. // [BREAK] [ # ] [ 0 ] [ * ] // [RESET] [ 9 ] [ 8 ] [ 7 ] // [PAUSE] [ 6 ] [ 5 ] [ 4 ] // [START] [ 3 ] [ 2 ] [ 1 ] int key[16]; int last_key_still_pressed; int lastRead; } CONTROLLER; #define POT_MAX 223 #define POT_CENTRE 115 #define POT_LEFT (POT_CENTRE-100) //15 #define POT_RIGHT (POT_CENTRE+100) // 210 #define CONSOL 0xC01F #define NUM_16K_ROM_MAPS 200 typedef struct { // 80 bytes char crc[8]; int mapping; char description[68]; } Map16k_t; // global variables int tv_mode = TV_PAL; //unsigned char mem[MEMORY_SIZE]; unsigned char * memory=NULL; //mem; // local variables static char logmsg[64]; static CONTROLLER cont1, cont2; static int pot_max_left = POT_LEFT; static int pot_max_right = POT_RIGHT; static int framesdrawn=0; /* MEMORY MAP INDEX (0 is invalid) * 0-3FFF RAM (read/write) 1 * 4000-BFFF ROM (ro) 2 * C000-C0FF GTIA regs 3 * D300-D3FF Serial??? 7 * D400-D4FF ANTIC regs 4 * E000 I/O expansion 5 * E800-E8FF POKEY regs 6 * EB00-EBFF also POKEY regs??? 6 * F800-FFFF ROM (BIOS)(ro) 2 */ // memory CPU read (load) handler uint8 Atari_GetByte(uint16 addr) { if (addr < 0xC000) { // MAPPER_RAM or MAPPER_ROM return(memory[addr]); } else if (addr < 0xC100) { // MAPPER_GTIA return GTIA_GetByte(addr,1); } else if ( (addr >= 0xD400) && (addr < 0xD500) ) { // MAPPER_ANTIC return ANTIC_GetByte(addr,1); } else if ( (addr >= 0xE800) && (addr < 0xE900) ) { // MAPPER_POKEY return POKEY_GetByte(addr,1); } else if ( (addr >= 0xEB00) && (addr < 0xEC00) ) { // MAPPER_POKEY mirror return POKEY_GetByte(addr,1); } else if (addr >= 0xF800) { // MAPPER_ROM (bios) return(BIOSData[addr-0xF800]); } //case MAPPER_IOEXP: // I/O exp read // return IOEXPread(addr); return 0xff; } // memory CPU write (store) handler void Atari_PutByte(uint16 addr, uint8 byte) { if (addr < 0x4000) { // MAPPER_RAM memory[addr] = byte; } else if (addr < 0xC000) { // MAPPER_ROM } else if (addr < 0xC100) { // MAPPER_GTIA GTIA_PutByte(addr, byte); } else if ( (addr >= 0xD400) && (addr < 0xD500) ) { // MAPPER_ANTIC ANTIC_PutByte(addr, byte); } else if ( (addr >= 0xE800) && (addr < 0xE900) ) { // MAPPER_POKEY POKEY_PutByte(addr, byte); } else if ( (addr >= 0xEB00) && (addr < 0xEC00) ) { // MAPPER_POKEY mirror POKEY_PutByte(addr, byte); } //else if (addr >= 0xF800) { // MAPPER_ROM (bios) // POKEY_PutByte(addr, byte); //} //case MAPPER_IOEXP: // I/O exp write // IOEXPwrite(addr, byte); } // check keyboard and set kbcode on VBI void INPUT_Scanline(void) { // NB: 5200 will do a keyboard IRQ every 32 scanlines if a key is held down CONTROLLER *which = NULL; UBYTE consol=GTIA_GetByte(CONSOL,1); switch (consol & 0x03) { case 0: which = &cont1; break; case 1: which = &cont2; break; // 3 and 4 in the future default: return; } // "loose bit" (bit 5 of KBCODE) - fluctuates 0 or 1 randomly uint8 loose_bit = (framesdrawn & 0x1) << 5; // Default to "key not pressed" POKEY_KBCODE = loose_bit | 0x1F; which->last_key_still_pressed = 0; for (int8 i = 0; i < 16; i++) { if (which->key[i]) { //emu_printi(i); /* 2016-06-18 - commented out (reset in HostDoEvents()) which->key[i] = 0; which->last_key_still_pressed = 0; // Don't respond to the same thing twice in a row... if (i == which->lastRead) { which->last_key_still_pressed = 1; // flag key still held return; } */ if (i == which->lastRead) which->last_key_still_pressed = 1; // flag key still held which->lastRead = i; // Write in the change POKEY_KBCODE = (i << 1) | loose_bit | 0x1; // set KEY interrupt bit (bit 6) to 0 (key int req "on") POKEY_IRQST &= 0xbf; // check irqen and do interrupt if bit 6 set if(POKEY_IRQEN & 0x40) { CPU_GenerateIRQ(); } return; } } // 2016-06-18 - Reset kbd irq if no key pressed // NO - "POKEY_IRQST is latched, only reset by write to IRQEN" //POKEY_IRQST |= 0x40; // If no keys are down at all, we can write anything again which->lastRead = 0xFF; // This should in theory work but in practise breaks some games? //POKEY_KBCODE = which->lastRead = 0xFF; } uint8 INPUT_handle_trigger(uint16 POKEYreg) { CONTROLLER *which; switch (POKEYreg) { case 0: case 1: which = &cont1; if (which->trig) GTIA_TRIG[0]=0; else GTIA_TRIG[0]=1; break; case 2: case 3: which = &cont2; if (which->trig) GTIA_TRIG[1]=0; else GTIA_TRIG[1]=1; break; // 3 and 4 in the future default: return 0x80; } // Top to bottom if (POKEYreg & 1) { #if ANALOGJOY return which->analog_v;; #else if (which->up) return pot_max_left; else if (which->down) return pot_max_right; else return POT_CENTRE; #endif } else { #if ANALOGJOY return which->analog_h;; #else if (which->left) return pot_max_left; else if (which->right) return pot_max_right; else return POT_CENTRE; #endif } } uint8 INPUT_handle_skstat(uint16 POKEYreg) { uint8 skstatreg = 0x0C; UBYTE consol=GTIA_GetByte(CONSOL,1); //emu_printi(consol&3); switch(consol & 0x03) { case 0 : // controller 1 if(cont1.side_button) skstatreg &= 0x07; if(cont1.last_key_still_pressed) skstatreg &= 0x0B; break; case 1 : // controller 2 if(cont2.side_button) skstatreg &= 0x07; if(cont2.last_key_still_pressed) skstatreg &= 0x0B; break; } return skstatreg; } static void load_CART(char * cartname) { int i, mapnum, flen; char sig[40]; unsigned long crc32; flen = emu_FileSize(cartname); emu_FileOpen(cartname); // set POT left and right values to default pot_max_left = POT_LEFT; pot_max_right = POT_RIGHT; // load cart into memory image // Note: 5200 cartridge mapping has only a few // variations, so this mess of code below // works, and it avoids having a cartridge // config file. switch (flen) { case 32768: // 32k cart for (i = 0; i < 32768; i++) memory[0x4000 + i] = emu_FileGetc(); // get crc32 from 32k data crc32 = calc_crc32(memory + 0x4000, 32768); sprintf(logmsg, "32 Trying to load '%s', crc32=0x%08X\n", cartname, (unsigned int)crc32); emu_printf(logmsg); break; case 16384: // 16k cart // here we hack and load it twice (mapped like that?) for (i = 0; i < 16384; i++) memory[0x4000 + i] = memory[0x8000 + i] = emu_FileGetc(); // get crc32 from 16k data crc32 = calc_crc32(memory + 0x4000, 16384); sprintf(logmsg, "16 Trying to load '%s', crc32=0x%08X\n", cartname, (unsigned int)crc32); emu_printf(logmsg); // get cart "signature" strncpy(sig, &memory[0xBFE8], 20); sig[20] = 0; //printf("Cart signature is %s\n", sig); // check for Moon Patrol if (strcmp("@@@@@moon@patrol@@@@", sig) == 0) { //printf("Mapping for Moon Patrol (16+16)\n"); // already loaded correctly break; } // check for SW-Arcade if (strncmp("asfilmLt", sig, 8) == 0) { //printf("Mapping for SW-Arcade (16+16)\n"); // already loaded correctly break; } // check for Super Pacman using start vector if ((memory[0xBFFF] == 0x92) && (memory[0xBFFE] == 0x55)) { //printf("Mapping for Super Pacman (16+16)\n"); // already loaded correctly break; } // check for other carts with reset vec 8000h // (eg: Space Shuttle) if (memory[0xBFFF] == 0x80) { //printf("Mapping for reset vec = 8000h (16+16)\n"); // already loaded corectly break; } // Tempest if (memory[0xBFFF] == 0x81) { //printf("Mapping for reset vec = 81xxh eg: Tempest (16+16)\n"); // already loaded corectly break; } // PAM Diagnostics v2.0 // NB: this seems to prevent the emu from crashing when running // pamdiag2.bin if ((memory[0xBFFF] == 0x9F) && (memory[0xBFFE] == 0xD0)) { //printf("Mapping for reset vector = $9FD0 (PAM DIAG 2.0)\n"); // move cart up by 0x1000 break; } #ifdef SKIP // Notes: check for megamania cart // 8K mirrored at 0x8000 and 0xA000, nothing from 0x4000-0x7FFF // see if we have a 16k mapping for this cart in jum52.cfg sprintf(sig, "%08X", crc32); mapnum = 0; // invalid // initialise 16k rom maps emu_printf("Allocating p16kMaps"); int num16kMappings = 0; // pointer to 16k rom mappings and number of 16k rom mappings Map16k_t * p16kMaps = (Map16k_t *)emu_TmpMemory(); //emu_Malloc(sizeof(Map16k_t) * NUM_16K_ROM_MAPS); if (p16kMaps) memset(p16kMaps, 0, sizeof(Map16k_t) * NUM_16K_ROM_MAPS); for (i = 0; i < num16kMappings; i++) { if (0 == strncmp(sig, p16kMaps[i].crc, 8)) { mapnum = p16kMaps[i].mapping; sprintf(logmsg, "Mapping %d found for crc=0x%s !\n", mapnum, sig); emu_printf(logmsg); i = num16kMappings; // exit search } } //emu_printf("freeing p16kMaps"); //emu_Free(p16kMaps); // if the mapping was 16+16, then break, since we have loaded it 16+16 already if (1 == mapnum) break; #endif // default to 16k+8k mapping emu_FileSeek(0); for(i=0; i<16384; i++) memory[0x6000 + i] = emu_FileGetc(); for(i=0; i<8192; i++) memory[0xA000 + i] = memory[0x8000 + i]; break; case 8192 : // 8k cart // Load mirrored 4 times for(i = 0; i < 8192; i++) { uint8 c = emu_FileGetc(); memory[0x4000 + i] = c; memory[0x6000 + i] = c; memory[0x8000 + i] = c; memory[0xA000 + i] = c; } // get crc32 from 8k data crc32 = calc_crc32(memory + 0x4000, 8192); sprintf(logmsg, "8k cart load '%s', crc32=0x%08X\n", cartname, (unsigned int)crc32); emu_printf(logmsg); break; default: // oops! // these rom dumps are strange, because some carts are 8K, yet // all the dumps are either 16K or 32K! sprintf(logmsg, "Cartridge ROM size not 16K or 32K. Unable to load."); emu_printf(logmsg); return -1; break; } // check for Pengo if (strncmp("pengo", memory + 0xBFEF, 8) == 0) { emu_printf("Pengo detected! Switching controller to Pengo mode."); pot_max_left = 70; pot_max_right = 170; } // check for Centipede if (strncmp("centipede", memory + 0xBFEF, 8) == 0) { emu_printf("centipede detected! Switching controller to centipede mode."); pot_max_left = (POT_CENTRE-10); pot_max_right = (POT_CENTRE+10); } // is cartridge PAL-compatible? // (doesn't seem to work!) //if(memory[0xBFE7] == 0x02) printf("Cart is PAL-compatible!\n"); //else printf("Cart is *not* PAL-compatible.\n"); emu_FileClose(); } static void Initialise(void) { int i; emu_printf("Initialising ..."); // Set up memory area memset(memory, 0, MEMORY_SIZE); // init controllers memset(&cont1, 0, sizeof(CONTROLLER)); memset(&cont2, 0, sizeof(CONTROLLER)); pot_max_left = POT_LEFT; pot_max_right = POT_RIGHT; cont1.analog_h = POT_CENTRE; cont1.analog_v = POT_CENTRE; cont2.analog_h = POT_CENTRE; cont2.analog_v = POT_CENTRE; } void at5_Init(void) { int i; // Palette for (i = 0; i < PALETTE_SIZE; i++) { emu_SetPaletteEntry(R32(colourtable[i]), G32(colourtable[i]), B32(colourtable[i]), i); } #if HAS_SND emu_sndInit(); POKEYSND_Init(POKEYSND_FREQ_17_EXACT, POKEYSND_SAMRATE, 1, POKEYSND_BIT16); POKEYSND_SetVolume(0x40); #endif emu_printf("Allocating RAM"); if (memory == NULL) memory = emu_Malloc(MEMORY_SIZE); Initialise(); } static int prevKey=-1; static int countKey = 0; void at5_Step(void) { //emu_printf("step"); int k,j; j=emu_ReadKeys(); k=emu_GetPad(); CONTROLLER * which; if (j & 0x8000) which=&cont2; else which=&cont1; // Start if (j & MASK_KEY_USER1) which->key[12] = 1; else which->key[12] = 0; // 1 if (j & MASK_KEY_USER3) which->key[15] = 1; else which->key[15] = 0; // 2 //if (j & MASK_KEY_USER4) // which->key[14] = 1; //else // which->key[14] = 0; if (countKey) { which->key[prevKey] = 1; //emu_printi(cont1.key[prevKey]); countKey--; } else { if (prevKey>0) { //emu_printf("resetting"); which->key[prevKey] = 0; prevKey=-1; //emu_printi(cont1.key[prevKey]); } if (k) { prevKey = k-1; which->key[prevKey] = 1; //emu_printi(cont1.key[prevKey]); countKey = 4; } } // Joystick side button, trigger and directions if (j & MASK_JOY2_BTN) which->trig = 1; else which->trig = 0; if (j & MASK_KEY_USER2) which->side_button = 1; else which->side_button = 0; if (j & MASK_JOY2_DOWN) which->down = 1; else which->down = 0; if (j & MASK_JOY2_UP) which->up = 1; else which->up = 0; if (j & MASK_JOY2_RIGHT) which->left = 1; else which->left = 0; if (j & MASK_JOY2_LEFT) which->right = 1; else which->right = 0; which->analog_h = emu_ReadAnalogJoyX(0,230); which->analog_v = emu_ReadAnalogJoyY(0,230); GTIA_Frame(); ANTIC_Frame(1); emu_DrawVsync(); POKEY_Frame(); //int i; //for (i=0xC000; i< 0x10000; i++) // if (memory[i] !=0) emu_printf("bug"); framesdrawn = framesdrawn +1; } void at5_Start(char * cartname) { int i; load_CART(cartname); emu_printf("antic"); ANTIC_Initialise(); emu_printf("gtia"); GTIA_Initialise(); emu_printf("pokey"); POKEY_Initialise(); GTIA_TRIG[0]=1; GTIA_TRIG[1]=1; GTIA_TRIG[2]=1; GTIA_TRIG[3]=1; emu_printf("6502 reset"); CPU_Reset(); emu_printf("init done"); }