mirror of https://github.com/inolen/redream.git
141 lines
3.3 KiB
C++
141 lines
3.3 KiB
C++
#include "hw/holly/holly.h"
|
|
#include "hw/maple/maple.h"
|
|
#include "hw/maple/maple_controller.h"
|
|
#include "hw/dreamcast.h"
|
|
#include "hw/memory.h"
|
|
|
|
using namespace re;
|
|
using namespace re::hw;
|
|
using namespace re::hw::holly;
|
|
using namespace re::hw::maple;
|
|
using namespace re::hw::sh4;
|
|
using namespace re::ui;
|
|
|
|
Maple::Maple(Dreamcast &dc)
|
|
: Device(dc),
|
|
WindowInterface(this),
|
|
dc_(dc),
|
|
memory_(nullptr),
|
|
holly_(nullptr),
|
|
holly_regs_(nullptr),
|
|
devices_() {
|
|
// default controller device
|
|
devices_[0] = std::unique_ptr<MapleController>(new MapleController());
|
|
}
|
|
|
|
bool Maple::Init() {
|
|
memory_ = dc_.memory;
|
|
holly_ = dc_.holly;
|
|
holly_regs_ = dc_.holly_regs;
|
|
|
|
return true;
|
|
}
|
|
|
|
// The controller can be started up by two methods: by software, or by hardware
|
|
// in synchronization with the V-BLANK signal. These methods are selected
|
|
// through the trigger selection register (SB_MDTSEL).
|
|
void Maple::VBlank() {
|
|
uint32_t enabled = dc_.SB_MDEN;
|
|
uint32_t vblank_initiate = dc_.SB_MDTSEL;
|
|
|
|
if (enabled && vblank_initiate) {
|
|
StartDMA();
|
|
}
|
|
|
|
// TODO maple vblank interrupt?
|
|
}
|
|
|
|
void Maple::OnKeyDown(Keycode key, int16_t value) {
|
|
std::unique_ptr<MapleDevice> &dev = devices_[0];
|
|
|
|
if (!dev) {
|
|
return;
|
|
}
|
|
|
|
dev->HandleInput(key, value);
|
|
}
|
|
|
|
template uint8_t Maple::ReadRegister(uint32_t addr);
|
|
template uint16_t Maple::ReadRegister(uint32_t addr);
|
|
template uint32_t Maple::ReadRegister(uint32_t addr);
|
|
template <typename T>
|
|
T Maple::ReadRegister(uint32_t addr) {
|
|
uint32_t offset = addr >> 2;
|
|
Register ® = holly_regs_[offset];
|
|
|
|
if (!(reg.flags & R)) {
|
|
LOG_WARNING("Invalid read access at 0x%x", addr);
|
|
return 0;
|
|
}
|
|
|
|
return static_cast<T>(reg.value);
|
|
}
|
|
|
|
template void Maple::WriteRegister(uint32_t addr, uint8_t value);
|
|
template void Maple::WriteRegister(uint32_t addr, uint16_t value);
|
|
template void Maple::WriteRegister(uint32_t addr, uint32_t value);
|
|
template <typename T>
|
|
void Maple::WriteRegister(uint32_t addr, T value) {
|
|
uint32_t offset = addr >> 2;
|
|
Register ® = holly_regs_[offset];
|
|
|
|
if (!(reg.flags & W)) {
|
|
LOG_WARNING("Invalid write access at 0x%x", addr);
|
|
return;
|
|
}
|
|
|
|
// uint32_t old = reg.value;
|
|
reg.value = static_cast<uint32_t>(value);
|
|
|
|
switch (offset) {
|
|
case SB_MDST_OFFSET: {
|
|
uint32_t enabled = dc_.SB_MDEN;
|
|
if (enabled) {
|
|
if (value) {
|
|
StartDMA();
|
|
}
|
|
} else {
|
|
reg.value = 0;
|
|
}
|
|
} break;
|
|
}
|
|
}
|
|
|
|
void Maple::StartDMA() {
|
|
uint32_t start_addr = dc_.SB_MDSTAR;
|
|
MapleTransferDesc desc;
|
|
MapleFrame frame, res;
|
|
|
|
do {
|
|
desc.full = memory_->R64(start_addr);
|
|
start_addr += 8;
|
|
|
|
// read input
|
|
frame.header.full = memory_->R32(start_addr);
|
|
start_addr += 4;
|
|
|
|
for (uint32_t i = 0; i < frame.header.num_words; i++) {
|
|
frame.params[i] = memory_->R32(start_addr);
|
|
start_addr += 4;
|
|
}
|
|
|
|
// handle frame and write response
|
|
std::unique_ptr<MapleDevice> &dev = devices_[desc.port];
|
|
|
|
if (dev && dev->HandleFrame(frame, res)) {
|
|
memory_->W32(desc.result_addr, res.header.full);
|
|
desc.result_addr += 4;
|
|
|
|
for (uint32_t i = 0; i < res.header.num_words; i++) {
|
|
memory_->W32(desc.result_addr, res.params[i]);
|
|
desc.result_addr += 4;
|
|
}
|
|
} else {
|
|
memory_->W32(desc.result_addr, 0xffffffff);
|
|
}
|
|
} while (!desc.last);
|
|
|
|
dc_.SB_MDST = 0;
|
|
holly_->RequestInterrupt(HOLLY_INTC_MDEINT);
|
|
}
|