From 5f035496bb404fb6a4bab88aaea046a91096124e Mon Sep 17 00:00:00 2001 From: Near <77224854+near-san@users.noreply.github.com> Date: Wed, 8 Jul 2020 11:59:00 +0000 Subject: [PATCH] Update to ares v114r17 release. - PlayStation: started implementing timers - MSX: added more cartridge mappers (Konami SCC, ASCII 8kbit, ASCII 16kbit, etc) --- ares/ares/information.hpp | 2 +- ares/msx/cartridge/board/asc16.cpp | 43 +++ ares/msx/cartridge/board/asc8.cpp | 51 ++++ ares/msx/cartridge/board/board.cpp | 50 ++++ ares/msx/cartridge/board/board.hpp | 22 ++ ares/msx/cartridge/board/cross-blaim.cpp | 56 ++++ ares/msx/cartridge/board/konami-scc.cpp | 252 ++++++++++++++++++ ares/msx/cartridge/board/konami.cpp | 45 ++++ ares/msx/cartridge/board/linear.cpp | 29 ++ .../msx/cartridge/board/super-lode-runner.cpp | 37 +++ ares/msx/cartridge/board/super-pierrot.cpp | 47 ++++ ares/msx/cartridge/cartridge.cpp | 88 ++---- ares/msx/cartridge/cartridge.hpp | 10 +- ares/msx/cartridge/serialization.cpp | 2 +- ares/ps1/GNUmakefile | 4 + ares/ps1/cpu/core/disassembler.hpp | 2 +- ares/ps1/cpu/cpu.cpp | 15 +- ares/ps1/cpu/cpu.hpp | 91 ------- ares/ps1/cpu/interrupt.cpp | 145 ---------- ares/ps1/disc/command.cpp | 44 ++- ares/ps1/disc/disc.cpp | 18 +- ares/ps1/disc/disc.hpp | 30 ++- ares/ps1/disc/irq.cpp | 4 +- ares/ps1/dma/dma.cpp | 36 +++ ares/ps1/dma/dma.hpp | 66 +++++ ares/ps1/{cpu/dma.cpp => dma/io.cpp} | 99 +------ ares/ps1/dma/serialization.cpp | 2 + ares/ps1/dma/transfer.cpp | 54 ++++ ares/ps1/gpu/gpu.cpp | 4 +- ares/ps1/irq/io.cpp | 90 +++++++ ares/ps1/irq/irq.cpp | 71 +++++ ares/ps1/irq/irq.hpp | 47 ++++ ares/ps1/irq/serialization.cpp | 2 + ares/ps1/memory/bus.hpp | 6 +- ares/ps1/ps1.hpp | 3 + ares/ps1/system/serialization.cpp | 3 + ares/ps1/system/system.cpp | 11 +- ares/ps1/timer/io.cpp | 172 ++++++++++++ ares/ps1/timer/serialization.cpp | 2 + ares/ps1/timer/timer.cpp | 23 ++ ares/ps1/timer/timer.hpp | 44 +++ 41 files changed, 1404 insertions(+), 418 deletions(-) create mode 100644 ares/msx/cartridge/board/asc16.cpp create mode 100644 ares/msx/cartridge/board/asc8.cpp create mode 100644 ares/msx/cartridge/board/board.cpp create mode 100644 ares/msx/cartridge/board/board.hpp create mode 100644 ares/msx/cartridge/board/cross-blaim.cpp create mode 100644 ares/msx/cartridge/board/konami-scc.cpp create mode 100644 ares/msx/cartridge/board/konami.cpp create mode 100644 ares/msx/cartridge/board/linear.cpp create mode 100644 ares/msx/cartridge/board/super-lode-runner.cpp create mode 100644 ares/msx/cartridge/board/super-pierrot.cpp delete mode 100644 ares/ps1/cpu/interrupt.cpp create mode 100644 ares/ps1/dma/dma.cpp create mode 100644 ares/ps1/dma/dma.hpp rename ares/ps1/{cpu/dma.cpp => dma/io.cpp} (67%) create mode 100644 ares/ps1/dma/serialization.cpp create mode 100644 ares/ps1/dma/transfer.cpp create mode 100644 ares/ps1/irq/io.cpp create mode 100644 ares/ps1/irq/irq.cpp create mode 100644 ares/ps1/irq/irq.hpp create mode 100644 ares/ps1/irq/serialization.cpp create mode 100644 ares/ps1/timer/io.cpp create mode 100644 ares/ps1/timer/serialization.cpp create mode 100644 ares/ps1/timer/timer.cpp create mode 100644 ares/ps1/timer/timer.hpp diff --git a/ares/ares/information.hpp b/ares/ares/information.hpp index 95a4d7399..ce6131675 100644 --- a/ares/ares/information.hpp +++ b/ares/ares/information.hpp @@ -2,7 +2,7 @@ namespace ares { static const string Name = "ares"; - static const string Version = "114.16"; + static const string Version = "114.17"; static const string Copyright = "ares team"; static const string License = "BY-NC-ND 4.0"; static const string LicenseURI = "https://creativecommons.org/licenses/by-nc-nd/4.0/"; diff --git a/ares/msx/cartridge/board/asc16.cpp b/ares/msx/cartridge/board/asc16.cpp new file mode 100644 index 000000000..82c62cfc2 --- /dev/null +++ b/ares/msx/cartridge/board/asc16.cpp @@ -0,0 +1,43 @@ +//ASCII 16kbit + +struct ASC16 : Interface { + using Interface::Interface; + Memory::Readable rom; + + auto load(Markup::Node document) -> void override { + auto board = document["game/board"]; + Interface::load(rom, board["memory(type=ROM,content=Program)"]); + } + + auto save(Markup::Node document) -> void override { + } + + auto unload() -> void override { + } + + auto read(uint16 address, uint8 data) -> uint8 override { + if(address >= 0x4000 && address <= 0x7fff) data = rom.read(bank[0] << 14 | (uint14)address); + if(address >= 0x8000 && address <= 0xbfff) data = rom.read(bank[1] << 14 | (uint14)address); + + if(address >= 0xc000 && address <= 0xffff) data = rom.read(bank[0] << 14 | (uint14)address); + if(address >= 0x0000 && address <= 0x3fff) data = rom.read(bank[1] << 14 | (uint14)address); + + return data; + } + + auto write(uint16 address, uint8 data) -> void override { + if(address >= 0x6000 && address <= 0x6fff) bank[0] = data; + if(address >= 0x7000 && address <= 0xbfff) bank[1] = data; + } + + auto power() -> void override { + bank[0] = 0x0f; //R-Type = 0x0f; others = 0x00 + bank[1] = 0x00; + } + + auto serialize(serializer& s) -> void override { + s.array(bank); + } + + uint8 bank[2]; +}; diff --git a/ares/msx/cartridge/board/asc8.cpp b/ares/msx/cartridge/board/asc8.cpp new file mode 100644 index 000000000..1abf23fad --- /dev/null +++ b/ares/msx/cartridge/board/asc8.cpp @@ -0,0 +1,51 @@ +//ASCII 8kbit + +struct ASC8 : Interface { + using Interface::Interface; + Memory::Readable rom; + + auto load(Markup::Node document) -> void override { + auto board = document["game/board"]; + Interface::load(rom, board["memory(type=ROM,content=Program)"]); + } + + auto save(Markup::Node document) -> void override { + } + + auto unload() -> void override { + } + + auto read(uint16 address, uint8 data) -> uint8 override { + if(address >= 0x4000 && address <= 0x5fff) data = rom.read(bank[0] << 13 | (uint13)address); + if(address >= 0x6000 && address <= 0x7fff) data = rom.read(bank[1] << 13 | (uint13)address); + if(address >= 0x8000 && address <= 0x9fff) data = rom.read(bank[2] << 13 | (uint13)address); + if(address >= 0xa000 && address <= 0xbfff) data = rom.read(bank[3] << 13 | (uint13)address); + + if(address >= 0xc000 && address <= 0xdfff) data = rom.read(bank[0] << 13 | (uint13)address); + if(address >= 0xe000 && address <= 0xffff) data = rom.read(bank[1] << 13 | (uint13)address); + if(address >= 0x0000 && address <= 0x1fff) data = rom.read(bank[2] << 13 | (uint13)address); + if(address >= 0x2000 && address <= 0x3fff) data = rom.read(bank[3] << 13 | (uint13)address); + + return data; + } + + auto write(uint16 address, uint8 data) -> void override { + if(address >= 0x6000 && address <= 0x67ff) bank[0] = data; + if(address >= 0x6800 && address <= 0x6fff) bank[1] = data; + if(address >= 0x7000 && address <= 0x77ff) bank[2] = data; + if(address >= 0x7800 && address <= 0x7fff) bank[3] = data; + } + + auto power() -> void override { + bank[0] = 0; + bank[1] = 0; + bank[2] = 0; + bank[3] = 0; + } + + auto serialize(serializer& s) -> void override { + s.array(bank); + } + + uint8 bank[4]; +}; diff --git a/ares/msx/cartridge/board/board.cpp b/ares/msx/cartridge/board/board.cpp new file mode 100644 index 000000000..4bb6496ca --- /dev/null +++ b/ares/msx/cartridge/board/board.cpp @@ -0,0 +1,50 @@ +namespace Board { + +#include "asc16.cpp" +#include "asc8.cpp" +#include "cross-blaim.cpp" +#include "konami.cpp" +#include "konami-scc.cpp" +#include "linear.cpp" +#include "super-lode-runner.cpp" +#include "super-pierrot.cpp" + +auto Interface::load(Memory::Readable& memory, Markup::Node node) -> bool { + if(!node) return false; + memory.allocate(node["size"].natural()); + auto name = string{node["content"].string(), ".", node["type"].string()}.downcase(); + if(auto fp = platform->open(cartridge.node, name, File::Read, File::Required)) { + memory.load(fp); + return true; + } + return false; +} + +auto Interface::load(Memory::Writable& memory, Markup::Node node) -> bool { + if(!node) return false; + memory.allocate(node["size"].natural()); + if(node["volatile"]) return true; + auto name = string{node["content"].string(), ".", node["type"].string()}.downcase(); + if(auto fp = platform->open(cartridge.node, name, File::Read)) { + memory.load(fp); + return true; + } + return false; +} + +auto Interface::save(Memory::Writable& memory, Markup::Node node) -> bool { + if(!node) return false; + if(node["volatile"]) return true; + auto name = string{node["content"].string(), ".", node["type"].string()}.downcase(); + if(auto fp = platform->open(cartridge.node, name, File::Write)) { + memory.save(fp); + return true; + } + return false; +} + +auto Interface::main() -> void { + cartridge.step(system.colorburst()); +} + +} diff --git a/ares/msx/cartridge/board/board.hpp b/ares/msx/cartridge/board/board.hpp new file mode 100644 index 000000000..878fc04b3 --- /dev/null +++ b/ares/msx/cartridge/board/board.hpp @@ -0,0 +1,22 @@ +namespace Board { + +struct Interface { + Interface(Cartridge& cartridge) : cartridge(cartridge) {} + virtual ~Interface() = default; + virtual auto load(Markup::Node) -> void {} + virtual auto save(Markup::Node) -> void {} + virtual auto unload() -> void {} + virtual auto main() -> void; + virtual auto read(uint16 address, uint8 data) -> uint8 { return data; } + virtual auto write(uint16 address, uint8 data) -> void {} + virtual auto power() -> void {} + virtual auto serialize(serializer&) -> void {} + + auto load(Memory::Readable&, Markup::Node) -> bool; + auto load(Memory::Writable&, Markup::Node) -> bool; + auto save(Memory::Writable&, Markup::Node) -> bool; + + Cartridge& cartridge; +}; + +} diff --git a/ares/msx/cartridge/board/cross-blaim.cpp b/ares/msx/cartridge/board/cross-blaim.cpp new file mode 100644 index 000000000..bcdb2cfb2 --- /dev/null +++ b/ares/msx/cartridge/board/cross-blaim.cpp @@ -0,0 +1,56 @@ +//Cross Blaim + +struct CrossBlaim : Interface { + using Interface::Interface; + Memory::Readable rom; + + auto load(Markup::Node document) -> void override { + auto board = document["game/board"]; + Interface::load(rom, board["memory(type=ROM,content=Program)"]); + } + + auto save(Markup::Node document) -> void override { + } + + auto unload() -> void override { + } + + auto read(uint16 address, uint8 data) -> uint8 override { + if(mode == 0 || mode == 1) { + if(address >> 14 == 0) data = rom.read((uint14)address + 16_KiB); + if(address >> 14 == 1) data = rom.read((uint14)address); + if(address >> 14 == 2) data = rom.read((uint14)address + 16_KiB); + if(address >> 14 == 3) data = rom.read((uint14)address + 16_KiB); + } + + if(mode == 2) { + if(address >> 14 == 0) data = 0xff; + if(address >> 14 == 1) data = rom.read((uint14)address); + if(address >> 14 == 2) data = rom.read((uint14)address + 32_KiB); + if(address >> 14 == 3) data = 0xff; + } + + if(mode == 3) { + if(address >> 14 == 0) data = 0xff; + if(address >> 14 == 1) data = rom.read((uint14)address); + if(address >> 14 == 2) data = rom.read((uint14)address + 48_KiB); + if(address >> 14 == 3) data = 0xff; + } + + return data; + } + + auto write(uint16 address, uint8 data) -> void override { + mode = data; + } + + auto power() -> void override { + mode = 0; + } + + auto serialize(serializer& s) -> void override { + s.integer(mode); + } + + uint2 mode; +}; diff --git a/ares/msx/cartridge/board/konami-scc.cpp b/ares/msx/cartridge/board/konami-scc.cpp new file mode 100644 index 000000000..6e8a0c79d --- /dev/null +++ b/ares/msx/cartridge/board/konami-scc.cpp @@ -0,0 +1,252 @@ +//Konami (with Sound Creative Chip) + +struct KonamiSCC : Interface { + using Interface::Interface; + Memory::Readable rom; + Node::Stream stream; + + auto load(Markup::Node document) -> void override { + auto board = document["game/board"]; + Interface::load(rom, board["memory(type=ROM,content=Program)"]); + + stream = cartridge.node->append("SCC"); + stream->setChannels(1); + stream->setFrequency(system.colorburst() / 16.0); + stream->addHighPassFilter(20.0, 1); + } + + auto save(Markup::Node document) -> void override { + } + + auto unload() -> void override { + } + + auto main() -> void override { + int sample = 256 * 5; + + for(auto& voice : voices) { + if(voice.frequency <= 8) continue; //voice is halted when frequency < 9 + + voice.clock += 32; + while(voice.clock > voice.frequency) { + voice.clock -= voice.frequency + 1; + voice.counter++; + } + sample += voice.wave[voice.counter] * voice.volume * voice.key >> 3; + } + + stream->sample(mixer[sample] / 32768.0); + cartridge.step(16); + } + + auto read(uint16 address, uint8 data) -> uint8 override { + if(address >= 0x4000 && address <= 0x5fff) data = rom.read(bank[0] << 13 | (uint13)address); + if(address >= 0x6000 && address <= 0x7fff) data = rom.read(bank[1] << 13 | (uint13)address); + if(address >= 0x8000 && address <= 0x9fff) data = rom.read(bank[2] << 13 | (uint13)address); + if(address >= 0xa000 && address <= 0xbfff) data = rom.read(bank[3] << 13 | (uint13)address); + + if(address >= 0xc000 && address <= 0xdfff) data = rom.read(bank[0] << 13 | (uint13)address); + if(address >= 0xe000 && address <= 0xffff) data = rom.read(bank[1] << 13 | (uint13)address); + if(address >= 0x0000 && address <= 0x1fff) data = rom.read(bank[2] << 13 | (uint13)address); + if(address >= 0x2000 && address <= 0x3fff) data = rom.read(bank[3] << 13 | (uint13)address); + + address.bit(8) = 0; //SCC ignores A8 + + if(address >= 0x9800 && address <= 0x981f) { + data = voices[0].wave[address & 0x1f]; + if(test.bit(6)) data = voices[0].wave[address + voices[0].counter & 0x1f]; + } + + if(address >= 0x9820 && address <= 0x983f) { + data = voices[1].wave[address & 0x1f]; + if(test.bit(6)) data = voices[1].wave[address + voices[1].counter & 0x1f]; + } + + if(address >= 0x9840 && address <= 0x985f) { + data = voices[2].wave[address & 0x1f]; + if(test.bit(6)) data = voices[2].wave[address + voices[2].counter & 0x1f]; + } + + if(address >= 0x9860 && address <= 0x987f) { + data = voices[3].wave[address & 0x1f]; + if(test.bit(6) || test.bit(7)) data = voices[3].wave[address + voices[3 + test.bit(6)].counter & 0x1f]; + } + + if(address >= 0x9880 && address <= 0x98df) { + data = 0xff; + } + + if(address >= 0x98e0 && address <= 0x98ff) { + //reading the test register sets it to 0xff + data = test = 0xff; + } + + return data; + } + + auto write(uint16 address, uint8 data) -> void override { + if(address >= 0x5000 && address <= 0x57ff) bank[0] = data; + if(address >= 0x7000 && address <= 0x77ff) bank[1] = data; + if(address >= 0x9000 && address <= 0x97ff) bank[2] = data; + if(address >= 0xb000 && address <= 0xb7ff) bank[3] = data; + + address.bit(8) = 0; //SCC ignores A8 + + if(address >= 0x9800 && address <= 0x981f && !test.bit(6)) { + voices[0].wave[address & 0x1f] = data; + } + + if(address >= 0x9820 && address <= 0x983f && !test.bit(6)) { + voices[1].wave[address & 0x1f] = data; + } + + if(address >= 0x9840 && address <= 0x985f && !test.bit(6)) { + voices[2].wave[address & 0x1f] = data; + } + + if(address >= 0x9860 && address <= 0x987f && !test.bit(6) && !test.bit(7)) { + voices[3].wave[address & 0x1f] = data; + voices[4].wave[address & 0x1f] = data; //shares data with wave channel 3 + } + + if(address == 0x9880) { + voices[0].frequency.bit(0, 7) = data.bit(0,7); + if(voices[0].frequency < 9) voices[0].clock = 0; + if(test.bit(5)) voices[0].clock = 0, voices[0].counter = 0; + } + + if(address == 0x9881) { + voices[0].frequency.bit(8,11) = data.bit(0,3); + if(voices[0].frequency < 9) voices[0].clock = 0; + if(test.bit(5)) voices[0].clock = 0, voices[0].counter = 0; + } + + if(address == 0x9882) { + voices[1].frequency.bit(0, 7) = data.bit(0,7); + if(voices[1].frequency < 9) voices[1].clock = 0; + if(test.bit(5)) voices[1].clock = 0, voices[1].counter = 0; + } + + if(address == 0x9883) { + voices[1].frequency.bit(8,11) = data.bit(0,3); + if(voices[1].frequency < 9) voices[1].clock = 0; + if(test.bit(5)) voices[1].clock = 0, voices[1].counter = 0; + } + + if(address == 0x9884) { + voices[2].frequency.bit(0, 7) = data.bit(0,7); + if(voices[2].frequency < 9) voices[2].clock = 0; + if(test.bit(5)) voices[2].clock = 0, voices[2].counter = 0; + } + + if(address == 0x9885) { + voices[2].frequency.bit(8,11) = data.bit(0,3); + if(voices[2].frequency < 9) voices[2].clock = 0; + if(test.bit(5)) voices[2].clock = 0, voices[2].counter = 0; + } + + if(address == 0x9886) { + voices[3].frequency.bit(0, 7) = data.bit(0,7); + if(voices[3].frequency < 9) voices[3].clock = 0; + if(test.bit(5)) voices[3].clock = 0, voices[3].counter = 0; + } + + if(address == 0x9887) { + voices[3].frequency.bit(8,11) = data.bit(0,3); + if(voices[3].frequency < 9) voices[3].clock = 0; + if(test.bit(5)) voices[3].clock = 0, voices[3].counter = 0; + } + + if(address == 0x9888) { + voices[4].frequency.bit(0, 7) = data.bit(0,7); + if(voices[4].frequency < 9) voices[4].clock = 0; + if(test.bit(5)) voices[4].clock = 0, voices[4].counter = 0; + } + + if(address == 0x9889) { + voices[4].frequency.bit(8,11) = data.bit(0,3); + if(voices[4].frequency < 9) voices[4].clock = 0; + if(test.bit(5)) voices[4].clock = 0, voices[4].counter = 0; + } + + if(address == 0x988a) { + voices[0].volume = data.bit(0,3); + } + + if(address == 0x988b) { + voices[1].volume = data.bit(0,3); + } + + if(address == 0x988c) { + voices[2].volume = data.bit(0,3); + } + + if(address == 0x988d) { + voices[3].volume = data.bit(0,3); + } + + if(address == 0x988e) { + voices[4].volume = data.bit(0,3); + } + + if(address == 0x988f) { + voices[0].key = data.bit(0); + voices[1].key = data.bit(1); + voices[2].key = data.bit(2); + voices[3].key = data.bit(3); + voices[4].key = data.bit(4); + } + + if(address >= 0x98e0 && address <= 0x98ff) test = data; + } + + auto power() -> void override { + bank[0] = 0; + bank[1] = 1; + bank[2] = 2; + bank[3] = 3; + voices[0] = {}; + voices[1] = {}; + voices[2] = {}; + voices[3] = {}; + voices[4] = {}; + test = 0; + + mixer.resize(512 * 5); + auto table = mixer.data() + 256 * 5; + for(int n : range(256 * 5)) { + int16 volume = n * 8 * 16 / 5; + table[+n] = +volume; + table[-n] = -volume; + } + } + + auto serialize(serializer& s) -> void override { + s.array(bank); + for(auto& voice : voices) { + s.integer(voice.clock); + s.integer(voice.frequency); + s.integer(voice.counter); + s.integer(voice.volume); + s.integer(voice.key); + s.array(voice.wave); + } + s.integer(test); + } + + uint8 bank[4]; + + struct Voice { + uint16 clock; + uint12 frequency; + uint5 counter; + uint4 volume; + uint1 key; + int8 wave[32]; + } voices[5]; + + uint8 test; + +//unserialized: + vector mixer; +}; diff --git a/ares/msx/cartridge/board/konami.cpp b/ares/msx/cartridge/board/konami.cpp new file mode 100644 index 000000000..8588fbfd4 --- /dev/null +++ b/ares/msx/cartridge/board/konami.cpp @@ -0,0 +1,45 @@ +//Konami (without Sound Creative Chip) + +struct Konami : Interface { + using Interface::Interface; + Memory::Readable rom; + + auto load(Markup::Node document) -> void override { + auto board = document["game/board"]; + Interface::load(rom, board["memory(type=ROM,content=Program)"]); + } + + auto save(Markup::Node document) -> void override { + } + + auto unload() -> void override { + } + + auto read(uint16 address, uint8 data) -> uint8 override { + if(address >> 13 == 2) data = rom.read(bank[0] << 13 | (uint13)address); + if(address >> 13 == 3) data = rom.read(bank[1] << 13 | (uint13)address); + if(address >> 13 == 4) data = rom.read(bank[2] << 13 | (uint13)address); + if(address >> 13 == 5) data = rom.read(bank[3] << 13 | (uint13)address); + return data; + } + + auto write(uint16 address, uint8 data) -> void override { + if(address >> 13 == 2) bank[0] = 0; + if(address >> 13 == 3) bank[1] = data; + if(address >> 13 == 4) bank[2] = data; + if(address >> 13 == 5) bank[3] = data; + } + + auto power() -> void override { + bank[0] = 0; + bank[1] = 1; + bank[2] = 0; + bank[3] = 0; + } + + auto serialize(serializer& s) -> void override { + s.array(bank); + } + + uint8 bank[4]; +}; diff --git a/ares/msx/cartridge/board/linear.cpp b/ares/msx/cartridge/board/linear.cpp new file mode 100644 index 000000000..b7a2832a2 --- /dev/null +++ b/ares/msx/cartridge/board/linear.cpp @@ -0,0 +1,29 @@ +struct Linear : Interface { + using Interface::Interface; + Memory::Readable rom; + + auto load(Markup::Node document) -> void override { + auto board = document["game/board"]; + Interface::load(rom, board["memory(type=ROM,content=Program)"]); + } + + auto save(Markup::Node document) -> void override { + } + + auto unload() -> void override { + } + + auto read(uint16 address, uint8 data) -> uint8 override { + data = rom.read(address); + return data; + } + + auto write(uint16 address, uint8 data) -> void override { + } + + auto power() -> void override { + } + + auto serialize(serializer& s) -> void override { + } +}; diff --git a/ares/msx/cartridge/board/super-lode-runner.cpp b/ares/msx/cartridge/board/super-lode-runner.cpp new file mode 100644 index 000000000..44c5186db --- /dev/null +++ b/ares/msx/cartridge/board/super-lode-runner.cpp @@ -0,0 +1,37 @@ +//Super Lode Runner +//(not working: requires MSX BASIC) + +struct SuperLodeRunner : Interface { + using Interface::Interface; + Memory::Readable rom; + + auto load(Markup::Node document) -> void override { + auto board = document["game/board"]; + Interface::load(rom, board["memory(type=ROM,content=Program)"]); + } + + auto save(Markup::Node document) -> void override { + } + + auto unload() -> void override { + } + + auto read(uint16 address, uint8 data) -> uint8 override { + if(address >= 0x8000 && address <= 0xbfff) data = rom.read(bank << 14 | (uint14)address); + return data; + } + + auto write(uint16 address, uint8 data) -> void override { + if(address >= 0x0000 && address <= 0x3fff) bank = data; + } + + auto power() -> void override { + bank = 0; + } + + auto serialize(serializer& s) -> void override { + s.integer(bank); + } + + uint8 bank; +}; diff --git a/ares/msx/cartridge/board/super-pierrot.cpp b/ares/msx/cartridge/board/super-pierrot.cpp new file mode 100644 index 000000000..825ebb5b9 --- /dev/null +++ b/ares/msx/cartridge/board/super-pierrot.cpp @@ -0,0 +1,47 @@ +//Super Pierrot +//(not working) + +struct SuperPierrot : Interface { + using Interface::Interface; + Memory::Readable rom; + + auto load(Markup::Node document) -> void override { + auto board = document["game/board"]; + Interface::load(rom, board["memory(type=ROM,content=Program)"]); + } + + auto save(Markup::Node document) -> void override { + } + + auto unload() -> void override { + } + + auto read(uint16 address, uint8 data) -> uint8 override { + if(address >= 0x4000 && address <= 0x7fff) data = rom.read(bank[0] << 14 | (uint14)address); + if(address >= 0x8000 && address <= 0xbfff) data = rom.read(bank[1] << 14 | (uint14)address); + return data; + } + + auto write(uint16 address, uint8 data) -> void override { + if(address >= 0x4000 && address <= 0x4fff) bank[0] = data; + if(address >= 0x6000 && address <= 0x6fff) bank[0] = data; + if(address >= 0x8000 && address <= 0x8fff) bank[0] = data; + if(address >= 0xa000 && address <= 0xafff) bank[0] = data; + + if(address >= 0x5000 && address <= 0x5fff) bank[1] = data; + if(address >= 0x7000 && address <= 0x7fff) bank[1] = data; + if(address >= 0x9000 && address <= 0x9fff) bank[1] = data; + if(address >= 0xa000 && address <= 0xafff) bank[1] = data; + } + + auto power() -> void override { + bank[0] = 0; + bank[1] = 0; + } + + auto serialize(serializer& s) -> void override { + s.array(bank); + } + + uint8 bank[2]; +}; diff --git a/ares/msx/cartridge/cartridge.cpp b/ares/msx/cartridge/cartridge.cpp index 3100ea951..dc340e9e2 100644 --- a/ares/msx/cartridge/cartridge.cpp +++ b/ares/msx/cartridge/cartridge.cpp @@ -4,6 +4,7 @@ namespace ares::MSX { Cartridge& cartridge = cartridgeSlot.cartridge; Cartridge& expansion = expansionSlot.cartridge; +#include "board/board.cpp" #include "slot.cpp" #include "serialization.cpp" @@ -23,87 +24,56 @@ auto Cartridge::connect() -> void { auto document = BML::unserialize(information.manifest); information.name = document["game/label"].string(); information.region = document["game/region"].string(); + information.board = document["game/board"].string(); - if(auto memory = document["game/board/memory(type=ROM,content=Program)"]) { - rom.allocate(memory["size"].natural()); - if(auto fp = platform->open(node, "program.rom", File::Read, File::Required)) { - rom.load(fp); - } - } - - if(auto memory = document["game/board/memory(type=RAM,content=Save)"]) { - ram.allocate(memory["size"].natural()); - if(auto fp = platform->open(node, "save.ram", File::Read)) { - ram.load(fp); - } - } + if(information.board == "ASC16") board = new Board::ASC16{*this}; + if(information.board == "ASC8") board = new Board::ASC8{*this}; + if(information.board == "CrossBlaim") board = new Board::CrossBlaim{*this}; + if(information.board == "Konami") board = new Board::Konami{*this}; + if(information.board == "KonamiSCC") board = new Board::KonamiSCC{*this}; + if(information.board == "Linear") board = new Board::Linear{*this}; + if(information.board == "SuperLodeRunner") board = new Board::SuperLodeRunner{*this}; + if(information.board == "SuperPierrot") board = new Board::SuperPierrot{*this}; + if(!board) board = new Board::KonamiSCC{*this}; + board->load(document); power(); } auto Cartridge::disconnect() -> void { if(!node) return; - save(); - rom.reset(); - ram.reset(); - node = {}; + if(board) board->unload(), board.reset(); + node.reset(); } auto Cartridge::save() -> void { if(!node) return; auto document = BML::unserialize(information.manifest); + board->save(document); +} - if(auto memory = document["game/board/memory(type=RAM,content=Save)"]) { - if(auto fp = platform->open(node, "save.ram", File::Write)) { - ram.save(fp); - } - } +auto Cartridge::main() -> void { + if(board) return board->main(); + step(system.colorburst()); +} + +auto Cartridge::step(uint clocks) -> void { + Thread::step(clocks); + Thread::synchronize(cpu); } auto Cartridge::power() -> void { + Thread::create(system.colorburst(), {&Cartridge::main, this}); + if(board) board->power(); } -uint2 RB; //Cross Blaim -uint8 B8K[4]={0,1,0,0}; //Konami 8K (non-SCC) - auto Cartridge::read(uint16 address) -> uint8 { - if(!rom) return 0xff; - -/* -if(RB==0||RB==1){ - if(address>>14==0)return rom.read((uint14)address+16_KiB); - if(address>>14==1)return rom.read((uint14)address); - if(address>>14==2)return rom.read((uint14)address+16_KiB); - if(address>>14==3)return rom.read((uint14)address+16_KiB); -} -if(RB==2){ - if(address>>14==0)return 0xff; - if(address>>14==1)return rom.read((uint14)address); - if(address>>14==2)return rom.read((uint14)address+32_KiB); - if(address>>14==3)return 0xff; -} -if(RB==3){ - if(address>>14==0)return 0xff; - if(address>>14==1)return rom.read((uint14)address); - if(address>>14==2)return rom.read((uint14)address+48_KiB); - if(address>>14==3)return 0xff; -} -*/ - -if(address>>13==2)return rom.read(B8K[0]<<13|(uint13)address); -if(address>>13==3)return rom.read(B8K[1]<<13|(uint13)address); -if(address>>13==4)return rom.read(B8K[2]<<13|(uint13)address); -if(address>>13==5)return rom.read(B8K[3]<<13|(uint13)address); - - return rom.read(address); + if(board) return board->read(address, 0xff); + return 0xff; } auto Cartridge::write(uint16 address, uint8 data) -> void { - RB = data; -if(address>>13==2)B8K[0]=0; -if(address>>13==3)B8K[1]=data; -if(address>>13==4)B8K[2]=data; -if(address>>13==5)B8K[3]=data; + if(board) return board->write(address, data); } } diff --git a/ares/msx/cartridge/cartridge.hpp b/ares/msx/cartridge/cartridge.hpp index c452a465c..3d05f9bd4 100644 --- a/ares/msx/cartridge/cartridge.hpp +++ b/ares/msx/cartridge/cartridge.hpp @@ -1,4 +1,7 @@ -struct Cartridge { +struct Cartridge; +#include "board/board.hpp" + +struct Cartridge : Thread { Node::Peripheral node; Memory::Readable rom; Memory::Writable ram; @@ -13,6 +16,8 @@ struct Cartridge { auto disconnect() -> void; auto save() -> void; + auto main() -> void; + auto step(uint clocks) -> void; auto power() -> void; auto read(uint16 address) -> uint8; @@ -21,11 +26,14 @@ struct Cartridge { //serialization.cpp auto serialize(serializer&) -> void; + unique_pointer board; + private: struct Information { string manifest; string name; string region; + string board; } information; }; diff --git a/ares/msx/cartridge/serialization.cpp b/ares/msx/cartridge/serialization.cpp index 13665ef9a..a6c7f158d 100644 --- a/ares/msx/cartridge/serialization.cpp +++ b/ares/msx/cartridge/serialization.cpp @@ -1,3 +1,3 @@ auto Cartridge::serialize(serializer& s) -> void { - if(ram) s.array(ram.data(), ram.size()); + if(board) board->serialize(s); } diff --git a/ares/ps1/GNUmakefile b/ares/ps1/GNUmakefile index e3e9825b6..bb3bc60ac 100644 --- a/ares/ps1/GNUmakefile +++ b/ares/ps1/GNUmakefile @@ -1,5 +1,6 @@ ares.objects += ares-ps1-interface ares-ps1-memory ares-ps1-system ares.objects += ares-ps1-disc ares-ps1-cpu ares-ps1-gpu ares-ps1-spu +ares.objects += ares-ps1-irq ares-ps1-dma ares-ps1-timer $(object.path)/ares-ps1-interface.o: $(ares.path)/ps1/interface/interface.cpp $(object.path)/ares-ps1-memory.o: $(ares.path)/ps1/memory/memory.cpp @@ -8,3 +9,6 @@ $(object.path)/ares-ps1-disc.o: $(ares.path)/ps1/disc/disc.cpp $(object.path)/ares-ps1-cpu.o: $(ares.path)/ps1/cpu/cpu.cpp $(object.path)/ares-ps1-gpu.o: $(ares.path)/ps1/gpu/gpu.cpp $(object.path)/ares-ps1-spu.o: $(ares.path)/ps1/spu/spu.cpp +$(object.path)/ares-ps1-irq.o: $(ares.path)/ps1/irq/irq.cpp +$(object.path)/ares-ps1-dma.o: $(ares.path)/ps1/dma/dma.cpp +$(object.path)/ares-ps1-timer.o: $(ares.path)/ps1/timer/timer.cpp diff --git a/ares/ps1/cpu/core/disassembler.hpp b/ares/ps1/cpu/core/disassembler.hpp index c05ba76d3..cb5907f32 100644 --- a/ares/ps1/cpu/core/disassembler.hpp +++ b/ares/ps1/cpu/core/disassembler.hpp @@ -7,7 +7,7 @@ auto disassemble(u32 address, u32 instruction) -> string; template auto hint(P&&... p) const -> string; - bool showColors = false; + bool showColors = true; bool showValues = true; //private: diff --git a/ares/ps1/cpu/cpu.cpp b/ares/ps1/cpu/cpu.cpp index c357ac1c7..ab379948e 100644 --- a/ares/ps1/cpu/cpu.cpp +++ b/ares/ps1/cpu/cpu.cpp @@ -4,8 +4,6 @@ namespace ares::PlayStation { CPU cpu; #include "core/core.cpp" -#include "interrupt.cpp" -#include "dma.cpp" #include "debugger.cpp" #include "serialization.cpp" @@ -28,10 +26,14 @@ auto CPU::main() -> void { } auto CPU::step(uint clocks) -> void { - gpu.clock -= clocks; - spu.clock -= clocks; - while(gpu.clock < 0) gpu.main(); - while(spu.clock < 0) spu.main(); + dma.step(clocks); + timer.step(clocks); + gpu.clock -= clocks; + spu.clock -= clocks; + disc.clock -= clocks; + while(gpu.clock < 0) gpu.main(); + while(spu.clock < 0) spu.main(); + while(disc.clock < 0) disc.main(); } auto CPU::power(bool reset) -> void { @@ -39,7 +41,6 @@ auto CPU::power(bool reset) -> void { powerCore(reset); ram.fill(); cache.fill(); - dma.power(reset); } } diff --git a/ares/ps1/cpu/cpu.hpp b/ares/ps1/cpu/cpu.hpp index 4eb3cdc40..7c8316e99 100644 --- a/ares/ps1/cpu/cpu.hpp +++ b/ares/ps1/cpu/cpu.hpp @@ -37,97 +37,6 @@ struct CPU : Thread { auto serialize(serializer&) -> void; #include "core/core.hpp" - - struct Interrupt { - enum : uint { Vblank, GPU, CDROM, DMA, Timer0, Timer1, Timer2, Peripheral, SIO, SPU, PIO }; - - CPU& self; - Interrupt(CPU& self) : self(self) {} - - //interrupt.cpp - auto poll() -> void; - auto pulse(uint source) -> void; - auto raise(uint source) -> void; - auto lower(uint source) -> void; - - auto readByte(u32 address) -> u8; - auto readHalf(u32 address) -> u16; - auto readWord(u32 address) -> u32; - auto writeByte(u32 address, u8 data) -> void; - auto writeHalf(u32 address, u16 data) -> void; - auto writeWord(u32 address, u32 data) -> void; - - struct Source { - uint1 line = 0; - uint1 stat = 0; - uint1 mask = 0; - }; - - uint1 line = 0; - Source vblank; - Source gpu; - Source cdrom; - Source dma; - Source timer0; - Source timer1; - Source timer2; - Source peripheral; - Source sio; - Source spu; - Source pio; - } interrupt{*this}; - - struct DMA { - enum : uint { MDECIN, MDECOUT, GPU, CDROM, SPU, PIO, OTC }; //channels - - CPU& self; - DMA(CPU& self) : self(self) {} - - //dma.cpp - auto readByte(u32 address) -> u8; - auto readHalf(u32 address) -> u16; - auto readWord(u32 address) -> u32; - auto writeByte(u32 address, u8 data) -> void; - auto writeHalf(u32 address, u16 data) -> void; - auto writeWord(u32 address, u32 data) -> void; - auto transferLinear(uint c) -> void; - auto transferLinked(uint c) -> void; - auto pollIRQ() -> void; - auto power(bool reset) -> void; - - struct IRQ { - uint1 force; - uint1 enable; - uint1 flag; - uint6 unknown; - } irq; - - struct Channel { - //dma.cpp - auto active() const -> bool; - - uint1 masterEnable; - uint3 priority; - uint24 address; - uint16 length; - uint16 blocks; - uint1 direction; - uint1 step; //0 = increment; 1 = decrement - uint2 synchronization; - struct Chopping { - uint1 enable; - uint3 dmaWindow; - uint3 cpuWindow; - } chopping; - uint1 enable; - uint1 trigger; - uint2 unknown; - struct IRQ { - uint1 enable; - uint1 flag; - } irq; - } channel[7]; - } dma{*this}; }; extern CPU cpu; diff --git a/ares/ps1/cpu/interrupt.cpp b/ares/ps1/cpu/interrupt.cpp deleted file mode 100644 index 92783906e..000000000 --- a/ares/ps1/cpu/interrupt.cpp +++ /dev/null @@ -1,145 +0,0 @@ -auto CPU::Interrupt::poll() -> void { - line = 0; - line |= vblank.stat & vblank.mask; - line |= gpu.stat & gpu.mask; - line |= cdrom.stat & cdrom.mask; - line |= dma.stat & dma.mask; - line |= timer0.stat & timer0.mask; - line |= timer1.stat & timer1.mask; - line |= timer2.stat & timer2.mask; - line |= peripheral.stat & peripheral.mask; - line |= sio.stat & sio.mask; - line |= spu.stat & spu.mask; - line |= pio.stat & pio.mask; - self.scc.cause.interruptPending.bit(2) = line; -} - -auto CPU::Interrupt::pulse(uint source) -> void { - raise(source); - lower(source); -} - -auto CPU::Interrupt::raise(uint source) -> void { - if(source == 0 && !vblank.line) vblank.line = vblank.stat = 1; - if(source == 1 && !gpu.line) gpu.line = gpu.stat = 1; - if(source == 2 && !cdrom.line) cdrom.line = cdrom.stat = 1; - if(source == 3 && !dma.line) dma.line = dma.stat = 1; - if(source == 4 && !timer0.line) timer0.line = timer0.stat = 1; - if(source == 5 && !timer1.line) timer1.line = timer1.stat = 1; - if(source == 6 && !timer2.line) timer2.line = timer2.stat = 1; - if(source == 7 && !peripheral.line) peripheral.line = peripheral.stat = 1; - if(source == 8 && !sio.line) sio.line = sio.stat = 1; - if(source == 9 && !spu.line) spu.line = spu.stat = 1; - if(source == 10 && !pio.line) pio.line = pio.stat = 1; - poll(); -} - -auto CPU::Interrupt::lower(uint source) -> void { - if(source == 0) vblank.line = 0; - if(source == 1) gpu.line = 0; - if(source == 2) cdrom.line = 0; - if(source == 3) dma.line = 0; - if(source == 4) timer0.line = 0; - if(source == 5) timer1.line = 0; - if(source == 6) timer2.line = 0; - if(source == 7) peripheral.line = 0; - if(source == 8) sio.line = 0; - if(source == 9) spu.line = 0; - if(source == 10) pio.line = 0; - poll(); -} - -auto CPU::Interrupt::readByte(u32 address) -> u8 { - uint8 data = 0; - print("* read byte ", hex(address, 8L), "\n"); - return data; -} - -auto CPU::Interrupt::readHalf(u32 address) -> u16 { - uint16 data = 0; - - //I_STAT - if(address == 0x1f80'1070) { - data.bit( 0) = vblank.stat; - data.bit( 1) = gpu.stat; - data.bit( 2) = cdrom.stat; - data.bit( 3) = dma.stat; - data.bit( 4) = timer0.stat; - data.bit( 5) = timer1.stat; - data.bit( 6) = timer2.stat; - data.bit( 7) = peripheral.stat; - data.bit( 8) = sio.stat; - data.bit( 9) = spu.stat; - data.bit(10) = pio.stat; - } - - //I_MASK - if(address == 0x1f80'1074) { - data.bit( 0) = vblank.mask; - data.bit( 1) = gpu.mask; - data.bit( 2) = cdrom.mask; - data.bit( 3) = dma.mask; - data.bit( 4) = timer0.mask; - data.bit( 5) = timer1.mask; - data.bit( 6) = timer2.mask; - data.bit( 7) = peripheral.mask; - data.bit( 8) = sio.mask; - data.bit( 9) = spu.mask; - data.bit(10) = pio.mask; - } - - return data; -} - -auto CPU::Interrupt::readWord(u32 address) -> u32 { - uint32 data = 0; - data |= readHalf(address & ~3 | 0) << 0; - data |= readHalf(address & ~3 | 2) << 16; - return data; -} - -auto CPU::Interrupt::writeByte(u32 address, u8 value) -> void { - uint8 data = value; - print("* write byte ", hex(address, 8L), " = ", hex(value, 2L), "\n"); -} - -auto CPU::Interrupt::writeHalf(u32 address, u16 value) -> void { - uint16 data = value; - - //I_STAT - if(address == 0x1f80'1070) { - if(!data.bit( 0)) vblank.stat = 0; - if(!data.bit( 1)) gpu.stat = 0; - if(!data.bit( 2)) cdrom.stat = 0; - if(!data.bit( 3)) dma.stat = 0; - if(!data.bit( 4)) timer0.stat = 0; - if(!data.bit( 5)) timer1.stat = 0; - if(!data.bit( 6)) timer2.stat = 0; - if(!data.bit( 7)) peripheral.stat = 0; - if(!data.bit( 8)) sio.stat = 0; - if(!data.bit( 9)) spu.stat = 0; - if(!data.bit(10)) pio.stat = 0; - poll(); - } - - //I_MASK - if(address == 0x1f80'1074) { - vblank.mask = data.bit( 0); - gpu.mask = data.bit( 1); - cdrom.mask = data.bit( 2); - dma.mask = data.bit( 3); - timer0.mask = data.bit( 4); - timer1.mask = data.bit( 5); - timer2.mask = data.bit( 6); - peripheral.mask = data.bit( 7); - sio.mask = data.bit( 8); - spu.mask = data.bit( 9); - pio.mask = data.bit(10); - poll(); - } -} - -auto CPU::Interrupt::writeWord(u32 address, u32 data) -> void { - writeHalf(address & ~3 | 0, data >> 0); - writeHalf(address & ~3 | 2, data >> 16); -} diff --git a/ares/ps1/disc/command.cpp b/ares/ps1/disc/command.cpp index a33385817..95ca56ba7 100644 --- a/ares/ps1/disc/command.cpp +++ b/ares/ps1/disc/command.cpp @@ -3,7 +3,10 @@ auto Disc::command(u8 operation) -> void { switch(operation) { case 0x01: return commandGetStatus(); + case 0x13: return commandGetFirstAndLastTrackNumbers(); + case 0x14: return commandGetTrackStart(); case 0x19: return commandTest(); + case 0x1a: return commandGetID(); } } @@ -21,8 +24,25 @@ auto Disc::commandGetStatus() -> void { fifo.response.write(data); ssr.shellOpen = 0; - irq.acknowledge.flag = 1; - irq.poll(); + irq.acknowledge.delay = 3; +} + +//0x13 +auto Disc::commandGetFirstAndLastTrackNumbers() -> void { + fifo.response.write(0x00); + fifo.response.write(0x01); + fifo.response.write(0x01); + + irq.acknowledge.delay = 3; +} + +//0x14 +auto Disc::commandGetTrackStart() -> void { + fifo.response.write(0x00); + fifo.response.write(0x00); + fifo.response.write(0x00); + + irq.acknowledge.delay = 3; } //0x19 @@ -40,6 +60,22 @@ auto Disc::commandTestControllerDate() -> void { fifo.response.write(0x16); fifo.response.write(0xc1); - irq.acknowledge.flag = 1; - irq.poll(); + irq.acknowledge.delay = 3; +} + +//0x1a +auto Disc::commandGetID() -> void { +/* + fifo.response.write(0x0a); + fifo.response.write(0x90); + fifo.response.write(0x00); + fifo.response.write(0x00); + fifo.response.write(0x00); + fifo.response.write(0x00); + fifo.response.write(0x00); + fifo.response.write(0x00); +*/ + + irq.acknowledge.delay = 3; + irq.error.delay = 3; } diff --git a/ares/ps1/disc/disc.cpp b/ares/ps1/disc/disc.cpp index 69ef57333..c0706186f 100644 --- a/ares/ps1/disc/disc.cpp +++ b/ares/ps1/disc/disc.cpp @@ -69,6 +69,22 @@ auto Disc::disconnect() -> void { } auto Disc::main() -> void { + if(irq.acknowledge.delay && !--irq.acknowledge.delay) { + irq.acknowledge.flag = 1; + irq.poll(); + } else if(irq.error.delay && !--irq.error.delay) { + fifo.response.write(0x0a); + fifo.response.write(0x90); + fifo.response.write(0x00); + fifo.response.write(0x00); + fifo.response.write(0x00); + fifo.response.write(0x00); + fifo.response.write(0x00); + fifo.response.write(0x00); + + irq.error.flag = 1; + irq.poll(); + } step(33'868'800 / 75); } @@ -76,7 +92,7 @@ auto Disc::step(uint clocks) -> void { Thread::clock += clocks; } -auto Disc::power() -> void { +auto Disc::power(bool reset) -> void { Thread::reset(); io = {}; } diff --git a/ares/ps1/disc/disc.hpp b/ares/ps1/disc/disc.hpp index 64a804271..2d809d751 100644 --- a/ares/ps1/disc/disc.hpp +++ b/ares/ps1/disc/disc.hpp @@ -18,7 +18,7 @@ struct Disc : Thread { auto main() -> void; auto step(uint clocks) -> void; - auto power() -> void; + auto power(bool reset) -> void; //io.cpp auto readByte(u32 address) -> u32; @@ -31,8 +31,11 @@ struct Disc : Thread { //command.cpp auto command(u8 operation) -> void; auto commandGetStatus() -> void; + auto commandGetFirstAndLastTrackNumbers() -> void; + auto commandGetTrackStart() -> void; auto commandTest() -> void; auto commandTestControllerDate() -> void; + auto commandGetID() -> void; //serialization.cpp auto serialize(serializer&) -> void; @@ -42,25 +45,26 @@ struct Disc : Thread { string name; } information; - struct Interrupt { - uint1 enable; - uint1 flag; - }; - struct IRQ { //irq.cpp auto poll() -> void; + struct Source { + uint1 enable; + uint1 flag; + uint32 delay; + }; + uint5 flag; uint5 mask; - Interrupt ready; //INT1 - Interrupt complete; //INT2 - Interrupt acknowledge; //INT3 - Interrupt end; //INT4 - Interrupt error; //INT5 - Interrupt unknown; //INT8 - Interrupt start; //INT10 + Source ready; //INT1 + Source complete; //INT2 + Source acknowledge; //INT3 + Source end; //INT4 + Source error; //INT5 + Source unknown; //INT8 + Source start; //INT10 } irq; struct FIFO { diff --git a/ares/ps1/disc/irq.cpp b/ares/ps1/disc/irq.cpp index df05df50e..44ed91429 100644 --- a/ares/ps1/disc/irq.cpp +++ b/ares/ps1/disc/irq.cpp @@ -6,6 +6,6 @@ auto Disc::IRQ::poll() -> void { pending |= end.flag & end.enable; pending |= error.flag & error.enable; - if(pending == 0) cpu.interrupt.lower(CPU::Interrupt::CDROM); - if(pending == 1) cpu.interrupt.raise(CPU::Interrupt::CDROM), print("* IRQ\n"); + if(pending == 0) interrupt.lower(Interrupt::CDROM); + if(pending == 1) interrupt.raise(Interrupt::CDROM), print("* IRQ\n"); } diff --git a/ares/ps1/dma/dma.cpp b/ares/ps1/dma/dma.cpp new file mode 100644 index 000000000..714a1dca4 --- /dev/null +++ b/ares/ps1/dma/dma.cpp @@ -0,0 +1,36 @@ +#include + +namespace ares::PlayStation { + +DMA dma; +#include "io.cpp" +#include "transfer.cpp" +#include "serialization.cpp" + +auto DMA::load(Node::Object parent) -> void { + node = parent->append("DMA"); +} + +auto DMA::unload() -> void { + node.reset(); +} + +auto DMA::step(uint clocks) -> void { +} + +auto DMA::pollIRQ() -> void { + irq.flag = irq.force; + if(!irq.enable) return; + for(uint n : range(7)) { + if(channel[n].irq.flag & channel[n].irq.enable) irq.flag = 1; + } +} + +auto DMA::power(bool reset) -> void { + for(uint n : range(7)) { + channel[n].priority = 1 + n; + channel[n].masterEnable = 0; + } +} + +} diff --git a/ares/ps1/dma/dma.hpp b/ares/ps1/dma/dma.hpp new file mode 100644 index 000000000..420ff35ee --- /dev/null +++ b/ares/ps1/dma/dma.hpp @@ -0,0 +1,66 @@ +struct DMA { + Node::Component node; + + //dma.cpp + auto load(Node::Object) -> void; + auto unload() -> void; + + auto step(uint clocks) -> void; + auto pollIRQ() -> void; + auto power(bool reset) -> void; + + //io.cpp + auto readByte(u32 address) -> u32; + auto readHalf(u32 address) -> u32; + auto readWord(u32 address) -> u32; + auto writeByte(u32 address, u32 data) -> void; + auto writeHalf(u32 address, u32 data) -> void; + auto writeWord(u32 address, u32 data) -> void; + + //transfer.cpp + auto transferLinear(uint c) -> void; + auto transferLinked(uint c) -> void; + + //serialization.cpp + auto serialize(serializer&) -> void; + + enum : uint { MDECIN, MDECOUT, GPU, CDROM, SPU, PIO, OTC }; //channels + + struct IRQ { + uint1 force; + uint1 enable; + uint1 flag; + uint6 unknown; + } irq; + + struct Channel { + //dma.cpp + auto active() const -> bool { + if(synchronization == 0) return enable && trigger; + return enable; + } + + uint1 masterEnable; + uint3 priority; + uint24 address; + uint16 length; + uint16 blocks; + uint1 direction; + uint1 step; //0 = increment; 1 = decrement + uint2 synchronization; + struct Chopping { + uint1 enable; + uint3 dmaWindow; + uint3 cpuWindow; + } chopping; + uint1 enable; + uint1 trigger; + uint2 unknown; + struct IRQ { + uint1 enable; + uint1 flag; + } irq; + } channel[7]; +}; + +extern DMA dma; diff --git a/ares/ps1/cpu/dma.cpp b/ares/ps1/dma/io.cpp similarity index 67% rename from ares/ps1/cpu/dma.cpp rename to ares/ps1/dma/io.cpp index 2890908a4..888fbed01 100644 --- a/ares/ps1/cpu/dma.cpp +++ b/ares/ps1/dma/io.cpp @@ -1,15 +1,15 @@ -auto CPU::DMA::readByte(u32 address) -> u8 { - print("* read byte ", hex(address, 8L), "\n"); +auto DMA::readByte(u32 address) -> u32 { + print("* rb", hex(address, 8L), "\n"); return 0; } -auto CPU::DMA::readHalf(u32 address) -> u16 { - print("* read half ", hex(address, 8L), "\n"); +auto DMA::readHalf(u32 address) -> u32 { + print("* rh", hex(address, 8L), "\n"); return 0; } -auto CPU::DMA::readWord(u32 address) -> u32 { - uint32 data = 0; +auto DMA::readWord(u32 address) -> u32 { + uint32 data; uint32 c = address >> 4 & 7; //DnMADR: DMA Base Address @@ -78,15 +78,15 @@ auto CPU::DMA::readWord(u32 address) -> u32 { return data; } -auto CPU::DMA::writeByte(u32 address, u8 value) -> void { - print("* write byte ", hex(address, 8L), " = ", hex(value, 2L), "\n"); +auto DMA::writeByte(u32 address, u32 value) -> void { + print("* wb", hex(address, 8L), " = ", hex(value, 2L), "\n"); } -auto CPU::DMA::writeHalf(u32 address, u16 value) -> void { - print("* write half ", hex(address, 8L), " = ", hex(value, 4L), "\n"); +auto DMA::writeHalf(u32 address, u32 value) -> void { + print("* wh", hex(address, 8L), " = ", hex(value, 4L), "\n"); } -auto CPU::DMA::writeWord(u32 address, u32 value) -> void { +auto DMA::writeWord(u32 address, u32 value) -> void { uint32 data = value; uint32 c = address >> 4 & 7; @@ -120,7 +120,7 @@ auto CPU::DMA::writeWord(u32 address, u32 value) -> void { if(channel[c].synchronization == 0) transferLinear(c); if(channel[c].synchronization == 1) transferLinear(c); if(channel[c].synchronization == 2) transferLinked(c); - self.interrupt.pulse(CPU::Interrupt::DMA); + interrupt.pulse(Interrupt::DMA); } } @@ -164,78 +164,3 @@ auto CPU::DMA::writeWord(u32 address, u32 value) -> void { pollIRQ(); } } - -auto CPU::DMA::transferLinear(uint c) -> void { - u32 address = channel[c].address; - u16 blocks = channel[c].synchronization == 0 ? uint16(1) : channel[c].blocks; - - do { - u16 length = channel[c].length; - do { - if(channel[c].direction == 0) { - u32 data = 0; - if(c == 6) { - data = address - 4 & 0xfffffc; //point to previous entry - if(length == 1) data = 0xffffff; //end of ordering table - } - bus.writeWord(address, data); - } - - if(channel[c].direction == 1) { - u32 data = bus.readWord(address); - if(c == 2) { - gpu.gp0(data); - } - } - - if(channel[c].step == 0) address += 4; - if(channel[c].step == 1) address -= 4; - } while(--length); - } while(--blocks); - channel[c].enable = 0; - channel[c].trigger = 0; -} - -auto CPU::DMA::transferLinked(uint c) -> void { - if(channel[c].direction == 0) return; //invalid direction for this mode - - u32 address = channel[c].address; - u32 timeout = 0x40000; //unverified; prevents potential infinite loop - do { - u32 header = bus.readWord(address); - - for(uint count : range(header >> 24)) { - address += 4; - u32 data = bus.readWord(address); - - if(c == 2) { - gpu.gp0(data); - } - } - - address = header & 0xffffff; - if(address & 0x800000) break; - } while(--timeout); - channel[c].enable = 0; - channel[c].trigger = 0; -} - -auto CPU::DMA::pollIRQ() -> void { - irq.flag = irq.force; - if(!irq.enable) return; - for(uint n : range(7)) { - if(channel[n].irq.flag & channel[n].irq.enable) irq.flag = 1; - } -} - -auto CPU::DMA::power(bool reset) -> void { - for(uint n : range(7)) { - channel[n].priority = 1 + n; - channel[n].masterEnable = 0; - } -} - -auto CPU::DMA::Channel::active() const -> bool { - if(synchronization == 0) return enable && trigger; - return enable; -} diff --git a/ares/ps1/dma/serialization.cpp b/ares/ps1/dma/serialization.cpp new file mode 100644 index 000000000..1e9a0dfd5 --- /dev/null +++ b/ares/ps1/dma/serialization.cpp @@ -0,0 +1,2 @@ +auto DMA::serialize(serializer& s) -> void { +} diff --git a/ares/ps1/dma/transfer.cpp b/ares/ps1/dma/transfer.cpp new file mode 100644 index 000000000..1a54878a1 --- /dev/null +++ b/ares/ps1/dma/transfer.cpp @@ -0,0 +1,54 @@ +auto DMA::transferLinear(uint c) -> void { + u32 address = channel[c].address; + u16 blocks = channel[c].synchronization == 0 ? uint16(1) : channel[c].blocks; + + do { + u16 length = channel[c].length; + do { + if(channel[c].direction == 0) { + u32 data = 0; + if(c == 6) { + data = address - 4 & 0xfffffc; //point to previous entry + if(length == 1) data = 0xffffff; //end of ordering table + } + bus.writeWord(address, data); + } + + if(channel[c].direction == 1) { + u32 data = bus.readWord(address); + if(c == 2) { + gpu.gp0(data); + } + } + + if(channel[c].step == 0) address += 4; + if(channel[c].step == 1) address -= 4; + } while(--length); + } while(--blocks); + channel[c].enable = 0; + channel[c].trigger = 0; +} + +auto DMA::transferLinked(uint c) -> void { + if(channel[c].direction == 0) return; //invalid direction for this mode + + u32 address = channel[c].address; + u32 timeout = 0x40000; //unverified; prevents potential infinite loop + do { + u32 header = bus.readWord(address); + + for(uint count : range(header >> 24)) { + address += 4; + u32 data = bus.readWord(address); + + if(c == 2) { + gpu.gp0(data); + } + } + + address = header & 0xffffff; + if(address & 0x800000) break; + } while(--timeout); + channel[c].enable = 0; + channel[c].trigger = 0; +} diff --git a/ares/ps1/gpu/gpu.cpp b/ares/ps1/gpu/gpu.cpp index bf11098b9..5e79d7027 100644 --- a/ares/ps1/gpu/gpu.cpp +++ b/ares/ps1/gpu/gpu.cpp @@ -36,13 +36,13 @@ auto GPU::unload() -> void { auto GPU::main() -> void { if(io.vcounter == 240) { - cpu.interrupt.raise(CPU::Interrupt::Vblank); + interrupt.raise(Interrupt::Vblank); } if(++io.vcounter == 262) { io.vcounter = 0; io.field = !io.field; - cpu.interrupt.lower(CPU::Interrupt::Vblank); + interrupt.lower(Interrupt::Vblank); refreshed = true; } diff --git a/ares/ps1/irq/io.cpp b/ares/ps1/irq/io.cpp new file mode 100644 index 000000000..0af1572cd --- /dev/null +++ b/ares/ps1/irq/io.cpp @@ -0,0 +1,90 @@ +auto Interrupt::readByte(u32 address) -> u32 { + print("* rb", hex(address, 8L), "\n"); + return 0; +} + +auto Interrupt::readHalf(u32 address) -> u32 { + uint16 data; + + //I_STAT + if(address == 0x1f80'1070) { + data.bit( 0) = vblank.stat; + data.bit( 1) = gpu.stat; + data.bit( 2) = cdrom.stat; + data.bit( 3) = dma.stat; + data.bit( 4) = timer0.stat; + data.bit( 5) = timer1.stat; + data.bit( 6) = timer2.stat; + data.bit( 7) = peripheral.stat; + data.bit( 8) = sio.stat; + data.bit( 9) = spu.stat; + data.bit(10) = pio.stat; + } + + //I_MASK + if(address == 0x1f80'1074) { + data.bit( 0) = vblank.mask; + data.bit( 1) = gpu.mask; + data.bit( 2) = cdrom.mask; + data.bit( 3) = dma.mask; + data.bit( 4) = timer0.mask; + data.bit( 5) = timer1.mask; + data.bit( 6) = timer2.mask; + data.bit( 7) = peripheral.mask; + data.bit( 8) = sio.mask; + data.bit( 9) = spu.mask; + data.bit(10) = pio.mask; + } + + return data; +} + +auto Interrupt::readWord(u32 address) -> u32 { + uint32 data = readHalf(address & ~3 | 0) << 0; + return data | readHalf(address & ~3 | 2) << 16; +} + +auto Interrupt::writeByte(u32 address, u32 value) -> void { + print("* wb", hex(address, 8L), " = ", hex(value, 2L), "\n"); +} + +auto Interrupt::writeHalf(u32 address, u32 value) -> void { + uint16 data = value; + + //I_STAT + if(address == 0x1f80'1070) { + if(!data.bit( 0)) vblank.stat = 0; + if(!data.bit( 1)) gpu.stat = 0; + if(!data.bit( 2)) cdrom.stat = 0; + if(!data.bit( 3)) dma.stat = 0; + if(!data.bit( 4)) timer0.stat = 0; + if(!data.bit( 5)) timer1.stat = 0; + if(!data.bit( 6)) timer2.stat = 0; + if(!data.bit( 7)) peripheral.stat = 0; + if(!data.bit( 8)) sio.stat = 0; + if(!data.bit( 9)) spu.stat = 0; + if(!data.bit(10)) pio.stat = 0; + poll(); + } + + //I_MASK + if(address == 0x1f80'1074) { + vblank.mask = data.bit( 0); + gpu.mask = data.bit( 1); + cdrom.mask = data.bit( 2); + dma.mask = data.bit( 3); + timer0.mask = data.bit( 4); + timer1.mask = data.bit( 5); + timer2.mask = data.bit( 6); + peripheral.mask = data.bit( 7); + sio.mask = data.bit( 8); + spu.mask = data.bit( 9); + pio.mask = data.bit(10); + poll(); + } +} + +auto Interrupt::writeWord(u32 address, u32 data) -> void { + writeHalf(address & ~3 | 0, data >> 0); + writeHalf(address & ~3 | 2, data >> 16); +} diff --git a/ares/ps1/irq/irq.cpp b/ares/ps1/irq/irq.cpp new file mode 100644 index 000000000..cb0e3c848 --- /dev/null +++ b/ares/ps1/irq/irq.cpp @@ -0,0 +1,71 @@ +#include + +namespace ares::PlayStation { + +Interrupt interrupt; +#include "io.cpp" +#include "serialization.cpp" + +auto Interrupt::load(Node::Object parent) -> void { + node = parent->append("Interrupt"); +} + +auto Interrupt::unload() -> void { + node.reset(); +} + +auto Interrupt::poll() -> void { + line = 0; + line |= vblank.stat & vblank.mask; + line |= gpu.stat & gpu.mask; + line |= cdrom.stat & cdrom.mask; + line |= dma.stat & dma.mask; + line |= timer0.stat & timer0.mask; + line |= timer1.stat & timer1.mask; + line |= timer2.stat & timer2.mask; + line |= peripheral.stat & peripheral.mask; + line |= sio.stat & sio.mask; + line |= spu.stat & spu.mask; + line |= pio.stat & pio.mask; + cpu.scc.cause.interruptPending.bit(2) = line; +} + +auto Interrupt::pulse(uint source) -> void { + raise(source); + lower(source); +} + +auto Interrupt::raise(uint source) -> void { + if(source == 0 && !vblank.line) vblank.line = vblank.stat = 1; + if(source == 1 && !gpu.line) gpu.line = gpu.stat = 1; + if(source == 2 && !cdrom.line) cdrom.line = cdrom.stat = 1; + if(source == 3 && !dma.line) dma.line = dma.stat = 1; + if(source == 4 && !timer0.line) timer0.line = timer0.stat = 1; + if(source == 5 && !timer1.line) timer1.line = timer1.stat = 1; + if(source == 6 && !timer2.line) timer2.line = timer2.stat = 1; + if(source == 7 && !peripheral.line) peripheral.line = peripheral.stat = 1; + if(source == 8 && !sio.line) sio.line = sio.stat = 1; + if(source == 9 && !spu.line) spu.line = spu.stat = 1; + if(source == 10 && !pio.line) pio.line = pio.stat = 1; + poll(); +} + +auto Interrupt::lower(uint source) -> void { + if(source == 0) vblank.line = 0; + if(source == 1) gpu.line = 0; + if(source == 2) cdrom.line = 0; + if(source == 3) dma.line = 0; + if(source == 4) timer0.line = 0; + if(source == 5) timer1.line = 0; + if(source == 6) timer2.line = 0; + if(source == 7) peripheral.line = 0; + if(source == 8) sio.line = 0; + if(source == 9) spu.line = 0; + if(source == 10) pio.line = 0; + poll(); +} + +auto Interrupt::power(bool reset) -> void { +} + +} diff --git a/ares/ps1/irq/irq.hpp b/ares/ps1/irq/irq.hpp new file mode 100644 index 000000000..8d4d3143c --- /dev/null +++ b/ares/ps1/irq/irq.hpp @@ -0,0 +1,47 @@ +struct Interrupt { + Node::Component node; + + //irq.cpp + auto load(Node::Object) -> void; + auto unload() -> void; + + auto poll() -> void; + auto pulse(uint source) -> void; + auto raise(uint source) -> void; + auto lower(uint source) -> void; + auto power(bool reset) -> void; + + //io.cpp + auto readByte(u32 address) -> u32; + auto readHalf(u32 address) -> u32; + auto readWord(u32 address) -> u32; + auto writeByte(u32 address, u32 data) -> void; + auto writeHalf(u32 address, u32 data) -> void; + auto writeWord(u32 address, u32 data) -> void; + + //serialization.cpp + auto serialize(serializer&) -> void; + + enum : uint { Vblank, GPU, CDROM, DMA, Timer0, Timer1, Timer2, Peripheral, SIO, SPU, PIO }; + + struct Source { + uint1 line = 0; + uint1 stat = 0; + uint1 mask = 0; + }; + + uint1 line = 0; + Source vblank; + Source gpu; + Source cdrom; + Source dma; + Source timer0; + Source timer1; + Source timer2; + Source peripheral; + Source sio; + Source spu; + Source pio; +}; + +extern Interrupt interrupt; diff --git a/ares/ps1/irq/serialization.cpp b/ares/ps1/irq/serialization.cpp new file mode 100644 index 000000000..9b9e524ab --- /dev/null +++ b/ares/ps1/irq/serialization.cpp @@ -0,0 +1,2 @@ +auto Interrupt::serialize(serializer& s) -> void { +} diff --git a/ares/ps1/memory/bus.hpp b/ares/ps1/memory/bus.hpp index 8ce0274f8..b08f34afa 100644 --- a/ares/ps1/memory/bus.hpp +++ b/ares/ps1/memory/bus.hpp @@ -6,8 +6,9 @@ if(address <= 0x1f7f'ffff) return unmapped; \ if(address <= 0x1f80'03ff) return cpu.cache.access(__VA_ARGS__); \ if(address <= 0x1f80'106f) return unmapped; \ - if(address <= 0x1f80'107f) return cpu.interrupt.access(__VA_ARGS__); \ - if(address <= 0x1f80'10ff) return cpu.dma.access(__VA_ARGS__); \ + if(address <= 0x1f80'107f) return interrupt.access(__VA_ARGS__); \ + if(address <= 0x1f80'10ff) return dma.access(__VA_ARGS__); \ + if(address <= 0x1f80'112f) return timer.access(__VA_ARGS__); \ if(address <= 0x1f80'17ff) return unmapped; \ if(address <= 0x1f80'180f) return disc.access(__VA_ARGS__); \ if(address <= 0x1f80'181f) return gpu.access(__VA_ARGS__); \ @@ -24,6 +25,7 @@ inline auto Bus::readByte(u32 address) -> u8 { } inline auto Bus::readHalf(u32 address) -> u16 { + if(address == 0x1f80'1044) return 0x0007; decode(0, readHalf, address); } diff --git a/ares/ps1/ps1.hpp b/ares/ps1/ps1.hpp index 23cb3e74a..b8aaef172 100644 --- a/ares/ps1/ps1.hpp +++ b/ares/ps1/ps1.hpp @@ -24,6 +24,9 @@ namespace ares::PlayStation { #include #include #include + #include + #include + #include #include } diff --git a/ares/ps1/system/serialization.cpp b/ares/ps1/system/serialization.cpp index bbfa71699..6ef5148ff 100644 --- a/ares/ps1/system/serialization.cpp +++ b/ares/ps1/system/serialization.cpp @@ -49,6 +49,9 @@ auto System::serializeAll(serializer& s, bool synchronize) -> void { gpu.serialize(s); spu.serialize(s); disc.serialize(s); + interrupt.serialize(s); + dma.serialize(s); + timer.serialize(s); } auto System::serializeInit(bool synchronize) -> uint { diff --git a/ares/ps1/system/system.cpp b/ares/ps1/system/system.cpp index 0bfa7e559..3e5c087fa 100644 --- a/ares/ps1/system/system.cpp +++ b/ares/ps1/system/system.cpp @@ -23,6 +23,9 @@ auto System::load(Node::Object& root) -> void { gpu.load(node); spu.load(node); disc.load(node); + interrupt.load(node); + dma.load(node); + timer.load(node); } auto System::unload() -> void { @@ -32,6 +35,9 @@ auto System::unload() -> void { gpu.unload(); spu.unload(); disc.unload(); + interrupt.unload(); + dma.unload(); + timer.unload(); node.reset(); } @@ -50,7 +56,10 @@ auto System::power(bool reset) -> void { cpu.power(reset); gpu.power(reset); spu.power(reset); - disc.power(); + disc.power(reset); + interrupt.power(reset); + dma.power(reset); + timer.power(reset); information.serializeSize[0] = serializeInit(0); information.serializeSize[1] = serializeInit(1); diff --git a/ares/ps1/timer/io.cpp b/ares/ps1/timer/io.cpp new file mode 100644 index 000000000..d19a45646 --- /dev/null +++ b/ares/ps1/timer/io.cpp @@ -0,0 +1,172 @@ +auto Timer::readByte(u32 address) -> u32 { + print("* rb", hex(address, 8L), "\n"); + return 0; +} + +auto Timer::readHalf(u32 address) -> u32 { + uint16 data; + + if(address == 0x1f80'1100) { + data.bit(0,15) = htimer.counter; + } + + if(address == 0x1f80'1104) { + data.bit( 0) = htimer.synchronizeEnable; + data.bit( 1, 2) = htimer.synchronizeMode; + data.bit( 3) = htimer.resetMode; + data.bit( 4) = htimer.irqOnTarget; + data.bit( 5) = htimer.irqOnSaturate; + data.bit( 6) = htimer.irqRepeat; + data.bit( 7) = htimer.irqMode; + data.bit( 8, 9) = htimer.clockSource; + data.bit(10) = htimer.irqLine; + data.bit(11) = htimer.reachedTarget; + data.bit(12) = htimer.reachedSaturate; + data.bit(13,15) = htimer.unknown; + htimer.reachedTarget = 0; + htimer.reachedSaturate = 0; + } + + if(address == 0x1f80'1108) { + data.bit(0,15) = htimer.target; + } + + if(address == 0x1f80'1110) { + data.bit(0,15) = vtimer.counter; + } + + if(address == 0x1f80'1114) { + data.bit( 0) = vtimer.synchronizeEnable; + data.bit( 1, 2) = vtimer.synchronizeMode; + data.bit( 3) = vtimer.resetMode; + data.bit( 4) = vtimer.irqOnTarget; + data.bit( 5) = vtimer.irqOnSaturate; + data.bit( 6) = vtimer.irqRepeat; + data.bit( 7) = vtimer.irqMode; + data.bit( 8, 9) = vtimer.clockSource; + data.bit(10) = vtimer.irqLine; + data.bit(11) = vtimer.reachedTarget; + data.bit(12) = vtimer.reachedSaturate; + data.bit(13,15) = vtimer.unknown; + vtimer.reachedTarget = 0; + vtimer.reachedSaturate = 0; + } + + if(address == 0x1f80'1118) { + data.bit(0,15) = vtimer.target; + } + + if(address == 0x1f80'1120) { + data.bit(0,15) = ftimer.counter; + } + + if(address == 0x1f80'1124) { + data.bit( 0) = ftimer.synchronizeEnable; + data.bit( 1, 2) = ftimer.synchronizeMode; + data.bit( 3) = ftimer.resetMode; + data.bit( 4) = ftimer.irqOnTarget; + data.bit( 5) = ftimer.irqOnSaturate; + data.bit( 6) = ftimer.irqRepeat; + data.bit( 7) = ftimer.irqMode; + data.bit( 8, 9) = ftimer.clockSource; + data.bit(10) = ftimer.irqLine; + data.bit(11) = ftimer.reachedTarget; + data.bit(12) = ftimer.reachedSaturate; + data.bit(13,15) = ftimer.unknown; + ftimer.reachedTarget = 0; + ftimer.reachedSaturate = 0; + } + + if(address == 0x1f80'1128) { + data.bit(0,15) = ftimer.counter; + } + + return data; +} + +auto Timer::readWord(u32 address) -> u32 { + uint32 data = readHalf(address & ~3 | 0) << 0; + return data | readHalf(address & ~3 | 2) << 16; +} + +auto Timer::writeByte(u32 address, u32 value) -> void { + print("* wb", hex(address, 8L), "\n"); +} + +auto Timer::writeHalf(u32 address, u32 value) -> void { + uint16 data = value; + + if(address == 0x1f80'1100) { + htimer.counter = data.bit(0,15); + } + + if(address == 0x1f80'1104) { + htimer.synchronizeEnable = data.bit( 0); + htimer.synchronizeMode = data.bit( 1, 2); + htimer.resetMode = data.bit( 3); + htimer.irqOnTarget = data.bit( 4); + htimer.irqOnSaturate = data.bit( 5); + htimer.irqRepeat = data.bit( 6); + htimer.irqMode = data.bit( 7); + htimer.clockSource = data.bit( 8, 9); + htimer.irqLine = data.bit(10); + htimer.reachedTarget = data.bit(11); + htimer.reachedSaturate = data.bit(12); + htimer.unknown = data.bit(13,15); + } + + if(address == 0x1f80'1108) { + htimer.target = data.bit(0,15); + } + + if(address == 0x1f80'1110) { + vtimer.counter = data.bit(0,15); + } + + if(address == 0x1f80'1114) { + vtimer.synchronizeEnable = data.bit( 0); + vtimer.synchronizeMode = data.bit( 1, 2); + vtimer.resetMode = data.bit( 3); + vtimer.irqOnTarget = data.bit( 4); + vtimer.irqOnSaturate = data.bit( 5); + vtimer.irqRepeat = data.bit( 6); + vtimer.irqMode = data.bit( 7); + vtimer.clockSource = data.bit( 8, 9); + vtimer.irqLine = data.bit(10); + vtimer.reachedTarget = data.bit(11); + vtimer.reachedSaturate = data.bit(12); + vtimer.unknown = data.bit(13,15); + } + + if(address == 0x1f80'1118) { + vtimer.target = data.bit(0,15); + } + + if(address == 0x1f80'1120) { + ftimer.counter = data.bit(0,15); + } + + if(address == 0x1f80'1124) { + ftimer.synchronizeEnable = data.bit( 0); + ftimer.synchronizeMode = data.bit( 1, 2); + ftimer.resetMode = data.bit( 3); + ftimer.irqOnTarget = data.bit( 4); + ftimer.irqOnSaturate = data.bit( 5); + ftimer.irqRepeat = data.bit( 6); + ftimer.irqMode = data.bit( 7); + ftimer.clockSource = data.bit( 8, 9); + ftimer.irqLine = data.bit(10); + ftimer.reachedTarget = data.bit(11); + ftimer.reachedSaturate = data.bit(12); + ftimer.unknown = data.bit(13,15); + } + + if(address == 0x1f80'1128) { + ftimer.target = data.bit(0,15); + } +} + +auto Timer::writeWord(u32 address, u32 data) -> void { + writeHalf(address & ~3 | 0, data >> 0); + writeHalf(address & ~3 | 2, data >> 16); +} diff --git a/ares/ps1/timer/serialization.cpp b/ares/ps1/timer/serialization.cpp new file mode 100644 index 000000000..fce49a96b --- /dev/null +++ b/ares/ps1/timer/serialization.cpp @@ -0,0 +1,2 @@ +auto Timer::serialize(serializer& s) -> void { +} diff --git a/ares/ps1/timer/timer.cpp b/ares/ps1/timer/timer.cpp new file mode 100644 index 000000000..cba87020e --- /dev/null +++ b/ares/ps1/timer/timer.cpp @@ -0,0 +1,23 @@ +#include + +namespace ares::PlayStation { + +Timer timer; +#include "io.cpp" +#include "serialization.cpp" + +auto Timer::load(Node::Object parent) -> void { + node = parent->append("Timer"); +} + +auto Timer::unload() -> void { + node.reset(); +} + +auto Timer::step(uint clocks) -> void { +} + +auto Timer::power(bool reset) -> void { +} + +} diff --git a/ares/ps1/timer/timer.hpp b/ares/ps1/timer/timer.hpp new file mode 100644 index 000000000..8d0298b09 --- /dev/null +++ b/ares/ps1/timer/timer.hpp @@ -0,0 +1,44 @@ +struct Timer { + Node::Component node; + + //timer.cpp + auto load(Node::Object) -> void; + auto unload() -> void; + + auto step(uint clocks) -> void; + auto power(bool reset) -> void; + + //io.cpp + auto readByte(u32 address) -> u32; + auto readHalf(u32 address) -> u32; + auto readWord(u32 address) -> u32; + auto writeByte(u32 address, u32 data) -> void; + auto writeHalf(u32 address, u32 data) -> void; + auto writeWord(u32 address, u32 data) -> void; + + //serialization.cpp + auto serialize(serializer&) -> void; + + struct Source { + uint16 counter; + uint16 target; + uint1 synchronizeEnable; + uint2 synchronizeMode; + uint1 resetMode; + uint1 irqOnTarget; + uint1 irqOnSaturate; + uint1 irqRepeat; + uint1 irqMode; + uint2 clockSource; + uint1 irqLine; + uint1 reachedTarget; + uint1 reachedSaturate; + uint3 unknown; + }; + + Source htimer; //Hblank timer 0 + Source vtimer; //Vblank timer 1 + Source ftimer; //free timer 2 +}; + +extern Timer timer;