a52: add Atari 5200 scaffold and CPU

This commit is contained in:
ZengGengSen
2026-08-20 16:37:55 +01:00
committed by Luke Usher
parent a840e6427e
commit e5d619c238
34 changed files with 912 additions and 1 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ add_subdirectory(hiro)
# gersemi: off
set(
ARES_CORES
a26 fc sfc sg ms md ps1 pce ng msx cv myvision gb gba ws ngp spec n64
a26 a52 fc sfc sg ms md ps1 pce ng msx cv myvision gb gba ws ngp spec n64
CACHE STRING "List of systems to be built by the project"
)
# gersemi: on
+7
View File
@@ -152,6 +152,13 @@ else()
disable_core("Atari 2600")
endif()
if(a52 IN_LIST ARES_CORES)
enable_core("Atari 5200")
add_subdirectory(a52)
else()
disable_core("Atari 5200")
endif()
if(fc IN_LIST ARES_CORES)
enable_core("NES / Famicom")
add_subdirectory(fc)
+37
View File
@@ -0,0 +1,37 @@
ares_components(mos6502)
ares_add_sources(
CORE #
a52
UNITY #
a52.cpp
PRIMARY #
system/system.cpp
cartridge/cartridge.cpp
cpu/cpu.cpp
antic/antic.cpp
gtia/gtia.cpp
pokey/pokey.cpp
)
ares_add_sources(
CORE #
a52
INCLUDED #
a52.hpp
CMakeLists.txt
system/system.hpp
cartridge/cartridge.hpp
cartridge/slot.cpp
cartridge/slot.hpp
cartridge/board/board.cpp
cartridge/board/board.hpp
cartridge/board/linear.cpp
cpu/cpu.hpp
cpu/debugger.cpp
cpu/memory.cpp
cpu/timing.cpp
antic/antic.hpp
gtia/gtia.hpp
pokey/pokey.hpp
)
+6
View File
@@ -0,0 +1,6 @@
#include <a52/cartridge/cartridge.cpp>
#include <a52/antic/antic.cpp>
#include <a52/gtia/gtia.cpp>
#include <a52/pokey/pokey.cpp>
#include <a52/cpu/cpu.cpp>
#include <a52/system/system.cpp>
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include <ares/ares.hpp>
#include <vector>
#include <component/processor/mos6502/mos6502.hpp>
namespace ares::Atari5200 {
#include <ares/inline.hpp>
auto enumerate() -> std::vector<string>;
auto load(Node::System& node, string name) -> bool;
struct Timing {
static constexpr u32 MachineCyclesPerScanline = 114;
static constexpr u32 ColorClocksPerMachineCycle = 2;
static constexpr u32 ColorClocksPerScanline = MachineCyclesPerScanline * ColorClocksPerMachineCycle;
static constexpr u32 SamplesPerColorClock = 2;
static constexpr u32 SamplesPerMachineCycle = ColorClocksPerMachineCycle * SamplesPerColorClock;
static constexpr u32 SamplesPerScanline = ColorClocksPerScanline * SamplesPerColorClock;
static constexpr u32 ScanlinesPerFrame = 262;
};
#include <a52/system/system.hpp>
#include <a52/cartridge/cartridge.hpp>
#include <a52/antic/antic.hpp>
#include <a52/gtia/gtia.hpp>
#include <a52/pokey/pokey.hpp>
#include <a52/cpu/cpu.hpp>
}
+41
View File
@@ -0,0 +1,41 @@
#include <a52/a52.hpp>
namespace ares::Atari5200 {
ANTIC antic;
auto ANTIC::load(Node::Object parent) -> void {
node = parent->append<Node::Object>("ANTIC");
}
auto ANTIC::unload() -> void {
Thread::destroy();
node = {};
}
auto ANTIC::main() -> void {
Thread::step(Timing::ColorClocksPerScanline);
Thread::synchronize(cpu);
if(++scanline == Timing::ScanlinesPerFrame) {
scanline = 0;
scheduler.exit(Event::Frame);
}
}
auto ANTIC::power() -> void {
Thread::create(system.frequency(), std::bind_front(&ANTIC::main, this));
scanline = 0;
}
auto ANTIC::read(n8 address) -> n8 {
return peek(address);
}
auto ANTIC::peek(n8 address) const -> n8 {
return 0xff;
}
auto ANTIC::write(n8 address, n8 data) -> void {
}
}
+17
View File
@@ -0,0 +1,17 @@
struct ANTIC : Thread {
Node::Object node;
auto load(Node::Object parent) -> void;
auto unload() -> void;
auto main() -> void;
auto power() -> void;
auto read(n8 address) -> n8;
auto peek(n8 address) const -> n8;
auto write(n8 address, n8 data) -> void;
private:
u32 scanline = 0;
};
extern ANTIC antic;
+5
View File
@@ -0,0 +1,5 @@
namespace Board {
#include "linear.cpp"
}
+19
View File
@@ -0,0 +1,19 @@
namespace Board {
struct Interface {
VFS::Pak pak;
Interface(Cartridge& cartridge) : cartridge(cartridge) {}
virtual ~Interface() = default;
virtual auto load() -> bool { return false; }
virtual auto unload() -> void {}
virtual auto power() -> void {}
virtual auto read(n16 address, n8 data) -> n8 { return data; }
virtual auto peek(n16 address, n8 data) const -> n8 { return data; }
virtual auto write(n16 address, n8 data) -> bool { return false; }
Cartridge& cartridge;
};
}
+27
View File
@@ -0,0 +1,27 @@
struct Linear32K : Interface {
using Interface::Interface;
auto load() -> bool override {
auto fp = pak->read("program.rom");
if(!fp || fp->size() != 32_KiB) return false;
rom.allocate(32_KiB);
rom.load(fp);
return true;
}
auto unload() -> void override {
rom.reset();
}
auto read(n16 address, n8 data) -> n8 override {
return peek(address, data);
}
auto peek(n16 address, n8 data) const -> n8 override {
if(!rom) return data;
return rom.read(address & 0x7fff);
}
private:
Memory::Readable<n8> rom;
};
+59
View File
@@ -0,0 +1,59 @@
#include <a52/a52.hpp>
namespace ares::Atari5200 {
Cartridge& cartridge = cartridgeSlot.cartridge;
#include "board/board.cpp"
#include "slot.cpp"
auto Cartridge::allocate(Node::Port parent) -> Node::Peripheral {
return node = parent->append<Node::Peripheral>("Atari 5200 Cartridge");
}
auto Cartridge::connect() -> void {
if(!node->setPak(pak = platform->pak(node))) return;
information = {};
information.title = pak->attribute("title");
information.board = pak->attribute("board");
if(information.board == "Linear32K") board = std::make_unique<Board::Linear32K>(*this);
if(!board) return;
board->pak = pak;
if(!board->load()) {
board.reset();
return;
}
}
auto Cartridge::disconnect() -> void {
if(board) board->unload();
board.reset();
pak.reset();
node.reset();
}
auto Cartridge::save() -> void {
}
auto Cartridge::power() -> void {
if(board) board->power();
}
auto Cartridge::read(n16 address, n8 data) -> n8 {
if(!board) return data;
return board->read(address, data);
}
auto Cartridge::peek(n16 address, n8 data) const -> n8 {
if(!board) return data;
return board->peek(address, data);
}
auto Cartridge::write(n16 address, n8 data) -> bool {
if(!board) return false;
return board->write(address, data);
}
}
+31
View File
@@ -0,0 +1,31 @@
struct Cartridge;
#include "board/board.hpp"
struct Cartridge {
Node::Peripheral node;
VFS::Pak pak;
auto title() const -> string { return information.title; }
auto allocate(Node::Port parent) -> Node::Peripheral;
auto connect() -> void;
auto disconnect() -> void;
auto save() -> void;
auto power() -> void;
auto read(n16 address, n8 data) -> n8;
auto peek(n16 address, n8 data) const -> n8;
auto write(n16 address, n8 data) -> bool;
std::unique_ptr<Board::Interface> board;
private:
struct Information {
string title;
string board;
} information;
};
#include "slot.hpp"
extern Cartridge& cartridge;
+15
View File
@@ -0,0 +1,15 @@
CartridgeSlot cartridgeSlot;
auto CartridgeSlot::load(Node::Object parent) -> void {
port = parent->append<Node::Port>("Cartridge Slot");
port->setFamily(system.name());
port->setType("Cartridge");
port->setAllocate([&](auto name) { return cartridge.allocate(port); });
port->setConnect([&] { return cartridge.connect(); });
port->setDisconnect([&] { return cartridge.disconnect(); });
}
auto CartridgeSlot::unload() -> void {
cartridge.disconnect();
port = {};
}
+9
View File
@@ -0,0 +1,9 @@
struct CartridgeSlot {
Node::Port port;
Cartridge cartridge;
auto load(Node::Object parent) -> void;
auto unload() -> void;
};
extern CartridgeSlot cartridgeSlot;
+56
View File
@@ -0,0 +1,56 @@
#include <a52/a52.hpp>
namespace ares::Atari5200 {
CPU cpu;
#include "memory.cpp"
#include "timing.cpp"
#include "debugger.cpp"
auto CPU::load(Node::Object parent) -> void {
node = parent->append<Node::Object>("CPU");
debugger.load(node);
}
auto CPU::unload() -> void {
Thread::destroy();
debugger = {};
node = {};
}
auto CPU::main() -> void {
if(io.interruptPending) {
if(io.resetPending) {
debugger.interrupt("Reset");
reset();
io.resetPending = 0;
} else if(io.nmiPending) {
debugger.interrupt("NMI");
interrupt();
} else {
debugger.interrupt("IRQ");
interrupt();
}
}
debugger.instruction();
instruction();
}
auto CPU::step(u32 clocks) -> void {
Thread::step(clocks);
Thread::synchronize();
}
auto CPU::power(bool reset) -> void {
MOS6502::BCD = 1;
if(!reset) MOS6502::power();
Thread::create(system.frequency() / Timing::ColorClocksPerMachineCycle, std::bind_front(&CPU::main, this));
io = {};
io.rdyLine = 1;
io.resetPending = 1;
io.interruptPending = 1;
}
}
+61
View File
@@ -0,0 +1,61 @@
struct CPU : MOS6502, Thread {
Node::Object node;
struct Debugger {
//debugger.cpp
auto load(Node::Object parent) -> void;
auto instruction() -> void;
auto interrupt(string_view type) -> void;
struct Memory {
Node::Debugger::Memory bus;
Node::Debugger::Memory ram;
} memory;
struct Tracer {
Node::Debugger::Tracer::Instruction instruction;
Node::Debugger::Tracer::Notification interrupt;
} tracer;
} debugger;
//cpu.cpp
auto load(Node::Object parent) -> void;
auto unload() -> void;
auto main() -> void;
auto step(u32 clocks) -> void;
auto power(bool reset) -> void;
//memory.cpp
auto readBus(n16 address) -> n8;
auto writeBus(n16 address, n8 data) -> void;
auto readDebugger(n16 address) -> n8 override;
//timing.cpp
auto read(n16 address) -> n8 override;
auto write(n16 address, n8 data) -> void override;
auto lastCycle() -> void override;
auto cancelNmi() -> void override;
auto delayIrq() -> void override;
auto irqPending() -> bool override;
auto nmi(n16& vector) -> void override;
auto nmiLine(bool line) -> void;
auto irqLine(bool line) -> void;
auto rdyLine(bool line) -> void;
private:
//memory.cpp
auto peekBus(n16 address) const -> n8;
struct IO {
n1 interruptPending;
n1 resetPending;
n1 nmiPending;
n1 nmiLine;
n1 irqLine;
n1 rdyLine = 1;
n8 openBus;
} io;
};
extern CPU cpu;
+30
View File
@@ -0,0 +1,30 @@
auto CPU::Debugger::load(Node::Object parent) -> void {
memory.bus = parent->append<Node::Debugger::Memory>("CPU Bus");
memory.bus->setSize(64_KiB);
memory.bus->setRead([&](u32 address) -> u8 {
return cpu.readDebugger(address);
});
memory.ram = parent->append<Node::Debugger::Memory>("CPU RAM");
memory.ram->setSize(system.ram.size());
memory.ram->setRead([&](u32 address) -> u8 {
return system.ram.read(address);
});
memory.ram->setWrite([&](u32 address, u8 data) -> void {
system.ram.write(address, data);
});
tracer.instruction = parent->append<Node::Debugger::Tracer::Instruction>("Instruction", "CPU");
tracer.instruction->setAddressBits(16);
tracer.interrupt = parent->append<Node::Debugger::Tracer::Notification>("Interrupt", "CPU");
}
auto CPU::Debugger::instruction() -> void {
if(tracer.instruction->enabled() && tracer.instruction->address(cpu.PC)) {
tracer.instruction->notify(cpu.disassembleInstruction(), cpu.disassembleContext());
}
}
auto CPU::Debugger::interrupt(string_view type) -> void {
if(tracer.interrupt->enabled()) tracer.interrupt->notify(type);
}
+33
View File
@@ -0,0 +1,33 @@
auto CPU::readBus(n16 address) -> n8 {
if(auto result = platform->cheat(address)) return *result;
if(address <= 0x3fff) return system.ram.read(address);
if(address <= 0xbfff) return cartridge.read(address - 0x4000, io.openBus);
if(address <= 0xc0ff) return gtia.read(address);
if(address >= 0xd400 && address <= 0xd4ff) return antic.read(address);
if(address >= 0xe800 && address <= 0xefff) return pokey.read(address);
if(address >= 0xf800) return system.bios.read(address - 0xf800);
return io.openBus;
}
auto CPU::peekBus(n16 address) const -> n8 {
if(address <= 0x3fff) return system.ram.read(address);
if(address <= 0xbfff) return cartridge.peek(address - 0x4000, io.openBus);
if(address <= 0xc0ff) return gtia.peek(address);
if(address >= 0xd400 && address <= 0xd4ff) return antic.peek(address);
if(address >= 0xe800 && address <= 0xefff) return pokey.peek(address);
if(address >= 0xf800) return system.bios.read(address - 0xf800);
return io.openBus;
}
auto CPU::writeBus(n16 address, n8 data) -> void {
if(address <= 0x3fff) return system.ram.write(address, data);
if(address <= 0xbfff) return (void)cartridge.write(address - 0x4000, data);
if(address <= 0xc0ff) return gtia.write(address, data);
if(address >= 0xd400 && address <= 0xd4ff) return antic.write(address, data);
if(address >= 0xe800 && address <= 0xefff) return pokey.write(address, data);
}
auto CPU::readDebugger(n16 address) -> n8 {
return peekBus(address);
}
+49
View File
@@ -0,0 +1,49 @@
auto CPU::read(n16 address) -> n8 {
while(!io.rdyLine) step(1);
auto data = readBus(address);
io.openBus = data;
step(1);
return data;
}
auto CPU::write(n16 address, n8 data) -> void {
writeBus(address, data);
io.openBus = data;
step(1);
}
auto CPU::lastCycle() -> void {
io.interruptPending = io.nmiPending | irqPending();
}
auto CPU::cancelNmi() -> void {
io.interruptPending = irqPending();
}
auto CPU::delayIrq() -> void {
io.interruptPending = io.nmiPending;
}
auto CPU::irqPending() -> bool {
return io.irqLine && !P.i;
}
auto CPU::nmi(n16& vector) -> void {
if(io.nmiPending) {
io.nmiPending = 0;
vector = 0xfffa;
}
}
auto CPU::nmiLine(bool line) -> void {
if(!io.nmiLine && line) io.nmiPending = 1;
io.nmiLine = line;
}
auto CPU::irqLine(bool line) -> void {
io.irqLine = line;
}
auto CPU::rdyLine(bool line) -> void {
io.rdyLine = line;
}
+31
View File
@@ -0,0 +1,31 @@
#include <a52/a52.hpp>
namespace ares::Atari5200 {
GTIA gtia;
auto GTIA::load(Node::Object parent) -> void {
node = parent->append<Node::Object>("GTIA");
}
auto GTIA::unload() -> void {
node = {};
}
auto GTIA::power() -> void {
}
auto GTIA::read(n8 address) -> n8 {
return peek(address);
}
auto GTIA::peek(n8 address) const -> n8 {
address &= 0x1f;
if(address <= 0x13) return 0x00;
return 0x0f;
}
auto GTIA::write(n8 address, n8 data) -> void {
}
}
+14
View File
@@ -0,0 +1,14 @@
struct GTIA {
Node::Object node;
auto load(Node::Object parent) -> void;
auto unload() -> void;
auto power() -> void;
auto read(n8 address) -> n8;
auto peek(n8 address) const -> n8;
auto write(n8 address, n8 data) -> void;
};
extern GTIA gtia;
+29
View File
@@ -0,0 +1,29 @@
#include <a52/a52.hpp>
namespace ares::Atari5200 {
POKEY pokey;
auto POKEY::load(Node::Object parent) -> void {
node = parent->append<Node::Object>("POKEY");
}
auto POKEY::unload() -> void {
node = {};
}
auto POKEY::power() -> void {
}
auto POKEY::read(n8 address) -> n8 {
return peek(address);
}
auto POKEY::peek(n8 address) const -> n8 {
return 0xff;
}
auto POKEY::write(n8 address, n8 data) -> void {
}
}
+14
View File
@@ -0,0 +1,14 @@
struct POKEY {
Node::Object node;
auto load(Node::Object parent) -> void;
auto unload() -> void;
auto power() -> void;
auto read(n8 address) -> n8;
auto peek(n8 address) const -> n8;
auto write(n8 address, n8 data) -> void;
};
extern POKEY pokey;
+106
View File
@@ -0,0 +1,106 @@
#include <a52/a52.hpp>
#include <algorithm>
namespace ares::Atari5200 {
auto enumerate() -> std::vector<string> {
return {
"[Atari] Atari 5200 (NTSC)",
};
}
auto load(Node::System& node, string name) -> bool {
auto configurations = enumerate();
if(std::find(configurations.begin(), configurations.end(), name) == configurations.end()) return false;
return system.load(node, name);
}
Random random;
Scheduler scheduler;
System system;
auto System::game() -> string {
if(cartridge.node) return cartridge.title();
return "(no cartridge connected)";
}
auto System::run() -> void {
scheduler.enter();
}
auto System::load(Node::System& root, string name) -> bool {
if(node) unload();
information = {};
node = std::make_shared<Core::System>(information.name);
node->setAttribute("configuration", name);
node->setGame(std::bind_front(&System::game, this));
node->setRun(std::bind_front(&System::run, this));
node->setPower(std::bind_front(&System::power, this));
node->setSave(std::bind_front(&System::save, this));
node->setUnload(std::bind_front(&System::unload, this));
root = node;
if(!node->setPak(pak = platform->pak(node))) {
root = {};
node = {};
return false;
}
auto firmware = pak->read("bios.rom");
if(!firmware || firmware->size() != 2_KiB) {
pak.reset();
root = {};
node = {};
return false;
}
ram.allocate(16_KiB);
bios.allocate(2_KiB);
bios.load(firmware);
scheduler.reset();
cpu.load(node);
antic.load(node);
gtia.load(node);
pokey.load(node);
cartridgeSlot.load(node);
return true;
}
auto System::save() -> void {
if(!node) return;
cartridge.save();
}
auto System::unload() -> void {
if(!node) return;
save();
cpu.unload();
antic.unload();
gtia.unload();
pokey.unload();
cartridgeSlot.unload();
ram.reset();
bios.reset();
pak.reset();
node.reset();
}
auto System::power(bool reset) -> void {
for(auto& setting : node->find<Node::Setting::Setting>()) setting->setLatch();
random.entropy(Random::Entropy::Low);
if(!reset) {
for(auto& byte : ram) byte = random();
}
cartridge.power();
antic.power();
gtia.power();
pokey.power();
cpu.power(reset);
scheduler.power(cpu);
}
}
+28
View File
@@ -0,0 +1,28 @@
extern Random random;
struct System {
Node::System node;
VFS::Pak pak;
auto name() const -> string { return information.name; }
auto frequency() const -> f64 { return information.frequency; }
auto game() -> string;
auto run() -> void;
auto load(Node::System& node, string name) -> bool;
auto save() -> void;
auto unload() -> void;
auto power(bool reset) -> void;
Memory::Writable<n8> ram;
Memory::Readable<n8> bios;
private:
struct Information {
string name = "Atari 5200";
f64 frequency = Constants::Colorburst::NTSC;
} information;
};
extern System system;
+1
View File
@@ -60,6 +60,7 @@ target_sources(
PRIVATE
emulator/arcade.cpp
emulator/atari-2600.cpp
emulator/atari-5200.cpp
emulator/colecovision.cpp
emulator/emulator.cpp
emulator/emulator.hpp
+57
View File
@@ -0,0 +1,57 @@
struct Atari5200 : Emulator {
Atari5200();
auto load() -> LoadResult override;
auto save() -> bool override;
auto pak(ares::Node::Object node) -> std::shared_ptr<vfs::directory> override;
};
Atari5200::Atari5200() {
manufacturer = "Atari";
name = "Atari 5200";
firmware.push_back({
"BIOS",
"NTSC-U Four-port",
"06b250f18983d058c0f156ce7ee88ae48b6eaf11e6f10f21dccf6ac7ffb6a6af"
});
}
auto Atari5200::load() -> LoadResult {
game = mia::Medium::create("Atari 5200");
string location = Emulator::load(game, configuration.game);
if(!location) return noFileSelected;
LoadResult result = game->load(location);
if(result != successful) return result;
system = mia::System::create("Atari 5200");
if(system->load(firmware[0].location) != successful) {
result.firmwareSystemName = "Atari 5200";
result.firmwareType = firmware[0].type;
result.firmwareRegion = firmware[0].region;
result.result = noFirmware;
return result;
}
if(!ares::Atari5200::load(root, "[Atari] Atari 5200 (NTSC)")) return otherError;
if(auto port = root->find<ares::Node::Port>("Cartridge Slot")) {
port->allocate();
port->connect();
}
return successful;
}
auto Atari5200::save() -> bool {
root->save();
system->save(system->location);
game->save(game->location);
return true;
}
auto Atari5200::pak(ares::Node::Object node) -> std::shared_ptr<vfs::directory> {
if(node->name() == "Atari 5200") return system->pak;
if(node->name() == "Atari 5200 Cartridge") return game->pak;
return {};
}
+11
View File
@@ -6,6 +6,13 @@ namespace ares::Atari2600 {
#include "atari-2600.cpp"
#endif
#ifdef CORE_A52
namespace ares::Atari5200 {
auto load(Node::System& node, string name) -> bool;
}
#include "atari-5200.cpp"
#endif
#ifdef CORE_CV
namespace ares::ColecoVision {
auto load(Node::System& node, string name) -> bool;
@@ -169,6 +176,10 @@ auto Emulator::construct() -> void {
emulators.push_back(std::make_shared<Atari2600>());
#endif
#ifdef CORE_A52
emulators.push_back(std::make_shared<Atari5200>());
#endif
#ifdef CORE_WS
emulators.push_back(std::make_shared<WonderSwan>());
emulators.push_back(std::make_shared<WonderSwanColor>());
+2
View File
@@ -16,6 +16,7 @@ target_sources(
resource/resource.hpp
medium/arcade.cpp
medium/atari-2600.cpp
medium/atari-5200.cpp
medium/bs-memory.cpp
medium/colecovision.cpp
medium/famicom-disk-system.cpp
@@ -81,6 +82,7 @@ target_sources(
PRIVATE
system/arcade.cpp
system/atari-2600.cpp
system/atari-5200.cpp
system/colecovision.cpp
system/famicom.cpp
system/game-boy-advance.cpp
+61
View File
@@ -0,0 +1,61 @@
struct Atari5200 : Cartridge {
auto name() -> string override { return "Atari 5200"; }
auto extensions() -> std::vector<string> override { return {"a52", "bin", "car"}; }
auto load(string location) -> LoadResult override;
auto save(string location) -> bool override;
auto analyze(const std::vector<u8>& rom) -> string;
};
auto Atari5200::load(string location) -> LoadResult {
std::vector<u8> rom;
if(directory::exists(location)) {
append(rom, {location, "program.rom"});
} else if(file::exists(location)) {
rom = Cartridge::read(location);
}
if(rom.empty()) return romNotFound;
if(rom.size() >= 4 && rom[0] == 'C' && rom[1] == 'A' && rom[2] == 'R' && rom[3] == 'T') {
return invalidROM;
}
sha256 = Hash::SHA256(rom).digest();
if(rom.size() != 32_KiB) {
// Raw 16 KiB images are ambiguous between one-chip and two-chip boards.
// Smaller images, headered .car files, and additional board layouts belong
// to the mapper child so this scaffold never guesses a wiring layout.
return invalidROM;
}
this->location = location;
this->manifest = analyze(rom);
auto document = BML::unserialize(manifest);
if(!document) return couldNotParseManifest;
pak = std::make_shared<vfs::directory>();
pak->setAttribute("title", document["game/title"].string());
pak->setAttribute("region", document["game/region"].string());
pak->setAttribute("board", document["game/board"].string());
pak->append("manifest.bml", manifest);
pak->append("program.rom", rom);
return successful;
}
auto Atari5200::save(string location) -> bool {
return true;
}
auto Atari5200::analyze(const std::vector<u8>& rom) -> string {
string manifest;
manifest += "game\n";
manifest +={" name: ", Medium::name(location), "\n"};
manifest +={" title: ", Medium::name(location), "\n"};
manifest += " region: NTSC\n";
manifest +={" sha256: ", sha256, "\n"};
manifest += " board: Linear32K\n";
manifest += " memory\n";
manifest += " type: ROM\n";
manifest +={" size: 0x", hex(rom.size()), "\n"};
manifest += " content: Program\n";
return manifest;
}
+2
View File
@@ -3,6 +3,7 @@ namespace Media {
#include "mame.cpp"
#include "arcade.cpp"
#include "atari-2600.cpp"
#include "atari-5200.cpp"
#include "colecovision.cpp"
#include "myvision.cpp"
#include "famicom.cpp"
@@ -48,6 +49,7 @@ namespace Media {
auto Medium::create(string name) -> std::shared_ptr<Pak> {
if(name == "Arcade") return std::make_shared<Media::Arcade>();
if(name == "Atari 2600") return std::make_shared<Media::Atari2600>();
if(name == "Atari 5200") return std::make_shared<Media::Atari5200>();
if(name == "ColecoVision") return std::make_shared<Media::ColecoVision>();
if(name == "MyVision") return std::make_shared<Media::MyVision>();
if(name == "Famicom") return std::make_shared<Media::Famicom>();
+1
View File
@@ -87,6 +87,7 @@ auto construct() -> void {
initialized = true;
media.push_back("Atari 2600");
media.push_back("Atari 5200");
media.push_back("BS Memory");
media.push_back("ColecoVision");
media.push_back("MyVision");
+20
View File
@@ -0,0 +1,20 @@
struct Atari5200 : System {
auto name() -> string override { return "Atari 5200"; }
auto load(string location) -> LoadResult override;
auto save(string location) -> bool override;
};
auto Atari5200::load(string location) -> LoadResult {
auto bios = Pak::read(location);
if(bios.empty()) return romNotFound;
if(bios.size() != 2_KiB) return invalidROM;
this->location = locate();
pak = std::make_shared<vfs::directory>();
pak->append("bios.rom", bios);
return successful;
}
auto Atari5200::save(string location) -> bool {
return true;
}
+2
View File
@@ -1,6 +1,7 @@
namespace Systems {
#include "arcade.cpp"
#include "atari-2600.cpp"
#include "atari-5200.cpp"
#include "colecovision.cpp"
#include "myvision.cpp"
#include "famicom.cpp"
@@ -40,6 +41,7 @@ namespace Systems {
auto System::create(string name) -> std::shared_ptr<Pak> {
if(name == "Arcade") return std::make_shared<Systems::Arcade>();
if(name == "Atari 2600") return std::make_shared<Systems::Atari2600>();
if(name == "Atari 5200") return std::make_shared<Systems::Atari5200>();
if(name == "ColecoVision") return std::make_shared<Systems::ColecoVision>();
if(name == "MyVision") return std::make_shared<Systems::MyVision>();
if(name == "Famicom") return std::make_shared<Systems::Famicom>();