Update to ares v114r16 release.
- Super Famicom: mosaic fix wasn't exactly right before; now it should be - PlayStation: started implementing CD interface - PlayStation: started implementing GTE coprocessor
このコミットが含まれているのは:
コミット
bfdb287505
@ -2,7 +2,7 @@
|
||||
|
||||
namespace ares {
|
||||
static const string Name = "ares";
|
||||
static const string Version = "114.15";
|
||||
static const string Version = "114.16";
|
||||
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/";
|
||||
|
@ -85,8 +85,8 @@ auto PCD::connect() -> void {
|
||||
vector<uint8_t> subchannel;
|
||||
subchannel.resize(sectors * 96);
|
||||
for(uint sector : range(sectors)) {
|
||||
pcd.fd->seek(sector * 2448 + 2352);
|
||||
pcd.fd->read(subchannel.data() + sector * 96, 96);
|
||||
fd->seek(sector * 2448 + 2352);
|
||||
fd->read(subchannel.data() + sector * 96, 96);
|
||||
}
|
||||
session.decode(subchannel, 96);
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
ares.objects += ares-ps1-interface ares-ps1-memory ares-ps1-system
|
||||
ares.objects += ares-ps1-cpu ares-ps1-gpu ares-ps1-spu
|
||||
ares.objects += ares-ps1-disc ares-ps1-cpu ares-ps1-gpu ares-ps1-spu
|
||||
|
||||
$(object.path)/ares-ps1-interface.o: $(ares.path)/ps1/interface/interface.cpp
|
||||
$(object.path)/ares-ps1-memory.o: $(ares.path)/ps1/memory/memory.cpp
|
||||
$(object.path)/ares-ps1-system.o: $(ares.path)/ps1/system/system.cpp
|
||||
$(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
|
||||
|
@ -86,7 +86,7 @@ auto CPU::instructionDebug() -> void {
|
||||
|
||||
static vector<bool> mask;
|
||||
if(!mask) mask.resize(0x0800'0000);
|
||||
//if(mask[(PC & 0x1fff'ffff) >> 2]) return;
|
||||
if(mask[(PC & 0x1fff'ffff) >> 2]) return;
|
||||
mask[(PC & 0x1fff'ffff) >> 2] = 1;
|
||||
|
||||
static uint counter = 0;
|
||||
|
@ -196,7 +196,21 @@
|
||||
{
|
||||
switch(OP >> 21 & 0x1f) {
|
||||
op(0x00, MFC0, RT, RDn);
|
||||
op(0x01, INVALID);
|
||||
op(0x02, INVALID);
|
||||
op(0x03, INVALID);
|
||||
op(0x04, MTC0, RT, RDn);
|
||||
op(0x05, INVALID);
|
||||
op(0x06, INVALID);
|
||||
op(0x07, INVALID);
|
||||
op(0x08, INVALID);
|
||||
op(0x09, INVALID);
|
||||
op(0x0a, INVALID);
|
||||
op(0x0b, INVALID);
|
||||
op(0x0c, INVALID);
|
||||
op(0x0d, INVALID);
|
||||
op(0x0e, INVALID);
|
||||
op(0x0f, INVALID);
|
||||
}
|
||||
|
||||
switch(OP & 0x3f) {
|
||||
@ -208,6 +222,51 @@
|
||||
|
||||
#ifdef DECODER_GTE
|
||||
{
|
||||
switch(OP >> 21 & 0x1f) {
|
||||
op(0x00, MFC2, RT, RDn);
|
||||
op(0x01, INVALID);
|
||||
op(0x02, CFC2, RT, RDn);
|
||||
op(0x03, INVALID);
|
||||
op(0x04, MTC2, RT, RDn);
|
||||
op(0x05, INVALID);
|
||||
op(0x06, CTC2, RT, RDn);
|
||||
op(0x07, INVALID);
|
||||
op(0x08, INVALID);
|
||||
op(0x09, INVALID);
|
||||
op(0x0a, INVALID);
|
||||
op(0x0b, INVALID);
|
||||
op(0x0c, INVALID);
|
||||
op(0x0d, INVALID);
|
||||
op(0x0e, INVALID);
|
||||
op(0x0f, INVALID);
|
||||
}
|
||||
|
||||
switch(OP & 0x3f) {
|
||||
op(0x00, RTPS);
|
||||
op(0x01, RTPS); //0x00 mirror?
|
||||
op(0x06, NCLIP);
|
||||
op(0x0c, OP);
|
||||
op(0x10, DPCS);
|
||||
op(0x11, INTPL);
|
||||
op(0x12, MVMVA);
|
||||
op(0x13, NCDS);
|
||||
op(0x14, CDP);
|
||||
op(0x16, NCDT);
|
||||
op(0x1a, DCPL); //0x29 mirror?
|
||||
op(0x1b, NCCS);
|
||||
op(0x1c, CC);
|
||||
op(0x1e, NCS);
|
||||
op(0x20, NCT);
|
||||
op(0x28, SQR);
|
||||
op(0x29, DCPL);
|
||||
op(0x2a, DPCT);
|
||||
op(0x2d, AVSZ3);
|
||||
op(0x2e, AVSZ4);
|
||||
op(0x30, RTPT);
|
||||
op(0x3d, GPF);
|
||||
op(0x3e, GPL);
|
||||
op(0x3f, NCCT);
|
||||
}
|
||||
}
|
||||
#undef DECODER_GTE
|
||||
#endif
|
||||
|
@ -260,6 +260,23 @@ auto CPU::Disassembler::SCC() -> vector<string> {
|
||||
}
|
||||
|
||||
auto CPU::Disassembler::GTE() -> vector<string> {
|
||||
auto rtName = [&] { return cpuRegisterName (instruction >> 16 & 31); };
|
||||
auto rtValue = [&] { return cpuRegisterValue(instruction >> 16 & 31); };
|
||||
auto drName = [&] { return gteDataRegisterName (instruction >> 11 & 31); };
|
||||
auto drValue = [&] { return gteDataRegisterValue(instruction >> 11 & 31); };
|
||||
auto crName = [&] { return gteControlRegisterName (instruction >> 11 & 31); };
|
||||
auto crValue = [&] { return gteControlRegisterValue(instruction >> 11 & 31); };
|
||||
|
||||
switch(instruction >> 21 & 0x1f) {
|
||||
case 0x00: return {"mfc2", rtName(), drValue()};
|
||||
case 0x02: return {"cfc2", rtName(), crValue()};
|
||||
case 0x04: return {"mtc2", rtValue(), drName()};
|
||||
case 0x06: return {"ctc2", rtValue(), crName()};
|
||||
}
|
||||
if(!(instruction >> 25 & 1)) return {};
|
||||
switch(instruction & 0x3f) {
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -306,6 +323,36 @@ auto CPU::Disassembler::sccRegisterValue(u8 index) const -> string {
|
||||
return sccRegisterName(index);
|
||||
}
|
||||
|
||||
auto CPU::Disassembler::gteDataRegisterName(u8 index) const -> string {
|
||||
static const string registers[32] = {
|
||||
"vxy0", "vz0", "vxy1", "vz2", "vxy2", "vz2", "rgbc", "otz",
|
||||
"ir0", "ir1", "ir2", "ir3", "sxy0", "sxy1", "sxy2", "sxyp",
|
||||
"sz0", "sz1", "sz2", "sz3", "rgb0", "rgb1", "rgb2", "res1",
|
||||
"mac0", "mac1", "mac2", "mac3", "irgb", "orgb", "lzcs", "lzcr",
|
||||
};
|
||||
return registers[index];
|
||||
}
|
||||
|
||||
auto CPU::Disassembler::gteDataRegisterValue(u8 index) const -> string {
|
||||
if(showValues) return {gteDataRegisterName(index)}; //todo
|
||||
return gteDataRegisterName(index);
|
||||
}
|
||||
|
||||
auto CPU::Disassembler::gteControlRegisterName(u8 index) const -> string {
|
||||
static const string registers[32] = {
|
||||
"rt11+rt12", "rt13+rt21", "rt22+rt23", "rt31+rt32", "rt33", "trx", "try", "trz",
|
||||
"l11+l12", "l13+l21", "l22+l23", "l31+l32", "l33", "rbk", "gbk", "bbk",
|
||||
"lr1+lr2", "lr3+lg1", "lg2+lg3", "lb1+lb2", "lb3", "rfc", "gfc", "bfc",
|
||||
"ofx", "ofy", "h", "dqa", "dqb", "zsf3", "zsf4", "flag",
|
||||
};
|
||||
return registers[index];
|
||||
}
|
||||
|
||||
auto CPU::Disassembler::gteControlRegisterValue(u8 index) const -> string {
|
||||
if(showValues) return {gteControlRegisterName(index)}; //todo
|
||||
return gteControlRegisterName(index);
|
||||
}
|
||||
|
||||
template<typename... P>
|
||||
auto CPU::Disassembler::hint(P&&... p) const -> string {
|
||||
if(showColors) return {"\e[0m\e[37m", forward<P>(p)..., "\e[0m"};
|
||||
|
@ -22,6 +22,10 @@
|
||||
auto cpuRegisterIndex(u8 index, i16 offset) const -> string;
|
||||
auto sccRegisterName(u8 index) const -> string;
|
||||
auto sccRegisterValue(u8 index) const -> string;
|
||||
auto gteDataRegisterName(u8 index) const -> string;
|
||||
auto gteDataRegisterValue(u8 index) const -> string;
|
||||
auto gteControlRegisterName(u8 index) const -> string;
|
||||
auto gteControlRegisterValue(u8 index) const -> string;
|
||||
|
||||
u32 address;
|
||||
u32 instruction;
|
||||
|
@ -0,0 +1,292 @@
|
||||
#include "gte-registers.hpp"
|
||||
|
||||
auto CPU::instructionCFC2(u32& rt, u8 rd) -> void {
|
||||
switch(rd) {
|
||||
case 0: rt = RT11 << 0 | RT12 << 16; break;
|
||||
case 1: rt = RT13 << 0 | RT21 << 16; break;
|
||||
case 2: rt = RT22 << 0 | RT23 << 16; break;
|
||||
case 3: rt = RT31 << 0 | RT32 << 16; break;
|
||||
case 4: rt = RT33 << 0; break;
|
||||
case 5: rt = TRX; break;
|
||||
case 6: rt = TRY; break;
|
||||
case 7: rt = TRZ; break;
|
||||
case 8: rt = L11 << 0 | L12 << 16; break;
|
||||
case 9: rt = L13 << 0 | L21 << 16; break;
|
||||
case 10: rt = L22 << 0 | L23 << 16; break;
|
||||
case 11: rt = L31 << 0 | L32 << 16; break;
|
||||
case 12: rt = L33 << 0; break;
|
||||
case 13: rt = RBK; break;
|
||||
case 14: rt = GBK; break;
|
||||
case 15: rt = BBK; break;
|
||||
case 16: rt = LR1 << 0 | LR2 << 16; break;
|
||||
case 17: rt = LR3 << 0 | LG1 << 16; break;
|
||||
case 18: rt = LG2 << 0 | LG3 << 16; break;
|
||||
case 19: rt = LB1 << 0 | LB2 << 16; break;
|
||||
case 20: rt = LB3 << 0; break;
|
||||
case 21: rt = RFC; break;
|
||||
case 22: rt = GFC; break;
|
||||
case 23: rt = BFC; break;
|
||||
case 24: rt = OFX; break;
|
||||
case 25: rt = OFY; break;
|
||||
case 26: rt = H; break;
|
||||
case 27: rt = DQA; break;
|
||||
case 28: rt = DQB; break;
|
||||
case 29: rt = ZSF3; break;
|
||||
case 30: rt = ZSF4; break;
|
||||
case 31: rt = 0;
|
||||
rt |= FLAG.saturated.ir0 << 12;
|
||||
rt |= FLAG.saturated.sy2 << 13;
|
||||
rt |= FLAG.saturated.sx2 << 14;
|
||||
rt |= FLAG.underflow.mac0 << 15;
|
||||
rt |= FLAG.overflow.mac0 << 16;
|
||||
rt |= FLAG.overflow.division << 17;
|
||||
rt |= FLAG.saturated.sz1_otz << 18;
|
||||
rt |= FLAG.saturated.b << 19;
|
||||
rt |= FLAG.saturated.g << 20;
|
||||
rt |= FLAG.saturated.r << 21;
|
||||
rt |= FLAG.saturated.ir3 << 22;
|
||||
rt |= FLAG.saturated.ir2 << 23;
|
||||
rt |= FLAG.saturated.ir1 << 24;
|
||||
rt |= FLAG.underflow.mac3 << 25;
|
||||
rt |= FLAG.underflow.mac2 << 26;
|
||||
rt |= FLAG.underflow.mac1 << 27;
|
||||
rt |= FLAG.overflow.mac3 << 28;
|
||||
rt |= FLAG.overflow.mac2 << 29;
|
||||
rt |= FLAG.overflow.mac1 << 30;
|
||||
rt |= FLAG.error << 31;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::instructionCTC2(cu32& rt, u8 rd) -> void {
|
||||
switch(rd) {
|
||||
case 0: RT11 = rt >> 0; RT12 = rt >> 16; break;
|
||||
case 1: RT13 = rt >> 0; RT21 = rt >> 16; break;
|
||||
case 2: RT22 = rt >> 0; RT23 = rt >> 16; break;
|
||||
case 3: RT31 = rt >> 0; RT32 = rt >> 16; break;
|
||||
case 4: RT33 = rt >> 0; break;
|
||||
case 5: TRX = rt; break;
|
||||
case 6: TRY = rt; break;
|
||||
case 7: TRZ = rt; break;
|
||||
case 8: L11 = rt >> 0; L12 = rt >> 16; break;
|
||||
case 9: L13 = rt >> 0; L21 = rt >> 16; break;
|
||||
case 10: L22 = rt >> 0; L23 = rt >> 16; break;
|
||||
case 11: L31 = rt >> 0; L32 = rt >> 16; break;
|
||||
case 12: L33 = rt >> 0; break;
|
||||
case 13: RBK = rt; break;
|
||||
case 14: GBK = rt; break;
|
||||
case 15: BBK = rt; break;
|
||||
case 16: LR1 = rt >> 0; LR2 = rt >> 16; break;
|
||||
case 17: LR3 = rt >> 0; LG1 = rt >> 16; break;
|
||||
case 18: LG2 = rt >> 0; LG3 = rt >> 16; break;
|
||||
case 19: LB1 = rt >> 0; LB2 = rt >> 16; break;
|
||||
case 20: LB3 = rt >> 0; break;
|
||||
case 21: RFC = rt; break;
|
||||
case 22: GFC = rt; break;
|
||||
case 23: BFC = rt; break;
|
||||
case 24: OFX = rt; break;
|
||||
case 25: OFY = rt; break;
|
||||
case 26: H = rt; break;
|
||||
case 27: DQA = rt; break;
|
||||
case 28: DQB = rt; break;
|
||||
case 29: ZSF3 = rt; break;
|
||||
case 30: ZSF4 = rt; break;
|
||||
case 31:
|
||||
FLAG.saturated.ir0 = rt >> 12 & 1;
|
||||
FLAG.saturated.sy2 = rt >> 13 & 1;
|
||||
FLAG.saturated.sx2 = rt >> 14 & 1;
|
||||
FLAG.underflow.mac0 = rt >> 15 & 1;
|
||||
FLAG.overflow.mac0 = rt >> 16 & 1;
|
||||
FLAG.overflow.division = rt >> 17 & 1;
|
||||
FLAG.saturated.sz1_otz = rt >> 18 & 1;
|
||||
FLAG.saturated.b = rt >> 19 & 1;
|
||||
FLAG.saturated.g = rt >> 20 & 1;
|
||||
FLAG.saturated.r = rt >> 21 & 1;
|
||||
FLAG.saturated.ir3 = rt >> 22 & 1;
|
||||
FLAG.saturated.ir2 = rt >> 23 & 1;
|
||||
FLAG.saturated.ir1 = rt >> 24 & 1;
|
||||
FLAG.underflow.mac3 = rt >> 25 & 1;
|
||||
FLAG.underflow.mac2 = rt >> 26 & 1;
|
||||
FLAG.underflow.mac1 = rt >> 27 & 1;
|
||||
FLAG.overflow.mac3 = rt >> 28 & 1;
|
||||
FLAG.overflow.mac2 = rt >> 29 & 1;
|
||||
FLAG.overflow.mac1 = rt >> 30 & 1;
|
||||
FLAG.error = rt >> 31 & 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::instructionMFC2(u32& rt, u8 rd) -> void {
|
||||
switch(rd) {
|
||||
case 0: rt = VX0 << 0 | VY0 << 16; break;
|
||||
case 1: rt = VZ0 << 0; break;
|
||||
case 2: rt = VX1 << 0 | VY1 << 16; break;
|
||||
case 3: rt = VZ1 << 0; break;
|
||||
case 4: rt = VX2 << 0 | VY2 << 16; break;
|
||||
case 5: rt = VZ2 << 0; break;
|
||||
case 6: rt = RGBC; break;
|
||||
case 7: rt = OTZ; break;
|
||||
case 8: rt = IR0; break;
|
||||
case 9: rt = IR1; break;
|
||||
case 10: rt = IR2; break;
|
||||
case 11: rt = IR3; break;
|
||||
case 12: rt = SX0 << 0 | SY0 << 16; break;
|
||||
case 13: rt = SX1 << 0 | SY1 << 16; break;
|
||||
case 14: rt = SX2 << 0 | SY2 << 16; break;
|
||||
case 15: rt = SX2 << 0 | SY2 << 16; break;
|
||||
case 16: rt = SZ0; break;
|
||||
case 17: rt = SZ1; break;
|
||||
case 18: rt = SZ2; break;
|
||||
case 19: rt = SZ3; break;
|
||||
case 20: rt = RGB0; break;
|
||||
case 21: rt = RGB1; break;
|
||||
case 22: rt = RGB2; break;
|
||||
case 23: rt = RES1; break;
|
||||
case 24: rt = MAC0; break;
|
||||
case 25: rt = MAC1; break;
|
||||
case 26: rt = MAC2; break;
|
||||
case 27: rt = MAC3; break;
|
||||
case 28: //IRGB
|
||||
case 29: {//ORGB
|
||||
i8 r = (IR1 >> 7 < 0) ? 0 : (IR1 >> 7 > 0x1f) ? 0x1f : (IR1 >> 7);
|
||||
i8 g = (IR2 >> 7 < 0) ? 0 : (IR2 >> 7 > 0x1f) ? 0x1f : (IR2 >> 7);
|
||||
i8 b = (IR3 >> 7 < 0) ? 0 : (IR3 >> 7 > 0x1f) ? 0x1f : (IR3 >> 7);
|
||||
rt = r << 0 | g << 5 | b << 10;
|
||||
} break;
|
||||
case 30: rt = LZCS; break;
|
||||
case 31: rt = LZCR; break;
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::instructionMTC2(cu32& rt, u8 rd) -> void {
|
||||
switch(rd) {
|
||||
case 0: VX0 = rt >> 0; VY0 = rt >> 16; break;
|
||||
case 1: VZ0 = rt >> 0; break;
|
||||
case 2: VX1 = rt >> 0; VY1 = rt >> 16; break;
|
||||
case 3: VZ1 = rt >> 0; break;
|
||||
case 4: VX2 = rt >> 0; VY2 = rt >> 16; break;
|
||||
case 5: VZ2 = rt >> 0; break;
|
||||
case 6: RGBC = rt; break;
|
||||
case 7: OTZ = rt; break;
|
||||
case 8: IR0 = rt; break;
|
||||
case 9: IR1 = rt; break;
|
||||
case 10: IR2 = rt; break;
|
||||
case 11: IR3 = rt; break;
|
||||
case 12: SX0 = rt >> 0; SY0 = rt >> 16; break;
|
||||
case 13: SX1 = rt >> 0; SY1 = rt >> 16; break;
|
||||
case 14: SX2 = rt >> 0; SY2 = rt >> 16; break;
|
||||
case 15: {//SXP
|
||||
SX0 = SX1; SY0 = SY1;
|
||||
SX1 = SX2; SY1 = SY2;
|
||||
SX2 = rt >> 0; SY2 = rt >> 16;
|
||||
} break;
|
||||
case 16: SZ0 = rt; break;
|
||||
case 17: SZ1 = rt; break;
|
||||
case 18: SZ2 = rt; break;
|
||||
case 19: SZ3 = rt; break;
|
||||
case 20: RGB0 = rt; break;
|
||||
case 21: RGB1 = rt; break;
|
||||
case 22: RGB2 = rt; break;
|
||||
case 23: RES1 = rt; break;
|
||||
case 24: MAC0 = rt; break;
|
||||
case 25: MAC1 = rt; break;
|
||||
case 26: MAC2 = rt; break;
|
||||
case 27: MAC3 = rt; break;
|
||||
case 28: IRGB = rt; break;
|
||||
case 29: ORGB = rt; break;
|
||||
case 30: LZCS = rt; break;
|
||||
case 31: LZCR = rt; break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto CPU::instructionAVSZ3() -> void {
|
||||
print("AVSZ3\n");
|
||||
}
|
||||
|
||||
auto CPU::instructionAVSZ4() -> void {
|
||||
print("AVSZ4\n");
|
||||
}
|
||||
|
||||
auto CPU::instructionCC() -> void {
|
||||
print("CC\n");
|
||||
}
|
||||
|
||||
auto CPU::instructionCDP() -> void {
|
||||
print("CDP\n");
|
||||
}
|
||||
|
||||
auto CPU::instructionDCPL() -> void {
|
||||
print("DCPL\n");
|
||||
}
|
||||
|
||||
auto CPU::instructionDPCS() -> void {
|
||||
print("DPCS\n");
|
||||
}
|
||||
|
||||
auto CPU::instructionDPCT() -> void {
|
||||
print("DPCT\n");
|
||||
}
|
||||
|
||||
auto CPU::instructionGPF() -> void {
|
||||
print("GPF\n");
|
||||
}
|
||||
|
||||
auto CPU::instructionGPL() -> void {
|
||||
print("GPL\n");
|
||||
}
|
||||
|
||||
auto CPU::instructionINTPL() -> void {
|
||||
print("INTPL\n");
|
||||
}
|
||||
|
||||
auto CPU::instructionMVMVA() -> void {
|
||||
print("MVMVA\n");
|
||||
}
|
||||
|
||||
auto CPU::instructionNCCS() -> void {
|
||||
print("NCCS\n");
|
||||
}
|
||||
|
||||
auto CPU::instructionNCCT() -> void {
|
||||
print("NCCT\n");
|
||||
}
|
||||
|
||||
auto CPU::instructionNCDS() -> void {
|
||||
print("NCDS\n");
|
||||
}
|
||||
|
||||
auto CPU::instructionNCDT() -> void {
|
||||
print("NCDT\n");
|
||||
}
|
||||
|
||||
auto CPU::instructionNCLIP() -> void {
|
||||
print("NCLIP\n");
|
||||
}
|
||||
|
||||
auto CPU::instructionNCS() -> void {
|
||||
print("NCS\n");
|
||||
}
|
||||
|
||||
auto CPU::instructionNCT() -> void {
|
||||
print("NCT\n");
|
||||
}
|
||||
|
||||
auto CPU::instructionOP() -> void {
|
||||
print("OP\n");
|
||||
}
|
||||
|
||||
auto CPU::instructionRTPS() -> void {
|
||||
print("RTPS\n");
|
||||
}
|
||||
|
||||
auto CPU::instructionRTPT() -> void {
|
||||
print("RTPT\n");
|
||||
}
|
||||
|
||||
auto CPU::instructionSQR() -> void {
|
||||
print("SQR\n");
|
||||
}
|
||||
|
||||
#include "gte-registers.hpp"
|
169
ares/ps1/cpu/core/gte-registers.hpp
ノーマルファイル
169
ares/ps1/cpu/core/gte-registers.hpp
ノーマルファイル
@ -0,0 +1,169 @@
|
||||
#if !defined(GTE_REGISTERS_HPP)
|
||||
#define GTE_REGISTERS_HPP
|
||||
|
||||
#define VX0 gte.vx0
|
||||
#define VY0 gte.vy0
|
||||
#define VZ0 gte.vz0
|
||||
#define VX1 gte.vx1
|
||||
#define VY1 gte.vy1
|
||||
#define VZ1 gte.vz1
|
||||
#define VX2 gte.vx2
|
||||
#define VY2 gte.vy2
|
||||
#define VZ2 gte.vz2
|
||||
#define RGBC gte.rgbc
|
||||
#define OTZ gte.otz
|
||||
#define IR0 gte.ir0
|
||||
#define IR1 gte.ir1
|
||||
#define IR2 gte.ir2
|
||||
#define IR3 gte.ir3
|
||||
#define SX0 gte.sx0
|
||||
#define SY0 gte.sy0
|
||||
#define SX1 gte.sx1
|
||||
#define SY1 gte.sy1
|
||||
#define SX2 gte.sx2
|
||||
#define SY2 gte.sy2
|
||||
#define SZ0 gte.sz0
|
||||
#define SZ1 gte.sz1
|
||||
#define SZ2 gte.sz2
|
||||
#define SZ3 gte.sz3
|
||||
#define RGB0 gte.rgb0
|
||||
#define RGB1 gte.rgb1
|
||||
#define RGB2 gte.rgb2
|
||||
#define RES1 gte.res1
|
||||
#define MAC0 gte.mac0
|
||||
#define MAC1 gte.mac1
|
||||
#define MAC2 gte.mac2
|
||||
#define MAC3 gte.mac3
|
||||
#define IRGB gte.irgb
|
||||
#define ORGB gte.orgb
|
||||
#define LZCS gte.lzcs
|
||||
#define LZCR gte.lzcr
|
||||
#define RT11 gte.rt11
|
||||
#define RT12 gte.rt12
|
||||
#define RT13 gte.rt13
|
||||
#define RT21 gte.rt21
|
||||
#define RT22 gte.rt22
|
||||
#define RT23 gte.rt23
|
||||
#define RT31 gte.rt31
|
||||
#define RT32 gte.rt32
|
||||
#define RT33 gte.rt33
|
||||
#define TRX gte.trx
|
||||
#define TRY gte.trY
|
||||
#define TRZ gte.trz
|
||||
#define L11 gte.l11
|
||||
#define L12 gte.l12
|
||||
#define L13 gte.l13
|
||||
#define L21 gte.l21
|
||||
#define L22 gte.l22
|
||||
#define L23 gte.l23
|
||||
#define L31 gte.l31
|
||||
#define L32 gte.l32
|
||||
#define L33 gte.l33
|
||||
#define RBK gte.rbk
|
||||
#define GBK gte.gbk
|
||||
#define BBK gte.bbk
|
||||
#define LR1 gte.lr1
|
||||
#define LR2 gte.lr2
|
||||
#define LR3 gte.lr3
|
||||
#define LG1 gte.lg1
|
||||
#define LG2 gte.lg2
|
||||
#define LG3 gte.lg3
|
||||
#define LB1 gte.lb1
|
||||
#define LB2 gte.lb2
|
||||
#define LB3 gte.lb3
|
||||
#define RFC gte.rfc
|
||||
#define GFC gte.gfc
|
||||
#define BFC gte.bfc
|
||||
#define OFX gte.ofx
|
||||
#define OFY gte.ofy
|
||||
#define H gte.h
|
||||
#define DQA gte.dqa
|
||||
#define DQB gte.dqb
|
||||
#define ZSF3 gte.zsf3
|
||||
#define ZSF4 gte.zsf4
|
||||
#define FLAG gte.flag
|
||||
#else
|
||||
#undef GTE_REGISTERS_HPP
|
||||
|
||||
#undef VX0
|
||||
#undef VY0
|
||||
#undef VZ0
|
||||
#undef VX1
|
||||
#undef VY1
|
||||
#undef VZ1
|
||||
#undef VX2
|
||||
#undef VY2
|
||||
#undef VZ2
|
||||
#undef RGBC
|
||||
#undef OTZ
|
||||
#undef IR0
|
||||
#undef IR1
|
||||
#undef IR2
|
||||
#undef IR3
|
||||
#undef SX0
|
||||
#undef SY0
|
||||
#undef SX1
|
||||
#undef SY1
|
||||
#undef SX2
|
||||
#undef SY2
|
||||
#undef SZ0
|
||||
#undef SZ1
|
||||
#undef SZ2
|
||||
#undef SZ3
|
||||
#undef RGB0
|
||||
#undef RGB1
|
||||
#undef RGB2
|
||||
#undef RES1
|
||||
#undef MAC0
|
||||
#undef MAC1
|
||||
#undef MAC2
|
||||
#undef MAC3
|
||||
#undef IRGB
|
||||
#undef ORGB
|
||||
#undef LZCS
|
||||
#undef LZCR
|
||||
#undef RT11
|
||||
#undef RT12
|
||||
#undef RT13
|
||||
#undef RT21
|
||||
#undef RT22
|
||||
#undef RT23
|
||||
#undef RT31
|
||||
#undef RT32
|
||||
#undef RT33
|
||||
#undef TRX
|
||||
#undef TRY
|
||||
#undef TRZ
|
||||
#undef L11
|
||||
#undef L12
|
||||
#undef L13
|
||||
#undef L21
|
||||
#undef L22
|
||||
#undef L23
|
||||
#undef L31
|
||||
#undef L32
|
||||
#undef L33
|
||||
#undef RBK
|
||||
#undef GBK
|
||||
#undef BBK
|
||||
#undef LR1
|
||||
#undef LR2
|
||||
#undef LR3
|
||||
#undef LG1
|
||||
#undef LG2
|
||||
#undef LG3
|
||||
#undef LB1
|
||||
#undef LB2
|
||||
#undef LB3
|
||||
#undef RFC
|
||||
#undef GFC
|
||||
#undef BFC
|
||||
#undef OFX
|
||||
#undef OFY
|
||||
#undef H
|
||||
#undef DQA
|
||||
#undef DQB
|
||||
#undef ZSF3
|
||||
#undef ZSF4
|
||||
#undef FLAG
|
||||
#endif
|
@ -1,7 +1,81 @@
|
||||
//{
|
||||
//Geometry Transformation Engine
|
||||
struct GTE {
|
||||
i16 vx0, vy0, vz0;
|
||||
i16 vx1, vy1, vz1;
|
||||
i16 vx2, vy2, vz2;
|
||||
u32 rgbc;
|
||||
u16 otz;
|
||||
i16 ir0, ir1, ir2, ir3;
|
||||
i16 sx0, sy0;
|
||||
i16 sx1, sy1;
|
||||
i16 sx2, sy2;
|
||||
u16 sz0, sz1, sz2, sz3;
|
||||
u32 rgb0, rgb1, rgb2;
|
||||
u32 res1;
|
||||
i32 mac0, mac1, mac2, mac3;
|
||||
u32 irgb, orgb;
|
||||
u32 lzcs, lzcr;
|
||||
i16 rt11, rt12, rt13;
|
||||
i16 rt21, rt22, rt23;
|
||||
i16 rt31, rt32, rt33;
|
||||
i32 trx, trY, trz;
|
||||
i16 l11, l12, l13;
|
||||
i16 l21, l22, l23;
|
||||
i16 l31, l32, l33;
|
||||
i32 rbk, gbk, bbk;
|
||||
i16 lr1, lr2, lr3;
|
||||
i16 lg1, lg2, lg3;
|
||||
i16 lb1, lb2, lb3;
|
||||
i32 rfc, gfc, bfc;
|
||||
i32 ofx, ofy;
|
||||
u16 h;
|
||||
i16 dqa;
|
||||
i32 dqb;
|
||||
i16 zsf3, zsf4;
|
||||
struct Flag {
|
||||
struct Saturated {
|
||||
bool ir0, ir1, ir2, ir3;
|
||||
bool sx2, sy2, sz1_otz;
|
||||
bool r, g, b;
|
||||
} saturated;
|
||||
struct Underflow {
|
||||
bool mac0, mac1, mac2, mac3;
|
||||
} underflow;
|
||||
struct Overflow {
|
||||
bool mac0, mac1, mac2, mac3;
|
||||
bool division;
|
||||
} overflow;
|
||||
bool error;
|
||||
} flag;
|
||||
} gte;
|
||||
|
||||
//gte-instructions.cpp
|
||||
auto instructionCFC2(u32& rt, u8 rd) -> void;
|
||||
auto instructionCTC2(cu32& rt, u8 rd) -> void;
|
||||
auto instructionMFC2(u32& rt, u8 rd) -> void;
|
||||
auto instructionMTC2(cu32& rt, u8 rd) -> void;
|
||||
|
||||
auto instructionAVSZ3() -> void;
|
||||
auto instructionAVSZ4() -> void;
|
||||
auto instructionCC() -> void;
|
||||
auto instructionCDP() -> void;
|
||||
auto instructionDCPL() -> void;
|
||||
auto instructionDPCS() -> void;
|
||||
auto instructionDPCT() -> void;
|
||||
auto instructionGPF() -> void;
|
||||
auto instructionGPL() -> void;
|
||||
auto instructionINTPL() -> void;
|
||||
auto instructionMVMVA() -> void;
|
||||
auto instructionNCCS() -> void;
|
||||
auto instructionNCCT() -> void;
|
||||
auto instructionNCDS() -> void;
|
||||
auto instructionNCDT() -> void;
|
||||
auto instructionNCLIP() -> void;
|
||||
auto instructionNCS() -> void;
|
||||
auto instructionNCT() -> void;
|
||||
auto instructionOP() -> void;
|
||||
auto instructionRTPS() -> void;
|
||||
auto instructionRTPT() -> void;
|
||||
auto instructionSQR() -> void;
|
||||
//};
|
||||
|
@ -139,8 +139,7 @@ auto CPU::Interrupt::writeHalf(u32 address, u16 value) -> void {
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::Interrupt::writeWord(u32 address, u32 value) -> void {
|
||||
uint32 data = value;
|
||||
writeHalf(address & ~3 | 0, value >> 0);
|
||||
writeHalf(address & ~3 | 2, value >> 16);
|
||||
auto CPU::Interrupt::writeWord(u32 address, u32 data) -> void {
|
||||
writeHalf(address & ~3 | 0, data >> 0);
|
||||
writeHalf(address & ~3 | 2, data >> 16);
|
||||
}
|
||||
|
45
ares/ps1/disc/command.cpp
ノーマルファイル
45
ares/ps1/disc/command.cpp
ノーマルファイル
@ -0,0 +1,45 @@
|
||||
auto Disc::command(u8 operation) -> void {
|
||||
print("* CDC ", hex(operation, 2L), "\n");
|
||||
|
||||
switch(operation) {
|
||||
case 0x01: return commandGetStatus();
|
||||
case 0x19: return commandTest();
|
||||
}
|
||||
}
|
||||
|
||||
//0x01
|
||||
auto Disc::commandGetStatus() -> void {
|
||||
uint8 data;
|
||||
data.bit(0) = ssr.error;
|
||||
data.bit(1) = ssr.motorOn;
|
||||
data.bit(2) = ssr.seekError;
|
||||
data.bit(3) = ssr.idError;
|
||||
data.bit(4) = ssr.shellOpen;
|
||||
data.bit(5) = ssr.reading;
|
||||
data.bit(6) = ssr.seeking;
|
||||
data.bit(7) = ssr.playingCDDA;
|
||||
fifo.response.write(data);
|
||||
ssr.shellOpen = 0;
|
||||
|
||||
irq.acknowledge.flag = 1;
|
||||
irq.poll();
|
||||
}
|
||||
|
||||
//0x19
|
||||
auto Disc::commandTest() -> void {
|
||||
u8 operation = fifo.parameter.read();
|
||||
switch(operation) {
|
||||
case 0x20: return commandTestControllerDate();
|
||||
}
|
||||
}
|
||||
|
||||
//0x19 0x20
|
||||
auto Disc::commandTestControllerDate() -> void {
|
||||
fifo.response.write(0x95);
|
||||
fifo.response.write(0x05);
|
||||
fifo.response.write(0x16);
|
||||
fifo.response.write(0xc1);
|
||||
|
||||
irq.acknowledge.flag = 1;
|
||||
irq.poll();
|
||||
}
|
84
ares/ps1/disc/disc.cpp
ノーマルファイル
84
ares/ps1/disc/disc.cpp
ノーマルファイル
@ -0,0 +1,84 @@
|
||||
#include <ps1/ps1.hpp>
|
||||
|
||||
namespace ares::PlayStation {
|
||||
|
||||
Disc disc;
|
||||
#include "io.cpp"
|
||||
#include "command.cpp"
|
||||
#include "irq.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto Disc::load(Node::Object parent) -> void {
|
||||
node = parent->append<Node::Component>("PlayStation");
|
||||
|
||||
tray = node->append<Node::Port>("Disc Tray");
|
||||
tray->setFamily("PlayStation");
|
||||
tray->setType("Compact Disc");
|
||||
tray->setHotSwappable(true);
|
||||
tray->setAllocate([&](auto name) { return allocate(tray); });
|
||||
tray->setConnect([&] { return connect(); });
|
||||
tray->setDisconnect([&] { return disconnect(); });
|
||||
|
||||
fifo.parameter.resize(16);
|
||||
fifo.response.resize(16);
|
||||
fifo.data.resize(2340);
|
||||
}
|
||||
|
||||
auto Disc::unload() -> void {
|
||||
fifo.parameter.reset();
|
||||
fifo.response.reset();
|
||||
fifo.data.reset();
|
||||
|
||||
disconnect();
|
||||
tray = {};
|
||||
node = {};
|
||||
}
|
||||
|
||||
auto Disc::allocate(Node::Port parent) -> Node::Peripheral {
|
||||
return cd = parent->append<Node::Peripheral>("PlayStation");
|
||||
}
|
||||
|
||||
auto Disc::connect() -> void {
|
||||
cd->setManifest([&] { return information.manifest; });
|
||||
|
||||
information = {};
|
||||
if(auto fp = platform->open(cd, "manifest.bml", File::Read, File::Required)) {
|
||||
information.manifest = fp->reads();
|
||||
}
|
||||
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
information.name = document["game/label"].string();
|
||||
|
||||
fd = platform->open(cd, "cd.rom", File::Read, File::Required);
|
||||
if(!fd) return disconnect();
|
||||
|
||||
//read disc TOC (table of contents)
|
||||
uint sectors = fd->size() / 2448;
|
||||
vector<uint8_t> subchannel;
|
||||
subchannel.resize(sectors * 96);
|
||||
for(uint sector : range(sectors)) {
|
||||
fd->seek(sector * 2448 + 2352);
|
||||
fd->read(subchannel.data() + sector * 96, 96);
|
||||
}
|
||||
session.decode(subchannel, 96);
|
||||
}
|
||||
|
||||
auto Disc::disconnect() -> void {
|
||||
fd = {};
|
||||
cd = {};
|
||||
}
|
||||
|
||||
auto Disc::main() -> void {
|
||||
step(33'868'800 / 75);
|
||||
}
|
||||
|
||||
auto Disc::step(uint clocks) -> void {
|
||||
Thread::clock += clocks;
|
||||
}
|
||||
|
||||
auto Disc::power() -> void {
|
||||
Thread::reset();
|
||||
io = {};
|
||||
}
|
||||
|
||||
}
|
100
ares/ps1/disc/disc.hpp
ノーマルファイル
100
ares/ps1/disc/disc.hpp
ノーマルファイル
@ -0,0 +1,100 @@
|
||||
struct Disc : Thread {
|
||||
Node::Component node;
|
||||
Node::Port tray;
|
||||
Node::Peripheral cd;
|
||||
Shared::File fd;
|
||||
CD::Session session;
|
||||
|
||||
auto manifest() const -> string { return information.manifest; }
|
||||
auto name() const -> string { return information.name; }
|
||||
|
||||
//disc.cpp
|
||||
auto load(Node::Object) -> void;
|
||||
auto unload() -> void;
|
||||
|
||||
auto allocate(Node::Port) -> Node::Peripheral;
|
||||
auto connect() -> void;
|
||||
auto disconnect() -> void;
|
||||
|
||||
auto main() -> void;
|
||||
auto step(uint clocks) -> void;
|
||||
auto power() -> 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;
|
||||
|
||||
//command.cpp
|
||||
auto command(u8 operation) -> void;
|
||||
auto commandGetStatus() -> void;
|
||||
auto commandTest() -> void;
|
||||
auto commandTestControllerDate() -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
struct Information {
|
||||
string manifest;
|
||||
string name;
|
||||
} information;
|
||||
|
||||
struct Interrupt {
|
||||
uint1 enable;
|
||||
uint1 flag;
|
||||
};
|
||||
|
||||
struct IRQ {
|
||||
//irq.cpp
|
||||
auto poll() -> void;
|
||||
|
||||
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
|
||||
} irq;
|
||||
|
||||
struct FIFO {
|
||||
queue<u8> parameter;
|
||||
queue<u8> response;
|
||||
queue<u8> data;
|
||||
} fifo;
|
||||
|
||||
struct ADPCM {
|
||||
uint1 mute;
|
||||
} adpcm;
|
||||
|
||||
struct CDDA {
|
||||
uint8 volume[4];
|
||||
uint8 volumeLatch[4];
|
||||
} cdda;
|
||||
|
||||
struct PrimaryStatusRegister {
|
||||
} psr;
|
||||
|
||||
struct SecondaryStatusRegister {
|
||||
uint1 error;
|
||||
uint1 motorOn;
|
||||
uint1 seekError;
|
||||
uint1 idError;
|
||||
uint1 shellOpen;
|
||||
uint1 reading;
|
||||
uint1 seeking;
|
||||
uint1 playingCDDA;
|
||||
} ssr;
|
||||
|
||||
struct IO {
|
||||
uint2 index;
|
||||
} io;
|
||||
};
|
||||
|
||||
extern Disc disc;
|
164
ares/ps1/disc/io.cpp
ノーマルファイル
164
ares/ps1/disc/io.cpp
ノーマルファイル
@ -0,0 +1,164 @@
|
||||
auto Disc::readByte(u32 address) -> u32 {
|
||||
uint8 data = 0;
|
||||
|
||||
if(address == 0x1f80'1800) {
|
||||
data.bit(0) = io.index.bit(0);
|
||||
data.bit(1) = io.index.bit(1);
|
||||
data.bit(2) = 0; //XA-ADPCM FIFO (0 = empty)
|
||||
data.bit(3) = fifo.parameter.empty(); //1 when empty
|
||||
data.bit(4) = !fifo.parameter.full(); //0 when full
|
||||
data.bit(5) = !fifo.response.empty(); //0 when empty
|
||||
data.bit(6) = !fifo.data.empty(); //0 when empty
|
||||
data.bit(7) = 0; //command/parameter busy (0 = ready)
|
||||
}
|
||||
|
||||
//response FIFO
|
||||
if(address == 0x1f80'1801 && (io.index == 0 || io.index == 1 || io.index == 2 || io.index == 3)) {
|
||||
if(!fifo.response.empty()) data = fifo.response.read();
|
||||
}
|
||||
|
||||
//data FIFO
|
||||
if(address == 0x1f80'1802 && (io.index == 0 || io.index == 1 || io.index == 2 || io.index == 3)) {
|
||||
}
|
||||
|
||||
//interrupt enable
|
||||
if(address == 0x1f80'1803 && (io.index == 0 || io.index == 2)) {
|
||||
data.bit(0) = irq.ready.enable;
|
||||
data.bit(1) = irq.complete.enable;
|
||||
data.bit(2) = irq.acknowledge.enable;
|
||||
data.bit(3) = irq.end.enable;
|
||||
data.bit(4) = irq.error.enable;
|
||||
data.bit(5) = 1;
|
||||
data.bit(6) = 1;
|
||||
data.bit(7) = 1;
|
||||
}
|
||||
|
||||
//interrupt flag
|
||||
if(address == 0x1f80'1803 && (io.index == 1 || io.index == 3)) {
|
||||
uint3 flags = 0;
|
||||
if(irq.error.flag ) flags = 5;
|
||||
if(irq.end.flag ) flags = 4;
|
||||
if(irq.acknowledge.flag) flags = 3;
|
||||
if(irq.complete.flag ) flags = 2;
|
||||
if(irq.ready.flag ) flags = 1;
|
||||
data.bit(0,2) = flags;
|
||||
data.bit(3) = irq.end.flag;
|
||||
data.bit(4) = irq.error.flag;
|
||||
data.bit(5) = 1;
|
||||
data.bit(6) = 1;
|
||||
data.bit(7) = 1;
|
||||
}
|
||||
|
||||
print("* r", hex(address, 8L), ":", io.index, "=", hex(data, 2L), "\n");
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
auto Disc::readHalf(u32 address) -> u32 {
|
||||
uint16 data = readByte(address & ~1 | 0) << 0;
|
||||
return data | readByte(address & ~1 | 1) << 8;
|
||||
}
|
||||
|
||||
auto Disc::readWord(u32 address) -> u32 {
|
||||
uint32 data = readHalf(address & ~3 | 0) << 0;
|
||||
return data | readHalf(address & ~3 | 2) << 16;
|
||||
}
|
||||
|
||||
auto Disc::writeByte(u32 address, u32 value) -> void {
|
||||
uint8 data = value;
|
||||
|
||||
print("* w", hex(address, 8L), ":", io.index, "=", hex(data, 2L), "\n");
|
||||
|
||||
if(address == 0x1f80'1800) {
|
||||
io.index = data.bit(0,1);
|
||||
}
|
||||
|
||||
//command register
|
||||
if(address == 0x1f80'1801 && io.index == 0) {
|
||||
command(data);
|
||||
}
|
||||
|
||||
//sound map data output
|
||||
if(address == 0x1f80'1801 && io.index == 1) {
|
||||
}
|
||||
|
||||
//sound map coding information
|
||||
if(address == 0x1f80'1801 && io.index == 2) {
|
||||
}
|
||||
|
||||
//audio volume for right CD output to right SPU input
|
||||
if(address == 0x1f80'1801 && io.index == 3) {
|
||||
cdda.volumeLatch[3] = data;
|
||||
}
|
||||
|
||||
//parameter FIFO
|
||||
if(address == 0x1f80'1802 && io.index == 0) {
|
||||
if(!fifo.parameter.full()) fifo.parameter.write(data);
|
||||
}
|
||||
|
||||
//interrupt enable
|
||||
if(address == 0x1f80'1802 && io.index == 1) {
|
||||
irq.ready.enable = data.bit(0);
|
||||
irq.complete.enable = data.bit(1);
|
||||
irq.acknowledge.enable = data.bit(2);
|
||||
irq.end.enable = data.bit(3);
|
||||
irq.error.enable = data.bit(4);
|
||||
irq.poll();
|
||||
}
|
||||
|
||||
//audio volume for left CD output to left SPU input
|
||||
if(address == 0x1f80'1802 && io.index == 2) {
|
||||
cdda.volumeLatch[0] = data;
|
||||
}
|
||||
|
||||
//audio volume for right CD output to left SPU input
|
||||
if(address == 0x1f80'1802 && io.index == 3) {
|
||||
cdda.volumeLatch[2] = data;
|
||||
}
|
||||
|
||||
//request register
|
||||
if(address == 0x1f80'1803 && io.index == 0) {
|
||||
}
|
||||
|
||||
//interrupt flag
|
||||
if(address == 0x1f80'1803 && io.index == 1) {
|
||||
if(data.bit(0,2) == 7) {
|
||||
if(0);
|
||||
else if(irq.ready.flag ) irq.ready.flag = 0;
|
||||
else if(irq.complete.flag ) irq.complete.flag = 0;
|
||||
else if(irq.acknowledge.flag) irq.acknowledge.flag = 0;
|
||||
else if(irq.end.flag ) irq.end.flag = 0;
|
||||
else if(irq.error.flag ) irq.error.flag = 0;
|
||||
}
|
||||
if(data.bit(3)) irq.end.flag = 0;
|
||||
if(data.bit(4)) irq.error.flag = 0;
|
||||
if(data.bit(6)) fifo.parameter.flush();
|
||||
irq.poll();
|
||||
}
|
||||
|
||||
//audio volume for left CD output to right SPU input
|
||||
if(address == 0x1f80'1803 && io.index == 2) {
|
||||
cdda.volumeLatch[1] = data;
|
||||
}
|
||||
|
||||
//audio volume apply changes
|
||||
if(address == 0x1f80'1803 && io.index == 3) {
|
||||
adpcm.mute = data.bit(0);
|
||||
if(data.bit(5)) {
|
||||
cdda.volume[0] = cdda.volumeLatch[0];
|
||||
cdda.volume[1] = cdda.volumeLatch[1];
|
||||
cdda.volume[2] = cdda.volumeLatch[2];
|
||||
cdda.volume[3] = cdda.volumeLatch[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Disc::writeHalf(u32 address, u32 data) -> void {
|
||||
writeByte(address & ~1 | 0, data >> 0);
|
||||
writeByte(address & ~1 | 1, data >> 8);
|
||||
}
|
||||
|
||||
auto Disc::writeWord(u32 address, u32 data) -> void {
|
||||
writeHalf(address & ~3 | 0, data >> 0);
|
||||
writeHalf(address & ~3 | 2, data >> 16);
|
||||
}
|
11
ares/ps1/disc/irq.cpp
ノーマルファイル
11
ares/ps1/disc/irq.cpp
ノーマルファイル
@ -0,0 +1,11 @@
|
||||
auto Disc::IRQ::poll() -> void {
|
||||
bool pending = 0;
|
||||
pending |= ready.flag & ready.enable;
|
||||
pending |= complete.flag & complete.enable;
|
||||
pending |= acknowledge.flag & acknowledge.enable;
|
||||
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");
|
||||
}
|
2
ares/ps1/disc/serialization.cpp
ノーマルファイル
2
ares/ps1/disc/serialization.cpp
ノーマルファイル
@ -0,0 +1,2 @@
|
||||
auto Disc::serialize(serializer& s) -> void {
|
||||
}
|
@ -5,6 +5,10 @@ namespace ares::PlayStation {
|
||||
Interface* interface = nullptr;
|
||||
|
||||
auto PlayStationInterface::game() -> string {
|
||||
if(disc.cd) {
|
||||
return disc.name();
|
||||
}
|
||||
|
||||
return "(no disc inserted)";
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
if(address <= 0x1f80'107f) return cpu.interrupt.access(__VA_ARGS__); \
|
||||
if(address <= 0x1f80'10ff) return cpu.dma.access(__VA_ARGS__); \
|
||||
if(address <= 0x1f80'17ff) return unmapped; \
|
||||
if(address <= 0x1f80'180f) return unmapped; \
|
||||
if(address <= 0x1f80'180f) return disc.access(__VA_ARGS__); \
|
||||
if(address <= 0x1f80'181f) return gpu.access(__VA_ARGS__); \
|
||||
if(address <= 0x1f80'1bff) return unmapped; \
|
||||
if(address <= 0x1f80'1fff) return spu.access(__VA_ARGS__); \
|
||||
|
@ -20,6 +20,7 @@ namespace ares::PlayStation {
|
||||
|
||||
#include <ps1/memory/memory.hpp>
|
||||
#include <ps1/system/system.hpp>
|
||||
#include <ps1/disc/disc.hpp>
|
||||
#include <ps1/cpu/cpu.hpp>
|
||||
#include <ps1/gpu/gpu.hpp>
|
||||
#include <ps1/spu/spu.hpp>
|
||||
|
@ -380,8 +380,8 @@ auto SPU::readHalf(u32 address) -> u32 {
|
||||
}
|
||||
|
||||
auto SPU::readWord(u32 address) -> u32 {
|
||||
uint16 data = readHalf(address & ~1 ^ 0) << 0;
|
||||
return data | readHalf(address & ~1 ^ 2) << 16;
|
||||
uint32 data = readHalf(address & ~3 | 0) << 0;
|
||||
return data | readHalf(address & ~3 | 2) << 16;
|
||||
}
|
||||
|
||||
auto SPU::writeByte(u32 address, u32 value) -> void {
|
||||
@ -792,7 +792,7 @@ auto SPU::writeHalf(u32 address, u32 value) -> void {
|
||||
}
|
||||
}
|
||||
|
||||
auto SPU::writeWord(u32 address, u32 value) -> void {
|
||||
writeHalf(address & ~1 ^ 0, value >> 0);
|
||||
writeHalf(address & ~1 ^ 2, value >> 16);
|
||||
auto SPU::writeWord(u32 address, u32 data) -> void {
|
||||
writeHalf(address & ~3 | 0, data >> 0);
|
||||
writeHalf(address & ~3 | 2, data >> 16);
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ auto System::serializeAll(serializer& s, bool synchronize) -> void {
|
||||
cpu.serialize(s);
|
||||
gpu.serialize(s);
|
||||
spu.serialize(s);
|
||||
disc.serialize(s);
|
||||
}
|
||||
|
||||
auto System::serializeInit(bool synchronize) -> uint {
|
||||
|
@ -22,6 +22,7 @@ auto System::load(Node::Object& root) -> void {
|
||||
cpu.load(node);
|
||||
gpu.load(node);
|
||||
spu.load(node);
|
||||
disc.load(node);
|
||||
}
|
||||
|
||||
auto System::unload() -> void {
|
||||
@ -30,6 +31,7 @@ auto System::unload() -> void {
|
||||
cpu.unload();
|
||||
gpu.unload();
|
||||
spu.unload();
|
||||
disc.unload();
|
||||
node.reset();
|
||||
}
|
||||
|
||||
@ -48,6 +50,7 @@ auto System::power(bool reset) -> void {
|
||||
cpu.power(reset);
|
||||
gpu.power(reset);
|
||||
spu.power(reset);
|
||||
disc.power();
|
||||
|
||||
information.serializeSize[0] = serializeInit(0);
|
||||
information.serializeSize[1] = serializeInit(1);
|
||||
|
@ -30,7 +30,7 @@ auto PPU::Background::render() -> void {
|
||||
uint y = ppu.vcounter();
|
||||
if(hires) {
|
||||
hscroll <<= 1;
|
||||
if(ppu.io.interlace) y = y << 1 | ppu.field();
|
||||
if(ppu.io.interlace) y = y << 1 | (ppu.field() && !io.mosaicEnable);
|
||||
}
|
||||
if(io.mosaicEnable) {
|
||||
y -= ppu.mosaic.voffset() << (hires && ppu.io.interlace);
|
||||
@ -111,7 +111,7 @@ auto PPU::Background::render() -> void {
|
||||
color += data >> shift + 49 & 128;
|
||||
}
|
||||
|
||||
mosaicCounter = io.mosaicEnable ? (uint)ppu.mosaic.size : 1;
|
||||
mosaicCounter = io.mosaicEnable ? ppu.mosaic.size << hires : 1;
|
||||
mosaicPalette = color;
|
||||
mosaicPriority = tilePriority;
|
||||
if(directColorMode) {
|
||||
|
@ -37,7 +37,7 @@ auto PPU::Background::fetchNameTable() -> void {
|
||||
|
||||
if(hires()) {
|
||||
hscroll <<= 1;
|
||||
if(ppu.io.interlace) vpixel = vpixel << 1 | ppu.field();
|
||||
if(ppu.io.interlace) vpixel = vpixel << 1 | (ppu.field() && !mosaic.enable);
|
||||
}
|
||||
if(mosaic.enable) {
|
||||
vpixel -= ppu.mosaic.voffset() << (hires() && ppu.io.interlace);
|
||||
@ -197,7 +197,7 @@ auto PPU::Background::run(bool screen) -> void {
|
||||
if(x == 0 && (!hires() || screen == Screen::Below)) {
|
||||
mosaic.hcounter = ppu.mosaic.size;
|
||||
mosaic.pixel = pixel;
|
||||
} else if(--mosaic.hcounter == 0) {
|
||||
} else if((!hires() || screen == Screen::Below) && --mosaic.hcounter == 0) {
|
||||
mosaic.hcounter = ppu.mosaic.size;
|
||||
mosaic.pixel = pixel;
|
||||
} else if(mosaic.enable) {
|
||||
|
@ -167,6 +167,7 @@ auto MegaCD::open(ares::Node::Object node, string name, vfs::file::mode mode, bo
|
||||
}
|
||||
|
||||
if(auto result = vfs::cdrom::open(game.location)) return result;
|
||||
|
||||
MessageDialog().setText(
|
||||
"Failed to load CD-ROM image."
|
||||
).setAlignment(presentation).error();
|
||||
|
@ -173,6 +173,7 @@ auto PCEngineCD::open(ares::Node::Object node, string name, vfs::file::mode mode
|
||||
}
|
||||
|
||||
if(auto result = vfs::cdrom::open(game.location)) return result;
|
||||
|
||||
MessageDialog().setText(
|
||||
"Failed to load CD-ROM image."
|
||||
).setAlignment(presentation).error();
|
||||
|
@ -26,6 +26,11 @@ auto PlayStation::load() -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(auto port = root->find<ares::Node::Port>("PlayStation/Disc Tray")) {
|
||||
port->allocate();
|
||||
port->connect();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -34,6 +39,29 @@ auto PlayStation::open(ares::Node::Object node, string name, vfs::file::mode mod
|
||||
return Emulator::loadFirmware(firmware[regionID]);
|
||||
}
|
||||
|
||||
if(name == "manifest.bml") {
|
||||
if(auto manifest = medium->manifest(game.location)) {
|
||||
return vfs::memory::open(manifest.data<uint8_t>(), manifest.size());
|
||||
}
|
||||
return Emulator::manifest(game.location);
|
||||
}
|
||||
|
||||
if(name == "cd.rom") {
|
||||
if(game.location.iendsWith(".zip")) {
|
||||
MessageDialog().setText(
|
||||
"Sorry, compressed CD-ROM images are not currently supported.\n"
|
||||
"Please extract the image prior to loading it."
|
||||
).setAlignment(presentation).error();
|
||||
return {};
|
||||
}
|
||||
|
||||
if(auto result = vfs::cdrom::open(game.location)) return result;
|
||||
|
||||
MessageDialog().setText(
|
||||
"Failed to load CD-ROM image."
|
||||
).setAlignment(presentation).error();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
読み込み中…
新しいイシューから参照
ユーザーをブロックする