add SMS emu to TEECOMPUTER

pull/16/head
jean-marcharvengt 2022-02-20 15:10:13 +01:00
rodzic b064204c27
commit bc854b7c3b
39 zmienionych plików z 47894 dodań i 0 usunięć

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -0,0 +1,7 @@
#ifndef _ARDUINOPROTO_H_
#define _ARDUINOPROTO_H_
#include <Arduino.h>
//#define PROGMEM
#endif

Wyświetl plik

@ -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 */

Wyświetl plik

@ -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
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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
};

Wyświetl plik

@ -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

Wyświetl plik

@ -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--;
}
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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_ */

Wyświetl plik

@ -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_ */

Wyświetl plik

@ -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);
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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]);
}
}
}

Wyświetl plik

@ -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_ */

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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)]);
}

Wyświetl plik

@ -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_ */

Wyświetl plik

@ -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

Wyświetl plik

@ -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]);
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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