2015-02-15 22:13:32 -05:00
|
|
|
#include "VuAssembler.h"
|
2020-02-26 20:09:18 -05:00
|
|
|
#include <cassert>
|
2020-05-25 12:51:01 -04:00
|
|
|
#include <stdexcept>
|
|
|
|
|
|
|
|
#define BRANCH_MIN -1024
|
|
|
|
#define BRANCH_MAX 1023
|
2015-02-15 22:13:32 -05:00
|
|
|
|
|
|
|
CVuAssembler::CVuAssembler(uint32* ptr)
|
2018-04-30 21:01:23 +01:00
|
|
|
: m_ptr(ptr)
|
2020-05-25 12:51:01 -04:00
|
|
|
, m_startPtr(ptr)
|
2015-02-15 22:13:32 -05:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CVuAssembler::~CVuAssembler()
|
|
|
|
{
|
2020-05-25 12:51:01 -04:00
|
|
|
ResolveLabelReferences();
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int CVuAssembler::GetProgramSize() const
|
|
|
|
{
|
|
|
|
auto wordSize = static_cast<unsigned int>(m_ptr - m_startPtr);
|
|
|
|
assert((wordSize & 1) == 0);
|
|
|
|
return wordSize / 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
CVuAssembler::LABEL CVuAssembler::CreateLabel()
|
|
|
|
{
|
|
|
|
return m_nextLabelId++;
|
|
|
|
}
|
|
|
|
|
2020-05-25 16:25:52 -04:00
|
|
|
void CVuAssembler::MarkLabel(LABEL label)
|
2020-05-25 12:51:01 -04:00
|
|
|
{
|
|
|
|
m_labels[label] = GetProgramSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CVuAssembler::CreateLabelReference(LABEL label)
|
|
|
|
{
|
|
|
|
LABELREF reference;
|
|
|
|
reference.address = GetProgramSize();
|
|
|
|
m_labelReferences.insert(LabelReferenceMapType::value_type(label, reference));
|
|
|
|
}
|
|
|
|
|
|
|
|
void CVuAssembler::ResolveLabelReferences()
|
|
|
|
{
|
|
|
|
for(const auto& labelRef : m_labelReferences)
|
|
|
|
{
|
|
|
|
auto label(m_labels.find(labelRef.first));
|
|
|
|
if(label == m_labels.end())
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Invalid label.");
|
|
|
|
}
|
|
|
|
size_t referencePos = labelRef.second.address;
|
|
|
|
size_t labelPos = label->second;
|
|
|
|
int offset = static_cast<int>(labelPos - referencePos - 1);
|
|
|
|
if(offset > BRANCH_MAX || offset < BRANCH_MIN)
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Jump length too long.");
|
|
|
|
}
|
|
|
|
uint32& instruction = m_startPtr[referencePos * 2];
|
|
|
|
instruction &= 0xFFFFF800;
|
|
|
|
instruction |= static_cast<uint32>(offset & 0x7FF);
|
|
|
|
}
|
|
|
|
m_labelReferences.clear();
|
2015-02-15 22:13:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void CVuAssembler::Write(uint32 upperOp, uint32 lowerOp)
|
|
|
|
{
|
|
|
|
m_ptr[0] = lowerOp;
|
|
|
|
m_ptr[1] = upperOp;
|
|
|
|
m_ptr += 2;
|
|
|
|
}
|
|
|
|
|
2020-05-25 12:51:01 -04:00
|
|
|
void CVuAssembler::Write(uint32 upperOp, BRANCHOP lowerOp)
|
|
|
|
{
|
|
|
|
CreateLabelReference(lowerOp.label);
|
|
|
|
m_ptr[0] = lowerOp.op;
|
|
|
|
m_ptr[1] = upperOp;
|
|
|
|
m_ptr += 2;
|
|
|
|
}
|
|
|
|
|
2015-02-15 22:13:32 -05:00
|
|
|
//---------------------------------------------------------------------------------
|
|
|
|
//UPPER OPs
|
|
|
|
//---------------------------------------------------------------------------------
|
|
|
|
|
2020-06-01 17:42:26 -04:00
|
|
|
uint32 CVuAssembler::Upper::ADDbc(DEST dest, VF_REGISTER fd, VF_REGISTER fs, VF_REGISTER ft, BROADCAST bc)
|
|
|
|
{
|
|
|
|
uint32 result = 0x00000000;
|
|
|
|
result |= bc;
|
|
|
|
result |= (fd << 6);
|
|
|
|
result |= (fs << 11);
|
|
|
|
result |= (ft << 16);
|
|
|
|
result |= (dest << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-04-25 22:16:45 -04:00
|
|
|
uint32 CVuAssembler::Upper::ADDi(DEST dest, VF_REGISTER fd, VF_REGISTER fs)
|
|
|
|
{
|
|
|
|
uint32 result = 0x00000022;
|
2018-04-30 21:01:23 +01:00
|
|
|
result |= (fd << 6);
|
2015-04-25 22:16:45 -04:00
|
|
|
result |= (fs << 11);
|
|
|
|
result |= (dest << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-02-26 20:09:18 -05:00
|
|
|
uint32 CVuAssembler::Upper::CLIP(VF_REGISTER fs, VF_REGISTER ft)
|
|
|
|
{
|
|
|
|
uint32 result = 0x01E001FF;
|
|
|
|
result |= (fs << 11);
|
|
|
|
result |= (ft << 16);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CVuAssembler::Upper::FTOI4(DEST dest, VF_REGISTER ft, VF_REGISTER fs)
|
|
|
|
{
|
|
|
|
uint32 result = 0x0000017D;
|
|
|
|
result |= (fs << 11);
|
|
|
|
result |= (ft << 16);
|
|
|
|
result |= (dest << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-02-15 22:13:32 -05:00
|
|
|
uint32 CVuAssembler::Upper::ITOF0(DEST dest, VF_REGISTER ft, VF_REGISTER fs)
|
|
|
|
{
|
|
|
|
uint32 result = 0x0000013C;
|
|
|
|
result |= (fs << 11);
|
|
|
|
result |= (ft << 16);
|
|
|
|
result |= (dest << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-02-26 20:09:18 -05:00
|
|
|
uint32 CVuAssembler::Upper::ITOF12(DEST dest, VF_REGISTER ft, VF_REGISTER fs)
|
|
|
|
{
|
|
|
|
uint32 result = 0x0000013E;
|
|
|
|
result |= (fs << 11);
|
|
|
|
result |= (ft << 16);
|
|
|
|
result |= (dest << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-02-15 22:13:32 -05:00
|
|
|
uint32 CVuAssembler::Upper::MADDbc(DEST dest, VF_REGISTER fd, VF_REGISTER fs, VF_REGISTER ft, BROADCAST bc)
|
|
|
|
{
|
|
|
|
uint32 result = 0x00000008;
|
|
|
|
result |= bc;
|
2018-04-30 21:01:23 +01:00
|
|
|
result |= (fd << 6);
|
2015-02-15 22:13:32 -05:00
|
|
|
result |= (fs << 11);
|
|
|
|
result |= (ft << 16);
|
|
|
|
result |= (dest << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-02-16 01:07:17 -05:00
|
|
|
uint32 CVuAssembler::Upper::MADDAbc(DEST dest, VF_REGISTER fs, VF_REGISTER ft, BROADCAST bc)
|
|
|
|
{
|
|
|
|
uint32 result = 0x000000BC;
|
|
|
|
result |= bc;
|
|
|
|
result |= (fs << 11);
|
|
|
|
result |= (ft << 16);
|
|
|
|
result |= (dest << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-04-25 22:16:45 -04:00
|
|
|
uint32 CVuAssembler::Upper::MULi(DEST dest, VF_REGISTER fd, VF_REGISTER fs)
|
|
|
|
{
|
|
|
|
uint32 result = 0x0000001E;
|
2018-04-30 21:01:23 +01:00
|
|
|
result |= (fd << 6);
|
2015-04-25 22:16:45 -04:00
|
|
|
result |= (fs << 11);
|
|
|
|
result |= (dest << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-02-24 12:54:17 -05:00
|
|
|
uint32 CVuAssembler::Upper::MULq(DEST dest, VF_REGISTER fd, VF_REGISTER fs)
|
|
|
|
{
|
|
|
|
uint32 result = 0x0000001C;
|
|
|
|
result |= (fd << 6);
|
|
|
|
result |= (fs << 11);
|
|
|
|
result |= (dest << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-02-15 22:13:32 -05:00
|
|
|
uint32 CVuAssembler::Upper::MULAbc(DEST dest, VF_REGISTER fs, VF_REGISTER ft, BROADCAST bc)
|
|
|
|
{
|
|
|
|
uint32 result = 0x000001BC;
|
|
|
|
result |= bc;
|
|
|
|
result |= (fs << 11);
|
|
|
|
result |= (ft << 16);
|
|
|
|
result |= (dest << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-04-14 15:44:05 -04:00
|
|
|
uint32 CVuAssembler::Upper::MAX(DEST dest, VF_REGISTER fd, VF_REGISTER fs, VF_REGISTER ft)
|
|
|
|
{
|
|
|
|
uint32 result = 0x0000002B;
|
|
|
|
result |= (fd << 6);
|
|
|
|
result |= (fs << 11);
|
|
|
|
result |= (ft << 16);
|
|
|
|
result |= (dest << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2025-03-10 14:27:40 -04:00
|
|
|
uint32 CVuAssembler::Upper::MAXbc(DEST dest, VF_REGISTER fd, VF_REGISTER fs, VF_REGISTER ft, BROADCAST bc)
|
|
|
|
{
|
|
|
|
uint32 result = 0x00000010;
|
|
|
|
result |= bc;
|
|
|
|
result |= (fd << 6);
|
|
|
|
result |= (fs << 11);
|
|
|
|
result |= (ft << 16);
|
|
|
|
result |= (dest << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-04-11 15:11:43 -04:00
|
|
|
uint32 CVuAssembler::Upper::MINI(DEST dest, VF_REGISTER fd, VF_REGISTER fs, VF_REGISTER ft)
|
|
|
|
{
|
|
|
|
uint32 result = 0x0000002F;
|
|
|
|
result |= (fd << 6);
|
|
|
|
result |= (fs << 11);
|
|
|
|
result |= (ft << 16);
|
|
|
|
result |= (dest << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-02-15 22:13:32 -05:00
|
|
|
uint32 CVuAssembler::Upper::NOP()
|
|
|
|
{
|
|
|
|
return 0x000002FF;
|
|
|
|
}
|
|
|
|
|
2015-02-16 01:07:17 -05:00
|
|
|
uint32 CVuAssembler::Upper::OPMULA(VF_REGISTER fs, VF_REGISTER ft)
|
|
|
|
{
|
|
|
|
uint32 result = 0x01C002FE;
|
|
|
|
result |= (fs << 11);
|
|
|
|
result |= (ft << 16);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CVuAssembler::Upper::OPMSUB(VF_REGISTER fd, VF_REGISTER fs, VF_REGISTER ft)
|
|
|
|
{
|
|
|
|
uint32 result = 0x01C0002E;
|
2018-04-30 21:01:23 +01:00
|
|
|
result |= (fd << 6);
|
2015-02-16 01:07:17 -05:00
|
|
|
result |= (fs << 11);
|
|
|
|
result |= (ft << 16);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-06-01 17:42:26 -04:00
|
|
|
uint32 CVuAssembler::Upper::SUB(DEST dest, VF_REGISTER fd, VF_REGISTER fs, VF_REGISTER ft)
|
|
|
|
{
|
|
|
|
uint32 result = 0x0000002C;
|
|
|
|
result |= (fd << 6);
|
|
|
|
result |= (fs << 11);
|
|
|
|
result |= (ft << 16);
|
|
|
|
result |= (dest << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-02-15 22:13:32 -05:00
|
|
|
uint32 CVuAssembler::Upper::SUBbc(DEST dest, VF_REGISTER fd, VF_REGISTER fs, VF_REGISTER ft, BROADCAST bc)
|
|
|
|
{
|
|
|
|
uint32 result = 0x00000004;
|
|
|
|
result |= bc;
|
2018-04-30 21:01:23 +01:00
|
|
|
result |= (fd << 6);
|
2015-02-15 22:13:32 -05:00
|
|
|
result |= (fs << 11);
|
|
|
|
result |= (ft << 16);
|
|
|
|
result |= (dest << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------
|
|
|
|
//LOWER OPs
|
|
|
|
//---------------------------------------------------------------------------------
|
|
|
|
|
2020-05-25 12:51:01 -04:00
|
|
|
CVuAssembler::BRANCHOP CVuAssembler::Lower::B(LABEL label)
|
|
|
|
{
|
|
|
|
BRANCHOP result;
|
|
|
|
result.label = label;
|
|
|
|
result.op = 0x40000000;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-02-24 12:54:17 -05:00
|
|
|
uint32 CVuAssembler::Lower::DIV(VF_REGISTER fs, FVF fsf, VF_REGISTER ft, FVF ftf)
|
|
|
|
{
|
|
|
|
uint32 result = 0x800003BC;
|
|
|
|
result |= (ftf << 23);
|
|
|
|
result |= (fsf << 21);
|
|
|
|
result |= (ft << 16);
|
|
|
|
result |= (fs << 11);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-05-10 21:08:56 -04:00
|
|
|
uint32 CVuAssembler::Lower::ERLENG(VF_REGISTER fs)
|
|
|
|
{
|
|
|
|
uint32 result = 0x81C0073F;
|
|
|
|
result |= (fs << 11);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-02-26 20:09:18 -05:00
|
|
|
uint32 CVuAssembler::Lower::FCAND(uint32 imm)
|
|
|
|
{
|
|
|
|
uint32 result = 0x24000000;
|
|
|
|
result |= (imm & 0xFFFFFF);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-01-29 16:33:11 -05:00
|
|
|
uint32 CVuAssembler::Lower::FCGET(VI_REGISTER it)
|
|
|
|
{
|
|
|
|
uint32 result = 0x38000000;
|
|
|
|
result |= (it << 16);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-02-16 01:07:17 -05:00
|
|
|
uint32 CVuAssembler::Lower::FMAND(VI_REGISTER it, VI_REGISTER is)
|
|
|
|
{
|
|
|
|
uint32 result = 0x34000000;
|
|
|
|
result |= (it << 16);
|
|
|
|
result |= (is << 11);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-02-15 22:13:32 -05:00
|
|
|
uint32 CVuAssembler::Lower::FSAND(VI_REGISTER it, uint16 imm)
|
|
|
|
{
|
|
|
|
imm &= 0xFFF;
|
|
|
|
uint32 result = 0x2C000000;
|
|
|
|
result |= (it << 16);
|
|
|
|
result |= (imm & 0x7FF);
|
|
|
|
result |= (((imm & 0x800) >> 11) << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-02-26 20:09:18 -05:00
|
|
|
uint32 CVuAssembler::Lower::IADDIU(VI_REGISTER it, VI_REGISTER is, uint16 imm)
|
|
|
|
{
|
|
|
|
assert(imm <= 0x7FFF);
|
|
|
|
imm &= 0x7FFF;
|
|
|
|
uint32 result = 0x10000000;
|
|
|
|
result |= (it << 16);
|
|
|
|
result |= (is << 11);
|
|
|
|
result |= (imm & 0x7FF);
|
|
|
|
result |= (((imm & 0x7800) >> 11) << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-05-25 12:51:01 -04:00
|
|
|
CVuAssembler::BRANCHOP CVuAssembler::Lower::IBEQ(VI_REGISTER it, VI_REGISTER is, LABEL label)
|
|
|
|
{
|
|
|
|
BRANCHOP result;
|
|
|
|
result.label = label;
|
|
|
|
result.op = 0x50000000;
|
|
|
|
result.op |= (it << 16);
|
|
|
|
result.op |= (is << 11);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-08-19 10:22:00 -04:00
|
|
|
CVuAssembler::BRANCHOP CVuAssembler::Lower::IBNE(VI_REGISTER it, VI_REGISTER is, LABEL label)
|
|
|
|
{
|
|
|
|
BRANCHOP result;
|
|
|
|
result.label = label;
|
|
|
|
result.op = 0x52000000;
|
|
|
|
result.op |= (it << 16);
|
|
|
|
result.op |= (is << 11);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-08-31 17:50:20 -04:00
|
|
|
uint32 CVuAssembler::Lower::ILW(DEST dest, VI_REGISTER it, uint16 imm, VI_REGISTER is)
|
|
|
|
{
|
|
|
|
uint32 result = 0x08000000;
|
|
|
|
result |= (imm & 0x7FF);
|
|
|
|
result |= (is << 11);
|
|
|
|
result |= (it << 16);
|
|
|
|
result |= (dest << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-08-18 16:59:08 -04:00
|
|
|
uint32 CVuAssembler::Lower::ISUBIU(VI_REGISTER it, VI_REGISTER is, uint16 imm)
|
|
|
|
{
|
|
|
|
assert(imm <= 0x7FFF);
|
|
|
|
imm &= 0x7FFF;
|
|
|
|
uint32 result = 0x12000000;
|
|
|
|
result |= (it << 16);
|
|
|
|
result |= (is << 11);
|
|
|
|
result |= (imm & 0x7FF);
|
|
|
|
result |= (((imm & 0x7800) >> 11) << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-02-26 20:09:18 -05:00
|
|
|
uint32 CVuAssembler::Lower::LQ(DEST dest, VF_REGISTER ft, uint16 imm, VI_REGISTER is)
|
|
|
|
{
|
|
|
|
uint32 result = 0x00000000;
|
|
|
|
result |= (imm & 0x7FF);
|
|
|
|
result |= (is << 11);
|
|
|
|
result |= (ft << 16);
|
|
|
|
result |= (dest << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-08-19 10:22:00 -04:00
|
|
|
uint32 CVuAssembler::Lower::LQI(DEST dest, VF_REGISTER ft, VI_REGISTER is)
|
|
|
|
{
|
|
|
|
uint32 result = 0x8000037C;
|
|
|
|
result |= (is << 11);
|
|
|
|
result |= (ft << 16);
|
|
|
|
result |= (dest << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-01-29 16:33:11 -05:00
|
|
|
uint32 CVuAssembler::Lower::MFIR(DEST dest, VF_REGISTER ft, VI_REGISTER is)
|
|
|
|
{
|
|
|
|
uint32 result = 0x800003FD;
|
|
|
|
result |= (is << 11);
|
|
|
|
result |= (ft << 16);
|
|
|
|
result |= (dest << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CVuAssembler::Lower::MTIR(VI_REGISTER it, VF_REGISTER fs, FVF fsf)
|
|
|
|
{
|
|
|
|
uint32 result = 0x800003FC;
|
|
|
|
result |= (fsf << 21);
|
|
|
|
result |= (it << 16);
|
|
|
|
result |= (fs << 11);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-02-15 22:13:32 -05:00
|
|
|
uint32 CVuAssembler::Lower::NOP()
|
|
|
|
{
|
|
|
|
return 0x8000033C;
|
|
|
|
}
|
2020-02-24 12:54:17 -05:00
|
|
|
|
2020-02-26 20:09:18 -05:00
|
|
|
uint32 CVuAssembler::Lower::SQ(DEST dest, VF_REGISTER fs, uint16 imm, VI_REGISTER it)
|
|
|
|
{
|
|
|
|
uint32 result = 0x02000000;
|
|
|
|
result |= (imm & 0x7FF);
|
|
|
|
result |= (fs << 11);
|
|
|
|
result |= (it << 16);
|
|
|
|
result |= (dest << 21);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-05-10 21:08:56 -04:00
|
|
|
uint32 CVuAssembler::Lower::WAITP()
|
|
|
|
{
|
|
|
|
return 0x800007BF;
|
|
|
|
}
|
|
|
|
|
2020-02-24 12:54:17 -05:00
|
|
|
uint32 CVuAssembler::Lower::WAITQ()
|
|
|
|
{
|
|
|
|
return 0x800003BF;
|
|
|
|
}
|