add support for pt8211 DAC

pull/16/head
jean-marcharvengt 2022-04-24 20:50:09 +02:00
rodzic e6e0ec864b
commit 2a69fb40ec
179 zmienionych plików z 513464 dodań i 471101 usunięć

Wyświetl plik

@ -339,14 +339,14 @@
:1015100043F080731360434A136843F00103136080
:10152000414B1A68414B1A6000F076FAC4F8047116
:101530003F48C4F80091C4F8F470C4F8F08000F09B
:10154000FBFBF36E43F44053F3663A4B1D60C3F864
:1015400007FCF36E43F44053F3663A4B1D60C3F857
:101550000851C3F81851C3F82851C3F8385103F59E
:10156000A0239A6BD20708D4334A5A6542F6156213
:101570001A659A6B42F001029A639A6842F001126E
:101580009A6000F0FFF800F09FFB00F0DDFB00F038
:1015900071FA00F086F8294A1368284C132BFBD9FE
:1015A00000F0F6FA2368B3F5967FFBD300F07AF8E3
:1015B00000F0BAFB00F0C4FB30BFFDE7BFAAAAAA47
:1015B00000F0C6FB00F0B4FB30BFFDE7BFAAAAAA4B
:1015C00000C00A40070020000080062000800D4077
:1015D0007C2200600000000000330100C02E0020CB
:1015E000805501600000002060E10020C02E002036
@ -409,9 +409,9 @@
:101970003046FFF769FE4FF40000FFF779FEA842FA
:1019800007D14FF400010420FFF75EFE10232370FF
:1019900001E0082323701D4900231D4A2078521AB4
:1019A0000093012302EB00521A4800F0B9F902B08B
:1019A0000093012302EB00521A4800F0BDF902B087
:1019B00070BD10222146174802B0BDE8704000F00B
:1019C000C7B900BF00801F40F9B00100F910010045
:1019C000BBB900BF00801F40F9B00100F910010051
:1019D00000C00F4000402A401200FFFF00802A4054
:1019E00000FFF07C63000200FF000F8300432A40E9
:1019F000F05AF05A00422A409F041830EB06180AA9
@ -448,7 +448,7 @@
:101BE00040319B07FBD44FF400321D4B19201A6083
:101BF0004FF00042194B9A6300F09AF8174B0021FE
:101C00004FF08042174D144C9A63284619600A23FE
:101C10004FF42072C4F8A83100F09AF84FF4810311
:101C10004FF42072C4F8A83100F08EF84FF481031D
:101C2000114A2B604FF480032B6440F24313C4F835
:101C30005851C4F848310D4BC3F804220C4B4FF4F3
:101C400000321A600123C4F8403138BD00800D40D5
@ -465,10 +465,10 @@
:101CF00040F237625A64A0229A649A6C12F0800211
:101D0000FBD1034B1A70704700C00F4000800C409D
:101D100045640020F8B500BFF8BC08BC9E4670477B
:101D20005FF800F0671E01005FF800F0112201006B
:101D30005FF800F0850201005FF800F06D1A010005
:101D40005FF800F0551901005FF800F0A91D0100CF
:101D50005FF800F0E50101005FF800F0710D01008F
:101D20005FF800F0551901005FF800F0671E010030
:101D30005FF800F0850201005FF800F0E5010100A6
:101D40005FF800F0112201005FF800F0A91D01000A
:101D50005FF800F06D1A01005FF800F0710D0100EE
:101D600045000000A15D00004D600000796C00009E
:041D7000F5A50000D5
:101D7400090180961180FF3A81550A3601082A0428

Wyświetl plik

@ -339,14 +339,14 @@
:1015100043F080731360434A136843F00103136080
:10152000414B1A68414B1A6000F076FAC4F8047116
:101530003F48C4F80091C4F8F470C4F8F08000F09B
:1015400007FCF36E43F44053F3663A4B1D60C3F857
:10154000FBFBF36E43F44053F3663A4B1D60C3F864
:101550000851C3F81851C3F82851C3F8385103F59E
:10156000A0239A6BD20708D4334A5A6542F6156213
:101570001A659A6B42F001029A639A6842F001126E
:101580009A6000F0FFF800F09FFB00F0E5FB00F030
:101580009A6000F0FFF800F09FFB00F0E1FB00F034
:1015900071FA00F086F8294A1368284C132BFBD9FE
:1015A00000F0F6FA2368B3F5967FFBD300F07AF8E3
:1015B00000F0B6FB00F0C0FB30BFFDE7BFAAAAAA4F
:1015B00000F0CAFB00F0C4FB30BFFDE7BFAAAAAA37
:1015C00000C00A40070020000080062000800D4077
:1015D000582200600000000050330100C02E00209F
:1015E000AC55016000000020E0DF0020C02E00208C
@ -409,9 +409,9 @@
:101970003046FFF769FE4FF40000FFF779FEA842FA
:1019800007D14FF400010420FFF75EFE10232370FF
:1019900001E0082323701D4900231D4A2078521AB4
:1019A0000093012302EB00521A4800F0CDF902B077
:1019A0000093012302EB00521A4800F0C1F902B083
:1019B00070BD10222146174802B0BDE8704000F00B
:1019C000BFB900BF00801F40F9B00100F91001004D
:1019C000CBB900BF00801F40F9B00100F910010041
:1019D00000C00F4000402A401200FFFF00802A4054
:1019E00000FFF07C63000200FF000F8300432A40E9
:1019F000F05AF05A00422A409F041830EB06180AA9
@ -446,9 +446,9 @@
:101BC00019B9D3F8A811890718D04FF00041516313
:101BD000D3F8402142F00202C3F840211E4AD2F855
:101BE00040319B07FBD44FF400321D4B19201A6083
:101BF0004FF00042194B9A6300F09AF8174B0021FE
:101BF0004FF00042194B9A6300F092F8174B002106
:101C00004FF08042174D144C9A63284619600A23FE
:101C10004FF42072C4F8A83100F092F84FF4810319
:101C10004FF42072C4F8A83100F09EF84FF481030D
:101C2000114A2B604FF480032B6440F24313C4F835
:101C30005851C4F848310D4BC3F804220C4B4FF4F3
:101C400000321A600123C4F8403138BD00800D40D5
@ -465,10 +465,10 @@
:101CF00040F237625A64A0229A649A6C12F0800211
:101D0000FBD1034B1A70704700C00F4000800C409D
:101D1000C1620020F8B500BFF8BC08BC9E46704701
:101D20005FF800F0612201005FF800F0950C0100FF
:101D30005FF800F0A90101005FF800F0A5190100AB
:101D40005FF800F0090101005FF800F0B71E010024
:101D50005FF800F0BD1A01005FF800F0F91D010006
:101D20005FF800F0A90101005FF800F0950C0100D8
:101D30005FF800F0B71E01005FF800F0BD1A010067
:101D40005FF800F0A51901005FF800F061220100C2
:101D50005FF800F0F91D01005FF800F009010100D3
:101D600015020000515F0000F9610000BD6B00002A
:041D7000DDA00000F2
:101D7400000000000000000000000000000000005F

Wyświetl plik

@ -176,7 +176,6 @@ void AudioPlaySystem::step(void) {
}
#ifndef HAS_T4_VGA
/*******************************************************************
Experimental I2S interrupt based sound driver for PCM51xx !!!
*******************************************************************/
@ -263,7 +262,57 @@ FLASHMEM static void config_sai1()
I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE ;//<-- not using DMA */;
}
FLASHMEM static void config_pt8211()
{
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(0);
I2S1_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_BCP | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(1);
I2S1_TCR3 = I2S_TCR3_TCE;
I2S1_TCR4 = I2S_TCR4_FRSZ(1) | I2S_TCR4_SYWD(15) | I2S_TCR4_MF | I2S_TCR4_FSD /*| I2S_TCR4_FSE*/ | I2S_TCR4_FSP ; //PT8211
I2S1_TCR5 = I2S_TCR5_WNW(15) | I2S_TCR5_W0W(15) | I2S_TCR5_FBT(15);
I2S1_RMR = 0;
I2S1_RCR1 = I2S_RCR1_RFW(0);
I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_RCR2_BCP | I2S_RCR2_MSEL(1)| I2S_RCR2_BCD | I2S_RCR2_DIV(1) ;
I2S1_RCR3 = I2S_RCR3_RCE;
I2S1_RCR4 = I2S_RCR4_FRSZ(1) | I2S_RCR4_SYWD(15) | I2S_RCR4_MF /*| I2S_RCR4_FSE*/ | I2S_RCR4_FSP | I2S_RCR4_FSD; //PT8211
I2S1_RCR5 = I2S_RCR5_WNW(15) | I2S_RCR5_W0W(15) | I2S_RCR5_FBT(15);
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];
@ -277,7 +326,6 @@ 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];
@ -335,7 +383,14 @@ FLASHMEM void AudioPlaySystem::begin_audio(int samplesize, void (*callback)(shor
sampleBufferSize = samplesize;
#ifdef PT8211
txreg = (uint16_t *)((uint32_t)&I2S1_TDR0);
config_pt8211();
#else
txreg = (uint16_t *)((uint32_t)&I2S1_TDR0 + 2);
config_sai1();
#endif
attachInterruptVector(IRQ_SAI1, AUDIO_isr);
NVIC_ENABLE_IRQ(IRQ_SAI1);
NVIC_SET_PRIORITY(IRQ_QTIMER3, 0); // 0 highest priority, 255 = lowest priority
@ -358,4 +413,3 @@ FLASHMEM void AudioPlaySystem::end_audio()
}
#endif
#endif

Wyświetl plik

@ -19,13 +19,10 @@ public:
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
static void SOFTWARE_isr(void);
};

Wyświetl plik

@ -11,6 +11,8 @@
#define HAS_SND 1
#define HAS_USBKEY 1
#define INVX 1
#define PT8211 1
#else
#define HAS_T4_VGA 1

Wyświetl plik

@ -171,13 +171,7 @@ 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.begin_audio(256, mymixer.snd_Mixer);
mymixer.start();
}

Wyświetl plik

@ -176,7 +176,6 @@ void AudioPlaySystem::step(void) {
}
#ifndef HAS_T4_VGA
/*******************************************************************
Experimental I2S interrupt based sound driver for PCM51xx !!!
*******************************************************************/
@ -263,7 +262,57 @@ FLASHMEM static void config_sai1()
I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE ;//<-- not using DMA */;
}
FLASHMEM static void config_pt8211()
{
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(0);
I2S1_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_BCP | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(1);
I2S1_TCR3 = I2S_TCR3_TCE;
I2S1_TCR4 = I2S_TCR4_FRSZ(1) | I2S_TCR4_SYWD(15) | I2S_TCR4_MF | I2S_TCR4_FSD /*| I2S_TCR4_FSE*/ | I2S_TCR4_FSP ; //PT8211
I2S1_TCR5 = I2S_TCR5_WNW(15) | I2S_TCR5_W0W(15) | I2S_TCR5_FBT(15);
I2S1_RMR = 0;
I2S1_RCR1 = I2S_RCR1_RFW(0);
I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_RCR2_BCP | I2S_RCR2_MSEL(1)| I2S_RCR2_BCD | I2S_RCR2_DIV(1) ;
I2S1_RCR3 = I2S_RCR3_RCE;
I2S1_RCR4 = I2S_RCR4_FRSZ(1) | I2S_RCR4_SYWD(15) | I2S_RCR4_MF /*| I2S_RCR4_FSE*/ | I2S_RCR4_FSP | I2S_RCR4_FSD; //PT8211
I2S1_RCR5 = I2S_RCR5_WNW(15) | I2S_RCR5_W0W(15) | I2S_RCR5_FBT(15);
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];
@ -277,7 +326,6 @@ 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];
@ -335,7 +383,14 @@ FLASHMEM void AudioPlaySystem::begin_audio(int samplesize, void (*callback)(shor
sampleBufferSize = samplesize;
#ifdef PT8211
txreg = (uint16_t *)((uint32_t)&I2S1_TDR0);
config_pt8211();
#else
txreg = (uint16_t *)((uint32_t)&I2S1_TDR0 + 2);
config_sai1();
#endif
attachInterruptVector(IRQ_SAI1, AUDIO_isr);
NVIC_ENABLE_IRQ(IRQ_SAI1);
NVIC_SET_PRIORITY(IRQ_QTIMER3, 0); // 0 highest priority, 255 = lowest priority
@ -358,4 +413,3 @@ FLASHMEM void AudioPlaySystem::end_audio()
}
#endif
#endif

Wyświetl plik

@ -19,13 +19,10 @@ public:
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
static void SOFTWARE_isr(void);
};

Wyświetl plik

@ -11,6 +11,8 @@
#define HAS_SND 1
#define HAS_USBKEY 1
#define INVX 1
#define PT8211 1
#else
#define HAS_T4_VGA 1

Wyświetl plik

@ -171,13 +171,7 @@ 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.begin_audio(256, mymixer.snd_Mixer);
mymixer.start();
}

Wyświetl plik

@ -176,7 +176,6 @@ void AudioPlaySystem::step(void) {
}
#ifndef HAS_T4_VGA
/*******************************************************************
Experimental I2S interrupt based sound driver for PCM51xx !!!
*******************************************************************/
@ -263,7 +262,57 @@ FLASHMEM static void config_sai1()
I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE ;//<-- not using DMA */;
}
FLASHMEM static void config_pt8211()
{
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(0);
I2S1_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_BCP | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(1);
I2S1_TCR3 = I2S_TCR3_TCE;
I2S1_TCR4 = I2S_TCR4_FRSZ(1) | I2S_TCR4_SYWD(15) | I2S_TCR4_MF | I2S_TCR4_FSD /*| I2S_TCR4_FSE*/ | I2S_TCR4_FSP ; //PT8211
I2S1_TCR5 = I2S_TCR5_WNW(15) | I2S_TCR5_W0W(15) | I2S_TCR5_FBT(15);
I2S1_RMR = 0;
I2S1_RCR1 = I2S_RCR1_RFW(0);
I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_RCR2_BCP | I2S_RCR2_MSEL(1)| I2S_RCR2_BCD | I2S_RCR2_DIV(1) ;
I2S1_RCR3 = I2S_RCR3_RCE;
I2S1_RCR4 = I2S_RCR4_FRSZ(1) | I2S_RCR4_SYWD(15) | I2S_RCR4_MF /*| I2S_RCR4_FSE*/ | I2S_RCR4_FSP | I2S_RCR4_FSD; //PT8211
I2S1_RCR5 = I2S_RCR5_WNW(15) | I2S_RCR5_W0W(15) | I2S_RCR5_FBT(15);
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];
@ -277,7 +326,6 @@ 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];
@ -335,7 +383,14 @@ FLASHMEM void AudioPlaySystem::begin_audio(int samplesize, void (*callback)(shor
sampleBufferSize = samplesize;
#ifdef PT8211
txreg = (uint16_t *)((uint32_t)&I2S1_TDR0);
config_pt8211();
#else
txreg = (uint16_t *)((uint32_t)&I2S1_TDR0 + 2);
config_sai1();
#endif
attachInterruptVector(IRQ_SAI1, AUDIO_isr);
NVIC_ENABLE_IRQ(IRQ_SAI1);
NVIC_SET_PRIORITY(IRQ_QTIMER3, 0); // 0 highest priority, 255 = lowest priority
@ -358,4 +413,3 @@ FLASHMEM void AudioPlaySystem::end_audio()
}
#endif
#endif

Wyświetl plik

@ -19,13 +19,10 @@ public:
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
static void SOFTWARE_isr(void);
};

Wyświetl plik

@ -245,9 +245,9 @@ static void Initialise(void)
//add_esc(0xe459, ESC_SIOV);
}
#define INV_KEY 0
#define INV_KEY 255
const int16_t keyboardAsciiConv[] = // Ascii to Spectrum keys
const int8_t keyboardAsciiConv[] = // Ascii to Spectrum keys
{
/* 0x00 */ INV_KEY,
/* 0x01 */ INV_KEY,

Wyświetl plik

@ -11,6 +11,8 @@
#define HAS_SND 1
#define HAS_USBKEY 1
#define INVX 1
#define PT8211 1
#else
#define HAS_T4_VGA 1

Wyświetl plik

@ -169,13 +169,7 @@ 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.begin_audio(256, mymixer.snd_Mixer);
mymixer.start();
}

Wyświetl plik

@ -176,7 +176,6 @@ void AudioPlaySystem::step(void) {
}
#ifndef HAS_T4_VGA
/*******************************************************************
Experimental I2S interrupt based sound driver for PCM51xx !!!
*******************************************************************/
@ -263,7 +262,57 @@ FLASHMEM static void config_sai1()
I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE ;//<-- not using DMA */;
}
FLASHMEM static void config_pt8211()
{
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(0);
I2S1_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_BCP | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(1);
I2S1_TCR3 = I2S_TCR3_TCE;
I2S1_TCR4 = I2S_TCR4_FRSZ(1) | I2S_TCR4_SYWD(15) | I2S_TCR4_MF | I2S_TCR4_FSD /*| I2S_TCR4_FSE*/ | I2S_TCR4_FSP ; //PT8211
I2S1_TCR5 = I2S_TCR5_WNW(15) | I2S_TCR5_W0W(15) | I2S_TCR5_FBT(15);
I2S1_RMR = 0;
I2S1_RCR1 = I2S_RCR1_RFW(0);
I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_RCR2_BCP | I2S_RCR2_MSEL(1)| I2S_RCR2_BCD | I2S_RCR2_DIV(1) ;
I2S1_RCR3 = I2S_RCR3_RCE;
I2S1_RCR4 = I2S_RCR4_FRSZ(1) | I2S_RCR4_SYWD(15) | I2S_RCR4_MF /*| I2S_RCR4_FSE*/ | I2S_RCR4_FSP | I2S_RCR4_FSD; //PT8211
I2S1_RCR5 = I2S_RCR5_WNW(15) | I2S_RCR5_W0W(15) | I2S_RCR5_FBT(15);
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];
@ -277,7 +326,6 @@ 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];
@ -335,7 +383,14 @@ FLASHMEM void AudioPlaySystem::begin_audio(int samplesize, void (*callback)(shor
sampleBufferSize = samplesize;
#ifdef PT8211
txreg = (uint16_t *)((uint32_t)&I2S1_TDR0);
config_pt8211();
#else
txreg = (uint16_t *)((uint32_t)&I2S1_TDR0 + 2);
config_sai1();
#endif
attachInterruptVector(IRQ_SAI1, AUDIO_isr);
NVIC_ENABLE_IRQ(IRQ_SAI1);
NVIC_SET_PRIORITY(IRQ_QTIMER3, 0); // 0 highest priority, 255 = lowest priority
@ -358,4 +413,3 @@ FLASHMEM void AudioPlaySystem::end_audio()
}
#endif
#endif

Wyświetl plik

@ -19,13 +19,10 @@ public:
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
static void SOFTWARE_isr(void);
};

Wyświetl plik

@ -11,6 +11,8 @@
#define HAS_SND 1
#define HAS_USBKEY 1
#define INVX 1
#define PT8211 1
#else
#define HAS_T4_VGA 1

Wyświetl plik

@ -173,13 +173,7 @@ 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.begin_audio(256, mymixer.snd_Mixer);
mymixer.start();
}

Wyświetl plik

@ -176,7 +176,6 @@ void AudioPlaySystem::step(void) {
}
#ifndef HAS_T4_VGA
/*******************************************************************
Experimental I2S interrupt based sound driver for PCM51xx !!!
*******************************************************************/
@ -263,7 +262,57 @@ FLASHMEM static void config_sai1()
I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE ;//<-- not using DMA */;
}
FLASHMEM static void config_pt8211()
{
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(0);
I2S1_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_BCP | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(1);
I2S1_TCR3 = I2S_TCR3_TCE;
I2S1_TCR4 = I2S_TCR4_FRSZ(1) | I2S_TCR4_SYWD(15) | I2S_TCR4_MF | I2S_TCR4_FSD /*| I2S_TCR4_FSE*/ | I2S_TCR4_FSP ; //PT8211
I2S1_TCR5 = I2S_TCR5_WNW(15) | I2S_TCR5_W0W(15) | I2S_TCR5_FBT(15);
I2S1_RMR = 0;
I2S1_RCR1 = I2S_RCR1_RFW(0);
I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_RCR2_BCP | I2S_RCR2_MSEL(1)| I2S_RCR2_BCD | I2S_RCR2_DIV(1) ;
I2S1_RCR3 = I2S_RCR3_RCE;
I2S1_RCR4 = I2S_RCR4_FRSZ(1) | I2S_RCR4_SYWD(15) | I2S_RCR4_MF /*| I2S_RCR4_FSE*/ | I2S_RCR4_FSP | I2S_RCR4_FSD; //PT8211
I2S1_RCR5 = I2S_RCR5_WNW(15) | I2S_RCR5_W0W(15) | I2S_RCR5_FBT(15);
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];
@ -277,7 +326,6 @@ 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];
@ -335,7 +383,14 @@ FLASHMEM void AudioPlaySystem::begin_audio(int samplesize, void (*callback)(shor
sampleBufferSize = samplesize;
#ifdef PT8211
txreg = (uint16_t *)((uint32_t)&I2S1_TDR0);
config_pt8211();
#else
txreg = (uint16_t *)((uint32_t)&I2S1_TDR0 + 2);
config_sai1();
#endif
attachInterruptVector(IRQ_SAI1, AUDIO_isr);
NVIC_ENABLE_IRQ(IRQ_SAI1);
NVIC_SET_PRIORITY(IRQ_QTIMER3, 0); // 0 highest priority, 255 = lowest priority
@ -358,4 +413,3 @@ FLASHMEM void AudioPlaySystem::end_audio()
}
#endif
#endif

Wyświetl plik

@ -19,13 +19,10 @@ public:
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
static void SOFTWARE_isr(void);
};

Wyświetl plik

@ -11,6 +11,8 @@
//#define HAS_SND 1
#define HAS_USBKEY 1
#define INVX 1
#define PT8211 1
#else
#define HAS_T4_VGA 1

Wyświetl plik

@ -171,13 +171,7 @@ 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.begin_audio(256, mymixer.snd_Mixer);
mymixer.start();
}

Wyświetl plik

@ -176,7 +176,6 @@ void AudioPlaySystem::step(void) {
}
#ifndef HAS_T4_VGA
/*******************************************************************
Experimental I2S interrupt based sound driver for PCM51xx !!!
*******************************************************************/
@ -263,7 +262,57 @@ FLASHMEM static void config_sai1()
I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE ;//<-- not using DMA */;
}
FLASHMEM static void config_pt8211()
{
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(0);
I2S1_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_BCP | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(1);
I2S1_TCR3 = I2S_TCR3_TCE;
I2S1_TCR4 = I2S_TCR4_FRSZ(1) | I2S_TCR4_SYWD(15) | I2S_TCR4_MF | I2S_TCR4_FSD /*| I2S_TCR4_FSE*/ | I2S_TCR4_FSP ; //PT8211
I2S1_TCR5 = I2S_TCR5_WNW(15) | I2S_TCR5_W0W(15) | I2S_TCR5_FBT(15);
I2S1_RMR = 0;
I2S1_RCR1 = I2S_RCR1_RFW(0);
I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_RCR2_BCP | I2S_RCR2_MSEL(1)| I2S_RCR2_BCD | I2S_RCR2_DIV(1) ;
I2S1_RCR3 = I2S_RCR3_RCE;
I2S1_RCR4 = I2S_RCR4_FRSZ(1) | I2S_RCR4_SYWD(15) | I2S_RCR4_MF /*| I2S_RCR4_FSE*/ | I2S_RCR4_FSP | I2S_RCR4_FSD; //PT8211
I2S1_RCR5 = I2S_RCR5_WNW(15) | I2S_RCR5_W0W(15) | I2S_RCR5_FBT(15);
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];
@ -277,7 +326,6 @@ 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];
@ -335,7 +383,14 @@ FLASHMEM void AudioPlaySystem::begin_audio(int samplesize, void (*callback)(shor
sampleBufferSize = samplesize;
#ifdef PT8211
txreg = (uint16_t *)((uint32_t)&I2S1_TDR0);
config_pt8211();
#else
txreg = (uint16_t *)((uint32_t)&I2S1_TDR0 + 2);
config_sai1();
#endif
attachInterruptVector(IRQ_SAI1, AUDIO_isr);
NVIC_ENABLE_IRQ(IRQ_SAI1);
NVIC_SET_PRIORITY(IRQ_QTIMER3, 0); // 0 highest priority, 255 = lowest priority
@ -358,4 +413,3 @@ FLASHMEM void AudioPlaySystem::end_audio()
}
#endif
#endif

Wyświetl plik

@ -19,13 +19,10 @@ public:
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
static void SOFTWARE_isr(void);
};

Wyświetl plik

@ -1017,9 +1017,14 @@ int handleMenu(uint16_t bClick)
action = ACTION_RUN2;
}
else if ( bClick & MASK_KEY_USER2 ) {
menuRedraw=true;
//action = ACTION_RUN3;
emu_SwapJoysticks(0);
menuRedraw=true;
char newpath[MAX_FILENAME_PATH];
strcpy(newpath, selection);
strcat(newpath, "/");
strcat(newpath, selected_filename);
strcpy(selection,newpath);
action = ACTION_RUN3;
//emu_SwapJoysticks(0);
}
else if ( (bClick & MASK_JOY2_UP) || (bClick & MASK_JOY1_UP) ) {
if (curFile!=0) {

Wyświetl plik

@ -12,6 +12,7 @@
#define HIRES 1
#define HAS_SND 1
#define HAS_USBKEY 1
#define PT8211 1
#else

Wyświetl plik

@ -208,13 +208,7 @@ 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.begin_audio(256, mymixer.snd_Mixer);
mymixer.start();
}

Wyświetl plik

@ -176,7 +176,6 @@ void AudioPlaySystem::step(void) {
}
#ifndef HAS_T4_VGA
/*******************************************************************
Experimental I2S interrupt based sound driver for PCM51xx !!!
*******************************************************************/
@ -263,7 +262,57 @@ FLASHMEM static void config_sai1()
I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE ;//<-- not using DMA */;
}
FLASHMEM static void config_pt8211()
{
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(0);
I2S1_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_BCP | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(1);
I2S1_TCR3 = I2S_TCR3_TCE;
I2S1_TCR4 = I2S_TCR4_FRSZ(1) | I2S_TCR4_SYWD(15) | I2S_TCR4_MF | I2S_TCR4_FSD /*| I2S_TCR4_FSE*/ | I2S_TCR4_FSP ; //PT8211
I2S1_TCR5 = I2S_TCR5_WNW(15) | I2S_TCR5_W0W(15) | I2S_TCR5_FBT(15);
I2S1_RMR = 0;
I2S1_RCR1 = I2S_RCR1_RFW(0);
I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_RCR2_BCP | I2S_RCR2_MSEL(1)| I2S_RCR2_BCD | I2S_RCR2_DIV(1) ;
I2S1_RCR3 = I2S_RCR3_RCE;
I2S1_RCR4 = I2S_RCR4_FRSZ(1) | I2S_RCR4_SYWD(15) | I2S_RCR4_MF /*| I2S_RCR4_FSE*/ | I2S_RCR4_FSP | I2S_RCR4_FSD; //PT8211
I2S1_RCR5 = I2S_RCR5_WNW(15) | I2S_RCR5_W0W(15) | I2S_RCR5_FBT(15);
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];
@ -277,7 +326,6 @@ 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];
@ -335,7 +383,14 @@ FLASHMEM void AudioPlaySystem::begin_audio(int samplesize, void (*callback)(shor
sampleBufferSize = samplesize;
#ifdef PT8211
txreg = (uint16_t *)((uint32_t)&I2S1_TDR0);
config_pt8211();
#else
txreg = (uint16_t *)((uint32_t)&I2S1_TDR0 + 2);
config_sai1();
#endif
attachInterruptVector(IRQ_SAI1, AUDIO_isr);
NVIC_ENABLE_IRQ(IRQ_SAI1);
NVIC_SET_PRIORITY(IRQ_QTIMER3, 0); // 0 highest priority, 255 = lowest priority
@ -358,4 +413,3 @@ FLASHMEM void AudioPlaySystem::end_audio()
}
#endif
#endif

Wyświetl plik

@ -19,13 +19,10 @@ public:
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
static void SOFTWARE_isr(void);
};

Wyświetl plik

@ -11,6 +11,8 @@
#define HAS_SND 1
#define HAS_USBKEY 1
#define INVX 1
#define PT8211 1
#else
#define HAS_T4_VGA 1

Wyświetl plik

@ -171,14 +171,8 @@ 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);
Serial.println("sound init");
mymixer.begin_audio(256, mymixer.snd_Mixer);
mymixer.start();
}

Wyświetl plik

@ -176,7 +176,6 @@ void AudioPlaySystem::step(void) {
}
#ifndef HAS_T4_VGA
/*******************************************************************
Experimental I2S interrupt based sound driver for PCM51xx !!!
*******************************************************************/
@ -263,7 +262,57 @@ FLASHMEM static void config_sai1()
I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE ;//<-- not using DMA */;
}
FLASHMEM static void config_pt8211()
{
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(0);
I2S1_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_BCP | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(1);
I2S1_TCR3 = I2S_TCR3_TCE;
I2S1_TCR4 = I2S_TCR4_FRSZ(1) | I2S_TCR4_SYWD(15) | I2S_TCR4_MF | I2S_TCR4_FSD /*| I2S_TCR4_FSE*/ | I2S_TCR4_FSP ; //PT8211
I2S1_TCR5 = I2S_TCR5_WNW(15) | I2S_TCR5_W0W(15) | I2S_TCR5_FBT(15);
I2S1_RMR = 0;
I2S1_RCR1 = I2S_RCR1_RFW(0);
I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_RCR2_BCP | I2S_RCR2_MSEL(1)| I2S_RCR2_BCD | I2S_RCR2_DIV(1) ;
I2S1_RCR3 = I2S_RCR3_RCE;
I2S1_RCR4 = I2S_RCR4_FRSZ(1) | I2S_RCR4_SYWD(15) | I2S_RCR4_MF /*| I2S_RCR4_FSE*/ | I2S_RCR4_FSP | I2S_RCR4_FSD; //PT8211
I2S1_RCR5 = I2S_RCR5_WNW(15) | I2S_RCR5_W0W(15) | I2S_RCR5_FBT(15);
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];
@ -277,7 +326,6 @@ 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];
@ -335,7 +383,14 @@ FLASHMEM void AudioPlaySystem::begin_audio(int samplesize, void (*callback)(shor
sampleBufferSize = samplesize;
#ifdef PT8211
txreg = (uint16_t *)((uint32_t)&I2S1_TDR0);
config_pt8211();
#else
txreg = (uint16_t *)((uint32_t)&I2S1_TDR0 + 2);
config_sai1();
#endif
attachInterruptVector(IRQ_SAI1, AUDIO_isr);
NVIC_ENABLE_IRQ(IRQ_SAI1);
NVIC_SET_PRIORITY(IRQ_QTIMER3, 0); // 0 highest priority, 255 = lowest priority
@ -358,4 +413,3 @@ FLASHMEM void AudioPlaySystem::end_audio()
}
#endif
#endif

Wyświetl plik

@ -19,13 +19,10 @@ public:
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
static void SOFTWARE_isr(void);
};

Wyświetl plik

@ -11,6 +11,8 @@
#define HAS_SND 1
#define HAS_USBKEY 1
//#define INVX 1
#define PT8211 1
#else
#define HAS_T4_VGA 1

Wyświetl plik

@ -169,14 +169,8 @@ 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);
Serial.println("sound init");
mymixer.begin_audio(256, mymixer.snd_Mixer);
mymixer.start();
}

Wyświetl plik

@ -176,7 +176,6 @@ void AudioPlaySystem::step(void) {
}
#ifndef HAS_T4_VGA
/*******************************************************************
Experimental I2S interrupt based sound driver for PCM51xx !!!
*******************************************************************/
@ -263,7 +262,57 @@ FLASHMEM static void config_sai1()
I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE ;//<-- not using DMA */;
}
FLASHMEM static void config_pt8211()
{
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(0);
I2S1_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_BCP | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(1);
I2S1_TCR3 = I2S_TCR3_TCE;
I2S1_TCR4 = I2S_TCR4_FRSZ(1) | I2S_TCR4_SYWD(15) | I2S_TCR4_MF | I2S_TCR4_FSD /*| I2S_TCR4_FSE*/ | I2S_TCR4_FSP ; //PT8211
I2S1_TCR5 = I2S_TCR5_WNW(15) | I2S_TCR5_W0W(15) | I2S_TCR5_FBT(15);
I2S1_RMR = 0;
I2S1_RCR1 = I2S_RCR1_RFW(0);
I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_RCR2_BCP | I2S_RCR2_MSEL(1)| I2S_RCR2_BCD | I2S_RCR2_DIV(1) ;
I2S1_RCR3 = I2S_RCR3_RCE;
I2S1_RCR4 = I2S_RCR4_FRSZ(1) | I2S_RCR4_SYWD(15) | I2S_RCR4_MF /*| I2S_RCR4_FSE*/ | I2S_RCR4_FSP | I2S_RCR4_FSD; //PT8211
I2S1_RCR5 = I2S_RCR5_WNW(15) | I2S_RCR5_W0W(15) | I2S_RCR5_FBT(15);
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];
@ -277,7 +326,6 @@ 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];
@ -335,7 +383,14 @@ FLASHMEM void AudioPlaySystem::begin_audio(int samplesize, void (*callback)(shor
sampleBufferSize = samplesize;
#ifdef PT8211
txreg = (uint16_t *)((uint32_t)&I2S1_TDR0);
config_pt8211();
#else
txreg = (uint16_t *)((uint32_t)&I2S1_TDR0 + 2);
config_sai1();
#endif
attachInterruptVector(IRQ_SAI1, AUDIO_isr);
NVIC_ENABLE_IRQ(IRQ_SAI1);
NVIC_SET_PRIORITY(IRQ_QTIMER3, 0); // 0 highest priority, 255 = lowest priority
@ -358,4 +413,3 @@ FLASHMEM void AudioPlaySystem::end_audio()
}
#endif
#endif

Wyświetl plik

@ -19,13 +19,10 @@ public:
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
static void SOFTWARE_isr(void);
};

Wyświetl plik

@ -12,6 +12,7 @@
//#define HIRES 1
//#define HAS_SND 1
//#define HAS_USBKEY 1
#define PT8211 1
#else

Wyświetl plik

@ -81,14 +81,8 @@ 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);
Serial.println("sound init");
mymixer.begin_audio(256, mymixer.snd_Mixer);
mymixer.start();
}

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -0,0 +1,320 @@
/** EMULib Emulation Library *********************************/
/** **/
/** AY8910.c **/
/** **/
/** This file contains emulation for the AY8910 sound chip **/
/** produced by General Instruments, Yamaha, etc. See **/
/** AY8910.h for declarations. **/
/** **/
/** Copyright (C) Marat Fayzullin 1996-2005 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
#include "AY8910.h"
#include "Sound.h"
#include <string.h>
/** Reset8910() **********************************************/
/** Reset the sound chip and use sound channels from the **/
/** one given in First. **/
/*************************************************************/
void Reset8910(register AY8910 *D,int First)
{
static byte RegInit[16] =
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFD,
0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00
};
int J;
for(J=0;J<AY8910_CHANNELS;J++) D->Freq[J]=D->Volume[J]=0;
memcpy(D->R,RegInit,sizeof(D->R));
D->Phase[0]=D->Phase[1]=D->Phase[2]=0;
D->First = First;
D->Sync = AY8910_ASYNC;
D->Changed = 0x00;
D->EPeriod = 0;
D->ECount = 0;
D->Latch = 0x00;
/* Set sound types */
SetSound(0+First,SND_MELODIC);
SetSound(1+First,SND_MELODIC);
SetSound(2+First,SND_MELODIC);
SetSound(3+First,SND_NOISE);
SetSound(4+First,SND_NOISE);
SetSound(5+First,SND_NOISE);
}
/** WrCtrl8910() *********************************************/
/** Write a value V to the PSG Control Port. **/
/*************************************************************/
void WrCtrl8910(AY8910 *D,byte V)
{
D->Latch=V&0x0F;
}
/** WrData8910() *********************************************/
/** Write a value V to the PSG Data Port. **/
/*************************************************************/
void WrData8910(AY8910 *D,byte V)
{
Write8910(D,D->Latch,V);
}
/** RdData8910() *********************************************/
/** Read a value from the PSG Data Port. **/
/*************************************************************/
byte RdData8910(AY8910 *D)
{
return(D->R[D->Latch]);
}
/** Write8910() **********************************************/
/** Call this function to output a value V into the sound **/
/** chip. **/
/*************************************************************/
void Write8910(register AY8910 *D,register byte R,register byte V)
{
register int J,I;
/* Exit if no change */
if((R>15)||((V==D->R[R])&&(R<8)&&(R>10))) return;
switch(R)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
/* Write value */
D->R[R]=V;
/* Exit if the channel is silenced */
if(D->R[7]&(1<<(R>>1))) return;
/* Go to the first register in the pair */
R&=0xFE;
/* Compute frequency */
J=((int)(D->R[R+1]&0x0F)<<8)+D->R[R];
/* Compute channel number */
R>>=1;
/* Assign frequency */
D->Freq[R]=AY8910_BASE/(J+1);
/* Compute changed channels mask */
D->Changed|=1<<R;
break;
case 6:
/* Write value */
D->R[6]=V;
/* Exit if noise channels are silenced */
if(!(~D->R[7]&0x38)) return;
/* Compute and assign noise frequency */
J=AY8910_BASE/((V&0x1F)+1);
if(!(D->R[7]&0x08)) D->Freq[3]=J;
if(!(D->R[7]&0x10)) D->Freq[4]=J;
if(!(D->R[7]&0x20)) D->Freq[5]=J;
/* Compute changed channels mask */
D->Changed|=0x38&~D->R[7];
break;
case 7:
/* Find changed channels */
R=(V^D->R[7])&0x3F;
D->Changed|=R;
/* Write value */
D->R[7]=V;
/* Update frequencies */
for(J=0;R&&(J<AY8910_CHANNELS);J++,R>>=1,V>>=1)
if(R&1)
{
if(V&1) D->Freq[J]=0;
else
{
I=J<3? (((int)(D->R[J*2+1]&0x0F)<<8)+D->R[J*2]):(D->R[6]&0x1F);
D->Freq[J]=AY8910_BASE/(I+1);
}
}
break;
case 8:
case 9:
case 10:
/* Write value */
D->R[R]=V;
/* Compute channel number */
R-=8;
/* Compute and assign new volume */
D->Volume[R+3]=D->Volume[R]=
V&0x10? (V&0x04? 0:255):255*(V&0x0F)/15;
/* Start/stop envelope */
D->Phase[R]=V&0x10? 1:0;
/* Compute changed channels mask */
D->Changed|=(0x09<<R)&~D->R[7];
break;
case 11:
case 12:
/* Write value */
D->R[R]=V;
/* Compute frequency */
J=((int)D->R[12]<<8)+D->R[11]+1;
D->EPeriod=1000*(J<<4)/AY8910_BASE;
D->ECount=0;
/* No channels changed */
return;
case 13:
case 14:
case 15:
/* Write value */
D->R[R]=V;
/* No channels changed */
return;
default:
/* Wrong register, do nothing */
return;
}
/* For asynchronous mode, make Sound() calls right away */
if(!D->Sync&&D->Changed) Sync8910(D,AY8910_FLUSH);
}
/** Loop8910() ***********************************************/
/** Call this function periodically to update volume **/
/** envelopes. Use mS to pass the time since the last call **/
/** of Loop8910() in milliseconds. **/
/*************************************************************/
void Loop8910(register AY8910 *D,int mS)
{
register int J,I,Step;
/* Exit if no envelope running */
if(!D->EPeriod) return;
/* Count milliseconds */
D->ECount+=mS;
if(D->ECount<D->EPeriod) return;
/* By how much do we change volume? */
Step=(D->ECount<<8)/D->EPeriod;
/* Count the remaining milliseconds */
D->ECount%=D->EPeriod;
for(J=0;J<3;J++)
if(D->Phase[J]&&(D->R[J+8]&0x10))
switch(D->R[13]&0x0F)
{
case 0:
case 1:
case 2:
case 3:
case 9:
I=D->Volume[J]-Step;
D->Volume[J+3]=D->Volume[J]=I=I>=0? I:0;
if(!I) D->Phase[J]=0;
D->Changed|=(0x09<<J)&~D->R[7];
break;
case 4:
case 5:
case 6:
case 7:
I=D->Volume[J]+Step;
D->Volume[J+3]=D->Volume[J]=I=I<256? I:0;
if(!I) D->Phase[J]=0;
D->Changed|=(0x09<<J)&~D->R[7];
break;
case 8:
I=D->Volume[J]-Step;
D->Volume[J+3]=D->Volume[J]=I>=0? I:255;
D->Changed|=(0x09<<J)&~D->R[7];
break;
case 10:
if(D->Phase[J]==2)
{
I=D->Volume[J]+Step;
D->Volume[J+3]=D->Volume[J]=I=I<256? I:255;
if(I==255) D->Phase[J]=1;
}
else
{
I=D->Volume[J]-Step;
D->Volume[J+3]=D->Volume[J]=I=I>=0? I:0;
if(!I) D->Phase[J]=2;
}
D->Changed|=(0x09<<J)&~D->R[7];
break;
case 11:
I=D->Volume[J]-Step;
D->Volume[J+3]=D->Volume[J]=I=I>=0? I:255;
if(I==255) D->Phase[J]=0;
D->Changed|=(0x09<<J)&~D->R[7];
break;
case 12:
I=D->Volume[J]+Step;
D->Volume[J+3]=D->Volume[J]=I<256? I:0;
D->Changed|=(0x09<<J)&~D->R[7];
break;
case 13:
case 15:
I=D->Volume[J]+Step;
D->Volume[J+3]=D->Volume[J]=I<256? I:255;
if(I==255) D->Phase[J]=0;
D->Changed|=(0x09<<J)&~D->R[7];
break;
case 14:
if(D->Phase[J]==2)
{
I=D->Volume[J]-Step;
D->Volume[J+3]=D->Volume[J]=I=I>=0? I:0;
if(!I) D->Phase[J]=1;
}
else
{
I=D->Volume[J]+Step;
D->Volume[J+3]=D->Volume[J]=I=I<256? I:255;
if(I==255) D->Phase[J]=2;
}
D->Changed|=(0x09<<J)&~D->R[7];
break;
}
/* For asynchronous mode, make Sound() calls right away */
if(!D->Sync&&D->Changed) Sync8910(D,AY8910_FLUSH);
}
/** Sync8910() ***********************************************/
/** Flush all accumulated changes by issuing Sound() calls **/
/** and set the synchronization on/off. The second argument **/
/** should be AY8910_SYNC/AY8910_ASYNC to set/reset sync, **/
/** or AY8910_FLUSH to leave sync mode as it is. To emulate **/
/** noise channels with MIDI drums, OR second argument with **/
/** AY8910_DRUMS. **/
/*************************************************************/
void Sync8910(register AY8910 *D,register byte Sync)
{
register int J,I;
/* Hit MIDI drums for noise channels, if requested */
if(Sync&AY8910_DRUMS)
{
Sync&=~AY8910_DRUMS;
J=0;
if(D->Volume[3]&&D->Freq[3]) J+=D->Volume[3];
if(D->Volume[4]&&D->Freq[4]) J+=D->Volume[4];
if(D->Volume[5]&&D->Freq[5]) J+=D->Volume[5];
if(J) Drum(DRM_MIDI|28,(J+2)/3);
}
if(Sync!=AY8910_FLUSH) D->Sync=Sync;
for(J=0,I=D->Changed;I&&(J<AY8910_CHANNELS);J++,I>>=1)
if(I&1) Sound(J+D->First,D->Freq[J],D->Volume[J]);
D->Changed=0x00;
}

Wyświetl plik

@ -0,0 +1,91 @@
/** EMULib Emulation Library *********************************/
/** **/
/** AY8910.h **/
/** **/
/** This file contains emulation for the AY8910 sound chip **/
/** produced by General Instruments, Yamaha, etc. See **/
/** AY8910.c for the actual code. **/
/** **/
/** Copyright (C) Marat Fayzullin 1996-2005 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
#ifndef AY8910_H
#define AY8910_H
#define AY8910_BASE 111861 /* Base frequency for AY8910 */
#define AY8910_CHANNELS 6 /* 3 melodic + 3 noise chanls */
#define AY8910_ASYNC 0 /* Asynchronous emulation */
#define AY8910_SYNC 1 /* Synchronous emulation */
#define AY8910_FLUSH 2 /* Flush buffers only */
#define AY8910_DRUMS 0x80 /* Hit drums for noise chnls */
#ifndef BYTE_TYPE_DEFINED
#define BYTE_TYPE_DEFINED
typedef unsigned char byte;
#endif
/** AY8910 ***************************************************/
/** This data structure stores AY8910 state. **/
/*************************************************************/
typedef struct
{
byte R[16]; /* PSG registers contents */
int Freq[AY8910_CHANNELS]; /* Frequencies (0 for off) */
int Volume[AY8910_CHANNELS]; /* Volumes (0..255) */
int First; /* First used Sound() channel */
byte Changed; /* Bitmap of changed channels */
byte Sync; /* AY8910_SYNC/AY8910_ASYNC */
byte Latch; /* Latch for the register num */
int EPeriod; /* Envelope step in msecs */
int ECount; /* Envelope step counter */
byte Phase[3]; /* Envelope phase (0 for off) */
} AY8910;
/** Reset8910() **********************************************/
/** Reset the sound chip and use sound channels from the **/
/** one given in First. **/
/*************************************************************/
void Reset8910(register AY8910 *D,int First);
/** Write8910() **********************************************/
/** Call this function to output a value V into the sound **/
/** chip. **/
/*************************************************************/
void Write8910(register AY8910 *D,register byte R,register byte V);
/** WrCtrl8910() *********************************************/
/** Write a value V to the PSG Control Port. **/
/*************************************************************/
void WrCtrl8910(AY8910 *D,byte V);
/** WrData8910() *********************************************/
/** Write a value V to the PSG Data Port. **/
/*************************************************************/
void WrData8910(AY8910 *D,byte V);
/** RdData8910() *********************************************/
/** Read a value from the PSG Data Port. **/
/*************************************************************/
byte RdData8910(AY8910 *D);
/** Sync8910() ***********************************************/
/** Flush all accumulated changes by issuing Sound() calls **/
/** and set the synchronization on/off. The second argument **/
/** should be AY8910_SYNC/AY8910_ASYNC to set/reset sync, **/
/** or AY8910_FLUSH to leave sync mode as it is. To emulate **/
/** noise channels with MIDI drums, OR second argument with **/
/** AY8910_DRUMS. **/
/*************************************************************/
void Sync8910(register AY8910 *D,register byte Sync);
/** Loop8910() ***********************************************/
/** Call this function periodically to update volume **/
/** envelopes. Use mS to pass the time since the last call **/
/** of Loop8910() in milliseconds. **/
/*************************************************************/
void Loop8910(register AY8910 *D,int mS);
#endif /* AY8910_H */

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,48 @@
/** fMSX: portable MSX emulator ******************************/
/** **/
/** Boot.h **/
/** **/
/** This file contains MSX boot sector image used to create **/
/** new disk images during FORMAT operation. **/
/** **/
/** Copyright (C) Marat Fayzullin 1994-2003 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
#include "arduinoproto.h"
PROGMEM const unsigned char BootBlock[] =
{
0xEB,0xFE,0x90,0x56,0x46,0x42,0x2D,0x31,0x39,0x38,0x39,0x00,0x02,0x02,0x01,0x00,
0x02,0x70,0x00,0xA0,0x05,0xF9,0x03,0x00,0x09,0x00,0x02,0x00,0x00,0x00,0xD0,0xED,
0x53,0x58,0xC0,0x32,0xC2,0xC0,0x36,0x55,0x23,0x36,0xC0,0x31,0x1F,0xF5,0x11,0x9D,
0xC0,0x0E,0x0F,0xCD,0x7D,0xF3,0x3C,0x28,0x28,0x11,0x00,0x01,0x0E,0x1A,0xCD,0x7D,
0xF3,0x21,0x01,0x00,0x22,0xAB,0xC0,0x21,0x00,0x3F,0x11,0x9D,0xC0,0x0E,0x27,0xCD,
0x7D,0xF3,0xC3,0x00,0x01,0x57,0xC0,0xCD,0x00,0x00,0x79,0xE6,0xFE,0xFE,0x02,0x20,
0x07,0x3A,0xC2,0xC0,0xA7,0xCA,0x22,0x40,0x11,0x77,0xC0,0x0E,0x09,0xCD,0x7D,0xF3,
0x0E,0x07,0xCD,0x7D,0xF3,0x18,0xB4,0x42,0x6F,0x6F,0x74,0x20,0x65,0x72,0x72,0x6F,
0x72,0x0D,0x0A,0x50,0x72,0x65,0x73,0x73,0x20,0x61,0x6E,0x79,0x20,0x6B,0x65,0x79,
0x20,0x66,0x6F,0x72,0x20,0x72,0x65,0x74,0x72,0x79,0x0D,0x0A,0x24,0x00,0x4D,0x53,
0x58,0x44,0x4F,0x53,0x20,0x20,0x53,0x59,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF3,0x2A,
0x51,0xF3,0x11,0x00,0x01,0x19,0x01,0x00,0x01,0x11,0x00,0xC1,0xED,0xB0,0x3A,0xEE,
0xC0,0x47,0x11,0xEF,0xC0,0x21,0x00,0x00,0xCD,0x51,0x52,0xF3,0x76,0xC9,0x18,0x64,
0x3A,0xAF,0x80,0xF9,0xCA,0x6D,0x48,0xD3,0xA5,0x0C,0x8C,0x2F,0x9C,0xCB,0xE9,0x89,
0xD2,0x00,0x32,0x26,0x40,0x94,0x61,0x19,0x20,0xE6,0x80,0x6D,0x8A,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};

Wyświetl plik

@ -0,0 +1,13 @@
/** fMSX: portable MSX emulator ******************************/
/** **/
/** Boot.h **/
/** **/
/** This file contains MSX boot sector image used to create **/
/** new disk images during FORMAT operation. **/
/** **/
/** Copyright (C) Marat Fayzullin 1994-2003 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
extern const byte BootBlock[];

Wyświetl plik

@ -0,0 +1,385 @@
/** Z80: portable Z80 emulator *******************************/
/** **/
/** Codes.h **/
/** **/
/** This file contains implementation for the main table of **/
/** Z80 commands. It is included from Z80.c. **/
/** **/
/** Copyright (C) Marat Fayzullin 1994-2005 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
case JR_NZ: if(R->AF.B.l&Z_FLAG) R->PC.W++; else { R->ICount-=5;M_JR; } break;
case JR_NC: if(R->AF.B.l&C_FLAG) R->PC.W++; else { R->ICount-=5;M_JR; } break;
case JR_Z: if(R->AF.B.l&Z_FLAG) { R->ICount-=5;M_JR; } else R->PC.W++; break;
case JR_C: if(R->AF.B.l&C_FLAG) { R->ICount-=5;M_JR; } else R->PC.W++; break;
case JP_NZ: if(R->AF.B.l&Z_FLAG) R->PC.W+=2; else { M_JP; } break;
case JP_NC: if(R->AF.B.l&C_FLAG) R->PC.W+=2; else { M_JP; } break;
case JP_PO: if(R->AF.B.l&P_FLAG) R->PC.W+=2; else { M_JP; } break;
case JP_P: if(R->AF.B.l&S_FLAG) R->PC.W+=2; else { M_JP; } break;
case JP_Z: if(R->AF.B.l&Z_FLAG) { M_JP; } else R->PC.W+=2; break;
case JP_C: if(R->AF.B.l&C_FLAG) { M_JP; } else R->PC.W+=2; break;
case JP_PE: if(R->AF.B.l&P_FLAG) { M_JP; } else R->PC.W+=2; break;
case JP_M: if(R->AF.B.l&S_FLAG) { M_JP; } else R->PC.W+=2; break;
case RET_NZ: if(!(R->AF.B.l&Z_FLAG)) { R->ICount-=6;M_RET; } break;
case RET_NC: if(!(R->AF.B.l&C_FLAG)) { R->ICount-=6;M_RET; } break;
case RET_PO: if(!(R->AF.B.l&P_FLAG)) { R->ICount-=6;M_RET; } break;
case RET_P: if(!(R->AF.B.l&S_FLAG)) { R->ICount-=6;M_RET; } break;
case RET_Z: if(R->AF.B.l&Z_FLAG) { R->ICount-=6;M_RET; } break;
case RET_C: if(R->AF.B.l&C_FLAG) { R->ICount-=6;M_RET; } break;
case RET_PE: if(R->AF.B.l&P_FLAG) { R->ICount-=6;M_RET; } break;
case RET_M: if(R->AF.B.l&S_FLAG) { R->ICount-=6;M_RET; } break;
case CALL_NZ: if(R->AF.B.l&Z_FLAG) R->PC.W+=2; else { R->ICount-=7;M_CALL; } break;
case CALL_NC: if(R->AF.B.l&C_FLAG) R->PC.W+=2; else { R->ICount-=7;M_CALL; } break;
case CALL_PO: if(R->AF.B.l&P_FLAG) R->PC.W+=2; else { R->ICount-=7;M_CALL; } break;
case CALL_P: if(R->AF.B.l&S_FLAG) R->PC.W+=2; else { R->ICount-=7;M_CALL; } break;
case CALL_Z: if(R->AF.B.l&Z_FLAG) { R->ICount-=7;M_CALL; } else R->PC.W+=2; break;
case CALL_C: if(R->AF.B.l&C_FLAG) { R->ICount-=7;M_CALL; } else R->PC.W+=2; break;
case CALL_PE: if(R->AF.B.l&P_FLAG) { R->ICount-=7;M_CALL; } else R->PC.W+=2; break;
case CALL_M: if(R->AF.B.l&S_FLAG) { R->ICount-=7;M_CALL; } else R->PC.W+=2; break;
case ADD_B: M_ADD(R->BC.B.h);break;
case ADD_C: M_ADD(R->BC.B.l);break;
case ADD_D: M_ADD(R->DE.B.h);break;
case ADD_E: M_ADD(R->DE.B.l);break;
case ADD_H: M_ADD(R->HL.B.h);break;
case ADD_L: M_ADD(R->HL.B.l);break;
case ADD_A: M_ADD(R->AF.B.h);break;
case ADD_xHL: I=RdZ80(R->HL.W);M_ADD(I);break;
case ADD_BYTE: I=RdZ80(R->PC.W++);M_ADD(I);break;
case SUB_B: M_SUB(R->BC.B.h);break;
case SUB_C: M_SUB(R->BC.B.l);break;
case SUB_D: M_SUB(R->DE.B.h);break;
case SUB_E: M_SUB(R->DE.B.l);break;
case SUB_H: M_SUB(R->HL.B.h);break;
case SUB_L: M_SUB(R->HL.B.l);break;
case SUB_A: R->AF.B.h=0;R->AF.B.l=N_FLAG|Z_FLAG;break;
case SUB_xHL: I=RdZ80(R->HL.W);M_SUB(I);break;
case SUB_BYTE: I=RdZ80(R->PC.W++);M_SUB(I);break;
case AND_B: M_AND(R->BC.B.h);break;
case AND_C: M_AND(R->BC.B.l);break;
case AND_D: M_AND(R->DE.B.h);break;
case AND_E: M_AND(R->DE.B.l);break;
case AND_H: M_AND(R->HL.B.h);break;
case AND_L: M_AND(R->HL.B.l);break;
case AND_A: M_AND(R->AF.B.h);break;
case AND_xHL: I=RdZ80(R->HL.W);M_AND(I);break;
case AND_BYTE: I=RdZ80(R->PC.W++);M_AND(I);break;
case OR_B: M_OR(R->BC.B.h);break;
case OR_C: M_OR(R->BC.B.l);break;
case OR_D: M_OR(R->DE.B.h);break;
case OR_E: M_OR(R->DE.B.l);break;
case OR_H: M_OR(R->HL.B.h);break;
case OR_L: M_OR(R->HL.B.l);break;
case OR_A: M_OR(R->AF.B.h);break;
case OR_xHL: I=RdZ80(R->HL.W);M_OR(I);break;
case OR_BYTE: I=RdZ80(R->PC.W++);M_OR(I);break;
case ADC_B: M_ADC(R->BC.B.h);break;
case ADC_C: M_ADC(R->BC.B.l);break;
case ADC_D: M_ADC(R->DE.B.h);break;
case ADC_E: M_ADC(R->DE.B.l);break;
case ADC_H: M_ADC(R->HL.B.h);break;
case ADC_L: M_ADC(R->HL.B.l);break;
case ADC_A: M_ADC(R->AF.B.h);break;
case ADC_xHL: I=RdZ80(R->HL.W);M_ADC(I);break;
case ADC_BYTE: I=RdZ80(R->PC.W++);M_ADC(I);break;
case SBC_B: M_SBC(R->BC.B.h);break;
case SBC_C: M_SBC(R->BC.B.l);break;
case SBC_D: M_SBC(R->DE.B.h);break;
case SBC_E: M_SBC(R->DE.B.l);break;
case SBC_H: M_SBC(R->HL.B.h);break;
case SBC_L: M_SBC(R->HL.B.l);break;
case SBC_A: M_SBC(R->AF.B.h);break;
case SBC_xHL: I=RdZ80(R->HL.W);M_SBC(I);break;
case SBC_BYTE: I=RdZ80(R->PC.W++);M_SBC(I);break;
case XOR_B: M_XOR(R->BC.B.h);break;
case XOR_C: M_XOR(R->BC.B.l);break;
case XOR_D: M_XOR(R->DE.B.h);break;
case XOR_E: M_XOR(R->DE.B.l);break;
case XOR_H: M_XOR(R->HL.B.h);break;
case XOR_L: M_XOR(R->HL.B.l);break;
case XOR_A: R->AF.B.h=0;R->AF.B.l=P_FLAG|Z_FLAG;break;
case XOR_xHL: I=RdZ80(R->HL.W);M_XOR(I);break;
case XOR_BYTE: I=RdZ80(R->PC.W++);M_XOR(I);break;
case CP_B: M_CP(R->BC.B.h);break;
case CP_C: M_CP(R->BC.B.l);break;
case CP_D: M_CP(R->DE.B.h);break;
case CP_E: M_CP(R->DE.B.l);break;
case CP_H: M_CP(R->HL.B.h);break;
case CP_L: M_CP(R->HL.B.l);break;
case CP_A: R->AF.B.l=N_FLAG|Z_FLAG;break;
case CP_xHL: I=RdZ80(R->HL.W);M_CP(I);break;
case CP_BYTE: I=RdZ80(R->PC.W++);M_CP(I);break;
case LD_BC_WORD: M_LDWORD(BC);break;
case LD_DE_WORD: M_LDWORD(DE);break;
case LD_HL_WORD: M_LDWORD(HL);break;
case LD_SP_WORD: M_LDWORD(SP);break;
case LD_PC_HL: R->PC.W=R->HL.W;break;
case LD_SP_HL: R->SP.W=R->HL.W;break;
case LD_A_xBC: R->AF.B.h=RdZ80(R->BC.W);break;
case LD_A_xDE: R->AF.B.h=RdZ80(R->DE.W);break;
case ADD_HL_BC: M_ADDW(HL,BC);break;
case ADD_HL_DE: M_ADDW(HL,DE);break;
case ADD_HL_HL: M_ADDW(HL,HL);break;
case ADD_HL_SP: M_ADDW(HL,SP);break;
case DEC_BC: R->BC.W--;break;
case DEC_DE: R->DE.W--;break;
case DEC_HL: R->HL.W--;break;
case DEC_SP: R->SP.W--;break;
case INC_BC: R->BC.W++;break;
case INC_DE: R->DE.W++;break;
case INC_HL: R->HL.W++;break;
case INC_SP: R->SP.W++;break;
case DEC_B: M_DEC(R->BC.B.h);break;
case DEC_C: M_DEC(R->BC.B.l);break;
case DEC_D: M_DEC(R->DE.B.h);break;
case DEC_E: M_DEC(R->DE.B.l);break;
case DEC_H: M_DEC(R->HL.B.h);break;
case DEC_L: M_DEC(R->HL.B.l);break;
case DEC_A: M_DEC(R->AF.B.h);break;
case DEC_xHL: I=RdZ80(R->HL.W);M_DEC(I);WrZ80(R->HL.W,I);break;
case INC_B: M_INC(R->BC.B.h);break;
case INC_C: M_INC(R->BC.B.l);break;
case INC_D: M_INC(R->DE.B.h);break;
case INC_E: M_INC(R->DE.B.l);break;
case INC_H: M_INC(R->HL.B.h);break;
case INC_L: M_INC(R->HL.B.l);break;
case INC_A: M_INC(R->AF.B.h);break;
case INC_xHL: I=RdZ80(R->HL.W);M_INC(I);WrZ80(R->HL.W,I);break;
case RLCA:
I=R->AF.B.h&0x80? C_FLAG:0;
R->AF.B.h=(R->AF.B.h<<1)|I;
R->AF.B.l=(R->AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I;
break;
case RLA:
I=R->AF.B.h&0x80? C_FLAG:0;
R->AF.B.h=(R->AF.B.h<<1)|(R->AF.B.l&C_FLAG);
R->AF.B.l=(R->AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I;
break;
case RRCA:
I=R->AF.B.h&0x01;
R->AF.B.h=(R->AF.B.h>>1)|(I? 0x80:0);
R->AF.B.l=(R->AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I;
break;
case RRA:
I=R->AF.B.h&0x01;
R->AF.B.h=(R->AF.B.h>>1)|(R->AF.B.l&C_FLAG? 0x80:0);
R->AF.B.l=(R->AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I;
break;
case RST00: M_RST(0x0000);break;
case RST08: M_RST(0x0008);break;
case RST10: M_RST(0x0010);break;
case RST18: M_RST(0x0018);break;
case RST20: M_RST(0x0020);break;
case RST28: M_RST(0x0028);break;
case RST30: M_RST(0x0030);break;
case RST38: M_RST(0x0038);break;
case PUSH_BC: M_PUSH(BC);break;
case PUSH_DE: M_PUSH(DE);break;
case PUSH_HL: M_PUSH(HL);break;
case PUSH_AF: M_PUSH(AF);break;
case POP_BC: M_POP(BC);break;
case POP_DE: M_POP(DE);break;
case POP_HL: M_POP(HL);break;
case POP_AF: M_POP(AF);break;
case DJNZ: if(--R->BC.B.h) { R->ICount-=5;M_JR; } else R->PC.W++;break;
case JP: M_JP;break;
case JR: M_JR;break;
case CALL: M_CALL;break;
case RET: M_RET;break;
case SCF: S(C_FLAG);R(N_FLAG|H_FLAG);break;
case CPL: R->AF.B.h=~R->AF.B.h;S(N_FLAG|H_FLAG);break;
case NOP: break;
case OUTA: I=RdZ80(R->PC.W++);OutZ80(I,R->AF.B.h);break;
case INA: I=RdZ80(R->PC.W++);R->AF.B.h=InZ80(I);break;
case HALT:
R->PC.W--;
R->IFF|=IFF_HALT;
R->IBackup=0;
R->ICount=0;
break;
case DI:
if(R->IFF&IFF_EI) R->ICount+=R->IBackup-1;
R->IFF&=~(IFF_1|IFF_2|IFF_EI);
break;
case EI:
if(!(R->IFF&(IFF_1|IFF_EI)))
{
R->IFF|=IFF_2|IFF_EI;
R->IBackup=R->ICount;
R->ICount=1;
}
break;
case CCF:
R->AF.B.l^=C_FLAG;R(N_FLAG|H_FLAG);
R->AF.B.l|=R->AF.B.l&C_FLAG? 0:H_FLAG;
break;
case EXX:
J.W=R->BC.W;R->BC.W=R->BC1.W;R->BC1.W=J.W;
J.W=R->DE.W;R->DE.W=R->DE1.W;R->DE1.W=J.W;
J.W=R->HL.W;R->HL.W=R->HL1.W;R->HL1.W=J.W;
break;
case EX_DE_HL: J.W=R->DE.W;R->DE.W=R->HL.W;R->HL.W=J.W;break;
case EX_AF_AF: J.W=R->AF.W;R->AF.W=R->AF1.W;R->AF1.W=J.W;break;
case LD_B_B: R->BC.B.h=R->BC.B.h;break;
case LD_C_B: R->BC.B.l=R->BC.B.h;break;
case LD_D_B: R->DE.B.h=R->BC.B.h;break;
case LD_E_B: R->DE.B.l=R->BC.B.h;break;
case LD_H_B: R->HL.B.h=R->BC.B.h;break;
case LD_L_B: R->HL.B.l=R->BC.B.h;break;
case LD_A_B: R->AF.B.h=R->BC.B.h;break;
case LD_xHL_B: WrZ80(R->HL.W,R->BC.B.h);break;
case LD_B_C: R->BC.B.h=R->BC.B.l;break;
case LD_C_C: R->BC.B.l=R->BC.B.l;break;
case LD_D_C: R->DE.B.h=R->BC.B.l;break;
case LD_E_C: R->DE.B.l=R->BC.B.l;break;
case LD_H_C: R->HL.B.h=R->BC.B.l;break;
case LD_L_C: R->HL.B.l=R->BC.B.l;break;
case LD_A_C: R->AF.B.h=R->BC.B.l;break;
case LD_xHL_C: WrZ80(R->HL.W,R->BC.B.l);break;
case LD_B_D: R->BC.B.h=R->DE.B.h;break;
case LD_C_D: R->BC.B.l=R->DE.B.h;break;
case LD_D_D: R->DE.B.h=R->DE.B.h;break;
case LD_E_D: R->DE.B.l=R->DE.B.h;break;
case LD_H_D: R->HL.B.h=R->DE.B.h;break;
case LD_L_D: R->HL.B.l=R->DE.B.h;break;
case LD_A_D: R->AF.B.h=R->DE.B.h;break;
case LD_xHL_D: WrZ80(R->HL.W,R->DE.B.h);break;
case LD_B_E: R->BC.B.h=R->DE.B.l;break;
case LD_C_E: R->BC.B.l=R->DE.B.l;break;
case LD_D_E: R->DE.B.h=R->DE.B.l;break;
case LD_E_E: R->DE.B.l=R->DE.B.l;break;
case LD_H_E: R->HL.B.h=R->DE.B.l;break;
case LD_L_E: R->HL.B.l=R->DE.B.l;break;
case LD_A_E: R->AF.B.h=R->DE.B.l;break;
case LD_xHL_E: WrZ80(R->HL.W,R->DE.B.l);break;
case LD_B_H: R->BC.B.h=R->HL.B.h;break;
case LD_C_H: R->BC.B.l=R->HL.B.h;break;
case LD_D_H: R->DE.B.h=R->HL.B.h;break;
case LD_E_H: R->DE.B.l=R->HL.B.h;break;
case LD_H_H: R->HL.B.h=R->HL.B.h;break;
case LD_L_H: R->HL.B.l=R->HL.B.h;break;
case LD_A_H: R->AF.B.h=R->HL.B.h;break;
case LD_xHL_H: WrZ80(R->HL.W,R->HL.B.h);break;
case LD_B_L: R->BC.B.h=R->HL.B.l;break;
case LD_C_L: R->BC.B.l=R->HL.B.l;break;
case LD_D_L: R->DE.B.h=R->HL.B.l;break;
case LD_E_L: R->DE.B.l=R->HL.B.l;break;
case LD_H_L: R->HL.B.h=R->HL.B.l;break;
case LD_L_L: R->HL.B.l=R->HL.B.l;break;
case LD_A_L: R->AF.B.h=R->HL.B.l;break;
case LD_xHL_L: WrZ80(R->HL.W,R->HL.B.l);break;
case LD_B_A: R->BC.B.h=R->AF.B.h;break;
case LD_C_A: R->BC.B.l=R->AF.B.h;break;
case LD_D_A: R->DE.B.h=R->AF.B.h;break;
case LD_E_A: R->DE.B.l=R->AF.B.h;break;
case LD_H_A: R->HL.B.h=R->AF.B.h;break;
case LD_L_A: R->HL.B.l=R->AF.B.h;break;
case LD_A_A: R->AF.B.h=R->AF.B.h;break;
case LD_xHL_A: WrZ80(R->HL.W,R->AF.B.h);break;
case LD_xBC_A: WrZ80(R->BC.W,R->AF.B.h);break;
case LD_xDE_A: WrZ80(R->DE.W,R->AF.B.h);break;
case LD_B_xHL: R->BC.B.h=RdZ80(R->HL.W);break;
case LD_C_xHL: R->BC.B.l=RdZ80(R->HL.W);break;
case LD_D_xHL: R->DE.B.h=RdZ80(R->HL.W);break;
case LD_E_xHL: R->DE.B.l=RdZ80(R->HL.W);break;
case LD_H_xHL: R->HL.B.h=RdZ80(R->HL.W);break;
case LD_L_xHL: R->HL.B.l=RdZ80(R->HL.W);break;
case LD_A_xHL: R->AF.B.h=RdZ80(R->HL.W);break;
case LD_B_BYTE: R->BC.B.h=RdZ80(R->PC.W++);break;
case LD_C_BYTE: R->BC.B.l=RdZ80(R->PC.W++);break;
case LD_D_BYTE: R->DE.B.h=RdZ80(R->PC.W++);break;
case LD_E_BYTE: R->DE.B.l=RdZ80(R->PC.W++);break;
case LD_H_BYTE: R->HL.B.h=RdZ80(R->PC.W++);break;
case LD_L_BYTE: R->HL.B.l=RdZ80(R->PC.W++);break;
case LD_A_BYTE: R->AF.B.h=RdZ80(R->PC.W++);break;
case LD_xHL_BYTE: WrZ80(R->HL.W,RdZ80(R->PC.W++));break;
case LD_xWORD_HL:
J.B.l=RdZ80(R->PC.W++);
J.B.h=RdZ80(R->PC.W++);
WrZ80(J.W++,R->HL.B.l);
WrZ80(J.W,R->HL.B.h);
break;
case LD_HL_xWORD:
J.B.l=RdZ80(R->PC.W++);
J.B.h=RdZ80(R->PC.W++);
R->HL.B.l=RdZ80(J.W++);
R->HL.B.h=RdZ80(J.W);
break;
case LD_A_xWORD:
J.B.l=RdZ80(R->PC.W++);
J.B.h=RdZ80(R->PC.W++);
R->AF.B.h=RdZ80(J.W);
break;
case LD_xWORD_A:
J.B.l=RdZ80(R->PC.W++);
J.B.h=RdZ80(R->PC.W++);
WrZ80(J.W,R->AF.B.h);
break;
case EX_HL_xSP:
J.B.l=RdZ80(R->SP.W);WrZ80(R->SP.W++,R->HL.B.l);
J.B.h=RdZ80(R->SP.W);WrZ80(R->SP.W--,R->HL.B.h);
R->HL.W=J.W;
break;
case DAA:
J.W=R->AF.B.h;
if(R->AF.B.l&C_FLAG) J.W|=256;
if(R->AF.B.l&H_FLAG) J.W|=512;
if(R->AF.B.l&N_FLAG) J.W|=1024;
R->AF.W=DAATable[J.W];
break;
default:
if(R->TrapBadOps)
printf
(
"[Z80 %lX] Unrecognized instruction: %02X at PC=%04X\n",
(long)R->User,RdZ80(R->PC.W-1),R->PC.W-1
);
break;

Wyświetl plik

@ -0,0 +1,204 @@
/** Z80: portable Z80 emulator *******************************/
/** **/
/** CodesCB.h **/
/** **/
/** This file contains implementation for the CB table of **/
/** Z80 commands. It is included from Z80.c. **/
/** **/
/** Copyright (C) Marat Fayzullin 1994-2005 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
case RLC_B: M_RLC(R->BC.B.h);break; case RLC_C: M_RLC(R->BC.B.l);break;
case RLC_D: M_RLC(R->DE.B.h);break; case RLC_E: M_RLC(R->DE.B.l);break;
case RLC_H: M_RLC(R->HL.B.h);break; case RLC_L: M_RLC(R->HL.B.l);break;
case RLC_xHL: I=RdZ80(R->HL.W);M_RLC(I);WrZ80(R->HL.W,I);break;
case RLC_A: M_RLC(R->AF.B.h);break;
case RRC_B: M_RRC(R->BC.B.h);break; case RRC_C: M_RRC(R->BC.B.l);break;
case RRC_D: M_RRC(R->DE.B.h);break; case RRC_E: M_RRC(R->DE.B.l);break;
case RRC_H: M_RRC(R->HL.B.h);break; case RRC_L: M_RRC(R->HL.B.l);break;
case RRC_xHL: I=RdZ80(R->HL.W);M_RRC(I);WrZ80(R->HL.W,I);break;
case RRC_A: M_RRC(R->AF.B.h);break;
case RL_B: M_RL(R->BC.B.h);break; case RL_C: M_RL(R->BC.B.l);break;
case RL_D: M_RL(R->DE.B.h);break; case RL_E: M_RL(R->DE.B.l);break;
case RL_H: M_RL(R->HL.B.h);break; case RL_L: M_RL(R->HL.B.l);break;
case RL_xHL: I=RdZ80(R->HL.W);M_RL(I);WrZ80(R->HL.W,I);break;
case RL_A: M_RL(R->AF.B.h);break;
case RR_B: M_RR(R->BC.B.h);break; case RR_C: M_RR(R->BC.B.l);break;
case RR_D: M_RR(R->DE.B.h);break; case RR_E: M_RR(R->DE.B.l);break;
case RR_H: M_RR(R->HL.B.h);break; case RR_L: M_RR(R->HL.B.l);break;
case RR_xHL: I=RdZ80(R->HL.W);M_RR(I);WrZ80(R->HL.W,I);break;
case RR_A: M_RR(R->AF.B.h);break;
case SLA_B: M_SLA(R->BC.B.h);break; case SLA_C: M_SLA(R->BC.B.l);break;
case SLA_D: M_SLA(R->DE.B.h);break; case SLA_E: M_SLA(R->DE.B.l);break;
case SLA_H: M_SLA(R->HL.B.h);break; case SLA_L: M_SLA(R->HL.B.l);break;
case SLA_xHL: I=RdZ80(R->HL.W);M_SLA(I);WrZ80(R->HL.W,I);break;
case SLA_A: M_SLA(R->AF.B.h);break;
case SRA_B: M_SRA(R->BC.B.h);break; case SRA_C: M_SRA(R->BC.B.l);break;
case SRA_D: M_SRA(R->DE.B.h);break; case SRA_E: M_SRA(R->DE.B.l);break;
case SRA_H: M_SRA(R->HL.B.h);break; case SRA_L: M_SRA(R->HL.B.l);break;
case SRA_xHL: I=RdZ80(R->HL.W);M_SRA(I);WrZ80(R->HL.W,I);break;
case SRA_A: M_SRA(R->AF.B.h);break;
case SLL_B: M_SLL(R->BC.B.h);break; case SLL_C: M_SLL(R->BC.B.l);break;
case SLL_D: M_SLL(R->DE.B.h);break; case SLL_E: M_SLL(R->DE.B.l);break;
case SLL_H: M_SLL(R->HL.B.h);break; case SLL_L: M_SLL(R->HL.B.l);break;
case SLL_xHL: I=RdZ80(R->HL.W);M_SLL(I);WrZ80(R->HL.W,I);break;
case SLL_A: M_SLL(R->AF.B.h);break;
case SRL_B: M_SRL(R->BC.B.h);break; case SRL_C: M_SRL(R->BC.B.l);break;
case SRL_D: M_SRL(R->DE.B.h);break; case SRL_E: M_SRL(R->DE.B.l);break;
case SRL_H: M_SRL(R->HL.B.h);break; case SRL_L: M_SRL(R->HL.B.l);break;
case SRL_xHL: I=RdZ80(R->HL.W);M_SRL(I);WrZ80(R->HL.W,I);break;
case SRL_A: M_SRL(R->AF.B.h);break;
case BIT0_B: M_BIT(0,R->BC.B.h);break; case BIT0_C: M_BIT(0,R->BC.B.l);break;
case BIT0_D: M_BIT(0,R->DE.B.h);break; case BIT0_E: M_BIT(0,R->DE.B.l);break;
case BIT0_H: M_BIT(0,R->HL.B.h);break; case BIT0_L: M_BIT(0,R->HL.B.l);break;
case BIT0_xHL: I=RdZ80(R->HL.W);M_BIT(0,I);break;
case BIT0_A: M_BIT(0,R->AF.B.h);break;
case BIT1_B: M_BIT(1,R->BC.B.h);break; case BIT1_C: M_BIT(1,R->BC.B.l);break;
case BIT1_D: M_BIT(1,R->DE.B.h);break; case BIT1_E: M_BIT(1,R->DE.B.l);break;
case BIT1_H: M_BIT(1,R->HL.B.h);break; case BIT1_L: M_BIT(1,R->HL.B.l);break;
case BIT1_xHL: I=RdZ80(R->HL.W);M_BIT(1,I);break;
case BIT1_A: M_BIT(1,R->AF.B.h);break;
case BIT2_B: M_BIT(2,R->BC.B.h);break; case BIT2_C: M_BIT(2,R->BC.B.l);break;
case BIT2_D: M_BIT(2,R->DE.B.h);break; case BIT2_E: M_BIT(2,R->DE.B.l);break;
case BIT2_H: M_BIT(2,R->HL.B.h);break; case BIT2_L: M_BIT(2,R->HL.B.l);break;
case BIT2_xHL: I=RdZ80(R->HL.W);M_BIT(2,I);break;
case BIT2_A: M_BIT(2,R->AF.B.h);break;
case BIT3_B: M_BIT(3,R->BC.B.h);break; case BIT3_C: M_BIT(3,R->BC.B.l);break;
case BIT3_D: M_BIT(3,R->DE.B.h);break; case BIT3_E: M_BIT(3,R->DE.B.l);break;
case BIT3_H: M_BIT(3,R->HL.B.h);break; case BIT3_L: M_BIT(3,R->HL.B.l);break;
case BIT3_xHL: I=RdZ80(R->HL.W);M_BIT(3,I);break;
case BIT3_A: M_BIT(3,R->AF.B.h);break;
case BIT4_B: M_BIT(4,R->BC.B.h);break; case BIT4_C: M_BIT(4,R->BC.B.l);break;
case BIT4_D: M_BIT(4,R->DE.B.h);break; case BIT4_E: M_BIT(4,R->DE.B.l);break;
case BIT4_H: M_BIT(4,R->HL.B.h);break; case BIT4_L: M_BIT(4,R->HL.B.l);break;
case BIT4_xHL: I=RdZ80(R->HL.W);M_BIT(4,I);break;
case BIT4_A: M_BIT(4,R->AF.B.h);break;
case BIT5_B: M_BIT(5,R->BC.B.h);break; case BIT5_C: M_BIT(5,R->BC.B.l);break;
case BIT5_D: M_BIT(5,R->DE.B.h);break; case BIT5_E: M_BIT(5,R->DE.B.l);break;
case BIT5_H: M_BIT(5,R->HL.B.h);break; case BIT5_L: M_BIT(5,R->HL.B.l);break;
case BIT5_xHL: I=RdZ80(R->HL.W);M_BIT(5,I);break;
case BIT5_A: M_BIT(5,R->AF.B.h);break;
case BIT6_B: M_BIT(6,R->BC.B.h);break; case BIT6_C: M_BIT(6,R->BC.B.l);break;
case BIT6_D: M_BIT(6,R->DE.B.h);break; case BIT6_E: M_BIT(6,R->DE.B.l);break;
case BIT6_H: M_BIT(6,R->HL.B.h);break; case BIT6_L: M_BIT(6,R->HL.B.l);break;
case BIT6_xHL: I=RdZ80(R->HL.W);M_BIT(6,I);break;
case BIT6_A: M_BIT(6,R->AF.B.h);break;
case BIT7_B: M_BIT(7,R->BC.B.h);break; case BIT7_C: M_BIT(7,R->BC.B.l);break;
case BIT7_D: M_BIT(7,R->DE.B.h);break; case BIT7_E: M_BIT(7,R->DE.B.l);break;
case BIT7_H: M_BIT(7,R->HL.B.h);break; case BIT7_L: M_BIT(7,R->HL.B.l);break;
case BIT7_xHL: I=RdZ80(R->HL.W);M_BIT(7,I);break;
case BIT7_A: M_BIT(7,R->AF.B.h);break;
case RES0_B: M_RES(0,R->BC.B.h);break; case RES0_C: M_RES(0,R->BC.B.l);break;
case RES0_D: M_RES(0,R->DE.B.h);break; case RES0_E: M_RES(0,R->DE.B.l);break;
case RES0_H: M_RES(0,R->HL.B.h);break; case RES0_L: M_RES(0,R->HL.B.l);break;
case RES0_xHL: I=RdZ80(R->HL.W);M_RES(0,I);WrZ80(R->HL.W,I);break;
case RES0_A: M_RES(0,R->AF.B.h);break;
case RES1_B: M_RES(1,R->BC.B.h);break; case RES1_C: M_RES(1,R->BC.B.l);break;
case RES1_D: M_RES(1,R->DE.B.h);break; case RES1_E: M_RES(1,R->DE.B.l);break;
case RES1_H: M_RES(1,R->HL.B.h);break; case RES1_L: M_RES(1,R->HL.B.l);break;
case RES1_xHL: I=RdZ80(R->HL.W);M_RES(1,I);WrZ80(R->HL.W,I);break;
case RES1_A: M_RES(1,R->AF.B.h);break;
case RES2_B: M_RES(2,R->BC.B.h);break; case RES2_C: M_RES(2,R->BC.B.l);break;
case RES2_D: M_RES(2,R->DE.B.h);break; case RES2_E: M_RES(2,R->DE.B.l);break;
case RES2_H: M_RES(2,R->HL.B.h);break; case RES2_L: M_RES(2,R->HL.B.l);break;
case RES2_xHL: I=RdZ80(R->HL.W);M_RES(2,I);WrZ80(R->HL.W,I);break;
case RES2_A: M_RES(2,R->AF.B.h);break;
case RES3_B: M_RES(3,R->BC.B.h);break; case RES3_C: M_RES(3,R->BC.B.l);break;
case RES3_D: M_RES(3,R->DE.B.h);break; case RES3_E: M_RES(3,R->DE.B.l);break;
case RES3_H: M_RES(3,R->HL.B.h);break; case RES3_L: M_RES(3,R->HL.B.l);break;
case RES3_xHL: I=RdZ80(R->HL.W);M_RES(3,I);WrZ80(R->HL.W,I);break;
case RES3_A: M_RES(3,R->AF.B.h);break;
case RES4_B: M_RES(4,R->BC.B.h);break; case RES4_C: M_RES(4,R->BC.B.l);break;
case RES4_D: M_RES(4,R->DE.B.h);break; case RES4_E: M_RES(4,R->DE.B.l);break;
case RES4_H: M_RES(4,R->HL.B.h);break; case RES4_L: M_RES(4,R->HL.B.l);break;
case RES4_xHL: I=RdZ80(R->HL.W);M_RES(4,I);WrZ80(R->HL.W,I);break;
case RES4_A: M_RES(4,R->AF.B.h);break;
case RES5_B: M_RES(5,R->BC.B.h);break; case RES5_C: M_RES(5,R->BC.B.l);break;
case RES5_D: M_RES(5,R->DE.B.h);break; case RES5_E: M_RES(5,R->DE.B.l);break;
case RES5_H: M_RES(5,R->HL.B.h);break; case RES5_L: M_RES(5,R->HL.B.l);break;
case RES5_xHL: I=RdZ80(R->HL.W);M_RES(5,I);WrZ80(R->HL.W,I);break;
case RES5_A: M_RES(5,R->AF.B.h);break;
case RES6_B: M_RES(6,R->BC.B.h);break; case RES6_C: M_RES(6,R->BC.B.l);break;
case RES6_D: M_RES(6,R->DE.B.h);break; case RES6_E: M_RES(6,R->DE.B.l);break;
case RES6_H: M_RES(6,R->HL.B.h);break; case RES6_L: M_RES(6,R->HL.B.l);break;
case RES6_xHL: I=RdZ80(R->HL.W);M_RES(6,I);WrZ80(R->HL.W,I);break;
case RES6_A: M_RES(6,R->AF.B.h);break;
case RES7_B: M_RES(7,R->BC.B.h);break; case RES7_C: M_RES(7,R->BC.B.l);break;
case RES7_D: M_RES(7,R->DE.B.h);break; case RES7_E: M_RES(7,R->DE.B.l);break;
case RES7_H: M_RES(7,R->HL.B.h);break; case RES7_L: M_RES(7,R->HL.B.l);break;
case RES7_xHL: I=RdZ80(R->HL.W);M_RES(7,I);WrZ80(R->HL.W,I);break;
case RES7_A: M_RES(7,R->AF.B.h);break;
case SET0_B: M_SET(0,R->BC.B.h);break; case SET0_C: M_SET(0,R->BC.B.l);break;
case SET0_D: M_SET(0,R->DE.B.h);break; case SET0_E: M_SET(0,R->DE.B.l);break;
case SET0_H: M_SET(0,R->HL.B.h);break; case SET0_L: M_SET(0,R->HL.B.l);break;
case SET0_xHL: I=RdZ80(R->HL.W);M_SET(0,I);WrZ80(R->HL.W,I);break;
case SET0_A: M_SET(0,R->AF.B.h);break;
case SET1_B: M_SET(1,R->BC.B.h);break; case SET1_C: M_SET(1,R->BC.B.l);break;
case SET1_D: M_SET(1,R->DE.B.h);break; case SET1_E: M_SET(1,R->DE.B.l);break;
case SET1_H: M_SET(1,R->HL.B.h);break; case SET1_L: M_SET(1,R->HL.B.l);break;
case SET1_xHL: I=RdZ80(R->HL.W);M_SET(1,I);WrZ80(R->HL.W,I);break;
case SET1_A: M_SET(1,R->AF.B.h);break;
case SET2_B: M_SET(2,R->BC.B.h);break; case SET2_C: M_SET(2,R->BC.B.l);break;
case SET2_D: M_SET(2,R->DE.B.h);break; case SET2_E: M_SET(2,R->DE.B.l);break;
case SET2_H: M_SET(2,R->HL.B.h);break; case SET2_L: M_SET(2,R->HL.B.l);break;
case SET2_xHL: I=RdZ80(R->HL.W);M_SET(2,I);WrZ80(R->HL.W,I);break;
case SET2_A: M_SET(2,R->AF.B.h);break;
case SET3_B: M_SET(3,R->BC.B.h);break; case SET3_C: M_SET(3,R->BC.B.l);break;
case SET3_D: M_SET(3,R->DE.B.h);break; case SET3_E: M_SET(3,R->DE.B.l);break;
case SET3_H: M_SET(3,R->HL.B.h);break; case SET3_L: M_SET(3,R->HL.B.l);break;
case SET3_xHL: I=RdZ80(R->HL.W);M_SET(3,I);WrZ80(R->HL.W,I);break;
case SET3_A: M_SET(3,R->AF.B.h);break;
case SET4_B: M_SET(4,R->BC.B.h);break; case SET4_C: M_SET(4,R->BC.B.l);break;
case SET4_D: M_SET(4,R->DE.B.h);break; case SET4_E: M_SET(4,R->DE.B.l);break;
case SET4_H: M_SET(4,R->HL.B.h);break; case SET4_L: M_SET(4,R->HL.B.l);break;
case SET4_xHL: I=RdZ80(R->HL.W);M_SET(4,I);WrZ80(R->HL.W,I);break;
case SET4_A: M_SET(4,R->AF.B.h);break;
case SET5_B: M_SET(5,R->BC.B.h);break; case SET5_C: M_SET(5,R->BC.B.l);break;
case SET5_D: M_SET(5,R->DE.B.h);break; case SET5_E: M_SET(5,R->DE.B.l);break;
case SET5_H: M_SET(5,R->HL.B.h);break; case SET5_L: M_SET(5,R->HL.B.l);break;
case SET5_xHL: I=RdZ80(R->HL.W);M_SET(5,I);WrZ80(R->HL.W,I);break;
case SET5_A: M_SET(5,R->AF.B.h);break;
case SET6_B: M_SET(6,R->BC.B.h);break; case SET6_C: M_SET(6,R->BC.B.l);break;
case SET6_D: M_SET(6,R->DE.B.h);break; case SET6_E: M_SET(6,R->DE.B.l);break;
case SET6_H: M_SET(6,R->HL.B.h);break; case SET6_L: M_SET(6,R->HL.B.l);break;
case SET6_xHL: I=RdZ80(R->HL.W);M_SET(6,I);WrZ80(R->HL.W,I);break;
case SET6_A: M_SET(6,R->AF.B.h);break;
case SET7_B: M_SET(7,R->BC.B.h);break; case SET7_C: M_SET(7,R->BC.B.l);break;
case SET7_D: M_SET(7,R->DE.B.h);break; case SET7_E: M_SET(7,R->DE.B.l);break;
case SET7_H: M_SET(7,R->HL.B.h);break; case SET7_L: M_SET(7,R->HL.B.l);break;
case SET7_xHL: I=RdZ80(R->HL.W);M_SET(7,I);WrZ80(R->HL.W,I);break;
case SET7_A: M_SET(7,R->AF.B.h);break;

Wyświetl plik

@ -0,0 +1,304 @@
/** Z80: portable Z80 emulator *******************************/
/** **/
/** CodesED.h **/
/** **/
/** This file contains implementation for the ED table of **/
/** Z80 commands. It is included from Z80.c. **/
/** **/
/** Copyright (C) Marat Fayzullin 1994-2005 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
/** This is a special patch for emulating BIOS calls: ********/
case DB_FE: PatchZ80(R);break;
/*************************************************************/
case ADC_HL_BC: M_ADCW(BC);break;
case ADC_HL_DE: M_ADCW(DE);break;
case ADC_HL_HL: M_ADCW(HL);break;
case ADC_HL_SP: M_ADCW(SP);break;
case SBC_HL_BC: M_SBCW(BC);break;
case SBC_HL_DE: M_SBCW(DE);break;
case SBC_HL_HL: M_SBCW(HL);break;
case SBC_HL_SP: M_SBCW(SP);break;
case LD_xWORDe_HL:
J.B.l=RdZ80(R->PC.W++);
J.B.h=RdZ80(R->PC.W++);
WrZ80(J.W++,R->HL.B.l);
WrZ80(J.W,R->HL.B.h);
break;
case LD_xWORDe_DE:
J.B.l=RdZ80(R->PC.W++);
J.B.h=RdZ80(R->PC.W++);
WrZ80(J.W++,R->DE.B.l);
WrZ80(J.W,R->DE.B.h);
break;
case LD_xWORDe_BC:
J.B.l=RdZ80(R->PC.W++);
J.B.h=RdZ80(R->PC.W++);
WrZ80(J.W++,R->BC.B.l);
WrZ80(J.W,R->BC.B.h);
break;
case LD_xWORDe_SP:
J.B.l=RdZ80(R->PC.W++);
J.B.h=RdZ80(R->PC.W++);
WrZ80(J.W++,R->SP.B.l);
WrZ80(J.W,R->SP.B.h);
break;
case LD_HL_xWORDe:
J.B.l=RdZ80(R->PC.W++);
J.B.h=RdZ80(R->PC.W++);
R->HL.B.l=RdZ80(J.W++);
R->HL.B.h=RdZ80(J.W);
break;
case LD_DE_xWORDe:
J.B.l=RdZ80(R->PC.W++);
J.B.h=RdZ80(R->PC.W++);
R->DE.B.l=RdZ80(J.W++);
R->DE.B.h=RdZ80(J.W);
break;
case LD_BC_xWORDe:
J.B.l=RdZ80(R->PC.W++);
J.B.h=RdZ80(R->PC.W++);
R->BC.B.l=RdZ80(J.W++);
R->BC.B.h=RdZ80(J.W);
break;
case LD_SP_xWORDe:
J.B.l=RdZ80(R->PC.W++);
J.B.h=RdZ80(R->PC.W++);
R->SP.B.l=RdZ80(J.W++);
R->SP.B.h=RdZ80(J.W);
break;
case RRD:
I=RdZ80(R->HL.W);
J.B.l=(I>>4)|(R->AF.B.h<<4);
WrZ80(R->HL.W,J.B.l);
R->AF.B.h=(I&0x0F)|(R->AF.B.h&0xF0);
R->AF.B.l=PZSTable[R->AF.B.h]|(R->AF.B.l&C_FLAG);
break;
case RLD:
I=RdZ80(R->HL.W);
J.B.l=(I<<4)|(R->AF.B.h&0x0F);
WrZ80(R->HL.W,J.B.l);
R->AF.B.h=(I>>4)|(R->AF.B.h&0xF0);
R->AF.B.l=PZSTable[R->AF.B.h]|(R->AF.B.l&C_FLAG);
break;
case LD_A_I:
R->AF.B.h=R->I;
R->AF.B.l=(R->AF.B.l&C_FLAG)|(R->IFF&IFF_2? P_FLAG:0)|ZSTable[R->AF.B.h];
break;
case LD_A_R:
R->R++;
R->AF.B.h=(byte)(R->R-R->ICount);
R->AF.B.l=(R->AF.B.l&C_FLAG)|(R->IFF&IFF_2? P_FLAG:0)|ZSTable[R->AF.B.h];
break;
case LD_I_A: R->I=R->AF.B.h;break;
case LD_R_A: break;
case IM_0: R->IFF&=~(IFF_IM1|IFF_IM2);break;
case IM_1: R->IFF=(R->IFF&~IFF_IM2)|IFF_IM1;break;
case IM_2: R->IFF=(R->IFF&~IFF_IM1)|IFF_IM2;break;
case RETI: M_RET;break;
case RETN: if(R->IFF&IFF_2) R->IFF|=IFF_1; else R->IFF&=~IFF_1;
M_RET;break;
case NEG: I=R->AF.B.h;R->AF.B.h=0;M_SUB(I);break;
case IN_B_xC: M_IN(R->BC.B.h);break;
case IN_C_xC: M_IN(R->BC.B.l);break;
case IN_D_xC: M_IN(R->DE.B.h);break;
case IN_E_xC: M_IN(R->DE.B.l);break;
case IN_H_xC: M_IN(R->HL.B.h);break;
case IN_L_xC: M_IN(R->HL.B.l);break;
case IN_A_xC: M_IN(R->AF.B.h);break;
case IN_F_xC: M_IN(J.B.l);break;
case OUT_xC_B: OutZ80(R->BC.B.l,R->BC.B.h);break;
case OUT_xC_C: OutZ80(R->BC.B.l,R->BC.B.l);break;
case OUT_xC_D: OutZ80(R->BC.B.l,R->DE.B.h);break;
case OUT_xC_E: OutZ80(R->BC.B.l,R->DE.B.l);break;
case OUT_xC_H: OutZ80(R->BC.B.l,R->HL.B.h);break;
case OUT_xC_L: OutZ80(R->BC.B.l,R->HL.B.l);break;
case OUT_xC_A: OutZ80(R->BC.B.l,R->AF.B.h);break;
case INI:
WrZ80(R->HL.W++,InZ80(R->BC.B.l));
R->BC.B.h--;
R->AF.B.l=N_FLAG|(R->BC.B.h? 0:Z_FLAG);
break;
case INIR:
do
{
WrZ80(R->HL.W++,InZ80(R->BC.B.l));
R->BC.B.h--;R->ICount-=21;
}
while(R->BC.B.h&&(R->ICount>0));
if(R->BC.B.h) { R->AF.B.l=N_FLAG;R->PC.W-=2; }
else { R->AF.B.l=Z_FLAG|N_FLAG;R->ICount+=5; }
break;
case IND:
WrZ80(R->HL.W--,InZ80(R->BC.B.l));
R->BC.B.h--;
R->AF.B.l=N_FLAG|(R->BC.B.h? 0:Z_FLAG);
break;
case INDR:
do
{
WrZ80(R->HL.W--,InZ80(R->BC.B.l));
R->BC.B.h--;R->ICount-=21;
}
while(R->BC.B.h&&(R->ICount>0));
if(R->BC.B.h) { R->AF.B.l=N_FLAG;R->PC.W-=2; }
else { R->AF.B.l=Z_FLAG|N_FLAG;R->ICount+=5; }
break;
case OUTI:
I=RdZ80(R->HL.W++);
OutZ80(R->BC.B.l,I);
R->BC.B.h--;
R->AF.B.l=N_FLAG|(R->BC.B.h? 0:Z_FLAG)|(R->HL.B.l+I>255? (C_FLAG|H_FLAG):0);
break;
case OTIR:
do
{
I=RdZ80(R->HL.W++);
OutZ80(R->BC.B.l,I);
R->BC.B.h--;
R->ICount-=21;
}
while(R->BC.B.h&&(R->ICount>0));
if(R->BC.B.h)
{
R->AF.B.l=N_FLAG|(R->HL.B.l+I>255? (C_FLAG|H_FLAG):0);
R->PC.W-=2;
}
else
{
R->AF.B.l=Z_FLAG|N_FLAG|(R->HL.B.l+I>255? (C_FLAG|H_FLAG):0);
R->ICount+=5;
}
break;
case OUTD:
I=RdZ80(R->HL.W--);
OutZ80(R->BC.B.l,I);
R->BC.B.h--;
R->AF.B.l=N_FLAG|(R->BC.B.h? 0:Z_FLAG)|(R->HL.B.l+I>255? (C_FLAG|H_FLAG):0);
break;
case OTDR:
do
{
I=RdZ80(R->HL.W--);
OutZ80(R->BC.B.l,I);
R->BC.B.h--;
R->ICount-=21;
}
while(R->BC.B.h&&(R->ICount>0));
if(R->BC.B.h)
{
R->AF.B.l=N_FLAG|(R->HL.B.l+I>255? (C_FLAG|H_FLAG):0);
R->PC.W-=2;
}
else
{
R->AF.B.l=Z_FLAG|N_FLAG|(R->HL.B.l+I>255? (C_FLAG|H_FLAG):0);
R->ICount+=5;
}
break;
case LDI:
WrZ80(R->DE.W++,RdZ80(R->HL.W++));
R->BC.W--;
R->AF.B.l=(R->AF.B.l&~(N_FLAG|H_FLAG|P_FLAG))|(R->BC.W? P_FLAG:0);
break;
case LDIR:
do
{
WrZ80(R->DE.W++,RdZ80(R->HL.W++));
R->BC.W--;R->ICount-=21;
}
while(R->BC.W&&(R->ICount>0));
R->AF.B.l&=~(N_FLAG|H_FLAG|P_FLAG);
if(R->BC.W) { R->AF.B.l|=N_FLAG;R->PC.W-=2; }
else R->ICount+=5;
break;
case LDD:
WrZ80(R->DE.W--,RdZ80(R->HL.W--));
R->BC.W--;
R->AF.B.l=(R->AF.B.l&~(N_FLAG|H_FLAG|P_FLAG))|(R->BC.W? P_FLAG:0);
break;
case LDDR:
do
{
WrZ80(R->DE.W--,RdZ80(R->HL.W--));
R->BC.W--;R->ICount-=21;
}
while(R->BC.W&&(R->ICount>0));
R->AF.B.l&=~(N_FLAG|H_FLAG|P_FLAG);
if(R->BC.W) { R->AF.B.l|=N_FLAG;R->PC.W-=2; }
else R->ICount+=5;
break;
case CPI:
I=RdZ80(R->HL.W++);
J.B.l=R->AF.B.h-I;
R->BC.W--;
R->AF.B.l =
N_FLAG|(R->AF.B.l&C_FLAG)|ZSTable[J.B.l]|
((R->AF.B.h^I^J.B.l)&H_FLAG)|(R->BC.W? P_FLAG:0);
break;
case CPIR:
do
{
I=RdZ80(R->HL.W++);
J.B.l=R->AF.B.h-I;
R->BC.W--;R->ICount-=21;
}
while(R->BC.W&&J.B.l&&(R->ICount>0));
R->AF.B.l =
N_FLAG|(R->AF.B.l&C_FLAG)|ZSTable[J.B.l]|
((R->AF.B.h^I^J.B.l)&H_FLAG)|(R->BC.W? P_FLAG:0);
if(R->BC.W&&J.B.l) R->PC.W-=2; else R->ICount+=5;
break;
case CPD:
I=RdZ80(R->HL.W--);
J.B.l=R->AF.B.h-I;
R->BC.W--;
R->AF.B.l =
N_FLAG|(R->AF.B.l&C_FLAG)|ZSTable[J.B.l]|
((R->AF.B.h^I^J.B.l)&H_FLAG)|(R->BC.W? P_FLAG:0);
break;
case CPDR:
do
{
I=RdZ80(R->HL.W--);
J.B.l=R->AF.B.h-I;
R->BC.W--;R->ICount-=21;
}
while(R->BC.W&&J.B.l);
R->AF.B.l =
N_FLAG|(R->AF.B.l&C_FLAG)|ZSTable[J.B.l]|
((R->AF.B.h^I^J.B.l)&H_FLAG)|(R->BC.W? P_FLAG:0);
if(R->BC.W&&J.B.l) R->PC.W-=2; else R->ICount+=5;
break;

Wyświetl plik

@ -0,0 +1,64 @@
/** Z80: portable Z80 emulator *******************************/
/** **/
/** CodesXCB.h **/
/** **/
/** This file contains implementation for FD/DD-CB tables **/
/** of Z80 commands. It is included from Z80.c. **/
/** **/
/** Copyright (C) Marat Fayzullin 1994-2005 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
case RLC_xHL: I=RdZ80(J.W);M_RLC(I);WrZ80(J.W,I);break;
case RRC_xHL: I=RdZ80(J.W);M_RRC(I);WrZ80(J.W,I);break;
case RL_xHL: I=RdZ80(J.W);M_RL(I);WrZ80(J.W,I);break;
case RR_xHL: I=RdZ80(J.W);M_RR(I);WrZ80(J.W,I);break;
case SLA_xHL: I=RdZ80(J.W);M_SLA(I);WrZ80(J.W,I);break;
case SRA_xHL: I=RdZ80(J.W);M_SRA(I);WrZ80(J.W,I);break;
case SLL_xHL: I=RdZ80(J.W);M_SLL(I);WrZ80(J.W,I);break;
case SRL_xHL: I=RdZ80(J.W);M_SRL(I);WrZ80(J.W,I);break;
case BIT0_B: case BIT0_C: case BIT0_D: case BIT0_E:
case BIT0_H: case BIT0_L: case BIT0_A:
case BIT0_xHL: I=RdZ80(J.W);M_BIT(0,I);break;
case BIT1_B: case BIT1_C: case BIT1_D: case BIT1_E:
case BIT1_H: case BIT1_L: case BIT1_A:
case BIT1_xHL: I=RdZ80(J.W);M_BIT(1,I);break;
case BIT2_B: case BIT2_C: case BIT2_D: case BIT2_E:
case BIT2_H: case BIT2_L: case BIT2_A:
case BIT2_xHL: I=RdZ80(J.W);M_BIT(2,I);break;
case BIT3_B: case BIT3_C: case BIT3_D: case BIT3_E:
case BIT3_H: case BIT3_L: case BIT3_A:
case BIT3_xHL: I=RdZ80(J.W);M_BIT(3,I);break;
case BIT4_B: case BIT4_C: case BIT4_D: case BIT4_E:
case BIT4_H: case BIT4_L: case BIT4_A:
case BIT4_xHL: I=RdZ80(J.W);M_BIT(4,I);break;
case BIT5_B: case BIT5_C: case BIT5_D: case BIT5_E:
case BIT5_H: case BIT5_L: case BIT5_A:
case BIT5_xHL: I=RdZ80(J.W);M_BIT(5,I);break;
case BIT6_B: case BIT6_C: case BIT6_D: case BIT6_E:
case BIT6_H: case BIT6_L: case BIT6_A:
case BIT6_xHL: I=RdZ80(J.W);M_BIT(6,I);break;
case BIT7_B: case BIT7_C: case BIT7_D: case BIT7_E:
case BIT7_H: case BIT7_L: case BIT7_A:
case BIT7_xHL: I=RdZ80(J.W);M_BIT(7,I);break;
case RES0_xHL: I=RdZ80(J.W);M_RES(0,I);WrZ80(J.W,I);break;
case RES1_xHL: I=RdZ80(J.W);M_RES(1,I);WrZ80(J.W,I);break;
case RES2_xHL: I=RdZ80(J.W);M_RES(2,I);WrZ80(J.W,I);break;
case RES3_xHL: I=RdZ80(J.W);M_RES(3,I);WrZ80(J.W,I);break;
case RES4_xHL: I=RdZ80(J.W);M_RES(4,I);WrZ80(J.W,I);break;
case RES5_xHL: I=RdZ80(J.W);M_RES(5,I);WrZ80(J.W,I);break;
case RES6_xHL: I=RdZ80(J.W);M_RES(6,I);WrZ80(J.W,I);break;
case RES7_xHL: I=RdZ80(J.W);M_RES(7,I);WrZ80(J.W,I);break;
case SET0_xHL: I=RdZ80(J.W);M_SET(0,I);WrZ80(J.W,I);break;
case SET1_xHL: I=RdZ80(J.W);M_SET(1,I);WrZ80(J.W,I);break;
case SET2_xHL: I=RdZ80(J.W);M_SET(2,I);WrZ80(J.W,I);break;
case SET3_xHL: I=RdZ80(J.W);M_SET(3,I);WrZ80(J.W,I);break;
case SET4_xHL: I=RdZ80(J.W);M_SET(4,I);WrZ80(J.W,I);break;
case SET5_xHL: I=RdZ80(J.W);M_SET(5,I);WrZ80(J.W,I);break;
case SET6_xHL: I=RdZ80(J.W);M_SET(6,I);WrZ80(J.W,I);break;
case SET7_xHL: I=RdZ80(J.W);M_SET(7,I);WrZ80(J.W,I);break;

Wyświetl plik

@ -0,0 +1,396 @@
/** Z80: portable Z80 emulator *******************************/
/** **/
/** CodesXX.h **/
/** **/
/** This file contains implementation for FD/DD tables of **/
/** Z80 commands. It is included from Z80.c. **/
/** **/
/** Copyright (C) Marat Fayzullin 1994-2005 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
case JR_NZ: if(R->AF.B.l&Z_FLAG) R->PC.W++; else { R->ICount-=5;M_JR; } break;
case JR_NC: if(R->AF.B.l&C_FLAG) R->PC.W++; else { R->ICount-=5;M_JR; } break;
case JR_Z: if(R->AF.B.l&Z_FLAG) { R->ICount-=5;M_JR; } else R->PC.W++; break;
case JR_C: if(R->AF.B.l&C_FLAG) { R->ICount-=5;M_JR; } else R->PC.W++; break;
case JP_NZ: if(R->AF.B.l&Z_FLAG) R->PC.W+=2; else { M_JP; } break;
case JP_NC: if(R->AF.B.l&C_FLAG) R->PC.W+=2; else { M_JP; } break;
case JP_PO: if(R->AF.B.l&P_FLAG) R->PC.W+=2; else { M_JP; } break;
case JP_P: if(R->AF.B.l&S_FLAG) R->PC.W+=2; else { M_JP; } break;
case JP_Z: if(R->AF.B.l&Z_FLAG) { M_JP; } else R->PC.W+=2; break;
case JP_C: if(R->AF.B.l&C_FLAG) { M_JP; } else R->PC.W+=2; break;
case JP_PE: if(R->AF.B.l&P_FLAG) { M_JP; } else R->PC.W+=2; break;
case JP_M: if(R->AF.B.l&S_FLAG) { M_JP; } else R->PC.W+=2; break;
case RET_NZ: if(!(R->AF.B.l&Z_FLAG)) { R->ICount-=6;M_RET; } break;
case RET_NC: if(!(R->AF.B.l&C_FLAG)) { R->ICount-=6;M_RET; } break;
case RET_PO: if(!(R->AF.B.l&P_FLAG)) { R->ICount-=6;M_RET; } break;
case RET_P: if(!(R->AF.B.l&S_FLAG)) { R->ICount-=6;M_RET; } break;
case RET_Z: if(R->AF.B.l&Z_FLAG) { R->ICount-=6;M_RET; } break;
case RET_C: if(R->AF.B.l&C_FLAG) { R->ICount-=6;M_RET; } break;
case RET_PE: if(R->AF.B.l&P_FLAG) { R->ICount-=6;M_RET; } break;
case RET_M: if(R->AF.B.l&S_FLAG) { R->ICount-=6;M_RET; } break;
case CALL_NZ: if(R->AF.B.l&Z_FLAG) R->PC.W+=2; else { R->ICount-=7;M_CALL; } break;
case CALL_NC: if(R->AF.B.l&C_FLAG) R->PC.W+=2; else { R->ICount-=7;M_CALL; } break;
case CALL_PO: if(R->AF.B.l&P_FLAG) R->PC.W+=2; else { R->ICount-=7;M_CALL; } break;
case CALL_P: if(R->AF.B.l&S_FLAG) R->PC.W+=2; else { R->ICount-=7;M_CALL; } break;
case CALL_Z: if(R->AF.B.l&Z_FLAG) { R->ICount-=7;M_CALL; } else R->PC.W+=2; break;
case CALL_C: if(R->AF.B.l&C_FLAG) { R->ICount-=7;M_CALL; } else R->PC.W+=2; break;
case CALL_PE: if(R->AF.B.l&P_FLAG) { R->ICount-=7;M_CALL; } else R->PC.W+=2; break;
case CALL_M: if(R->AF.B.l&S_FLAG) { R->ICount-=7;M_CALL; } else R->PC.W+=2; break;
case ADD_B: M_ADD(R->BC.B.h);break;
case ADD_C: M_ADD(R->BC.B.l);break;
case ADD_D: M_ADD(R->DE.B.h);break;
case ADD_E: M_ADD(R->DE.B.l);break;
case ADD_H: M_ADD(R->XX.B.h);break;
case ADD_L: M_ADD(R->XX.B.l);break;
case ADD_A: M_ADD(R->AF.B.h);break;
case ADD_xHL: I=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++));
M_ADD(I);break;
case ADD_BYTE: I=RdZ80(R->PC.W++);M_ADD(I);break;
case SUB_B: M_SUB(R->BC.B.h);break;
case SUB_C: M_SUB(R->BC.B.l);break;
case SUB_D: M_SUB(R->DE.B.h);break;
case SUB_E: M_SUB(R->DE.B.l);break;
case SUB_H: M_SUB(R->XX.B.h);break;
case SUB_L: M_SUB(R->XX.B.l);break;
case SUB_A: R->AF.B.h=0;R->AF.B.l=N_FLAG|Z_FLAG;break;
case SUB_xHL: I=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++));
M_SUB(I);break;
case SUB_BYTE: I=RdZ80(R->PC.W++);M_SUB(I);break;
case AND_B: M_AND(R->BC.B.h);break;
case AND_C: M_AND(R->BC.B.l);break;
case AND_D: M_AND(R->DE.B.h);break;
case AND_E: M_AND(R->DE.B.l);break;
case AND_H: M_AND(R->XX.B.h);break;
case AND_L: M_AND(R->XX.B.l);break;
case AND_A: M_AND(R->AF.B.h);break;
case AND_xHL: I=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++));
M_AND(I);break;
case AND_BYTE: I=RdZ80(R->PC.W++);M_AND(I);break;
case OR_B: M_OR(R->BC.B.h);break;
case OR_C: M_OR(R->BC.B.l);break;
case OR_D: M_OR(R->DE.B.h);break;
case OR_E: M_OR(R->DE.B.l);break;
case OR_H: M_OR(R->XX.B.h);break;
case OR_L: M_OR(R->XX.B.l);break;
case OR_A: M_OR(R->AF.B.h);break;
case OR_xHL: I=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++));
M_OR(I);break;
case OR_BYTE: I=RdZ80(R->PC.W++);M_OR(I);break;
case ADC_B: M_ADC(R->BC.B.h);break;
case ADC_C: M_ADC(R->BC.B.l);break;
case ADC_D: M_ADC(R->DE.B.h);break;
case ADC_E: M_ADC(R->DE.B.l);break;
case ADC_H: M_ADC(R->XX.B.h);break;
case ADC_L: M_ADC(R->XX.B.l);break;
case ADC_A: M_ADC(R->AF.B.h);break;
case ADC_xHL: I=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++));
M_ADC(I);break;
case ADC_BYTE: I=RdZ80(R->PC.W++);M_ADC(I);break;
case SBC_B: M_SBC(R->BC.B.h);break;
case SBC_C: M_SBC(R->BC.B.l);break;
case SBC_D: M_SBC(R->DE.B.h);break;
case SBC_E: M_SBC(R->DE.B.l);break;
case SBC_H: M_SBC(R->XX.B.h);break;
case SBC_L: M_SBC(R->XX.B.l);break;
case SBC_A: M_SBC(R->AF.B.h);break;
case SBC_xHL: I=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++));
M_SBC(I);break;
case SBC_BYTE: I=RdZ80(R->PC.W++);M_SBC(I);break;
case XOR_B: M_XOR(R->BC.B.h);break;
case XOR_C: M_XOR(R->BC.B.l);break;
case XOR_D: M_XOR(R->DE.B.h);break;
case XOR_E: M_XOR(R->DE.B.l);break;
case XOR_H: M_XOR(R->XX.B.h);break;
case XOR_L: M_XOR(R->XX.B.l);break;
case XOR_A: R->AF.B.h=0;R->AF.B.l=P_FLAG|Z_FLAG;break;
case XOR_xHL: I=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++));
M_XOR(I);break;
case XOR_BYTE: I=RdZ80(R->PC.W++);M_XOR(I);break;
case CP_B: M_CP(R->BC.B.h);break;
case CP_C: M_CP(R->BC.B.l);break;
case CP_D: M_CP(R->DE.B.h);break;
case CP_E: M_CP(R->DE.B.l);break;
case CP_H: M_CP(R->XX.B.h);break;
case CP_L: M_CP(R->XX.B.l);break;
case CP_A: R->AF.B.l=N_FLAG|Z_FLAG;break;
case CP_xHL: I=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++));
M_CP(I);break;
case CP_BYTE: I=RdZ80(R->PC.W++);M_CP(I);break;
case LD_BC_WORD: M_LDWORD(BC);break;
case LD_DE_WORD: M_LDWORD(DE);break;
case LD_HL_WORD: M_LDWORD(XX);break;
case LD_SP_WORD: M_LDWORD(SP);break;
case LD_PC_HL: R->PC.W=R->XX.W;break;
case LD_SP_HL: R->SP.W=R->XX.W;break;
case LD_A_xBC: R->AF.B.h=RdZ80(R->BC.W);break;
case LD_A_xDE: R->AF.B.h=RdZ80(R->DE.W);break;
case ADD_HL_BC: M_ADDW(XX,BC);break;
case ADD_HL_DE: M_ADDW(XX,DE);break;
case ADD_HL_HL: M_ADDW(XX,XX);break;
case ADD_HL_SP: M_ADDW(XX,SP);break;
case DEC_BC: R->BC.W--;break;
case DEC_DE: R->DE.W--;break;
case DEC_HL: R->XX.W--;break;
case DEC_SP: R->SP.W--;break;
case INC_BC: R->BC.W++;break;
case INC_DE: R->DE.W++;break;
case INC_HL: R->XX.W++;break;
case INC_SP: R->SP.W++;break;
case DEC_B: M_DEC(R->BC.B.h);break;
case DEC_C: M_DEC(R->BC.B.l);break;
case DEC_D: M_DEC(R->DE.B.h);break;
case DEC_E: M_DEC(R->DE.B.l);break;
case DEC_H: M_DEC(R->XX.B.h);break;
case DEC_L: M_DEC(R->XX.B.l);break;
case DEC_A: M_DEC(R->AF.B.h);break;
case DEC_xHL: I=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W));M_DEC(I);
WrZ80(R->XX.W+(offset)RdZ80(R->PC.W++),I);
break;
case INC_B: M_INC(R->BC.B.h);break;
case INC_C: M_INC(R->BC.B.l);break;
case INC_D: M_INC(R->DE.B.h);break;
case INC_E: M_INC(R->DE.B.l);break;
case INC_H: M_INC(R->XX.B.h);break;
case INC_L: M_INC(R->XX.B.l);break;
case INC_A: M_INC(R->AF.B.h);break;
case INC_xHL: I=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W));M_INC(I);
WrZ80(R->XX.W+(offset)RdZ80(R->PC.W++),I);
break;
case RLCA:
I=(R->AF.B.h&0x80? C_FLAG:0);
R->AF.B.h=(R->AF.B.h<<1)|I;
R->AF.B.l=(R->AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I;
break;
case RLA:
I=(R->AF.B.h&0x80? C_FLAG:0);
R->AF.B.h=(R->AF.B.h<<1)|(R->AF.B.l&C_FLAG);
R->AF.B.l=(R->AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I;
break;
case RRCA:
I=R->AF.B.h&0x01;
R->AF.B.h=(R->AF.B.h>>1)|(I? 0x80:0);
R->AF.B.l=(R->AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I;
break;
case RRA:
I=R->AF.B.h&0x01;
R->AF.B.h=(R->AF.B.h>>1)|(R->AF.B.l&C_FLAG? 0x80:0);
R->AF.B.l=(R->AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I;
break;
case RST00: M_RST(0x0000);break;
case RST08: M_RST(0x0008);break;
case RST10: M_RST(0x0010);break;
case RST18: M_RST(0x0018);break;
case RST20: M_RST(0x0020);break;
case RST28: M_RST(0x0028);break;
case RST30: M_RST(0x0030);break;
case RST38: M_RST(0x0038);break;
case PUSH_BC: M_PUSH(BC);break;
case PUSH_DE: M_PUSH(DE);break;
case PUSH_HL: M_PUSH(XX);break;
case PUSH_AF: M_PUSH(AF);break;
case POP_BC: M_POP(BC);break;
case POP_DE: M_POP(DE);break;
case POP_HL: M_POP(XX);break;
case POP_AF: M_POP(AF);break;
case DJNZ: if(--R->BC.B.h) { R->ICount-=5;M_JR; } else R->PC.W++;break;
case JP: M_JP;break;
case JR: M_JR;break;
case CALL: M_CALL;break;
case RET: M_RET;break;
case SCF: S(C_FLAG);R(N_FLAG|H_FLAG);break;
case CPL: R->AF.B.h=~R->AF.B.h;S(N_FLAG|H_FLAG);break;
case NOP: break;
case OUTA: OutZ80(RdZ80(R->PC.W++),R->AF.B.h);break;
case INA: R->AF.B.h=InZ80(RdZ80(R->PC.W++));break;
case HALT:
R->PC.W--;
R->IFF|=IFF_HALT;
R->IBackup=0;
R->ICount=0;
break;
case DI:
if(R->IFF&IFF_EI) R->ICount+=R->IBackup-1;
R->IFF&=~(IFF_1|IFF_2|IFF_EI);
break;
case EI:
if(!(R->IFF&(IFF_1|IFF_EI)))
{
R->IFF|=IFF_2|IFF_EI;
R->IBackup=R->ICount;
R->ICount=1;
}
break;
case CCF:
R->AF.B.l^=C_FLAG;R(N_FLAG|H_FLAG);
R->AF.B.l|=R->AF.B.l&C_FLAG? 0:H_FLAG;
break;
case EXX:
J.W=R->BC.W;R->BC.W=R->BC1.W;R->BC1.W=J.W;
J.W=R->DE.W;R->DE.W=R->DE1.W;R->DE1.W=J.W;
J.W=R->HL.W;R->HL.W=R->HL1.W;R->HL1.W=J.W;
break;
case EX_DE_HL: J.W=R->DE.W;R->DE.W=R->HL.W;R->HL.W=J.W;break;
case EX_AF_AF: J.W=R->AF.W;R->AF.W=R->AF1.W;R->AF1.W=J.W;break;
case LD_B_B: R->BC.B.h=R->BC.B.h;break;
case LD_C_B: R->BC.B.l=R->BC.B.h;break;
case LD_D_B: R->DE.B.h=R->BC.B.h;break;
case LD_E_B: R->DE.B.l=R->BC.B.h;break;
case LD_H_B: R->XX.B.h=R->BC.B.h;break;
case LD_L_B: R->XX.B.l=R->BC.B.h;break;
case LD_A_B: R->AF.B.h=R->BC.B.h;break;
case LD_xHL_B: J.W=R->XX.W+(offset)RdZ80(R->PC.W++);
WrZ80(J.W,R->BC.B.h);break;
case LD_B_C: R->BC.B.h=R->BC.B.l;break;
case LD_C_C: R->BC.B.l=R->BC.B.l;break;
case LD_D_C: R->DE.B.h=R->BC.B.l;break;
case LD_E_C: R->DE.B.l=R->BC.B.l;break;
case LD_H_C: R->XX.B.h=R->BC.B.l;break;
case LD_L_C: R->XX.B.l=R->BC.B.l;break;
case LD_A_C: R->AF.B.h=R->BC.B.l;break;
case LD_xHL_C: J.W=R->XX.W+(offset)RdZ80(R->PC.W++);
WrZ80(J.W,R->BC.B.l);break;
case LD_B_D: R->BC.B.h=R->DE.B.h;break;
case LD_C_D: R->BC.B.l=R->DE.B.h;break;
case LD_D_D: R->DE.B.h=R->DE.B.h;break;
case LD_E_D: R->DE.B.l=R->DE.B.h;break;
case LD_H_D: R->XX.B.h=R->DE.B.h;break;
case LD_L_D: R->XX.B.l=R->DE.B.h;break;
case LD_A_D: R->AF.B.h=R->DE.B.h;break;
case LD_xHL_D: J.W=R->XX.W+(offset)RdZ80(R->PC.W++);
WrZ80(J.W,R->DE.B.h);break;
case LD_B_E: R->BC.B.h=R->DE.B.l;break;
case LD_C_E: R->BC.B.l=R->DE.B.l;break;
case LD_D_E: R->DE.B.h=R->DE.B.l;break;
case LD_E_E: R->DE.B.l=R->DE.B.l;break;
case LD_H_E: R->XX.B.h=R->DE.B.l;break;
case LD_L_E: R->XX.B.l=R->DE.B.l;break;
case LD_A_E: R->AF.B.h=R->DE.B.l;break;
case LD_xHL_E: J.W=R->XX.W+(offset)RdZ80(R->PC.W++);
WrZ80(J.W,R->DE.B.l);break;
case LD_B_H: R->BC.B.h=R->XX.B.h;break;
case LD_C_H: R->BC.B.l=R->XX.B.h;break;
case LD_D_H: R->DE.B.h=R->XX.B.h;break;
case LD_E_H: R->DE.B.l=R->XX.B.h;break;
case LD_H_H: R->XX.B.h=R->XX.B.h;break;
case LD_L_H: R->XX.B.l=R->XX.B.h;break;
case LD_A_H: R->AF.B.h=R->XX.B.h;break;
case LD_xHL_H: J.W=R->XX.W+(offset)RdZ80(R->PC.W++);
WrZ80(J.W,R->HL.B.h);break;
case LD_B_L: R->BC.B.h=R->XX.B.l;break;
case LD_C_L: R->BC.B.l=R->XX.B.l;break;
case LD_D_L: R->DE.B.h=R->XX.B.l;break;
case LD_E_L: R->DE.B.l=R->XX.B.l;break;
case LD_H_L: R->XX.B.h=R->XX.B.l;break;
case LD_L_L: R->XX.B.l=R->XX.B.l;break;
case LD_A_L: R->AF.B.h=R->XX.B.l;break;
case LD_xHL_L: J.W=R->XX.W+(offset)RdZ80(R->PC.W++);
WrZ80(J.W,R->HL.B.l);break;
case LD_B_A: R->BC.B.h=R->AF.B.h;break;
case LD_C_A: R->BC.B.l=R->AF.B.h;break;
case LD_D_A: R->DE.B.h=R->AF.B.h;break;
case LD_E_A: R->DE.B.l=R->AF.B.h;break;
case LD_H_A: R->XX.B.h=R->AF.B.h;break;
case LD_L_A: R->XX.B.l=R->AF.B.h;break;
case LD_A_A: R->AF.B.h=R->AF.B.h;break;
case LD_xHL_A: J.W=R->XX.W+(offset)RdZ80(R->PC.W++);
WrZ80(J.W,R->AF.B.h);break;
case LD_xBC_A: WrZ80(R->BC.W,R->AF.B.h);break;
case LD_xDE_A: WrZ80(R->DE.W,R->AF.B.h);break;
case LD_B_xHL: R->BC.B.h=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++));break;
case LD_C_xHL: R->BC.B.l=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++));break;
case LD_D_xHL: R->DE.B.h=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++));break;
case LD_E_xHL: R->DE.B.l=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++));break;
case LD_H_xHL: R->HL.B.h=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++));break;
case LD_L_xHL: R->HL.B.l=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++));break;
case LD_A_xHL: R->AF.B.h=RdZ80(R->XX.W+(offset)RdZ80(R->PC.W++));break;
case LD_B_BYTE: R->BC.B.h=RdZ80(R->PC.W++);break;
case LD_C_BYTE: R->BC.B.l=RdZ80(R->PC.W++);break;
case LD_D_BYTE: R->DE.B.h=RdZ80(R->PC.W++);break;
case LD_E_BYTE: R->DE.B.l=RdZ80(R->PC.W++);break;
case LD_H_BYTE: R->XX.B.h=RdZ80(R->PC.W++);break;
case LD_L_BYTE: R->XX.B.l=RdZ80(R->PC.W++);break;
case LD_A_BYTE: R->AF.B.h=RdZ80(R->PC.W++);break;
case LD_xHL_BYTE: J.W=R->XX.W+(offset)RdZ80(R->PC.W++);
WrZ80(J.W,RdZ80(R->PC.W++));break;
case LD_xWORD_HL:
J.B.l=RdZ80(R->PC.W++);
J.B.h=RdZ80(R->PC.W++);
WrZ80(J.W++,R->XX.B.l);
WrZ80(J.W,R->XX.B.h);
break;
case LD_HL_xWORD:
J.B.l=RdZ80(R->PC.W++);
J.B.h=RdZ80(R->PC.W++);
R->XX.B.l=RdZ80(J.W++);
R->XX.B.h=RdZ80(J.W);
break;
case LD_A_xWORD:
J.B.l=RdZ80(R->PC.W++);
J.B.h=RdZ80(R->PC.W++);
R->AF.B.h=RdZ80(J.W);
break;
case LD_xWORD_A:
J.B.l=RdZ80(R->PC.W++);
J.B.h=RdZ80(R->PC.W++);
WrZ80(J.W,R->AF.B.h);
break;
case EX_HL_xSP:
J.B.l=RdZ80(R->SP.W);WrZ80(R->SP.W++,R->XX.B.l);
J.B.h=RdZ80(R->SP.W);WrZ80(R->SP.W--,R->XX.B.h);
R->XX.W=J.W;
break;
case DAA:
J.W=R->AF.B.h;
if(R->AF.B.l&C_FLAG) J.W|=256;
if(R->AF.B.l&H_FLAG) J.W|=512;
if(R->AF.B.l&N_FLAG) J.W|=1024;
R->AF.W=DAATable[J.W];
break;

Wyświetl plik

@ -0,0 +1,96 @@
/** fMSX: portable MSX emulator ******************************/
/** **/
/** Disk.c **/
/** **/
/** This file contains standard disk access drivers working **/
/** with disk images from files. **/
/** **/
/** Copyright (C) Marat Fayzullin 1994-2003 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
#include "MSX.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#ifdef __BORLANDC__
#include <io.h>
#endif
#ifdef UNIX
#include <unistd.h>
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
static int Drives[2] = { -1,-1 }; /* Disk image files */
static int RdOnly[2]; /* 1 = read-only */
/** DiskPresent() ********************************************/
/** Return 1 if disk drive with a given ID is present. **/
/*************************************************************/
byte DiskPresent(byte ID)
{
return((ID<MAXDRIVES)&&(Drives[ID]>=0));
}
/** DiskRead() ***********************************************/
/** Read requested sector from the drive into a buffer. **/
/*************************************************************/
byte DiskRead(byte ID,byte *Buf,int N)
{
#ifdef unused
if((ID<MAXDRIVES)&&(Drives[ID]>=0))
if(lseek(Drives[ID],N*512L,0)==N*512L)
return(read(Drives[ID],Buf,512)==512);
#endif
return(0);
}
/** DiskWrite() **********************************************/
/** Write contents of the buffer into a given sector of the **/
/** disk. **/
/*************************************************************/
byte DiskWrite(byte ID,byte *Buf,int N)
{
#ifdef unused
if((ID<MAXDRIVES)&&(Drives[ID]>=0)&&!RdOnly[ID])
if(lseek(Drives[ID],N*512L,0)==N*512L)
return(write(Drives[ID],Buf,512)==512);
#endif
return(0);
}
/** ChangeDisk() *********************************************/
/** Change disk image in a given drive. Closes current disk **/
/** image if Name=0 was given. Returns 1 on success or 0 on **/
/** failure. **/
/*************************************************************/
byte ChangeDisk(byte ID,char *Name)
{
#ifdef unused
/* We only have MAXDRIVES drives */
if(ID>=MAXDRIVES) return(0);
/* Close previous disk image */
if(Drives[ID]>=0) { close(Drives[ID]);Drives[ID]=-1; }
/* If no disk image given, consider drive empty */
if(!Name) return(1);
/* Open new disk image */
Drives[ID]=open(Name,O_RDWR|O_BINARY);
RdOnly[ID]=0;
/* If failed to open for writing, open read-only */
if(Drives[ID]<0)
{
Drives[ID]=open(Name,O_RDONLY|O_BINARY);
RdOnly[ID]=1;
}
#endif
/* Return operation result */
return(Drives[ID]>=0);
}

Wyświetl plik

@ -0,0 +1,95 @@
/*************************************************************/
/** **/
/** diskwork.h **/
/** **/
/** Common definitions for programs working with **/
/** disk-images that can be used with fMSX **/
/** **/
/** **/
/** Copyright (c) Arnold Metselaar 1996 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
#ifndef O_BINARY
#define O_BINARY 0
#endif
#define usint unsigned short int
#define byte unsigned char
#define EOF_FAT 0xFFF /* signals EOF in FAT */
typedef struct de {
char d_fname[8];
char d_ext[3];
char d_attrib;
char d_reserv[10]; /* unused */
byte d_time[2]; /* byte-ordering of ints is machine-dependent */
byte d_date[2];
byte d_first[2];
byte d_size[4];
} DirEntry;
/* macros to change DirEntries */
#define setsh(x,y) {x[0]=y;x[1]=y>>8;}
#define setlg(x,y) {x[0]=y;x[1]=y>>8;x[2]=y>>16;x[3]=y>>24;}
/* macros to read DirEntries */
#define rdsh(x) (x[0]+(x[1]<<8))
#define rdlg(x) (x[0]+(x[1]<<8)+(x[2]<<16)+(x[3]<<24))
#define PError(x) { fprintf(stderr,"%s: ",progname); perror(x); }
#define seclen 512 /* length of sector */
#define cluslen 1024 /* length of cluster */
void *xalloc(size_t len)
{
void *p;
if (!(p=malloc(len)))
{
puts("Out of memory\n"); exit(2);
}
return p;
}
extern byte *FAT;
/* read FAT-entry from FAT in memory */
usint ReadFAT(usint clnr)
{ register byte *P;
P=FAT+(clnr*3)/2;
return (clnr&1)? (P[0]>>4)+(P[1]<<4) : P[0]+((P[1]&0x0F)<<8);
}
/* write an entry to FAT in memory */
void WriteFAT(usint clnr, usint val)
{ register byte *P;
P=FAT+(clnr*3)/2;
if (clnr&1)
{
P[0]=(P[0]&0x0F)+(val<<4);
P[1]=val>>4;
}
else
{
P[0]=val;
P[1]=(P[1]&0xF0)+((val>>8)&0x0F);
}
}

Wyświetl plik

@ -0,0 +1,196 @@
/** EMULib Emulation Library *********************************/
/** **/
/** I8251.c **/
/** **/
/** This file contains emulation for the Intel 8251 UART **/
/** chip and the 8253 timer chip implementing a generic **/
/** RS232 interface. **/
/** **/
/** Copyright (C) Marat Fayzullin 2004-2005 **/
/** Maarten ter Huurne 2000 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
#include "I8251.h"
/** Reset8251 ************************************************/
/** Reset 8251 chip, assigning In and Out to the input and **/
/** output streams. **/
/*************************************************************/
void Reset8251(register I8251 *D,FILE *In,FILE *Out)
{
D->IRQMask = 0x0F; /* All interrupts on */
D->IRQs = 0x00; /* No interrupts yet */
D->Mode = 1; /* Setting mode next */
D->Flow = 0x00; /* Flow control off */
D->NextChr = -1; /* No data yet */
/* Assign input and output streams */
D->In = In? In:stdin;
D->Out = Out? Out:stdout;
}
/** Rd8251 ***************************************************/
/** Read a byte from a given 8251 register. All values of R **/
/** will be truncated to 3 bits as there are only 8 regs. **/
/*************************************************************/
byte Rd8251(register I8251 *D,register byte R)
{
register int J;
/* We only have 8 addressable ports */
R&=0x07;
switch(R)
{
case 0: /* Data */
if(D->Flow)
{
if(D->NextChr<0) D->NextChr=fgetc(D->In);
J=D->NextChr;
D->NextChr=-1;
return((J<0? 0xFF:J)&((0x20<<((D->Control&0x0C)>>2))-1));
}
return(0xFF);
case 1: /* Status */
if(D->NextChr<0) D->NextChr=fgetc(D->In);
return(D->Flow&&(D->NextChr>=0)? 0x87:0x85);
/*
76543210
1....... data set ready (dsr)
.1...... sync detect, sync only
..1..... framing error (fe), async only
...1.... overrun error (oe)
....1... parity error (pe)
.....1.. transmitter empty
......1. receiver ready
.......1 transmitter ready
D->Flow is checked first, so that stdin input doesn't block
fMSX until it's actually being read by the emulated MSX.
*/
case 0x82: /* Status of CTS, timer/counter 2, RI and CD */
return(0x7F);
/*
76543210
1....... CTS (Clear To Send) 0=asserted
.1...... timer/counter output-2 from 8253
..XXXX.. reserved
......1. RI (Ring Indicator) 0=asserted
.......1 CD (Carrier Detect) 0=asserted
RI and CD are optional. If only one of them is implemented,
it must be CD. Implemented like this:
- CTS always returns 0 (asserted)
- Everything else is not implemented
*/
}
/* Other RS232 ports:
3: not standardised - unused
4: 8253 counter 0 - not implemented
5: 8253 counter 1 - not implemented
6: 8253 counter 2 - not implemented
7: 8253 mode register - write only
*/
return(0xFF);
}
/** Wr8251 ***************************************************/
/** Write a byte to a given 8251 register. All values of R **/
/** will be truncated to 3 bits as there are only 8 regs. **/
/*************************************************************/
void Wr8251(register I8251 *D,register byte R,register byte V)
{
/* We only have 8 addressable ports */
R&=0x07;
switch(R)
{
case 0: /* Data */
fputc(V&((0x20<<((D->Control&0x0C)>>2))-1),D->Out);
fflush(D->Out);
return;
/*
TODO: Flush the stream at appropriate intervals, instead of
flushing for every single character. If flushing after every
character remains, make the stream unbuffered.
*/
case 1: /* Command */
if(D->Mode)
{
D->Control=V;
D->Mode=0;
/* Set mode:
......00 sync mode
......01 async, baud rate factor is 1
......10 async, baud rate factor is 16
......11 async, baud rate factor is 64
....00.. character length is 5 bits
....01.. character length is 6 bits
....10.. character length is 7 bits
....11.. character length is 8 bits
...1.... parity enable
..1..... even/odd parity
.1...... sync: external sync detect (syndet) is an input/output
1....... sync: single/double character sync
00...... async: invalid
01...... async: 1 stop bit
10...... async: 1.5 stop bits
11...... async: 2 stop bits
*/
}
else
{
D->Mode=V&0x40;
D->Flow=(V>>4)&0x02;
/* Execute command:
76543210
1....... enter hunt mode (enable search for sync characters)
.1...... internal reset
..1..... request to send (rts)
...1.... reset error flags (pe,oe,fe)
....1... send break character
.....1.. receive enable
......1. data terminal ready (dtr)
.......1 transmit enable
Only RESET (bit6) and DTR (bit2) are implemented.
*/
}
return;
case 2: /* Interrupt mask register */
D->IRQMask=V;
return;
/*
76543210
XXXX.... reserved
....1... timer interrupt from 8253 channel-2 (0=enable int)
.....1.. sync character detect/break detect (0=enable int)
......1. transmit data ready (TxReady) (0=enable int)
.......1 receive data ready (RxReady) (0=enable int)
Initially all interrupts are disabled. RxReady interrupt must be
implemented, the others are optional.
However, currently no interrupt at all is implemented. The result
is that only one character is read per VDP interrupt, so serial
communication is 50/60 baud.
*/
}
/* Other RS232 ports:
3: not standardised - unused
4: 8253 counter 0 - not implemented
5: 8253 counter 1 - not implemented
6: 8253 counter 2 - not implemented
7: 8253 mode register - not implemented
*/
}

Wyświetl plik

@ -0,0 +1,57 @@
/** EMULib Emulation Library *********************************/
/** **/
/** I8251.h **/
/** **/
/** This file contains definitions and declarations for **/
/** routines in I8251.c. **/
/** **/
/** Copyright (C) Marat Fayzullin 2004-2005 **/
/** Maarten ter Huurne 2000 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
#ifndef I8251_H
#define I8251_H
#include <stdio.h>
#ifndef BYTE_TYPE_DEFINED
#define BYTE_TYPE_DEFINED
typedef unsigned char byte;
#endif
/** I8251 ****************************************************/
/** This data structure stores I8251 state. **/
/*************************************************************/
typedef struct
{
byte Control; /* 8251 ACIA control reg. */
byte IRQMask; /* RS232 interrupt mask */
byte IRQs; /* RS232 interrupts */
byte Mode; /* 8251 mode/cmd select */
byte Flow; /* Flow control state */
int NextChr; /* Next char or -1 */
FILE *In; /* Input stream */
FILE *Out; /* Output stream */
} I8251;
/** Reset8251 ************************************************/
/** Reset 8251 chip, assigning In and Out to the input and **/
/** output streams. **/
/*************************************************************/
void Reset8251(register I8251 *D,FILE *In,FILE *Out);
/** Rd8251 ***************************************************/
/** Read a byte from a given 8251 register. All values of R **/
/** will be truncated to 3 bits as there are only 8 regs. **/
/*************************************************************/
byte Rd8251(register I8251 *D,register byte R);
/** Wr8251 ***************************************************/
/** Write a byte to a given 8251 register. All values of R **/
/** will be truncated to 3 bits as there are only 8 regs. **/
/*************************************************************/
void Wr8251(register I8251 *D,register byte R,register byte V);
#endif /* I8251_H */

Wyświetl plik

@ -0,0 +1,88 @@
/** EMULib Emulation Library *********************************/
/** **/
/** I8255.c **/
/** **/
/** This file contains emulation for the i8255 parallel **/
/** port interface (PPI) chip from Intel. See I8255.h for **/
/** declarations. **/
/** **/
/** Copyright (C) Marat Fayzullin 2001-2005 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
#include "I8255.h"
/** Reset8255 ************************************************/
/** Reset the chip. Set all data to 0x00. Set all ports to **/
/** "input" mode. **/
/*************************************************************/
void Reset8255(register I8255 *D)
{
/* Initialize all registers and ports */
D->R[0]=D->Rout[0]=D->Rin[0]=0x00;
D->R[1]=D->Rout[1]=D->Rin[1]=0x00;
D->R[2]=D->Rout[2]=D->Rin[2]=0x00;
D->R[3]=0x9B;
}
/** Write8255 ************************************************/
/** Write value V into i8255 register A. Returns 0 when A **/
/** is out of range, 1 otherwise. **/
/*************************************************************/
byte Write8255(register I8255 *D,register byte A,register byte V)
{
switch(A)
{
case 0:
case 1:
case 2:
/* Data registers */
D->R[A]=V;
break;
case 3:
/* Control register */
if(V&0x80) D->R[A]=V;
else
{
A=1<<((V&0x0E)>>1);
if(V&0x01) D->R[2]|=A; else D->R[2]&=~A;
}
break;
default:
/* Invalid register */
return(0);
}
/* Set output ports */
V=D->R[3];
D->Rout[0] = V&0x10? 0x00:D->R[0];
D->Rout[1] = V&0x02? 0x00:D->R[1];
D->Rout[2] = ((V&0x01? 0x00:D->R[2])&0x0F)
| ((V&0x08? 0x00:D->R[2])&0xF0);
/* Done */
return(1);
}
/** Read8255 *************************************************/
/** Read value from an i8255 register A. Returns 0 when A **/
/** is out of range. **/
/*************************************************************/
byte Read8255(register I8255 *D,register byte A)
{
switch(A)
{
case 0: return(D->R[3]&0x10? D->Rin[0]:D->R[0]);
case 1: return(D->R[3]&0x02? D->Rin[1]:D->R[1]);
case 2: return
(
((D->R[3]&0x01? D->Rin[2]:D->R[2])&0x0F)|
((D->R[3]&0x08? D->Rin[2]:D->R[2])&0xF0)
);
case 3: return(D->R[3]);
}
/* Invalid address */
return(0x00);
}

Wyświetl plik

@ -0,0 +1,50 @@
/** EMULib Emulation Library *********************************/
/** **/
/** I8255.h **/
/** **/
/** This file contains emulation for the i8255 parallel **/
/** port interface (PPI) chip from Intel. See I8255.h for **/
/** the actual code. **/
/** **/
/** Copyright (C) Marat Fayzullin 2001-2005 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
#ifndef I8255_H
#define I8255_H
#ifndef BYTE_TYPE_DEFINED
#define BYTE_TYPE_DEFINED
typedef unsigned char byte;
#endif
/** I8255 ****************************************************/
/** This data structure stores i8255 state and port values. **/
/*************************************************************/
typedef struct
{
byte R[4]; /* Registers */
byte Rout[3]; /* Output ports */
byte Rin[3]; /* Input ports */
} I8255;
/** Reset8255 ************************************************/
/** Reset the i8255 chip. Set all data to 0x00. Set all **/
/** ports to "input" mode. **/
/*************************************************************/
void Reset8255(register I8255 *D);
/** Write8255 ************************************************/
/** Write value V into i8255 register A. Returns 0 when A **/
/** is out of range, 1 otherwise. **/
/*************************************************************/
byte Write8255(register I8255 *D,register byte A,register byte V);
/** Read8255 *************************************************/
/** Read value from an i8255 register A. Returns 0 when A **/
/** is out of range. **/
/*************************************************************/
byte Read8255(register I8255 *D,register byte A);
#endif /* I8255_H */

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,222 @@
/** fMSX: portable MSX emulator ******************************/
/** **/
/** MSX.h **/
/** **/
/** This file contains declarations relevant to the drivers **/
/** and MSX emulation itself. See Z80.h for #defines **/
/** related to Z80 emulation. **/
/** **/
/** Copyright (C) Marat Fayzullin 1994-2003 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
#ifndef MSX_H
#define MSX_H
#include "Z80.h" /* Z80 CPU emulation */
#include "V9938.h" /* V9938 VDP opcode emulation */
#include "AY8910.h" /* AY8910 PSG emulation */
#include "YM2413.h" /* YM2413 OPLL emulation */
#include "SCC.h" /* Konami SCC chip emulation */
#include "I8255.h" /* Intel 8255 PPI emulation */
#include "I8251.h" /* Intel 8251 UART emulation */
#include <stdio.h>
#define CPU_CLOCK 3580 /* CPU clock frequency, kHz */
#define VDP_CLOCK 21480 /* VDP clock frequency, kHz */
#define HPERIOD 1368 /* HPeriod, VDP cycles */
#define VPERIOD_PAL (HPERIOD*313) /* PAL VPeriod, VDP ccls */
#define VPERIOD_NTSC (HPERIOD*262) /* NTSC VPeriod, VDP ccls */
#define HREFRESH_240 960 /* 240dot scanline refresh */
#define HREFRESH_256 1024 /* 256dot scanline refresh */
#define CPU_VPERIOD (VPERIOD_NTSC/6)
#define CPU_V262 (VPERIOD_NTSC/6)
#define CPU_V313 (VPERIOD_PAL/6)
#define CPU_HPERIOD (HPERIOD/6)
#define CPU_H240 (HREFRESH_240/6)
#define CPU_H256 (HREFRESH_256/6)
#define INT_IE0 0x01
#define INT_IE1 0x02
#define INT_IE2 0x04
#define PAGESIZE 0x4000L /* Size of a RAM page */
#define NORAM 0xFF /* Byte to be returned from */
/* non-existing pages and ports */
#define MAXSCREEN 12 /* Highest screen mode supported */
#define MAXSPRITE1 4 /* Sprites/line in SCREEN 1-3 */
#define MAXSPRITE2 8 /* Sprites/line in SCREEN 4-8 */
#define MAXDRIVES 2 /* Number of disk drives */
#define MAXDISKS 32 /* Number of disks for a drive */
#define MAXMAPPERS 7 /* Total defined MegaROM mappers */
#define MAXCHANNELS (AY8910_CHANNELS+YM2413_CHANNELS)
/* Number of sound channels used by the emulation */
/** Following macros can be used in screen drivers ***********/
#define BigSprites (VDP[1]&0x01) /* Zoomed sprites */
#define Sprites16x16 (VDP[1]&0x02) /* 16x16/8x8 sprites */
#define ScreenON (VDP[1]&0x40) /* Show screen */
#define SpritesOFF (VDP[8]&0x02) /* Don't show sprites */
#define SolidColor0 (VDP[8]&0x20) /* Solid/Tran. COLOR 0 */
#define PALVideo (VDP[9]&0x02) /* PAL/NTSC video */
#define FlipEvenOdd (VDP[9]&0x04) /* Flip even/odd pages */
#define InterlaceON (VDP[9]&0x08) /* Interlaced screen */
#define ScanLines212 (VDP[9]&0x80) /* 212/192 scanlines */
#define HScroll512 (VDP[25]&0x01) /* HScroll both pages */
#define MaskEdges (VDP[25]&0x02) /* Mask 8-pixel edges */
#define ModeYJK (VDP[25]&0x08) /* YJK screen mode */
#define ModeYAE (VDP[25]&0x10) /* YJK/YAE screen mode */
#define VScroll VDP[23]
#define HScroll ((VDP[27]&0x07)|((int)(VDP[26]&0x3F)<<3))
#define VAdjust (-((signed char)(VDP[18])>>4))
#define HAdjust (-((signed char)(VDP[18]<<4)>>4))
/*************************************************************/
/** Variables used to control emulator behavior **************/
extern byte Verbose; /* Debug msgs ON/OFF */
extern byte MSXVersion; /* 0=MSX,1=MSX2,2=MSX2+*/
extern byte ROMTypeA,ROMTypeB; /* MegaROM types */
extern int RAMPages,VRAMPages; /* Number of RAM pages */
extern int VPeriod; /* CPU cycles / VBlank */
extern int HPeriod; /* CPU cycles / HBlank */
extern byte UPeriod; /* Int-pts/Scr. update */
extern byte JoyTypeA,JoyTypeB; /* 0=No,1=Jstk,2/3=Mse */
extern byte AutoFire; /* Autofire on [SPACE] */
extern byte UseDrums; /* Drums for PSG noise */
/*************************************************************/
extern Z80 CPU; /* CPU state/registers */
extern byte *VRAM; /* Video RAM */
extern byte VDP[64]; /* VDP control reg-ers */
extern byte VDPStatus[16]; /* VDP status reg-ers */
extern byte *ChrGen,*ChrTab,*ColTab; /* VDP tables (screen) */
extern byte *SprGen,*SprTab; /* VDP tables (sprites)*/
extern int ChrGenM,ChrTabM,ColTabM; /* VDP masks (screen) */
extern int SprTabM; /* VDP masks (sprites) */
extern byte FGColor,BGColor; /* Colors */
extern byte XFGColor,XBGColor; /* Alternative colors */
extern byte ScrMode; /* Current screen mode */
extern int ScanLine; /* Current scanline */
extern byte KeyMap[16]; /* Keyboard map */
extern byte ExitNow; /* 1: Exit emulator */
extern byte PSLReg; /* Primary slot reg. */
extern byte SSLReg; /* Secondary slot reg. */
//extern char *DiskA; /* Drive A disk image */
//extern char *DiskB; /* Drive B disk image */
#ifdef unused
extern char *SndName; /* Soundtrack log file */
extern char *PrnName; /* Printer redir. file */
extern char *CasName; /* Tape image file */
extern char *ComName; /* Serial redir. file */
extern int *CasStream; /* Cassette I/O stream */
#endif
extern char *FontName; /* Font file for text */
extern byte *FontBuf; /* Font for text modes */
extern byte UseFont; /* 1: Use external font*/
/** StartMSX() ***********************************************/
/** Allocate memory, load ROM image, initialize hardware, **/
/** CPU and start the emulation. This function returns 0 in **/
/** the case of failure. **/
/*************************************************************/
int StartMSX(void);
/** TrashMSX() ***********************************************/
/** Free memory allocated by StartMSX(). **/
/*************************************************************/
void TrashMSX(void);
/** SaveState() **********************************************/
/** Save emulation state to a .STA file. **/
/*************************************************************/
int SaveState(const char *FileName);
/** LoadState() **********************************************/
/** Load emulation state from a .STA file. **/
/*************************************************************/
int LoadState(const char *FileName);
/** ChangeDisk() *********************************************/
/** Change disk image in a given drive. Closes current disk **/
/** image if Name=0 was given. Returns 1 on success or 0 on **/
/** failure. This function is part of generic disk drivers **/
/** in Disk.c. It is compiled when DISK is #defined. **/
/*************************************************************/
#ifdef DISK
byte ChangeDisk(byte ID,char *Name);
#endif
/** InitMachine() ********************************************/
/** Allocate resources needed by the machine-dependent code.**/
/************************************ TO BE WRITTEN BY USER **/
int InitMachine(void);
/** TrashMachine() *******************************************/
/** Deallocate all resources taken by InitMachine(). **/
/************************************ TO BE WRITTEN BY USER **/
void TrashMachine(void);
/** Keyboard() ***********************************************/
/** This function is periodically called to poll keyboard. **/
/************************************ TO BE WRITTEN BY USER **/
void Keyboard(void);
/** Joystick() ***********************************************/
/** Query position of a joystick connected to port N. **/
/** Returns 0.0.F2.F1.R.L.D.U. **/
/************************************ TO BE WRITTEN BY USER **/
byte Joystick(byte N);
/** Mouse() **************************************************/
/** Query coordinates of a mouse connected to port N. **/
/** Returns F2.F1.Y.Y.Y.Y.Y.Y.Y.Y.X.X.X.X.X.X.X.X. **/
/************************************ TO BE WRITTEN BY USER **/
int Mouse(byte N);
/** DiskPresent()/DiskRead()/DiskWrite() *********************/
/*** These three functions are called to check for floppyd **/
/*** disk presence in the "drive", and to read/write given **/
/*** sector to the disk. **/
/************************************ TO BE WRITTEN BY USER **/
byte DiskPresent(byte ID);
byte DiskRead(byte ID,byte *Buf,int N);
byte DiskWrite(byte ID,byte *Buf,int N);
/** SetColor() ***********************************************/
/** Set color N (0..15) to (R,G,B). **/
/************************************ TO BE WRITTEN BY USER **/
void SetColor(byte N,byte R,byte G,byte B);
/** RefreshScreen() ******************************************/
/** Refresh screen. This function is called in the end of **/
/** refresh cycle to show the entire screen. **/
/************************************ TO BE WRITTEN BY USER **/
void RefreshScreen(void);
/** RefreshLine#() *******************************************/
/** Refresh line Y (0..191/211), on an appropriate SCREEN#, **/
/** including sprites in this line. **/
/************************************ TO BE WRITTEN BY USER **/
//void RefreshLineTx80(byte Y);
//void RefreshLine0(byte Y);
//void RefreshLine1(byte Y);
//void RefreshLine2(byte Y);
//void RefreshLine3(byte Y);
//void RefreshLine4(byte Y);
//void RefreshLine5(byte Y);
//void RefreshLine6(byte Y);
//void RefreshLine7(byte Y);
//void RefreshLine8(byte Y);
//void RefreshLine10(byte Y);
//void RefreshLine12(byte Y);
#endif /* MSX_H */

Wyświetl plik

@ -0,0 +1,440 @@
/** fMSX: portable MSX emulator ******************************/
/** **/
/** Patch.c **/
/** **/
/** This file contains implementation for the PatchZ80() **/
/** function necessary for emulating MSX disk and tape IO. **/
/** **/
/** Copyright (C) Marat Fayzullin 1994-2005 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
#include "MSX.h"
#include "Boot.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include "shared.h"
#ifndef SEEK_CUR
#define SEEK_CUR 1
#endif
void SSlot(byte Value); /* Used to switch secondary slots */
#ifdef FMSX
extern byte *RAM[],PSL[],SSLReg;
static byte RdZ80(word A)
{
if(A!=0xFFFF) return(RAM[A>>13][A&0x1FFF]);
else return((PSL[3]==3)? ~SSLReg:RAM[7][0x1FFF]);
}
#endif
/** PatchZ80() ***********************************************/
/** Emulate BIOS calls. This function is called on an ED FE **/
/** instruction to emulate disk/tape access, etc. **/
/*************************************************************/
void PatchZ80(Z80 *R)
{
static const byte TapeHeader[8] = { 0x1F,0xA6,0xDE,0xBA,0xCC,0x13,0x7D,0x74 };
static const struct
{ int Sectors;byte Heads,Names,PerTrack,PerFAT,PerCluster; }
Info[8] =
{
{ 720,1,112,9,2,2 },
{ 1440,2,112,9,3,2 },
{ 640,1,112,8,1,2 },
{ 1280,2,112,8,2,2 },
{ 360,1, 64,9,2,1 },
{ 720,2,112,9,2,2 },
{ 320,1, 64,8,1,1 },
{ 640,2,112,8,1,2 }
};
byte Buf[512],Count,PS,SS,N,*P;
int J,I,Sector;
word Addr;
switch(R->PC.W-2)
{
case 0x4010:
/** PHYDIO: Read/write sectors to disk **************************
*** Input: ***
*** [F] CARRY=WRITE [A] Drive number (0=A:) ***
*** [B] Number of sectors to write [C] Media descriptor ***
*** [DE] Logical sector number (starts at 0) ***
*** [HL] Transfer address ***
*** Output: ***
*** [F] CARRY=ERROR [A] If error: errorcode ***
*** [B] Number of sectors remaining (not read/written) ***
*** Error codes in [A] can be: ***
*** 0 Write protected 8 Record not found ***
*** 2 Not ready 10 Write fault ***
*** 4 Data (CRC) error 12 Other errors ***
*** 6 Seek error ***
****************************************************************/
{
//if(Verbose&0x04)
// printf
// (
// "%s DISK %c: %d sectors starting from %04Xh [buffer at %04Xh]\n",
// R->AF.B.l&C_FLAG? "WRITE":"READ",R->AF.B.h+'A',R->BC.B.h,
// R->DE.W,R->HL.W
// );
R->IFF|=1;
Addr = R->HL.W;
Count = R->BC.B.h;
if(!DiskPresent(R->AF.B.h))
{ R->AF.W=0x0201;return; } /* No disk -> "Not ready" */
if((int)(R->DE.W)+Count>Info[R->BC.B.l-0xF8].Sectors)
{ R->AF.W=0x0801;return; } /* Wrong sector -> "Record not found" */
/* If data does not fit into 64kB address space, trim it */
if((int)(R->HL.W)+Count*512>0x10000) Count=(0x10000-R->HL.W)/512;
/* Save slot states */
PS=PSLReg;SS=SSLReg;
/* Turn on RAM in all slots */
OutZ80(0xA8,0xFF);
SSlot(0xAA);
if(R->AF.B.l&C_FLAG)
for(Sector=R->DE.W;Count--;Sector++) /* WRITE */
{
for(J=0;J<512;J++) Buf[J]=RdZ80(Addr++);
if(DiskWrite(R->AF.B.h,Buf,Sector)) R->BC.B.h--;
else
{
R->AF.W=0x0A01;
SSlot(SS);
OutZ80(0xA8,PS);
return;
}
}
else
for(Sector=R->DE.W;Count--;Sector++) /* READ */
{
if(DiskRead(R->AF.B.h,Buf,Sector)) R->BC.B.h--;
else
{
R->AF.W=0x0401;
SSlot(SS);
OutZ80(0xA8,PS);
return;
}
for(J=0;J<512;J++) WrZ80(Addr++,Buf[J]);
}
/* Restore slot states */
SSlot(SS);
OutZ80(0xA8,PS);
/* Return "Success" */
R->AF.B.l&=~C_FLAG;
return;
}
case 0x4013:
/** DSKCHG: Check if the disk was changed ***********************
*** Input: ***
*** [A] Drive number (0=A:) [B] Media descriptor ***
*** [C] Media descriptor [HL] Base address of DPB ***
*** Output: ***
*** [F] CARRY=ERROR [A] If error: errorcode (see DSKIO) ***
*** [B] If success: 1=Unchanged, 0=Unknown, -1=Changed ***
*** Note: ***
*** If the disk has been changed or may have been changed ***
*** (unknown) read the boot sector or the FAT sector for disk ***
*** media descriptor and transfer a new DPB as with GETDPB. ***
****************************************************************/
{
//if(Verbose&0x04) printf("CHECK DISK %c\n",R->AF.B.h+'A');
R->IFF|=1;
/* If no disk, return "Not ready": */
if(!DiskPresent(R->AF.B.h)) { R->AF.W=0x0201;return; }
/* This requires some major work to be done: */
R->BC.B.h=0;R->AF.B.l&=~C_FLAG;
/* We continue with GETDPB now... */
}
case 0x4016:
/** GETDPB: Disk format *****************************************
*** Input: ***
*** [A] Drive number [B] 1st byte of FAT (media descriptor) ***
*** [C] Media descriptor [HL] Base address of DPB ***
*** Output: ***
*** [HL+1] .. [HL+18] = DPB for specified drive ***
*** DPB consists of: ***
*** Name Offset Size Description ***
*** MEDIA 0 1 Media type (F8..FF) ***
*** SECSIZ 1 2 Sector size (must be 2^n) ***
*** DIRMSK 3 1 (SECSIZE/32)-1 ***
*** DIRSHFT 4 1 Number of one bits in DIRMSK ***
*** CLUSMSK 5 1 (Sectors per cluster)-1 ***
*** CLUSSHFT 6 1 (Number of one bits in CLUSMSK)+1 ***
*** FIRFAT 7 2 Logical sector number of first FAT ***
*** FATCNT 8 1 Number of FATs ***
*** MAXENT A 1 Number of directory entries (max 254) ***
*** FIRREC B 2 Logical sector number of first data ***
*** MAXCLUS D 2 Number of clusters (not including ***
*** reserved, FAT and directory sectors)+1 ***
*** FATSIZ F 1 Number of sectors used ***
*** FIRDIR 10 2 FAT logical sector number of start of ***
*** directory ***
****************************************************************/
{
int BytesPerSector,SectorsPerDisk,SectorsPerFAT,ReservedSectors;
/* If no disk, return "Not ready": */
if(!DiskPresent(R->AF.B.h)) { R->AF.W=0x0201;return; }
/* If can't read, return "Other error": */
if(!DiskRead(R->AF.B.h,Buf,0)) { R->AF.W=0x0C01;return; }
BytesPerSector = (int)Buf[0x0C]*256+Buf[0x0B];
SectorsPerDisk = (int)Buf[0x14]*256+Buf[0x13];
SectorsPerFAT = (int)Buf[0x17]*256+Buf[0x16];
ReservedSectors = (int)Buf[0x0F]*256+Buf[0x0E];
Addr=R->HL.W+1;
WrZ80(Addr++,Buf[0x15]); /* Format ID [F8h-FFh] */
WrZ80(Addr++,Buf[0x0B]); /* Sector size */
WrZ80(Addr++,Buf[0x0C]);
J=(BytesPerSector>>5)-1;
for(I=0;J&(1<<I);I++);
WrZ80(Addr++,J); /* Directory mask/shft */
WrZ80(Addr++,I);
J=Buf[0x0D]-1;
for(I=0;J&(1<<I);I++);
WrZ80(Addr++,J); /* Cluster mask/shift */
WrZ80(Addr++,I+1);
WrZ80(Addr++,Buf[0x0E]); /* Sector # of 1st FAT */
WrZ80(Addr++,Buf[0x0F]);
WrZ80(Addr++,Buf[0x10]); /* Number of FATs */
WrZ80(Addr++,Buf[0x11]); /* Number of dirent-s */
J=ReservedSectors+Buf[0x10]*SectorsPerFAT;
J+=32*Buf[0x11]/BytesPerSector;
WrZ80(Addr++,J&0xFF); /* Sector # of data */
WrZ80(Addr++,(J>>8)&0xFF);
J=(SectorsPerDisk-J)/Buf[0x0D];
WrZ80(Addr++,J&0xFF); /* Number of clusters */
WrZ80(Addr++,(J>>8)&0xFF);
WrZ80(Addr++,Buf[0x16]); /* Sectors per FAT */
J=ReservedSectors+Buf[0x10]*SectorsPerFAT;
WrZ80(Addr++,J&0xFF); /* Sector # of dir. */
WrZ80(Addr,(J>>8)&0xFF);
/* Return success */
R->AF.B.l&=~C_FLAG;
return;
}
case 0x401C:
/** DSKFMT: Disk format *****************************************
*** Input: ***
*** [A] Specified choice (1-9) [D] Drive number (0=A:) ***
*** [HL] Begin address of work area [BC] Length of work area ***
*** Output: ***
*** [F] CARRY=ERROR ***
*** Notes: ***
*** 1) Also writes a MSX boot sector at sector 0, clears all ***
*** FATs (media descriptor at first byte, 0FFh at second/ ***
*** third byte and rest zero) and clears the directory ***
*** filling it with zeros. ***
*** 2) Error codes are: ***
*** 0 Write protected 10 Write fault ***
*** 2 Not ready 12 Bad parameter ***
*** 4 Data (CRC) error 14 Insufficient memory ***
*** 6 Seek error 16 Other errors ***
*** 8 Record not found ***
****************************************************************/
{
R->IFF|=1;
/* If invalid choice, return "Bad parameter": */
if(!R->AF.B.h||(R->AF.B.h>2)) { R->AF.W=0x0C01;return; }
/* If no disk, return "Not ready": */
if(!DiskPresent(R->DE.B.h)) { R->AF.W=0x0201;return; }
/* Fill bootblock with data: */
P=BootBlock+3;
N=2-R->AF.B.h;
memcpy(P,"fMSXdisk",8);P+=10; /* Manufacturer's ID */
*P=Info[N].PerCluster;P+=4; /* Sectors per cluster */
*P++=Info[N].Names;*P++=0x00; /* Number of names */
*P++=Info[N].Sectors&0xFF; /* Number of sectors */
*P++=(Info[N].Sectors>>8)&0xFF;
*P++=N+0xF8; /* Format ID [F8h-FFh] */
*P++=Info[N].PerFAT;*P++=0x00; /* Sectors per FAT */
*P++=Info[N].PerTrack;*P++=0x00; /* Sectors per track */
*P++=Info[N].Heads;*P=0x00; /* Number of heads */
/* If can't write bootblock, return "Write protected": */
if(!DiskWrite(R->DE.B.h,BootBlock,0)) { R->AF.W=0x0001;return; };
/* Writing FATs: */
for(Sector=1,J=0;J<2;J++)
{
Buf[0]=N+0xF8;
Buf[1]=Buf[2]=0xFF;
memset(Buf+3,0x00,509);
if(!DiskWrite(R->DE.B.h,Buf,Sector++)) { R->AF.W=0x0A01;return; }
memset(Buf,0x00,512);
for(I=Info[N].PerFAT;I>1;I--)
if(!DiskWrite(R->DE.B.h,Buf,Sector++)) { R->AF.W=0x0A01;return; }
}
J=Info[N].Names/16; /* Directory size */
I=Info[N].Sectors-2*Info[N].PerFAT-J-1; /* Data size */
for(memset(Buf,0x00,512);J;J--)
if(!DiskWrite(R->DE.B.h,Buf,Sector++)) { R->AF.W=0x0A01;return; }
for(memset(Buf,0xFF,512);I;I--)
if(!DiskWrite(R->DE.B.h,Buf,Sector++)) { R->AF.W=0x0A01;return; }
/* Return success */
R->AF.B.l&=~C_FLAG;
return;
}
case 0x401F:
/** DRVOFF: Stop drives *****************************************
*** Input: None ***
*** Output: None ***
****************************************************************/
return;
case 0x00E1:
/** TAPION: Open for read and read header ***********************
****************************************************************/
{
long Pos;
//if(Verbose&0x04) printf("TAPE: Looking for header...");
R->AF.B.l|=C_FLAG;
#ifdef unused
if(CasStream)
{
Pos=ftell(CasStream);
if(Pos&7)
if(fseek(CasStream,8-(Pos&7),SEEK_CUR))
{
if(Verbose&0x04) puts("FAILED");
rewind(CasStream);return;
}
while(fread(Buf,1,8,CasStream)==8)
if(!memcmp(Buf,TapeHeader,8))
{
if(Verbose&0x04) puts("OK");
R->AF.B.l&=~C_FLAG;return;
}
rewind(CasStream);
}
if(Verbose&0x04) puts("FAILED");
#endif
return;
}
case 0x00E4:
/** TAPIN: Read tape ********************************************
****************************************************************/
{
R->AF.B.l|=C_FLAG;
#ifdef unused
if(CasStream)
{
J=fgetc(CasStream);
if(J<0) rewind(CasStream);
else { R->AF.B.h=J;R->AF.B.l&=~C_FLAG; }
}
#endif
return;
}
case 0x00E7:
/** TAPIOF: *****************************************************
****************************************************************/
R->AF.B.l&=~C_FLAG;
return;
case 0x00EA:
/** TAPOON: *****************************************************
****************************************************************/
{
long Pos;
R->AF.B.l|=C_FLAG;
#ifdef unused
if(CasStream)
{
Pos=ftell(CasStream);
if(Pos&7)
if(fseek(CasStream,8-(Pos&7),SEEK_CUR))
{ R->AF.B.l|=C_FLAG;return; }
fwrite(TapeHeader,1,8,CasStream);
R->AF.B.l&=~C_FLAG;
}
#endif
return;
}
case 0x00ED:
/** TAPOUT: Write tape ******************************************
****************************************************************/
R->AF.B.l|=C_FLAG;
#ifdef unused
if(CasStream)
{
fputc(R->AF.B.h,CasStream);
R->AF.B.l&=~C_FLAG;
}
#endif
return;
case 0x00F0:
/** TAPOOF: *****************************************************
****************************************************************/
R->AF.B.l&=~C_FLAG;
return;
case 0x00F3:
/** STMOTR: *****************************************************
****************************************************************/
R->AF.B.l&=~C_FLAG;
return;
default:
//printf("Unknown BIOS trap called at PC=%04Xh\n",R->PC.W-2);
break;
}
}

Wyświetl plik

@ -0,0 +1,187 @@
/** EMULib Emulation Library *********************************/
/** **/
/** SCC.c **/
/** **/
/** This file contains emulation for the SCC sound chip **/
/** produced by Konami. **/
/** **/
/** Copyright (C) Marat Fayzullin 1996-2005 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
#include "SCC.h"
#include "Sound.h"
#include <string.h>
/** ResetSCC() ***********************************************/
/** Reset the sound chip and use sound channels from the **/
/** one given in First. **/
/*************************************************************/
void ResetSCC(register SCC *D,int First)
{
int J;
/* Reset registers */
memset(D->R,0x00,sizeof(D->R));
/* Set instruments, frequencies, volumes */
for(J=0;J<SCC_CHANNELS;J++)
{
SetSound(0+First,SND_MELODIC);
D->Freq[J]=D->Volume[J]=0;
}
D->First = First;
D->Sync = SCC_ASYNC;
D->Changed = 0x00;
D->WChanged = 0x00;
}
/** ReadSCC() ************************************************/
/** Call this function to read contents of the generic SCC **/
/** sound chip registers. **/
/*************************************************************/
byte ReadSCC(register SCC *D,register byte R)
{
return(R<0x80? D->R[R]:0xFF);
}
/** ReadSCCP() ***********************************************/
/** Call this function to read contents of the newer SCC+ **/
/** sound chip registers. **/
/*************************************************************/
byte ReadSCCP(register SCC *D,register byte R)
{
return(R<0xA0? D->R[R]:0xFF);
}
/** WriteSCC() ***********************************************/
/** Call this function to output a value V into the generic **/
/** SCC sound chip. **/
/*************************************************************/
void WriteSCC(register SCC *D,register byte R,register byte V)
{
/* Prevent rollover */
if(R>=0xE0) return;
/* Generic SCC has one waveform less than SCC+ */
if(R>=0x80) { WriteSCCP(D,R+0x20,V);return; }
/* The last waveform applies to both channels 3 and 4 */
if(R>=0x60) { WriteSCCP(D,R,V);WriteSCCP(D,R+0x20,V);return; }
/* Other waveforms are the same */
WriteSCCP(D,R,V);
}
/** WriteSCCP() **********************************************/
/** Call this function to output a value V into the newer **/
/** SCC+ sound chip. **/
/*************************************************************/
void WriteSCCP(register SCC *D,register byte R,register byte V)
{
register int J;
register byte I;
/* Exit if no change */
if(V==D->R[R]) return;
if((R&0xE0)==0xA0)
{
/* Emulate melodic features */
/* Save active channel mask in I */
I=D->R[0xAF];
/* Write to a register */
R&=0xEF;
D->R[R]=D->R[R+0x10]=V;
/* Melodic register number 0..15 */
R&=0x0F;
switch(R)
{
case 0: case 1: case 2: case 3: case 4:
case 5: case 6: case 7: case 8: case 9:
/* Exit if the channel is silenced */
if(!(I&(1<<(R>>1)))) return;
/* Go to the first register of the pair */
R=(R&0xFE)+0xA0;
/* Compute frequency */
J=((int)(D->R[R+1]&0x0F)<<8)+D->R[R];
/* Compute channel number */
R=(R&0x0F)>>1;
/* Assign frequency */
D->Freq[R]=J? SCC_BASE/J:0;
/* Compute changed channels mask */
D->Changed|=1<<R;
break;
case 10: case 11: case 12: case 13: case 14:
/* Compute channel number */
R-=10;
/* Compute and assign new volume */
D->Volume[R]=255*(V&0x0F)/15;
/* Compute changed channels mask */
D->Changed|=(1<<R)&I;
break;
case 15:
/* Find changed channels */
R=(V^I)&0x1F;
D->Changed|=R;
/* Update frequencies */
for(I=0;R&&(I<SCC_CHANNELS);I++,R>>=1,V>>=1)
if(R&1)
{
if(!(V&1)) D->Freq[I]=0;
else
{
J=I*2+0xA0;
J=((int)(D->R[J+1]&0x0F)<<8)+D->R[J];
D->Freq[I]=J? SCC_BASE/J:0;
}
}
break;
default:
/* Wrong register, do nothing */
return;
}
}
else
{
/* Emulate wave table features */
/* Write data to SCC */
D->R[R]=V;
/* Wrong register, do nothing */
if(R>=0xA0) return;
/* Mark channel waveform as changed */
D->WChanged|=1<<(R>>5);
}
/* For asynchronous mode, make Sound() calls right away */
if(!D->Sync&&(D->Changed||D->WChanged)) SyncSCC(D,SCC_FLUSH);
}
/** SyncSCC() ************************************************/
/** Flush all accumulated changes by issuing Sound() calls **/
/** and set the synchronization on/off. The second argument **/
/** should be SCC_SYNC/SCC_ASYNC to set/reset sync, or **/
/** SCC_FLUSH to leave sync mode as it is. **/
/*************************************************************/
void SyncSCC(register SCC *D,register byte Sync)
{
register int J,I;
if(Sync!=SCC_FLUSH) D->Sync=Sync;
/* Modify waveforms */
for(J=0,I=D->WChanged;I&&(J<SCC_CHANNELS);J++,I>>=1)
if(I&1) SetWave(J+D->First,(signed char *)(D->R+(J<<5)),32,0);
/* Modify frequencies and volumes */
for(J=0,I=D->Changed;I&&(J<SCC_CHANNELS);J++,I>>=1)
if(I&1) Sound(J+D->First,D->Freq[J],D->Volume[J]);
D->Changed=D->WChanged=0x00;
}

Wyświetl plik

@ -0,0 +1,80 @@
/** EMULib Emulation Library *********************************/
/** **/
/** SCC.h **/
/** **/
/** This file contains definitions and declarations for **/
/** routines in SCC.c. **/
/** **/
/** Copyright (C) Marat Fayzullin 1996-2005 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
#ifndef SCC_H
#define SCC_H
#define SCC_BASE 111861 /* Base frequency for SCC */
#define SCC_CHANNELS 5 /* 5 melodic channels */
#define SCC_ASYNC 0 /* Asynchronous emulation */
#define SCC_SYNC 1 /* Synchronous emulation mode */
#define SCC_FLUSH 2 /* Flush buffers only */
#ifndef BYTE_TYPE_DEFINED
#define BYTE_TYPE_DEFINED
typedef unsigned char byte;
#endif
/** SCC ******************************************************/
/** This data structure stores SCC state. **/
/*************************************************************/
typedef struct
{
byte R[256]; /* SCC register contents */
int Freq[SCC_CHANNELS]; /* Frequencies (0 for off) */
int Volume[SCC_CHANNELS]; /* Volumes (0..255) */
int First; /* First used Sound() channel */
byte Changed; /* Bitmap of changed channels */
byte WChanged; /* Bitmap of changed waveforms */
byte Sync; /* SCC_SYNC/SCC_ASYNC */
} SCC;
/** ResetSCC() ***********************************************/
/** Reset the sound chip and use sound channels from the **/
/** one given in First. **/
/*************************************************************/
void ResetSCC(register SCC *D,int First);
/** ReadSCC() ************************************************/
/** Call this function to read contents of the generic SCC **/
/** sound chip registers. **/
/*************************************************************/
byte ReadSCC(register SCC *D,register byte R);
/** ReadSCCP() ***********************************************/
/** Call this function to read contents of the newer SCC+ **/
/** sound chip registers. **/
/*************************************************************/
byte ReadSCCP(register SCC *D,register byte R);
/** WriteSCC() ***********************************************/
/** Call this function to output a value V into the generic **/
/** SCC sound chip. **/
/*************************************************************/
void WriteSCC(register SCC *D,register byte R,register byte V);
/** WriteSCCP() **********************************************/
/** Call this function to output a value V into the newer **/
/** SCC+ sound chip. **/
/*************************************************************/
void WriteSCCP(register SCC *D,register byte R,register byte V);
/** SyncSCC() ************************************************/
/** Flush all accumulated changes by issuing Sound() calls **/
/** and set the synchronization on/off. The second argument **/
/** should be SCC_SYNC/SCC_ASYNC to set/reset sync, or **/
/** SCC_FLUSH to leave sync mode as it is. **/
/*************************************************************/
void SyncSCC(register SCC *D,register byte Sync);
#endif /* SCC_H */

Wyświetl plik

@ -0,0 +1,479 @@
/** EMULib Emulation Library *********************************/
/** **/
/** Sound.c **/
/** **/
/** This file file implements core part of the sound API **/
/** and functions needed to log soundtrack into a MIDI **/
/** file. See Sound.h for declarations. **/
/** **/
/** Copyright (C) Marat Fayzullin 1996-2003 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
#include "Sound.h"
#include <stdio.h>
#include <string.h>
#ifdef UNIX
#include <unistd.h>
#endif
typedef unsigned char byte;
typedef unsigned short word;
struct SndDriverStruct SndDriver =
{
(void (*)(int,int))0,
(void (*)(int,int))0,
(void (*)(int,int))0,
(void (*)(int,int,int))0,
(void (*)(int,const signed char *,int,int))0
};
#ifdef unused
static const struct { byte Note;word Wheel; } Freqs[4096] =
{
#include "MIDIFreq.h"
};
#endif
static const int Programs[5] =
{
80, /* SND_MELODIC/SND_RECTANGLE */
80, /* SND_TRIANGLE */
122, /* SND_NOISE */
122, /* SND_PERIODIC */
80 /* SND_WAVE */
};
#ifdef unused
static struct
{
int Type;
int Note;
int Pitch;
int Level;
} CH[MIDI_CHANNELS];
static const char *LogName = 0;
static int Logging = MIDI_OFF;
static int TickCount = 0;
static int LastMsg = -1;
static FILE *MIDIOut = 0;
static void MIDISound(int Channel,int Freq,int Volume);
static void MIDISetSound(int Channel,int Type);
static void MIDIDrum(int Type,int Force);
static void MIDIMessage(byte D0,byte D1,byte D2);
static void NoteOn(byte Channel,byte Note,byte Level);
static void NoteOff(byte Channel);
static void WriteDelta(void);
static void WriteTempo(int Freq);
/** SHIFT() **************************************************/
/** Make MIDI channel#10 last, as it is normally used for **/
/** percussion instruments only and doesn't sound nice. **/
/*************************************************************/
#define SHIFT(Ch) (Ch==15? 9:Ch>8? Ch+1:Ch)
#endif
/** Sound() **************************************************/
/** Generate sound of given frequency (Hz) and volume **/
/** (0..255) via given channel. Setting Freq=0 or Volume=0 **/
/** turns sound off. **/
/*************************************************************/
void Sound(int Channel,int Freq,int Volume)
{
if(Channel<0) return;
Freq = Freq<0? 0:Freq;
Volume = Volume<0? 0:Volume>255? 255:Volume;
/* Call sound driver if present */
if(SndDriver.Sound) (*SndDriver.Sound)(Channel,Freq,Volume);
#ifdef unused
/* Log sound to MIDI file */
MIDISound(Channel,Freq,Volume);
#endif
}
/** Drum() ***************************************************/
/** Hit a drum of given type with given force (0..255). **/
/** MIDI drums can be used by ORing their numbers with **/
/** SND_MIDI. **/
/*************************************************************/
void Drum(int Type,int Force)
{
Force = Force<0? 0:Force>255? 255:Force;
if(SndDriver.Drum) (*SndDriver.Drum)(Type,Force);
#ifdef unused
/* Log drum to MIDI file */
MIDIDrum(Type,Force);
#endif
}
/** SetSound() ***********************************************/
/** Set sound type at a given channel. MIDI instruments can **/
/** be set directly by ORing their numbers with SND_MIDI. **/
/*************************************************************/
void SetSound(int Channel,int Type)
{
if(Channel<0) return;
if(SndDriver.SetSound) (*SndDriver.SetSound)(Channel,Type);
#ifdef unused
/* Log instrument change to MIDI file */
MIDISetSound(Channel,Type);
#endif
}
/** SetChannels() ********************************************/
/** Set master volume (0..255) and switch channels on/off. **/
/** Each channel N has corresponding bit 2^N in Switch. Set **/
/** or reset this bit to turn the channel on or off. **/
/*************************************************************/
void SetChannels(int Volume,int Switch)
{
Volume = Volume<0? 0:Volume>255? 255:Volume;
if(SndDriver.SetChannels) (*SndDriver.SetChannels)(Volume,Switch);
}
/** SetWave() ************************************************/
/** Set waveform for a given channel. The channel will be **/
/** marked with sound type SND_WAVE. Set Rate=0 if you want **/
/** waveform to be an instrument or set it to the waveform **/
/** own playback rate. **/
/*************************************************************/
void SetWave(int Channel,const signed char *Data,int Length,int Rate)
{
if((Channel<0)||(Length<=0)) return;
if(SndDriver.SetWave) (*SndDriver.SetWave)(Channel,Data,Length,Rate);
#ifdef unused
/* Log instrument change to MIDI file */
MIDISetSound(Channel,Rate? -1:SND_MELODIC);
#endif
}
#ifdef unused
/** InitMIDI() ***********************************************/
/** Initialize soundtrack logging into MIDI file FileName. **/
/** Repeated calls to InitMIDI() will close current MIDI **/
/** file and continue logging into a new one. **/
/*************************************************************/
void InitMIDI(const char *FileName)
{
int WasLogging,J;
/* Must pass a name! */
if(!FileName) return;
/* Memorize logging status */
WasLogging=Logging;
/* If MIDI logging in progress, close current file */
if(MIDIOut) TrashMIDI();
/* Clear instrument types */
for(J=0;J<MIDI_CHANNELS;J++) CH[J].Type=-1;
/* Set log file name and ticks/second parameter, no logging yet */
//LogName = FileName;
Logging = MIDI_OFF;
LastMsg = -1;
TickCount = 0;
MIDIOut = 0;
/* If was logging, restart */
if(WasLogging) MIDILogging(MIDI_ON);
}
/** TrashMIDI() **********************************************/
/** Finish logging soundtrack and close the MIDI file. **/
/*************************************************************/
void TrashMIDI(void)
{
long Length;
int J;
/* If not logging, drop out */
if(!MIDIOut) return;
/* Turn sound off */
for(J=0;J<MIDI_CHANNELS;J++) NoteOff(J);
/* End of track */
MIDIMessage(0xFF,0x2F,0x00);
/* Put track length in file */
fseek(MIDIOut,0,SEEK_END);
Length=ftell(MIDIOut)-22;
fseek(MIDIOut,18,SEEK_SET);
fputc((Length>>24)&0xFF,MIDIOut);
fputc((Length>>16)&0xFF,MIDIOut);
fputc((Length>>8)&0xFF,MIDIOut);
fputc(Length&0xFF,MIDIOut);
/* Done logging */
fclose(MIDIOut);
Logging = MIDI_OFF;
LastMsg = -1;
TickCount = 0;
MIDIOut = 0;
}
/** MIDILogging() ********************************************/
/** Turn soundtrack logging on/off and return its current **/
/** status. Possible values of Switch are MIDI_OFF (turn **/
/** logging off), MIDI_ON (turn logging on), MIDI_TOGGLE **/
/** (toggle logging), and MIDI_QUERY (just return current **/
/** state of logging). **/
/*************************************************************/
int MIDILogging(int Switch)
{
static const char MThd[] = "MThd\0\0\0\006\0\0\0\1";
/* ID DataLen Fmt Trks */
static const char MTrk[] = "MTrk\0\0\0\0";
/* ID TrkLen */
int J,I;
/* Toggle logging if requested */
if(Switch==MIDI_TOGGLE) Switch=!Logging;
if((Switch==MIDI_ON)||(Switch==MIDI_OFF))
if(Switch^Logging)
{
/* When turning logging off, silence all channels */
if(!Switch&&MIDIOut)
for(J=0;J<MIDI_CHANNELS;J++) NoteOff(J);
/* When turning logging on, open MIDI file */
if(Switch&&!MIDIOut&&LogName)
{
/* No messages have been sent yet */
LastMsg=-1;
/* Clear all storage */
for(J=0;J<MIDI_CHANNELS;J++)
CH[J].Note=CH[J].Pitch=CH[J].Level=-1;
/* Open new file and write out the header */
MIDIOut=fopen(LogName,"wb");
if(!MIDIOut) return(MIDI_OFF);
if(fwrite(MThd,1,12,MIDIOut)!=12)
{ fclose(MIDIOut);MIDIOut=0;return(MIDI_OFF); }
fputc((MIDI_DIVISIONS>>8)&0xFF,MIDIOut);
fputc(MIDI_DIVISIONS&0xFF,MIDIOut);
if(fwrite(MTrk,1,8,MIDIOut)!=8)
{ fclose(MIDIOut);MIDIOut=0;return(MIDI_OFF); }
/* Write out the tempo */
WriteTempo(MIDI_DIVISIONS);
}
/* Turn logging off on failure to open MIDIOut */
if(!MIDIOut) Switch=MIDI_OFF;
/* Assign new switch value */
Logging=Switch;
/* If switching logging on... */
if(Switch)
{
/* Start logging without a pause */
TickCount=0;
/* Write instrument changes */
for(J=0;J<MIDI_CHANNELS;J++)
if((CH[J].Type>=0)&&(CH[J].Type&0x10000))
{
I=CH[J].Type&~0x10000;
CH[J].Type=-1;
MIDISetSound(J,I);
}
}
}
/* Return current logging status */
return(Logging);
}
/** MIDITicks() **********************************************/
/** Log N 1ms MIDI ticks. **/
/*************************************************************/
void MIDITicks(int N)
{
if(Logging&&MIDIOut&&(N>0)) TickCount+=N;
}
/** MIDISound() **********************************************/
/** Set sound frequency (Hz) and volume (0..255) for a **/
/** given channel. **/
/*************************************************************/
void MIDISound(int Channel,int Freq,int Volume)
{
int MIDIVolume,MIDINote,MIDIWheel;
/* If logging off, file closed, or invalid channel, drop out */
if(!Logging||!MIDIOut||(Channel>=MIDI_CHANNELS-1)||(Channel<0)) return;
/* Frequency must be in range */
if((Freq<MIDI_MINFREQ)||(Freq>MIDI_MAXFREQ)) Freq=0;
/* Volume must be in range */
if(Volume<0) Volume=0; else if(Volume>255) Volume=255;
/* Instrument number must be valid */
if(CH[Channel].Type<0) Freq=0;
if(!Volume||!Freq) NoteOff(Channel);
else
{
/* SND_TRIANGLE is twice quieter than SND_MELODIC */
if(CH[Channel].Type==SND_TRIANGLE) Volume=(Volume+1)/2;
/* Compute MIDI note parameters */
MIDIVolume = (127*Volume+128)/255;
MIDINote = Freqs[Freq/3].Note;
MIDIWheel = Freqs[Freq/3].Wheel;
/* Play new note */
NoteOn(Channel,MIDINote,MIDIVolume);
/* Change pitch */
if(CH[Channel].Pitch!=MIDIWheel)
{
MIDIMessage(0xE0+SHIFT(Channel),MIDIWheel&0x7F,(MIDIWheel>>7)&0x7F);
CH[Channel].Pitch=MIDIWheel;
}
}
}
/** MIDISetSound() *******************************************/
/** Set sound type for a given channel. **/
/*************************************************************/
void MIDISetSound(int Channel,int Type)
{
/* Channel must be valid */
if((Channel>=MIDI_CHANNELS-1)||(Channel<0)) return;
/* If instrument changed... */
if(CH[Channel].Type!=Type)
{
/* If logging off or file closed, drop out */
if(!Logging||!MIDIOut) CH[Channel].Type=Type|0x10000;
else
{
CH[Channel].Type=Type;
if(Type<0) NoteOff(Channel);
else
{
Type=Type&SND_MIDI? (Type&0x7F):Programs[Type%5];
MIDIMessage(0xC0+SHIFT(Channel),Type,255);
}
}
}
}
/** MIDIDrum() ***********************************************/
/** Hit a drum of a given type with given force. **/
/*************************************************************/
void MIDIDrum(int Type,int Force)
{
/* If logging off or invalid channel, drop out */
if(!Logging||!MIDIOut) return;
/* The only non-MIDI drum is a click ("Low Wood Block") */
Type=Type&DRM_MIDI? (Type&0x7F):77;
MIDIMessage(0x99,Type,(Force&0xFF)/2);
}
/** MIDIMessage() ********************************************/
/** Write out a MIDI message. **/
/*************************************************************/
void MIDIMessage(byte D0,byte D1,byte D2)
{
/* Write number of ticks that passed */
WriteDelta();
/* Write out the command */
if(D0!=LastMsg) { LastMsg=D0;fputc(D0,MIDIOut); }
/* Write out the arguments */
if(D1<128)
{
fputc(D1,MIDIOut);
if(D2<128) fputc(D2,MIDIOut);
}
}
/** NoteOn() *************************************************/
/** Turn on a note on a given channel. **/
/*************************************************************/
void NoteOn(byte Channel,byte Note,byte Level)
{
Note = Note>0x7F? 0x7F:Note;
Level = Level>0x7F? 0x7F:Level;
if((CH[Channel].Note!=Note)||(CH[Channel].Level!=Level))
{
if((CH[Channel].Note>=0)&&(CH[Channel].Note!=Note)) NoteOff(Channel);
MIDIMessage(0x90+SHIFT(Channel),Note,Level);
CH[Channel].Note=Note;
CH[Channel].Level=Level;
}
}
/** NoteOff() ************************************************/
/** Turn off a note on a given channel. **/
/*************************************************************/
void NoteOff(byte Channel)
{
if(CH[Channel].Note>=0)
{
MIDIMessage(0x80+SHIFT(Channel),CH[Channel].Note,127);
CH[Channel].Note=-1;
}
}
/** WriteDelta() *********************************************/
/** Write number of ticks since the last MIDI command and **/
/** reset the counter. **/
/*************************************************************/
void WriteDelta(void)
{
if(TickCount<128) fputc(TickCount,MIDIOut);
else
{
if(TickCount<128*128)
{
fputc((TickCount>>7)|0x80,MIDIOut);
fputc(TickCount&0x7F,MIDIOut);
}
else
{
fputc(((TickCount>>14)&0x7F)|0x80,MIDIOut);
fputc(((TickCount>>7)&0x7F)|0x80,MIDIOut);
fputc(TickCount&0x7F,MIDIOut);
}
}
TickCount=0;
}
/** WriteTempo() *********************************************/
/** Write out soundtrack tempo (Hz). **/
/*************************************************************/
void WriteTempo(int Freq)
{
int J;
J=500000*MIDI_DIVISIONS*2/Freq;
WriteDelta();
fputc(0xFF,MIDIOut);
fputc(0x51,MIDIOut);
fputc(0x03,MIDIOut);
fputc((J>>16)&0xFF,MIDIOut);
fputc((J>>8)&0xFF,MIDIOut);
fputc(J&0xFF,MIDIOut);
}
#endif

Wyświetl plik

@ -0,0 +1,152 @@
/** EMULib Emulation Library *********************************/
/** **/
/** Sound.h **/
/** **/
/** This file defines standard sound generation API and **/
/** functions needed to log soundtrack into a MIDI file. **/
/** See Sound.c and the sound drivers for the code. **/
/** **/
/** Copyright (C) Marat Fayzullin 1996-2003 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
#ifndef SOUND_H
#define SOUND_H
/* SetSound() arguments: */
#define SND_MELODIC 0 /* Melodic sound (default) */
#define SND_RECTANGLE 0 /* Rectangular wave */
#define SND_TRIANGLE 1 /* Triangular wave (1/2 rect.)*/
#define SND_NOISE 2 /* White noise */
#define SND_PERIODIC 3 /* Periodic noise (not im-ed) */
#define SND_WAVE 4 /* Wave sound set by SetWave()*/
#define SND_MIDI 0x100 /* MIDI instrument (ORable) */
/* Drum() arguments: */
#define DRM_CLICK 0 /* Click (default) */
#define DRM_MIDI 0x100 /* MIDI drum (ORable) */
/* MIDI characteristics: */
#define MIDI_CHANNELS 16 /* Number of MIDI channels */
#define MIDI_MINFREQ 9 /* Min MIDI frequency (Hz) */
#define MIDI_MAXFREQ 12285 /* Max MIDI frequency (Hz) */
#define MIDI_DIVISIONS 1000 /* Number of ticks per second */
/* MIDILogging() arguments: */
#define MIDI_OFF 0 /* Turn MIDI logging off */
#define MIDI_ON 1 /* Turn MIDI logging on */
#define MIDI_TOGGLE 2 /* Toggle MIDI logging */
#define MIDI_QUERY 3 /* Query MIDI logging status */
/** TrashSound() *********************************************/
/** Shut down sound driver. Each driver implements its own **/
/** TrashSound() function. **/
/*************************************************************/
void TrashSound(void);
/** Sound() **************************************************/
/** Generate sound of given frequency (Hz) and volume **/
/** (0..255) via given channel. Setting Freq=0 or Volume=0 **/
/** turns sound off. **/
/*************************************************************/
void Sound(int Channel,int Freq,int Volume);
/** Drum() ***************************************************/
/** Hit a drum of given type with given force (0..255). **/
/** MIDI drums can be used by ORing their numbers with **/
/** SND_MIDI. **/
/*************************************************************/
void Drum(int Type,int Force);
/** SetSound() ***********************************************/
/** Set sound type at a given channel. MIDI instruments can **/
/** be set directly by ORing their numbers with SND_MIDI. **/
/*************************************************************/
void SetSound(int Channel,int NewType);
/** SetChannels() ********************************************/
/** Set master volume (0..255) and switch channels on/off. **/
/** Each channel N has corresponding bit 2^N in Switch. Set **/
/** or reset this bit to turn the channel on or off. **/
/*************************************************************/
void SetChannels(int Volume,int Switch);
/** SetWave() ************************************************/
/** Set waveform for a given channel. The channel will be **/
/** marked with sound type SND_WAVE. Set Rate=0 if you want **/
/** waveform to be an instrument or set it to the waveform **/
/** own playback rate. **/
/*************************************************************/
void SetWave(int Channel,const signed char *Data,int Length,int Rate);
/** InitMIDI() ***********************************************/
/** Initialize soundtrack logging into MIDI file FileName. **/
/** Repeated calls to InitMIDI() will close current MIDI **/
/** file and continue logging into a new one. **/
/*************************************************************/
void InitMIDI(const char *FileName);
/** TrashMIDI() **********************************************/
/** Finish logging soundtrack and close the MIDI file. **/
/*************************************************************/
void TrashMIDI(void);
/** MIDILogging() ********************************************/
/** Turn soundtrack logging on/off and return its current **/
/** status. Possible values of Switch are MIDI_OFF (turn **/
/** logging off), MIDI_ON (turn logging on), MIDI_TOGGLE **/
/** (toggle logging), and MIDI_QUERY (just return current **/
/** state of logging). **/
/*************************************************************/
int MIDILogging(int Switch);
/** MIDITicks() **********************************************/
/** Log N 1ms MIDI ticks. **/
/*************************************************************/
void MIDITicks(int N);
#define SND_CHANNELS 16 /* Number of channels */
#define SND_SAMPLESIZE 128 //256 /* Max. SetWave() sample size */
#define SND_BUFSIZE 128 //256 /* Buffer size, <= 2^SND_BITS */
#define SND_BITS 8 /* Number of bits in a fragment */
#define SND_BUFFERS 8 /* Number of fragments, >= 2 */
/* Bigger value results in better behaviour on loaded */
/* but output gets more delayed. */
/** InitSound() **********************************************/
/** Initialize Unix sound driver with given synthesis rate. **/
/** Returns Rate on success, 0 otherwise. Pass Rate=0 to **/
/** skip initialization and be silent. Pass Verbose!=0 to **/
/** see initialization messages. **/
/*************************************************************/
int InitSound(int Rate,int Verbose);
/** StopSound() **********************************************/
/** Temporarily suspend sound. **/
/*************************************************************/
void StopSound(void);
/** ResumeSound() ********************************************/
/** Resume sound after StopSound(). **/
/*************************************************************/
void ResumeSound(void);
/** SndDriver ************************************************/
/** Each sound driver should fill this structure with **/
/** pointers to hardware-dependent handlers. This has to be **/
/** done inside the InitSound() function. **/
/*************************************************************/
struct SndDriverStruct
{
void (*SetSound)(int Channel,int NewType);
void (*Drum)(int Type,int Force);
void (*SetChannels)(int Volume,int Switch);
void (*Sound)(int Channel,int NewFreq,int NewVolume);
void (*SetWave)(int Channel,const signed char *Data,int Length,int Freq);
};
extern struct SndDriverStruct SndDriver;
#endif /* SOUND_H */

Wyświetl plik

@ -0,0 +1,447 @@
/** Z80: portable Z80 emulator *******************************/
/** **/
/** Tables.h **/
/** **/
/** This file contains tables of used by Z80 emulation to **/
/** compute SIGN,ZERO, PARITY flags, and decimal correction **/
/** There are also timing tables for Z80 opcodes. This file **/
/** is included from Z80.c. **/
/** **/
/** Copyright (C) Marat Fayzullin 1994-2005 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
static const byte Cycles[256] =
{
4,10, 7, 6, 4, 4, 7, 4, 4,11, 7, 6, 4, 4, 7, 4,
8,10, 7, 6, 4, 4, 7, 4,12,11, 7, 6, 4, 4, 7, 4,
7,10,16, 6, 4, 4, 7, 4, 7,11,16, 6, 4, 4, 7, 4,
7,10,13, 6,11,11,10, 4, 7,11,13, 6, 4, 4, 7, 4,
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
7, 7, 7, 7, 7, 7, 4, 7, 4, 4, 4, 4, 4, 4, 7, 4,
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
5,10,10,10,10,11, 7,11, 5,10,10, 0,10,17, 7,11,
5,10,10,11,10,11, 7,11, 5, 4,10,11,10, 0, 7,11,
5,10,10,19,10,11, 7,11, 5, 4,10, 4,10, 0, 7,11,
5,10,10, 4,10,11, 7,11, 5, 6,10, 4,10, 0, 7,11
};
static const byte CyclesCB[256] =
{
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8
};
static const byte CyclesED[256] =
{
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, 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, 0, 0, 0, 0,
12,12,15,20, 8,14, 8, 9,12,12,15,20, 0,14, 0, 9,
12,12,15,20, 0, 0, 8, 9,12,12,15,20, 0, 0, 8, 9,
12,12,15,20, 0, 0, 0,18,12,12,15,20, 0, 0, 0,18,
12, 0,15,20, 0, 0, 0, 0,12,12,15,20, 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, 0, 0, 0, 0, 0, 0,
16,16,16,16, 0, 0, 0, 0,16,16,16,16, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static const byte CyclesXX[256] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0,15, 0, 0, 0, 0, 0, 0,
0,14,20,10, 9, 9, 9, 0, 0,15,20,10, 9, 9, 9, 0,
0, 0, 0, 0,23,23,19, 0, 0,15, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 9, 9,19, 0, 0, 0, 0, 0, 9, 9,19, 0,
0, 0, 0, 0, 9, 9,19, 0, 0, 0, 0, 0, 9, 9,19, 0,
9, 9, 9, 9, 9, 9,19, 9, 9, 9, 9, 9, 9, 9,19, 9,
19,19,19,19,19,19,19,19, 0, 0, 0, 0, 9, 9,19, 0,
0, 0, 0, 0, 9, 9,19, 0, 0, 0, 0, 0, 9, 9,19, 0,
0, 0, 0, 0, 9, 9,19, 0, 0, 0, 0, 0, 9, 9,19, 0,
0, 0, 0, 0, 9, 9,19, 0, 0, 0, 0, 0, 9, 9,19, 0,
0, 0, 0, 0, 9, 9,19, 0, 0, 0, 0, 0, 9, 9,19, 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, 0, 0, 0,
0,14, 0,23, 0,15, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0,10, 0, 0, 0, 0, 0, 0
};
static const byte CyclesXXCB[256] =
{
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0,
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0,
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0,
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0,
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0,
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0,
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0,
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0,
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0,
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0,
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0,
0, 0, 0, 0, 0, 0,23, 0, 0, 0, 0, 0, 0, 0,23, 0
};
static const byte ZSTable[256] =
{
Z_FLAG,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,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,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,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,0,0,0,0,0,0,0,
S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,
S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,
S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,
S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,
S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,
S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,
S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,
S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,
S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,
S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,
S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,
S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,
S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,
S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,
S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,
S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG,S_FLAG
};
static const byte PZSTable[256] =
{
Z_FLAG|P_FLAG,0,0,P_FLAG,0,P_FLAG,P_FLAG,0,
0,P_FLAG,P_FLAG,0,P_FLAG,0,0,P_FLAG,
0,P_FLAG,P_FLAG,0,P_FLAG,0,0,P_FLAG,P_FLAG,0,0,P_FLAG,0,P_FLAG,P_FLAG,0,
0,P_FLAG,P_FLAG,0,P_FLAG,0,0,P_FLAG,P_FLAG,0,0,P_FLAG,0,P_FLAG,P_FLAG,0,
P_FLAG,0,0,P_FLAG,0,P_FLAG,P_FLAG,0,0,P_FLAG,P_FLAG,0,P_FLAG,0,0,P_FLAG,
0,P_FLAG,P_FLAG,0,P_FLAG,0,0,P_FLAG,P_FLAG,0,0,P_FLAG,0,P_FLAG,P_FLAG,0,
P_FLAG,0,0,P_FLAG,0,P_FLAG,P_FLAG,0,0,P_FLAG,P_FLAG,0,P_FLAG,0,0,P_FLAG,
P_FLAG,0,0,P_FLAG,0,P_FLAG,P_FLAG,0,0,P_FLAG,P_FLAG,0,P_FLAG,0,0,P_FLAG,
0,P_FLAG,P_FLAG,0,P_FLAG,0,0,P_FLAG,P_FLAG,0,0,P_FLAG,0,P_FLAG,P_FLAG,0,
S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG,
S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG,
S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG,
S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG,
S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG,
S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG,
S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG,
S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG,
S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG,
S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG,
S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG,
S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG,
S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG,
S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG,
S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG,
S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG,
S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG,
S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG,
S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG,
S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG,
S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG,
S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG,
S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG,
S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG,
S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG,
S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG,
S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG,
S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG,
S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG,
S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG,
S_FLAG,S_FLAG|P_FLAG,S_FLAG|P_FLAG,S_FLAG,
S_FLAG|P_FLAG,S_FLAG,S_FLAG,S_FLAG|P_FLAG
};
static const word DAATable[2048] =
{
0x0044,0x0100,0x0200,0x0304,0x0400,0x0504,0x0604,0x0700,
0x0808,0x090C,0x1010,0x1114,0x1214,0x1310,0x1414,0x1510,
0x1000,0x1104,0x1204,0x1300,0x1404,0x1500,0x1600,0x1704,
0x180C,0x1908,0x2030,0x2134,0x2234,0x2330,0x2434,0x2530,
0x2020,0x2124,0x2224,0x2320,0x2424,0x2520,0x2620,0x2724,
0x282C,0x2928,0x3034,0x3130,0x3230,0x3334,0x3430,0x3534,
0x3024,0x3120,0x3220,0x3324,0x3420,0x3524,0x3624,0x3720,
0x3828,0x392C,0x4010,0x4114,0x4214,0x4310,0x4414,0x4510,
0x4000,0x4104,0x4204,0x4300,0x4404,0x4500,0x4600,0x4704,
0x480C,0x4908,0x5014,0x5110,0x5210,0x5314,0x5410,0x5514,
0x5004,0x5100,0x5200,0x5304,0x5400,0x5504,0x5604,0x5700,
0x5808,0x590C,0x6034,0x6130,0x6230,0x6334,0x6430,0x6534,
0x6024,0x6120,0x6220,0x6324,0x6420,0x6524,0x6624,0x6720,
0x6828,0x692C,0x7030,0x7134,0x7234,0x7330,0x7434,0x7530,
0x7020,0x7124,0x7224,0x7320,0x7424,0x7520,0x7620,0x7724,
0x782C,0x7928,0x8090,0x8194,0x8294,0x8390,0x8494,0x8590,
0x8080,0x8184,0x8284,0x8380,0x8484,0x8580,0x8680,0x8784,
0x888C,0x8988,0x9094,0x9190,0x9290,0x9394,0x9490,0x9594,
0x9084,0x9180,0x9280,0x9384,0x9480,0x9584,0x9684,0x9780,
0x9888,0x998C,0x0055,0x0111,0x0211,0x0315,0x0411,0x0515,
0x0045,0x0101,0x0201,0x0305,0x0401,0x0505,0x0605,0x0701,
0x0809,0x090D,0x1011,0x1115,0x1215,0x1311,0x1415,0x1511,
0x1001,0x1105,0x1205,0x1301,0x1405,0x1501,0x1601,0x1705,
0x180D,0x1909,0x2031,0x2135,0x2235,0x2331,0x2435,0x2531,
0x2021,0x2125,0x2225,0x2321,0x2425,0x2521,0x2621,0x2725,
0x282D,0x2929,0x3035,0x3131,0x3231,0x3335,0x3431,0x3535,
0x3025,0x3121,0x3221,0x3325,0x3421,0x3525,0x3625,0x3721,
0x3829,0x392D,0x4011,0x4115,0x4215,0x4311,0x4415,0x4511,
0x4001,0x4105,0x4205,0x4301,0x4405,0x4501,0x4601,0x4705,
0x480D,0x4909,0x5015,0x5111,0x5211,0x5315,0x5411,0x5515,
0x5005,0x5101,0x5201,0x5305,0x5401,0x5505,0x5605,0x5701,
0x5809,0x590D,0x6035,0x6131,0x6231,0x6335,0x6431,0x6535,
0x6025,0x6121,0x6221,0x6325,0x6421,0x6525,0x6625,0x6721,
0x6829,0x692D,0x7031,0x7135,0x7235,0x7331,0x7435,0x7531,
0x7021,0x7125,0x7225,0x7321,0x7425,0x7521,0x7621,0x7725,
0x782D,0x7929,0x8091,0x8195,0x8295,0x8391,0x8495,0x8591,
0x8081,0x8185,0x8285,0x8381,0x8485,0x8581,0x8681,0x8785,
0x888D,0x8989,0x9095,0x9191,0x9291,0x9395,0x9491,0x9595,
0x9085,0x9181,0x9281,0x9385,0x9481,0x9585,0x9685,0x9781,
0x9889,0x998D,0xA0B5,0xA1B1,0xA2B1,0xA3B5,0xA4B1,0xA5B5,
0xA0A5,0xA1A1,0xA2A1,0xA3A5,0xA4A1,0xA5A5,0xA6A5,0xA7A1,
0xA8A9,0xA9AD,0xB0B1,0xB1B5,0xB2B5,0xB3B1,0xB4B5,0xB5B1,
0xB0A1,0xB1A5,0xB2A5,0xB3A1,0xB4A5,0xB5A1,0xB6A1,0xB7A5,
0xB8AD,0xB9A9,0xC095,0xC191,0xC291,0xC395,0xC491,0xC595,
0xC085,0xC181,0xC281,0xC385,0xC481,0xC585,0xC685,0xC781,
0xC889,0xC98D,0xD091,0xD195,0xD295,0xD391,0xD495,0xD591,
0xD081,0xD185,0xD285,0xD381,0xD485,0xD581,0xD681,0xD785,
0xD88D,0xD989,0xE0B1,0xE1B5,0xE2B5,0xE3B1,0xE4B5,0xE5B1,
0xE0A1,0xE1A5,0xE2A5,0xE3A1,0xE4A5,0xE5A1,0xE6A1,0xE7A5,
0xE8AD,0xE9A9,0xF0B5,0xF1B1,0xF2B1,0xF3B5,0xF4B1,0xF5B5,
0xF0A5,0xF1A1,0xF2A1,0xF3A5,0xF4A1,0xF5A5,0xF6A5,0xF7A1,
0xF8A9,0xF9AD,0x0055,0x0111,0x0211,0x0315,0x0411,0x0515,
0x0045,0x0101,0x0201,0x0305,0x0401,0x0505,0x0605,0x0701,
0x0809,0x090D,0x1011,0x1115,0x1215,0x1311,0x1415,0x1511,
0x1001,0x1105,0x1205,0x1301,0x1405,0x1501,0x1601,0x1705,
0x180D,0x1909,0x2031,0x2135,0x2235,0x2331,0x2435,0x2531,
0x2021,0x2125,0x2225,0x2321,0x2425,0x2521,0x2621,0x2725,
0x282D,0x2929,0x3035,0x3131,0x3231,0x3335,0x3431,0x3535,
0x3025,0x3121,0x3221,0x3325,0x3421,0x3525,0x3625,0x3721,
0x3829,0x392D,0x4011,0x4115,0x4215,0x4311,0x4415,0x4511,
0x4001,0x4105,0x4205,0x4301,0x4405,0x4501,0x4601,0x4705,
0x480D,0x4909,0x5015,0x5111,0x5211,0x5315,0x5411,0x5515,
0x5005,0x5101,0x5201,0x5305,0x5401,0x5505,0x5605,0x5701,
0x5809,0x590D,0x6035,0x6131,0x6231,0x6335,0x6431,0x6535,
0x0604,0x0700,0x0808,0x090C,0x0A0C,0x0B08,0x0C0C,0x0D08,
0x0E08,0x0F0C,0x1010,0x1114,0x1214,0x1310,0x1414,0x1510,
0x1600,0x1704,0x180C,0x1908,0x1A08,0x1B0C,0x1C08,0x1D0C,
0x1E0C,0x1F08,0x2030,0x2134,0x2234,0x2330,0x2434,0x2530,
0x2620,0x2724,0x282C,0x2928,0x2A28,0x2B2C,0x2C28,0x2D2C,
0x2E2C,0x2F28,0x3034,0x3130,0x3230,0x3334,0x3430,0x3534,
0x3624,0x3720,0x3828,0x392C,0x3A2C,0x3B28,0x3C2C,0x3D28,
0x3E28,0x3F2C,0x4010,0x4114,0x4214,0x4310,0x4414,0x4510,
0x4600,0x4704,0x480C,0x4908,0x4A08,0x4B0C,0x4C08,0x4D0C,
0x4E0C,0x4F08,0x5014,0x5110,0x5210,0x5314,0x5410,0x5514,
0x5604,0x5700,0x5808,0x590C,0x5A0C,0x5B08,0x5C0C,0x5D08,
0x5E08,0x5F0C,0x6034,0x6130,0x6230,0x6334,0x6430,0x6534,
0x6624,0x6720,0x6828,0x692C,0x6A2C,0x6B28,0x6C2C,0x6D28,
0x6E28,0x6F2C,0x7030,0x7134,0x7234,0x7330,0x7434,0x7530,
0x7620,0x7724,0x782C,0x7928,0x7A28,0x7B2C,0x7C28,0x7D2C,
0x7E2C,0x7F28,0x8090,0x8194,0x8294,0x8390,0x8494,0x8590,
0x8680,0x8784,0x888C,0x8988,0x8A88,0x8B8C,0x8C88,0x8D8C,
0x8E8C,0x8F88,0x9094,0x9190,0x9290,0x9394,0x9490,0x9594,
0x9684,0x9780,0x9888,0x998C,0x9A8C,0x9B88,0x9C8C,0x9D88,
0x9E88,0x9F8C,0x0055,0x0111,0x0211,0x0315,0x0411,0x0515,
0x0605,0x0701,0x0809,0x090D,0x0A0D,0x0B09,0x0C0D,0x0D09,
0x0E09,0x0F0D,0x1011,0x1115,0x1215,0x1311,0x1415,0x1511,
0x1601,0x1705,0x180D,0x1909,0x1A09,0x1B0D,0x1C09,0x1D0D,
0x1E0D,0x1F09,0x2031,0x2135,0x2235,0x2331,0x2435,0x2531,
0x2621,0x2725,0x282D,0x2929,0x2A29,0x2B2D,0x2C29,0x2D2D,
0x2E2D,0x2F29,0x3035,0x3131,0x3231,0x3335,0x3431,0x3535,
0x3625,0x3721,0x3829,0x392D,0x3A2D,0x3B29,0x3C2D,0x3D29,
0x3E29,0x3F2D,0x4011,0x4115,0x4215,0x4311,0x4415,0x4511,
0x4601,0x4705,0x480D,0x4909,0x4A09,0x4B0D,0x4C09,0x4D0D,
0x4E0D,0x4F09,0x5015,0x5111,0x5211,0x5315,0x5411,0x5515,
0x5605,0x5701,0x5809,0x590D,0x5A0D,0x5B09,0x5C0D,0x5D09,
0x5E09,0x5F0D,0x6035,0x6131,0x6231,0x6335,0x6431,0x6535,
0x6625,0x6721,0x6829,0x692D,0x6A2D,0x6B29,0x6C2D,0x6D29,
0x6E29,0x6F2D,0x7031,0x7135,0x7235,0x7331,0x7435,0x7531,
0x7621,0x7725,0x782D,0x7929,0x7A29,0x7B2D,0x7C29,0x7D2D,
0x7E2D,0x7F29,0x8091,0x8195,0x8295,0x8391,0x8495,0x8591,
0x8681,0x8785,0x888D,0x8989,0x8A89,0x8B8D,0x8C89,0x8D8D,
0x8E8D,0x8F89,0x9095,0x9191,0x9291,0x9395,0x9491,0x9595,
0x9685,0x9781,0x9889,0x998D,0x9A8D,0x9B89,0x9C8D,0x9D89,
0x9E89,0x9F8D,0xA0B5,0xA1B1,0xA2B1,0xA3B5,0xA4B1,0xA5B5,
0xA6A5,0xA7A1,0xA8A9,0xA9AD,0xAAAD,0xABA9,0xACAD,0xADA9,
0xAEA9,0xAFAD,0xB0B1,0xB1B5,0xB2B5,0xB3B1,0xB4B5,0xB5B1,
0xB6A1,0xB7A5,0xB8AD,0xB9A9,0xBAA9,0xBBAD,0xBCA9,0xBDAD,
0xBEAD,0xBFA9,0xC095,0xC191,0xC291,0xC395,0xC491,0xC595,
0xC685,0xC781,0xC889,0xC98D,0xCA8D,0xCB89,0xCC8D,0xCD89,
0xCE89,0xCF8D,0xD091,0xD195,0xD295,0xD391,0xD495,0xD591,
0xD681,0xD785,0xD88D,0xD989,0xDA89,0xDB8D,0xDC89,0xDD8D,
0xDE8D,0xDF89,0xE0B1,0xE1B5,0xE2B5,0xE3B1,0xE4B5,0xE5B1,
0xE6A1,0xE7A5,0xE8AD,0xE9A9,0xEAA9,0xEBAD,0xECA9,0xEDAD,
0xEEAD,0xEFA9,0xF0B5,0xF1B1,0xF2B1,0xF3B5,0xF4B1,0xF5B5,
0xF6A5,0xF7A1,0xF8A9,0xF9AD,0xFAAD,0xFBA9,0xFCAD,0xFDA9,
0xFEA9,0xFFAD,0x0055,0x0111,0x0211,0x0315,0x0411,0x0515,
0x0605,0x0701,0x0809,0x090D,0x0A0D,0x0B09,0x0C0D,0x0D09,
0x0E09,0x0F0D,0x1011,0x1115,0x1215,0x1311,0x1415,0x1511,
0x1601,0x1705,0x180D,0x1909,0x1A09,0x1B0D,0x1C09,0x1D0D,
0x1E0D,0x1F09,0x2031,0x2135,0x2235,0x2331,0x2435,0x2531,
0x2621,0x2725,0x282D,0x2929,0x2A29,0x2B2D,0x2C29,0x2D2D,
0x2E2D,0x2F29,0x3035,0x3131,0x3231,0x3335,0x3431,0x3535,
0x3625,0x3721,0x3829,0x392D,0x3A2D,0x3B29,0x3C2D,0x3D29,
0x3E29,0x3F2D,0x4011,0x4115,0x4215,0x4311,0x4415,0x4511,
0x4601,0x4705,0x480D,0x4909,0x4A09,0x4B0D,0x4C09,0x4D0D,
0x4E0D,0x4F09,0x5015,0x5111,0x5211,0x5315,0x5411,0x5515,
0x5605,0x5701,0x5809,0x590D,0x5A0D,0x5B09,0x5C0D,0x5D09,
0x5E09,0x5F0D,0x6035,0x6131,0x6231,0x6335,0x6431,0x6535,
0x0046,0x0102,0x0202,0x0306,0x0402,0x0506,0x0606,0x0702,
0x080A,0x090E,0x0402,0x0506,0x0606,0x0702,0x080A,0x090E,
0x1002,0x1106,0x1206,0x1302,0x1406,0x1502,0x1602,0x1706,
0x180E,0x190A,0x1406,0x1502,0x1602,0x1706,0x180E,0x190A,
0x2022,0x2126,0x2226,0x2322,0x2426,0x2522,0x2622,0x2726,
0x282E,0x292A,0x2426,0x2522,0x2622,0x2726,0x282E,0x292A,
0x3026,0x3122,0x3222,0x3326,0x3422,0x3526,0x3626,0x3722,
0x382A,0x392E,0x3422,0x3526,0x3626,0x3722,0x382A,0x392E,
0x4002,0x4106,0x4206,0x4302,0x4406,0x4502,0x4602,0x4706,
0x480E,0x490A,0x4406,0x4502,0x4602,0x4706,0x480E,0x490A,
0x5006,0x5102,0x5202,0x5306,0x5402,0x5506,0x5606,0x5702,
0x580A,0x590E,0x5402,0x5506,0x5606,0x5702,0x580A,0x590E,
0x6026,0x6122,0x6222,0x6326,0x6422,0x6526,0x6626,0x6722,
0x682A,0x692E,0x6422,0x6526,0x6626,0x6722,0x682A,0x692E,
0x7022,0x7126,0x7226,0x7322,0x7426,0x7522,0x7622,0x7726,
0x782E,0x792A,0x7426,0x7522,0x7622,0x7726,0x782E,0x792A,
0x8082,0x8186,0x8286,0x8382,0x8486,0x8582,0x8682,0x8786,
0x888E,0x898A,0x8486,0x8582,0x8682,0x8786,0x888E,0x898A,
0x9086,0x9182,0x9282,0x9386,0x9482,0x9586,0x9686,0x9782,
0x988A,0x998E,0x3423,0x3527,0x3627,0x3723,0x382B,0x392F,
0x4003,0x4107,0x4207,0x4303,0x4407,0x4503,0x4603,0x4707,
0x480F,0x490B,0x4407,0x4503,0x4603,0x4707,0x480F,0x490B,
0x5007,0x5103,0x5203,0x5307,0x5403,0x5507,0x5607,0x5703,
0x580B,0x590F,0x5403,0x5507,0x5607,0x5703,0x580B,0x590F,
0x6027,0x6123,0x6223,0x6327,0x6423,0x6527,0x6627,0x6723,
0x682B,0x692F,0x6423,0x6527,0x6627,0x6723,0x682B,0x692F,
0x7023,0x7127,0x7227,0x7323,0x7427,0x7523,0x7623,0x7727,
0x782F,0x792B,0x7427,0x7523,0x7623,0x7727,0x782F,0x792B,
0x8083,0x8187,0x8287,0x8383,0x8487,0x8583,0x8683,0x8787,
0x888F,0x898B,0x8487,0x8583,0x8683,0x8787,0x888F,0x898B,
0x9087,0x9183,0x9283,0x9387,0x9483,0x9587,0x9687,0x9783,
0x988B,0x998F,0x9483,0x9587,0x9687,0x9783,0x988B,0x998F,
0xA0A7,0xA1A3,0xA2A3,0xA3A7,0xA4A3,0xA5A7,0xA6A7,0xA7A3,
0xA8AB,0xA9AF,0xA4A3,0xA5A7,0xA6A7,0xA7A3,0xA8AB,0xA9AF,
0xB0A3,0xB1A7,0xB2A7,0xB3A3,0xB4A7,0xB5A3,0xB6A3,0xB7A7,
0xB8AF,0xB9AB,0xB4A7,0xB5A3,0xB6A3,0xB7A7,0xB8AF,0xB9AB,
0xC087,0xC183,0xC283,0xC387,0xC483,0xC587,0xC687,0xC783,
0xC88B,0xC98F,0xC483,0xC587,0xC687,0xC783,0xC88B,0xC98F,
0xD083,0xD187,0xD287,0xD383,0xD487,0xD583,0xD683,0xD787,
0xD88F,0xD98B,0xD487,0xD583,0xD683,0xD787,0xD88F,0xD98B,
0xE0A3,0xE1A7,0xE2A7,0xE3A3,0xE4A7,0xE5A3,0xE6A3,0xE7A7,
0xE8AF,0xE9AB,0xE4A7,0xE5A3,0xE6A3,0xE7A7,0xE8AF,0xE9AB,
0xF0A7,0xF1A3,0xF2A3,0xF3A7,0xF4A3,0xF5A7,0xF6A7,0xF7A3,
0xF8AB,0xF9AF,0xF4A3,0xF5A7,0xF6A7,0xF7A3,0xF8AB,0xF9AF,
0x0047,0x0103,0x0203,0x0307,0x0403,0x0507,0x0607,0x0703,
0x080B,0x090F,0x0403,0x0507,0x0607,0x0703,0x080B,0x090F,
0x1003,0x1107,0x1207,0x1303,0x1407,0x1503,0x1603,0x1707,
0x180F,0x190B,0x1407,0x1503,0x1603,0x1707,0x180F,0x190B,
0x2023,0x2127,0x2227,0x2323,0x2427,0x2523,0x2623,0x2727,
0x282F,0x292B,0x2427,0x2523,0x2623,0x2727,0x282F,0x292B,
0x3027,0x3123,0x3223,0x3327,0x3423,0x3527,0x3627,0x3723,
0x382B,0x392F,0x3423,0x3527,0x3627,0x3723,0x382B,0x392F,
0x4003,0x4107,0x4207,0x4303,0x4407,0x4503,0x4603,0x4707,
0x480F,0x490B,0x4407,0x4503,0x4603,0x4707,0x480F,0x490B,
0x5007,0x5103,0x5203,0x5307,0x5403,0x5507,0x5607,0x5703,
0x580B,0x590F,0x5403,0x5507,0x5607,0x5703,0x580B,0x590F,
0x6027,0x6123,0x6223,0x6327,0x6423,0x6527,0x6627,0x6723,
0x682B,0x692F,0x6423,0x6527,0x6627,0x6723,0x682B,0x692F,
0x7023,0x7127,0x7227,0x7323,0x7427,0x7523,0x7623,0x7727,
0x782F,0x792B,0x7427,0x7523,0x7623,0x7727,0x782F,0x792B,
0x8083,0x8187,0x8287,0x8383,0x8487,0x8583,0x8683,0x8787,
0x888F,0x898B,0x8487,0x8583,0x8683,0x8787,0x888F,0x898B,
0x9087,0x9183,0x9283,0x9387,0x9483,0x9587,0x9687,0x9783,
0x988B,0x998F,0x9483,0x9587,0x9687,0x9783,0x988B,0x998F,
0xFABE,0xFBBA,0xFCBE,0xFDBA,0xFEBA,0xFFBE,0x0046,0x0102,
0x0202,0x0306,0x0402,0x0506,0x0606,0x0702,0x080A,0x090E,
0x0A1E,0x0B1A,0x0C1E,0x0D1A,0x0E1A,0x0F1E,0x1002,0x1106,
0x1206,0x1302,0x1406,0x1502,0x1602,0x1706,0x180E,0x190A,
0x1A1A,0x1B1E,0x1C1A,0x1D1E,0x1E1E,0x1F1A,0x2022,0x2126,
0x2226,0x2322,0x2426,0x2522,0x2622,0x2726,0x282E,0x292A,
0x2A3A,0x2B3E,0x2C3A,0x2D3E,0x2E3E,0x2F3A,0x3026,0x3122,
0x3222,0x3326,0x3422,0x3526,0x3626,0x3722,0x382A,0x392E,
0x3A3E,0x3B3A,0x3C3E,0x3D3A,0x3E3A,0x3F3E,0x4002,0x4106,
0x4206,0x4302,0x4406,0x4502,0x4602,0x4706,0x480E,0x490A,
0x4A1A,0x4B1E,0x4C1A,0x4D1E,0x4E1E,0x4F1A,0x5006,0x5102,
0x5202,0x5306,0x5402,0x5506,0x5606,0x5702,0x580A,0x590E,
0x5A1E,0x5B1A,0x5C1E,0x5D1A,0x5E1A,0x5F1E,0x6026,0x6122,
0x6222,0x6326,0x6422,0x6526,0x6626,0x6722,0x682A,0x692E,
0x6A3E,0x6B3A,0x6C3E,0x6D3A,0x6E3A,0x6F3E,0x7022,0x7126,
0x7226,0x7322,0x7426,0x7522,0x7622,0x7726,0x782E,0x792A,
0x7A3A,0x7B3E,0x7C3A,0x7D3E,0x7E3E,0x7F3A,0x8082,0x8186,
0x8286,0x8382,0x8486,0x8582,0x8682,0x8786,0x888E,0x898A,
0x8A9A,0x8B9E,0x8C9A,0x8D9E,0x8E9E,0x8F9A,0x9086,0x9182,
0x9282,0x9386,0x3423,0x3527,0x3627,0x3723,0x382B,0x392F,
0x3A3F,0x3B3B,0x3C3F,0x3D3B,0x3E3B,0x3F3F,0x4003,0x4107,
0x4207,0x4303,0x4407,0x4503,0x4603,0x4707,0x480F,0x490B,
0x4A1B,0x4B1F,0x4C1B,0x4D1F,0x4E1F,0x4F1B,0x5007,0x5103,
0x5203,0x5307,0x5403,0x5507,0x5607,0x5703,0x580B,0x590F,
0x5A1F,0x5B1B,0x5C1F,0x5D1B,0x5E1B,0x5F1F,0x6027,0x6123,
0x6223,0x6327,0x6423,0x6527,0x6627,0x6723,0x682B,0x692F,
0x6A3F,0x6B3B,0x6C3F,0x6D3B,0x6E3B,0x6F3F,0x7023,0x7127,
0x7227,0x7323,0x7427,0x7523,0x7623,0x7727,0x782F,0x792B,
0x7A3B,0x7B3F,0x7C3B,0x7D3F,0x7E3F,0x7F3B,0x8083,0x8187,
0x8287,0x8383,0x8487,0x8583,0x8683,0x8787,0x888F,0x898B,
0x8A9B,0x8B9F,0x8C9B,0x8D9F,0x8E9F,0x8F9B,0x9087,0x9183,
0x9283,0x9387,0x9483,0x9587,0x9687,0x9783,0x988B,0x998F,
0x9A9F,0x9B9B,0x9C9F,0x9D9B,0x9E9B,0x9F9F,0xA0A7,0xA1A3,
0xA2A3,0xA3A7,0xA4A3,0xA5A7,0xA6A7,0xA7A3,0xA8AB,0xA9AF,
0xAABF,0xABBB,0xACBF,0xADBB,0xAEBB,0xAFBF,0xB0A3,0xB1A7,
0xB2A7,0xB3A3,0xB4A7,0xB5A3,0xB6A3,0xB7A7,0xB8AF,0xB9AB,
0xBABB,0xBBBF,0xBCBB,0xBDBF,0xBEBF,0xBFBB,0xC087,0xC183,
0xC283,0xC387,0xC483,0xC587,0xC687,0xC783,0xC88B,0xC98F,
0xCA9F,0xCB9B,0xCC9F,0xCD9B,0xCE9B,0xCF9F,0xD083,0xD187,
0xD287,0xD383,0xD487,0xD583,0xD683,0xD787,0xD88F,0xD98B,
0xDA9B,0xDB9F,0xDC9B,0xDD9F,0xDE9F,0xDF9B,0xE0A3,0xE1A7,
0xE2A7,0xE3A3,0xE4A7,0xE5A3,0xE6A3,0xE7A7,0xE8AF,0xE9AB,
0xEABB,0xEBBF,0xECBB,0xEDBF,0xEEBF,0xEFBB,0xF0A7,0xF1A3,
0xF2A3,0xF3A7,0xF4A3,0xF5A7,0xF6A7,0xF7A3,0xF8AB,0xF9AF,
0xFABF,0xFBBB,0xFCBF,0xFDBB,0xFEBB,0xFFBF,0x0047,0x0103,
0x0203,0x0307,0x0403,0x0507,0x0607,0x0703,0x080B,0x090F,
0x0A1F,0x0B1B,0x0C1F,0x0D1B,0x0E1B,0x0F1F,0x1003,0x1107,
0x1207,0x1303,0x1407,0x1503,0x1603,0x1707,0x180F,0x190B,
0x1A1B,0x1B1F,0x1C1B,0x1D1F,0x1E1F,0x1F1B,0x2023,0x2127,
0x2227,0x2323,0x2427,0x2523,0x2623,0x2727,0x282F,0x292B,
0x2A3B,0x2B3F,0x2C3B,0x2D3F,0x2E3F,0x2F3B,0x3027,0x3123,
0x3223,0x3327,0x3423,0x3527,0x3627,0x3723,0x382B,0x392F,
0x3A3F,0x3B3B,0x3C3F,0x3D3B,0x3E3B,0x3F3F,0x4003,0x4107,
0x4207,0x4303,0x4407,0x4503,0x4603,0x4707,0x480F,0x490B,
0x4A1B,0x4B1F,0x4C1B,0x4D1F,0x4E1F,0x4F1B,0x5007,0x5103,
0x5203,0x5307,0x5403,0x5507,0x5607,0x5703,0x580B,0x590F,
0x5A1F,0x5B1B,0x5C1F,0x5D1B,0x5E1B,0x5F1F,0x6027,0x6123,
0x6223,0x6327,0x6423,0x6527,0x6627,0x6723,0x682B,0x692F,
0x6A3F,0x6B3B,0x6C3F,0x6D3B,0x6E3B,0x6F3F,0x7023,0x7127,
0x7227,0x7323,0x7427,0x7523,0x7623,0x7727,0x782F,0x792B,
0x7A3B,0x7B3F,0x7C3B,0x7D3F,0x7E3F,0x7F3B,0x8083,0x8187,
0x8287,0x8383,0x8487,0x8583,0x8683,0x8787,0x888F,0x898B,
0x8A9B,0x8B9F,0x8C9B,0x8D9F,0x8E9F,0x8F9B,0x9087,0x9183,
0x9283,0x9387,0x9483,0x9587,0x9687,0x9783,0x988B,0x998F
};

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,38 @@
/** fMSX: portable MSX emulator ******************************/
/** **/
/** V9938.h **/
/** **/
/** This file contains declarations for V9938 special **/
/** graphical operations support implemented in V9938.c. **/
/** **/
/** Copyright (C) Marat Fayzullin 1994-2005 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
#ifndef V9938_H
#define V9938_H
#include "MSX.h"
/** VDPWrite() ***********************************************/
/** Use this function to transfer pixel(s) from CPU to VDP. **/
/*************************************************************/
void VDPWrite(register byte V);
/** VDPRead() ************************************************/
/** Use this function to transfer pixel(s) from VDP to CPU. **/
/*************************************************************/
byte VDPRead(void);
/** VDPDraw() ************************************************/
/** Perform a given V9938 graphical operation. **/
/*************************************************************/
byte VDPDraw(register byte Op);
/** LoopVDP() ************************************************/
/** Perform a number of steps of the active operation **/
/*************************************************************/
void LoopVDP(void);
#endif /* V9938_H */

Wyświetl plik

@ -0,0 +1,289 @@
/** EMULib Emulation Library *********************************/
/** **/
/** YM2413.c **/
/** **/
/** This file contains emulation for the OPLL sound chip **/
/** produced by Yamaha (also see OPL2, OPL3, OPL4 chips). **/
/** See YM2413.h for declarations. **/
/** **/
/** Copyright (C) Marat Fayzullin 1996-2005 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
#include "YM2413.h"
#include "Sound.h"
#include <string.h>
#include "arduinoproto.h"
/** Patches2413() ********************************************/
/** MIDI instruments corresponding to the OPLL patches. **/
/*************************************************************/
PROGMEM static const byte Patches2413[16] =
{
/*** OPLL ***/ /*** MIDI ***/
90, /* Original */ /* User (Polysynth) */
40, /* Violin */ /* Violin */
27, /* Guitar */ /* Electric Guitar (clean) */
1, /* Piano */ /* Bright Acoustic Piano */
73, /* Flute */ /* Flute */
71, /* Clarinet */ /* Clarinet */
68, /* Oboe */ /* Oboe */
56, /* Trumpet */ /* Trumpet */
20, /* Organ */ /* Reed Organ */
58, /* Horn */ /* Tuba */
50, /* Synthesizer */ /* Synth Strings 1 */
6, /* Harpsichord */ /* Harpsichord */
11, /* Vibraphone */ /* Vibraphone */
38, /* Synth Bass */ /* Synth Bass 1 */
34, /* Wood Bass */ /* Electric Bass (pick) */
33 /* Elec Guitar */ /* Electric Bass (finger) */
};
/** Drums2413() **********************************************/
/** MIDI instruments corresponding to the OPLL drums. **/
/*************************************************************/
PROGMEM static const byte Drums2413[5] =
{
/*** OPLL ***/ /*** MIDI ***/
42, /* High Hat */ /* Closed Hi Hat */
49, /* Top Cymbal */ /* Crash Cymbal 1 */
47, /* Tom-Tom */ /* Low-Mid Tom */
40, /* Snare Drum */ /* Electric Snare */
36 /* Bass Drum */ /* Bass Drum 1 */
};
/** Synth2413() **********************************************/
/** Synthesizer parameters corresponding to OPLL patches. **/
/*************************************************************/
PROGMEM static const byte Synth2413[19*16] =
{
0x49,0x4c,0x4c,0x32,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x61,0x61,0x1e,0x17,0xf0,0x7f,0x00,0x17,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x13,0x41,0x16,0x0e,0xfd,0xf4,0x23,0x23,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x03,0x01,0x9a,0x04,0xf3,0xf3,0x13,0xf3,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x11,0x61,0x0e,0x07,0xfa,0x64,0x70,0x17,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x22,0x21,0x1e,0x06,0xf0,0x76,0x00,0x28,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x21,0x22,0x16,0x05,0xf0,0x71,0x00,0x18,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x21,0x61,0x1d,0x07,0x82,0x80,0x17,0x17,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x23,0x21,0x2d,0x16,0x90,0x90,0x00,0x07,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x21,0x21,0x1b,0x06,0x64,0x65,0x10,0x17,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x21,0x21,0x0b,0x1a,0x85,0xa0,0x70,0x07,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x23,0x01,0x83,0x10,0xff,0xb4,0x10,0xf4,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x97,0xc1,0x20,0x07,0xff,0xf4,0x22,0x22,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x61,0x00,0x0c,0x05,0xc2,0xf6,0x40,0x44,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x01,0x56,0x03,0x94,0xc2,0x03,0x12,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x21,0x01,0x89,0x03,0xf1,0xe4,0xf0,0x23,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x07,0x21,0x14,0x00,0xee,0xf8,0xff,0xf8,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x31,0x00,0x00,0xf8,0xf7,0xf8,0xf7,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x25,0x11,0x00,0x00,0xf8,0xfa,0xf8,0x55,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
/** Reset2413() **********************************************/
/** Reset the sound chip and use sound channels from the **/
/** one given in First. **/
/*************************************************************/
void Reset2413(register YM2413 *D,int First)
{
int J;
/* All registers filled with 0x00 by default */
memset(D->R,0x00,sizeof(D->R));
/* Set initial frequencies, volumes, and instruments */
for(J=0;J<YM2413_CHANNELS;J++)
{
SetSound(J+First,SND_MELODIC);
D->Freq[J] = 0;
D->Volume[J] = 0;
D->R[J+0x30] = 0x0F;
}
D->First = First;
D->Sync = YM2413_ASYNC;
D->Changed = 0x000;
D->PChanged = 0x000;
D->DChanged = 0x000;
D->Latch = 0;
}
/** WrCtrl2413() *********************************************/
/** Write a value V to the OPLL Control Port. **/
/*************************************************************/
void WrCtrl2413(register YM2413 *D,register byte V)
{
D->Latch=V&0x3F;
}
/** WrData2413() *********************************************/
/** Write a value V to the OPLL Data Port. **/
/*************************************************************/
void WrData2413(register YM2413 *D,register byte V)
{
Write2413(D,D->Latch,V);
}
/** Write2413() **********************************************/
/** Call this function to output a value V into the sound **/
/** chip. **/
/*************************************************************/
void Write2413(register YM2413 *D,register byte R,register byte V)
{
register byte C,Oct;
register int Frq;
/* OPLL registers are 0..63 */
R&=0x3F;
/* Lowest 4 bits are channel number */
C=R&0x0F;
switch(R>>4)
{
case 0:
switch(C)
{
case 0x0E:
if(V==D->R[R]) return;
/* Keep all drums off when drum mode is off */
if(!(V&0x20)) V&=0xE0;
/* Mark all activated drums as changed */
D->DChanged|=(V^D->R[R])&0x1F;
/* If drum mode was turned on... */
if((V^D->R[R])&V&0x20)
{
/* Turn off melodic channels 6,7,8 */
D->Freq[6]=D->Freq[7]=D->Freq[8]=0;
/* Mark channels 6,7,8 as changed */
D->Changed|=0x1C0;
}
/* Done */
break;
}
break;
case 1:
if((C>8)||(V==D->R[R])) return;
if(!YM2413_DRUMS(D)||(C<6))
if(D->R[R+0x10]&0x10)
{
/* Set channel frequency */
Oct=D->R[R+0x10];
Frq=((int)(Oct&0x01)<<8)+V;
Oct=(Oct&0x0E)>>1;
D->Freq[C]=(3125*Frq*(1<<Oct))>>15;
/* Mark channel as changed */
D->Changed|=1<<C;
}
/* Done */
break;
case 2:
if(C>8) return;
if(!YM2413_DRUMS(D)||(C<6))
{
/* Depending on whether channel is on/off... */
if(!(V&0x10)) D->Freq[C]=0;
else
{
/* Set channel frequency */
Frq=((int)(V&0x01)<<8)+D->R[R-0x10];
Oct=(V&0x0E)>>1;
D->Freq[C]=(3125*Frq*(1<<Oct))>>15;
}
/* Mark channel as changed */
D->Changed|=1<<C;
}
/* Done */
break;
case 3:
if((C>8)||(V==D->R[R])) return;
/* Register any patch changes */
if((V^D->R[R])&0xF0) D->PChanged|=1<<C;
/* Register any volume changes */
if((V^D->R[R])&0x0F)
{
/* Set channel volume */
D->Volume[C]=255*(~V&0x0F)/15;
/* Mark channel as changed */
D->Changed|=1<<C;
}
/* Register drum volume changes */
if(YM2413_DRUMS(D))
switch(C)
{
case 6: D->DChanged|=0x10&D->R[0x0E];break;
case 7: D->DChanged|=0x09&D->R[0x0E];break;
case 8: D->DChanged|=0x06&D->R[0x0E];break;
}
/* Done */
break;
}
/* Write value into the register */
D->R[R]=V;
/* For asynchronous mode, make Sound() calls right away */
if(!D->Sync&&(D->Changed||D->PChanged||D->DChanged))
Sync2413(D,YM2413_FLUSH);
}
/** Sync2413() ***********************************************/
/** Flush all accumulated changes by issuing Sound() calls **/
/** and set the synchronization on/off. The second argument **/
/** should be YM2413_SYNC/YM2413_ASYNC to set/reset sync, **/
/** or YM2413_FLUSH to leave sync mode as it is. **/
/*************************************************************/
void Sync2413(register YM2413 *D,register byte Sync)
{
register int J,I;
/* Change sync mode as requested */
if(Sync!=YM2413_FLUSH) D->Sync=Sync;
/* Convert channel instrument changes into SetSound() calls */
for(J=0,I=D->PChanged;I&&(J<YM2413_CHANNELS);J++,I>>=1)
if(I&1) SetSound(J+D->First,SND_MIDI|Patches2413[D->R[J+0x30]>>4]);
/* Convert channel freq/volume changes into Sound() calls */
for(J=0,I=D->Changed;I&&(J<YM2413_CHANNELS);J++,I>>=1)
if(I&1) Sound(J+D->First,D->Freq[J],D->Volume[J]);
/* If there were any changes to the drums... */
I=D->DChanged;
J=D->R[0x0E];
if(I)
{
/* Turn drums on/off as requested */
if(I&0x01) Drum(DRM_MIDI|Drums2413[0],J&0x01? 255*(D->R[0x37]>>4)/15:0);
if(I&0x02) Drum(DRM_MIDI|Drums2413[1],J&0x02? 255*(D->R[0x38]&0x0F)/15:0);
if(I&0x04) Drum(DRM_MIDI|Drums2413[2],J&0x04? 255*(D->R[0x38]>>4)/15:0);
if(I&0x08) Drum(DRM_MIDI|Drums2413[3],J&0x08? 255*(D->R[0x37]&0x0F)/15:0);
if(I&0x10) Drum(DRM_MIDI|Drums2413[4],J&0x10? 255*(D->R[0x36]&0x0F)/15:0);
}
D->Changed=D->PChanged=D->DChanged=0x000;
}

Wyświetl plik

@ -0,0 +1,77 @@
/** EMULib Emulation Library *********************************/
/** **/
/** YM2413.h **/
/** **/
/** This file contains emulation for the OPLL sound chip **/
/** produced by Yamaha (also see OPL2, OPL3, OPL4 chips). **/
/** See YM2413.h for the code. **/
/** **/
/** Copyright (C) Marat Fayzullin 1996-2005 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
#ifndef YM2413_H
#define YM2413_H
#define YM2413_BASE 3125 /* Base frequency for OPLL */
#define YM2413_CHANNELS 9 /* 9 melodic channels */
#define YM2413_ASYNC 0 /* Asynchronous emulation */
#define YM2413_SYNC 1 /* Synchronous emulation mode */
#define YM2413_FLUSH 2 /* Flush buffers only */
#define YM2413_DRUMS(D) ((D)->R[0x0E]&0x20)
#ifndef BYTE_TYPE_DEFINED
#define BYTE_TYPE_DEFINED
typedef unsigned char byte;
#endif
/** YM2413 ***************************************************/
/** This data structure stores OPLL state. **/
/*************************************************************/
typedef struct
{
byte R[64]; /* OPLL register contents */
int Freq[YM2413_CHANNELS]; /* Frequencies (0 for off) */
int Volume[YM2413_CHANNELS]; /* Volumes (0..255) */
int First; /* First used Sound() channel */
int Changed; /* Bitmap of changed channels */
int PChanged; /* Bitmap of changed patches */
int DChanged; /* Bitmap of changed drums */
byte Sync; /* YM2413_SYNC/YM2413_ASYNC */
byte Latch; /* Latch for the register num */
} YM2413;
/** Reset2413() **********************************************/
/** Reset the sound chip and use sound channels from the **/
/** one given in First. **/
/*************************************************************/
void Reset2413(register YM2413 *D,int First);
/** WrCtrl2413() *********************************************/
/** Write a value V to the OPLL Control Port. **/
/*************************************************************/
void WrCtrl2413(register YM2413 *D,register byte V);
/** WrData2413() *********************************************/
/** Write a value V to the OPLL Data Port. **/
/*************************************************************/
void WrData2413(register YM2413 *D,register byte V);
/** Write2413() **********************************************/
/** Call this function to output a value V into given OPLL **/
/** register R. **/
/*************************************************************/
void Write2413(register YM2413 *D,register byte R,register byte V);
/** Sync2413() ***********************************************/
/** Flush all accumulated changes by issuing Sound() calls **/
/** and set the synchronization on/off. The second argument **/
/** should be YM2413_SYNC/YM2413_ASYNC to set/reset sync, **/
/** or YM2413_FLUSH to leave sync mode as it is. **/
/*************************************************************/
void Sync2413(register YM2413 *D,register byte Sync);
#endif /* YM2413_H */

Wyświetl plik

@ -0,0 +1,631 @@
/** Z80: portable Z80 emulator *******************************/
/** **/
/** Z80.c **/
/** **/
/** This file contains implementation for Z80 CPU. Don't **/
/** forget to provide RdZ80(), WrZ80(), InZ80(), OutZ80(), **/
/** LoopZ80(), and PatchZ80() functions to accomodate the **/
/** emulated machine's architecture. **/
/** **/
/** Copyright (C) Marat Fayzullin 1994-2005 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
#include "shared.h" // For endianess!!!
#include "Z80.h"
#include "Tables.h"
#include <stdio.h>
/** INLINE ***************************************************/
/** Different compilers inline C functions differently. **/
/*************************************************************/
#ifdef __GNUC__
#define INLINE inline
#else
#define INLINE static
#endif
/** System-Dependent Stuff ***********************************/
/** This is system-dependent code put here to speed things **/
/** up. It has to stay inlined to be fast. **/
/*************************************************************/
#ifdef COLEM
extern byte *Page[];
INLINE byte RdZ80(word A) { return(Page[A>>15][A&0x7FFF]); }
#endif
#ifdef MG
extern byte *Page[];
INLINE byte RdZ80(word A) { return(Page[A>>13][A&0x1FFF]); }
#endif
#ifdef FMSX
extern byte *RAM[],PSL[],SSLReg;
INLINE byte RdZ80(word A)
{
if(A!=0xFFFF) return(RAM[A>>13][A&0x1FFF]);
else return((PSL[3]==3)? ~SSLReg:RAM[7][0x1FFF]);
}
#endif
#define S(Fl) R->AF.B.l|=Fl
#define R(Fl) R->AF.B.l&=~(Fl)
#define FLAGS(Rg,Fl) R->AF.B.l=Fl|ZSTable[Rg]
#define M_RLC(Rg) \
R->AF.B.l=Rg>>7;Rg=(Rg<<1)|R->AF.B.l;R->AF.B.l|=PZSTable[Rg]
#define M_RRC(Rg) \
R->AF.B.l=Rg&0x01;Rg=(Rg>>1)|(R->AF.B.l<<7);R->AF.B.l|=PZSTable[Rg]
#define M_RL(Rg) \
if(Rg&0x80) \
{ \
Rg=(Rg<<1)|(R->AF.B.l&C_FLAG); \
R->AF.B.l=PZSTable[Rg]|C_FLAG; \
} \
else \
{ \
Rg=(Rg<<1)|(R->AF.B.l&C_FLAG); \
R->AF.B.l=PZSTable[Rg]; \
}
#define M_RR(Rg) \
if(Rg&0x01) \
{ \
Rg=(Rg>>1)|(R->AF.B.l<<7); \
R->AF.B.l=PZSTable[Rg]|C_FLAG; \
} \
else \
{ \
Rg=(Rg>>1)|(R->AF.B.l<<7); \
R->AF.B.l=PZSTable[Rg]; \
}
#define M_SLA(Rg) \
R->AF.B.l=Rg>>7;Rg<<=1;R->AF.B.l|=PZSTable[Rg]
#define M_SRA(Rg) \
R->AF.B.l=Rg&C_FLAG;Rg=(Rg>>1)|(Rg&0x80);R->AF.B.l|=PZSTable[Rg]
#define M_SLL(Rg) \
R->AF.B.l=Rg>>7;Rg=(Rg<<1)|0x01;R->AF.B.l|=PZSTable[Rg]
#define M_SRL(Rg) \
R->AF.B.l=Rg&0x01;Rg>>=1;R->AF.B.l|=PZSTable[Rg]
#define M_BIT(Bit,Rg) \
R->AF.B.l=(R->AF.B.l&C_FLAG)|H_FLAG|PZSTable[Rg&(1<<Bit)]
#define M_SET(Bit,Rg) Rg|=1<<Bit
#define M_RES(Bit,Rg) Rg&=~(1<<Bit)
#define M_POP(Rg) \
R->Rg.B.l=RdZ80(R->SP.W++);R->Rg.B.h=RdZ80(R->SP.W++)
#define M_PUSH(Rg) \
WrZ80(--R->SP.W,R->Rg.B.h);WrZ80(--R->SP.W,R->Rg.B.l)
#define M_CALL \
J.B.l=RdZ80(R->PC.W++);J.B.h=RdZ80(R->PC.W++); \
WrZ80(--R->SP.W,R->PC.B.h);WrZ80(--R->SP.W,R->PC.B.l); \
R->PC.W=J.W
#define M_JP J.B.l=RdZ80(R->PC.W++);J.B.h=RdZ80(R->PC.W);R->PC.W=J.W
#define M_JR R->PC.W+=(offset)RdZ80(R->PC.W)+1
#define M_RET R->PC.B.l=RdZ80(R->SP.W++);R->PC.B.h=RdZ80(R->SP.W++)
#define M_RST(Ad) \
WrZ80(--R->SP.W,R->PC.B.h);WrZ80(--R->SP.W,R->PC.B.l);R->PC.W=Ad
#define M_LDWORD(Rg) \
R->Rg.B.l=RdZ80(R->PC.W++);R->Rg.B.h=RdZ80(R->PC.W++)
#define M_ADD(Rg) \
J.W=R->AF.B.h+Rg; \
R->AF.B.l= \
(~(R->AF.B.h^Rg)&(Rg^J.B.l)&0x80? V_FLAG:0)| \
J.B.h|ZSTable[J.B.l]| \
((R->AF.B.h^Rg^J.B.l)&H_FLAG); \
R->AF.B.h=J.B.l
#define M_SUB(Rg) \
J.W=R->AF.B.h-Rg; \
R->AF.B.l= \
((R->AF.B.h^Rg)&(R->AF.B.h^J.B.l)&0x80? V_FLAG:0)| \
N_FLAG|-J.B.h|ZSTable[J.B.l]| \
((R->AF.B.h^Rg^J.B.l)&H_FLAG); \
R->AF.B.h=J.B.l
#define M_ADC(Rg) \
J.W=R->AF.B.h+Rg+(R->AF.B.l&C_FLAG); \
R->AF.B.l= \
(~(R->AF.B.h^Rg)&(Rg^J.B.l)&0x80? V_FLAG:0)| \
J.B.h|ZSTable[J.B.l]| \
((R->AF.B.h^Rg^J.B.l)&H_FLAG); \
R->AF.B.h=J.B.l
#define M_SBC(Rg) \
J.W=R->AF.B.h-Rg-(R->AF.B.l&C_FLAG); \
R->AF.B.l= \
((R->AF.B.h^Rg)&(R->AF.B.h^J.B.l)&0x80? V_FLAG:0)| \
N_FLAG|-J.B.h|ZSTable[J.B.l]| \
((R->AF.B.h^Rg^J.B.l)&H_FLAG); \
R->AF.B.h=J.B.l
#define M_CP(Rg) \
J.W=R->AF.B.h-Rg; \
R->AF.B.l= \
((R->AF.B.h^Rg)&(R->AF.B.h^J.B.l)&0x80? V_FLAG:0)| \
N_FLAG|-J.B.h|ZSTable[J.B.l]| \
((R->AF.B.h^Rg^J.B.l)&H_FLAG)
#define M_AND(Rg) R->AF.B.h&=Rg;R->AF.B.l=H_FLAG|PZSTable[R->AF.B.h]
#define M_OR(Rg) R->AF.B.h|=Rg;R->AF.B.l=PZSTable[R->AF.B.h]
#define M_XOR(Rg) R->AF.B.h^=Rg;R->AF.B.l=PZSTable[R->AF.B.h]
#define M_IN(Rg) \
Rg=InZ80(R->BC.B.l); \
R->AF.B.l=PZSTable[Rg]|(R->AF.B.l&C_FLAG)
#define M_INC(Rg) \
Rg++; \
R->AF.B.l= \
(R->AF.B.l&C_FLAG)|ZSTable[Rg]| \
(Rg==0x80? V_FLAG:0)|(Rg&0x0F? 0:H_FLAG)
#define M_DEC(Rg) \
Rg--; \
R->AF.B.l= \
N_FLAG|(R->AF.B.l&C_FLAG)|ZSTable[Rg]| \
(Rg==0x7F? V_FLAG:0)|((Rg&0x0F)==0x0F? H_FLAG:0)
#define M_ADDW(Rg1,Rg2) \
J.W=(R->Rg1.W+R->Rg2.W)&0xFFFF; \
R->AF.B.l= \
(R->AF.B.l&~(H_FLAG|N_FLAG|C_FLAG))| \
((R->Rg1.W^R->Rg2.W^J.W)&0x1000? H_FLAG:0)| \
(((long)R->Rg1.W+(long)R->Rg2.W)&0x10000? C_FLAG:0); \
R->Rg1.W=J.W
#define M_ADCW(Rg) \
I=R->AF.B.l&C_FLAG;J.W=(R->HL.W+R->Rg.W+I)&0xFFFF; \
R->AF.B.l= \
(((long)R->HL.W+(long)R->Rg.W+(long)I)&0x10000? C_FLAG:0)| \
(~(R->HL.W^R->Rg.W)&(R->Rg.W^J.W)&0x8000? V_FLAG:0)| \
((R->HL.W^R->Rg.W^J.W)&0x1000? H_FLAG:0)| \
(J.W? 0:Z_FLAG)|(J.B.h&S_FLAG); \
R->HL.W=J.W
#define M_SBCW(Rg) \
I=R->AF.B.l&C_FLAG;J.W=(R->HL.W-R->Rg.W-I)&0xFFFF; \
R->AF.B.l= \
N_FLAG| \
(((long)R->HL.W-(long)R->Rg.W-(long)I)&0x10000? C_FLAG:0)| \
((R->HL.W^R->Rg.W)&(R->HL.W^J.W)&0x8000? V_FLAG:0)| \
((R->HL.W^R->Rg.W^J.W)&0x1000? H_FLAG:0)| \
(J.W? 0:Z_FLAG)|(J.B.h&S_FLAG); \
R->HL.W=J.W
enum Codes
{
NOP,LD_BC_WORD,LD_xBC_A,INC_BC,INC_B,DEC_B,LD_B_BYTE,RLCA,
EX_AF_AF,ADD_HL_BC,LD_A_xBC,DEC_BC,INC_C,DEC_C,LD_C_BYTE,RRCA,
DJNZ,LD_DE_WORD,LD_xDE_A,INC_DE,INC_D,DEC_D,LD_D_BYTE,RLA,
JR,ADD_HL_DE,LD_A_xDE,DEC_DE,INC_E,DEC_E,LD_E_BYTE,RRA,
JR_NZ,LD_HL_WORD,LD_xWORD_HL,INC_HL,INC_H,DEC_H,LD_H_BYTE,DAA,
JR_Z,ADD_HL_HL,LD_HL_xWORD,DEC_HL,INC_L,DEC_L,LD_L_BYTE,CPL,
JR_NC,LD_SP_WORD,LD_xWORD_A,INC_SP,INC_xHL,DEC_xHL,LD_xHL_BYTE,SCF,
JR_C,ADD_HL_SP,LD_A_xWORD,DEC_SP,INC_A,DEC_A,LD_A_BYTE,CCF,
LD_B_B,LD_B_C,LD_B_D,LD_B_E,LD_B_H,LD_B_L,LD_B_xHL,LD_B_A,
LD_C_B,LD_C_C,LD_C_D,LD_C_E,LD_C_H,LD_C_L,LD_C_xHL,LD_C_A,
LD_D_B,LD_D_C,LD_D_D,LD_D_E,LD_D_H,LD_D_L,LD_D_xHL,LD_D_A,
LD_E_B,LD_E_C,LD_E_D,LD_E_E,LD_E_H,LD_E_L,LD_E_xHL,LD_E_A,
LD_H_B,LD_H_C,LD_H_D,LD_H_E,LD_H_H,LD_H_L,LD_H_xHL,LD_H_A,
LD_L_B,LD_L_C,LD_L_D,LD_L_E,LD_L_H,LD_L_L,LD_L_xHL,LD_L_A,
LD_xHL_B,LD_xHL_C,LD_xHL_D,LD_xHL_E,LD_xHL_H,LD_xHL_L,HALT,LD_xHL_A,
LD_A_B,LD_A_C,LD_A_D,LD_A_E,LD_A_H,LD_A_L,LD_A_xHL,LD_A_A,
ADD_B,ADD_C,ADD_D,ADD_E,ADD_H,ADD_L,ADD_xHL,ADD_A,
ADC_B,ADC_C,ADC_D,ADC_E,ADC_H,ADC_L,ADC_xHL,ADC_A,
SUB_B,SUB_C,SUB_D,SUB_E,SUB_H,SUB_L,SUB_xHL,SUB_A,
SBC_B,SBC_C,SBC_D,SBC_E,SBC_H,SBC_L,SBC_xHL,SBC_A,
AND_B,AND_C,AND_D,AND_E,AND_H,AND_L,AND_xHL,AND_A,
XOR_B,XOR_C,XOR_D,XOR_E,XOR_H,XOR_L,XOR_xHL,XOR_A,
OR_B,OR_C,OR_D,OR_E,OR_H,OR_L,OR_xHL,OR_A,
CP_B,CP_C,CP_D,CP_E,CP_H,CP_L,CP_xHL,CP_A,
RET_NZ,POP_BC,JP_NZ,JP,CALL_NZ,PUSH_BC,ADD_BYTE,RST00,
RET_Z,RET,JP_Z,PFX_CB,CALL_Z,CALL,ADC_BYTE,RST08,
RET_NC,POP_DE,JP_NC,OUTA,CALL_NC,PUSH_DE,SUB_BYTE,RST10,
RET_C,EXX,JP_C,INA,CALL_C,PFX_DD,SBC_BYTE,RST18,
RET_PO,POP_HL,JP_PO,EX_HL_xSP,CALL_PO,PUSH_HL,AND_BYTE,RST20,
RET_PE,LD_PC_HL,JP_PE,EX_DE_HL,CALL_PE,PFX_ED,XOR_BYTE,RST28,
RET_P,POP_AF,JP_P,DI,CALL_P,PUSH_AF,OR_BYTE,RST30,
RET_M,LD_SP_HL,JP_M,EI,CALL_M,PFX_FD,CP_BYTE,RST38
};
enum CodesCB
{
RLC_B,RLC_C,RLC_D,RLC_E,RLC_H,RLC_L,RLC_xHL,RLC_A,
RRC_B,RRC_C,RRC_D,RRC_E,RRC_H,RRC_L,RRC_xHL,RRC_A,
RL_B,RL_C,RL_D,RL_E,RL_H,RL_L,RL_xHL,RL_A,
RR_B,RR_C,RR_D,RR_E,RR_H,RR_L,RR_xHL,RR_A,
SLA_B,SLA_C,SLA_D,SLA_E,SLA_H,SLA_L,SLA_xHL,SLA_A,
SRA_B,SRA_C,SRA_D,SRA_E,SRA_H,SRA_L,SRA_xHL,SRA_A,
SLL_B,SLL_C,SLL_D,SLL_E,SLL_H,SLL_L,SLL_xHL,SLL_A,
SRL_B,SRL_C,SRL_D,SRL_E,SRL_H,SRL_L,SRL_xHL,SRL_A,
BIT0_B,BIT0_C,BIT0_D,BIT0_E,BIT0_H,BIT0_L,BIT0_xHL,BIT0_A,
BIT1_B,BIT1_C,BIT1_D,BIT1_E,BIT1_H,BIT1_L,BIT1_xHL,BIT1_A,
BIT2_B,BIT2_C,BIT2_D,BIT2_E,BIT2_H,BIT2_L,BIT2_xHL,BIT2_A,
BIT3_B,BIT3_C,BIT3_D,BIT3_E,BIT3_H,BIT3_L,BIT3_xHL,BIT3_A,
BIT4_B,BIT4_C,BIT4_D,BIT4_E,BIT4_H,BIT4_L,BIT4_xHL,BIT4_A,
BIT5_B,BIT5_C,BIT5_D,BIT5_E,BIT5_H,BIT5_L,BIT5_xHL,BIT5_A,
BIT6_B,BIT6_C,BIT6_D,BIT6_E,BIT6_H,BIT6_L,BIT6_xHL,BIT6_A,
BIT7_B,BIT7_C,BIT7_D,BIT7_E,BIT7_H,BIT7_L,BIT7_xHL,BIT7_A,
RES0_B,RES0_C,RES0_D,RES0_E,RES0_H,RES0_L,RES0_xHL,RES0_A,
RES1_B,RES1_C,RES1_D,RES1_E,RES1_H,RES1_L,RES1_xHL,RES1_A,
RES2_B,RES2_C,RES2_D,RES2_E,RES2_H,RES2_L,RES2_xHL,RES2_A,
RES3_B,RES3_C,RES3_D,RES3_E,RES3_H,RES3_L,RES3_xHL,RES3_A,
RES4_B,RES4_C,RES4_D,RES4_E,RES4_H,RES4_L,RES4_xHL,RES4_A,
RES5_B,RES5_C,RES5_D,RES5_E,RES5_H,RES5_L,RES5_xHL,RES5_A,
RES6_B,RES6_C,RES6_D,RES6_E,RES6_H,RES6_L,RES6_xHL,RES6_A,
RES7_B,RES7_C,RES7_D,RES7_E,RES7_H,RES7_L,RES7_xHL,RES7_A,
SET0_B,SET0_C,SET0_D,SET0_E,SET0_H,SET0_L,SET0_xHL,SET0_A,
SET1_B,SET1_C,SET1_D,SET1_E,SET1_H,SET1_L,SET1_xHL,SET1_A,
SET2_B,SET2_C,SET2_D,SET2_E,SET2_H,SET2_L,SET2_xHL,SET2_A,
SET3_B,SET3_C,SET3_D,SET3_E,SET3_H,SET3_L,SET3_xHL,SET3_A,
SET4_B,SET4_C,SET4_D,SET4_E,SET4_H,SET4_L,SET4_xHL,SET4_A,
SET5_B,SET5_C,SET5_D,SET5_E,SET5_H,SET5_L,SET5_xHL,SET5_A,
SET6_B,SET6_C,SET6_D,SET6_E,SET6_H,SET6_L,SET6_xHL,SET6_A,
SET7_B,SET7_C,SET7_D,SET7_E,SET7_H,SET7_L,SET7_xHL,SET7_A
};
enum CodesED
{
DB_00,DB_01,DB_02,DB_03,DB_04,DB_05,DB_06,DB_07,
DB_08,DB_09,DB_0A,DB_0B,DB_0C,DB_0D,DB_0E,DB_0F,
DB_10,DB_11,DB_12,DB_13,DB_14,DB_15,DB_16,DB_17,
DB_18,DB_19,DB_1A,DB_1B,DB_1C,DB_1D,DB_1E,DB_1F,
DB_20,DB_21,DB_22,DB_23,DB_24,DB_25,DB_26,DB_27,
DB_28,DB_29,DB_2A,DB_2B,DB_2C,DB_2D,DB_2E,DB_2F,
DB_30,DB_31,DB_32,DB_33,DB_34,DB_35,DB_36,DB_37,
DB_38,DB_39,DB_3A,DB_3B,DB_3C,DB_3D,DB_3E,DB_3F,
IN_B_xC,OUT_xC_B,SBC_HL_BC,LD_xWORDe_BC,NEG,RETN,IM_0,LD_I_A,
IN_C_xC,OUT_xC_C,ADC_HL_BC,LD_BC_xWORDe,DB_4C,RETI,DB_,LD_R_A,
IN_D_xC,OUT_xC_D,SBC_HL_DE,LD_xWORDe_DE,DB_54,DB_55,IM_1,LD_A_I,
IN_E_xC,OUT_xC_E,ADC_HL_DE,LD_DE_xWORDe,DB_5C,DB_5D,IM_2,LD_A_R,
IN_H_xC,OUT_xC_H,SBC_HL_HL,LD_xWORDe_HL,DB_64,DB_65,DB_66,RRD,
IN_L_xC,OUT_xC_L,ADC_HL_HL,LD_HL_xWORDe,DB_6C,DB_6D,DB_6E,RLD,
IN_F_xC,DB_71,SBC_HL_SP,LD_xWORDe_SP,DB_74,DB_75,DB_76,DB_77,
IN_A_xC,OUT_xC_A,ADC_HL_SP,LD_SP_xWORDe,DB_7C,DB_7D,DB_7E,DB_7F,
DB_80,DB_81,DB_82,DB_83,DB_84,DB_85,DB_86,DB_87,
DB_88,DB_89,DB_8A,DB_8B,DB_8C,DB_8D,DB_8E,DB_8F,
DB_90,DB_91,DB_92,DB_93,DB_94,DB_95,DB_96,DB_97,
DB_98,DB_99,DB_9A,DB_9B,DB_9C,DB_9D,DB_9E,DB_9F,
LDI,CPI,INI,OUTI,DB_A4,DB_A5,DB_A6,DB_A7,
LDD,CPD,IND,OUTD,DB_AC,DB_AD,DB_AE,DB_AF,
LDIR,CPIR,INIR,OTIR,DB_B4,DB_B5,DB_B6,DB_B7,
LDDR,CPDR,INDR,OTDR,DB_BC,DB_BD,DB_BE,DB_BF,
DB_C0,DB_C1,DB_C2,DB_C3,DB_C4,DB_C5,DB_C6,DB_C7,
DB_C8,DB_C9,DB_CA,DB_CB,DB_CC,DB_CD,DB_CE,DB_CF,
DB_D0,DB_D1,DB_D2,DB_D3,DB_D4,DB_D5,DB_D6,DB_D7,
DB_D8,DB_D9,DB_DA,DB_DB,DB_DC,DB_DD,DB_DE,DB_DF,
DB_E0,DB_E1,DB_E2,DB_E3,DB_E4,DB_E5,DB_E6,DB_E7,
DB_E8,DB_E9,DB_EA,DB_EB,DB_EC,DB_ED,DB_EE,DB_EF,
DB_F0,DB_F1,DB_F2,DB_F3,DB_F4,DB_F5,DB_F6,DB_F7,
DB_F8,DB_F9,DB_FA,DB_FB,DB_FC,DB_FD,DB_FE,DB_FF
};
static void CodesCB(register Z80 *R)
{
register byte I;
I=RdZ80(R->PC.W++);
R->ICount-=CyclesCB[I];
switch(I)
{
#include "CodesCB.h"
default:
if(R->TrapBadOps)
printf
(
"[Z80 %lX] Unrecognized instruction: CB %02X at PC=%04X\n",
(long)(R->User),RdZ80(R->PC.W-1),R->PC.W-2
);
}
}
static void CodesDDCB(register Z80 *R)
{
register pair J;
register byte I;
#define XX IX
J.W=R->XX.W+(offset)RdZ80(R->PC.W++);
I=RdZ80(R->PC.W++);
R->ICount-=CyclesXXCB[I];
switch(I)
{
#include "CodesXCB.h"
default:
if(R->TrapBadOps)
printf
(
"[Z80 %lX] Unrecognized instruction: DD CB %02X %02X at PC=%04X\n",
(long)(R->User),RdZ80(R->PC.W-2),RdZ80(R->PC.W-1),R->PC.W-4
);
}
#undef XX
}
static void CodesFDCB(register Z80 *R)
{
register pair J;
register byte I;
#define XX IY
J.W=R->XX.W+(offset)RdZ80(R->PC.W++);
I=RdZ80(R->PC.W++);
R->ICount-=CyclesXXCB[I];
switch(I)
{
#include "CodesXCB.h"
default:
if(R->TrapBadOps)
printf
(
"[Z80 %lX] Unrecognized instruction: FD CB %02X %02X at PC=%04X\n",
(long)R->User,RdZ80(R->PC.W-2),RdZ80(R->PC.W-1),R->PC.W-4
);
}
#undef XX
}
static void CodesED(register Z80 *R)
{
register byte I;
register pair J;
I=RdZ80(R->PC.W++);
R->ICount-=CyclesED[I];
switch(I)
{
#include "CodesED.h"
case PFX_ED:
R->PC.W--;break;
default:
if(R->TrapBadOps)
printf
(
"[Z80 %lX] Unrecognized instruction: ED %02X at PC=%04X\n",
(long)R->User,RdZ80(R->PC.W-1),R->PC.W-2
);
}
}
static void CodesDD(register Z80 *R)
{
register byte I;
register pair J;
#define XX IX
I=RdZ80(R->PC.W++);
R->ICount-=CyclesXX[I];
switch(I)
{
#include "CodesXX.h"
case PFX_FD:
case PFX_DD:
R->PC.W--;break;
case PFX_CB:
CodesDDCB(R);break;
default:
if(R->TrapBadOps)
printf
(
"[Z80 %lX] Unrecognized instruction: DD %02X at PC=%04X\n",
(long)R->User,RdZ80(R->PC.W-1),R->PC.W-2
);
}
#undef XX
}
static void CodesFD(register Z80 *R)
{
register byte I;
register pair J;
#define XX IY
I=RdZ80(R->PC.W++);
R->ICount-=CyclesXX[I];
switch(I)
{
#include "CodesXX.h"
case PFX_FD:
case PFX_DD:
R->PC.W--;break;
case PFX_CB:
CodesFDCB(R);break;
default:
printf
(
"Unrecognized instruction: FD %02X at PC=%04X\n",
RdZ80(R->PC.W-1),R->PC.W-2
);
}
#undef XX
}
/** ResetZ80() ***********************************************/
/** This function can be used to reset the register struct **/
/** before starting execution with Z80(). It sets the **/
/** registers to their supposed initial values. **/
/*************************************************************/
void ResetZ80(Z80 *R)
{
R->PC.W = 0x0000;
R->SP.W = 0xF000;
R->AF.W = 0x0000;
R->BC.W = 0x0000;
R->DE.W = 0x0000;
R->HL.W = 0x0000;
R->AF1.W = 0x0000;
R->BC1.W = 0x0000;
R->DE1.W = 0x0000;
R->HL1.W = 0x0000;
R->IX.W = 0x0000;
R->IY.W = 0x0000;
R->I = 0x00;
R->IFF = 0x00;
R->ICount = R->IPeriod;
R->IRequest = INT_NONE;
}
/** ExecZ80() ************************************************/
/** This function will execute a single Z80 opcode. It will **/
/** then return next PC, and current register values in R. **/
/*************************************************************/
word ExecZ80(Z80 *R)
{
register byte I;
register pair J;
I=RdZ80(R->PC.W++);
R->ICount-=Cycles[I];
switch(I)
{
#include "Codes.h"
case PFX_CB: CodesCB(R);break;
case PFX_ED: CodesED(R);break;
case PFX_FD: CodesFD(R);break;
case PFX_DD: CodesDD(R);break;
}
/* We are done */
return(R->PC.W);
}
/** IntZ80() *************************************************/
/** This function will generate interrupt of given vector. **/
/*************************************************************/
void IntZ80(Z80 *R,word Vector)
{
if((R->IFF&IFF_1)||(Vector==INT_NMI))
{
/* If HALTed, take CPU off HALT instruction */
if(R->IFF&IFF_HALT) { R->PC.W++;R->IFF&=~IFF_HALT; }
/* Save PC on stack */
M_PUSH(PC);
/* Automatically reset IRequest if needed */
if(R->IAutoReset&&(Vector==R->IRequest)) R->IRequest=INT_NONE;
/* If it is NMI... */
if(Vector==INT_NMI)
{
/* Copy IFF1 to IFF2 */
if(R->IFF&IFF_1) R->IFF|=IFF_2; else R->IFF&=~IFF_2;
/* Clear IFF1 */
R->IFF&=~(IFF_1|IFF_EI);
/* Jump to hardwired NMI vector */
R->PC.W=0x0066;
/* Done */
return;
}
/* Further interrupts off */
R->IFF&=~(IFF_1|IFF_2|IFF_EI);
/* If in IM2 mode... */
if(R->IFF&IFF_IM2)
{
/* Make up the vector address */
Vector=(Vector&0xFF)|((word)(R->I)<<8);
/* Read the vector */
R->PC.B.l=RdZ80(Vector++);
R->PC.B.h=RdZ80(Vector);
/* Done */
return;
}
/* If in IM1 mode, just jump to hardwired IRQ vector */
if(R->IFF&IFF_IM1) { R->PC.W=0x0038;return; }
/* If in IM0 mode... */
/* Jump to a vector */
switch(Vector)
{
case INT_RST00: R->PC.W=0x0000;break;
case INT_RST08: R->PC.W=0x0008;break;
case INT_RST10: R->PC.W=0x0010;break;
case INT_RST18: R->PC.W=0x0018;break;
case INT_RST20: R->PC.W=0x0020;break;
case INT_RST28: R->PC.W=0x0028;break;
case INT_RST30: R->PC.W=0x0030;break;
case INT_RST38: R->PC.W=0x0038;break;
}
}
}
/** RunZ80() *************************************************/
/** This function will run Z80 code until an LoopZ80() call **/
/** returns INT_QUIT. It will return the PC at which **/
/** emulation stopped, and current register values in R. **/
/*************************************************************/
word RunZ80(Z80 *R)
{
register byte I;
register pair J;
int ras=0;
for(;;)
{
#ifdef DEBUG
/* Turn tracing on when reached trap address */
if(R->PC.W==R->Trap) R->Trace=1;
/* Call single-step debugger, exit if requested */
if(R->Trace)
if(!DebugZ80(R)) return(R->PC.W);
#endif
I=RdZ80(R->PC.W++);
R->ICount-=Cycles[I];
switch(I)
{
#include "Codes.h"
case PFX_CB: CodesCB(R);break;
case PFX_ED: CodesED(R);break;
case PFX_FD: CodesFD(R);break;
case PFX_DD: CodesDD(R);break;
}
/* If cycle counter expired... */
if(R->ICount<=0)
{
/* If we have come after EI, get address from IRequest */
/* Otherwise, get it from the loop handler */
if(R->IFF&IFF_EI)
{
R->IFF=(R->IFF&~IFF_EI)|IFF_1; /* Done with AfterEI state */
R->ICount+=R->IBackup-1; /* Restore the ICount */
/* Call periodic handler or set pending IRQ */
if(R->ICount>0) J.W=R->IRequest;
else
{
J.W=LoopZ80(R, &ras); /* Call periodic handler */
R->ICount+=R->IPeriod; /* Reset the cycle counter */
if(J.W==INT_NONE) J.W=R->IRequest; /* Pending IRQ */
}
}
else
{
J.W=LoopZ80(R, &ras); /* Call periodic handler */
R->ICount+=R->IPeriod; /* Reset the cycle counter */
if(J.W==INT_NONE) J.W=R->IRequest; /* Pending IRQ */
}
if(J.W==INT_QUIT) return(R->PC.W); /* Exit if INT_QUIT */
if(J.W!=INT_NONE) IntZ80(R,J.W); /* Int-pt if needed */
}
if (ras == 1) break;
}
/* Execution stopped */
return(R->PC.W);
}

Wyświetl plik

@ -0,0 +1,167 @@
/** Z80: portable Z80 emulator *******************************/
/** **/
/** Z80.h **/
/** **/
/** This file contains declarations relevant to emulation **/
/** of Z80 CPU. **/
/** **/
/** Copyright (C) Marat Fayzullin 1994-2005 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
#ifndef Z80_H
#define Z80_H
/* Compilation options: */
/* #define DEBUG */ /* Compile debugging version */
/* #define LSB_FIRST */ /* Compile for low-endian CPU */
/* #define MSB_FIRST */ /* Compile for hi-endian CPU */
/* LoopZ80() may return: */
#define INT_RST00 0x00C7 /* RST 00h */
#define INT_RST08 0x00CF /* RST 08h */
#define INT_RST10 0x00D7 /* RST 10h */
#define INT_RST18 0x00DF /* RST 18h */
#define INT_RST20 0x00E7 /* RST 20h */
#define INT_RST28 0x00EF /* RST 28h */
#define INT_RST30 0x00F7 /* RST 30h */
#define INT_RST38 0x00FF /* RST 38h */
#define INT_IRQ INT_RST38 /* Default IRQ opcode is FFh */
#define INT_NMI 0xFFFD /* Non-maskable interrupt */
#define INT_NONE 0xFFFF /* No interrupt required */
#define INT_QUIT 0xFFFE /* Exit the emulation */
/* Bits in Z80 F register: */
#define S_FLAG 0x80 /* 1: Result negative */
#define Z_FLAG 0x40 /* 1: Result is zero */
#define H_FLAG 0x10 /* 1: Halfcarry/Halfborrow */
#define P_FLAG 0x04 /* 1: Result is even */
#define V_FLAG 0x04 /* 1: Overflow occured */
#define N_FLAG 0x02 /* 1: Subtraction occured */
#define C_FLAG 0x01 /* 1: Carry/Borrow occured */
/* Bits in IFF flip-flops: */
#define IFF_1 0x01 /* IFF1 flip-flop */
#define IFF_IM1 0x02 /* 1: IM1 mode */
#define IFF_IM2 0x04 /* 1: IM2 mode */
#define IFF_2 0x08 /* IFF2 flip-flop */
#define IFF_EI 0x20 /* 1: EI pending */
#define IFF_HALT 0x80 /* 1: CPU HALTed */
/** Simple Datatypes *****************************************/
/** NOTICE: sizeof(byte)=1 and sizeof(word)=2 **/
/*************************************************************/
#ifndef BYTE_TYPE_DEFINED
#define BYTE_TYPE_DEFINED
typedef unsigned char byte;
#endif
#ifndef WORD_TYPE_DEFINED
#define WORD_TYPE_DEFINED
#ifndef word
typedef unsigned short word;
#endif
#endif
typedef signed char offset;
/** Structured Datatypes *************************************/
/** NOTICE: #define LSB_FIRST for machines where least **/
/** signifcant byte goes first. **/
/*************************************************************/
typedef union
{
#ifdef LSB_FIRST
struct { byte l,h; } B;
#else
struct { byte h,l; } B;
#endif
word W;
} pair;
typedef struct
{
pair AF,BC,DE,HL,IX,IY,PC,SP; /* Main registers */
pair AF1,BC1,DE1,HL1; /* Shadow registers */
byte IFF,I; /* Interrupt registers */
byte R; /* Refresh register */
int IPeriod,ICount; /* Set IPeriod to number of CPU cycles */
/* between calls to LoopZ80() */
int IBackup; /* Private, don't touch */
word IRequest; /* Set to address of pending IRQ */
byte IAutoReset; /* Set to 1 to autom. reset IRequest */
byte TrapBadOps; /* Set to 1 to warn of illegal opcodes */
word Trap; /* Set Trap to address to trace from */
byte Trace; /* Set Trace=1 to start tracing */
void *User; /* Arbitrary user data (ID,RAM*,etc.) */
} Z80;
/** ResetZ80() ***********************************************/
/** This function can be used to reset the registers before **/
/** starting execution with RunZ80(). It sets registers to **/
/** their initial values. **/
/*************************************************************/
void ResetZ80(register Z80 *R);
/** ExecZ80() ************************************************/
/** This function will execute a single Z80 opcode. It will **/
/** then return next PC, and current register values in R. **/
/*************************************************************/
word ExecZ80(register Z80 *R);
/** IntZ80() *************************************************/
/** This function will generate interrupt of given vector. **/
/*************************************************************/
void IntZ80(register Z80 *R,register word Vector);
/** RunZ80() *************************************************/
/** This function will run Z80 code until an LoopZ80() call **/
/** returns INT_QUIT. It will return the PC at which **/
/** emulation stopped, and current register values in R. **/
/*************************************************************/
word RunZ80(register Z80 *R);
/** RdZ80()/WrZ80() ******************************************/
/** These functions are called when access to RAM occurs. **/
/** They allow to control memory access. **/
/************************************ TO BE WRITTEN BY USER **/
void WrZ80(register word Addr,register byte Value);
byte RdZ80(register word Addr);
/** InZ80()/OutZ80() *****************************************/
/** Z80 emulation calls these functions to read/write from **/
/** I/O ports. There can be 65536 I/O ports, but only first **/
/** 256 are usually used. **/
/************************************ TO BE WRITTEN BY USER **/
void OutZ80(register word Port,register byte Value);
byte InZ80(register word Port);
/** PatchZ80() ***********************************************/
/** Z80 emulation calls this function when it encounters a **/
/** special patch command (ED FE) provided for user needs. **/
/** For example, it can be called to emulate BIOS calls, **/
/** such as disk and tape access. Replace it with an empty **/
/** macro for no patching. **/
/************************************ TO BE WRITTEN BY USER **/
void PatchZ80(register Z80 *R);
/** DebugZ80() ***********************************************/
/** This function should exist if DEBUG is #defined. When **/
/** Trace!=0, it is called after each command executed by **/
/** the CPU, and given the Z80 registers. Emulation exits **/
/** if DebugZ80() returns 0. **/
/*************************************************************/
#ifdef DEBUG
byte DebugZ80(register Z80 *R);
#endif
/** LoopZ80() ************************************************/
/** Z80 emulation calls this function periodically to check **/
/** if the system hardware requires any interrupts. This **/
/** function must return an address of the interrupt vector **/
/** (0x0038, 0x0066, etc.) or INT_NONE for no interrupt. **/
/** Return INT_QUIT to exit the emulation loop. **/
/************************************ TO BE WRITTEN BY USER **/
word LoopZ80(register Z80 *R, int * ras);
#endif /* Z80_H */

Wyświetl plik

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

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,222 @@
#ifndef EMUAPI_H
#define EMUAPI_H
#include "platform_config.h"
#define CUSTOM_SND 1
//#define TIMER_REND 1
#define EXTRA_HEAP 0x30000
// Title: < >
#define TITLE " MSX Emulator "
#define ROMSDIR "/msx"
#define emu_Init(ROM) {msx_Init(); msx_Start(ROM);}
#define emu_Step(x) {msx_Step();}
#define emu_Input(x) {msx_Input(x);}
#define MAX_FILENAME_PATH 64
#define NB_FILE_HANDLER 4
#define PALETTE_SIZE 256
#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
/*
const unsigned short key_map1[]={
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31, 32, 33, 34, 35, 36, 37, 38, 39, 40 };
*/
#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',127, //lowecase
0,'a','s','d','f','g','h','j','k','l',10,
0,'z','x','c','v','b','n','m',',','.',';','/',
0,0,0,0, //U L R D
0,'+',' ','-'
};
#define keylables_map1_0 (char *)"1234567890 "
#define keylables_map1_1 (char *)" "
#define keylables_map1_2 (char *)" "
#define keylables_map1_3 (char *)" "
const unsigned short key_map1[] = {
'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_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,0,0,'<','>',':','?',
153,151,150,152, //U L R D
0,'=',' ','_'
};
#define keylables_map3_0 (char *)"\x11\x12\x13\x14\x15\x16\x17\x18 "
#define keylables_map3_1 (char *)" "
#define keylables_map3_2 (char *)" "
#define keylables_map3_3 (char *)" "
const unsigned short key_map3[] = {
129,130,131,132,133,134,135,136,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_map4_0 (char *)"QWERTYUIOP@"
#define keylables_map4_1 (char *)" ASDFGHJKL\x19"
#define keylables_map4_2 (char *)" ZXCVBNM<>:?"
#define keylables_map4_3 (char *)" =\x10_"
const unsigned short key_map4[] = {
'Q','W','E','R','T','Y','U','I','O','P','@', //shift uppercase
0,'A','S','D','F','G','H','J','K','L',10,
0,'Z','X','C','V','B','N','M','<','>',':','?',
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,
153,151,150,152, //U L R D
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

Some files were not shown because too many files have changed in this diff Show More