mirror of
https://github.com/liuk7071/ChonkyStation.git
synced 2024-05-20 12:57:52 -04:00
GPU rectangles and other stuff
This commit is contained in:
parent
ffebb51058
commit
2fb4c68e87
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"); };
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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 };
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue