Implement reglist and image mode of GIF.

This commit is contained in:
Marco Satti 2018-09-16 14:16:14 +08:00
parent 48c4efcce6
commit e10163634d
3 changed files with 250 additions and 62 deletions

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

@ -1,3 +1,5 @@
#include <algorithm>
#include "Controller/Ee/Gif/CGif.hpp"
#include "Core.hpp"
@ -51,6 +53,8 @@ int CGif::time_step(const int ticks_available)
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.
@ -58,6 +62,7 @@ int CGif::time_step(const int ticks_available)
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))
@ -67,7 +72,8 @@ int CGif::time_step(const int ticks_available)
fifo->read(reinterpret_cast<ubyte*>(&data), NUMBER_BYTES_IN_QWORD);
ctrl.transfer_started = true;
handle_tag(Giftag(data));
cycles_consumed = handle_tag(Giftag(data));
}
else
{
@ -81,17 +87,21 @@ int CGif::time_step(const int ticks_available)
uqword data;
fifo->read(reinterpret_cast<ubyte*>(&data), NUMBER_BYTES_IN_QWORD);
handle_data_packed(data);
cycles_consumed = handle_data_packed(data);
}
case Giftag::DataFormat::Reglist:
{
if (!fifo->has_read_available(NUMBER_BYTES_IN_DWORD))
// 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_DWORD);
fifo->read(reinterpret_cast<ubyte*>(&data), NUMBER_BYTES_IN_QWORD);
handle_data_packed(data);
cycles_consumed = handle_data_reglist(data);
}
case Giftag::DataFormat::Image:
case Giftag::DataFormat::Disabled:
@ -102,21 +112,30 @@ int CGif::time_step(const int ticks_available)
uqword data;
fifo->read(reinterpret_cast<ubyte*>(&data), NUMBER_BYTES_IN_QWORD);
handle_data_image(data);
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");
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;
}
return 1;
// At least 1 cycle is consumed always if no paths had data available for processing.
return std::max(cycles_consumed, 1);
}
void CGif::handle_tag(const Giftag tag)
int CGif::handle_tag(const Giftag tag)
{
auto& r = core->get_resources();
auto& ctrl = r.ee.gif.ctrl;
@ -146,9 +165,14 @@ void CGif::handle_tag(const Giftag tag)
}
}
}
// 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;
}
void CGif::handle_data_packed(const uqword data)
int CGif::handle_data_packed(const uqword data)
{
auto& r = core->get_resources();
auto& ctrl = r.ee.gif.ctrl;
@ -169,6 +193,7 @@ void CGif::handle_data_packed(const uqword data)
//auto& prim = r.gs.prim;
//prim.write_udword(prim_value);
break;
}
case 0x1:
{
@ -190,6 +215,7 @@ void CGif::handle_data_packed(const uqword data)
//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:
{
@ -208,6 +234,7 @@ void CGif::handle_data_packed(const uqword 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:
{
@ -221,6 +248,7 @@ void CGif::handle_data_packed(const uqword 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:
{
@ -242,10 +270,11 @@ void CGif::handle_data_packed(const uqword data)
//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
// XYZ2/3
constexpr Bitfield X = Bitfield(0, 16);
constexpr Bitfield Y = Bitfield(32, 16);
constexpr Bitfield Z = Bitfield(64, 32);
@ -260,30 +289,35 @@ void CGif::handle_data_packed(const uqword data)
//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:
{
@ -296,6 +330,7 @@ void CGif::handle_data_packed(const uqword data)
//auto& fog = r.gs.fog;
//fog.write_field(GsRegister_Fog::F, f_value);
break;
}
case 0xB:
{
@ -307,12 +342,14 @@ void CGif::handle_data_packed(const uqword data)
// 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:
{
@ -323,10 +360,12 @@ void CGif::handle_data_packed(const uqword data)
udword data_value = data.lo;
//r.gs.bus.write_udword(BusContext::Gif, addr_value, data_value);
break;
}
case 0xF:
{
// NOP
break;
}
default:
{
@ -343,36 +382,174 @@ void CGif::handle_data_packed(const uqword data)
if (ctrl.transfer_loop_count == ctrl.tag.nloop())
ctrl.transfer_started = false;
return 1;
}
void CGif::handle_data_reglist(const udword data)
int CGif::handle_data_reglist(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;
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;
}
void CGif::handle_data_image(const uqword data)
int 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())
//auto& hwreg = r.gs.hwreg;
udword datas[] = { data.lo, data.hi };
for (auto& data : datas)
{
ctrl.transfer_register_count = 0;
ctrl.transfer_loop_count += 1;
// 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,5 +1,7 @@
#pragma once
#include <utility>
#include "Common/Types/Primitive.hpp"
#include "Controller/CController.hpp"
#include "Resources/Ee/Gif/Giftag.hpp"
@ -17,11 +19,20 @@ public:
int time_step(const int ticks_available);
void handle_tag(const Giftag tag);
/// 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);
void handle_data_packed(const uqword data);
int handle_data_packed(const uqword data);
void handle_data_reglist(const udword 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);
void handle_data_image(const uqword data);
int handle_data_image(const uqword data);
std::pair<size_t, SizedDwordRegister*> get_register_descriptor() const;
};