GPU rectangles and other stuff

This commit is contained in:
liuk7071 2023-09-22 18:54:44 +02:00
parent ffebb51058
commit 2fb4c68e87
11 changed files with 129 additions and 15 deletions

View file

@ -133,7 +133,7 @@ void CDROM::int2(void* classptr) {
cdrom->statusReg.rslrrdy = 1; // Response fifo not empty
while (cdrom->secondResponse.size()) cdrom->secondResponse.pop();
log("---INT2\n");
log("--INT2\n");
}
else
log("INT2\n");
@ -159,7 +159,7 @@ void CDROM::int5(void* classptr) {
cdrom->statusReg.rslrrdy = 1; // Response fifo not empty
while (cdrom->secondResponse.size()) cdrom->secondResponse.pop();
log("---INT5\n");
log("--INT5\n");
}
else
log("INT5\n");

View file

@ -1,6 +1,9 @@
#include "interpreter.hpp"
#define DONT_CRASH_ON_BAD_READWRITE
#define DONT_CRASH_ON_BAD_JUMP
void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
// Handle interrupts
core->checkInterrupt(mem->interrupt);
@ -55,7 +58,11 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
case CpuOpcodes::SPECIALOpcode::JR: {
const u32 addr = gprs[instr.rs];
if (addr & 3) {
#ifndef DONT_CRASH_ON_BAD_JUMP
Helpers::panic("Bad JR addr\n");
#else
break;
#endif
}
core->nextPc = addr;
core->branched = true;
@ -64,7 +71,11 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
case CpuOpcodes::SPECIALOpcode::JALR: {
const u32 addr = gprs[instr.rs];
if (addr & 3) {
#ifndef DONT_CRASH_ON_BAD_JUMP
Helpers::panic("Bad JALR addr\n");
#else
break;
#endif
}
gprs[CpuOpcodes::CpuReg::RA] = core->nextPc;
core->nextPc = addr;
@ -193,7 +204,7 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
break;
}
case CpuOpcodes::Opcode::REGIMM: {
switch (instr.regimmOpc) {
switch (instr.regimmOpc & 0x11) {
case CpuOpcodes::REGIMMOpcode::BLTZ: {
if ((s32)gprs[instr.rs] < 0) {
core->nextPc = core->pc + ((u32)(s16)instr.imm << 2);
@ -339,7 +350,9 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
case CpuOpcodes::Opcode::LH: {
const u32 addr = gprs[instr.rs] + (u32)(s16)instr.imm;
if (addr & 1) {
#ifndef DONT_CRASH_ON_BAD_READWRITE
Helpers::panic("Bad lh addr 0x%08x\n", addr);
#endif
}
gprs[instr.rt] = (u32)(s16)mem->read<u16>(addr);
break;
@ -356,7 +369,9 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
case CpuOpcodes::Opcode::LW: {
const u32 addr = gprs[instr.rs] + (u32)(s16)instr.imm;
if (addr & 3) {
#ifndef DONT_CRASH_ON_BAD_READWRITE
Helpers::panic("Bad lw addr 0x%08x\n", addr);
#endif
}
gprs[instr.rt] = mem->read<u32>(addr);
break;
@ -369,7 +384,9 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
case CpuOpcodes::Opcode::LHU: {
const u32 addr = gprs[instr.rs] + (u32)(s16)instr.imm;
if (addr & 1) {
#ifndef DONT_CRASH_ON_BAD_READWRITE
Helpers::panic("Bad lhu addr 0x%08x\n", addr);
#endif
}
gprs[instr.rt] = mem->read<u16>(addr);
break;
@ -393,7 +410,9 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
if (core->cop0.status.isc) return;
const u32 addr = gprs[instr.rs] + (u32)(s16)instr.imm;
if (addr & 1) {
#ifndef DONT_CRASH_ON_BAD_READWRITE
Helpers::panic("Bad sh addr 0x%08x\n", addr);
#endif
}
mem->write<u16>(addr, gprs[instr.rt]);
break;
@ -411,7 +430,9 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
if (core->cop0.status.isc) break;
const u32 addr = gprs[instr.rs] + (u32)(s16)instr.imm;
if (addr & 3) {
#ifndef DONT_CRASH_ON_BAD_READWRITE
Helpers::panic("Bad sw addr 0x%08x\n", addr);
#endif
}
mem->write<u32>(addr, gprs[instr.rt]);
break;

View file

@ -77,6 +77,7 @@ struct COP0 {
case (u32)COP0Reg::BDA: return 0;
case (u32)COP0Reg::JumpDest: return 0;
case (u32)COP0Reg::DCIC: return 0;
case (u32)COP0Reg::BadVAddr: return 0;
case (u32)COP0Reg::BDAM: return 0;
case (u32)COP0Reg::BPCM: return 0;
case (u32)COP0Reg::Status: return status.raw;

View file

@ -16,6 +16,8 @@ public:
// Drawing
virtual void drawTriUntextured(Vertex v0, Vertex v1, Vertex v2) { Helpers::panic("[ FATAL ] GPU Backend did not define drawTriUntextured function\n"); }
virtual void drawTriTextured(Vertex v0, Vertex v1, Vertex v2, u16 clut, u16 texpage) { Helpers::panic("[ FATAL ] GPU Backend did not define drawTriTextured function\n"); }
virtual void drawRectUntextured(Vertex v, u16 width, u16 height) { Helpers::panic("[ FATAL ] GPU Backend did not define drawRectUntextured function\n"); };
// Textures
virtual void beginTextureUpload(u16 x, u16 y, u16 width) { Helpers::panic("[ FATAL ] GPU Backend did not define beginTextureUpload function\n"); };

View file

@ -148,4 +148,12 @@ void GPUSoftware::drawTriTextured(Vertex v0, Vertex v1, Vertex v2, u16 clut, u16
}
}
}
}
void GPUSoftware::drawRectUntextured(Vertex v, u16 width, u16 height) {
for (s16 y = v.y; y < v.y + height; y++) {
for (s16 x = v.x; x < v.x + width; x++) {
writePixel(x, y, v.getBGR555());
}
}
}

View file

@ -16,6 +16,8 @@ public:
void drawTriUntextured(Vertex v0, Vertex v1, Vertex v2) override;
void drawTriTextured(Vertex v0, Vertex v1, Vertex v2, u16 clut, u16 texpage) override;
void drawRectUntextured(Vertex v, u16 width, u16 height) override;
void beginTextureUpload(u16 x, u16 y, u16 width) override;
void textureUploadData(u16 data) override;
void endTextureUpload() override;

View file

@ -118,7 +118,7 @@ void GPU::writeGp0(u32 data) {
verts[i].v = (uv >> 8) & 0xff;
}
}
// Draw
if (!poly.textured) {
backend->drawTriUntextured(verts[0], verts[1], verts[2]);
@ -129,10 +129,37 @@ void GPU::writeGp0(u32 data) {
u16 clut = fifo[2] >> 16;
u16 texpage = fifo[4] >> 16;
backend->drawTriTextured(verts[0], verts[1], verts[2], clut, texpage);
if(poly.quad)
if (poly.quad)
backend->drawTriTextured(verts[1], verts[2], verts[3], clut, texpage);
}
}
else if (drawCommand.drawType == DrawCommand::DrawType::Rectangle) {
auto rect = drawCommand.getRectangle();
Vertex vert;
auto idx = 0;
u32 col = fifo[idx++] & 0xffffff;
vert.writeBGR888(col);
vert.x = fifo[idx] & 0xffff;
vert.y = (fifo[idx++] >> 16) & 0xffff;
if (rect.textured) {
vert.u = fifo[idx] & 0xff;
vert.v = (fifo[idx++] >> 8) & 0xff;
}
// TODO: variable size
Helpers::debugAssert(rect.size != 0, "[FATAL] Unimplemented variable size rectangle\n");
// TODO: textured
Helpers::debugAssert(!rect.textured, "[FATAL] Unimplemented textured rectangle\n");
u16 width = 0;
u16 height = 0;
switch (rect.size) {
case 1: width = 1; height = 1; break;
case 2: width = 8; height = 8; break;
case 3: width = 16; height = 16; break;
}
backend->drawRectUntextured(vert, width, height);
}
}
}
else {
@ -277,16 +304,28 @@ void GPU::startCommand(u32 rawCommand) {
}
GPU::DrawCommand::DrawCommand(u32 raw) {
Polygon temp = { .raw = raw };
this->raw = raw;
if (temp.polygonCommand == 1) {
switch ((raw >> 29) & 7) {
// Polygon
case 0b001: {
Polygon temp = { .raw = raw };
log("Polygon:\n");
log(temp.quad ? " Quad\n" : " Tri\n");
log(temp.shaded ? " Shaded\n" : " Monochrome\n");
log(temp.textured ? " Textured\n" : " Untextured\n");
drawType = DrawType::Polygon;
break;
}
else {
// Rectangle
case 0b011: {
// TODO: Logging
drawType = DrawType::Rectangle;
break;
}
default:
Helpers::panic("[GPU] Unimplemented gp0 command 0x%02x (0x%08x)\n", raw >> 24, raw);
}
}
@ -304,6 +343,11 @@ u32 GPU::DrawCommand::getCommandSize() {
// First colour is included in the command word
if (poly.shaded) size--;
}
else if (drawType == DrawType::Rectangle) {
Rectangle rect = getRectangle();
if (rect.textured) size++;
if (rect.size == 0) size++;
}
else {
Helpers::panic("[GPU] Tried to get command size for unimplemented command type\n");
}
@ -314,4 +358,9 @@ u32 GPU::DrawCommand::getCommandSize() {
GPU::DrawCommand::Polygon GPU::DrawCommand::getPolygon() {
if (drawType != DrawType::Polygon) Helpers::panic("[GPU] Tried to getPolygon but drawType was not polygon\n");
return { .raw = this->raw };
}
GPU::DrawCommand::Rectangle GPU::DrawCommand::getRectangle() {
if (drawType != DrawType::Rectangle) Helpers::panic("[GPU] Tried to getRectangle but drawType was not rectangle\n");
return { .raw = this->raw };
}

View file

@ -81,7 +81,8 @@ private:
u32 getCommandSize(); // In words
enum class DrawType {
Polygon,
Line
Line,
Rectangle
} drawType;
union Polygon {
@ -95,7 +96,18 @@ private:
BitField<29, 3, u32> polygonCommand; // Should be 0b001
};
union Rectangle {
u32 raw;
BitField<0, 24, u32> rgb; // Colour
BitField<24, 1, u32> rawTexture;
BitField<25, 1, u32> semiTransparent;
BitField<26, 1, u32> textured;
BitField<27, 2, u32> size;
BitField<29, 3, u32> rectangleCommand; // Should be 0b011
};
Polygon getPolygon();
Rectangle getRectangle();
private:
u32 raw;

View file

@ -64,8 +64,9 @@ u8 Memory::read(u32 vaddr) {
u32 paddr = maskAddress(vaddr);
if (Helpers::inRangeSized<u32>(paddr, 0x1f800000, 1_KB)) return scratchpad[paddr - 0x1f800000];
// CDROM
if (paddr == 0x1f801800) return cdrom->readStatus();
else if (paddr == 0x1f801800) return cdrom->readStatus();
else if (paddr == 0x1f801801) {
switch (cdrom->getIndex()) {
case 1: return cdrom->getResponseByte();
@ -99,8 +100,14 @@ u16 Memory::read(u32 vaddr) {
u32 paddr = maskAddress(vaddr);
// Scratchpad
if (Helpers::inRangeSized<u32>(paddr, 0x1f800000, 1_KB)) {
u32 data = 0;
std::memcpy(&data, &scratchpad[paddr - 0x1f800000], sizeof(u16));
return data;
}
// Interrupt
if (paddr == 0x1f801070) return interrupt->readIstat();
else if (paddr == 0x1f801070) return interrupt->readIstat();
else if (paddr == 0x1f801074) return interrupt->readImask();
// SIO
else if (Helpers::inRangeSized<u32>(paddr, (u32)MemoryBase::SIO, (u32)MemorySize::SIO)) return 0;
@ -151,7 +158,8 @@ u32 Memory::read(u32 vaddr) {
// Timers
else if (Helpers::inRangeSized<u32>(paddr, (u32)MemoryBase::Timer, (u32)MemorySize::Timer)) return 0;
else
Helpers::panic("[ FATAL ] Unhandled read32 0x%08x (virtual 0x%08x)\n", paddr, vaddr);
Helpers::dump("ramdump.bin", ram, 2_MB);
Helpers::panic("[ FATAL ] Unhandled read32 0x%08x (virtual 0x%08x) @ pc 0x%08x\n", paddr, vaddr, core->pc);
}
@ -168,8 +176,9 @@ void Memory::write(u32 vaddr, u8 data) {
u32 paddr = maskAddress(vaddr);
if (Helpers::inRangeSized<u32>(paddr, 0x1f800000, 1_KB)) scratchpad[paddr - 0x1f800000] = data;
// CDROM
if (paddr == 0x1f801800) { cdrom->writeStatus(data); return; }
else if (paddr == 0x1f801800) cdrom->writeStatus(data);
else if (paddr == 0x1f801801) {
switch (cdrom->getIndex()) {
case 0: {
@ -222,8 +231,11 @@ void Memory::write(u32 vaddr, u16 data) {
u32 paddr = maskAddress(vaddr);
if (Helpers::inRangeSized<u32>(paddr, 0x1f800000, 1_KB)) {
std::memcpy(&scratchpad[paddr - 0x1f800000], &data, sizeof(u16));
}
// Interrupt
if (paddr == 0x1f801070) interrupt->writeIstat(data);
else if (paddr == 0x1f801070) interrupt->writeIstat(data);
else if (paddr == 0x1f801074) interrupt->writeImask(data);
// SIO
else if (Helpers::inRangeSized<u32>(paddr, (u32)MemoryBase::SIO, (u32)MemorySize::SIO)) return;
@ -248,8 +260,11 @@ void Memory::write(u32 vaddr, u32 data) {
u32 paddr = maskAddress(vaddr);
if (Helpers::inRangeSized<u32>(paddr, 0x1f800000, 1_KB)) {
std::memcpy(&scratchpad[paddr - 0x1f800000], &data, sizeof(u32));
}
// GPU
if (paddr == 0x1f801810) gpu->writeGp0(data);
else if (paddr == 0x1f801810) gpu->writeGp0(data);
else if (paddr == 0x1f801814) gpu->writeGp1(data);
// Interrupt
else if (paddr == 0x1f801070) interrupt->writeIstat(data);

View file

@ -5,6 +5,7 @@
#include <dma.hpp>
#include <gpu.hpp>
#include <cdrom.hpp>
#include <cpu_core.hpp>
class Memory {
@ -20,6 +21,7 @@ public:
DMA* dma;
GPU* gpu;
CDROM* cdrom;
CpuCore* core; // Mainly used for debugging (i.e. get pc of bad read/writes)
// Base addresses
enum class MemoryBase {

View file

@ -13,6 +13,8 @@
class PlayStation {
public:
PlayStation(const fs::path& biosPath) : cdrom(&scheduler), interrupt(), gpu(&scheduler), dma(), mem(&interrupt, &dma, &gpu, &cdrom), cpu(&mem) {
mem.core = &cpu.core;
mem.loadBios(biosPath);
cpu.switchBackend(Cpu::Backend::Interpreter);