diff --git a/libHawk/MSXHawk/MSXHawk/MSXHawk.vcxproj b/libHawk/MSXHawk/MSXHawk/MSXHawk.vcxproj index a7d78dee69..f512c51c99 100644 --- a/libHawk/MSXHawk/MSXHawk/MSXHawk.vcxproj +++ b/libHawk/MSXHawk/MSXHawk/MSXHawk.vcxproj @@ -159,6 +159,8 @@ + + diff --git a/libHawk/MSXHawk/MSXHawk/PSG.h b/libHawk/MSXHawk/MSXHawk/PSG.h new file mode 100644 index 0000000000..c3e5892994 --- /dev/null +++ b/libHawk/MSXHawk/MSXHawk/PSG.h @@ -0,0 +1,264 @@ +#pragma once + +#include +#include +#include +#include + +using namespace std; + +namespace MSXHawk +{ + class SN76489sms + { + public: + int current_sample_L; + int current_sample_R; + + SN76489sms() + { + Reset(); + } + + uint8_t Chan_vol[4]; + uint16_t Chan_tone[4]; + + int chan_sel; + bool vol_tone; + bool noise_type; + int noise_rate; + bool noise_bit; + + bool A_L, B_L, C_L, noise_L; + bool A_R, B_R, C_R, noise_R; + + int psg_clock; + + int clock_A, clock_B, clock_C; + + bool A_up, B_up, C_up; + + int noise_clock; + int noise; + + uint8_t stereo_panning; + const uint8_t LogScale[16] = { 255, 203, 161, 128, 102, 86, 64, 51, 40, 32, 26, 20, 16, 13, 10, 0 }; + + void Reset() + { + clock_A = clock_B = clock_C = 0x1000; + noise_clock = 0x10; + chan_sel = 0; + + // reset the shift register + noise = 0x40000; + + Chan_vol[0] = 0xF; + Chan_vol[1] = 0xF; + Chan_vol[2] = 0xF; + Chan_vol[3] = 0xF; + + Set_Panning(0xFF); + } + + void Set_Panning(uint8_t value) + { + A_L = (value & 0x10) != 0; + A_R = (value & 0x01) != 0; + B_L = (value & 0x20) != 0; + B_R = (value & 0x02) != 0; + C_L = (value & 0x40) != 0; + C_R = (value & 0x04) != 0; + noise_L = (value & 0x80) != 0; + noise_R = (value & 0x08) != 0; + + stereo_panning = value; + } + + /* + void SyncState(Serializer ser) + { + ser.BeginSection("SN76489"); + + ser.Sync(nameof(Chan_vol), ref Chan_vol, false); + ser.Sync(nameof(Chan_tone), ref Chan_tone, false); + + ser.Sync(nameof(chan_sel), ref chan_sel); + ser.Sync(nameof(vol_tone), ref vol_tone); + ser.Sync(nameof(noise_type), ref noise_type); + ser.Sync(nameof(noise_rate), ref noise_rate); + + ser.Sync(nameof(clock_A), ref clock_A); + ser.Sync(nameof(clock_B), ref clock_B); + ser.Sync(nameof(clock_C), ref clock_C); + ser.Sync(nameof(noise_clock), ref noise_clock); + ser.Sync(nameof(noise_bit), ref noise_bit); + + ser.Sync(nameof(psg_clock), ref psg_clock); + + ser.Sync(nameof(A_up), ref A_up); + ser.Sync(nameof(B_up), ref B_up); + ser.Sync(nameof(C_up), ref C_up); + ser.Sync(nameof(noise), ref noise); + + ser.Sync(nameof(A_L), ref A_L); + ser.Sync(nameof(B_L), ref B_L); + ser.Sync(nameof(C_L), ref C_L); + ser.Sync(nameof(noise_L), ref noise_L); + ser.Sync(nameof(A_L), ref A_R); + ser.Sync(nameof(B_L), ref B_R); + ser.Sync(nameof(C_L), ref C_R); + ser.Sync(nameof(noise_L), ref noise_R); + + ser.Sync(nameof(current_sample_L), ref current_sample_L); + ser.Sync(nameof(current_sample_R), ref current_sample_R); + ser.Sync(nameof(stereo_panning), ref stereo_panning); + + ser.EndSection(); + } + */ + uint8_t ReadReg() + { + // not used, reading not allowed, just return 0xFF + return 0xFF; + } + + void WriteReg(uint8_t value) + { + // if bit 7 is set, change the latch, otherwise modify the currently latched register + if ((value & 0x80) > 0) + { + chan_sel = (value >> 5) & 3; + vol_tone = ((value & 0x10) > 0); + + if (vol_tone) + { + Chan_vol[chan_sel] = (uint8_t)(value & 0xF); + } + else + { + if (chan_sel < 3) + { + Chan_tone[chan_sel] &= 0x3F0; + Chan_tone[chan_sel] |= (uint16_t)(value & 0xF); + } + else + { + noise_type = ((value & 0x4) > 0); + noise_rate = value & 3; + + // reset the shift register + noise = 0x40000; + } + } + } + else + { + if (vol_tone) + { + Chan_vol[chan_sel] = (uint8_t)(value & 0xF); + } + else + { + if (chan_sel < 3) + { + Chan_tone[chan_sel] &= 0xF; + Chan_tone[chan_sel] |= (uint16_t)((value & 0x3F) << 4); + } + else + { + noise_type = ((value & 0x4) > 0); + noise_rate = value & 3; + + // reset the shift register + noise = 0x40000; + } + } + } + } + + void generate_sound() + { + // there are 16 cpu cycles for every psg cycle + psg_clock++; + + if (psg_clock == 16) + { + psg_clock = 0; + + clock_A--; + clock_B--; + clock_C--; + noise_clock--; + + // clock noise + if (noise_clock == 0) + { + noise_bit = ((noise & 1) > 0); + if (noise_type) + { + noise = (((noise & 1) ^ ((noise >> 1) & 1)) << 14) | (noise >> 1); + } + else + { + noise = ((noise & 1) << 14) | (noise >> 1); + } + + if (noise_rate == 0) + { + noise_clock = 0x10; + } + else if (noise_rate == 1) + { + noise_clock = 0x20; + } + else if (noise_rate == 2) + { + noise_clock = 0x40; + } + else + { + noise_clock = Chan_tone[2] + 1; + } + + noise_clock *= 2; + } + + if (clock_A == 0) + { + A_up = !A_up; + clock_A = Chan_tone[0] + 1; + } + + if (clock_B == 0) + { + B_up = !B_up; + clock_B = Chan_tone[1] + 1; + } + + if (clock_C == 0) + { + C_up = !C_up; + clock_C = Chan_tone[2] + 1; + } + + // now calculate the volume of each channel and add them together + current_sample_L = (A_L ? (A_up ? LogScale[Chan_vol[0]] * 42 : 0) : 0); + + current_sample_L += (B_L ? (B_up ? LogScale[Chan_vol[1]] * 42 : 0) : 0); + + current_sample_L += (C_L ? (C_up ? LogScale[Chan_vol[2]] * 42 : 0) : 0); + + current_sample_L += (noise_L ? (noise_bit ? LogScale[Chan_vol[3]] * 42 : 0) : 0); + + current_sample_R = (A_R ? (A_up ? LogScale[Chan_vol[0]] * 42 : 0) : 0); + + current_sample_R += (B_R ? (B_up ? LogScale[Chan_vol[1]] * 42 : 0) : 0); + + current_sample_R += (C_R ? (C_up ? LogScale[Chan_vol[2]] * 42 : 0) : 0); + + current_sample_R += (noise_R ? (noise_bit ? LogScale[Chan_vol[3]] * 42 : 0) : 0); + } + } + }; +} \ No newline at end of file diff --git a/libHawk/MSXHawk/MSXHawk/VDP.h b/libHawk/MSXHawk/MSXHawk/VDP.h new file mode 100644 index 0000000000..98f1150712 --- /dev/null +++ b/libHawk/MSXHawk/MSXHawk/VDP.h @@ -0,0 +1,1247 @@ +#pragma once + +#include +#include +#include +#include + +using namespace std; + +namespace MSXHawk +{ + class VDP + { + public: + #pragma region VDP + + // external pointers to CPU + bool* INT_FLAG; + // external flags to display background or sprites + bool SHOW_BG, SHOW_SPRITES; + + + // VDP State + uint8_t VRAM[0x4000]; //16kb video RAM + uint8_t CRAM[64]; // SMS = 32 uint8_ts, GG = 64 uint8_ts CRAM + uint8_t Registers[16] = { 0x06, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xF0, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t Statusuint8_t; + + const int Command_VramRead = 0x00; + const int Command_VramWrite = 0x40; + const int Command_RegisterWrite = 0x80; + const int Command_CramWrite = 0xC0; + + const int MODE_SMS = 1; + const int MODE_GG = 2; + + const int DISP_TYPE_NTSC = 1; + const int DISP_TYPE_PAL = 2; + + bool VdpWaitingForLatchuint8_t = true; + uint8_t VdpLatch; + uint8_t VdpBuffer; + uint16_t VdpAddress; + uint8_t VdpCommand; + int TmsMode = 4; + + bool VIntPending; + bool HIntPending; + int lineIntLinesRemaining; + + int mode; + int DisplayType; + + bool SpriteLimit; + int IPeriod = 228; + + int FrameHeight = 192; + int ScanLine; + uint8_t HCounter = 0x90; + int FrameBuffer[256 * 240]; + int GameGearFrameBuffer[160 * 144]; + int OverscanFrameBuffer[1]; + + bool Mode1Bit() { return (Registers[1] & 16) > 0; } + bool Mode2Bit() {return (Registers[0] & 2) > 0; } + bool Mode3Bit() {return (Registers[1] & 8) > 0; } + bool Mode4Bit() {return (Registers[0] & 4) > 0; } + bool ShiftSpritesLeft8Pixels() { return (Registers[0] & 8) > 0; } + bool EnableLineInterrupts() { return (Registers[0] & 16) > 0; } + bool LeftBlanking() { return (Registers[0] & 32) > 0; } + bool HorizScrollLock() { return (Registers[0] & 64) > 0; } + bool VerticalScrollLock() { return (Registers[0] & 128) > 0; } + bool EnableDoubledSprites() { return (Registers[1] & 1) > 0; } + bool EnableLargeSprites() { return (Registers[1] & 2) > 0; } + bool EnableFrameInterrupts() { return (Registers[1] & 32) > 0; } + bool DisplayOn() { return (Registers[1] & 64) > 0; } + int SpriteAttributeTableBase() { return ((Registers[5] >> 1) << 8) & 0x3FFF; } + int SpriteTileBase() { return (Registers[6] & 4) > 0 ? 256 : 0; } + uint8_t BackdropColor() { return (uint8_t)(16 + (Registers[7] & 15)); } + + int NameTableBase; + int ColorTableBase; + int PatternGeneratorBase; + int SpritePatternGeneratorBase; + int TmsPatternNameTableBase; + int TmsSpriteAttributeBase; + + // preprocessed state assist stuff. + int Palette[32]; + uint8_t PatternBuffer[0x8000]; + + uint8_t ScanlinePriorityBuffer[256]; + uint8_t SpriteCollisionBuffer[256]; + + const uint8_t SMSPalXlatTable[4] = { 0, 85, 170, 255 }; + const uint8_t GGPalXlatTable[16] = { 0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255 }; + + VDP(int vdp_mode, int displayType) + { + mode = vdp_mode; + + DisplayType = displayType; + NameTableBase = CalcNameTableBase(); + } + + uint8_t ReadData() + { + VdpWaitingForLatchuint8_t = true; + uint8_t value = VdpBuffer; + VdpBuffer = VRAM[VdpAddress & 0x3FFF]; + VdpAddress++; + return value; + } + + uint8_t ReadVdpStatus() + { + VdpWaitingForLatchuint8_t = true; + uint8_t returnValue = Statusuint8_t; + Statusuint8_t &= 0x1F; + HIntPending = false; + VIntPending = false; + INT_FLAG[0] = false; + return returnValue; + } + + uint8_t ReadVLineCounter() + { + if (DisplayType == DISP_TYPE_NTSC) + { + if (FrameHeight == 192) + return VLineCounterTableNTSC192[ScanLine]; + if (FrameHeight == 224) + return VLineCounterTableNTSC224[ScanLine]; + return VLineCounterTableNTSC240[ScanLine]; + } + else + { // PAL + if (FrameHeight == 192) + return VLineCounterTablePAL192[ScanLine]; + if (FrameHeight == 224) + return VLineCounterTablePAL224[ScanLine]; + return VLineCounterTablePAL240[ScanLine]; + } + } + + uint8_t ReadHLineCounter() + { + return HCounter; + } + + void WriteVdpControl(uint8_t value) + { + if (VdpWaitingForLatchuint8_t) + { + VdpLatch = value; + VdpWaitingForLatchuint8_t = false; + VdpAddress = (uint16_t)((VdpAddress & 0xFF00) | value); + return; + } + + VdpWaitingForLatchuint8_t = true; + VdpAddress = (uint16_t)(((value & 63) << 8) | VdpLatch); + switch (value & 0xC0) + { + case 0x00: // read VRAM + VdpCommand = Command_VramRead; + VdpBuffer = VRAM[VdpAddress & 0x3FFF]; + VdpAddress++; + break; + case 0x40: // write VRAM + VdpCommand = Command_VramWrite; + break; + case 0x80: // VDP register write + VdpCommand = Command_RegisterWrite; + int reg = value & 0x0F; + WriteRegister(reg, VdpLatch); + break; + case 0xC0: // write CRAM / modify palette + VdpCommand = Command_CramWrite; + break; + } + } + + void WriteVdpData(uint8_t value) + { + VdpWaitingForLatchuint8_t = true; + VdpBuffer = value; + if (VdpCommand == Command_CramWrite) + { + // Write Palette / CRAM + int mask = mode == MODE_SMS ? 0x1F : 0x3F; + CRAM[VdpAddress & mask] = value; + UpdatePrecomputedPalette(); + } + else + { + // Write VRAM and update pre-computed pattern buffer. + UpdatePatternBuffer((uint16_t)(VdpAddress & 0x3FFF), value); + VRAM[VdpAddress & 0x3FFF] = value; + } + VdpAddress++; + } + + void UpdatePrecomputedPalette() + { + if (mode == MODE_SMS) + { + for (int i = 0; i < 32; i++) + { + uint8_t value = CRAM[i]; + uint8_t r = SMSPalXlatTable[(value & 0x03)]; + uint8_t g = SMSPalXlatTable[(value & 0x0C) >> 2]; + uint8_t b = SMSPalXlatTable[(value & 0x30) >> 4]; + Palette[i] = ARGB(r, g, b); + } + } + else + { // GameGear + for (int i = 0; i < 32; i++) + { + uint16_t value = (uint16_t)((CRAM[(i * 2) + 1] << 8) | CRAM[(i * 2) + 0]); + uint8_t r = GGPalXlatTable[(value & 0x000F)]; + uint8_t g = GGPalXlatTable[(value & 0x00F0) >> 4]; + uint8_t b = GGPalXlatTable[(value & 0x0F00) >> 8]; + Palette[i] = ARGB(r, g, b); + } + } + } + + int ARGB(uint8_t red, uint8_t green, uint8_t blue) + { + return (int)((red << 0x10) | (green << 8) | blue | (0xFF << 0x18)); + } + + int CalcNameTableBase() + { + if (FrameHeight == 192) + return 1024 * (Registers[2] & 0x0E); + return (1024 * (Registers[2] & 0x0C)) + 0x0700; + } + + void CheckVideoMode() + { + if (Mode4Bit == false) // check old TMS modes + { + if (Mode1Bit) TmsMode = 1; + else if (Mode2Bit) TmsMode = 2; + else if (Mode3Bit) TmsMode = 3; + else TmsMode = 0; + } + + else if (Mode4Bit && Mode2Bit) // if Mode4 and Mode2 set, then check extension modes + { + TmsMode = 4; + switch (Registers[1] & 0x18) + { + case 0x00: + case 0x18: // 192-line mode + if (FrameHeight != 192) + { + FrameHeight = 192; + NameTableBase = CalcNameTableBase(); + } + break; + case 0x10: // 224-line mode + if (FrameHeight != 224) + { + FrameHeight = 224; + NameTableBase = CalcNameTableBase(); + } + break; + case 0x08: // 240-line mode + if (FrameHeight != 240) + { + FrameHeight = 240; + NameTableBase = CalcNameTableBase(); + } + break; + } + } + + else + { // default to standard 192-line mode4 + TmsMode = 4; + if (FrameHeight != 192) + { + FrameHeight = 192; + NameTableBase = CalcNameTableBase(); + } + } + } + + void WriteRegister(int reg, uint8_t data) + { + Registers[reg] = data; + + switch (reg) + { + case 0: // Mode Control Register 1 + CheckVideoMode(); + INT_FLAG[0] = (EnableLineInterrupts && HIntPending); + INT_FLAG[0] |= (EnableFrameInterrupts && VIntPending); + break; + case 1: // Mode Control Register 2 + CheckVideoMode(); + INT_FLAG[0] = (EnableFrameInterrupts && VIntPending); + INT_FLAG[0] |= (EnableLineInterrupts && HIntPending); + break; + case 2: // Name Table Base Address + NameTableBase = CalcNameTableBase(); + TmsPatternNameTableBase = (Registers[2] << 10) & 0x3C00; + break; + case 3: // Color Table Base Address + ColorTableBase = (Registers[3] << 6) & 0x3FC0; + break; + case 4: // Pattern Generator Base Address + PatternGeneratorBase = (Registers[4] << 11) & 0x3800; + break; + case 5: // Sprite Attribute Table Base Address + // ??? should I move from my property to precalculated? + TmsSpriteAttributeBase = (Registers[5] << 7) & 0x3F80; + break; + case 6: // Sprite Pattern Generator Base Adderss + SpritePatternGeneratorBase = (Registers[6] << 11) & 0x3800; + break; + } + + } + + const uint8_t pow2[8] = { 1, 2, 4, 8, 16, 32, 64, 128 }; + + void UpdatePatternBuffer(uint16_t address, uint8_t value) + { + // writing one uint8_t affects 8 pixels due to stupid planar storage. + for (int i = 0; i < 8; i++) + { + uint8_t colorBit = pow2[address % 4]; + uint8_t sourceBit = pow2[7 - i]; + uint16_t dest = (uint16_t)(((address & 0xFFFC) * 2) + i); + if ((value & sourceBit) > 0) // setting bit + PatternBuffer[dest] |= colorBit; + else // clearing bit + PatternBuffer[dest] &= (uint8_t)~colorBit; + } + } + + void ProcessFrameInterrupt() + { + if (ScanLine == FrameHeight + 1) + { + Statusuint8_t |= 0x80; + VIntPending = true; + } + + if (VIntPending && EnableFrameInterrupts) + { + INT_FLAG[0] = true; + } + + } + + void ProcessLineInterrupt() + { + if (ScanLine <= FrameHeight) + { + if (lineIntLinesRemaining-- <= 0) + { + HIntPending = true; + if (EnableLineInterrupts) + { + INT_FLAG[0] = true; + } + lineIntLinesRemaining = Registers[0x0A]; + } + return; + } + // else we're outside the active display period + lineIntLinesRemaining = Registers[0x0A]; + } + + void RenderCurrentScanline(bool render) + { + // only mode 4 supports frameskip. deal with it + if (TmsMode == 4) + { + if (render) + RenderBackgroundCurrentLine(SHOW_BG); + + if (EnableDoubledSprites) + RenderSpritesCurrentLineDoubleSize(SHOW_SPRITES & render); + else + RenderSpritesCurrentLine(SHOW_SPRITES & render); + + RenderLineBlanking(render); + } + else if (TmsMode == 2) + { + RenderBackgroundM2(SHOW_BG); + RenderTmsSprites(SHOW_SPRITES); + } + else if (TmsMode == 0) + { + RenderBackgroundM0(SHOW_BG); + RenderTmsSprites(SHOW_SPRITES); + } + } + /* + void SyncState(Serializer ser) + { + ser.BeginSection(nameof(VDP)); + ser.Sync(nameof(Statusuint8_t), ref Statusuint8_t); + ser.Sync("WaitingForLatchuint8_t", ref VdpWaitingForLatchuint8_t); + ser.Sync("Latch", ref VdpLatch); + ser.Sync("ReadBuffer", ref VdpBuffer); + ser.Sync(nameof(VdpAddress), ref VdpAddress); + ser.Sync("Command", ref VdpCommand); + ser.Sync(nameof(HIntPending), ref HIntPending); + ser.Sync(nameof(VIntPending), ref VIntPending); + ser.Sync("LineIntLinesRemaining", ref lineIntLinesRemaining); + ser.Sync(nameof(Registers), ref Registers, false); + ser.Sync(nameof(CRAM), ref CRAM, false); + ser.Sync(nameof(VRAM), ref VRAM, false); + ser.Sync(nameof(HCounter), ref HCounter); + ser.EndSection(); + + if (ser.IsReader) + { + for (int i = 0; i < Registers.Length; i++) + WriteRegister(i, Registers[i]); + for (uint16_t i = 0; i < VRAM.Length; i++) + UpdatePatternBuffer(i, VRAM[i]); + UpdatePrecomputedPalette(); + } + } + */ + + int VirtualWidth = 160; + + int VirtualHeight = 160; // GameGear + + int BufferHeight = 144; // GameGear + + int BackgroundColor() { return Palette[BackdropColor()]; } + + int VsyncNumerator = 60; + + int VsyncDenominator = 1; + #pragma endregion + + #pragma region Mode4 + + void RenderBackgroundCurrentLine(bool show) + { + if (ScanLine >= FrameHeight) + return; + + if (DisplayOn == false) + { + for (int x = 0; x < 256; x++) + FrameBuffer[(ScanLine * 256) + x] = Palette[BackdropColor()]; + return; + } + + // Clear the priority buffer for this scanline + for (int i = 0; i < 256; i++) + { + ScanlinePriorityBuffer[i] = 0; + } + + int mapBase = NameTableBase; + + int vertOffset = ScanLine + Registers[9]; + if (FrameHeight == 192) + { + if (vertOffset >= 224) + vertOffset -= 224; + } + else + { + if (vertOffset >= 256) + vertOffset -= 256; + } + uint8_t horzOffset = (HorizScrollLock && ScanLine < 16) ? (uint8_t)0 : Registers[8]; + + int yTile = vertOffset / 8; + + for (int xTile = 0; xTile < 32; xTile++) + { + if (xTile == 24 && VerticalScrollLock) + { + vertOffset = ScanLine; + yTile = vertOffset / 8; + } + + uint8_t PaletteBase = 0; + int tileInfo = VRAM[mapBase + ((yTile * 32) + xTile) * 2] | (VRAM[mapBase + (((yTile * 32) + xTile) * 2) + 1] << 8); + int tileNo = tileInfo & 0x01FF; + if ((tileInfo & 0x800) != 0) + PaletteBase = 16; + bool Priority = (tileInfo & 0x1000) != 0; + bool VFlip = (tileInfo & 0x400) != 0; + bool HFlip = (tileInfo & 0x200) != 0; + + int yOfs = vertOffset & 7; + if (VFlip) + yOfs = 7 - yOfs; + + if (HFlip == false) + { + FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 0] + PaletteBase] : Palette[BackdropColor()]; + FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 1] + PaletteBase] : Palette[BackdropColor()]; + FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 2] + PaletteBase] : Palette[BackdropColor()]; + FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 3] + PaletteBase] : Palette[BackdropColor()]; + FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 4] + PaletteBase] : Palette[BackdropColor()]; + FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 5] + PaletteBase] : Palette[BackdropColor()]; + FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 6] + PaletteBase] : Palette[BackdropColor()]; + FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 7] + PaletteBase] : Palette[BackdropColor()]; + + if (Priority) + { + horzOffset -= 8; + for (int k = 0; k < 8; k++) + { + if (PatternBuffer[(tileNo * 64) + (yOfs * 8) + k] != 0) + ScanlinePriorityBuffer[horzOffset] = 1; + horzOffset++; + } + } + } + else // Flipped Horizontally + { + FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 7] + PaletteBase] : Palette[BackdropColor()]; + FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 6] + PaletteBase] : Palette[BackdropColor()]; + FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 5] + PaletteBase] : Palette[BackdropColor()]; + FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 4] + PaletteBase] : Palette[BackdropColor()]; + FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 3] + PaletteBase] : Palette[BackdropColor()]; + FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 2] + PaletteBase] : Palette[BackdropColor()]; + FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 1] + PaletteBase] : Palette[BackdropColor()]; + FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 0] + PaletteBase] : Palette[BackdropColor()]; + + if (Priority) + { + horzOffset -= 8; + for (int k = 7; k >= 0; k--) + { + if (PatternBuffer[(tileNo * 64) + (yOfs * 8) + k] != 0) + ScanlinePriorityBuffer[horzOffset] = 1; + horzOffset++; + } + } + } + } + } + + void RenderSpritesCurrentLine(bool show) + { + bool overflowHappens = true; + bool collisionHappens = true; + bool renderHappens = show; + + if (!DisplayOn) + { + renderHappens = false; + collisionHappens = false; + } + if (ScanLine >= FrameHeight) + { + renderHappens = false; + overflowHappens = false; + } + + int SpriteBase = SpriteAttributeTableBase(); + int SpriteHeight = EnableLargeSprites ? 16 : 8; + + // Clear the sprite collision buffer for this scanline + for (int i = 0; i < 256; i++) + { + SpriteCollisionBuffer[i] = 0; + } + + // Loop through these sprites and render the current scanline + int SpritesDrawnThisScanline = 0; + for (int i = 0; i < 64; i++) + { + int x = VRAM[SpriteBase + 0x80 + (i * 2)]; + if (ShiftSpritesLeft8Pixels) + x -= 8; + + int y = VRAM[SpriteBase + i] + 1; + if (y == 209 && FrameHeight == 192) + break; // 208 is special terminator sprite (in 192-line mode) + if (y >= (EnableLargeSprites ? 240 : 248)) + y -= 256; + + if (y + SpriteHeight <= ScanLine || y > ScanLine) + continue; + + if (SpritesDrawnThisScanline >= 8) + { + collisionHappens = false; // technically the VDP stops processing sprite past this so we would never set the collision bit for sprites past this + if (overflowHappens) + Statusuint8_t |= 0x40; // Set Overflow bit + if (SpriteLimit) + renderHappens = false; // should be able to break/return, but to ensure this has no effect on sync we keep processing and disable rendering + } + + int tileNo = VRAM[SpriteBase + 0x80 + (i * 2) + 1]; + if (EnableLargeSprites) + tileNo &= 0xFE; + tileNo += SpriteTileBase(); + + int ys = ScanLine - y; + + for (int xs = 0; xs < 8 && x + xs < 256; xs++) + { + uint8_t color = PatternBuffer[(tileNo * 64) + (ys * 8) + xs]; + if (color != 0 && x + xs >= 0) + { + if (SpriteCollisionBuffer[x + xs] != 0) + { + if (collisionHappens) + Statusuint8_t |= 0x20; // Set Collision bit + } + else if (renderHappens && ScanlinePriorityBuffer[x + xs] == 0) + { + FrameBuffer[(ys + y) * 256 + x + xs] = Palette[(color + 16)]; + } + SpriteCollisionBuffer[x + xs] = 1; + } + } + SpritesDrawnThisScanline++; + } + } + + void RenderSpritesCurrentLineDoubleSize(bool show) + { + bool overflowHappens = true; + bool collisionHappens = true; + bool renderHappens = show; + + if (!DisplayOn) + { + renderHappens = false; + collisionHappens = false; + } + if (ScanLine >= FrameHeight) + { + renderHappens = false; + overflowHappens = false; + } + + int SpriteBase = SpriteAttributeTableBase(); + int SpriteHeight = EnableLargeSprites ? 16 : 8; + + // Clear the sprite collision buffer for this scanline + for (int i = 0; i < 256; i++) + { + SpriteCollisionBuffer[i] = 0; + } + + // Loop through these sprites and render the current scanline + int SpritesDrawnThisScanline = 0; + for (int i = 0; i < 64; i++) + { + int x = VRAM[SpriteBase + 0x80 + (i * 2)]; + if (ShiftSpritesLeft8Pixels) + x -= 8; + + int y = VRAM[SpriteBase + i] + 1; + if (y == 209 && FrameHeight == 192) + break; // terminator sprite + if (y >= (EnableLargeSprites ? 240 : 248)) + y -= 256; + + if (y + (SpriteHeight * 2) <= ScanLine || y > ScanLine) + continue; + + if (SpritesDrawnThisScanline >= 8) + { + collisionHappens = false; // technically the VDP stops processing sprite past this so we would never set the collision bit for sprites past this + if (overflowHappens) + Statusuint8_t |= 0x40; // Set Overflow bit + if (SpriteLimit) + renderHappens = false; // should be able to break/return, but to ensure this has no effect on sync we keep processing and disable rendering + } + + int tileNo = VRAM[SpriteBase + 0x80 + (i * 2) + 1]; + if (EnableLargeSprites) + tileNo &= 0xFE; + tileNo += SpriteTileBase(); + + int ys = ScanLine - y; + + for (int xs = 0; xs < 16 && x + xs < 256; xs++) + { + uint8_t color = PatternBuffer[(tileNo * 64) + ((ys / 2) * 8) + (xs / 2)]; + if (color != 0 && x + xs >= 0) + { + if (SpriteCollisionBuffer[x + xs] != 0) + { + if (collisionHappens) + Statusuint8_t |= 0x20; // Set Collision bit + } + else if (renderHappens && ScanlinePriorityBuffer[x + xs] == 0) + { + FrameBuffer[(ys + y) * 256 + x + xs] = Palette[(color + 16)]; + } + SpriteCollisionBuffer[x + xs] = 1; + } + } + SpritesDrawnThisScanline++; + } + } + + // Renders left-blanking. Should be done per scanline, not per-frame. + void RenderLineBlanking(bool render) + { + if (!LeftBlanking || ScanLine >= FrameHeight || !render) + return; + + int ofs = ScanLine * 256; + for (int x = 0; x < 8; x++) + FrameBuffer[ofs++] = Palette[BackdropColor()]; + } + + int OverscanFrameWidth, OverscanFrameHeight; + int overscanTop; + int overscanBottom; + int overscanLeft; + int overscanRight; + + /* + void ProcessOverscan() + { + if (Sms.Settings.DisplayOverscan == false) + return; + + if (OverscanFrameBuffer == null) + { + if (Sms.Region == Common.DisplayType.NTSC) + { + overscanLeft = 13; + overscanRight = 15; + overscanTop = 27; + overscanBottom = 24; + } + else // PAL + { + overscanLeft = 13; + overscanRight = 15; + overscanTop = 48; + overscanBottom = 48; + } + + OverscanFrameWidth = overscanLeft + 256 + overscanRight; + OverscanFrameHeight = overscanTop + 192 + overscanBottom; + OverscanFrameBuffer = new int[OverscanFrameHeight * OverscanFrameWidth]; + } + + // Top overscan + for (int y = 0; y < overscanTop; y++) + for (int x = 0; x < OverscanFrameWidth; x++) + OverscanFrameBuffer[(y * OverscanFrameWidth) + x] = BackgroundColor(); + + // Bottom overscan + for (int y = overscanTop + 192; y < OverscanFrameHeight; y++) + for (int x = 0; x < OverscanFrameWidth; x++) + OverscanFrameBuffer[(y * OverscanFrameWidth) + x] = BackgroundColor(); + + // Left overscan + for (int y = overscanTop; y < overscanTop + 192; y++) + for (int x = 0; x < overscanLeft; x++) + OverscanFrameBuffer[(y * OverscanFrameWidth) + x] = BackgroundColor(); + + // Right overscan + for (int y = overscanTop; y < overscanTop + 192; y++) + for (int x = overscanLeft + 256; x < OverscanFrameWidth; x++) + OverscanFrameBuffer[(y * OverscanFrameWidth) + x] = BackgroundColor(); + + // Active display area + for (int y = 0; y < 192; y++) + for (int x = 0; x < 256; x++) + OverscanFrameBuffer[((y + overscanTop) * OverscanFrameWidth) + overscanLeft + x] = FrameBuffer[y * 256 + x]; + } + */ + + + // Handles GG clipping or highlighting + void ProcessGGScreen() + { + int yStart = (FrameHeight - 144) / 2; + for (int y = 0; y < 144; y++) + for (int x = 0; x < 160; x++) + GameGearFrameBuffer[(y * 160) + x] = FrameBuffer[((y + yStart) * 256) + x + 48]; + /* + if (Sms.Settings.HighlightActiveDisplayRegion && Sms.Settings.ShowClippedRegions) + { + // Top 24 scanlines + for (int y = 0; y < 24; y++) + { + for (int x = 0; x < 256; x++) + { + int frameOffset = (y * 256) + x; + int p = (FrameBuffer[frameOffset] >> 1) & 0x7F7F7F7F; + FrameBuffer[frameOffset] = (int)(p | 0x80000000); + } + } + + // Bottom 24 scanlines + for (int y = 168; y < 192; y++) + { + for (int x = 0; x < 256; x++) + { + int frameOffset = (y * 256) + x; + int p = (FrameBuffer[frameOffset] >> 1) & 0x7F7F7F7F; + FrameBuffer[frameOffset] = (int)(p | 0x80000000); + } + } + + // Left 48 pixels + for (int y = 24; y < 168; y++) + { + for (int x = 0; x < 48; x++) + { + int frameOffset = (y * 256) + x; + int p = (FrameBuffer[frameOffset] >> 1) & 0x7F7F7F7F; + FrameBuffer[frameOffset] = (int)(p | 0x80000000); + } + } + + // Right 48 pixels + for (int y = 24; y < 168; y++) + { + for (int x = 208; x < 256; x++) + { + int frameOffset = (y * 256) + x; + int p = (FrameBuffer[frameOffset] >> 1) & 0x7F7F7F7F; + FrameBuffer[frameOffset] = (int)(p | 0x80000000); + } + } + } + */ + } + #pragma endregion + + #pragma region ModeTMS + + unsigned int PaletteTMS9918[16] + { + 0xFF000000, + 0xFF000000, + 0xFF47B73B, + 0xFF7CCF6F, + 0xFF5D4EFF, + 0xFF8072FF, + 0xFFB66247, + 0xFF5DC8ED, + 0xFFD76B48, + 0xFFFB8F6C, + 0xFFC3CD41, + 0xFFD3DA76, + 0xFF3E9F2F, + 0xFFB664C7, + 0xFFCCCCCC, + 0xFFFFFFFF + }; + + void RenderBackgroundM0(bool show) + { + if (ScanLine >= FrameHeight) + return; + + if (DisplayOn == false) + { + for (int i = ScanLine * 256; i < (ScanLine * 256 + 256); i++) + { + FrameBuffer[i] = 0; + } + return; + } + + int yc = ScanLine / 8; + int yofs = ScanLine % 8; + int FrameBufferOffset = ScanLine * 256; + int PatternNameOffset = TmsPatternNameTableBase + (yc * 32); + int ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F]; + + for (int xc = 0; xc < 32; xc++) + { + int pn = VRAM[PatternNameOffset++]; + int pv = VRAM[PatternGeneratorBase + (pn * 8) + yofs]; + int colorEntry = VRAM[ColorTableBase + (pn / 8)]; + int fgIndex = (colorEntry >> 4) & 0x0F; + int bgIndex = colorEntry & 0x0F; + int fgColor = fgIndex == 0 ? ScreenBGColor : PaletteTMS9918[fgIndex]; + int bgColor = bgIndex == 0 ? ScreenBGColor : PaletteTMS9918[bgIndex]; + + FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x80) > 0) ? fgColor : bgColor) : 0; + FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x40) > 0) ? fgColor : bgColor) : 0; + FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x20) > 0) ? fgColor : bgColor) : 0; + FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x10) > 0) ? fgColor : bgColor) : 0; + FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x08) > 0) ? fgColor : bgColor) : 0; + FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x04) > 0) ? fgColor : bgColor) : 0; + FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x02) > 0) ? fgColor : bgColor) : 0; + FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x01) > 0) ? fgColor : bgColor) : 0; + } + } + + void RenderBackgroundM2(bool show) + { + if (ScanLine >= FrameHeight) + return; + + if (DisplayOn == false) + { + for (int i = ScanLine * 256; i < (ScanLine * 256 + 256); i++) + { + FrameBuffer[i] = 0; + } + return; + } + + int yrow = ScanLine / 8; + int yofs = ScanLine % 8; + int FrameBufferOffset = ScanLine * 256; + int PatternNameOffset = TmsPatternNameTableBase + (yrow * 32); + int PatternGeneratorOffset = (((Registers[4] & 4) << 11) & 0x2000);// +((yrow / 8) * 0x100); + int ColorOffset = (ColorTableBase & 0x2000);// +((yrow / 8) * 0x100); + int ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F]; + + for (int xc = 0; xc < 32; xc++) + { + int pn = VRAM[PatternNameOffset++] + ((yrow / 8) * 0x100); + int pv = VRAM[PatternGeneratorOffset + (pn * 8) + yofs]; + int colorEntry = VRAM[ColorOffset + (pn * 8) + yofs]; + int fgIndex = (colorEntry >> 4) & 0x0F; + int bgIndex = colorEntry & 0x0F; + int fgColor = fgIndex == 0 ? ScreenBGColor : PaletteTMS9918[fgIndex]; + int bgColor = bgIndex == 0 ? ScreenBGColor : PaletteTMS9918[bgIndex]; + + FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x80) > 0) ? fgColor : bgColor) : 0; + FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x40) > 0) ? fgColor : bgColor) : 0; + FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x20) > 0) ? fgColor : bgColor) : 0; + FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x10) > 0) ? fgColor : bgColor) : 0; + FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x08) > 0) ? fgColor : bgColor) : 0; + FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x04) > 0) ? fgColor : bgColor) : 0; + FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x02) > 0) ? fgColor : bgColor) : 0; + FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x01) > 0) ? fgColor : bgColor) : 0; + } + } + + void RenderTmsSprites(bool show) + { + if (ScanLine >= FrameHeight || DisplayOn == false) + return; + + if (EnableDoubledSprites == false) + RenderTmsSpritesStandard(show); + else + RenderTmsSpritesDouble(show); + } + + void RenderTmsSpritesStandard(bool show) + { + for (int i = 0; i < 256; i++) + { + ScanlinePriorityBuffer[i] = 0; + } + for (int i = 0; i < 256; i++) + { + SpriteCollisionBuffer[i] = 0; + } + + bool LargeSprites = EnableLargeSprites; + + int SpriteSize = 8; + if (LargeSprites) SpriteSize *= 2; + const int OneCellSize = 8; + + int NumSpritesOnScanline = 0; + for (int i = 0; i < 32; i++) + { + int SpriteBase = TmsSpriteAttributeBase + (i * 4); + int y = VRAM[SpriteBase++]; + int x = VRAM[SpriteBase++]; + int Pattern = VRAM[SpriteBase++]; + int Color = VRAM[SpriteBase]; + + if (y == 208) break; // terminator sprite + if (y > 224) y -= 256; // sprite Y wrap + y++; // inexplicably, sprites start on Y+1 + if (y > ScanLine || y + SpriteSize <= ScanLine) continue; // sprite is not on this scanline + if ((Color & 0x80) > 0) x -= 32; // Early Clock adjustment + + if (++NumSpritesOnScanline == 5) + { + Statusuint8_t &= 0xE0; // Clear FS0-FS4 bits + Statusuint8_t |= (uint8_t)i; // set 5th sprite index + Statusuint8_t |= 0x40; // set overflow bit + break; + } + + if (LargeSprites) Pattern &= 0xFC; // 16x16 sprites forced to 4-uint8_t alignment + int SpriteLine = ScanLine - y; + + // pv contains the VRAM uint8_t holding the pattern data for this character at this scanline. + // each uint8_t contains the pattern data for each the 8 pixels on this line. + // the bit-shift further down on PV pulls out the relevant horizontal pixel. + + uint8_t pv = VRAM[SpritePatternGeneratorBase + (Pattern * 8) + SpriteLine]; + + for (int xp = 0; xp < SpriteSize && x + xp < 256; xp++) + { + if (x + xp < 0) continue; + if (LargeSprites && xp == OneCellSize) + pv = VRAM[SpritePatternGeneratorBase + (Pattern * 8) + SpriteLine + 16]; + + if (Color != 0 && (pv & (1 << (7 - (xp & 7)))) > 0) + { + if (SpriteCollisionBuffer[x + xp] != 0) + Statusuint8_t |= 0x20; // Set sprite collision flag + + if (ScanlinePriorityBuffer[x + xp] == 0) + { + ScanlinePriorityBuffer[x + xp] = 1; + SpriteCollisionBuffer[x + xp] = 1; + if (show) + FrameBuffer[(ScanLine * 256) + x + xp] = PaletteTMS9918[Color & 0x0F]; + } + } + } + } + } + + void RenderTmsSpritesDouble(bool show) + { + for (int i = 0; i < 256; i++) + { + ScanlinePriorityBuffer[i] = 0; + } + for (int i = 0; i < 256; i++) + { + SpriteCollisionBuffer[i] = 0; + } + + bool LargeSprites = EnableLargeSprites; + + int SpriteSize = 8; + if (LargeSprites) SpriteSize *= 2; + SpriteSize *= 2; // because sprite magnification + const int OneCellSize = 16; // once 8-pixel cell, doubled, will take 16 pixels + + int NumSpritesOnScanline = 0; + for (int i = 0; i < 32; i++) + { + int SpriteBase = TmsSpriteAttributeBase + (i * 4); + int y = VRAM[SpriteBase++]; + int x = VRAM[SpriteBase++]; + int Pattern = VRAM[SpriteBase++]; + int Color = VRAM[SpriteBase]; + + if (y == 208) break; // terminator sprite + if (y > 224) y -= 256; // sprite Y wrap + y++; // inexplicably, sprites start on Y+1 + if (y > ScanLine || y + SpriteSize <= ScanLine) continue; // sprite is not on this scanline + if ((Color & 0x80) > 0) x -= 32; // Early Clock adjustment + + if (++NumSpritesOnScanline == 5) + { + Statusuint8_t &= 0xE0; // Clear FS0-FS4 bits + Statusuint8_t |= (uint8_t)i; // set 5th sprite index + Statusuint8_t |= 0x40; // set overflow bit + break; + } + + if (LargeSprites) Pattern &= 0xFC; // 16x16 sprites forced to 4-uint8_t alignment + int SpriteLine = ScanLine - y; + SpriteLine /= 2; // because of sprite magnification + + uint8_t pv = VRAM[SpritePatternGeneratorBase + (Pattern * 8) + SpriteLine]; + + for (int xp = 0; xp < SpriteSize && x + xp < 256; xp++) + { + if (x + xp < 0) continue; + if (LargeSprites && xp == OneCellSize) + pv = VRAM[SpritePatternGeneratorBase + (Pattern * 8) + SpriteLine + 16]; + + if (Color != 0 && (pv & (1 << (7 - ((xp / 2) & 7)))) > 0) // xp/2 is due to sprite magnification + { + if (SpriteCollisionBuffer[x + xp] != 0) + Statusuint8_t |= 0x20; // Set sprite collision flag + + if (ScanlinePriorityBuffer[x + xp] == 0) + { + ScanlinePriorityBuffer[x + xp] = 1; + SpriteCollisionBuffer[x + xp] = 1; + if (show) + FrameBuffer[(ScanLine * 256) + x + xp] = PaletteTMS9918[Color & 0x0F]; + } + } + } + } + } + #pragma endregion + + #pragma region Tables + + // TODO: HCounter + uint8_t VLineCounterTableNTSC192[262] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, + 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, + }; + + uint8_t VLineCounterTableNTSC224[262] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, + 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, + }; + + uint8_t VLineCounterTableNTSC240[262] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 + }; + + uint8_t VLineCounterTablePAL192[313] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, + 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF + }; + + uint8_t VLineCounterTablePAL224[313] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, + 0x00, 0x01, 0x02, + 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF + }; + + uint8_t VLineCounterTablePAL240[313] = + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, + 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF + }; + #pragma endregion + }; +} diff --git a/libHawk/MSXHawk/MSXHawk/Z80A.h b/libHawk/MSXHawk/MSXHawk/Z80A.h index 67ab7bd08f..7906f10a25 100644 --- a/libHawk/MSXHawk/MSXHawk/Z80A.h +++ b/libHawk/MSXHawk/MSXHawk/Z80A.h @@ -15,10 +15,10 @@ namespace MSXHawk #pragma region Variable Declarations - int* MemoryMap; - int* MemoryMapMask; - int* HWMemoryMap; - int* HWMemoryMapMask; + uint8_t* MemoryMap; + uint8_t* MemoryMapMask; + uint8_t* HWMemoryMap; + uint8_t* HWMemoryMapMask; // when connected devices do not output a value on the BUS, they are responsible for determining open bus behaviour and returning it int ExternalDB; @@ -35,59 +35,56 @@ namespace MSXHawk int BUSRQ [19] = {}; // fixed size - do not change at runtime int MEMRQ [19] = {}; // fixed size - do not change at runtime int IRQS; - char opcode; bool NO_prefix, CB_prefix, IX_prefix, EXTD_prefix, IY_prefix, IXCB_prefix, IYCB_prefix; bool halted; bool I_skip; + bool FlagI; + bool FlagW; // wait flag, when set to true reads / writes will be delayed + + uint8_t opcode; + uint8_t temp_R; + uint8_t Regs[36] = {}; // non-state variables int Ztemp1, Ztemp2, Ztemp3, Ztemp4; - char temp_R; + int Reg16_d, Reg16_s, ans, temp, carry; - int Regs [36] = {}; - bool FlagI; + inline bool FlagCget() { return (Regs[5] & 0x01) != 0; }; + inline void FlagCset(bool value) { Regs[5] = (int)((Regs[5] & ~0x01) | (value ? 0x01 : 0x00)); } - bool FlagW; // wait flag, when set to true reads / writes will be delayed + inline bool FlagNget() { return (Regs[5] & 0x02) != 0; }; + inline void FlagNset(bool value) { Regs[5] = (int)((Regs[5] & ~0x02) | (value ? 0x02 : 0x00)); } - bool FlagCget() { return (Regs[5] & 0x01) != 0; }; - void FlagCset(bool value) { Regs[5] = (int)((Regs[5] & ~0x01) | (value ? 0x01 : 0x00)); } + inline bool FlagPget() { return (Regs[5] & 0x04) != 0; }; + inline void FlagPset(bool value) { Regs[5] = (int)((Regs[5] & ~0x04) | (value ? 0x04 : 0x00)); } - bool FlagNget() { return (Regs[5] & 0x02) != 0; }; - void FlagNset(bool value) { Regs[5] = (int)((Regs[5] & ~0x02) | (value ? 0x02 : 0x00)); } + inline bool Flag3get() { return (Regs[5] & 0x08) != 0; }; + inline void Flag3set(bool value) { Regs[5] = (int)((Regs[5] & ~0x08) | (value ? 0x08 : 0x00)); } - bool FlagPget() { return (Regs[5] & 0x04) != 0; }; - void FlagPset(bool value) { Regs[5] = (int)((Regs[5] & ~0x04) | (value ? 0x04 : 0x00)); } + inline bool FlagHget() { return (Regs[5] & 0x10) != 0; }; + inline void FlagHset(bool value) { Regs[5] = (int)((Regs[5] & ~0x10) | (value ? 0x10 : 0x00)); } - bool Flag3get() { return (Regs[5] & 0x08) != 0; }; - void Flag3set(bool value) { Regs[5] = (int)((Regs[5] & ~0x08) | (value ? 0x08 : 0x00)); } + inline bool Flag5get() { return (Regs[5] & 0x20) != 0; }; + inline void Flag5set(bool value) { Regs[5] = (int)((Regs[5] & ~0x20) | (value ? 0x20 : 0x00)); } - bool FlagHget() { return (Regs[5] & 0x10) != 0; }; - void FlagHset(bool value) { Regs[5] = (int)((Regs[5] & ~0x10) | (value ? 0x10 : 0x00)); } + inline bool FlagZget() { return (Regs[5] & 0x40) != 0; }; + inline void FlagZset(bool value) { Regs[5] = (int)((Regs[5] & ~0x40) | (value ? 0x40 : 0x00)); } - bool Flag5get() { return (Regs[5] & 0x20) != 0; }; - void Flag5set(bool value) { Regs[5] = (int)((Regs[5] & ~0x20) | (value ? 0x20 : 0x00)); } + inline bool FlagSget() { return (Regs[5] & 0x80) != 0; }; + inline void FlagSset(bool value) { Regs[5] = (int)((Regs[5] & ~0x80) | (value ? 0x80 : 0x00)); } - bool FlagZget() { return (Regs[5] & 0x40) != 0; }; - void FlagZset(bool value) { Regs[5] = (int)((Regs[5] & ~0x40) | (value ? 0x40 : 0x00)); } - - bool FlagSget() { return (Regs[5] & 0x80) != 0; }; - void FlagSset(bool value) { Regs[5] = (int)((Regs[5] & ~0x80) | (value ? 0x80 : 0x00)); } - - int RegPCget() { return (int)(Regs[0] | (Regs[1] << 8)); } - void RegPCset(int value) { Regs[0] = (int)(value & 0xFF); Regs[1] = (int)((value >> 8) & 0xFF); } + inline int RegPCget() { return (int)(Regs[0] | (Regs[1] << 8)); } + inline void RegPCset(int value) { Regs[0] = (int)(value & 0xFF); Regs[1] = (int)((value >> 8) & 0xFF); } bool TableParity [256] = {}; - bool IFF1; - bool IFF2; - bool nonMaskableInterrupt; bool nonMaskableInterruptPending; - bool NonMaskableInterruptget() { return nonMaskableInterrupt; }; - void NonMaskableInterruptset(bool value) + inline bool NonMaskableInterruptget() { return nonMaskableInterrupt; }; + inline void NonMaskableInterruptset(bool value) { if (value && !nonMaskableInterrupt) nonMaskableInterruptPending = true; nonMaskableInterrupt = value; @@ -95,8 +92,8 @@ namespace MSXHawk int interruptMode; - int InterruptModeget() { return interruptMode; }; - void InterruptModeset(int value) + inline int InterruptModeget() { return interruptMode; }; + inline void InterruptModeset(int value) { if (value < 0 || value > 2) { /* add exception here */ } interruptMode = value; @@ -1027,18 +1024,17 @@ namespace MSXHawk #pragma region Interrupts void NMI_() { - PopulateCURINSTR - (IDLE, - IDLE, - IDLE, - IDLE, - DEC16, SPl, SPh, - TR, ALU, PCl, - WAIT, - WR_DEC, SPl, SPh, PCh, - TR16, PCl, PCh, NMI_V, ZERO, - WAIT, - WR, SPl, SPh, ALU); + PopulateCURINSTR(IDLE, + IDLE, + IDLE, + IDLE, + DEC16, SPl, SPh, + TR, ALU, PCl, + WAIT, + WR_DEC, SPl, SPh, PCh, + TR16, PCl, PCh, NMI_V, ZERO, + WAIT, + WR, SPl, SPh, ALU); PopulateBUSRQ(0, 0, 0, 0, 0, SPh, 0, 0, SPh, 0, 0); PopulateMEMRQ(0, 0, 0, 0, 0, SPh, 0, 0, SPh, 0, 0); @@ -3750,9 +3746,9 @@ namespace MSXHawk void ADD16_Func(int dest_l, int dest_h, int src_l, int src_h) { - int Reg16_d = Regs[dest_l] | (Regs[dest_h] << 8); - int Reg16_s = Regs[src_l] | (Regs[src_h] << 8); - int temp = Reg16_d + Reg16_s; + Reg16_d = Regs[dest_l] | (Regs[dest_h] << 8); + Reg16_s = Regs[src_l] | (Regs[src_h] << 8); + temp = Reg16_d + Reg16_s; FlagCset((temp & 0x10000) > 0); FlagHset(((Reg16_d & 0xFFF) + (Reg16_s & 0xFFF)) > 0xFFF); @@ -3760,19 +3756,19 @@ namespace MSXHawk Flag3set((temp & 0x0800) != 0); Flag5set((temp & 0x2000) != 0); - Regs[dest_l] = (int)(temp & 0xFF); - Regs[dest_h] = (int)((temp & 0xFF00) >> 8); + Regs[dest_l] = (uint8_t)(temp & 0xFF); + Regs[dest_h] = (uint8_t)((temp & 0xFF00) >> 8); } void ADD8_Func(int dest, int src) { - int Reg16_d = Regs[dest]; + Reg16_d = Regs[dest]; Reg16_d += Regs[src]; FlagCset((Reg16_d & 0x100) > 0); FlagZset((Reg16_d & 0xFF) == 0); - int ans = (int)(Reg16_d & 0xFF); + ans = (Reg16_d & 0xFF); // redo for half carry flag Reg16_d = Regs[dest] & 0xF; @@ -3785,18 +3781,18 @@ namespace MSXHawk FlagPset(((Regs[dest] & 0x80) == (Regs[src] & 0x80)) && ((Regs[dest] & 0x80) != (ans & 0x80))); FlagSset(ans > 127); - Regs[dest] = ans; + Regs[dest] = (uint8_t)ans; } void SUB8_Func(int dest, int src) { - int Reg16_d = Regs[dest]; + Reg16_d = Regs[dest]; Reg16_d -= Regs[src]; FlagCset((Reg16_d & 0x100) > 0); FlagZset((Reg16_d & 0xFF) == 0); - int ans = (int)(Reg16_d & 0xFF); + ans = (Reg16_d & 0xFF); // redo for half carry flag Reg16_d = Regs[dest] & 0xF; @@ -3809,7 +3805,7 @@ namespace MSXHawk FlagPset(((Regs[dest] & 0x80) != (Regs[src] & 0x80)) && ((Regs[dest] & 0x80) != (ans & 0x80))); FlagSset(ans > 127); - Regs[dest] = ans; + Regs[dest] = (uint8_t)ans; } void BIT_Func(int bit, int src) @@ -3886,9 +3882,9 @@ namespace MSXHawk { FlagCset((Regs[src] & 0x01) > 0); - int temp = (int)(Regs[src] & 0x80); // MSB doesn't change in this operation + temp = (int)(Regs[src] & 0x80); // MSB doesn't change in this operation - Regs[src] = (int)((Regs[src] >> 1) | temp); + Regs[src] = (uint8_t)((Regs[src] >> 1) | temp); FlagSset((Regs[src] & 0x80) > 0); FlagZset(Regs[src] == 0); @@ -3903,7 +3899,7 @@ namespace MSXHawk { FlagCset((Regs[src] & 0x01) > 0); - Regs[src] = (int)(Regs[src] >> 1); + Regs[src] = (uint8_t)(Regs[src] >> 1); FlagSset((Regs[src] & 0x80) > 0); FlagZset(Regs[src] == 0); @@ -3916,7 +3912,7 @@ namespace MSXHawk void CPL_Func(int src) { - Regs[src] = (int)((~Regs[src]) & 0xFF); + Regs[src] = (uint8_t)((~Regs[src]) & 0xFF); FlagHset(true); FlagNset(true); @@ -3944,7 +3940,7 @@ namespace MSXHawk void AND8_Func(int dest, int src) { - Regs[dest] = (int)(Regs[dest] & Regs[src]); + Regs[dest] = (uint8_t)(Regs[dest] & Regs[src]); FlagZset(Regs[dest] == 0); FlagCset(false); @@ -3958,7 +3954,7 @@ namespace MSXHawk void OR8_Func(int dest, int src) { - Regs[dest] = (int)(Regs[dest] | Regs[src]); + Regs[dest] = (uint8_t)(Regs[dest] | Regs[src]); FlagZset(Regs[dest] == 0); FlagCset(false); @@ -3972,7 +3968,7 @@ namespace MSXHawk void XOR8_Func(int dest, int src) { - Regs[dest] = (int)((Regs[dest] ^ Regs[src])); + Regs[dest] = (uint8_t)((Regs[dest] ^ Regs[src])); FlagZset(Regs[dest] == 0); FlagCset(false); @@ -3986,13 +3982,13 @@ namespace MSXHawk void CP8_Func(int dest, int src) { - int Reg16_d = Regs[dest]; + Reg16_d = Regs[dest]; Reg16_d -= Regs[src]; FlagCset((Reg16_d & 0x100) > 0); FlagZset((Reg16_d & 0xFF) == 0); - int ans = (int)(Reg16_d & 0xFF); + ans = (int)(Reg16_d & 0xFF); // redo for half carry flag Reg16_d = Regs[dest] & 0xF; @@ -4013,7 +4009,7 @@ namespace MSXHawk FlagCset((Regs[src] & 0x01) > 0); - Regs[src] = (int)((FlagCget() ? 0x80 : 0) | (Regs[src] >> 1)); + Regs[src] = (uint8_t)((FlagCget() ? 0x80 : 0) | (Regs[src] >> 1)); if (!imm) { @@ -4033,11 +4029,11 @@ namespace MSXHawk bool imm = src == Aim; if (imm) { src = A; } - int c = (int)(FlagCget() ? 0x80 : 0); + carry = (int)(FlagCget() ? 0x80 : 0); FlagCset((Regs[src] & 0x01) > 0); - Regs[src] = (int)(c | (Regs[src] >> 1)); + Regs[src] = (uint8_t)(carry | (Regs[src] >> 1)); if (!imm) { @@ -4057,10 +4053,10 @@ namespace MSXHawk bool imm = src == Aim; if (imm) { src = A; } - int c = (int)(((Regs[src] & 0x80) > 0) ? 1 : 0); + carry = (int)(((Regs[src] & 0x80) > 0) ? 1 : 0); FlagCset((Regs[src] & 0x80) > 0); - Regs[src] = (int)(((Regs[src] << 1) & 0xFF) | c); + Regs[src] = (uint8_t)(((Regs[src] << 1) & 0xFF) | carry); if (!imm) { @@ -4080,10 +4076,10 @@ namespace MSXHawk bool imm = src == Aim; if (imm) { src = A; } - int c = (int)(FlagCget() ? 1 : 0); + carry = (int)(FlagCget() ? 1 : 0); FlagCset((Regs[src] & 0x80) > 0); - Regs[src] = (int)(((Regs[src] << 1) & 0xFF) | c); + Regs[src] = (uint8_t)(((Regs[src] << 1) & 0xFF) | carry); if (!imm) { @@ -4100,12 +4096,12 @@ namespace MSXHawk void INC8_Func(int src) { - int Reg16_d = Regs[src]; + Reg16_d = Regs[src]; Reg16_d += 1; FlagZset((Reg16_d & 0xFF) == 0); - int ans = (int)(Reg16_d & 0xFF); + ans = (int)(Reg16_d & 0xFF); // redo for half carry flag Reg16_d = Regs[src] & 0xF; @@ -4114,7 +4110,7 @@ namespace MSXHawk FlagHset((Reg16_d & 0x10) > 0); FlagNset(false); - Regs[src] = ans; + Regs[src] = (uint8_t)ans; FlagSset((Regs[src] & 0x80) > 0); FlagPset(Regs[src] == 0x80); @@ -4124,12 +4120,12 @@ namespace MSXHawk void DEC8_Func(int src) { - int Reg16_d = Regs[src]; + Reg16_d = Regs[src]; Reg16_d -= 1; FlagZset((Reg16_d & 0xFF) == 0); - int ans = (int)(Reg16_d & 0xFF); + ans = (int)(Reg16_d & 0xFF); // redo for half carry flag Reg16_d = Regs[src] & 0xF; @@ -4138,7 +4134,7 @@ namespace MSXHawk FlagHset((Reg16_d & 0x10) > 0); FlagNset(true); - Regs[src] = ans; + Regs[src] = (uint8_t)ans; FlagSset((Regs[src] & 0x80) > 0); FlagPset(Regs[src] == 0x7F); @@ -4148,39 +4144,39 @@ namespace MSXHawk void INC16_Func(int src_l, int src_h) { - int Reg16_d = Regs[src_l] | (Regs[src_h] << 8); + Reg16_d = Regs[src_l] | (Regs[src_h] << 8); Reg16_d += 1; - Regs[src_l] = (int)(Reg16_d & 0xFF); - Regs[src_h] = (int)((Reg16_d & 0xFF00) >> 8); + Regs[src_l] = (uint8_t)(Reg16_d & 0xFF); + Regs[src_h] = (uint8_t)((Reg16_d & 0xFF00) >> 8); } void DEC16_Func(int src_l, int src_h) { - int Reg16_d = Regs[src_l] | (Regs[src_h] << 8); + Reg16_d = Regs[src_l] | (Regs[src_h] << 8); Reg16_d -= 1; - Regs[src_l] = (int)(Reg16_d & 0xFF); - Regs[src_h] = (int)((Reg16_d & 0xFF00) >> 8); + Regs[src_l] = (uint8_t)(Reg16_d & 0xFF); + Regs[src_h] = (uint8_t)((Reg16_d & 0xFF00) >> 8); } void ADC8_Func(int dest, int src) { - int Reg16_d = Regs[dest]; - int c = FlagCget() ? 1 : 0; + Reg16_d = Regs[dest]; + carry = FlagCget() ? 1 : 0; - Reg16_d += (Regs[src] + c); + Reg16_d += (Regs[src] + carry); FlagCset((Reg16_d & 0x100) > 0); FlagZset((Reg16_d & 0xFF) == 0); - int ans = (int)(Reg16_d & 0xFF); + ans = (int)(Reg16_d & 0xFF); // redo for half carry flag Reg16_d = Regs[dest] & 0xF; - Reg16_d += ((Regs[src] & 0xF) + c); + Reg16_d += ((Regs[src] & 0xF) + carry); FlagHset((Reg16_d & 0x10) > 0); FlagNset(false); @@ -4189,24 +4185,24 @@ namespace MSXHawk FlagPset(((Regs[dest] & 0x80) == (Regs[src] & 0x80)) && ((Regs[dest] & 0x80) != (ans & 0x80))); FlagSset(ans > 127); - Regs[dest] = ans; + Regs[dest] = (uint8_t)ans; } void SBC8_Func(int dest, int src) { - int Reg16_d = Regs[dest]; - int c = FlagCget() ? 1 : 0; + Reg16_d = Regs[dest]; + carry = FlagCget() ? 1 : 0; - Reg16_d -= (Regs[src] + c); + Reg16_d -= (Regs[src] + carry); FlagCset((Reg16_d & 0x100) > 0); FlagZset((Reg16_d & 0xFF) == 0); - int ans = (int)(Reg16_d & 0xFF); + ans = (int)(Reg16_d & 0xFF); // redo for half carry flag Reg16_d = Regs[dest] & 0xF; - Reg16_d -= ((Regs[src] & 0xF) + c); + Reg16_d -= ((Regs[src] & 0xF) + carry); FlagHset((Reg16_d & 0x10) > 0); FlagNset(true); @@ -4215,13 +4211,13 @@ namespace MSXHawk FlagPset(((Regs[dest] & 0x80) != (Regs[src] & 0x80)) && ((Regs[dest] & 0x80) != (ans & 0x80))); FlagSset(ans > 127); - Regs[dest] = ans; + Regs[dest] = (uint8_t)ans; } void DA_Func(int src) { int a = (Regs[src] & 0xFF); - int temp = a; + temp = a; if (FlagNget()) { @@ -4244,18 +4240,18 @@ namespace MSXHawk Flag3set((temp & 0x08) != 0); Flag5set((temp & 0x20) != 0); - Regs[src] = temp; + Regs[src] = (uint8_t)temp; } // used for signed operations void ADDS_Func(int dest_l, int dest_h, int src_l, int src_h) { - int Reg16_d = Regs[dest_l]; - int Reg16_s = Regs[src_l]; + Reg16_d = Regs[dest_l]; + Reg16_s = Regs[src_l]; Reg16_d += Reg16_s; - int temp = 0; + temp = 0; // since this is signed addition, calculate the high byte carry appropriately // note that flags are unaffected by this operation @@ -4277,29 +4273,29 @@ namespace MSXHawk int ans_l = (int)(Reg16_d & 0xFF); - Regs[dest_l] = ans_l; - Regs[dest_h] += temp; + Regs[dest_l] = (uint8_t)ans_l; + Regs[dest_h] += (uint8_t)temp; Regs[dest_h] &= 0xFF; } void EXCH_16_Func(int dest_l, int dest_h, int src_l, int src_h) { - int temp = Regs[dest_l]; + temp = Regs[dest_l]; Regs[dest_l] = Regs[src_l]; - Regs[src_l] = temp; + Regs[src_l] = (uint8_t)temp; temp = Regs[dest_h]; Regs[dest_h] = Regs[src_h]; - Regs[src_h] = temp; + Regs[src_h] = (uint8_t)temp; } void SBC_16_Func(int dest_l, int dest_h, int src_l, int src_h) { - int Reg16_d = Regs[dest_l] | (Regs[dest_h] << 8); - int Reg16_s = Regs[src_l] | (Regs[src_h] << 8); - int c = FlagCget() ? 1 : 0; + Reg16_d = Regs[dest_l] | (Regs[dest_h] << 8); + Reg16_s = Regs[src_l] | (Regs[src_h] << 8); + carry = FlagCget() ? 1 : 0; - int ans = Reg16_d - Reg16_s - c; + ans = Reg16_d - Reg16_s - carry; FlagNset(true); FlagCset((ans & 0x10000) > 0); @@ -4311,20 +4307,20 @@ namespace MSXHawk // redo for half carry flag Reg16_d &= 0xFFF; - Reg16_d -= ((Reg16_s & 0xFFF) + c); + Reg16_d -= ((Reg16_s & 0xFFF) + carry); FlagHset((Reg16_d & 0x1000) > 0); - Regs[dest_l] = (int)(ans & 0xFF); - Regs[dest_h] = (int)((ans >> 8) & 0xFF); + Regs[dest_l] = (uint8_t)(ans & 0xFF); + Regs[dest_h] = (uint8_t)((ans >> 8) & 0xFF); } void ADC_16_Func(int dest_l, int dest_h, int src_l, int src_h) { - int Reg16_d = Regs[dest_l] | (Regs[dest_h] << 8); - int Reg16_s = Regs[src_l] | (Regs[src_h] << 8); + Reg16_d = Regs[dest_l] | (Regs[dest_h] << 8); + Reg16_s = Regs[src_l] | (Regs[src_h] << 8); - int ans = Reg16_d + Reg16_s + (FlagCget() ? 1 : 0); + ans = Reg16_d + Reg16_s + (FlagCget() ? 1 : 0); FlagHset(((Reg16_d & 0xFFF) + (Reg16_s & 0xFFF) + (FlagCget() ? 1 : 0)) > 0xFFF); FlagNset(false); @@ -4335,13 +4331,13 @@ namespace MSXHawk Flag3set((ans & 0x0800) != 0); Flag5set((ans & 0x2000) != 0); - Regs[dest_l] = (int)(ans & 0xFF); - Regs[dest_h] = (int)((ans >> 8) & 0xFF); + Regs[dest_l] = (uint8_t)(ans & 0xFF); + Regs[dest_h] = (uint8_t)((ans >> 8) & 0xFF); } void NEG_8_Func(int src) { - int Reg16_d = 0; + Reg16_d = 0; Reg16_d -= Regs[src]; FlagCset(Regs[src] != 0); @@ -4349,12 +4345,12 @@ namespace MSXHawk FlagPset(Regs[src] == 0x80); FlagSset((Reg16_d & 0xFF) > 127); - int ans = (int)(Reg16_d & 0xFF); + ans = (int)(Reg16_d & 0xFF); // redo for half carry flag Reg16_d = 0; Reg16_d -= (Regs[src] & 0xF); FlagHset((Reg16_d & 0x10) > 0); - Regs[src] = ans; + Regs[src] = (uint8_t)ans; FlagNset(true); Flag3set((ans & 0x08) != 0); Flag5set((ans & 0x20) != 0); @@ -4362,36 +4358,36 @@ namespace MSXHawk void RRD_Func(int dest, int src) { - int temp1 = Regs[src]; - int temp2 = Regs[dest]; - Regs[dest] = (int)(((temp1 & 0x0F) << 4) + ((temp2 & 0xF0) >> 4)); - Regs[src] = (int)((temp1 & 0xF0) + (temp2 & 0x0F)); + Reg16_s = Regs[src]; + Reg16_d = Regs[dest]; + Regs[dest] = (uint8_t)(((Reg16_s & 0x0F) << 4) + ((Reg16_d & 0xF0) >> 4)); + Regs[src] = (uint8_t)((Reg16_s & 0xF0) + (Reg16_d & 0x0F)); - temp1 = Regs[src]; - FlagSset(temp1 > 127); - FlagZset(temp1 == 0); + Reg16_s = Regs[src]; + FlagSset(Reg16_s > 127); + FlagZset(Reg16_s == 0); FlagHset(false); - FlagPset(TableParity[temp1]); + FlagPset(TableParity[Reg16_s]); FlagNset(false); - Flag3set((temp1 & 0x08) != 0); - Flag5set((temp1 & 0x20) != 0); + Flag3set((Reg16_s & 0x08) != 0); + Flag5set((Reg16_s & 0x20) != 0); } void RLD_Func(int dest, int src) { - int temp1 = Regs[src]; - int temp2 = Regs[dest]; - Regs[dest] = (int)((temp1 & 0x0F) + ((temp2 & 0x0F) << 4)); - Regs[src] = (int)((temp1 & 0xF0) + ((temp2 & 0xF0) >> 4)); + Reg16_s = Regs[src]; + Reg16_d = Regs[dest]; + Regs[dest] = (uint8_t)((Reg16_s & 0x0F) + ((Reg16_d & 0x0F) << 4)); + Regs[src] = (uint8_t)((Reg16_s & 0xF0) + ((Reg16_d & 0xF0) >> 4)); - temp1 = Regs[src]; - FlagSset(temp1 > 127); - FlagZset(temp1 == 0); + Reg16_s = Regs[src]; + FlagSset(Reg16_s > 127); + FlagZset(Reg16_s == 0); FlagHset(false); - FlagPset(TableParity[temp1]); + FlagPset(TableParity[Reg16_s]); FlagNset(false); - Flag3set((temp1 & 0x08) != 0); - Flag5set((temp1 & 0x20) != 0); + Flag3set((Reg16_s & 0x08) != 0); + Flag5set((Reg16_s & 0x20) != 0); } // sets flags for LD/R