mirror of
https://github.com/PoroCYon/teakra.git
synced 2025-06-18 14:25:33 -04:00
Merge pull request #48 from PoroCYon/expose-ahbm
Expose AHBM things and add 16- and 32-bit memory accesses
This commit is contained in:
commit
d4bea3ec3a
@ -10,6 +10,12 @@ namespace Teakra {
|
||||
struct AHBMCallback {
|
||||
std::function<std::uint8_t(std::uint32_t address)> read8;
|
||||
std::function<void(std::uint32_t address, std::uint8_t value)> write8;
|
||||
|
||||
std::function<std::uint16_t(std::uint32_t address)> read16;
|
||||
std::function<void(std::uint32_t address, std::uint16_t value)> write16;
|
||||
|
||||
std::function<std::uint32_t(std::uint32_t address)> read32;
|
||||
std::function<void(std::uint32_t address, std::uint32_t value)> write32;
|
||||
};
|
||||
|
||||
class Teakra {
|
||||
@ -52,6 +58,15 @@ public:
|
||||
std::uint16_t DMAChan0GetSrcHigh();
|
||||
std::uint16_t DMAChan0GetDstHigh();
|
||||
|
||||
std::uint16_t AHBMGetUnitSize(std::uint16_t i) const;
|
||||
std::uint16_t AHBMGetDirection(std::uint16_t i) const;
|
||||
std::uint16_t AHBMGetDmaChannel(std::uint16_t i) const;
|
||||
// we need these as AHBM does some weird stuff on unaligned accesses internally
|
||||
std::uint16_t AHBMRead16(std::uint32_t addr);
|
||||
void AHBMWrite16(std::uint32_t addr, std::uint16_t value);
|
||||
std::uint16_t AHBMRead32(std::uint32_t addr);
|
||||
void AHBMWrite32(std::uint32_t addr, std::uint32_t value);
|
||||
|
||||
// core
|
||||
void Run(unsigned cycle);
|
||||
|
||||
|
@ -12,8 +12,15 @@ typedef struct TeakraObject TeakraContext;
|
||||
|
||||
typedef void (*Teakra_InterruptCallback)(void* userdata);
|
||||
typedef void (*Teakra_AudioCallback)(void* userdata, int16_t samples[2]);
|
||||
typedef uint8_t (*Teakra_AHBMReadCallback)(void* userdata, uint32_t address);
|
||||
typedef void (*Teakra_AHBMWriteCallback)(void* userdata, uint32_t address, uint8_t value);
|
||||
|
||||
typedef uint8_t (*Teakra_AHBMReadCallback8)(void* userdata, uint32_t address);
|
||||
typedef void (*Teakra_AHBMWriteCallback8)(void* userdata, uint32_t address, uint8_t value);
|
||||
|
||||
typedef uint16_t (*Teakra_AHBMReadCallback16)(void* userdata, uint32_t address);
|
||||
typedef void (*Teakra_AHBMWriteCallback16)(void* userdata, uint32_t address, uint16_t value);
|
||||
|
||||
typedef uint32_t (*Teakra_AHBMReadCallback32)(void* userdata, uint32_t address);
|
||||
typedef void (*Teakra_AHBMWriteCallback32)(void* userdata, uint32_t address, uint32_t value);
|
||||
|
||||
TeakraContext* Teakra_Create();
|
||||
void Teakra_Destroy(TeakraContext* context);
|
||||
@ -47,10 +54,24 @@ void Teakra_MMIOWrite(TeakraContext* context, uint16_t address, uint16_t value);
|
||||
uint16_t Teakra_DMAChan0GetSrcHigh(TeakraContext* context);
|
||||
uint16_t Teakra_DMAChan0GetDstHigh(TeakraContext* context);
|
||||
|
||||
uint16_t Teakra_AHBMGetUnitSize(TeakraContext* context, uint16_t i);
|
||||
uint16_t Teakra_AHBMGetDirection(TeakraContext* context, uint16_t i);
|
||||
uint16_t Teakra_AHBMGetDmaChannel(TeakraContext* context, uint16_t i);
|
||||
|
||||
uint16_t Teakra_AHBMRead16(TeakraContext* context, uint32_t addr);
|
||||
void Teakra_AHBMWrite16(TeakraContext* context, uint32_t addr, uint16_t value);
|
||||
uint16_t Teakra_AHBMRead32(TeakraContext* context, uint32_t addr);
|
||||
void Teakra_AHBMWrite32(TeakraContext* context, uint32_t addr, uint32_t value);
|
||||
|
||||
|
||||
void Teakra_Run(TeakraContext* context, unsigned cycle);
|
||||
|
||||
void Teakra_SetAHBMCallback(TeakraContext* context, Teakra_AHBMReadCallback read,
|
||||
Teakra_AHBMWriteCallback write, void* userdata);
|
||||
void Teakra_SetAHBMCallback(TeakraContext* context,
|
||||
Teakra_AHBMReadCallback8 read8 , Teakra_AHBMWriteCallback8 write8 ,
|
||||
Teakra_AHBMReadCallback16 read16, Teakra_AHBMWriteCallback16 write16,
|
||||
Teakra_AHBMReadCallback32 read32, Teakra_AHBMWriteCallback32 write32,
|
||||
void* userdata);
|
||||
|
||||
|
||||
void Teakra_SetAudioCallback(TeakraContext* context, Teakra_AudioCallback callback, void* userdata);
|
||||
#ifdef __cplusplus
|
||||
|
41
src/ahbm.cpp
41
src/ahbm.cpp
@ -42,7 +42,7 @@ u32 Ahbm::Read32(u16 channel, u32 address) {
|
||||
u32 value = 0;
|
||||
switch (channels[channel].unit_size) {
|
||||
case UnitSize::U8:
|
||||
value = read_external(current);
|
||||
value = read_external8(current);
|
||||
if ((current & 1) == 1) {
|
||||
value <<= 8; // this weird bahiviour is hwtested
|
||||
}
|
||||
@ -50,17 +50,13 @@ u32 Ahbm::Read32(u16 channel, u32 address) {
|
||||
break;
|
||||
case UnitSize::U16: {
|
||||
u32 current_masked = current & 0xFFFFFFFE;
|
||||
value =
|
||||
read_external(current_masked) | ((u32)read_external(current_masked + 1) << 8);
|
||||
value = read_external16(current_masked);
|
||||
current += 2;
|
||||
break;
|
||||
}
|
||||
case UnitSize::U32: {
|
||||
u32 current_masked = current & 0xFFFFFFFC;
|
||||
value = read_external(current_masked) |
|
||||
((u32)read_external(current_masked + 1) << 8) |
|
||||
((u32)read_external(current_masked + 2) << 16) |
|
||||
((u32)read_external(current_masked + 3) << 24);
|
||||
value = read_external32(current_masked);
|
||||
current += 4;
|
||||
break;
|
||||
}
|
||||
@ -82,7 +78,7 @@ void Ahbm::Write16(u16 channel, u32 address, u16 value) {
|
||||
}
|
||||
void Ahbm::Write32(u16 channel, u32 address, u32 value) {
|
||||
if ((address & 1) == 1) {
|
||||
value >>= 16; // this weird bahiviour is hwtested
|
||||
value >>= 16; // this weird behaviour is hwtested
|
||||
}
|
||||
WriteInternal(channel, address, value);
|
||||
}
|
||||
@ -104,9 +100,9 @@ void Ahbm::WriteInternal(u16 channel, u32 address, u32 value) {
|
||||
channels[channel].burst_queue.pop();
|
||||
switch (channels[channel].unit_size) {
|
||||
case UnitSize::U8: {
|
||||
// this weird bahiviour is hwtested
|
||||
// this weird behaviour is hwtested
|
||||
u8 value8 = ((current & 1) == 1) ? (u8)(value32 >> 8) : (u8)value32;
|
||||
write_external(current, value8);
|
||||
write_external8(current, value8);
|
||||
current += 1;
|
||||
break;
|
||||
}
|
||||
@ -114,9 +110,10 @@ void Ahbm::WriteInternal(u16 channel, u32 address, u32 value) {
|
||||
u32 c0 = current & 0xFFFFFFFE;
|
||||
u32 c1 = c0 + 1;
|
||||
if (c0 >= current) {
|
||||
write_external(c0, (u8)value32);
|
||||
write_external16(c0, (u16)value32);
|
||||
} else {
|
||||
write_external8(c1, (u8)(value32 >> 8));
|
||||
}
|
||||
write_external(c1, (u8)(value32 >> 8));
|
||||
current += 2;
|
||||
break;
|
||||
}
|
||||
@ -125,16 +122,18 @@ void Ahbm::WriteInternal(u16 channel, u32 address, u32 value) {
|
||||
u32 c1 = c0 + 1;
|
||||
u32 c2 = c0 + 2;
|
||||
u32 c3 = c0 + 3;
|
||||
if (c0 >= current) {
|
||||
write_external(c0, (u8)value32);
|
||||
|
||||
if (c0 >= current && c1 >= current && c2 >= current) {
|
||||
write_external32(c0, value32);
|
||||
} else if (c2 >= current) {
|
||||
if (c1 >= current) {
|
||||
write_external8(c1, (u8)(value32 >> 8));
|
||||
}
|
||||
write_external16(c2, (u16)(value32 >> 16));
|
||||
} else {
|
||||
write_external8(c3, (u8)(value32 >> 24));
|
||||
}
|
||||
if (c1 >= current) {
|
||||
write_external(c1, (u8)(value32 >> 8));
|
||||
}
|
||||
if (c2 >= current) {
|
||||
write_external(c2, (u8)(value32 >> 16));
|
||||
}
|
||||
write_external(c3, (u8)(value32 >> 24));
|
||||
|
||||
current += 4;
|
||||
break;
|
||||
}
|
||||
|
23
src/ahbm.h
23
src/ahbm.h
@ -63,10 +63,17 @@ public:
|
||||
|
||||
u16 GetChannelForDma(u16 dma_channel) const;
|
||||
|
||||
void SetExternalMemoryCallback(std::function<u8(u32)> read,
|
||||
std::function<void(u32, u8)> write) {
|
||||
read_external = std::move(read);
|
||||
write_external = std::move(write);
|
||||
void SetExternalMemoryCallback(
|
||||
std::function<u8 (u32)> read8 , std::function<void(u32, u8 )> write8 ,
|
||||
std::function<u16(u32)> read16, std::function<void(u32, u16)> write16,
|
||||
std::function<u32(u32)> read32, std::function<void(u32, u32)> write32) {
|
||||
|
||||
read_external8 = std::move(read8);
|
||||
write_external8 = std::move(write8);
|
||||
read_external16 = std::move(read16);
|
||||
write_external16 = std::move(write16);
|
||||
read_external32 = std::move(read32);
|
||||
write_external32 = std::move(write32);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -83,8 +90,12 @@ private:
|
||||
};
|
||||
std::array<Channel, 3> channels;
|
||||
|
||||
std::function<u8(u32)> read_external;
|
||||
std::function<void(u32, u8)> write_external;
|
||||
std::function<u8(u32)> read_external8;
|
||||
std::function<void(u32, u8)> write_external8;
|
||||
std::function<u16(u32)> read_external16;
|
||||
std::function<void(u32, u16)> write_external16;
|
||||
std::function<u32(u32)> read_external32;
|
||||
std::function<void(u32, u32)> write_external32;
|
||||
|
||||
void WriteInternal(u16 channel, u32 address, u32 value);
|
||||
};
|
||||
|
@ -118,7 +118,32 @@ void Teakra::MaskSemaphore(std::uint16_t value) {
|
||||
impl->apbp_from_dsp.MaskSemaphore(value);
|
||||
}
|
||||
void Teakra::SetAHBMCallback(const AHBMCallback& callback) {
|
||||
impl->ahbm.SetExternalMemoryCallback(callback.read8, callback.write8);
|
||||
impl->ahbm.SetExternalMemoryCallback(callback.read8, callback.write8,
|
||||
callback.read16, callback.write16,
|
||||
callback.read32, callback.write32);
|
||||
}
|
||||
|
||||
std::uint16_t Teakra::AHBMGetUnitSize(std::uint16_t i) const {
|
||||
return impl->ahbm.GetUnitSize(i);
|
||||
}
|
||||
std::uint16_t Teakra::AHBMGetDirection(std::uint16_t i) const {
|
||||
return impl->ahbm.GetDirection(i);
|
||||
}
|
||||
std::uint16_t Teakra::AHBMGetDmaChannel(std::uint16_t i) const {
|
||||
return impl->ahbm.GetDmaChannel(i);
|
||||
}
|
||||
|
||||
std::uint16_t Teakra::AHBMRead16(std::uint32_t addr) {
|
||||
return impl->ahbm.Read16(0, addr);
|
||||
}
|
||||
void Teakra::AHBMWrite16(std::uint32_t addr, std::uint16_t value) {
|
||||
impl->ahbm.Write16(0, addr, value);
|
||||
}
|
||||
std::uint16_t Teakra::AHBMRead32(std::uint32_t addr) {
|
||||
return impl->ahbm.Read32(0, addr);
|
||||
}
|
||||
void Teakra::AHBMWrite32(std::uint32_t addr, std::uint32_t value) {
|
||||
impl->ahbm.Write32(0, addr, value);
|
||||
}
|
||||
|
||||
void Teakra::SetAudioCallback(std::function<void(std::array<s16, 2>)> callback) {
|
||||
|
@ -98,18 +98,49 @@ uint16_t Teakra_DMAChan0GetDstHigh(TeakraContext* context){
|
||||
return context->teakra.DMAChan0GetDstHigh();
|
||||
}
|
||||
|
||||
uint16_t Teakra_AHBMGetUnitSize(TeakraContext* context, uint16_t i) {
|
||||
return context->teakra.AHBMGetUnitSize(i);
|
||||
}
|
||||
uint16_t Teakra_AHBMGetDirection(TeakraContext* context, uint16_t i) {
|
||||
return context->teakra.AHBMGetDirection(i);
|
||||
}
|
||||
uint16_t Teakra_AHBMGetDmaChannel(TeakraContext* context, uint16_t i) {
|
||||
return context->teakra.AHBMGetDmaChannel(i);
|
||||
}
|
||||
|
||||
uint16_t Teakra_AHBMRead16(TeakraContext* context, uint32_t addr) {
|
||||
return context->teakra.AHBMRead16(addr);
|
||||
}
|
||||
void Teakra_AHBMWrite16(TeakraContext* context, uint32_t addr, uint16_t value) {
|
||||
context->teakra.AHBMWrite16(addr, value);
|
||||
}
|
||||
uint16_t Teakra_AHBMRead32(TeakraContext* context, uint32_t addr) {
|
||||
return context->teakra.AHBMRead32(addr);
|
||||
}
|
||||
void Teakra_AHBMWrite32(TeakraContext* context, uint32_t addr, uint32_t value) {
|
||||
context->teakra.AHBMWrite32(addr, value);
|
||||
}
|
||||
|
||||
void Teakra_Run(TeakraContext* context, unsigned cycle) {
|
||||
context->teakra.Run(cycle);
|
||||
}
|
||||
|
||||
void Teakra_SetAHBMCallback(TeakraContext* context, Teakra_AHBMReadCallback read,
|
||||
Teakra_AHBMWriteCallback write, void* userdata) {
|
||||
void Teakra_SetAHBMCallback(TeakraContext* context,
|
||||
Teakra_AHBMReadCallback8 read8 , Teakra_AHBMWriteCallback8 write8 ,
|
||||
Teakra_AHBMReadCallback16 read16, Teakra_AHBMWriteCallback16 write16,
|
||||
Teakra_AHBMReadCallback32 read32, Teakra_AHBMWriteCallback32 write32,
|
||||
void* userdata) {
|
||||
Teakra::AHBMCallback callback;
|
||||
callback.read8 = [=](uint32_t address) { return read(userdata, address); };
|
||||
callback.write8 = [=](uint32_t address, uint8_t value) { write(userdata, address, value); };
|
||||
callback.read8 = [=](uint32_t address) { return read8(userdata, address); };
|
||||
callback.write8 = [=](uint32_t address, uint8_t value) { write8(userdata, address, value); };
|
||||
callback.read16 = [=](uint32_t address) { return read16(userdata, address); };
|
||||
callback.write16 = [=](uint32_t address, uint16_t value) { write16(userdata, address, value); };
|
||||
callback.read32 = [=](uint32_t address) { return read32(userdata, address); };
|
||||
callback.write32 = [=](uint32_t address, uint32_t value) { write32(userdata, address, value); };
|
||||
context->teakra.SetAHBMCallback(callback);
|
||||
}
|
||||
|
||||
|
||||
void Teakra_SetAudioCallback(TeakraContext* context, Teakra_AudioCallback callback,
|
||||
void* userdata) {
|
||||
context->teakra.SetAudioCallback(
|
||||
|
@ -21,6 +21,27 @@ TEST_CASE("DMA + AHBM test", "[dma]") {
|
||||
[&fcram](u32 address, u8 v) {
|
||||
REQUIRE(address >= 0x20000000);
|
||||
fcram[address - 0x20000000] = v;
|
||||
},
|
||||
[&fcram](u32 address) -> u16 {
|
||||
REQUIRE(address >= 0x20000000);
|
||||
return fcram[address - 0x20000000] | ((u16)fcram[address - 0x20000000 + 1] << 8);
|
||||
},
|
||||
[&fcram](u32 address, u16 v) {
|
||||
REQUIRE(address >= 0x20000000);
|
||||
fcram[address - 0x20000000 + 0] = (u8)v;
|
||||
fcram[address - 0x20000000 + 1] = v >> 8;
|
||||
},
|
||||
[&fcram](u32 address) -> u32 {
|
||||
REQUIRE(address >= 0x20000000);
|
||||
return fcram[address - 0x20000000] | ((u32)fcram[address - 0x20000000 + 1] << 8)
|
||||
| ((u32)fcram[address - 0x20000000 + 2] << 16) | ((u32)fcram[address - 0x20000000 + 3] << 24);
|
||||
},
|
||||
[&fcram](u32 address, u32 v) {
|
||||
REQUIRE(address >= 0x20000000);
|
||||
fcram[address - 0x20000000 + 0] = (u8)v;
|
||||
fcram[address - 0x20000000 + 1] = (u8)(v >> 8);
|
||||
fcram[address - 0x20000000 + 2] = (u8)(v >> 16);
|
||||
fcram[address - 0x20000000 + 3] = (u8)(v >> 24);
|
||||
});
|
||||
|
||||
for (u8 i = 0; i < 0x80; ++i) {
|
||||
|
Loading…
Reference in New Issue
Block a user