mirror of
https://github.com/libretro/FBNeo.git
synced 2024-11-27 11:00:27 +00:00
new SMS driver
This commit is contained in:
parent
57b7164b13
commit
acae9bcdb1
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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_ */
|
||||
|
165
src/burn/drv/sms/smsfmintf.cpp
Normal file
165
src/burn/drv/sms/smsfmintf.cpp
Normal 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;
|
||||
}
|
27
src/burn/drv/sms/smsfmintf.h
Normal file
27
src/burn/drv/sms/smsfmintf.h
Normal 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
189
src/burn/drv/sms/smshvc.h
Normal 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
257
src/burn/drv/sms/smspio.cpp
Normal 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
57
src/burn/drv/sms/smspio.h
Normal 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_ */
|
606
src/burn/drv/sms/smsrender.cpp
Normal file
606
src/burn/drv/sms/smsrender.cpp
Normal 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;
|
||||
}
|
||||
}
|
39
src/burn/drv/sms/smsrender.h
Normal file
39
src/burn/drv/sms/smsrender.h
Normal 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_ */
|
24
src/burn/drv/sms/smsshared.h
Normal file
24
src/burn/drv/sms/smsshared.h
Normal 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_ */
|
249
src/burn/drv/sms/smssn76489.cpp
Normal file
249
src/burn/drv/sms/smssn76489.cpp
Normal 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); */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
78
src/burn/drv/sms/smssn76489.h
Normal file
78
src/burn/drv/sms/smssn76489.h
Normal 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_ */
|
||||
|
268
src/burn/drv/sms/smssound.cpp
Normal file
268
src/burn/drv/sms/smssound.cpp
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
46
src/burn/drv/sms/smssound.h
Normal file
46
src/burn/drv/sms/smssound.h
Normal 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_ */
|
187
src/burn/drv/sms/smssystem.cpp
Normal file
187
src/burn/drv/sms/smssystem.cpp
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
|
90
src/burn/drv/sms/smssystem.h
Normal file
90
src/burn/drv/sms/smssystem.h
Normal 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
517
src/burn/drv/sms/smstms.cpp
Normal 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
19
src/burn/drv/sms/smstms.h
Normal 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
548
src/burn/drv/sms/smsvdp.cpp
Normal 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
65
src/burn/drv/sms/smsvdp.h
Normal 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_ */
|
||||
|
Loading…
Reference in New Issue
Block a user