Skip to content

Commit

Permalink
wip property rework
Browse files Browse the repository at this point in the history
  • Loading branch information
gulrak committed Sep 21, 2024
1 parent 1c0d8af commit 52b1716
Show file tree
Hide file tree
Showing 12 changed files with 131 additions and 42 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.16)

project(cadmium VERSION 1.1.15 LANGUAGES C CXX)
project(cadmium VERSION 1.9.90 LANGUAGES C CXX)
cmake_policy(VERSION 3.16)

include(cmake/BuildSettings.cmake)
Expand Down
23 changes: 18 additions & 5 deletions src/emulation/chip8generic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ Properties Chip8GenericOptions::asProperties() const
result[PROP_Q_XO_CHIP_SOUND].setBool(optXOChipSound);
result[PROP_Q_EXTENDED_VBLANK].setBool(optExtendedVBlank);
result[PROP_Q_PAL_VIDEO].setBool(optPalVideo);
result.palette() = palette;
return result;
}

Expand Down Expand Up @@ -133,6 +134,7 @@ Chip8GenericOptions Chip8GenericOptions::fromProperties(const Properties& props)
opts.optXOChipSound = props[PROP_Q_XO_CHIP_SOUND].getBool();
opts.optExtendedVBlank = props[PROP_Q_EXTENDED_VBLANK].getBool();
opts.optPalVideo = props[PROP_Q_PAL_VIDEO].getBool();
opts.palette = props.palette();
return opts;
}

Expand All @@ -145,7 +147,7 @@ Properties& Chip8GenericOptions::registeredPrototype()
prototype.registerProperty({PROP_TRACE_LOG, false, "Enable trace log", eWritable});
prototype.registerProperty({PROP_INSTRUCTIONS_PER_FRAME, Property::Integer{11, 0, 1'000'000}, "Number of instructions per frame, default depends on variant", eWritable});
prototype.registerProperty({PROP_FRAME_RATE, Property::Integer{60, 50, 100}, "Number of frames per second, default 60", eWritable});
prototype.registerProperty({PROP_RAM, Property::Combo{"2048"s, "4096"s, "8192"s, "12288"s, "16384"s, "32768"s}, "Size of ram in bytes", eWritable});
prototype.registerProperty({PROP_RAM, Property::Combo{"2048"s, "4096"s, "8192"s, "16384"s, "32768"s, "65536"s, "16777216"s}, "Size of ram in bytes", eWritable});
prototype.registerProperty({PROP_START_ADDRESS, Property::Integer{0x200, 0, 0x7f0}, "Number of instructions per frame, default depends on variant", eReadOnly});
prototype.registerProperty({PROP_CLEAN_RAM, false, "Delete ram on startup", eWritable});
prototype.registerProperty({{PROP_Q_JUST_SHIFT_VX, "just-Shift-Vx"}, false, eWritable});
Expand Down Expand Up @@ -224,7 +226,9 @@ Chip8GenericSetupInfo genericPresets[] = {
"CHIP-8X",
"An official update to CHIP-8 by RCA, requiring the color extension VP-590 and the simple sound board VP-595, 1980",
".c8x",
{.behaviorBase = Chip8GenericOptions::eCHIP8X, .startAddress = 768, .optExtendedVBlank = true, .instructionsPerFrame = 18}
{.behaviorBase = Chip8GenericOptions::eCHIP8X, .startAddress = 768, .optExtendedVBlank = true, .instructionsPerFrame = 18,
.palette = {"#000080","#000000","#008000","#800000","#181818","#FF0000","#0000FF","#FF00FF","#00FF00","#FFFF00","#00FFFF","#FFFFFF","#000000","#000000","#000000","#000000"}
}
},
{
"CHIP-48",
Expand Down Expand Up @@ -260,13 +264,13 @@ Chip8GenericSetupInfo genericPresets[] = {
"MEGACHIP",
"MegaChip as specified by Martijn Wanting, Revival-Studios, 2007",
".mc8",
{.behaviorBase = Chip8GenericOptions::eMEGACHIP, .optJustShiftVx = true, .optDontResetVf = true, .optLoadStoreDontIncI = true, .optLoresDxy0Is8x16 = true, .optSC11Collision = true, .optModeChangeClear = true, .optJump0Bxnn = true, .optAllowHires = true, .instructionsPerFrame = 3000, .frameRate = 50}
{.behaviorBase = Chip8GenericOptions::eMEGACHIP, .ramSize = 0x1000000, .optJustShiftVx = true, .optDontResetVf = true, .optLoadStoreDontIncI = true, .optLoresDxy0Is8x16 = true, .optSC11Collision = true, .optModeChangeClear = true, .optJump0Bxnn = true, .optAllowHires = true, .instructionsPerFrame = 3000, .frameRate = 50}
},
{
"XO-CHIP",
"A modern extension to SUPER-CHIP supporting colors and actual sound first implemented in Octo by John Earnest, 2014",
"xo8",
{.behaviorBase = Chip8GenericOptions::eXOCHIP, .optDontResetVf = true, .optWrapSprites = true, .optInstantDxyn = true, .optLoresDxy0Is16x16 = true, .optModeChangeClear = true, .optAllowHires = true, .optAllowColors = true, .optHas16BitAddr = true, .optXOChipSound = true, .instructionsPerFrame = 1000}
{.behaviorBase = Chip8GenericOptions::eXOCHIP, .ramSize = 0x10000, .optDontResetVf = true, .optWrapSprites = true, .optInstantDxyn = true, .optLoresDxy0Is16x16 = true, .optModeChangeClear = true, .optAllowHires = true, .optAllowColors = true, .optHas16BitAddr = true, .optXOChipSound = true, .instructionsPerFrame = 1000}
}
/*{Opts::eCHIP10, R"({"optAllowHires":true,"optOnlyHires":true})"},
{Opts::eCHIP8E, R"({})"},
Expand Down Expand Up @@ -307,7 +311,7 @@ Chip8GenericEmulator::Chip8GenericEmulator(EmulatorHost& host, Properties& props
, _options(Chip8GenericOptions::fromProperties(props))
, _opcodeHandler(0x10000, &Chip8GenericEmulator::opInvalid)
{
ADDRESS_MASK = _options.behaviorBase == Chip8GenericOptions::eMEGACHIP ? 0xFFFFFF : _options.ramSize>4096 ? 0xFFFF : 0xFFF;
ADDRESS_MASK = _options.ramSize - 1; //_options.behaviorBase == Chip8GenericOptions::eMEGACHIP ? 0xFFFFFF : _options.ramSize>4096 ? 0xFFFF : 0xFFF;
SCREEN_WIDTH = _options.behaviorBase == Chip8GenericOptions::eMEGACHIP ? 256 : (_options.optAllowHires ? 128 : 64);
SCREEN_HEIGHT = _options.behaviorBase == Chip8GenericOptions::eMEGACHIP ? 192 : (_options.optAllowHires ? 64 : (_options.optPalVideo ? 48 : 32));
_memory.resize(_options.ramSize, 0);
Expand Down Expand Up @@ -419,6 +423,11 @@ void Chip8GenericEmulator::reset()
_mcPalette[254] = 0xffffffff;
}

bool Chip8GenericEmulator::loadData(std::span<const uint8_t> data, std::optional<uint32_t> loadAddress)
{
return Chip8GenericBase::loadData(data, loadAddress ? loadAddress : _options.startAddress);
}

void Chip8GenericEmulator::setHandler()
{
on(0xFFFF, 0x00E0, &Chip8GenericEmulator::op00E0);
Expand Down Expand Up @@ -691,7 +700,11 @@ void Chip8GenericEmulator::executeFrame()
do {
executeInstructions(487);
}
#ifdef PLATFORM_WEB
while(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count() < 12);
#else
while(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count() < 15);
#endif
}
else {
auto instructionsLeft = calcNextFrame() - _cycleCounter;
Expand Down
2 changes: 2 additions & 0 deletions src/emulation/chip8generic.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ struct Chip8GenericOptions
bool traceLog{false};
int instructionsPerFrame{15};
int frameRate{60};
Palette palette;
};

//---------------------------------------------------------------------------------------
Expand Down Expand Up @@ -117,6 +118,7 @@ class Chip8GenericEmulator : public Chip8GenericBase
const VideoRGBAType* getScreenRGBA() const override { return _isMegaChipMode ? _screenRGBA : nullptr; }
uint8_t getScreenAlpha() const override { return _screenAlpha; }
bool isDoublePixel() const override { return _options.behaviorBase == Chip8GenericOptions::eMEGACHIP ? false : (_options.optAllowHires && !_isHires); }
bool loadData(std::span<const uint8_t> data, std::optional<uint32_t> loadAddress) override;

uint8_t getNextMCSample();

Expand Down
2 changes: 2 additions & 0 deletions src/emulation/chip8strict.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Properties Chip8StrictOptions::asProperties() const
result[PROP_CLOCK].setInt(clockFrequency);
result[PROP_RAM].setSelectedText(std::to_string(ramSize)); // !!!!
result[PROP_CLEAN_RAM].setBool(cleanRam);
result.palette() = palette;
return result;
}

Expand All @@ -30,6 +31,7 @@ Chip8StrictOptions Chip8StrictOptions::fromProperties(const Properties& props)
opts.clockFrequency = props[PROP_CLOCK].getInt();
opts.ramSize = std::stoul(props[PROP_RAM].getSelectedText()); // !!!!
opts.cleanRam = props[PROP_CLEAN_RAM].getBool();
opts.palette = props.palette();
return opts;
}

Expand Down
9 changes: 5 additions & 4 deletions src/emulation/chip8strict.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ struct Chip8StrictOptions {
Properties asProperties() const;
static Chip8StrictOptions fromProperties(const Properties& props);
static Properties& registeredPrototype();
int clockFrequency;
size_t ramSize;
bool cleanRam;
bool traceLog;
int clockFrequency{};
size_t ramSize{};
bool cleanRam{};
bool traceLog{};
Palette palette;
};

class Chip8StrictEmulator : public Chip8GenericBase
Expand Down
17 changes: 9 additions & 8 deletions src/emulation/coreregistry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,15 @@ class CoreRegistry {
}
std::pair<std::string, EmulatorInstance> createCore(EmulatorHost& host, Properties& props) const override
{
std::string variant = prefix().empty() ? "CUSTOM" : prefix() + "-CUSTOM";
for(const auto& setupInfo : presets) {
if(props == setupInfo.options.asProperties()) {
if(prefix().empty())
variant = setupInfo.presetName;
else
variant = !std::strcmp(setupInfo.presetName, "NONE") ? prefix() : prefix() + "-" + setupInfo.presetName;
}
std::string variant;
auto idx = variantIndex(props);
const auto& info = presets[idx.index];
if(prefix().empty())
variant = info.presetName;
else
variant = !std::strcmp(info.presetName, "NONE") ? prefix() : prefix() + "-" + info.presetName;
if(props != info.options.asProperties()) {
variant += "*";
}
auto options = OptionsType::fromProperties(props);
return {variant, std::make_unique<CoreType>(host, props)};
Expand Down
13 changes: 10 additions & 3 deletions src/emulation/cosmacvip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ struct CosmacVIPOptions
result[PROP_ROM_NAME].setString(romName);
result[PROP_INTERPRETER].setSelectedIndex(toType(interpreter));
result[PROP_START_ADDRESS].setInt(startAddress);
result.palette() = palette;
return result;
}
static CosmacVIPOptions fromProperties(const Properties& props)
Expand All @@ -67,6 +68,7 @@ struct CosmacVIPOptions
opts.romName = props[PROP_ROM_NAME].getString();
opts.interpreter = static_cast<VIPChip8Interpreter>(props[PROP_INTERPRETER].getSelectedIndex());
opts.startAddress = props[PROP_START_ADDRESS].getInt();
opts.palette = props.palette();
return opts;
}
static Properties& registeredPrototype()
Expand Down Expand Up @@ -100,6 +102,7 @@ struct CosmacVIPOptions
std::string romName;
VIPChip8Interpreter interpreter;
uint16_t startAddress;
Palette palette;
};

struct CosmacVipSetupInfo {
Expand Down Expand Up @@ -220,7 +223,7 @@ class CosmacVIP::Private {
uint32_t _memorySize{4096};
Cdp1802 _cpu;
Cdp186x _video;
int64_t _irqStart{0};
//int64_t _irqStart{0};
int64_t _nextFrame{0};
uint8_t _keyLatch{0};
uint8_t _frequencyLatch{0};
Expand All @@ -235,7 +238,7 @@ class CosmacVIP::Private {
bool _powerOn{true};
float _wavePhase{0};
std::vector<uint8_t> _ram{};
std::array<uint8_t,1024> _colorRam{};
std::array<uint8_t,256> _colorRam{};
std::array<uint8_t,512> _rom{};
VideoType _screen;
};
Expand Down Expand Up @@ -664,7 +667,7 @@ void CosmacVIP::reset()
std::memset(_impl->_colorRam.data(), 0, _impl->_colorRam.size());
if(_isHybridChipMode) {
std::memcpy(_impl->_ram.data(), _chip8_cvip, sizeof(_chip8_cvip));
_impl->_startAddress = 0x200;
_impl->_startAddress = _impl->_options.startAddress;
_impl->_fetchEntry = 0x1B;
if (_impl->_options.interpreter != VC8I_CHIP8) {
auto size = patchRAM(_impl->_options.interpreter, _impl->_ram.data(), _impl->_ram.size());
Expand All @@ -674,6 +677,8 @@ void CosmacVIP::reset()
}
}
else {
_impl->_startAddress = 0;
_impl->_fetchEntry = 0;
_impl->_properties[PROP_INTERPRETER].setSelectedIndex(VIPChip8Interpreter::VC8I_NONE);
_impl->_properties[PROP_INTERPRETER].setAdditionalInfo("No CHIP-8 interpreter used");
}
Expand All @@ -684,8 +689,10 @@ void CosmacVIP::reset()
_frames = 0;
_impl->_nextFrame = 0;
_impl->_lastOpcode = 0;
_impl->_currentOpcode = 0;
_impl->_initialChip8SP = 0;
_impl->_frequencyLatch = 0x80;
_impl->_keyLatch = 0;
_impl->_mapRam = false;
_impl->_wavePhase = 0;
_cpuState = eNORMAL;
Expand Down
6 changes: 3 additions & 3 deletions src/emulation/hardware/cdp186x.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ const Cdp186x::VideoType& Cdp186x::getScreen() const

std::pair<int,bool> Cdp186x::executeStep()
{
auto fc = (_cpu.cycles() >> 3) % 3668;
auto fc = static_cast<int>((_cpu.cycles() >> 3) % 3668);
bool vsync = false;
if(fc < _frameCycle) {
vsync = true;
Expand Down Expand Up @@ -120,14 +120,14 @@ std::pair<int,bool> Cdp186x::executeStep()
if(lineCycle == 4 || lineCycle == 5) {
auto dmaStart = _cpu.getR(0);
auto highBits = 0;
auto mask = _type == eVP590 && _subMode != eVP590_DEFAULT ? (_subMode == eVP590_HIRES ? 0x3FF : 0x3E7) : 0;
auto mask = _type == eVP590 && _subMode != eVP590_DEFAULT ? (_subMode == eVP590_HIRES ? 0xFF : 0xE7) : 0;
if(_subMode == eVP590_DEFAULT)
highBits = 7;
for (int i = 0; i < 8; ++i) {
auto [data, addr] = _displayEnabledLatch ? _cpu.executeDMAOut() : std::make_pair((uint8_t)0, (uint16_t)0);
if(mask)
highBits = _cpu.readByteDMA(0xD000 | (addr & mask)) << 4;
// std::cout << fmt::format("{:04x}/{:04x} = {:02x}", addr, 0xD000 | (addr & mask), highBits) << std::endl;
//std::cout << fmt::format("{:04x}/{:04x} = {:02x}", addr, 0xD000 | (addr & mask), highBits) << std::endl;
for (int j = 0; j < 8; ++j) {
_screen.setPixel(i * 8 + j, (line - VIDEO_FIRST_VISIBLE_LINE), highBits | ((data >> (7 - j)) & 1));
}
Expand Down
2 changes: 1 addition & 1 deletion src/emulation/hardware/cdp186x.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class Cdp186x
Cdp1802& _cpu;
Type _type{eCDP1861};
SubMode _subMode{eNONE};
std::array<uint32_t,256> _cdp1862Palette;
std::array<uint32_t,256> _cdp1862Palette{};
VideoScreen<uint8_t,256,192> _screen;
int _frameCycle{0};
int _frameCounter{0};
Expand Down
31 changes: 30 additions & 1 deletion src/emulation/properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ namespace emu {

std::map<std::string_view,Properties> Properties::propertyRegistry{};

std::string Palette::Color::toString() const
{
return fmt::format("#{:02x}{:02x}{:02x}", r, g, b);
}


Property::Property(const std::string& name, Value val, std::string description, std::string additionalInfo, PropertyAccess access_)
: _name(name)
Expand Down Expand Up @@ -96,12 +101,15 @@ void to_json(nlohmann::json& j, const Properties& props)
[&](const emu::Property::Combo& val) { j[name] = val.selectedText(); }
}, prop.getValue());
}
if(!props.palette().empty()) {
j["palette"] = props.palette();
}
}

void from_json(const nlohmann::json& j, Properties& props)
{
if(j.is_object()) {
auto cls = j.value("class", "GenericCore");
auto cls = j.value("class", "CHIP-8 GENERIC");
props = Properties::getProperties(cls);
if(props) {
for(size_t i = 0; i < props.numProperties(); ++i) {
Expand All @@ -116,8 +124,29 @@ void from_json(const nlohmann::json& j, Properties& props)
}, prop.getValue());
}
}
if(j.contains("palette")) {
j["palette"].get_to(props.palette());
}
}
}

void to_json(nlohmann::json& j, const Palette& pal)
{
j = nlohmann::json::array();
for(const auto& c : pal.colors) {
j.push_back(c.toString());
}
}

void from_json(const nlohmann::json& j, Palette& pal)
{
if(j.is_array()) {
pal.colors.clear();
pal.colors.reserve(j.size());
for(const std::string col : j) {
pal.colors.emplace_back(col);
}
}
}

}
Loading

0 comments on commit 52b1716

Please sign in to comment.