Implement gif packed mode

This commit is contained in:
Marco Satti 2018-09-09 19:15:22 +08:00
parent 30ad98be49
commit 48c4efcce6
5 changed files with 374 additions and 65 deletions

View file

@ -58,26 +58,58 @@ int CGif::time_step(const int ticks_available)
for (auto& fifo : paths)
{
if (!fifo->has_read_available(NUMBER_BYTES_IN_QWORD))
continue;
uqword data;
fifo->read(reinterpret_cast<ubyte*>(&data), NUMBER_BYTES_IN_QWORD);
if (!ctrl.transfer_started)
{
if (!fifo->has_read_available(NUMBER_BYTES_IN_QWORD))
continue;
uqword data;
fifo->read(reinterpret_cast<ubyte*>(&data), NUMBER_BYTES_IN_QWORD);
ctrl.transfer_started = true;
handle_tag(Giftag(data));
}
else
{
handle_data(data);
switch (ctrl.tag.flg())
{
case Giftag::DataFormat::Packed:
{
if (!fifo->has_read_available(NUMBER_BYTES_IN_QWORD))
continue;
uqword data;
fifo->read(reinterpret_cast<ubyte*>(&data), NUMBER_BYTES_IN_QWORD);
handle_data_packed(data);
}
case Giftag::DataFormat::Reglist:
{
if (!fifo->has_read_available(NUMBER_BYTES_IN_DWORD))
continue;
uqword data;
fifo->read(reinterpret_cast<ubyte*>(&data), NUMBER_BYTES_IN_DWORD);
handle_data_packed(data);
}
case Giftag::DataFormat::Image:
case Giftag::DataFormat::Disabled:
{
if (!fifo->has_read_available(NUMBER_BYTES_IN_QWORD))
continue;
uqword data;
fifo->read(reinterpret_cast<ubyte*>(&data), NUMBER_BYTES_IN_QWORD);
handle_data_image(data);
}
}
}
if (ctrl.transfer_end_of_packet)
if (ctrl.tag.eop())
{
if (ctrl.transfer_data_count == ctrl.transfer_data_target)
ctrl.transfer_started = false;
throw std::runtime_error("End of GS packet reached");
}
}
@ -89,13 +121,258 @@ void CGif::handle_tag(const Giftag tag)
auto& r = core->get_resources();
auto& ctrl = r.ee.gif.ctrl;
ctrl.transfer_data_count = 0;
ctrl.tag = tag;
ctrl.transfer_register_count = 0;
ctrl.transfer_loop_count = 0;
// Initialise the RGBAQ.Q value on every tag read.
// See EE Users manual page 153.
ctrl.rgbaq_q = 1.0f;
// Some special processing when the NLOOP field is non-zero
// "Values other than the EOP field are disregarded."
// See EE Users Manual page 151.
if (tag.nloop())
{
if (tag.flg() == Giftag::DataFormat::Packed)
{
// Output the packed PRIM data to GS if the PRE bit is set.
if (tag.pre())
{
throw std::runtime_error("Sending GIFtag packed PRIM data not implemented yet");
//uhword prim_value = tag.prim();
//auto& prim = r.gs.prim;
//prim.write_udword(prim_value);
}
}
}
}
void CGif::handle_data(const uqword data)
void CGif::handle_data_packed(const uqword data)
{
auto& r = core->get_resources();
auto& ctrl = r.ee.gif.ctrl;
// Get the register descirptor.
size_t register_descirptor = ctrl.tag.regs(ctrl.transfer_register_count);
// Process the data given, and write to the GS register.
// See EE Users Manual page 152 onwards for processing details.
switch (register_descirptor)
{
case 0x0:
{
// PRIM
constexpr Bitfield PRIM = Bitfield(0, 11);
udword prim_value = PRIM.extract_from<udword>(data);
//auto& prim = r.gs.prim;
//prim.write_udword(prim_value);
}
case 0x1:
{
// RGBAQ
constexpr Bitfield R = Bitfield(0, 8);
constexpr Bitfield G = Bitfield(32, 8);
constexpr Bitfield B = Bitfield(64, 8);
constexpr Bitfield A = Bitfield(96, 8);
udword r_value = R.extract_from<udword>(data);
udword g_value = G.extract_from<udword>(data);
udword b_value = B.extract_from<udword>(data);
udword a_value = A.extract_from<udword>(data);
udword q_value = *reinterpret_cast<udword*>(&ctrl.rgbaq_q);
//auto& rgbaq = r.gs.rgbaq;
//rgbaq.write_field(GsRegister_Rgbaq::R, r_value);
//rgbaq.write_field(GsRegister_Rgbaq::G, g_value);
//rgbaq.write_field(GsRegister_Rgbaq::B, b_value);
//rgbaq.write_field(GsRegister_Rgbaq::A, a_value);
//rgbaq.write_field(GsRegister_Rgbaq::Q, q_value);
}
case 0x2:
{
// ST
constexpr Bitfield S = Bitfield(0, 32);
constexpr Bitfield T = Bitfield(32, 32);
constexpr Bitfield Q = Bitfield(64, 32);
// Store the Q value internally, used when handling RGBAQ register descriptor (see above).
uword q_value = Q.extract_from<uword>(data);
ctrl.rgbaq_q = *reinterpret_cast<f32*>(&q_value);
udword s_value = S.extract_from<udword>(data);
udword t_value = T.extract_from<udword>(data);
//auto& st = r.gs.st;
//st.write_field(GsRegister_St::S, s_value);
//st.write_field(GsRegister_St::T, t_value);
}
case 0x3:
{
// UV
constexpr Bitfield U = Bitfield(0, 14);
constexpr Bitfield V = Bitfield(32, 14);
udword u_value = U.extract_from<udword>(data);
udword v_value = V.extract_from<udword>(data);
//auto& uv = r.gs.uv;
//uv.write_field(GsRegister_Uv::U, u_value);
//uv.write_field(GsRegister_Uv::V, v_value);
}
case 0x4:
{
// XYZF2/3
constexpr Bitfield X = Bitfield(0, 16);
constexpr Bitfield Y = Bitfield(32, 16);
constexpr Bitfield Z = Bitfield(68, 24);
constexpr Bitfield F = Bitfield(100, 8);
constexpr Bitfield ADC = Bitfield(111, 1);
udword x_value = X.extract_from<udword>(data);
udword y_value = Y.extract_from<udword>(data);
udword z_value = Z.extract_from<udword>(data);
udword f_value = F.extract_from<udword>(data);
udword adc_value = ADC.extract_from<udword>(data);
//GsRegister_Xyzf * xyzf = adc_value ? &r.gs.xyzf2 : &r.gs.xyzf3;
//xyzf->write_field(GsRegister_Xyzf::X, x_value);
//xyzf->write_field(GsRegister_Xyzf::Y, y_value);
//xyzf->write_field(GsRegister_Xyzf::Z, z_value);
//xyzf->write_field(GsRegister_Xyzf::F, f_value);
}
case 0x5:
{
// XYZ2
constexpr Bitfield X = Bitfield(0, 16);
constexpr Bitfield Y = Bitfield(32, 16);
constexpr Bitfield Z = Bitfield(64, 32);
constexpr Bitfield ADC = Bitfield(111, 1);
udword x_value = X.extract_from<udword>(data);
udword y_value = Y.extract_from<udword>(data);
udword z_value = Z.extract_from<udword>(data);
udword adc_value = ADC.extract_from<udword>(data);
//GsRegister_Xyzf * xyz = adc_value ? &r.gs.xyz2 : &r.gs.xyz3;
//xyz->write_field(GsRegister_Xyzf::X, x_value);
//xyz->write_field(GsRegister_Xyzf::Y, y_value);
//xyz->write_field(GsRegister_Xyzf::Z, z_value);
}
case 0x6:
{
// TEX0_1
//auto& tex0_1 = r.gs.tex0_1;
//tex0_1.write_udword(data.lo);
}
case 0x7:
{
// TEX0_2
//auto& tex0_2 = r.gs.tex0_2;
//tex0_2.write_udword(data.lo);
}
case 0x8:
{
// CLAMP_1
//auto& clamp_1 = r.gs.clamp_1;
//clamp_1.write_udword(data.lo);
}
case 0x9:
{
// CLAMP_2
//auto& clamp_2 = r.gs.clamp_2;
//clamp_2.write_udword(data.lo);
}
case 0xA:
{
// FOG
// TODO: Not sure if we need to extract the integral part? Wording a bit unclear.
// See EE Users Manual page 155.
constexpr Bitfield F = Bitfield(100, 8);
udword f_value = F.extract_from<udword>(data);
//auto& fog = r.gs.fog;
//fog.write_field(GsRegister_Fog::F, f_value);
}
case 0xB:
{
// Reserved
throw std::runtime_error("Reserved register descriptor read from GIFtag");
}
case 0xC:
{
// XYZF3
//auto& xyzf3 = r.gs.xyzf3;
//xyzf3.write_udword(data.lo);
}
case 0xD:
{
// XYZ3
//auto& xyz3 = r.gs.xyz3;
//xyz3.write_udword(data.lo);
}
case 0xE:
{
// A+D (packed address + data)
constexpr Bitfield ADDR = Bitfield(64, 8);
uptr addr_value = ADDR.extract_from<uptr>(data);
udword data_value = data.lo;
//r.gs.bus.write_udword(BusContext::Gif, addr_value, data_value);
}
case 0xF:
{
// NOP
}
default:
{
throw std::runtime_error("Unknown register descriptor given");
}
}
ctrl.transfer_register_count += 1;
if (ctrl.transfer_register_count == ctrl.tag.nreg())
{
ctrl.transfer_register_count = 0;
ctrl.transfer_loop_count += 1;
}
if (ctrl.transfer_loop_count == ctrl.tag.nloop())
ctrl.transfer_started = false;
}
void CGif::handle_data_reglist(const udword data)
{
auto& r = core->get_resources();
auto& ctrl = r.ee.gif.ctrl;
ctrl.transfer_data_count += 1;
ctrl.transfer_register_count += 1;
if (ctrl.transfer_register_count == ctrl.tag.nreg())
{
ctrl.transfer_register_count = 0;
ctrl.transfer_loop_count += 1;
}
if (ctrl.transfer_loop_count == ctrl.tag.nloop())
ctrl.transfer_started = false;
}
void CGif::handle_data_image(const uqword data)
{
auto& r = core->get_resources();
auto& ctrl = r.ee.gif.ctrl;
ctrl.transfer_register_count += 1;
if (ctrl.transfer_register_count == ctrl.tag.nreg())
{
ctrl.transfer_register_count = 0;
ctrl.transfer_loop_count += 1;
}
if (ctrl.transfer_loop_count == ctrl.tag.nloop())
ctrl.transfer_started = false;
}

View file

@ -19,5 +19,9 @@ public:
void handle_tag(const Giftag tag);
void handle_data(const uqword data);
void handle_data_packed(const uqword data);
void handle_data_reglist(const udword data);
void handle_data_image(const uqword data);
};

View file

@ -2,8 +2,9 @@
GifRegister_Ctrl::GifRegister_Ctrl() :
transfer_started(false),
transfer_data_target(0),
transfer_data_count(0),
transfer_end_of_packet(false)
tag(),
transfer_register_count(0),
transfer_loop_count(0),
rgbaq_q(1.0f)
{
}

View file

@ -6,6 +6,8 @@
#include "Common/Types/Bitfield.hpp"
#include "Common/Types/Register/SizedWordRegister.hpp"
#include "Resources/Ee/Gif/Giftag.hpp"
class GifRegister_Ctrl : public SizedWordRegister
{
public:
@ -14,17 +16,20 @@ public:
GifRegister_Ctrl();
/// Indicates whether the GIF is currently processing a GS primitive
/// (excluding the tag). Reset upon finishing a GS primitive.
/// Indicates whether the GIF is currently processing GS primitive
/// data (otherwise read a tag). Reset upon finishing a GS primitive.
bool transfer_started;
/// Number of qwords total/left for the current GS primitive.
/// Set by the tag read.
size_t transfer_data_target;
size_t transfer_data_count;
/// Current transfer tag being processed.
Giftag tag;
/// End of GS packet indicator. Set by the tag read.
bool transfer_end_of_packet;
/// Number of registers / loops processed for the current tag.
size_t transfer_register_count;
size_t transfer_loop_count;
/// Special holding area for the RGBAQ.Q value, set when the ST
/// register descriptor is written to. See EE Users manual page 153/154.
f32 rgbaq_q;
public:
template<class Archive>
@ -33,9 +38,9 @@ public:
archive(
cereal::base_class<SizedWordRegister>(this),
CEREAL_NVP(transfer_started),
CEREAL_NVP(transfer_data_target),
CEREAL_NVP(transfer_data_count),
CEREAL_NVP(transfer_end_of_packet)
CEREAL_NVP(tag),
CEREAL_NVP(transfer_register_count),
CEREAL_NVP(transfer_loop_count),
);
}
};

View file

@ -39,14 +39,16 @@ public:
Disabled // Disabled means the same operation mode as Image.
};
Giftag() = default;
Giftag(const uqword tag) :
tag(tag)
{
}
int nloop() const
size_t nloop() const
{
return NLOOP.extract_from<int>(tag);
return NLOOP.extract_from<size_t>(tag);
}
bool eop() const
@ -59,6 +61,12 @@ public:
return EOP.extract_from<int>(tag) > 0;
}
udword prim() const
{
// The PRIM register is dword in size.
return PRIM.extract_from<udword>(tag);
}
DataFormat flg() const
{
switch (FLG.extract_from<int>(tag))
@ -76,94 +84,108 @@ public:
}
}
int nreg() const
size_t nreg() const
{
int nreg = NREG.extract_from<int>(tag);
size_t nreg = NREG.extract_from<size_t>(tag);
if (nreg >= 16 || nreg < 0)
if (nreg >= 16)
throw std::runtime_error("Unknown nreg value");
return (nreg == 0) ? 16 : nreg;
}
int regs0() const
size_t regs0() const
{
return REGS0.extract_from<int>(tag);
return REGS0.extract_from<size_t>(tag);
}
int regs1() const
size_t regs1() const
{
return REGS1.extract_from<int>(tag);
return REGS1.extract_from<size_t>(tag);
}
int regs2() const
size_t regs2() const
{
return REGS2.extract_from<int>(tag);
return REGS2.extract_from<size_t>(tag);
}
int regs3() const
size_t regs3() const
{
return REGS3.extract_from<int>(tag);
return REGS3.extract_from<size_t>(tag);
}
int regs4() const
size_t regs4() const
{
return REGS4.extract_from<int>(tag);
return REGS4.extract_from<size_t>(tag);
}
int regs5() const
size_t regs5() const
{
return REGS5.extract_from<int>(tag);
return REGS5.extract_from<size_t>(tag);
}
int regs6() const
size_t regs6() const
{
return REGS6.extract_from<int>(tag);
return REGS6.extract_from<size_t>(tag);
}
int regs7() const
size_t regs7() const
{
return REGS7.extract_from<int>(tag);
return REGS7.extract_from<size_t>(tag);
}
int regs8() const
size_t regs8() const
{
return REGS8.extract_from<int>(tag);
return REGS8.extract_from<size_t>(tag);
}
int regs9() const
size_t regs9() const
{
return REGS9.extract_from<int>(tag);
return REGS9.extract_from<size_t>(tag);
}
int regs10() const
size_t regs10() const
{
return REGS10.extract_from<int>(tag);
return REGS10.extract_from<size_t>(tag);
}
int regs11() const
size_t regs11() const
{
return REGS11.extract_from<int>(tag);
return REGS11.extract_from<size_t>(tag);
}
int regs12() const
size_t regs12() const
{
return REGS12.extract_from<int>(tag);
return REGS12.extract_from<size_t>(tag);
}
int regs13() const
size_t regs13() const
{
return REGS13.extract_from<int>(tag);
return REGS13.extract_from<size_t>(tag);
}
int regs14() const
size_t regs14() const
{
return REGS14.extract_from<int>(tag);
return REGS14.extract_from<size_t>(tag);
}
int regs15() const
size_t regs15() const
{
return REGS15.extract_from<int>(tag);
return REGS15.extract_from<size_t>(tag);
}
size_t regs(const size_t descriptor_index) const
{
using RegisterDescriptor = size_t(Giftag::*)() const;
static const RegisterDescriptor register_descriptors[] = {
&Giftag::regs0, &Giftag::regs1, &Giftag::regs2, &Giftag::regs3,
&Giftag::regs4, &Giftag::regs5, &Giftag::regs6, &Giftag::regs7,
&Giftag::regs8, &Giftag::regs9, &Giftag::regs10, &Giftag::regs11,
&Giftag::regs12, &Giftag::regs13, &Giftag::regs14, &Giftag::regs15
};
auto fn = register_descriptors[descriptor_index];
return (this->*fn)();
}
private: