kopia lustrzana https://github.com/Jean-MarcHarvengt/MCUME
603 wiersze
14 KiB
C
603 wiersze
14 KiB
C
#include "atari5200.h"
|
|
#include <string.h>
|
|
#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");
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|