mirror of https://github.com/inolen/redream.git
convert over to using re::delegate for dynamic memory handlers
This commit is contained in:
parent
bf7999d0ae
commit
b6731d3df6
|
@ -0,0 +1,102 @@
|
|||
#ifndef DELEGATE_H
|
||||
#define DELEGATE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <type_traits>
|
||||
|
||||
namespace re {
|
||||
|
||||
template <typename F>
|
||||
class delegate;
|
||||
|
||||
template <typename R, typename... A>
|
||||
class delegate<R(A...)> {
|
||||
typedef R (*thunk_type)(void *, A...);
|
||||
|
||||
template <typename T>
|
||||
struct const_member_data {
|
||||
T *callee;
|
||||
R (T::*func)(A...) const;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct member_data {
|
||||
T *callee;
|
||||
R (T::*func)(A...);
|
||||
};
|
||||
|
||||
typedef R (*func_data)(A...);
|
||||
|
||||
public:
|
||||
delegate() : thunk_(nullptr), data_() {}
|
||||
|
||||
template <typename T>
|
||||
delegate(T *callee, R (T::*func)(A...) const) {
|
||||
static_assert(sizeof(const_member_data<T>) < sizeof(data_),
|
||||
"data not large enough to hold member function pointer");
|
||||
|
||||
thunk_ = reinterpret_cast<thunk_type>(&const_member_thunk<T>);
|
||||
|
||||
*reinterpret_cast<const_member_data<T> *>(data_) = {callee, func};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
delegate(T *callee, R (T::*func)(A...)) {
|
||||
static_assert(sizeof(member_data<T>) < sizeof(data_),
|
||||
"data not large enough to hold member function pointer");
|
||||
|
||||
thunk_ = reinterpret_cast<thunk_type>(&member_thunk<T>);
|
||||
|
||||
*reinterpret_cast<member_data<T> *>(data_) = {callee, func};
|
||||
}
|
||||
|
||||
delegate(R (*func)(A...)) {
|
||||
thunk_ = reinterpret_cast<thunk_type>(&func_thunk);
|
||||
|
||||
*reinterpret_cast<func_data *>(data_) = func;
|
||||
}
|
||||
|
||||
bool operator==(const delegate &rhs) const noexcept {
|
||||
return (thunk_ == rhs.thunk_) && !memcmp(data_, rhs.data_, sizeof(data_));
|
||||
}
|
||||
|
||||
bool operator!=(const delegate &rhs) const noexcept {
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
R operator()(A... args) { return thunk_(data_, args...); }
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
static R const_member_thunk(const_member_data<T> *data, A... args) {
|
||||
return (data->callee->*data->func)(args...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static R member_thunk(member_data<T> *data, A... args) {
|
||||
return (data->callee->*data->func)(args...);
|
||||
}
|
||||
|
||||
static R func_thunk(func_data *data, A... args) { return (*data)(args...); }
|
||||
|
||||
thunk_type thunk_;
|
||||
uint8_t data_[32];
|
||||
};
|
||||
|
||||
template <typename T, typename R, typename... A>
|
||||
delegate<R(A...)> make_delegate(R (T::*func)(A...) const, T *callee) {
|
||||
return delegate<R(A...)>(callee, func);
|
||||
}
|
||||
|
||||
template <typename T, typename R, typename... A>
|
||||
delegate<R(A...)> make_delegate(R (T::*func)(A...), T *callee) {
|
||||
return delegate<R(A...)>(callee, func);
|
||||
}
|
||||
|
||||
template <typename R, typename... A>
|
||||
delegate<R(A...)> make_delegate(R (*func)(A...)) {
|
||||
return delegate<R(A...)>(func);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -40,13 +40,11 @@ bool AICA::Init() {
|
|||
// re::store(&self->aica_regs_[addr], value);
|
||||
// }
|
||||
|
||||
template uint8_t AICA::ReadWave(void *ctx, uint32_t addr);
|
||||
template uint16_t AICA::ReadWave(void *ctx, uint32_t addr);
|
||||
template uint32_t AICA::ReadWave(void *ctx, uint32_t addr);
|
||||
template uint8_t AICA::ReadWave(uint32_t addr);
|
||||
template uint16_t AICA::ReadWave(uint32_t addr);
|
||||
template uint32_t AICA::ReadWave(uint32_t addr);
|
||||
template <typename T>
|
||||
T AICA::ReadWave(void *ctx, uint32_t addr) {
|
||||
AICA *self = reinterpret_cast<AICA *>(ctx);
|
||||
|
||||
T AICA::ReadWave(uint32_t addr) {
|
||||
if (sizeof(T) == 4) {
|
||||
// FIXME temp hacks to get Crazy Taxi 1 booting
|
||||
if (addr == 0x104 || addr == 0x284 || addr == 0x288) {
|
||||
|
@ -58,14 +56,13 @@ T AICA::ReadWave(void *ctx, uint32_t addr) {
|
|||
}
|
||||
}
|
||||
|
||||
return re::load<T>(&self->wave_ram_[addr]);
|
||||
return re::load<T>(&wave_ram_[addr]);
|
||||
}
|
||||
|
||||
template void AICA::WriteWave(void *ctx, uint32_t addr, uint8_t value);
|
||||
template void AICA::WriteWave(void *ctx, uint32_t addr, uint16_t value);
|
||||
template void AICA::WriteWave(void *ctx, uint32_t addr, uint32_t value);
|
||||
template void AICA::WriteWave(uint32_t addr, uint8_t value);
|
||||
template void AICA::WriteWave(uint32_t addr, uint16_t value);
|
||||
template void AICA::WriteWave(uint32_t addr, uint32_t value);
|
||||
template <typename T>
|
||||
void AICA::WriteWave(void *ctx, uint32_t addr, T value) {
|
||||
AICA *self = reinterpret_cast<AICA *>(ctx);
|
||||
re::store(&self->wave_ram_[addr], value);
|
||||
void AICA::WriteWave(uint32_t addr, T value) {
|
||||
re::store(&wave_ram_[addr], value);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace aica {
|
|||
|
||||
class AICA {
|
||||
public:
|
||||
AICA(hw::Dreamcast *dc);
|
||||
AICA(Dreamcast *dc);
|
||||
|
||||
bool Init();
|
||||
|
||||
|
@ -19,13 +19,13 @@ class AICA {
|
|||
// static void WriteRegister(void *ctx, uint32_t addr, uint32_t value);
|
||||
|
||||
template <typename T>
|
||||
static T ReadWave(void *ctx, uint32_t addr);
|
||||
T ReadWave(uint32_t addr);
|
||||
|
||||
template <typename T>
|
||||
static void WriteWave(void *ctx, uint32_t addr, T value);
|
||||
void WriteWave(uint32_t addr, T value);
|
||||
|
||||
private:
|
||||
hw::Dreamcast *dc_;
|
||||
Dreamcast *dc_;
|
||||
// uint8_t *aica_regs_;
|
||||
uint8_t *wave_ram_;
|
||||
};
|
||||
|
|
|
@ -47,24 +47,24 @@ static bool MapMemory(Dreamcast &dc) {
|
|||
|
||||
// second, allocate dynamic regions that overlap static regions
|
||||
RegionHandle holly_handle = memory->AllocRegion(
|
||||
HOLLY_REG_START, HOLLY_REG_SIZE, dc.holly,
|
||||
&Holly::ReadRegister<uint8_t>,
|
||||
&Holly::ReadRegister<uint16_t>,
|
||||
&Holly::ReadRegister<uint32_t>,
|
||||
HOLLY_REG_START, HOLLY_REG_SIZE,
|
||||
make_delegate(&Holly::ReadRegister<uint8_t>, dc.holly),
|
||||
make_delegate(&Holly::ReadRegister<uint16_t>, dc.holly),
|
||||
make_delegate(&Holly::ReadRegister<uint32_t>, dc.holly),
|
||||
nullptr,
|
||||
&Holly::WriteRegister<uint8_t>,
|
||||
&Holly::WriteRegister<uint16_t>,
|
||||
&Holly::WriteRegister<uint32_t>,
|
||||
make_delegate(&Holly::WriteRegister<uint8_t>, dc.holly),
|
||||
make_delegate(&Holly::WriteRegister<uint16_t>, dc.holly),
|
||||
make_delegate(&Holly::WriteRegister<uint32_t>, dc.holly),
|
||||
nullptr);
|
||||
RegionHandle pvr_reg_handle = memory->AllocRegion(
|
||||
PVR_REG_START, PVR_REG_SIZE, dc.pvr,
|
||||
PVR_REG_START, PVR_REG_SIZE,
|
||||
nullptr,
|
||||
nullptr,
|
||||
&PVR2::ReadRegister,
|
||||
make_delegate(&PVR2::ReadRegister, dc.pvr),
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
&PVR2::WriteRegister,
|
||||
make_delegate(&PVR2::WriteRegister, dc.pvr),
|
||||
nullptr);
|
||||
// RegionHandle aica_reg_handle = memory->AllocRegion(
|
||||
// AICA_REG_START, AICA_REG_SIZE, aica(),
|
||||
|
@ -77,74 +77,74 @@ static bool MapMemory(Dreamcast &dc) {
|
|||
// &AICA::WriteRegister,
|
||||
// nullptr);
|
||||
RegionHandle wave_ram_handle = memory->AllocRegion(
|
||||
WAVE_RAM_START, WAVE_RAM_SIZE, dc.aica,
|
||||
&AICA::ReadWave<uint8_t>,
|
||||
&AICA::ReadWave<uint16_t>,
|
||||
&AICA::ReadWave<uint32_t>,
|
||||
WAVE_RAM_START, WAVE_RAM_SIZE,
|
||||
make_delegate(&AICA::ReadWave<uint8_t>, dc.aica),
|
||||
make_delegate(&AICA::ReadWave<uint16_t>, dc.aica),
|
||||
make_delegate(&AICA::ReadWave<uint32_t>, dc.aica),
|
||||
nullptr,
|
||||
&AICA::WriteWave<uint8_t>,
|
||||
&AICA::WriteWave<uint16_t>,
|
||||
&AICA::WriteWave<uint32_t>,
|
||||
make_delegate(&AICA::WriteWave<uint8_t>, dc.aica),
|
||||
make_delegate(&AICA::WriteWave<uint16_t>, dc.aica),
|
||||
make_delegate(&AICA::WriteWave<uint32_t>, dc.aica),
|
||||
nullptr);
|
||||
RegionHandle pvr_vram64_handle = memory->AllocRegion(
|
||||
PVR_VRAM64_START, PVR_VRAM64_SIZE, dc.pvr,
|
||||
&PVR2::ReadVRamInterleaved<uint8_t>,
|
||||
&PVR2::ReadVRamInterleaved<uint16_t>,
|
||||
&PVR2::ReadVRamInterleaved<uint32_t>,
|
||||
PVR_VRAM64_START, PVR_VRAM64_SIZE,
|
||||
make_delegate(&PVR2::ReadVRamInterleaved<uint8_t>, dc.pvr),
|
||||
make_delegate(&PVR2::ReadVRamInterleaved<uint16_t>, dc.pvr),
|
||||
make_delegate(&PVR2::ReadVRamInterleaved<uint32_t>, dc.pvr),
|
||||
nullptr,
|
||||
nullptr,
|
||||
&PVR2::WriteVRamInterleaved<uint16_t>,
|
||||
&PVR2::WriteVRamInterleaved<uint32_t>,
|
||||
make_delegate(&PVR2::WriteVRamInterleaved<uint16_t>, dc.pvr),
|
||||
make_delegate(&PVR2::WriteVRamInterleaved<uint32_t>, dc.pvr),
|
||||
nullptr);
|
||||
RegionHandle ta_cmd_handle = memory->AllocRegion(
|
||||
TA_CMD_START, TA_CMD_SIZE, dc.ta,
|
||||
TA_CMD_START, TA_CMD_SIZE,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
&TileAccelerator::WriteCommand,
|
||||
make_delegate(&TileAccelerator::WriteCommand, dc.ta),
|
||||
nullptr);
|
||||
RegionHandle ta_texture_handle = memory->AllocRegion(
|
||||
TA_TEXTURE_START, TA_TEXTURE_SIZE, dc.ta,
|
||||
TA_TEXTURE_START, TA_TEXTURE_SIZE,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
&TileAccelerator::WriteTexture,
|
||||
make_delegate(&TileAccelerator::WriteTexture, dc.ta),
|
||||
nullptr);
|
||||
RegionHandle sh4_reg_handle = memory->AllocRegion(
|
||||
SH4_REG_START, SH4_REG_SIZE, dc.sh4,
|
||||
&SH4::ReadRegister<uint8_t>,
|
||||
&SH4::ReadRegister<uint16_t>,
|
||||
&SH4::ReadRegister<uint32_t>,
|
||||
SH4_REG_START, SH4_REG_SIZE,
|
||||
make_delegate(&SH4::ReadRegister<uint8_t>, dc.sh4),
|
||||
make_delegate(&SH4::ReadRegister<uint16_t>, dc.sh4),
|
||||
make_delegate(&SH4::ReadRegister<uint32_t>, dc.sh4),
|
||||
nullptr,
|
||||
&SH4::WriteRegister<uint8_t>,
|
||||
&SH4::WriteRegister<uint16_t>,
|
||||
&SH4::WriteRegister<uint32_t>,
|
||||
make_delegate(&SH4::WriteRegister<uint8_t>, dc.sh4),
|
||||
make_delegate(&SH4::WriteRegister<uint16_t>, dc.sh4),
|
||||
make_delegate(&SH4::WriteRegister<uint32_t>, dc.sh4),
|
||||
nullptr);
|
||||
RegionHandle sh4_cache_handle = memory->AllocRegion(
|
||||
SH4_CACHE_START, SH4_CACHE_SIZE, dc.sh4,
|
||||
&SH4::ReadCache<uint8_t>,
|
||||
&SH4::ReadCache<uint16_t>,
|
||||
&SH4::ReadCache<uint32_t>,
|
||||
&SH4::ReadCache<uint64_t>,
|
||||
&SH4::WriteCache<uint8_t>,
|
||||
&SH4::WriteCache<uint16_t>,
|
||||
&SH4::WriteCache<uint32_t>,
|
||||
&SH4::WriteCache<uint64_t>);
|
||||
SH4_CACHE_START, SH4_CACHE_SIZE,
|
||||
make_delegate(&SH4::ReadCache<uint8_t>, dc.sh4),
|
||||
make_delegate(&SH4::ReadCache<uint16_t>, dc.sh4),
|
||||
make_delegate(&SH4::ReadCache<uint32_t>, dc.sh4),
|
||||
make_delegate(&SH4::ReadCache<uint64_t>, dc.sh4),
|
||||
make_delegate(&SH4::WriteCache<uint8_t>, dc.sh4),
|
||||
make_delegate(&SH4::WriteCache<uint16_t>, dc.sh4),
|
||||
make_delegate(&SH4::WriteCache<uint32_t>, dc.sh4),
|
||||
make_delegate(&SH4::WriteCache<uint64_t>, dc.sh4));
|
||||
RegionHandle sh4_sq_handle = memory->AllocRegion(
|
||||
SH4_SQ_START, SH4_SQ_SIZE, dc.sh4,
|
||||
&SH4::ReadSQ<uint8_t>,
|
||||
&SH4::ReadSQ<uint16_t>,
|
||||
&SH4::ReadSQ<uint32_t>,
|
||||
SH4_SQ_START, SH4_SQ_SIZE,
|
||||
make_delegate(&SH4::ReadSQ<uint8_t>, dc.sh4),
|
||||
make_delegate(&SH4::ReadSQ<uint16_t>, dc.sh4),
|
||||
make_delegate(&SH4::ReadSQ<uint32_t>, dc.sh4),
|
||||
nullptr,
|
||||
&SH4::WriteSQ<uint8_t>,
|
||||
&SH4::WriteSQ<uint16_t>,
|
||||
&SH4::WriteSQ<uint32_t>,
|
||||
make_delegate(&SH4::WriteSQ<uint8_t>, dc.sh4),
|
||||
make_delegate(&SH4::WriteSQ<uint16_t>, dc.sh4),
|
||||
make_delegate(&SH4::WriteSQ<uint32_t>, dc.sh4),
|
||||
nullptr);
|
||||
|
||||
// setup memory mapping for the allocated regions
|
||||
|
|
|
@ -50,15 +50,13 @@ void GDROM::SetDisc(std::unique_ptr<Disc> disc) {
|
|||
status_.BSY = 0;
|
||||
}
|
||||
|
||||
template uint8_t GDROM::ReadRegister(void *ctx, uint32_t addr);
|
||||
template uint16_t GDROM::ReadRegister(void *ctx, uint32_t addr);
|
||||
template uint32_t GDROM::ReadRegister(void *ctx, uint32_t addr);
|
||||
template uint8_t GDROM::ReadRegister(uint32_t addr);
|
||||
template uint16_t GDROM::ReadRegister(uint32_t addr);
|
||||
template uint32_t GDROM::ReadRegister(uint32_t addr);
|
||||
template <typename T>
|
||||
T GDROM::ReadRegister(void *ctx, uint32_t addr) {
|
||||
GDROM *self = reinterpret_cast<GDROM *>(ctx);
|
||||
|
||||
T GDROM::ReadRegister(uint32_t addr) {
|
||||
uint32_t offset = addr >> 2;
|
||||
Register ® = self->holly_regs_[offset];
|
||||
Register ® = holly_regs_[offset];
|
||||
|
||||
if (!(reg.flags & R)) {
|
||||
LOG_WARNING("Invalid read access at 0x%x", addr);
|
||||
|
@ -70,14 +68,14 @@ T GDROM::ReadRegister(void *ctx, uint32_t addr) {
|
|||
case GD_ALTSTAT_DEVCTRL_OFFSET:
|
||||
// this register is the same as the status register, but it does not
|
||||
// clear DMA status information when it is accessed
|
||||
return self->status_.full;
|
||||
return status_.full;
|
||||
|
||||
case GD_DATA_OFFSET: {
|
||||
// TODO add ReadData function
|
||||
uint16_t v = *(uint16_t *)&self->pio_buffer_[self->pio_idx_];
|
||||
self->pio_idx_ += 2;
|
||||
if (self->pio_idx_ == self->pio_size_) {
|
||||
self->TriggerEvent(EV_SPI_WRITE_END);
|
||||
uint16_t v = *(uint16_t *)&pio_buffer_[pio_idx_];
|
||||
pio_idx_ += 2;
|
||||
if (pio_idx_ == pio_size_) {
|
||||
TriggerEvent(EV_SPI_WRITE_END);
|
||||
}
|
||||
return static_cast<T>(v);
|
||||
}
|
||||
|
@ -87,24 +85,24 @@ T GDROM::ReadRegister(void *ctx, uint32_t addr) {
|
|||
return 0;
|
||||
|
||||
case GD_INTREASON_SECTCNT_OFFSET:
|
||||
return self->intreason_.full;
|
||||
return intreason_.full;
|
||||
|
||||
case GD_SECTNUM_OFFSET:
|
||||
return self->sectnum_.full;
|
||||
return sectnum_.full;
|
||||
|
||||
case GD_BYCTLLO_OFFSET:
|
||||
return self->byte_count_.lo;
|
||||
return byte_count_.lo;
|
||||
|
||||
case GD_BYCTLHI_OFFSET:
|
||||
return self->byte_count_.hi;
|
||||
return byte_count_.hi;
|
||||
|
||||
case GD_DRVSEL_OFFSET:
|
||||
// LOG_INFO("GD_DRVSEL");
|
||||
return 0;
|
||||
|
||||
case GD_STATUS_COMMAND_OFFSET:
|
||||
self->holly_->UnrequestInterrupt(HOLLY_INTC_G1GDINT);
|
||||
return self->status_.full;
|
||||
holly_->UnrequestInterrupt(HOLLY_INTC_G1GDINT);
|
||||
return status_.full;
|
||||
|
||||
// g1 bus regs
|
||||
}
|
||||
|
@ -112,15 +110,13 @@ T GDROM::ReadRegister(void *ctx, uint32_t addr) {
|
|||
return reg.value;
|
||||
}
|
||||
|
||||
template void GDROM::WriteRegister(void *ctx, uint32_t addr, uint8_t value);
|
||||
template void GDROM::WriteRegister(void *ctx, uint32_t addr, uint16_t value);
|
||||
template void GDROM::WriteRegister(void *ctx, uint32_t addr, uint32_t value);
|
||||
template void GDROM::WriteRegister(uint32_t addr, uint8_t value);
|
||||
template void GDROM::WriteRegister(uint32_t addr, uint16_t value);
|
||||
template void GDROM::WriteRegister(uint32_t addr, uint32_t value);
|
||||
template <typename T>
|
||||
void GDROM::WriteRegister(void *ctx, uint32_t addr, T value) {
|
||||
GDROM *self = reinterpret_cast<GDROM *>(ctx);
|
||||
|
||||
void GDROM::WriteRegister(uint32_t addr, T value) {
|
||||
uint32_t offset = addr >> 2;
|
||||
Register ® = self->holly_regs_[offset];
|
||||
Register ® = holly_regs_[offset];
|
||||
|
||||
if (!(reg.flags & W)) {
|
||||
LOG_WARNING("Invalid write access at 0x%x", addr);
|
||||
|
@ -138,17 +134,17 @@ void GDROM::WriteRegister(void *ctx, uint32_t addr, T value) {
|
|||
|
||||
case GD_DATA_OFFSET: {
|
||||
// TODO add WriteData function
|
||||
*(uint16_t *)(&self->pio_buffer_[self->pio_idx_]) = reg.value & 0xffff;
|
||||
self->pio_idx_ += 2;
|
||||
if ((self->state_ == STATE_SPI_READ_CMD && self->pio_idx_ == 12) ||
|
||||
(self->state_ == STATE_SPI_READ_DATA &&
|
||||
self->pio_idx_ == self->pio_size_)) {
|
||||
self->TriggerEvent(EV_SPI_READ_END);
|
||||
*(uint16_t *)(&pio_buffer_[pio_idx_]) = reg.value & 0xffff;
|
||||
pio_idx_ += 2;
|
||||
if ((state_ == STATE_SPI_READ_CMD && pio_idx_ == 12) ||
|
||||
(state_ == STATE_SPI_READ_DATA &&
|
||||
pio_idx_ == pio_size_)) {
|
||||
TriggerEvent(EV_SPI_READ_END);
|
||||
}
|
||||
} break;
|
||||
|
||||
case GD_ERROR_FEATURES_OFFSET:
|
||||
self->features_.full = reg.value;
|
||||
features_.full = reg.value;
|
||||
break;
|
||||
|
||||
case GD_INTREASON_SECTCNT_OFFSET:
|
||||
|
@ -156,15 +152,15 @@ void GDROM::WriteRegister(void *ctx, uint32_t addr, T value) {
|
|||
break;
|
||||
|
||||
case GD_SECTNUM_OFFSET:
|
||||
self->sectnum_.full = reg.value;
|
||||
sectnum_.full = reg.value;
|
||||
break;
|
||||
|
||||
case GD_BYCTLLO_OFFSET:
|
||||
self->byte_count_.lo = reg.value;
|
||||
byte_count_.lo = reg.value;
|
||||
break;
|
||||
|
||||
case GD_BYCTLHI_OFFSET:
|
||||
self->byte_count_.hi = reg.value;
|
||||
byte_count_.hi = reg.value;
|
||||
break;
|
||||
|
||||
case GD_DRVSEL_OFFSET:
|
||||
|
@ -172,7 +168,7 @@ void GDROM::WriteRegister(void *ctx, uint32_t addr, T value) {
|
|||
break;
|
||||
|
||||
case GD_STATUS_COMMAND_OFFSET:
|
||||
self->ProcessATACommand((ATACommand)reg.value);
|
||||
ProcessATACommand((ATACommand)reg.value);
|
||||
break;
|
||||
|
||||
// g1 bus regs
|
||||
|
@ -194,26 +190,26 @@ void GDROM::WriteRegister(void *ctx, uint32_t addr, T value) {
|
|||
// SB_GDSTAR, SB_GDLEN, or SB_GDDIR register is overwritten while a DMA
|
||||
// operation is in progress, the new setting has no effect on the
|
||||
// current DMA operation.
|
||||
CHECK_EQ(self->dc_->SB_GDEN, 1); // dma enabled
|
||||
CHECK_EQ(self->dc_->SB_GDDIR, 1); // gd-rom -> system memory
|
||||
CHECK_EQ(self->dc_->SB_GDLEN, (uint32_t)self->dma_size_);
|
||||
CHECK_EQ(dc_->SB_GDEN, 1); // dma enabled
|
||||
CHECK_EQ(dc_->SB_GDDIR, 1); // gd-rom -> system memory
|
||||
CHECK_EQ(dc_->SB_GDLEN, (uint32_t)dma_size_);
|
||||
|
||||
int transfer_size = self->dc_->SB_GDLEN;
|
||||
uint32_t start = self->dc_->SB_GDSTAR;
|
||||
int transfer_size = dc_->SB_GDLEN;
|
||||
uint32_t start = dc_->SB_GDSTAR;
|
||||
|
||||
printf("GD DMA START 0x%x -> 0x%x, 0x%x bytes\n", start,
|
||||
start + transfer_size, transfer_size);
|
||||
|
||||
self->memory_->Memcpy(start, self->dma_buffer_, transfer_size);
|
||||
memory_->Memcpy(start, dma_buffer_, transfer_size);
|
||||
|
||||
// done
|
||||
self->dc_->SB_GDSTARD = start + transfer_size;
|
||||
self->dc_->SB_GDLEND = transfer_size;
|
||||
self->dc_->SB_GDST = 0;
|
||||
self->holly_->RequestInterrupt(HOLLY_INTC_G1DEINT);
|
||||
dc_->SB_GDSTARD = start + transfer_size;
|
||||
dc_->SB_GDLEND = transfer_size;
|
||||
dc_->SB_GDST = 0;
|
||||
holly_->RequestInterrupt(HOLLY_INTC_G1DEINT);
|
||||
|
||||
// finish off CD_READ command
|
||||
self->TriggerEvent(EV_SPI_CMD_DONE);
|
||||
TriggerEvent(EV_SPI_CMD_DONE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -204,7 +204,7 @@ enum DataMask {
|
|||
|
||||
class GDROM {
|
||||
public:
|
||||
GDROM(hw::Dreamcast *dc);
|
||||
GDROM(Dreamcast *dc);
|
||||
~GDROM();
|
||||
|
||||
bool Init();
|
||||
|
@ -212,9 +212,9 @@ class GDROM {
|
|||
void SetDisc(std::unique_ptr<Disc> disc);
|
||||
|
||||
template <typename T>
|
||||
static T ReadRegister(void *ctx, uint32_t addr);
|
||||
T ReadRegister(uint32_t addr);
|
||||
template <typename T>
|
||||
static void WriteRegister(void *ctx, uint32_t addr, T value);
|
||||
void WriteRegister(uint32_t addr, T value);
|
||||
|
||||
private:
|
||||
void TriggerEvent(GDEvent ev);
|
||||
|
@ -228,10 +228,10 @@ class GDROM {
|
|||
int ReadSectors(int fad, SectorFormat format, DataMask mask, int num_sectors,
|
||||
uint8_t *dst);
|
||||
|
||||
hw::Dreamcast *dc_;
|
||||
hw::Memory *memory_;
|
||||
hw::holly::Holly *holly_;
|
||||
hw::Register *holly_regs_;
|
||||
Dreamcast *dc_;
|
||||
Memory *memory_;
|
||||
holly::Holly *holly_;
|
||||
Register *holly_regs_;
|
||||
|
||||
GD_FEATURES_T features_;
|
||||
GD_INTREASON_T intreason_;
|
||||
|
|
|
@ -77,23 +77,21 @@ void Holly::UnrequestInterrupt(HollyInterrupt intr) {
|
|||
ForwardRequestInterrupts();
|
||||
}
|
||||
|
||||
template uint8_t Holly::ReadRegister(void *ctx, uint32_t addr);
|
||||
template uint16_t Holly::ReadRegister(void *ctx, uint32_t addr);
|
||||
template uint32_t Holly::ReadRegister(void *ctx, uint32_t addr);
|
||||
template uint8_t Holly::ReadRegister(uint32_t addr);
|
||||
template uint16_t Holly::ReadRegister(uint32_t addr);
|
||||
template uint32_t Holly::ReadRegister(uint32_t addr);
|
||||
template <typename T>
|
||||
T Holly::ReadRegister(void *ctx, uint32_t addr) {
|
||||
Holly *self = reinterpret_cast<Holly *>(ctx);
|
||||
|
||||
T Holly::ReadRegister(uint32_t addr) {
|
||||
// service all devices connected through the system bus
|
||||
uint32_t offset = addr >> 2;
|
||||
if (offset >= SB_MDSTAR_OFFSET && offset <= SB_MRXDBD_OFFSET) {
|
||||
return Maple::ReadRegister<T>(self->maple_, addr);
|
||||
return maple_->ReadRegister<T>(addr);
|
||||
}
|
||||
if (offset >= GD_ALTSTAT_DEVCTRL_OFFSET && offset <= SB_GDLEND_OFFSET) {
|
||||
return GDROM::ReadRegister<T>(self->gdrom_, addr);
|
||||
return gdrom_->ReadRegister<T>(addr);
|
||||
}
|
||||
|
||||
Register ® = self->holly_regs_[offset];
|
||||
Register ® = holly_regs_[offset];
|
||||
|
||||
if (!(reg.flags & R)) {
|
||||
LOG_WARNING("Invalid read access at 0x%x", addr);
|
||||
|
@ -106,10 +104,10 @@ T Holly::ReadRegister(void *ctx, uint32_t addr) {
|
|||
// bits in SB_ISTEXT and SB_ISTERR, respectively, and writes to these two
|
||||
// bits are ignored.
|
||||
uint32_t v = reg.value & 0x3fffffff;
|
||||
if (self->dc_->SB_ISTEXT) {
|
||||
if (dc_->SB_ISTEXT) {
|
||||
v |= 0x40000000;
|
||||
}
|
||||
if (self->dc_->SB_ISTERR) {
|
||||
if (dc_->SB_ISTERR) {
|
||||
v |= 0x80000000;
|
||||
}
|
||||
return static_cast<T>(v);
|
||||
|
@ -119,25 +117,23 @@ T Holly::ReadRegister(void *ctx, uint32_t addr) {
|
|||
return static_cast<T>(reg.value);
|
||||
}
|
||||
|
||||
template void Holly::WriteRegister(void *ctx, uint32_t addr, uint8_t value);
|
||||
template void Holly::WriteRegister(void *ctx, uint32_t addr, uint16_t value);
|
||||
template void Holly::WriteRegister(void *ctx, uint32_t addr, uint32_t value);
|
||||
template void Holly::WriteRegister(uint32_t addr, uint8_t value);
|
||||
template void Holly::WriteRegister(uint32_t addr, uint16_t value);
|
||||
template void Holly::WriteRegister(uint32_t addr, uint32_t value);
|
||||
template <typename T>
|
||||
void Holly::WriteRegister(void *ctx, uint32_t addr, T value) {
|
||||
Holly *self = reinterpret_cast<Holly *>(ctx);
|
||||
|
||||
void Holly::WriteRegister(uint32_t addr, T value) {
|
||||
// service all devices connected through the system bus
|
||||
uint32_t offset = addr >> 2;
|
||||
if (offset >= SB_MDSTAR_OFFSET && offset <= SB_MRXDBD_OFFSET) {
|
||||
Maple::WriteRegister<T>(self->maple_, addr, value);
|
||||
maple_->WriteRegister<T>(addr, value);
|
||||
return;
|
||||
}
|
||||
if (offset >= GD_ALTSTAT_DEVCTRL_OFFSET && offset <= SB_GDLEND_OFFSET) {
|
||||
GDROM::WriteRegister<T>(self->gdrom_, addr, value);
|
||||
gdrom_->WriteRegister<T>(addr, value);
|
||||
return;
|
||||
}
|
||||
|
||||
Register ® = self->holly_regs_[offset];
|
||||
Register ® = holly_regs_[offset];
|
||||
|
||||
if (!(reg.flags & W)) {
|
||||
LOG_WARNING("Invalid write access at 0x%x", addr);
|
||||
|
@ -153,7 +149,7 @@ void Holly::WriteRegister(void *ctx, uint32_t addr, T value) {
|
|||
case SB_ISTERR_OFFSET: {
|
||||
// writing a 1 clears the interrupt
|
||||
reg.value = old & ~value;
|
||||
self->ForwardRequestInterrupts();
|
||||
ForwardRequestInterrupts();
|
||||
} break;
|
||||
|
||||
case SB_IML2NRM_OFFSET:
|
||||
|
@ -165,18 +161,18 @@ void Holly::WriteRegister(void *ctx, uint32_t addr, T value) {
|
|||
case SB_IML6NRM_OFFSET:
|
||||
case SB_IML6EXT_OFFSET:
|
||||
case SB_IML6ERR_OFFSET:
|
||||
self->ForwardRequestInterrupts();
|
||||
ForwardRequestInterrupts();
|
||||
break;
|
||||
|
||||
case SB_C2DST_OFFSET:
|
||||
if (value) {
|
||||
self->CH2DMATransfer();
|
||||
CH2DMATransfer();
|
||||
}
|
||||
break;
|
||||
|
||||
case SB_SDST_OFFSET:
|
||||
if (value) {
|
||||
self->SortDMATransfer();
|
||||
SortDMATransfer();
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@ enum HollyInterrupt : uint64_t {
|
|||
|
||||
class Holly {
|
||||
public:
|
||||
Holly(hw::Dreamcast *dc);
|
||||
Holly(Dreamcast *dc);
|
||||
|
||||
bool Init();
|
||||
|
||||
|
@ -165,20 +165,20 @@ class Holly {
|
|||
void UnrequestInterrupt(HollyInterrupt intr);
|
||||
|
||||
template <typename T>
|
||||
static T ReadRegister(void *ctx, uint32_t addr);
|
||||
T ReadRegister(uint32_t addr);
|
||||
template <typename T>
|
||||
static void WriteRegister(void *ctx, uint32_t addr, T value);
|
||||
void WriteRegister(uint32_t addr, T value);
|
||||
|
||||
private:
|
||||
void CH2DMATransfer();
|
||||
void SortDMATransfer();
|
||||
void ForwardRequestInterrupts();
|
||||
|
||||
hw::Dreamcast *dc_;
|
||||
hw::Register *holly_regs_;
|
||||
hw::gdrom::GDROM *gdrom_;
|
||||
hw::maple::Maple *maple_;
|
||||
hw::sh4::SH4 *sh4_;
|
||||
Dreamcast *dc_;
|
||||
Register *holly_regs_;
|
||||
gdrom::GDROM *gdrom_;
|
||||
maple::Maple *maple_;
|
||||
sh4::SH4 *sh4_;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,11 +31,9 @@ bool PVR2::Init() {
|
|||
return true;
|
||||
}
|
||||
|
||||
uint32_t PVR2::ReadRegister(void *ctx, uint32_t addr) {
|
||||
PVR2 *self = reinterpret_cast<PVR2 *>(ctx);
|
||||
|
||||
uint32_t PVR2::ReadRegister(uint32_t addr) {
|
||||
uint32_t offset = addr >> 2;
|
||||
Register ® = self->pvr_regs_[offset];
|
||||
Register ® = pvr_regs_[offset];
|
||||
|
||||
if (!(reg.flags & R)) {
|
||||
LOG_WARNING("Invalid read access at 0x%x", addr);
|
||||
|
@ -45,11 +43,9 @@ uint32_t PVR2::ReadRegister(void *ctx, uint32_t addr) {
|
|||
return reg.value;
|
||||
}
|
||||
|
||||
void PVR2::WriteRegister(void *ctx, uint32_t addr, uint32_t value) {
|
||||
PVR2 *self = reinterpret_cast<PVR2 *>(ctx);
|
||||
|
||||
void PVR2::WriteRegister(uint32_t addr, uint32_t value) {
|
||||
uint32_t offset = addr >> 2;
|
||||
Register ® = self->pvr_regs_[offset];
|
||||
Register ® = pvr_regs_[offset];
|
||||
|
||||
if (!(reg.flags & W)) {
|
||||
LOG_WARNING("Invalid write access at 0x%x", addr);
|
||||
|
@ -62,12 +58,12 @@ void PVR2::WriteRegister(void *ctx, uint32_t addr, uint32_t value) {
|
|||
case SOFTRESET_OFFSET: {
|
||||
bool reset_ta = value & 0x1;
|
||||
if (reset_ta) {
|
||||
self->ta_->SoftReset();
|
||||
ta_->SoftReset();
|
||||
}
|
||||
} break;
|
||||
|
||||
case TA_LIST_INIT_OFFSET: {
|
||||
self->ta_->InitContext(self->dc_->TA_ISP_BASE.base_address);
|
||||
ta_->InitContext(dc_->TA_ISP_BASE.base_address);
|
||||
} break;
|
||||
|
||||
case STARTRENDER_OFFSET: {
|
||||
|
@ -75,17 +71,17 @@ void PVR2::WriteRegister(void *ctx, uint32_t addr, uint32_t value) {
|
|||
{
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
auto delta = std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
now - self->last_render_);
|
||||
self->last_render_ = now;
|
||||
self->rps_ = 1000000000.0f / delta.count();
|
||||
now - last_render_);
|
||||
last_render_ = now;
|
||||
rps_ = 1000000000.0f / delta.count();
|
||||
}
|
||||
|
||||
self->ta_->FinalizeContext(self->dc_->PARAM_BASE.base_address);
|
||||
ta_->FinalizeContext(dc_->PARAM_BASE.base_address);
|
||||
} break;
|
||||
|
||||
case SPG_LOAD_OFFSET:
|
||||
case FB_R_CTRL_OFFSET: {
|
||||
self->ReconfigureSPG();
|
||||
ReconfigureSPG();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
@ -111,29 +107,21 @@ static uint32_t MAP64(uint32_t addr) {
|
|||
(addr & 0x3));
|
||||
}
|
||||
|
||||
template uint8_t PVR2::ReadVRamInterleaved(void *ctx, uint32_t addr);
|
||||
template uint16_t PVR2::ReadVRamInterleaved(void *ctx, uint32_t addr);
|
||||
template uint32_t PVR2::ReadVRamInterleaved(void *ctx, uint32_t addr);
|
||||
template uint8_t PVR2::ReadVRamInterleaved(uint32_t addr);
|
||||
template uint16_t PVR2::ReadVRamInterleaved(uint32_t addr);
|
||||
template uint32_t PVR2::ReadVRamInterleaved(uint32_t addr);
|
||||
template <typename T>
|
||||
T PVR2::ReadVRamInterleaved(void *ctx, uint32_t addr) {
|
||||
PVR2 *self = reinterpret_cast<PVR2 *>(ctx);
|
||||
|
||||
T PVR2::ReadVRamInterleaved(uint32_t addr) {
|
||||
addr = MAP64(addr);
|
||||
|
||||
return re::load<T>(&self->video_ram_[addr]);
|
||||
return re::load<T>(&video_ram_[addr]);
|
||||
}
|
||||
|
||||
template void PVR2::WriteVRamInterleaved(void *ctx, uint32_t addr,
|
||||
uint16_t value);
|
||||
template void PVR2::WriteVRamInterleaved(void *ctx, uint32_t addr,
|
||||
uint32_t value);
|
||||
template void PVR2::WriteVRamInterleaved(uint32_t addr, uint16_t value);
|
||||
template void PVR2::WriteVRamInterleaved(uint32_t addr, uint32_t value);
|
||||
template <typename T>
|
||||
void PVR2::WriteVRamInterleaved(void *ctx, uint32_t addr, T value) {
|
||||
PVR2 *self = reinterpret_cast<PVR2 *>(ctx);
|
||||
|
||||
void PVR2::WriteVRamInterleaved(uint32_t addr, T value) {
|
||||
addr = MAP64(addr);
|
||||
|
||||
re::store(&self->video_ram_[addr], value);
|
||||
re::store(&video_ram_[addr], value);
|
||||
}
|
||||
|
||||
void PVR2::ReconfigureSPG() {
|
||||
|
|
|
@ -198,34 +198,34 @@ union TA_ISP_BASE_T {
|
|||
|
||||
class PVR2 {
|
||||
public:
|
||||
PVR2(hw::Dreamcast *dc);
|
||||
PVR2(Dreamcast *dc);
|
||||
|
||||
float rps() { return rps_; }
|
||||
|
||||
bool Init();
|
||||
|
||||
static uint32_t ReadRegister(void *ctx, uint32_t addr);
|
||||
static void WriteRegister(void *ctx, uint32_t addr, uint32_t value);
|
||||
uint32_t ReadRegister(uint32_t addr);
|
||||
void WriteRegister(uint32_t addr, uint32_t value);
|
||||
|
||||
template <typename T>
|
||||
static T ReadVRamInterleaved(void *ctx, uint32_t addr);
|
||||
T ReadVRamInterleaved(uint32_t addr);
|
||||
template <typename T>
|
||||
static void WriteVRamInterleaved(void *ctx, uint32_t addr, T value);
|
||||
void WriteVRamInterleaved(uint32_t addr, T value);
|
||||
|
||||
private:
|
||||
void ReconfigureSPG();
|
||||
void NextScanline();
|
||||
|
||||
hw::Dreamcast *dc_;
|
||||
hw::Scheduler *scheduler_;
|
||||
hw::holly::Holly *holly_;
|
||||
hw::holly::TileAccelerator *ta_;
|
||||
hw::holly::TextureCache *texcache_;
|
||||
hw::Register *pvr_regs_;
|
||||
Dreamcast *dc_;
|
||||
Scheduler *scheduler_;
|
||||
holly::Holly *holly_;
|
||||
holly::TileAccelerator *ta_;
|
||||
holly::TextureCache *texcache_;
|
||||
Register *pvr_regs_;
|
||||
uint8_t *palette_ram_;
|
||||
uint8_t *video_ram_;
|
||||
|
||||
hw::TimerHandle line_timer_;
|
||||
TimerHandle line_timer_;
|
||||
uint32_t current_scanline_;
|
||||
|
||||
std::chrono::high_resolution_clock::time_point last_render_;
|
||||
|
|
|
@ -347,18 +347,14 @@ TileContext *TileAccelerator::GetLastContext() {
|
|||
return pending_contexts_.front();
|
||||
}
|
||||
|
||||
void TileAccelerator::WriteCommand(void *ctx, uint32_t addr, uint32_t value) {
|
||||
TileAccelerator *self = reinterpret_cast<TileAccelerator *>(ctx);
|
||||
|
||||
self->WriteContext(self->dc_->TA_ISP_BASE.base_address, value);
|
||||
void TileAccelerator::WriteCommand(uint32_t addr, uint32_t value) {
|
||||
WriteContext(dc_->TA_ISP_BASE.base_address, value);
|
||||
}
|
||||
|
||||
void TileAccelerator::WriteTexture(void *ctx, uint32_t addr, uint32_t value) {
|
||||
TileAccelerator *self = reinterpret_cast<TileAccelerator *>(ctx);
|
||||
|
||||
void TileAccelerator::WriteTexture(uint32_t addr, uint32_t value) {
|
||||
addr &= 0xeeffffff;
|
||||
|
||||
re::store(&self->video_ram_[addr], value);
|
||||
re::store(&video_ram_[addr], value);
|
||||
}
|
||||
|
||||
void TileAccelerator::WritePVRState(TileContext *tactx) {
|
||||
|
|
|
@ -486,7 +486,7 @@ class TileAccelerator {
|
|||
static int GetPolyType(const PCW &pcw);
|
||||
static int GetVertexType(const PCW &pcw);
|
||||
|
||||
TileAccelerator(hw::Dreamcast *dc);
|
||||
TileAccelerator(Dreamcast *dc);
|
||||
|
||||
bool Init();
|
||||
|
||||
|
@ -497,17 +497,17 @@ class TileAccelerator {
|
|||
|
||||
TileContext *GetLastContext();
|
||||
|
||||
static void WriteCommand(void *ctx, uint32_t addr, uint32_t value);
|
||||
static void WriteTexture(void *ctx, uint32_t addr, uint32_t value);
|
||||
void WriteCommand(uint32_t addr, uint32_t value);
|
||||
void WriteTexture(uint32_t addr, uint32_t value);
|
||||
|
||||
private:
|
||||
void WritePVRState(TileContext *tactx);
|
||||
void WriteBackgroundState(TileContext *tactx);
|
||||
|
||||
hw::Dreamcast *dc_;
|
||||
hw::Memory *memory_;
|
||||
hw::holly::Holly *holly_;
|
||||
hw::holly::TextureCache *texcache_;
|
||||
Dreamcast *dc_;
|
||||
Memory *memory_;
|
||||
holly::Holly *holly_;
|
||||
holly::TextureCache *texcache_;
|
||||
uint8_t *video_ram_;
|
||||
|
||||
std::mutex context_mutex_;
|
||||
|
|
|
@ -814,7 +814,8 @@ TextureHandle TileRenderer::RegisterTexture(const TileContext *tactx,
|
|||
break;
|
||||
|
||||
default:
|
||||
LOG_FATAL("Unsupported 4bpp palette pixel format %d", tactx->pal_pxl_format);
|
||||
LOG_FATAL("Unsupported 4bpp palette pixel format %d",
|
||||
tactx->pal_pxl_format);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -838,7 +839,8 @@ TextureHandle TileRenderer::RegisterTexture(const TileContext *tactx,
|
|||
break;
|
||||
|
||||
default:
|
||||
LOG_FATAL("Unsupported 8bpp palette pixel format %d", tactx->pal_pxl_format);
|
||||
LOG_FATAL("Unsupported 8bpp palette pixel format %d",
|
||||
tactx->pal_pxl_format);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -46,15 +46,13 @@ void Maple::VBlank() {
|
|||
// TODO maple vblank interrupt?
|
||||
}
|
||||
|
||||
template uint8_t Maple::ReadRegister(void *ctx, uint32_t addr);
|
||||
template uint16_t Maple::ReadRegister(void *ctx, uint32_t addr);
|
||||
template uint32_t Maple::ReadRegister(void *ctx, uint32_t addr);
|
||||
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(void *ctx, uint32_t addr) {
|
||||
Maple *self = reinterpret_cast<Maple *>(ctx);
|
||||
|
||||
T Maple::ReadRegister(uint32_t addr) {
|
||||
uint32_t offset = addr >> 2;
|
||||
Register ® = self->holly_regs_[offset];
|
||||
Register ® = holly_regs_[offset];
|
||||
|
||||
if (!(reg.flags & R)) {
|
||||
LOG_WARNING("Invalid read access at 0x%x", addr);
|
||||
|
@ -64,15 +62,13 @@ T Maple::ReadRegister(void *ctx, uint32_t addr) {
|
|||
return static_cast<T>(reg.value);
|
||||
}
|
||||
|
||||
template void Maple::WriteRegister(void *ctx, uint32_t addr, uint8_t value);
|
||||
template void Maple::WriteRegister(void *ctx, uint32_t addr, uint16_t value);
|
||||
template void Maple::WriteRegister(void *ctx, uint32_t addr, uint32_t 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(void *ctx, uint32_t addr, T value) {
|
||||
Maple *self = reinterpret_cast<Maple *>(ctx);
|
||||
|
||||
void Maple::WriteRegister(uint32_t addr, T value) {
|
||||
uint32_t offset = addr >> 2;
|
||||
Register ® = self->holly_regs_[offset];
|
||||
Register ® = holly_regs_[offset];
|
||||
|
||||
if (!(reg.flags & W)) {
|
||||
LOG_WARNING("Invalid write access at 0x%x", addr);
|
||||
|
@ -84,10 +80,10 @@ void Maple::WriteRegister(void *ctx, uint32_t addr, T value) {
|
|||
|
||||
switch (offset) {
|
||||
case SB_MDST_OFFSET: {
|
||||
uint32_t enabled = self->dc_->SB_MDEN;
|
||||
uint32_t enabled = dc_->SB_MDEN;
|
||||
if (enabled) {
|
||||
if (value) {
|
||||
self->StartDMA();
|
||||
StartDMA();
|
||||
}
|
||||
} else {
|
||||
reg.value = 0;
|
||||
|
|
|
@ -101,7 +101,7 @@ class MapleDevice {
|
|||
|
||||
class Maple {
|
||||
public:
|
||||
Maple(hw::Dreamcast *dc);
|
||||
Maple(Dreamcast *dc);
|
||||
|
||||
bool Init();
|
||||
|
||||
|
@ -109,18 +109,18 @@ class Maple {
|
|||
void VBlank();
|
||||
|
||||
template <typename T>
|
||||
static T ReadRegister(void *ctx, uint32_t addr);
|
||||
T ReadRegister(uint32_t addr);
|
||||
template <typename T>
|
||||
static void WriteRegister(void *ctx, uint32_t addr, T value);
|
||||
void WriteRegister(uint32_t addr, T value);
|
||||
|
||||
private:
|
||||
bool HandleFrame(const MapleFrame &frame, MapleFrame &res);
|
||||
void StartDMA();
|
||||
|
||||
hw::Dreamcast *dc_;
|
||||
hw::Memory *memory_;
|
||||
hw::holly::Holly *holly_;
|
||||
hw::Register *holly_regs_;
|
||||
Dreamcast *dc_;
|
||||
Memory *memory_;
|
||||
holly::Holly *holly_;
|
||||
Register *holly_regs_;
|
||||
|
||||
std::unique_ptr<MapleDevice> devices_[MAX_PORTS];
|
||||
};
|
||||
|
|
|
@ -247,15 +247,14 @@ RegionHandle Memory::AllocRegion(uint32_t physical_addr, uint32_t size) {
|
|||
}
|
||||
|
||||
RegionHandle Memory::AllocRegion(uint32_t physical_addr, uint32_t size,
|
||||
void *ctx, R8Handler r8, R16Handler r16,
|
||||
R32Handler r32, R64Handler r64, W8Handler w8,
|
||||
W16Handler w16, W32Handler w32,
|
||||
W64Handler w64) {
|
||||
R8Delegate r8, R16Delegate r16,
|
||||
R32Delegate r32, R64Delegate r64,
|
||||
W8Delegate w8, W16Delegate w16,
|
||||
W32Delegate w32, W64Delegate w64) {
|
||||
MemoryRegion *region = AllocRegion();
|
||||
region->dynamic = true;
|
||||
region->physical_addr = physical_addr;
|
||||
region->size = size;
|
||||
region->ctx = ctx;
|
||||
region->r8 = r8;
|
||||
region->r16 = r16;
|
||||
region->r32 = r32;
|
||||
|
@ -536,7 +535,7 @@ void Memory::UnmapVirtualSpace() {
|
|||
unmap_virtual(protected_base_);
|
||||
}
|
||||
|
||||
template <typename INT, INT (*MemoryRegion::*HANDLER)(void *, uint32_t)>
|
||||
template <typename INT, delegate<INT(uint32_t)> MemoryRegion::*DELEGATE>
|
||||
inline INT Memory::ReadBytes(uint32_t addr) {
|
||||
PageEntry page = pages_[PageIndex(addr)];
|
||||
uint32_t page_offset = PageOffset(addr);
|
||||
|
@ -547,16 +546,11 @@ inline INT Memory::ReadBytes(uint32_t addr) {
|
|||
}
|
||||
|
||||
MemoryRegion ®ion = regions_[RegionIndex(page)];
|
||||
if (!(region.*HANDLER)) {
|
||||
LOG_WARNING("Unmapped read at 0x%08x", addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t region_offset = RegionOffset(page);
|
||||
return (region.*HANDLER)(region.ctx, region_offset + page_offset);
|
||||
return (region.*DELEGATE)(region_offset + page_offset);
|
||||
}
|
||||
|
||||
template <typename INT, void (*MemoryRegion::*HANDLER)(void *, uint32_t, INT)>
|
||||
template <typename INT, delegate<void(uint32_t, INT)> MemoryRegion::*DELEGATE>
|
||||
inline void Memory::WriteBytes(uint32_t addr, INT value) {
|
||||
PageEntry page = pages_[PageIndex(addr)];
|
||||
uint32_t page_offset = PageOffset(addr);
|
||||
|
@ -568,11 +562,6 @@ inline void Memory::WriteBytes(uint32_t addr, INT value) {
|
|||
}
|
||||
|
||||
MemoryRegion ®ion = regions_[RegionIndex(page)];
|
||||
if (!(region.*HANDLER)) {
|
||||
LOG_WARNING("Unmapped write at 0x%08x", addr);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t region_offset = RegionOffset(page);
|
||||
(region.*HANDLER)(region.ctx, region_offset + page_offset, value);
|
||||
(region.*DELEGATE)(region_offset + page_offset, value);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef MEMORY_H
|
||||
#define MEMORY_H
|
||||
|
||||
#include <functional>
|
||||
#include "core/delegate.h"
|
||||
#include "sys/exception_handler.h"
|
||||
#include "sys/memory.h"
|
||||
|
||||
|
@ -86,14 +88,15 @@ class MemoryMap {
|
|||
// entries are always non-zero
|
||||
typedef uintptr_t PageEntry;
|
||||
|
||||
typedef uint8_t (*R8Handler)(void *, uint32_t);
|
||||
typedef uint16_t (*R16Handler)(void *, uint32_t);
|
||||
typedef uint32_t (*R32Handler)(void *, uint32_t);
|
||||
typedef uint64_t (*R64Handler)(void *, uint32_t);
|
||||
typedef void (*W8Handler)(void *, uint32_t, uint8_t);
|
||||
typedef void (*W16Handler)(void *, uint32_t, uint16_t);
|
||||
typedef void (*W32Handler)(void *, uint32_t, uint32_t);
|
||||
typedef void (*W64Handler)(void *, uint32_t, uint64_t);
|
||||
typedef delegate<uint8_t(uint32_t)> R8Delegate;
|
||||
typedef delegate<uint16_t(uint32_t)> R16Delegate;
|
||||
typedef delegate<uint32_t(uint32_t)> R32Delegate;
|
||||
typedef delegate<uint64_t(uint32_t)> R64Delegate;
|
||||
|
||||
typedef delegate<void(uint32_t, uint8_t)> W8Delegate;
|
||||
typedef delegate<void(uint32_t, uint16_t)> W16Delegate;
|
||||
typedef delegate<void(uint32_t, uint32_t)> W32Delegate;
|
||||
typedef delegate<void(uint32_t, uint64_t)> W64Delegate;
|
||||
|
||||
enum {
|
||||
PAGE_BITS = 20,
|
||||
|
@ -131,14 +134,15 @@ struct MemoryRegion {
|
|||
uint32_t physical_addr;
|
||||
uint32_t size;
|
||||
void *ctx;
|
||||
R8Handler r8;
|
||||
R16Handler r16;
|
||||
R32Handler r32;
|
||||
R64Handler r64;
|
||||
W8Handler w8;
|
||||
W16Handler w16;
|
||||
W32Handler w32;
|
||||
W64Handler w64;
|
||||
|
||||
R8Delegate r8;
|
||||
R16Delegate r16;
|
||||
R32Delegate r32;
|
||||
R64Delegate r64;
|
||||
W8Delegate w8;
|
||||
W16Delegate w16;
|
||||
W32Delegate w32;
|
||||
W64Delegate w64;
|
||||
};
|
||||
|
||||
class Memory {
|
||||
|
@ -162,10 +166,10 @@ class Memory {
|
|||
bool Init();
|
||||
|
||||
RegionHandle AllocRegion(uint32_t physical_addr, uint32_t size);
|
||||
RegionHandle AllocRegion(uint32_t physical_addr, uint32_t size, void *ctx,
|
||||
R8Handler r8, R16Handler r16, R32Handler r32,
|
||||
R64Handler r64, W8Handler w8, W16Handler w16,
|
||||
W32Handler w32, W64Handler w64);
|
||||
RegionHandle AllocRegion(uint32_t physical_addr, uint32_t size, R8Delegate r8,
|
||||
R16Delegate r16, R32Delegate r32, R64Delegate r64,
|
||||
W8Delegate w8, W16Delegate w16, W32Delegate w32,
|
||||
W64Delegate w64);
|
||||
|
||||
bool Map(const MemoryMap &map);
|
||||
|
||||
|
@ -203,9 +207,9 @@ class Memory {
|
|||
bool MapVirtualSpace();
|
||||
void UnmapVirtualSpace();
|
||||
|
||||
template <typename INT, INT (*MemoryRegion::*HANDLER)(void *, uint32_t)>
|
||||
template <typename INT, delegate<INT(uint32_t)> MemoryRegion::*DELEGATE>
|
||||
INT ReadBytes(uint32_t addr);
|
||||
template <typename INT, void (*MemoryRegion::*HANDLER)(void *, uint32_t, INT)>
|
||||
template <typename INT, delegate<void(uint32_t, INT)> MemoryRegion::*DELEGATE>
|
||||
void WriteBytes(uint32_t addr, INT value);
|
||||
|
||||
// shared memory object where all physical data is written to
|
||||
|
|
|
@ -138,13 +138,11 @@ void SH4::UnrequestInterrupt(Interrupt intr) {
|
|||
UpdatePendingInterrupts();
|
||||
}
|
||||
|
||||
template uint8_t SH4::ReadRegister(void *ctx, uint32_t addr);
|
||||
template uint16_t SH4::ReadRegister(void *ctx, uint32_t addr);
|
||||
template uint32_t SH4::ReadRegister(void *ctx, uint32_t addr);
|
||||
template uint8_t SH4::ReadRegister(uint32_t addr);
|
||||
template uint16_t SH4::ReadRegister(uint32_t addr);
|
||||
template uint32_t SH4::ReadRegister(uint32_t addr);
|
||||
template <typename T>
|
||||
T SH4::ReadRegister(void *ctx, uint32_t addr) {
|
||||
SH4 *self = reinterpret_cast<SH4 *>(ctx);
|
||||
|
||||
T SH4::ReadRegister(uint32_t addr) {
|
||||
// translate from 64mb space to our 16kb space
|
||||
addr = ((addr & 0x1fe0000) >> 11) | ((addr & 0xfc) >> 2);
|
||||
|
||||
|
@ -177,8 +175,8 @@ T SH4::ReadRegister(void *ctx, uint32_t addr) {
|
|||
// reg[PDTRA] = reg[PDTRA] & 0xfffd;
|
||||
// _8c00b92c(0);
|
||||
// reg[PCTRA] = old_PCTRA;
|
||||
uint32_t pctra = self->PCTRA;
|
||||
uint32_t pdtra = self->PDTRA;
|
||||
uint32_t pctra = PCTRA;
|
||||
uint32_t pdtra = PDTRA;
|
||||
uint32_t v = 0;
|
||||
if ((pctra & 0xf) == 0x8 ||
|
||||
((pctra & 0xf) == 0xb && (pdtra & 0xf) != 0x2) ||
|
||||
|
@ -218,29 +216,27 @@ T SH4::ReadRegister(void *ctx, uint32_t addr) {
|
|||
}
|
||||
|
||||
case TCNT0_OFFSET:
|
||||
return self->TimerCount(0);
|
||||
return TimerCount(0);
|
||||
|
||||
case TCNT1_OFFSET:
|
||||
return self->TimerCount(1);
|
||||
return TimerCount(1);
|
||||
|
||||
case TCNT2_OFFSET:
|
||||
return self->TimerCount(2);
|
||||
return TimerCount(2);
|
||||
}
|
||||
|
||||
return static_cast<T>(self->area7_[addr]);
|
||||
return static_cast<T>(area7_[addr]);
|
||||
}
|
||||
|
||||
template void SH4::WriteRegister(void *ctx, uint32_t addr, uint8_t value);
|
||||
template void SH4::WriteRegister(void *ctx, uint32_t addr, uint16_t value);
|
||||
template void SH4::WriteRegister(void *ctx, uint32_t addr, uint32_t value);
|
||||
template void SH4::WriteRegister(uint32_t addr, uint8_t value);
|
||||
template void SH4::WriteRegister(uint32_t addr, uint16_t value);
|
||||
template void SH4::WriteRegister(uint32_t addr, uint32_t value);
|
||||
template <typename T>
|
||||
void SH4::WriteRegister(void *ctx, uint32_t addr, T value) {
|
||||
SH4 *self = reinterpret_cast<SH4 *>(ctx);
|
||||
|
||||
void SH4::WriteRegister(uint32_t addr, T value) {
|
||||
// translate from 64mb space to our 16kb space
|
||||
addr = ((addr & 0x1fe0000) >> 11) | ((addr & 0xfc) >> 2);
|
||||
|
||||
self->area7_[addr] = static_cast<uint32_t>(value);
|
||||
area7_[addr] = static_cast<uint32_t>(value);
|
||||
|
||||
switch (addr) {
|
||||
case MMUCR_OFFSET: {
|
||||
|
@ -252,35 +248,35 @@ void SH4::WriteRegister(void *ctx, uint32_t addr, T value) {
|
|||
// it seems the only aspect of the cache control register that needs to be
|
||||
// emulated is the instruction cache invalidation
|
||||
case CCR_OFFSET: {
|
||||
if (self->CCR.ICI) {
|
||||
self->ResetCache();
|
||||
if (CCR.ICI) {
|
||||
ResetCache();
|
||||
}
|
||||
} break;
|
||||
|
||||
case IPRA_OFFSET:
|
||||
case IPRB_OFFSET:
|
||||
case IPRC_OFFSET: {
|
||||
self->ReprioritizeInterrupts();
|
||||
ReprioritizeInterrupts();
|
||||
} break;
|
||||
|
||||
// TODO UnrequestInterrupt on TCR write
|
||||
|
||||
case TSTR_OFFSET: {
|
||||
self->ScheduleTimer(0);
|
||||
self->ScheduleTimer(1);
|
||||
self->ScheduleTimer(2);
|
||||
ScheduleTimer(0);
|
||||
ScheduleTimer(1);
|
||||
ScheduleTimer(2);
|
||||
} break;
|
||||
|
||||
case TCNT0_OFFSET: {
|
||||
self->ScheduleTimer(0);
|
||||
ScheduleTimer(0);
|
||||
} break;
|
||||
|
||||
case TCNT1_OFFSET: {
|
||||
self->ScheduleTimer(1);
|
||||
ScheduleTimer(1);
|
||||
} break;
|
||||
|
||||
case TCNT2_OFFSET: {
|
||||
self->ScheduleTimer(2);
|
||||
ScheduleTimer(2);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
@ -289,50 +285,46 @@ void SH4::WriteRegister(void *ctx, uint32_t addr, T value) {
|
|||
#define CACHE_OFFSET(addr, OIX) \
|
||||
((OIX ? ((addr & 0x2000000) >> 13) : ((addr & 0x2000) >> 1)) | (addr & 0xfff))
|
||||
|
||||
template uint8_t SH4::ReadCache(void *ctx, uint32_t addr);
|
||||
template uint16_t SH4::ReadCache(void *ctx, uint32_t addr);
|
||||
template uint32_t SH4::ReadCache(void *ctx, uint32_t addr);
|
||||
template uint64_t SH4::ReadCache(void *ctx, uint32_t addr);
|
||||
template uint8_t SH4::ReadCache(uint32_t addr);
|
||||
template uint16_t SH4::ReadCache(uint32_t addr);
|
||||
template uint32_t SH4::ReadCache(uint32_t addr);
|
||||
template uint64_t SH4::ReadCache(uint32_t addr);
|
||||
template <typename T>
|
||||
T SH4::ReadCache(void *ctx, uint32_t addr) {
|
||||
SH4 *self = reinterpret_cast<SH4 *>(ctx);
|
||||
CHECK_EQ(self->CCR.ORA, 1u);
|
||||
addr = CACHE_OFFSET(addr, self->CCR.OIX);
|
||||
return re::load<T>(&self->cache_[addr]);
|
||||
T SH4::ReadCache(uint32_t addr) {
|
||||
CHECK_EQ(CCR.ORA, 1u);
|
||||
addr = CACHE_OFFSET(addr, CCR.OIX);
|
||||
return re::load<T>(&cache_[addr]);
|
||||
}
|
||||
|
||||
template void SH4::WriteCache(void *ctx, uint32_t addr, uint8_t value);
|
||||
template void SH4::WriteCache(void *ctx, uint32_t addr, uint16_t value);
|
||||
template void SH4::WriteCache(void *ctx, uint32_t addr, uint32_t value);
|
||||
template void SH4::WriteCache(void *ctx, uint32_t addr, uint64_t value);
|
||||
template void SH4::WriteCache(uint32_t addr, uint8_t value);
|
||||
template void SH4::WriteCache(uint32_t addr, uint16_t value);
|
||||
template void SH4::WriteCache(uint32_t addr, uint32_t value);
|
||||
template void SH4::WriteCache(uint32_t addr, uint64_t value);
|
||||
template <typename T>
|
||||
void SH4::WriteCache(void *ctx, uint32_t addr, T value) {
|
||||
SH4 *self = reinterpret_cast<SH4 *>(ctx);
|
||||
CHECK_EQ(self->CCR.ORA, 1u);
|
||||
addr = CACHE_OFFSET(addr, self->CCR.OIX);
|
||||
re::store(&self->cache_[addr], value);
|
||||
void SH4::WriteCache(uint32_t addr, T value) {
|
||||
CHECK_EQ(CCR.ORA, 1u);
|
||||
addr = CACHE_OFFSET(addr, CCR.OIX);
|
||||
re::store(&cache_[addr], value);
|
||||
}
|
||||
|
||||
template uint8_t SH4::ReadSQ(void *ctx, uint32_t addr);
|
||||
template uint16_t SH4::ReadSQ(void *ctx, uint32_t addr);
|
||||
template uint32_t SH4::ReadSQ(void *ctx, uint32_t addr);
|
||||
template uint8_t SH4::ReadSQ(uint32_t addr);
|
||||
template uint16_t SH4::ReadSQ(uint32_t addr);
|
||||
template uint32_t SH4::ReadSQ(uint32_t addr);
|
||||
template <typename T>
|
||||
T SH4::ReadSQ(void *ctx, uint32_t addr) {
|
||||
SH4 *self = reinterpret_cast<SH4 *>(ctx);
|
||||
T SH4::ReadSQ(uint32_t addr) {
|
||||
uint32_t sqi = (addr & 0x20) >> 5;
|
||||
unsigned idx = (addr & 0x1c) >> 2;
|
||||
return static_cast<T>(self->ctx_.sq[sqi][idx]);
|
||||
return static_cast<T>(ctx_.sq[sqi][idx]);
|
||||
}
|
||||
|
||||
template void SH4::WriteSQ(void *ctx, uint32_t addr, uint8_t value);
|
||||
template void SH4::WriteSQ(void *ctx, uint32_t addr, uint16_t value);
|
||||
template void SH4::WriteSQ(void *ctx, uint32_t addr, uint32_t value);
|
||||
template void SH4::WriteSQ(uint32_t addr, uint8_t value);
|
||||
template void SH4::WriteSQ(uint32_t addr, uint16_t value);
|
||||
template void SH4::WriteSQ(uint32_t addr, uint32_t value);
|
||||
template <typename T>
|
||||
void SH4::WriteSQ(void *ctx, uint32_t addr, T value) {
|
||||
SH4 *self = reinterpret_cast<SH4 *>(ctx);
|
||||
void SH4::WriteSQ(uint32_t addr, T value) {
|
||||
uint32_t sqi = (addr & 0x20) >> 5;
|
||||
uint32_t idx = (addr & 0x1c) >> 2;
|
||||
self->ctx_.sq[sqi][idx] = static_cast<uint32_t>(value);
|
||||
ctx_.sq[sqi][idx] = static_cast<uint32_t>(value);
|
||||
}
|
||||
|
||||
uint32_t SH4::CompilePC() {
|
||||
|
|
|
@ -110,7 +110,7 @@ class SH4 {
|
|||
friend void RunSH4Test(const SH4Test &);
|
||||
|
||||
public:
|
||||
SH4(hw::Dreamcast *dc);
|
||||
SH4(Dreamcast *dc);
|
||||
~SH4();
|
||||
|
||||
bool Init();
|
||||
|
@ -125,19 +125,19 @@ class SH4 {
|
|||
void UnrequestInterrupt(Interrupt intr);
|
||||
|
||||
template <typename T>
|
||||
static T ReadRegister(void *ctx, uint32_t addr);
|
||||
T ReadRegister(uint32_t addr);
|
||||
template <typename T>
|
||||
static void WriteRegister(void *ctx, uint32_t addr, T value);
|
||||
void WriteRegister(uint32_t addr, T value);
|
||||
|
||||
template <typename T>
|
||||
static T ReadCache(void *ctx, uint32_t addr);
|
||||
T ReadCache(uint32_t addr);
|
||||
template <typename T>
|
||||
static void WriteCache(void *ctx, uint32_t addr, T value);
|
||||
void WriteCache(uint32_t addr, T value);
|
||||
|
||||
template <typename T>
|
||||
static T ReadSQ(void *ctx, uint32_t addr);
|
||||
T ReadSQ(uint32_t addr);
|
||||
template <typename T>
|
||||
static void WriteSQ(void *ctx, uint32_t addr, T value);
|
||||
void WriteSQ(uint32_t addr, T value);
|
||||
|
||||
private:
|
||||
static uint32_t CompilePC();
|
||||
|
@ -164,9 +164,9 @@ class SH4 {
|
|||
void ScheduleTimer(int n);
|
||||
void ExpireTimer(int n);
|
||||
|
||||
hw::Dreamcast *dc_;
|
||||
hw::Memory *memory_;
|
||||
hw::Scheduler *scheduler_;
|
||||
Dreamcast *dc_;
|
||||
Memory *memory_;
|
||||
Scheduler *scheduler_;
|
||||
SH4CodeCache *code_cache_;
|
||||
|
||||
jit::frontend::sh4::SH4Context ctx_;
|
||||
|
|
|
@ -1610,7 +1610,7 @@ EMITTER(FMOV_INDEX_LOAD) {
|
|||
EMITTER(FMOV_STORE) {
|
||||
Value *addr = b.LoadRegister(i.Rn, VALUE_I32);
|
||||
|
||||
if (fpu.double_sz) {
|
||||
if (fpu.double_sz) {
|
||||
if (i.Rm & 1) {
|
||||
b.StoreGuest(addr, b.LoadRegisterXF(i.Rm & 0xe, VALUE_I32));
|
||||
b.StoreGuest(b.Add(addr, b.AllocConstant(4)),
|
||||
|
|
Loading…
Reference in New Issue