mirror of https://github.com/stella-emu/stella.git
Merge branch 'feature-moviecart' of git://github.com/lodefmode/stella into feature/lodefmode-moviecart
This commit is contained in:
commit
8873ffd0b7
|
@ -140,6 +140,7 @@ Bankswitch::BSList = {{
|
||||||
{ "FC" , "FC (32K Amiga)" },
|
{ "FC" , "FC (32K Amiga)" },
|
||||||
{ "FE" , "FE (8K Decathlon)" },
|
{ "FE" , "FE (8K Decathlon)" },
|
||||||
{ "MDM" , "MDM (Menu Driven Megacart)" },
|
{ "MDM" , "MDM (Menu Driven Megacart)" },
|
||||||
|
{ "MVC" , "MVC (Movie Cart)" },
|
||||||
{ "SB" , "SB (128-256K SUPERbank)" },
|
{ "SB" , "SB (128-256K SUPERbank)" },
|
||||||
{ "TVBOY" , "TV Boy (512K)" },
|
{ "TVBOY" , "TV Boy (512K)" },
|
||||||
{ "UA" , "UA (8K UA Ltd.)" },
|
{ "UA" , "UA (8K UA Ltd.)" },
|
||||||
|
@ -226,6 +227,7 @@ Bankswitch::ExtensionMap Bankswitch::ourExtensions = {
|
||||||
{ "FC" , Bankswitch::Type::_FC },
|
{ "FC" , Bankswitch::Type::_FC },
|
||||||
{ "FE" , Bankswitch::Type::_FE },
|
{ "FE" , Bankswitch::Type::_FE },
|
||||||
{ "MDM" , Bankswitch::Type::_MDM },
|
{ "MDM" , Bankswitch::Type::_MDM },
|
||||||
|
{ "MVC" , Bankswitch::Type::_MVC },
|
||||||
{ "SB" , Bankswitch::Type::_SB },
|
{ "SB" , Bankswitch::Type::_SB },
|
||||||
{ "TVB" , Bankswitch::Type::_TVBOY },
|
{ "TVB" , Bankswitch::Type::_TVBOY },
|
||||||
{ "TVBOY" , Bankswitch::Type::_TVBOY },
|
{ "TVBOY" , Bankswitch::Type::_TVBOY },
|
||||||
|
@ -284,6 +286,7 @@ Bankswitch::NameToTypeMap Bankswitch::ourNameToTypes = {
|
||||||
{ "FC" , Bankswitch::Type::_FC },
|
{ "FC" , Bankswitch::Type::_FC },
|
||||||
{ "FE" , Bankswitch::Type::_FE },
|
{ "FE" , Bankswitch::Type::_FE },
|
||||||
{ "MDM" , Bankswitch::Type::_MDM },
|
{ "MDM" , Bankswitch::Type::_MDM },
|
||||||
|
{ "MVC" , Bankswitch::Type::_MVC },
|
||||||
{ "SB" , Bankswitch::Type::_SB },
|
{ "SB" , Bankswitch::Type::_SB },
|
||||||
{ "TVBOY" , Bankswitch::Type::_TVBOY },
|
{ "TVBOY" , Bankswitch::Type::_TVBOY },
|
||||||
{ "UA" , Bankswitch::Type::_UA },
|
{ "UA" , Bankswitch::Type::_UA },
|
||||||
|
|
|
@ -44,8 +44,8 @@ class Bankswitch
|
||||||
_CDF, _CM, _CTY, _CV, _DF, _DFSC, _DPC,
|
_CDF, _CM, _CTY, _CV, _DF, _DFSC, _DPC,
|
||||||
_DPCP, _E0, _E7, _E78K, _EF, _EFSC, _F0,
|
_DPCP, _E0, _E7, _E78K, _EF, _EFSC, _F0,
|
||||||
_F4, _F4SC, _F6, _F6SC, _F8, _F8SC, _FA,
|
_F4, _F4SC, _F6, _F6SC, _F8, _F8SC, _FA,
|
||||||
_FA2, _FC, _FE, _MDM, _SB, _TVBOY, _UA,
|
_FA2, _FC, _FE, _MDM, _MVC, _SB, _TVBOY,
|
||||||
_UASW, _WD, _WDSW, _X07,
|
_UA, _UASW, _WD, _WDSW, _X07,
|
||||||
#ifdef CUSTOM_ARM
|
#ifdef CUSTOM_ARM
|
||||||
_CUSTOM,
|
_CUSTOM,
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
#include "CartFC.hxx"
|
#include "CartFC.hxx"
|
||||||
#include "CartFE.hxx"
|
#include "CartFE.hxx"
|
||||||
#include "CartMDM.hxx"
|
#include "CartMDM.hxx"
|
||||||
|
#include "CartMVC.hxx"
|
||||||
#include "CartSB.hxx"
|
#include "CartSB.hxx"
|
||||||
#include "CartTVBoy.hxx"
|
#include "CartTVBoy.hxx"
|
||||||
#include "CartUA.hxx"
|
#include "CartUA.hxx"
|
||||||
|
@ -197,6 +198,10 @@ unique_ptr<Cartridge> CartCreator::create(const FilesystemNode& file,
|
||||||
Bankswitch::typeToName(type) + "'");
|
Bankswitch::typeToName(type) + "'");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Bankswitch::Type::_MVC:
|
||||||
|
cartridge = make_unique<CartridgeMVC>(file.getPath(), size, md5, settings);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
cartridge = createFromImage(image, size, detectedType, md5, settings);
|
cartridge = createFromImage(image, size, detectedType, md5, settings);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "Logger.hxx"
|
#include "Logger.hxx"
|
||||||
|
|
||||||
#include "CartDetector.hxx"
|
#include "CartDetector.hxx"
|
||||||
|
#include "CartMVC.hxx"
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t size)
|
Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t size)
|
||||||
|
@ -240,6 +241,8 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si
|
||||||
type = Bankswitch::Type::_3EP;
|
type = Bankswitch::Type::_3EP;
|
||||||
else if(isProbablyMDM(image, size))
|
else if(isProbablyMDM(image, size))
|
||||||
type = Bankswitch::Type::_MDM;
|
type = Bankswitch::Type::_MDM;
|
||||||
|
else if(isProbablyMVC(image, size))
|
||||||
|
type = Bankswitch::Type::_MVC;
|
||||||
|
|
||||||
// If we get here and autodetection failed, then we force '4K'
|
// If we get here and autodetection failed, then we force '4K'
|
||||||
if(type == Bankswitch::Type::_AUTO)
|
if(type == Bankswitch::Type::_AUTO)
|
||||||
|
@ -689,6 +692,38 @@ bool CartDetector::isProbablyMDM(const ByteBuffer& image, size_t size)
|
||||||
return searchForBytes(image, std::min<size_t>(size, 8_KB), mdmc, 4);
|
return searchForBytes(image, std::min<size_t>(size, 8_KB), mdmc, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool CartDetector::isProbablyMVC(const ByteBuffer& image, size_t size)
|
||||||
|
{
|
||||||
|
// MVC version 0
|
||||||
|
uInt8 sig[] = { 'M', 'V', 'C', 0 };
|
||||||
|
int sigSize = sizeof(sig);
|
||||||
|
return searchForBytes(image, std::min<size_t>(size, sigSize+1), sig, sigSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
size_t CartDetector::isProbablyMVC(std::istream &in, size_t maxSize)
|
||||||
|
{
|
||||||
|
const size_t frameSize = 2 * MVC_FIELD_PAD_SIZE;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
// Returns size of field if stream is probably an MVC movie cartridge
|
||||||
|
|
||||||
|
if (maxSize >= frameSize)
|
||||||
|
{
|
||||||
|
auto pos = in.tellg();
|
||||||
|
|
||||||
|
ByteBuffer image = make_unique<uInt8[]>(frameSize);
|
||||||
|
in.read(reinterpret_cast<char*>(image.get()), frameSize);
|
||||||
|
|
||||||
|
in.seekg(pos);
|
||||||
|
|
||||||
|
found = isProbablyMVC(image, frameSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return found ? frameSize : 0;
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool CartDetector::isProbablySB(const ByteBuffer& image, size_t size)
|
bool CartDetector::isProbablySB(const ByteBuffer& image, size_t size)
|
||||||
{
|
{
|
||||||
|
|
|
@ -40,6 +40,13 @@ class CartDetector
|
||||||
*/
|
*/
|
||||||
static Bankswitch::Type autodetectType(const ByteBuffer& image, size_t size);
|
static Bankswitch::Type autodetectType(const ByteBuffer& image, size_t size);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
MVC cartridges are of arbitary large length
|
||||||
|
Returns size of frame if stream is probably an MVC movie cartridge
|
||||||
|
*/
|
||||||
|
static size_t isProbablyMVC(std::istream &in, size_t size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
Search the image for the specified byte signature
|
Search the image for the specified byte signature
|
||||||
|
@ -189,6 +196,11 @@ class CartDetector
|
||||||
*/
|
*/
|
||||||
static bool isProbablyMDM(const ByteBuffer& image, size_t size);
|
static bool isProbablyMDM(const ByteBuffer& image, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns true if the image is probably an MVC movie cartridge
|
||||||
|
*/
|
||||||
|
static bool isProbablyMVC(const ByteBuffer& image, size_t size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns true if the image is probably a SB bankswitching cartridge
|
Returns true if the image is probably a SB bankswitching cartridge
|
||||||
*/
|
*/
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,185 @@
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// SSSS tt lll lll
|
||||||
|
// SS SS tt ll ll
|
||||||
|
// SS tttttt eeee ll ll aaaa
|
||||||
|
// SSSS tt ee ee ll ll aa
|
||||||
|
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||||
|
// SS SS tt ee ll ll aa aa
|
||||||
|
// SSSS ttt eeeee llll llll aaaaa
|
||||||
|
//
|
||||||
|
// Copyright (c) 1995-2021 by Bradford W. Mott, Stephen Anthony
|
||||||
|
// and the Stella Team
|
||||||
|
//
|
||||||
|
// See the file "License.txt" for information on usage and redistribution of
|
||||||
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
#ifndef CARTRIDGEMVC_HXX
|
||||||
|
#define CARTRIDGEMVC_HXX
|
||||||
|
|
||||||
|
class System;
|
||||||
|
class MovieCart;
|
||||||
|
|
||||||
|
#include "bspf.hxx"
|
||||||
|
#include "Cart.hxx"
|
||||||
|
|
||||||
|
/**
|
||||||
|
Implementation of MovieCart.
|
||||||
|
1K of memory is presented on the bus, but is repeated to fill the 4K image space.
|
||||||
|
Contents are dynamically altered with streaming image and audio content as specific
|
||||||
|
128-byte regions are entered.
|
||||||
|
Original implementation: github.com/lodefmode/moviecart
|
||||||
|
|
||||||
|
@author Rob Bairos
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MVC_FIELD_SIZE 2560 // round field to nearest 512 byte boundary
|
||||||
|
#define MVC_FIELD_PAD_SIZE 4096 // round to nearest 4K
|
||||||
|
|
||||||
|
class CartridgeMVC : public Cartridge
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
Create a new cartridge using the specified image
|
||||||
|
|
||||||
|
@param image Pointer to the ROM image
|
||||||
|
@param size The size of the ROM image (<= 2048 bytes)
|
||||||
|
@param md5 The md5sum of the ROM image
|
||||||
|
@param settings A reference to the various settings (read-only)
|
||||||
|
@param bsSize The size specified by the bankswitching scheme
|
||||||
|
*/
|
||||||
|
CartridgeMVC(const string& path, size_t size, const string& md5,
|
||||||
|
const Settings& settings, size_t bsSize = 2_KB);
|
||||||
|
~CartridgeMVC() override = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Reset device to its power-on state
|
||||||
|
*/
|
||||||
|
void reset() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Install cartridge in the specified system. Invoked by the system
|
||||||
|
when the cartridge is attached to it.
|
||||||
|
|
||||||
|
@param system The system the device should install itself in
|
||||||
|
*/
|
||||||
|
void install(System& system) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Access the internal ROM image for this cartridge.
|
||||||
|
|
||||||
|
@param size Set to the size of the internal ROM image data
|
||||||
|
@return A reference to the internal ROM image data
|
||||||
|
*/
|
||||||
|
virtual const ByteBuffer& getImage(size_t& size) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Patch the cartridge ROM.
|
||||||
|
|
||||||
|
@param address The ROM address to patch
|
||||||
|
@param value The value to place into the address
|
||||||
|
@return Success or failure of the patch operation
|
||||||
|
*/
|
||||||
|
virtual bool patch(uInt16 address, uInt8 value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get the byte at the specified address.
|
||||||
|
|
||||||
|
@return The byte at the specified address
|
||||||
|
*/
|
||||||
|
uInt8 peek(uInt16 address) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Change the byte at the specified address to the given value
|
||||||
|
|
||||||
|
@param address The address where the value should be stored
|
||||||
|
@param value The value to be stored at the address
|
||||||
|
@return True if the poke changed the device address space, else false
|
||||||
|
*/
|
||||||
|
bool poke(uInt16 address, uInt8 value) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get a descriptor for the device name (used in error checking).
|
||||||
|
|
||||||
|
@return The name of the object
|
||||||
|
*/
|
||||||
|
string name() const override { return "CartridgeMVC"; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
Save the current state of this cart to the given Serializer.
|
||||||
|
|
||||||
|
@param out The Serializer object to use
|
||||||
|
@return False on any errors, else true
|
||||||
|
*/
|
||||||
|
bool save(Serializer& out) const override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Load the current state of this cart from the given Serializer.
|
||||||
|
|
||||||
|
@param in The Serializer object to use
|
||||||
|
@return False on any errors, else true
|
||||||
|
*/
|
||||||
|
bool load(Serializer& in) override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Install pages for the specified bank in the system.
|
||||||
|
|
||||||
|
@param bank The bank that should be installed in the system
|
||||||
|
@param segment The segment the bank should be using
|
||||||
|
|
||||||
|
@return true, if bank has changed
|
||||||
|
*/
|
||||||
|
bool bank(uInt16 bank, uInt16 segment = 0) override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get the current bank.
|
||||||
|
|
||||||
|
@param address The address to use when querying the bank
|
||||||
|
*/
|
||||||
|
uInt16 getBank(uInt16 address = 0) const override
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Query the number of banks supported by the cartridge.
|
||||||
|
*/
|
||||||
|
uInt16 romBankCount() const override
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// Currently not used:
|
||||||
|
// Pointer to a dynamically allocated ROM image of the cartridge
|
||||||
|
ByteBuffer myImage{nullptr};
|
||||||
|
size_t mySize{0};
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Following constructors and assignment operators not supported
|
||||||
|
CartridgeMVC() = delete;
|
||||||
|
CartridgeMVC(const CartridgeMVC&) = delete;
|
||||||
|
CartridgeMVC(CartridgeMVC&&) = delete;
|
||||||
|
CartridgeMVC& operator=(const CartridgeMVC&) = delete;
|
||||||
|
CartridgeMVC& operator=(CartridgeMVC&&) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
unique_ptr<MovieCart> myMovie;
|
||||||
|
string myPath;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include "FSNodeFactory.hxx"
|
#include "FSNodeFactory.hxx"
|
||||||
#include "FSNode.hxx"
|
#include "FSNode.hxx"
|
||||||
|
#include "CartDetector.hxx"
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
FilesystemNode::FilesystemNode(const AbstractFSNodePtr& realNode)
|
FilesystemNode::FilesystemNode(const AbstractFSNodePtr& realNode)
|
||||||
|
@ -355,6 +356,12 @@ size_t FilesystemNode::read(ByteBuffer& buffer) const
|
||||||
if (sizeRead == 0)
|
if (sizeRead == 0)
|
||||||
throw runtime_error("Zero-byte file");
|
throw runtime_error("Zero-byte file");
|
||||||
|
|
||||||
|
// In the case of MVC (MovieCart) files, contents are streaming data
|
||||||
|
// of arbitrary length, so just read first frame.
|
||||||
|
size_t subSize = CartDetector::isProbablyMVC(in, sizeRead);
|
||||||
|
if (subSize > 0)
|
||||||
|
sizeRead = subSize;
|
||||||
|
|
||||||
buffer = make_unique<uInt8[]>(sizeRead);
|
buffer = make_unique<uInt8[]>(sizeRead);
|
||||||
in.read(reinterpret_cast<char*>(buffer.get()), sizeRead);
|
in.read(reinterpret_cast<char*>(buffer.get()), sizeRead);
|
||||||
}
|
}
|
||||||
|
|
|
@ -753,6 +753,7 @@
|
||||||
<ClCompile Include="..\emucore\CartMDM.cxx" />
|
<ClCompile Include="..\emucore\CartMDM.cxx" />
|
||||||
<ClCompile Include="..\emucore\CartMNetwork.cxx" />
|
<ClCompile Include="..\emucore\CartMNetwork.cxx" />
|
||||||
<ClCompile Include="..\emucore\CartE78K.cxx" />
|
<ClCompile Include="..\emucore\CartE78K.cxx" />
|
||||||
|
<ClCompile Include="..\emucore\CartMVC.cxx" />
|
||||||
<ClCompile Include="..\emucore\CartTVBoy.cxx" />
|
<ClCompile Include="..\emucore\CartTVBoy.cxx" />
|
||||||
<ClCompile Include="..\emucore\CartWD.cxx" />
|
<ClCompile Include="..\emucore\CartWD.cxx" />
|
||||||
<ClCompile Include="..\emucore\CompuMate.cxx" />
|
<ClCompile Include="..\emucore\CompuMate.cxx" />
|
||||||
|
@ -1817,6 +1818,7 @@
|
||||||
<ClInclude Include="..\emucore\CartMDM.hxx" />
|
<ClInclude Include="..\emucore\CartMDM.hxx" />
|
||||||
<ClInclude Include="..\emucore\CartMNetwork.hxx" />
|
<ClInclude Include="..\emucore\CartMNetwork.hxx" />
|
||||||
<ClInclude Include="..\emucore\CartE78K.hxx" />
|
<ClInclude Include="..\emucore\CartE78K.hxx" />
|
||||||
|
<ClInclude Include="..\emucore\CartMVC.hxx" />
|
||||||
<ClInclude Include="..\emucore\CartTVBoy.hxx" />
|
<ClInclude Include="..\emucore\CartTVBoy.hxx" />
|
||||||
<ClInclude Include="..\emucore\CartWD.hxx" />
|
<ClInclude Include="..\emucore\CartWD.hxx" />
|
||||||
<ClInclude Include="..\emucore\CompuMate.hxx" />
|
<ClInclude Include="..\emucore\CompuMate.hxx" />
|
||||||
|
|
|
@ -1110,6 +1110,9 @@
|
||||||
<ClCompile Include="..\common\repository\CompositeKeyValueRepository.cxx">
|
<ClCompile Include="..\common\repository\CompositeKeyValueRepository.cxx">
|
||||||
<Filter>Source Files\repository</Filter>
|
<Filter>Source Files\repository</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\emucore\CartMVC.cxx">
|
||||||
|
<Filter>Source Files\emucore</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\common\bspf.hxx">
|
<ClInclude Include="..\common\bspf.hxx">
|
||||||
|
@ -2282,6 +2285,9 @@
|
||||||
<ClInclude Include="..\emucore\OSystemStandalone.hxx">
|
<ClInclude Include="..\emucore\OSystemStandalone.hxx">
|
||||||
<Filter>Header Files\emucore</Filter>
|
<Filter>Header Files\emucore</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\emucore\CartMVC.hxx">
|
||||||
|
<Filter>Header Files\emucore</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="stella.ico">
|
<None Include="stella.ico">
|
||||||
|
|
Loading…
Reference in New Issue