MSXHawk: Refactor and start work on SCC

This commit is contained in:
alyosha-tas 2021-11-24 20:26:31 -05:00
parent 0cd769222b
commit f32961001e
9 changed files with 772 additions and 68 deletions

Binary file not shown.

View File

@ -1246,7 +1246,7 @@ D2560E3B7D4E137BDBBA8426030D2F44 Rotors (1984)(ASCII)(JP) MSX JP
324E6E87465ECF49AF0C613A87467E10 R-Type v2 (1988)(IREM)(JP)[a] MSX JP
0F03B2306E11C5182351DB3B7AA30533 Saimazoom (2005)(Karoshi)[RK708] MSX
B0D4FB9A9A88FB65C12D2B567B567171 Saimazoom (2005)(Karoshi)[RK708EN] MSX
EC869B375D7517A7BA6161B10F5DEE06 Salamander - Operation X (1987)(Konami)(JP)[RC-758] MSX JP
EC869B375D7517A7BA6161B10F5DEE06 Salamander - Operation X (1987)(Konami)(JP)[RC-758] MSX mapper=2 JP
59767E46E226F5C69469694817839189 Salamander - Operation X (1987)(Konami)(JP)[SCC][RC-758] MSX JP
0DA25C28FCE818D6FA7231CB6A914783 Salamander - Operation X (1988)(Zemina)(KR)[RC-758] MSX KR
305BF5B78B03D28B92DEF20AD89A4E4B Sangokushi. Romance of Three Kingdoms (1986)(Koei)(JP) MSX JP

View File

@ -43,6 +43,7 @@ namespace MSXHawk
uint32_t noise = 0x1;
int32_t old_sample;
int32_t current_sample;
// non stated if only on frame boundaries
bool sound_out_A;
@ -51,11 +52,6 @@ namespace MSXHawk
uint8_t Clock_Divider;
int32_t current_sample;
uint32_t sampleclock;
uint32_t num_samples;
int32_t samples[9000] = {};
void Reset()
{
clock_A = clock_B = clock_C = 0x1000;
@ -168,7 +164,7 @@ namespace MSXHawk
}
}
void generate_sound()
bool generate_sound()
{
// there are 8 cpu cycles for every psg cycle
clock_A--;
@ -282,13 +278,9 @@ namespace MSXHawk
current_sample *= 2;
if ((current_sample != old_sample) && (num_samples < 4500))
{
samples[num_samples * 2] = sampleclock;
samples[num_samples * 2 + 1] = current_sample - old_sample;
num_samples++;
old_sample = current_sample;
}
if (current_sample != old_sample) { return true; }
return false;
}
#pragma endregion

View File

@ -5,6 +5,7 @@
#include "Z80A.h"
#include "AY_3_8910.h"
#include "SCC.h"
#include "TMS9918A.h"
#include "Memory.h"
@ -18,19 +19,31 @@ namespace MSXHawk
MemMap.cpu_pntr = &cpu;
MemMap.vdp_pntr = &vdp;
MemMap.psg_pntr = &psg;
MemMap.SCC_1_pntr = &SCC_1;
MemMap.SCC_2_pntr = &SCC_2;
cpu.mem_ctrl = &MemMap;
vdp.IRQ_PTR = &cpu.FlagI;
vdp.SHOW_BG = vdp.SHOW_SPRITES = true;
psg.Clock_Divider = 16;
sl_case = 0;
SCC_1.page_pointer = &MemMap.SCC_1_page[0];
SCC_2.page_pointer = &MemMap.SCC_2_page[0];
};
TMS9918A vdp;
Z80A cpu;
AY_3_8910 psg;
SCC SCC_1;
SCC SCC_2;
MemoryManager MemMap;
uint8_t sl_case = 0;
bool new_sample = false;
// combine audio from all sources
uint32_t sampleclock;
uint32_t num_samples;
int32_t samples[9000] = {};
void Load_BIOS(uint8_t* bios, uint8_t* basic)
{
@ -65,8 +78,8 @@ namespace MSXHawk
uint32_t scanlinesPerFrame = 262;
vdp.SpriteLimit = true;
psg.num_samples = 0;
psg.sampleclock = 0;
num_samples = 0;
sampleclock = 0;
for (uint32_t i = 0; i < scanlinesPerFrame; i++)
{
@ -87,55 +100,76 @@ namespace MSXHawk
for (int i = 0; i < 14; i++)
{
cpu.ExecuteOne(16);
psg.sampleclock+=16;
psg.generate_sound();
sampleclock+=16;
new_sample |= psg.generate_sound();
new_sample |= SCC_1.generate_sound();
//new_sample |= SCC_2.generate_sound();
if (new_sample) { Add_Audio_Sample(); }
}
cpu.ExecuteOne(4);
psg.sampleclock += 4;
sampleclock += 4;
sl_case = 1;
break;
case 1:
cpu.ExecuteOne(12);
psg.sampleclock += 12;
psg.generate_sound();
sampleclock += 12;
new_sample |= psg.generate_sound();
new_sample |= SCC_1.generate_sound();
//new_sample |= SCC_2.generate_sound();
if (new_sample) { Add_Audio_Sample(); }
for (int i = 0; i < 13; i++)
{
cpu.ExecuteOne(16);
psg.sampleclock += 16;
psg.generate_sound();
sampleclock += 16;
new_sample |= psg.generate_sound();
new_sample |= SCC_1.generate_sound();
//new_sample |= SCC_2.generate_sound();
if (new_sample) { Add_Audio_Sample(); }
}
cpu.ExecuteOne(8);
psg.sampleclock += 8;
sampleclock += 8;
sl_case = 2;
break;
case 2:
cpu.ExecuteOne(8);
psg.sampleclock += 8;
psg.generate_sound();
sampleclock += 8;
new_sample |= psg.generate_sound();
new_sample |= SCC_1.generate_sound();
//new_sample |= SCC_2.generate_sound();
if (new_sample) { Add_Audio_Sample(); }
for (int i = 0; i < 13; i++)
{
cpu.ExecuteOne(16);
psg.sampleclock += 16;
psg.generate_sound();
sampleclock += 16;
new_sample |= psg.generate_sound();
new_sample |= SCC_1.generate_sound();
//new_sample |= SCC_2.generate_sound();
if (new_sample) { Add_Audio_Sample(); }
}
cpu.ExecuteOne(12);
psg.sampleclock += 12;
sampleclock += 12;
sl_case = 3;
break;
case 3:
cpu.ExecuteOne(4);
psg.sampleclock += 4;
psg.generate_sound();
sampleclock += 4;
new_sample |= psg.generate_sound();
new_sample |= SCC_1.generate_sound();
//new_sample |= SCC_2.generate_sound();
if (new_sample) { Add_Audio_Sample(); }
for (int i = 0; i < 14; i++)
{
cpu.ExecuteOne(16);
psg.sampleclock += 16;
psg.generate_sound();
sampleclock += 16;
new_sample |= psg.generate_sound();
new_sample |= SCC_1.generate_sound();
//new_sample |= SCC_2.generate_sound();
if (new_sample) { Add_Audio_Sample(); }
}
sl_case = 0;
break;
@ -145,6 +179,23 @@ namespace MSXHawk
return MemMap.lagged;
}
void Add_Audio_Sample()
{
if (num_samples < 4500)
{
samples[num_samples * 2] = sampleclock;
samples[num_samples * 2 + 1] = psg.current_sample - psg.old_sample;
samples[num_samples * 2 + 1] += SCC_1.current_sample - SCC_1.old_sample;
//samples[num_samples * 2 + 1] = SCC_2.current_sample - SCC_2.old_sample;
num_samples++;
psg.old_sample = psg.current_sample;
SCC_1.old_sample = SCC_1.current_sample;
//SCC_2.old_sample = SCC_2.current_sample;
new_sample = false;
}
}
void GetVideo(uint32_t* dest)
{
uint32_t* src = vdp.FrameBuffer;
@ -155,13 +206,13 @@ namespace MSXHawk
uint32_t GetAudio(int32_t* dest, int32_t* n_samp)
{
int32_t* src = psg.samples;
int32_t* src = samples;
int32_t* dst = dest;
std::memcpy(dst, src, sizeof int32_t * psg.num_samples * 2);
n_samp[0] = psg.num_samples;
std::memcpy(dst, src, sizeof int32_t * num_samples * 2);
n_samp[0] = num_samples;
return psg.sampleclock;
return sampleclock;
}
int GetMessageLength()
@ -182,8 +233,11 @@ namespace MSXHawk
saver = vdp.SaveState(saver);
saver = cpu.SaveState(saver);
saver = psg.SaveState(saver);
saver = SCC_1.SaveState(saver);
saver = SCC_2.SaveState(saver);
saver = MemMap.SaveState(saver);
*saver = (uint8_t)(new_sample ? 1 : 0); saver++;
*saver = sl_case; saver++;
}
@ -192,8 +246,11 @@ namespace MSXHawk
loader = vdp.LoadState(loader);
loader = cpu.LoadState(loader);
loader = psg.LoadState(loader);
loader = SCC_1.LoadState(loader);
loader = SCC_2.LoadState(loader);
loader = MemMap.LoadState(loader);
new_sample = *loader == 1; loader++;
sl_case = *loader; loader++;
}

View File

@ -160,6 +160,7 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="Core.h" />
<ClInclude Include="SCC.h" />
<ClInclude Include="Memory.h" />
<ClInclude Include="TMS9918A.h" />
<ClInclude Include="AY_3_8910.h" />

View File

@ -7,6 +7,7 @@
#include "Z80A.h"
#include "TMS9918A.h"
#include "AY_3_8910.h"
#include "SCC.h"
using namespace std;
@ -300,6 +301,72 @@ namespace MSXHawk
}
}
}
else if (rom_mapper_1 == 2) // konami mapper with SCC
{
if (base_addr == 0)
{
if (segment < 8)
{
if (SCC_1_enabled)
{
return &unmapped[0];
}
return &rom_1[rom1_konami_page_2 * 0x2000 + (0x400 * segment)];
}
else
{
segment -= 8;
return &rom_1[rom1_konami_page_3 * 0x2000 + (0x400 * segment)];
}
}
else if (base_addr == 0x4000)
{
if (segment < 8)
{
return &rom_1[(0x400 * segment)];
}
else
{
segment -= 8;
return &rom_1[rom1_konami_page_1 * 0x2000 + (0x400 * segment)];
}
}
else if (base_addr == 0x8000)
{
if (segment < 8)
{
if (SCC_1_enabled)
{
if (segment < 6)
{
return &unmapped[0];
}
else
{
return &SCC_1_page[0];
}
}
return &rom_1[rom1_konami_page_2 * 0x2000 + (0x400 * segment)];
}
else
{
segment -= 8;
return &rom_1[rom1_konami_page_3 * 0x2000 + (0x400 * segment)];
}
}
else
{
if (segment < 8)
{
return &rom_1[(0x400 * segment)];
}
else
{
segment -= 8;
return &rom_1[rom1_konami_page_1 * 0x2000 + (0x400 * segment)];
}
}
}
else
{
return &unmapped[0];
@ -363,9 +430,126 @@ namespace MSXHawk
}
}
}
else if (rom_mapper_2 == 2) // konami mapper with SCC
{
if (base_addr == 0)
{
if (segment < 8)
{
if (SCC_2_enabled)
{
return &unmapped[0];
}
return &rom_2[rom2_konami_page_2 * 0x2000 + (0x400 * segment)];
}
else
{
segment -= 8;
return &rom_2[rom2_konami_page_3 * 0x2000 + (0x400 * segment)];
}
}
else if (base_addr == 0x4000)
{
if (segment < 8)
{
return &rom_2[(0x400 * segment)];
}
else
{
segment -= 8;
return &rom_2[rom2_konami_page_1 * 0x2000 + (0x400 * segment)];
}
}
else if (base_addr == 0x8000)
{
if (segment < 8)
{
if (SCC_2_enabled)
{
if (segment < 6)
{
return &unmapped[0];
}
else
{
return &SCC_2_page[0];
}
}
return &rom_2[rom2_konami_page_2 * 0x2000 + (0x400 * segment)];
}
else
{
segment -= 8;
return &rom_2[rom2_konami_page_3 * 0x2000 + (0x400 * segment)];
}
}
else
{
if (segment < 8)
{
return &rom_2[(0x400 * segment)];
}
else
{
segment -= 8;
return &rom_2[rom2_konami_page_1 * 0x2000 + (0x400 * segment)];
}
}
}
else
{
return &unmapped[0];
}
}
void MemoryManager::MemoryWrite(uint32_t addr, uint8_t value)
{
// Konami addresses without SCC
if (rom_mapper_1 == 1)
{
if (addr >= 0x6000 && addr < 0x8000 && slot_1_has_rom == 1) { rom1_konami_page_1 = (uint8_t)(value & rom_size_1); remap(); }
if (addr >= 0x8000 && addr < 0xA000 && slot_2_has_rom == 1) { rom1_konami_page_2 = (uint8_t)(value & rom_size_1); remap(); }
if (addr >= 0xA000 && addr < 0xC000 && slot_2_has_rom == 1) { rom1_konami_page_3 = (uint8_t)(value & rom_size_1); remap(); }
}
if (rom_mapper_2 == 1)
{
if (addr >= 0x6000 && addr < 0x8000 && slot_1_has_rom == 2) { rom2_konami_page_1 = (uint8_t)(value & rom_size_2); remap(); }
if (addr >= 0x8000 && addr < 0xA000 && slot_2_has_rom == 2) { rom2_konami_page_2 = (uint8_t)(value & rom_size_2); remap(); }
if (addr >= 0xA000 && addr < 0xC000 && slot_2_has_rom == 2) { rom2_konami_page_3 = (uint8_t)(value & rom_size_2); remap(); }
}
// Konami addresses with SCC
if (rom_mapper_1 == 2)
{
if (addr >= 0x5000 && addr < 0x5800 && slot_1_has_rom == 1) { rom1_konami_page_0 = (uint8_t)(value & rom_size_1); remap(); }
if (addr >= 0x7000 && addr < 0x7800 && slot_1_has_rom == 1) { rom1_konami_page_1 = (uint8_t)(value & rom_size_1); remap(); }
if (addr >= 0x9000 && addr < 0x9800 && slot_2_has_rom == 1)
{
if ((value & 0xFF) == 0x3F) { SCC_1_enabled = true; }
else { SCC_1_enabled = false; }
rom1_konami_page_2 = (uint8_t)(value & rom_size_1); remap();
}
if (addr >= 0x9800 && addr < 0xA000 && slot_2_has_rom == 1 && SCC_1_enabled)
{
SCC_1_pntr->WriteReg(value & 0xFF);
}
if (addr >= 0xB000 && addr < 0xB800 && slot_2_has_rom == 1) { rom1_konami_page_3 = (uint8_t)(value & rom_size_1); remap(); }
}
if (rom_mapper_2 == 2)
{
if (addr >= 0x5000 && addr < 0x5800 && slot_1_has_rom == 2) { rom2_konami_page_0 = (uint8_t)(value & rom_size_2); remap(); }
if (addr >= 0x7000 && addr < 0x7800 && slot_1_has_rom == 2) { rom2_konami_page_1 = (uint8_t)(value & rom_size_2); remap(); }
if (addr >= 0x9000 && addr < 0x9800 && slot_2_has_rom == 2)
{
if ((value & 0xFF) == 0x3F) { SCC_2_enabled = true; }
else { SCC_2_enabled = false; }
rom2_konami_page_2 = (uint8_t)(value & rom_size_2); remap();
}
if (addr >= 0x9800 && addr < 0xA000 && slot_2_has_rom == 1 && SCC_2_enabled)
{
SCC_2_pntr->WriteReg(value & 0xFF);
}
if (addr >= 0xB000 && addr < 0xB800 && slot_2_has_rom == 2) { rom2_konami_page_3 = (uint8_t)(value & rom_size_2); remap(); }
}
}
}

View File

@ -10,6 +10,7 @@ namespace MSXHawk
class Z80A;
class TMS9918A;
class AY_3_8910;
class SCC;
class MemoryManager
{
@ -17,6 +18,8 @@ namespace MSXHawk
TMS9918A* vdp_pntr = nullptr;
AY_3_8910* psg_pntr = nullptr;
SCC* SCC_1_pntr = nullptr;
SCC* SCC_2_pntr = nullptr;
Z80A* cpu_pntr = nullptr;
uint8_t* rom_1 = nullptr;
uint8_t* rom_2 = nullptr;
@ -44,6 +47,16 @@ namespace MSXHawk
uint8_t ram[0x10000] = {};
uint8_t cart_ram[0x8000] = {};
uint8_t unmapped[0x400] = {};
uint8_t SCC_1_page[0x400] = {};
uint8_t SCC_2_page[0x400] = {};
// mapper support and variables
uint8_t slot_0_has_rom, slot_1_has_rom, slot_2_has_rom, slot_3_has_rom;
uint8_t rom1_konami_page_0, rom1_konami_page_1, rom1_konami_page_2, rom1_konami_page_3;
uint8_t rom2_konami_page_0, rom2_konami_page_1, rom2_konami_page_2, rom2_konami_page_3;
bool SCC_1_enabled = false;
bool SCC_2_enabled = false;
MemoryManager()
{
@ -59,6 +72,8 @@ namespace MSXHawk
void HardwareWrite(uint32_t addr, uint8_t value);
void MemoryWrite(uint32_t addr, uint8_t value);
void remap();
uint8_t* remap_rom1(uint32_t, uint32_t);
@ -83,20 +98,24 @@ namespace MSXHawk
memcpy(rom_1, ext_rom_1, ext_rom_size_1);
memcpy(rom_2, ext_rom_2, ext_rom_size_2);
rom_size_1 = ext_rom_size_1 / 0x400 - 1;
rom_mapper_1 = ext_rom_mapper_1;
rom_size_2 = ext_rom_size_2 / 0x400 - 1;
rom_mapper_2 = ext_rom_mapper_2;
if (rom_mapper_1 == 1)
// page size 0x2000 for konami games
if (rom_mapper_1 == 1 || rom_mapper_1 == 2) { rom_size_1 = ext_rom_size_1 / 0x2000 - 1; }
if (rom_mapper_2 == 1 || rom_mapper_2 == 2) { rom_size_2 = ext_rom_size_2 / 0x2000 - 1; }
if (rom_mapper_1 == 1 || rom_mapper_1 == 2)
{
rom1_konami_page_0 = 0;
rom1_konami_page_1 = 1;
rom1_konami_page_2 = 2;
rom1_konami_page_3 = 3;
}
if (rom_mapper_2 == 1)
if (rom_mapper_2 == 1 || rom_mapper_2 == 2)
{
rom2_konami_page_0 = 0;
rom2_konami_page_1 = 1;
rom2_konami_page_2 = 2;
rom2_konami_page_3 = 3;
@ -108,28 +127,6 @@ namespace MSXHawk
remap();
}
// mapper support and variables
uint8_t slot_0_has_rom, slot_1_has_rom, slot_2_has_rom, slot_3_has_rom;
uint8_t rom1_konami_page_1, rom1_konami_page_2, rom1_konami_page_3;
uint8_t rom2_konami_page_1, rom2_konami_page_2, rom2_konami_page_3;
void MemoryWrite(uint32_t addr, uint8_t value)
{
if (rom_mapper_1 == 1)
{
if (addr >= 0x6000 && addr < 0x8000 && slot_1_has_rom == 1) { rom1_konami_page_1 = (uint8_t)(value & rom_size_1); remap(); }
if (addr >= 0x8000 && addr < 0xA000 && slot_2_has_rom == 1) { rom1_konami_page_2 = (uint8_t)(value & rom_size_1); remap(); }
if (addr >= 0xA000 && addr < 0xC000 && slot_2_has_rom == 1) { rom1_konami_page_3 = (uint8_t)(value & rom_size_1); remap(); }
}
if (rom_mapper_2 == 1)
{
if (addr >= 0x6000 && addr < 0x8000 && slot_1_has_rom == 2) { rom2_konami_page_1 = (uint8_t)(value & rom_size_2); remap(); }
if (addr >= 0x8000 && addr < 0xA000 && slot_2_has_rom == 2) { rom2_konami_page_2 = (uint8_t)(value & rom_size_2); remap(); }
if (addr >= 0xA000 && addr < 0xC000 && slot_2_has_rom == 2) { rom2_konami_page_3 = (uint8_t)(value & rom_size_2); remap(); }
}
}
#pragma region State Save / Load
uint8_t* SaveState(uint8_t* saver)
@ -137,6 +134,8 @@ namespace MSXHawk
*saver = (uint8_t)(PortDEEnabled ? 1 : 0); saver++;
*saver = (uint8_t)(lagged ? 1 : 0); saver++;
*saver = (uint8_t)(start_pressed ? 1 : 0); saver++;
*saver = (uint8_t)(SCC_1_enabled ? 1 : 0); saver++;
*saver = (uint8_t)(SCC_2_enabled ? 1 : 0); saver++;
*saver = kb_rows_sel; saver++;
*saver = PortA8; saver++;
@ -150,15 +149,19 @@ namespace MSXHawk
*saver = slot_2_has_rom; saver++;
*saver = slot_3_has_rom; saver++;
*saver = rom1_konami_page_0; saver++;
*saver = rom1_konami_page_1; saver++;
*saver = rom1_konami_page_2; saver++;
*saver = rom1_konami_page_3; saver++;
*saver = rom2_konami_page_0; saver++;
*saver = rom2_konami_page_1; saver++;
*saver = rom2_konami_page_2; saver++;
*saver = rom2_konami_page_3; saver++;
std::memcpy(saver, &ram, 0x10000); saver += 0x10000;
std::memcpy(saver, &cart_ram, 0x8000); saver += 0x8000;
std::memcpy(saver, &SCC_1_page, 0x400); saver += 0x400;
std::memcpy(saver, &SCC_2_page, 0x400); saver += 0x400;
return saver;
}
@ -168,6 +171,8 @@ namespace MSXHawk
PortDEEnabled = *loader == 1; loader++;
lagged = *loader == 1; loader++;
start_pressed = *loader == 1; loader++;
SCC_1_enabled = *loader == 1; loader++;
SCC_2_enabled = *loader == 1; loader++;
kb_rows_sel = *loader; loader++;
PortA8 = *loader; loader++;
@ -181,15 +186,19 @@ namespace MSXHawk
slot_2_has_rom = *loader; loader++;
slot_3_has_rom = *loader; loader++;
rom1_konami_page_0 = *loader; loader++;
rom1_konami_page_1 = *loader; loader++;
rom1_konami_page_2 = *loader; loader++;
rom1_konami_page_3 = *loader; loader++;
rom2_konami_page_0 = *loader; loader++;
rom2_konami_page_1 = *loader; loader++;
rom2_konami_page_2 = *loader; loader++;
rom2_konami_page_3 = *loader; loader++;
std::memcpy(&ram, loader, 0x10000); loader += 0x10000;
std::memcpy(&cart_ram, loader, 0x8000); loader += 0x8000;
std::memcpy(&SCC_1_page, loader, 0x400); loader += 0x400;
std::memcpy(&SCC_2_page, loader, 0x400); loader += 0x400;
remap();

View File

@ -0,0 +1,437 @@
#include <iostream>
#include <cstdint>
#include <iomanip>
#include <string>
using namespace std;
namespace MSXHawk
{
class SCC
{
public:
#pragma region SCC
SCC()
{
Reset();
}
uint8_t* page_pointer = nullptr;
bool A_on, B_on, C_on;
bool A_up, B_up, C_up;
bool A_noise, B_noise, C_noise;
bool env_vol_A, env_vol_B, env_vol_C;
uint8_t env_shape;
uint8_t port_sel;
uint8_t vol_A, vol_B, vol_C;
uint8_t Register[16] = {};
uint32_t psg_clock;
uint32_t sq_per_A, sq_per_B, sq_per_C;
uint32_t clock_A, clock_B, clock_C;
uint32_t env_per;
uint32_t env_clock;
int32_t env_E;
int32_t E_up_down;
uint32_t noise_clock;
uint32_t noise_per;
uint32_t noise = 0x1;
int32_t old_sample;
int32_t current_sample;
// non stated if only on frame boundaries
bool sound_out_A;
bool sound_out_B;
bool sound_out_C;
uint8_t Clock_Divider;
void Reset()
{
clock_A = clock_B = clock_C = 0x1000;
noise_clock = 0x20;
port_sel = 0;
for (int i = 0; i < 16; i++)
{
Register[i] = 0x0;
}
sync_psg_state();
}
short Sample()
{
return current_sample;
}
const uint32_t VolumeTable[16] =
{
0x0000, 0x0055, 0x0079, 0x00AB, 0x00F1, 0x0155, 0x01E3, 0x02AA,
0x03C5, 0x0555, 0x078B, 0x0AAB, 0x0F16, 0x1555, 0x1E2B, 0x2AAA
};
// returns do not occur in this iplementation, they come from the core
uint8_t ReadReg()
{
}
void sync_psg_state()
{
sq_per_A = (Register[0] & 0xFF) | (((Register[1] & 0xF) << 8));
if (sq_per_A == 0)
{
sq_per_A = 0x1000;
}
sq_per_B = (Register[2] & 0xFF) | (((Register[3] & 0xF) << 8));
if (sq_per_B == 0)
{
sq_per_B = 0x1000;
}
sq_per_C = (Register[4] & 0xFF) | (((Register[5] & 0xF) << 8));
if (sq_per_C == 0)
{
sq_per_C = 0x1000;
}
env_per = (Register[11] & 0xFF) | (((Register[12] & 0xFF) << 8));
if (env_per == 0)
{
env_per = 0x10000;
}
env_per *= 2;
A_on = (Register[7] & 0x1) > 0;
B_on = (Register[7] & 0x2) > 0;
C_on = (Register[7] & 0x4) > 0;
A_noise = (Register[7] & 0x8) > 0;
B_noise = (Register[7] & 0x10) > 0;
C_noise = (Register[7] & 0x20) > 0;
noise_per = Register[6] & 0x1F;
if (noise_per == 0)
{
noise_per = 0x20;
}
uint8_t shape_select = Register[13] & 0xF;
if (shape_select < 4) { env_shape = 0; }
else if (shape_select < 8) { env_shape = 1; }
else { env_shape = 2 + (shape_select - 8); }
vol_A = Register[8] & 0xF;
env_vol_A = ((Register[8] >> 4) & 0x1) > 0;
vol_B = Register[9] & 0xF;
env_vol_B = ((Register[9] >> 4) & 0x1) > 0;
vol_C = Register[10] & 0xF;
env_vol_C = ((Register[10] >> 4) & 0x1) > 0;
}
void WriteReg(uint8_t value)
{
value &= 0xFF;
if (port_sel != 0xE) { Register[port_sel] = value; }
sync_psg_state();
if (port_sel == 13)
{
env_clock = env_per;
if (env_shape == 0 || env_shape == 2 || env_shape == 3 || env_shape == 4 || env_shape == 5)
{
env_E = 15;
E_up_down = -1;
}
else
{
env_E = 0;
E_up_down = 1;
}
}
}
bool generate_sound()
{
// there are 8 cpu cycles for every psg cycle
clock_A--;
clock_B--;
clock_C--;
noise_clock--;
env_clock--;
// clock noise
if (noise_clock == 0)
{
noise = (noise >> 1) ^ (((noise & 0x1) > 0) ? 0x10004 : 0);
noise_clock = noise_per;
}
if (env_clock == 0)
{
env_clock = env_per;
env_E += E_up_down;
if (env_E == 16 || env_E == -1)
{
// we just completed a period of the envelope, determine what to do now based on the envelope shape
if (env_shape == 0 || env_shape == 1 || env_shape == 3 || env_shape == 9)
{
E_up_down = 0;
env_E = 0;
}
else if (env_shape == 5 || env_shape == 7)
{
E_up_down = 0;
env_E = 15;
}
else if (env_shape == 4 || env_shape == 8)
{
if (env_E == 16)
{
env_E = 15;
E_up_down = -1;
}
else
{
env_E = 0;
E_up_down = 1;
}
}
else if (env_shape == 2)
{
env_E = 15;
}
else
{
env_E = 0;
}
}
}
if (clock_A == 0)
{
A_up = !A_up;
clock_A = sq_per_A;
}
if (clock_B == 0)
{
B_up = !B_up;
clock_B = sq_per_B;
}
if (clock_C == 0)
{
C_up = !C_up;
clock_C = sq_per_C;
}
sound_out_A = (((noise & 0x1) > 0) | A_noise) & (A_on | A_up);
sound_out_B = (((noise & 0x1) > 0) | B_noise) & (B_on | B_up);
sound_out_C = (((noise & 0x1) > 0) | C_noise) & (C_on | C_up);
// now calculate the volume of each channel and add them together
current_sample = 0;
if (env_vol_A)
{
current_sample = (sound_out_A ? VolumeTable[env_E] : 0);
}
else
{
current_sample = (sound_out_A ? VolumeTable[vol_A] : 0);
}
if (env_vol_B)
{
current_sample += (sound_out_B ? VolumeTable[env_E] : 0);
}
else
{
current_sample += (sound_out_B ? VolumeTable[vol_B] : 0);
}
if (env_vol_C)
{
current_sample += (sound_out_C ? VolumeTable[env_E] : 0);
}
else
{
current_sample += (sound_out_C ? VolumeTable[vol_C] : 0);
}
current_sample *= 2;
if (current_sample != old_sample) { return true; }
return false;
}
#pragma endregion
#pragma region State Save / Load
uint8_t* SaveState(uint8_t* saver)
{
*saver = (uint8_t)(A_on ? 1 : 0); saver++;
*saver = (uint8_t)(B_on ? 1 : 0); saver++;
*saver = (uint8_t)(C_on ? 1 : 0); saver++;
*saver = (uint8_t)(A_up ? 1 : 0); saver++;
*saver = (uint8_t)(B_up ? 1 : 0); saver++;
*saver = (uint8_t)(C_up ? 1 : 0); saver++;
*saver = (uint8_t)(A_noise ? 1 : 0); saver++;
*saver = (uint8_t)(B_noise ? 1 : 0); saver++;
*saver = (uint8_t)(C_noise ? 1 : 0); saver++;
*saver = (uint8_t)(env_vol_A ? 1 : 0); saver++;
*saver = (uint8_t)(env_vol_B ? 1 : 0); saver++;
*saver = (uint8_t)(env_vol_C ? 1 : 0); saver++;
*saver = env_shape; saver++;
*saver = port_sel; saver++;
*saver = vol_A; saver++;
*saver = vol_B; saver++;
*saver = vol_C; saver++;
for (int i = 0; i < 16; i++) { *saver = Register[i]; saver++; }
*saver = (uint8_t)(psg_clock & 0xFF); saver++; *saver = (uint8_t)((psg_clock >> 8) & 0xFF); saver++;
*saver = (uint8_t)((psg_clock >> 16) & 0xFF); saver++; *saver = (uint8_t)((psg_clock >> 24) & 0xFF); saver++;
*saver = (uint8_t)(sq_per_A & 0xFF); saver++; *saver = (uint8_t)((sq_per_A >> 8) & 0xFF); saver++;
*saver = (uint8_t)((sq_per_A >> 16) & 0xFF); saver++; *saver = (uint8_t)((sq_per_A >> 24) & 0xFF); saver++;
*saver = (uint8_t)(sq_per_B & 0xFF); saver++; *saver = (uint8_t)((sq_per_B >> 8) & 0xFF); saver++;
*saver = (uint8_t)((sq_per_B >> 16) & 0xFF); saver++; *saver = (uint8_t)((sq_per_B >> 24) & 0xFF); saver++;
*saver = (uint8_t)(sq_per_C & 0xFF); saver++; *saver = (uint8_t)((sq_per_C >> 8) & 0xFF); saver++;
*saver = (uint8_t)((sq_per_C >> 16) & 0xFF); saver++; *saver = (uint8_t)((sq_per_C >> 24) & 0xFF); saver++;
*saver = (uint8_t)(clock_A & 0xFF); saver++; *saver = (uint8_t)((clock_A >> 8) & 0xFF); saver++;
*saver = (uint8_t)((clock_A >> 16) & 0xFF); saver++; *saver = (uint8_t)((clock_A >> 24) & 0xFF); saver++;
*saver = (uint8_t)(clock_B & 0xFF); saver++; *saver = (uint8_t)((clock_B >> 8) & 0xFF); saver++;
*saver = (uint8_t)((clock_B >> 16) & 0xFF); saver++; *saver = (uint8_t)((clock_B >> 24) & 0xFF); saver++;
*saver = (uint8_t)(clock_C & 0xFF); saver++; *saver = (uint8_t)((clock_C >> 8) & 0xFF); saver++;
*saver = (uint8_t)((clock_C >> 16) & 0xFF); saver++; *saver = (uint8_t)((clock_C >> 24) & 0xFF); saver++;
*saver = (uint8_t)(env_per & 0xFF); saver++; *saver = (uint8_t)((env_per >> 8) & 0xFF); saver++;
*saver = (uint8_t)((env_per >> 16) & 0xFF); saver++; *saver = (uint8_t)((env_per >> 24) & 0xFF); saver++;
*saver = (uint8_t)(env_clock & 0xFF); saver++; *saver = (uint8_t)((env_clock >> 8) & 0xFF); saver++;
*saver = (uint8_t)((env_clock >> 16) & 0xFF); saver++; *saver = (uint8_t)((env_clock >> 24) & 0xFF); saver++;
*saver = (uint8_t)(env_E & 0xFF); saver++; *saver = (uint8_t)((env_E >> 8) & 0xFF); saver++;
*saver = (uint8_t)((env_E >> 16) & 0xFF); saver++; *saver = (uint8_t)((env_E >> 24) & 0xFF); saver++;
*saver = (uint8_t)(E_up_down & 0xFF); saver++; *saver = (uint8_t)((E_up_down >> 8) & 0xFF); saver++;
*saver = (uint8_t)((E_up_down >> 16) & 0xFF); saver++; *saver = (uint8_t)((E_up_down >> 24) & 0xFF); saver++;
*saver = (uint8_t)(noise_clock & 0xFF); saver++; *saver = (uint8_t)((noise_clock >> 8) & 0xFF); saver++;
*saver = (uint8_t)((noise_clock >> 16) & 0xFF); saver++; *saver = (uint8_t)((noise_clock >> 24) & 0xFF); saver++;
*saver = (uint8_t)(noise_per & 0xFF); saver++; *saver = (uint8_t)((noise_per >> 8) & 0xFF); saver++;
*saver = (uint8_t)((noise_per >> 16) & 0xFF); saver++; *saver = (uint8_t)((noise_per >> 24) & 0xFF); saver++;
*saver = (uint8_t)(noise & 0xFF); saver++; *saver = (uint8_t)((noise >> 8) & 0xFF); saver++;
*saver = (uint8_t)((noise >> 16) & 0xFF); saver++; *saver = (uint8_t)((noise >> 24) & 0xFF); saver++;
*saver = (uint8_t)(old_sample & 0xFF); saver++; *saver = (uint8_t)((old_sample >> 8) & 0xFF); saver++;
*saver = (uint8_t)((old_sample >> 16) & 0xFF); saver++; *saver = (uint8_t)((old_sample >> 24) & 0xFF); saver++;
return saver;
}
uint8_t* LoadState(uint8_t* loader)
{
A_on = *loader == 1; loader++;
B_on = *loader == 1; loader++;
C_on = *loader == 1; loader++;
A_up = *loader == 1; loader++;
B_up = *loader == 1; loader++;
C_up = *loader == 1; loader++;
A_noise = *loader == 1; loader++;
B_noise = *loader == 1; loader++;
C_noise = *loader == 1; loader++;
env_vol_A = *loader == 1; loader++;
env_vol_B = *loader == 1; loader++;
env_vol_C = *loader == 1; loader++;
env_shape = *loader; loader++;
port_sel = *loader; loader++;
vol_A = *loader; loader++;
vol_B = *loader; loader++;
vol_C = *loader; loader++;
for (int i = 0; i < 16; i++) { Register[i] = *loader; loader++; }
psg_clock = *loader; loader++; psg_clock |= (*loader << 8); loader++;
psg_clock |= (*loader << 16); loader++; psg_clock |= (*loader << 24); loader++;
sq_per_A = *loader; loader++; sq_per_A |= (*loader << 8); loader++;
sq_per_A |= (*loader << 16); loader++; sq_per_A |= (*loader << 24); loader++;
sq_per_B = *loader; loader++; sq_per_B |= (*loader << 8); loader++;
sq_per_B |= (*loader << 16); loader++; sq_per_B |= (*loader << 24); loader++;
sq_per_C = *loader; loader++; sq_per_C |= (*loader << 8); loader++;
sq_per_C |= (*loader << 16); loader++; sq_per_C |= (*loader << 24); loader++;
clock_A = *loader; loader++; clock_A |= (*loader << 8); loader++;
clock_A |= (*loader << 16); loader++; clock_A |= (*loader << 24); loader++;
clock_B = *loader; loader++; clock_B |= (*loader << 8); loader++;
clock_B |= (*loader << 16); loader++; clock_B |= (*loader << 24); loader++;
clock_C = *loader; loader++; clock_C |= (*loader << 8); loader++;
clock_C |= (*loader << 16); loader++; clock_C |= (*loader << 24); loader++;
env_per = *loader; loader++; env_per |= (*loader << 8); loader++;
env_per |= (*loader << 16); loader++; env_per |= (*loader << 24); loader++;
env_clock = *loader; loader++; env_clock |= (*loader << 8); loader++;
env_clock |= (*loader << 16); loader++; env_clock |= (*loader << 24); loader++;
env_E = *loader; loader++; env_E |= (*loader << 8); loader++;
env_E |= (*loader << 16); loader++; env_E |= (*loader << 24); loader++;
E_up_down = *loader; loader++; E_up_down |= (*loader << 8); loader++;
E_up_down |= (*loader << 16); loader++; E_up_down |= (*loader << 24); loader++;
noise_clock = *loader; loader++; noise_clock |= (*loader << 8); loader++;
noise_clock |= (*loader << 16); loader++; noise_clock |= (*loader << 24); loader++;
noise_per = *loader; loader++; noise_per |= (*loader << 8); loader++;
noise_per |= (*loader << 16); loader++; noise_per |= (*loader << 24); loader++;
noise = *loader; loader++; noise |= (*loader << 8); loader++;
noise |= (*loader << 16); loader++; noise |= (*loader << 24); loader++;
old_sample = *loader; loader++; old_sample |= (*loader << 8); loader++;
old_sample |= (*loader << 16); loader++; old_sample |= (*loader << 24); loader++;
return loader;
}
#pragma endregion
};
}

View File

@ -1,5 +1,6 @@
using System;
using System.Text;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Computers.MSX
@ -16,7 +17,13 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
SyncSettings = (MSXSyncSettings)syncSettings ?? new MSXSyncSettings();
RomData = new byte[rom.Length];
// look up game in db before transforming ROM
var hash_md5 = MD5Checksum.ComputePrefixedHex(rom);
var gi = Database.CheckDatabase(hash_md5);
var dict = gi.GetOptions();
string s_mapper;
for (int i = 0; i < rom.Length; i++)
{
RomData[i] = rom[i];
@ -38,8 +45,25 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
}
else
{
mapper_1 = 1;
Console.WriteLine("Konami Mapper");
// Assume default konami style mapper
if (gi == null)
{
}
else if (!dict.TryGetValue("mapper", out s_mapper))
{
mapper_1 = 1;
Console.WriteLine("Using Konami Mapper");
}
else
{
if (s_mapper == "2")
{
mapper_1 = 2;
Console.WriteLine("Using Konami Mapper with SCC");
}
}
}
// if the original was not 64 or 48 k, move it (may need to do this case by case)
@ -135,7 +159,7 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
}
private IntPtr MSX_Pntr { get; set; } = IntPtr.Zero;
private byte[] MSX_core = new byte[0x20000];
private byte[] MSX_core = new byte[0x28000];
public static byte[] Bios = null;
public static byte[] Basic;