Merge marco9999/gif-impl.

This commit is contained in:
hch12907 2018-10-12 18:44:34 +08:00
commit 62bb9925ab
12 changed files with 947 additions and 66 deletions

View file

@ -161,6 +161,9 @@ set(COMMON_SRC_FILES
"${CMAKE_SOURCE_DIR}/liborbum/src/Resources/Ee/EeRegisters.hpp"
"${CMAKE_SOURCE_DIR}/liborbum/src/Resources/Ee/Gif/RGif.cpp"
"${CMAKE_SOURCE_DIR}/liborbum/src/Resources/Ee/Gif/RGif.hpp"
"${CMAKE_SOURCE_DIR}/liborbum/src/Resources/Ee/Gif/Giftag.hpp"
"${CMAKE_SOURCE_DIR}/liborbum/src/Resources/Ee/Gif/GifRegisters.cpp"
"${CMAKE_SOURCE_DIR}/liborbum/src/Resources/Ee/Gif/GifRegisters.hpp"
"${CMAKE_SOURCE_DIR}/liborbum/src/Resources/Ee/Intc/EeIntcConstants.hpp"
"${CMAKE_SOURCE_DIR}/liborbum/src/Resources/Ee/Intc/EeIntcRegisters.cpp"
"${CMAKE_SOURCE_DIR}/liborbum/src/Resources/Ee/Intc/EeIntcRegisters.hpp"

View file

@ -2,6 +2,8 @@
#include <stdexcept>
#include "Common/Types/Primitive.hpp"
/// Describes a bitfield within a primitive value.
struct Bitfield
{
@ -50,6 +52,35 @@ struct Bitfield
return cleaned_value | cleaned_field_value;
}
template <typename To, typename From>
constexpr To extract_from(const From value) const
{
return static_cast<To>((value & shifted_mask<From>()) >> start);
}
template <typename To, typename From>
constexpr To insert_into(const From value, const From field_value) const
{
From cleaned_value = value & (~shifted_mask<From>());
From cleaned_field_value = (field_value & unshifted_mask<From>()) << start;
return static_cast<To>(cleaned_value | cleaned_field_value);
}
/// qword template specialization.
template <typename To>
constexpr To extract_from(const uqword value) const
{
// Most (all?) bitfields within uqword types are aligned to 64 bit
// boundaries... But this should be easy to implement if needed.
if ((start < 64) && ((length + start) >= 64))
throw std::logic_error("Cannot extract bitfield over 64 bit boundary from a uqword [not implemented]");
if (start < 64)
return Bitfield(start, length).extract_from<To>(value.lo);
else
return Bitfield(start - 64, length).extract_from<To>(value.hi);
}
constexpr bool operator==(const Bitfield& rhs) const
{
return (start == rhs.start) && (length == rhs.length);
@ -62,4 +93,4 @@ struct Bitfield
int start;
int length;
};
};

View file

@ -119,36 +119,6 @@ public:
finished:; // Done.
}
/// Given the address properties, performs a lookup in the page
/// table and returns the mapped entry. On a nullptr object being
/// retrieved, a runtime_error is thrown (debug builds only).
const Page& get_page(const AddressTy address) const
{
const size_t vdn = get_vdn(address);
#if DEBUG_BYTEBUS_RUNTIME_LOOKUP_CHECKS
if (vdn >= table.size())
throw std::runtime_error(str(boost::format("ByteBus lookup: no directory exists, address = 0x%08X.") % address));
#endif
const auto& directory = table[vdn];
const size_t page_index = directory.page_mask.extract_from(address);
#if DEBUG_BYTEBUS_RUNTIME_LOOKUP_CHECKS
if (page_index >= directory.page_table.size())
throw std::runtime_error(str(boost::format("ByteBus lookup: no page exists (probably culled), address = 0x%08X.") % address));
#endif
const auto& page = directory.page_table[page_index];
#if DEBUG_BYTEBUS_RUNTIME_LOOKUP_CHECKS
if (page.object == nullptr)
throw std::runtime_error(str(boost::format("ByteBus lookup: nullptr object, address = 0x%08X.") % address));
#endif
return page;
}
/// Read or write to a mapped object.
ubyte read_ubyte(const BusContext context, const AddressTy address) const
{
@ -292,6 +262,36 @@ public:
}
private:
/// Given the address properties, performs a lookup in the page
/// table and returns the mapped entry. On a nullptr object being
/// retrieved, a runtime_error is thrown (debug builds only).
const Page& get_page(const AddressTy address) const
{
const size_t vdn = get_vdn(address);
#if DEBUG_BYTEBUS_RUNTIME_LOOKUP_CHECKS
if (vdn >= table.size())
throw std::runtime_error(str(boost::format("ByteBus lookup: no directory exists, address = 0x%08X.") % address));
#endif
const auto& directory = table[vdn];
const size_t page_index = directory.page_mask.extract_from(address);
#if DEBUG_BYTEBUS_RUNTIME_LOOKUP_CHECKS
if (page_index >= directory.page_table.size())
throw std::runtime_error(str(boost::format("ByteBus lookup: no page exists (probably culled), address = 0x%08X.") % address));
#endif
const auto& page = directory.page_table[page_index];
#if DEBUG_BYTEBUS_RUNTIME_LOOKUP_CHECKS
if (page.object == nullptr)
throw std::runtime_error(str(boost::format("ByteBus lookup: nullptr object, address = 0x%08X.") % address));
#endif
return page;
}
/// Returns the VDN (virtual directory number) for the address
/// given using this Bus' context.
size_t get_vdn(const AddressTy address) const

View file

@ -43,6 +43,29 @@ static_assert(sizeof(f32) * CHAR_BIT == 32, "f32 is not 32-bits long!");
/// TODO: Look into boost/multiprecision (uint128_t) for endianess and compiler ordering?
struct uqword
{
constexpr uqword() :
lo(0),
hi(0)
{
}
constexpr uqword(const udword ud) :
lo(ud),
hi(ud)
{
}
constexpr uqword(const udword lo, const udword hi) :
lo(lo),
hi(hi)
{
}
constexpr uqword(const uword uw0, const uword uw1, const uword uw2, const uword uw3) :
uw{uw0, uw1, uw2, uw3}
{
}
union {
struct
{
@ -56,31 +79,8 @@ struct uqword
ubyte ub[16];
};
uqword() :
lo(0),
hi(0)
{
}
uqword(const udword ud) :
lo(ud),
hi(ud)
{
}
uqword(const udword lo, const udword hi) :
lo(lo),
hi(hi)
{
}
uqword(const uword uw0, const uword uw1, const uword uw2, const uword uw3) :
uw{uw0, uw1, uw2, uw3}
{
}
template <class Archive>
void serialize(Archive& archive)
void serialize(Archive & archive)
{
archive(
CEREAL_NVP(hi),

View file

@ -1,3 +1,5 @@
#include <algorithm>
#include "Controller/Ee/Gif/CGif.hpp"
#include "Core.hpp"
@ -28,7 +30,6 @@ void CGif::handle_event(const ControllerEvent& event)
int CGif::time_to_ticks(const double time_us)
{
// TODO: find out for sure.
int ticks = static_cast<int>(time_us / 1.0e6 * Constants::EE::EEBUS_CLK_SPEED * core->get_options().system_bias_gif);
if (ticks < 10)
@ -46,6 +47,509 @@ int CGif::time_to_ticks(const double time_us)
int CGif::time_step(const int ticks_available)
{
// Not yet implemented.
return ticks_available;
}
auto& r = core->get_resources();
auto& ctrl = r.ee.gif.ctrl;
auto& fifo_gif_path1 = r.fifo_gif_path1;
auto& fifo_gif_path2 = r.fifo_gif_path2;
auto& fifo_gif_path3 = r.fifo_gif_path3;
int cycles_consumed = 0;
// Prioritise paths by 1 -> 2 -> 3.
// TODO: GIF code does not do path arbitration currently.
// See EE Users Manual page 149.
DmaFifoQueue<>* paths[3] = {&fifo_gif_path1, &fifo_gif_path2, &fifo_gif_path3};
for (auto& fifo : paths)
{
// A GIFtag is always read before processing data.
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;
cycles_consumed = handle_tag(Giftag(data));
}
else
{
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);
cycles_consumed = handle_data_packed(data);
}
case Giftag::DataFormat::Reglist:
{
// TODO: maybe a weird situation can occur where there is only
// 1 dword available which should be processed first before
// attempting processing of other paths... Probably should make
// this proper at some stage. Manual doesn't really say what to do...
if (!fifo->has_read_available(NUMBER_BYTES_IN_QWORD))
continue;
uqword data;
fifo->read(reinterpret_cast<ubyte*>(&data), NUMBER_BYTES_IN_QWORD);
cycles_consumed = handle_data_reglist(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);
cycles_consumed = handle_data_image(data);
}
default:
{
throw std::runtime_error("Unknown GIF data processing method");
}
}
}
if (ctrl.tag.eop())
{
throw std::runtime_error("End of GS packet reached - what do we do?");
}
// Do not process other paths if at least one path was successfully processed.
if (cycles_consumed)
break;
}
// At least 1 cycle is consumed always if no paths had data available for processing.
return std::max(cycles_consumed, 1);
}
int CGif::handle_tag(const Giftag tag)
{
auto& r = core->get_resources();
auto& ctrl = r.ee.gif.ctrl;
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);
}
}
}
// 1 cycle consumed for the tag, and 1 cycle for the handling of the PRIM data
// (always done even if it's not used). See the descriptions of the transfer
// modes in the EE Users Manual page 153, 159, 160.
return 2;
}
int 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);
break;
}
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);
break;
}
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);
break;
}
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);
break;
}
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);
break;
}
case 0x5:
{
// XYZ2/3
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);
break;
}
case 0x6:
{
// TEX0_1
//auto& tex0_1 = r.gs.tex0_1;
//tex0_1.write_udword(data.lo);
break;
}
case 0x7:
{
// TEX0_2
//auto& tex0_2 = r.gs.tex0_2;
//tex0_2.write_udword(data.lo);
break;
}
case 0x8:
{
// CLAMP_1
//auto& clamp_1 = r.gs.clamp_1;
//clamp_1.write_udword(data.lo);
break;
}
case 0x9:
{
// CLAMP_2
//auto& clamp_2 = r.gs.clamp_2;
//clamp_2.write_udword(data.lo);
break;
}
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);
break;
}
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);
break;
}
case 0xD:
{
// XYZ3
//auto& xyz3 = r.gs.xyz3;
//xyz3.write_udword(data.lo);
break;
}
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);
break;
}
case 0xF:
{
// NOP
break;
}
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;
return 1;
}
int CGif::handle_data_reglist(const uqword data)
{
auto& r = core->get_resources();
auto& ctrl = r.ee.gif.ctrl;
udword datas[] = { data.lo, data.hi };
for (auto& data : datas)
{
// Get the register descirptor.
size_t register_descirptor = ctrl.tag.regs(ctrl.transfer_register_count);
// Write data directly to the GS register.
// See EE Users Manual page 159 onwards for processing details.
switch (register_descirptor)
{
case 0x0:
{
// PRIM
//auto& prim = r.gs.prim;
//prim.write_udword(data);
break;
}
case 0x1:
{
// RGBAQ
//auto& rgbaq = r.gs.rgbaq;
//rgbaq.write_udword(data);
break;
}
case 0x2:
{
// ST
//auto& st = r.gs.st;
//st.write_udword(data);
break;
}
case 0x3:
{
// UV
//auto& uv = r.gs.uv;
//uv.write_udword(data);
break;
}
case 0x4:
{
// XYZF2
//auto& xyzf2 = r.gs.xyzf2;
//xyzf2.write_udword(data);
break;
}
case 0x5:
{
// XYZ2
//auto& xyz2 = r.gs.xyz2;
//xyz2.write_udword(data);
break;
}
case 0x6:
{
// TEX0_1
//auto& tex0_1 = r.gs.tex0_1;
//tex0_1.write_udword(data);
break;
}
case 0x7:
{
// TEX0_2
//auto& tex0_2 = r.gs.tex0_2;
//tex0_2.write_udword(data);
break;
}
case 0x8:
{
// CLAMP_1
//auto& clamp_1 = r.gs.clamp_1;
//clamp_1.write_udword(data);
break;
}
case 0x9:
{
// CLAMP_2
//auto& clamp_2 = r.gs.clamp_2;
//clamp_2.write_udword(data);
break;
}
case 0xA:
{
// FOG
//auto& fog = r.gs.fog;
//fog.write_udword(data);
break;
}
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);
break;
}
case 0xD:
{
// XYZ3
//auto& xyz3 = r.gs.xyz3;
//xyz3.write_udword(data);
break;
}
case 0xE:
{
// A+D (packed address + data)
// No-op for REGLIST mode. See EE Users Manual page 159.
break;
}
case 0xF:
{
// NOP
break;
}
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;
break;
}
}
// Although not stated, I'm gussing the GIF consumes an extra cycle even when
// NREGS is odd (ie: upper 64-bits of last qword of data discarded).
return 2;
}
int CGif::handle_data_image(const uqword data)
{
auto& r = core->get_resources();
auto& ctrl = r.ee.gif.ctrl;
//auto& hwreg = r.gs.hwreg;
udword datas[] = { data.lo, data.hi };
for (auto& data : datas)
{
// Data is output sequentially to the HWREG transfer register of the GS.
// See EE Users manual page 160.
//hwreg.write_udword(data);
}
ctrl.transfer_loop_count += 1;
if (ctrl.transfer_loop_count == ctrl.tag.nloop())
ctrl.transfer_started = false;
return 1;
}

View file

@ -1,7 +1,12 @@
#pragma once
#include "Controller/CController.hpp"
#include <utility>
#include "Common/Types/Primitive.hpp"
#include "Controller/CController.hpp"
#include "Resources/Ee/Gif/Giftag.hpp"
/// GIF interface, controls data between the EE (EE Core, VPU1) to the GS.
class CGif : public CController
{
public:
@ -13,4 +18,21 @@ public:
int time_to_ticks(const double time_us);
int time_step(const int ticks_available);
/// Handle the initial processing of a GIFtag. For tag details, see EE Users
/// manual page 151.
/// Note: consumes 2 cycles when the PRE bit is set and FLG is set to packed
/// mode. (PRE handling is considered a single cycle.) See EE Users manual
/// page 153 about this.
int handle_tag(const Giftag tag);
int handle_data_packed(const uqword data);
/// Handle a GS primitive using the REGLIST processing method.
/// Note: consumes 2 cycles (processes both 64-bit data strings at the same time).
int handle_data_reglist(const uqword data);
int handle_data_image(const uqword data);
std::pair<size_t, SizedDwordRegister*> get_register_descriptor() const;
};

View file

@ -0,0 +1,10 @@
#include "Resources/Ee/Gif/GifRegisters.hpp"
GifRegister_Ctrl::GifRegister_Ctrl() :
transfer_started(false),
tag(),
transfer_register_count(0),
transfer_loop_count(0),
rgbaq_q(1.0f)
{
}

View file

@ -0,0 +1,113 @@
#pragma once
#include <cereal/cereal.hpp>
#include <cereal/types/polymorphic.hpp>
#include "Common/Types/Bitfield.hpp"
#include "Common/Types/Register/SizedWordRegister.hpp"
#include "Resources/Ee/Gif/Giftag.hpp"
class GifRegister_Ctrl : public SizedWordRegister
{
public:
static constexpr Bitfield RST = Bitfield(0, 1);
static constexpr Bitfield PSE = Bitfield(3, 1);
GifRegister_Ctrl();
/// Indicates whether the GIF is currently processing GS primitive
/// data (otherwise read a tag). Reset upon finishing a GS primitive.
bool transfer_started;
/// Current transfer tag being processed.
Giftag tag;
/// 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>
void serialize(Archive & archive)
{
archive(
cereal::base_class<SizedWordRegister>(this),
CEREAL_NVP(transfer_started),
CEREAL_NVP(tag),
CEREAL_NVP(transfer_register_count),
CEREAL_NVP(transfer_loop_count),
);
}
};
class GifRegister_Mode : public SizedWordRegister
{
public:
static constexpr Bitfield M3R = Bitfield(0, 1);
static constexpr Bitfield IMT = Bitfield(2, 1);
};
class GifRegister_Stat : public SizedWordRegister
{
public:
static constexpr Bitfield M3R = Bitfield(0, 1);
static constexpr Bitfield M3P = Bitfield(1, 1);
static constexpr Bitfield IMT = Bitfield(2, 1);
static constexpr Bitfield PSE = Bitfield(3, 1);
static constexpr Bitfield IP3 = Bitfield(5, 1);
static constexpr Bitfield P3Q = Bitfield(6, 1);
static constexpr Bitfield P2Q = Bitfield(7, 1);
static constexpr Bitfield P1Q = Bitfield(8, 1);
static constexpr Bitfield OPH = Bitfield(9, 1);
static constexpr Bitfield APATH = Bitfield(10, 2);
static constexpr Bitfield DIR = Bitfield(12, 1);
static constexpr Bitfield FQC = Bitfield(24, 5);
};
class GifRegister_Tag0 : public SizedWordRegister
{
public:
static constexpr Bitfield NLOOP = Bitfield(0, 15);
static constexpr Bitfield EOP = Bitfield(15, 1);
static constexpr Bitfield TAG = Bitfield(16, 16);
};
class GifRegister_Tag1 : public SizedWordRegister
{
public:
static constexpr Bitfield TAG = Bitfield(0, 14);
static constexpr Bitfield PRE = Bitfield(14, 1);
static constexpr Bitfield PRIM = Bitfield(15, 11);
static constexpr Bitfield FLG = Bitfield(26, 2);
static constexpr Bitfield NREG = Bitfield(28, 4);
};
class GifRegister_Tag2 : public SizedWordRegister
{
public:
static constexpr Bitfield TAG = Bitfield(0, 32);
};
class GifRegister_Tag3 : public SizedWordRegister
{
public:
static constexpr Bitfield TAG = Bitfield(0, 32);
};
class GifRegister_Cnt : public SizedWordRegister
{
public:
static constexpr Bitfield P3CNT = Bitfield(0, 15);
};
class GifRegister_P3tag : public SizedWordRegister
{
public:
static constexpr Bitfield LOOPCNT = Bitfield(0, 15);
static constexpr Bitfield EOP = Bitfield(15, 1);
};

View file

@ -0,0 +1,193 @@
#pragma once
#include <stdexcept>
#include "Common/Types/Bitfield.hpp"
#include "Common/Types/Primitive.hpp"
class Giftag
{
public:
static constexpr Bitfield NLOOP = Bitfield(0, 15);
static constexpr Bitfield EOP = Bitfield(15, 1);
static constexpr Bitfield PRE = Bitfield(46, 1);
static constexpr Bitfield PRIM = Bitfield(47, 11);
static constexpr Bitfield FLG = Bitfield(58, 2);
static constexpr Bitfield NREG = Bitfield(60, 4);
static constexpr Bitfield REGS0 = Bitfield(64, 4);
static constexpr Bitfield REGS1 = Bitfield(68, 4);
static constexpr Bitfield REGS2 = Bitfield(72, 4);
static constexpr Bitfield REGS3 = Bitfield(76, 4);
static constexpr Bitfield REGS4 = Bitfield(80, 4);
static constexpr Bitfield REGS5 = Bitfield(84, 4);
static constexpr Bitfield REGS6 = Bitfield(88, 4);
static constexpr Bitfield REGS7 = Bitfield(92, 4);
static constexpr Bitfield REGS8 = Bitfield(96, 4);
static constexpr Bitfield REGS9 = Bitfield(100, 4);
static constexpr Bitfield REGS10 = Bitfield(104, 4);
static constexpr Bitfield REGS11 = Bitfield(108, 4);
static constexpr Bitfield REGS12 = Bitfield(112, 4);
static constexpr Bitfield REGS13 = Bitfield(116, 4);
static constexpr Bitfield REGS14 = Bitfield(120, 4);
static constexpr Bitfield REGS15 = Bitfield(124, 4);
enum DataFormat
{
Packed,
Reglist,
Image,
Disabled // Disabled means the same operation mode as Image.
};
Giftag() = default;
Giftag(const uqword tag) :
tag(tag)
{
}
size_t nloop() const
{
return NLOOP.extract_from<size_t>(tag);
}
bool eop() const
{
return EOP.extract_from<int>(tag) > 0;
}
bool pre() const
{
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))
{
case 0:
return Packed;
case 1:
return Reglist;
case 2:
return Image;
case 3:
return Disabled;
default:
throw std::runtime_error("Unknown Giftag data format");
}
}
size_t nreg() const
{
size_t nreg = NREG.extract_from<size_t>(tag);
if (nreg >= 16)
throw std::runtime_error("Unknown nreg value");
return (nreg == 0) ? 16 : nreg;
}
size_t regs0() const
{
return REGS0.extract_from<size_t>(tag);
}
size_t regs1() const
{
return REGS1.extract_from<size_t>(tag);
}
size_t regs2() const
{
return REGS2.extract_from<size_t>(tag);
}
size_t regs3() const
{
return REGS3.extract_from<size_t>(tag);
}
size_t regs4() const
{
return REGS4.extract_from<size_t>(tag);
}
size_t regs5() const
{
return REGS5.extract_from<size_t>(tag);
}
size_t regs6() const
{
return REGS6.extract_from<size_t>(tag);
}
size_t regs7() const
{
return REGS7.extract_from<size_t>(tag);
}
size_t regs8() const
{
return REGS8.extract_from<size_t>(tag);
}
size_t regs9() const
{
return REGS9.extract_from<size_t>(tag);
}
size_t regs10() const
{
return REGS10.extract_from<size_t>(tag);
}
size_t regs11() const
{
return REGS11.extract_from<size_t>(tag);
}
size_t regs12() const
{
return REGS12.extract_from<size_t>(tag);
}
size_t regs13() const
{
return REGS13.extract_from<size_t>(tag);
}
size_t regs14() const
{
return REGS14.extract_from<size_t>(tag);
}
size_t regs15() const
{
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:
uqword tag;
};

View file

@ -4,6 +4,7 @@
#include "Common/Types/Memory/ArrayByteMemory.hpp"
#include "Common/Types/Register/SizedWordRegister.hpp"
#include "Resources/Ee/Gif/GifRegisters.hpp"
class RGif
{
@ -11,7 +12,7 @@ public:
RGif();
/// GIF memory mapped registers. See page 21 of EE Users Manual.
SizedWordRegister ctrl;
GifRegister_Ctrl ctrl;
SizedWordRegister mode;
SizedWordRegister stat;
ArrayByteMemory memory_3030;

View file

@ -119,7 +119,7 @@ void initialise_ee_dmac(RResources* r)
// Init DMA FIFO queues.
r->ee.dmac.channels[0].dma_fifo_queue = &r->fifo_vif0;
r->ee.dmac.channels[1].dma_fifo_queue = &r->fifo_vif1;
r->ee.dmac.channels[2].dma_fifo_queue = &r->fifo_gif;
r->ee.dmac.channels[2].dma_fifo_queue = &r->fifo_gif_path3;
r->ee.dmac.channels[3].dma_fifo_queue = &r->fifo_fromipu;
r->ee.dmac.channels[4].dma_fifo_queue = &r->fifo_toipu;
r->ee.dmac.channels[5].dma_fifo_queue = &r->fifo_sif0;
@ -419,7 +419,7 @@ void initialise_ee(RResources* r)
// FIFO Registers.
r->ee.bus.map(0x10004000, &r->fifo_vif0);
r->ee.bus.map(0x10005000, &r->fifo_vif1);
r->ee.bus.map(0x10006000, &r->fifo_gif);
r->ee.bus.map(0x10006000, &r->fifo_gif_path3);
r->ee.bus.map(0x10007000, &r->fifo_fromipu);
r->ee.bus.map(0x10007010, &r->fifo_toipu);

View file

@ -54,10 +54,10 @@ public:
SbusRegister_F300 sbus_f300; // TODO: related to psx sif2/gpu? Investigate (see PCSX2).
SizedWordRegister sbus_f380;
/// FIFO Queue registers, attached to both the EE and IOP DMAC channels.
/// DMA FIFO queues, attached to both the EE and IOP DMAC channels.
DmaFifoQueue<> fifo_vif0;
DmaFifoQueue<> fifo_vif1;
DmaFifoQueue<> fifo_gif;
DmaFifoQueue<> fifo_gif_path3;
DmaFifoQueue<> fifo_fromipu;
DmaFifoQueue<> fifo_toipu;
DmaFifoQueue<> fifo_sif0;
@ -74,6 +74,10 @@ public:
DmaFifoQueue<> fifo_fromsio2;
DmaFifoQueue<> fifo_tosio2;
// GIF FIFO queues (alternate paths).
DmaFifoQueue<> fifo_gif_path1;
DmaFifoQueue<> fifo_gif_path2;
public:
template <class Archive>
void serialize(Archive& archive)
@ -99,7 +103,7 @@ public:
CEREAL_NVP(sbus_f380),
CEREAL_NVP(fifo_vif0),
CEREAL_NVP(fifo_vif1),
CEREAL_NVP(fifo_gif),
CEREAL_NVP(fifo_gif_path3),
CEREAL_NVP(fifo_fromipu),
CEREAL_NVP(fifo_toipu),
CEREAL_NVP(fifo_sif0),