new SMS driver

This commit is contained in:
dinkc64 2015-02-24 18:33:53 +00:00
parent 57b7164b13
commit acae9bcdb1
21 changed files with 16020 additions and 1152 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,122 @@
extern UINT8 SMSPaletteRecalc;
extern UINT8 SMSReset;
extern UINT8 MastInput[2];
extern UINT8 SMSDips[3];
extern UINT8 SMSJoy1[12];
INT32 SMSGetZipName(char** pszName, UINT32 i);
INT32 SMSInit();
INT32 SMSExit();
INT32 SMSDraw();
INT32 SMSFrame();
INT32 SMSScan(INT32 nAction, INT32 *pnMin);
#ifndef _SMS_H_
#define _SMS_H_
enum {
SLOT_BIOS = 0,
SLOT_CARD = 1,
SLOT_CART = 2,
SLOT_EXP = 3
};
enum {
MAPPER_NONE = 0,
MAPPER_SEGA = 1,
MAPPER_CODIES = 2
};
enum {
DISPLAY_NTSC = 0,
DISPLAY_PAL = 1
};
enum {
FPS_NTSC = 60,
FPS_PAL = 50
};
enum {
CLOCK_NTSC = 3579545,
CLOCK_PAL = 3579545
};
enum {
CONSOLE_SMS = 0x20,
CONSOLE_SMSJ = 0x21,
CONSOLE_SMS2 = 0x22,
CONSOLE_GG = 0x40,
CONSOLE_GGMS = 0x41,
CONSOLE_MD = 0x80,
CONSOLE_MDPBC = 0x81,
CONSOLE_GEN = 0x82,
CONSOLE_GENPBC = 0x83
};
#define HWTYPE_SMS CONSOLE_SMS
#define HWTYPE_GG CONSOLE_GG
#define HWTYPE_MD CONSOLE_MD
#define IS_SMS (sms.console & HWTYPE_SMS)
#define IS_GG (sms.console & HWTYPE_GG)
#define IS_MD (sms.console & HWTYPE_MD)
typedef unsigned char UINT8;
typedef signed char INT8;
typedef unsigned short UINT16;
typedef signed short INT16;
typedef unsigned int UINT32;
typedef signed int INT32;
typedef unsigned char uint8;
typedef signed char int8;
typedef unsigned short int uint16;
typedef signed short int int16;
typedef unsigned long int uint32;
typedef signed long int int32;
enum {
TERRITORY_DOMESTIC = 0,
TERRITORY_EXPORT = 1
};
/* SMS context */
typedef struct
{
UINT8 wram[0x2000];
UINT8 paused;
UINT8 save;
UINT8 territory;
UINT8 console;
UINT8 display;
UINT8 fm_detect;
UINT8 use_fm;
UINT8 memctrl;
UINT8 ioctrl;
struct {
UINT8 pdr; /* Parallel data register */
UINT8 ddr; /* Data direction register */
UINT8 txdata; /* Transmit data buffer */
UINT8 rxdata; /* Receive data buffer */
UINT8 sctrl; /* Serial mode control and status */
} sio;
struct {
int type;
} device[2];
} sms_t;
/* Global data */
extern sms_t sms;
extern UINT8 dummy_write[0x2000];
/* Function prototypes */
void sms_init(void);
void sms_reset(void);
void sms_shutdown(void);
void sms_mapper_w(INT32 address, UINT8 data);
/* port-map Function prototypes */
uint8 z80_read_unmapped(void);
void gg_port_w(uint16 port, uint8 data);
uint8 gg_port_r(uint16 port);
void ggms_port_w(uint16 port, uint8 data);
uint8 ggms_port_r(uint16 port);
void _fastcall sms_port_w(UINT16 port, UINT8 data);
UINT8 _fastcall sms_port_r(UINT16 port);
void smsj_port_w(uint16 port, uint8 data);
uint8 smsj_port_r(uint16 port);
void md_port_w(uint16 port, uint8 data);
uint8 md_port_r(uint16 port);
#endif /* _SMS_H_ */

View File

@ -0,0 +1,165 @@
/*
fmintf.c --
Interface to EMU2413 and YM2413 emulators.
Disabled Feb. 24, 2015, saving for possible future use
*/
#include "smsshared.h"
//static OPLL *opll;
//FM_Context fm_context;
void FM_Init(void)
{
/* switch(snd.fm_which)
{
case SND_EMU2413:
OPLL_init(snd.fm_clock, snd.sample_rate);
opll = OPLL_new();
OPLL_reset(opll);
OPLL_reset_patch(opll, 0);
break;
case SND_YM2413:
SMSYM2413Init(1, snd.fm_clock, snd.sample_rate);
SMSYM2413ResetChip(0);
break;
}*/
}
void FM_Shutdown(void)
{
/* switch(snd.fm_which)
{
case SND_EMU2413:
if(opll)
{
OPLL_delete(opll);
opll = NULL;
}
OPLL_close();
break;
case SND_YM2413:
SMSYM2413Shutdown();
break;
}*/
}
void FM_Reset(void)
{
/* switch(snd.fm_which)
{
case SND_EMU2413:
OPLL_reset(opll);
OPLL_reset_patch(opll, 0);
break;
case SND_YM2413:
SMSYM2413ResetChip(0);
break;
}*/
}
void FM_Update(int16 **buffer, int length)
{
/* switch(snd.fm_which)
{
case SND_EMU2413:
OPLL_update(opll, buffer, length);
break;
case SND_YM2413:
SMSYM2413UpdateOne(0, buffer, length);
break;
}*/
}
void FM_WriteReg(int reg, int data)
{
/* FM_Write(0, reg);
FM_Write(1, data);*/
}
void FM_Write(int offset, int data)
{
/* if(offset & 1)
fm_context.reg[ fm_context.latch ] = data;
else
fm_context.latch = data;
switch(snd.fm_which)
{
case SND_EMU2413:
OPLL_write(opll, offset & 1, data);
break;
case SND_YM2413:
SMSYM2413Write(0, offset & 1, data);
break;
}*/
}
void FM_GetContext(uint8 *data)
{
// memcpy(data, &fm_context, sizeof(FM_Context));
}
void FM_SetContext(uint8 *data)
{
/*
int i;
uint8 *reg = fm_context.reg;
memcpy(&fm_context, data, sizeof(FM_Context));
// If we are loading a save state, we want to update the YM2413 context
// but not actually write to the current YM2413 emulator.
if(!snd.enabled || !sms.use_fm)
return;
FM_Write(0, 0x0E);
FM_Write(1, reg[0x0E]);
for(i = 0x00; i <= 0x07; i++)
{
FM_Write(0, i);
FM_Write(1, reg[i]);
}
for(i = 0x10; i <= 0x18; i++)
{
FM_Write(0, i);
FM_Write(1, reg[i]);
}
for(i = 0x20; i <= 0x28; i++)
{
FM_Write(0, i);
FM_Write(1, reg[i]);
}
for(i = 0x30; i <= 0x38; i++)
{
FM_Write(0, i);
FM_Write(1, reg[i]);
}
FM_Write(0, fm_context.latch);
*/
}
int FM_GetContextSize(void)
{
return 0; //sizeof(FM_Context);
}
uint8 *FM_GetContextPtr(void)
{
//return (uint8 *)&fm_context;
return (uint8 *)NULL;
}

View File

@ -0,0 +1,27 @@
#ifndef _FMINTF_H_
#define _FMINTF_H_
enum {
SND_EMU2413, /* Mitsutaka Okazaki's YM2413 emulator */
SND_YM2413 /* Jarek Burczynski's YM2413 emulator */
};
typedef struct {
uint8 latch;
uint8 reg[0x40];
} FM_Context;
/* Function prototypes */
void FM_Init(void);
void FM_Shutdown(void);
void FM_Reset(void);
void FM_Update(int16 **buffer, int length);
void FM_Write(int offset, int data);
void FM_GetContext(uint8 *data);
void FM_SetContext(uint8 *data);
int FM_GetContextSize(void);
uint8 *FM_GetContextPtr(void);
void FM_WriteReg(int reg, int data);
#endif /* _FMINTF_H_ */

189
src/burn/drv/sms/smshvc.h Normal file
View File

@ -0,0 +1,189 @@
#ifndef _HVC_H_
#define _HVC_H_
uint8 hc_ntsc_256[] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9,
0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
};
uint8 vc_ntsc_192[] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA,
0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
};
uint8 vc_ntsc_224[] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
};
uint8 vc_ntsc_256[] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05
};
uint8 vc_pal_192[] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2,
0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
};
uint8 vc_pal_224[] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
0x00, 0x01, 0x02,
0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
};
uint8 vc_pal_256[] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
};
uint8 *hc_table[] =
{
hc_ntsc_256,
};
uint8 *vc_table[2][4] =
{
{
vc_ntsc_192,
vc_ntsc_224,
vc_ntsc_256,
vc_ntsc_192,
},
{
vc_pal_192,
vc_pal_224,
vc_pal_256,
vc_pal_192,
}
};
#endif /* _HVC_H_ */

257
src/burn/drv/sms/smspio.cpp Normal file
View File

@ -0,0 +1,257 @@
/*
pio.c --
I/O chip and peripheral emulation.
*/
#include "smsshared.h"
io_state io_lut[2][256];
io_state *io_current;
void pio_init(void)
{
int i, j;
/* Make pin state LUT */
for(j = 0; j < 2; j++)
{
for(i = 0; i < 0x100; i++)
{
/* Common control: pin direction */
io_lut[j][i].tr_dir[0] = (i & 0x01) ? PIN_DIR_IN : PIN_DIR_OUT;
io_lut[j][i].th_dir[0] = (i & 0x02) ? PIN_DIR_IN : PIN_DIR_OUT;
io_lut[j][i].tr_dir[1] = (i & 0x04) ? PIN_DIR_IN : PIN_DIR_OUT;
io_lut[j][i].th_dir[1] = (i & 0x08) ? PIN_DIR_IN : PIN_DIR_OUT;
if(j == 1)
{
/* Programmable output state (Export machines only) */
io_lut[j][i].tr_level[0] = (i & 0x01) ? PIN_LVL_HI : (i & 0x10) ? PIN_LVL_HI : PIN_LVL_LO;
io_lut[j][i].th_level[0] = (i & 0x02) ? PIN_LVL_HI : (i & 0x20) ? PIN_LVL_HI : PIN_LVL_LO;
io_lut[j][i].tr_level[1] = (i & 0x04) ? PIN_LVL_HI : (i & 0x40) ? PIN_LVL_HI : PIN_LVL_LO;
io_lut[j][i].th_level[1] = (i & 0x08) ? PIN_LVL_HI : (i & 0x80) ? PIN_LVL_HI : PIN_LVL_LO;
}
else
{
/* Fixed output state (Domestic machines only) */
io_lut[j][i].tr_level[0] = (i & 0x01) ? PIN_LVL_HI : PIN_LVL_LO;
io_lut[j][i].th_level[0] = (i & 0x02) ? PIN_LVL_HI : PIN_LVL_LO;
io_lut[j][i].tr_level[1] = (i & 0x04) ? PIN_LVL_HI : PIN_LVL_LO;
io_lut[j][i].th_level[1] = (i & 0x08) ? PIN_LVL_HI : PIN_LVL_LO;
}
}
}
// hack dos code doesn't call system_reset
pio_reset();
}
void pio_reset(void)
{
/* GG SIO power-on defaults */
sms.sio.pdr = 0x7F;
sms.sio.ddr = 0xFF;
sms.sio.txdata = 0x00;
sms.sio.rxdata = 0xFF;
sms.sio.sctrl = 0x00;
/* SMS I/O power-on defaults */
ioctrl_w(0xFF);
}
void pio_shutdown(void)
{
/* Nothing to do */
}
void system_assign_device(int port, int type)
{
sms.device[port].type = type;
}
void ioctrl_w(uint8 data)
{
sms.ioctrl = data;
io_current = &io_lut[sms.territory][data];
}
uint8 device_r(int offset)
{
uint8 temp = 0x7F;
switch(sms.device[offset].type)
{
case DEVICE_NONE:
break;
case DEVICE_PAD2B:
break;
case DEVICE_PADDLE:
break;
}
return temp;
}
uint8 input_r(int offset)
{
uint8 temp = 0xFF;
/*
If I/O chip is disabled, reads return last byte of instruction that
read the I/O port.
*/
if(sms.memctrl & 0x04)
return z80_read_unmapped();
offset &= 1;
if(offset == 0)
{
/* Input port #0 */
if(input.pad[0] & INPUT_UP) temp &= ~0x01; /* D0 */
if(input.pad[0] & INPUT_DOWN) temp &= ~0x02; /* D1 */
if(input.pad[0] & INPUT_LEFT) temp &= ~0x04; /* D2 */
if(input.pad[0] & INPUT_RIGHT) temp &= ~0x08; /* D3 */
if(input.pad[0] & INPUT_BUTTON2) temp &= ~0x10; /* TL */
if(input.pad[0] & INPUT_BUTTON1) temp &= ~0x20; /* TR */
if(sms.console == CONSOLE_GG)
{
uint8 state = sio_r(0x01);
temp = (temp & 0x3F) | (state & 0x03) << 6; /* Insert D1,D0 */
}
else
{
if(input.pad[1] & INPUT_UP) temp &= ~0x40; /* D0 */
if(input.pad[1] & INPUT_DOWN) temp &= ~0x80; /* D1 */
}
/* Adjust TR state if it is an output */
if(io_current->tr_dir[0] == PIN_DIR_OUT) {
temp &= ~0x20;
temp |= (io_current->tr_level[0] == PIN_LVL_HI) ? 0x20 : 0x00;
}
}
else
{
/* Input port #1 */
if(sms.console == CONSOLE_GG)
{
uint8 state = sio_r(0x01);
temp = (temp & 0xF0) | ((state & 0x3C) >> 2); /* Insert TR,TL,D3,D2 */
temp = (temp & 0x7F) | ((state & 0x40) << 1); /* Insert TH */
}
else
{
if(input.pad[1] & INPUT_LEFT) temp &= ~0x01; /* D2 */
if(input.pad[1] & INPUT_RIGHT) temp &= ~0x02; /* D3 */
if(input.pad[1] & INPUT_BUTTON2) temp &= ~0x04; /* TL */
if(input.pad[1] & INPUT_BUTTON1) temp &= ~0x08; /* TR */
/* Adjust TR state if it is an output */
if(io_current->tr_dir[1] == PIN_DIR_OUT) {
temp &= ~0x08;
temp |= (io_current->tr_level[1] == PIN_LVL_HI) ? 0x08 : 0x00;
}
/* Adjust TH state if it is an output */
if(io_current->th_dir[1] == PIN_DIR_OUT) {
temp &= ~0x80;
temp |= (io_current->th_level[1] == PIN_LVL_HI) ? 0x80 : 0x00;
}
if(input.system & INPUT_RESET) temp &= ~0x10;
}
/* /CONT fixed at '1' for SMS/SMS2/GG */
/* /CONT fixed at '0' for GEN/MD */
if(IS_MD) temp &= ~0x20;
/* Adjust TH state if it is an output */
if(io_current->th_dir[0] == PIN_DIR_OUT) {
temp &= ~0x40;
temp |= (io_current->th_level[0] == PIN_LVL_HI) ? 0x40 : 0x00;
}
}
return temp;
}
uint8 sio_r(int offset)
{
uint8 temp;
switch(offset & 0xFF)
{
case 0: /* Input port #2 */
temp = 0xE0;
if(input.system & INPUT_START) temp &= ~0x80;
if(sms.territory == TERRITORY_DOMESTIC) temp &= ~0x40;
if(sms.display == DISPLAY_NTSC) temp &= ~0x20;
return temp;
case 1: /* Parallel data register */
temp = 0x00;
temp |= (sms.sio.ddr & 0x01) ? 0x01 : (sms.sio.pdr & 0x01);
temp |= (sms.sio.ddr & 0x02) ? 0x02 : (sms.sio.pdr & 0x02);
temp |= (sms.sio.ddr & 0x04) ? 0x04 : (sms.sio.pdr & 0x04);
temp |= (sms.sio.ddr & 0x08) ? 0x08 : (sms.sio.pdr & 0x08);
temp |= (sms.sio.ddr & 0x10) ? 0x10 : (sms.sio.pdr & 0x10);
temp |= (sms.sio.ddr & 0x20) ? 0x20 : (sms.sio.pdr & 0x20);
temp |= (sms.sio.ddr & 0x40) ? 0x40 : (sms.sio.pdr & 0x40);
temp |= (sms.sio.pdr & 0x80);
return temp;
case 2: /* Data direction register and NMI enable */
return sms.sio.ddr;
case 3: /* Transmit data buffer */
return sms.sio.txdata;
case 4: /* Receive data buffer */
return sms.sio.rxdata;
case 5: /* Serial control */
return sms.sio.sctrl;
case 6: /* Stereo sound control */
return 0xFF;
}
/* Just to please compiler */
return -1;
}
void sio_w(int offset, int data)
{
switch(offset & 0xFF)
{
case 0: /* Input port #2 (read-only) */
return;
case 1: /* Parallel data register */
sms.sio.pdr = data;
return;
case 2: /* Data direction register and NMI enable */
sms.sio.ddr = data;
return;
case 3: /* Transmit data buffer */
sms.sio.txdata = data;
return;
case 4: /* Receive data buffer */
return;
case 5: /* Serial control */
sms.sio.sctrl = data & 0xF8;
return;
case 6: /* Stereo output control */
psg_stereo_w(data);
return;
}
}

57
src/burn/drv/sms/smspio.h Normal file
View File

@ -0,0 +1,57 @@
#ifndef _SMSPIO_H_
#define _SMSPIO_H_
#define SIO_TXFL (1 << 0) /* 1= Transmit buffer full */
#define SIO_RXRD (1 << 1) /* 1= Receive buffer full */
#define SIO_FRER (1 << 2) /* 1= Framing error occured */
#define MAX_DEVICE 2
#define DEVICE_D0 (1 << 0)
#define DEVICE_D1 (1 << 1)
#define DEVICE_D2 (1 << 2)
#define DEVICE_D3 (1 << 3)
#define DEVICE_TL (1 << 4)
#define DEVICE_TR (1 << 5)
#define DEVICE_TH (1 << 6)
#define DEVICE_ALL (DEVICE_D0 | DEVICE_D1 | DEVICE_D2 | DEVICE_D3 | DEVICE_TL | DEVICE_TR | DEVICE_TH)
#define PIN_LVL_LO 0 /* Pin outputs 0V */
#define PIN_LVL_HI 1 /* Pin outputs +5V */
#define PIN_DIR_OUT 0 /* Pin is is an active driving output */
#define PIN_DIR_IN 1 /* Pin is in active-low input mode */
enum {
PORT_A = 0, /* I/O port A */
PORT_B = 1 /* I/O port B */
};
enum {
DEVICE_NONE = 0, /* No peripheral */
DEVICE_PAD2B = 1, /* Standard 2-button digital joystick/gamepad */
DEVICE_PADDLE = 2 /* Paddle controller; rotary dial with fire button */
};
typedef struct {
uint8 tr_level[2]; /* TR pin output level */
uint8 th_level[2]; /* TH pin output level */
uint8 tr_dir[2]; /* TR pin direction */
uint8 th_dir[2]; /* TH pin direction */
} io_state;
/* Global variables */
extern io_state io_lut[2][256];
extern io_state *io_current;
/* Function prototypes */
void pio_init(void);
void pio_reset(void);
void pio_shutdown(void);
void system_assign_device(int port, int type);
void io_lut_init(void);
void ioctrl_w(uint8 data);
uint8 input_r(int offset);
void sio_w(int offset, int data);
uint8 sio_r(int offset);
#endif /* _PIO_H_ */

View File

@ -0,0 +1,606 @@
/*
render.c --
Display rendering.
*/
#include "tiles_generic.h"
#include "smsshared.h"
uint8 sms_cram_expand_table[4];
uint8 gg_cram_expand_table[16];
/* Background drawing function */
void (*render_bg)(int line) = NULL;
void (*render_obj)(int line) = NULL;
/* Pointer to output buffer */
uint8 *linebuf;
/* Internal buffer for drawing non 8-bit displays */
uint8 internal_buffer[0x100];
/* Precalculated pixel table */
uint16 pixel[PALETTE_SIZE];
/* Dirty pattern info */
uint8 bg_name_dirty[0x200]; /* 1= This pattern is dirty */
uint16 bg_name_list[0x200]; /* List of modified pattern indices */
uint16 bg_list_index; /* # of modified patterns in list */
uint8 bg_pattern_cache[0x20000];/* Cached and flipped patterns */
/* Pixel look-up table */
uint8 lut[0x10000];
/* Attribute expansion table */
static const uint32 atex[4] =
{
0x00000000,
0x10101010,
0x20202020,
0x30303030,
};
/* Bitplane to packed pixel LUT */
uint32 bp_lut[0x10000];
/* Macros to access memory 32-bits at a time (from MAME's drawgfx.c) */
#ifdef ALIGN_DWORD
static __inline__ uint32 read_dword(void *address)
{
if ((uint32)address & 3)
{
#ifdef LSB_FIRST /* little endian version */
return ( *((uint8 *)address) +
(*((uint8 *)address+1) << 8) +
(*((uint8 *)address+2) << 16) +
(*((uint8 *)address+3) << 24) );
#else /* big endian version */
return ( *((uint8 *)address+3) +
(*((uint8 *)address+2) << 8) +
(*((uint8 *)address+1) << 16) +
(*((uint8 *)address) << 24) );
#endif
}
else
return *(uint32 *)address;
}
static __inline__ void write_dword(void *address, uint32 data)
{
if ((uint32)address & 3)
{
#ifdef LSB_FIRST
*((uint8 *)address) = data;
*((uint8 *)address+1) = (data >> 8);
*((uint8 *)address+2) = (data >> 16);
*((uint8 *)address+3) = (data >> 24);
#else
*((uint8 *)address+3) = data;
*((uint8 *)address+2) = (data >> 8);
*((uint8 *)address+1) = (data >> 16);
*((uint8 *)address) = (data >> 24);
#endif
return;
}
else
*(uint32 *)address = data;
}
#else
#define read_dword(address) *(uint32 *)address
#define write_dword(address,data) *(uint32 *)address=data
#endif
/****************************************************************************/
void render_shutdown(void)
{
}
/* Initialize the rendering data */
void render_init(void)
{
int i, j;
int bx, sx, b, s, bp, bf, sf, c;
make_tms_tables();
/* Generate 64k of data for the look up table */
for(bx = 0; bx < 0x100; bx++)
{
for(sx = 0; sx < 0x100; sx++)
{
/* Background pixel */
b = (bx & 0x0F);
/* Background priority */
bp = (bx & 0x20) ? 1 : 0;
/* Full background pixel + priority + sprite marker */
bf = (bx & 0x7F);
/* Sprite pixel */
s = (sx & 0x0F);
/* Full sprite pixel, w/ palette and marker bits added */
sf = (sx & 0x0F) | 0x10 | 0x40;
/* Overwriting a sprite pixel ? */
if(bx & 0x40)
{
/* Return the input */
c = bf;
}
else
{
/* Work out priority and transparency for both pixels */
if(bp)
{
/* Underlying pixel is high priority */
if(b)
{
c = bf | 0x40;
}
else
{
if(s)
{
c = sf;
}
else
{
c = bf;
}
}
}
else
{
/* Underlying pixel is low priority */
if(s)
{
c = sf;
}
else
{
c = bf;
}
}
}
/* Store result */
lut[(bx << 8) | (sx)] = c;
}
}
/* Make bitplane to pixel lookup table */
for(i = 0; i < 0x100; i++)
for(j = 0; j < 0x100; j++)
{
int x;
uint32 out = 0;
for(x = 0; x < 8; x++)
{
out |= (j & (0x80 >> x)) ? (uint32)(8 << (x << 2)) : 0;
out |= (i & (0x80 >> x)) ? (uint32)(4 << (x << 2)) : 0;
}
#if LSB_FIRST
bp_lut[(j << 8) | (i)] = out;
#else
bp_lut[(i << 8) | (j)] = out;
#endif
}
for(i = 0; i < 4; i++)
{
uint8 c2 = i << 6 | i << 4 | i << 2 | i;
sms_cram_expand_table[i] = c2;
}
for(i = 0; i < 16; i++)
{
uint8 c2 = i << 4 | i;
gg_cram_expand_table[i] = c2;
}
render_reset();
}
/* Reset the rendering data */
void render_reset(void)
{
int i;
/* Clear display bitmap */
memset(bitmap.data, 0, bitmap.pitch * bitmap.height);
/* Clear palette */
for(i = 0; i < PALETTE_SIZE; i++)
{
palette_sync(i, 1);
}
/* Invalidate pattern cache */
memset(bg_name_dirty, 0, sizeof(bg_name_dirty));
memset(bg_name_list, 0, sizeof(bg_name_list));
bg_list_index = 0;
memset(bg_pattern_cache, 0, sizeof(bg_pattern_cache));
/* Pick render routine */
render_bg = render_bg_sms;
render_obj = render_obj_sms;
}
/* Draw a line of the display */
void render_line(int line)
{
/* Ensure we're within the viewport range */
if(line >= vdp.height)
return;
/* Point to current line in output buffer */
linebuf = (bitmap.depth == 8) ? &bitmap.data[(line * bitmap.pitch)] : &internal_buffer[0];
/* Update pattern cache */
update_bg_pattern_cache();
/* Blank line (full width) */
if(!(vdp.reg[1] & 0x40))
{
memset(linebuf, BACKDROP_COLOR, bitmap.width);
}
else
{
/* Draw background */
if(render_bg != NULL)
render_bg(line);
/* Draw sprites */
if(render_obj != NULL)
render_obj(line);
/* Blank leftmost column of display */
if(vdp.reg[0] & 0x20)
{
memset(linebuf, BACKDROP_COLOR, 8);
// center the screen -dink
memmove(linebuf+4, linebuf+8, bitmap.width);
memset(linebuf+bitmap.width-4, BACKDROP_COLOR, 4);
}
}
if(bitmap.depth != 8) remap_8_to_16(line);
}
/* Draw the Master System background */
void render_bg_sms(int line)
{
int locked = 0;
int yscroll_mask = (vdp.extended) ? 256 : 224;
int v_line = (line + vdp.reg[9]) % yscroll_mask;
int v_row = (v_line & 7) << 3;
int hscroll = ((vdp.reg[0] & 0x40) && (line < 0x10)) ? 0 : (0x100 - vdp.reg[8]);
int column = 0;
uint16 attr;
uint16 *nt = (uint16 *)&vdp.vram[vdp.ntab + ((v_line >> 3) << 6)];
int nt_scroll = (hscroll >> 3);
int shift = (hscroll & 7);
uint32 atex_mask;
uint32 *cache_ptr;
uint32 *linebuf_ptr = (uint32 *)&linebuf[0 - shift];
/* Draw first column (clipped) */
if(shift)
{
int x;
for(x = shift; x < 8; x++)
linebuf[(0 - shift) + (x)] = 0;
column++;
}
/* Draw a line of the background */
for(; column < 32; column++)
{
/* Stop vertical scrolling for leftmost eight columns */
if((vdp.reg[0] & 0x80) && (!locked) && (column >= 24))
{
locked = 1;
v_row = (line & 7) << 3;
nt = (uint16 *)&vdp.vram[((vdp.reg[2] << 10) & 0x3800) + ((line >> 3) << 6)];
}
/* Get name table attribute word */
attr = nt[(column + nt_scroll) & 0x1F];
#ifndef LSB_FIRST
attr = (((attr & 0xFF) << 8) | ((attr & 0xFF00) >> 8));
#endif
/* Expand priority and palette bits */
atex_mask = atex[(attr >> 11) & 3];
/* Point to a line of pattern data in cache */
cache_ptr = (uint32 *)&bg_pattern_cache[((attr & 0x7FF) << 6) | (v_row)];
/* Copy the left half, adding the attribute bits in */
write_dword( &linebuf_ptr[(column << 1)] , read_dword( &cache_ptr[0] ) | (atex_mask));
/* Copy the right half, adding the attribute bits in */
write_dword( &linebuf_ptr[(column << 1) | (1)], read_dword( &cache_ptr[1] ) | (atex_mask));
}
/* Draw last column (clipped) */
if(shift)
{
int x, c, a;
uint8 *p = &linebuf[(0 - shift)+(column << 3)];
attr = nt[(column + nt_scroll) & 0x1F];
#ifndef LSB_FIRST
attr = (((attr & 0xFF) << 8) | ((attr & 0xFF00) >> 8));
#endif
a = (attr >> 7) & 0x30;
for(x = 0; x < shift; x++)
{
c = bg_pattern_cache[((attr & 0x7FF) << 6) | (v_row) | (x)];
p[x] = ((c) | (a));
}
}
}
/* Draw sprites */
void render_obj_sms(int line)
{
int i;
uint8 collision_buffer = 0;
/* Sprite count for current line (8 max.) */
int count = 0;
/* Sprite dimensions */
int width = 8;
int height = (vdp.reg[1] & 0x02) ? 16 : 8;
/* Pointer to sprite attribute table */
uint8 *st = (uint8 *)&vdp.vram[vdp.satb];
/* Adjust dimensions for double size sprites */
if(vdp.reg[1] & 0x01)
{
width *= 2;
height *= 2;
}
/* Draw sprites in front-to-back order */
for(i = 0; i < 64; i++)
{
/* Sprite Y position */
int yp = st[i];
/* Found end of sprite list marker for non-extended modes? */
if(vdp.extended == 0 && yp == 208)
goto end;
/* Actual Y position is +1 */
yp++;
/* Wrap Y coordinate for sprites > 240 */
if(yp > 240) yp -= 256;
/* Check if sprite falls on current line */
if((line >= yp) && (line < (yp + height)))
{
uint8 *linebuf_ptr;
/* Width of sprite */
int start = 0;
int end = width;
/* Sprite X position */
int xp = st[0x80 + (i << 1)];
/* Pattern name */
int n = st[0x81 + (i << 1)];
/* Bump sprite count */
count++;
/* Too many sprites on this line ? */
if(count == 9)
{
vdp.status |= 0x40;
goto end;
}
/* X position shift */
if(vdp.reg[0] & 0x08) xp -= 8;
/* Add MSB of pattern name */
if(vdp.reg[6] & 0x04) n |= 0x0100;
/* Mask LSB for 8x16 sprites */
if(vdp.reg[1] & 0x02) n &= 0x01FE;
/* Point to offset in line buffer */
linebuf_ptr = (uint8 *)&linebuf[xp];
/* Clip sprites on left edge */
if(xp < 0)
{
start = (0 - xp);
}
/* Clip sprites on right edge */
if((xp + width) > 256)
{
end = (256 - xp);
}
/* Draw double size sprite */
if(vdp.reg[1] & 0x01)
{
int x;
uint8 *cache_ptr = (uint8 *)&bg_pattern_cache[(n << 6) | (((line - yp) >> 1) << 3)];
/* Draw sprite line */
for(x = start; x < end; x++)
{
/* Source pixel from cache */
uint8 sp = cache_ptr[(x >> 1)];
/* Only draw opaque sprite pixels */
if(sp)
{
/* Background pixel from line buffer */
uint8 bg = linebuf_ptr[x];
/* Look up result */
linebuf_ptr[x] = lut[(bg << 8) | (sp)];
/* Update collision buffer */
collision_buffer |= bg;
}
}
}
else /* Regular size sprite (8x8 / 8x16) */
{
int x;
uint8 *cache_ptr = (uint8 *)&bg_pattern_cache[(n << 6) | ((line - yp) << 3)];
/* Draw sprite line */
for(x = start; x < end; x++)
{
/* Source pixel from cache */
uint8 sp = cache_ptr[x];
/* Only draw opaque sprite pixels */
if(sp)
{
/* Background pixel from line buffer */
uint8 bg = linebuf_ptr[x];
/* Look up result */
linebuf_ptr[x] = lut[(bg << 8) | (sp)];
/* Update collision buffer */
collision_buffer |= bg;
}
}
}
}
}
end:
/* Set sprite collision flag */
if(collision_buffer & 0x40)
vdp.status |= 0x20;
}
void update_bg_pattern_cache(void)
{
int i;
uint8 x, y;
uint16 name;
if(!bg_list_index) return;
for(i = 0; i < bg_list_index; i++)
{
name = bg_name_list[i];
bg_name_list[i] = 0;
for(y = 0; y < 8; y++)
{
if(bg_name_dirty[name] & (1 << y))
{
uint8 *dst = &bg_pattern_cache[name << 6];
uint16 bp01 = *(uint16 *)&vdp.vram[(name << 5) | (y << 2) | (0)];
uint16 bp23 = *(uint16 *)&vdp.vram[(name << 5) | (y << 2) | (2)];
uint32 temp = (bp_lut[bp01] >> 2) | (bp_lut[bp23]);
for(x = 0; x < 8; x++)
{
uint8 c = (temp >> (x << 2)) & 0x0F;
dst[0x00000 | (y << 3) | (x)] = (c);
dst[0x08000 | (y << 3) | (x ^ 7)] = (c);
dst[0x10000 | ((y ^ 7) << 3) | (x)] = (c);
dst[0x18000 | ((y ^ 7) << 3) | (x ^ 7)] = (c);
}
}
}
bg_name_dirty[name] = 0;
}
bg_list_index = 0;
}
/* Update a palette entry */
void palette_sync(int index, int force)
{
int r, g, b;
// unless we are forcing an update,
// if not in mode 4, exit
if(IS_SMS && !force && ((vdp.reg[0] & 4) == 0) )
return;
if(IS_GG)
{
/* ----BBBBGGGGRRRR */
r = (vdp.cram[(index << 1) | (0)] >> 0) & 0x0F;
g = (vdp.cram[(index << 1) | (0)] >> 4) & 0x0F;
b = (vdp.cram[(index << 1) | (1)] >> 0) & 0x0F;
r = gg_cram_expand_table[r];
g = gg_cram_expand_table[g];
b = gg_cram_expand_table[b];
}
else
{
/* --BBGGRR */
r = (vdp.cram[index] >> 0) & 3;
g = (vdp.cram[index] >> 2) & 3;
b = (vdp.cram[index] >> 4) & 3;
r = sms_cram_expand_table[r];
g = sms_cram_expand_table[g];
b = sms_cram_expand_table[b];
}
bitmap.pal.color[index][0] = r;
bitmap.pal.color[index][1] = g;
bitmap.pal.color[index][2] = b;
pixel[index] = MAKE_PIXEL(r, g, b);
bitmap.pal.dirty[index] = bitmap.pal.update = 1;
}
void remap_8_to_16(int line)
{
int i;
uint16 *p = (uint16 *)&bitmap.data[(line * bitmap.pitch)];
for(i = bitmap.viewport.x; i < bitmap.viewport.w + bitmap.viewport.x; i++)
{
p[i] = internal_buffer[i] & PIXEL_MASK;
}
}

View File

@ -0,0 +1,39 @@
#ifndef _SMSRENDER_H_
#define _SMSRENDER_H_
/* Pack RGB data into a 16-bit RGB 5:6:5 format */
#define MAKE_PIXEL(r,g,b) (((r << 8) & 0xF800) | ((g << 3) & 0x07E0) | ((b >> 3) & 0x001F))
/* Used for blanking a line in whole or in part */
#define BACKDROP_COLOR (0x10 | (vdp.reg[7] & 0x0F))
extern uint8 sms_cram_expand_table[4];
extern uint8 gg_cram_expand_table[16];
extern void (*render_bg)(int line);
extern void (*render_obj)(int line);
extern uint8 *linebuf;
extern uint8 internal_buffer[0x100];
extern uint16 pixel[];
extern uint8 bg_name_dirty[0x200];
extern uint16 bg_name_list[0x200];
extern uint16 bg_list_index;
extern uint8 bg_pattern_cache[0x20000];
extern uint8 tms_lookup[16][256][2];
extern uint8 mc_lookup[16][256][8];
extern uint8 txt_lookup[256][2];
extern uint8 bp_expand[256][8];
extern uint8 lut[0x10000];
extern uint32 bp_lut[0x10000];
void render_shutdown(void);
void render_init(void);
void render_reset(void);
void render_line(int line);
void render_bg_sms(int line);
void render_obj_sms(int line);
void update_bg_pattern_cache(void);
void palette_sync(int index, int force);
void remap_8_to_16(int line);
#endif /* _RENDER_H_ */

View File

@ -0,0 +1,24 @@
#ifndef _SMSSHARED_H_
#define _SMSSHARED_H_
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <signal.h>
#include <malloc.h>
#include <math.h>
#include <limits.h>
#include <zlib.h>
#include "sms.h"
#include "smspio.h"
#include "smsvdp.h"
#include "smsrender.h"
#include "smstms.h"
#include "smssn76489.h"
#include "smsfmintf.h"
#include "smssound.h"
#include "smssystem.h"
#endif /* _SHARED_H_ */

View File

@ -0,0 +1,249 @@
/*
SN76489 emulation
by Maxim in 2001 and 2002
converted from my original Delphi implementation
I'm a C newbie so I'm sure there are loads of stupid things
in here which I'll come back to some day and redo
Includes:
- Super-high quality tone channel "oversampling" by calculating fractional positions on transitions
- Noise output pattern reverse engineered from actual SMS output
- Volume levels taken from actual SMS output
07/08/04 Charles MacDonald
Modified for use with SMS Plus:
- Added support for multiple PSG chips.
- Added reset/config/update routines.
- Added context management routines.
- Removed SN76489_GetValues().
- Removed some unused variables.
*/
#include "smsshared.h"
#define NoiseInitialState 0x8000 /* Initial state of shift register */
#define PSG_CUTOFF 0x6 /* Value below which PSG does not output */
/* These values are taken from a real SMS2's output */
static const int PSGVolumeValues[2][16] = {
{892,892,892,760,623,497,404,323,257,198,159,123,96,75,60,0}, /* I can't remember why 892... :P some scaling I did at some point */
{892,774,669,575,492,417,351,292,239,192,150,113,80,50,24,0}
};
static SN76489_Context SN76489[MAX_SN76489];
void SN76489_Init(int which, int PSGClockValue, int SamplingRate)
{
SN76489_Context *p = &SN76489[which];
p->dClock=(float)PSGClockValue/16/SamplingRate;
SN76489_Config(which, MUTE_ALLON, BOOST_ON, VOL_FULL, FB_SEGAVDP);
SN76489_Reset(which);
}
void SN76489_Reset(int which)
{
SN76489_Context *p = &SN76489[which];
int i;
p->PSGStereo = 0xFF;
for(i = 0; i <= 3; i++)
{
/* Initialise PSG state */
p->Registers[2*i] = 1; /* tone freq=1 */
p->Registers[2*i+1] = 0xf; /* vol=off */
p->NoiseFreq = 0x10;
/* Set counters to 0 */
p->ToneFreqVals[i] = 0;
/* Set flip-flops to 1 */
p->ToneFreqPos[i] = 1;
/* Set intermediate positions to do-not-use value */
p->IntermediatePos[i] = LONG_MIN;
}
p->LatchedRegister=0;
/* Initialise noise generator */
p->NoiseShiftRegister=NoiseInitialState;
/* Zero clock */
p->Clock=0;
}
void SN76489_Shutdown(void)
{
}
void SN76489_Config(int which, int mute, int boost, int volume, int feedback)
{
SN76489_Context *p = &SN76489[which];
p->Mute = mute;
p->BoostNoise = boost;
p->VolumeArray = volume;
p->WhiteNoiseFeedback = feedback;
}
void SN76489_SetContext(int which, uint8 *data)
{
memcpy(&SN76489[which], data, sizeof(SN76489_Context));
}
void SN76489_GetContext(int which, uint8 *data)
{
memcpy(data, &SN76489[which], sizeof(SN76489_Context));
}
uint8 *SN76489_GetContextPtr(int which)
{
return (uint8 *)&SN76489[which];
}
int SN76489_GetContextSize(void)
{
return sizeof(SN76489_Context);
}
void SN76489_Write(int which, int data)
{
SN76489_Context *p = &SN76489[which];
if (data&0x80) {
/* Latch/data byte %1 cc t dddd */
p->LatchedRegister=((data>>4)&0x07);
p->Registers[p->LatchedRegister]=
(p->Registers[p->LatchedRegister] & 0x3f0) /* zero low 4 bits */
| (data&0xf); /* and replace with data */
} else {
/* Data byte %0 - dddddd */
if (!(p->LatchedRegister%2)&&(p->LatchedRegister<5))
/* Tone register */
p->Registers[p->LatchedRegister]=
(p->Registers[p->LatchedRegister] & 0x00f) /* zero high 6 bits */
| ((data&0x3f)<<4); /* and replace with data */
else
/* Other register */
p->Registers[p->LatchedRegister]=data&0x0f; /* Replace with data */
}
switch (p->LatchedRegister) {
case 0:
case 2:
case 4: /* Tone channels */
if (p->Registers[p->LatchedRegister]==0) p->Registers[p->LatchedRegister]=1; /* Zero frequency changed to 1 to avoid div/0 */
break;
case 6: /* Noise */
p->NoiseShiftRegister=NoiseInitialState; /* reset shift register */
p->NoiseFreq=0x10<<(p->Registers[6]&0x3); /* set noise signal generator frequency */
break;
}
}
void SN76489_GGStereoWrite(int which, int data)
{
SN76489_Context *p = &SN76489[which];
p->PSGStereo=data;
}
void SN76489_Update(int which, INT16 **buffer, int length)
{
SN76489_Context *p = &SN76489[which];
int i, j;
for(j = 0; j < length; j++)
{
for (i=0;i<=2;++i)
if (p->IntermediatePos[i]!=LONG_MIN)
p->Channels[i]=(p->Mute >> i & 0x1)*PSGVolumeValues[p->VolumeArray][p->Registers[2*i+1]]*p->IntermediatePos[i]/65536;
else
p->Channels[i]=(p->Mute >> i & 0x1)*PSGVolumeValues[p->VolumeArray][p->Registers[2*i+1]]*p->ToneFreqPos[i];
p->Channels[3]=(short)((p->Mute >> 3 & 0x1)*PSGVolumeValues[p->VolumeArray][p->Registers[7]]*(p->NoiseShiftRegister & 0x1));
if (p->BoostNoise) p->Channels[3]<<=1; /* Double noise volume to make some people happy */
buffer[0][j] =0;
buffer[1][j] =0;
for (i=0;i<=3;++i) {
buffer[0][j] +=(p->PSGStereo >> (i+4) & 0x1)*p->Channels[i]; /* left */
buffer[1][j] +=(p->PSGStereo >> i & 0x1)*p->Channels[i]; /* right */
}
p->Clock+=p->dClock;
p->NumClocksForSample=(int)p->Clock; /* truncates */
p->Clock-=p->NumClocksForSample; /* remove integer part */
/* Looks nicer in Delphi... */
/* Clock:=Clock+p->dClock; */
/* NumClocksForSample:=Trunc(Clock); */
/* Clock:=Frac(Clock); */
/* Decrement tone channel counters */
for (i=0;i<=2;++i)
p->ToneFreqVals[i]-=p->NumClocksForSample;
/* Noise channel: match to tone2 or decrement its counter */
if (p->NoiseFreq==0x80) p->ToneFreqVals[3]=p->ToneFreqVals[2];
else p->ToneFreqVals[3]-=p->NumClocksForSample;
/* Tone channels: */
for (i=0;i<=2;++i) {
if (p->ToneFreqVals[i]<=0) { /* If it gets below 0... */
if (p->Registers[i*2]>PSG_CUTOFF) {
/* Calculate how much of the sample is + and how much is - */
/* Go to floating point and include the clock fraction for extreme accuracy :D */
/* Store as long int, maybe it's faster? I'm not very good at this */
p->IntermediatePos[i]=(long)((p->NumClocksForSample-p->Clock+2*p->ToneFreqVals[i])*p->ToneFreqPos[i]/(p->NumClocksForSample+p->Clock)*65536);
p->ToneFreqPos[i]=-p->ToneFreqPos[i]; /* Flip the flip-flop */
} else {
p->ToneFreqPos[i]=1; /* stuck value */
p->IntermediatePos[i]=LONG_MIN;
}
p->ToneFreqVals[i]+=p->Registers[i*2]*(p->NumClocksForSample/p->Registers[i*2]+1);
} else p->IntermediatePos[i]=LONG_MIN;
}
/* Noise channel */
if (p->ToneFreqVals[3]<=0) { /* If it gets below 0... */
p->ToneFreqPos[3]=-p->ToneFreqPos[3]; /* Flip the flip-flop */
if (p->NoiseFreq!=0x80) /* If not matching tone2, decrement counter */
p->ToneFreqVals[3]+=p->NoiseFreq*(p->NumClocksForSample/p->NoiseFreq+1);
if (p->ToneFreqPos[3]==1) { /* Only once per cycle... */
int Feedback;
if (p->Registers[6]&0x4) { /* White noise */
/* Calculate parity of fed-back bits for feedback */
switch (p->WhiteNoiseFeedback) {
/* Do some optimised calculations for common (known) feedback values */
case 0x0006: /* SC-3000 %00000110 */
case 0x0009: /* SMS, GG, MD %00001001 */
/* If two bits fed back, I can do Feedback=(nsr & fb) && (nsr & fb ^ fb) */
/* since that's (one or more bits set) && (not all bits set) */
/* which one? Feedback=((p->NoiseShiftRegister&p->WhiteNoiseFeedback) && (p->NoiseShiftRegister&p->WhiteNoiseFeedback^p->WhiteNoiseFeedback)); */
Feedback=((p->NoiseShiftRegister&p->WhiteNoiseFeedback) && ((p->NoiseShiftRegister&p->WhiteNoiseFeedback)^p->WhiteNoiseFeedback));
break;
case 0x8005: /* BBC Micro */
/* fall through :P can't be bothered to think too much */
default: /* Default handler for all other feedback values */
Feedback=p->NoiseShiftRegister&p->WhiteNoiseFeedback;
Feedback^=Feedback>>8;
Feedback^=Feedback>>4;
Feedback^=Feedback>>2;
Feedback^=Feedback>>1;
Feedback&=1;
break;
}
} else /* Periodic noise */
Feedback=p->NoiseShiftRegister&1;
p->NoiseShiftRegister=(p->NoiseShiftRegister>>1) | (Feedback<<15);
/* Original code: */
/* p->NoiseShiftRegister=(p->NoiseShiftRegister>>1) | ((p->Registers[6]&0x4?((p->NoiseShiftRegister&0x9) && (p->NoiseShiftRegister&0x9^0x9)):p->NoiseShiftRegister&1)<<15); */
}
}
}
}

View File

@ -0,0 +1,78 @@
#ifndef _SN76489_H_
#define _SN76489_H_
#define MAX_SN76489 4
/*
More testing is needed to find and confirm feedback patterns for
SN76489 variants and compatible chips.
*/
enum feedback_patterns {
FB_BBCMICRO = 0x8005, /* Texas Instruments TMS SN76489N (original) from BBC Micro computer */
FB_SC3000 = 0x0006, /* Texas Instruments TMS SN76489AN (rev. A) from SC-3000H computer */
FB_SEGAVDP = 0x0009 /* SN76489 clone in Sega's VDP chips (315-5124, 315-5246, 315-5313, Game Gear) */
};
enum volume_modes {
VOL_TRUNC = 0, /* Volume levels 13-15 are identical */
VOL_FULL = 1 /* Volume levels 13-15 are unique */
};
enum boost_modes {
BOOST_OFF = 0, /* Regular noise channel volume */
BOOST_ON = 1 /* Doubled noise channel volume */
};
enum mute_values {
MUTE_ALLOFF = 0, /* All channels muted */
MUTE_TONE1 = 1, /* Tone 1 mute control */
MUTE_TONE2 = 2, /* Tone 2 mute control */
MUTE_TONE3 = 4, /* Tone 3 mute control */
MUTE_NOISE = 8, /* Noise mute control */
MUTE_ALLON = 15 /* All channels enabled */
};
typedef struct
{
/* expose this for inspection/modification for channel muting */
int Mute;
int BoostNoise;
int VolumeArray;
/* Variables */
float Clock;
float dClock;
int PSGStereo;
int NumClocksForSample;
int WhiteNoiseFeedback;
/* PSG registers: */
UINT16 Registers[8]; /* Tone, vol x4 */
int LatchedRegister;
UINT16 NoiseShiftRegister;
INT16 NoiseFreq; /* Noise channel signal generator frequency */
/* Output calculation variables */
INT16 ToneFreqVals[4]; /* Frequency register values (counters) */
INT8 ToneFreqPos[4]; /* Frequency channel flip-flops */
INT16 Channels[4]; /* Value of each channel, before stereo is applied */
INT32 IntermediatePos[4]; /* intermediate values used at boundaries between + and - */
} SN76489_Context;
/* Function prototypes */
void SN76489_Init(int which, int PSGClockValue, int SamplingRate);
void SN76489_Reset(int which);
void SN76489_Shutdown(void);
void SN76489_Config(int which, int mute, int boost, int volume, int feedback);
void SN76489_SetContext(int which, uint8 *data);
void SN76489_GetContext(int which, uint8 *data);
uint8 *SN76489_GetContextPtr(int which);
int SN76489_GetContextSize(void);
void SN76489_Write(int which, int data);
void SN76489_GGStereoWrite(int which, int data);
void SN76489_Update(int which, INT16 **buffer, int length);
#endif /* _SN76489_H_ */

View File

@ -0,0 +1,268 @@
/*
sound.c --
Sound emulation.
*/
#include "tiles_generic.h"
#include "smsshared.h"
snd_t snd;
static int16 **fm_buffer;
static int16 **psg_buffer;
int *smptab;
int smptab_len;
int sound_init(void)
{
uint8 *buf = NULL;
int restore_fm = 0;
int i;
/* Save register settings */
if(snd.enabled && sms.use_fm)
{
restore_fm = 1;
buf = (uint8 *)malloc(FM_GetContextSize());
FM_GetContext(buf);
}
/* If we are reinitializing, shut down sound emulation */
if(snd.enabled)
{
sound_shutdown();
}
/* Disable sound until initialization is complete */
snd.enabled = 0;
/* Check if sample rate is invalid */
if(snd.sample_rate < 8000 || snd.sample_rate > 48000)
return 0;
/* Assign stream mixing callback if none provided */
if(!snd.mixer_callback)
snd.mixer_callback = sound_mixer_callback;
/* Calculate number of samples generated per frame */
snd.sample_count = (snd.sample_rate / snd.fps);
/* Calculate size of sample buffer */
snd.buffer_size = snd.sample_count * 2;
/* Free sample buffer position table if previously allocated */
if(smptab)
{
free(smptab);
smptab = NULL;
}
/* Prepare incremental info */
snd.done_so_far = 0;
smptab_len = (sms.display == DISPLAY_NTSC) ? 262 : 313;
smptab = (int *)malloc(smptab_len * sizeof(int));
if(!smptab) return 0;
for (i = 0; i < smptab_len; i++)
{
double calc = (snd.sample_count * i);
calc = calc / (double)smptab_len;
smptab[i] = (int)calc;
}
/* Allocate emulated sound streams */
for(i = 0; i < STREAM_MAX; i++)
{
snd.stream[i] = (int16 *)malloc(snd.buffer_size);
if(!snd.stream[i]) return 0;
memset(snd.stream[i], 0, snd.buffer_size);
}
/* Allocate sound output streams */
snd.output[0] = (int16 *)malloc(snd.buffer_size);
snd.output[1] = (int16 *)malloc(snd.buffer_size);
if(!snd.output[0] || !snd.output[1]) return 0;
/* Set up buffer pointers */
fm_buffer = (int16 **)&snd.stream[STREAM_FM_MO];
psg_buffer = (int16 **)&snd.stream[STREAM_PSG_L];
/* Set up SN76489 emulation */
SN76489_Init(0, snd.psg_clock, snd.sample_rate);
/* Set up YM2413 emulation */
FM_Init();
/* Inform other functions that we can use sound */
snd.enabled = 1;
/* Restore YM2413 register settings */
if(restore_fm)
{
FM_SetContext(buf);
free(buf);
}
return 1;
}
void sound_shutdown(void)
{
int i;
if(!snd.enabled)
return;
/* Free emulated sound streams */
for(i = 0; i < STREAM_MAX; i++)
{
if(snd.stream[i])
{
free(snd.stream[i]);
snd.stream[i] = NULL;
}
}
/* Free sound output buffers */
for(i = 0; i < 2; i++)
{
if(snd.output[i])
{
free(snd.output[i]);
snd.output[i] = NULL;
}
}
/* Shut down SN76489 emulation */
SN76489_Shutdown();
/* Shut down YM2413 emulation */
FM_Shutdown();
}
void sound_reset(void)
{
if(!snd.enabled)
return;
/* Reset SN76489 emulator */
SN76489_Reset(0);
/* Reset YM2413 emulator */
FM_Reset();
}
void sound_update(int line)
{
int16 *fm[2], *psg[2];
if(!snd.enabled)
return;
/* Finish buffers at end of frame */
if(line == smptab_len - 1)
{
psg[0] = psg_buffer[0] + snd.done_so_far;
psg[1] = psg_buffer[1] + snd.done_so_far;
fm[0] = fm_buffer[0] + snd.done_so_far;
fm[1] = fm_buffer[1] + snd.done_so_far;
/* Generate SN76489 sample data */
SN76489_Update(0, psg, snd.sample_count - snd.done_so_far);
/* Generate YM2413 sample data */
FM_Update(fm, snd.sample_count - snd.done_so_far);
/* Mix streams into output buffer */
snd.mixer_callback(snd.stream, snd.output, snd.sample_count);
/* Reset */
snd.done_so_far = 0;
}
else
{
int tinybit;
tinybit = smptab[line] - snd.done_so_far;
/* Do a tiny bit */
psg[0] = psg_buffer[0] + snd.done_so_far;
psg[1] = psg_buffer[1] + snd.done_so_far;
fm[0] = fm_buffer[0] + snd.done_so_far;
fm[1] = fm_buffer[1] + snd.done_so_far;
/* Generate SN76489 sample data */
SN76489_Update(0, psg, tinybit);
/* Generate YM2413 sample data */
FM_Update(fm, tinybit);
/* Sum total */
snd.done_so_far += tinybit;
}
}
/* Generic FM+PSG stereo mixer callback */
void sound_mixer_callback(int16 **stream, int16 **output, int length)
{
int i;
for(i = 0; i < length; i++)
{
//int16 temp = (fm_buffer[0][i] + fm_buffer[1][i]) / 2; // FM is disabled.
//output[0][i] = temp + psg_buffer[0][i];
//output[1][i] = temp + psg_buffer[1][i];
output[0][i] = psg_buffer[0][i];
output[1][i] = psg_buffer[1][i];
}
}
/*--------------------------------------------------------------------------*/
/* Sound chip access handlers */
/*--------------------------------------------------------------------------*/
void psg_stereo_w(int data)
{
if(!snd.enabled)
return;
SN76489_GGStereoWrite(0, data);
}
void stream_update(int which, int position)
{
}
void psg_write(int data)
{
if(!snd.enabled)
return;
SN76489_Write(0, data);
}
/*--------------------------------------------------------------------------*/
/* Mark III FM Unit / Master System (J) built-in FM handlers */
/*--------------------------------------------------------------------------*/
int fmunit_detect_r(void)
{
return sms.fm_detect;
}
void fmunit_detect_w(int data)
{
sms.fm_detect = data;
}
void fmunit_write(int offset, int data)
{
if(!snd.enabled || !sms.use_fm)
return;
FM_Write(offset, data);
}

View File

@ -0,0 +1,46 @@
#ifndef _SMSSOUND_H_
#define _SMSSOUND_H_
enum {
STREAM_PSG_L, /* PSG left channel */
STREAM_PSG_R, /* PSG right channel */
STREAM_FM_MO, /* YM2413 melody channel */
STREAM_FM_RO, /* YM2413 rhythm channel */
STREAM_MAX /* Total # of sound streams */
};
/* Sound emulation structure */
typedef struct
{
void (*mixer_callback)(int16 **stream, int16 **output, int length);
int16 *output[2];
int16 *stream[STREAM_MAX];
int fm_which;
int enabled;
int fps;
int buffer_size;
int sample_count;
int sample_rate;
int done_so_far;
uint32 fm_clock;
uint32 psg_clock;
} snd_t;
/* Global data */
extern snd_t snd;
/* Function prototypes */
void psg_write(int data);
void psg_stereo_w(int data);
int fmunit_detect_r(void);
void fmunit_detect_w(int data);
void fmunit_write(int offset, int data);
int sound_init(void);
void sound_shutdown(void);
void sound_reset(void);
void sound_update(int line);
void sound_mixer_callback(int16 **stream, int16 **output, int length);
#endif /* _SOUND_H_ */

View File

@ -0,0 +1,187 @@
/*
Copyright (C) 1998-2004 Charles MacDonald
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "smsshared.h"
#include "burnint.h"
#include "z80_intf.h"
bitmap_t bitmap;
cart_t cart;
input_t input;
/* Run the virtual console emulation for one frame */
void system_frame(int skip_render)
{
static int iline_table[] = {0xC0, 0xE0, 0xF0};
int lpf = (sms.display == DISPLAY_NTSC) ? 262 : 313;
int iline;
/* Debounce pause key */
if(input.system & INPUT_PAUSE)
{
if(!sms.paused)
{
sms.paused = 1;
//z80_set_irq_line(IRQ_LINE_NMI, ASSERT_LINE);
//z80_set_irq_line(IRQ_LINE_NMI, CLEAR_LINE);
ZetNmi();
}
}
else
{
sms.paused = 0;
}
text_counter = 0;
/* End of frame, parse sprites for line 0 on line 261 (VCount=$FF) */
if(vdp.mode <= 7)
parse_line(0);
for(vdp.line = 0; vdp.line < lpf;)
{
ZetRun(227);
iline = iline_table[vdp.extended];
if(!skip_render)
{
render_line(vdp.line);
}
if(vdp.line <= iline)
{
vdp.left -= 1;
if(vdp.left == -1)
{
vdp.left = vdp.reg[0x0A];
vdp.hint_pending = 1;
ZetRun(16);
if(vdp.reg[0x00] & 0x10)
{
ZetSetIRQLine(0, CPU_IRQSTATUS_ACK);
}
}
}
else
{
vdp.left = vdp.reg[0x0A];
}
if(vdp.line == iline)
{
vdp.status |= 0x80;
vdp.vint_pending = 1;
ZetRun(16);
if(vdp.reg[0x01] & 0x20)
{
ZetSetIRQLine(0, CPU_IRQSTATUS_ACK);
}
}
sound_update(vdp.line);
++vdp.line;
if(vdp.mode <= 7)
parse_line(vdp.line);
}
}
void system_init(void)
{
//error_init();
sms_init();
pio_init();
vdp_init();
render_init();
sound_init();
sms.save = 0;
}
void system_shutdown(void)
{
#ifdef DEBUG
int i;
/*error("PC:%04X\tSP:%04X\n", z80_get_reg(Z80_PC), z80_get_reg(Z80_SP));
error("AF:%04X\tAF:%04X\n", z80_get_reg(Z80_AF), z80_get_reg(Z80_AF2));
error("BC:%04X\tBC:%04X\n", z80_get_reg(Z80_BC), z80_get_reg(Z80_BC2));
error("DE:%04X\tDE:%04X\n", z80_get_reg(Z80_DE), z80_get_reg(Z80_DE2));
error("HL:%04X\tHL:%04X\n", z80_get_reg(Z80_HL), z80_get_reg(Z80_HL2));
error("IX:%04X\tIY:%04X\n", z80_get_reg(Z80_IX), z80_get_reg(Z80_IY));
for(i = 0; i <= 0x0A; i++)
error("%02X ", vdp.reg[i]);
error("\n");
error("MODE:%02X\n", vdp.mode & 7);
error("PN:%04X\n", vdp.pn);
error("CT:%04X\n", vdp.ct);
error("PG:%04X\n", vdp.pg);
error("SA:%04X\n", vdp.sa);
error("SG:%04X\n", vdp.sg);
error("\n");*/
#endif
sms_shutdown();
pio_shutdown();
vdp_shutdown();
render_shutdown();
sound_shutdown();
//error_shutdown();
}
void system_reset(void)
{
sms_reset();
pio_reset();
vdp_reset();
render_reset();
sound_reset();
// system_manage_sram(cart.sram, SLOT_CART, SRAM_LOAD);
}
void system_poweron(void)
{
system_reset();
}
void system_poweroff(void)
{
// system_manage_sram(cart.sram, SLOT_CART, SRAM_SAVE);
}

View File

@ -0,0 +1,90 @@
#ifndef _SMSSYSTEM_H_
#define _SMSSYSTEM_H_
#define APP_NAME "SMS Plus"
#define APP_VERSION "1.3"
#define PALETTE_SIZE 0x20
/* Mask for removing unused pixel data */
#define PIXEL_MASK 0x1F
/* These can be used for 'input.pad[]' */
#define INPUT_UP 0x00000001
#define INPUT_DOWN 0x00000002
#define INPUT_LEFT 0x00000004
#define INPUT_RIGHT 0x00000008
#define INPUT_BUTTON2 0x00000010
#define INPUT_BUTTON1 0x00000020
/* These can be used for 'input.system' */
#define INPUT_START 0x00000001 /* Game Gear only */
#define INPUT_PAUSE 0x00000002 /* Master System only */
#define INPUT_RESET 0x00000004 /* Master System only */
enum {
SRAM_SAVE = 0,
SRAM_LOAD = 1
};
/* User input structure */
typedef struct
{
uint32 pad[2];
uint8 analog[2];
uint32 system;
} input_t;
/* Game image structure */
typedef struct
{
uint8 *rom;
uint8 pages;
uint32 crc;
uint32 sram_crc;
int mapper;
uint8 sram[0x8000];
uint8 fcr[4];
} cart_t;
/* Bitmap structure */
typedef struct
{
unsigned char *data;
int width;
int height;
int pitch;
int depth;
int granularity;
struct {
int x, y, w, h;
int ox, oy, ow, oh;
int changed;
} viewport;
struct
{
uint8 color[PALETTE_SIZE][3];
uint8 dirty[PALETTE_SIZE];
uint8 update;
}pal;
} bitmap_t;
/* Global variables */
extern bitmap_t bitmap; /* Display bitmap */
extern cart_t cart; /* Game cartridge data */
extern input_t input; /* Controller input */
/* Function prototypes */
void system_frame(int skip_render);
void system_init(void);
void system_shutdown(void);
void system_reset(void);
void system_manage_sram(uint8 *sram, int slot, int mode);
void system_poweron(void);
void system_poweroff(void);
#endif /* _SYSTEM_H_ */

517
src/burn/drv/sms/smstms.cpp Normal file
View File

@ -0,0 +1,517 @@
/*
tms.c --
TMS9918 and legacy video mode support.
*/
#include "smsshared.h"
int text_counter; /* Text offset counter */
uint8 tms_lookup[16][256][2]; /* Expand BD, PG data into 8-bit pixels (G1,G2) */
uint8 mc_lookup[16][256][8]; /* Expand BD, PG data into 8-bit pixels (MC) */
uint8 txt_lookup[256][2]; /* Expand BD, PG data into 8-bit pixels (TX) */
uint8 bp_expand[256][8]; /* Expand PG data into 8-bit pixels */
uint8 tms_obj_lut[16*256]; /* Look up priority between SG and display pixels */
static const uint8 diff_mask[] = {0x07, 0x07, 0x0F, 0x0F};
static const uint8 name_mask[] = {0xFF, 0xFF, 0xFC, 0xFC};
static const uint8 diff_shift[] = {0, 1, 0, 1};
static const uint8 size_tab[] = {8, 16, 16, 32};
/* Internally latched sprite data in the VDP */
typedef struct {
int xpos;
uint8 attr;
uint8 sg[2];
} tms_sprite;
tms_sprite sprites[4];
int sprites_found;
void parse_line(int line)
{
int yp, i;
int mode = vdp.reg[1] & 3;
int size = size_tab[mode];
int diff, name;
uint8 *sa, *sg;
tms_sprite *p;
/* Reset # of sprites found */
sprites_found = 0;
/* Parse sprites */
for(i = 0; i < 32; i++)
{
/* Point to current sprite in SA and our current sprite record */
p = &sprites[sprites_found];
sa = &vdp.vram[vdp.sa + (i << 2)];
/* Fetch Y coordinate */
yp = sa[0];
/* Check for end marker */
if(yp == 0xD0)
goto parse_end;
/* Wrap Y position */
if(yp > 0xE0)
yp -= 256;
/* Check if sprite falls on following line */
if(line >= yp && line < (yp + size))
{
/* Sprite overflow on this line */
if(sprites_found == 4)
{
/* Set 5S and abort parsing */
vdp.status |= 0x40;
goto parse_end;
}
/* Fetch X position */
p->xpos = sa[1];
/* Fetch name */
name = sa[2] & name_mask[mode];
/* Load attribute into attribute storage */
p->attr = sa[3];
/* Apply early clock bit */
if(p->attr & 0x80)
p->xpos -= 32;
/* Calculate offset in pattern */
diff = ((line - yp) >> diff_shift[mode]) & diff_mask[mode];
/* Insert additional name bit for 16-pixel tall sprites */
if(diff & 8)
name |= 1;
/* Fetch SG data */
sg = &vdp.vram[vdp.sg | (name << 3) | (diff & 7)];
p->sg[0] = sg[0x00];
p->sg[1] = sg[0x10];
/* Bump found sprite count */
++sprites_found;
}
}
parse_end:
/* Insert number of last sprite entry processed */
vdp.status = (vdp.status & 0xE0) | (i & 0x1F);
}
void render_obj_tms(int line)
{
int i, x = 0;
int size, start, end, mode;
uint8 *lb, *lutp, *ex[2];
tms_sprite *p;
mode = vdp.reg[1] & 3;
size = size_tab[mode];
/* Render sprites */
for(i = 0; i < sprites_found; i++)
{
p = &sprites[i];
lb = &linebuf[p->xpos];
lutp = &tms_obj_lut[(p->attr & 0x0F) << 8];
/* Point to expanded PG data */
ex[0] = bp_expand[p->sg[0]];
ex[1] = bp_expand[p->sg[1]];
/* Clip left edge */
if(p->xpos < 0)
start = 0 - p->xpos;
else
start = 0;
/* Clip right edge */
if(p->xpos > 256 - size)
end = 256 - p->xpos;
else
end = size;
/* Render sprite line */
switch(mode)
{
case 0: /* 8x8 */
for(x = start; x < end; x++) {
if(ex[0][x])
lb[x] = lutp[lb[x]];
}
break;
case 1: /* 8x8 zoomed */
for(x = start; x < end; x++) {
if(ex[0][x >> 1])
lb[x] = lutp[lb[x]];
}
break;
case 2: /* 16x16 */
for(x = start; x < end; x++) {
if(ex[(x >> 3) & 1][x & 7])
lb[x] = lutp[lb[x]];
}
break;
case 3: /* 16x16 zoomed */
for(x = start; x < end; x++) {
if(ex[(x >> 4) & 1][(x >> 1) & 7])
lb[x] = lutp[lb[x]];
}
break;
}
}
}
/****
1.) NOTE: xpos can be negative, but the 'start' value that is added
to xpos will ensure it is positive.
For an EC sprite that is offscreen, 'start' will be larger
than 'end' and the for-loop used for rendering will abort
on the first pass.
***/
#define RENDER_TX_LINE \
*lb++ = 0x10 | clut[ *bpex++ ]; \
*lb++ = 0x10 | clut[ *bpex++ ]; \
*lb++ = 0x10 | clut[ *bpex++ ]; \
*lb++ = 0x10 | clut[ *bpex++ ]; \
*lb++ = 0x10 | clut[ *bpex++ ]; \
*lb++ = 0x10 | clut[ *bpex++ ];
#define RENDER_TX_BORDER \
*lb++ = 0x10 | clut[0]; \
*lb++ = 0x10 | clut[0]; \
*lb++ = 0x10 | clut[0]; \
*lb++ = 0x10 | clut[0]; \
*lb++ = 0x10 | clut[0]; \
*lb++ = 0x10 | clut[0]; \
*lb++ = 0x10 | clut[0]; \
*lb++ = 0x10 | clut[0]; \
*lb++ = 0x10 | clut[0]; \
*lb++ = 0x10 | clut[0]; \
*lb++ = 0x10 | clut[0]; \
*lb++ = 0x10 | clut[0]; \
*lb++ = 0x10 | clut[0]; \
*lb++ = 0x10 | clut[0]; \
*lb++ = 0x10 | clut[0]; \
*lb++ = 0x10 | clut[0];
#define RENDER_GR_LINE \
*lb++ = 0x10 | clut[ *bpex++ ]; \
*lb++ = 0x10 | clut[ *bpex++ ]; \
*lb++ = 0x10 | clut[ *bpex++ ]; \
*lb++ = 0x10 | clut[ *bpex++ ]; \
*lb++ = 0x10 | clut[ *bpex++ ]; \
*lb++ = 0x10 | clut[ *bpex++ ]; \
*lb++ = 0x10 | clut[ *bpex++ ]; \
*lb++ = 0x10 | clut[ *bpex++ ];
#define RENDER_MC_LINE \
*lb++ = 0x10 | *mcex++; \
*lb++ = 0x10 | *mcex++; \
*lb++ = 0x10 | *mcex++; \
*lb++ = 0x10 | *mcex++; \
*lb++ = 0x10 | *mcex++; \
*lb++ = 0x10 | *mcex++; \
*lb++ = 0x10 | *mcex++; \
*lb++ = 0x10 | *mcex++;
void make_tms_tables(void)
{
int i, j, x;
int bd, pg, ct;
int sx, bx;
for(sx = 0; sx < 16; sx++)
{
for(bx = 0; bx < 256; bx++)
{
// uint8 bd = (bx & 0x0F);
uint8 bs = (bx & 0x40);
// uint8 bt = (bd == 0) ? 1 : 0;
uint8 sd = (sx & 0x0F);
// uint8 st = (sd == 0) ? 1 : 0;
// opaque sprite pixel, choose 2nd pal and set sprite marker
if(sd && !bs)
{
tms_obj_lut[(sx<<8)|(bx)] = sd | 0x10 | 0x40;
}
else
if(sd && bs)
{
// writing over a sprite
tms_obj_lut[(sx<<8)|(bx)] = bx;
}
else
{
tms_obj_lut[(sx<<8)|(bx)] = bx;
}
}
}
/* Text lookup table */
for(bd = 0; bd < 256; bd++)
{
uint8 bg = (bd >> 0) & 0x0F;
uint8 fg = (bd >> 4) & 0x0F;
/* If foreground is transparent, use background color */
if(fg == 0) fg = bg;
txt_lookup[bd][0] = bg;
txt_lookup[bd][1] = fg;
}
/* Multicolor lookup table */
for(bd = 0; bd < 16; bd++)
{
for(pg = 0; pg < 256; pg++)
{
int l = (pg >> 4) & 0x0F;
int r = (pg >> 0) & 0x0F;
/* If foreground is transparent, use background color */
if(l == 0) l = bd;
if(r == 0) r = bd;
/* Unpack 2 nibbles across eight pixels */
for(x = 0; x < 8; x++)
{
int c = (x & 4) ? r : l;
mc_lookup[bd][pg][x] = c;
}
}
}
/* Make bitmap data expansion table */
memset(bp_expand, 0, sizeof(bp_expand));
for(i = 0; i < 256; i++)
{
for(j = 0; j < 8; j++)
{
int c = (i >> (j ^ 7)) & 1;
bp_expand[i][j] = c;
}
}
/* Graphics I/II lookup table */
for(bd = 0; bd < 0x10; bd++)
{
for(ct = 0; ct < 0x100; ct++)
{
int backdrop = (bd & 0x0F);
int background = (ct >> 0) & 0x0F;
int foreground = (ct >> 4) & 0x0F;
/* If foreground is transparent, use background color */
if(background == 0) background = backdrop;
if(foreground == 0) foreground = backdrop;
tms_lookup[bd][ct][0] = background;
tms_lookup[bd][ct][1] = foreground;
}
}
}
void render_bg_tms(int line)
{
switch(vdp.mode & 7)
{
case 0: /* Graphics I */
render_bg_m0(line);
break;
case 1: /* Text */
render_bg_m1(line);
break;
case 2: /* Graphics II */
render_bg_m2(line);
break;
case 3: /* Text (Extended PG) */
render_bg_m1x(line);
break;
case 4: /* Multicolor */
render_bg_m3(line);
break;
case 5: /* Invalid (1+3) */
render_bg_inv(line);
break;
case 6: /* Multicolor (Extended PG) */
render_bg_m3x(line);
break;
case 7: /* Invalid (1+2+3) */
render_bg_inv(line);
break;
}
}
/* Graphics I */
void render_bg_m0(int line)
{
int v_row = (line & 7);
int column;
int name;
uint8 *clut;
uint8 *bpex;
uint8 *lb = &linebuf[0];
uint8 *pn = &vdp.vram[vdp.pn + ((line >> 3) << 5)];
uint8 *ct = &vdp.vram[vdp.ct];
uint8 *pg = &vdp.vram[vdp.pg | (v_row)];
for(column = 0; column < 32; column++)
{
name = pn[column];
clut = &tms_lookup[vdp.bd][ct[name >> 3]][0];
bpex = &bp_expand[pg[name << 3]][0];
RENDER_GR_LINE
}
}
/* Text */
void render_bg_m1(int line)
{
int v_row = (line & 7);
int column;
uint8 *clut;
uint8 *bpex;
uint8 *lb = &linebuf[0];
// uint8 *pn = &vdp.vram[vdp.pn + ((line >> 3) * 40)];
uint8 *pn = &vdp.vram[vdp.pn + text_counter];
uint8 *pg = &vdp.vram[vdp.pg | (v_row)];
uint8 bk = vdp.reg[7];
clut = &txt_lookup[bk][0];
for(column = 0; column < 40; column++)
{
bpex = &bp_expand[pg[pn[column] << 3]][0];
RENDER_TX_LINE
}
/* V3 */
if((vdp.line & 7) == 7)
text_counter += 40;
RENDER_TX_BORDER
}
/* Text + extended PG */
void render_bg_m1x(int line)
{
int v_row = (line & 7);
int column;
uint8 *clut;
uint8 *bpex;
uint8 *lb = &linebuf[0];
uint8 *pn = &vdp.vram[vdp.pn + ((line >> 3) * 40)];
uint8 *pg = &vdp.vram[vdp.pg + (v_row) + ((line & 0xC0) << 5)];
uint8 bk = vdp.reg[7];
clut = &tms_lookup[0][bk][0];
for(column = 0; column < 40; column++)
{
bpex = &bp_expand[pg[pn[column] << 3]][0];
RENDER_TX_LINE
}
RENDER_TX_BORDER
}
/* Invalid (2+3/1+2+3) */
void render_bg_inv(int line)
{
int column;
uint8 *clut;
uint8 *bpex;
uint8 *lb = &linebuf[0];
uint8 bk = vdp.reg[7];
clut = &txt_lookup[bk][0];
for(column = 0; column < 40; column++)
{
bpex = &bp_expand[0xF0][0];
RENDER_TX_LINE
}
}
/* Multicolor */
void render_bg_m3(int line)
{
int column;
uint8 *mcex;
uint8 *lb = &linebuf[0];
uint8 *pn = &vdp.vram[vdp.pn + ((line >> 3) << 5)];
uint8 *pg = &vdp.vram[vdp.pg + ((line >> 2) & 7)];
for(column = 0; column < 32; column++)
{
mcex = &mc_lookup[vdp.bd][pg[pn[column]<<3]][0];
RENDER_MC_LINE
}
}
/* Multicolor + extended PG */
void render_bg_m3x(int line)
{
int column;
uint8 *mcex;
uint8 *lb = &linebuf[0];
uint8 *pn = &vdp.vram[vdp.pn + ((line >> 3) << 5)];
uint8 *pg = &vdp.vram[vdp.pg + ((line >> 2) & 7) + ((line & 0xC0) << 5)];
for(column = 0; column < 32; column++)
{
mcex = &mc_lookup[vdp.bd][pg[pn[column]<<3]][0];
RENDER_MC_LINE
}
}
/* Graphics II */
void render_bg_m2(int line)
{
int v_row = (line & 7);
int column;
int name;
uint8 *clut;
uint8 *bpex;
uint8 *lb = &linebuf[0];
uint8 *pn = &vdp.vram[vdp.pn | ((line & 0xF8) << 2)];
uint8 *ct = &vdp.vram[(vdp.ct & 0x2000) | (v_row) | ((line & 0xC0) << 5)];
uint8 *pg = &vdp.vram[(vdp.pg & 0x2000) | (v_row) | ((line & 0xC0) << 5)];
for(column = 0; column < 32; column++)
{
name = pn[column] << 3;
clut = &tms_lookup[vdp.bd][ct[name]][0];
bpex = &bp_expand[pg[name]][0];
RENDER_GR_LINE
}
}

19
src/burn/drv/sms/smstms.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef _SMSTMS_H_
#define _SMSTMS_H_
extern int text_counter;
void make_tms_tables(void);
void render_bg_tms(int line);
void render_bg_m0(int line);
void render_bg_m1(int line);
void render_bg_m1x(int line);
void render_bg_inv(int line);
void render_bg_m3(int line);
void render_bg_m3x(int line);
void render_bg_m2(int line);
void render_obj_tms(int line);
void parse_line(int line);
#endif /* _TMS_H_ */

548
src/burn/drv/sms/smsvdp.cpp Normal file
View File

@ -0,0 +1,548 @@
/*
vdp.c --
Video Display Processor (VDP) emulation.
*/
#include "smsshared.h"
#include "tiles_generic.h"
#include "driver.h"
#include "z80_intf.h"
#include "smshvc.h"
static const uint8 tms_crom[] =
{
0x00, 0x00, 0x08, 0x0C,
0x10, 0x30, 0x01, 0x3C,
0x02, 0x03, 0x05, 0x0F,
0x04, 0x33, 0x15, 0x3F
};
/* Mark a pattern as dirty */
#define MARK_BG_DIRTY(addr) \
{ \
int name = (addr >> 5) & 0x1FF; \
if(bg_name_dirty[name] == 0) \
{ \
bg_name_list[bg_list_index] = name; \
bg_list_index++; \
} \
bg_name_dirty[name] |= (1 << ((addr >> 2) & 7)); \
}
/* VDP context */
vdp_t vdp;
/* Initialize VDP emulation */
void vdp_init(void)
{
vdp_reset();
}
void vdp_shutdown(void)
{
/* Nothing to do */
}
/* Reset VDP emulation */
void vdp_reset(void)
{
memset(&vdp, 0, sizeof(vdp_t));
vdp.extended = 0;
vdp.height = 192;
bitmap.viewport.x = (IS_GG) ? 48 : 0;
bitmap.viewport.y = (IS_GG) ? 24 : 0;
bitmap.viewport.w = (IS_GG) ? 160 : 256;
bitmap.viewport.h = (IS_GG) ? 144 : 192;
bitmap.viewport.changed = 1;
}
void viewport_check(void)
{
int i;
int m1 = (vdp.reg[1] >> 4) & 1;
int m3 = (vdp.reg[1] >> 3) & 1;
int m2 = (vdp.reg[0] >> 1) & 1;
int m4 = (vdp.reg[0] >> 2) & 1;
vdp.mode = (m4 << 3 | m3 << 2 | m2 << 1 | m1 << 0);
// check if this is switching out of tms
if(!IS_GG)
{
if(m4)
{
/* Restore SMS palette */
for(i = 0; i < PALETTE_SIZE; i++)
{
palette_sync(i, 1);
}
}
else
{
/* Load TMS9918 palette */
for(i = 0; i < PALETTE_SIZE; i++)
{
int r, g, b;
r = (tms_crom[i & 0x0F] >> 0) & 3;
g = (tms_crom[i & 0x0F] >> 2) & 3;
b = (tms_crom[i & 0x0F] >> 4) & 3;
r = sms_cram_expand_table[r];
g = sms_cram_expand_table[g];
b = sms_cram_expand_table[b];
bitmap.pal.color[i][0] = r;
bitmap.pal.color[i][1] = g;
bitmap.pal.color[i][2] = b;
pixel[i] = MAKE_PIXEL(r, g, b);
bitmap.pal.dirty[i] = bitmap.pal.update = 1;
}
}
}
/* Check for extended modes when M4 and M2 are set */
if((vdp.reg[0] & 0x06) == 0x06)
{
/* Examine M1 and M3 to determine selected mode */
switch(vdp.reg[1] & 0x18)
{
case 0x00: /* 192 */
case 0x18: /* 192 */
vdp.height = 192;
vdp.extended = 0;
if(bitmap.viewport.h != 192 && IS_SMS)
{
bitmap.viewport.oh = bitmap.viewport.h;
bitmap.viewport.h = 192;
bitmap.viewport.changed = 1;
}
vdp.ntab = (vdp.reg[2] << 10) & 0x3800;
break;
case 0x08: /* 240 */
vdp.height = 240;
vdp.extended = 2;
if(bitmap.viewport.h != 240 && IS_SMS)
{
bitmap.viewport.oh = bitmap.viewport.h;
bitmap.viewport.h = 240;
bitmap.viewport.changed = 1;
}
vdp.ntab = ((vdp.reg[2] << 10) & 0x3000) | 0x0700;
break;
case 0x10: /* 224 */
vdp.height = 224;
vdp.extended = 1;
if(bitmap.viewport.h != 224 && IS_SMS)
{
bitmap.viewport.oh = bitmap.viewport.h;
bitmap.viewport.h = 224;
bitmap.viewport.changed = 1;
}
vdp.ntab = ((vdp.reg[2] << 10) & 0x3000) | 0x0700;
break;
}
}
else
{
vdp.height = 192;
vdp.extended = 0;
if(bitmap.viewport.h != 192 && IS_SMS)
{
bitmap.viewport.oh = bitmap.viewport.h;
bitmap.viewport.h = 192;
bitmap.viewport.changed = 1;
}
vdp.ntab = (vdp.reg[2] << 10) & 0x3800;
}
vdp.pn = (vdp.reg[2] << 10) & 0x3C00;
vdp.ct = (vdp.reg[3] << 6) & 0x3FC0;
vdp.pg = (vdp.reg[4] << 11) & 0x3800;
vdp.sa = (vdp.reg[5] << 7) & 0x3F80;
vdp.sg = (vdp.reg[6] << 11) & 0x3800;
render_bg = (vdp.mode & 8) ? render_bg_sms : render_bg_tms;
render_obj = (vdp.mode & 8) ? render_obj_sms : render_obj_tms;
}
void vdp_reg_w(uint8 r, uint8 d)
{
/* Store register data */
vdp.reg[r] = d;
switch(r)
{
case 0x00: /* Mode Control No. 1 */
if(vdp.hint_pending)
{
if(d & 0x10)
ZetSetIRQLine(0, CPU_IRQSTATUS_ACK);
else
ZetSetIRQLine(0, CPU_IRQSTATUS_NONE);
}
viewport_check();
break;
case 0x01: /* Mode Control No. 2 */
if(vdp.vint_pending)
{
if(d & 0x20)
ZetSetIRQLine(0, CPU_IRQSTATUS_ACK);
else
ZetSetIRQLine(0, CPU_IRQSTATUS_NONE);
}
viewport_check();
break;
case 0x02: /* Name Table A Base Address */
vdp.ntab = (vdp.reg[2] << 10) & 0x3800;
vdp.pn = (vdp.reg[2] << 10) & 0x3C00;
viewport_check();
break;
case 0x03:
vdp.ct = (vdp.reg[3] << 6) & 0x3FC0;
break;
case 0x04:
vdp.pg = (vdp.reg[4] << 11) & 0x3800;
break;
case 0x05: /* Sprite Attribute Table Base Address */
vdp.satb = (vdp.reg[5] << 7) & 0x3F00;
vdp.sa = (vdp.reg[5] << 7) & 0x3F80;
break;
case 0x06:
vdp.sg = (vdp.reg[6] << 11) & 0x3800;
break;
case 0x07:
vdp.bd = (vdp.reg[7] & 0x0F);
break;
}
}
void vdp_write(int offset, uint8 data)
{
int index;
switch(offset & 1)
{
case 0: /* Data port */
vdp.pending = 0;
switch(vdp.code)
{
case 0: /* VRAM write */
case 1: /* VRAM write */
case 2: /* VRAM write */
index = (vdp.addr & 0x3FFF);
if(data != vdp.vram[index])
{
vdp.vram[index] = data;
MARK_BG_DIRTY(vdp.addr);
}
break;
case 3: /* CRAM write */
index = (vdp.addr & 0x1F);
if(data != vdp.cram[index])
{
vdp.cram[index] = data;
palette_sync(index, 0);
}
break;
}
vdp.addr = (vdp.addr + 1) & 0x3FFF;
return;
case 1: /* Control port */
if(vdp.pending == 0)
{
vdp.addr = (vdp.addr & 0x3F00) | (data & 0xFF);
vdp.latch = data;
vdp.pending = 1;
}
else
{
vdp.pending = 0;
vdp.code = (data >> 6) & 3;
vdp.addr = (data << 8 | vdp.latch) & 0x3FFF;
if(vdp.code == 0)
{
vdp.buffer = vdp.vram[vdp.addr & 0x3FFF];
vdp.addr = (vdp.addr + 1) & 0x3FFF;
}
if(vdp.code == 2)
{
int r = (data & 0x0F);
int d = vdp.latch;
vdp_reg_w(r, d);
}
}
return;
}
}
uint8 vdp_read(int offset)
{
uint8 temp;
switch(offset & 1)
{
case 0: /* CPU <-> VDP data buffer */
vdp.pending = 0;
temp = vdp.buffer;
vdp.buffer = vdp.vram[vdp.addr & 0x3FFF];
vdp.addr = (vdp.addr + 1) & 0x3FFF;
return temp;
case 1: /* Status flags */
temp = vdp.status;
vdp.pending = 0;
vdp.status = 0;
vdp.vint_pending = 0;
vdp.hint_pending = 0;
ZetSetIRQLine(0, CPU_IRQSTATUS_NONE);
return temp;
}
/* Just to please the compiler */
return -1;
}
uint8 vdp_counter_r(int offset)
{
int cpixel;
switch(offset & 1)
{
case 0: /* V Counter */
return vc_table[sms.display][vdp.extended][vdp.line & 0x1FF];
case 1: /* H Counter */
cpixel = (((ZetTotalCycles() % CYCLES_PER_LINE) / 4) * 3) * 2;
return hc_table[0][(cpixel >> 1) & 0x01FF];
}
/* Just to please the compiler */
return -1;
}
/*--------------------------------------------------------------------------*/
/* Game Gear VDP handlers */
/*--------------------------------------------------------------------------*/
void gg_vdp_write(int offset, uint8 data)
{
int index;
switch(offset & 1)
{
case 0: /* Data port */
vdp.pending = 0;
switch(vdp.code)
{
case 0: /* VRAM write */
case 1: /* VRAM write */
case 2: /* VRAM write */
index = (vdp.addr & 0x3FFF);
if(data != vdp.vram[index])
{
vdp.vram[index] = data;
MARK_BG_DIRTY(vdp.addr);
}
break;
case 3: /* CRAM write */
if(vdp.addr & 1)
{
vdp.cram_latch = (vdp.cram_latch & 0x00FF) | ((data & 0xFF) << 8);
vdp.cram[(vdp.addr & 0x3E) | (0)] = (vdp.cram_latch >> 0) & 0xFF;
vdp.cram[(vdp.addr & 0x3E) | (1)] = (vdp.cram_latch >> 8) & 0xFF;
palette_sync((vdp.addr >> 1) & 0x1F, 0);
}
else
{
vdp.cram_latch = (vdp.cram_latch & 0xFF00) | ((data & 0xFF) << 0);
}
break;
}
vdp.addr = (vdp.addr + 1) & 0x3FFF;
return;
case 1: /* Control port */
if(vdp.pending == 0)
{
vdp.addr = (vdp.addr & 0x3F00) | (data & 0xFF);
vdp.latch = data;
vdp.pending = 1;
}
else
{
vdp.pending = 0;
vdp.code = (data >> 6) & 3;
vdp.addr = (data << 8 | vdp.latch) & 0x3FFF;
if(vdp.code == 0)
{
vdp.buffer = vdp.vram[vdp.addr & 0x3FFF];
vdp.addr = (vdp.addr + 1) & 0x3FFF;
}
if(vdp.code == 2)
{
int r = (data & 0x0F);
int d = vdp.latch;
vdp_reg_w(r, d);
}
}
return;
}
}
/*--------------------------------------------------------------------------*/
/* MegaDrive / Genesis VDP handlers */
/*--------------------------------------------------------------------------*/
void md_vdp_write(int offset, uint8 data)
{
int index;
switch(offset & 1)
{
case 0: /* Data port */
vdp.pending = 0;
switch(vdp.code)
{
case 0: /* VRAM write */
case 1: /* VRAM write */
index = (vdp.addr & 0x3FFF);
if(data != vdp.vram[index])
{
vdp.vram[index] = data;
MARK_BG_DIRTY(vdp.addr);
}
break;
case 2: /* CRAM write */
case 3: /* CRAM write */
index = (vdp.addr & 0x1F);
if(data != vdp.cram[index])
{
vdp.cram[index] = data;
palette_sync(index, 0);
}
break;
}
vdp.addr = (vdp.addr + 1) & 0x3FFF;
return;
case 1: /* Control port */
if(vdp.pending == 0)
{
vdp.latch = data;
vdp.pending = 1;
}
else
{
vdp.pending = 0;
vdp.code = (data >> 6) & 3;
vdp.addr = (data << 8 | vdp.latch) & 0x3FFF;
if(vdp.code == 0)
{
vdp.buffer = vdp.vram[vdp.addr & 0x3FFF];
vdp.addr = (vdp.addr + 1) & 0x3FFF;
}
if(vdp.code == 2)
{
int r = (data & 0x0F);
int d = vdp.latch;
vdp_reg_w(r, d);
}
}
return;
}
}
/*--------------------------------------------------------------------------*/
/* TMS9918 VDP handlers */
/*--------------------------------------------------------------------------*/
void tms_write(int offset, int data)
{
int index;
switch(offset & 1)
{
case 0: /* Data port */
vdp.pending = 0;
switch(vdp.code)
{
case 0: /* VRAM write */
case 1: /* VRAM write */
case 2: /* VRAM write */
case 3: /* VRAM write */
index = (vdp.addr & 0x3FFF);
if(data != vdp.vram[index])
{
vdp.vram[index] = data;
MARK_BG_DIRTY(vdp.addr);
}
break;
}
vdp.addr = (vdp.addr + 1) & 0x3FFF;
return;
case 1: /* Control port */
if(vdp.pending == 0)
{
vdp.latch = data;
vdp.pending = 1;
}
else
{
vdp.pending = 0;
vdp.code = (data >> 6) & 3;
vdp.addr = (data << 8 | vdp.latch) & 0x3FFF;
if(vdp.code == 0)
{
vdp.buffer = vdp.vram[vdp.addr & 0x3FFF];
vdp.addr = (vdp.addr + 1) & 0x3FFF;
}
if(vdp.code == 2)
{
int r = (data & 0x07);
int d = vdp.latch;
vdp_reg_w(r, d);
}
}
return;
}
}

65
src/burn/drv/sms/smsvdp.h Normal file
View File

@ -0,0 +1,65 @@
#ifndef _SMSVDP_H_
#define _SMSVDP_H_
/*
vdp1
mode 4 when m4 set and m1 reset
vdp2
mode 4 when m4 set and m2,m1 != 1,0
*/
/* Display timing (NTSC) */
#define MASTER_CLOCK 3579545
#define LINES_PER_FRAME 262
#define FRAMES_PER_SECOND 60
#define CYCLES_PER_LINE ((MASTER_CLOCK / FRAMES_PER_SECOND) / LINES_PER_FRAME)
/* VDP context */
typedef struct
{
uint8 vram[0x4000];
uint8 cram[0x40];
uint8 reg[0x10];
uint8 status;
uint8 latch;
uint8 pending;
uint8 buffer;
uint8 code;
uint16 addr;
int pn, ct, pg, sa, sg;
int ntab;
int satb;
int line;
int left;
uint8 height;
uint8 extended;
uint8 mode;
uint8 vint_pending;
uint8 hint_pending;
uint16 cram_latch;
uint8 bd;
} vdp_t;
/* Global data */
extern vdp_t vdp;
/* Function prototypes */
void vdp_init(void);
void vdp_shutdown(void);
void vdp_reset(void);
uint8 vdp_counter_r(int offset);
uint8 vdp_read(int offset);
void vdp_write(int offset, uint8 data);
void gg_vdp_write(int offset, uint8 data);
void md_vdp_write(int offset, uint8 data);
void tms_write(int offset, int data);
#endif /* _VDP_H_ */