obj/
ROMs/
sounds/
+test/
+mame/
+*.wav
+*.raw
+*.pcx
*.log
+*.txt
thunder
pin 34: Same as other processor (1.538 MHz)
Hope this helps! ;)
-
-
-ROM_START( rthunder )
- ROM_REGION( 0x18000, REGION_CPU1, 0 )
- ROM_LOAD( "rt3-1b.9c", 0x8000, 0x8000) /* 9d empty */
-
- ROM_REGION( 0x40000, REGION_USER1, 0 ) /* bank switched data for CPU1 */
- ROM_LOAD( "rt1-17.f1", 0x00000, 0x10000)
- ROM_LOAD( "rt1-18.h1", 0x10000, 0x10000)
- ROM_LOAD( "rt1-19.k1", 0x20000, 0x10000)
- ROM_LOAD( "rt1-20.m1", 0x30000, 0x10000)
-
- ROM_REGION( 0x18000, REGION_CPU2, 0 )
- ROM_LOAD( "rt3-2b.12c", 0x08000, 0x8000)
- ROM_LOAD( "rt3-3.12d", 0x10000, 0x8000)
-
- ROM_REGION( 0x18000, REGION_GFX1, ROMREGION_DISPOSE )
- ROM_LOAD( "rt1-7.7r", 0x00000, 0x10000) /* plane 1,2 */
- ROM_LOAD( "rt1-8.7s", 0x10000, 0x08000) /* plane 3 */
-
- ROM_REGION( 0x0c000, REGION_GFX2, ROMREGION_DISPOSE )
- ROM_LOAD( "rt1-5.4r", 0x00000, 0x08000) /* plane 1,2 */
- ROM_LOAD( "rt1-6.4s", 0x08000, 0x04000) /* plane 3 */
-
- ROM_REGION( 0x80000, REGION_GFX3, ROMREGION_DISPOSE )
- ROM_LOAD( "rt1-9.12h", 0x00000, 0x10000)
- ROM_LOAD( "rt1-10.12k", 0x10000, 0x10000)
- ROM_LOAD( "rt1-11.12l", 0x20000, 0x10000)
- ROM_LOAD( "rt1-12.12m", 0x30000, 0x10000)
- ROM_LOAD( "rt1-13.12p", 0x40000, 0x10000)
- ROM_LOAD( "rt1-14.12r", 0x50000, 0x10000)
- ROM_LOAD( "rt1-15.12t", 0x60000, 0x10000)
- ROM_LOAD( "rt1-16.12u", 0x70000, 0x10000)
-
- ROM_REGION( 0x1420, REGION_PROMS, 0 )
- ROM_LOAD( "mb7124e.3r", 0x0000, 0x0200) /* red & green components */
- ROM_LOAD( "mb7116e.3s", 0x0200, 0x0200) /* blue component */
- ROM_LOAD( "mb7138h.4v", 0x0400, 0x0800) /* tiles colortable */
- ROM_LOAD( "mb7138h.6v", 0x0c00, 0x0800) /* sprites colortable */
- ROM_LOAD( "mb7112e.6u", 0x1400, 0x0020) /* tile address decoder (used at runtime) */
-
- ROM_REGION( 0x10000, REGION_CPU3, 0 )
- ROM_LOAD( "rt1-4.6b", 0x04000, 0x8000)
- ROM_LOAD( "rt1-mcu.bin", 0x0f000, 0x1000)
-
- ROM_REGION( 0x40000, REGION_SOUND1, 0 ) /* PCM samples for Hitachi CPU */
- ROM_LOAD( "rt1-21.f3", 0x00000, 0x10000)
- ROM_LOAD( "rt1-22.h3", 0x10000, 0x10000)
- /* k3 empty */
- /* m3 empty */
-ROM_END
-
# This software is licensed under the GPL v3 or later
#
-ifeq "$(OSTYPE)" "msys" # Win32
+ifeq "$(OSTYPE)" "msys" # Win32
SYSTYPE = __GCCWIN32__
EXESUFFIX = .exe
// by James Hammons
// (C) 2004, 2014 Underground Software
//
-
#ifndef __DIS63701_H__
#define __DIS63701_H__
// by James Hammons
// (C) 2004, 2014 Underground Software
//
-
#ifndef __DIS6809_H__
#define __DIS6809_H__
-//#include "types.h"
#include "v6809.h"
-//int Decode6809(uint16);
int Decode6809(V6809REGS);
#endif // __DIS6809_H__
// by James Hammmons
// (C) 1998, 2014 Underground Software
//
-
#ifndef __GUI_H__
#define __GUI_H__
static FILE * logStream = NULL;
static uint32_t logSize = 0;
-
bool InitLog(const char * path)
{
logStream = fopen(path, "wrt");
return true;
}
-
void LogDone(void)
{
if (logStream)
fclose(logStream);
}
-
//
// This logger is used mainly to ensure that text gets written to the log file
// even if the program crashes. The performance hit is acceptable in this case!
va_end(arg);
fflush(logStream); // Make sure that text is written!
}
-
//
// LOG.H
//
-
#ifndef __LOG_H__
#define __LOG_H__
//
// Notes:
// ------
-// The emulator creates signed 16-bit samples. Make sure there's enough room in
-// your buffer for them!
+// The emulator creates signed 16-bit samples. Make sure there's enough room
+// in your buffer for them!
//
#include "psg.h"
#include <stdio.h>
#include <string.h>
-
struct Voice
{
uint8_t leftVolume;
static Voice voice[8];
static uint8_t memory[0x200];
-//static
static uint32_t sampleRate = 44100;
static uint32_t divisor;
-
void InitPSG(uint32_t s/*=44100*/)
{
sampleRate = s;
voice[i].noiseSeed = 1;
}
-
//
-// Note that it doesn't wipe out the buffer passed in, if you want it wiped,
-// you have to wipe it yourself. :-)
+// Note that it doesn't wipe out the buffer passed in; if you want it wiped,
+// you have to wipe it yourself. :-)
//
void UpdatePSG(uint8_t * buffer, int count)
{
}
}
-
void WritePSG(uint16_t address, uint8_t data)
{
if ((address >= 0x100) && (address <= 0x13F))
break;
case 1:
voice[channel].waveform = data >> 4;
- voice[channel].frequency = ((data & 0x0F) << 16)
+ voice[channel].frequency = ((data & 0x0F) << 16)
| (voice[channel].frequency & 0x0FFFF);
#if 0
printf("PSG: Setting waveform on channel %i to %i...\n", channel, voice[channel].waveform);
memory[address & 0x01FF] = data;
}
-
uint8_t ReadPSG(uint16_t address)
{
return memory[address & 0x01FF];
}
-
extern bool show_text; // Whether or not to show text
-
//
// Render the NAMCO screen
//
RenderScreenBuffer();
}
-
//
// Render tilemap
//
for(uint8_t sy=0; sy<29; sy++)
{
for(uint8_t sx=0; sx<37; sx++)
- {
-
DrawChar(sx, sy, ramBase, tileBase << 16, xAddress & 0x07, yAddress & 0x07, transparent);
- }
}
}
-
//
// Draw character on screen
//
}
}
-
//
// Copy sprites in sprite RAM from positions 4-9 to 10-15
-// (N.B.: This still doesn't solve the shifting signs on the walls problem...)
//
void CopySprites(void)
{
}
}
-
//
-// Draw sprites at priority level (new code)
+// Draw sprites at priority level
+// We read from the sprite copy RAM to render sprites, as that seems to be the
+// way the real H/W does it.
//
void DrawSprites(uint8_t priority)
{
//
// Offset Note
// ------ --------------------------------------------------------------------
-// 4 h.fb .nnn (f = horz. flip, h = horz. expand, b = sprite offset lo
+// 4 (10) h.fb .nnn (f = horz. flip, h = horz. expand, b = sprite offset lo
// bit, nnn = upper bits of sprite #)
-// 5 Lower 7 bits of sprite #
-// 6 Sprite color index (top 7 bits only), bottom bit is bit 8 of X
+// 5 (11) Lower 7 bits of sprite #
+// 6 (12) Sprite color index (top 7 bits only), bottom bit is bit 8 of X
// position
-// 7 Sprite X position (bits 0-7)
-// 8 Top two bits are sprite priority, bits 4 & 2 are sprite offset hi
+// 7 (13) Sprite X position (bits 0-7)
+// 8 (14) Top two bits are sprite priority, bits 4 & 2 are sprite offset hi
// bit, vert. expand
-// 9 Sprite Y position (192 - value)
+// 9 (15) Sprite Y position (192 - value)
- extern uint8_t gram1[]; // Game RAM space
+ extern uint8_t gram1[]; // Game RAM space
for(uint16_t i=0x5800; i<0x6000; i+=0x10)
{
- if ((gram1[i + 8 + 6] & 0xC0) == priority) // Check for correct layer...
- {
- spr_color_index = gram1[i + 6 + 6] >> 1; // Set color...
- uint16_t x = ((gram1[i + 6 + 6] & 0x01) << 8) | gram1[i + 7 + 6];
+ uint8_t * sprRAM = &gram1[i];
- if (x > 512 - 32)
- x -= 512; // Handle neg x values
+ // Skip sprite if it's not on the correct layer...
+ if ((sprRAM[14] & 0xC0) != priority)
+ continue;
- uint16_t y = 192 - gram1[i + 9 + 6];
- uint8_t flip = gram1[i + 4 + 6] & 0x20; // Horizontal flip
- uint32_t spr_num = ((gram1[i + 4 + 6] & 0x07) << 9)
- | ((gram1[i + 5 + 6] & 0x7F) << 2)
- | ((gram1[i + 4 + 6] & 0x10) >> 4)
- | ((gram1[i + 8 + 6] & 0x10) >> 3);
+ spr_color_index = sprRAM[12] >> 1; // Set color...
+ uint16_t x = ((sprRAM[12] & 0x01) << 8) | sprRAM[13];
- // Draw sprite...
- Sprite(spr_num, x, y, flip, gram1[i + 4 + 6] & 0x80, gram1[i + 8 + 6] & 0x04);
- }
+ if (x > 512 - 32)
+ x -= 512; // Handle neg x values
+
+ uint16_t y = 192 - sprRAM[15];
+ uint8_t horzFlip = sprRAM[10] & 0x20;
+ uint32_t spr_num = ((sprRAM[10] & 0x07) << 9)
+ | ((sprRAM[11] & 0x7F) << 2)
+ | ((sprRAM[10] & 0x10) >> 4)
+ | ((sprRAM[14] & 0x10) >> 3);
+
+ // Draw the sprite...
+ Sprite(spr_num, x, y, horzFlip, sprRAM[10] & 0x80, sprRAM[14] & 0x04);
}
}
-
static inline void DrawSpriteBlock(uint32_t & sprnum, uint16_t x, uint16_t y, uint16_t xStart, uint16_t xEnd, int16_t xInc)
{
extern uint8_t spr_rom[];
}
}
-
static inline void DrawSpriteBlock2(uint32_t & sprnum, uint16_t x, uint16_t y, uint16_t xStart, uint16_t xEnd, int16_t xInc)
{
extern uint8_t spr_rom[];
}
}
-
//
// Sprite handler
//
}
}
-
int FindPCXName(void)
{
static int pcxNum = -1; // This needs to go elsewhere... (or does it?)
return -1;
}
-
void SavePCXSnapshot(void)
{
char filename[30];
// Success!
fclose(fw);
}
-
#include "resource.h"
#include "ym2151.h"
-
-#define SAMPLE_RATE 48000
+#define SAMPLE_RATE 48000
+#define BUFFER_SIZE 512
// Function prototypes
void SoundFunc(void *, Uint8 *, int);
extern uint8_t voice_rom[]; // PCM data pointer
static bool soundInitialized = false;
-const float sampleBase = (float)SAMPLE_RATE/6000.0; // Voice is between 5512.5 and 6000 Hz
-bool snd_go = false;
-bool chan1_go = false, chan2_go = false;//, chan3_go = false;
-bool /*chan4_go = false, chan5_go = false,*/ chan6_go = false;
-uint8_t * sndp1, * sndp2, /* sndp3, * sndp4, * sndp5,*/ * sndp6;
-uint32_t rom_pos, end_pos;
+const float sampleBase = (float)SAMPLE_RATE / 6000.0; // Voice is between 5512.5 and 6000 Hz
+bool chan1_go = false, chan2_go = false;
+bool chan6_go = false;
+uint8_t * sndp1, * sndp2, * sndp6;
uint32_t spos1, end_pos1;
uint32_t spos2, end_pos2;
-//uint32_t spos3, end_pos3;
-//uint32_t spos4, end_pos4;
-//uint32_t spos5, end_pos5;
uint32_t spos6, end_pos6;
-float sample1;
-int16_t prevSamp1;
-//int8_t delta_x1;
-float sample2;
-int16_t prevSamp2;
-//int8_t delta_x2;
+float sample1, sample2;
+int16_t prevSamp1, prevSamp2;
uint16_t snd_num;
-uint8_t * snd_array[3] = { sunknown, scya, scamera }; // From RESOURCE.H
+// From RESOURCE.H
+uint8_t * snd_array[3] = { sunknown, scya, scamera };
uint32_t snd_lens[3] = { sunknownlen, scyalen, scameralen };
-
void InitSound(void)
{
// params 1, 4 & 5 are useless
-// if (YMInit(1, 3579580, 22050, 16, 512))//, (SAMPLE **)sbp))
- if (YMInit(1, 3579580, SAMPLE_RATE, 16, 512))
+// if (YMInit(1, 3579580, SAMPLE_RATE, 16, 512))
+ if (YMInit(3579580, SAMPLE_RATE))
{
printf("SOUND: Could not init YM2151 emulator!\n");
- return;// -1;
+ return;
}
InitPSG(SAMPLE_RATE);
desired.freq = SAMPLE_RATE;
desired.format = AUDIO_S16;
desired.channels = 1;
- desired.samples = 1024;
+ desired.samples = BUFFER_SIZE * 2; // Size is in BYTES, so x2
desired.callback = SoundFunc;
desired.userdata = NULL;
- // Also, should check to see if it got the hardware it needed, correct sample size, etc.
+ // Also, should check to see if it got the hardware it needed, correct sample size, etc. (actually, SDL guarantees we get what we asked for--I think)
if (SDL_OpenAudio(&desired, &obtained) < 0)
{
soundInitialized = false;
soundInitialized = true;
}
-
void SpawnSound(int type, int snd, int channel/* = 0*/)
{
-// extern uint32_t psg_lens[16];
-// extern uint8_t * psg_adrs[16];
-// extern uint32_t voc_lens[32];
-// extern uint8_t * voc_adrs[32];
-// extern uint32_t fm_lens[14];
-// extern uint8_t * fm_adrs[14];
-
if (!soundInitialized)
return;
snd_num = snd;
-// SpawnMsg(MSHOWNUMS);
// Voice type sounds...
if (type == GAMESOUND)
chan2_go = true;
}
}
-#if 0
- else if (type == PSGSOUND)
- {
- if (snd_num & 0x10) // Second channel?
- {
- spos3 = 0;
- end_pos3 = psg_lens[snd_num & 0x0F];
- sndp3 = psg_adrs[snd_num & 0x0F];
- chan3_go = true;
-
- if (spos3 == end_pos3)
- chan3_go = false; // No sound loaded, so don't do it!
- }
- else // First channel
- {
- spos4 = 0;
- end_pos4 = psg_lens[snd_num & 0x0F];
- sndp4 = psg_adrs[snd_num & 0x0F];
- chan4_go = true;
-
- if (spos4 == end_pos4)
- chan4_go = false; // No sound loaded, so don't do it!
- }
- }
-#endif
-#if 0
- else if (type == FMSOUND)
- {
- spos5 = 0;
- end_pos5 = fm_lens[snd_num];
- sndp5 = fm_adrs[snd_num];
- chan5_go = true;
-
- if (spos5 == end_pos5)
- chan5_go = false; // No sound loaded, so don't do it!
- }
-#endif
else if (type == USERSOUND)
{
spos6 = 0;
}
}
-
void SoundFunc(void * userdata, Uint8 * buffer, int num)
{
- static bool psg1go = false, psg2go = false;
- // Length / 2 is because it's set up for 16-bit samples
-// YM2151UpdateOne(buffer, length / 2);
- // Have to go into ym2151.cpp and change this manually back to 8 bit
+ // We do num / 2 because num is in BYTES, and the buffer uses signed WORDs.
YM2151UpdateOne(buffer, num / 2);
-// return;
UpdatePSG(buffer, num / 2);
// 0-22 different sounds...
- uint16_t cnt = 0;//, sample;
+ uint16_t cnt = 0;
uint8_t start_samp1, end_samp1, start_samp2, end_samp2;
int16_t samp1 = 0, samp2 = 0, samp6 = 0; // Zero samples...
- if (!(chan1_go || chan2_go /*|| chan3_go || chan4_go || chan5_go*/ || chan6_go))
+ if (!(chan1_go || chan2_go || chan6_go))
return;
while (cnt != (num / 2))
{
uint8_t voiceSample = voice_rom[spos2++];
samp2 = ((int16_t)voiceSample - 128) * 160;
-// samp2 = voice_rom[spos2++];
if (voiceSample == 0xFF)
{
sample2 -= 1.0;
}
-#if 0
- if (chan3_go)
- {
- samp3 = ((psg1go ? sndp3[spos3++] : sndp3[spos3]) - 128) * 160;
- psg1go = !psg1go;
-
- if (spos3 == end_pos3)
- {
- chan3_go = false;
- samp3 = 0; // Kill channel 3 if done...
- }
- }
-
- if (chan4_go)
- {
- samp4 = ((psg2go ? sndp4[spos4++] : sndp4[spos4]) - 128) * 160;
- psg2go = !psg2go;
-
- if (spos4 == end_pos4)
- {
- chan4_go = false;
- samp4 = 0; // Kill channel 4 if done...
- }
- }
-
- if (chan5_go)
- {
- samp5 = sndp5[spos5++];
-
- if (spos5 == end_pos5)
- {
- chan5_go = false;
- samp5 = 128; // Kill channel 5 if done...
- }
- }
-#endif
if (chan6_go)
{
samp6 = sndp6[spos6++];
}
// Mix 'em...
-// sample = samp1 + samp2 + samp3 + samp4 + samp5 + samp6 - 640;
int32_t sample = samp1 + samp2 + samp6;
sample += ((int16_t *)buffer)[cnt];
// If it overflowed, clip it
-// if (sample & 0xFFFF0000)
-// sample = (sample & 0x8000 ? 0x00 : 0xFF);
-// sample = (sample & 0x80000000 ? 0x0000 : 0xFFFF);
if (sample > 32767)
sample = 32767;
else if (sample < -32767)
((int16_t *)buffer)[cnt++] = (int16_t)sample;
}
}
-
#define SCYA 1
#define SCAMERA 2
-
// Functions
void InitSound(void);
void SpawnSound(int, int, int channel = 0);
-
// Exported vars
extern uint16_t snd_num;
#endif // __SOUND_H__
-
// Thunder: A Rolling Thunder Emulator
//
// by James Hammons
-// (C) 2004, 2014 Underground Software
+// (C) 2004, 2023 Underground Software
//
// JLH = James Hammons <jlhamm@acm.org>
//
// JLH 08/12/2009 Stabilized emulation so that it works
// JLH 04/04/2014 Converted to SDL 2
// JLH 04/17/2014 Removed a metric fuck-tonne of cruft, added YM2151 & MCU
+// JLH 01/13/2023 Finally fixed the sprite lag problem :-D
//
-#define THUNDER_VERSION "1.2.0"
+#define THUNDER_VERSION "1.2.1"
#include <SDL2/SDL.h>
#include <string>
#include "video.h"
#include "ym2151.h"
-
#define ROM1 "rt3-1b.9c"
#define ROM2 "rt3-2b.12c"
#define ROM3 "rt3-3.12d"
#define PROM5 "mb7112e.6u"
#define MCUROM "rt1-mcu.bin"
-
// Global defines
uint8_t gram1[0x10000], grom1[0x10000], grom2[0x10000];
// MCU inputs
Byte input1, input2, input3, input4, input5;
+// Copy sprites flag
+bool copySprites = false;
+
// Function prototypes
uint8_t MCUReadMemory(uint16_t address);
void MCUWriteMemory(uint16_t address, uint8_t data);
-
//
// Read a byte from memory
//
return grom1[addr];
}
-
//
// Write a byte to memory
//
void MainWriteMemory(uint16_t address, uint8_t data)
{
- extern bool disasm;
-
if (address == 0x6000)
SpawnSound(GAMESOUND, gram1[0x6200], 0); // Do voice chan 1
if (address == 0x6400)
gram1[address] = data;
if (address == 0x5FF2)
- CopySprites();
+ copySprites = true;
if (address == 0x8800)
charBankSwitch = false; // Char banksw1
if (address == 0x8C00)
charBankSwitch = true; // Char banksw2
- if (address == 0x8400) // Frame go strobe? VBlank acknowledge?
- {
-// BlitChar(charROM, gram1);
-
- // IRQ Ack (may also be frame go...)
- ClearLineOfCurrentV6809(V6809_ASSERT_LINE_IRQ);
-#if 1
- if (disasm)
- WriteLog("WriteMem: CPU #1 Acknowledging IRQ...\n", data);
-#endif
- }
+ if (address == 0x8400) // Frame go strobe? VBlank acknowledge?
+ ClearLineOfCurrentV6809(V6809_LINE_IRQ); // IRQ Ack
}
-
//
// Read a byte from memory (2nd processor)
//
return grom2[address];
}
-
//
// Write a byte to memory (2nd processor)
//
void SubWriteMemory(uint16_t address, uint8_t data)
{
- extern bool disasm;
-
// Set sprite data bank switch
if (address == 0xD803)
banksw2 = (uint32_t)(data & 0x03) << 13;
gram1[address - 0x2000] = data;
if (address == 0x1FF2)
- CopySprites();
+ copySprites = true;
if (address == 0x8800)
- {
- // IRQ Ack (may also be frame go...)
- ClearLineOfCurrentV6809(V6809_ASSERT_LINE_IRQ);
-#if 1
- if (disasm)
- WriteLog("WriteMem: CPU #2 Acknowledging IRQ...\n", data);
-#endif
- }
+ ClearLineOfCurrentV6809(V6809_LINE_IRQ); // IRQ Ack
}
-
uint8_t MCUReadMemory(uint16_t address)
{
if (address < 0x20)
return mcuMem[address];
}
-
void MCUWriteMemory(uint16_t address, uint8_t data)
{
static uint8_t ymRegister;
mcuMem[address] = data;
}
-
uint8_t V63701ReadPort1(void)
{
// printf("V63701ReadPort1: Read $%02X...\n", input3.byte);
return input3.byte;
}
-
uint8_t V63701ReadPort2(void)
{
return 0xFF;
}
-
void V63701WritePort1(uint8_t data)
{
// printf("V63701WritePort1: Wrote $%02X...\n", data);
}
-
void V63701WritePort2(uint8_t data)
{
// printf("V63701WritePort2: Wrote $%02X...\n", data);
}
-
//
// Generic Load file into image space
// (No error checking performed! Responsibility of caller!)
return false;
}
- fread(&mem[address], 1, length, file);
+ size_t ignored = fread(&mem[address], 1, length, file);
fclose(file);
return true;
}
-
//
// Read color PROMs
//
bool ReadColorPROMs(void)
{
- FILE * file1 = fopen("./ROMs/"PROM3, "rb");
+ FILE * file1 = fopen("./ROMs/" PROM3, "rb");
if (file1)
{
fclose(file1);
}
- file1 = fopen("./ROMs/"PROM4, "rb");
+ file1 = fopen("./ROMs/" PROM4, "rb");
if (file1)
{
fclose(file1);
}
- file1 = fopen("./ROMs/"PROM1, "rb");
- FILE * file2 = fopen("./ROMs/"PROM2, "rb");
+ file1 = fopen("./ROMs/" PROM1, "rb");
+ FILE * file2 = fopen("./ROMs/" PROM2, "rb");
// If open was successful...
if (file1 && file2)
// PROM5 has the following in it (tile address decoder):
// 00: 00 20 40 60 02 22 42 62 04 24 44 64 06 26 46 66
- // 10: 88 A8 C8 E8 8A AA CA EA 8C AC CC EC 8E AE CE EE
+ // 10: 88 A8 C8 E8 8A AA CA EA 8C AC CC EC 8E AE CE EE
if (!file1)
{
return true;
}
-
//
// Unpack font data
//
bool UnpackFonts(void)
{
// 0x4000 $800 chars
- FILE * file1 = fopen("./ROMs/"ROM7, "rb");
- FILE * file2 = fopen("./ROMs/"ROM8, "rb");
+ FILE * file1 = fopen("./ROMs/" ROM7, "rb");
+ FILE * file2 = fopen("./ROMs/" ROM8, "rb");
if (!file1 || !file2)
{
- printf("Could not open either "ROM7" or "ROM8"!\n");
+ printf("Could not open either " ROM7 " or " ROM8 "!\n");
return false;
}
fclose(file1);
fclose(file2);
- file1 = fopen("./ROMs/"ROM5, "rb");
- file2 = fopen("./ROMs/"ROM6, "rb");
+ file1 = fopen("./ROMs/" ROM5, "rb");
+ file2 = fopen("./ROMs/" ROM6, "rb");
if (!file1 || !file2)
{
- printf("Could not open either "ROM5" or "ROM6"!\n");
+ printf("Could not open either " ROM5 " or " ROM6 "!\n");
return false;
}
return true;
}
-
//
// Main loop
//
{
InitLog("thunder.log");
- extern bool disasm; // From 'V6809.CPP'
-
bool running; // CPU running state flag...
SDL_Event event; // SDL "event"
uint32_t ticks, oldTicks;
uint8_t frameTickCount = 0;
- printf("THUNDER v"THUNDER_VERSION" by James Hammons\n");
- printf("Serial #20149417 / Prerelease\n");
- printf("© 2003, 2014 Underground Software\n\n");
+ printf("THUNDER v" THUNDER_VERSION " by James Hammons\n");
+ printf("Serial #20230113 / Prerelease\n");
+ printf("© 2003, 2023 Underground Software\n\n");
printf("This emulator is free software. If you paid for it you were RIPPED OFF\n\n");
// SDL_WM_SetCaption("Thunder v"THUNDER_VERSION" ", "Thunder");
memset(&cpu1, 0, sizeof(V6809REGS));
cpu1.RdMem = MainReadMemory;
cpu1.WrMem = MainWriteMemory;
- cpu1.cpuFlags |= V6809_ASSERT_LINE_RESET;
+ cpu1.cpuFlags |= V6809_LINE_RESET;
memset(&cpu2, 0, sizeof(V6809REGS));
cpu2.RdMem = SubReadMemory;
cpu2.WrMem = SubWriteMemory;
- cpu2.cpuFlags |= V6809_ASSERT_LINE_RESET;
+ cpu2.cpuFlags |= V6809_LINE_RESET;
memset(&mcu, 0, sizeof(V63701REGS));
mcu.RdMem = MCUReadMemory;
mcu.WrMem = MCUWriteMemory;
- mcu.cpuFlags |= V63701_ASSERT_LINE_RESET;
+ mcu.cpuFlags |= V63701_LINE_RESET;
running = true;
InitGUI(); // Reset # of coins
// Set up DIP switches...
- input4.bit.b0 = 1; // DSW B-0: Contiues (1 = 6, 0 = 3)
+ input4.bit.b0 = 1; // DSW B-0: Continues (1 = 6, 0 = 3)
input4.bit.b1 = 1; // DSW B-2: ???
input4.bit.b2 = 1; // DSW B-4: Difficulty (1 = normal, 0 = easy)
input4.bit.b3 = 1; // DSW B-6: Bonus lives (70K/200K = 1, 100K/300K = 0)
WriteLog("About to set up audio...\n");
InitSound();
-//memset(scrBuffer, 0xFF, VIRTUAL_SCREEN_WIDTH*VIRTUAL_SCREEN_HEIGHT*sizeof(uint32_t));
-//RenderScreenBuffer();
-
WriteLog("About to enter main loop...\n");
while (running)
{
// Dipswitches are presented to the main CPUs as 0 or 1 at locations
// $423D - $425B by the MCU
-//testing... (works)
-//gram1[0x423D] = 1;
- //gram1[0x423D] = self_test; // Reset DSW1-1
-// gram1[0x4268] = 0; // Reset Video test
-
// SDL key handling...
SDL_Event event;
#endif
// We can do this here because we're not executing the cores yet.
- cpu1.cpuFlags |= V6809_ASSERT_LINE_IRQ;
- cpu2.cpuFlags |= V6809_ASSERT_LINE_IRQ;
- mcu.cpuFlags |= V63701_ASSERT_LINE_IRQ;
+ cpu1.cpuFlags |= V6809_LINE_IRQ;
+ cpu2.cpuFlags |= V6809_LINE_IRQ;
+ mcu.cpuFlags |= V63701_LINE_IRQ;
// while (cpu1.clock < 25000)
// 1.538 MHz = 25633.333... cycles per frame (1/60 s)
// 25600 cycles/frame
// 40 works, until it doesn't... :-P
// 640 * 40
// 800 * 32
+// 20 seems to work... :-)
// Interesting, putting IRQs at 30 Hz makes it run at the correct speed. Still hangs in the demo, though.
- for(int i=0; i<640; i++)
+// for(int i=0; i<640; i++)
+ for(int i=0; i<1280; i++)
{
// Gay, but what are ya gonna do?
// There's better ways, such as keeping track of when slave writes to master, etc...
- Execute6809(&cpu1, 40);
- Execute6809(&cpu2, 40);
+// Execute6809(&cpu1, 40);
+// Execute6809(&cpu2, 40);
+ Execute6809(&cpu1, 20);
+ Execute6809(&cpu2, 20);
// MCU runs at 1,536,000 Hz
// 1536000 / 60 / 640 == 40
- Execute63701(&mcu, 40);
+// Execute63701(&mcu, 40);
+ Execute63701(&mcu, 20);
}
BlitChar(charROM, gram1);
+ // Make sure that the sprite RAM lags by one frame... :-)
+ if (copySprites)
+ {
+ CopySprites();
+ copySprites = false;
+ }
+
frameTickCount++;
if (frameTickCount == 3)
return 1;
}
-
-#if 0
-/*
-Hitachi uC runs at 6.144 MHz
-YM2151 runs at 3.579580 MHz
-
-
-Rolling Thunder Memory map
---------------------------
-Most of the decoding is done by custom chips (CUS47 and CUS41), so the memory
-map is inferred by program behaviour. The customs also handle internally irq
-and watchdog.
-
-The main CPU memory map is the same in all games because CUS47 is used by all
-games. The sub CPU and sound CPU, on the other hand, change because CUS41 is
-replaced by other chips.
-
-All RAM is shared between main and sub CPU, except for sound RAM which is
-shared between main and sound CPU; the portion of object RAM that is overlapped
-by sound RAM is used exclusively by the sub CPU.
-
-MAIN CPU:
-
-Address Dir Data Name Description
-------------------- --- -------- --------- -----------------------
-000x xxxx xxxx xxxx R/W xxxxxxxx SCROLL0 tilemap 0/1 RAM (shared with sub CPU)
-001x xxxx xxxx xxxx R/W xxxxxxxx SCROLL1 tilemap 2/3 RAM (shared with sub CPU)
-0100 00xx xxxx xxxx R/W xxxxxxxx SOUND sound RAM (through CUS30, shared with MCU)
-0100 0000 xxxx xxxx R/W xxxxxxxx portion holding the sound wave data
-0100 0001 00xx xxxx R/W xxxxxxxx portion holding the sound registers
-010x xxxx xxxx xxxx R/W xxxxxxxx OBJECT work RAM (shared with sub CPU) [1]
-0101 1xxx xxxx xxxx R/W xxxxxxxx portion holding sprite registers
-011x xxxx xxxx xxxx R xxxxxxxx ROM 9D program ROM (banked) [2]
-1xxx xxxx xxxx xxxx R xxxxxxxx ROM 9C program ROM
-1000 00-- ---- ---- W -------- watchdog reset (RES generated by CUS47)
-1000 01-- ---- ---- W -------- main CPU irq acknowledge (IRQ generated by CUS47)
-1000 1x-- ---- ---- W -------- BANK tile gfx bank select (data is in A10) (latch in CUS47)
-1001 00-- ---- -x0x W xxxxxxxx LATCH0 tilemap 0/1 X scroll + priority
-1001 00-- ---- -x10 W xxxxxxxx LATCH0 tilemap 0/1 Y scroll
-1001 00-- ---- --11 W ------xx BAMNKM ROM 9D bank select
-1001 01-- ---- -x0x W xxxxxxxx LATCH1 tilemap 2/3 X scroll + priority
-1001 01-- ---- -x10 W xxxxxxxx LATCH1 tilemap 2/3 Y scroll
-1001 01-- ---- --11 W ------xx BAMNKS ROM 12D bank select
-1100 00-- ---- ---- W xxxxxxxx BACKCOLOR background color
-
-[1] Note that this is partially overlapped by sound RAM
-[2] In Rolling Thunder and others, replaced by the ROM/voice expansion board
-
-
-SUB CPU:
-
-Address Dir Data Name Description
-------------------- --- -------- --------- -----------------------
-000x xxxx xxxx xxxx R/W xxxxxxxx SUBOBJ work RAM (shared with main CPU)
-0001 1xxx xxxx xxxx R/W xxxxxxxx portion holding sprite registers
-001x xxxx xxxx xxxx R/W xxxxxxxx SUBSCR0 tilemap 0/1 RAM (shared with main CPU)
-010x xxxx xxxx xxxx R/W xxxxxxxx SUBSCR1 tilemap 2/3 RAM (shared with main CPU)
-011x xxxx xxxx xxxx R xxxxxxxx ROM 12D program ROM (banked) [1]
-1xxx xxxx xxxx xxxx R xxxxxxxx ROM 12C program ROM
-1000 0--- ---- ---- W -------- watchdog reset (MRESET generated by CUS41)
-1000 1--- ---- ---- W -------- main CPU irq acknowledge (generated by CUS41)
-1101 0--- ---- -x0x W xxxxxxxx LATCH0 tilemap 0/1 X scroll + priority
-1101 0--- ---- -x10 W xxxxxxxx LATCH0 tilemap 0/1 Y scroll
-1101 0--- ---- --11 W ------xx BAMNKM ROM 9D bank select
-1101 1--- ---- -x0x W xxxxxxxx LATCH1 tilemap 2/3 X scroll + priority
-1101 1--- ---- -x10 W xxxxxxxx LATCH1 tilemap 2/3 Y scroll
-1101 1--- ---- --11 W ------xx BAMNKS ROM 12D bank select
-
-[1] Only used by Rolling Thunder
-
-
-MCU:
-
-Address Dir Data Name Description
-------------------- --- -------- --------- -----------------------
-0000 0000 xxxx xxxx MCU internal registers, timers, ports and RAM
-0001 xxxx xxxx xxxx R/W xxxxxxxx RAM 3F sound RAM (through CUS30, partially shared with main CPU)
-0001 0000 xxxx xxxx R/W xxxxxxxx portion holding the sound wave data
-0001 0001 00xx xxxx R/W xxxxxxxx portion holding the sound registers
-0010 0--- --00 ---x R/W xxxxxxxx YMCS YM2151
-0010 0--- --01 ---- n.c.
-0010 0--- --10 ---- R xxxxxxxx PORTA switch inputs
-0010 0--- --11 ---- R xxxxxxxx PORTB dip switches
-01xx xxxx xxxx xxxx R xxxxxxxx ROM 6B program ROM (lower half)
-10xx xxxx xxxx xxxx R xxxxxxxx ROM 6B program ROM (upper half)
-1011 0--- ---- ---- W unknown (CUS41)
-1011 1--- ---- ---- W unknown (CUS41)
-1111 xxxx xxxx xxxx R xxxxxxxx MCU internal ROM
-
-
-Notes:
------
-- There are two watchdogs, one per CPU (or maybe three). Handling them
- separately is necessary to allow entering service mode without manually
- resetting in rthunder and genpeitd: only one of the CPUs stops writing to
- the watchdog.
-
-- The sprite hardware buffers spriteram: the program writes the sprite list to
- offsets 4-9 of every 16-byte block, then at the end writes to offset 0x1ff2
- of sprite RAM to signal the chip that the list is complete. The chip will
- copy the list from 4-9 to 10-15 and use it from there. This has not been
- verified on the real hardware, but it is the most logical way of doing it.
- Emulating this behaviour and not using an external buffer is important in
- rthunder: when you insert a coin, the whole sprite RAM is cleared, but 0x1ff2
- is not written to. If we buffered spriteram to an external buffer, this would
- cause dangling sprites because the buffer would not be updated.
-
-- spriteram buffering fixes sprite lag, but causes a glitch in rthunder when
- entering a door. The *closed* door is made of tiles, but the *moving* door is
- made of sprites. Since sprites are delayed by 1 frame, when you enter a door
- there is one frame where neither the tile-based closed door nor the
- sprite-based moving door is shown, so it flickers. This behavior has been
- confirmed on a real PCB.
-
-TODO:
-----
-- The two unknown writes for the MCU are probably watchdog reset and irq acknowledge,
- but they don't seem to work as expected. During the first few frames they are
- written out of order and hooking them up in the usual way causes the MCU to
- stop receiving interrupts.
-*/
-#endif
-
// work well. It's a fair sight better than the one that's in MAME,
// that's for sure. :-D
-// Some random thoughts: Could there be a performance gain by breaking
-// out the flags in regs.cc into separate uint8_t variables (or bools)?
-// You'd have to convert on entering and exiting the emulation loop, but I
-// think the perfomance hit would be negligible compared to the gain in not
-// having to mask and shift flags all the time. Investigate after the
-// conversion to macro style opcodes is completed. :-)
-// [DONE--remain to be seen if there is any performance increase]
-
#define __DEBUG__
#define TEST_DONT_BRANCH_OPTIMIZATION
static uint16_t FetchMemW(uint16_t);
static inline void HandleInterrupt(uint16_t, uint16_t flag = 0);
-
//
// Read a word out of 63701 memory (little endian format)
//
return (uint16_t)(regs.RdMem(address) << 8) | regs.RdMem(address + 1);
}
-
//
// Fetch a word out of 63701 memory (little endian format). Increments PC
//
return (uint16_t)(regs.RdMem(address) << 8) | regs.RdMem(address + 1);
}
-
//
// 63701 OPCODE IMPLEMENTATION
//
OP_ADD_HANDLER(m, regs.d.acc.a);
}
-
static void Op9B(void) // ADDA ZP
{
uint16_t m = READ_ZP;
OP_ADD_HANDLER(m, regs.d.acc.a);
}
-
static void OpAB(void) // ADDA ZP, X
{
uint16_t m = READ_ZP_X;
OP_ADD_HANDLER(m, regs.d.acc.a);
}
-
static void OpBB(void) // ADDA ABS
{
uint16_t m = READ_ABS;
OP_ADD_HANDLER(m, regs.d.acc.a);
}
-
static void OpCB(void) // ADDB #
{
uint16_t m = READ_IMM;
OP_ADD_HANDLER(m, regs.d.acc.b);
}
-
static void OpDB(void) // ADDB ZP
{
uint16_t m = READ_ZP;
OP_ADD_HANDLER(m, regs.d.acc.b);
}
-
static void OpEB(void) // ADDB ZP, X
{
uint16_t m = READ_ZP_X;
OP_ADD_HANDLER(m, regs.d.acc.b);
}
-
static void OpFB(void) // ADDB ABS
{
uint16_t m = READ_ABS;
OP_ADD_HANDLER(m, regs.d.acc.b);
}
-
static void Op1B(void) // ABA
{
OP_ADD_HANDLER(regs.d.acc.b, regs.d.acc.a);
}
-
static void Op3A(void) // ABX
{
// Seems this one does *not* affect any flags...
regs.x += (uint16_t)regs.d.acc.b;
}
-
static void OpC3(void) // ADDD #
{
uint16_t m = READ_IMM16;
OP_ADD_HANDLER16(m, regs.d.word);
}
-
static void OpD3(void) // ADDD ZP
{
uint16_t m = READ_ZP16;
OP_ADD_HANDLER16(m, regs.d.word);
}
-
static void OpE3(void) // ADDD ZP, X
{
uint16_t m = READ_ZP_X16;
OP_ADD_HANDLER16(m, regs.d.word);
}
-
static void OpF3(void) // ADDD ABS
{
uint16_t m = READ_ABS16;
OP_ADD_HANDLER16(m, regs.d.word);
}
-
/*
Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
| |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
OP_ADC_HANDLER(m, regs.d.acc.a);
}
-
static void Op99(void) // ADCA ZP
{
uint16_t m = READ_ZP;
OP_ADC_HANDLER(m, regs.d.acc.a);
}
-
static void OpA9(void) // ADCA ZP, X
{
uint16_t m = READ_ZP_X;
OP_ADC_HANDLER(m, regs.d.acc.a);
}
-
static void OpB9(void) // ADCA ABS
{
uint16_t m = READ_ABS;
OP_ADC_HANDLER(m, regs.d.acc.a);
}
-
static void OpC9(void) // ADCB #
{
uint16_t m = READ_IMM;
OP_ADC_HANDLER(m, regs.d.acc.b);
}
-
static void OpD9(void) // ADCB ZP
{
uint16_t m = READ_ZP;
OP_ADC_HANDLER(m, regs.d.acc.b);
}
-
static void OpE9(void) // ADCB ZP, X
{
uint16_t m = READ_ZP_X;
OP_ADC_HANDLER(m, regs.d.acc.b);
}
-
static void OpF9(void) // ADCB ABS
{
uint16_t m = READ_ABS;
OP_ADC_HANDLER(m, regs.d.acc.b);
}
-
/*
Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
| |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
OP_AND_HANDLER(m, regs.d.acc.a);
}
-
static void Op94(void) // ANDA ZP
{
uint8_t m = READ_ZP;
OP_AND_HANDLER(m, regs.d.acc.a);
}
-
static void OpA4(void) // ANDA ZP, X
{
uint16_t m = READ_ZP_X;
OP_AND_HANDLER(m, regs.d.acc.a);
}
-
static void OpB4(void) // ANDA ABS
{
uint16_t m = READ_ABS;
OP_AND_HANDLER(m, regs.d.acc.a);
}
-
static void OpC4(void) // ANDB #
{
uint8_t m = READ_IMM;
OP_AND_HANDLER(m, regs.d.acc.b);
}
-
static void OpD4(void) // ANDB ZP
{
uint8_t m = READ_ZP;
OP_AND_HANDLER(m, regs.d.acc.b);
}
-
static void OpE4(void) // ANDB ZP, X
{
uint16_t m = READ_ZP_X;
OP_AND_HANDLER(m, regs.d.acc.b);
}
-
static void OpF4(void) // ANDB ABS
{
uint16_t m = READ_ABS;
OP_AND_HANDLER(m, regs.d.acc.b);
}
-
static void Op61(void) // AIM ZP, X (AND immediate with index)
{
uint8_t m;
WRITE_BACK(m);
}
-
static void Op71(void) // AIM ZP (AND immediate with zero page)
{
uint8_t m;
WRITE_BACK(m);
}
-
/*
Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
| |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
OP_BIT_HANDLER(m, regs.d.acc.a);
}
-
static void Op95(void) // BITA ZP
{
uint8_t m = READ_ZP;
OP_BIT_HANDLER(m, regs.d.acc.a);
}
-
static void OpA5(void) // BITA ZP, X
{
uint8_t m = READ_ZP_X;
OP_BIT_HANDLER(m, regs.d.acc.a);
}
-
static void OpB5(void) // BITA ABS
{
uint8_t m = READ_ABS;
OP_BIT_HANDLER(m, regs.d.acc.a);
}
-
static void OpC5(void) // BITB #
{
uint8_t m = READ_IMM;
OP_BIT_HANDLER(m, regs.d.acc.b);
}
-
static void OpD5(void) // BITB ZP
{
uint8_t m = READ_ZP;
OP_BIT_HANDLER(m, regs.d.acc.b);
}
-
static void OpE5(void) // BITB ZP, X
{
uint8_t m = READ_ZP_X;
OP_BIT_HANDLER(m, regs.d.acc.b);
}
-
static void OpF5(void) // BITB ABS
{
uint8_t m = READ_ABS;
SET_Z(0);
}
-
static void Op7F(void) // CLR ABS
{
regs.WrMem(EA_ABS, 0);
SET_Z(0);
}
-
static void Op4F(void) // CLRA
{
regs.d.acc.a = 0;
SET_Z(0);
}
-
static void Op5F(void) // CLRB
{
regs.d.acc.b = 0;
OP_CMP_HANDLER(m, regs.d.acc.a);
}
-
static void Op91(void) // CMPA ZP
{
uint8_t m = READ_ZP;
OP_CMP_HANDLER(m, regs.d.acc.a);
}
-
static void OpA1(void) // CMPA ZP, X
{
uint8_t m = READ_ZP_X;
OP_CMP_HANDLER(m, regs.d.acc.a);
}
-
static void OpB1(void) // CMPA ABS
{
uint8_t m = READ_ABS;
OP_CMP_HANDLER(m, regs.d.acc.a);
}
-
static void OpC1(void) // CMPB #
{
uint8_t m = READ_IMM;
OP_CMP_HANDLER(m, regs.d.acc.b);
}
-
static void OpD1(void) // CMPB ZP
{
uint8_t m = READ_ZP;
OP_CMP_HANDLER(m, regs.d.acc.b);
}
-
static void OpE1(void) // CMPB ZP, X
{
uint8_t m = READ_ZP_X;
OP_CMP_HANDLER(m, regs.d.acc.b);
}
-
static void OpF1(void) // CMPB ABS
{
uint8_t m = READ_ABS;
OP_CMP_HANDLER(m, regs.d.acc.b);
}
-
static void Op11(void) // CBA
{
OP_CMP_HANDLER(regs.d.acc.b, regs.d.acc.a);
WRITE_BACK(m);
}
-
static void Op73(void) // COM ABS
{
uint8_t m;
WRITE_BACK(m);
}
-
static void Op43(void) // COMA
{
OP_COM_HANDLER(regs.d.acc.a);
}
-
static void Op53(void) // COMB
{
OP_COM_HANDLER(regs.d.acc.b);
WRITE_BACK(m);
}
-
static void Op70(void) // NEG ABS
{
uint8_t m;
WRITE_BACK(m);
}
-
static void Op40(void) // NEGA
{
OP_NEG_HANDLER(regs.d.acc.a);
}
-
static void Op50(void) // NEGB
{
OP_NEG_HANDLER(regs.d.acc.b);
WRITE_BACK(m);
}
-
static void Op7A(void) // DEC ABS
{
uint8_t m;
WRITE_BACK(m);
}
-
static void Op4A(void) // DECA
{
OP_DEC_HANDLER(regs.d.acc.a);
}
-
static void Op5A(void) // DECB
{
OP_DEC_HANDLER(regs.d.acc.b);
OP_EOR_HANDLER(m, regs.d.acc.a);
}
-
static void Op98(void) // EORA ZP
{
uint8_t m = READ_ZP;
OP_EOR_HANDLER(m, regs.d.acc.a);
}
-
static void OpA8(void) // EORA ZP, X
{
uint8_t m = READ_ZP_X;
OP_EOR_HANDLER(m, regs.d.acc.a);
}
-
static void OpB8(void) // EORA ABS
{
uint8_t m = READ_ABS;
OP_EOR_HANDLER(m, regs.d.acc.a);
}
-
static void OpC8(void) // EORB #
{
uint8_t m = READ_IMM;
OP_EOR_HANDLER(m, regs.d.acc.b);
}
-
static void OpD8(void) // EORB ZP
{
uint8_t m = READ_ZP;
OP_EOR_HANDLER(m, regs.d.acc.b);
}
-
static void OpE8(void) // EORB ZP, X
{
uint8_t m = READ_ZP_X;
OP_EOR_HANDLER(m, regs.d.acc.b);
}
-
static void OpF8(void) // EORB ABS
{
uint8_t m = READ_ABS;
OP_EOR_HANDLER(m, regs.d.acc.b);
}
-
static void Op65(void) // EIM ZP, X (EOR immediate with index)
{
uint8_t m;
WRITE_BACK(m);
}
-
static void Op75(void) // EIM ZP (EOR immediate with zero page)
{
uint8_t m;
WRITE_BACK(m);
}
-
/*
Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
| |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
WRITE_BACK(m);
}
-
static void Op7C(void) // INC ABS
{
uint8_t m;
WRITE_BACK(m);
}
-
static void Op4C(void) // INCA
{
OP_INC_HANDLER(regs.d.acc.a);
}
-
static void Op5C(void) // INCB
{
OP_INC_HANDLER(regs.d.acc.b);
OP_LDA_HANDLER(m, regs.d.acc.a);
}
-
static void Op96(void) // LDAA ZP
{
uint8_t m = READ_ZP;
OP_LDA_HANDLER(m, regs.d.acc.a);
}
-
static void OpA6(void) // LDAA ZP, X
{
uint8_t m = READ_ZP_X;
OP_LDA_HANDLER(m, regs.d.acc.a);
}
-
static void OpB6(void) // LDAA ABS
{
uint8_t m = READ_ABS;
OP_LDA_HANDLER(m, regs.d.acc.a);
}
-
static void OpC6(void) // LDAB #
{
uint8_t m = READ_IMM;
OP_LDA_HANDLER(m, regs.d.acc.b);
}
-
static void OpD6(void) // LDAB ZP
{
uint8_t m = READ_ZP;
OP_LDA_HANDLER(m, regs.d.acc.b);
}
-
static void OpE6(void) // LDAB ZP, X
{
uint8_t m = READ_ZP_X;
OP_LDA_HANDLER(m, regs.d.acc.b);
}
-
static void OpF6(void) // LDAB ABS
{
uint8_t m = READ_ABS;
OP_LDA_HANDLER(m, regs.d.acc.b);
}
-
/*
Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
| |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
OP_ORA_HANDLER(m, regs.d.acc.a);
}
-
static void Op9A(void) // ORAA ZP
{
uint8_t m = READ_ZP;
OP_ORA_HANDLER(m, regs.d.acc.a);
}
-
static void OpAA(void) // ORAA ZP, X
{
uint8_t m = READ_ZP_X;
OP_ORA_HANDLER(m, regs.d.acc.a);
}
-
static void OpBA(void) // ORAA ABS
{
uint8_t m = READ_ABS;
OP_ORA_HANDLER(m, regs.d.acc.a);
}
-
static void OpCA(void) // ORAB #
{
uint8_t m = READ_IMM;
OP_ORA_HANDLER(m, regs.d.acc.b);
}
-
static void OpDA(void) // ORAB ZP
{
uint8_t m = READ_ZP;
OP_ORA_HANDLER(m, regs.d.acc.b);
}
-
static void OpEA(void) // ORAB ZP, X
{
uint8_t m = READ_ZP_X;
OP_ORA_HANDLER(m, regs.d.acc.b);
}
-
static void OpFA(void) // ORAB ABS
{
uint8_t m = READ_ABS;
OP_ORA_HANDLER(m, regs.d.acc.b);
}
-
static void Op62(void) // OIM ZP, X (ORA immediate with index)
{
uint8_t m;
WRITE_BACK(m);
}
-
static void Op72(void) // OIM ZP (ORA immediate with zero page)
{
uint8_t m;
WRITE_BACK(m);
}
-
/*
Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
| |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
PUSH(regs.d.acc.a);
}
-
static void Op37(void) // PSHB
{
PUSH(regs.d.acc.b);
}
-
static void Op32(void) // PULA
{
regs.d.acc.a = PULL;
}
-
static void Op33(void) // PULB
{
regs.d.acc.b = PULL;
}
-
static void Op38(void) // PULX
{
regs.x = PULL16;
}
-
static void Op3C(void) // PSHX
{
PUSH16(regs.x);
}
-
/*
Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
| |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
WRITE_BACK(m);
}
-
static void Op79(void) // ROL ABS
{
uint8_t m;
WRITE_BACK(m);
}
-
static void Op49(void) // ROLA
{
OP_ROL_HANDLER(regs.d.acc.a);
}
-
static void Op59(void) // ROLB
{
OP_ROL_HANDLER(regs.d.acc.b);
WRITE_BACK(m);
}
-
static void Op76(void) // ROR ABS
{
uint8_t m;
WRITE_BACK(m);
}
-
static void Op46(void) // RORA
{
OP_ROR_HANDLER(regs.d.acc.a);
}
-
static void Op56(void) // RORB
{
OP_ROR_HANDLER(regs.d.acc.b);
WRITE_BACK(m);
}
-
static void Op78(void) // ASL ABS
{
uint8_t m;
WRITE_BACK(m);
}
-
static void Op48(void) // ASLA
{
OP_ASL_HANDLER(regs.d.acc.a);
}
-
static void Op58(void) // ASLB
{
OP_ASL_HANDLER(regs.d.acc.b);
}
-
static void Op05(void) // ASLD
{
uint8_t newCarry = (regs.d.word & 0x8000) >> 15;
flagV = flagN ^ flagC;
}
-
/*
Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
| |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
WRITE_BACK(m);
}
-
static void Op77(void) // ASR ABS
{
uint8_t m;
WRITE_BACK(m);
}
-
static void Op47(void) // ASRA
{
OP_ASR_HANDLER(regs.d.acc.a);
}
-
static void Op57(void) // ASRB
{
OP_ASR_HANDLER(regs.d.acc.b);
}
-
/*
Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
| |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
WRITE_BACK(m);
}
-
static void Op74(void) // LSR ABS
{
uint8_t m;
WRITE_BACK(m);
}
-
static void Op44(void) // LSRA
{
OP_LSR_HANDLER(regs.d.acc.a);
}
-
static void Op54(void) // LSRB
{
OP_LSR_HANDLER(regs.d.acc.b);
}
-
static void Op04(void) // LSRD
{
uint8_t newCarry = regs.d.word & 0x01;
flagV = flagN ^ flagC;
}
-
/*
Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
| |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
regs.WrMem(EA_ZP, regs.d.acc.a);
}
-
static void OpA7(void) // STAA ZP, X
{
regs.WrMem(EA_ZP_X, regs.d.acc.a);
}
-
static void OpB7(void) // STAA ABS
{
regs.WrMem(EA_ABS, regs.d.acc.a);
}
-
static void OpD7(void) // STAB ZP
{
regs.WrMem(EA_ZP, regs.d.acc.b);
}
-
static void OpE7(void) // STAB ZP, X
{
regs.WrMem(EA_ZP_X, regs.d.acc.b);
}
-
static void OpF7(void) // STAB ABS
{
regs.WrMem(EA_ABS, regs.d.acc.b);
}
-
// These are illegal instructions!
#if 0
static void Op87(void) // STA #
}
#endif
-
/*
Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
| |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
OP_SUB_HANDLER(m, regs.d.acc.a);
}
-
static void Op90(void) // SUBA ZP
{
uint16_t m = READ_ZP;
OP_SUB_HANDLER(m, regs.d.acc.a);
}
-
static void OpA0(void) // SUBA ZP, X
{
uint16_t m = READ_ZP_X;
OP_SUB_HANDLER(m, regs.d.acc.a);
}
-
static void OpB0(void) // SUBA ABS
{
uint16_t m = READ_ABS;
OP_SUB_HANDLER(m, regs.d.acc.a);
}
-
static void OpC0(void) // SUBB #
{
uint16_t m = READ_IMM;
OP_SUB_HANDLER(m, regs.d.acc.b);
}
-
static void OpD0(void) // SUBB ZP
{
uint16_t m = READ_ZP;
OP_SUB_HANDLER(m, regs.d.acc.b);
}
-
static void OpE0(void) // SUBB ZP, X
{
uint16_t m = READ_ZP_X;
OP_SUB_HANDLER(m, regs.d.acc.b);
}
-
static void OpF0(void) // SUBB ABS
{
uint16_t m = READ_ABS;
OP_SUB_HANDLER(m, regs.d.acc.b);
}
-
static void Op10(void) // SBA
{
OP_SUB_HANDLER(regs.d.acc.b, regs.d.acc.a);
}
-
static void Op83(void) // SUBD #
{
uint16_t m = READ_IMM16;
OP_SUB_HANDLER16(m, regs.d.word);
}
-
static void Op93(void) // SUBD ZP
{
uint16_t m = READ_ZP16;
OP_SUB_HANDLER16(m, regs.d.word);
}
-
static void OpA3(void) // SUBD ZP, X
{
uint16_t m = READ_ZP_X16;
OP_SUB_HANDLER16(m, regs.d.word);
}
-
static void OpB3(void) // SUBD ABS
{
uint16_t m = READ_ABS16;
OP_SUB_HANDLER16(m, regs.d.word);
}
-
/*
Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
| |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
OP_SBC_HANDLER(m, regs.d.acc.a);
}
-
static void Op92(void) // SBCA ZP
{
uint16_t m = READ_ZP;
OP_SBC_HANDLER(m, regs.d.acc.a);
}
-
static void OpA2(void) // SBCA ZP, X
{
uint16_t m = READ_ZP_X;
OP_SBC_HANDLER(m, regs.d.acc.a);
}
-
static void OpB2(void) // SBCA ABS
{
uint16_t m = READ_ABS;
OP_SBC_HANDLER(m, regs.d.acc.a);
}
-
static void OpC2(void) // SBCB #
{
uint16_t m = READ_IMM;
OP_SBC_HANDLER(m, regs.d.acc.b);
}
-
static void OpD2(void) // SBCB ZP
{
uint16_t m = READ_ZP;
OP_SBC_HANDLER(m, regs.d.acc.b);
}
-
static void OpE2(void) // SBCB ZP, X
{
uint16_t m = READ_ZP_X;
OP_SBC_HANDLER(m, regs.d.acc.b);
}
-
static void OpF2(void) // SBCB ABS
{
uint16_t m = READ_ABS;
CLR_V;
}
-
static void Op17(void) // TBA
{
regs.d.acc.a = regs.d.acc.b;
#endif
}
-
static void Op7D(void) // TST ABS
{
#if 0
#endif
}
-
static void Op4D(void) // TSTA
{
OP_TST_HANDLER(regs.d.acc.a);
}
-
static void Op5D(void) // TSTB
{
OP_TST_HANDLER(regs.d.acc.b);
}
-
static void Op6B(void) // TIM ZP, X (TST immediate with index)
{
// uint8_t m;
// WRITE_BACK(m);
}
-
static void Op7B(void) // TIM ZP (TST immediate with zero page)
{
// uint8_t m;
// WRITE_BACK(m);
}
-
/*
Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
| |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
OP_CPX_HANDLER(m);
}
-
static void Op9C(void) // CPX ZP
{
uint16_t m = READ_ZP16;
OP_CPX_HANDLER(m);
}
-
static void OpAC(void) // CPX ZP, X
{
uint16_t m = READ_ZP_X16;
OP_CPX_HANDLER(m);
}
-
static void OpBC(void) // CPX ABS
{
uint16_t m = READ_ABS16;
SET_Z(regs.x);
}
-
static void Op34(void) // DES
{
regs.s--;
}
-
static void Op08(void) // INX
{
regs.x++;
SET_Z(regs.x);
}
-
static void Op31(void) // INS
{
regs.s++;
OP_LD_HANDLER(regs.x);
}
-
static void OpDE(void) // LDX ZP
{
regs.x = READ_ZP16;
OP_LD_HANDLER(regs.x);
}
-
static void OpEE(void) // LDX ZP, X
{
regs.x = READ_ZP_X16;
OP_LD_HANDLER(regs.x);
}
-
static void OpFE(void) // LDX ABS
{
regs.x = READ_ABS16;
OP_LD_HANDLER(regs.x);
}
-
static void Op8E(void) // LDS #
{
regs.s = READ_IMM16;
OP_LD_HANDLER(regs.s);
}
-
static void Op9E(void) // LDS ZP
{
regs.s = READ_ZP16;
OP_LD_HANDLER(regs.s);
}
-
static void OpAE(void) // LDS ZP, X
{
regs.s = READ_ZP_X16;
OP_LD_HANDLER(regs.s);
}
-
static void OpBE(void) // LDS ABS
{
regs.s = READ_ABS16;
OP_LD_HANDLER(regs.s);
}
-
static void OpCC(void) // LDD #
{
regs.d.word = READ_IMM16;
OP_LD_HANDLER(regs.d.word);
}
-
static void OpDC(void) // LDD ZP
{
regs.d.word = READ_ZP16;
OP_LD_HANDLER(regs.d.word);
}
-
static void OpEC(void) // LDD ZP, X
{
regs.d.word = READ_ZP_X16;
OP_LD_HANDLER(regs.d.word);
}
-
static void OpFC(void) // LDD ABS
{
regs.d.word = READ_ABS16;
OP_LD_HANDLER(regs.d.word);
}
-
/*
Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
| |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
OP_ST_HANDLER(m, regs.x);
}
-
static void OpEF(void) // STX ZP, X
{
uint16_t m = EA_ZP_X;
OP_ST_HANDLER(m, regs.x);
}
-
static void OpFF(void) // STX ABS
{
uint16_t m = EA_ABS;
OP_ST_HANDLER(m, regs.x);
}
-
static void Op9F(void) // STS ZP
{
uint16_t m = EA_ZP;
OP_ST_HANDLER(m, regs.s);
}
-
static void OpAF(void) // STS ZP, X
{
uint16_t m = EA_ZP_X;
OP_ST_HANDLER(m, regs.s);
}
-
static void OpBF(void) // STS ABS
{
uint16_t m = EA_ABS;
OP_ST_HANDLER(m, regs.s);
}
-
// These are illegal instructions!
#if 0
// Store immediate--nonsensical opcodes :-P
OP_ST_HANDLER(effectiveAddress, regs.s);
}
-
static void OpCF(void) // STX #
{
uint16_t effectiveAddress = regs.pc;
OP_ST_HANDLER(effectiveAddress, regs.x);
}
-
static void OpCD(void) // STD #
{
uint16_t effectiveAddress = regs.pc;
}
#endif
-
static void OpDD(void) // STD ZP
{
uint16_t m = EA_ZP;
OP_ST_HANDLER(m, regs.d.word);
}
-
static void OpED(void) // STD ZP, X
{
uint16_t m = EA_ZP_X;
OP_ST_HANDLER(m, regs.d.word);
}
-
static void OpFD(void) // STD ABS
{
uint16_t m = EA_ABS;
OP_ST_HANDLER(m, regs.d.word);
}
-
/*
Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
| |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
regs.s = regs.x - 1;
}
-
static void Op30(void) // TSX
{
regs.x = regs.s + 1;
regs.pc += m;
}
-
static void Op21(void) // BRN
{
int16_t m = (int16_t)(int8_t)READ_IMM;
// regs.pc += m;
}
-
static void Op24(void) // BCC
{
// NOTE: We can optimize this by following the maxim: "Don't branch!" by
#endif
}
-
static void Op25(void) // BCS
{
int16_t m = (int16_t)(int8_t)READ_IMM;
#endif
}
-
static void Op27(void) // BEQ
{
int16_t m = (int16_t)(int8_t)READ_IMM;
#endif
}
-
static void Op2C(void) // BGE
{
int16_t m = (int16_t)(int8_t)READ_IMM;
#endif
}
-
static void Op2E(void) // BGT
{
int16_t m = (int16_t)(int8_t)READ_IMM;
#endif
}
-
static void Op22(void) // BHI
{
int16_t m = (int16_t)(int8_t)READ_IMM;
#endif
}
-
static void Op2F(void) // BLE
{
int16_t m = (int16_t)(int8_t)READ_IMM;
#endif
}
-
static void Op23(void) // BLS
{
int16_t m = (int16_t)(int8_t)READ_IMM;
#endif
}
-
static void Op2D(void) // BLT
{
int16_t m = (int16_t)(int8_t)READ_IMM;
#endif
}
-
static void Op2B(void) // BMI
{
int16_t m = (int16_t)(int8_t)READ_IMM;
#endif
}
-
static void Op26(void) // BNE
{
int16_t m = (int16_t)(int8_t)READ_IMM;
#endif
}
-
static void Op28(void) // BVC
{
int16_t m = (int16_t)(int8_t)READ_IMM;
#endif
}
-
static void Op29(void) // BVS
{
int16_t m = (int16_t)(int8_t)READ_IMM;
#endif
}
-
static void Op2A(void) // BPL
{
int16_t m = (int16_t)(int8_t)READ_IMM;
regs.pc += m;
}
-
static void Op6E(void) // JMP ZP, X
{
uint16_t m = EA_ZP_X;
regs.pc = m;
}
-
static void Op7E(void) // JMP ABS
{
regs.pc = EA_ABS;
}
-
static void Op9D(void) // JSR ZP
{
uint16_t m = (uint16_t)EA_ZP;
regs.pc = m;
}
-
static void OpAD(void) // JSR ZP, X
{
uint16_t m = EA_ZP_X;
regs.pc = m;
}
-
static void OpBD(void) // JSR ABS
{
uint16_t m = EA_ABS;
regs.pc = m;
}
-
/*
Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
| |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
{
}
-
static void Op3B(void) // RTI
{
regs.cc = PULL;
UNPACK_FLAGS;
}
-
static void Op39(void) // RTS
{
regs.pc = PULL16;
}
-
static void Op3F(void) // SWI
{
// It seems that the SWI is non-maskable, unlike the IRQ...
HandleInterrupt(0xFFFA);
}
-
static void Op3E(void) // WAI
{
#ifdef __DEBUG__
regs.cpuFlags |= V63701_STATE_WAI; // And signal that we're in WAI mode
}
-
// Multiply opcode
static void Op3D(void) // MUL
flagC = regs.d.acc.b >> 7; // bug? No, this is how it really does it
}
-
// Exchange X and D opcode
static void Op18(void) // XGDX
regs.d.word = temp;
}
-
// Sleep opcode (similar to WAI)
static void Op1A(void) // SLP
regs.cpuFlags |= V63701_STATE_WAI;
}
-
// Undocumented opcode ($12 & $13)
static void OpUN(void) // Undocumented
regs.x += regs.RdMem(regs.s + 1);
}
-
/*
Operation |Mnem.|Immed.|Direct|Index |Extend|Inher.|Operation |CC Reg|
| |OP ~ #|OP ~ #|OP ~ #|OP ~ #|OP ~ #| |HINZVC|
flagC = 0;
}
-
static void Op0E(void) // CLI
{
flagI = 0;
}
-
static void Op0A(void) // CLV
{
flagV = 0;
}
-
static void Op0D(void) // SEC
{
flagC = 1;
}
-
static void Op0F(void) // SEI
{
flagI = 1;
}
-
static void Op0B(void) // SEV
{
flagV = 1;
}
-
static void Op06(void) // TAP
{
regs.cc = regs.d.acc.a;
UNPACK_FLAGS;
}
-
static void Op07(void) // TPA
{
regs.d.acc.a = PACK_FLAGS;
}
-
/*
OP Operation Code, in Hexadecimal
~ Number of MPU cycles required
4: M=Xh, M+1=Xl
*/
-
static void Op__(void)
{
// TRAP is non-maskable, unlike the IRQ... Also, highest priority after
// regs.cpuFlags |= V63701_STATE_ILLEGAL_INST;
}
-
//
// Ok, the exec_op[] array is globally defined here basically to save
// a LOT of unnecessary typing. Sure it's ugly, but hey, it works!
OpF0, OpF1, OpF2, OpF3, OpF4, OpF5, OpF6, OpF7, OpF8, OpF9, OpFA, OpFB, OpFC, OpFD, OpFE, OpFF
};
-
//
// Internal "memcpy" (so we don't have to link with any external libraries!)
//
d[i] = s[i];
}
-
#ifdef __DEBUG__
//int instCount[256];
bool V63701LogGo = false;
if (regs.cpuFlags & V63701_STATE_WAI)
{
// Only bail out if no interrupts/resets are pending
- if (!(regs.cpuFlags & (V63701_ASSERT_LINE_IRQ | V63701_ASSERT_LINE_NMI | V63701_ASSERT_LINE_RESET | V63701_ASSERT_TIMER_OVERFLOW | V63701_ASSERT_OUTPUT_COMPARE | V63701_ASSERT_INPUT_CAPTURE)))
+ if (!(regs.cpuFlags & (V63701_LINE_IRQ | V63701_LINE_NMI | V63701_LINE_RESET | V63701_TIMER_OVERFLOW | V63701_OUTPUT_COMPARE | V63701_INPUT_CAPTURE)))
// Burn any remaining cycles...
regs.clock = endCycles;
}
if (regs.tcsr.bit.eoci)
{
- regs.cpuFlags |= V63701_ASSERT_OUTPUT_COMPARE;
- regsPointer->cpuFlags |= V63701_ASSERT_OUTPUT_COMPARE;
+ regs.cpuFlags |= V63701_OUTPUT_COMPARE;
+ regsPointer->cpuFlags |= V63701_OUTPUT_COMPARE;
}
}
if (regs.tcsr.bit.etoi)
{
- regs.cpuFlags |= V63701_ASSERT_TIMER_OVERFLOW;
- regsPointer->cpuFlags |= V63701_ASSERT_TIMER_OVERFLOW;
+ regs.cpuFlags |= V63701_TIMER_OVERFLOW;
+ regsPointer->cpuFlags |= V63701_TIMER_OVERFLOW;
}
}
#ifdef __DEBUG__
#endif
}
- if (regs.cpuFlags & V63701_ASSERT_LINE_RESET)
+ if (regs.cpuFlags & V63701_LINE_RESET)
{
#ifdef __DEBUG__
if (V63701LogGo)
context->cpuFlags = 0; // Clear all lingering flags...
regs.cpuFlags = 0;
}
- else if (regs.cpuFlags & V63701_ASSERT_LINE_NMI)
+ else if (regs.cpuFlags & V63701_LINE_NMI)
{
#ifdef __DEBUG__
if (V63701LogGo)
WriteLog("*** NMI LINE ASSERTED ***\n");
#endif
- HandleInterrupt(0xFFFC, V63701_ASSERT_LINE_NMI);
+ HandleInterrupt(0xFFFC, V63701_LINE_NMI);
}
- else if (regs.cpuFlags & V63701_ASSERT_LINE_IRQ)
+ else if (regs.cpuFlags & V63701_LINE_IRQ)
{
#ifdef __DEBUG__
if (V63701LogGo)
WriteLog(" IRQ TAKEN!\n");
//V63701LogGo = true;
#endif
- HandleInterrupt(0xFFF8, V63701_ASSERT_LINE_IRQ);
+ HandleInterrupt(0xFFF8, V63701_LINE_IRQ);
}
}
- else if (regs.cpuFlags & V63701_ASSERT_INPUT_CAPTURE)
+ else if (regs.cpuFlags & V63701_INPUT_CAPTURE)
{
#ifdef __DEBUG__
if (V63701LogGo)
WriteLog(" IC TAKEN!\n");
//V63701LogGo = true;
#endif
- HandleInterrupt(0xFFF6, V63701_ASSERT_INPUT_CAPTURE);
+ HandleInterrupt(0xFFF6, V63701_INPUT_CAPTURE);
}
}
- else if (regs.cpuFlags & V63701_ASSERT_OUTPUT_COMPARE)
+ else if (regs.cpuFlags & V63701_OUTPUT_COMPARE)
{
#ifdef __DEBUG__
if (V63701LogGo)
WriteLog(" OC TAKEN!\n");
//V63701LogGo = true;
#endif
- HandleInterrupt(0xFFF4, V63701_ASSERT_OUTPUT_COMPARE);
+ HandleInterrupt(0xFFF4, V63701_OUTPUT_COMPARE);
}
}
- else if (regs.cpuFlags & V63701_ASSERT_TIMER_OVERFLOW)
+ else if (regs.cpuFlags & V63701_TIMER_OVERFLOW)
{
#ifdef __DEBUG__
if (V63701LogGo)
WriteLog(" TO TAKEN!\n");
//V63701LogGo = true;
#endif
- HandleInterrupt(0xFFF2, V63701_ASSERT_TIMER_OVERFLOW);
+ HandleInterrupt(0xFFF2, V63701_TIMER_OVERFLOW);
}
}
}
myMemcpy(context, ®s, sizeof(V63701REGS));
}
-
//
// Get the clock of the currently executing CPU
//
return regs.clock;
}
-
static inline void HandleInterrupt(uint16_t vector, uint16_t flag/*= 0*/)
{
if (regs.cpuFlags & V63701_STATE_WAI)
regsPointer->cpuFlags &= ~(flag | V63701_STATE_WAI);
}
-
uint8_t InternalRegisterRead(uint16_t address)
{
switch (address & 0x1F)
return 0x00;
}
-
void InternalRegisterWrite(uint16_t address, uint8_t data)
{
uint8_t writeData;
#endif
}
}
-
// by James Hammons
// (C) 2014 Underground Software
//
-
#ifndef __V63701_H__
#define __V63701_H__
#define FLAG_V 0x02 // oVerflow
#define FLAG_C 0x01 // Carry
-#define V63701_ASSERT_LINE_RESET 0x0001 // v63701 RESET line
-#define V63701_ASSERT_LINE_IRQ 0x0002 // v63701 IRQ line
-#define V63701_ASSERT_LINE_NMI 0x0004 // v63701 NMI line
-#define V63701_STATE_WAI 0x0008 // v63701 wait for IRQ line
-#define V63701_ASSERT_TIMER_OVERFLOW 0x0010
-#define V63701_ASSERT_OUTPUT_COMPARE 0x0020
-#define V63701_ASSERT_INPUT_CAPTURE 0x0040
-#define V63701_ASSERT_TRAP 0x0080 // Illegal instruction executed flag
+#define V63701_LINE_RESET 0x0001 // v63701 RESET line
+#define V63701_LINE_IRQ 0x0002 // v63701 IRQ line
+#define V63701_LINE_NMI 0x0004 // v63701 NMI line
+#define V63701_STATE_WAI 0x0008 // v63701 wait for IRQ line
+#define V63701_TIMER_OVERFLOW 0x0010
+#define V63701_OUTPUT_COMPARE 0x0020
+#define V63701_INPUT_CAPTURE 0x0040
+#define V63701_TRAP 0x0080 // Illegal instruction executed flag
//#define V6809_START_DEBUG_LOG 0x8000 // Debug log go (temporary!)
// Useful structs
extern void V63701WritePort2(uint8_t);
#endif // __V63701_H__
-
//
-// Virtual 6809 v1.4.1
+// Virtual 6809 v1.4.2
//
-// by James L. Hammons
-// (C) 1997, 2009, 2014 Underground Software
+// by James Hammons
+// (C) 1997, 2009, 2014, 2023 Underground Software
//
-// JLH = James L. Hammons <jlhamm@acm.org>
+// JLH = James Hammons <jlhamm@acm.org>
//
// WHO WHEN WHAT
// --- ---------- -----------------------------------------------------------
// JLH 11/11/2006 Removed all SignedX() references
// JLH 09/29/2009 Converted V6809 to macro implementation!
// JLH 04/17/2014 Misc. cleanups, fixes to missing instructions
+// JLH 01/03/2023 Added missing clock cycles to indexed memory accesses
//
-#define __DEBUG__
-
#include "v6809.h"
-#ifdef __DEBUG__
-#include "dis6809.h" // Temporary...
-#include "log.h" // Temporary...
-bool disasm = false;//so we can extern this shit
-#endif
-
#define TEST_DONT_BRANCH_OPTIMIZATION
// Various macros
#define SET_V(a,b,r) (flagV = (((b) ^ (a) ^ (r) ^ ((r) >> 1)) & 0x80) >> 7)
#define SET_V16(a,b,r) (flagV = (((b) ^ (a) ^ (r) ^ ((r) >> 1)) & 0x8000) >> 15)
#define SET_H(a,b,r) (flagH = (((a) ^ (b) ^ (r)) & 0x10) >> 4)
-
-//Not sure that this code is computing the carry correctly... Investigate! [Seems to be]
-//#define SET_C_ADD(a,b) (flagC = ((uint8_t)(b) > (uint8_t)(~(a)) ? 1 : 0))
-//#define SET_C_SUB(a,b) (regs.cc = ((uint8_t)(b) >= (uint8_t)(a) ? regs.cc | FLAG_C : regs.cc & ~FLAG_C))
-//#define SET_C_CMP(a,b) (flagC = ((uint8_t)(b) >= (uint8_t)(a) ? 1 : 0))
#define SET_ZN(r) SET_N(r); SET_Z(r)
#define SET_ZN16(r) SET_N16(r); SET_Z(r)
-//#define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
-//#define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
-//#define SET_ZNC_CMP(a,b,r) SET_N(r); SET_Z(r); SET_C_CMP(a,b)
#define EA_IMM regs.pc++
#define EA_DP (regs.dp << 8) | regs.RdMem(regs.pc++)
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // $Fx
};
+// Cycle counts for PUL/PSHx instructions
+static uint8_t bitCount[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
+
// Private function prototypes
static uint16_t RdMemW(uint16_t addr);
static uint16_t DecodeReg(uint8_t); // Decode register data
static uint16_t DecodeIDX(uint8_t); // Decode IDX data
-
//
// Read word from memory function
//
return (uint16_t)(regs.RdMem(addr) << 8) | regs.RdMem(addr + 1);
}
-
//
// Fetch a word from memory function. Increments PC
//
return (uint16_t)(regs.RdMem(addr) << 8) | regs.RdMem(addr + 1);
}
-
//
// Write word to memory function
//
regs.WrMem(addr + 1, w & 0xFF);
}
-
//
// Function to read TFR/EXG post byte
//
return retval;
}
-
//
// Function to set TFR/EXG data
//
}
}
-
//
// Function to decode register data
//
return retval;
}
-
//
// Function to decode IDX data
//
static uint16_t DecodeIDX(uint8_t code)
{
+/*
+Cycle counts are now taken into account here...
+
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+90 5 6 5 6 3 4 4 0 4 7 0 7 4 8 0 5
+B0 5 6 5 6 3 4 4 0 4 7 0 7 4 8 0 5
+D0 5 6 5 6 3 4 4 0 4 7 0 7 4 8 0 5
+F0 5 6 5 6 3 4 4 0 4 7 0 7 4 8 0 5
+
+80 2 3 2 3 0 1 1 0 1 4 0 4 1 5 0 5
+A0 2 3 2 3 0 1 1 0 1 4 0 4 1 5 0 5
+C0 2 3 2 3 0 1 1 0 1 4 0 4 1 5 0 5
+E0 2 3 2 3 0 1 1 0 1 4 0 4 1 5 0 5
+*/
uint16_t addr, woff;
+ int16_t offset;
uint8_t reg = (code & 0x60) >> 5, idxind = (code & 0x10) >> 4, lo_nyb = code & 0x0F;
if (!(code & 0x80)) // Hi bit unset? Then decode 4 bit offset
+ {
addr = DecodeReg(reg) + (idxind ? lo_nyb - 16 : lo_nyb);
+ regs.clock++;
+ }
else
{
if (idxind)
case 2: regs.u += 2; break;
case 3: regs.s += 2; break;
}
+ regs.clock += 6;
break;
case 3:
switch (reg)
}
woff = DecodeReg(reg);
addr = RdMemW(woff);
+ regs.clock += 6;
break;
case 4:
woff = DecodeReg(reg);
addr = RdMemW(woff);
+ regs.clock += 3;
break;
case 5:
woff = DecodeReg(reg) + (int16_t)(int8_t)regs.b;
addr = RdMemW(woff);
+ regs.clock += 4;
break;
case 6:
woff = DecodeReg(reg) + (int16_t)(int8_t)regs.a;
addr = RdMemW(woff);
+ regs.clock += 4;
break;
case 8:
woff = DecodeReg(reg) + (int16_t)(int8_t)regs.RdMem(regs.pc++);
addr = RdMemW(woff);
+ regs.clock += 4;
break;
case 9:
woff = DecodeReg(reg) + FetchMemW(regs.pc);
addr = RdMemW(woff);
+ regs.clock += 7;
break;
case 11:
woff = DecodeReg(reg) + ((regs.a << 8) | regs.b);
addr = RdMemW(woff);
+ regs.clock += 7;
break;
case 12:
// woff = regs.pc + (int16_t)(int8_t)regs.RdMem(regs.pc++);
+#if 1
+ // I believe this is the correct interpretation
+ offset = (int16_t)(int8_t)regs.RdMem(regs.pc++);
+ woff = regs.pc + offset;
+#else
woff = regs.pc + (int16_t)(int8_t)regs.RdMem(regs.pc);
regs.pc++;
+#endif
addr = RdMemW(woff);
+ regs.clock += 4;
break;
case 13:
woff = regs.pc + FetchMemW(regs.pc);
addr = RdMemW(woff);
+ regs.clock += 8;
break;
case 15:
woff = FetchMemW(regs.pc);
addr = RdMemW(woff);
+ regs.clock += 5;
break;
+ default:
+ addr = 0;
}
}
else
case 2: regs.u++; break;
case 3: regs.s++; break;
}
+ regs.clock += 2;
break;
case 1:
addr = DecodeReg(reg);
case 2: regs.u += 2; break;
case 3: regs.s += 2; break;
}
+ regs.clock += 3;
+ break;
+ case 2:
+ switch(reg)
+ {
+ case 0: regs.x--; break;
+ case 1: regs.y--; break;
+ case 2: regs.u--; break;
+ case 3: regs.s--; break;
+ }
+ addr = DecodeReg(reg);
+ regs.clock += 2;
+ break;
+ case 3:
+ switch(reg)
+ {
+ case 0: regs.x -= 2; break;
+ case 1: regs.y -= 2; break;
+ case 2: regs.u -= 2; break;
+ case 3: regs.s -= 2; break;
+ }
+ addr = DecodeReg(reg);
+ regs.clock += 3;
+ break;
+ case 4:
+ addr = DecodeReg(reg);
+ break;
+ case 5:
+ addr = DecodeReg(reg) + (int16_t)(int8_t)regs.b;
+ regs.clock++;
+ break;
+ case 6:
+ addr = DecodeReg(reg) + (int16_t)(int8_t)regs.a;
+ regs.clock++;
break;
- case 2: { switch(reg)
- {
- case 0: regs.x--; break;
- case 1: regs.y--; break;
- case 2: regs.u--; break;
- case 3: regs.s--; break;
- }
- addr = DecodeReg(reg); break; }
- case 3: { switch(reg)
- {
- case 0: regs.x--; regs.x--; break;
- case 1: regs.y--; regs.y--; break;
- case 2: regs.u--; regs.u--; break;
- case 3: regs.s--; regs.s--; break;
- }
- addr = DecodeReg(reg); break; }
- case 4: { addr = DecodeReg(reg); break; }
- case 5: { addr = DecodeReg(reg) + (int16_t)(int8_t)regs.b; break; }
- case 6: { addr = DecodeReg(reg) + (int16_t)(int8_t)regs.a; break; }
- case 8: { addr = DecodeReg(reg) + (int16_t)(int8_t)regs.RdMem(regs.pc++); break; }
- case 9: { addr = DecodeReg(reg) + FetchMemW(regs.pc); break; }
- case 11: { addr = DecodeReg(reg) + ((regs.a << 8) | regs.b); break; }
-// case 12: { addr = regs.pc + (int16_t)(int8_t)regs.RdMem(regs.pc++); break; }
- case 12: { addr = regs.pc + (int16_t)(int8_t)regs.RdMem(regs.pc); regs.pc++; break; }
- case 13: { addr = regs.pc + FetchMemW(regs.pc); break; }
+ case 8:
+ addr = DecodeReg(reg) + (int16_t)(int8_t)regs.RdMem(regs.pc++);
+ regs.clock++;
+ break;
+ case 9:
+ addr = DecodeReg(reg) + FetchMemW(regs.pc);
+ regs.clock += 4;
+ break;
+ case 11:
+ addr = DecodeReg(reg) + ((regs.a << 8) | regs.b);
+ regs.clock += 4;
+ break;
+ case 12:
+// addr = regs.pc + (int16_t)(int8_t)regs.RdMem(regs.pc++);
+#if 1
+ // I believe this is the correct interpretation of the above
+ offset = (int16_t)(int8_t)regs.RdMem(regs.pc++);
+ addr = regs.pc + offset;
+#else
+ addr = regs.pc + (int16_t)(int8_t)regs.RdMem(regs.pc);
+ regs.pc++;
+#endif
+ regs.clock++;
+ break;
+ case 13:
+ addr = regs.pc + FetchMemW(regs.pc);
+ regs.clock += 5;
+ break;
+ default:
+ addr = 0;
}
}
}
acc = sum & 0xFF; \
SET_ZN(acc)
-/*
-Old flag handling code:
- (addr > 0x00FF ? regs.cc |= 0x01 : regs.cc &= 0xFE); // Adjust Carry
- ((regs.a^tmp^addr)&0x10 ? regs.cc |= 0x20 : regs.cc &= 0xDF); // Set Half carry
- ((regs.a^tmp^addr^(regs.cc<<7))&0x80 ? regs.cc |= 0x02 : regs.cc &= 0xFD); // oVerflow
- regs.a = addr & 0xFF; // Set accumulator
- (regs.a == 0 ? regs.cc |= 0x04 : regs.cc &= 0xFB); // Adjust Zero
- (regs.a&0x80 ? regs.cc |= 0x08 : regs.cc &= 0xF7); // Adjust Negative
-*/
-
static void Op89(void) // ADCA #
{
uint16_t m = READ_IMM;
OP_ADC_HANDLER(m, regs.a);
}
-
static void Op99(void) // ADCA DP
{
uint16_t m = READ_DP;
OP_ADC_HANDLER(m, regs.a);
}
-
static void OpA9(void) // ADCA IDX
{
uint16_t m = READ_IDX;
OP_ADC_HANDLER(m, regs.a);
}
-
static void OpB9(void) // ADCA ABS
{
uint16_t m = READ_ABS;
OP_ADC_HANDLER(m, regs.a);
}
-
static void OpC9(void) // ADCB #
{
uint16_t m = READ_IMM;
OP_ADC_HANDLER(m, regs.b);
}
-
static void OpD9(void) // ADCB DP
{
uint16_t m = READ_DP;
OP_ADC_HANDLER(m, regs.b);
}
-
static void OpE9(void) // ADCB IDX
{
uint16_t m = READ_IDX;
OP_ADC_HANDLER(m, regs.b);
}
-
static void OpF9(void) // ADCB ABS
{
uint16_t m = READ_ABS;
OP_ADC_HANDLER(m, regs.b);
}
-
/*
+-----------------------------------------------------------------+
| Opcode | | Addressing | | |
loreg = acc & 0xFF; \
SET_ZN16(acc)
-/*
-Old flags:
- (addr > 0xFF ? regs.cc |= 0x01 : regs.cc &= 0xFE); // Set Carry flag
- ((regs.a^tmp^addr)&0x10 ? regs.cc |= 0x20 : regs.cc &= 0xDF); // Set Half carry
- ((regs.a^tmp^addr^(regs.cc<<7))&0x80 ? regs.cc |= 0x02 : regs.cc &= 0xFD); // oVerflow
- regs.a = addr & 0xFF; // Set accumulator
- (regs.a == 0 ? regs.cc |= 0x04 : regs.cc &= 0xFB); // Set Zero flag
- (regs.a&0x80 ? regs.cc |= 0x08 : regs.cc &= 0xF7); // Set Negative flag
-
- dr += addr;
- (dr > 0xFFFF ? regs.cc |= 0x01 : regs.cc &= 0xFE); // Adjust Carry flag
- dr &= 0xFFFF;
- (dr == 0 ? regs.cc |= 0x04 : regs.cc &= 0xFB); // Adjust Zero flag
- (dr&0x8000 ? regs.cc |= 0x08 : regs.cc &= 0xF7); // Adjust Negative flag
- ((ds^addr^dr^(regs.cc<<15))&0x8000 ? regs.cc |= 0x02 : regs.cc &= 0xFD); // oVerfl
- regs.a = dr>>8; regs.b = dr&0xFF;
- regs.clock += 4;
-*/
-
static void Op3A(void) // ABX
{
regs.x += (uint16_t)regs.b;
}
-
static void Op8B(void) // ADDA #
{
uint16_t m = READ_IMM;
OP_ADD_HANDLER(m, regs.a);
}
-
static void Op9B(void) // ADDA DP
{
uint16_t m = READ_DP;
OP_ADD_HANDLER(m, regs.a);
}
-
static void OpAB(void) // ADDA IDX
{
uint16_t m = READ_IDX;
OP_ADD_HANDLER(m, regs.a);
}
-
static void OpBB(void) // ADDA ABS
{
uint16_t m = READ_ABS;
OP_ADD_HANDLER(m, regs.a);
}
-
static void OpC3(void) // ADDD #
{
uint32_t m = READ_IMM16;
OP_ADD_HANDLER16(m, regs.a, regs.b);
}
-
static void OpCB(void) // ADDB #
{
uint16_t m = READ_IMM;
OP_ADD_HANDLER(m, regs.b);
}
-
static void OpD3(void) // ADDD DP
{
uint32_t m = READ_DP16;
OP_ADD_HANDLER16(m, regs.a, regs.b);
}
-
static void OpDB(void) // ADDB DP
{
uint16_t m = READ_DP;
OP_ADD_HANDLER(m, regs.b);
}
-
static void OpE3(void) // ADDD IDX
{
uint32_t m = READ_IDX16;
OP_ADD_HANDLER16(m, regs.a, regs.b);
}
-
static void OpEB(void) // ADDB IDX
{
uint16_t m = READ_IDX;
OP_ADD_HANDLER(m, regs.b);
}
-
static void OpF3(void) // ADDD ABS
{
uint32_t m = READ_ABS16;
OP_ADD_HANDLER16(m, regs.a, regs.b);
}
-
static void OpFB(void) // ADDB ABS
{
uint16_t m = READ_ABS;
OP_ADD_HANDLER(m, regs.b);
}
-
/*
+-----------------------------------------------------------------+
| Opcode | | Addressing | | |
{
// C
int16_t offset = (int16_t)(int8_t)READ_IMM;
-//if (disasm)
-// WriteLog("[offset=%04X,flagC=%08X]", offset, flagC);
#ifdef TEST_DONT_BRANCH_OPTIMIZATION
regs.pc += offset * flagC;
static void Op3E(void) // RESET
{
- regs.cpuFlags |= V6809_ASSERT_LINE_RESET;
+ regs.cpuFlags |= V6809_LINE_RESET;
}
static void Op3F(void) // SWI
{
}
-/*
-D3F8: A6 47 LDA (7),U CC=--H----- A=30 B=00 DP=9C X=3C72 Y=CE5C S=BFFF U=BAF0 PC=D3FA
-D3FA: 8B 01 ADDA #$01 CC=--H----- A=31 B=00 DP=9C X=3C72 Y=CE5C S=BFFF U=BAF0 PC=D3FC
-D3FC: 19 DAA CC=--H----- A=37 B=00 DP=9C X=3C72 Y=CE5C S=BFFF U=BAF0 PC=D3FD
-*/
-
static void Op19() // DAA
{
uint16_t result = (uint16_t)regs.a;
-// if ((regs.a & 0x0F) > 0x09 || (regs.cc & FLAG_H))
if ((regs.a & 0x0F) > 0x09 || flagH)
result += 0x06;
-// if ((regs.a & 0xF0) > 0x90 || (regs.cc & FLAG_C) || ((regs.a & 0xF0) > 0x80 && (regs.a & 0x0F) > 0x09))
if ((regs.a & 0xF0) > 0x90 || flagC || ((regs.a & 0xF0) > 0x80 && (regs.a & 0x0F) > 0x09))
result += 0x60;
WRITE_BACK(m);
}
-
static void Op4C(void) // INCA
{
OP_INC_HANDLER(regs.a);
}
-
static void Op5C(void) // INCB
{
OP_INC_HANDLER(regs.b);
}
-
static void Op6C(void) // INC IDX
{
uint8_t m;
WRITE_BACK(m);
}
-
static void Op7C(void) // INC ABS
{
uint8_t m;
WRITE_BACK(m);
}
-
/*
+-----------------------------------------------------------------+
| Opcode | | Addressing | | |
regs.pc = m;
}
-
static void Op17(void) // LBSR
{
uint16_t word = FetchMemW(regs.pc);
regs.pc += word;
}
-
static void Op39(void) // RTS
{
PULLS16(regs.pc);
}
-
static void Op3B(void) // RTI
{
PULLS(regs.cc);
PULLS16(regs.pc);
}
-
static void Op6E(void) // JMP IDX
{
regs.pc = EA_IDX;
}
-
static void Op7E(void) // JMP ABS
{
regs.pc = EA_ABS;
}
-
static void Op8D(void) // BSR
{
uint16_t word = (int16_t)(int8_t)READ_IMM;
regs.pc += word;
}
-
static void Op9D(void) // JSR DP
{
uint16_t word = EA_DP;
regs.pc = word;
}
-
static void OpAD(void) // JSR IDX
{
uint16_t word = EA_IDX;
regs.pc = word;
}
-
static void OpBD(void) // JSR ABS
{
uint16_t word = EA_ABS;
regs.pc = word;
}
-
/*
+-----------------------------------------------------------------+
| Opcode | | Addressing | | |
flagC = (res >= 0x80 ? 1 : 0); \
m = res
-/*
- UINT16 r,t;
- DIRBYTE(t);
- r = -t;
- CLR_NZVC;
- SET_FLAGS8(0,t,r);
- WM(EAD,r);
-#define SET_FLAGS8(a,b,r) {SET_N8(r);SET_Z8(r);SET_V8(a,b,r);SET_C8(r);}
-#define SET_C8(a) CC|=((a&0x100)>>8)
-*/
static void Op00(void) // NEG DP
{
uint8_t m;
}
// Count bits in each nybble to come up with correct cycle counts...
- uint8_t bitCount[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
regs.clock += (1 * bitCount[m & 0x0F]) + (2 * bitCount[m >> 4]);
}
PULLS16(regs.pc);
// Count bits in each nybble to come up with correct cycle counts...
- uint8_t bitCount[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
regs.clock += (1 * bitCount[m & 0x0F]) + (2 * bitCount[m >> 4]);
}
}
// Count bits in each nybble to come up with correct cycle counts...
- uint8_t bitCount[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
regs.clock += (1 * bitCount[m & 0x0F]) + (2 * bitCount[m >> 4]);
}
PULLU16(regs.pc);
// Count bits in each nybble to come up with correct cycle counts...
- uint8_t bitCount[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
regs.clock += (1 * bitCount[m & 0x0F]) + (2 * bitCount[m >> 4]);
}
flagC = (m >> 7) & 0x01; \
m = res
-/*
- UINT16 t,r;
- DIRBYTE(t);
- r = (CC & CC_C) | (t << 1);
- CLR_NZVC;
- SET_FLAGS8(t,t,r);
- WM(EAD,r);
-*/
static void Op09(void) // ROL DP
{
uint8_t m;
OP_TST_HANDLER(m);
}
-
static void Op4D(void) // TSTA
{
OP_TST_HANDLER(regs.a);
}
-
static void Op5D(void) // TSTB
{
OP_TST_HANDLER(regs.b);
}
-
static void Op6D(void) // TST IDX
{
uint8_t m = READ_IDX;
OP_TST_HANDLER(m);
}
-
static void Op7D(void) // TST ABS
{
uint8_t m = READ_ABS;
OP_TST_HANDLER(m);
}
-
//
// Undocumented Opcodes
//
Op00(); // NEG DP
}
-
-//temp, for testing...
-#ifdef __DEBUG__
-static uint8_t backTrace[256];
-static uint16_t btPC[256];
-static int btPtr = 0;//*/
-#endif
static void Op__(void) // Illegal opcode
{
regs.clock++;
-// illegal = true;
regs.cpuFlags |= V6809_STATE_ILLEGAL_INST;
-#ifdef __DEBUG__
-/*WriteLog("V6809: Executed illegal opcode %02X at PC=%04X...\n\nBacktrace:\n\n", regs.RdMem(regs.pc - 1), regs.pc - 1);
-for(int i=0; i<256; i++)
-{
- Decode6809(btPC[(btPtr + i) & 0xFF]);
- WriteLog("\n");
-}//*/
-#endif
}
//
Op__, Op__, Op__, Op__, Op__, Op__, Op__, Op__, Op__, Op__, Op__, Op__, Op__, Op__, Op__, Op__
};
-
// These are here to save typing a ton of forward declarations...
-
// Page 1 opcode
static void Op10(void)
{
-// exec_op1[regs.RdMem(regs.pc++)]();
uint8_t opcode = regs.RdMem(regs.pc++);
exec_op1[opcode]();
regs.clock += page1Cycles[opcode];
}
-
// Page 2 opcode
static void Op11(void)
{
-// exec_op2[regs.RdMem(regs.pc++)]();
uint8_t opcode = regs.RdMem(regs.pc++);
exec_op2[opcode]();
regs.clock += page2Cycles[opcode];
}
-
//
// Internal "memcpy" (so we don't have to link with any external libraries!)
//
d[i] = s[i];
}
-
//
// Function to execute 6809 instructions
//
-//#define DEBUG_ILLEGAL
-#ifdef DEBUG_ILLEGAL
-#include "log.h"
-#include "dis6809.h"
-uint8_t btPtr = 0;
-uint8_t backTrace[256];
-V6809REGS btRegs[256];
-bool tripped = false;
-#endif
void Execute6809(V6809REGS * context, uint32_t cycles)
{
// If this is not in place, the clockOverrun calculations can cause the
// V6809 to get stuck in an infinite loop.
- if (cycles == 0)
+ if (cycles == 0) // Nothing to do, so bail!
return;
myMemcpy(®s, context, sizeof(V6809REGS));
while (regs.clock < endCycles)
{
-#ifdef DEBUG_ILLEGAL
-if (!tripped)
-{
- backTrace[btPtr] = regs.RdMem(regs.pc);
- btRegs[btPtr] = regs;
- btPtr = (btPtr + 1) & 0xFF;
-
- if (regs.cpuFlags & V6809_STATE_ILLEGAL_INST)
- {
- WriteLog("V6809: Executed illegal instruction!!!!\n\nBacktrace:\n\n");
- regs.cpuFlags &= ~V6809_STATE_ILLEGAL_INST;
-
- for(uint16_t i=btPtr; i<btPtr+256; i++)
- {
- Decode6809(btRegs[i & 0xFF].pc);
-// Note that these values are *before* execution, so stale...
- WriteLog("\n\tA=%02X B=%02X CC=%02X DP=%02X X=%04X Y=%04X S=%04X U=%04X PC=%04X\n",
- btRegs[i & 0xFF].a, btRegs[i & 0xFF].b, btRegs[i & 0xFF].cc, btRegs[i & 0xFF].dp, btRegs[i & 0xFF].x, btRegs[i & 0xFF].y, btRegs[i & 0xFF].s, btRegs[i & 0xFF].u, btRegs[i & 0xFF].pc);//*/
- }
-
- tripped = true;
- }
-}
-#endif
-#ifdef __DEBUG__
-if (disasm)
-{
- Decode6809(regs);
-// WriteLog("[e=%02X,f=%02X,h=%02X,i=%02X,n=%02X,z=%02X,v=%02X,c=%02X]", flagE, flagF, flagH, flagI, flagN, flagZ, flagV, flagC);
-}
-#if 0 //we solved this...
-if ((flagE | flagF | flagH | flagI | flagN | flagZ | flagV | flagC) > 1)
- WriteLog("\n\n!!! FLAG OUT OF BOUNDS !!!\n\n");
-#endif
-//static bool disasm = false;
-/*//if (regs.pc == 0x15BA) disasm = true;
-//if (regs.pc == 0xFE76) disasm = true;
-if (regs.x == 0xFED4) disasm = true;
-if (disasm) Decode6809(regs.pc);
-//if (regs.pc == 0x164A) disasm = false;//*/
-
-//temp, for testing...
-/*backTrace[btPtr] = regs.RdMem(regs.pc);
-btPC[btPtr] = regs.pc;
-btPtr = (btPtr + 1) & 0xFF;//*/
-#endif
-// exec_op0[regs.RdMem(regs.pc++)]();
uint8_t opcode = regs.RdMem(regs.pc++);
exec_op0[opcode]();
regs.clock += page0Cycles[opcode];
// uint32_t flags = context->cpuFlags;
uint32_t flags = regs.cpuFlags;
- if (flags & V6809_ASSERT_LINE_RESET) // *** RESET handler ***
+ // *** RESET handler ***
+ if (flags & V6809_LINE_RESET)
{
-#ifdef __DEBUG__
-if (disasm) WriteLog("\nV6809: RESET line asserted!\n");
-#endif
flagF = flagI = 1; // Set F, I
regs.dp = 0; // Reset direct page register
regs.pc = RdMemW(0xFFFE); // And load PC with the RESET vector
- context->cpuFlags &= ~V6809_ASSERT_LINE_RESET;
- regs.cpuFlags &= ~V6809_ASSERT_LINE_RESET;
+ context->cpuFlags &= ~V6809_LINE_RESET;
+ regs.cpuFlags &= ~V6809_LINE_RESET;
}
- else if (flags & V6809_ASSERT_LINE_NMI) // *** NMI handler ***
+ // *** NMI handler ***
+ else if (flags & V6809_LINE_NMI)
{
-#ifdef __DEBUG__
-if (disasm) WriteLog("\nV6809: NMI line asserted!\n");
-#endif
flagE = 1; // Set Entire flag
regs.cc = PACK_FLAGS; // Mash flags back into the CC register
flagI = flagF = 1; // Set IRQ/FIRQ suppress flags
regs.pc = RdMemW(0xFFFC); // And load PC with the NMI vector
regs.clock += 19;
-// context->cpuFlags &= ~V6809_ASSERT_LINE_NMI;// Reset the asserted line (NMI)...
-// regs.cpuFlags &= ~V6809_ASSERT_LINE_NMI; // Reset the asserted line (NMI)...
}
- else if (flags & V6809_ASSERT_LINE_FIRQ) // *** FIRQ handler ***
+ // *** FIRQ handler ***
+ else if (flags & V6809_LINE_FIRQ)
{
-#ifdef __DEBUG__
-if (disasm) WriteLog("\nV6809: FIRQ line asserted!\n");
-#endif
if (!flagF) // Is the FIRQ masked (F == 1)?
{
-#ifdef __DEBUG__
-if (disasm) WriteLog(" FIRQ taken...\n");
-#endif
flagE = 0; // Clear Entire flag
regs.cc = PACK_FLAGS; // Mash flags back into the CC register
flagI = flagF = 1; // Set IRQ/FIRQ suppress flags
regs.pc = RdMemW(0xFFF6); // And load PC with the IRQ vector
regs.clock += 10;
-// context->cpuFlags &= ~V6809_ASSERT_LINE_FIRQ; // Reset the asserted line (FIRQ)...
-// regs.cpuFlags &= ~V6809_ASSERT_LINE_FIRQ; // Reset the asserted line (FIRQ)...
}
}
- else if (flags & V6809_ASSERT_LINE_IRQ) // *** IRQ handler ***
+ // *** IRQ handler ***
+ else if (flags & V6809_LINE_IRQ)
{
-#ifdef __DEBUG__
-if (disasm) WriteLog("\nV6809: IRQ line asserted!\n");
-#endif
if (!flagI) // Is the IRQ masked (I == 1)?
{
-#ifdef __DEBUG__
-if (disasm) WriteLog(" IRQ taken...\n");
-#endif
flagE = 1; // Set the Entire flag
regs.cc = PACK_FLAGS; // Mash flags back into the CC register
flagI = 1; // Specs say that it doesn't affect FIRQ... or FLAG_F [WAS: Set IRQ/FIRQ suppress flags]
regs.pc = RdMemW(0xFFF8); // And load PC with the IRQ vector
regs.clock += 19;
-// Apparently, not done here!
-// context->cpuFlags &= ~V6809_ASSERT_LINE_IRQ; // Reset the asserted line (IRQ)...
-// regs.cpuFlags &= ~V6809_ASSERT_LINE_IRQ; // Reset the asserted line (IRQ)...
}
}
-#ifdef __DEBUG__
-if (disasm) WriteLog("CC=%s%s%s%s%s%s%s%s A=%02X B=%02X DP=%02X X=%04X Y=%04X S=%04X U=%04X PC=%04X\n",
- (flagE ? "E" : "-"), (flagF ? "F" : "-"), (flagH ? "H" : "-"), (flagI ? "I" : "-"),
- (flagN ? "N" : "-"), (flagZ ? "Z" : "-"), (flagV ? "V" : "-"), (flagC ? "C" : "-"),
- regs.a, regs.b, regs.dp, regs.x, regs.y, regs.s, regs.u, regs.pc);//*/
-/*WriteLog("\tA=%02X B=%02X CC=%02X DP=%02X X=%04X Y=%04X S=%04X U=%04X PC=%04X\n",
- regs.a, regs.b, regs.cc, regs.dp, regs.x, regs.y, regs.s, regs.u, regs.pc);//*/
-#endif
}
// Keep track of how much we overran so we can adjust on the next run...
myMemcpy(context, ®s, sizeof(V6809REGS));
}
-
//
// Get the clock of the currently executing CPU
//
return regs.clock;
}
-
//
// Get the PC of the currently executing CPU
//
return regs.pc;
}
-
// Set a line of the currently executing CPU
void SetLineOfCurrentV6809(uint32_t line)
{
regs.cpuFlags |= line;
}
-
// Clear a line of the currently executing CPU
void ClearLineOfCurrentV6809(uint32_t line)
{
-#ifdef __DEBUG__
-if (disasm)
- WriteLog("V6809: Clearing line %s...", (line == V6809_ASSERT_LINE_IRQ ? "IRQ" : "OTHER"));
-#endif
regs.cpuFlags &= ~line;
}
-
-#if 0
-FE54: 27 6A BEQ $FEC0 CC=EF-I-Z-- A=39 B=01 DP=00 X=FEE2 Y=F51
-E S=BFFF U=0000 PC=FEC0
-FEC0: 6E A4 JMP ,Y CC=EF-I-Z-- A=39 B=01 DP=00 X=FEE2 Y=F51E S=BFFF
- U=0000 PC=F51E
-F51E: 86 34 LDA #$34 CC=EF-I---- A=34 B=01 DP=00 X=FEE2 Y=F51E S=BFFF
- U=0000 PC=F520
-F520: B7 C8 0D STA $C80D CC=EF-I---- A=34 B=01 DP=00 X=FEE2 Y=F51E S=BFFF U=0000 PC=F523
-F523: B7 C8 0F STA $C80F CC=EF-I---- A=34 B=01 DP=00 X=FEE2 Y=F51E S=BFFF U=0000 PC=F526
-F526: 7F C8 0E CLR $C80EV6809: Clearing line IRQ... CC=EF-I-Z-- A=34 B=01 DP=00 X=FEE2 Y=F51E S=BFFF U=0000 PC=F529
-F529: 86 9C LDA #$9C CC=EF-IN--- A=9C B=01 DP=00 X=FEE2 Y=F51E S=BFFF U=0000 PC=F52B
-F52B: 1F 8B TFR A,DP CC=EF-IN--- A=9C B=01 DP=9C X=FEE2 Y=F51E S=BFFF U=0000 PC=F52D
-F52D: 10 CE BF FF LDS #$BFFF CC=EF-IN--- A=9C B=01 DP=9C X=FEE2 Y=F51E S=BFFF U=0000 PC=F531
-F531: BD 13 BD JSR $13BD CC=EF-IN--- A=9C B=01 DP=9C X=FEE2 Y=F51E S=BFFD U=0000 PC=13BD
-13BD: 34 76 PSHS A B X Y U CC=EF-IN--- A=9C B=01 DP=9C X=FEE2 Y=F51E S=BFF5 U=0000 PC=13BF
-13BF: CE 9C 00 LDU #$9C00 CC=EF-IN--- A=9C B=01 DP=9C X=FEE2 Y=F51E S=BFF5 U=9C00 PC=13C2
-13C2: 8E 00 00 LDX #$0000 CC=EF-I-Z-- A=9C B=01 DP=9C X=0000 Y=F51E S=BFF5 U=9C00 PC=13C5
-13C5: 1F 12 TFR X,Y CC=EF-I-Z-- A=9C B=01 DP=9C X=0000 Y=0000 S=BFF5 U=9C00 PC=13C7
-13C7: 1F 10 TFR X,D CC=EF-I-Z-- A=00 B=00 DP=9C X=0000 Y=0000 S=BFF5 U=9C00 PC=13C9
-13C9: 36 36 PSHU A B X Y CC=EF-I-Z-- A=00 B=00 DP=9C X=0000 Y=0000 S=BFEF U=9C00 PC=13CB
-13CB: 36 36 PSHU A B X Y CC=EF-I-Z-- A=00 B=00 DP=9C X=0000 Y=0000 S=BFE9 U=9C00 PC=13CD
-13CD: 36 36 PSHU A B X Y CC=EF-I-Z-- A=00 B=00 DP=9C X=0000 Y=0000 S=BFE3 U=9C00 PC=13CF
-13CF: 36 36 PSHU A B X Y CC=EF-I-Z-- A=00 B=00 DP=9C X=0000 Y=0000 S=BFDD U=9C00 PC=13D1
-13D1: 36 36 PSHU A B X Y CC=EF-I-Z-- A=00 B=00 DP=9C X=0000 Y=0000 S=BFD7 U=9C00 PC=13D3
-13D3: 36 10 PSHU X CC=EF-I-Z-- A=00 B=00 DP=9C X=0000 Y=0000 S=BFD5 U=9C00 PC=13D5
-13D5: 11 83 00 00 CMPU #$0000 CC=EF-IN--- A=00 B=00 DP=9C X=0000 Y=000
-#endif
// Virtual 6809 Header file
//
// by James L. Hammons
-//
// (C) 1997, 2004 Underground Software
//
-
#ifndef __V6809_H__
#define __V6809_H__
#define FLAG_V 0x02 // oVerflow
#define FLAG_C 0x01 // Carry
-#define V6809_ASSERT_LINE_RESET 0x0001 // v6809 RESET line
-#define V6809_ASSERT_LINE_IRQ 0x0002 // v6809 IRQ line
-#define V6809_ASSERT_LINE_FIRQ 0x0004 // v6809 FIRQ line
-#define V6809_ASSERT_LINE_NMI 0x0008 // v6809 NMI line
+#define V6809_LINE_RESET 0x0001 // v6809 RESET line
+#define V6809_LINE_IRQ 0x0002 // v6809 IRQ line
+#define V6809_LINE_FIRQ 0x0004 // v6809 FIRQ line
+#define V6809_LINE_NMI 0x0008 // v6809 NMI line
#define V6809_STATE_SYNC 0x0010 // v6809 SYNC line
#define V6809_STATE_ILLEGAL_INST 0x0020 // Illegal instruction executed flag
-
//#define V6809_START_DEBUG_LOG EQU 0020h // Debug log go (temporary!)
// Useful structs
void ClearLineOfCurrentV6809(uint32_t line); // Clear a line of the currently executing CPU
#endif // __V6809_H__
-
//
// VIDEO.H: Header file
//
-
#ifndef __VIDEO_H__
#define __VIDEO_H__
//extern uint32_t mainScrBuffer[];
#endif // __VIDEO_H__
-
#include <math.h>
#include <stdint.h>
-
// Missing shit (from M.A.M.E.)
#if 1
#endif
-
/*
** some globals ...
*/
static void (* envelope_calc[5])(OscilRec *);
static void (* register_writes[256])(uint8_t, uint8_t, uint8_t);
-//save output as raw 16-bit sample - just in case you would like to listen to it offline ;-)
-//#define SAVE_SAMPLE
-//#define SAVE_SEPARATE_CHANNELS
-
-#ifdef SAVE_SAMPLE
-#ifdef SAVE_SEPARATE_CHANNELS
-FILE * sample1;
-FILE * sample2;
-FILE * sample3;
-FILE * sample4;
-FILE * sample5;
-FILE * sample6;
-#endif
-FILE * samplesum;
-#endif
-
int PMTab[8]; /*8 channels */
/* this table is used for PM setup of LFO */
static signed int LFOdeltas[256]; /*frequency deltas for LFO*/
-
void sin_init(void)
{
int x, i;
decib45[x] = i;
//if (errorlog) fprintf(errorlog,"decib45[%04x]=%08x\n",x,i );
}
-
-#ifdef SAVE_SAMPLE
-#ifdef SAVE_SEPARATE_CHANNELS
-sample1=fopen("samp.raw","wb");
-sample2=fopen("samp2.raw","wb");
-sample3=fopen("samp3.raw","wb");
-sample4=fopen("samp4.raw","wb");
-sample5=fopen("samp5.raw","wb");
-sample6=fopen("samp6.raw","wb");
-#endif
-samplesum=fopen("sampsum.raw","wb");
-#endif
}
-
void hertz(void)
{
int i, j, oct;
}
}
-
void envelope_attack(OscilRec * op)
{
if ((op->attack_volume -= op->delta_AR) < MIN_VOLUME_INDEX) //is volume index min already ?
op->volume = attack_curve[op->attack_volume>>ENV_SH];
}
-
void envelope_decay(OscilRec * op)
{
if ((op->volume += op->delta_D1R) > op->D1L)
}
}
-
void envelope_sustain(OscilRec * op)
{
if ((op->volume += op->delta_D2R) > MAX_VOLUME_INDEX)
}
}
-
void envelope_release(OscilRec * op)
{
if ((op->volume += op->delta_RR) > MAX_VOLUME_INDEX)
}
}
-
void envelope_nothing(OscilRec *op)
{
}
-
inline void envelope_KOFF(OscilRec * op)
{
op->state = 3; /*release*/
}
-
inline void envelope_KON(OscilRec * op)
{
/*this is to remove the gap time if TL>0*/
op->OscilFB = 0; /*Clear feedback after key on */
}
-
void refresh_chip(YM2151 * PSG)
{
uint16_t kc_index_oscil, kc_index_channel, mul;
}
}
-
void write_YM_NON_EMULATED(uint8_t n, uint8_t r, uint8_t v)
{
if (errorlog)
fprintf(errorlog, "Write to non emulated register %02x value %02x\n", r, v);
}
-
void write_YM_KON(uint8_t n, uint8_t r, uint8_t v)
{
uint8_t chan;
envelope_KOFF(&PSG->Oscils[chan + 24]);
}
-
void write_YM_CLOCKA1(uint8_t n, uint8_t r, uint8_t v)
{
YMPSG[n].Regs[r] = v;
}
-
void write_YM_CLOCKA2(uint8_t n, uint8_t r, uint8_t v)
{
YMPSG[n].Regs[r] = v & 0x03;
}
-
void write_YM_CLOCKB(uint8_t n, uint8_t r, uint8_t v)
{
YMPSG[n].Regs[r] = v;
}
-
static void timer_callback_a(int n)
{
YM2151 * PSG = &YMPSG[n];
PSG->TimATimer = 0;
}
-
static void timer_callback_b(int n)
{
YM2151 * PSG = &YMPSG[n];
PSG->TimBTimer = 0;
}
-
void write_YM_CLOCKSET(uint8_t n, uint8_t r, uint8_t v)
{
YM2151 * PSG = &(YMPSG[n]);
}
}
-
void write_YM_CT1_CT2_W(uint8_t n, uint8_t r, uint8_t v)
{
YMPSG[n].Regs[r] = v;
}
-
void write_YM_CONNECT_BASE(uint8_t n, uint8_t r, uint8_t v)
{
// NOTE: L/R Channel enables are ignored! This emu is mono!
PSG->FeedBack[chan] = FEED[(v >> 3) & 7];
}
-
void write_YM_KC_BASE(uint8_t n, uint8_t r, uint8_t v)
{
YMPSG[n].KC[r - YM_KC_BASE] = v;
//freq_calc(chan,PSG);
}
-
void write_YM_KF_BASE(uint8_t n, uint8_t r, uint8_t v)
{
YMPSG[n].KF[r - YM_KF_BASE] = v >> 2;
//freq_calc(chan,PSG);
}
-
void write_YM_PMS_AMS_BASE(uint8_t n, uint8_t r, uint8_t v)
{
// uint8_t chan, i;
}
-
void write_YM_DT1_MUL_BASE(uint8_t n, uint8_t r, uint8_t v)
{
YMPSG[n].Regs[r] = v;
//freq_calc(chan,PSG);
}
-
void write_YM_TL_BASE(uint8_t n, uint8_t r, uint8_t v)
{
v &= 0x7F;
YMPSG[n].Oscils[r - YM_TL_BASE].TL = v << (ENV_BITS - 7); /*7bit TL*/
}
-
void write_YM_KS_AR_BASE(uint8_t n, uint8_t r, uint8_t v)
{
uint8_t op;
PSG->Oscils[op].AR = (v & 0x1F) << 1;
}
-
void write_YM_AMS_D1R_BASE(uint8_t n, uint8_t r, uint8_t v)
{
uint8_t op = r - YM_AMS_D1R_BASE;
YMPSG[n].Oscils[op].D1R = (v & 0x1F) << 1;
}
-
void write_YM_DT2_D2R_BASE(uint8_t n, uint8_t r, uint8_t v)
{
YM2151 * PSG = &(YMPSG[n]);
//freq_calc(chan,PSG);
}
-
void write_YM_D1L_RR_BASE(uint8_t n, uint8_t r, uint8_t v)
{
OscilRec * osc = &YMPSG[n].Oscils[r - YM_D1L_RR_BASE];
osc->RR = ((v & 0x0F) << 2) | 0x02;
}
-
/*
** Initialize YM2151 emulator(s).
**
** 'rate' is sampling rate and 'bufsiz' is the size of the
** buffer that should be updated at each interval
*/
-int YMInit(int num, int clock, int rate, int sample_bits, int bufsiz)//, SAMPLE ** buffer)
+//int YMInit(int num, int clock, int rate, int sample_bits, int bufsiz)//, SAMPLE ** buffer)
+int YMInit(int clock, int rate)
{
int i;
if (YMPSG)
return (-1); /* duplicate init. */
- YMNumChips = num;
+// YMNumChips = num;
+ YMNumChips = 1;
YM2151_SAMPFREQ = rate;
#if 0
#endif
YM2151_CLOCK = clock;
- YMBufSize = bufsiz;
+// YMBufSize = bufsiz;
envelope_calc[0] = envelope_attack;
envelope_calc[1] = envelope_decay;
return 0;
}
-
void YMShutdown()
{
if (!YMPSG)
}
YM2151_SAMPFREQ = YMBufSize = 0;
-
-#ifdef SAVE_SAMPLE
-#ifdef SAVE_SEPARATE_CHANNELS
-fclose(sample1);
-fclose(sample2);
-fclose(sample3);
-fclose(sample4);
-fclose(sample5);
-fclose(sample6);
-#endif
-fclose(samplesum);
-#endif
}
-
/* write a register on YM2151 chip number 'n' */
void YMWriteReg(int n, int r, int v)
{
register_writes[(uint8_t)r]((uint8_t)n, (uint8_t)r, (uint8_t)v);
}
-
uint8_t YMReadReg(uint8_t n)
{
return YMPSG[n].TimIRQ;
}
-
/*
** reset all chip registers.
*/
PSG->TimIRQ = 0;
}
-
static inline signed int op_calc(OscilRec * OP, signed int pm)
{
return sin_tab[(((OP->phase += OP->freq) >> FREQ_SH) + (pm)) & SIN_MASK]
[OP->TL + (OP->volume >> ENV_SH)];
}
-
//void YM2151UpdateOne(int num, int endp)
void YM2151UpdateOne(void * BUF, int endp)
{
OscilRec * OP0, * OP1, * OP2, * OP3;
uint16_t i;
signed int k, wy;
-#ifdef SAVE_SEPARATE_CHANNELS
- signed int pom;
-#endif
refresh_chip(PSG);
case 6: *(PSGBUF) = op_calc(OP2, wy) + op_calc(OP1, 0) + op_calc(OP3, 0); break;
default: *(PSGBUF) = wy + op_calc(OP2, 0) + op_calc(OP1, 0) + op_calc(OP3, 0); break;
}
-#ifdef SAVE_SEPARATE_CHANNELS
-fputc((uint16_t)(*PSGBUF) & 0xFF, sample1);
-fputc(((uint16_t)(*PSGBUF) >> 8) & 0xFF, sample1);
-#endif
}
//chan1
else
OP0->OscilFB = 0;
-#ifdef SAVE_SEPARATE_CHANNELS
-pom = *(PSGBUF);
-#endif
switch(PSG->ConnectTab[1])
{
case 0: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,wy) ) ); break;
case 6: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP1,0) + op_calc(OP3,0); break;
default: *(PSGBUF) += wy + op_calc(OP2, 0) + op_calc(OP1, 0) + op_calc(OP3, 0); break;
}
-
-#ifdef SAVE_SEPARATE_CHANNELS
-fputc((uint16_t)((*PSGBUF)-pom)&0xff,sample2);
-fputc(((uint16_t)((*PSGBUF)-pom)>>8)&0xff,sample2);
-#endif
}
//chan2
else
OP0->OscilFB = 0;
-#ifdef SAVE_SEPARATE_CHANNELS
- pom=*(PSGBUF);
-#endif
switch(PSG->ConnectTab[2])
{
case 0: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,wy) ) ); break;
case 6: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP1,0) + op_calc(OP3,0); break;
default:*(PSGBUF) += wy + op_calc(OP2,0) + op_calc(OP1,0) + op_calc(OP3,0);break;
}
-#ifdef SAVE_SEPARATE_CHANNELS
-fputc((uint16_t)((*PSGBUF)-pom)&0xff,sample3);
-fputc(((uint16_t)((*PSGBUF)-pom)>>8)&0xff,sample3);
-#endif
}
//chan3
else
OP0->OscilFB = 0;
-#ifdef SAVE_SEPARATE_CHANNELS
- pom=*(PSGBUF);
-#endif
switch(PSG->ConnectTab[3])
{
case 0: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,wy) ) ); break;
case 6: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP1,0) + op_calc(OP3,0); break;
default:*(PSGBUF) += wy + op_calc(OP2,0) + op_calc(OP1,0) + op_calc(OP3,0);break;
}
-#ifdef SAVE_SEPARATE_CHANNELS
-fputc((uint16_t)((*PSGBUF)-pom)&0xff,sample4);
-fputc(((uint16_t)((*PSGBUF)-pom)>>8)&0xff,sample4);
-#endif
}
//chan4
else
OP0->OscilFB = 0;
- #ifdef SAVE_SEPARATE_CHANNELS
- pom = *(PSGBUF);
- #endif
-
switch(PSG->ConnectTab[4])
{
case 0: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,wy) ) ); break;
case 6: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP1,0) + op_calc(OP3,0); break;
default:*(PSGBUF) += wy + op_calc(OP2,0) + op_calc(OP1,0) + op_calc(OP3,0);break;
}
-
-#ifdef SAVE_SEPARATE_CHANNELS
-fputc((uint16_t)((*PSGBUF)-pom)&0xff,sample5);
-fputc(((uint16_t)((*PSGBUF)-pom)>>8)&0xff,sample5);
-#endif
}
//chan5
else
OP0->OscilFB = 0;
-#ifdef SAVE_SEPARATE_CHANNELS
- pom=*(PSGBUF);
-#endif
switch(PSG->ConnectTab[5])
{
case 0: *(PSGBUF) += op_calc(OP3, op_calc(OP1, op_calc(OP2,wy) ) ); break;
case 6: *(PSGBUF) += op_calc(OP2,wy) + op_calc(OP1,0) + op_calc(OP3,0); break;
default:*(PSGBUF) += wy + op_calc(OP2,0) + op_calc(OP1,0) + op_calc(OP3,0);break;
}
-#ifdef SAVE_SEPARATE_CHANNELS
-fputc((uint16_t)((*PSGBUF)-pom)&0xff,sample6);
-fputc(((uint16_t)((*PSGBUF)-pom)>>8)&0xff,sample6);
-#endif
}
//chan6
{
k = *(PSGBUF++);
-#ifdef SAVE_SAMPLE
-fputc((uint16_t)(-k) & 0xFF, samplesum);
-fputc(((uint16_t)(-k) >> 8) & 0xFF, samplesum);
-#endif
-
#if 1
// if (sample_16bit)
{
/*16 bit mode*/
k >>= FINAL_SH16; //AUDIO_CONV
- k <<= 2;
+// We don't shift by 2, as it's too loud (eventually, we need to do proper volume control here)
+// k <<= 2;
+ k <<= 1;
if (k > 32767)
k = 32767;
PSG->bufp = endp;
}
-
/*
** called to update all chips
*/
}
}
-
/*
** return the buffer into which YM2151Update() has just written it's sample
** data
return YMPSG[n].Buf;
}
-
void YMSetIrqHandler(int n, void(* handler)(void))
{
YMPSG[n].handler = handler;
}
-
** 'rate' is sampling rate and 'bufsiz' is the size of the
** buffer that should be updated at each interval
*/
-int YMInit(int num, int clock, int rate, int sample_bits, int bufsiz); //, SAMPLE ** buffer);
+//int YMInit(int num, int clock, int rate, int sample_bits, int bufsiz); //, SAMPLE ** buffer);
+int YMInit(int clock, int rate);
/*
** shutdown the YM2151 emulators ...
// Union bit fields...
-//#include <dos.h>
-//#include <conio.h>
-#include <fstream>
-#include <iostream>
+#include <dos.h>
+#include <conio.h>
+#include <fstream.h>
#include <string.h>
-#include <iomanip>
+#include <iomanip.h>
#include <stdio.h>
#include <stdlib.h>
-using namespace std;
-
union {
- struct {
- unsigned char C: 1; // Carry flag
- unsigned char V: 1; // oVerflow flag
- unsigned char Z: 1; // Zero flag
- unsigned char N: 1; // Negative flag
- unsigned char I: 1; // IRQ flag
- unsigned char H: 1; // Half carry flag
- unsigned char F: 1; // Fast IRQ flag
- unsigned char E: 1; // Entire flag
- } flag;
- unsigned char byte; } cc;
+ struct {
+ unsigned char C: 1; // Carry flag
+ unsigned char V: 1; // oVerflow flag
+ unsigned char Z: 1; // Zero flag
+ unsigned char N: 1; // Negative flag
+ unsigned char I: 1; // IRQ flag
+ unsigned char H: 1; // Half carry flag
+ unsigned char F: 1; // Fast IRQ flag
+ unsigned char E: 1; // Entire flag
+ } flag;
+ unsigned char byte; } cc;
union BYTE {
- struct {
- unsigned char b0: 1; unsigned char b1: 1; unsigned char b2: 1;
- unsigned char b3: 1; unsigned char b4: 1; unsigned char b5: 1;
- unsigned char b6: 1; unsigned char b7: 1;
- } bit;
- unsigned char byte; };
+ struct {
+ unsigned char b0: 1; unsigned char b1: 1; unsigned char b2: 1;
+ unsigned char b3: 1; unsigned char b4: 1; unsigned char b5: 1;
+ unsigned char b6: 1; unsigned char b7: 1;
+ } bit;
+ unsigned char byte; };
union WORD {
- struct { unsigned char lo: 8; unsigned char hi: 8; } b;
- unsigned int word; } hilo;
-
+ struct { unsigned char lo: 8; unsigned char hi: 8; } b;
+ unsigned int word; } hilo;
-int main(int, char * [])
+void main()
{
- for(int i=0; i<256; i++)
- {
- cc.byte = i;
- cout << (cc.flag.E ? "1" : ".") << " " << (cc.flag.F ? "1" : ".") << " "
- << (cc.flag.H ? "1" : ".") << " " << (cc.flag.I ? "1" : ".") << " "
- << (cc.flag.N ? "1" : ".") << " " << (cc.flag.Z ? "1" : ".") << " "
- << (cc.flag.V ? "1" : ".") << " " << (cc.flag.C ? "1" : ".") << endl;
- }
-
- hilo.word = 0x6A44;
- cout << hex << hilo.word << " "
- << (int) hilo.b.lo << " " << (int) hilo.b.hi << endl;
-
- BYTE b;
- b.byte = (unsigned char)0xA5;
- cout << "Byte = " << hex << (int)b.byte << ", bits = "
- << (b.bit.b7 ? "1" : "0")
- << (b.bit.b6 ? "1" : "0")
- << (b.bit.b5 ? "1" : "0")
- << (b.bit.b4 ? "1" : "0")
- << (b.bit.b3 ? "1" : "0")
- << (b.bit.b2 ? "1" : "0")
- << (b.bit.b1 ? "1" : "0")
- << (b.bit.b0 ? "1" : "0")
- << endl;
-
- b.bit.b4 ^= 1;
- cout << "Byte = " << hex << (int)b.byte << ", bits = "
- << (b.bit.b7 ? "1" : "0")
- << (b.bit.b6 ? "1" : "0")
- << (b.bit.b5 ? "1" : "0")
- << (b.bit.b4 ? "1" : "0")
- << (b.bit.b3 ? "1" : "0")
- << (b.bit.b2 ? "1" : "0")
- << (b.bit.b1 ? "1" : "0")
- << (b.bit.b0 ? "1" : "0")
- << endl;
-
- return 0;
+ for(int i=0; i<256; i++)
+ {
+ cc.byte = i;
+ cout << cc.flag.E << " " << cc.flag.F << " "
+ << cc.flag.H << " " << cc.flag.I << " "
+ << cc.flag.N << " " << cc.flag.Z << " "
+ << cc.flag.V << " " << cc.flag.C << endl;
+ }
+ hilo.word = 0x6A44;
+ cout << hex << hilo.word << " "
+ << (int) hilo.b.lo << " " << (int) hilo.b.hi << endl;
}
-