Skip to content
Snippets Groups Projects
Commit 96ac24fd authored by Geo Ster's avatar Geo Ster
Browse files

GIF: Introduce the GIF FIFO

* The GIF similarly to the VIF also contains a 16 qword FIFO
for queueing data. The implementation is very similar to the VIF
and I used similar function names to make it easier to follow.

* In addition introduce proper reset routines. Messing with the
this pointer is not possible in our case, because it breaks the
Handler infrastructure that relies on the pointer not changing.
parent 76bd5820
No related branches found
No related tags found
No related merge requests found
...@@ -193,6 +193,7 @@ namespace common ...@@ -193,6 +193,7 @@ namespace common
dmac->tick(cycles); dmac->tick(cycles);
vif[0]->tick(cycles); vif[0]->tick(cycles);
vif[1]->tick(cycles); vif[1]->tick(cycles);
gif->tick(cycles);
/* Tick IOP components */ /* Tick IOP components */
cycles /= 4; cycles /= 4;
......
...@@ -199,16 +199,20 @@ namespace ee ...@@ -199,16 +199,20 @@ namespace ee
{ {
auto& gif = emulator->gif; auto& gif = emulator->gif;
uint128_t qword = *(uint128_t*)&emulator->ee->ram[channel.address]; uint128_t qword = *(uint128_t*)&emulator->ee->ram[channel.address];
uint64_t upper = qword >> 64, lower = qword;
fmt::print("[DMAC][GIF] Writing {:#x}{:016x} to PATH3\n", upper, lower);
gif->write_path3(0x10006000, qword); /* Send data to the PATH3 port of the GIF */
channel.address += 16; if (gif->write_path3(NULL, qword))
channel.qword_count--; {
uint64_t upper = qword >> 64, lower = qword;
fmt::print("[DMAC][GIF] Writing {:#x}{:016x} to PATH3\n", upper, lower);
assert(!channel.control.mode); channel.address += 16;
if (!channel.qword_count) channel.qword_count--;
channel.end_transfer = true;
assert(!channel.control.mode);
if (!channel.qword_count)
channel.end_transfer = true;
}
break; break;
} }
......
...@@ -48,7 +48,13 @@ namespace vu ...@@ -48,7 +48,13 @@ namespace vu
void VIF::reset() void VIF::reset()
{ {
/* Reset all the VIF registers */ /* Reset all the VIF registers */
*this = VIF(emulator, id); status = {}; fbrst = {}; cycle = {};
err = mark = mode = num = 0;
mask = code = itops = 0;
base = ofst = tops = itop = top = 0;
rn = {}; cn = {}; fifo = {}; command = {};
subpacket_count = address = qwords_written = word_cycles = 0;
write_mode = WriteMode::Skipping;
} }
uint32_t VIF::read(uint32_t address) uint32_t VIF::read(uint32_t address)
...@@ -81,6 +87,11 @@ namespace vu ...@@ -81,6 +87,11 @@ namespace vu
break; break;
case 1: case 1:
fbrst.value = data; fbrst.value = data;
/* Reset VIF is RST bit is set */
if (fbrst.reset)
reset();
break; break;
case 2: case 2:
err = data; err = data;
......
#pragma once #pragma once
#include <common/component.h> #include <common/component.h>
#include <queue>
#include <utils/queue.h> #include <utils/queue.h>
#include <array>
namespace common namespace common
{ {
...@@ -176,7 +176,7 @@ namespace vu ...@@ -176,7 +176,7 @@ namespace vu
/* These only on exist on VIF1 */ /* These only on exist on VIF1 */
uint32_t base = 0, ofst = 0; uint32_t base = 0, ofst = 0;
uint32_t tops = 0, itop = 0, top = 0; uint32_t tops = 0, itop = 0, top = 0;
uint32_t rn[4] = {}, cn[4] = {}; std::array<uint32_t, 4> rn = {}, cn = {};
/* VIF FIFO */ /* VIF FIFO */
util::Queue<uint32_t, 64> fifo; util::Queue<uint32_t, 64> fifo;
......
...@@ -29,56 +29,104 @@ namespace gs ...@@ -29,56 +29,104 @@ namespace gs
uint32_t GIF::read(uint32_t addr) uint32_t GIF::read(uint32_t addr)
{ {
assert(addr <= 0x100030A0); uint32_t data;
auto offset = (addr & 0xf0) >> 4;
uint32_t offset = (addr & 0xf0) >> 4; switch (offset)
auto ptr = (uint32_t*)&regs + offset; {
case 2:
fmt::print("[GIF] Read {:#x} from {}\n", *ptr, REGS[offset]); /* TODO: repoth PATH status */
status.fifo_count = fifo.size<uint128_t>();
data = status.value;
break;
default:
fmt::print("[GIF] Read from unknown register {}\n", REGS[offset]);
std::abort();
}
return *ptr; return data;
} }
void GIF::write(uint32_t addr, uint32_t data) void GIF::write(uint32_t addr, uint32_t data)
{ {
assert(addr <= 0x100030A0); auto offset = (addr & 0xf0) >> 4;
switch (offset)
{
case 0:
control.value = data;
/* Reset the GIF when the RST bit is set */
if (control.reset)
reset();
break;
default:
fmt::print("[GIF] Write to unknown register {}\n", REGS[offset]);
std::abort();
}
uint32_t offset = (addr & 0xf0) >> 4; fmt::print("[GIF] Writing {:#x} to {}\n", data, REGS[offset]);
auto ptr = (uint32_t*)&regs + offset; }
fmt::print("[GIF] Write {:#x} to {}\n", data, REGS[offset]); void GIF::tick(uint32_t cycles)
{
while (!fifo.empty() && cycles--)
{
if (!data_count)
process_tag();
else
execute_command();
}
}
*ptr = data; void GIF::reset()
{
/* Reset all class members */
control = {};
mode = 0;
status = {};
fifo = {};
tag = {};
data_count = reg_count = 0;
interal_Q = 0;
} }
void GIF::write_path3(uint32_t addr, uint128_t qword) bool GIF::write_path3(uint32_t, uint128_t qword)
{ {
assert(addr == 0x10006000); return fifo.push<uint128_t>(qword);
}
if (!data_count) /* Initiallize tag */
void GIF::process_tag()
{
if (fifo.read(&tag.value))
{ {
auto& gs_regs = emulator->gs->regs;
tag.value = qword;
data_count = tag.nloop; data_count = tag.nloop;
reg_count = tag.nreg; reg_count = tag.nreg;
auto& gs_regs = emulator->gs->regs;
fmt::print("[GIF] Received new GS primitive!\n"); fmt::print("[GIF] Received new GS primitive!\n");
/* Set the GS PRIM register to the PRIM field of GIFTag. /* Set the GS PRIM register to the PRIM field of GIFTag
NOTE: This only happens when PRE == 1 */ NOTE: This only happens when PRE == 1 */
if (tag.pre) gs_regs.prim = tag.pre ? tag.prim : gs_regs.prim;
gs_regs.prim = tag.prim;
/* The initial value of Q is 1.0f and is set /* The initial value of Q is 1.0f and is set
when the GIFTag is read */ when the GIFTag is read */
gs_regs.rgbaq.q = 1.0f; gs_regs.rgbaq.q = 1.0f;
/* Remove tag from fifo */
fifo.pop<uint128_t>();
} }
else }
void GIF::execute_command()
{
uint128_t qword;
if (fifo.read(&qword))
{ {
uint16_t format = tag.flg; uint16_t format = tag.flg;
switch (format) switch (format)
{ {
case Format::PACKED: case Format::Packed:
{ {
process_packed(qword); process_packed(qword);
if (!reg_count) if (!reg_count)
...@@ -88,12 +136,10 @@ namespace gs ...@@ -88,12 +136,10 @@ namespace gs
} }
break; break;
} }
case Format::IMAGE: case Format::Image:
{ {
uint64_t lower = qword; emulator->gs->write_hwreg(qword);
uint64_t upper = qword >> 64; emulator->gs->write_hwreg(qword >> 64);
emulator->gs->write_hwreg(lower);
emulator->gs->write_hwreg(upper);
data_count--; data_count--;
break; break;
} }
...@@ -101,9 +147,11 @@ namespace gs ...@@ -101,9 +147,11 @@ namespace gs
fmt::print("[GIF] Unknown format {:d}\n", format); fmt::print("[GIF] Unknown format {:d}\n", format);
std::abort(); std::abort();
} }
fifo.pop<uint128_t>();
} }
} }
void GIF::process_packed(uint128_t qword) void GIF::process_packed(uint128_t qword)
{ {
int curr_reg = tag.nreg - reg_count; int curr_reg = tag.nreg - reg_count;
......
#pragma once #pragma once
#include <common/component.h> #include <common/component.h>
#include <utils/queue.h>
namespace common namespace common
{ {
...@@ -8,40 +9,37 @@ namespace common ...@@ -8,40 +9,37 @@ namespace common
namespace gs namespace gs
{ {
union GIFSTAT union GIFCTRL
{ {
uint32_t value; uint32_t value;
struct struct
{ {
uint32_t M3R : 1; uint32_t reset : 1;
uint32_t M3P : 1; uint32_t : 2;
uint32_t IMT : 1; uint32_t stop : 1;
uint32_t PSE : 1;
uint32_t IP3 : 1;
uint32_t P3Q : 1;
uint32_t P2Q : 1;
uint32_t P1Q : 1;
uint32_t OPH : 1;
uint32_t APATH : 2;
uint32_t DIR : 1;
uint32_t : 12;
uint32_t FQC : 5;
uint32_t : 3;
}; };
}; };
struct GIFRegs union GIFSTAT
{ {
uint32_t GIF_CTRL; uint32_t value;
uint32_t GIF_MODE; struct
GIFSTAT GIF_STAT; {
uint32_t GIF_TAG0; uint32_t path3_mask : 1;
uint32_t GIF_TAG1; uint32_t path3_vif_mask : 1;
uint32_t GIF_TAG2; uint32_t path3_imt : 1;
uint32_t GIF_TAG3; uint32_t stop : 1;
uint32_t GIF_CNT; uint32_t : 1;
uint32_t GIF_P3CNT; uint32_t path3_interrupted : 1;
uint32_t GIF_P3TAG; uint32_t path3_queued : 1;
uint32_t path2_queued : 1;
uint32_t path1_queued : 1;
uint32_t output_path : 1;
uint32_t active_path : 2;
uint32_t direction : 1;
uint32_t : 12;
uint32_t fifo_count : 5;
};
}; };
/* The header of each GS Primitive */ /* The header of each GS Primitive */
...@@ -82,31 +80,43 @@ namespace gs ...@@ -82,31 +80,43 @@ namespace gs
enum Format : uint32_t enum Format : uint32_t
{ {
PACKED = 0, Packed = 0,
REGLIST = 1, Reglist = 1,
IMAGE = 2, Image = 2,
Disable = 3 Disable = 3
}; };
struct GIF : public common::Component struct GIF : public common::Component
{ {
GIF(common::Emulator* parent); GIF(common::Emulator* parent);
~GIF() = default;
void tick(uint32_t cycles);
void reset();
uint32_t read(uint32_t addr); uint32_t read(uint32_t addr);
void write(uint32_t addr, uint32_t data); void write(uint32_t addr, uint32_t data);
/* Writes from various PATHs */ /* Writes from various PATHs */
void write_path3(uint32_t addr, uint128_t data); bool write_path3(uint32_t, uint128_t data);
private: private:
void process_tag();
void execute_command();
void process_packed(uint128_t qword); void process_packed(uint128_t qword);
private: private:
common::Emulator* emulator; common::Emulator* emulator;
GIFRegs regs = {};
/* GIF registers */
GIFCTRL control = {};
uint32_t mode = 0;
GIFSTAT status = {};
util::Queue<uint32_t, 64> fifo;
/* Used during transfers */ /* Used during transfers */
GIFTag tag; GIFTag tag = {};
int data_count = 0, reg_count = 0; int data_count = 0, reg_count = 0;
/* Stores the last Q value provided by ST */ /* Stores the last Q value provided by ST */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment