kopia lustrzana https://github.com/Jean-MarcHarvengt/MCUME
add SMS emu to TEECOMPUTER
rodzic
b064204c27
commit
bc854b7c3b
Plik diff jest za duży
Load Diff
Plik diff jest za duży
Load Diff
|
@ -0,0 +1,361 @@
|
|||
#include "emuapi.h"
|
||||
|
||||
#ifdef HAS_SND
|
||||
|
||||
#include "AudioPlaySystem.h"
|
||||
#include <Arduino.h>
|
||||
#define SAMPLERATE AUDIO_SAMPLE_RATE_EXACT
|
||||
#define CLOCKFREQ 985248
|
||||
|
||||
#ifndef CUSTOM_SND
|
||||
PROGMEM static const short square[]={
|
||||
32767,32767,32767,32767,
|
||||
32767,32767,32767,32767,
|
||||
32767,32767,32767,32767,
|
||||
32767,32767,32767,32767,
|
||||
32767,32767,32767,32767,
|
||||
32767,32767,32767,32767,
|
||||
32767,32767,32767,32767,
|
||||
32767,32767,32767,32767,
|
||||
-32767,-32767,-32767,-32767,
|
||||
-32767,-32767,-32767,-32767,
|
||||
-32767,-32767,-32767,-32767,
|
||||
-32767,-32767,-32767,-32767,
|
||||
-32767,-32767,-32767,-32767,
|
||||
-32767,-32767,-32767,-32767,
|
||||
-32767,-32767,-32767,-32767,
|
||||
-32767,-32767,-32767,-32767,
|
||||
};
|
||||
|
||||
PROGMEM const short noise[] {
|
||||
-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,
|
||||
-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,-32767,32767,-32767,
|
||||
-32767,-32767,32767,-32767,-32767,-32767,32767,-32767,-32767,-32767,32767,-32767,-32767,-32767,32767,-32767,
|
||||
-32767,-32767,32767,-32767,-32767,-32767,32767,-32767,-32767,-32767,32767,-32767,-32767,32767,32767,-32767,
|
||||
-32767,-32767,32767,-32767,-32767,32767,32767,-32767,-32767,-32767,32767,-32767,-32767,32767,32767,-32767,
|
||||
-32767,-32767,32767,-32767,-32767,32767,32767,-32767,-32767,-32767,32767,-32767,32767,32767,32767,-32767,
|
||||
32767,-32767,32767,-32767,-32767,32767,32767,-32767,-32767,-32767,32767,-32767,32767,32767,32767,-32767,
|
||||
32767,-32767,32767,-32767,-32767,32767,32767,-32767,-32767,-32767,32767,32767,32767,32767,32767,-32767,
|
||||
32767,-32767,32767,-32767,-32767,32767,32767,-32767,-32767,-32767,32767,32767,32767,32767,32767,-32767,
|
||||
32767,-32767,32767,-32767,-32767,32767,32767,-32767,-32767,-32767,-32767,32767,32767,32767,-32767,-32767,
|
||||
32767,-32767,-32767,-32767,-32767,32767,-32767,-32767,-32767,-32767,32767,32767,32767,32767,32767,-32767,
|
||||
32767,-32767,32767,-32767,-32767,32767,32767,-32767,-32767,32767,-32767,32767,32767,32767,-32767,-32767,
|
||||
32767,32767,-32767,-32767,-32767,32767,-32767,-32767,-32767,-32767,32767,32767,32767,32767,32767,-32767,
|
||||
32767,-32767,32767,-32767,-32767,32767,32767,-32767,32767,32767,-32767,32767,-32767,32767,-32767,-32767,
|
||||
32767,32767,-32767,-32767,-32767,32767,-32767,-32767,-32767,-32767,32767,32767,32767,32767,32767,-32767,
|
||||
32767,-32767,32767,-32767,-32767,32767,32767,32767,32767,32767,-32767,32767,-32767,32767,-32767,-32767,
|
||||
};
|
||||
|
||||
#define NOISEBSIZE 0x100
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int spos;
|
||||
unsigned int sinc;
|
||||
unsigned int vol;
|
||||
} Channel;
|
||||
|
||||
static Channel chan[6] = {
|
||||
{0,0,0},
|
||||
{0,0,0},
|
||||
{0,0,0},
|
||||
{0,0,0},
|
||||
{0,0,0},
|
||||
{0,0,0} };
|
||||
|
||||
#endif
|
||||
|
||||
volatile bool playing = false;
|
||||
|
||||
|
||||
static void snd_Reset(void)
|
||||
{
|
||||
#ifndef CUSTOM_SND
|
||||
chan[0].vol = 0;
|
||||
chan[1].vol = 0;
|
||||
chan[2].vol = 0;
|
||||
chan[3].vol = 0;
|
||||
chan[4].vol = 0;
|
||||
chan[5].vol = 0;
|
||||
chan[0].sinc = 0;
|
||||
chan[1].sinc = 0;
|
||||
chan[2].sinc = 0;
|
||||
chan[3].sinc = 0;
|
||||
chan[4].sinc = 0;
|
||||
chan[5].sinc = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef CUSTOM_SND
|
||||
//extern "C" {
|
||||
void SND_Process(void *sndbuffer, int sndn);
|
||||
//}
|
||||
#endif
|
||||
|
||||
|
||||
FASTRUN void AudioPlaySystem::snd_Mixer(short * stream, int len )
|
||||
{
|
||||
if (playing)
|
||||
{
|
||||
#ifdef CUSTOM_SND
|
||||
SND_Process((void*)stream, len);
|
||||
#else
|
||||
int i;
|
||||
long s;
|
||||
len = len >> 1;
|
||||
short v0=chan[0].vol;
|
||||
short v1=chan[1].vol;
|
||||
short v2=chan[2].vol;
|
||||
short v3=chan[3].vol;
|
||||
short v4=chan[4].vol;
|
||||
short v5=chan[5].vol;
|
||||
for (i=0;i<len;i++)
|
||||
{
|
||||
s =((v0*square[(chan[0].spos>>8)&0x3f])>>11);
|
||||
s+=((v1*square[(chan[1].spos>>8)&0x3f])>>11);
|
||||
s+=((v2*square[(chan[2].spos>>8)&0x3f])>>11);
|
||||
s+=((v3*noise[(chan[3].spos>>8)&(NOISEBSIZE-1)])>>11);
|
||||
s+=((v4*noise[(chan[4].spos>>8)&(NOISEBSIZE-1)])>>11);
|
||||
s+=((v5*noise[(chan[5].spos>>8)&(NOISEBSIZE-1)])>>11);
|
||||
*stream++ = (short)(s);
|
||||
*stream++ = (short)(s);
|
||||
chan[0].spos += chan[0].sinc;
|
||||
chan[1].spos += chan[1].sinc;
|
||||
chan[2].spos += chan[2].sinc;
|
||||
chan[3].spos += chan[3].sinc;
|
||||
chan[4].spos += chan[4].sinc;
|
||||
chan[5].spos += chan[5].sinc;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void AudioPlaySystem::begin(void)
|
||||
{
|
||||
this->reset();
|
||||
}
|
||||
|
||||
void AudioPlaySystem::start(void)
|
||||
{
|
||||
playing = true;
|
||||
}
|
||||
|
||||
void AudioPlaySystem::setSampleParameters(float clockfreq, float samplerate) {
|
||||
}
|
||||
|
||||
void AudioPlaySystem::reset(void)
|
||||
{
|
||||
snd_Reset();
|
||||
}
|
||||
|
||||
void AudioPlaySystem::stop(void)
|
||||
{
|
||||
//__disable_irq();
|
||||
playing = false;
|
||||
//__enable_irq();
|
||||
}
|
||||
|
||||
bool AudioPlaySystem::isPlaying(void)
|
||||
{
|
||||
return playing;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AudioPlaySystem::sound(int C, int F, int V) {
|
||||
#ifndef CUSTOM_SND
|
||||
if (C < 6) {
|
||||
chan[C].vol = V;
|
||||
chan[C].sinc = F>>1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void AudioPlaySystem::step(void) {
|
||||
}
|
||||
|
||||
|
||||
#ifndef HAS_T4_VGA
|
||||
/*******************************************************************
|
||||
Experimental I2S interrupt based sound driver for PCM51xx !!!
|
||||
*******************************************************************/
|
||||
|
||||
FLASHMEM static void set_audioClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL4
|
||||
{
|
||||
if (!force && (CCM_ANALOG_PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_ENABLE)) return;
|
||||
|
||||
CCM_ANALOG_PLL_AUDIO = CCM_ANALOG_PLL_AUDIO_BYPASS | CCM_ANALOG_PLL_AUDIO_ENABLE
|
||||
| CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2) // 2: 1/4; 1: 1/2; 0: 1/1
|
||||
| CCM_ANALOG_PLL_AUDIO_DIV_SELECT(nfact);
|
||||
|
||||
CCM_ANALOG_PLL_AUDIO_NUM = nmult & CCM_ANALOG_PLL_AUDIO_NUM_MASK;
|
||||
CCM_ANALOG_PLL_AUDIO_DENOM = ndiv & CCM_ANALOG_PLL_AUDIO_DENOM_MASK;
|
||||
|
||||
CCM_ANALOG_PLL_AUDIO &= ~CCM_ANALOG_PLL_AUDIO_POWERDOWN;//Switch on PLL
|
||||
while (!(CCM_ANALOG_PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_LOCK)) {}; //Wait for pll-lock
|
||||
|
||||
const int div_post_pll = 1; // other values: 2,4
|
||||
CCM_ANALOG_MISC2 &= ~(CCM_ANALOG_MISC2_DIV_MSB | CCM_ANALOG_MISC2_DIV_LSB);
|
||||
if(div_post_pll>1) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_LSB;
|
||||
if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB;
|
||||
|
||||
CCM_ANALOG_PLL_AUDIO &= ~CCM_ANALOG_PLL_AUDIO_BYPASS;//Disable Bypass
|
||||
}
|
||||
|
||||
#define AUDIO_SAMPLE_RATE_EXACT 11025.0 //44117.64706 //11025.0 //22050.0 //44117.64706 //31778.0
|
||||
|
||||
FLASHMEM static void config_sai1()
|
||||
{
|
||||
CCM_CCGR5 |= CCM_CCGR5_SAI1(CCM_CCGR_ON);
|
||||
double fs = AUDIO_SAMPLE_RATE_EXACT;
|
||||
// PLL between 27*24 = 648MHz und 54*24=1296MHz
|
||||
int n1 = 4; //SAI prescaler 4 => (n1*n2) = multiple of 4
|
||||
int n2 = 1 + (24000000 * 27) / (fs * 256 * n1);
|
||||
double C = (fs * 256 * n1 * n2) / 24000000;
|
||||
int c0 = C;
|
||||
int c2 = 10000;
|
||||
int c1 = C * c2 - (c0 * c2);
|
||||
|
||||
set_audioClock(c0, c1, c2, true);
|
||||
// clear SAI1_CLK register locations
|
||||
CCM_CSCMR1 = (CCM_CSCMR1 & ~(CCM_CSCMR1_SAI1_CLK_SEL_MASK))
|
||||
| CCM_CSCMR1_SAI1_CLK_SEL(2); // &0x03 // (0,1,2): PLL3PFD0, PLL5, PLL4
|
||||
|
||||
n1 = n1 / 2; //Double Speed for TDM
|
||||
|
||||
CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_SAI1_CLK_PRED_MASK | CCM_CS1CDR_SAI1_CLK_PODF_MASK))
|
||||
| CCM_CS1CDR_SAI1_CLK_PRED(n1 - 1) // &0x07
|
||||
| CCM_CS1CDR_SAI1_CLK_PODF(n2 - 1); // &0x3f
|
||||
|
||||
IOMUXC_GPR_GPR1 = (IOMUXC_GPR_GPR1 & ~(IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL_MASK))
|
||||
| (IOMUXC_GPR_GPR1_SAI1_MCLK_DIR | IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL(0)); //Select MCLK
|
||||
|
||||
|
||||
// configure transmitter
|
||||
int rsync = 0;
|
||||
int tsync = 1;
|
||||
|
||||
I2S1_TMR = 0;
|
||||
I2S1_TCR1 = I2S_TCR1_RFW(1);
|
||||
I2S1_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_BCP // sync=0; tx is async;
|
||||
| (I2S_TCR2_BCD | I2S_TCR2_DIV((1)) | I2S_TCR2_MSEL(1));
|
||||
I2S1_TCR3 = I2S_TCR3_TCE;
|
||||
I2S1_TCR4 = I2S_TCR4_FRSZ((2-1)) | I2S_TCR4_SYWD((32-1)) | I2S_TCR4_MF
|
||||
| I2S_TCR4_FSD | I2S_TCR4_FSE | I2S_TCR4_FSP;
|
||||
I2S1_TCR5 = I2S_TCR5_WNW((32-1)) | I2S_TCR5_W0W((32-1)) | I2S_TCR5_FBT((32-1));
|
||||
|
||||
|
||||
I2S1_RMR = 0;
|
||||
I2S1_RCR1 = I2S_RCR1_RFW(1);
|
||||
I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_RCR2_BCP // sync=0; rx is async;
|
||||
| (I2S_RCR2_BCD | I2S_RCR2_DIV((1)) | I2S_RCR2_MSEL(1));
|
||||
I2S1_RCR3 = I2S_RCR3_RCE;
|
||||
I2S1_RCR4 = I2S_RCR4_FRSZ((2-1)) | I2S_RCR4_SYWD((32-1)) | I2S_RCR4_MF
|
||||
| I2S_RCR4_FSE | I2S_RCR4_FSP | I2S_RCR4_FSD;
|
||||
I2S1_RCR5 = I2S_RCR5_WNW((32-1)) | I2S_RCR5_W0W((32-1)) | I2S_RCR5_FBT((32-1));
|
||||
|
||||
//CORE_PIN23_CONFIG = 3; // MCLK
|
||||
CORE_PIN21_CONFIG = 3; // RX_BCLK
|
||||
CORE_PIN20_CONFIG = 3; // RX_SYNC
|
||||
CORE_PIN7_CONFIG = 3; // TX_DATA0
|
||||
I2S1_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE;
|
||||
I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE ;//<-- not using DMA */;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//DMAMEM __attribute__((aligned(32))) static uint32_t i2s_tx[1024];
|
||||
|
||||
static bool fillfirsthalf = true;
|
||||
static uint16_t cnt = 0;
|
||||
static uint16_t sampleBufferSize = 0;
|
||||
|
||||
static void (*fillsamples)(short * stream, int len) = nullptr;
|
||||
|
||||
static uint32_t * i2s_tx_buffer __attribute__((aligned(32)));
|
||||
static uint16_t * i2s_tx_buffer16;
|
||||
static uint16_t * txreg = (uint16_t *)((uint32_t)&I2S1_TDR0 + 2);
|
||||
|
||||
|
||||
FASTRUN void AudioPlaySystem::AUDIO_isr() {
|
||||
|
||||
*txreg = i2s_tx_buffer16[cnt];
|
||||
cnt = cnt + 1;
|
||||
cnt = cnt & (sampleBufferSize*2-1);
|
||||
|
||||
if (cnt == 0) {
|
||||
fillfirsthalf = false;
|
||||
NVIC_SET_PENDING(IRQ_SOFTWARE);
|
||||
}
|
||||
else if (cnt == sampleBufferSize) {
|
||||
fillfirsthalf = true;
|
||||
NVIC_SET_PENDING(IRQ_SOFTWARE);
|
||||
}
|
||||
/*
|
||||
I2S1_TDR0 = i2s_tx_buffer[cnt];
|
||||
cnt = cnt + 1;
|
||||
cnt = cnt & (sampleBufferSize-1);
|
||||
if (cnt == 0) {
|
||||
fillfirsthalf = false;
|
||||
NVIC_SET_PENDING(IRQ_SOFTWARE);
|
||||
}
|
||||
else if (cnt == sampleBufferSize/2) {
|
||||
fillfirsthalf = true;
|
||||
NVIC_SET_PENDING(IRQ_SOFTWARE);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
FASTRUN void AudioPlaySystem::SOFTWARE_isr() {
|
||||
//Serial.println("x");
|
||||
if (fillfirsthalf) {
|
||||
fillsamples((short *)i2s_tx_buffer, sampleBufferSize);
|
||||
arm_dcache_flush_delete((void*)i2s_tx_buffer, (sampleBufferSize/2)*sizeof(uint32_t));
|
||||
}
|
||||
else {
|
||||
fillsamples((short *)&i2s_tx_buffer[sampleBufferSize/2], sampleBufferSize);
|
||||
arm_dcache_flush_delete((void*)&i2s_tx_buffer[sampleBufferSize/2], (sampleBufferSize/2)*sizeof(uint32_t));
|
||||
}
|
||||
}
|
||||
|
||||
// display VGA image
|
||||
FLASHMEM void AudioPlaySystem::begin_audio(int samplesize, void (*callback)(short * stream, int len))
|
||||
{
|
||||
fillsamples = callback;
|
||||
i2s_tx_buffer = (uint32_t*)malloc(samplesize*sizeof(uint32_t)); //&i2s_tx[0];
|
||||
|
||||
if (i2s_tx_buffer == NULL) {
|
||||
Serial.println("could not allocate audio samples");
|
||||
return;
|
||||
}
|
||||
memset((void*)i2s_tx_buffer,0, samplesize*sizeof(uint32_t));
|
||||
arm_dcache_flush_delete((void*)i2s_tx_buffer, samplesize*sizeof(uint32_t));
|
||||
i2s_tx_buffer16 = (uint16_t*)i2s_tx_buffer;
|
||||
|
||||
sampleBufferSize = samplesize;
|
||||
|
||||
config_sai1();
|
||||
attachInterruptVector(IRQ_SAI1, AUDIO_isr);
|
||||
NVIC_ENABLE_IRQ(IRQ_SAI1);
|
||||
NVIC_SET_PRIORITY(IRQ_QTIMER3, 0); // 0 highest priority, 255 = lowest priority
|
||||
NVIC_SET_PRIORITY(IRQ_SAI1, 127);
|
||||
attachInterruptVector(IRQ_SOFTWARE, SOFTWARE_isr);
|
||||
NVIC_SET_PRIORITY(IRQ_SOFTWARE, 208);
|
||||
NVIC_ENABLE_IRQ(IRQ_SOFTWARE);
|
||||
|
||||
I2S1_TCSR |= 1<<8; // start generating TX FIFO interrupts
|
||||
|
||||
Serial.print("Audio sample buffer = ");
|
||||
Serial.println(samplesize);
|
||||
}
|
||||
|
||||
FLASHMEM void AudioPlaySystem::end_audio()
|
||||
{
|
||||
if (i2s_tx_buffer != NULL) {
|
||||
free(i2s_tx_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef audioplaysystem_h_
|
||||
#define audioplaysystem_h_
|
||||
|
||||
#ifdef HAS_SND
|
||||
|
||||
#include "platform_config.h"
|
||||
|
||||
class AudioPlaySystem
|
||||
{
|
||||
public:
|
||||
AudioPlaySystem(void) { };
|
||||
void begin(void);
|
||||
void setSampleParameters(float clockfreq, float samplerate);
|
||||
void reset(void);
|
||||
void start(void);
|
||||
void stop(void);
|
||||
bool isPlaying(void);
|
||||
void sound(int C, int F, int V);
|
||||
void buzz(int size, int val);
|
||||
void step(void);
|
||||
static void snd_Mixer(short * stream, int len );
|
||||
#ifndef HAS_T4_VGA
|
||||
void begin_audio(int samplesize, void (*callback)(short * stream, int len));
|
||||
void end_audio();
|
||||
static void AUDIO_isr(void);
|
||||
static void SOFTWARE_isr(void);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef _ARDUINOPROTO_H_
|
||||
#define _ARDUINOPROTO_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
//#define PROGMEM
|
||||
|
||||
#endif
|
|
@ -0,0 +1,383 @@
|
|||
#ifndef CPUINTRF_H
|
||||
#define CPUINTRF_H
|
||||
|
||||
|
||||
/* The old system is obsolete and no longer supported by the core */
|
||||
#define NEW_INTERRUPT_SYSTEM 1
|
||||
|
||||
#define MAX_IRQ_LINES 8 /* maximum number of IRQ lines per CPU */
|
||||
|
||||
#define CLEAR_LINE 0 /* clear (a fired, held or pulsed) line */
|
||||
#define ASSERT_LINE 1 /* assert an interrupt immediately */
|
||||
#define HOLD_LINE 2 /* hold interrupt line until enable is true */
|
||||
#define PULSE_LINE 3 /* pulse interrupt line for one instruction */
|
||||
|
||||
#define MAX_REGS 64 /* maximum number of register of any CPU */
|
||||
|
||||
/* Values passed to the cpu_info function of a core to retrieve information */
|
||||
enum {
|
||||
CPU_INFO_REG,
|
||||
CPU_INFO_FLAGS=MAX_REGS,
|
||||
CPU_INFO_NAME,
|
||||
CPU_INFO_FAMILY,
|
||||
CPU_INFO_VERSION,
|
||||
CPU_INFO_FILE,
|
||||
CPU_INFO_CREDITS,
|
||||
CPU_INFO_REG_LAYOUT,
|
||||
CPU_INFO_WIN_LAYOUT
|
||||
};
|
||||
|
||||
#define CPU_IS_LE 0 /* emulated CPU is little endian */
|
||||
#define CPU_IS_BE 1 /* emulated CPU is big endian */
|
||||
|
||||
/*
|
||||
* This value is passed to cpu_get_reg to retrieve the previous
|
||||
* program counter value, ie. before a CPU emulation started
|
||||
* to fetch opcodes and arguments for the current instrution.
|
||||
*/
|
||||
#define REG_PREVIOUSPC -1
|
||||
|
||||
/*
|
||||
* This value is passed to cpu_get_reg/cpu_set_reg, instead of one of
|
||||
* the names from the enum a CPU core defines for it's registers,
|
||||
* to get or set the contents of the memory pointed to by a stack pointer.
|
||||
* You can specify the n'th element on the stack by (REG_SP_CONTENTS-n),
|
||||
* ie. lower negative values. The actual element size (UINT16 or UINT32)
|
||||
* depends on the CPU core.
|
||||
* This is also used to replace the cpu_geturnpc() function.
|
||||
*/
|
||||
#define REG_SP_CONTENTS -2
|
||||
|
||||
|
||||
/* ASG 971222 -- added this generic structure */
|
||||
struct cpu_interface
|
||||
{
|
||||
unsigned cpu_num;
|
||||
void (*reset)(void *param);
|
||||
void (*exit)(void);
|
||||
int (*execute)(int cycles);
|
||||
void (*burn)(int cycles);
|
||||
unsigned (*get_context)(void *reg);
|
||||
void (*set_context)(void *reg);
|
||||
unsigned (*get_pc)(void);
|
||||
void (*set_pc)(unsigned val);
|
||||
unsigned (*get_sp)(void);
|
||||
void (*set_sp)(unsigned val);
|
||||
unsigned (*get_reg)(int regnum);
|
||||
void (*set_reg)(int regnum, unsigned val);
|
||||
void (*set_nmi_line)(int linestate);
|
||||
void (*set_irq_line)(int irqline, int linestate);
|
||||
void (*set_irq_callback)(int(*callback)(int irqline));
|
||||
void (*internal_interrupt)(int type);
|
||||
void (*cpu_state_save)(void *file);
|
||||
void (*cpu_state_load)(void *file);
|
||||
const char* (*cpu_info)(void *context,int regnum);
|
||||
unsigned (*cpu_dasm)(char *buffer,unsigned pc);
|
||||
unsigned num_irqs;
|
||||
int default_vector;
|
||||
int *icount;
|
||||
double overclock;
|
||||
int no_int, irq_int, nmi_int;
|
||||
int (*memory_read)(int offset);
|
||||
void (*memory_write)(int offset, int data);
|
||||
void (*set_op_base)(int pc);
|
||||
int address_shift;
|
||||
unsigned address_bits, endianess, align_unit, max_inst_len;
|
||||
unsigned abits1, abits2, abitsmin;
|
||||
};
|
||||
|
||||
extern struct cpu_interface cpuintf[];
|
||||
|
||||
void cpu_init(void);
|
||||
void cpu_run(void);
|
||||
|
||||
/* optional watchdog */
|
||||
void watchdog_reset_w(int offset,int data);
|
||||
int watchdog_reset_r(int offset);
|
||||
/* Use this function to reset the machine */
|
||||
void machine_reset(void);
|
||||
/* Use this function to reset a single CPU */
|
||||
void cpu_set_reset_line(int cpu,int state);
|
||||
/* Use this function to halt a single CPU */
|
||||
void cpu_set_halt_line(int cpu,int state);
|
||||
|
||||
/* This function returns CPUNUM current status (running or halted) */
|
||||
int cpu_getstatus(int cpunum);
|
||||
int cpu_gettotalcpu(void);
|
||||
int cpu_getactivecpu(void);
|
||||
void cpu_setactivecpu(int cpunum);
|
||||
|
||||
/* Returns the current program counter */
|
||||
unsigned cpu_get_pc(void);
|
||||
/* Set the current program counter */
|
||||
void cpu_set_pc(unsigned val);
|
||||
|
||||
/* Returns the current stack pointer */
|
||||
unsigned cpu_get_sp(void);
|
||||
/* Set the current stack pointer */
|
||||
void cpu_set_sp(unsigned val);
|
||||
|
||||
/* Get the active CPUs context and return it's size */
|
||||
unsigned cpu_get_context(void *context);
|
||||
/* Set the active CPUs context */
|
||||
void cpu_set_context(void *context);
|
||||
|
||||
/* Returns a specific register value (mamedbg) */
|
||||
unsigned cpu_get_reg(int regnum);
|
||||
/* Sets a specific register value (mamedbg) */
|
||||
void cpu_set_reg(int regnum, unsigned val);
|
||||
|
||||
/* Returns previous pc (start of opcode causing read/write) */
|
||||
/* int cpu_getpreviouspc(void); */
|
||||
#define cpu_getpreviouspc() cpu_get_reg(REG_PREVIOUSPC)
|
||||
|
||||
/* Returns the return address from the top of the stack (Z80 only) */
|
||||
/* int cpu_getreturnpc(void); */
|
||||
/* This can now be handled with a generic function */
|
||||
#define cpu_geturnpc() cpu_get_reg(REG_SP_CONTENTS)
|
||||
|
||||
int cycles_currently_ran(void);
|
||||
int cycles_left_to_run(void);
|
||||
|
||||
/* Returns the number of CPU cycles which take place in one video frame */
|
||||
int cpu_gettotalcycles(void);
|
||||
/* Returns the number of CPU cycles before the next interrupt handler call */
|
||||
int cpu_geticount(void);
|
||||
/* Returns the number of CPU cycles before the end of the current video frame */
|
||||
int cpu_getfcount(void);
|
||||
/* Returns the number of CPU cycles in one video frame */
|
||||
int cpu_getfperiod(void);
|
||||
/* Scales a given value by the ratio of fcount / fperiod */
|
||||
int cpu_scalebyfcount(int value);
|
||||
/* Returns the current scanline number */
|
||||
int cpu_getscanline(void);
|
||||
/* Returns the amount of time until a given scanline */
|
||||
double cpu_getscanlinetime(int scanline);
|
||||
/* Returns the duration of a single scanline */
|
||||
double cpu_getscanlineperiod(void);
|
||||
/* Returns the duration of a single scanline in cycles */
|
||||
int cpu_getscanlinecycles(void);
|
||||
/* Returns the number of cycles since the beginning of this frame */
|
||||
int cpu_getcurrentcycles(void);
|
||||
/* Returns the current horizontal beam position in pixels */
|
||||
int cpu_gethorzbeampos(void);
|
||||
/*
|
||||
Returns the number of times the interrupt handler will be called before
|
||||
the end of the current video frame. This is can be useful to interrupt
|
||||
handlers to synchronize their operation. If you call this from outside
|
||||
an interrupt handler, add 1 to the result, i.e. if it returns 0, it means
|
||||
that the interrupt handler will be called once.
|
||||
*/
|
||||
int cpu_getiloops(void);
|
||||
|
||||
/* Returns the current VBLANK state */
|
||||
int cpu_getvblank(void);
|
||||
|
||||
/* Returns the number of the video frame we are currently playing */
|
||||
int cpu_getcurrentframe(void);
|
||||
|
||||
|
||||
/* generate a trigger after a specific period of time */
|
||||
void cpu_triggertime (double duration, int trigger);
|
||||
/* generate a trigger now */
|
||||
void cpu_trigger (int trigger);
|
||||
|
||||
/* burn CPU cycles until a timer trigger */
|
||||
void cpu_spinuntil_trigger (int trigger);
|
||||
/* burn CPU cycles until the next interrupt */
|
||||
void cpu_spinuntil_int (void);
|
||||
/* burn CPU cycles until our timeslice is up */
|
||||
void cpu_spin (void);
|
||||
/* burn CPU cycles for a specific period of time */
|
||||
void cpu_spinuntil_time (double duration);
|
||||
|
||||
/* yield our timeslice for a specific period of time */
|
||||
void cpu_yielduntil_trigger (int trigger);
|
||||
/* yield our timeslice until the next interrupt */
|
||||
void cpu_yielduntil_int (void);
|
||||
/* yield our current timeslice */
|
||||
void cpu_yield (void);
|
||||
/* yield our timeslice for a specific period of time */
|
||||
void cpu_yielduntil_time (double duration);
|
||||
|
||||
/* set the NMI line state for a CPU, normally use PULSE_LINE */
|
||||
void cpu_set_nmi_line(int cpunum, int state);
|
||||
/* set the IRQ line state for a specific irq line of a CPU */
|
||||
/* normally use state HOLD_LINE, irqline 0 for first IRQ type of a cpu */
|
||||
void cpu_set_irq_line(int cpunum, int irqline, int state);
|
||||
/* this is to be called by CPU cores only! */
|
||||
void cpu_generate_internal_interrupt(int cpunum, int type);
|
||||
/* set the vector to be returned during a CPU's interrupt acknowledge cycle */
|
||||
void cpu_irq_line_vector_w(int cpunum, int irqline, int vector);
|
||||
|
||||
/* use these in your write memory/port handles to set an IRQ vector */
|
||||
/* offset corresponds to the irq line number here */
|
||||
void cpu_0_irq_line_vector_w(int offset, int data);
|
||||
void cpu_1_irq_line_vector_w(int offset, int data);
|
||||
void cpu_2_irq_line_vector_w(int offset, int data);
|
||||
void cpu_3_irq_line_vector_w(int offset, int data);
|
||||
void cpu_4_irq_line_vector_w(int offset, int data);
|
||||
void cpu_5_irq_line_vector_w(int offset, int data);
|
||||
void cpu_6_irq_line_vector_w(int offset, int data);
|
||||
void cpu_7_irq_line_vector_w(int offset, int data);
|
||||
|
||||
/* Obsolete functions: avoid to use them in new drivers if possible. */
|
||||
|
||||
/* cause an interrupt on a CPU */
|
||||
void cpu_cause_interrupt(int cpu,int type);
|
||||
void cpu_clear_pending_interrupts(int cpu);
|
||||
void interrupt_enable_w(int offset,int data);
|
||||
void interrupt_vector_w(int offset,int data);
|
||||
int interrupt(void);
|
||||
int nmi_interrupt(void);
|
||||
int m68_level1_irq(void);
|
||||
int m68_level2_irq(void);
|
||||
int m68_level3_irq(void);
|
||||
int m68_level4_irq(void);
|
||||
int m68_level5_irq(void);
|
||||
int m68_level6_irq(void);
|
||||
int m68_level7_irq(void);
|
||||
int ignore_interrupt(void);
|
||||
|
||||
/* CPU context access */
|
||||
void* cpu_getcontext (int _activecpu);
|
||||
int cpu_is_saving_context(int _activecpu);
|
||||
|
||||
/***************************************************************************
|
||||
* Get information for the currently active CPU
|
||||
* cputype is a value from the CPU enum in driver.h
|
||||
***************************************************************************/
|
||||
/* Return number of address bits */
|
||||
unsigned cpu_address_bits(void);
|
||||
/* Return address mask */
|
||||
unsigned cpu_address_mask(void);
|
||||
/* Return address shift factor (TMS34010 bit addressing mode) */
|
||||
int cpu_address_shift(void);
|
||||
/* Return endianess of the emulated CPU (CPU_IS_LE or CPU_IS_BE) */
|
||||
unsigned cpu_endianess(void);
|
||||
/* Return opcode align unit (1 byte, 2 word, 4 dword) */
|
||||
unsigned cpu_align_unit(void);
|
||||
/* Return maximum instruction length */
|
||||
unsigned cpu_max_inst_len(void);
|
||||
|
||||
/* Return name of the active CPU */
|
||||
const char *cpu_name(void);
|
||||
/* Return family name of the active CPU */
|
||||
const char *cpu_core_family(void);
|
||||
/* Return core version of the active CPU */
|
||||
const char *cpu_core_version(void);
|
||||
/* Return core filename of the active CPU */
|
||||
const char *cpu_core_file(void);
|
||||
/* Return credits info for of the active CPU */
|
||||
const char *cpu_core_credits(void);
|
||||
/* Return register layout definition for the active CPU */
|
||||
const char *cpu_reg_layout(void);
|
||||
/* Return (debugger) window layout definition for the active CPU */
|
||||
const char *cpu_win_layout(void);
|
||||
|
||||
/* Disassemble an instruction at PC into the given buffer */
|
||||
unsigned cpu_dasm(char *buffer, unsigned pc);
|
||||
/* Return a string describing the currently set flag (status) bits of the active CPU */
|
||||
const char *cpu_flags(void);
|
||||
/* Return a string with a register name and hex value for the active CPU */
|
||||
/* regnum is a value defined in the CPU cores header files */
|
||||
const char *cpu_dump_reg(int regnum);
|
||||
/* Return a string describing the active CPUs current state */
|
||||
const char *cpu_dump_state(void);
|
||||
|
||||
/***************************************************************************
|
||||
* Get information for a specific CPU type
|
||||
* cputype is a value from the CPU enum in driver.h
|
||||
***************************************************************************/
|
||||
/* Return address shift factor */
|
||||
/* TMS320C10 -1: word addressing mode, TMS34010 3: bit addressing mode */
|
||||
int cputype_address_shift(int cputype);
|
||||
/* Return number of address bits */
|
||||
unsigned cputype_address_bits(int cputype);
|
||||
/* Return address mask */
|
||||
unsigned cputype_address_mask(int cputype);
|
||||
/* Return endianess of the emulated CPU (CPU_IS_LE or CPU_IS_BE) */
|
||||
unsigned cputype_endianess(int cputype);
|
||||
/* Return opcode align unit (1 byte, 2 word, 4 dword) */
|
||||
unsigned cputype_align_unit(int cputype);
|
||||
/* Return maximum instruction length */
|
||||
unsigned cputype_max_inst_len(int cputype);
|
||||
|
||||
/* Return name of the CPU */
|
||||
const char *cputype_name(int cputype);
|
||||
/* Return family name of the CPU */
|
||||
const char *cputype_core_family(int cputype);
|
||||
/* Return core version number of the CPU */
|
||||
const char *cputype_core_version(int cputype);
|
||||
/* Return core filename of the CPU */
|
||||
const char *cputype_core_file(int cputype);
|
||||
/* Return credits for the CPU core */
|
||||
const char *cputype_core_credits(int cputype);
|
||||
/* Return register layout definition for the CPU core */
|
||||
const char *cputype_reg_layout(int cputype);
|
||||
/* Return (debugger) window layout definition for the CPU core */
|
||||
const char *cputype_win_layout(int cputype);
|
||||
|
||||
/***************************************************************************
|
||||
* Get (or set) information for a numbered CPU of the running machine
|
||||
* cpunum is a value between 0 and cpu_gettotalcpu() - 1
|
||||
***************************************************************************/
|
||||
/* Return number of address bits */
|
||||
unsigned cpunum_address_bits(int cputype);
|
||||
/* Return address mask */
|
||||
unsigned cpunum_address_mask(int cputype);
|
||||
/* Return endianess of the emulated CPU (CPU_LSB_FIRST or CPU_MSB_FIRST) */
|
||||
unsigned cpunum_endianess(int cputype);
|
||||
/* Return opcode align unit (1 byte, 2 word, 4 dword) */
|
||||
unsigned cpunum_align_unit(int cputype);
|
||||
/* Return maximum instruction length */
|
||||
unsigned cpunum_max_inst_len(int cputype);
|
||||
|
||||
/* Get a register value for the specified CPU number of the running machine */
|
||||
unsigned cpunum_get_reg(int cpunum, int regnum);
|
||||
/* Set a register value for the specified CPU number of the running machine */
|
||||
void cpunum_set_reg(int cpunum, int regnum, unsigned val);
|
||||
|
||||
/* Return (debugger) register layout definition for the CPU core */
|
||||
const char *cpunum_reg_layout(int cpunum);
|
||||
/* Return (debugger) window layout definition for the CPU core */
|
||||
const char *cpunum_win_layout(int cpunum);
|
||||
|
||||
unsigned cpunum_dasm(int cpunum,char *buffer,unsigned pc);
|
||||
/* Return a string describing the currently set flag (status) bits of the CPU */
|
||||
const char *cpunum_flags(int cpunum);
|
||||
/* Return a string with a register name and value */
|
||||
/* regnum is a value defined in the CPU cores header files */
|
||||
const char *cpunum_dump_reg(int cpunum, int regnum);
|
||||
/* Return a string describing the CPUs current state */
|
||||
const char *cpunum_dump_state(int cpunum);
|
||||
/* Return a name for the specified cpu number */
|
||||
const char *cpunum_name(int cpunum);
|
||||
/* Return a family name for the specified cpu number */
|
||||
const char *cpunum_core_family(int cpunum);
|
||||
/* Return a version for the specified cpu number */
|
||||
const char *cpunum_core_version(int cpunum);
|
||||
/* Return a the source filename for the specified cpu number */
|
||||
const char *cpunum_core_file(int cpunum);
|
||||
/* Return a the credits for the specified cpu number */
|
||||
const char *cpunum_core_credits(int cpunum);
|
||||
|
||||
/* Dump all of the running machines CPUs state to stderr */
|
||||
void cpu_dump_states(void);
|
||||
|
||||
/* daisy-chain link */
|
||||
typedef struct {
|
||||
void (*reset)(int); /* reset callback */
|
||||
int (*interrupt_entry)(int); /* entry callback */
|
||||
void (*interrupt_reti)(int); /* reti callback */
|
||||
int irq_param; /* callback paramater */
|
||||
} Z80_DaisyChain;
|
||||
|
||||
#define Z80_MAXDAISY 4 /* maximum of daisy chan device */
|
||||
|
||||
#define Z80_INT_REQ 0x01 /* interrupt request mask */
|
||||
#define Z80_INT_IEO 0x02 /* interrupt disable mask(IEO) */
|
||||
|
||||
#define Z80_VECTOR(device,state) (((device)<<8)|(state))
|
||||
|
||||
#endif /* CPUINTRF_H */
|
|
@ -0,0 +1,168 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "emuapi.h"
|
||||
#include "tft_t_dma.h"
|
||||
#include "iopins.h"
|
||||
|
||||
extern "C" {
|
||||
#include "shared.h"
|
||||
}
|
||||
|
||||
static int rom_offset = 0;
|
||||
|
||||
|
||||
EXTMEM static unsigned char MemPool[8*1024*1024];
|
||||
|
||||
extern "C" uint8 read_rom(int address) {
|
||||
return (MemPool[address+rom_offset]);
|
||||
}
|
||||
|
||||
extern "C" void write_rom(int address, uint8 val) {
|
||||
MemPool[address]=val;
|
||||
}
|
||||
|
||||
|
||||
static int ik; // joypad key
|
||||
static int ihk; // I2C keyboard key
|
||||
static int iusbhk; // USB keyboard key
|
||||
static int prevhk; // previous keyboard key
|
||||
|
||||
void emu_KeyboardOnDown(int keymodifer, int key) {
|
||||
int keyCode = -1; //INV_KEY;
|
||||
if ((key >=0xc0) && (key <=0xdf)) {
|
||||
keyCode = ((key-0xc0) & 0x1f) + 0x7f;
|
||||
}
|
||||
else {
|
||||
keyCode = key & 0x7f;
|
||||
}
|
||||
|
||||
//Serial.println(keyCode);
|
||||
|
||||
if (keyCode != -1) {
|
||||
iusbhk = keyCode;
|
||||
}
|
||||
}
|
||||
|
||||
void emu_KeyboardOnUp(int keymodifer, int key) {
|
||||
iusbhk = 0;
|
||||
}
|
||||
|
||||
|
||||
void sms_Init(void)
|
||||
{
|
||||
emu_printf("Allocating MEM");
|
||||
mem_init();
|
||||
emu_printf("Allocating MEM done");
|
||||
}
|
||||
|
||||
|
||||
void sms_Input(int click) {
|
||||
ik = emu_GetPad();
|
||||
ihk = emu_ReadI2CKeyboard();
|
||||
}
|
||||
|
||||
|
||||
void sms_Start(char * filename)
|
||||
{
|
||||
emu_printf("load and init");
|
||||
|
||||
int size = emu_FileSize(filename);
|
||||
int pos = 0;
|
||||
int n;
|
||||
int i;
|
||||
char * buf = (char*)cache;
|
||||
|
||||
int f = emu_FileOpen(filename, "r+b");
|
||||
if (f) {
|
||||
while ( (n = emu_FileRead(buf,CACHE_SIZE,f) ) ) {
|
||||
for (int i=0; i<n; i++) {
|
||||
write_rom(pos++,buf[i]);
|
||||
}
|
||||
emu_printi(pos);
|
||||
//emu_printi(n);
|
||||
}
|
||||
emu_FileClose(f);
|
||||
}
|
||||
|
||||
if((size / 512) & 1)
|
||||
{
|
||||
size -= 512;
|
||||
rom_offset += 512;
|
||||
}
|
||||
|
||||
cart.pages = (size / 0x4000);
|
||||
|
||||
int namelen = strlen(filename);
|
||||
emu_printf(&filename[namelen-4]);
|
||||
if (namelen > 4) {
|
||||
if ( (!strcmp(&filename[namelen-4],".sms")) || (!strcmp(&filename[namelen-4],".SMS")) ) {
|
||||
emu_printf("Master system");
|
||||
cart.type = TYPE_SMS;
|
||||
}
|
||||
else {
|
||||
emu_printf("Game Gear");
|
||||
cart.type = TYPE_GG;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAS_SND
|
||||
#ifdef SOUND_PRESENT
|
||||
system_init(22050);
|
||||
emu_sndInit();
|
||||
#else
|
||||
system_init(0);
|
||||
#endif
|
||||
#else
|
||||
system_init(0);
|
||||
#endif
|
||||
emu_printf("init done");
|
||||
}
|
||||
|
||||
void sms_Step(void)
|
||||
{
|
||||
input.pad[0]=0;
|
||||
|
||||
int k = ik;
|
||||
int hk = ihk;
|
||||
if (iusbhk) hk = iusbhk;
|
||||
|
||||
if (( k & MASK_JOY1_RIGHT) || ( k & MASK_JOY2_RIGHT)) {
|
||||
input.pad[0] |= INPUT_RIGHT;
|
||||
}
|
||||
if (( k & MASK_JOY1_LEFT) || ( k & MASK_JOY2_LEFT)) {
|
||||
input.pad[0] |= INPUT_LEFT;
|
||||
}
|
||||
if (( k & MASK_JOY1_UP) || ( k & MASK_JOY2_UP)) {
|
||||
input.pad[0] |= INPUT_UP;
|
||||
}
|
||||
if (( k & MASK_JOY1_DOWN) || ( k & MASK_JOY2_DOWN)) {
|
||||
input.pad[0] |= INPUT_DOWN;
|
||||
}
|
||||
if ( k & MASK_JOY2_BTN) {
|
||||
input.pad[0] |= INPUT_BUTTON1;
|
||||
}
|
||||
|
||||
if ( (k & MASK_KEY_USER1) || (hk == 'q') ) {
|
||||
input.pad[0] |= INPUT_BUTTON2;
|
||||
}
|
||||
|
||||
if ( (k & MASK_KEY_USER2) || (hk == 'w') ) input.system |= (IS_GG) ? INPUT_START : INPUT_PAUSE;
|
||||
if (hk == 'r') input.system |= INPUT_HARD_RESET;
|
||||
//if (hk == 'e') input.system |= (IS_GG) ? INPUT_HARD_RESET : INPUT_SOFT_RESET;
|
||||
|
||||
prevhk = hk;
|
||||
|
||||
sms_frame(0);
|
||||
//emu_printi(emu_FrameSkip());
|
||||
|
||||
emu_DrawVsync();
|
||||
}
|
||||
|
||||
void SND_Process(void *stream, int len) {
|
||||
#ifdef SOUND_PRESENT
|
||||
#ifdef HAS_SND
|
||||
audio_play_sample(stream, 0, len);
|
||||
#endif
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
extern void sms_Init(void);
|
||||
extern void sms_Step(void);
|
||||
extern void sms_Start(char * filename);
|
||||
extern void sms_Input(int click);
|
Plik diff jest za duży
Load Diff
|
@ -0,0 +1,214 @@
|
|||
#ifndef EMUAPI_H
|
||||
#define EMUAPI_H
|
||||
|
||||
#include "platform_config.h"
|
||||
|
||||
#define CUSTOM_SND 1
|
||||
//#define TIMER_REND 1
|
||||
|
||||
#define EXTRA_HEAP 0x10 //0x9000
|
||||
|
||||
// Title: < >
|
||||
#define TITLE " Master System Emulator "
|
||||
#define ROMSDIR "/sms"
|
||||
|
||||
#define emu_Init(ROM) {sms_Init(); sms_Start(ROM);}
|
||||
#define emu_Step(x) {sms_Step();}
|
||||
#define emu_Input(x) {sms_Input(x);}
|
||||
|
||||
#define MAX_FILENAME_PATH 64
|
||||
#define NB_FILE_HANDLER 4
|
||||
#define PALETTE_SIZE 32
|
||||
#define VID_FRAME_SKIP 0x0
|
||||
#define TFT_VBUFFER_YCROP 0
|
||||
#define SINGLELINE_RENDERING 1
|
||||
|
||||
#define R32(rgb) ((rgb>>16)&0xff)
|
||||
#define G32(rgb) ((rgb>>8)&0xff)
|
||||
#define B32(rgb) (rgb & 0xff)
|
||||
|
||||
#define ACTION_NONE 0
|
||||
#define ACTION_MAXKBDVAL 16
|
||||
#define ACTION_EXITKBD 128
|
||||
#define ACTION_RUN1 129
|
||||
#define ACTION_RUN2 130
|
||||
#define ACTION_RUN3 131
|
||||
|
||||
#ifdef KEYMAP_PRESENT
|
||||
|
||||
#define keylables_map0_0 (char *)"qwertyuiop\x1a"
|
||||
#define keylables_map0_1 (char *)" asdfghjkl\x19"
|
||||
#define keylables_map0_2 (char *)" zxcvbnm,.;/"
|
||||
#define keylables_map0_3 (char *)" +\x10-"
|
||||
const unsigned short key_map0[] = {
|
||||
'q','w','e','r','t','y','u','i','o','p',157, //lowecase
|
||||
0,'a','s','d','f','g','h','j','k','l',0x0D,
|
||||
0,'z','x','c','v','b','n','m',',','.',';','/',
|
||||
145,157,29,17,
|
||||
0,'+',' ','-'
|
||||
};
|
||||
|
||||
#define keylables_map1_0 (char *)"QWERTYUIOP@"
|
||||
#define keylables_map1_1 (char *)" ASDFGHJKL\x19"
|
||||
#define keylables_map1_2 (char *)" ZXCVBNM<>:?"
|
||||
#define keylables_map1_3 (char *)" =\x10_"
|
||||
const unsigned short key_map1[] = {
|
||||
'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase
|
||||
0,'A','S','D','F','G','H','J','K','L',0x0D,
|
||||
0,'Z','X','C','V','B','N','M','<','>',':','?',
|
||||
145,157,29,17,
|
||||
0,'=',' ','_'
|
||||
};
|
||||
|
||||
#define keylables_map2_0 (char *)"!\"#$%^&*()@"
|
||||
#define keylables_map2_1 (char *)" |\\[]{} "
|
||||
#define keylables_map2_2 (char *)" <>:?"
|
||||
#define keylables_map2_3 (char *)" =\x10_"
|
||||
const unsigned short key_map2[] = {
|
||||
'!','"','#','$','%','^','&','*','(',')','@', // shiftothers
|
||||
0, '|','\\','[',']','{','}','\'',0,0,0,
|
||||
0, 0,0,0,0,0,0,0,'<','>',':','?',
|
||||
0,0,0,0,
|
||||
0,'=',' ','_'
|
||||
};
|
||||
|
||||
#define keylables_map3_0 (char *)"1234567890 "
|
||||
#define keylables_map3_1 (char *)" "
|
||||
#define keylables_map3_2 (char *)" "
|
||||
#define keylables_map3_3 (char *)" "
|
||||
|
||||
const unsigned short key_map3[] = {
|
||||
'1','2','3','4','5','6','7','8','9','0',0, // digit keys
|
||||
0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,
|
||||
0,0,' ',0
|
||||
};
|
||||
|
||||
#define keylables_map4_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 "
|
||||
#define keylables_map4_1 (char *)" "
|
||||
#define keylables_map4_2 (char *)" "
|
||||
#define keylables_map4_3 (char *)" "
|
||||
|
||||
const unsigned short key_map4[] = {
|
||||
133,134,135,136,137,138,139,140,0,0,0, // function keys
|
||||
0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,
|
||||
0,0,' ',0
|
||||
};
|
||||
|
||||
#define keylables_map5_0 (char *)" "
|
||||
#define keylables_map5_1 (char *)" "
|
||||
#define keylables_map5_2 (char *)" "
|
||||
#define keylables_map5_3 (char *)" "
|
||||
|
||||
const unsigned short key_map5[] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0, // extra keys
|
||||
0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0, 0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,
|
||||
0,0,' ',0
|
||||
};
|
||||
|
||||
const unsigned short matkeys[] = {
|
||||
0x004,0x008,0x108,0x104,0x208,0x204,0x308,0x304,0x408,0x404,0x410, // row 1
|
||||
0x502,0x002,0x020,0x102,0x120,0x202,0x220,0x302,0x320,0x402,0x420, // row 2
|
||||
0x508,0x001,0x040,0x101,0x140,0x201,0x240,0x210,0x340,0x301,0x401,0x440, // row 3
|
||||
0x504,0x520,0x540,0x501, // UP LEFT RIGHT DOWN
|
||||
0x510,0x010,0x110,0x310, // row 4
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define MASK_JOY2_RIGHT 0x0001
|
||||
#define MASK_JOY2_LEFT 0x0002
|
||||
#define MASK_JOY2_UP 0x0004
|
||||
#define MASK_JOY2_DOWN 0x0008
|
||||
#define MASK_JOY2_BTN 0x0010
|
||||
#define MASK_KEY_USER1 0x0020
|
||||
#define MASK_KEY_USER2 0x0040
|
||||
#define MASK_KEY_USER3 0x0080
|
||||
#define MASK_JOY1_RIGHT 0x0100
|
||||
#define MASK_JOY1_LEFT 0x0200
|
||||
#define MASK_JOY1_UP 0x0400
|
||||
#define MASK_JOY1_DOWN 0x0800
|
||||
#define MASK_JOY1_BTN 0x1000
|
||||
#define MASK_KEY_USER4 0x2000
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void emu_init(void);
|
||||
extern void emu_start(void);
|
||||
extern void emu_printf(const char * text);
|
||||
extern void emu_printi(int val);
|
||||
extern void emu_printh(int val);
|
||||
extern void * emu_Malloc(unsigned int size);
|
||||
extern void * emu_MallocI(unsigned int size);
|
||||
extern void emu_Free(void * pt);
|
||||
|
||||
extern int emu_FileOpen(const char * filepath, const char * mode);
|
||||
extern int emu_FileRead(void * buf, int size, int handler);
|
||||
extern int emu_FileGetc(int handler);
|
||||
extern int emu_FileSeek(int handler, int seek, int origin);
|
||||
extern int emu_FileTell(int handler);
|
||||
extern void emu_FileClose(int handler);
|
||||
|
||||
extern unsigned int emu_FileSize(const char * filepath);
|
||||
extern unsigned int emu_LoadFile(const char * filepath, void * buf, int size);
|
||||
extern unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek);
|
||||
|
||||
extern void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index);
|
||||
extern void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride);
|
||||
extern void emu_DrawLine(unsigned char * VBuf, int width, int height, int line);
|
||||
extern void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line);
|
||||
extern void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line);
|
||||
extern void emu_CopyLine(int width, int height, int ysrc, int ydst);
|
||||
extern void emu_DrawVsync(void);
|
||||
extern int emu_FrameSkip(void);
|
||||
extern void * emu_LineBuffer(int line);
|
||||
extern void emu_tweakVideo(int shiftdelta, int numdelta, int denomdelta);
|
||||
|
||||
extern bool menuActive(void);
|
||||
extern char * menuSelection(void);
|
||||
extern char * menuSecondSelection(void);
|
||||
extern void toggleMenu(bool on);
|
||||
extern int handleMenu(unsigned short bClick);
|
||||
|
||||
extern int handleOSKB(void);
|
||||
extern void toggleOSKB(bool forceon);
|
||||
|
||||
extern void emu_InitJoysticks(void);
|
||||
extern int emu_SwapJoysticks(int statusOnly);
|
||||
extern unsigned short emu_DebounceLocalKeys(void);
|
||||
extern int emu_ReadKeys(void);
|
||||
extern int emu_GetPad(void);
|
||||
extern int emu_GetMouse(int *x, int *y, int *buts);
|
||||
extern int emu_MouseDetected(void);
|
||||
extern int emu_KeyboardDetected(void);
|
||||
extern int emu_ReadAnalogJoyX(int min, int max);
|
||||
extern int emu_ReadAnalogJoyY(int min, int max);
|
||||
extern int emu_ReadI2CKeyboard(void);
|
||||
extern unsigned char emu_ReadI2CKeyboard2(int row);
|
||||
extern void emu_KeyboardOnUp(int keymodifer, int key);
|
||||
extern void emu_KeyboardOnDown(int keymodifer, int key);
|
||||
extern void emu_MidiOnDataReceived(unsigned char data);
|
||||
|
||||
extern void emu_sndPlaySound(int chan, int volume, int freq);
|
||||
extern void emu_sndPlayBuzz(int size, int val);
|
||||
extern void emu_sndInit();
|
||||
extern void emu_resetus(void);
|
||||
extern int emu_us(void);
|
||||
|
||||
extern int emu_setKeymap(int index);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
Plik diff jest za duży
Load Diff
|
@ -0,0 +1,142 @@
|
|||
#ifndef __FMOPL_H_
|
||||
#define __FMOPL_H_
|
||||
|
||||
typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
|
||||
typedef void (*OPL_IRQHANDLER)(int param,int irq);
|
||||
typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
|
||||
typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data);
|
||||
typedef unsigned char (*OPL_PORTHANDLER_R)(int param);
|
||||
|
||||
/* !!!!! here is private section , do not access there member direct !!!!! */
|
||||
|
||||
#define OPL_TYPE_WAVESEL 0x01 /* waveform select */
|
||||
#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */
|
||||
#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */
|
||||
#define OPL_TYPE_IO 0x08 /* I/O port */
|
||||
|
||||
/* ---------- OPL one of slot ---------- */
|
||||
typedef struct fm_opl_slot {
|
||||
INT32 TL; /* total level :TL << 8 */
|
||||
INT32 TLL; /* adjusted now TL */
|
||||
UINT8 KSR; /* key scale rate :(shift down bit) */
|
||||
INT32 *AR; /* attack rate :&AR_TABLE[AR<<2] */
|
||||
INT32 *DR; /* decay rate :&DR_TALBE[DR<<2] */
|
||||
INT32 SL; /* sustin level :SL_TALBE[SL] */
|
||||
INT32 *RR; /* release rate :&DR_TABLE[RR<<2] */
|
||||
UINT8 ksl; /* keyscale level :(shift down bits) */
|
||||
UINT8 ksr; /* key scale rate :kcode>>KSR */
|
||||
UINT32 mul; /* multiple :ML_TABLE[ML] */
|
||||
UINT32 Cnt; /* frequency count : */
|
||||
UINT32 Incr; /* frequency step : */
|
||||
/* envelope generator state */
|
||||
UINT8 eg_typ; /* envelope type flag */
|
||||
UINT8 evm; /* envelope phase */
|
||||
INT32 evc; /* envelope counter */
|
||||
INT32 eve; /* envelope counter end point */
|
||||
INT32 evs; /* envelope counter step */
|
||||
INT32 evsa; /* envelope step for AR :AR[ksr] */
|
||||
INT32 evsd; /* envelope step for DR :DR[ksr] */
|
||||
INT32 evsr; /* envelope step for RR :RR[ksr] */
|
||||
/* LFO */
|
||||
UINT8 ams; /* ams flag */
|
||||
UINT8 vib; /* vibrate flag */
|
||||
/* wave selector */
|
||||
INT32 **wavetable;
|
||||
}OPL_SLOT;
|
||||
|
||||
/* ---------- OPL one of channel ---------- */
|
||||
typedef struct fm_opl_channel {
|
||||
OPL_SLOT SLOT[2];
|
||||
UINT8 CON; /* connection type */
|
||||
UINT8 FB; /* feed back :(shift down bit) */
|
||||
INT32 *connect1; /* slot1 output pointer */
|
||||
INT32 *connect2; /* slot2 output pointer */
|
||||
INT32 op1_out[2]; /* slot1 output for selfeedback */
|
||||
/* phase generator state */
|
||||
UINT32 block_fnum; /* block+fnum : */
|
||||
UINT8 kcode; /* key code : KeyScaleCode */
|
||||
UINT32 fc; /* Freq. Increment base */
|
||||
UINT32 ksl_base; /* KeyScaleLevel Base step */
|
||||
UINT8 keyon; /* key on/off flag */
|
||||
} OPL_CH;
|
||||
|
||||
/* OPL state */
|
||||
typedef struct fm_opl_f {
|
||||
UINT8 type; /* chip type */
|
||||
int clock; /* master clock (Hz) */
|
||||
int rate; /* sampling rate (Hz) */
|
||||
double freqbase; /* frequency base */
|
||||
double TimerBase; /* Timer base time (==sampling time) */
|
||||
UINT8 address; /* address register */
|
||||
UINT8 status; /* status flag */
|
||||
UINT8 statusmask; /* status mask */
|
||||
UINT32 mode; /* Reg.08 : CSM , notesel,etc. */
|
||||
/* Timer */
|
||||
int T[2]; /* timer counter */
|
||||
UINT8 st[2]; /* timer enable */
|
||||
/* FM channel slots */
|
||||
OPL_CH *P_CH; /* pointer of CH */
|
||||
int max_ch; /* maximum channel */
|
||||
/* Rythm sention */
|
||||
UINT8 rythm; /* Rythm mode , key flag */
|
||||
#if BUILD_Y8950
|
||||
/* Delta-T ADPCM unit (Y8950) */
|
||||
YM_DELTAT *deltat; /* DELTA-T ADPCM */
|
||||
#endif
|
||||
/* Keyboard / I/O interface unit (Y8950) */
|
||||
UINT8 portDirection;
|
||||
UINT8 portLatch;
|
||||
OPL_PORTHANDLER_R porthandler_r;
|
||||
OPL_PORTHANDLER_W porthandler_w;
|
||||
int port_param;
|
||||
OPL_PORTHANDLER_R keyboardhandler_r;
|
||||
OPL_PORTHANDLER_W keyboardhandler_w;
|
||||
int keyboard_param;
|
||||
/* time tables */
|
||||
INT32 AR_TABLE[75]; /* atttack rate tables */
|
||||
INT32 DR_TABLE[75]; /* decay rate tables */
|
||||
UINT32 FN_TABLE[1024]; /* fnumber -> increment counter */
|
||||
/* LFO */
|
||||
INT32 *ams_table;
|
||||
INT32 *vib_table;
|
||||
INT32 amsCnt;
|
||||
INT32 amsIncr;
|
||||
INT32 vibCnt;
|
||||
INT32 vibIncr;
|
||||
/* wave selector enable flag */
|
||||
UINT8 wavesel;
|
||||
/* external event callback handler */
|
||||
OPL_TIMERHANDLER TimerHandler; /* TIMER handler */
|
||||
int TimerParam; /* TIMER parameter */
|
||||
OPL_IRQHANDLER IRQHandler; /* IRQ handler */
|
||||
int IRQParam; /* IRQ parameter */
|
||||
OPL_UPDATEHANDLER UpdateHandler; /* stream update handler */
|
||||
int UpdateParam; /* stream update parameter */
|
||||
} FM_OPL;
|
||||
|
||||
/* ---------- Generic interface section ---------- */
|
||||
#define OPL_TYPE_YM3526 (0)
|
||||
#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL)
|
||||
#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO)
|
||||
|
||||
FM_OPL *OPLCreate(int type, int clock, int rate);
|
||||
void OPLDestroy(FM_OPL *OPL);
|
||||
void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset);
|
||||
void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param);
|
||||
void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param);
|
||||
/* Y8950 port handlers */
|
||||
void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param);
|
||||
void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param);
|
||||
|
||||
void OPLResetChip(FM_OPL *OPL);
|
||||
int OPLWrite(FM_OPL *OPL,int a,int v);
|
||||
void OPLWriteReg(FM_OPL *OPL, int r, int v);
|
||||
unsigned char OPLRead(FM_OPL *OPL,int a);
|
||||
int OPLTimerOver(FM_OPL *OPL,int c);
|
||||
|
||||
/* YM3626/YM3812 local section */
|
||||
void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
|
||||
|
||||
void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,148 @@
|
|||
|
||||
// Font: c64_lower.64c
|
||||
|
||||
PROGMEM const unsigned char font8x8[128][8] =
|
||||
{
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0000 (nul)
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0001
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0002
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0003
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0004
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0005
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0006
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0007
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0008
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0009
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000A
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000B
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000C
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000D
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000E
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000F
|
||||
|
||||
{ 0x7f, 0x41, 0x41, 0x41, 0x41, 0x41, 0x7f, 0x00 }, // Space // 0x10
|
||||
{ 0x00, 0x27, 0x31, 0x27, 0x21, 0x71, 0x00, 0x00 }, // F1 // 0x11
|
||||
{ 0x00, 0x77, 0x41, 0x77, 0x11, 0x71, 0x00, 0x00 }, // F2
|
||||
{ 0x00, 0x77, 0x41, 0x77, 0x41, 0x71, 0x00, 0x00 }, // F3
|
||||
{ 0x00, 0x17, 0x51, 0x77, 0x41, 0x41, 0x00, 0x00 }, // F4
|
||||
{ 0x00, 0x77, 0x11, 0x77, 0x41, 0x71, 0x00, 0x00 }, // F5
|
||||
{ 0x00, 0x77, 0x11, 0x77, 0x51, 0x71, 0x00, 0x00 }, // F6
|
||||
{ 0x00, 0x77, 0x41, 0x47, 0x41, 0x41, 0x00, 0x00 }, // F7
|
||||
{ 0x00, 0x77, 0x51, 0x77, 0x51, 0x71, 0x00, 0x00 }, // F8 // 0x18
|
||||
{ 0x00, 0x00, 0x20, 0x24, 0x3e, 0x04, 0x00, 0x00 }, // Return // 0x19
|
||||
{ 0x00, 0x59, 0x4b, 0x5b, 0x4b, 0xd9, 0x00, 0x00 }, // Del // 0x1A
|
||||
//{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0010
|
||||
//{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0011
|
||||
//{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0012
|
||||
//{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0013
|
||||
//{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0014
|
||||
//{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0015
|
||||
//{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0016
|
||||
//{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0017
|
||||
//{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0018
|
||||
//{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0019
|
||||
//{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001A
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001B
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001C
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001D
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001E
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001F
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 (space)
|
||||
{ 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // U+0021 (!)
|
||||
{ 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0022 (")
|
||||
{ 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // U+0023 (#)
|
||||
{ 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // U+0024 ($)
|
||||
{ 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // U+0025 (%)
|
||||
{ 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // U+0026 (&)
|
||||
{ 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0027 (')
|
||||
{ 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // U+0028 (()
|
||||
{ 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // U+0029 ())
|
||||
{ 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // U+002A (*)
|
||||
{ 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // U+002B (+)
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+002C (,)
|
||||
{ 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // U+002D (-)
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+002E (.)
|
||||
{ 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // U+002F (/)
|
||||
{ 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // U+0030 (0)
|
||||
{ 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // U+0031 (1)
|
||||
{ 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // U+0032 (2)
|
||||
{ 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // U+0033 (3)
|
||||
{ 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // U+0034 (4)
|
||||
{ 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // U+0035 (5)
|
||||
{ 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // U+0036 (6)
|
||||
{ 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // U+0037 (7)
|
||||
{ 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+0038 (8)
|
||||
{ 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // U+0039 (9)
|
||||
{ 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+003A (:)
|
||||
{ 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+003B (//)
|
||||
{ 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // U+003C (<)
|
||||
{ 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00}, // U+003D (=)
|
||||
{ 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // U+003E (>)
|
||||
{ 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // U+003F (?)
|
||||
{ 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // U+0040 (@)
|
||||
{ 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // U+0041 (A)
|
||||
{ 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // U+0042 (B)
|
||||
{ 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // U+0043 (C)
|
||||
{ 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // U+0044 (D)
|
||||
{ 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // U+0045 (E)
|
||||
{ 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // U+0046 (F)
|
||||
{ 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // U+0047 (G)
|
||||
{ 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // U+0048 (H)
|
||||
{ 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0049 (I)
|
||||
{ 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // U+004A (J)
|
||||
{ 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // U+004B (K)
|
||||
{ 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // U+004C (L)
|
||||
{ 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // U+004D (M)
|
||||
{ 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // U+004E (N)
|
||||
{ 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // U+004F (O)
|
||||
{ 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // U+0050 (P)
|
||||
{ 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // U+0051 (Q)
|
||||
{ 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // U+0052 (R)
|
||||
{ 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // U+0053 (S)
|
||||
{ 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0054 (T)
|
||||
{ 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U+0055 (U)
|
||||
{ 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0056 (V)
|
||||
{ 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // U+0057 (W)
|
||||
{ 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // U+0058 (X)
|
||||
{ 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+0059 (Y)
|
||||
{ 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // U+005A (Z)
|
||||
{ 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // U+005B ([)
|
||||
{ 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // U+005C (\)
|
||||
{ 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // U+005D (])
|
||||
{ 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // U+005E (^)
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // U+005F (_)
|
||||
{ 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0060 (`)
|
||||
{ 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // U+0061 (a)
|
||||
{ 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00}, // U+0062 (b)
|
||||
{ 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // U+0063 (c)
|
||||
{ 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00}, // U+0064 (d)
|
||||
{ 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00}, // U+0065 (e)
|
||||
{ 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00}, // U+0066 (f)
|
||||
{ 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0067 (g)
|
||||
{ 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // U+0068 (h)
|
||||
{ 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0069 (i)
|
||||
{ 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // U+006A (j)
|
||||
{ 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // U+006B (k)
|
||||
{ 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+006C (l)
|
||||
{ 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // U+006D (m)
|
||||
{ 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // U+006E (n)
|
||||
{ 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+006F (o)
|
||||
{ 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+0070 (p)
|
||||
{ 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // U+0071 (q)
|
||||
{ 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00}, // U+0072 (r)
|
||||
{ 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // U+0073 (s)
|
||||
{ 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // U+0074 (t)
|
||||
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // U+0075 (u)
|
||||
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0076 (v)
|
||||
{ 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00}, // U+0077 (w)
|
||||
{ 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // U+0078 (x)
|
||||
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0079 (y)
|
||||
{ 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // U+007A (z)
|
||||
{ 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00}, // U+007B ({)
|
||||
{ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+007C (|)
|
||||
{ 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00}, // U+007D (})
|
||||
{ 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007E (~)
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // U+007F
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
#ifndef IOPINS_H
|
||||
#define IOPINS_H
|
||||
|
||||
#include "platform_config.h"
|
||||
|
||||
#ifdef TEECOMPUTER
|
||||
|
||||
// Teecomputer layout
|
||||
|
||||
// VGA
|
||||
// R 3 2K
|
||||
// R 4 1K
|
||||
// R 33 500
|
||||
// G 11 2K
|
||||
// G 13 1K
|
||||
// G 2 500
|
||||
// B 10 820
|
||||
// B 12 390
|
||||
// HSYNC 15 82
|
||||
// VSYNC 8 82
|
||||
|
||||
// Display
|
||||
#define TFT_SCLK 27
|
||||
#define TFT_MOSI 26
|
||||
#define TFT_MISO 255
|
||||
#define TFT_TOUCH_CS 255
|
||||
#define TFT_TOUCH_INT 255
|
||||
#define TFT_DC 23
|
||||
#define TFT_CS 22 // 255 for LORES ST7789 (NO CS)
|
||||
#define TFT_RST 255 // 255 for ILI/ST if connected to 3.3V or 24 if really needed
|
||||
|
||||
|
||||
// SD
|
||||
#define SD_CS BUILTIN_SDCARD
|
||||
|
||||
// Audio
|
||||
#define AUDIO_I2S_DIN 7
|
||||
#define AUDIO_I2S_BCK 21
|
||||
#define AUDIO_I2S_LCK 20
|
||||
|
||||
// Keyboard matrix
|
||||
#define KLED 14
|
||||
//Cols (out)
|
||||
//pico 1,2,3,4,5,14
|
||||
//teen 16,6,24,25,28,31
|
||||
#define KCOLOUT1 16
|
||||
#define KCOLOUT2 6
|
||||
#define KCOLOUT3 24
|
||||
#define KCOLOUT4 25
|
||||
#define KCOLOUT5 28
|
||||
#define KCOLOUT6 31
|
||||
//Rows (in)
|
||||
//pico 9,8,6,15,7,22
|
||||
//teen 19,18,17,5,29,30,32 //5,6,16,17,18,19
|
||||
#define KROWIN1 19
|
||||
#define KROWIN2 18
|
||||
#define KROWIN3 17
|
||||
#define KROWIN4 5
|
||||
#define KROWIN5 29
|
||||
#define KROWIN6 30
|
||||
#define KROWIN7 32
|
||||
|
||||
#define PIN_KEY_USER1 41
|
||||
#define PIN_KEY_USER2 40
|
||||
|
||||
// Second joystick (external)
|
||||
#define PIN_JOY1_BTN 34
|
||||
#define PIN_JOY1_1 35 // UP
|
||||
#define PIN_JOY1_2 36 // DOWN
|
||||
#define PIN_JOY1_3 38 // RIGHT
|
||||
#define PIN_JOY1_4 37 // LEFT
|
||||
|
||||
#else
|
||||
|
||||
// Original Layout
|
||||
#define TFT_SCLK 13
|
||||
#define TFT_MOSI 11
|
||||
#define TFT_MISO 12
|
||||
#define TFT_TOUCH_CS 255
|
||||
#define TFT_TOUCH_INT 255
|
||||
#define TFT_DC 9
|
||||
#define TFT_CS 22 // 255 for LORES ST7789 (NO CS)
|
||||
#define TFT_RST 23 // 255 for ILI/ST if connected to 3.3V
|
||||
|
||||
// SD
|
||||
#define SD_CS BUILTIN_SDCARD
|
||||
|
||||
// I2C keyboard
|
||||
#define I2C_SCL_IO 19
|
||||
#define I2C_SDA_IO 18
|
||||
|
||||
// Analog joystick (primary) for JOY2 and 5 extra buttons
|
||||
#ifdef HAS_T4_VGA
|
||||
#define PIN_JOY2_A1X A3
|
||||
#define PIN_JOY2_A2Y A2
|
||||
#define PIN_JOY2_BTN 14
|
||||
#define PIN_KEY_USER1 22
|
||||
#define PIN_KEY_USER2 23
|
||||
|
||||
// Second joystick
|
||||
#define PIN_JOY1_BTN 34
|
||||
#define PIN_JOY1_1 35 // UP
|
||||
#define PIN_JOY1_2 36 // DOWN
|
||||
#define PIN_JOY1_3 38 // RIGHT
|
||||
#define PIN_JOY1_4 37 // LEFT
|
||||
|
||||
#else
|
||||
#define PIN_JOY2_A1X A1
|
||||
#define PIN_JOY2_A2Y A2
|
||||
#define PIN_JOY2_BTN 17
|
||||
#define PIN_KEY_USER1 3 //34
|
||||
#define PIN_KEY_USER2 4 //35
|
||||
|
||||
// Second joystick
|
||||
#define PIN_JOY1_BTN 2
|
||||
#define PIN_JOY1_1 14 // UP
|
||||
#define PIN_JOY1_2 7 // DOWN
|
||||
#define PIN_JOY1_3 6 // RIGHT
|
||||
#define PIN_JOY1_4 5 // LEFT
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,25 @@
|
|||
#include "shared.h"
|
||||
|
||||
|
||||
uint8 * cache;
|
||||
|
||||
|
||||
|
||||
void mem_init(void) {
|
||||
cache = emu_Malloc(CACHE_SIZE);
|
||||
}
|
||||
|
||||
|
||||
int mem_test(void) {
|
||||
// for (int i=0x40000;i<OBJ_CACHE_SIZE;i++) {
|
||||
// if (obj_pattern_cache[i] != 0) return 0;;
|
||||
// }
|
||||
return 1;
|
||||
}
|
||||
|
||||
void memcpy_rom(int dst, int src, int size) {
|
||||
while (size > 0) {
|
||||
write_rom(dst++, read_rom(src++));
|
||||
size--;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef _MEMORY_H_
|
||||
#define _MEMORY_H_
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
#define CACHE_SIZE 0x20000
|
||||
|
||||
|
||||
extern uint8 * cache;
|
||||
|
||||
|
||||
extern void mem_init(void);
|
||||
extern int mem_test(void);
|
||||
extern uint8 rom_version(void);
|
||||
extern uint8 readb_rom(int address);
|
||||
extern uint8 readb_swap_rom(int address);
|
||||
extern uint16 readw_swap_rom(int address);
|
||||
extern void write_rom(int address, uint8 val);
|
||||
|
||||
extern void memcpy_rom(int dst, int src, int size);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef _PLATFORM_CONFIG_H_
|
||||
#define _PLATFORM_CONFIG_H_
|
||||
|
||||
#define TEECOMPUTER 1
|
||||
|
||||
#ifdef TEECOMPUTER
|
||||
//#define ILI9341 1
|
||||
//#define ST7789 1
|
||||
//#define TFTSPI1 1
|
||||
#define HAS_T4_VGA 1
|
||||
#define HAS_SND 1
|
||||
#define HAS_USBKEY 1
|
||||
//#define INVX 1
|
||||
#else
|
||||
|
||||
#define HAS_T4_VGA 1
|
||||
//#define INVX 1
|
||||
#define INVY 1
|
||||
#define HAS_SND 1
|
||||
#define HAS_USBKEY 1
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//#define ILI9341 1
|
||||
//#define ST7789 1
|
||||
//#define SWAP_JOYSTICK 1
|
||||
//#define LOHRES 1
|
||||
//#define ROTATE_SCREEN 1
|
||||
//#define EXTERNAL_SD 1
|
||||
|
||||
|
||||
//#define USE_SDFAT 1
|
||||
//#define SD_FAT_TYPE 1
|
||||
//#define USE_SDFS 1
|
||||
//#define SDFSDEV "1:"
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,510 @@
|
|||
#include "shared.h"
|
||||
|
||||
/* Background drawing function */
|
||||
static void (*render_bg)(int line);
|
||||
|
||||
/* Pointer to output buffer */
|
||||
static byte *linebuf;
|
||||
|
||||
/* Internal buffer for drawing non 8-bit displays */
|
||||
static byte internal_buffer[0x100];
|
||||
|
||||
/* Pattern cache */
|
||||
//static byte cache[0x20000];
|
||||
|
||||
/* Dirty pattern info */
|
||||
byte svram_dirty[0x200];
|
||||
byte sis_vram_dirty;
|
||||
|
||||
/* Pixel look-up table */
|
||||
//#include "genlut.h"
|
||||
#include "smslut.h"
|
||||
//static byte lut[0x10000];
|
||||
|
||||
|
||||
/* Attribute expansion table */
|
||||
static UINT32 atex[4] =
|
||||
{
|
||||
0x00000000,
|
||||
0x10101010,
|
||||
0x20202020,
|
||||
0x30303030,
|
||||
};
|
||||
|
||||
/* Display sizes */
|
||||
static int vp_vstart;
|
||||
static int vp_vend;
|
||||
static int vp_hstart;
|
||||
static int vp_hend;
|
||||
|
||||
extern void emu_DrawLine(unsigned short *src, int width , int height, int line);
|
||||
extern void emu_printf(char * text);
|
||||
|
||||
/* 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 ( *((byte *)address) +
|
||||
(*((byte *)address+1) << 8) +
|
||||
(*((byte *)address+2) << 16) +
|
||||
(*((byte *)address+3) << 24) );
|
||||
#else /* big endian version */
|
||||
return ( *((byte *)address+3) +
|
||||
(*((byte *)address+2) << 8) +
|
||||
(*((byte *)address+1) << 16) +
|
||||
(*((byte *)address) << 24) );
|
||||
#endif
|
||||
}
|
||||
else
|
||||
return *(UINT32 *)address;
|
||||
}
|
||||
|
||||
|
||||
static __inline__ void write_dword(void *address, UINT32 data)
|
||||
{
|
||||
if ((UINT32)address & 3)
|
||||
{
|
||||
#ifdef LSB_FIRST
|
||||
*((byte *)address) = data;
|
||||
*((byte *)address+1) = (data >> 8);
|
||||
*((byte *)address+2) = (data >> 16);
|
||||
*((byte *)address+3) = (data >> 24);
|
||||
#else
|
||||
*((byte *)address+3) = data;
|
||||
*((byte *)address+2) = (data >> 8);
|
||||
*((byte *)address+1) = (data >> 16);
|
||||
*((byte *)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
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
|
||||
/* Initialize the rendering data */
|
||||
void render_init(void)
|
||||
{
|
||||
render_reset();
|
||||
}
|
||||
|
||||
|
||||
/* Reset the rendering data */
|
||||
void render_reset(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Clear display bitmap */
|
||||
// memset(sbitmap.data, 0, sbitmap.pitch * sbitmap.height);
|
||||
|
||||
/* Clear palette */
|
||||
for(i = 0; i < PALETTE_SIZE; i += 1)
|
||||
{
|
||||
palette_sync(i);
|
||||
}
|
||||
|
||||
/* Invalidate pattern cache */
|
||||
sis_vram_dirty = 1;
|
||||
memset(svram_dirty, 1, 0x200);
|
||||
memset(cache, 0, CACHE_SIZE);
|
||||
|
||||
/* Set up viewport size */
|
||||
if(IS_GG)
|
||||
{
|
||||
vp_vstart = 24;
|
||||
vp_vend = 168;
|
||||
vp_hstart = 6;
|
||||
vp_hend = 26;
|
||||
}
|
||||
else
|
||||
{
|
||||
vp_vstart = 0;
|
||||
vp_vend = 192;
|
||||
vp_hstart = 0;
|
||||
vp_hend = 32;
|
||||
}
|
||||
|
||||
/* Pick render routine */
|
||||
render_bg = IS_GG ? render_bg_gg : render_bg_sms;
|
||||
}
|
||||
|
||||
|
||||
/* Draw a line of the display */
|
||||
void render_line(int line)
|
||||
{
|
||||
/* Ensure we're within the viewport range */
|
||||
if((line < vp_vstart) || (line >= vp_vend)) return;
|
||||
|
||||
/* Point to current line in output buffer */
|
||||
linebuf = &internal_buffer[0];
|
||||
|
||||
/* Update pattern cache */
|
||||
update_cache();
|
||||
|
||||
/* Blank line */
|
||||
if( (!(vdp.reg[1] & 0x40)) || (((vdp.reg[2] & 1) == 0) && (IS_SMS)))
|
||||
{
|
||||
memset(linebuf + (vp_hstart << 3), BACKDROP_COLOR, BMP_WIDTH);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Draw background */
|
||||
render_bg(line);
|
||||
|
||||
/* Draw sprites */
|
||||
render_obj(line);
|
||||
|
||||
/* Blank leftmost column of display */
|
||||
if(vdp.reg[0] & 0x20)
|
||||
{
|
||||
memset(linebuf, BACKDROP_COLOR, 8);
|
||||
}
|
||||
}
|
||||
for (int i=0; i<BMP_WIDTH ;i++)
|
||||
internal_buffer[i] &= 0x1F;
|
||||
emu_DrawLine(&internal_buffer[BMP_X_OFFSET], BMP_WIDTH , BMP_HEIGHT, line);
|
||||
}
|
||||
|
||||
|
||||
/* Draw the Master System background */
|
||||
void render_bg_sms(int line)
|
||||
{
|
||||
int locked = 0;
|
||||
int v_line = (line + vdp.reg[9]) % 224;
|
||||
int v_row = (v_line & 7) << 3;
|
||||
int hscroll = ((vdp.reg[0] & 0x40) && (line < 0x10)) ? 0 : (0x100 - vdp.reg[8]);
|
||||
int column = vp_hstart;
|
||||
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, c, a;
|
||||
|
||||
attr = nt[(column + nt_scroll) & 0x1F];
|
||||
|
||||
#ifndef LSB_FIRST
|
||||
attr = (((attr & 0xFF) << 8) | ((attr & 0xFF00) >> 8));
|
||||
#endif
|
||||
a = (attr >> 7) & 0x30;
|
||||
|
||||
for(x = shift; x < 8; x += 1)
|
||||
{
|
||||
c = cache[((attr & 0x7FF) << 6) | (v_row) | (x)];
|
||||
linebuf[(0 - shift) + (x) ] = ((c) | (a));
|
||||
}
|
||||
|
||||
column += 1;
|
||||
}
|
||||
|
||||
/* Draw a line of the background */
|
||||
for(; column < vp_hend; column += 1)
|
||||
{
|
||||
/* 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 *)&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;
|
||||
|
||||
char *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 += 1)
|
||||
{
|
||||
c = cache[((attr & 0x7FF) << 6) | (v_row) | (x)];
|
||||
p[x] = ((c) | (a));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Draw the Game Gear background */
|
||||
void render_bg_gg(int line)
|
||||
{
|
||||
int v_line = (line + vdp.reg[9]) % 224;
|
||||
int v_row = (v_line & 7) << 3;
|
||||
int hscroll = (0x100 - vdp.reg[8]);
|
||||
int column;
|
||||
UINT16 attr;
|
||||
UINT16 *nt = (UINT16 *)&vdp.vram[vdp.ntab + ((v_line >> 3) << 6)];
|
||||
int nt_scroll = (hscroll >> 3);
|
||||
UINT32 atex_mask;
|
||||
UINT32 *cache_ptr;
|
||||
UINT32 *linebuf_ptr = (UINT32 *)&linebuf[0 - (hscroll & 7)];
|
||||
|
||||
/* Draw a line of the background */
|
||||
for(column = vp_hstart; column <= vp_hend; column += 1)
|
||||
{
|
||||
/* 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 *)&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 sprites */
|
||||
void render_obj(int line)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* 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 */
|
||||
byte *st = (byte *)&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 += 1)
|
||||
{
|
||||
/* Sprite Y position */
|
||||
int yp = st[i];
|
||||
|
||||
/* End of sprite list marker? */
|
||||
if(yp == 208) return;
|
||||
|
||||
/* Actual Y position is +1 */
|
||||
yp += 1;
|
||||
|
||||
/* Wrap Y coordinate for sprites > 240 */
|
||||
if(yp > 240) yp -= 256;
|
||||
|
||||
/* Check if sprite falls on current line */
|
||||
if((line >= yp) && (line < (yp + height)))
|
||||
{
|
||||
byte *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 += 1;
|
||||
|
||||
/* Too many sprites on this line ? */
|
||||
if((vdp.limit) && (count == 9)) return;
|
||||
|
||||
/* 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 = (byte *)&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;
|
||||
byte *cache_ptr = (byte *)&cache[(n << 6) | (((line - yp) >> 1) << 3)];
|
||||
|
||||
/* Draw sprite line */
|
||||
for(x = start; x < end; x += 1)
|
||||
{
|
||||
/* Source pixel from cache */
|
||||
byte sp = cache_ptr[(x >> 1)];
|
||||
|
||||
/* Only draw opaque sprite pixels */
|
||||
if(sp)
|
||||
{
|
||||
/* Background pixel from line buffer */
|
||||
byte bg = linebuf_ptr[x];
|
||||
|
||||
/* Look up result */
|
||||
linebuf_ptr[x] = lut[(bg << 8) | (sp)]; /* + COL_OFFSET; */
|
||||
|
||||
/* Set sprite collision flag */
|
||||
if(bg & 0x40) vdp.status |= 0x20;
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* Regular size sprite (8x8 / 8x16) */
|
||||
{
|
||||
int x;
|
||||
byte *cache_ptr = (byte *)&cache[(n << 6) | ((line - yp) << 3)];
|
||||
|
||||
/* Draw sprite line */
|
||||
for(x = start; x < end; x += 1)
|
||||
{
|
||||
/* Source pixel from cache */
|
||||
byte sp = cache_ptr[x];
|
||||
|
||||
/* Only draw opaque sprite pixels */
|
||||
if(sp)
|
||||
{
|
||||
/* Background pixel from line buffer */
|
||||
byte bg = linebuf_ptr[x];
|
||||
|
||||
/* Look up result */
|
||||
linebuf_ptr[x] = lut[(bg << 8) | (sp)]; /* + COL_OFFSET; */
|
||||
|
||||
/* Set sprite collision flag */
|
||||
if(bg & 0x40) vdp.status |= 0x20;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Update pattern cache with modified tiles */
|
||||
void update_cache(void)
|
||||
{
|
||||
int i, x, y, c;
|
||||
int b0, b1, b2, b3;
|
||||
int i0, i1, i2, i3;
|
||||
|
||||
if(!sis_vram_dirty) return;
|
||||
sis_vram_dirty = 0;
|
||||
|
||||
for(i = 0; i < 0x200; i += 1)
|
||||
{
|
||||
if(svram_dirty[i])
|
||||
{
|
||||
svram_dirty[i] = 0;
|
||||
|
||||
for(y = 0; y < 8; y += 1)
|
||||
{
|
||||
b0 = vdp.vram[(i << 5) | (y << 2) | (0)];
|
||||
b1 = vdp.vram[(i << 5) | (y << 2) | (1)];
|
||||
b2 = vdp.vram[(i << 5) | (y << 2) | (2)];
|
||||
b3 = vdp.vram[(i << 5) | (y << 2) | (3)];
|
||||
|
||||
for(x = 0; x < 8; x += 1)
|
||||
{
|
||||
i0 = (b0 >> (7 - x)) & 1;
|
||||
i1 = (b1 >> (7 - x)) & 1;
|
||||
i2 = (b2 >> (7 - x)) & 1;
|
||||
i3 = (b3 >> (7 - x)) & 1;
|
||||
|
||||
c = (i3 << 3 | i2 << 2 | i1 << 1 | i0);
|
||||
|
||||
cache[0x00000 | (i << 6) | ((y ) << 3) | (x )] = c;
|
||||
cache[0x08000 | (i << 6) | ((y ) << 3) | (7-x)] = c;
|
||||
cache[0x10000 | (i << 6) | ((7-y) << 3) | (x )] = c;
|
||||
cache[0x18000 | (i << 6) | ((7-y) << 3) | (7-x)] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Update a palette entry */
|
||||
void palette_sync(int index)
|
||||
{
|
||||
int r, g, b;
|
||||
|
||||
if(IS_GG)
|
||||
{
|
||||
r = ((vdp.cram[(index << 1) | 0] >> 1) & 7) << 5;
|
||||
g = ((vdp.cram[(index << 1) | 0] >> 5) & 7) << 5;
|
||||
b = ((vdp.cram[(index << 1) | 1] >> 1) & 7) << 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = ((vdp.cram[index] >> 0) & 3) << 6;
|
||||
g = ((vdp.cram[index] >> 2) & 3) << 6;
|
||||
b = ((vdp.cram[index] >> 4) & 3) << 6;
|
||||
}
|
||||
|
||||
emu_SetPaletteEntry(r,g,b,index);
|
||||
|
||||
sbitmap.pal.dirty[index] = sbitmap.pal.update = 1;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
#ifndef _RENDER_H_
|
||||
#define _RENDER_H_
|
||||
|
||||
|
||||
/* Used for blanking a line in whole or in part */
|
||||
#define BACKDROP_COLOR (0x10 | (vdp.reg[7] & 0x0F))
|
||||
|
||||
/* Global data - used by 'vdp.c' */
|
||||
extern byte svram_dirty[0x200];
|
||||
extern byte sis_vram_dirty;
|
||||
|
||||
/* Function prototypes */
|
||||
void render_init(void);
|
||||
void render_reset(void);
|
||||
void render_bg_gg(int line);
|
||||
void render_bg_sms(int line);
|
||||
void render_obj(int line);
|
||||
void render_line(int line);
|
||||
void update_cache(void);
|
||||
void palette_sync(int index);
|
||||
|
||||
#endif /* _RENDER_H_ */
|
|
@ -0,0 +1,60 @@
|
|||
|
||||
#ifndef _SHARED_H_
|
||||
#define _SHARED_H_
|
||||
|
||||
#define VERSION "0.9.3"
|
||||
|
||||
//#define ALIGN_DWORD 1
|
||||
#define LSB_FIRST 1
|
||||
#define SOUND_PRESENT 1
|
||||
|
||||
/* Data types */
|
||||
|
||||
typedef unsigned char byte;
|
||||
|
||||
typedef unsigned char UINT8;
|
||||
typedef unsigned short UINT16;
|
||||
typedef unsigned int UINT32;
|
||||
typedef signed char INT8;
|
||||
typedef signed short INT16;
|
||||
typedef signed int INT32;
|
||||
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned int uint32;
|
||||
typedef signed char int8;
|
||||
typedef signed short int16;
|
||||
typedef signed int int32;
|
||||
|
||||
#define NULL 0
|
||||
|
||||
typedef union {
|
||||
#ifdef LSB_FIRST
|
||||
struct { UINT8 l,h,h2,h3; } b;
|
||||
struct { UINT16 l,h; } w;
|
||||
#else
|
||||
struct { UINT8 h3,h2,h,l; } b;
|
||||
struct { UINT16 h,l; } w;
|
||||
#endif
|
||||
UINT32 d;
|
||||
} PAIR;
|
||||
|
||||
#define __inline__
|
||||
|
||||
/* To keep the MAME code happy */
|
||||
#define HAS_YM3812 1
|
||||
typedef signed short int FMSAMPLE;
|
||||
|
||||
|
||||
#include "memory.h"
|
||||
#include "z80.h"
|
||||
#include "sms.h"
|
||||
#include "vdp.h"
|
||||
#include "render.h"
|
||||
#include "sn76496.h"
|
||||
#include "fmopl.h"
|
||||
#include "ym2413.h"
|
||||
#include "system.h"
|
||||
|
||||
#endif /* _SHARED_H_ */
|
||||
|
|
@ -0,0 +1,316 @@
|
|||
#include "shared.h"
|
||||
|
||||
/* SMS context */
|
||||
t_sms sms;
|
||||
t_input input; /* Controller input */
|
||||
|
||||
/* Run the virtual console emulation for one frame */
|
||||
void sms_frame(int skip_render)
|
||||
{
|
||||
/* Take care of hard resets */
|
||||
if(input.system & INPUT_HARD_RESET)
|
||||
{
|
||||
system_reset();
|
||||
}
|
||||
|
||||
/* Debounce pause key */
|
||||
if(input.system & INPUT_PAUSE)
|
||||
{
|
||||
if(!sms.paused)
|
||||
{
|
||||
sms.paused = 1;
|
||||
|
||||
z80_set_nmi_line(ASSERT_LINE);
|
||||
z80_set_nmi_line(CLEAR_LINE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sms.paused = 0;
|
||||
}
|
||||
|
||||
if(smssnd.log) smssnd.callback(0x00);
|
||||
|
||||
for(vdp.line = 0; vdp.line < 262; vdp.line += 1)
|
||||
{
|
||||
/* Handle VDP line events */
|
||||
vdp_run();
|
||||
|
||||
/* Draw the current frame */
|
||||
if(!skip_render) render_line(vdp.line);
|
||||
|
||||
/* Run the Z80 for a line */
|
||||
z80_execute(227);
|
||||
}
|
||||
}
|
||||
|
||||
void audio_play_sample(int16 *bufl, int16 *bufr, int length)
|
||||
{
|
||||
length = length/2;
|
||||
|
||||
if(smssnd.enabled)
|
||||
{
|
||||
int count;
|
||||
|
||||
SN76496Update(0, smssnd.psg_buffer, length, sms.psg_mask);
|
||||
if(sms.use_fm) YM3812UpdateOne(ym3812, smssnd.fm_buffer, length);
|
||||
|
||||
for(count = 0; count < length; count += 1)
|
||||
{
|
||||
signed short left = 0;
|
||||
signed short right = 0;
|
||||
if (sms.use_fm) left = right = smssnd.fm_buffer[count];
|
||||
left += smssnd.psg_buffer[0][count];
|
||||
right += smssnd.psg_buffer[1][count];
|
||||
*bufl++ = left;
|
||||
*bufl++ = right;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void sms_init(void)
|
||||
{
|
||||
#if PSX
|
||||
z80_set_context((void *)0x1F800000);
|
||||
#endif
|
||||
cpu_reset();
|
||||
sms_reset();
|
||||
}
|
||||
|
||||
|
||||
void sms_reset(void)
|
||||
{
|
||||
memset(&input, 0, sizeof(t_input));
|
||||
|
||||
/* Clear SMS context */
|
||||
memset(sms.dummy, 0, 0x2000);
|
||||
memset(sms.ram, 0, 0x2000);
|
||||
memset(sms.sram, 0, 0x8000);
|
||||
sms.paused = sms.save = sms.port_3F = sms.port_F2 = sms.irq = 0x00;
|
||||
sms.psg_mask = 0xFF;
|
||||
|
||||
/* Load memory maps with default values */
|
||||
cpu_readmap[0] = 0x0000;
|
||||
cpu_readmap[1] = 0x2000;
|
||||
cpu_readmap[2] = 0x4000;
|
||||
cpu_readmap[3] = 0x6000;
|
||||
cpu_readmap[4] = 0x0000;
|
||||
cpu_readmap[5] = 0x2000;
|
||||
cpu_readmap[6] = sms.ram;
|
||||
cpu_readmap[7] = sms.ram;
|
||||
|
||||
cpu_writemap[0] = sms.dummy;
|
||||
cpu_writemap[1] = sms.dummy;
|
||||
cpu_writemap[2] = sms.dummy;
|
||||
cpu_writemap[3] = sms.dummy;
|
||||
cpu_writemap[4] = sms.dummy;
|
||||
cpu_writemap[5] = sms.dummy;
|
||||
cpu_writemap[6] = sms.ram;
|
||||
cpu_writemap[7] = sms.ram;
|
||||
|
||||
sms.fcr[0] = 0x00;
|
||||
sms.fcr[1] = 0x00;
|
||||
sms.fcr[2] = 0x01;
|
||||
sms.fcr[3] = 0x00;
|
||||
}
|
||||
|
||||
|
||||
/* Reset Z80 emulator */
|
||||
void cpu_reset(void)
|
||||
{
|
||||
z80_reset(0);
|
||||
z80_set_irq_callback(sms_irq_callback);
|
||||
}
|
||||
|
||||
|
||||
/* Write to memory */
|
||||
void cpu_writemem16(int address, int data)
|
||||
{
|
||||
cpu_writemap[(address >> 13)][(address & 0x1FFF)] = data;
|
||||
if(address >= 0xFFFC) sms_mapper_w(address & 3, data);
|
||||
}
|
||||
|
||||
|
||||
/* Write to an I/O port */
|
||||
void cpu_writeport(int port, int data)
|
||||
{
|
||||
switch(port & 0xFF)
|
||||
{
|
||||
case 0x01: /* GG SIO */
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
case 0x04:
|
||||
case 0x05:
|
||||
break;
|
||||
|
||||
case 0x06: /* GG STEREO */
|
||||
if(smssnd.log) {
|
||||
smssnd.callback(0x04);
|
||||
smssnd.callback(data);
|
||||
}
|
||||
sms.psg_mask = (data & 0xFF);
|
||||
break;
|
||||
|
||||
case 0x7E: /* SN76489 PSG */
|
||||
case 0x7F:
|
||||
if(smssnd.log) {
|
||||
smssnd.callback(0x03);
|
||||
smssnd.callback(data);
|
||||
}
|
||||
if(smssnd.enabled) SN76496Write(0, data);
|
||||
break;
|
||||
|
||||
case 0xBE: /* VDP DATA */
|
||||
vdp_data_w(data);
|
||||
break;
|
||||
|
||||
case 0xBD: /* VDP CTRL */
|
||||
case 0xBF:
|
||||
vdp_ctrl_w(data);
|
||||
break;
|
||||
|
||||
case 0xF0: /* YM2413 */
|
||||
case 0xF1:
|
||||
if(smssnd.log) {
|
||||
smssnd.callback((port & 1) ? 0x06 : 0x05);
|
||||
smssnd.callback(data);
|
||||
}
|
||||
if(smssnd.enabled && sms.use_fm) ym2413_write(0, port & 1, data);
|
||||
break;
|
||||
|
||||
case 0xF2: /* YM2413 DETECT */
|
||||
if(sms.use_fm) sms.port_F2 = (data & 1);
|
||||
break;
|
||||
|
||||
case 0x3F: /* TERRITORY CTRL. */
|
||||
sms.port_3F = ((data & 0x80) | (data & 0x20) << 1) & 0xC0;
|
||||
if(sms.country == TYPE_DOMESTIC) sms.port_3F ^= 0xC0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Read from an I/O port */
|
||||
int cpu_readport(int port)
|
||||
{
|
||||
byte temp = 0xFF;
|
||||
|
||||
switch(port & 0xFF)
|
||||
{
|
||||
case 0x01: /* GG SIO */
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
case 0x04:
|
||||
case 0x05:
|
||||
return (0x00);
|
||||
|
||||
case 0x7E: /* V COUNTER */
|
||||
return (vdp_vcounter_r());
|
||||
break;
|
||||
|
||||
case 0x7F: /* H COUNTER */
|
||||
return (vdp_hcounter_r());
|
||||
break;
|
||||
|
||||
case 0x00: /* INPUT #2 */
|
||||
temp = 0xFF;
|
||||
if(input.system & INPUT_START) temp &= ~0x80;
|
||||
if(sms.country == TYPE_DOMESTIC) temp &= ~0x40;
|
||||
return (temp);
|
||||
|
||||
case 0xC0: /* INPUT #0 */
|
||||
case 0xDC:
|
||||
temp = 0xFF;
|
||||
if(input.pad[0] & INPUT_UP) temp &= ~0x01;
|
||||
if(input.pad[0] & INPUT_DOWN) temp &= ~0x02;
|
||||
if(input.pad[0] & INPUT_LEFT) temp &= ~0x04;
|
||||
if(input.pad[0] & INPUT_RIGHT) temp &= ~0x08;
|
||||
if(input.pad[0] & INPUT_BUTTON2) temp &= ~0x10;
|
||||
if(input.pad[0] & INPUT_BUTTON1) temp &= ~0x20;
|
||||
if(input.pad[1] & INPUT_UP) temp &= ~0x40;
|
||||
if(input.pad[1] & INPUT_DOWN) temp &= ~0x80;
|
||||
return (temp);
|
||||
|
||||
case 0xC1: /* INPUT #1 */
|
||||
case 0xDD:
|
||||
temp = 0xFF;
|
||||
if(input.pad[1] & INPUT_LEFT) temp &= ~0x01;
|
||||
if(input.pad[1] & INPUT_RIGHT) temp &= ~0x02;
|
||||
if(input.pad[1] & INPUT_BUTTON2) temp &= ~0x04;
|
||||
if(input.pad[1] & INPUT_BUTTON1) temp &= ~0x08;
|
||||
if(input.system & INPUT_SOFT_RESET) temp &= ~0x10;
|
||||
return ((temp & 0x3F) | (sms.port_3F & 0xC0));
|
||||
|
||||
case 0xBE: /* VDP DATA */
|
||||
return (vdp_data_r());
|
||||
|
||||
case 0xBD:
|
||||
case 0xBF: /* VDP CTRL */
|
||||
return (vdp_ctrl_r());
|
||||
|
||||
case 0xF2: /* YM2413 DETECT */
|
||||
if(sms.use_fm) return (sms.port_F2);
|
||||
break;
|
||||
}
|
||||
return (0xFF);
|
||||
}
|
||||
|
||||
|
||||
void sms_mapper_w(int address, int data)
|
||||
{
|
||||
/* Calculate ROM page index */
|
||||
byte page = (data % cart.pages);
|
||||
|
||||
/* Save frame control register data */
|
||||
sms.fcr[address] = data;
|
||||
|
||||
switch(address)
|
||||
{
|
||||
case 0:
|
||||
if(data & 8)
|
||||
{
|
||||
sms.save = 1;
|
||||
/* Page in ROM */
|
||||
cpu_readmap[4] = &sms.sram[(data & 4) ? 0x4000 : 0x0000];
|
||||
cpu_readmap[5] = &sms.sram[(data & 4) ? 0x6000 : 0x2000];
|
||||
cpu_writemap[4] = &sms.sram[(data & 4) ? 0x4000 : 0x0000];
|
||||
cpu_writemap[5] = &sms.sram[(data & 4) ? 0x6000 : 0x2000];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Page in RAM */
|
||||
cpu_readmap[4] = ((sms.fcr[3] % cart.pages) << 14) + 0x0000;
|
||||
cpu_readmap[5] = ((sms.fcr[3] % cart.pages) << 14) + 0x2000;
|
||||
cpu_writemap[4] = sms.dummy;
|
||||
cpu_writemap[5] = sms.dummy;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
cpu_readmap[0] = (page << 14) + 0x0000;
|
||||
cpu_readmap[1] = (page << 14) + 0x2000;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
cpu_readmap[2] = (page << 14) + 0x0000;
|
||||
cpu_readmap[3] = (page << 14) + 0x2000;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if(!(sms.fcr[0] & 0x08))
|
||||
{
|
||||
cpu_readmap[4] = (page << 14) + 0x0000;
|
||||
cpu_readmap[5] = (page << 14) + 0x2000;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int sms_irq_callback(int param)
|
||||
{
|
||||
return (0xFF);
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
#ifndef _SMS_H_
|
||||
#define _SMS_H_
|
||||
|
||||
#define TYPE_OVERSEAS (0)
|
||||
#define TYPE_DOMESTIC (1)
|
||||
|
||||
/* SMS context */
|
||||
typedef struct
|
||||
{
|
||||
byte dummy[0x2000];
|
||||
byte ram[0x2000];
|
||||
byte sram[0x8000];
|
||||
byte fcr[4];
|
||||
byte paused;
|
||||
byte save;
|
||||
byte country;
|
||||
byte port_3F;
|
||||
byte port_F2;
|
||||
byte use_fm;
|
||||
byte irq;
|
||||
byte psg_mask;
|
||||
}t_sms;
|
||||
|
||||
/* Global data */
|
||||
extern t_sms sms;
|
||||
|
||||
/* Function prototypes */
|
||||
void sms_frame(int skip_render);
|
||||
void sms_init(void);
|
||||
void sms_reset(void);
|
||||
int sms_irq_callback(int param);
|
||||
void sms_mapper_w(int address, int data);
|
||||
void cpu_reset(void);
|
||||
|
||||
#endif /* _SMS_H_ */
|
Plik diff jest za duży
Load Diff
|
@ -0,0 +1,245 @@
|
|||
#include "shared.h"
|
||||
|
||||
#define MAX_OUTPUT 0x7FFF
|
||||
#define STEP 0x10000
|
||||
#define FB_WNOISE 0x12000
|
||||
#define FB_PNOISE 0x08000
|
||||
#define NG_PRESET 0x0F35
|
||||
|
||||
t_SN76496 sn[MAX_76496];
|
||||
|
||||
void SN76496Write(int chip,int data)
|
||||
{
|
||||
t_SN76496 *R = &sn[chip];
|
||||
|
||||
|
||||
if (data & 0x80)
|
||||
{
|
||||
int r = (data & 0x70) >> 4;
|
||||
int c = r/2;
|
||||
|
||||
R->LastRegister = r;
|
||||
R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f);
|
||||
switch (r)
|
||||
{
|
||||
case 0: /* tone 0 : frequency */
|
||||
case 2: /* tone 1 : frequency */
|
||||
case 4: /* tone 2 : frequency */
|
||||
R->Period[c] = R->UpdateStep * R->Register[r];
|
||||
if (R->Period[c] == 0) R->Period[c] = R->UpdateStep;
|
||||
if (r == 4)
|
||||
{
|
||||
/* update noise shift frequency */
|
||||
if ((R->Register[6] & 0x03) == 0x03)
|
||||
R->Period[3] = 2 * R->Period[2];
|
||||
}
|
||||
break;
|
||||
case 1: /* tone 0 : volume */
|
||||
case 3: /* tone 1 : volume */
|
||||
case 5: /* tone 2 : volume */
|
||||
case 7: /* noise : volume */
|
||||
R->Volume[c] = R->VolTable[data & 0x0f];
|
||||
break;
|
||||
case 6: /* noise : frequency, mode */
|
||||
{
|
||||
int n = R->Register[6];
|
||||
R->NoiseFB = (n & 4) ? FB_WNOISE : FB_PNOISE;
|
||||
n &= 3;
|
||||
/* N/512,N/1024,N/2048,Tone #3 output */
|
||||
R->Period[3] = (n == 3) ? 2 * R->Period[2] : (R->UpdateStep << (5+n));
|
||||
|
||||
/* reset noise shifter */
|
||||
R->RNG = NG_PRESET;
|
||||
R->Output[3] = R->RNG & 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int r = R->LastRegister;
|
||||
int c = r/2;
|
||||
|
||||
switch (r)
|
||||
{
|
||||
case 0: /* tone 0 : frequency */
|
||||
case 2: /* tone 1 : frequency */
|
||||
case 4: /* tone 2 : frequency */
|
||||
R->Register[r] = (R->Register[r] & 0x0f) | ((data & 0x3f) << 4);
|
||||
R->Period[c] = R->UpdateStep * R->Register[r];
|
||||
if (R->Period[c] == 0) R->Period[c] = R->UpdateStep;
|
||||
if (r == 4)
|
||||
{
|
||||
/* update noise shift frequency */
|
||||
if ((R->Register[6] & 0x03) == 0x03)
|
||||
R->Period[3] = 2 * R->Period[2];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SN76496Update(int chip,INT16 *buffer[2],int length, unsigned char mask)
|
||||
{
|
||||
int i, j;
|
||||
int buffer_index = 0;
|
||||
t_SN76496 *R = &sn[chip];
|
||||
|
||||
/* If the volume is 0, increase the counter */
|
||||
for (i = 0;i < 4;i++)
|
||||
{
|
||||
if (R->Volume[i] == 0)
|
||||
{
|
||||
/* note that I do count += length, NOT count = length + 1. You might think */
|
||||
/* it's the same since the volume is 0, but doing the latter could cause */
|
||||
/* interferencies when the program is rapidly modulating the volume. */
|
||||
if (R->Count[i] <= length*STEP) R->Count[i] += length*STEP;
|
||||
}
|
||||
}
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
int vol[4];
|
||||
unsigned int out[2];
|
||||
int left;
|
||||
|
||||
|
||||
/* vol[] keeps track of how long each square wave stays */
|
||||
/* in the 1 position during the sample period. */
|
||||
vol[0] = vol[1] = vol[2] = vol[3] = 0;
|
||||
|
||||
for (i = 0;i < 3;i++)
|
||||
{
|
||||
if (R->Output[i]) vol[i] += R->Count[i];
|
||||
R->Count[i] -= STEP;
|
||||
/* Period[i] is the half period of the square wave. Here, in each */
|
||||
/* loop I add Period[i] twice, so that at the end of the loop the */
|
||||
/* square wave is in the same status (0 or 1) it was at the start. */
|
||||
/* vol[i] is also incremented by Period[i], since the wave has been 1 */
|
||||
/* exactly half of the time, regardless of the initial position. */
|
||||
/* If we exit the loop in the middle, Output[i] has to be inverted */
|
||||
/* and vol[i] incremented only if the exit status of the square */
|
||||
/* wave is 1. */
|
||||
while (R->Count[i] <= 0)
|
||||
{
|
||||
R->Count[i] += R->Period[i];
|
||||
if (R->Count[i] > 0)
|
||||
{
|
||||
R->Output[i] ^= 1;
|
||||
if (R->Output[i]) vol[i] += R->Period[i];
|
||||
break;
|
||||
}
|
||||
R->Count[i] += R->Period[i];
|
||||
vol[i] += R->Period[i];
|
||||
}
|
||||
if (R->Output[i]) vol[i] -= R->Count[i];
|
||||
}
|
||||
|
||||
left = STEP;
|
||||
do
|
||||
{
|
||||
int nextevent;
|
||||
|
||||
|
||||
if (R->Count[3] < left) nextevent = R->Count[3];
|
||||
else nextevent = left;
|
||||
|
||||
if (R->Output[3]) vol[3] += R->Count[3];
|
||||
R->Count[3] -= nextevent;
|
||||
if (R->Count[3] <= 0)
|
||||
{
|
||||
if (R->RNG & 1) R->RNG ^= R->NoiseFB;
|
||||
R->RNG >>= 1;
|
||||
R->Output[3] = R->RNG & 1;
|
||||
R->Count[3] += R->Period[3];
|
||||
if (R->Output[3]) vol[3] += R->Period[3];
|
||||
}
|
||||
if (R->Output[3]) vol[3] -= R->Count[3];
|
||||
|
||||
left -= nextevent;
|
||||
} while (left > 0);
|
||||
|
||||
out[0] = out[1] = 0;
|
||||
for(j = 0; j < 4; j += 1)
|
||||
{
|
||||
int k = vol[j] * R->Volume[j];
|
||||
if(mask & (1 << (4+j))) out[0] += k;
|
||||
if(mask & (1 << (0+j))) out[1] += k;
|
||||
}
|
||||
|
||||
if(out[0] > MAX_OUTPUT * STEP) out[0] = MAX_OUTPUT * STEP;
|
||||
if(out[1] > MAX_OUTPUT * STEP) out[1] = MAX_OUTPUT * STEP;
|
||||
buffer[0][buffer_index] = out[0] / STEP;
|
||||
buffer[1][buffer_index] = out[1] / STEP;
|
||||
|
||||
/* Next sample set */
|
||||
buffer_index += 1;
|
||||
|
||||
length--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SN76496_set_clock(int chip,int clock)
|
||||
{
|
||||
t_SN76496 *R = &sn[chip];
|
||||
|
||||
R->UpdateStep = ((double)STEP * R->SampleRate * 16) / clock;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SN76496_set_gain(int chip,int gain)
|
||||
{
|
||||
t_SN76496 *R = &sn[chip];
|
||||
int i;
|
||||
double out;
|
||||
|
||||
gain &= 0xff;
|
||||
out = MAX_OUTPUT / 3;
|
||||
while (gain-- > 0)
|
||||
out *= 1.023292992;
|
||||
|
||||
for (i = 0;i < 15;i++)
|
||||
{
|
||||
if (out > MAX_OUTPUT / 3) R->VolTable[i] = MAX_OUTPUT / 3;
|
||||
else R->VolTable[i] = out;
|
||||
out /= 1.258925412;
|
||||
}
|
||||
|
||||
R->VolTable[15] = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int SN76496_init(int chip,int clock,int volume,int sample_rate)
|
||||
{
|
||||
int i;
|
||||
t_SN76496 *R = &sn[chip];
|
||||
|
||||
R->SampleRate = sample_rate;
|
||||
SN76496_set_clock(chip,clock);
|
||||
|
||||
for (i = 0;i < 4;i++) R->Volume[i] = 0;
|
||||
|
||||
R->LastRegister = 0;
|
||||
for (i = 0;i < 8;i+=2)
|
||||
{
|
||||
R->Register[i] = 0;
|
||||
R->Register[i + 1] = 0x0f; /* volume = 0 */
|
||||
}
|
||||
|
||||
for (i = 0;i < 4;i++)
|
||||
{
|
||||
R->Output[i] = 0;
|
||||
R->Period[i] = R->Count[i] = R->UpdateStep;
|
||||
}
|
||||
R->RNG = NG_PRESET;
|
||||
R->Output[3] = R->RNG & 1;
|
||||
|
||||
SN76496_set_gain(0, (volume >> 8) & 0xFF);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef SN76496_H
|
||||
#define SN76496_H
|
||||
|
||||
#define MAX_76496 4
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int Channel;
|
||||
int SampleRate;
|
||||
unsigned int UpdateStep;
|
||||
int VolTable[16];
|
||||
int Register[8];
|
||||
int LastRegister;
|
||||
int Volume[4];
|
||||
unsigned int RNG;
|
||||
int NoiseFB;
|
||||
int Period[4];
|
||||
int Count[4];
|
||||
int Output[4];
|
||||
}t_SN76496;
|
||||
|
||||
extern t_SN76496 sn[MAX_76496];
|
||||
|
||||
void SN76496Write(int chip,int data);
|
||||
void SN76496Update(int chip, signed short int *buffer[2],int length,unsigned char mask);
|
||||
void SN76496_set_clock(int chip,int clock);
|
||||
void SN76496_set_gain(int chip,int gain);
|
||||
int SN76496_init(int chip,int clock,int volume,int sample_rate);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
Copyright (C) 1998, 1999, 2000 Charles Mac Donald
|
||||
|
||||
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 "shared.h"
|
||||
|
||||
|
||||
t_bitmap sbitmap;
|
||||
t_cart cart;
|
||||
t_snd smssnd;
|
||||
static t_input minput;
|
||||
FM_OPL *ym3812;
|
||||
|
||||
|
||||
void system_init(int rate)
|
||||
{
|
||||
/* Initialize the VDP emulation */
|
||||
vdp_init();
|
||||
|
||||
/* Initialize the SMS emulation */
|
||||
sms_init();
|
||||
|
||||
/* Initialize the look-up tables and related data */
|
||||
render_init();
|
||||
|
||||
/* Enable sound emulation if the sample rate was specified */
|
||||
audio_init(rate);
|
||||
|
||||
/* Don't save SRAM by default */
|
||||
sms.save = 0;
|
||||
|
||||
/* Clear emulated button state */
|
||||
memset(&minput, 0, sizeof(t_input));
|
||||
}
|
||||
|
||||
|
||||
void audio_init(int rate)
|
||||
{
|
||||
/* Clear sound context */
|
||||
memset(&smssnd, 0, sizeof(t_snd));
|
||||
|
||||
/* Reset logging data */
|
||||
smssnd.log = 0;
|
||||
smssnd.callback = NULL;
|
||||
|
||||
/* Oops.. sound is disabled */
|
||||
if(!rate) return;
|
||||
|
||||
/* Calculate buffer size in samples */
|
||||
smssnd.bufsize = (rate / 50);
|
||||
|
||||
/* YM3812/YM2413 sound stream */
|
||||
smssnd.fm_buffer = (signed short int *)emu_Malloc(smssnd.bufsize * 2);
|
||||
if(!smssnd.fm_buffer) return;
|
||||
|
||||
/* SN76489 sound stream */
|
||||
smssnd.psg_buffer[0] = (signed short int *)emu_Malloc(smssnd.bufsize * 2);
|
||||
smssnd.psg_buffer[1] = (signed short int *)emu_Malloc(smssnd.bufsize * 2);
|
||||
if(!smssnd.psg_buffer[0] || !smssnd.psg_buffer[1]) return;
|
||||
|
||||
/* Set up SN76489 emulation */
|
||||
SN76496_init(0, MASTER_CLOCK, 255, rate);
|
||||
|
||||
/* Set up YM3812 emulation */
|
||||
ym3812 = OPLCreate(OPL_TYPE_YM3812, MASTER_CLOCK, rate);
|
||||
if(!ym3812) return;
|
||||
|
||||
/* Set up YM2413 emulation */
|
||||
ym2413_init(1);
|
||||
|
||||
/* Inform other functions that we can use sound */
|
||||
smssnd.enabled = 1;
|
||||
}
|
||||
|
||||
|
||||
void system_shutdown(void)
|
||||
{
|
||||
if(smssnd.enabled) OPLDestroy(ym3812);
|
||||
}
|
||||
|
||||
|
||||
void system_reset(void)
|
||||
{
|
||||
cpu_reset();
|
||||
vdp_reset();
|
||||
sms_reset();
|
||||
render_reset();
|
||||
// system_load_sram();
|
||||
if(smssnd.enabled)
|
||||
{
|
||||
OPLResetChip(ym3812);
|
||||
ym2413_reset(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void system_save_state(void *fd)
|
||||
{
|
||||
/* Save VDP context */
|
||||
fwrite(&vdp, sizeof(t_vdp), 1, fd);
|
||||
|
||||
/* Save SMS context */
|
||||
fwrite(&sms, sizeof(t_sms), 1, fd);
|
||||
|
||||
/* Save Z80 context */
|
||||
fwrite(Z80_Context, sizeof(Z80_Regs), 1, fd);
|
||||
fwrite(&after_EI, sizeof(int), 1, fd);
|
||||
|
||||
/* Save YM2413 registers */
|
||||
fwrite(&ym2413[0].reg[0], 0x40, 1, fd);
|
||||
|
||||
/* Save SN76489 context */
|
||||
fwrite(&sn[0], sizeof(t_SN76496), 1, fd);
|
||||
}
|
||||
|
||||
|
||||
void system_load_state(void *fd)
|
||||
{
|
||||
int i;
|
||||
byte reg[0x40];
|
||||
|
||||
/* Initialize everything */
|
||||
cpu_reset();
|
||||
system_reset();
|
||||
|
||||
/* Load VDP context */
|
||||
fread(&vdp, sizeof(t_vdp), 1, fd);
|
||||
|
||||
/* Load SMS context */
|
||||
fread(&sms, sizeof(t_sms), 1, fd);
|
||||
|
||||
/* Load Z80 context */
|
||||
fread(Z80_Context, sizeof(Z80_Regs), 1, fd);
|
||||
fread(&after_EI, sizeof(int), 1, fd);
|
||||
|
||||
/* Load YM2413 registers */
|
||||
fread(reg, 0x40, 1, fd);
|
||||
|
||||
/* Load SN76489 context */
|
||||
fread(&sn[0], sizeof(t_SN76496), 1, fd);
|
||||
|
||||
/* Restore callbacks */
|
||||
z80_set_irq_callback(sms_irq_callback);
|
||||
|
||||
cpu_readmap[0] = 0x0000; /* 0000-3FFF */
|
||||
cpu_readmap[1] = 0x2000;
|
||||
cpu_readmap[2] = 0x4000; /* 4000-7FFF */
|
||||
cpu_readmap[3] = 0x6000;
|
||||
cpu_readmap[4] = 0x0000; /* 0000-3FFF */
|
||||
cpu_readmap[5] = 0x2000;
|
||||
cpu_readmap[6] = sms.ram;
|
||||
cpu_readmap[7] = sms.ram;
|
||||
|
||||
cpu_writemap[0] = sms.dummy;
|
||||
cpu_writemap[1] = sms.dummy;
|
||||
cpu_writemap[2] = sms.dummy;
|
||||
cpu_writemap[3] = sms.dummy;
|
||||
cpu_writemap[4] = sms.dummy;
|
||||
cpu_writemap[5] = sms.dummy;
|
||||
cpu_writemap[6] = sms.ram;
|
||||
cpu_writemap[7] = sms.ram;
|
||||
|
||||
sms_mapper_w(3, sms.fcr[3]);
|
||||
sms_mapper_w(2, sms.fcr[2]);
|
||||
sms_mapper_w(1, sms.fcr[1]);
|
||||
sms_mapper_w(0, sms.fcr[0]);
|
||||
|
||||
/* Force full pattern cache update */
|
||||
sis_vram_dirty = 1;
|
||||
memset(svram_dirty, 1, 0x200);
|
||||
|
||||
/* Restore palette */
|
||||
for(i = 0; i < PALETTE_SIZE; i += 1)
|
||||
palette_sync(i);
|
||||
|
||||
/* Restore sound state */
|
||||
if(smssnd.enabled)
|
||||
{
|
||||
/* Restore YM2413 emulation */
|
||||
OPLResetChip(ym3812);
|
||||
|
||||
/* Clear YM2413 context */
|
||||
ym2413_reset(0);
|
||||
|
||||
/* Restore rhythm enable first */
|
||||
ym2413_write(0, 0, 0x0E);
|
||||
ym2413_write(0, 1, reg[0x0E]);
|
||||
|
||||
/* User instrument settings */
|
||||
for(i = 0x00; i <= 0x07; i += 1)
|
||||
{
|
||||
ym2413_write(0, 0, i);
|
||||
ym2413_write(0, 1, reg[i]);
|
||||
}
|
||||
|
||||
/* Channel frequency */
|
||||
for(i = 0x10; i <= 0x18; i += 1)
|
||||
{
|
||||
ym2413_write(0, 0, i);
|
||||
ym2413_write(0, 1, reg[i]);
|
||||
}
|
||||
|
||||
/* Channel frequency + ctrl. */
|
||||
for(i = 0x20; i <= 0x28; i += 1)
|
||||
{
|
||||
ym2413_write(0, 0, i);
|
||||
ym2413_write(0, 1, reg[i]);
|
||||
}
|
||||
|
||||
/* Instrument and volume settings */
|
||||
for(i = 0x30; i <= 0x38; i += 1)
|
||||
{
|
||||
ym2413_write(0, 0, i);
|
||||
ym2413_write(0, 1, reg[i]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
|
||||
#ifndef _SYSTEM_H_
|
||||
#define _SYSTEM_H_
|
||||
|
||||
#define PALETTE_SIZE (0x20)
|
||||
|
||||
/* Console / cartridge types */
|
||||
#define TYPE_SMS (0)
|
||||
#define TYPE_GG (1)
|
||||
|
||||
#define IS_GG (cart.type == TYPE_GG)
|
||||
#define IS_SMS (cart.type == TYPE_SMS)
|
||||
|
||||
/* Macro to get offset to actual display within bitmap */
|
||||
#define BMP_X_OFFSET ((cart.type == TYPE_GG) ? 48 : 0)
|
||||
#define BMP_Y_OFFSET ((cart.type == TYPE_GG) ? 24 : 0)
|
||||
|
||||
#define BMP_WIDTH (IS_GG ? 160 : 256)
|
||||
#define BMP_HEIGHT (IS_GG ? 144 : 192)
|
||||
|
||||
/* 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_SOFT_RESET (0x00000004) /* Master System only */
|
||||
#define INPUT_HARD_RESET (0x00000008) /* Works for either console type */
|
||||
|
||||
/* User input structure */
|
||||
typedef struct
|
||||
{
|
||||
int pad[2];
|
||||
int system;
|
||||
}t_input;
|
||||
|
||||
/* Sound emulation structure */
|
||||
typedef struct
|
||||
{
|
||||
int enabled;
|
||||
int bufsize;
|
||||
signed short *fm_buffer; /* internal use only */
|
||||
signed short *psg_buffer[2]; /* internal use only */
|
||||
int log;
|
||||
void (*callback)(int data);
|
||||
}t_snd;
|
||||
|
||||
/* Game image structure */
|
||||
typedef struct
|
||||
{
|
||||
//byte *rom;
|
||||
byte pages;
|
||||
byte type;
|
||||
}t_cart;
|
||||
|
||||
/* Bitmap structure */
|
||||
typedef struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
byte color[32][3];
|
||||
byte dirty[32];
|
||||
byte update;
|
||||
}pal;
|
||||
}t_bitmap;
|
||||
|
||||
/* Global variables */
|
||||
extern t_bitmap sbitmap; /* Display bitmap */
|
||||
extern t_snd smssnd; /* Sound streams */
|
||||
extern t_cart cart; /* Game cartridge data */
|
||||
extern t_input input; /* Controller input */
|
||||
extern FM_OPL *ym3812; /* YM3812 emulator data */
|
||||
|
||||
/* Function prototypes */
|
||||
void system_init(int rate);
|
||||
void system_shutdown(void);
|
||||
void system_reset(void);
|
||||
void system_load_sram(void);
|
||||
void system_save_state(void *fd);
|
||||
void system_load_state(void *fd);
|
||||
void audio_init(int rate);
|
||||
void audio_play_sample(int16 *bufl, int16 *bufr, int length);
|
||||
|
||||
#endif /* _SYSTEM_H_ */
|
|
@ -0,0 +1,203 @@
|
|||
extern "C" {
|
||||
#include "iopins.h"
|
||||
#include "emuapi.h"
|
||||
}
|
||||
|
||||
#include "emu.h"
|
||||
#ifdef HAS_T4_VGA
|
||||
#include "vga_t_dma.h"
|
||||
TFT_T_DMA tft;
|
||||
#else
|
||||
#include "tft_t_dma.h"
|
||||
TFT_T_DMA tft = TFT_T_DMA(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO, TFT_TOUCH_CS, TFT_TOUCH_INT);
|
||||
#endif
|
||||
|
||||
bool vgaMode = false;
|
||||
|
||||
static unsigned char palette8[PALETTE_SIZE];
|
||||
static unsigned short palette16[PALETTE_SIZE];
|
||||
static IntervalTimer myTimer;
|
||||
volatile boolean vbl=true;
|
||||
static int skip=0;
|
||||
static elapsedMicros tius;
|
||||
|
||||
static void vblCount() {
|
||||
if (vbl) {
|
||||
vbl = false;
|
||||
} else {
|
||||
vbl = true;
|
||||
}
|
||||
}
|
||||
|
||||
void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index)
|
||||
{
|
||||
if (index<PALETTE_SIZE) {
|
||||
//Serial.println("%d: %d %d %d\n", index, r,g,b);
|
||||
palette8[index] = RGBVAL8(r,g,b);
|
||||
palette16[index] = RGBVAL16(r,g,b);
|
||||
}
|
||||
}
|
||||
|
||||
void emu_DrawVsync(void)
|
||||
{
|
||||
volatile boolean vb=vbl;
|
||||
skip += 1;
|
||||
skip &= VID_FRAME_SKIP;
|
||||
if (!vgaMode) {
|
||||
#ifdef HAS_T4_VGA
|
||||
tft.waitSync();
|
||||
#else
|
||||
while (vbl==vb) {};
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void emu_DrawLine(unsigned char * VBuf, int width, int height, int line)
|
||||
{
|
||||
if (!vgaMode) {
|
||||
#ifdef HAS_T4_VGA
|
||||
tft.writeLine(width,1,line, VBuf, palette8);
|
||||
#else
|
||||
tft.writeLine(width,1,line, VBuf, palette16);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void emu_DrawLine8(unsigned char * VBuf, int width, int height, int line)
|
||||
{
|
||||
if (!vgaMode) {
|
||||
if (skip==0) {
|
||||
#ifdef HAS_T4_VGA
|
||||
tft.writeLine(width,height,line, VBuf);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void emu_DrawLine16(unsigned short * VBuf, int width, int height, int line)
|
||||
{
|
||||
if (!vgaMode) {
|
||||
if (skip==0) {
|
||||
#ifdef HAS_T4_VGA
|
||||
tft.writeLine16(width,height,line, VBuf);
|
||||
#else
|
||||
tft.writeLine(width,height,line, VBuf);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride)
|
||||
{
|
||||
if (!vgaMode) {
|
||||
if (skip==0) {
|
||||
#ifdef HAS_T4_VGA
|
||||
tft.writeScreen(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette8);
|
||||
#else
|
||||
tft.writeScreen(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int emu_FrameSkip(void)
|
||||
{
|
||||
return skip;
|
||||
}
|
||||
|
||||
void * emu_LineBuffer(int line)
|
||||
{
|
||||
if (!vgaMode) {
|
||||
return (void*)tft.getLineBuffer(line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ****************************************************
|
||||
// the setup() method runs once, when the sketch starts
|
||||
// ****************************************************
|
||||
void setup() {
|
||||
|
||||
#ifdef HAS_T4_VGA
|
||||
tft.begin(VGA_MODE_320x240);
|
||||
// NVIC_SET_PRIORITY(IRQ_QTIMER3, 0);
|
||||
#else
|
||||
tft.begin();
|
||||
#endif
|
||||
|
||||
emu_init();
|
||||
}
|
||||
|
||||
|
||||
// ****************************************************
|
||||
// the loop() method runs continuously
|
||||
// ****************************************************
|
||||
void loop(void)
|
||||
{
|
||||
if (menuActive()) {
|
||||
uint16_t bClick = emu_DebounceLocalKeys();
|
||||
int action = handleMenu(bClick);
|
||||
char * filename = menuSelection();
|
||||
if (action == ACTION_RUN1) {
|
||||
toggleMenu(false);
|
||||
vgaMode = false;
|
||||
emu_start();
|
||||
emu_Init(filename);
|
||||
tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) );
|
||||
tft.startDMA();
|
||||
myTimer.begin(vblCount, 16666); //to run every 16.666ms
|
||||
}
|
||||
delay(20);
|
||||
}
|
||||
else {
|
||||
uint16_t bClick = emu_DebounceLocalKeys();
|
||||
emu_Input(bClick);
|
||||
emu_Step();
|
||||
delay(10);
|
||||
//uint16_t bClick = emu_DebounceLocalKeys();
|
||||
//if (bClick & MASK_KEY_USER1) {
|
||||
// emu_Input(bClick);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAS_SND
|
||||
|
||||
#include "AudioPlaySystem.h"
|
||||
|
||||
AudioPlaySystem mymixer;
|
||||
|
||||
|
||||
void emu_sndInit() {
|
||||
Serial.println("sound init");
|
||||
#ifdef HAS_T4_VGA
|
||||
tft.begin_audio(256, mymixer.snd_Mixer);
|
||||
#else
|
||||
mymixer.begin_audio(256, mymixer.snd_Mixer);
|
||||
#endif
|
||||
// sgtl5000_1.enable();
|
||||
// sgtl5000_1.volume(0.6);
|
||||
mymixer.start();
|
||||
}
|
||||
|
||||
void emu_sndPlaySound(int chan, int volume, int freq)
|
||||
{
|
||||
if (chan < 6) {
|
||||
mymixer.sound(chan, freq, volume);
|
||||
}
|
||||
/*
|
||||
Serial.print(chan);
|
||||
Serial.print(":" );
|
||||
Serial.print(volume);
|
||||
Serial.print(":" );
|
||||
Serial.println(freq);
|
||||
*/
|
||||
}
|
||||
|
||||
void emu_sndPlayBuzz(int size, int val) {
|
||||
mymixer.buzz(size,val);
|
||||
//Serial.print((val==1)?1:0);
|
||||
//Serial.print(":");
|
||||
//Serial.println(size);
|
||||
}
|
||||
#endif
|
Plik diff jest za duży
Load Diff
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
Based on C64 ILI9341 dma driver from Frank Bösing, 2017
|
||||
*/
|
||||
|
||||
#ifndef _TFT_T_DMAH_
|
||||
#define _TFT_T_DMAH_
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#include <DMAChannel.h>
|
||||
#endif
|
||||
|
||||
#include "tft_t_dma_config.h"
|
||||
|
||||
#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b )
|
||||
#define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) )
|
||||
#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) )
|
||||
#define R16(rgb) ((rgb>>8)&0xf8)
|
||||
#define G16(rgb) ((rgb>>3)&0xfc)
|
||||
#define B16(rgb) ((rgb<<3)&0xf8)
|
||||
|
||||
#define PAL_COLOR_MASK 0xff
|
||||
|
||||
#ifdef LOHRES
|
||||
#define TFT_WIDTH 240
|
||||
#define TFT_REALWIDTH 240
|
||||
#else
|
||||
#define TFT_WIDTH 256
|
||||
#define TFT_REALWIDTH 320
|
||||
#endif
|
||||
#define TFT_HEIGHT 192
|
||||
#define TFT_REALHEIGHT 240
|
||||
|
||||
//#define WIDTH 272
|
||||
//#define HEIGHT 228
|
||||
|
||||
#define LINES_PER_BLOCK 64
|
||||
#define NR_OF_BLOCK 4
|
||||
#define SCREEN_DMA_NUM_SETTINGS NR_OF_BLOCK
|
||||
|
||||
|
||||
#ifdef ILI9341
|
||||
|
||||
#define ILI9341_NOP 0x00
|
||||
#define ILI9341_SWRESET 0x01
|
||||
#define ILI9341_RDDID 0x04
|
||||
#define ILI9341_RDDST 0x09
|
||||
|
||||
#define ILI9341_SLPIN 0x10
|
||||
#define ILI9341_SLPOUT 0x11
|
||||
#define ILI9341_PTLON 0x12
|
||||
#define ILI9341_NORON 0x13
|
||||
|
||||
#define ILI9341_RDMODE 0x0A
|
||||
#define ILI9341_RDMADCTL 0x0B
|
||||
#define ILI9341_RDPIXFMT 0x0C
|
||||
#define ILI9341_RDIMGFMT 0x0D
|
||||
#define ILI9341_RDSELFDIAG 0x0F
|
||||
|
||||
#define ILI9341_INVOFF 0x20
|
||||
#define ILI9341_INVON 0x21
|
||||
#define ILI9341_GAMMASET 0x26
|
||||
#define ILI9341_DISPOFF 0x28
|
||||
#define ILI9341_DISPON 0x29
|
||||
|
||||
#define ILI9341_CASET 0x2A
|
||||
#define ILI9341_PASET 0x2B
|
||||
#define ILI9341_RAMWR 0x2C
|
||||
#define ILI9341_RAMRD 0x2E
|
||||
|
||||
#define ILI9341_PTLAR 0x30
|
||||
#define ILI9341_MADCTL 0x36
|
||||
#define ILI9341_VSCRSADD 0x37
|
||||
#define ILI9341_PIXFMT 0x3A
|
||||
|
||||
#define ILI9341_FRMCTR1 0xB1
|
||||
#define ILI9341_FRMCTR2 0xB2
|
||||
#define ILI9341_FRMCTR3 0xB3
|
||||
#define ILI9341_INVCTR 0xB4
|
||||
#define ILI9341_DFUNCTR 0xB6
|
||||
|
||||
#define ILI9341_PWCTR1 0xC0
|
||||
#define ILI9341_PWCTR2 0xC1
|
||||
#define ILI9341_PWCTR3 0xC2
|
||||
#define ILI9341_PWCTR4 0xC3
|
||||
#define ILI9341_PWCTR5 0xC4
|
||||
#define ILI9341_VMCTR1 0xC5
|
||||
#define ILI9341_VMCTR2 0xC7
|
||||
|
||||
#define ILI9341_RDID1 0xDA
|
||||
#define ILI9341_RDID2 0xDB
|
||||
#define ILI9341_RDID3 0xDC
|
||||
#define ILI9341_RDID4 0xDD
|
||||
|
||||
#define ILI9341_GMCTRP1 0xE0
|
||||
#define ILI9341_GMCTRN1 0xE1
|
||||
|
||||
#define ILI9341_MADCTL_MY 0x80
|
||||
#define ILI9341_MADCTL_MX 0x40
|
||||
#define ILI9341_MADCTL_MV 0x20
|
||||
#define ILI9341_MADCTL_ML 0x10
|
||||
#define ILI9341_MADCTL_RGB 0x00
|
||||
#define ILI9341_MADCTL_BGR 0x08
|
||||
#define ILI9341_MADCTL_MH 0x04
|
||||
|
||||
#define TFT_CASET ILI9341_CASET
|
||||
#define TFT_PASET ILI9341_PASET
|
||||
#define TFT_RAMWR ILI9341_RAMWR
|
||||
#define TFT_MADCTL ILI9341_MADCTL
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ST7789
|
||||
|
||||
#define ST7735_NOP 0x00
|
||||
#define ST7735_SWRESET 0x01
|
||||
#define ST7735_RDDID 0x04
|
||||
#define ST7735_RDDST 0x09
|
||||
|
||||
#define ST7735_SLPIN 0x10
|
||||
#define ST7735_SLPOUT 0x11
|
||||
#define ST7735_PTLON 0x12
|
||||
#define ST7735_NORON 0x13
|
||||
|
||||
#define ST7735_INVOFF 0x20
|
||||
#define ST7735_INVON 0x21
|
||||
#define ST7735_DISPOFF 0x28
|
||||
#define ST7735_DISPON 0x29
|
||||
#define ST7735_CASET 0x2A
|
||||
#define ST7735_RASET 0x2B
|
||||
#define ST7735_RAMWR 0x2C
|
||||
#define ST7735_RAMRD 0x2E
|
||||
|
||||
#define ST7735_PTLAR 0x30
|
||||
#define ST7735_COLMOD 0x3A
|
||||
#define ST7735_MADCTL 0x36
|
||||
|
||||
#define ST7735_FRMCTR1 0xB1
|
||||
#define ST7735_FRMCTR2 0xB2
|
||||
#define ST7735_FRMCTR3 0xB3
|
||||
#define ST7735_INVCTR 0xB4
|
||||
#define ST7735_DISSET5 0xB6
|
||||
|
||||
#define ST7735_PWCTR1 0xC0
|
||||
#define ST7735_PWCTR2 0xC1
|
||||
#define ST7735_PWCTR3 0xC2
|
||||
#define ST7735_PWCTR4 0xC3
|
||||
#define ST7735_PWCTR5 0xC4
|
||||
#define ST7735_VMCTR1 0xC5
|
||||
|
||||
#define ST7735_RDID1 0xDA
|
||||
#define ST7735_RDID2 0xDB
|
||||
#define ST7735_RDID3 0xDC
|
||||
#define ST7735_RDID4 0xDD
|
||||
|
||||
#define ST7735_PWCTR6 0xFC
|
||||
|
||||
#define ST7735_GMCTRP1 0xE0
|
||||
#define ST7735_GMCTRN1 0xE1
|
||||
|
||||
#define ST77XX_MADCTL_MY 0x80
|
||||
#define ST77XX_MADCTL_MX 0x40
|
||||
#define ST77XX_MADCTL_MV 0x20
|
||||
#define ST77XX_MADCTL_ML 0x10
|
||||
#define ST77XX_MADCTL_RGB 0x00
|
||||
#define ST77XX_MADCTL_BGR 0x08
|
||||
#define ST77XX_MADCTL_MH 0x04
|
||||
|
||||
#define TFT_CASET ST7735_CASET
|
||||
#define TFT_PASET ST7735_RASET
|
||||
#define TFT_RAMWR ST7735_RAMWR
|
||||
#define TFT_MADCTL ST7735_MADCTL
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
class TFT_T_DMA
|
||||
{
|
||||
public:
|
||||
TFT_T_DMA(uint8_t _CS, uint8_t _DC, uint8_t _RST = 255, uint8_t _MOSI=11, uint8_t _SCLK=13, uint8_t _MISO=12, uint8_t touch_cs=38, uint8_t touch_irq=37);
|
||||
|
||||
void setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2);
|
||||
void begin(void);
|
||||
void flipscreen(bool flip);
|
||||
boolean isflipped(void);
|
||||
void startDMA(void);
|
||||
void stopDMA();
|
||||
int get_frame_buffer_size(int *width, int *height);
|
||||
|
||||
// Touch screen functions
|
||||
#define TOUCH_ENABLED() ((_touch_cs != 255) && (_touch_irq != 255))
|
||||
bool isTouching(void) { return ((!TOUCH_ENABLED())?false:(digitalRead(_touch_irq) == LOW)); }
|
||||
void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ);
|
||||
void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ);
|
||||
void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax);
|
||||
|
||||
// NoDMA functions
|
||||
void writeScreenNoDma(const uint16_t *pcolors);
|
||||
void fillScreenNoDma(uint16_t color);
|
||||
void drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize);
|
||||
void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
|
||||
void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap);
|
||||
void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh);
|
||||
|
||||
// DMA functions
|
||||
uint16_t * getLineBuffer(int j);
|
||||
void writeScreen(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16);
|
||||
void writeLine(int width, int height, int stride, uint8_t *buffer, uint16_t *palette16);
|
||||
void writeLine(int width, int height, int y, uint16_t *buf);
|
||||
void fillScreen(uint16_t color);
|
||||
void drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize);
|
||||
void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
|
||||
void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap);
|
||||
void drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh);
|
||||
|
||||
protected:
|
||||
uint8_t _rst, _cs, _dc;
|
||||
uint8_t _miso, _mosi, _sclk;
|
||||
uint8_t _touch_irq=255, _touch_cs=255;
|
||||
bool flipped=false;
|
||||
|
||||
void wait(void);
|
||||
void enableTouchIrq();
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,13 @@
|
|||
#include "platform_config.h"
|
||||
|
||||
//#define ST7789 1
|
||||
//#define ILI9341 1
|
||||
|
||||
#define TFT_LINEARINT 1
|
||||
#define LINEARINT_HACK 1
|
||||
|
||||
//#define FLIP_SCREEN 1
|
||||
//#define TFT_DEBUG 1
|
||||
#if defined(__IMXRT1052__) || defined(__IMXRT1062__)
|
||||
//#define TFT_STATICFB 1
|
||||
#endif
|
|
@ -0,0 +1,297 @@
|
|||
#include "shared.h"
|
||||
|
||||
|
||||
/* VDP context */
|
||||
t_vdp vdp;
|
||||
|
||||
|
||||
/* Return values from the V counter */
|
||||
byte vcnt[0x200] =
|
||||
{
|
||||
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,
|
||||
};
|
||||
|
||||
/* Return values from the H counter */
|
||||
byte hcnt[0x200] =
|
||||
{
|
||||
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,
|
||||
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,
|
||||
};
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/* Initialize VDP emulation */
|
||||
void vdp_init(void)
|
||||
{
|
||||
vdp_reset();
|
||||
}
|
||||
|
||||
|
||||
/* Reset VDP emulation */
|
||||
void vdp_reset(void)
|
||||
{
|
||||
memset(&vdp, 0, sizeof(t_vdp));
|
||||
vdp.limit = 1;
|
||||
}
|
||||
|
||||
|
||||
/* Write data to the VDP's control port */
|
||||
void vdp_ctrl_w(int data)
|
||||
{
|
||||
/* Waiting for the reset of the command? */
|
||||
if(vdp.pending == 0)
|
||||
{
|
||||
/* Save data for later */
|
||||
vdp.latch = data;
|
||||
|
||||
/* Set pending flag */
|
||||
vdp.pending = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Clear pending flag */
|
||||
vdp.pending = 0;
|
||||
|
||||
/* VDP register write */
|
||||
if((data & 0xF0) == 0x80)
|
||||
{
|
||||
int r = (data & 0x0F);
|
||||
int d = vdp.latch;
|
||||
|
||||
/* Store register data */
|
||||
vdp.reg[r] = d;
|
||||
|
||||
/* Update table addresses */
|
||||
vdp.ntab = (vdp.reg[2] << 10) & 0x3800;
|
||||
vdp.satb = (vdp.reg[5] << 7) & 0x3F00;
|
||||
|
||||
vdp.addr = vdp.code = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Extract code bits */
|
||||
vdp.code = (data >> 6) & 3;
|
||||
|
||||
/* Make address */
|
||||
vdp.addr = (data << 8 | vdp.latch);
|
||||
|
||||
/* Read VRAM for code 0x00 */
|
||||
if(vdp.code == 0x00)
|
||||
{
|
||||
/* Load buffer with current VRAM byte */
|
||||
vdp.buffer = vdp.vram[(vdp.addr & 0x3FFF)];
|
||||
|
||||
/* Bump address */
|
||||
vdp.addr += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Read the status flags */
|
||||
int vdp_ctrl_r(void)
|
||||
{
|
||||
/* Save the status flags */
|
||||
byte temp = vdp.status;
|
||||
|
||||
/* Clear pending flag */
|
||||
vdp.pending = 0;
|
||||
|
||||
/* Clear pending interrupt and sprite collision flags */
|
||||
vdp.status &= ~(0x80 | 0x40 | 0x20);
|
||||
|
||||
/* Lower the IRQ line */
|
||||
if(sms.irq == 1)
|
||||
{
|
||||
sms.irq = 0;
|
||||
z80_set_irq_line(0, CLEAR_LINE);
|
||||
}
|
||||
|
||||
/* Return the old status flags */
|
||||
return (temp);
|
||||
}
|
||||
|
||||
|
||||
/* Write data to the VDP's data port */
|
||||
void vdp_data_w(int data)
|
||||
{
|
||||
int index;
|
||||
|
||||
/* Clear the pending flag */
|
||||
vdp.pending = 0;
|
||||
|
||||
switch(vdp.code)
|
||||
{
|
||||
case 0: /* VRAM write */
|
||||
case 1: /* VRAM write */
|
||||
case 2: /* VRAM write */
|
||||
|
||||
/* Get current address in VRAM */
|
||||
index = (vdp.addr & 0x3FFF);
|
||||
|
||||
/* Only update if data is new */
|
||||
if(data != vdp.vram[index])
|
||||
{
|
||||
/* Store VRAM byte */
|
||||
vdp.vram[index] = data;
|
||||
|
||||
/* Mark patterns as dirty */
|
||||
svram_dirty[(index >> 5)] = sis_vram_dirty = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: /* CRAM write */
|
||||
if(cart.type == TYPE_GG)
|
||||
{
|
||||
index = (vdp.addr & 0x3F);
|
||||
if(data != vdp.cram[index])
|
||||
{
|
||||
vdp.cram[index] = data;
|
||||
index = (vdp.addr >> 1) & 0x1F;
|
||||
palette_sync(index);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
index = (vdp.addr & 0x1F);
|
||||
if(data != vdp.cram[index])
|
||||
{
|
||||
vdp.cram[index] = data;
|
||||
palette_sync(index);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Bump the VRAM address */
|
||||
vdp.addr += 1;
|
||||
}
|
||||
|
||||
|
||||
/* Read data from the VDP's data port */
|
||||
int vdp_data_r(void)
|
||||
{
|
||||
byte temp = 0;
|
||||
|
||||
/* Clear the pending flag */
|
||||
vdp.pending = 0;
|
||||
|
||||
switch(vdp.code)
|
||||
{
|
||||
case 0: /* VRAM read */
|
||||
case 1: /* VRAM read */
|
||||
case 2: /* VRAM read */
|
||||
|
||||
/* Return the buffered value */
|
||||
temp = vdp.buffer;
|
||||
|
||||
/* Get data from the current VRAM address */
|
||||
vdp.buffer = vdp.vram[(vdp.addr & 0x3FFF)];
|
||||
break;
|
||||
|
||||
case 3: /* Undefined */
|
||||
/* Return 'no value' data */
|
||||
temp = 0xFF;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Bump address register */
|
||||
vdp.addr += 1;
|
||||
return (temp);
|
||||
}
|
||||
|
||||
|
||||
/* Process frame events */
|
||||
void vdp_run(void)
|
||||
{
|
||||
if(vdp.line <= 0xC0)
|
||||
{
|
||||
if(vdp.line == 0xC0)
|
||||
{
|
||||
vdp.status |= 0x80;
|
||||
}
|
||||
|
||||
if(vdp.line == 0)
|
||||
{
|
||||
vdp.left = vdp.reg[10];
|
||||
}
|
||||
|
||||
if(vdp.left == 0)
|
||||
{
|
||||
vdp.left = vdp.reg[10];
|
||||
vdp.status |= 0x40;
|
||||
}
|
||||
else
|
||||
{
|
||||
vdp.left -= 1;
|
||||
}
|
||||
|
||||
if((vdp.status & 0x40) && (vdp.reg[0] & 0x10))
|
||||
{
|
||||
sms.irq = 1;
|
||||
z80_set_irq_line(0, ASSERT_LINE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vdp.left = vdp.reg[10];
|
||||
|
||||
if((vdp.line < 0xE0) && (vdp.status & 0x80) && (vdp.reg[1] & 0x20))
|
||||
{
|
||||
sms.irq = 1;
|
||||
z80_set_irq_line(0, ASSERT_LINE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
byte vdp_vcounter_r(void)
|
||||
{
|
||||
return (vcnt[(vdp.line & 0x1FF)]);
|
||||
}
|
||||
|
||||
|
||||
byte vdp_hcounter_r(void)
|
||||
{
|
||||
int pixel = (((z80_ICount % CYCLES_PER_LINE) / 4) * 3) * 2;
|
||||
return (hcnt[((pixel >> 1) & 0x1FF)]);
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
|
||||
#ifndef _VDP_H_
|
||||
#define _VDP_H_
|
||||
|
||||
/* 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
|
||||
{
|
||||
byte vram[0x4000];
|
||||
byte cram[0x40];
|
||||
byte reg[0x10];
|
||||
byte status;
|
||||
byte latch;
|
||||
byte pending;
|
||||
byte buffer;
|
||||
byte code;
|
||||
UINT16 addr;
|
||||
int ntab;
|
||||
int satb;
|
||||
int line;
|
||||
int left;
|
||||
byte limit;
|
||||
}t_vdp;
|
||||
|
||||
/* Global data */
|
||||
extern t_vdp vdp;
|
||||
|
||||
/* Function prototypes */
|
||||
void vdp_init(void);
|
||||
void vdp_reset(void);
|
||||
void vdp_ctrl_w(int data);
|
||||
int vdp_ctrl_r(void);
|
||||
byte vdp_vcounter_r(void);
|
||||
byte vdp_hcounter_r(void);
|
||||
void vdp_data_w(int data);
|
||||
int vdp_data_r(void);
|
||||
void vdp_run(void);
|
||||
|
||||
#endif /* _VDP_H_ */
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
Wrapping class to extend VGA_T4 to TFT_T_DMA
|
||||
*/
|
||||
|
||||
#ifndef _VGA_T_DMAH_
|
||||
#define _VGA_T_DMAH_
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <VGA_t4.h>
|
||||
#endif
|
||||
|
||||
|
||||
#define RGBVAL16(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) )
|
||||
#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) )
|
||||
|
||||
|
||||
|
||||
|
||||
#define TFT_WIDTH 320
|
||||
#define TFT_REALWIDTH 320
|
||||
|
||||
#define TFT_HEIGHT 240
|
||||
#define TFT_REALHEIGHT 240
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
class TFT_T_DMA: public VGA_T4
|
||||
{
|
||||
public:
|
||||
// Fake touch screen functions
|
||||
bool isTouching(void) { return false; }
|
||||
void readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { }
|
||||
void readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) { };
|
||||
void callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) { }
|
||||
|
||||
// fake DMA functions
|
||||
void startDMA(void) { };
|
||||
void stopDMA(void) { };
|
||||
|
||||
// fake no DMA functions
|
||||
void writeScreenNoDma(const vga_pixel *pcolors) { writeScreen(pcolors); }
|
||||
void fillScreenNoDma(vga_pixel color) { clear(color); }
|
||||
void drawTextNoDma(int16_t x, int16_t y, const char * text, vga_pixel fgcolor, vga_pixel bgcolor, bool doublesize) { drawText(x,y,text,fgcolor,bgcolor,doublesize); }
|
||||
void drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, vga_pixel color) { drawRect(x, y, w, h, color); }
|
||||
void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap) { drawSprite(x, y, bitmap); }
|
||||
void drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t croparx, uint16_t cropary, uint16_t croparw, uint16_t croparh) { drawSprite(x, y, bitmap, croparx, cropary, croparw, croparh); }
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,397 @@
|
|||
/*
|
||||
Copyright (C) 2000 Charles Mac Donald
|
||||
|
||||
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
|
||||
|
||||
YM2413 (OPLL) emulator
|
||||
by Charles Mac Donald
|
||||
E-mail: cgfm2@hooked.net
|
||||
WWW: http://cgfm2.emuviews.com
|
||||
|
||||
Change log:
|
||||
|
||||
[061300]
|
||||
- Fixed bug where channel numbers larger than 9 could be written to
|
||||
register groups $10-18, $20-28, $30-38.
|
||||
|
||||
[060800]
|
||||
- Now the YM2413 chip number is passed to the OPL_WRITE macro,
|
||||
and the user instrument data is stored in the YM2413 context,
|
||||
both for multiple YM2413 emulation.
|
||||
|
||||
[060100]
|
||||
- Added alternate instrument table taken from Allegro's 'fm_inst.h'.
|
||||
- Changed source so it can compile seperately from SMS Plus.
|
||||
- Added 'ym2413_reset' function and changed ym2413_init.
|
||||
|
||||
Known issues:
|
||||
|
||||
- The sustain on/off flag (bit 5 of register group $20-28) is not
|
||||
emulated. According to the manual, the release rate is set to
|
||||
five when this bit is set.
|
||||
|
||||
- The table of fixed instrument values probably need to be compared
|
||||
against a real YM2413, so they can be hand-tuned.
|
||||
|
||||
- The rhythm instruments sound good, but are too loud.
|
||||
The same settings are used for channels 7, 8, 9, which can't be right.
|
||||
|
||||
I based the YM2413 emulation on the following documents. If you want
|
||||
to improve it or make changes, I'd advise reading the following:
|
||||
|
||||
- Yamaha's YMF-272 (OPL-3) programmer's manual. (ymf272.pdf)
|
||||
(Has useful table of how the operators map to YM3812 registers)
|
||||
|
||||
- Yamaha's YM2413 programmer's manual. (ym2413.lzh)
|
||||
|
||||
- Vladimir Arnost's OPL-3 programmer's guide. (opl3.txt)
|
||||
(Explains operator allocation in rhythm mode)
|
||||
|
||||
- The YM2413 emulation from MAME. (ym2413.c/2413intf.h)
|
||||
*/
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
/* You can replace this to output to another YM3812 emulator
|
||||
or a perhaps a real OPL-2/OPL-3 sound chip */
|
||||
#if USE_ADLIB
|
||||
#define OPL_WRITE(c,r,d) { outp(0x388+c*2, r); outp(0x389+c*2, d); }
|
||||
#else
|
||||
#define OPL_WRITE(c,r,d) OPLWriteReg(ym3812, r, d)
|
||||
#endif
|
||||
|
||||
/* YM2413 chip contexts */
|
||||
t_ym2413 ym2413[MAX_YM2413];
|
||||
|
||||
/* Fixed instrument settings, from MAME's YM2413 emulation */
|
||||
/* This might need some tweaking... */
|
||||
unsigned char table[16][11] =
|
||||
{
|
||||
/* 20 23 40 43 60 63 80 83 E0 E3 C0 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
#if 1 /* Instrument settings from MAME */
|
||||
{ 0x01, 0x22, 0x23, 0x07, 0xF0, 0xF0, 0x07, 0x18, 0x00, 0x00, 0x00 },
|
||||
{ 0x23, 0x01, 0x68, 0x05, 0xF2, 0x74, 0x6C, 0x89, 0x00, 0x00, 0x00 },
|
||||
{ 0x13, 0x11, 0x25, 0x00, 0xD2, 0xB2, 0xF4, 0xF4, 0x00, 0x00, 0x00 },
|
||||
{ 0x22, 0x21, 0x1B, 0x05, 0xC0, 0xA1, 0x18, 0x08, 0x00, 0x00, 0x00 },
|
||||
{ 0x22, 0x21, 0x2C, 0x03, 0xD2, 0xA1, 0x18, 0x57, 0x00, 0x00, 0x00 },
|
||||
{ 0x01, 0x22, 0xBA, 0x01, 0xF1, 0xF1, 0x1E, 0x04, 0x00, 0x00, 0x00 },
|
||||
{ 0x21, 0x21, 0x28, 0x06, 0xF1, 0xF1, 0x6B, 0x3E, 0x00, 0x00, 0x00 },
|
||||
{ 0x27, 0x21, 0x60, 0x00, 0xF0, 0xF0, 0x0D, 0x0F, 0x00, 0x00, 0x00 },
|
||||
{ 0x20, 0x21, 0x2B, 0x06, 0x85, 0xF1, 0x6D, 0x89, 0x00, 0x00, 0x00 },
|
||||
{ 0x01, 0x21, 0xBF, 0x02, 0x53, 0x62, 0x5F, 0xAE, 0x01, 0x00, 0x00 },
|
||||
{ 0x23, 0x21, 0x70, 0x07, 0xD4, 0xA3, 0x4E, 0x64, 0x01, 0x00, 0x00 },
|
||||
{ 0x2B, 0x21, 0xA4, 0x07, 0xF6, 0x93, 0x5C, 0x4D, 0x00, 0x00, 0x00 },
|
||||
{ 0x21, 0x23, 0xAD, 0x07, 0x77, 0xF1, 0x18, 0x37, 0x00, 0x00, 0x00 },
|
||||
{ 0x21, 0x21, 0x2A, 0x03, 0xF3, 0xE2, 0x29, 0x46, 0x00, 0x00, 0x00 },
|
||||
{ 0x21, 0x23, 0x37, 0x03, 0xF3, 0xE2, 0x29, 0x46, 0x00, 0x00, 0x00 },
|
||||
#else /* Instrument settings from Allegro */
|
||||
{ 0x31, 0x21, 0x15, 0x09, 0xdd, 0x56, 0x13, 0x26, 0x01, 0x00, 0x08 }, /* Violin */
|
||||
{ 0x03, 0x11, 0x54, 0x09, 0xf3, 0xf1, 0x9a, 0xe7, 0x01, 0x00, 0x0c }, /* Acoustic Guitar(steel) */
|
||||
{ 0x21, 0x21, 0x8f, 0x0c, 0xf2, 0xf2, 0x45, 0x76, 0x00, 0x00, 0x08 }, /* Acoustic Grand */
|
||||
{ 0xe1, 0xe1, 0x46, 0x09, 0x88, 0x65, 0x5f, 0x1a, 0x00, 0x00, 0x00 }, /* Flute */
|
||||
{ 0x32, 0x21, 0x90, 0x09, 0x9b, 0x72, 0x21, 0x17, 0x00, 0x00, 0x04 }, /* Clarinet */
|
||||
{ 0x21, 0x21, 0x4b, 0x09, 0xaa, 0x8f, 0x16, 0x0a, 0x01, 0x00, 0x08 }, /* Oboe */
|
||||
{ 0x21, 0x21, 0x92, 0x0a, 0x85, 0x8f, 0x17, 0x09, 0x00, 0x00, 0x0c }, /* Trumpet */
|
||||
{ 0x23, 0xb1, 0x93, 0x09, 0x97, 0x55, 0x23, 0x14, 0x01, 0x00, 0x04 }, /* Church Organ */
|
||||
{ 0x21, 0x21, 0x9b, 0x09, 0x61, 0x7f, 0x6a, 0x0a, 0x00, 0x00, 0x02 }, /* French Horn */
|
||||
{ 0x71, 0x72, 0x57, 0x09, 0x54, 0x7a, 0x05, 0x05, 0x00, 0x00, 0x0c }, /* Synth Voice */
|
||||
{ 0x21, 0x36, 0x80, 0x17, 0xa2, 0xf1, 0x01, 0xd5, 0x00, 0x00, 0x08 }, /* Harpsichord */
|
||||
{ 0x18, 0x81, 0x62, 0x09, 0xf3, 0xf2, 0xe6, 0xf6, 0x00, 0x00, 0x00 }, /* Vibraphone */
|
||||
{ 0x31, 0x31, 0x8b, 0x09, 0xf4, 0xf1, 0xe8, 0x78, 0x00, 0x00, 0x0a }, /* Synth Bass 1 */
|
||||
{ 0x21, 0xa2, 0x1e, 0x09, 0x94, 0xc3, 0x06, 0xa6, 0x00, 0x00, 0x02 }, /* Acoustic Bass */
|
||||
{ 0x03, 0x21, 0x87, 0x89, 0xf6, 0xf3, 0x22, 0xf8, 0x01, 0x00, 0x06 }, /* Electric Guitar(clean) */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
void ym2413_init(int count)
|
||||
{
|
||||
int n;
|
||||
for(n = 0; n < count; n += 1)
|
||||
{
|
||||
/* Reset YM2413 data */
|
||||
ym2413_reset(n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ym2413_reset(int chip)
|
||||
{
|
||||
int n;
|
||||
|
||||
/* Point to current YM2413 context */
|
||||
t_ym2413 *opll = &ym2413[chip];
|
||||
|
||||
/* Clear channel data context */
|
||||
memset(opll, 0, sizeof(t_ym2413));
|
||||
|
||||
/* Clear all YM3812 registers */
|
||||
for(n = 0; n < 0x100; n += 1)
|
||||
{
|
||||
OPL_WRITE(chip, n, 0x00);
|
||||
}
|
||||
|
||||
/* Turn off rhythm mode and key-on bits */
|
||||
opll->rhythm = 0;
|
||||
OPL_WRITE(chip, 0xBD, 0x00);
|
||||
|
||||
/* Enable waveform select */
|
||||
OPL_WRITE(chip, 0x01, 0x20);
|
||||
}
|
||||
|
||||
|
||||
void ym2413_write(int chip, int address, int data)
|
||||
{
|
||||
/* Point to current YM2413 context */
|
||||
t_ym2413 *opll = &ym2413[chip];
|
||||
|
||||
if(address & 1) /* Data port */
|
||||
{
|
||||
/* Store register data */
|
||||
opll->reg[opll->latch] = data;
|
||||
|
||||
switch(opll->latch & 0x30)
|
||||
{
|
||||
case 0x00: /* User instrument registers */
|
||||
switch(opll->latch & 0x0F)
|
||||
{
|
||||
case 0x00: /* Misc. ctrl. (modulator) */
|
||||
case 0x01: /* Misc. ctrl. (carrier) */
|
||||
case 0x02: /* Key scale level and total level (modulator) */
|
||||
case 0x04: /* Attack / Decay (modulator) */
|
||||
case 0x05: /* Attack / Decay (carrier) */
|
||||
case 0x06: /* Sustain / Release (modulator) */
|
||||
case 0x07: /* Sustain / Release (carrier) */
|
||||
opll->user[(opll->latch & 0x07)] = data;
|
||||
break;
|
||||
|
||||
case 0x03: /* Key scale level, carrier/modulator waveform, feedback */
|
||||
|
||||
/* Key scale level (carrier) */
|
||||
/* Don't touch the total level (channel volume) */
|
||||
opll->user[3] = (opll->user[3] & 0x3F) | (data & 0xC0);
|
||||
|
||||
/* Waveform select for the modulator */
|
||||
opll->user[8] = (data >> 3) & 1;
|
||||
|
||||
/* Waveform select for the carrier */
|
||||
opll->user[9] = (data >> 4) & 1;
|
||||
|
||||
/* Store feedback level in YM3812 format */
|
||||
opll->user[10] = ((data & 0x07) << 1) & 0x0E;
|
||||
break;
|
||||
|
||||
case 0x0E: /* Rhythm enable and key-on bits */
|
||||
if((data & 0x20) && (opll->rhythm == 0))
|
||||
{
|
||||
opll->rhythm = 1;
|
||||
rhythm_mode_init(chip);
|
||||
}
|
||||
else
|
||||
{
|
||||
opll->rhythm = 0;
|
||||
}
|
||||
OPL_WRITE(chip, 0xBD, (data & 0x3F));
|
||||
break;
|
||||
}
|
||||
|
||||
/* If the user instrument registers were accessed, then
|
||||
go through each channel and update the ones that were
|
||||
currently using the user instrument. We can skip the
|
||||
last three channels in rhythm mode since they can
|
||||
only use percussion sounds anyways. */
|
||||
if(opll->latch <= 0x07)
|
||||
{
|
||||
int x;
|
||||
for(x = 0; x < ((opll->reg[0x0E] & 0x20) ? 6 : 9); x += 1)
|
||||
if(opll->channel[x].instrument == 0x00)
|
||||
load_instrument(chip, x, 0x00, opll->channel[x].volume);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x10: /* Channel Frequency (LSB) */
|
||||
case 0x20: /* Channel Frequency (MSB) + key-on and sustain control */
|
||||
{
|
||||
int block;
|
||||
int frequency;
|
||||
int ch = (opll->latch & 0x0F);
|
||||
|
||||
/* Ensure proper channel range */
|
||||
if(ch > 0x08) break;
|
||||
|
||||
/* Get YM2413 channel frequency */
|
||||
frequency = ((opll->reg[0x10 + ch] & 0xFF) | ((opll->reg[0x20 + ch] & 0x01) << 8));
|
||||
|
||||
/* Scale 9 bit frequency to 10 bits */
|
||||
frequency = (frequency << 1) & 0x1FFF;
|
||||
|
||||
/* Get YM2413 block */
|
||||
block = (opll->reg[0x20 + ch] >> 1) & 7;
|
||||
|
||||
/* Add in block */
|
||||
frequency |= (block << 10);
|
||||
|
||||
/* Add key-on flag */
|
||||
if(opll->reg[0x20 + ch] & 0x10) frequency |= 0x2000;
|
||||
|
||||
/* Save current frequency/block/key-on setting */
|
||||
opll->channel[ch].frequency = (frequency & 0x3FFF);
|
||||
|
||||
/* TODO: Handle sustain flag (bit 5) before key-on */
|
||||
|
||||
/* Write changes to YM3812 */
|
||||
OPL_WRITE(chip, 0xA0 + ch, (opll->channel[ch].frequency >> 0) & 0xFF);
|
||||
OPL_WRITE(chip, 0xB0 + ch, (opll->channel[ch].frequency >> 8) & 0xFF);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x30: /* Channel Volume Level and Instrument Select */
|
||||
|
||||
/* Ensure proper channel range */
|
||||
if(opll->latch > 0x38) break;
|
||||
|
||||
/* If we're accessing registers 36, 37, or 38, and we're
|
||||
in rhythm mode, then update the individual volume
|
||||
settings. */
|
||||
if((opll->latch >= 0x36) && (opll->reg[0x0E] & 0x20))
|
||||
{
|
||||
switch(opll->latch & 0x0F)
|
||||
{
|
||||
case 0x06: /* Bass drum */
|
||||
OPL_WRITE(chip, 0x53, ((data >> 0) & 0x0F) << 2);
|
||||
break;
|
||||
|
||||
case 0x07: /* High hat and snare drum */
|
||||
OPL_WRITE(chip, 0x51, ((data >> 4) & 0x0F) << 2);
|
||||
OPL_WRITE(chip, 0x54, ((data >> 0) & 0x0F) << 2);
|
||||
break;
|
||||
|
||||
case 0x08: /* Tom-top and top cymbal */
|
||||
OPL_WRITE(chip, 0x52, ((data >> 4) & 0x0F) << 2);
|
||||
OPL_WRITE(chip, 0x55, ((data >> 0) & 0x0F) << 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else /* Set the new instrument and volume for this channel */
|
||||
{
|
||||
int ch = (opll->latch & 0x0F);
|
||||
int inst = (data >> 4) & 0x0F;
|
||||
int vol = (data & 0x0F) << 2;
|
||||
|
||||
load_instrument(chip, ch, inst, vol);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else /* Register latch */
|
||||
{
|
||||
opll->latch = (data & 0x3F);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void rhythm_mode_init(int chip)
|
||||
{
|
||||
/* Point to current YM2413 context */
|
||||
t_ym2413 *opll = &ym2413[chip];
|
||||
|
||||
/* Load instrument settings for channel seven. (Bass drum) */
|
||||
OPL_WRITE(chip, 0x30, 0x13);
|
||||
OPL_WRITE(chip, 0x33, 0x11);
|
||||
OPL_WRITE(chip, 0x50, 0x25);
|
||||
OPL_WRITE(chip, 0x53, ((opll->reg[0x36] >> 0) & 0x0F) << 2);
|
||||
OPL_WRITE(chip, 0x70, 0xD7);
|
||||
OPL_WRITE(chip, 0x73, 0xB7);
|
||||
OPL_WRITE(chip, 0x90, 0xF4);
|
||||
OPL_WRITE(chip, 0x93, 0xF4);
|
||||
OPL_WRITE(chip, 0xF0, 0x00);
|
||||
OPL_WRITE(chip, 0xF3, 0x00);
|
||||
OPL_WRITE(chip, 0xC6, 0x00);
|
||||
/* Use old frequency, but strip key-on bit */
|
||||
OPL_WRITE(chip, 0xA6, (opll->channel[6].frequency >> 0) & 0xFF);
|
||||
OPL_WRITE(chip, 0xB6, (opll->channel[6].frequency >> 8) & 0x1F);
|
||||
|
||||
/* Load instrument settings for channel eight. (High hat and snare drum) */
|
||||
OPL_WRITE(chip, 0x31, 0x13);
|
||||
OPL_WRITE(chip, 0x34, 0x11);
|
||||
OPL_WRITE(chip, 0x51, ((opll->reg[0x37] >> 4) & 0x0f) << 2);
|
||||
OPL_WRITE(chip, 0x54, ((opll->reg[0x37] >> 0) & 0x0f) << 2);
|
||||
OPL_WRITE(chip, 0x71, 0xD7);
|
||||
OPL_WRITE(chip, 0x74, 0xB7);
|
||||
OPL_WRITE(chip, 0x91, 0xF4);
|
||||
OPL_WRITE(chip, 0x94, 0xF4);
|
||||
OPL_WRITE(chip, 0xF1, 0x00);
|
||||
OPL_WRITE(chip, 0xF4, 0x00);
|
||||
OPL_WRITE(chip, 0xC7, 0x00);
|
||||
/* Use old frequency, but strip key-on bit */
|
||||
OPL_WRITE(chip, 0xA7, (opll->channel[7].frequency >> 0) & 0xFF);
|
||||
OPL_WRITE(chip, 0xB7, (opll->channel[7].frequency >> 8) & 0x1F);
|
||||
|
||||
/* Load instrument settings for channel nine. (Tom-tom and top cymbal) */
|
||||
OPL_WRITE(chip, 0x32, 0x13);
|
||||
OPL_WRITE(chip, 0x35, 0x11);
|
||||
OPL_WRITE(chip, 0x52, ((opll->reg[0x38] >> 4) & 0x0F) << 2);
|
||||
OPL_WRITE(chip, 0x55, ((opll->reg[0x38] >> 0) & 0x0F) << 2);
|
||||
OPL_WRITE(chip, 0x72, 0xD7);
|
||||
OPL_WRITE(chip, 0x75, 0xB7);
|
||||
OPL_WRITE(chip, 0x92, 0xF4);
|
||||
OPL_WRITE(chip, 0x95, 0xF4);
|
||||
OPL_WRITE(chip, 0xF2, 0x00);
|
||||
OPL_WRITE(chip, 0xF5, 0x00);
|
||||
OPL_WRITE(chip, 0xC8, 0x00);
|
||||
/* Use old frequency, but strip key-on bit */
|
||||
OPL_WRITE(chip, 0xA8, (opll->channel[8].frequency >> 0) & 0xFF);
|
||||
OPL_WRITE(chip, 0xB8, (opll->channel[8].frequency >> 8) & 0x1F);
|
||||
}
|
||||
|
||||
|
||||
/* channel (0-9), instrument (0-F), volume (0-3F, YM3812 format) */
|
||||
void load_instrument(int chip, int ch, int inst, int vol)
|
||||
{
|
||||
/* Point to current YM2413 context */
|
||||
t_ym2413 *opll = &ym2413[chip];
|
||||
|
||||
/* Point to fixed instrument or user table */
|
||||
unsigned char *param = (inst == 0) ? &opll->user[0] : &table[inst][0];
|
||||
|
||||
/* Maps channels to operator registers */
|
||||
unsigned char ch2op[] = {0, 1, 2, 8, 9, 10, 16, 17, 18};
|
||||
|
||||
/* Make operator offset from requested channel */
|
||||
int op = ch2op[ch];
|
||||
|
||||
/* Store volume level */
|
||||
opll->channel[ch].volume = (vol & 0x3F);
|
||||
|
||||
/* Store instrument number */
|
||||
opll->channel[ch].instrument = (inst & 0x0F);
|
||||
|
||||
/* Update instrument settings, except frequency registers */
|
||||
OPL_WRITE(chip, 0x20 + op, param[0]);
|
||||
OPL_WRITE(chip, 0x23 + op, param[1]);
|
||||
OPL_WRITE(chip, 0x40 + op, param[2]);
|
||||
OPL_WRITE(chip, 0x43 + op, (param[3] & 0xC0) | opll->channel[ch].volume);
|
||||
OPL_WRITE(chip, 0x60 + op, param[4]);
|
||||
OPL_WRITE(chip, 0x63 + op, param[5]);
|
||||
OPL_WRITE(chip, 0x80 + op, param[6]);
|
||||
OPL_WRITE(chip, 0x83 + op, param[7]);
|
||||
OPL_WRITE(chip, 0xE0 + op, param[8]);
|
||||
OPL_WRITE(chip, 0xE3 + op, param[9]);
|
||||
OPL_WRITE(chip, 0xC0 + ch, param[10]);
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
|
||||
#ifndef _YM2413_H_
|
||||
#define _YM2413_H_
|
||||
|
||||
/* Total # of YM2413's that can be used at once - change as needed */
|
||||
#define MAX_YM2413 (4)
|
||||
|
||||
/* YM2413 context */
|
||||
typedef struct
|
||||
{
|
||||
unsigned char reg[0x40]; /* 64 registers */
|
||||
unsigned char latch; /* Register latch */
|
||||
unsigned char rhythm; /* Rhythm instruments loaded flag */
|
||||
unsigned char user[0x10]; /* User instrument settings */
|
||||
struct
|
||||
{
|
||||
unsigned short int frequency; /* Channel frequency */
|
||||
unsigned char volume; /* Channel volume */
|
||||
unsigned char instrument; /* Channel instrument */
|
||||
}channel[9];
|
||||
}t_ym2413;
|
||||
|
||||
/* Global data */
|
||||
extern t_ym2413 ym2413[MAX_YM2413];
|
||||
|
||||
/* Function prototypes */
|
||||
void ym2413_init(int count);
|
||||
void ym2413_reset(int chip);
|
||||
void ym2413_write(int chip, int address, int data);
|
||||
void load_instrument(int chip, int ch, int inst, int vol);
|
||||
void rhythm_mode_init(int chip);
|
||||
|
||||
#endif /* _YM2413_H_ */
|
Plik diff jest za duży
Load Diff
|
@ -0,0 +1,76 @@
|
|||
#ifndef Z80_H
|
||||
#define Z80_H
|
||||
|
||||
|
||||
/*#define CLEAR_LINE 0*/ /* clear (a fired, held or pulsed) line */
|
||||
/*#define ASSERT_LINE 1*/ /* assert an interrupt immediately */
|
||||
|
||||
#include "cpuintrf.h"
|
||||
|
||||
enum {
|
||||
Z80_PC=1, Z80_SP, Z80_AF, Z80_BC, Z80_DE, Z80_HL,
|
||||
Z80_IX, Z80_IY, Z80_AF2, Z80_BC2, Z80_DE2, Z80_HL2,
|
||||
Z80_R, Z80_I, Z80_IM, Z80_IFF1, Z80_IFF2, Z80_HALT,
|
||||
Z80_NMI_STATE, Z80_IRQ_STATE, Z80_DC0, Z80_DC1, Z80_DC2, Z80_DC3,
|
||||
Z80_NMI_NESTING
|
||||
};
|
||||
|
||||
extern int z80_ICount; /* T-state count */
|
||||
|
||||
#define Z80_IGNORE_INT -1 /* Ignore interrupt */
|
||||
#define Z80_NMI_INT -2 /* Execute NMI */
|
||||
#define Z80_IRQ_INT -1000 /* Execute IRQ */
|
||||
|
||||
/* Port number written to when entering/leaving HALT state */
|
||||
#define Z80_HALT_PORT 0x10000
|
||||
|
||||
extern void z80_reset (void *param);
|
||||
extern void z80_exit (void);
|
||||
extern int z80_execute(int cycles);
|
||||
extern void z80_burn(int cycles);
|
||||
extern unsigned z80_get_context (void *dst);
|
||||
extern void z80_set_context (void *src);
|
||||
extern unsigned z80_get_pc (void);
|
||||
extern void z80_set_pc (unsigned val);
|
||||
extern unsigned z80_get_sp (void);
|
||||
extern void z80_set_sp (unsigned val);
|
||||
extern unsigned z80_get_reg (int regnum);
|
||||
extern void z80_set_reg (int regnum, unsigned val);
|
||||
extern void z80_set_nmi_line(int state);
|
||||
extern void z80_set_irq_line(int irqline, int state);
|
||||
extern void z80_set_irq_callback(int (*irq_callback)(int));
|
||||
extern void z80_state_save(void *file);
|
||||
extern void z80_state_load(void *file);
|
||||
extern const char *z80_info(void *context, int regnum);
|
||||
extern unsigned z80_dasm(char *buffer, unsigned pc);
|
||||
|
||||
#ifdef MAME_DEBUG
|
||||
extern unsigned DasmZ80(char *buffer, unsigned pc);
|
||||
#endif
|
||||
|
||||
/****************************************************************************/
|
||||
/* The Z80 registers. HALT is set to 1 when the CPU is halted, the refresh */
|
||||
/* register is calculated as follows: refresh=(Regs.R&127)|(Regs.R2&128) */
|
||||
/****************************************************************************/
|
||||
typedef struct {
|
||||
/* 00 */ PAIR PREPC,PC,SP,AF,BC,DE,HL,IX,IY;
|
||||
/* 24 */ PAIR AF2,BC2,DE2,HL2;
|
||||
/* 34 */ UINT8 R,R2,IFF1,IFF2,HALT,IM,I;
|
||||
/* 3B */ UINT8 irq_max; /* number of daisy chain devices */
|
||||
/* 3C */ INT8 request_irq; /* daisy chain next request device */
|
||||
/* 3D */ INT8 service_irq; /* daisy chain next reti handling device */
|
||||
/* 3E */ UINT8 nmi_state; /* nmi line state */
|
||||
/* 3F */ UINT8 irq_state; /* irq line state */
|
||||
/* 40 */ UINT8 int_state[Z80_MAXDAISY];
|
||||
/* 44 */ Z80_DaisyChain irq[Z80_MAXDAISY];
|
||||
/* 84 */ int (*irq_callback)(int irqline);
|
||||
/* 88 */ int extra_cycles; /* extra cycles for interrupts */
|
||||
} Z80_Regs;
|
||||
|
||||
extern Z80_Regs *Z80_Context;
|
||||
extern int after_EI;
|
||||
extern unsigned char *cpu_readmap[8];
|
||||
extern unsigned char *cpu_writemap[8];
|
||||
|
||||
#endif
|
||||
|
Plik diff jest za duży
Load Diff
Ładowanie…
Reference in New Issue