Update to ares v114r17 release.

- PlayStation: started implementing timers
  - MSX: added more cartridge mappers (Konami SCC, ASCII 8kbit, ASCII
    16kbit, etc)
このコミットが含まれているのは:
Near 2020-07-08 11:59:00 +00:00
コミット 5f035496bb
41個のファイルの変更1404行の追加418行の削除

ファイルの表示

@ -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/";

43
ares/msx/cartridge/board/asc16.cpp ノーマルファイル
ファイルの表示

@ -0,0 +1,43 @@
//ASCII 16kbit
struct ASC16 : Interface {
using Interface::Interface;
Memory::Readable<uint8> 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];
};

51
ares/msx/cartridge/board/asc8.cpp ノーマルファイル
ファイルの表示

@ -0,0 +1,51 @@
//ASCII 8kbit
struct ASC8 : Interface {
using Interface::Interface;
Memory::Readable<uint8> 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];
};

50
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<uint8>& 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<uint8>& 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<uint8>& 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());
}
}

22
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<uint8>&, Markup::Node) -> bool;
auto load(Memory::Writable<uint8>&, Markup::Node) -> bool;
auto save(Memory::Writable<uint8>&, Markup::Node) -> bool;
Cartridge& cartridge;
};
}

56
ares/msx/cartridge/board/cross-blaim.cpp ノーマルファイル
ファイルの表示

@ -0,0 +1,56 @@
//Cross Blaim
struct CrossBlaim : Interface {
using Interface::Interface;
Memory::Readable<uint8> 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;
};

252
ares/msx/cartridge/board/konami-scc.cpp ノーマルファイル
ファイルの表示

@ -0,0 +1,252 @@
//Konami (with Sound Creative Chip)
struct KonamiSCC : Interface {
using Interface::Interface;
Memory::Readable<uint8> 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<Node::Stream>("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<int16> mixer;
};

45
ares/msx/cartridge/board/konami.cpp ノーマルファイル
ファイルの表示

@ -0,0 +1,45 @@
//Konami (without Sound Creative Chip)
struct Konami : Interface {
using Interface::Interface;
Memory::Readable<uint8> 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];
};

29
ares/msx/cartridge/board/linear.cpp ノーマルファイル
ファイルの表示

@ -0,0 +1,29 @@
struct Linear : Interface {
using Interface::Interface;
Memory::Readable<uint8> 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 {
}
};

ファイルの表示

@ -0,0 +1,37 @@
//Super Lode Runner
//(not working: requires MSX BASIC)
struct SuperLodeRunner : Interface {
using Interface::Interface;
Memory::Readable<uint8> 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;
};

47
ares/msx/cartridge/board/super-pierrot.cpp ノーマルファイル
ファイルの表示

@ -0,0 +1,47 @@
//Super Pierrot
//(not working)
struct SuperPierrot : Interface {
using Interface::Interface;
Memory::Readable<uint8> 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];
};

ファイルの表示

@ -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);
}
}

ファイルの表示

@ -1,4 +1,7 @@
struct Cartridge {
struct Cartridge;
#include "board/board.hpp"
struct Cartridge : Thread {
Node::Peripheral node;
Memory::Readable<uint8> rom;
Memory::Writable<uint8> 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::Interface> board;
private:
struct Information {
string manifest;
string name;
string region;
string board;
} information;
};

ファイルの表示

@ -1,3 +1,3 @@
auto Cartridge::serialize(serializer& s) -> void {
if(ram) s.array(ram.data(), ram.size());
if(board) board->serialize(s);
}

ファイルの表示

@ -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

ファイルの表示

@ -7,7 +7,7 @@
auto disassemble(u32 address, u32 instruction) -> string;
template<typename... P> auto hint(P&&... p) const -> string;
bool showColors = false;
bool showColors = true;
bool showValues = true;
//private:

ファイルの表示

@ -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);
}
}

ファイルの表示

@ -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;

ファイルの表示

@ -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);
}

ファイルの表示

@ -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;
}

ファイルの表示

@ -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 = {};
}

ファイルの表示

@ -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 {

ファイルの表示

@ -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");
}

36
ares/ps1/dma/dma.cpp ノーマルファイル
ファイルの表示

@ -0,0 +1,36 @@
#include <ps1/ps1.hpp>
namespace ares::PlayStation {
DMA dma;
#include "io.cpp"
#include "transfer.cpp"
#include "serialization.cpp"
auto DMA::load(Node::Object parent) -> void {
node = parent->append<Node::Component>("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;
}
}
}

66
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;

ファイルの表示

@ -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;
}

2
ares/ps1/dma/serialization.cpp ノーマルファイル
ファイルの表示

@ -0,0 +1,2 @@
auto DMA::serialize(serializer& s) -> void {
}

54
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;
}

ファイルの表示

@ -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;
}

90
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);
}

71
ares/ps1/irq/irq.cpp ノーマルファイル
ファイルの表示

@ -0,0 +1,71 @@
#include <ps1/ps1.hpp>
namespace ares::PlayStation {
Interrupt interrupt;
#include "io.cpp"
#include "serialization.cpp"
auto Interrupt::load(Node::Object parent) -> void {
node = parent->append<Node::Component>("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 {
}
}

47
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;

2
ares/ps1/irq/serialization.cpp ノーマルファイル
ファイルの表示

@ -0,0 +1,2 @@
auto Interrupt::serialize(serializer& s) -> void {
}

ファイルの表示

@ -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);
}

ファイルの表示

@ -24,6 +24,9 @@ namespace ares::PlayStation {
#include <ps1/cpu/cpu.hpp>
#include <ps1/gpu/gpu.hpp>
#include <ps1/spu/spu.hpp>
#include <ps1/irq/irq.hpp>
#include <ps1/dma/dma.hpp>
#include <ps1/timer/timer.hpp>
#include <ps1/memory/bus.hpp>
}

ファイルの表示

@ -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 {

ファイルの表示

@ -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);

172
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);
}

2
ares/ps1/timer/serialization.cpp ノーマルファイル
ファイルの表示

@ -0,0 +1,2 @@
auto Timer::serialize(serializer& s) -> void {
}

23
ares/ps1/timer/timer.cpp ノーマルファイル
ファイルの表示

@ -0,0 +1,23 @@
#include <ps1/ps1.hpp>
namespace ares::PlayStation {
Timer timer;
#include "io.cpp"
#include "serialization.cpp"
auto Timer::load(Node::Object parent) -> void {
node = parent->append<Node::Component>("Timer");
}
auto Timer::unload() -> void {
node.reset();
}
auto Timer::step(uint clocks) -> void {
}
auto Timer::power(bool reset) -> void {
}
}

44
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;