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
このコミットが含まれているのは:
Near 2020-07-04 19:46:00 +00:00
コミット bfdb287505
28個のファイルの変更1109行の追加19行の削除

ファイルの表示

@ -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 ノーマルファイル
ファイルの表示

@ -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 ノーマルファイル
ファイルの表示

@ -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 ノーマルファイル
ファイルの表示

@ -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 ノーマルファイル
ファイルの表示

@ -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 ノーマルファイル
ファイルの表示

@ -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 ノーマルファイル
ファイルの表示

@ -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 ノーマルファイル
ファイルの表示

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