This commit is contained in:
goyuken 2014-09-15 20:12:11 +00:00
parent ed4c715a9f
commit 28a37a57da
40 changed files with 12035 additions and 1 deletions

View File

@ -45,7 +45,8 @@ namespace BizHawk.Client.EmuHawk
{ "C64", "C64" }, { "C64", "C64" },
{ "GEN", "Genesis" }, { "GEN", "Genesis" },
{ "SMS", "Sega Master System" }, { "SMS", "Sega Master System" },
{ "PSX", "Sony PlayStation" } { "PSX", "Sony PlayStation" },
{ "LYNX", "Atari Lynx" },
}; };
public string TargetSystem = null; public string TargetSystem = null;

View File

@ -331,6 +331,10 @@ namespace BizHawk.Emulation.Common
case ".WSC": case ".WSC":
game.System = "WSWAN"; game.System = "WSWAN";
break; break;
case ".LNX":
game.System = "LYNX";
break;
} }
game.Name = Path.GetFileNameWithoutExtension(fileName).Replace('_', ' '); game.Name = Path.GetFileNameWithoutExtension(fileName).Replace('_', ' ');

View File

@ -39,6 +39,9 @@ namespace BizHawk.Emulation.Common
Option("GBA", "Bios", GBA_JDebug); Option("GBA", "Bios", GBA_JDebug);
} }
FirmwareAndOption("e4ed47fae31693e016b081c6bda48da5b70d7ccb", "LYNX", "Boot", "lynxboot.img", "Boot Rom");
//FirmwareAndOption("24F67BDEA115A2C847C8813A262502EE1607B7DF", "NDS", "Bios_Arm7", "biosnds7.rom", "ARM7 Bios"); //FirmwareAndOption("24F67BDEA115A2C847C8813A262502EE1607B7DF", "NDS", "Bios_Arm7", "biosnds7.rom", "ARM7 Bios");
//FirmwareAndOption("BFAAC75F101C135E32E2AAF541DE6B1BE4C8C62D", "NDS", "Bios_Arm9", "biosnds9.rom", "ARM9 Bios"); //FirmwareAndOption("BFAAC75F101C135E32E2AAF541DE6B1BE4C8C62D", "NDS", "Bios_Arm9", "biosnds9.rom", "ARM9 Bios");
FirmwareAndOption("5A65B922B562CB1F57DAB51B73151283F0E20C7A", "INTV", "EROM", "erom.bin", "Executive Rom"); FirmwareAndOption("5A65B922B562CB1F57DAB51B73151283F0E20C7A", "INTV", "EROM", "erom.bin", "Executive Rom");

View File

@ -223,6 +223,8 @@
<Compile Include="Consoles\Atari\7800\Atari7800.Core.cs" /> <Compile Include="Consoles\Atari\7800\Atari7800.Core.cs" />
<Compile Include="Consoles\Atari\7800\Atari7800.cs" /> <Compile Include="Consoles\Atari\7800\Atari7800.cs" />
<Compile Include="Consoles\Atari\7800\Atari7800Control.cs" /> <Compile Include="Consoles\Atari\7800\Atari7800Control.cs" />
<Compile Include="Consoles\Atari\lynx\LibLynx.cs" />
<Compile Include="Consoles\Atari\lynx\Lynx.cs" />
<Compile Include="Consoles\Coleco\ColecoVision.cs" /> <Compile Include="Consoles\Coleco\ColecoVision.cs" />
<Compile Include="Consoles\Coleco\Input.cs" /> <Compile Include="Consoles\Coleco\Input.cs" />
<Compile Include="Consoles\Coleco\MemoryMap.cs" /> <Compile Include="Consoles\Coleco\MemoryMap.cs" />

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace BizHawk.Emulation.Cores.Atari.Lynx
{
public static class LibLynx
{
const string dllname = "bizlynx.dll";
const CallingConvention cc = CallingConvention.Cdecl;
[DllImport(dllname, CallingConvention = cc)]
public static extern IntPtr Create(byte[] game, int gamesize, byte[] bios, int biossize, int pagesize0, int pagesize1, bool lowpass);
[DllImport(dllname, CallingConvention = cc)]
public static extern void Destroy(IntPtr s);
[DllImport(dllname, CallingConvention = cc)]
public static extern void Reset(IntPtr s);
[DllImport(dllname, CallingConvention = cc)]
public static extern void Advance(IntPtr s, int buttons, int[] vbuff, short[] sbuff, ref int sbuffsize);
}
}

View File

@ -0,0 +1,287 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Atari.Lynx
{
[CoreAttributes("Handy", "K. Wilkins", true, false, "mednafen 0-9-34-1", "http://mednafen.sourceforge.net/")]
public class Lynx : IEmulator, IVideoProvider, ISyncSoundProvider
{
IntPtr Core;
[CoreConstructor("LYNX")]
public Lynx(byte[] file, GameInfo game, CoreComm comm)
{
CoreComm = comm;
byte[] bios = CoreComm.CoreFileProvider.GetFirmware("LYNX", "Boot", true, "Boot rom is required");
if (bios.Length != 512)
throw new MissingFirmwareException("Lynx Bootrom must be 512 bytes!");
int pagesize0 = 0;
int pagesize1 = 0;
byte[] realfile = null;
{
var ms = new MemoryStream(file, false);
var br = new BinaryReader(ms);
string header = Encoding.ASCII.GetString(br.ReadBytes(4));
int p0 = br.ReadUInt16();
int p1 = br.ReadUInt16();
int ver = br.ReadUInt16();
string cname = Encoding.ASCII.GetString(br.ReadBytes(32)).Trim();
string mname = Encoding.ASCII.GetString(br.ReadBytes(16)).Trim();
int rot = br.ReadByte();
ms.Position = 6;
string bs93 = Encoding.ASCII.GetString(br.ReadBytes(6));
if (bs93 == "BS93")
throw new InvalidOperationException("Unsupported BS93 Lynx ram image");
if (header == "LYNX" && (ver & 255) == 1)
{
Console.WriteLine("Processing Handy-Lynx header");
pagesize0 = p0;
pagesize1 = p1;
Console.WriteLine("TODO: Rotate {0}", rot);
Console.WriteLine("Cart: {0} Manufacturer: {1}", cname, mname);
realfile = new byte[file.Length - 64];
Buffer.BlockCopy(file, 64, realfile, 0, realfile.Length);
Console.WriteLine("Header Listed banking: {0} {1}", p0, p1);
}
else
{
Console.WriteLine("No Handy-Lynx header found! Assuming raw rom image.");
realfile = file;
}
}
if (game.OptionPresent("pagesize0"))
{
pagesize0 = int.Parse(game.OptionValue("pagesize0"));
pagesize1 = int.Parse(game.OptionValue("pagesize1"));
Console.WriteLine("Loading banking options {0} {1} from gamedb", pagesize0, pagesize1);
}
if (pagesize0 == 0 && pagesize1 == 0)
{
switch (realfile.Length)
{
// these are untested
case 0x10000: pagesize0 = 0x100; break;
case 0x20000: pagesize0 = 0x200; break;
case 0x40000: pagesize0 = 0x400; break;
case 0x80000: pagesize0 = 0x800; break;
case 0x30000: pagesize0 = 0x200; pagesize1 = 0x100; break;
case 0x60000: pagesize0 = 0x400; pagesize1 = 0x200; break;
case 0xc0000: pagesize0 = 0x800; pagesize1 = 0x400; break;
case 0x100000: pagesize0 = 0x800; pagesize1 = 0x800; break;
}
Console.WriteLine("Auto-guessed banking options {0} {1}", pagesize0, pagesize1);
}
Core = LibLynx.Create(realfile, realfile.Length, bios, bios.Length, pagesize0, pagesize1, false);
try
{
// ...
}
catch
{
Dispose();
throw;
}
}
public void FrameAdvance(bool render, bool rendersound = true)
{
Frame++;
if (Controller["Power"])
LibLynx.Reset(Core);
int samples = soundbuff.Length;
LibLynx.Advance(Core, 0, videobuff, soundbuff, ref samples);
numsamp = samples;
Console.WriteLine(numsamp);
}
public int Frame { get; private set; }
public int LagCount { get; set; }
public bool IsLagFrame { get; private set; }
public string SystemId { get { return "LYNX"; } }
public bool DeterministicEmulation { get { return true; } }
public void ResetCounters()
{
Frame = 0;
LagCount = 0;
IsLagFrame = false;
}
public string BoardName { get { return null; } }
public CoreComm CoreComm { get; private set; }
public void Dispose()
{
if (Core != IntPtr.Zero)
{
LibLynx.Destroy(Core);
Core = IntPtr.Zero;
}
}
#region debugging
public Dictionary<string, int> GetCpuFlagsAndRegisters()
{
return new Dictionary<string, int>();
}
public void SetCpuRegister(string register, int value)
{
}
#endregion
#region Controller
public ControllerDefinition ControllerDefinition { get { return NullEmulator.NullController; } }
public IController Controller { get; set; }
#endregion
#region savestates
public void SaveStateText(TextWriter writer)
{
}
public void LoadStateText(TextReader reader)
{
}
public void SaveStateBinary(BinaryWriter writer)
{
}
public void LoadStateBinary(BinaryReader reader)
{
}
public byte[] SaveStateBinary()
{
return new byte[0];
}
public bool BinarySaveStatesPreferred
{
get { return true; }
}
#endregion
#region saveram
public byte[] CloneSaveRam()
{
return new byte[0];
}
public void StoreSaveRam(byte[] data)
{
}
public void ClearSaveRam()
{
}
public bool SaveRamModified
{
get
{
return false;
}
set
{
throw new InvalidOperationException();
}
}
#endregion
#region VideoProvider
const int WIDTH = 160;
const int HEIGHT = 102;
int[] videobuff = new int[WIDTH * HEIGHT];
public IVideoProvider VideoProvider { get { return this; } }
public int[] GetVideoBuffer() { return videobuff; }
public int VirtualWidth { get { return WIDTH; } }
public int VirtualHeight { get { return HEIGHT; } }
public int BufferWidth { get { return WIDTH; } }
public int BufferHeight { get { return HEIGHT; } }
public int BackgroundColor { get { return unchecked((int)0xff000000); } }
#endregion
#region SoundProvider
short[] soundbuff = new short[1000000]; // todo: make this smaller once frame loop is resolved
int numsamp;
public ISoundProvider SoundProvider { get { return null; } }
public ISyncSoundProvider SyncSoundProvider { get { return this; } }
public bool StartAsyncSound() { return false; }
public void EndAsyncSound() { }
public void GetSamples(out short[] samples, out int nsamp)
{
samples = soundbuff;
nsamp = numsamp;
}
public void DiscardSamples()
{
}
#endregion
#region Settings
public object GetSettings()
{
return null;
}
public object GetSyncSettings()
{
return null;
}
public bool PutSettings(object o)
{
return false;
}
public bool PutSyncSettings(object o)
{
return false;
}
#endregion
}
}

20
lynx/bizlynx/bizlynx.sln Normal file
View File

@ -0,0 +1,20 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bizlynx", "bizlynx.vcxproj", "{C8DC23FF-551E-45DE-852D-22F66EDBACB9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C8DC23FF-551E-45DE-852D-22F66EDBACB9}.Debug|Win32.ActiveCfg = Debug|Win32
{C8DC23FF-551E-45DE-852D-22F66EDBACB9}.Debug|Win32.Build.0 = Debug|Win32
{C8DC23FF-551E-45DE-852D-22F66EDBACB9}.Release|Win32.ActiveCfg = Release|Win32
{C8DC23FF-551E-45DE-852D-22F66EDBACB9}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{C8DC23FF-551E-45DE-852D-22F66EDBACB9}</ProjectGuid>
<RootNamespace>bizlynx</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\msvc</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<PostBuildEvent>
<Command>copy /y $(TargetDir)$(TargetFileName) $(ProjectDir)..\..\output\dll\$(TargetFileName)</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\msvc</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
<PostBuildEvent>
<Command>copy /y $(TargetDir)$(TargetFileName) $(ProjectDir)..\..\output\dll\$(TargetFileName)</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\c65c02.cpp" />
<ClCompile Include="..\cart.cpp" />
<ClCompile Include="..\cinterface.cpp" />
<ClCompile Include="..\memmap.cpp" />
<ClCompile Include="..\mikie.cpp" />
<ClCompile Include="..\ram.cpp" />
<ClCompile Include="..\rom.cpp" />
<ClCompile Include="..\sound\Blip_Buffer.cpp" />
<ClCompile Include="..\sound\Stereo_Buffer.cpp" />
<ClCompile Include="..\susie.cpp" />
<ClCompile Include="..\system.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\c6502mak.h" />
<ClInclude Include="..\c65c02.h" />
<ClInclude Include="..\cart.h" />
<ClInclude Include="..\lynxbase.h" />
<ClInclude Include="..\lynxdef.h" />
<ClInclude Include="..\machine.h" />
<ClInclude Include="..\mednafen.h" />
<ClInclude Include="..\memmap.h" />
<ClInclude Include="..\mikie.h" />
<ClInclude Include="..\ram.h" />
<ClInclude Include="..\rom.h" />
<ClInclude Include="..\sound\Blip_Buffer.h" />
<ClInclude Include="..\sound\Stereo_Buffer.h" />
<ClInclude Include="..\susie.h" />
<ClInclude Include="..\sysbase.h" />
<ClInclude Include="..\system.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Source Files\sound">
<UniqueIdentifier>{676beda4-1fca-49a2-acc8-67df1ab69690}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\sound">
<UniqueIdentifier>{7790947c-e33d-4f9b-a3bd-c72d9932bd76}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\c65c02.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\cart.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\memmap.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\mikie.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\ram.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\rom.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\susie.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\system.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\sound\Blip_Buffer.cpp">
<Filter>Source Files\sound</Filter>
</ClCompile>
<ClCompile Include="..\sound\Stereo_Buffer.cpp">
<Filter>Source Files\sound</Filter>
</ClCompile>
<ClCompile Include="..\cinterface.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\c65c02.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\c6502mak.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\cart.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\lynxbase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\lynxdef.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\machine.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\memmap.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\mikie.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\ram.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\rom.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\susie.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\sysbase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\system.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\mednafen.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\sound\Blip_Buffer.h">
<Filter>Header Files\sound</Filter>
</ClInclude>
<ClInclude Include="..\sound\Stereo_Buffer.h">
<Filter>Header Files\sound</Filter>
</ClInclude>
</ItemGroup>
</Project>

694
lynx/c6502mak.h Normal file
View File

@ -0,0 +1,694 @@
//
// Copyright (c) 2004 K. Wilkins
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
//////////////////////////////////////////////////////////////////////////////
// Handy - An Atari Lynx Emulator //
// Copyright (c) 1996,1997 //
// K. Wilkins //
//////////////////////////////////////////////////////////////////////////////
// 65C02 Macro definitions //
//////////////////////////////////////////////////////////////////////////////
// //
// This file contains all of the required address mode and operand //
// macro definitions for the 65C02 emulation //
// //
// K. Wilkins //
// August 1997 //
// //
//////////////////////////////////////////////////////////////////////////////
// Revision History: //
// ----------------- //
// //
// 01Aug1997 KW Document header added & class documented. //
// //
//////////////////////////////////////////////////////////////////////////////
//
// Addressing mode decoding
//
#define xIMMEDIATE() {mOperand=mPC;mPC++;}
#define xABSOLUTE() {mOperand=CPU_PEEKW(mPC);mPC+=2;}
#define xZEROPAGE() {mOperand=CPU_PEEK(mPC);mPC++;}
#define xZEROPAGE_X() {mOperand=CPU_PEEK(mPC)+mX;mPC++;mOperand&=0xff;}
#define xZEROPAGE_Y() {mOperand=CPU_PEEK(mPC)+mY;mPC++;mOperand&=0xff;}
#define xABSOLUTE_X() {mOperand=CPU_PEEKW(mPC);mPC+=2;mOperand+=mX;mOperand&=0xffff;}
#define xABSOLUTE_Y() {mOperand=CPU_PEEKW(mPC);mPC+=2;mOperand+=mY;mOperand&=0xffff;}
#define xINDIRECT_ABSOLUTE_X() {mOperand=CPU_PEEKW(mPC);mPC+=2;mOperand+=mX;mOperand&=0xffff;mOperand=CPU_PEEKW(mOperand);}
#define xRELATIVE() {mOperand=CPU_PEEK(mPC);mPC++;mOperand=(mPC+mOperand)&0xffff;}
#define xINDIRECT_X() {mOperand=CPU_PEEK(mPC);mPC++;mOperand=mOperand+mX;mOperand&=0x00ff;mOperand=CPU_PEEKW(mOperand);}
#define xINDIRECT_Y() {mOperand=CPU_PEEK(mPC);mPC++;mOperand=CPU_PEEKW(mOperand);mOperand=mOperand+mY;mOperand&=0xffff;}
#define xINDIRECT_ABSOLUTE() {mOperand=CPU_PEEKW(mPC);mPC+=2;mOperand=CPU_PEEKW(mOperand);}
#define xINDIRECT() {mOperand=CPU_PEEK(mPC);mPC++;mOperand=CPU_PEEKW(mOperand);}
//
// Helper Macros
//
//#define SET_Z(m) { mZ=(m)?false:true; }
//#define SET_N(m) { mN=(m&0x80)?true:false; }
//#define SET_NZ(m) SET_Z(m) SET_N(m)
#define SET_Z(m) { mZ=!(m); }
#define SET_N(m) { mN=(m)&0x80; }
#define SET_NZ(m) { mZ=!(m); mN=(m)&0x80; }
#define PULL(m) { mSP++; mSP&=0xff; m=CPU_PEEK(mSP+0x0100); }
#define PUSH(m) { CPU_POKE(0x0100+mSP,m); mSP--; mSP&=0xff; }
//
// Opcode execution
//
#define xADC()\
{\
int value=CPU_PEEK(mOperand);\
if(mD)\
{\
int c = mC?1:0;\
int lo = (mA & 0x0f) + (value & 0x0f) + c;\
int hi = (mA & 0xf0) + (value & 0xf0);\
mV=0;\
mC=0;\
if (lo > 0x09)\
{\
hi += 0x10;\
lo += 0x06;\
}\
if (~(mA^value) & (mA^hi) & 0x80) mV=1;\
if (hi > 0x90) hi += 0x60;\
if (hi & 0xff00) mC=1;\
mA = (lo & 0x0f) + (hi & 0xf0);\
}\
else\
{\
int c = mC?1:0;\
int sum = mA + value + c;\
mV=0;\
mC=0;\
if (~(mA^value) & (mA^sum) & 0x80) mV=1;\
if (sum & 0xff00) mC=1;\
mA = (uint8) sum;\
}\
SET_NZ(mA)\
}
#define xAND()\
{\
mA&=CPU_PEEK(mOperand);\
SET_NZ(mA);\
}
#define xASL()\
{\
int value=CPU_PEEK(mOperand);\
mC=value&0x80;\
value<<=1;\
value&=0xff;\
SET_NZ(value);\
CPU_POKE(mOperand,value);\
}
#define xASLA()\
{\
mC=mA&0x80;\
mA<<=1;\
mA&=0xff;\
SET_NZ(mA);\
}
#define xBCC()\
{\
if(!mC)\
{\
int offset=(signed char)CPU_PEEK(mPC);\
mPC++;\
mPC+=offset;\
mPC&=0xffff;\
}\
else\
{\
mPC++;\
mPC&=0xffff;\
}\
}
#define xBCS()\
{\
if(mC)\
{\
int offset=(signed char)CPU_PEEK(mPC);\
mPC++;\
mPC+=offset;\
mPC&=0xffff;\
}\
else\
{\
mPC++;\
mPC&=0xffff;\
}\
}
#define xBEQ()\
{\
if(mZ)\
{\
int offset=(signed char)CPU_PEEK(mPC);\
mPC++;\
mPC+=offset;\
mPC&=0xffff;\
}\
else\
{\
mPC++;\
mPC&=0xffff;\
}\
}
// This version of bit, not setting N and V status flags in immediate, seems to be correct.
// The same behaviour is reported on the 65C02 used in old Apple computers, at least.
// (From a pragmatic sense, using the normal version of bit for immediate
// mode breaks the title screen of "California Games" in a subtle way.)
#define xBIT()\
{\
int value=CPU_PEEK(mOperand);\
SET_Z(mA&value);\
\
if(mOpcode!=0x89)\
{\
mN=value&0x80;\
mV=value&0x40;\
}\
}
#define xBMI()\
{\
if(mN)\
{\
int offset=(signed char)CPU_PEEK(mPC);\
mPC++;\
mPC+=offset;\
mPC&=0xffff;\
}\
else\
{\
mPC++;\
mPC&=0xffff;\
}\
}
#define xBNE()\
{\
if(!mZ)\
{\
int offset=(signed char)CPU_PEEK(mPC);\
mPC++;\
mPC+=offset;\
mPC&=0xffff;\
}\
else\
{\
mPC++;\
mPC&=0xffff;\
}\
}
#define xBPL()\
{\
if(!mN)\
{\
int offset=(signed char)CPU_PEEK(mPC);\
mPC++;\
mPC+=offset;\
mPC&=0xffff;\
}\
else\
{\
mPC++;\
mPC&=0xffff;\
}\
}
#define xBRA()\
{\
int offset=(signed char)CPU_PEEK(mPC);\
mPC++;\
mPC+=offset;\
mPC&=0xffff;\
}
#define xBRK()\
{\
mPC++;\
PUSH(mPC>>8);\
PUSH(mPC&0xff);\
PUSH(PS()|0x10);\
\
mD=FALSE;\
mI=TRUE;\
\
mPC=CPU_PEEKW(IRQ_VECTOR);\
}
// KW 4/11/98 B flag needed to be set IN the stack status word = 0x10.
#define xBVC()\
{\
if(!mV)\
{\
int offset=(signed char)CPU_PEEK(mPC);\
mPC++;\
mPC+=offset;\
mPC&=0xffff;\
}\
else\
{\
mPC++;\
mPC&=0xffff;\
}\
}
#define xBVS()\
{\
if(mV)\
{\
int offset=(signed char)CPU_PEEK(mPC);\
mPC++;\
mPC+=offset;\
mPC&=0xffff;\
}\
else\
{\
mPC++;\
mPC&=0xffff;\
}\
}
#define xCLC()\
{\
mC=FALSE;\
}
#define xCLD()\
{\
mD=FALSE;\
}
#define xCLI()\
{\
mI=FALSE;\
}
#define xCLV()\
{\
mV=FALSE;\
}
#define xCMP()\
{\
int value=CPU_PEEK(mOperand);\
mC=0;\
if (mA >= value) mC=1;\
SET_NZ((uint8)(mA - value))\
}
#define xCPX()\
{\
int value=CPU_PEEK(mOperand);\
mC=0;\
if (mX >= value) mC=1;\
SET_NZ((uint8)(mX - value))\
}
#define xCPY()\
{\
int value=CPU_PEEK(mOperand);\
mC=0;\
if (mY >= value) mC=1;\
SET_NZ((uint8)(mY - value))\
}
#define xDEC()\
{\
int value=CPU_PEEK(mOperand)-1;\
value&=0xff;\
CPU_POKE(mOperand,value);\
SET_NZ(value);\
}
#define xDECA()\
{\
mA--;\
mA&=0xff;\
SET_NZ(mA);\
}
#define xDEX()\
{\
mX--;\
mX&=0xff;\
SET_NZ(mX);\
}
#define xDEY()\
{\
mY--;\
mY&=0xff;\
SET_NZ(mY);\
}
#define xEOR()\
{\
mA^=CPU_PEEK(mOperand);\
SET_NZ(mA);\
}
#define xINC()\
{\
int value=CPU_PEEK(mOperand)+1;\
value&=0xff;\
CPU_POKE(mOperand,value);\
SET_NZ(value);\
}
#define xINCA()\
{\
mA++;\
mA&=0xff;\
SET_NZ(mA);\
}
#define xINX()\
{\
mX++;\
mX&=0xff;\
SET_NZ(mX);\
}
#define xINY()\
{\
mY++;\
mY&=0xff;\
SET_NZ(mY);\
}
#define xJMP()\
{\
mPC=mOperand;\
}
#define xJSR()\
{\
PUSH((mPC-1)>>8);\
PUSH((mPC-1)&0xff);\
mPC=mOperand;\
}
#define xLDA()\
{\
mA=CPU_PEEK(mOperand);\
SET_NZ(mA);\
}
#define xLDX()\
{\
mX=CPU_PEEK(mOperand);\
SET_NZ(mX);\
}
#define xLDY()\
{\
mY=CPU_PEEK(mOperand);\
SET_NZ(mY);\
}
#define xLSR()\
{\
int value=CPU_PEEK(mOperand);\
mC=value&0x01;\
value=(value>>1)&0x7f;\
CPU_POKE(mOperand,value);\
SET_NZ(value);\
}
#define xLSRA()\
{\
mC=mA&0x01;\
mA=(mA>>1)&0x7f;\
SET_NZ(mA);\
}
#define xNOP()\
{\
}
#define xORA()\
{\
mA|=CPU_PEEK(mOperand);\
SET_NZ(mA);\
}
#define xPHA()\
{\
PUSH(mA);\
}
#define xPHP()\
{\
PUSH(PS());\
}
#define xPHX()\
{\
PUSH(mX);\
}
#define xPHY()\
{\
PUSH(mY);\
}
#define xPLA()\
{\
PULL(mA);\
SET_NZ(mA);\
}
#define xPLP()\
{\
int P;\
PULL(P);\
PS(P);\
}
#define xPLX()\
{\
PULL(mX);\
SET_NZ(mX);\
}
#define xPLY()\
{\
PULL(mY);\
SET_NZ(mY);\
}
#define xROL()\
{\
int value=CPU_PEEK(mOperand);\
int oldC=mC;\
mC=value&0x80;\
value=(value<<1)|(oldC?1:0);\
value&=0xff;\
CPU_POKE(mOperand,value);\
SET_NZ(value);\
}
#define xROLA()\
{\
int oldC=mC;\
mC=mA&0x80;\
mA=(mA<<1)|(oldC?1:0);\
mA&=0xff;\
SET_NZ(mA);\
}
#define xROR()\
{\
int value=CPU_PEEK(mOperand);\
int oldC=mC;\
mC=value&0x01;\
value=((value>>1)&0x7f)|(oldC?0x80:0x00);\
value&=0xff;\
CPU_POKE(mOperand,value);\
SET_NZ(value);\
}
#define xRORA()\
{\
int oldC=mC;\
mC=mA&0x01;\
mA=((mA>>1)&0x7f)|(oldC?0x80:0x00);\
mA&=0xff;\
SET_NZ(mA);\
}
#define xRTI()\
{\
int tmp;\
PULL(tmp);\
PS(tmp);\
PULL(mPC);\
PULL(tmp);\
mPC|=tmp<<8;\
}
#define xRTS()\
{\
int tmp;\
PULL(mPC);\
PULL(tmp);\
mPC|=tmp<<8;\
mPC++;\
}
#define xSBC()\
{\
int value=CPU_PEEK(mOperand);\
if (mD)\
{\
int c = mC?0:1;\
int sum = mA - value - c;\
int lo = (mA & 0x0f) - (value & 0x0f) - c;\
int hi = (mA & 0xf0) - (value & 0xf0);\
mV=0;\
mC=0;\
if ((mA^value) & (mA^sum) & 0x80) mV=1;\
if (lo & 0xf0) lo -= 6;\
if (lo & 0x80) hi -= 0x10;\
if (hi & 0x0f00) hi -= 0x60;\
if ((sum & 0xff00) == 0) mC=1;\
mA = (lo & 0x0f) + (hi & 0xf0);\
}\
else\
{\
int c = mC?0:1;\
int sum = mA - value - c;\
mV=0;\
mC=0;\
if ((mA^value) & (mA^sum) & 0x80) mV=1;\
if ((sum & 0xff00) == 0) mC=1;\
mA = (uint8) sum;\
}\
SET_NZ(mA)\
}
#define xSEC()\
{\
mC=true;\
}
#define xSED()\
{\
mD=true;\
}
#define xSEI()\
{\
mI=true;\
}
#define xSTA()\
{\
CPU_POKE(mOperand,mA);\
}
#define xSTP()\
{\
mSystem.gSystemCPUSleep=TRUE;\
}
#define xSTX()\
{\
CPU_POKE(mOperand,mX);\
}
#define xSTY()\
{\
CPU_POKE(mOperand,mY);\
}
#define xSTZ()\
{\
CPU_POKE(mOperand,0);\
}
#define xTAX()\
{\
mX=mA;\
SET_NZ(mX);\
}
#define xTAY()\
{\
mY=mA;\
SET_NZ(mY);\
}
#define xTRB()\
{\
int value=CPU_PEEK(mOperand);\
SET_Z(mA&value);\
value=value&(mA^0xff);\
CPU_POKE(mOperand,value);\
}
#define xTSB()\
{\
int value=CPU_PEEK(mOperand);\
SET_Z(mA&value);\
value=value|mA;\
CPU_POKE(mOperand,value);\
}
#define xTSX()\
{\
mX=mSP;\
SET_NZ(mX);\
}
#define xTXA()\
{\
mA=mX;\
SET_NZ(mA);\
}
#define xTXS()\
{\
mSP=mX;\
}
#define xTYA()\
{\
mA=mY;\
SET_NZ(mA);\
}
#define xWAI()\
{\
mSystem.gSystemCPUSleep=TRUE;\
}

1046
lynx/c65c02.cpp Normal file

File diff suppressed because it is too large Load Diff

229
lynx/c65c02.h Normal file
View File

@ -0,0 +1,229 @@
//
// Copyright (c) 2004 K. Wilkins
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
//////////////////////////////////////////////////////////////////////////////
// Handy - An Atari Lynx Emulator //
// Copyright (c) 1996,1997 //
// K. Wilkins //
//////////////////////////////////////////////////////////////////////////////
// 65C02 Emulation class //
//////////////////////////////////////////////////////////////////////////////
// //
// This class emulates a 65C02 processor. It is interfaced to the rest of //
// the system via the PEEK/POKE macros and a number of global variables //
// //
// K. Wilkins //
// August 1997 //
// //
//////////////////////////////////////////////////////////////////////////////
// Revision History: //
// ----------------- //
// //
// 01Aug1997 KW Document header added & class documented. //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef C65C02_H
#define C65C02_H
//#include <crtdbg.h>
//#define TRACE_CPU
#ifdef TRACE_CPU
#define TRACE_CPU0(msg) _RPT1(_CRT_WARN,"C65C02::"msg" (Time=%012d)\n",gSystemCycleCount)
#define TRACE_CPU1(msg,arg1) _RPT2(_CRT_WARN,"C65C02::"msg" (Time=%012d)\n",arg1,gSystemCycleCount)
#define TRACE_CPU2(msg,arg1,arg2) _RPT3(_CRT_WARN,"C65C02::"msg" (Time=%012d)\n",arg1,arg2,gSystemCycleCount)
#define TRACE_CPU3(msg,arg1,arg2,arg3) _RPT4(_CRT_WARN,"C65C02::"msg" (Time=%012d)\n",arg1,arg2,arg3,gSystemCycleCount)
#else
#define TRACE_CPU0(msg)
#define TRACE_CPU1(msg,arg1)
#define TRACE_CPU2(msg,arg1,arg2)
#define TRACE_CPU3(msg,arg1,arg2,arg3)
#endif
//
// Handy definitions
//
#define NMI_VECTOR 0xfffa
#define BOOT_VECTOR 0xfffc
#define IRQ_VECTOR 0xfffe
#define MAX_CPU_BREAKPOINTS 8
//
// ACCESS MACROS
//
//#define CPU_PEEK(m) (mSystem.Peek_CPU(m))
//#define CPU_PEEKW(m) (mSystem.PeekW_CPU(m))
//#define CPU_POKE(m1,m2) (mSystem.Poke_CPU(m1,m2))
#define CPU_PEEK(m) (((m<0xfc00)?mRamPointer[m]:mSystem.Peek_CPU(m)))
#define CPU_PEEKW(m) (((m<0xfc00)?(mRamPointer[m]+(mRamPointer[m+1]<<8)):mSystem.PeekW_CPU(m)))
#define CPU_POKE(m1,m2) {if(m1<0xfc00) mRamPointer[m1]=m2; else mSystem.Poke_CPU(m1,m2);}
enum { illegal=0,
accu,
imm,
absl,
zp,
zpx,
zpy,
absx,
absy,
iabsx,
impl,
rel,
zrel,
indx,
indy,
iabs,
ind
};
typedef struct
{
int PS; // Processor status register 8 bits
int A; // Accumulator 8 bits
int X; // X index register 8 bits
int Y; // Y index register 8 bits
int SP; // Stack Pointer 8 bits
int Opcode; // Instruction opcode 8 bits
int Operand;// Intructions operand 16 bits
int PC; // Program Counter 16 bits
bool NMI;
bool IRQ;
bool WAIT;
}C6502_REGS;
//
// The CPU emulation macros
//
#include "c6502mak.h"
//
// The CPU emulation macros
//
class C65C02
{
public:
C65C02(CSystem& parent)
:mSystem(parent)
{
TRACE_CPU0("C65C02()");
// Compute the BCD lookup table
for(uint16 t=0;t<256;++t)
{
mBCDTable[0][t]=((t >> 4) * 10) + (t & 0x0f);
mBCDTable[1][t]=(((t % 100) / 10) << 4) | (t % 10);
}
Reset();
}
~C65C02()
{
TRACE_CPU0("~C65C02()");
}
public:
void Reset();
void Update();
void SetRegs(C6502_REGS &regs);
void GetRegs(C6502_REGS &regs);
inline int GetPC() { return mPC; }
private:
CSystem &mSystem;
// CPU Flags & status
int mA; // Accumulator 8 bits
int mX; // X index register 8 bits
int mY; // Y index register 8 bits
int mSP; // Stack Pointer 8 bits
int mOpcode; // Instruction opcode 8 bits
int mOperand; // Intructions operand 16 bits
int mPC; // Program Counter 16 bits
int mN; // N flag for processor status register
int mV; // V flag for processor status register
int mB; // B flag for processor status register
int mD; // D flag for processor status register
int mI; // I flag for processor status register
int mZ; // Z flag for processor status register
int mC; // C flag for processor status register
int mIRQActive;
uint8 *mRamPointer;
// Associated lookup tables
int mBCDTable[2][256];
//
// Opcode prototypes
//
private:
// Answers value of the Processor Status register
INLINE int PS() const
{
uint8 ps = 0x20;
if(mN) ps|=0x80;
if(mV) ps|=0x40;
if(mB) ps|=0x10;
if(mD) ps|=0x08;
if(mI) ps|=0x04;
if(mZ) ps|=0x02;
if(mC) ps|=0x01;
return ps;
}
// Change the processor flags to correspond to the given value
INLINE void PS(int ps)
{
mN=ps&0x80;
mV=ps&0x40;
mB=ps&0x10;
mD=ps&0x08;
mI=ps&0x04;
mZ=ps&0x02;
mC=ps&0x01;
}
};
#endif

316
lynx/cart.cpp Normal file
View File

@ -0,0 +1,316 @@
//
// Copyright (c) 2004 K. Wilkins
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
//////////////////////////////////////////////////////////////////////////////
// Handy - An Atari Lynx Emulator //
// Copyright (c) 1996,1997 //
// K. Wilkins //
//////////////////////////////////////////////////////////////////////////////
// Lynx Cartridge Class //
//////////////////////////////////////////////////////////////////////////////
// //
// This class emulates the Lynx cartridge interface, given a filename it //
// will contstruct a cartridge object via the constructor. //
// //
// K. Wilkins //
// August 1997 //
// //
//////////////////////////////////////////////////////////////////////////////
// Revision History: //
// ----------------- //
// //
// 01Aug1997 KW Document header added & class documented. //
// //
//////////////////////////////////////////////////////////////////////////////
#define CART_CPP
#include "system.h"
#include <algorithm>
#include <string.h>
#include "cart.h"
/*
bool CCart::TestMagic(const uint8 *data, uint32 size)
{
if(size <= HEADER_RAW_SIZE)
return(FALSE);
if(memcmp(data, "LYNX", 4) || data[8] != 0x01)
return(FALSE);
return(TRUE);
}
*/
CCart::CCart(const uint8 *gamedata, uint32 gamesize, int pagesize0, int pagesize1)
{
CTYPE banktype0,banktype1;
switch(pagesize0)
{
default:
// warn?
case 0x000:
banktype0=UNUSED;
mMaskBank0=0;
mShiftCount0=0;
mCountMask0=0;
break;
case 0x100:
banktype0=C64K;
mMaskBank0=0x00ffff;
mShiftCount0=8;
mCountMask0=0x0ff;
break;
case 0x200:
banktype0=C128K;
mMaskBank0=0x01ffff;
mShiftCount0=9;
mCountMask0=0x1ff;
break;
case 0x400:
banktype0=C256K;
mMaskBank0=0x03ffff;
mShiftCount0=10;
mCountMask0=0x3ff;
break;
case 0x800:
banktype0=C512K;
mMaskBank0=0x07ffff;
mShiftCount0=11;
mCountMask0=0x7ff;
break;
}
switch(pagesize1)
{
default:
// warn?
case 0x000:
banktype1=UNUSED;
mMaskBank1=0;
mShiftCount1=0;
mCountMask1=0;
break;
case 0x100:
banktype1=C64K;
mMaskBank1=0x00ffff;
mShiftCount1=8;
mCountMask1=0x0ff;
break;
case 0x200:
banktype1=C128K;
mMaskBank1=0x01ffff;
mShiftCount1=9;
mCountMask1=0x1ff;
break;
case 0x400:
banktype1=C256K;
mMaskBank1=0x03ffff;
mShiftCount1=10;
mCountMask1=0x3ff;
break;
case 0x800:
banktype1=C512K;
mMaskBank1=0x07ffff;
mShiftCount1=11;
mCountMask1=0x7ff;
break;
}
// Make some space for the new carts
mCartBank0 = new uint8[mMaskBank0+1];
mCartBank1 = new uint8[mMaskBank1+1];
// Set default bank
mBank=bank0;
// Initialiase
std::memset(mCartBank0, DEFAULT_CART_CONTENTS, mMaskBank0 + 1);
std::memset(mCartBank1, DEFAULT_CART_CONTENTS, mMaskBank1 + 1);
// Read in the BANK0 bytes
if(mMaskBank0)
{
int size = std::min(gamesize, mMaskBank0+1);
std::memcpy(mCartBank0, gamedata, size);
gamedata += size;
gamesize -= size;
}
// Read in the BANK1 bytes
if(mMaskBank1)
{
int size = std::min(gamesize, mMaskBank1+1);
std::memcpy(mCartBank1, gamedata, size);
gamedata += size;
}
// As this is a cartridge boot unset the boot address
// mSystem.gCPUBootAddress=0;
// Dont allow an empty Bank1 - Use it for shadow SRAM/EEPROM
if(banktype1==UNUSED)
{
// Delete the single byte allocated earlier
delete[] mCartBank1;
// Allocate some new memory for us
banktype1=C64K;
mMaskBank1=0x00ffff;
mShiftCount1=8;
mCountMask1=0x0ff;
mCartBank1 = (uint8*) new uint8[mMaskBank1+1];
std::memset(mCartBank1, DEFAULT_RAM_CONTENTS, mMaskBank1 + 1);
mWriteEnableBank1=TRUE;
mCartRAM=TRUE;
}
}
CCart::~CCart()
{
delete[] mCartBank0;
delete[] mCartBank1;
}
void CCart::Reset()
{
mCounter = 0;
mShifter = 0;
mAddrData = 0;
mStrobe = 0;
last_strobe = 0;
}
INLINE void CCart::Poke(uint32 addr, uint8 data)
{
if(mBank==bank0)
{
if(mWriteEnableBank0)
mCartBank0[addr&mMaskBank0]=data;
}
else
{
if(mWriteEnableBank1)
mCartBank1[addr&mMaskBank1]=data;
}
}
INLINE uint8 CCart::Peek(uint32 addr)
{
if(mBank==bank0)
{
return(mCartBank0[addr&mMaskBank0]);
}
else
{
return(mCartBank1[addr&mMaskBank1]);
}
}
void CCart::CartAddressStrobe(bool strobe)
{
mStrobe=strobe;
if(mStrobe) mCounter=0;
//
// Either of the two below seem to work OK.
//
// if(!strobe && last_strobe)
//
if(mStrobe && !last_strobe)
{
// Clock a bit into the shifter
mShifter=mShifter<<1;
mShifter+=mAddrData?1:0;
mShifter&=0xff;
}
last_strobe=mStrobe;
}
void CCart::CartAddressData(bool data)
{
mAddrData=data;
}
void CCart::Poke0(uint8 data)
{
if(mWriteEnableBank0)
{
uint32 address=(mShifter<<mShiftCount0)+(mCounter&mCountMask0);
mCartBank0[address&mMaskBank0]=data;
}
if(!mStrobe)
{
mCounter++;
mCounter&=0x07ff;
}
}
void CCart::Poke1(uint8 data)
{
if(mWriteEnableBank1)
{
uint32 address=(mShifter<<mShiftCount1)+(mCounter&mCountMask1);
mCartBank1[address&mMaskBank1]=data;
}
if(!mStrobe)
{
mCounter++;
mCounter&=0x07ff;
}
}
uint8 CCart::Peek0(void)
{
uint32 address=(mShifter<<mShiftCount0)+(mCounter&mCountMask0);
uint8 data=mCartBank0[address&mMaskBank0];
if(!mStrobe)
{
mCounter++;
mCounter&=0x07ff;
}
return data;
}
uint8 CCart::Peek1(void)
{
uint32 address=(mShifter<<mShiftCount1)+(mCounter&mCountMask1);
uint8 data=mCartBank1[address&mMaskBank1];
if(!mStrobe)
{
mCounter++;
mCounter&=0x07ff;
}
return data;
}

130
lynx/cart.h Normal file
View File

@ -0,0 +1,130 @@
//
// Copyright (c) 2004 K. Wilkins
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
//////////////////////////////////////////////////////////////////////////////
// Handy - An Atari Lynx Emulator //
// Copyright (c) 1996,1997 //
// K. Wilkins //
//////////////////////////////////////////////////////////////////////////////
// Lynx cartridge class header file //
//////////////////////////////////////////////////////////////////////////////
// //
// This header file provides the interface definition and code for some of //
// the simpler cartridge API. //
// //
// K. Wilkins //
// August 1997 //
// //
//////////////////////////////////////////////////////////////////////////////
// Revision History: //
// ----------------- //
// //
// 01Aug1997 KW Document header added & class documented. //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef CART_H
#define CART_H
#define DEFAULT_CART_CONTENTS 0x11
enum CTYPE {UNUSED,C64K,C128K,C256K,C512K,C1024K};
/*
#define CART_NO_ROTATE 0
#define CART_ROTATE_LEFT 1
#define CART_ROTATE_RIGHT 2
struct LYNX_HEADER
{
uint8 magic[4]; // "LYNX"
uint16 page_size_bank0;
uint16 page_size_bank1; // "BS93" for unsupported homebrews
uint16 version;
uint8 cartname[32];
uint8 manufname[16];
uint8 rotation;
uint8 spare[5];
};
*/
class CCart : public CLynxBase
{
// Function members
public:
CCart(const uint8 *gamedata, uint32 gamesize, int pagesize0, int pagesize1) MDFN_COLD;
~CCart() MDFN_COLD;
public:
// Access for sensible members of the clan
enum { HEADER_RAW_SIZE = 64 };
//static bool TestMagic(const uint8 *data, uint32 size);
void Reset(void) MDFN_COLD;
void Poke(uint32 addr,uint8 data);
uint8 Peek(uint32 addr);
uint32 ReadCycle(void) {return 15;};
uint32 WriteCycle(void) {return 15;};
void BankSelect(EMMODE newbank) {mBank=newbank;}
uint32 ObjectSize(void) {return (mBank==bank0)?mMaskBank0+1:mMaskBank1+1;};
// Access for the lynx itself, it has no idea of address etc as this is done by the
// cartridge emulation hardware
void CartAddressStrobe(bool strobe);
void CartAddressData(bool data);
void Poke0(uint8 data);
void Poke1(uint8 data);
uint8 Peek0(void);
uint8 Peek1(void);
// Data members
public:
uint32 mWriteEnableBank0;
uint32 mWriteEnableBank1;
uint32 mCartRAM;
private:
EMMODE mBank;
uint32 mMaskBank0;
uint32 mMaskBank1;
uint8 *mCartBank0;
uint8 *mCartBank1;
uint32 mCounter;
uint32 mShifter;
uint32 mAddrData;
uint32 mStrobe;
uint32 mShiftCount0;
uint32 mCountMask0;
uint32 mShiftCount1;
uint32 mCountMask1;
int8 last_strobe;
};
#endif

38
lynx/cinterface.cpp Normal file
View File

@ -0,0 +1,38 @@
#include <cstdlib>
#include "system.h"
void *operator new(std::size_t n)
{
void *p = std::malloc(n);
std::memset(p, 0, n);
return p;
}
void operator delete(void *p)
{
std::free(p);
}
#define EXPORT extern "C" __declspec(dllexport)
EXPORT CSystem *Create(const uint8 *game, uint32 gamesize, const uint8 *bios, uint32 biossize, int pagesize0, int pagesize1, int lowpass)
{
return new CSystem(game, gamesize, bios, biossize, pagesize0, pagesize1, lowpass);
}
EXPORT void Destroy(CSystem *s)
{
delete s;
}
EXPORT void Reset(CSystem *s)
{
s->Reset();
}
EXPORT void Advance(CSystem *s, int buttons, uint32 *vbuff, int16 *sbuff, int *sbuffsize)
{
s->Advance(buttons, vbuff, sbuff, *sbuffsize);
}

21
lynx/license.txt Normal file
View File

@ -0,0 +1,21 @@
//
// Copyright (c) 2004 K. Wilkins
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//

56
lynx/lynxbase.h Normal file
View File

@ -0,0 +1,56 @@
//
// Copyright (c) 2004 K. Wilkins
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
//
// Generic Lynx base class.
//
#ifndef LYNXBASE_H
#define LYNXBASE_H
//
// bank0 - Cartridge bank 0
// bank1 - Cartridge bank 1
// ram - all ram
// cpu - system memory as viewed by the cpu
//
enum EMMODE {bank0,bank1,ram,cpu};
class CLynxBase
{
// Function members
public:
virtual ~CLynxBase() {};
public:
virtual void Reset(void) {};
virtual void Poke(uint32 addr,uint8 data)=0;
virtual uint8 Peek(uint32 addr)=0;
virtual void PokeW(uint32 addr,uint16 data) {}; // ONLY mSystem overloads these, they are never use by the clients
virtual uint16 PeekW(uint32 addr) {return 0;};
virtual void BankSelect(EMMODE newbank){};
virtual uint32 ObjectSize(void) {return 1;};
};
#endif

287
lynx/lynxdef.h Normal file
View File

@ -0,0 +1,287 @@
//
// Copyright (c) 2004 K. Wilkins
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
//////////////////////////////////////////////////////////////////////////////
// Handy - An Atari Lynx Emulator //
// Copyright (c) 1996,1997 //
// K. Wilkins //
//////////////////////////////////////////////////////////////////////////////
// Generic lyynx definition header file //
//////////////////////////////////////////////////////////////////////////////
// //
// This header file provides the definition of all of the useful hardware //
// addreses within the Lynx. //
// //
// K. Wilkins //
// August 1997 //
// //
//////////////////////////////////////////////////////////////////////////////
// Revision History: //
// ----------------- //
// //
// 01Aug1997 KW Document header added & class documented. //
// //
//////////////////////////////////////////////////////////////////////////////
#define TMPADR 0xfc00
#define TMPADRL 0xfc00
#define TMPADRH 0xfc01
#define TILTACUM 0xfc02
#define TILTACUML 0xfc02
#define TILTACUMH 0xfc03
#define HOFF 0xfc04
#define HOFFL 0xfc04
#define HOFFH 0xfc05
#define VOFF 0xfc06
#define VOFFL 0xfc06
#define VOFFH 0xfc07
#define VIDBAS 0xfc08
#define VIDBASL 0xfc08
#define VIDBASH 0xfc09
#define COLLBAS 0xfc0a
#define COLLBASL 0xfc0a
#define COLLBASH 0xfc0b
#define VIDADR 0xfc0c
#define VIDADRL 0xfc0c
#define VIDADRH 0xfc0d
#define COLLADR 0xfc0e
#define COLLADRL 0xfc0e
#define COLLADRH 0xfc0f
#define SCBNEXT 0xfc10
#define SCBNEXTL 0xfc10
#define SCBNEXTH 0xfc11
#define SPRDLINE 0xfc12
#define SPRDLINEL 0xfc12
#define SPRDLINEH 0xfc13
#define HPOSSTRT 0xfc14
#define HPOSSTRTL 0xfc14
#define HPOSSTRTH 0xfc15
#define VPOSSTRT 0xfc16
#define VPOSSTRTL 0xfc16
#define VPOSSTRTH 0xfc17
#define SPRHSIZ 0xfc18
#define SPRHSIZL 0xfc18
#define SPRHSIZH 0xfc19
#define SPRVSIZ 0xfc1a
#define SPRVSIZL 0xfc1a
#define SPRVSIZH 0xfc1b
#define STRETCH 0xfc1c
#define STRETCHL 0xfc1c
#define STRETCHH 0xfc1d
#define TILT 0xfc1e
#define TILTL 0xfc1e
#define TILTH 0xfc1f
#define SPRDOFF 0xfc20
#define SPRDOFFL 0xfc20
#define SPRDOFFH 0xfc21
#define SPRVPOS 0xfc22
#define SPRVPOSL 0xfc22
#define SPRVPOSH 0xfc23
#define COLLOFF 0xfc24
#define COLLOFFL 0xfc24
#define COLLOFFH 0xfc25
#define VSIZACUM 0xfc26
#define VSIZACUML 0xfc26
#define VSIZACUMH 0xfc27
#define HSIZOFF 0xfc28
#define HSIZOFFL 0xfc28
#define HSIZOFFH 0xfc29
#define VSIZOFF 0xfc2a
#define VSIZOFFL 0xfc2a
#define VSIZOFFH 0xfc2b
#define SCBADR 0xfc2c
#define SCBADRL 0xfc2c
#define SCBADRH 0xfc2d
#define PROCADR 0xfc2e
#define PROCADRL 0xfc2e
#define PROCADRH 0xfc2f
#define MATHD 0xfc52
#define MATHC 0xfc53
#define MATHB 0xfc54
#define MATHA 0xfc55
#define MATHP 0xfc56
#define MATHN 0xfc57
#define MATHH 0xfc60
#define MATHG 0xfc61
#define MATHF 0xfc62
#define MATHE 0xfc63
#define MATHM 0xfc6c
#define MATHL 0xfc6d
#define MATHK 0xfc6e
#define MATHJ 0xfc6f
#define SPRCTL0 0xfc80
#define SPRCTL1 0xfc81
#define SPRCOLL 0xfc82
#define SPRINIT 0xfc83
#define SUZYHREV 0xfc88
#define SUZYSREV 0xfc89
#define SUZYBUSEN 0xfc90
#define SPRGO 0xfc91
#define SPRSYS 0xfc92
#define JOYSTICK 0xfcb0
#define SWITCHES 0xfcb1
#define RCART0 0xfcb2
#define RCART1 0xfcb3
#define LEDS 0xfcc0
#define PPORTSTAT 0xfcc2
#define PPORTDATA 0xfcc3
#define HOWIE 0xfcc4
#define TIM0BKUP 0xfd00
#define TIM0CTLA 0xfd01
#define TIM0CNT 0xfd02
#define TIM0CTLB 0xfd03
#define TIM1BKUP 0xfd04
#define TIM1CTLA 0xfd05
#define TIM1CNT 0xfd06
#define TIM1CTLB 0xfd07
#define TIM2BKUP 0xfd08
#define TIM2CTLA 0xfd09
#define TIM2CNT 0xfd0a
#define TIM2CTLB 0xfd0b
#define TIM3BKUP 0xfd0c
#define TIM3CTLA 0xfd0d
#define TIM3CNT 0xfd0e
#define TIM3CTLB 0xfd0f
#define TIM4BKUP 0xfd10
#define TIM4CTLA 0xfd11
#define TIM4CNT 0xfd12
#define TIM4CTLB 0xfd13
#define TIM5BKUP 0xfd14
#define TIM5CTLA 0xfd15
#define TIM5CNT 0xfd16
#define TIM5CTLB 0xfd17
#define TIM6BKUP 0xfd18
#define TIM6CTLA 0xfd19
#define TIM6CNT 0xfd1a
#define TIM6CTLB 0xfd1b
#define TIM7BKUP 0xfd1c
#define TIM7CTLA 0xfd1d
#define TIM7CNT 0xfd1e
#define TIM7CTLB 0xfd1f
#define AUD0VOL 0xfd20
#define AUD0SHFTFB 0xfd21
#define AUD0OUTVAL 0xfd22
#define AUD0L8SHFT 0xfd23
#define AUD0TBACK 0xfd24
#define AUD0CTL 0xfd25
#define AUD0COUNT 0xfd26
#define AUD0MISC 0xfd27
#define AUD1VOL 0xfd28
#define AUD1SHFTFB 0xfd29
#define AUD1OUTVAL 0xfd2a
#define AUD1L8SHFT 0xfd2b
#define AUD1TBACK 0xfd2c
#define AUD1CTL 0xfd2d
#define AUD1COUNT 0xfd2e
#define AUD1MISC 0xfd2f
#define AUD2VOL 0xfd30
#define AUD2SHFTFB 0xfd31
#define AUD2OUTVAL 0xfd32
#define AUD2L8SHFT 0xfd33
#define AUD2TBACK 0xfd34
#define AUD2CTL 0xfd35
#define AUD2COUNT 0xfd36
#define AUD2MISC 0xfd37
#define AUD3VOL 0xfd38
#define AUD3SHFTFB 0xfd39
#define AUD3OUTVAL 0xfd3a
#define AUD3L8SHFT 0xfd3b
#define AUD3TBACK 0xfd3c
#define AUD3CTL 0xfd3d
#define AUD3COUNT 0xfd3e
#define AUD3MISC 0xfd3f
#define ATTEN_A 0xFD40 //
#define ATTEN_B 0xFD41
#define ATTEN_C 0xFD42 // Lynx2 Regs see macros/handy.equ
#define ATTEN_D 0xFD43
#define MPAN 0xFD44 //
#define MSTEREO 0xfd50
#define INTRST 0xfd80
#define INTSET 0xfd81
#define MAGRDY0 0xfd84
#define MAGRDY1 0xfd85
#define AUDIN 0xfd86
#define SYSCTL1 0xfd87
#define MIKEYHREV 0xfd88
#define MIKEYSREV 0xfd89
#define IODIR 0xfd8a
#define IODAT 0xfd8b
#define SERCTL 0xfd8c
#define SERDAT 0xfd8d
#define SDONEACK 0xfd90
#define CPUSLEEP 0xfd91
#define DISPCTL 0xfd92
#define PBKUP 0xfd93
#define DISPADR 0xfd94
#define DISPADRL 0xfd94
#define DISPADRH 0xfd95
#define Mtest0 0xfd9c
#define Mtest1 0xfd9d
#define Mtest2 0xfd9e
#define GREEN0 0xfda0
#define GREEN1 0xfda1
#define GREEN2 0xfda2
#define GREEN3 0xfda3
#define GREEN4 0xfda4
#define GREEN5 0xfda5
#define GREEN6 0xfda6
#define GREEN7 0xfda7
#define GREEN8 0xfda8
#define GREEN9 0xfda9
#define GREENA 0xfdaa
#define GREENB 0xfdab
#define GREENC 0xfdac
#define GREEND 0xfdad
#define GREENE 0xfdae
#define GREENF 0xfdaf
#define BLUERED0 0xfdb0
#define BLUERED1 0xfdb1
#define BLUERED2 0xfdb2
#define BLUERED3 0xfdb3
#define BLUERED4 0xfdb4
#define BLUERED5 0xfdb5
#define BLUERED6 0xfdb6
#define BLUERED7 0xfdb7
#define BLUERED8 0xfdb8
#define BLUERED9 0xfdb9
#define BLUEREDA 0xfdba
#define BLUEREDB 0xfdbb
#define BLUEREDC 0xfdbc
#define BLUEREDD 0xfdbd
#define BLUEREDE 0xfdbe
#define BLUEREDF 0xfdbf
#define MMAPCTL 0xfff9
#define CPUNMI 0xfffa
#define CPUNMIL 0xfffa
#define CPUNMIH 0xfffb
#define CPURESET 0xfffc
#define CPURESETL 0xfffc
#define CPURESETH 0xfffd
#define CPUINT 0xfffe
#define CPUINTL 0xfffe
#define CPUINTH 0xffff

65
lynx/machine.h Normal file
View File

@ -0,0 +1,65 @@
//
// Copyright (c) 2004 K. Wilkins
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
//////////////////////////////////////////////////////////////////////////////
// Handy - An Atari Lynx Emulator //
// Copyright (c) 1996,1997 //
// K. Wilkins //
//////////////////////////////////////////////////////////////////////////////
// Core machine definitions header file //
//////////////////////////////////////////////////////////////////////////////
// //
// This header file provides the interface definition and code for the core //
// definitions used throughout the Handy code. Additionally it provides //
// a generic memory object definition. //
// //
// K. Wilkins //
// August 1997 //
// //
//////////////////////////////////////////////////////////////////////////////
// Revision History: //
// ----------------- //
// //
// 01Aug1997 KW Document header added & class documented. //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef MACHINE_H
#define MACHINE_H
#include "mednafen.h"
// Read/Write Cycle definitions
#define CPU_RDWR_CYC 5
#define DMA_RDWR_CYC 4
#define SPR_RDWR_CYC 3
// Ammended to 2 on 28/04/00, 16Mhz = 62.5nS cycle
//
// 2 cycles is 125ns - PAGE MODE CYCLE
// 4 cycles is 250ns - NORMAL MODE CYCLE
//
#include "lynxbase.h"
#endif

58
lynx/mednafen.h Normal file
View File

@ -0,0 +1,58 @@
#ifndef MEDNAFEN_H
#define MEDNAFEN_H
#include <assert.h>
#include <inttypes.h>
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
#define MDFN_COLD
#define FALSE 0
#define TRUE 1
#define INLINE
typedef struct
{
union
{
struct
{
#ifdef MSB_FIRST
uint8 High;
uint8 Low;
#else
uint8 Low;
uint8 High;
#endif
} Union8;
uint16 Val16;
};
} Uuint16;
typedef struct
{
union
{
struct
{
#ifdef MSB_FIRST
Uuint16 High;
Uuint16 Low;
#else
Uuint16 Low;
Uuint16 High;
#endif
} Union16;
uint32 Val32;
};
} Uuint32;
#endif

189
lynx/memmap.cpp Normal file
View File

@ -0,0 +1,189 @@
//
// Copyright (c) 2004 K. Wilkins
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
//////////////////////////////////////////////////////////////////////////////
// Handy - An Atari Lynx Emulator //
// Copyright (c) 1996,1997 //
// K. Wilkins //
//////////////////////////////////////////////////////////////////////////////
// Lynx memory map class //
//////////////////////////////////////////////////////////////////////////////
// //
// This class provides the register $FFF9 functionality to the emulator, it //
// sets which devices can be seen by the CPU. //
// //
// K. Wilkins //
// August 1997 //
// //
//////////////////////////////////////////////////////////////////////////////
// Revision History: //
// ----------------- //
// //
// 01Aug1997 KW Document header added & class documented. //
// //
//////////////////////////////////////////////////////////////////////////////
#define MEMMAP_CPP
//#include <crtdbg.h>
//#define TRACE_MEMMAP
#include "system.h"
#include "memmap.h"
#include <string.h>
// IGNORE THIS TEXT, now overridden by new system
//
// We will hold 16 different memory maps for the "top" area which are selected
// on the basis of mMemMap->mSelector:
//
// Code Vect ROM Mikie Susie
//----------------------------------------------------
// (Default) 0000 V R M S
// 0001 V R M RAM
// 0001 V R RAM S
// 0011 V R RAM RAM
// 0100 V RAM M S
// ..
// ..
// 1111 RAM RAM RAM RAM
//
// Get it.....
//
// We can then index with mMemoryHandlers[mMemMap->mSelector][addr] for speed
//
CMemMap::CMemMap(CSystem& parent)
:mSystem(parent)
{
Reset();
}
void CMemMap::Reset(void)
{
// Initialise ALL pointers to RAM then overload to correct
for(int loop=0;loop<SYSTEM_SIZE;loop++) mSystem.mMemoryHandlers[loop]=mSystem.mRam;
// Special case for ourselves.
mSystem.mMemoryHandlers[0xFFF8]=mSystem.mRam;
mSystem.mMemoryHandlers[0xFFF9]=mSystem.mMemMap;
mSusieEnabled=-1;
mMikieEnabled=-1;
mRomEnabled=-1;
mVectorsEnabled=-1;
// Initialise everything correctly
Poke(0,0);
}
INLINE void CMemMap::Poke(uint32 addr, uint8 data)
{
TRACE_MEMMAP1("Poke() - Data %02x",data);
int newstate,loop;
// FC00-FCFF Susie area
newstate=(data&0x01)?FALSE:TRUE;
if(newstate!=mSusieEnabled)
{
mSusieEnabled=newstate;
if(mSusieEnabled)
{
for(loop=SUSIE_START;loop<SUSIE_START+SUSIE_SIZE;loop++) mSystem.mMemoryHandlers[loop]=mSystem.mSusie;
}
else
{
for(loop=SUSIE_START;loop<SUSIE_START+SUSIE_SIZE;loop++) mSystem.mMemoryHandlers[loop]=mSystem.mRam;
}
}
// FD00-FCFF Mikie area
newstate=(data&0x02)?FALSE:TRUE;
if(newstate!=mMikieEnabled)
{
mMikieEnabled=newstate;
if(mMikieEnabled)
{
for(loop=MIKIE_START;loop<MIKIE_START+MIKIE_SIZE;loop++) mSystem.mMemoryHandlers[loop]=mSystem.mMikie;
}
else
{
for(loop=MIKIE_START;loop<MIKIE_START+MIKIE_SIZE;loop++) mSystem.mMemoryHandlers[loop]=mSystem.mRam;
}
}
// FE00-FFF7 Rom area
newstate=(data&0x04)?FALSE:TRUE;
if(newstate!=mRomEnabled)
{
mRomEnabled=newstate;
if(mRomEnabled)
{
for(loop=BROM_START;loop<BROM_START+(BROM_SIZE-8);loop++) mSystem.mMemoryHandlers[loop]=mSystem.mRom;
}
else
{
for(loop=BROM_START;loop<BROM_START+(BROM_SIZE-8);loop++) mSystem.mMemoryHandlers[loop]=mSystem.mRam;
}
}
// FFFA-FFFF Vector area - Overload ROM space
newstate=(data&0x08)?FALSE:TRUE;
if(newstate!=mVectorsEnabled)
{
mVectorsEnabled=newstate;
if(mVectorsEnabled)
{
for(loop=VECTOR_START;loop<VECTOR_START+VECTOR_SIZE;loop++) mSystem.mMemoryHandlers[loop]=mSystem.mRom;
}
else
{
for(loop=VECTOR_START;loop<VECTOR_START+VECTOR_SIZE;loop++) mSystem.mMemoryHandlers[loop]=mSystem.mRam;
}
}
}
INLINE uint8 CMemMap::Peek(uint32 addr)
{
uint8 retval=0;
retval+=(mSusieEnabled)?0:0x01;
retval+=(mMikieEnabled)?0:0x02;
retval+=(mRomEnabled)?0:0x04;
retval+=(mVectorsEnabled)?0:0x08;
TRACE_MEMMAP1("Peek() - Data %02x",retval);
return retval;
}
//END OF FILE

95
lynx/memmap.h Normal file
View File

@ -0,0 +1,95 @@
//
// Copyright (c) 2004 K. Wilkins
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
//////////////////////////////////////////////////////////////////////////////
// Handy - An Atari Lynx Emulator //
// Copyright (c) 1996,1997 //
// K. Wilkins //
//////////////////////////////////////////////////////////////////////////////
// Lynx memory map object header file //
//////////////////////////////////////////////////////////////////////////////
// //
// This header file provides the interface definition for the memory map //
// object, this object controls which pieces of lynx hardware are //
// accesible by the CPU at any given time, it is the code for addr $FFF9 //
// //
// K. Wilkins //
// August 1997 //
// //
//////////////////////////////////////////////////////////////////////////////
// Revision History: //
// ----------------- //
// //
// 01Aug1997 KW Document header added & class documented. //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef MEMMAP_H
#define MEMMAP_H
#define MEMMAP_SIZE 0x1
#ifdef TRACE_CART
#define TRACE_MEMMAP0(msg) _RPT1(_CRT_WARN,"CMamMap::"msg" (Time=%012d)\n",gSystemCycleCount)
#define TRACE_MEMMAP1(msg,arg1) _RPT2(_CRT_WARN,"CMamMap::"msg" (Time=%012d)\n",arg1,gSystemCycleCount)
#define TRACE_MEMMAP2(msg,arg1,arg2) _RPT3(_CRT_WARN,"CMamMap::"msg" (Time=%012d)\n",arg1,arg2,gSystemCycleCount)
#define TRACE_MEMMAP3(msg,arg1,arg2,arg3) _RPT4(_CRT_WARN,"CMamMap::"msg" (Time=%012d)\n",arg1,arg2,arg3,gSystemCycleCount)
#else
#define TRACE_MEMMAP0(msg)
#define TRACE_MEMMAP1(msg,arg1)
#define TRACE_MEMMAP2(msg,arg1,arg2)
#define TRACE_MEMMAP3(msg,arg1,arg2,arg3)
#endif
class CMemMap : public CLynxBase
{
// Function members
public:
CMemMap(CSystem& parent) MDFN_COLD;
public:
void Reset(void) MDFN_COLD;
void Poke(uint32 addr,uint8 data);
uint8 Peek(uint32 addr);
uint32 ReadCycle(void) {return 5;};
uint32 WriteCycle(void) {return 5;};
uint32 ObjectSize(void) {return MEMMAP_SIZE;};
// Data members
private:
int mMikieEnabled;
int mSusieEnabled;
int mRomEnabled;
int mVectorsEnabled;
CSystem& mSystem;
};
#endif

2567
lynx/mikie.cpp Normal file

File diff suppressed because it is too large Load Diff

406
lynx/mikie.h Normal file
View File

@ -0,0 +1,406 @@
//
// Copyright (c) 2004 K. Wilkins
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
//////////////////////////////////////////////////////////////////////////////
// Handy - An Atari Lynx Emulator //
// Copyright (c) 1996,1997 //
// K. Wilkins //
//////////////////////////////////////////////////////////////////////////////
// Mikey class header file //
//////////////////////////////////////////////////////////////////////////////
// //
// This header file provides the interface definition and some of the code //
// for the Mikey chip within the Lynx. The most crucial code is the //
// Update() function which as you can probably guess updates all of the //
// Mikey hardware counters and screen DMA from the prevous time it was //
// called. Yes I know how to spell Mikey but I cant be bothered to change //
// it everywhere. //
// //
// K. Wilkins //
// August 1997 //
// //
//////////////////////////////////////////////////////////////////////////////
// Revision History: //
// ----------------- //
// //
// 01Aug1997 KW Document header added & class documented. //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef MIKIE_H
#define MIKIE_H
//#include <crtdbg.h>
//#define TRACE_MIKIE
#include <math.h>
#ifdef TRACE_MIKIE
#define TRACE_MIKIE0(msg) _RPT1(_CRT_WARN,"CMikie::"msg" (Time=%012d)\n",gSystemCycleCount)
#define TRACE_MIKIE1(msg,arg1) _RPT2(_CRT_WARN,"CMikie::"msg" (Time=%012d)\n",arg1,gSystemCycleCount)
#define TRACE_MIKIE2(msg,arg1,arg2) _RPT3(_CRT_WARN,"CMikie::"msg" (Time=%012d)\n",arg1,arg2,gSystemCycleCount)
#define TRACE_MIKIE3(msg,arg1,arg2,arg3) _RPT4(_CRT_WARN,"CMikie::"msg" (Time=%012d)\n",arg1,arg2,arg3,gSystemCycleCount)
#else
#define TRACE_MIKIE0(msg)
#define TRACE_MIKIE1(msg,arg1)
#define TRACE_MIKIE2(msg,arg1,arg2)
#define TRACE_MIKIE3(msg,arg1,arg2,arg3)
#endif
class CSystem;
#define MIKIE_START 0xfd00
#define MIKIE_SIZE 0x100
//
// Define counter types and defines
//
#define CTRL_A_IRQEN 0x80
#define CTRL_A_RTD 0x40
#define CTRL_A_RELOAD 0x10
#define CTRL_A_COUNT 0x08
#define CTRL_A_DIVIDE 0x07
#define CTRL_B_TDONE 0x08
#define CTRL_B_LASTCK 0x04
#define CTRL_B_CIN 0x02
#define CTRL_B_COUT 0x01
#define LINE_TIMER 0x00
#define SCREEN_TIMER 0x02
#define LINE_WIDTH 160
#define LINE_SIZE 80
#define UART_TX_INACTIVE 0x80000000
#define UART_RX_INACTIVE 0x80000000
#define UART_BREAK_CODE 0x00008000
#define UART_MAX_RX_QUEUE 32
#define UART_TX_TIME_PERIOD (11)
#define UART_RX_TIME_PERIOD (11)
#define UART_RX_NEXT_DELAY (44)
typedef struct
{
union
{
struct
{
#ifdef MSB_FIRST
uint8 unused:4;
uint8 Colour:1;
uint8 FourColour:1;
uint8 Flip:1;
uint8 DMAEnable:1;
#else
uint8 DMAEnable:1;
uint8 Flip:1;
uint8 FourColour:1;
uint8 Colour:1;
uint8 unused:4;
#endif
}Bits;
uint8 Byte;
};
}TDISPCTL;
typedef struct
{
union
{
struct
{
#ifdef MSB_FIRST
uint8 unused:8;
uint8 unused2:8;
uint8 unused3:4;
uint8 Blue:4;
uint8 Red:4;
uint8 Green:4;
#else
uint8 Green:4;
uint8 Red:4;
uint8 Blue:4;
#endif
}Colours;
uint32 Index;
};
}TPALETTE;
//
// Emumerated types for possible mikie windows independant modes
//
enum
{
MIKIE_BAD_MODE=0,
MIKIE_NO_ROTATE,
MIKIE_ROTATE_L,
MIKIE_ROTATE_R
};
enum
{
MIKIE_PIXEL_FORMAT_8BPP=0,
MIKIE_PIXEL_FORMAT_16BPP_555,
MIKIE_PIXEL_FORMAT_16BPP_565,
MIKIE_PIXEL_FORMAT_24BPP,
MIKIE_PIXEL_FORMAT_32BPP,
};
#include "sound/Stereo_Buffer.h"
typedef Blip_Synth<blip_good_quality, 256 * 4> Synth;
class CMikie : public CLynxBase
{
public:
CMikie(CSystem& parent) MDFN_COLD;
~CMikie() MDFN_COLD;
uint32 startTS;
Synth miksynth;
Stereo_Buffer mikbuf;
void Reset() MDFN_COLD;
uint8 Peek(uint32 addr);
void Poke(uint32 addr,uint8 data);
uint32 ReadCycle() {return 5;};
uint32 WriteCycle() {return 5;};
uint32 ObjectSize() {return MIKIE_SIZE;};
void PresetForHomebrew();
uint32 GetLfsrNext(uint32 current);
void ComLynxCable(int status);
void ComLynxRxData(int data);
void ComLynxTxLoopback(int data);
void ComLynxTxCallback(void (*function)(int data,uint32 objref),uint32 objref);
void DisplaySetAttributes();
void BlowOut();
uint32 DisplayRenderLine();
uint32 DisplayEndOfFrame();
inline void SetCPUSleep();
inline void ClearCPUSleep();
void CombobulateSound(uint32 teatime);
void Update();
void CheckWrap();
uint32* mpDisplayCurrent;
uint32 mpDisplayCurrentLine;
uint32 framebuffer[SCREEN_WIDTH * SCREEN_HEIGHT];
private:
CSystem &mSystem;
int last_lsample;
int last_rsample;
// Hardware storage
uint32 mDisplayAddress;
uint32 mAudioInputComparator;
uint32 mTimerStatusFlags;
uint32 mTimerInterruptMask;
TPALETTE mPalette[16];
uint32 mColourMap[4096];
uint32 mIODAT;
uint32 mIODIR;
uint32 mIODAT_REST_SIGNAL;
uint32 mDISPCTL_DMAEnable;
uint32 mDISPCTL_Flip;
uint32 mDISPCTL_FourColour;
uint32 mDISPCTL_Colour;
uint32 mTIM_0_BKUP;
uint32 mTIM_0_ENABLE_RELOAD;
uint32 mTIM_0_ENABLE_COUNT;
uint32 mTIM_0_LINKING;
uint32 mTIM_0_CURRENT;
uint32 mTIM_0_TIMER_DONE;
uint32 mTIM_0_LAST_CLOCK;
uint32 mTIM_0_BORROW_IN;
uint32 mTIM_0_BORROW_OUT;
uint32 mTIM_0_LAST_LINK_CARRY;
uint32 mTIM_0_LAST_COUNT;
uint32 mTIM_1_BKUP;
uint32 mTIM_1_ENABLE_RELOAD;
uint32 mTIM_1_ENABLE_COUNT;
uint32 mTIM_1_LINKING;
uint32 mTIM_1_CURRENT;
uint32 mTIM_1_TIMER_DONE;
uint32 mTIM_1_LAST_CLOCK;
uint32 mTIM_1_BORROW_IN;
uint32 mTIM_1_BORROW_OUT;
uint32 mTIM_1_LAST_LINK_CARRY;
uint32 mTIM_1_LAST_COUNT;
uint32 mTIM_2_BKUP;
uint32 mTIM_2_ENABLE_RELOAD;
uint32 mTIM_2_ENABLE_COUNT;
uint32 mTIM_2_LINKING;
uint32 mTIM_2_CURRENT;
uint32 mTIM_2_TIMER_DONE;
uint32 mTIM_2_LAST_CLOCK;
uint32 mTIM_2_BORROW_IN;
uint32 mTIM_2_BORROW_OUT;
uint32 mTIM_2_LAST_LINK_CARRY;
uint32 mTIM_2_LAST_COUNT;
uint32 mTIM_3_BKUP;
uint32 mTIM_3_ENABLE_RELOAD;
uint32 mTIM_3_ENABLE_COUNT;
uint32 mTIM_3_LINKING;
uint32 mTIM_3_CURRENT;
uint32 mTIM_3_TIMER_DONE;
uint32 mTIM_3_LAST_CLOCK;
uint32 mTIM_3_BORROW_IN;
uint32 mTIM_3_BORROW_OUT;
uint32 mTIM_3_LAST_LINK_CARRY;
uint32 mTIM_3_LAST_COUNT;
uint32 mTIM_4_BKUP;
uint32 mTIM_4_ENABLE_RELOAD;
uint32 mTIM_4_ENABLE_COUNT;
uint32 mTIM_4_LINKING;
uint32 mTIM_4_CURRENT;
uint32 mTIM_4_TIMER_DONE;
uint32 mTIM_4_LAST_CLOCK;
uint32 mTIM_4_BORROW_IN;
uint32 mTIM_4_BORROW_OUT;
uint32 mTIM_4_LAST_LINK_CARRY;
uint32 mTIM_4_LAST_COUNT;
uint32 mTIM_5_BKUP;
uint32 mTIM_5_ENABLE_RELOAD;
uint32 mTIM_5_ENABLE_COUNT;
uint32 mTIM_5_LINKING;
uint32 mTIM_5_CURRENT;
uint32 mTIM_5_TIMER_DONE;
uint32 mTIM_5_LAST_CLOCK;
uint32 mTIM_5_BORROW_IN;
uint32 mTIM_5_BORROW_OUT;
uint32 mTIM_5_LAST_LINK_CARRY;
uint32 mTIM_5_LAST_COUNT;
uint32 mTIM_6_BKUP;
uint32 mTIM_6_ENABLE_RELOAD;
uint32 mTIM_6_ENABLE_COUNT;
uint32 mTIM_6_LINKING;
uint32 mTIM_6_CURRENT;
uint32 mTIM_6_TIMER_DONE;
uint32 mTIM_6_LAST_CLOCK;
uint32 mTIM_6_BORROW_IN;
uint32 mTIM_6_BORROW_OUT;
uint32 mTIM_6_LAST_LINK_CARRY;
uint32 mTIM_6_LAST_COUNT;
uint32 mTIM_7_BKUP;
uint32 mTIM_7_ENABLE_RELOAD;
uint32 mTIM_7_ENABLE_COUNT;
uint32 mTIM_7_LINKING;
uint32 mTIM_7_CURRENT;
uint32 mTIM_7_TIMER_DONE;
uint32 mTIM_7_LAST_CLOCK;
uint32 mTIM_7_BORROW_IN;
uint32 mTIM_7_BORROW_OUT;
uint32 mTIM_7_LAST_LINK_CARRY;
uint32 mTIM_7_LAST_COUNT;
uint32 mAUDIO_BKUP[4];
uint32 mAUDIO_ENABLE_RELOAD[4];
uint32 mAUDIO_ENABLE_COUNT[4];
uint32 mAUDIO_LINKING[4];
uint32 mAUDIO_CURRENT[4];
uint32 mAUDIO_TIMER_DONE[4];
uint32 mAUDIO_LAST_CLOCK[4];
uint32 mAUDIO_BORROW_IN[4];
uint32 mAUDIO_BORROW_OUT[4];
uint32 mAUDIO_LAST_LINK_CARRY[4];
uint32 mAUDIO_LAST_COUNT[4];
int8 mAUDIO_VOLUME[4];
uint32 mAUDIO_INTEGRATE_ENABLE[4];
uint32 mAUDIO_WAVESHAPER[4];
int8 mAUDIO_OUTPUT[4];
uint8 mAUDIO_ATTEN[4];
uint32 mSTEREO;
uint32 mPAN;
//
// Serial related variables
//
uint32 mUART_RX_IRQ_ENABLE;
uint32 mUART_TX_IRQ_ENABLE;
uint32 mUART_RX_COUNTDOWN;
uint32 mUART_TX_COUNTDOWN;
uint32 mUART_SENDBREAK;
uint32 mUART_TX_DATA;
uint32 mUART_RX_DATA;
uint32 mUART_RX_READY;
uint32 mUART_PARITY_ENABLE;
uint32 mUART_PARITY_EVEN;
int mUART_CABLE_PRESENT;
void (*mpUART_TX_CALLBACK)(int data,uint32 objref);
uint32 mUART_TX_CALLBACK_OBJECT;
int mUART_Rx_input_queue[UART_MAX_RX_QUEUE];
unsigned int mUART_Rx_input_ptr;
unsigned int mUART_Rx_output_ptr;
int mUART_Rx_waiting;
int mUART_Rx_framing_error;
int mUART_Rx_overun_error;
//
// Screen related
//
uint8 *mpRamPointer;
uint32 mLynxLine;
uint32 mLynxLineDMACounter;
uint32 mLynxAddr;
void CopyLineSurface();
void BlankLineSurface();
};
#endif

138
lynx/msvc/changelog.txt Normal file
View File

@ -0,0 +1,138 @@
------------------------------------------------------------------------
r26 | 2009-10-02 13:36:47 +0400 | 2 lines
[Issue 5] Change <stdint.h> to "stdint.h" to let compiler search for it in local directory.
------------------------------------------------------------------------
r25 | 2009-09-17 23:46:49 +0400 | 2 lines
[Issue 4] Fix incorrect int8_t behaviour if compiled with /J flag.
------------------------------------------------------------------------
r24 | 2009-05-13 14:53:48 +0400 | 2 lines
Forgot about #ifdef __cplusplus guard around 'extern "C"', so inclusion to C files has been broken.
------------------------------------------------------------------------
r23 | 2009-05-12 01:27:45 +0400 | 3 lines
[Issue 2] Always wrap <wcharîàž with external "C" {}.
It turns out that not only Visual Studio 6 requires this, but also newer versions when compiling for ARM.
------------------------------------------------------------------------
r22 | 2009-05-11 22:22:15 +0400 | 3 lines
[Issue 3] Visual Studio 6 and Embedded Visual C++ 4 doesn't realize that, e.g. char has the same size as __int8 so we give up on __intX for them.
his should close Issue 3 in issue tracker.
------------------------------------------------------------------------
r21 | 2008-07-17 09:47:22 +0400 | 4 lines
Get rid of these compiler warnings when compiling for 32-bit:
warning C4311: 'type cast' : pointer truncation from 'void *' to 'uintptr_t'
warning C4312: 'type cast' : conversion from 'uintptr_t' to 'const void *' of greater size
------------------------------------------------------------------------
r20 | 2007-10-09 16:54:27 +0400 | 2 lines
Better C99 conformance: macros for format specifiers should only be included in C++ implementations if __STDC_FORMAT_MACROS is defined before <inttypes.h> is included.
------------------------------------------------------------------------
r19 | 2007-07-04 02:14:40 +0400 | 3 lines
Explicitly cast to appropriate type INT8_MIN, INT16_MIN, INT32_MIN and INT64_MIN constants.
Due to their unusual definition in Visual Studio headers (-_Ix_MAX-1) they are propagated to int and thus do not have expected type, causing VS6 strict compiler to claim about type inconsistency.
------------------------------------------------------------------------
r18 | 2007-06-26 16:53:23 +0400 | 2 lines
Better handling of (U)INTx_C macros - now they generate constants of exact width.
------------------------------------------------------------------------
r17 | 2007-03-29 20:16:14 +0400 | 2 lines
Fix typo: Miscrosoft -> Microsoft.
------------------------------------------------------------------------
r16 | 2007-02-24 17:32:58 +0300 | 4 lines
Remove <BaseTsd.h> include, as it is not present in Visual Studio 2005 Epxress Edition and required only for INT_PTR and UINT_PTR types.
'intptr_t' and 'uintptr_t' types now defined explicitly with #ifdef _WIN64.
------------------------------------------------------------------------
r15 | 2007-02-11 20:53:05 +0300 | 2 lines
More correct fix for compilation under VS6.
------------------------------------------------------------------------
r14 | 2007-02-11 20:04:32 +0300 | 2 lines
Bugfix: fix compiling under VS6, when stdint.h enclosed in 'extern "C" {}'.
------------------------------------------------------------------------
r13 | 2006-12-13 16:53:11 +0300 | 2 lines
Make _inline modifier for imaxdiv default option. Use STATIC_IMAXDIV to make it static.
------------------------------------------------------------------------
r12 | 2006-12-13 16:42:24 +0300 | 2 lines
Error message changed: VC6 supported from now.
------------------------------------------------------------------------
r11 | 2006-12-13 16:39:33 +0300 | 2 lines
All (U)INT* types changed to (unsigned) __int*. This should make stdint.h compatible with VC6.
------------------------------------------------------------------------
r10 | 2006-12-13 16:20:57 +0300 | 3 lines
Added INLINE_IMAXDIV define switch.
If INLINE_IMAXDIV is defined imaxdiv() have static modifier. If not - it is _inline.
------------------------------------------------------------------------
r9 | 2006-12-13 15:53:52 +0300 | 2 lines
Error message for non-MSC compiler changed.
------------------------------------------------------------------------
r8 | 2006-12-13 12:47:48 +0300 | 2 lines
Added #ifndef for SIZE_MAX (it is defined in limits.h on MSVSC 8).
------------------------------------------------------------------------
r7 | 2006-12-13 01:08:02 +0300 | 2 lines
License chaged to BSD-derivative.
------------------------------------------------------------------------
r6 | 2006-12-13 00:53:20 +0300 | 2 lines
Added <wchar.h> include to avoid warnings when it is included after stdint.h.
------------------------------------------------------------------------
r5 | 2006-12-12 00:58:05 +0300 | 2 lines
BUGFIX: Definitions of INTPTR_MIN, INTPTR_MAX and UINTPTR_MAX for WIN32 and WIN64 was mixed up.
------------------------------------------------------------------------
r4 | 2006-12-12 00:51:55 +0300 | 2 lines
Rise #error if _MSC_VER is not defined. I.e. compiler other then Microsoft Visual C++ is used.
------------------------------------------------------------------------
r3 | 2006-12-11 22:54:14 +0300 | 2 lines
Added <limits.h> include to stdint.h.
------------------------------------------------------------------------
r2 | 2006-12-11 21:39:27 +0300 | 2 lines
Initial check in.
------------------------------------------------------------------------
r1 | 2006-12-11 21:30:23 +0300 | 1 line
Initial directory structure.
------------------------------------------------------------------------

305
lynx/msvc/inttypes.h Normal file
View File

@ -0,0 +1,305 @@
// ISO C9x compliant inttypes.h for Microsoft Visual Studio
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
//
// Copyright (c) 2006 Alexander Chemeris
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. The name of the author may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef _MSC_VER // [
#error "Use this header only with Microsoft Visual C++ compilers!"
#endif // _MSC_VER ]
#ifndef _MSC_INTTYPES_H_ // [
#define _MSC_INTTYPES_H_
#if _MSC_VER > 1000
#pragma once
#endif
#include "stdint.h"
// 7.8 Format conversion of integer types
typedef struct {
intmax_t quot;
intmax_t rem;
} imaxdiv_t;
// 7.8.1 Macros for format specifiers
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
// The fprintf macros for signed integers are:
#define PRId8 "d"
#define PRIi8 "i"
#define PRIdLEAST8 "d"
#define PRIiLEAST8 "i"
#define PRIdFAST8 "d"
#define PRIiFAST8 "i"
#define PRId16 "hd"
#define PRIi16 "hi"
#define PRIdLEAST16 "hd"
#define PRIiLEAST16 "hi"
#define PRIdFAST16 "hd"
#define PRIiFAST16 "hi"
#define PRId32 "I32d"
#define PRIi32 "I32i"
#define PRIdLEAST32 "I32d"
#define PRIiLEAST32 "I32i"
#define PRIdFAST32 "I32d"
#define PRIiFAST32 "I32i"
#define PRId64 "I64d"
#define PRIi64 "I64i"
#define PRIdLEAST64 "I64d"
#define PRIiLEAST64 "I64i"
#define PRIdFAST64 "I64d"
#define PRIiFAST64 "I64i"
#define PRIdMAX "I64d"
#define PRIiMAX "I64i"
#define PRIdPTR "Id"
#define PRIiPTR "Ii"
// The fprintf macros for unsigned integers are:
#define PRIo8 "o"
#define PRIu8 "u"
#define PRIx8 "x"
#define PRIX8 "X"
#define PRIoLEAST8 "o"
#define PRIuLEAST8 "u"
#define PRIxLEAST8 "x"
#define PRIXLEAST8 "X"
#define PRIoFAST8 "o"
#define PRIuFAST8 "u"
#define PRIxFAST8 "x"
#define PRIXFAST8 "X"
#define PRIo16 "ho"
#define PRIu16 "hu"
#define PRIx16 "hx"
#define PRIX16 "hX"
#define PRIoLEAST16 "ho"
#define PRIuLEAST16 "hu"
#define PRIxLEAST16 "hx"
#define PRIXLEAST16 "hX"
#define PRIoFAST16 "ho"
#define PRIuFAST16 "hu"
#define PRIxFAST16 "hx"
#define PRIXFAST16 "hX"
#define PRIo32 "I32o"
#define PRIu32 "I32u"
#define PRIx32 "I32x"
#define PRIX32 "I32X"
#define PRIoLEAST32 "I32o"
#define PRIuLEAST32 "I32u"
#define PRIxLEAST32 "I32x"
#define PRIXLEAST32 "I32X"
#define PRIoFAST32 "I32o"
#define PRIuFAST32 "I32u"
#define PRIxFAST32 "I32x"
#define PRIXFAST32 "I32X"
#define PRIo64 "I64o"
#define PRIu64 "I64u"
#define PRIx64 "I64x"
#define PRIX64 "I64X"
#define PRIoLEAST64 "I64o"
#define PRIuLEAST64 "I64u"
#define PRIxLEAST64 "I64x"
#define PRIXLEAST64 "I64X"
#define PRIoFAST64 "I64o"
#define PRIuFAST64 "I64u"
#define PRIxFAST64 "I64x"
#define PRIXFAST64 "I64X"
#define PRIoMAX "I64o"
#define PRIuMAX "I64u"
#define PRIxMAX "I64x"
#define PRIXMAX "I64X"
#define PRIoPTR "Io"
#define PRIuPTR "Iu"
#define PRIxPTR "Ix"
#define PRIXPTR "IX"
// The fscanf macros for signed integers are:
#define SCNd8 "d"
#define SCNi8 "i"
#define SCNdLEAST8 "d"
#define SCNiLEAST8 "i"
#define SCNdFAST8 "d"
#define SCNiFAST8 "i"
#define SCNd16 "hd"
#define SCNi16 "hi"
#define SCNdLEAST16 "hd"
#define SCNiLEAST16 "hi"
#define SCNdFAST16 "hd"
#define SCNiFAST16 "hi"
#define SCNd32 "ld"
#define SCNi32 "li"
#define SCNdLEAST32 "ld"
#define SCNiLEAST32 "li"
#define SCNdFAST32 "ld"
#define SCNiFAST32 "li"
#define SCNd64 "I64d"
#define SCNi64 "I64i"
#define SCNdLEAST64 "I64d"
#define SCNiLEAST64 "I64i"
#define SCNdFAST64 "I64d"
#define SCNiFAST64 "I64i"
#define SCNdMAX "I64d"
#define SCNiMAX "I64i"
#ifdef _WIN64 // [
# define SCNdPTR "I64d"
# define SCNiPTR "I64i"
#else // _WIN64 ][
# define SCNdPTR "ld"
# define SCNiPTR "li"
#endif // _WIN64 ]
// The fscanf macros for unsigned integers are:
#define SCNo8 "o"
#define SCNu8 "u"
#define SCNx8 "x"
#define SCNX8 "X"
#define SCNoLEAST8 "o"
#define SCNuLEAST8 "u"
#define SCNxLEAST8 "x"
#define SCNXLEAST8 "X"
#define SCNoFAST8 "o"
#define SCNuFAST8 "u"
#define SCNxFAST8 "x"
#define SCNXFAST8 "X"
#define SCNo16 "ho"
#define SCNu16 "hu"
#define SCNx16 "hx"
#define SCNX16 "hX"
#define SCNoLEAST16 "ho"
#define SCNuLEAST16 "hu"
#define SCNxLEAST16 "hx"
#define SCNXLEAST16 "hX"
#define SCNoFAST16 "ho"
#define SCNuFAST16 "hu"
#define SCNxFAST16 "hx"
#define SCNXFAST16 "hX"
#define SCNo32 "lo"
#define SCNu32 "lu"
#define SCNx32 "lx"
#define SCNX32 "lX"
#define SCNoLEAST32 "lo"
#define SCNuLEAST32 "lu"
#define SCNxLEAST32 "lx"
#define SCNXLEAST32 "lX"
#define SCNoFAST32 "lo"
#define SCNuFAST32 "lu"
#define SCNxFAST32 "lx"
#define SCNXFAST32 "lX"
#define SCNo64 "I64o"
#define SCNu64 "I64u"
#define SCNx64 "I64x"
#define SCNX64 "I64X"
#define SCNoLEAST64 "I64o"
#define SCNuLEAST64 "I64u"
#define SCNxLEAST64 "I64x"
#define SCNXLEAST64 "I64X"
#define SCNoFAST64 "I64o"
#define SCNuFAST64 "I64u"
#define SCNxFAST64 "I64x"
#define SCNXFAST64 "I64X"
#define SCNoMAX "I64o"
#define SCNuMAX "I64u"
#define SCNxMAX "I64x"
#define SCNXMAX "I64X"
#ifdef _WIN64 // [
# define SCNoPTR "I64o"
# define SCNuPTR "I64u"
# define SCNxPTR "I64x"
# define SCNXPTR "I64X"
#else // _WIN64 ][
# define SCNoPTR "lo"
# define SCNuPTR "lu"
# define SCNxPTR "lx"
# define SCNXPTR "lX"
#endif // _WIN64 ]
#endif // __STDC_FORMAT_MACROS ]
// 7.8.2 Functions for greatest-width integer types
// 7.8.2.1 The imaxabs function
#define imaxabs _abs64
// 7.8.2.2 The imaxdiv function
// This is modified version of div() function from Microsoft's div.c found
// in %MSVC.NET%\crt\src\div.c
#ifdef STATIC_IMAXDIV // [
static
#else // STATIC_IMAXDIV ][
_inline
#endif // STATIC_IMAXDIV ]
imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
{
imaxdiv_t result;
result.quot = numer / denom;
result.rem = numer % denom;
if (numer < 0 && result.rem > 0) {
// did division wrong; must fix up
++result.quot;
result.rem -= denom;
}
return result;
}
// 7.8.2.3 The strtoimax and strtoumax functions
#define strtoimax _strtoi64
#define strtoumax _strtoui64
// 7.8.2.4 The wcstoimax and wcstoumax functions
#define wcstoimax _wcstoi64
#define wcstoumax _wcstoui64
#endif // _MSC_INTTYPES_H_ ]

247
lynx/msvc/stdint.h Normal file
View File

@ -0,0 +1,247 @@
// ISO C9x compliant stdint.h for Microsoft Visual Studio
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
//
// Copyright (c) 2006-2008 Alexander Chemeris
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. The name of the author may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef _MSC_VER // [
#error "Use this header only with Microsoft Visual C++ compilers!"
#endif // _MSC_VER ]
#ifndef _MSC_STDINT_H_ // [
#define _MSC_STDINT_H_
#if _MSC_VER > 1000
#pragma once
#endif
#include <limits.h>
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
// or compiler give many errors like this:
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
#ifdef __cplusplus
extern "C" {
#endif
# include <wchar.h>
#ifdef __cplusplus
}
#endif
// Define _W64 macros to mark types changing their size, like intptr_t.
#ifndef _W64
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
# define _W64 __w64
# else
# define _W64
# endif
#endif
// 7.18.1 Integer types
// 7.18.1.1 Exact-width integer types
// Visual Studio 6 and Embedded Visual C++ 4 doesn't
// realize that, e.g. char has the same size as __int8
// so we give up on __intX for them.
#if (_MSC_VER < 1300)
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
#else
typedef signed __int8 int8_t;
typedef signed __int16 int16_t;
typedef signed __int32 int32_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
#endif
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
// 7.18.1.2 Minimum-width integer types
typedef int8_t int_least8_t;
typedef int16_t int_least16_t;
typedef int32_t int_least32_t;
typedef int64_t int_least64_t;
typedef uint8_t uint_least8_t;
typedef uint16_t uint_least16_t;
typedef uint32_t uint_least32_t;
typedef uint64_t uint_least64_t;
// 7.18.1.3 Fastest minimum-width integer types
typedef int8_t int_fast8_t;
typedef int16_t int_fast16_t;
typedef int32_t int_fast32_t;
typedef int64_t int_fast64_t;
typedef uint8_t uint_fast8_t;
typedef uint16_t uint_fast16_t;
typedef uint32_t uint_fast32_t;
typedef uint64_t uint_fast64_t;
// 7.18.1.4 Integer types capable of holding object pointers
#ifdef _WIN64 // [
typedef signed __int64 intptr_t;
typedef unsigned __int64 uintptr_t;
#else // _WIN64 ][
typedef _W64 signed int intptr_t;
typedef _W64 unsigned int uintptr_t;
#endif // _WIN64 ]
// 7.18.1.5 Greatest-width integer types
typedef int64_t intmax_t;
typedef uint64_t uintmax_t;
// 7.18.2 Limits of specified-width integer types
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
// 7.18.2.1 Limits of exact-width integer types
#define INT8_MIN ((int8_t)_I8_MIN)
#define INT8_MAX _I8_MAX
#define INT16_MIN ((int16_t)_I16_MIN)
#define INT16_MAX _I16_MAX
#define INT32_MIN ((int32_t)_I32_MIN)
#define INT32_MAX _I32_MAX
#define INT64_MIN ((int64_t)_I64_MIN)
#define INT64_MAX _I64_MAX
#define UINT8_MAX _UI8_MAX
#define UINT16_MAX _UI16_MAX
#define UINT32_MAX _UI32_MAX
#define UINT64_MAX _UI64_MAX
// 7.18.2.2 Limits of minimum-width integer types
#define INT_LEAST8_MIN INT8_MIN
#define INT_LEAST8_MAX INT8_MAX
#define INT_LEAST16_MIN INT16_MIN
#define INT_LEAST16_MAX INT16_MAX
#define INT_LEAST32_MIN INT32_MIN
#define INT_LEAST32_MAX INT32_MAX
#define INT_LEAST64_MIN INT64_MIN
#define INT_LEAST64_MAX INT64_MAX
#define UINT_LEAST8_MAX UINT8_MAX
#define UINT_LEAST16_MAX UINT16_MAX
#define UINT_LEAST32_MAX UINT32_MAX
#define UINT_LEAST64_MAX UINT64_MAX
// 7.18.2.3 Limits of fastest minimum-width integer types
#define INT_FAST8_MIN INT8_MIN
#define INT_FAST8_MAX INT8_MAX
#define INT_FAST16_MIN INT16_MIN
#define INT_FAST16_MAX INT16_MAX
#define INT_FAST32_MIN INT32_MIN
#define INT_FAST32_MAX INT32_MAX
#define INT_FAST64_MIN INT64_MIN
#define INT_FAST64_MAX INT64_MAX
#define UINT_FAST8_MAX UINT8_MAX
#define UINT_FAST16_MAX UINT16_MAX
#define UINT_FAST32_MAX UINT32_MAX
#define UINT_FAST64_MAX UINT64_MAX
// 7.18.2.4 Limits of integer types capable of holding object pointers
#ifdef _WIN64 // [
# define INTPTR_MIN INT64_MIN
# define INTPTR_MAX INT64_MAX
# define UINTPTR_MAX UINT64_MAX
#else // _WIN64 ][
# define INTPTR_MIN INT32_MIN
# define INTPTR_MAX INT32_MAX
# define UINTPTR_MAX UINT32_MAX
#endif // _WIN64 ]
// 7.18.2.5 Limits of greatest-width integer types
#define INTMAX_MIN INT64_MIN
#define INTMAX_MAX INT64_MAX
#define UINTMAX_MAX UINT64_MAX
// 7.18.3 Limits of other integer types
#ifdef _WIN64 // [
# define PTRDIFF_MIN _I64_MIN
# define PTRDIFF_MAX _I64_MAX
#else // _WIN64 ][
# define PTRDIFF_MIN _I32_MIN
# define PTRDIFF_MAX _I32_MAX
#endif // _WIN64 ]
#define SIG_ATOMIC_MIN INT_MIN
#define SIG_ATOMIC_MAX INT_MAX
#ifndef SIZE_MAX // [
# ifdef _WIN64 // [
# define SIZE_MAX _UI64_MAX
# else // _WIN64 ][
# define SIZE_MAX _UI32_MAX
# endif // _WIN64 ]
#endif // SIZE_MAX ]
// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
#ifndef WCHAR_MIN // [
# define WCHAR_MIN 0
#endif // WCHAR_MIN ]
#ifndef WCHAR_MAX // [
# define WCHAR_MAX _UI16_MAX
#endif // WCHAR_MAX ]
#define WINT_MIN 0
#define WINT_MAX _UI16_MAX
#endif // __STDC_LIMIT_MACROS ]
// 7.18.4 Limits of other integer types
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
// 7.18.4.1 Macros for minimum-width integer constants
#define INT8_C(val) val##i8
#define INT16_C(val) val##i16
#define INT32_C(val) val##i32
#define INT64_C(val) val##i64
#define UINT8_C(val) val##ui8
#define UINT16_C(val) val##ui16
#define UINT32_C(val) val##ui32
#define UINT64_C(val) val##ui64
// 7.18.4.2 Macros for greatest-width integer constants
#define INTMAX_C INT64_C
#define UINTMAX_C UINT64_C
#endif // __STDC_CONSTANT_MACROS ]
#endif // _MSC_STDINT_H_ ]

64
lynx/ram.cpp Normal file
View File

@ -0,0 +1,64 @@
//
// Copyright (c) 2004 K. Wilkins
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
//////////////////////////////////////////////////////////////////////////////
// Handy - An Atari Lynx Emulator //
// Copyright (c) 1996,1997 //
// K. Wilkins //
//////////////////////////////////////////////////////////////////////////////
// RAM emulation class //
//////////////////////////////////////////////////////////////////////////////
// //
// This class emulates the system RAM (64KB), the interface is pretty //
// simple: constructor, reset, peek, poke. //
// //
// K. Wilkins //
// August 1997 //
// //
//////////////////////////////////////////////////////////////////////////////
// Revision History: //
// ----------------- //
// //
// 01Aug1997 KW Document header added & class documented. //
// //
//////////////////////////////////////////////////////////////////////////////
#define RAM_CPP
#include "system.h"
#include "ram.h"
CRam::CRam()
{
Reset();
}
CRam::~CRam()
{
}
void CRam::Reset(void)
{
//MDFNMP_AddRAM(65536, 0x0000, mRamData);
std::memset(mRamData, DEFAULT_RAM_CONTENTS, RAM_SIZE);
}

87
lynx/ram.h Normal file
View File

@ -0,0 +1,87 @@
//
// Copyright (c) 2004 K. Wilkins
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
//////////////////////////////////////////////////////////////////////////////
// Handy - An Atari Lynx Emulator //
// Copyright (c) 1996,1997 //
// K. Wilkins //
//////////////////////////////////////////////////////////////////////////////
// RAM object header file //
//////////////////////////////////////////////////////////////////////////////
// //
// This header file provides the interface definition for the RAM class //
// that emulates the Handy system RAM (64K) //
// //
// K. Wilkins //
// August 1997 //
// //
//////////////////////////////////////////////////////////////////////////////
// Revision History: //
// ----------------- //
// //
// 01Aug1997 KW Document header added & class documented. //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef RAM_H
#define RAM_H
#define RAM_SIZE 65536
#define RAM_ADDR_MASK 0xffff
#define DEFAULT_RAM_CONTENTS 0xff
struct HOME_HEADER
{
uint16 jump;
uint16 load_address;
uint16 size;
uint8 magic[4];
};
class CRam : public CLynxBase
{
// Function members
public:
CRam() MDFN_COLD;
~CRam() MDFN_COLD;
public:
void Reset(void) MDFN_COLD;
void Poke(uint32 addr, uint8 data){ mRamData[addr]=data;};
uint8 Peek(uint32 addr){ return(mRamData[addr]);};
uint32 ReadCycle(void) {return 5;};
uint32 WriteCycle(void) {return 5;};
uint32 ObjectSize(void) {return RAM_SIZE;};
uint8* GetRamPointer(void) { return mRamData; };
// Data members
private:
uint8 mRamData[RAM_SIZE];
};
#endif

60
lynx/rom.cpp Normal file
View File

@ -0,0 +1,60 @@
//
// Copyright (c) 2004 K. Wilkins
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
//////////////////////////////////////////////////////////////////////////////
// Handy - An Atari Lynx Emulator //
// Copyright (c) 1996,1997 //
// K. Wilkins //
//////////////////////////////////////////////////////////////////////////////
// ROM emulation class //
//////////////////////////////////////////////////////////////////////////////
// //
// This class emulates the system ROM (512B), the interface is pretty //
// simple: constructor, reset, peek, poke. //
// //
// K. Wilkins //
// August 1997 //
// //
//////////////////////////////////////////////////////////////////////////////
// Revision History: //
// ----------------- //
// //
// 01Aug1997 KW Document header added & class documented. //
// //
//////////////////////////////////////////////////////////////////////////////
#include "system.h"
#include "rom.h"
CRom::CRom(const uint8 *romfile, uint32 length)
{
mWriteEnable=FALSE;
Reset();
std::memset(mRomData, DEFAULT_ROM_CONTENTS, ROM_SIZE);
std::memcpy(mRomData, romfile, std::min<uint32>(ROM_SIZE, length));
}
void CRom::Reset(void)
{
}

79
lynx/rom.h Normal file
View File

@ -0,0 +1,79 @@
//
// Copyright (c) 2004 K. Wilkins
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
//////////////////////////////////////////////////////////////////////////////
// Handy - An Atari Lynx Emulator //
// Copyright (c) 1996,1997 //
// K. Wilkins //
//////////////////////////////////////////////////////////////////////////////
// ROM object header file //
//////////////////////////////////////////////////////////////////////////////
// //
// This header file provides the interface definition and inline code for //
// the class the emulates the internal 512 byte ROM embedded in Mikey //
// //
// K. Wilkins //
// August 1997 //
// //
//////////////////////////////////////////////////////////////////////////////
// Revision History: //
// ----------------- //
// //
// 01Aug1997 KW Document header added & class documented. //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef ROM_H
#define ROM_H
#define ROM_SIZE 0x200
#define ROM_ADDR_MASK 0x01ff
#define DEFAULT_ROM_CONTENTS 0x88
#define BROM_START 0xfe00
#define BROM_SIZE 0x200
#define VECTOR_START 0xfffa
#define VECTOR_SIZE 0x6
class CRom : public CLynxBase
{
public:
CRom(const uint8 *, uint32) MDFN_COLD;
public:
void Reset(void) MDFN_COLD;
void Poke(uint32 addr,uint8 data) { if(mWriteEnable) mRomData[addr&ROM_ADDR_MASK]=data;};
uint8 Peek(uint32 addr) { return(mRomData[addr&ROM_ADDR_MASK]);};
uint32 ReadCycle(void) {return 5;};
uint32 WriteCycle(void) {return 5;};
uint32 ObjectSize(void) {return ROM_SIZE;};
// Data members
public:
bool mWriteEnable;
private:
uint8 mRomData[ROM_SIZE];
};
#endif

457
lynx/sound/Blip_Buffer.cpp Normal file
View File

@ -0,0 +1,457 @@
// Blip_Buffer 0.4.1. http://www.slack.net/~ant/
#include "Blip_Buffer.h"
#include <assert.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#ifdef BLARGG_ENABLE_OPTIMIZER
#include BLARGG_ENABLE_OPTIMIZER
#endif
int const silent_buf_size = 1; // size used for Silent_Blip_Buffer
Blip_Buffer::Blip_Buffer()
{
factor_ = (blip_u64)ULLONG_MAX;
offset_ = 0;
buffer_ = 0;
buffer_size_ = 0;
sample_rate_ = 0;
reader_accum_ = 0;
bass_shift_ = 0;
clock_rate_ = 0;
bass_freq_ = 16;
length_ = 0;
// assumptions code makes about implementation-defined features
#ifndef NDEBUG
// right shift of negative value preserves sign
buf_t_ i = -0x7FFFFFFE;
assert( (i >> 1) == -0x3FFFFFFF );
// casting to short truncates to 16 bits and sign-extends
i = 0x18000;
assert( (short) i == -0x8000 );
#endif
}
Blip_Buffer::~Blip_Buffer()
{
if ( buffer_size_ != silent_buf_size )
free( buffer_ );
}
Silent_Blip_Buffer::Silent_Blip_Buffer()
{
factor_ = 0;
buffer_ = buf;
buffer_size_ = silent_buf_size;
memset( buf, 0, sizeof buf ); // in case machine takes exception for signed overflow
}
void Blip_Buffer::clear( int entire_buffer )
{
offset_ = 0;
reader_accum_ = 0;
modified_ = 0;
if ( buffer_ )
{
long count = (entire_buffer ? buffer_size_ : samples_avail());
memset( buffer_, 0, (count + blip_buffer_extra_) * sizeof (buf_t_) );
}
}
Blip_Buffer::blargg_err_t Blip_Buffer::set_sample_rate( long new_rate, int msec )
{
if ( buffer_size_ == silent_buf_size )
{
assert( 0 );
return "Internal (tried to resize Silent_Blip_Buffer)";
}
// start with maximum length that resampled time can represent
blip_s64 new_size = (ULLONG_MAX >> BLIP_BUFFER_ACCURACY) - blip_buffer_extra_ - 64;
// simple safety check, since code elsewhere may not be safe for sizes approaching (2 ^ 31).
if(new_size > ((1LL << 30) - 1))
new_size = (1LL << 30) - 1;
if ( msec != blip_max_length )
{
blip_s64 s = ((blip_s64)new_rate * (msec + 1) + 999) / 1000;
if ( s < new_size )
new_size = s;
else
assert( 0 ); // fails if requested buffer length exceeds limit
}
if ( buffer_size_ != new_size )
{
void* p = realloc( buffer_, (new_size + blip_buffer_extra_) * sizeof *buffer_ );
if ( !p )
return "Out of memory";
//if(new_size > buffer_size_)
// memset(buffer_ + buffer_size_, 0, (new_size + blip_buffer_extra_) * sizeof *buffer_
buffer_ = (buf_t_*) p;
}
buffer_size_ = new_size;
assert( buffer_size_ != silent_buf_size );
// update things based on the sample rate
sample_rate_ = new_rate;
length_ = new_size * 1000 / new_rate - 1;
if ( msec )
assert( length_ == msec ); // ensure length is same as that passed in
if ( clock_rate_ )
clock_rate( clock_rate_ );
bass_freq( bass_freq_ );
clear();
return 0; // success
}
blip_resampled_time_t Blip_Buffer::clock_rate_factor( long rate ) const
{
double ratio = (double) sample_rate_ / rate;
blip_s64 factor = (blip_s64) floor( ratio * (1LL << BLIP_BUFFER_ACCURACY) + 0.5 );
assert( factor > 0 || !sample_rate_ ); // fails if clock/output ratio is too large
return (blip_resampled_time_t) factor;
}
void Blip_Buffer::bass_freq( int freq )
{
bass_freq_ = freq;
int shift = 31;
if ( freq > 0 )
{
shift = 13;
long f = (freq << 16) / sample_rate_;
while ( (f >>= 1) && --shift ) { }
}
bass_shift_ = shift;
//printf("%d\n", bass_shift_);
}
void Blip_Buffer::end_frame( blip_time_t t )
{
offset_ += t * factor_;
assert( samples_avail() <= (long) buffer_size_ ); // time outside buffer length
}
void Blip_Buffer::remove_silence( long count )
{
assert( count <= samples_avail() ); // tried to remove more samples than available
offset_ -= (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;
}
long Blip_Buffer::count_samples( blip_time_t t ) const
{
unsigned long last_sample = resampled_time( t ) >> BLIP_BUFFER_ACCURACY;
unsigned long first_sample = offset_ >> BLIP_BUFFER_ACCURACY;
return (long) (last_sample - first_sample);
}
blip_time_t Blip_Buffer::count_clocks( long count ) const
{
if ( !factor_ )
{
assert( 0 ); // sample rate and clock rates must be set first
return 0;
}
if ( count > buffer_size_ )
count = buffer_size_;
blip_resampled_time_t time = (blip_resampled_time_t) count << BLIP_BUFFER_ACCURACY;
return (blip_time_t) ((time - offset_ + factor_ - 1) / factor_);
}
void Blip_Buffer::remove_samples( long count )
{
if ( count )
{
remove_silence( count );
// copy remaining samples to beginning and clear old samples
long remain = samples_avail() + blip_buffer_extra_;
memmove( buffer_, buffer_ + count, remain * sizeof *buffer_ );
memset( buffer_ + remain, 0, count * sizeof *buffer_ );
}
}
// Blip_Synth_
Blip_Synth_Fast_::Blip_Synth_Fast_()
{
buf = 0;
last_amp = 0;
delta_factor = 0;
}
void Blip_Synth_Fast_::volume_unit( double new_unit )
{
delta_factor = int (new_unit * (1L << blip_sample_bits) + 0.5);
}
#if !BLIP_BUFFER_FAST
Blip_Synth_::Blip_Synth_( short* p, int w ) :
impulses( p ),
width( w )
{
volume_unit_ = 0.0;
kernel_unit = 0;
buf = 0;
last_amp = 0;
delta_factor = 0;
}
#undef PI
#define PI 3.1415926535897932384626433832795029
static void gen_sinc( float* out, int count, double oversample, double treble, double cutoff )
{
if ( cutoff >= 0.999 )
cutoff = 0.999;
if ( treble < -300.0 )
treble = -300.0;
if ( treble > 5.0 )
treble = 5.0;
double const maxh = 4096.0;
double const rolloff = pow( 10.0, 1.0 / (maxh * 20.0) * treble / (1.0 - cutoff) );
double const pow_a_n = pow( rolloff, maxh - maxh * cutoff );
double const to_angle = PI / 2 / maxh / oversample;
for ( int i = 0; i < count; i++ )
{
double angle = ((i - count) * 2 + 1) * to_angle;
double c = rolloff * cos( (maxh - 1.0) * angle ) - cos( maxh * angle );
double cos_nc_angle = cos( maxh * cutoff * angle );
double cos_nc1_angle = cos( (maxh * cutoff - 1.0) * angle );
double cos_angle = cos( angle );
c = c * pow_a_n - rolloff * cos_nc1_angle + cos_nc_angle;
double d = 1.0 + rolloff * (rolloff - cos_angle - cos_angle);
double b = 2.0 - cos_angle - cos_angle;
double a = 1.0 - cos_angle - cos_nc_angle + cos_nc1_angle;
out [i] = (float) ((a * d + c * b) / (b * d)); // a / b + c / d
}
}
void blip_eq_t::generate( float* out, int count ) const
{
// lower cutoff freq for narrow kernels with their wider transition band
// (8 points->1.49, 16 points->1.15)
double oversample = blip_res * 2.25 / count + 0.85;
double half_rate = sample_rate * 0.5;
if ( cutoff_freq )
oversample = half_rate / cutoff_freq;
double cutoff = rolloff_freq * oversample / half_rate;
gen_sinc( out, count, blip_res * oversample, treble, cutoff );
// apply (half of) hamming window
double to_fraction = PI / (count - 1);
for ( int i = count; i--; )
out [i] *= 0.54f - 0.46f * (float) cos( i * to_fraction );
}
void Blip_Synth_::adjust_impulse()
{
// sum pairs for each phase and add error correction to end of first half
int const size = impulses_size();
for ( int p = blip_res; p-- >= blip_res / 2; )
{
int p2 = blip_res - 2 - p;
long error = kernel_unit;
for ( int i = 1; i < size; i += blip_res )
{
error -= impulses [i + p ];
error -= impulses [i + p2];
}
if ( p == p2 )
error /= 2; // phase = 0.5 impulse uses same half for both sides
impulses [size - blip_res + p] += (short) error;
//printf( "error: %ld\n", error );
}
//for ( int i = blip_res; i--; printf( "\n" ) )
// for ( int j = 0; j < width / 2; j++ )
// printf( "%5ld,", impulses [j * blip_res + i + 1] );
}
void Blip_Synth_::treble_eq( blip_eq_t const& eq )
{
float fimpulse [blip_res / 2 * (blip_widest_impulse_ - 1) + blip_res * 2];
int const half_size = blip_res / 2 * (width - 1);
eq.generate( &fimpulse [blip_res], half_size );
int i;
// need mirror slightly past center for calculation
for ( i = blip_res; i--; )
fimpulse [blip_res + half_size + i] = fimpulse [blip_res + half_size - 1 - i];
// starts at 0
for ( i = 0; i < blip_res; i++ )
fimpulse [i] = 0.0f;
// find rescale factor
double total = 0.0;
for ( i = 0; i < half_size; i++ )
total += fimpulse [blip_res + i];
//double const base_unit = 44800.0 - 128 * 18; // allows treble up to +0 dB
//double const base_unit = 37888.0; // allows treble to +5 dB
double const base_unit = 32768.0; // necessary for blip_unscaled to work
double rescale = base_unit / 2 / total;
kernel_unit = (long) base_unit;
// integrate, first difference, rescale, convert to int
double sum = 0.0;
double next = 0.0;
int const impulses_size_local = this->impulses_size();
for ( i = 0; i < impulses_size_local; i++ )
{
impulses [i] = (short) floor( (next - sum) * rescale + 0.5 );
sum += fimpulse [i];
next += fimpulse [i + blip_res];
}
adjust_impulse();
// volume might require rescaling
double vol = volume_unit_;
if ( vol )
{
volume_unit_ = 0.0;
volume_unit( vol );
}
}
void Blip_Synth_::volume_unit( double new_unit )
{
if ( new_unit != volume_unit_ )
{
// use default eq if it hasn't been set yet
if ( !kernel_unit )
treble_eq( -8.0 );
volume_unit_ = new_unit;
double factor = new_unit * (1L << blip_sample_bits) / kernel_unit;
if ( factor > 0.0 )
{
int shift = 0;
// if unit is really small, might need to attenuate kernel
while ( factor < 2.0 )
{
shift++;
factor *= 2.0;
}
if ( shift )
{
kernel_unit >>= shift;
assert( kernel_unit > 0 ); // fails if volume unit is too low
// keep values positive to avoid round-towards-zero of sign-preserving
// right shift for negative values
long offset = 0x8000 + (1 << (shift - 1));
long offset2 = 0x8000 >> shift;
for ( int i = impulses_size(); i--; )
impulses [i] = (short) (((impulses [i] + offset) >> shift) - offset2);
adjust_impulse();
}
}
delta_factor = (int) floor( factor + 0.5 );
//printf( "delta_factor: %d, kernel_unit: %d\n", delta_factor, kernel_unit );
}
}
#endif
long Blip_Buffer::read_samples( blip_sample_t* BLIP_RESTRICT out, long max_samples, int stereo )
{
long count = samples_avail();
if ( count > max_samples )
count = max_samples;
if ( count )
{
int const bass = BLIP_READER_BASS( *this );
BLIP_READER_BEGIN( reader, *this );
if ( !stereo )
{
for ( blip_long n = count; n; --n )
{
blip_long s = BLIP_READER_READ( reader );
if ( (blip_sample_t) s != s )
s = 0x7FFF - (s >> 24);
*out++ = (blip_sample_t) s;
BLIP_READER_NEXT( reader, bass );
}
}
else
{
for ( blip_long n = count; n; --n )
{
blip_long s = BLIP_READER_READ( reader );
if ( (blip_sample_t) s != s )
s = 0x7FFF - (s >> 24);
*out = (blip_sample_t) s;
out += 2;
BLIP_READER_NEXT( reader, bass );
}
}
BLIP_READER_END( reader, *this );
remove_samples( count );
}
return count;
}
void Blip_Buffer::mix_samples( blip_sample_t const* in, long count )
{
if ( buffer_size_ == silent_buf_size )
{
assert( 0 );
return;
}
buf_t_* out = buffer_ + (offset_ >> BLIP_BUFFER_ACCURACY) + blip_widest_impulse_ / 2;
int const sample_shift = blip_sample_bits - 16;
int prev = 0;
while ( count-- )
{
blip_long s = (blip_long) *in++ << sample_shift;
*out += s - prev;
prev = s;
++out;
}
*out -= prev;
}

498
lynx/sound/Blip_Buffer.h Normal file
View File

@ -0,0 +1,498 @@
// Band-limited sound synthesis buffer
// Various changes and hacks for use in Mednafen.
#ifdef __GNUC__
#define blip_inline inline __attribute__((always_inline))
#else
#define blip_inline inline
#endif
#include <limits.h>
#include <inttypes.h>
// Blip_Buffer 0.4.1
#ifndef BLIP_BUFFER_H
#define BLIP_BUFFER_H
// Internal
typedef int32_t blip_long;
typedef uint32_t blip_ulong;
typedef int64_t blip_s64;
typedef uint64_t blip_u64;
// Time unit at source clock rate
typedef blip_long blip_time_t;
// Output samples are 16-bit signed, with a range of -32768 to 32767
typedef short blip_sample_t;
enum { blip_sample_max = 32767 };
class Blip_Buffer {
public:
typedef const char* blargg_err_t;
// Set output sample rate and buffer length in milliseconds (1/1000 sec, defaults
// to 1/4 second), then clear buffer. Returns NULL on success, otherwise if there
// isn't enough memory, returns error without affecting current buffer setup.
blargg_err_t set_sample_rate( long samples_per_sec, int msec_length = 1000 / 4 );
// Set number of source time units per second
void clock_rate( long );
// End current time frame of specified duration and make its samples available
// (along with any still-unread samples) for reading with read_samples(). Begins
// a new time frame at the end of the current frame.
void end_frame( blip_time_t time );
// Read at most 'max_samples' out of buffer into 'dest', removing them from from
// the buffer. Returns number of samples actually read and removed. If stereo is
// true, increments 'dest' one extra time after writing each sample, to allow
// easy interleving of two channels into a stereo output buffer.
long read_samples( blip_sample_t* dest, long max_samples, int stereo = 0 );
// Additional optional features
// Current output sample rate
long sample_rate() const;
// Length of buffer, in milliseconds
int length() const;
// Number of source time units per second
long clock_rate() const;
// Set frequency high-pass filter frequency, where higher values reduce bass more
void bass_freq( int frequency );
// Number of samples delay from synthesis to samples read out
int output_latency() const;
// Remove all available samples and clear buffer to silence. If 'entire_buffer' is
// false, just clears out any samples waiting rather than the entire buffer.
void clear( int entire_buffer = 1 );
// Number of samples available for reading with read_samples()
long samples_avail() const;
// Remove 'count' samples from those waiting to be read
void remove_samples( long count );
// Experimental features
// Count number of clocks needed until 'count' samples will be available.
// If buffer can't even hold 'count' samples, returns number of clocks until
// buffer becomes full.
blip_time_t count_clocks( long count ) const;
// Number of raw samples that can be mixed within frame of specified duration.
long count_samples( blip_time_t duration ) const;
// Mix 'count' samples from 'buf' into buffer.
void mix_samples( blip_sample_t const* buf, long count );
// not documented yet
void set_modified() { modified_ = 1; }
int clear_modified() { int b = modified_; modified_ = 0; return b; }
typedef blip_u64 blip_resampled_time_t;
void remove_silence( long count );
blip_resampled_time_t resampled_duration( int t ) const { return t * factor_; }
blip_resampled_time_t resampled_time( blip_time_t t ) const { return t * factor_ + offset_; }
blip_resampled_time_t clock_rate_factor( long clock_rate ) const;
public:
Blip_Buffer();
~Blip_Buffer();
// Deprecated
typedef blip_resampled_time_t resampled_time_t;
blargg_err_t sample_rate( long r ) { return set_sample_rate( r ); }
blargg_err_t sample_rate( long r, int msec ) { return set_sample_rate( r, msec ); }
private:
// noncopyable
Blip_Buffer( const Blip_Buffer& );
Blip_Buffer& operator = ( const Blip_Buffer& );
public:
typedef blip_time_t buf_t_;
blip_u64 factor_;
blip_resampled_time_t offset_;
buf_t_* buffer_;
blip_long buffer_size_;
blip_long reader_accum_;
int bass_shift_;
private:
long sample_rate_;
long clock_rate_;
int bass_freq_;
int length_;
int modified_;
friend class Blip_Reader;
};
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#define BLIP_BUFFER_ACCURACY 32
#define BLIP_PHASE_BITS 8
// Number of bits in resample ratio fraction. Higher values give a more accurate ratio
// but reduce maximum buffer size.
//#ifndef BLIP_BUFFER_ACCURACY
// #define BLIP_BUFFER_ACCURACY 16
//#endif
// Number bits in phase offset. Fewer than 6 bits (64 phase offsets) results in
// noticeable broadband noise when synthesizing high frequency square waves.
// Affects size of Blip_Synth objects since they store the waveform directly.
//#ifndef BLIP_PHASE_BITS
// #if BLIP_BUFFER_FAST
// #define BLIP_PHASE_BITS 8
// #else
// #define BLIP_PHASE_BITS 6
// #endif
//#endif
// Internal
typedef blip_u64 blip_resampled_time_t;
int const blip_widest_impulse_ = 16;
int const blip_buffer_extra_ = blip_widest_impulse_ + 2;
int const blip_res = 1 << BLIP_PHASE_BITS;
class blip_eq_t;
class Blip_Synth_Fast_ {
public:
Blip_Buffer* buf;
int last_amp;
int delta_factor;
void volume_unit( double );
Blip_Synth_Fast_();
void treble_eq( blip_eq_t const& ) { }
};
class Blip_Synth_ {
public:
Blip_Buffer* buf;
int last_amp;
int delta_factor;
void volume_unit( double );
Blip_Synth_( short* impulses, int width );
void treble_eq( blip_eq_t const& );
private:
double volume_unit_;
short* const impulses;
int const width;
blip_long kernel_unit;
int impulses_size() const { return blip_res / 2 * width + 1; }
void adjust_impulse();
};
// Quality level. Start with blip_good_quality.
const int blip_med_quality = 8;
const int blip_good_quality = 12;
const int blip_high_quality = 16;
// Range specifies the greatest expected change in amplitude. Calculate it
// by finding the difference between the maximum and minimum expected
// amplitudes (max - min).
template<int quality,int range>
class Blip_Synth {
public:
// Set overall volume of waveform
void volume( double v ) { impl.volume_unit( v * (1.0 / (range < 0 ? -range : range)) ); }
// Configure low-pass filter (see blip_buffer.txt)
void treble_eq( blip_eq_t const& eq ) { impl.treble_eq( eq ); }
// Get/set Blip_Buffer used for output
Blip_Buffer* output() const { return impl.buf; }
void output( Blip_Buffer* b ) { impl.buf = b; impl.last_amp = 0; }
// Update amplitude of waveform at given time. Using this requires a separate
// Blip_Synth for each waveform.
void update( blip_time_t time, int amplitude );
// Low-level interface
// Add an amplitude transition of specified delta, optionally into specified buffer
// rather than the one set with output(). Delta can be positive or negative.
// The actual change in amplitude is delta * (volume / range)
void offset( blip_time_t, int delta, Blip_Buffer* ) const;
void offset( blip_time_t t, int delta ) const { offset( t, delta, impl.buf ); }
// Works directly in terms of fractional output samples. Contact author for more info.
void offset_resampled( blip_resampled_time_t, int delta, Blip_Buffer* ) const;
// Same as offset(), except code is inlined for higher performance
void offset_inline( blip_time_t t, int delta, Blip_Buffer* buf ) const {
offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );
}
void offset_inline( blip_time_t t, int delta ) const {
offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );
}
private:
#if BLIP_BUFFER_FAST
Blip_Synth_Fast_ impl;
#else
Blip_Synth_ impl;
typedef short imp_t;
imp_t impulses [blip_res * (quality / 2) + 1];
public:
Blip_Synth() : impl( impulses, quality ) { }
#endif
};
// Low-pass equalization parameters
class blip_eq_t {
public:
// Logarithmic rolloff to treble dB at half sampling rate. Negative values reduce
// treble, small positive values (0 to 5.0) increase treble.
blip_eq_t( double treble_db = 0 );
// See blip_buffer.txt
blip_eq_t( double treble, long rolloff_freq, long sample_rate, long cutoff_freq = 0 );
private:
double treble;
long rolloff_freq;
long sample_rate;
long cutoff_freq;
void generate( float* out, int count ) const;
friend class Blip_Synth_;
};
int const blip_sample_bits = 30;
// Dummy Blip_Buffer to direct sound output to, for easy muting without
// having to stop sound code.
class Silent_Blip_Buffer : public Blip_Buffer {
buf_t_ buf [blip_buffer_extra_ + 1];
public:
// The following cannot be used (an assertion will fail if attempted):
blargg_err_t set_sample_rate( long samples_per_sec, int msec_length );
blip_time_t count_clocks( long count ) const;
void mix_samples( blip_sample_t const* buf, long count );
Silent_Blip_Buffer();
};
#if defined (__GNUC__) || _MSC_VER >= 1100
#define BLIP_RESTRICT __restrict
#else
#define BLIP_RESTRICT
#endif
// Optimized reading from Blip_Buffer, for use in custom sample output
// Begin reading from buffer. Name should be unique to the current block.
#define BLIP_READER_BEGIN( name, blip_buffer ) \
const Blip_Buffer::buf_t_* BLIP_RESTRICT name##_reader_buf = (blip_buffer).buffer_;\
blip_long name##_reader_accum = (blip_buffer).reader_accum_
// Get value to pass to BLIP_READER_NEXT()
#define BLIP_READER_BASS( blip_buffer ) ((blip_buffer).bass_shift_)
// Constant value to use instead of BLIP_READER_BASS(), for slightly more optimal
// code at the cost of having no bass control
int const blip_reader_default_bass = 9;
// Current sample
#define BLIP_READER_READ( name ) (name##_reader_accum >> (blip_sample_bits - 16))
// Current raw sample in full internal resolution
#define BLIP_READER_READ_RAW( name ) (name##_reader_accum)
// Advance to next sample
#define BLIP_READER_NEXT( name, bass ) \
(void) (name##_reader_accum += *name##_reader_buf++ - (name##_reader_accum >> (bass)))
// End reading samples from buffer. The number of samples read must now be removed
// using Blip_Buffer::remove_samples().
#define BLIP_READER_END( name, blip_buffer ) \
(void) ((blip_buffer).reader_accum_ = name##_reader_accum)
// Compatibility with older version
const long blip_unscaled = 65535;
const int blip_low_quality = blip_med_quality;
const int blip_best_quality = blip_high_quality;
// Deprecated; use BLIP_READER macros as follows:
// Blip_Reader r; r.begin( buf ); -> BLIP_READER_BEGIN( r, buf );
// int bass = r.begin( buf ) -> BLIP_READER_BEGIN( r, buf ); int bass = BLIP_READER_BASS( buf );
// r.read() -> BLIP_READER_READ( r )
// r.read_raw() -> BLIP_READER_READ_RAW( r )
// r.next( bass ) -> BLIP_READER_NEXT( r, bass )
// r.next() -> BLIP_READER_NEXT( r, blip_reader_default_bass )
// r.end( buf ) -> BLIP_READER_END( r, buf )
class Blip_Reader {
public:
int begin( Blip_Buffer& );
blip_long read() const { return accum >> (blip_sample_bits - 16); }
blip_long read_raw() const { return accum; }
void next( int bass_shift = 9 ) { accum += *buf++ - (accum >> bass_shift); }
void end( Blip_Buffer& b ) { b.reader_accum_ = accum; }
private:
const Blip_Buffer::buf_t_* buf;
blip_long accum;
};
// End of public interface
#include <assert.h>
template<int quality,int range>
blip_inline void Blip_Synth<quality,range>::offset_resampled( blip_resampled_time_t time,
int delta, Blip_Buffer* blip_buf ) const
{
// Fails if time is beyond end of Blip_Buffer, due to a bug in caller code or the
// need for a longer buffer as set by set_sample_rate().
assert( (blip_long) (time >> BLIP_BUFFER_ACCURACY) < blip_buf->buffer_size_ );
delta *= impl.delta_factor;
blip_long* BLIP_RESTRICT buf = blip_buf->buffer_ + (time >> BLIP_BUFFER_ACCURACY);
int phase = (int) (time >> (BLIP_BUFFER_ACCURACY - BLIP_PHASE_BITS) & (blip_res - 1));
#if BLIP_BUFFER_FAST
blip_long left = buf [0] + delta;
// Kind of crappy, but doing shift after multiply results in overflow.
// Alternate way of delaying multiply by delta_factor results in worse
// sub-sample resolution.
blip_long right = (delta >> BLIP_PHASE_BITS) * phase;
left -= right;
right += buf [1];
buf [0] = left;
buf [1] = right;
#else
int const fwd = (blip_widest_impulse_ - quality) / 2;
int const rev = fwd + quality - 2;
int const mid = quality / 2 - 1;
imp_t const* BLIP_RESTRICT imp = impulses + blip_res - phase;
#if defined (_M_IX86) || defined (_M_IA64) || defined (__i486__) || \
defined (__x86_64__) || defined (__ia64__) || defined (__i386__)
// straight forward implementation resulted in better code on GCC for x86
#define ADD_IMP( out, in ) \
buf [out] += (blip_long) imp [blip_res * (in)] * delta
#define BLIP_FWD( i ) {\
ADD_IMP( fwd + i, i );\
ADD_IMP( fwd + 1 + i, i + 1 );\
}
#define BLIP_REV( r ) {\
ADD_IMP( rev - r, r + 1 );\
ADD_IMP( rev + 1 - r, r );\
}
BLIP_FWD( 0 )
if ( quality > 8 ) BLIP_FWD( 2 )
if ( quality > 12 ) BLIP_FWD( 4 )
{
ADD_IMP( fwd + mid - 1, mid - 1 );
ADD_IMP( fwd + mid , mid );
imp = impulses + phase;
}
if ( quality > 12 ) BLIP_REV( 6 )
if ( quality > 8 ) BLIP_REV( 4 )
BLIP_REV( 2 )
ADD_IMP( rev , 1 );
ADD_IMP( rev + 1, 0 );
#else
// for RISC processors, help compiler by reading ahead of writes
#define BLIP_FWD( i ) {\
blip_long t0 = i0 * delta + buf [fwd + i];\
blip_long t1 = imp [blip_res * (i + 1)] * delta + buf [fwd + 1 + i];\
i0 = imp [blip_res * (i + 2)];\
buf [fwd + i] = t0;\
buf [fwd + 1 + i] = t1;\
}
#define BLIP_REV( r ) {\
blip_long t0 = i0 * delta + buf [rev - r];\
blip_long t1 = imp [blip_res * r] * delta + buf [rev + 1 - r];\
i0 = imp [blip_res * (r - 1)];\
buf [rev - r] = t0;\
buf [rev + 1 - r] = t1;\
}
blip_long i0 = *imp;
BLIP_FWD( 0 )
if ( quality > 8 ) BLIP_FWD( 2 )
if ( quality > 12 ) BLIP_FWD( 4 )
{
blip_long t0 = i0 * delta + buf [fwd + mid - 1];
blip_long t1 = imp [blip_res * mid] * delta + buf [fwd + mid ];
imp = impulses + phase;
i0 = imp [blip_res * mid];
buf [fwd + mid - 1] = t0;
buf [fwd + mid ] = t1;
}
if ( quality > 12 ) BLIP_REV( 6 )
if ( quality > 8 ) BLIP_REV( 4 )
BLIP_REV( 2 )
blip_long t0 = i0 * delta + buf [rev ];
blip_long t1 = *imp * delta + buf [rev + 1];
buf [rev ] = t0;
buf [rev + 1] = t1;
#endif
#endif
}
#undef BLIP_FWD
#undef BLIP_REV
template<int quality,int range>
#if BLIP_BUFFER_FAST
blip_inline
#endif
void Blip_Synth<quality,range>::offset( blip_time_t t, int delta, Blip_Buffer* buf ) const
{
offset_resampled( t * buf->factor_ + buf->offset_, delta, buf );
}
template<int quality,int range>
#if BLIP_BUFFER_FAST
blip_inline
#endif
void Blip_Synth<quality,range>::update( blip_time_t t, int amp )
{
int delta = amp - impl.last_amp;
impl.last_amp = amp;
offset_resampled( t * impl.buf->factor_ + impl.buf->offset_, delta, impl.buf );
}
blip_inline blip_eq_t::blip_eq_t( double t ) :
treble( t ), rolloff_freq( 0 ), sample_rate( 44100 ), cutoff_freq( 0 ) { }
blip_inline blip_eq_t::blip_eq_t( double t, long rf, long sr, long cf ) :
treble( t ), rolloff_freq( rf ), sample_rate( sr ), cutoff_freq( cf ) { }
blip_inline int Blip_Buffer::length() const { return length_; }
blip_inline long Blip_Buffer::samples_avail() const { return (long) (offset_ >> BLIP_BUFFER_ACCURACY); }
blip_inline long Blip_Buffer::sample_rate() const { return sample_rate_; }
blip_inline int Blip_Buffer::output_latency() const { return blip_widest_impulse_ / 2; }
blip_inline long Blip_Buffer::clock_rate() const { return clock_rate_; }
blip_inline void Blip_Buffer::clock_rate( long cps ) { factor_ = clock_rate_factor( clock_rate_ = cps ); }
blip_inline int Blip_Reader::begin( Blip_Buffer& blip_buf )
{
buf = blip_buf.buffer_;
accum = blip_buf.reader_accum_;
return blip_buf.bass_shift_;
}
int const blip_max_length = 0;
int const blip_default_length = 250;
#endif

View File

@ -0,0 +1,146 @@
// Blip_Buffer 0.3.0. http://www.slack.net/~ant/nes-emu/
#include "Stereo_Buffer.h"
/* Library Copyright (C) 2004 Shay Green. Blip_Buffer is free software;
you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any later version.
Stereo_Buffer is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details. You should have received a copy of the GNU General
Public License along with Stereo_Buffer; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
Stereo_Buffer::Stereo_Buffer() {
stereo_added = false;
was_stereo = false;
}
Stereo_Buffer::~Stereo_Buffer() {
}
bool Stereo_Buffer::set_sample_rate( long rate, int msec )
{
for ( int i = 0; i < buf_count; i++ ) {
if ( bufs [i].set_sample_rate( rate, msec ) )
{
return false;
}
}
return true;
}
void Stereo_Buffer::clock_rate( long rate )
{
for ( int i = 0; i < buf_count; i++ )
bufs [i].clock_rate( rate );
}
void Stereo_Buffer::bass_freq( int bass )
{
for ( unsigned i = 0; i < buf_count; i++ )
bufs [i].bass_freq( bass );
}
void Stereo_Buffer::clear()
{
stereo_added = false;
was_stereo = false;
for ( int i = 0; i < buf_count; i++ )
bufs [i].clear();
}
void Stereo_Buffer::end_frame( blip_time_t clock_count, bool stereo )
{
for ( unsigned i = 0; i < buf_count; i++ )
{
bufs [i].end_frame( clock_count );
}
stereo_added |= stereo;
}
long Stereo_Buffer::read_samples( blip_sample_t* out, long max_samples )
{
long count = bufs [0].samples_avail();
if ( count > max_samples / 2 )
count = max_samples / 2;
if ( count )
{
if ( stereo_added || was_stereo )
{
mix_stereo( out, count );
bufs [0].remove_samples( count );
bufs [1].remove_samples( count );
bufs [2].remove_samples( count );
}
else
{
mix_mono( out, count );
bufs [0].remove_samples( count );
bufs [1].remove_silence( count );
bufs [2].remove_silence( count );
}
// to do: this might miss opportunities for optimization
if ( !bufs [0].samples_avail() ) {
was_stereo = stereo_added;
stereo_added = false;
}
}
return count * 2;
}
void Stereo_Buffer::mix_stereo( blip_sample_t* out, long count )
{
Blip_Reader l_left;
Blip_Reader l_right;
Blip_Reader l_center;
l_left.begin( bufs [1] );
l_right.begin( bufs [2] );
int bass = l_center.begin( bufs [0] );
while ( count-- )
{
int c = l_center.read();
out [0] = c + l_left.read();
out [1] = c + l_right.read();
out += 2;
l_center.next( bass );
l_left.next( bass );
l_right.next( bass );
}
l_center.end( bufs [0] );
l_right.end( bufs [2] );
l_left.end( bufs [1] );
}
void Stereo_Buffer::mix_mono( blip_sample_t* out, long count )
{
Blip_Reader in;
int bass = in.begin( bufs [0] );
while ( count-- )
{
int sample = in.read();
out [0] = sample;
out [1] = sample;
out += 2;
in.next( bass );
}
in.end( bufs [0] );
}

View File

@ -0,0 +1,69 @@
// Simple stereo Blip_Buffer for sound emulators whose oscillators output
// either on the left only, center, or right only.
// Blip_Buffer 0.3.0. Copyright (C) 2003-2004 Shay Green. GNU GPL license.
#ifndef STEREO_BUFFER_H
#define STEREO_BUFFER_H
#include "Blip_Buffer.h"
class Stereo_Buffer {
public:
Stereo_Buffer();
~Stereo_Buffer();
// Same as in Blip_Buffer (see Blip_Buffer.h)
bool set_sample_rate( long, int msec = 0 );
void clock_rate( long );
void bass_freq( int );
void clear();
// Buffers to output synthesis to
Blip_Buffer* left();
Blip_Buffer* center();
Blip_Buffer* right();
// Same as in Blip_Buffer. For more efficient operation, pass false
// for was_stereo if the left and right buffers had nothing added
// to them for this frame.
void end_frame( blip_time_t, bool was_stereo = true );
// Output is stereo with channels interleved, left before right. Counts
// are in samples, *not* pairs.
long samples_avail() const;
long read_samples( blip_sample_t*, long );
private:
// noncopyable
Stereo_Buffer( const Stereo_Buffer& );
Stereo_Buffer& operator = ( const Stereo_Buffer& );
enum { buf_count = 3 };
Blip_Buffer bufs [buf_count];
bool stereo_added;
bool was_stereo;
void mix_stereo( blip_sample_t*, long );
void mix_mono( blip_sample_t*, long );
};
inline Blip_Buffer* Stereo_Buffer::left() {
return &bufs [1];
}
inline Blip_Buffer* Stereo_Buffer::center() {
return &bufs [0];
}
inline Blip_Buffer* Stereo_Buffer::right() {
return &bufs [2];
}
inline long Stereo_Buffer::samples_avail() const {
return bufs [0].samples_avail();
}
#endif

2129
lynx/susie.cpp Normal file

File diff suppressed because it is too large Load Diff

445
lynx/susie.h Normal file
View File

@ -0,0 +1,445 @@
//
// Copyright (c) 2004 K. Wilkins
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
//////////////////////////////////////////////////////////////////////////////
// Handy - An Atari Lynx Emulator //
// Copyright (c) 1996,1997 //
// K. Wilkins //
//////////////////////////////////////////////////////////////////////////////
// Susie object header file //
//////////////////////////////////////////////////////////////////////////////
// //
// This header file provides the interface definition for the Suzy class //
// which provides math and sprite support to the emulator //
// //
// K. Wilkins //
// August 1997 //
// //
//////////////////////////////////////////////////////////////////////////////
// Revision History: //
// ----------------- //
// //
// 01Aug1997 KW Document header added & class documented. //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef SUSIE_H
#define SUSIE_H
#ifdef TRACE_SUSIE
#define TRACE_SUSIE0(msg) _RPT1(_CRT_WARN,"CSusie::"msg" (Time=%012d)\n",gSystemCycleCount)
#define TRACE_SUSIE1(msg,arg1) _RPT2(_CRT_WARN,"CSusie::"msg" (Time=%012d)\n",arg1,gSystemCycleCount)
#define TRACE_SUSIE2(msg,arg1,arg2) _RPT3(_CRT_WARN,"CSusie::"msg" (Time=%012d)\n",arg1,arg2,gSystemCycleCount)
#define TRACE_SUSIE3(msg,arg1,arg2,arg3) _RPT4(_CRT_WARN,"CSusie::"msg" (Time=%012d)\n",arg1,arg2,arg3,gSystemCycleCount)
#else
#define TRACE_SUSIE0(msg)
#define TRACE_SUSIE1(msg,arg1)
#define TRACE_SUSIE2(msg,arg1,arg2)
#define TRACE_SUSIE3(msg,arg1,arg2,arg3)
#endif
class CSystem;
#define SUSIE_START 0xfc00
#define SUSIE_SIZE 0x100
#define SCREEN_WIDTH 160
#define SCREEN_HEIGHT 102
#define LINE_END 0x80
//
// Define button values
//
#define BUTTON_A 0x0001
#define BUTTON_B 0x0002
#define BUTTON_OPT2 0x0004
#define BUTTON_OPT1 0x0008
#define BUTTON_LEFT 0x0010
#define BUTTON_RIGHT 0x0020
#define BUTTON_UP 0x0040
#define BUTTON_DOWN 0x0080
#define BUTTON_PAUSE 0x0100
enum {line_error=0,line_abs_literal,line_literal,line_packed};
enum {math_finished=0,math_divide,math_multiply,math_init_divide,math_init_multiply};
enum {sprite_background_shadow=0,
sprite_background_noncollide,
sprite_boundary_shadow,
sprite_boundary,
sprite_normal,
sprite_noncollide,
sprite_xor_shadow,
sprite_shadow};
typedef struct
{
union
{
struct
{
#ifdef MSB_FIRST
uint8 Fc1:1;
uint8 Fc2:1;
uint8 Fc3:1;
uint8 reserved:1;
uint8 Ac1:1;
uint8 Ac2:1;
uint8 Ac3:1;
uint8 Ac4:1;
#else
uint8 Ac4:1;
uint8 Ac3:1;
uint8 Ac2:1;
uint8 Ac1:1;
uint8 reserved:1;
uint8 Fc3:1;
uint8 Fc2:1;
uint8 Fc1:1;
#endif
}Bits;
uint8 Byte;
};
}TSPRINIT;
typedef struct
{
union
{
struct
{
#ifdef MSB_FIRST
uint8 Up:1;
uint8 Down:1;
uint8 Left:1;
uint8 Right:1;
uint8 Option1:1;
uint8 Option2:1;
uint8 Inside:1;
uint8 Outside:1;
#else
uint8 Outside:1;
uint8 Inside:1;
uint8 Option2:1;
uint8 Option1:1;
uint8 Right:1;
uint8 Left:1;
uint8 Down:1;
uint8 Up:1;
#endif
}Bits;
uint8 Byte;
};
}TJOYSTICK;
typedef struct
{
union
{
struct
{
#ifdef MSB_FIRST
uint8 spare:5;
uint8 Cart1IO:1;
uint8 Cart0IO:1;
uint8 Pause:1;
#else
uint8 Pause:1;
uint8 Cart0IO:1;
uint8 Cart1IO:1;
uint8 spare:5;
#endif
}Bits;
uint8 Byte;
};
}TSWITCHES;
typedef struct
{
union
{
struct
{
#ifdef MSB_FIRST
uint8 A;
uint8 B;
uint8 C;
uint8 D;
#else
uint8 D;
uint8 C;
uint8 B;
uint8 A;
#endif
}Bytes;
struct
{
#ifdef MSB_FIRST
uint16 AB;
uint16 CD;
#else
uint16 CD;
uint16 AB;
#endif
}Words;
uint32 Long;
};
}TMATHABCD;
typedef struct
{
union
{
struct
{
#ifdef MSB_FIRST
uint8 E;
uint8 F;
uint8 G;
uint8 H;
#else
uint8 H;
uint8 G;
uint8 F;
uint8 E;
#endif
}Bytes;
struct
{
#ifdef MSB_FIRST
uint16 EF;
uint16 GH;
#else
uint16 GH;
uint16 EF;
#endif
}Words;
uint32 Long;
};
}TMATHEFGH;
typedef struct
{
union
{
struct
{
#ifdef MSB_FIRST
uint8 J;
uint8 K;
uint8 L;
uint8 M;
#else
uint8 M;
uint8 L;
uint8 K;
uint8 J;
#endif
}Bytes;
struct
{
#ifdef MSB_FIRST
uint16 JK;
uint16 LM;
#else
uint16 LM;
uint16 JK;
#endif
}Words;
uint32 Long;
};
}TMATHJKLM;
typedef struct
{
union
{
struct
{
#ifdef MSB_FIRST
uint8 xx2;
uint8 xx1;
uint8 N;
uint8 P;
#else
uint8 P;
uint8 N;
uint8 xx1;
uint8 xx2;
#endif
}Bytes;
struct
{
#ifdef MSB_FIRST
uint16 xx1;
uint16 NP;
#else
uint16 NP;
uint16 xx1;
#endif
}Words;
uint32 Long;
};
}TMATHNP;
class CSusie : public CLynxBase
{
public:
CSusie(CSystem& parent) MDFN_COLD;
~CSusie() MDFN_COLD;
void Reset(void) MDFN_COLD;
uint8 Peek(uint32 addr);
void Poke(uint32 addr,uint8 data);
uint32 ReadCycle(void) {return 9;};
uint32 WriteCycle(void) {return 5;};
uint32 ObjectSize(void) {return SUSIE_SIZE;};
void SetButtonData(uint32 data) {mJOYSTICK.Byte=(uint8)data;mSWITCHES.Byte=(uint8)(data>>8);};
uint32 GetButtonData(void) {return mJOYSTICK.Byte+(mSWITCHES.Byte<<8);};
uint32 PaintSprites(void);
private:
void DoMathDivide(void);
void DoMathMultiply(void);
uint32 LineInit(uint32 voff);
uint32 LineGetPixel(void);
uint32 LineGetBits(uint32 bits);
void ProcessPixel(uint32 hoff,uint32 pixel);
void WritePixel(uint32 hoff,uint32 pixel);
uint32 ReadPixel(uint32 hoff);
void WriteCollision(uint32 hoff,uint32 pixel);
uint32 ReadCollision(uint32 hoff);
private:
CSystem& mSystem;
uint32 cycles_used;
Uuint16 mTMPADR; // ENG
Uuint16 mTILTACUM; // ENG
Uuint16 mHOFF; // CPU
Uuint16 mVOFF; // CPU
Uuint16 mVIDBAS; // CPU
Uuint16 mCOLLBAS; // CPU
Uuint16 mVIDADR; // ENG
Uuint16 mCOLLADR; // ENG
Uuint16 mSCBNEXT; // SCB
Uuint16 mSPRDLINE; // SCB
Uuint16 mHPOSSTRT; // SCB
Uuint16 mVPOSSTRT; // SCB
Uuint16 mSPRHSIZ; // SCB
Uuint16 mSPRVSIZ; // SCB
Uuint16 mSTRETCH; // ENG
Uuint16 mTILT; // ENG
Uuint16 mSPRDOFF; // ENG
Uuint16 mSPRVPOS; // ENG
Uuint16 mCOLLOFF; // CPU
Uuint16 mVSIZACUM; // ENG
Uuint16 mHSIZACUM; // K.s creation
Uuint16 mHSIZOFF; // CPU
Uuint16 mVSIZOFF; // CPU
Uuint16 mSCBADR; // ENG
Uuint16 mPROCADR; // ENG
TMATHABCD mMATHABCD; // ENG
TMATHEFGH mMATHEFGH; // ENG
TMATHJKLM mMATHJKLM; // ENG
TMATHNP mMATHNP; // ENG
int mMATHAB_sign;
int mMATHCD_sign;
int mMATHEFGH_sign;
int mSPRCTL0_Type; // SCB
int mSPRCTL0_Vflip;
int mSPRCTL0_Hflip;
int mSPRCTL0_PixelBits;
int mSPRCTL1_StartLeft; // SCB
int mSPRCTL1_StartUp;
int mSPRCTL1_SkipSprite;
int mSPRCTL1_ReloadPalette;
int mSPRCTL1_ReloadDepth;
int mSPRCTL1_Sizing;
int mSPRCTL1_Literal;
int mSPRCOLL_Number; //CPU
int mSPRCOLL_Collide;
int mSPRSYS_StopOnCurrent; //CPU
int mSPRSYS_LeftHand;
int mSPRSYS_VStretch;
int mSPRSYS_NoCollide;
int mSPRSYS_Accumulate;
int mSPRSYS_SignedMath;
int mSPRSYS_Status;
int mSPRSYS_UnsafeAccess;
int mSPRSYS_LastCarry;
int mSPRSYS_Mathbit;
int mSPRSYS_MathInProgress;
uint32 mSUZYBUSEN; // CPU
TSPRINIT mSPRINIT; // CPU
uint32 mSPRGO; // CPU
int mEVERON;
uint8 mPenIndex[16]; // SCB
// Line rendering related variables
uint32 mLineType;
uint32 mLineShiftRegCount;
uint32 mLineShiftReg;
uint32 mLineRepeatCount;
uint32 mLinePixel;
uint32 mLinePacketBitsLeft;
int mCollision;
uint8 *mRamPointer;
uint32 mLineBaseAddress;
uint32 mLineCollisionAddress;
int hquadoff, vquadoff;
// Joystick switches
TJOYSTICK mJOYSTICK;
TSWITCHES mSWITCHES;
};
#endif

73
lynx/sysbase.h Normal file
View File

@ -0,0 +1,73 @@
//
// Copyright (c) 2004 K. Wilkins
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
//////////////////////////////////////////////////////////////////////////////
// Handy - An Atari Lynx Emulator //
// Copyright (c) 1996,1997 //
// K. Wilkins //
//////////////////////////////////////////////////////////////////////////////
// Systembase object class definition //
//////////////////////////////////////////////////////////////////////////////
// //
// This header file provides the interface definition for the systembase //
// class that is required to get around cross dependencies between //
// cpu/mikie/system classes //
// //
// K. Wilkins //
// August 1997 //
// //
//////////////////////////////////////////////////////////////////////////////
// Revision History: //
// ----------------- //
// //
// 01Aug1997 KW Document header added & class documented. //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef SYSBASE_H
#define SYSBASE_H
class CSystemBase
{
// Function members
public:
virtual ~CSystemBase() {};
public:
virtual void Reset()=0;
virtual void Poke_CPU(uint32 addr,uint8 data)=0;
virtual uint8 Peek_CPU(uint32 addr)=0;
virtual void PokeW_CPU(uint32 addr,uint16 data)=0;
virtual uint16 PeekW_CPU(uint32 addr)=0;
virtual void Poke_RAM(uint32 addr,uint8 data)=0;
virtual uint8 Peek_RAM(uint32 addr)=0;
virtual void PokeW_RAM(uint32 addr,uint16 data)=0;
virtual uint16 PeekW_RAM(uint32 addr)=0;
virtual uint8* GetRamPointer()=0;
};
#endif

264
lynx/system.cpp Normal file
View File

@ -0,0 +1,264 @@
//
// Copyright (c) 2004 K. Wilkins
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
//////////////////////////////////////////////////////////////////////////////
// Handy - An Atari Lynx Emulator //
// Copyright (c) 1996,1997 //
// K. Wilkins //
//////////////////////////////////////////////////////////////////////////////
// System object class //
//////////////////////////////////////////////////////////////////////////////
// //
// This class provides the glue to bind of of the emulation objects //
// together via peek/poke handlers and pass thru interfaces to lower //
// objects, all control of the emulator is done via this class. Update() //
// does most of the work and each call emulates one CPU instruction and //
// updates all of the relevant hardware if required. It must be remembered //
// that if that instruction involves setting SPRGO then, it will cause a //
// sprite painting operation and then a corresponding update of all of the //
// hardware which will usually involve recursive calls to Update, see //
// Mikey SPRGO code for more details. //
// //
// K. Wilkins //
// August 1997 //
// //
//////////////////////////////////////////////////////////////////////////////
// Revision History: //
// ----------------- //
// //
// 01Aug1997 KW Document header added & class documented. //
// //
//////////////////////////////////////////////////////////////////////////////
#define SYSTEM_CPP
//#include <crtdbg.h>
//#define TRACE_SYSTEM
#include "system.h"
CSystem::CSystem(const uint8 *game, uint32 gamesize, const uint8 *bios, uint32 biossize, int pagesize0, int pagesize1, bool lowpass)
{
// load lynxboot.img
mRom = new CRom(bios, biossize);
mCart = new CCart(game, gamesize, pagesize0, pagesize1);
mRam = new CRam();
mMikie = new CMikie(*this);
mSusie = new CSusie(*this);
// Instantiate the memory map handler
mMemMap = new CMemMap(*this);
// Now the handlers are set we can instantiate the CPU as is will use handlers on reset
mCpu = new C65C02(*this);
mMikie->mikbuf.set_sample_rate(44100, 60);
mMikie->mikbuf.clock_rate((long int)(16000000 / 4));
mMikie->mikbuf.bass_freq(60);
mMikie->miksynth.volume(0.50);
mMikie->miksynth.treble_eq(lowpass ? -35 : 0);
// Now init is complete do a reset, this will cause many things to be reset twice
Reset();
}
CSystem::~CSystem()
{
delete mCart;
delete mRom;
delete mRam;
delete mCpu;
delete mMikie;
delete mSusie;
delete mMemMap;
}
void CSystem::Reset()
{
gSystemCycleCount=0;
gNextTimerEvent=0;
// gCPUBootAddress=0;
gSystemIRQ=FALSE;
gSystemNMI=FALSE;
gSystemCPUSleep=FALSE;
gSystemHalt=FALSE;
gSuzieDoneTime = 0;
mMemMap->Reset();
mCart->Reset();
mRom->Reset();
mRam->Reset();
mMikie->Reset();
mSusie->Reset();
mCpu->Reset();
}
/*
static int Load(MDFNFILE *fp)
{
try
{
lynxie = new CSystem(fp->data, fp->size);
switch(lynxie->CartGetRotate())
{
case CART_ROTATE_LEFT:
MDFNGameInfo->rotated = MDFN_ROTATE270;
break;
case CART_ROTATE_RIGHT:
MDFNGameInfo->rotated = MDFN_ROTATE90;
break;
}
memcpy(MDFNGameInfo->MD5, lynxie->mCart->MD5, 16);
MDFNGameInfo->GameSetMD5Valid = FALSE;
MDFN_printf(_("ROM: %dKiB\n"), (lynxie->mCart->InfoROMSize + 1023) / 1024);
MDFN_printf(_("ROM CRC32: 0x%08x\n"), lynxie->mCart->CRC32());
MDFN_printf(_("ROM MD5: 0x%s\n"), md5_context::asciistr(MDFNGameInfo->MD5, 0).c_str());
MDFNGameInfo->fps = (uint32)(59.8 * 65536 * 256);
if(MDFN_GetSettingB("lynx.lowpass"))
{
lynxie->mMikie->miksynth.treble_eq(-35);
}
else
{
lynxie->mMikie->miksynth.treble_eq(0);
}
}
*/
void CSystem::Advance(int buttons, uint32 *vbuff, int16 *sbuff, int &sbuffsize)
{
// this check needs to occur at least once every 250 million cycles or better
mMikie->CheckWrap();
SetButtonData(buttons);
uint32 start = gSystemCycleCount;
// audio start frame
mMikie->startTS = start;
mMikie->mpDisplayCurrent = vbuff;
// go to next frame end, or no more than 200,000 cycles to avoid exploding the output buffer (was set at 60ms limit)
while (mMikie->mpDisplayCurrent && gSystemCycleCount - start < 200000)
// while (gSystemCycleCount - start < 700000) // what's the magic significance?
{
Update();
}
// total cycles executed is now gSystemCycleCount - start
mMikie->mikbuf.end_frame((gSystemCycleCount - start) >> 2);
sbuffsize = mMikie->mikbuf.read_samples(sbuff, sbuffsize) / 2;
}
/*
static MDFNSetting LynxSettings[] =
{
{ "lynx.rotateinput", MDFNSF_NOFLAGS, gettext_noop("Virtually rotate D-pad along with screen."), NULL, MDFNST_BOOL, "1" },
{ "lynx.lowpass", MDFNSF_CAT_SOUND, gettext_noop("Enable sound output lowpass filter."), NULL, MDFNST_BOOL, "1" },
{ NULL }
};
*/
/*
static const InputDeviceInputInfoStruct IDII[] =
{
{ "a", "A (outer)", 8, IDIT_BUTTON_CAN_RAPID, NULL },
{ "b", "B (inner)", 7, IDIT_BUTTON_CAN_RAPID, NULL },
{ "option_2", "Option 2 (lower)", 5, IDIT_BUTTON_CAN_RAPID, NULL },
{ "option_1", "Option 1 (upper)", 4, IDIT_BUTTON_CAN_RAPID, NULL },
{ "left", "LEFT ←", 2, IDIT_BUTTON, "right", { "up", "right", "down" } },
{ "right", "RIGHT →", 3, IDIT_BUTTON, "left", { "down", "left", "up" } },
{ "up", "UP ↑", 0, IDIT_BUTTON, "down", { "right", "down", "left" } },
{ "down", "DOWN ↓", 1, IDIT_BUTTON, "up", { "left", "up", "right" } },
{ "pause", "PAUSE", 6, IDIT_BUTTON, NULL },
};
*/
/*
static const FileExtensionSpecStruct KnownExtensions[] =
{
{ ".lnx", gettext_noop("Atari Lynx ROM Image") },
{ NULL, NULL }
};
*/
/*
MDFNGI EmulatedLynx =
{
"lynx",
"Atari Lynx",
KnownExtensions,
MODPRIO_INTERNAL_HIGH,
NULL,
&InputInfo,
Load,
TestMagic,
NULL,
NULL,
CloseGame,
SetLayerEnableMask,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
false,
StateAction,
Emulate,
SetInput,
DoSimpleCommand,
LynxSettings,
MDFN_MASTERCLOCK_FIXED(16000000),
0,
false, // Multires possible?
160, // lcm_width
102, // lcm_height
NULL, // Dummy
160, // Nominal width
102, // Nominal height
160, // Framebuffer width
102, // Framebuffer height
2, // Number of output sound channels
};
*/

220
lynx/system.h Normal file
View File

@ -0,0 +1,220 @@
//
// Copyright (c) 2004 K. Wilkins
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
//////////////////////////////////////////////////////////////////////////////
// Handy - An Atari Lynx Emulator //
// Copyright (c) 1996,1997 //
// K. Wilkins //
//////////////////////////////////////////////////////////////////////////////
// System object header file //
//////////////////////////////////////////////////////////////////////////////
// //
// This header file provides the interface definition and inline code for //
// the system object, this object if what binds together all of the Handy //
// hardware enmulation objects, its the glue that holds the system together //
// //
// K. Wilkins //
// August 1997 //
// //
//////////////////////////////////////////////////////////////////////////////
// Revision History: //
// ----------------- //
// //
// 01Aug1997 KW Document header added & class documented. //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef SYSTEM_H
#define SYSTEM_H
#include "machine.h"
#include <string>
#define HANDY_SYSTEM_FREQ 16000000
#define HANDY_TIMER_FREQ 20
#define HANDY_FILETYPE_LNX 0
#define HANDY_FILETYPE_HOMEBREW 1
#define HANDY_FILETYPE_SNAPSHOT 2
#define HANDY_FILETYPE_ILLEGAL 3
#define HANDY_SCREEN_WIDTH 160
#define HANDY_SCREEN_HEIGHT 102
//
// Define the global variable list
//
/*
#ifdef SYSTEM_CPP
uint32 gSuzieDoneTime = 0;
uint32 gSystemCycleCount=0;
uint32 gNextTimerEvent=0;
uint32 gCPUBootAddress=0;
uint32 gSystemIRQ=FALSE;
uint32 gSystemNMI=FALSE;
uint32 gSystemCPUSleep=FALSE;
uint32 gSystemHalt=FALSE;
#else
extern uint32 gSystemCycleCount;
extern uint32 gSuzieDoneTime;
extern uint32 gNextTimerEvent;
extern uint32 gCPUBootAddress;
extern uint32 gSystemIRQ;
extern uint32 gSystemNMI;
extern uint32 gSystemCPUSleep;
extern uint32 gSystemHalt;
#endif
*/
//
// Define the interfaces before we start pulling in the classes
// as many classes look for articles from the interfaces to
// allow compilation
#include "sysbase.h"
class CSystem;
//
// Now pull in the parts that build the system
//
#include "lynxbase.h"
#include "ram.h"
#include "rom.h"
#include "memmap.h"
#include "cart.h"
#include "susie.h"
#include "mikie.h"
#include "c65c02.h"
#define TOP_START 0xfc00
#define TOP_MASK 0x03ff
#define TOP_SIZE 0x400
#define SYSTEM_SIZE 65536
class CSystem : public CSystemBase
{
public:
CSystem(const uint8 *, uint32, const uint8*, uint32, int, int, bool) MDFN_COLD;
~CSystem() MDFN_COLD;
public:
void Reset() MDFN_COLD;
inline void Update()
{
// Only update if there is a predicted timer event
if(gSystemCycleCount>=gNextTimerEvent)
{
mMikie->Update();
}
// Step the processor through 1 instruction
mCpu->Update();
// If the CPU is asleep then skip to the next timer event
if(gSystemCPUSleep)
{
gSystemCycleCount=gNextTimerEvent;
}
}
void Advance(int buttons, uint32 *vbuff, int16 *sbuff, int &sbuffsize);
//
// We MUST have separate CPU & RAM peek & poke handlers as all CPU accesses must
// go thru the address generator at $FFF9
//
// BUT, Mikie video refresh & Susie see the whole system as RAM
//
// Complete and utter wankers, its taken me 1 week to find the 2 lines
// in all the documentation that mention this fact, the mother of all
// bugs has been found and FIXED.......
// CPU
inline void Poke_CPU(uint32 addr, uint8 data) { mMemoryHandlers[addr]->Poke(addr,data);};
inline uint8 Peek_CPU(uint32 addr) { return mMemoryHandlers[addr]->Peek(addr);};
inline void PokeW_CPU(uint32 addr,uint16 data) { mMemoryHandlers[addr]->Poke(addr,data&0xff);addr++;mMemoryHandlers[addr]->Poke(addr,data>>8);};
inline uint16 PeekW_CPU(uint32 addr) {return ((mMemoryHandlers[addr]->Peek(addr))+(mMemoryHandlers[addr]->Peek(addr+1)<<8));};
// RAM
inline void Poke_RAM(uint32 addr, uint8 data) { mRam->Poke(addr,data);};
inline uint8 Peek_RAM(uint32 addr) { return mRam->Peek(addr);};
inline void PokeW_RAM(uint32 addr,uint16 data) { mRam->Poke(addr,data&0xff);addr++;mRam->Poke(addr,data>>8);};
inline uint16 PeekW_RAM(uint32 addr) {return ((mRam->Peek(addr))+(mRam->Peek(addr+1)<<8));};
// High level cart access for debug etc
inline void Poke_CART(uint32 addr, uint8 data) {mCart->Poke(addr,data);};
inline uint8 Peek_CART(uint32 addr) {return mCart->Peek(addr);};
inline void CartBank(EMMODE bank) {mCart->BankSelect(bank);};
inline uint32 CartSize() {return mCart->ObjectSize();};
// Low level cart access for Suzy, Mikey
inline void Poke_CARTB0(uint8 data) {mCart->Poke0(data);};
inline void Poke_CARTB1(uint8 data) {mCart->Poke1(data);};
inline uint8 Peek_CARTB0() {return mCart->Peek0();}
inline uint8 Peek_CARTB1() {return mCart->Peek1();}
inline void CartAddressStrobe(bool strobe) {mCart->CartAddressStrobe(strobe);};
inline void CartAddressData(bool data) {mCart->CartAddressData(data);};
// Low level CPU access
void SetRegs(C6502_REGS &regs) {mCpu->SetRegs(regs);};
void GetRegs(C6502_REGS &regs) {mCpu->GetRegs(regs);};
// Mikey system interfacing
void ComLynxCable(int status) { mMikie->ComLynxCable(status); };
void ComLynxRxData(int data) { mMikie->ComLynxRxData(data); };
void ComLynxTxCallback(void (*function)(int data,uint32 objref),uint32 objref) { mMikie->ComLynxTxCallback(function,objref); };
// Suzy system interfacing
uint32 PaintSprites() {return mSusie->PaintSprites();};
// Miscellaneous
void SetButtonData(uint32 data) {mSusie->SetButtonData(data);};
uint32 GetButtonData() {return mSusie->GetButtonData();};
void SetCycleBreakpoint(uint32 breakpoint) {mCycleCountBreakpoint=breakpoint;};
uint8* GetRamPointer() {return mRam->GetRamPointer();};
public:
uint32 mCycleCountBreakpoint;
CLynxBase *mMemoryHandlers[SYSTEM_SIZE];
CCart *mCart;
CRom *mRom;
CMemMap *mMemMap;
CRam *mRam;
C65C02 *mCpu;
CMikie *mMikie;
CSusie *mSusie;
// old globals
uint32 gSuzieDoneTime;
uint32 gSystemCycleCount;
uint32 gNextTimerEvent;
//uint32 gCPUBootAddress;
uint32 gSystemIRQ;
uint32 gSystemNMI;
uint32 gSystemCPUSleep;
uint32 gSystemHalt;
};
#endif