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) 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 (!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; ctrl.transfer_started = true;
handle_tag(Giftag(data)); handle_tag(Giftag(data));
} }
else 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) throw std::runtime_error("End of GS packet reached");
ctrl.transfer_started = false;
} }
} }
@ -89,13 +121,258 @@ void CGif::handle_tag(const Giftag tag)
auto& r = core->get_resources(); auto& r = core->get_resources();
auto& ctrl = r.ee.gif.ctrl; 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& r = core->get_resources();
auto& ctrl = r.ee.gif.ctrl; 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_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() : GifRegister_Ctrl::GifRegister_Ctrl() :
transfer_started(false), transfer_started(false),
transfer_data_target(0), tag(),
transfer_data_count(0), transfer_register_count(0),
transfer_end_of_packet(false) transfer_loop_count(0),
rgbaq_q(1.0f)
{ {
} }

View file

@ -6,6 +6,8 @@
#include "Common/Types/Bitfield.hpp" #include "Common/Types/Bitfield.hpp"
#include "Common/Types/Register/SizedWordRegister.hpp" #include "Common/Types/Register/SizedWordRegister.hpp"
#include "Resources/Ee/Gif/Giftag.hpp"
class GifRegister_Ctrl : public SizedWordRegister class GifRegister_Ctrl : public SizedWordRegister
{ {
public: public:
@ -14,17 +16,20 @@ public:
GifRegister_Ctrl(); GifRegister_Ctrl();
/// Indicates whether the GIF is currently processing a GS primitive /// Indicates whether the GIF is currently processing GS primitive
/// (excluding the tag). Reset upon finishing a GS primitive. /// data (otherwise read a tag). Reset upon finishing a GS primitive.
bool transfer_started; bool transfer_started;
/// Number of qwords total/left for the current GS primitive. /// Current transfer tag being processed.
/// Set by the tag read. Giftag tag;
size_t transfer_data_target;
size_t transfer_data_count;
/// End of GS packet indicator. Set by the tag read. /// Number of registers / loops processed for the current tag.
bool transfer_end_of_packet; 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: public:
template<class Archive> template<class Archive>
@ -33,9 +38,9 @@ public:
archive( archive(
cereal::base_class<SizedWordRegister>(this), cereal::base_class<SizedWordRegister>(this),
CEREAL_NVP(transfer_started), CEREAL_NVP(transfer_started),
CEREAL_NVP(transfer_data_target), CEREAL_NVP(tag),
CEREAL_NVP(transfer_data_count), CEREAL_NVP(transfer_register_count),
CEREAL_NVP(transfer_end_of_packet) CEREAL_NVP(transfer_loop_count),
); );
} }
}; };

View file

@ -39,14 +39,16 @@ public:
Disabled // Disabled means the same operation mode as Image. Disabled // Disabled means the same operation mode as Image.
}; };
Giftag() = default;
Giftag(const uqword tag) : Giftag(const uqword tag) :
tag(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 bool eop() const
@ -59,6 +61,12 @@ public:
return EOP.extract_from<int>(tag) > 0; 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 DataFormat flg() const
{ {
switch (FLG.extract_from<int>(tag)) 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"); throw std::runtime_error("Unknown nreg value");
return (nreg == 0) ? 16 : nreg; 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: private: