last fpu changes - ended basic first version
This commit is contained in:
parent
0d65cf39fa
commit
acce7800fb
Binary file not shown.
|
@ -1570,6 +1570,9 @@ bool startsWith(const char* pre, const char* str)
|
|||
#define x87SW_PRE_FIELD_STRING "x87SW_"
|
||||
#define x87CW_PRE_FIELD_STRING "x87CW_"
|
||||
#define x87TW_PRE_FIELD_STRING "x87TW_"
|
||||
#define MMX_PRE_FIELD_STRING "MM"
|
||||
#define XMM_PRE_FIELD_STRING "XMM"
|
||||
#define x8780BITFPU_PRE_FIELD_STRING "x87r"
|
||||
#define STRLEN_USING_SIZEOF(string) (sizeof(string) - 1)
|
||||
|
||||
|
||||
|
@ -1585,13 +1588,26 @@ void fpustuff(const char* string, uint value)
|
|||
|
||||
if(startsWith(MxCsr_PRE_FIELD_STRING, string))
|
||||
{
|
||||
uint flags = GetContextDataEx(hActiveThread, UE_MXCSR);
|
||||
flag = getmxcsrflagfromstring(string + STRLEN_USING_SIZEOF(MxCsr_PRE_FIELD_STRING));
|
||||
if(flags & flag and !set)
|
||||
xorval = flag;
|
||||
else if(set)
|
||||
xorval = flag;
|
||||
SetContextDataEx(hActiveThread, UE_MXCSR, flags ^ xorval);
|
||||
if(StrNCmpI(string + STRLEN_USING_SIZEOF(MxCsr_PRE_FIELD_STRING), "RC", strlen("RC")) == 0)
|
||||
{
|
||||
uint flags = GetContextDataEx(hActiveThread, UE_MXCSR);
|
||||
int i = 3;
|
||||
i <<= 13;
|
||||
flags &= ~i;
|
||||
value <<= 13;
|
||||
flags |= value;
|
||||
SetContextDataEx(hActiveThread, UE_MXCSR, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint flags = GetContextDataEx(hActiveThread, UE_MXCSR);
|
||||
flag = getmxcsrflagfromstring(string + STRLEN_USING_SIZEOF(MxCsr_PRE_FIELD_STRING));
|
||||
if(flags & flag and !set)
|
||||
xorval = flag;
|
||||
else if(set)
|
||||
xorval = flag;
|
||||
SetContextDataEx(hActiveThread, UE_MXCSR, flags ^ xorval);
|
||||
}
|
||||
}
|
||||
else if(startsWith(x87TW_PRE_FIELD_STRING, string))
|
||||
{
|
||||
|
@ -1605,7 +1621,7 @@ void fpustuff(const char* string, uint value)
|
|||
|
||||
flags = GetContextDataEx(hActiveThread, UE_X87_TAGWORD);
|
||||
|
||||
flag = 7;
|
||||
flag = 3;
|
||||
flag <<= i * 2;
|
||||
|
||||
flags &= ~flag;
|
||||
|
@ -1643,13 +1659,36 @@ void fpustuff(const char* string, uint value)
|
|||
}
|
||||
else if(startsWith(x87CW_PRE_FIELD_STRING, string))
|
||||
{
|
||||
uint flags = GetContextDataEx(hActiveThread, UE_X87_CONTROLWORD);
|
||||
flag = getx87controlwordflagfromstring(string + STRLEN_USING_SIZEOF(x87CW_PRE_FIELD_STRING));
|
||||
if(flags & flag and !set)
|
||||
xorval = flag;
|
||||
else if(set)
|
||||
xorval = flag;
|
||||
SetContextDataEx(hActiveThread, UE_X87_CONTROLWORD, flags ^ xorval);
|
||||
if(StrNCmpI(string + STRLEN_USING_SIZEOF(x87CW_PRE_FIELD_STRING), "RC", strlen("RC")) == 0)
|
||||
{
|
||||
uint flags = GetContextDataEx(hActiveThread, UE_X87_CONTROLWORD);
|
||||
int i = 3;
|
||||
i <<= 10;
|
||||
flags &= ~i;
|
||||
value <<= 10;
|
||||
flags |= value;
|
||||
SetContextDataEx(hActiveThread, UE_X87_CONTROLWORD, flags);
|
||||
}
|
||||
else if(StrNCmpI(string + STRLEN_USING_SIZEOF(x87CW_PRE_FIELD_STRING), "PC", strlen("PC")) == 0)
|
||||
{
|
||||
uint flags = GetContextDataEx(hActiveThread, UE_X87_CONTROLWORD);
|
||||
int i = 3;
|
||||
i <<= 8;
|
||||
flags &= ~i;
|
||||
value <<= 8;
|
||||
flags |= value;
|
||||
SetContextDataEx(hActiveThread, UE_X87_CONTROLWORD, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint flags = GetContextDataEx(hActiveThread, UE_X87_CONTROLWORD);
|
||||
flag = getx87controlwordflagfromstring(string + STRLEN_USING_SIZEOF(x87CW_PRE_FIELD_STRING));
|
||||
if(flags & flag and !set)
|
||||
xorval = flag;
|
||||
else if(set)
|
||||
xorval = flag;
|
||||
SetContextDataEx(hActiveThread, UE_X87_CONTROLWORD, flags ^ xorval);
|
||||
}
|
||||
}
|
||||
else if(StrNCmpI(string, "x87TagWord", strlen(string)) == 0)
|
||||
{
|
||||
|
@ -1667,6 +1706,176 @@ void fpustuff(const char* string, uint value)
|
|||
{
|
||||
SetContextDataEx(hActiveThread, UE_MXCSR, value);
|
||||
}
|
||||
else if(startsWith(x8780BITFPU_PRE_FIELD_STRING, string))
|
||||
{
|
||||
string += STRLEN_USING_SIZEOF(x8780BITFPU_PRE_FIELD_STRING);
|
||||
DWORD registerindex;
|
||||
bool found = true;
|
||||
switch(*string)
|
||||
{
|
||||
case '0':
|
||||
registerindex = UE_x87_r0;
|
||||
break;
|
||||
|
||||
case '1':
|
||||
registerindex = UE_x87_r1;
|
||||
break;
|
||||
|
||||
case '2':
|
||||
registerindex = UE_x87_r2;
|
||||
break;
|
||||
|
||||
case '3':
|
||||
registerindex = UE_x87_r3;
|
||||
break;
|
||||
|
||||
case '4':
|
||||
registerindex = UE_x87_r4;
|
||||
break;
|
||||
|
||||
case '5':
|
||||
registerindex = UE_x87_r5;
|
||||
break;
|
||||
|
||||
case '6':
|
||||
registerindex = UE_x87_r6;
|
||||
break;
|
||||
|
||||
case '7':
|
||||
registerindex = UE_x87_r7;
|
||||
break;
|
||||
|
||||
default:
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
if(found)
|
||||
SetContextDataEx(hActiveThread, registerindex, value);
|
||||
}
|
||||
else if(startsWith(MMX_PRE_FIELD_STRING, string))
|
||||
{
|
||||
string += STRLEN_USING_SIZEOF(MMX_PRE_FIELD_STRING);
|
||||
DWORD registerindex;
|
||||
bool found = true;
|
||||
switch(*string)
|
||||
{
|
||||
case '0':
|
||||
registerindex = UE_MMX0;
|
||||
break;
|
||||
|
||||
case '1':
|
||||
registerindex = UE_MMX1;
|
||||
break;
|
||||
|
||||
case '2':
|
||||
registerindex = UE_MMX2;
|
||||
break;
|
||||
|
||||
case '3':
|
||||
registerindex = UE_MMX3;
|
||||
break;
|
||||
|
||||
case '4':
|
||||
registerindex = UE_MMX4;
|
||||
break;
|
||||
|
||||
case '5':
|
||||
registerindex = UE_MMX5;
|
||||
break;
|
||||
|
||||
case '6':
|
||||
registerindex = UE_MMX6;
|
||||
break;
|
||||
|
||||
case '7':
|
||||
registerindex = UE_MMX7;
|
||||
break;
|
||||
|
||||
default:
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
if(found)
|
||||
SetContextDataEx(hActiveThread, registerindex, value);
|
||||
}
|
||||
else if(startsWith(XMM_PRE_FIELD_STRING, string))
|
||||
{
|
||||
string += STRLEN_USING_SIZEOF(XMM_PRE_FIELD_STRING);
|
||||
DWORD registerindex;
|
||||
bool found = true;
|
||||
switch(*string)
|
||||
{
|
||||
case '0':
|
||||
registerindex = UE_XMM0;
|
||||
break;
|
||||
|
||||
case '1':
|
||||
registerindex = UE_XMM1;
|
||||
break;
|
||||
|
||||
case '2':
|
||||
registerindex = UE_XMM2;
|
||||
break;
|
||||
|
||||
case '3':
|
||||
registerindex = UE_XMM3;
|
||||
break;
|
||||
|
||||
case '4':
|
||||
registerindex = UE_XMM4;
|
||||
break;
|
||||
|
||||
case '5':
|
||||
registerindex = UE_XMM5;
|
||||
break;
|
||||
|
||||
case '6':
|
||||
registerindex = UE_XMM6;
|
||||
break;
|
||||
|
||||
case '7':
|
||||
registerindex = UE_XMM7;
|
||||
break;
|
||||
|
||||
case '8':
|
||||
registerindex = UE_XMM8;
|
||||
break;
|
||||
|
||||
case '9':
|
||||
registerindex = UE_XMM9;
|
||||
break;
|
||||
|
||||
case '10':
|
||||
registerindex = UE_XMM10;
|
||||
break;
|
||||
|
||||
case '11':
|
||||
registerindex = UE_XMM11;
|
||||
break;
|
||||
|
||||
case '12':
|
||||
registerindex = UE_XMM12;
|
||||
break;
|
||||
|
||||
case '13':
|
||||
registerindex = UE_XMM13;
|
||||
break;
|
||||
|
||||
case '14':
|
||||
registerindex = UE_XMM14;
|
||||
break;
|
||||
|
||||
case '15':
|
||||
registerindex = UE_XMM15;
|
||||
break;
|
||||
|
||||
default:
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
if(found)
|
||||
SetContextDataEx(hActiveThread, registerindex, value);
|
||||
}
|
||||
}
|
||||
|
||||
bool valtostring(const char* string, uint* value, bool silent)
|
||||
|
|
|
@ -12,6 +12,7 @@ LineEditDialog::LineEditDialog(QWidget* parent) : QDialog(parent), ui(new Ui::Li
|
|||
setModal(true); //modal window
|
||||
ui->checkBox->hide();
|
||||
bChecked = false;
|
||||
this->fixed_size = 0;
|
||||
}
|
||||
|
||||
LineEditDialog::~LineEditDialog()
|
||||
|
@ -24,6 +25,12 @@ void LineEditDialog::setCursorPosition(int position)
|
|||
ui->textEdit->setCursorPosition(position);
|
||||
}
|
||||
|
||||
void LineEditDialog::ForceSize(unsigned int size)
|
||||
{
|
||||
this->fixed_size = size;
|
||||
|
||||
}
|
||||
|
||||
void LineEditDialog::setText(const QString & text)
|
||||
{
|
||||
ui->textEdit->setText(text);
|
||||
|
@ -52,6 +59,23 @@ void LineEditDialog::setCheckBoxText(const QString & text)
|
|||
void LineEditDialog::on_textEdit_textChanged(const QString & arg1)
|
||||
{
|
||||
editText = arg1;
|
||||
if(this->fixed_size != 0)
|
||||
{
|
||||
if(arg1.size() != this->fixed_size)
|
||||
{
|
||||
ui->buttonOk->setEnabled(false);
|
||||
QString symbolct = "";
|
||||
int ct = arg1.size() - (int) this->fixed_size;
|
||||
if(ct > 0)
|
||||
symbolct = "+";
|
||||
ui->label->setText(QString("<font color='red'>") + QString("CT: ") + symbolct + QString::number(ct) + QString("</font>"));
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->buttonOk->setEnabled(true);
|
||||
ui->label->setText(QString(""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LineEditDialog::on_checkBox_toggled(bool checked)
|
||||
|
|
|
@ -22,6 +22,7 @@ public:
|
|||
void setCheckBox(bool bSet);
|
||||
void setCheckBoxText(const QString & text);
|
||||
void setCursorPosition(int position);
|
||||
void ForceSize(unsigned int size);
|
||||
|
||||
private slots:
|
||||
void on_textEdit_textChanged(const QString & arg1);
|
||||
|
@ -29,6 +30,7 @@ private slots:
|
|||
|
||||
private:
|
||||
Ui::LineEditDialog* ui;
|
||||
unsigned int fixed_size;
|
||||
};
|
||||
|
||||
#endif // LINEEDITDIALOG_H
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>373</width>
|
||||
<width>414</width>
|
||||
<height>72</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -17,62 +17,56 @@
|
|||
<iconset resource="../../resource.qrc">
|
||||
<normaloff>:/icons/images/ui-combo-box-edit.png</normaloff>:/icons/images/ui-combo-box-edit.png</iconset>
|
||||
</property>
|
||||
<widget class="QWidget" name="layoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>351</width>
|
||||
<height>53</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="textEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox">
|
||||
<property name="text">
|
||||
<string>CheckBox</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonOk">
|
||||
<property name="text">
|
||||
<string>&OK</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonCancel">
|
||||
<property name="text">
|
||||
<string>&Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="textEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox">
|
||||
<property name="text">
|
||||
<string>CheckBox</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonOk">
|
||||
<property name="text">
|
||||
<string>&OK</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonCancel">
|
||||
<property name="text">
|
||||
<string>&Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../../resource.qrc"/>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "LineEditDialog.h"
|
||||
#include "SelectFields.h"
|
||||
#include <QMessageBox>
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
RegistersView::RegistersView(QWidget* parent) : QScrollArea(parent), mVScrollOffset(0)
|
||||
|
@ -36,6 +37,8 @@ RegistersView::RegistersView(QWidget* parent) : QScrollArea(parent), mVScrollOff
|
|||
wCM_FollowInDisassembly = new QAction(tr("Follow in Disassembler"), this);
|
||||
wCM_FollowInDump = new QAction(tr("Follow in Dump"), this);
|
||||
wCM_FollowInStack = new QAction("Follow in Stack", this);
|
||||
wCM_Incrementx87Stack = new QAction(tr("Increment x87 Stack"), this);
|
||||
wCM_Decrementx87Stack = new QAction("Decrement x87 Stack", this);
|
||||
|
||||
// general purposes register (we allow the user to modify the value)
|
||||
mGPR.insert(CAX);
|
||||
|
@ -350,6 +353,7 @@ RegistersView::RegistersView(QWidget* parent) : QScrollArea(parent), mVScrollOff
|
|||
mFPUx87.insert(x87CW_RC);
|
||||
mFIELDVALUE.insert(x87CW_RC);
|
||||
mFPU.insert(x87CW_RC);
|
||||
mMODIFYDISPLAY.insert(x87CW_RC);
|
||||
|
||||
mFPUx87.insert(x87TW_0);
|
||||
mFIELDVALUE.insert(x87TW_0);
|
||||
|
@ -402,6 +406,7 @@ RegistersView::RegistersView(QWidget* parent) : QScrollArea(parent), mVScrollOff
|
|||
mFPUx87.insert(x87CW_PC);
|
||||
mFIELDVALUE.insert(x87CW_PC);
|
||||
mFPU.insert(x87CW_PC);
|
||||
mMODIFYDISPLAY.insert(x87CW_PC);
|
||||
|
||||
mSETONEZEROTOGGLE.insert(x87CW_IEM);
|
||||
mFPUx87.insert(x87CW_IEM);
|
||||
|
@ -496,6 +501,7 @@ RegistersView::RegistersView(QWidget* parent) : QScrollArea(parent), mVScrollOff
|
|||
|
||||
mFIELDVALUE.insert(MxCsr_RC);
|
||||
mFPU.insert(MxCsr_RC);
|
||||
mMODIFYDISPLAY.insert(MxCsr_RC);
|
||||
|
||||
mMODIFYDISPLAY.insert(MM0);
|
||||
mFPUMMX.insert(MM0);
|
||||
|
@ -824,7 +830,7 @@ RegistersView::RegistersView(QWidget* parent) : QScrollArea(parent), mVScrollOff
|
|||
mRegisterMapping.insert(x87SW_I, "x87SW_I");
|
||||
mRegisterPlaces.insert(x87SW_I, Register_Position(offset + 20, 0, 9, 1));
|
||||
mRegisterMapping.insert(x87SW_TOP, "x87SW_TOP");
|
||||
mRegisterPlaces.insert(x87SW_TOP, Register_Position(offset + 20, 12, 10, 6));
|
||||
mRegisterPlaces.insert(x87SW_TOP, Register_Position(offset + 20, 12, 10, 12));
|
||||
|
||||
offset++;
|
||||
|
||||
|
@ -893,7 +899,7 @@ RegistersView::RegistersView(QWidget* parent) : QScrollArea(parent), mVScrollOff
|
|||
mRegisterMapping.insert(MxCsr_DM, "MxCsr_DM");
|
||||
mRegisterPlaces.insert(MxCsr_DM, Register_Position(offset + 31, 12, 10, 1));
|
||||
mRegisterMapping.insert(MxCsr_RC, "MxCsr_RC");
|
||||
mRegisterPlaces.insert(MxCsr_RC, Register_Position(offset + 31, 25, 10, 13));
|
||||
mRegisterPlaces.insert(MxCsr_RC, Register_Position(offset + 31, 25, 10, 18));
|
||||
|
||||
offset++;
|
||||
|
||||
|
@ -990,6 +996,8 @@ RegistersView::RegistersView(QWidget* parent) : QScrollArea(parent), mVScrollOff
|
|||
// context menu actions
|
||||
connect(wCM_Increment, SIGNAL(triggered()), this, SLOT(onIncrementAction()));
|
||||
connect(wCM_Decrement, SIGNAL(triggered()), this, SLOT(onDecrementAction()));
|
||||
connect(wCM_Incrementx87Stack, SIGNAL(triggered()), this, SLOT(onIncrementx87StackAction()));
|
||||
connect(wCM_Decrementx87Stack, SIGNAL(triggered()), this, SLOT(onDecrementx87StackAction()));
|
||||
connect(wCM_Zero, SIGNAL(triggered()), this, SLOT(onZeroAction()));
|
||||
connect(wCM_SetToOne, SIGNAL(triggered()), this, SLOT(onSetToOneAction()));
|
||||
connect(wCM_Modify, SIGNAL(triggered()), this, SLOT(onModifyAction()));
|
||||
|
@ -1283,93 +1291,29 @@ QString RegistersView::GetRegStringValueFromValue(REGISTER_NAME reg, char* value
|
|||
{
|
||||
valueText = QString("%1").arg((* ((unsigned short*) value)), 1, 16, QChar('0')).toUpper();
|
||||
valueText += QString("(");
|
||||
#define MxCsr_RC_NEAR 0
|
||||
#define MxCsr_RC_NEGATIVE 1
|
||||
#define MxCsr_RC_POSITIVE 2
|
||||
#define MxCsr_RC_TOZERO 3
|
||||
switch((* ((unsigned short*) value)))
|
||||
{
|
||||
case MxCsr_RC_NEAR:
|
||||
valueText += "round near";
|
||||
break;
|
||||
|
||||
case MxCsr_RC_NEGATIVE:
|
||||
valueText += "toward negative";
|
||||
break;
|
||||
|
||||
case MxCsr_RC_POSITIVE:
|
||||
valueText += "toward positive";
|
||||
break;
|
||||
|
||||
case MxCsr_RC_TOZERO:
|
||||
valueText += "toward zero";
|
||||
break;
|
||||
}
|
||||
|
||||
valueText += GetMxCsrRCStateString((* ((unsigned short*) value)));
|
||||
valueText += QString(")");
|
||||
}
|
||||
else if(reg == x87CW_RC)
|
||||
{
|
||||
valueText = QString("%1").arg((* ((unsigned short*) value)), 1, 16, QChar('0')).toUpper();
|
||||
valueText += QString("(");
|
||||
#define x87CW_RC_NEAR 0
|
||||
#define x87CW_RC_DOWN 1
|
||||
#define x87CW_RC_UP 2
|
||||
#define x87CW_RC_TRUNCATE 3
|
||||
switch((* ((unsigned short*) value)))
|
||||
{
|
||||
case x87CW_RC_NEAR:
|
||||
valueText += "round near";
|
||||
break;
|
||||
|
||||
case x87CW_RC_DOWN:
|
||||
valueText += "round down";
|
||||
break;
|
||||
|
||||
case x87CW_RC_UP:
|
||||
valueText += "round up";
|
||||
break;
|
||||
|
||||
case x87CW_RC_TRUNCATE:
|
||||
valueText += "truncate";
|
||||
break;
|
||||
}
|
||||
|
||||
valueText += GetControlWordRCStateString((* ((unsigned short*) value)));
|
||||
valueText += QString(")");
|
||||
}
|
||||
else if(reg == x87CW_PC)
|
||||
{
|
||||
valueText = QString("%1").arg((* ((unsigned short*) value)), 1, 16, QChar('0')).toUpper();
|
||||
valueText += QString("(");
|
||||
#define x87CW_PC_REAL4 0
|
||||
#define x87CW_PC_NOTUSED 1
|
||||
#define x87CW_PC_REAL8 2
|
||||
#define x87CW_PC_REAL10 3
|
||||
switch((* ((unsigned short*) value)))
|
||||
{
|
||||
case x87CW_PC_REAL4:
|
||||
valueText += "real4";
|
||||
break;
|
||||
|
||||
case x87CW_PC_NOTUSED:
|
||||
valueText += "not used";
|
||||
break;
|
||||
|
||||
case x87CW_PC_REAL8:
|
||||
valueText += "real8";
|
||||
break;
|
||||
|
||||
case x87CW_PC_REAL10:
|
||||
valueText += "real10";
|
||||
break;
|
||||
}
|
||||
|
||||
valueText += GetControlWordPCStateString((* ((unsigned short*) value)));
|
||||
valueText += QString(")");
|
||||
}
|
||||
else if(reg == x87SW_TOP)
|
||||
{
|
||||
valueText = QString("%1").arg((* ((unsigned short*) value)), 1, 16, QChar('0')).toUpper();
|
||||
valueText += QString("(ST") + valueText + QString(")");
|
||||
valueText += QString("(ST0=");
|
||||
valueText += GetStatusWordTOPStateString((* ((unsigned short*) value)));
|
||||
valueText += QString(")");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1384,17 +1328,179 @@ QString RegistersView::GetRegStringValueFromValue(REGISTER_NAME reg, char* value
|
|||
return valueText;
|
||||
}
|
||||
|
||||
#define MxCsr_RC_NEAR 0
|
||||
#define MxCsr_RC_NEGATIVE 1
|
||||
#define MxCsr_RC_POSITIVE 2
|
||||
#define MxCsr_RC_TOZERO 3
|
||||
|
||||
STRING_VALUE_TABLE_t MxCsrRCValueStringTable[] =
|
||||
{
|
||||
{"toward zero", MxCsr_RC_TOZERO},
|
||||
{"toward positive", MxCsr_RC_POSITIVE},
|
||||
{"toward negative", MxCsr_RC_NEGATIVE},
|
||||
{"round near", MxCsr_RC_NEAR}
|
||||
};
|
||||
|
||||
unsigned int RegistersView::GetMxCsrRCValueFromString(QString string)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < (sizeof(MxCsrRCValueStringTable) / sizeof(*MxCsrRCValueStringTable)); i++)
|
||||
{
|
||||
if(MxCsrRCValueStringTable[i].string == string)
|
||||
return MxCsrRCValueStringTable[i].value;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
QString RegistersView::GetMxCsrRCStateString(unsigned short state)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < (sizeof(MxCsrRCValueStringTable) / sizeof(*MxCsrRCValueStringTable)); i++)
|
||||
{
|
||||
if(MxCsrRCValueStringTable[i].value == state)
|
||||
return MxCsrRCValueStringTable[i].string;
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
#define x87CW_RC_NEAR 0
|
||||
#define x87CW_RC_DOWN 1
|
||||
#define x87CW_RC_UP 2
|
||||
#define x87CW_RC_TRUNCATE 3
|
||||
|
||||
STRING_VALUE_TABLE_t ControlWordRCValueStringTable[] =
|
||||
{
|
||||
{"truncate", x87CW_RC_TRUNCATE},
|
||||
{"round up", x87CW_RC_UP},
|
||||
{"round down", x87CW_RC_DOWN},
|
||||
{"round near", x87CW_RC_NEAR}
|
||||
};
|
||||
|
||||
unsigned int RegistersView::GetControlWordRCValueFromString(QString string)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < (sizeof(ControlWordRCValueStringTable) / sizeof(*ControlWordRCValueStringTable)); i++)
|
||||
{
|
||||
if(ControlWordRCValueStringTable[i].string == string)
|
||||
return ControlWordRCValueStringTable[i].value;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
QString RegistersView::GetControlWordRCStateString(unsigned short state)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < (sizeof(ControlWordRCValueStringTable) / sizeof(*ControlWordRCValueStringTable)); i++)
|
||||
{
|
||||
if(ControlWordRCValueStringTable[i].value == state)
|
||||
return ControlWordRCValueStringTable[i].string;
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
#define x87SW_TOP_0 0
|
||||
#define x87SW_TOP_1 1
|
||||
#define x87SW_TOP_2 2
|
||||
#define x87SW_TOP_3 3
|
||||
#define x87SW_TOP_4 4
|
||||
#define x87SW_TOP_5 5
|
||||
#define x87SW_TOP_6 6
|
||||
#define x87SW_TOP_7 7
|
||||
|
||||
STRING_VALUE_TABLE_t StatusWordTOPValueStringTable[] =
|
||||
{
|
||||
{"x87r0", x87SW_TOP_0},
|
||||
{"x87r1", x87SW_TOP_1},
|
||||
{"x87r2", x87SW_TOP_2},
|
||||
{"x87r3", x87SW_TOP_3},
|
||||
{"x87r4", x87SW_TOP_4},
|
||||
{"x87r5", x87SW_TOP_5},
|
||||
{"x87r6", x87SW_TOP_6},
|
||||
{"x87r7", x87SW_TOP_7}
|
||||
};
|
||||
|
||||
unsigned int RegistersView::GetStatusWordTOPValueFromString(QString string)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < (sizeof(StatusWordTOPValueStringTable) / sizeof(*StatusWordTOPValueStringTable)); i++)
|
||||
{
|
||||
if(StatusWordTOPValueStringTable[i].string == string)
|
||||
return StatusWordTOPValueStringTable[i].value;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
QString RegistersView::GetStatusWordTOPStateString(unsigned short state)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < (sizeof(StatusWordTOPValueStringTable) / sizeof(*StatusWordTOPValueStringTable)); i++)
|
||||
{
|
||||
if(StatusWordTOPValueStringTable[i].value == state)
|
||||
return StatusWordTOPValueStringTable[i].string;
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
|
||||
#define x87CW_PC_REAL4 0
|
||||
#define x87CW_PC_NOTUSED 1
|
||||
#define x87CW_PC_REAL8 2
|
||||
#define x87CW_PC_REAL10 3
|
||||
|
||||
STRING_VALUE_TABLE_t ControlWordPCValueStringTable[] =
|
||||
{
|
||||
{"real4", x87CW_PC_REAL4},
|
||||
{"not used", x87CW_PC_NOTUSED},
|
||||
{"real8", x87CW_PC_REAL8},
|
||||
{"real10", x87CW_PC_REAL10}
|
||||
};
|
||||
|
||||
|
||||
unsigned int RegistersView::GetControlWordPCValueFromString(QString string)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < (sizeof(ControlWordPCValueStringTable) / sizeof(*ControlWordPCValueStringTable)); i++)
|
||||
{
|
||||
if(ControlWordPCValueStringTable[i].string == string)
|
||||
return ControlWordPCValueStringTable[i].value;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
QString RegistersView::GetControlWordPCStateString(unsigned short state)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < (sizeof(ControlWordPCValueStringTable) / sizeof(*ControlWordPCValueStringTable)); i++)
|
||||
{
|
||||
if(ControlWordPCValueStringTable[i].value == state)
|
||||
return ControlWordPCValueStringTable[i].string;
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
|
||||
#define X87FPU_TAGWORD_NONZERO 0
|
||||
#define X87FPU_TAGWORD_ZERO 1
|
||||
#define X87FPU_TAGWORD_SPECIAL 2
|
||||
#define X87FPU_TAGWORD_EMPTY 3
|
||||
|
||||
typedef struct
|
||||
{
|
||||
QString string;
|
||||
unsigned int value;
|
||||
} STRING_VALUE_TABLE_t;
|
||||
|
||||
STRING_VALUE_TABLE_t TagWordValueStringTable[] =
|
||||
{
|
||||
{"nonzero", X87FPU_TAGWORD_NONZERO},
|
||||
|
@ -1481,15 +1587,71 @@ void RegistersView::drawRegister(QPainter* p, REGISTER_NAME reg, char* value)
|
|||
|
||||
if(mFPUx87_80BITSDISPLAY.contains(reg) && DbgIsDebugging())
|
||||
{
|
||||
p->setPen(ConfigColor("RegistersExtraInfoColor"));
|
||||
x += 1 * mCharWidth; //1 space
|
||||
QString newText;
|
||||
if(mRegisterUpdates.contains(x87SW_TOP))
|
||||
p->setPen(ConfigColor("RegistersModifiedColor"));
|
||||
|
||||
newText = QString("ST%1 ").arg(((x87FPURegister_t*) registerValue(&wRegDumpStruct, reg))->st_value);
|
||||
width = newText.length() * mCharWidth;
|
||||
p->drawText(x, y, width, mRowHeight, Qt::AlignVCenter, newText);
|
||||
|
||||
x += width;
|
||||
|
||||
newText = QString("");
|
||||
|
||||
p->setPen(ConfigColor("RegistersExtraInfoColor"));
|
||||
|
||||
if(reg == x87r0 && mRegisterUpdates.contains(x87TW_0))
|
||||
{
|
||||
p->setPen(ConfigColor("RegistersModifiedColor"));
|
||||
}
|
||||
else if(reg == x87r1 && mRegisterUpdates.contains(x87TW_1))
|
||||
{
|
||||
p->setPen(ConfigColor("RegistersModifiedColor"));
|
||||
}
|
||||
else if(reg == x87r2 && mRegisterUpdates.contains(x87TW_2))
|
||||
{
|
||||
p->setPen(ConfigColor("RegistersModifiedColor"));
|
||||
}
|
||||
else if(reg == x87r3 && mRegisterUpdates.contains(x87TW_3))
|
||||
{
|
||||
p->setPen(ConfigColor("RegistersModifiedColor"));
|
||||
}
|
||||
else if(reg == x87r4 && mRegisterUpdates.contains(x87TW_4))
|
||||
{
|
||||
p->setPen(ConfigColor("RegistersModifiedColor"));
|
||||
}
|
||||
else if(reg == x87r5 && mRegisterUpdates.contains(x87TW_5))
|
||||
{
|
||||
p->setPen(ConfigColor("RegistersModifiedColor"));
|
||||
}
|
||||
else if(reg == x87r6 && mRegisterUpdates.contains(x87TW_6))
|
||||
{
|
||||
p->setPen(ConfigColor("RegistersModifiedColor"));
|
||||
}
|
||||
else if(reg == x87r7 && mRegisterUpdates.contains(x87TW_7))
|
||||
{
|
||||
p->setPen(ConfigColor("RegistersModifiedColor"));
|
||||
}
|
||||
|
||||
newText += GetTagWordStateString(((x87FPURegister_t*) registerValue(&wRegDumpStruct, reg))->tag) + QString(" ");
|
||||
|
||||
width = newText.length() * mCharWidth;
|
||||
p->drawText(x, y, width, mRowHeight, Qt::AlignVCenter, newText);
|
||||
|
||||
x += width;
|
||||
|
||||
newText = QString("");
|
||||
|
||||
p->setPen(ConfigColor("RegistersExtraInfoColor"));
|
||||
|
||||
if(DbgIsDebugging() && mRegisterUpdates.contains(reg))
|
||||
p->setPen(ConfigColor("RegistersModifiedColor"));
|
||||
|
||||
newText += QString::number(readFloat80(((x87FPURegister_t*) registerValue(&wRegDumpStruct, reg))->data));
|
||||
width = newText.length() * mCharWidth;
|
||||
p->setPen(ConfigColor("RegistersExtraInfoColor"));
|
||||
p->drawText(x, y, width, mRowHeight, Qt::AlignVCenter, newText);
|
||||
}
|
||||
|
||||
|
@ -1522,54 +1684,57 @@ void RegistersView::updateRegistersSlot()
|
|||
setRegisters(&z);
|
||||
}
|
||||
|
||||
void RegistersView::ModifyFields(QString title, STRING_VALUE_TABLE_t* table, SIZE_T size)
|
||||
{
|
||||
SelectFields mSelectFields(this);
|
||||
QListWidget* mQListWidget = mSelectFields.GetList();
|
||||
|
||||
QStringList items;
|
||||
unsigned int i;
|
||||
|
||||
for(i = 0; i < size; i++)
|
||||
items << table[i].string;
|
||||
|
||||
mQListWidget->addItems(items);
|
||||
|
||||
mSelectFields.setWindowTitle(title);
|
||||
if(mSelectFields.exec() != QDialog::Accepted)
|
||||
return;
|
||||
|
||||
if(mQListWidget->selectedItems().count() != 1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = mQListWidget->takeItem(mQListWidget->currentRow());
|
||||
|
||||
uint_t value;
|
||||
|
||||
for(i = 0; i < size; i++)
|
||||
{
|
||||
if(table[i].string == item->text())
|
||||
break;
|
||||
}
|
||||
|
||||
value = table[i].value;
|
||||
|
||||
setRegister(mSelected, (uint_t)value);
|
||||
}
|
||||
|
||||
#define MODIFY_FIELDS_DISPLAY(title, table) ModifyFields(QString("Edit ") + QString(title), (STRING_VALUE_TABLE_t *) & table, SIZE_TABLE(table) )
|
||||
|
||||
void RegistersView::displayEditDialog()
|
||||
{
|
||||
if(mFPU.contains(mSelected))
|
||||
{
|
||||
if(mTAGWORD.contains(mSelected))
|
||||
{
|
||||
SelectFields mSelectFields(this);
|
||||
QListWidget* mQListWidget = mSelectFields.GetList();
|
||||
|
||||
QStringList items;
|
||||
items << GetTagWordStateString(X87FPU_TAGWORD_EMPTY) << GetTagWordStateString(X87FPU_TAGWORD_NONZERO)
|
||||
<< GetTagWordStateString(X87FPU_TAGWORD_SPECIAL) << GetTagWordStateString(X87FPU_TAGWORD_ZERO);
|
||||
|
||||
mQListWidget->addItems(items);
|
||||
|
||||
mSelectFields.setWindowTitle("Edit TAG");
|
||||
if(mSelectFields.exec() != QDialog::Accepted)
|
||||
return;
|
||||
|
||||
if(mQListWidget->selectedItems().count() != 1)
|
||||
return;
|
||||
|
||||
QListWidgetItem* item = mQListWidget->takeItem(mQListWidget->currentRow());
|
||||
|
||||
uint_t value = GetTagWordValueFromString(item->text());
|
||||
setRegister(mSelected, (uint_t)value);
|
||||
}
|
||||
MODIFY_FIELDS_DISPLAY("Tag " + mRegisterMapping.constFind(mSelected).value(), TagWordValueStringTable);
|
||||
else if(mSelected == MxCsr_RC)
|
||||
MODIFY_FIELDS_DISPLAY("MxCsr_RC", MxCsrRCValueStringTable);
|
||||
else if(mSelected == x87CW_RC)
|
||||
MODIFY_FIELDS_DISPLAY("x87CW_RC", ControlWordRCValueStringTable);
|
||||
else if(mSelected == x87CW_PC)
|
||||
MODIFY_FIELDS_DISPLAY("x87CW_PC", ControlWordPCValueStringTable);
|
||||
else if(mSelected == x87SW_TOP)
|
||||
{
|
||||
SelectFields mSelectFields(this);
|
||||
QListWidget* mQListWidget = mSelectFields.GetList();
|
||||
|
||||
QStringList items;
|
||||
items << "ST0" << "ST1" << "ST2" << "ST3" << "ST4"
|
||||
<< "ST5" << "ST6" << "ST7";
|
||||
|
||||
mQListWidget->addItems(items);
|
||||
|
||||
mSelectFields.setWindowTitle("Edit x87SW_TOP");
|
||||
if(mSelectFields.exec() != QDialog::Accepted)
|
||||
return;
|
||||
|
||||
if(mQListWidget->selectedItems().count() != 1)
|
||||
return;
|
||||
|
||||
uint_t value = mQListWidget->currentRow();
|
||||
setRegister(mSelected, (uint_t)value);
|
||||
}
|
||||
MODIFY_FIELDS_DISPLAY("x87SW_TOP ST0=", StatusWordTOPValueStringTable);
|
||||
else
|
||||
{
|
||||
bool errorinput = false;
|
||||
|
@ -1579,24 +1744,12 @@ void RegistersView::displayEditDialog()
|
|||
mLineEdit.setWindowTitle("Edit FPU register");
|
||||
mLineEdit.setWindowIcon(QIcon(":/icons/images/log.png"));
|
||||
mLineEdit.setCursorPosition(0);
|
||||
|
||||
mLineEdit.ForceSize(GetSizeRegister(mSelected) * 2);
|
||||
do
|
||||
{
|
||||
errorinput = false;
|
||||
if(mLineEdit.exec() != QDialog::Accepted)
|
||||
return; //pressed cancel
|
||||
|
||||
if(mLineEdit.editText.size() != GetSizeRegister(mSelected) * 2)
|
||||
{
|
||||
mLineEdit.setCursorPosition(GetSizeRegister(mSelected) * 2);
|
||||
errorinput = true;
|
||||
|
||||
QMessageBox msg(QMessageBox::Warning, "ERROR SIZE INPUT", "ERROR SIZE INPUT MUST BE: " + QString::number(GetSizeRegister(mSelected) * 2));
|
||||
msg.setWindowIcon(QIcon(":/icons/images/compile-warning.png"));
|
||||
msg.setParent(this, Qt::Dialog);
|
||||
msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||
msg.exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
bool ok = false;
|
||||
|
@ -1606,7 +1759,40 @@ void RegistersView::displayEditDialog()
|
|||
fpuvalue = (uint_t) mLineEdit.editText.toUShort(&ok, 16);
|
||||
else if(mDWORDDISPLAY.contains(mSelected))
|
||||
fpuvalue = mLineEdit.editText.toUInt(&ok, 16);
|
||||
else if(mFPUMMX.contains(mSelected) || mFPUXMM.contains(mSelected) || mFPUx87_80BITSDISPLAY.contains(mSelected))
|
||||
{
|
||||
QByteArray pArray = mLineEdit.editText.toLocal8Bit();
|
||||
if(pArray.size() == GetSizeRegister(mSelected) * 2)
|
||||
{
|
||||
char* pData = (char*) calloc(1, sizeof(char) * GetSizeRegister(mSelected));
|
||||
|
||||
if(pData != NULL)
|
||||
{
|
||||
ok = true;
|
||||
char actual_char[3];
|
||||
unsigned int i;
|
||||
for(i = 0; i < GetSizeRegister(mSelected); i++)
|
||||
{
|
||||
memset(actual_char, 0, sizeof(actual_char));
|
||||
memcpy(actual_char, (char*) pArray.data() + (i * 2), 2);
|
||||
if(! isxdigit(actual_char[0]) || ! isxdigit(actual_char[1]))
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
pData[i] = (char)strtol(actual_char, NULL, 16);
|
||||
}
|
||||
|
||||
if(ok)
|
||||
setRegister(mSelected, (uint_t) pData);
|
||||
|
||||
free(pData);
|
||||
|
||||
if(ok)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!ok)
|
||||
{
|
||||
errorinput = true;
|
||||
|
@ -1634,6 +1820,18 @@ void RegistersView::displayEditDialog()
|
|||
}
|
||||
}
|
||||
|
||||
void RegistersView::onIncrementx87StackAction()
|
||||
{
|
||||
if(mFPUx87_80BITSDISPLAY.contains(mSelected))
|
||||
setRegister(x87SW_TOP, ((* ((uint_t*) registerValue(&wRegDumpStruct, x87SW_TOP))) + 1) % 7);
|
||||
}
|
||||
|
||||
void RegistersView::onDecrementx87StackAction()
|
||||
{
|
||||
if(mFPUx87_80BITSDISPLAY.contains(mSelected))
|
||||
setRegister(x87SW_TOP, ((* ((uint_t*) registerValue(&wRegDumpStruct, x87SW_TOP))) - 1) % 7);
|
||||
}
|
||||
|
||||
void RegistersView::onIncrementAction()
|
||||
{
|
||||
if(mINCREMENTDECREMET.contains(mSelected))
|
||||
|
@ -1751,6 +1949,12 @@ void RegistersView::displayCustomContextMenuSlot(QPoint pos)
|
|||
wMenu.addAction(wCM_ToggleValue);
|
||||
}
|
||||
|
||||
if(mFPUx87_80BITSDISPLAY.contains(mSelected))
|
||||
{
|
||||
wMenu.addAction(wCM_Incrementx87Stack);
|
||||
wMenu.addAction(wCM_Decrementx87Stack);
|
||||
}
|
||||
|
||||
if(mINCREMENTDECREMET.contains(mSelected))
|
||||
{
|
||||
wMenu.addAction(wCM_Increment);
|
||||
|
|
|
@ -8,6 +8,14 @@
|
|||
|
||||
#define IsCharacterRegister(x) ((x>=CAX && x<CIP))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
QString string;
|
||||
unsigned int value;
|
||||
} STRING_VALUE_TABLE_t;
|
||||
|
||||
#define SIZE_TABLE(table) (sizeof(table) / sizeof(*table))
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class RegistersView;
|
||||
|
@ -110,6 +118,8 @@ protected slots:
|
|||
void fontsUpdatedSlot();
|
||||
void onIncrementAction();
|
||||
void onDecrementAction();
|
||||
void onIncrementx87StackAction();
|
||||
void onDecrementx87StackAction();
|
||||
void onZeroAction();
|
||||
void onSetToOneAction();
|
||||
void onModifyAction();
|
||||
|
@ -125,6 +135,15 @@ protected slots:
|
|||
QString GetRegStringValueFromValue(REGISTER_NAME reg , char* value);
|
||||
QString GetTagWordStateString(unsigned short);
|
||||
unsigned int GetTagWordValueFromString(QString string);
|
||||
QString GetControlWordPCStateString(unsigned short);
|
||||
unsigned int GetControlWordPCValueFromString(QString string);
|
||||
QString GetControlWordRCStateString(unsigned short);
|
||||
unsigned int GetControlWordRCValueFromString(QString string);
|
||||
QString GetMxCsrRCStateString(unsigned short);
|
||||
unsigned int GetMxCsrRCValueFromString(QString string);
|
||||
void ModifyFields(QString title, STRING_VALUE_TABLE_t* table, SIZE_T size);
|
||||
unsigned int GetStatusWordTOPValueFromString(QString string);
|
||||
QString GetStatusWordTOPStateString(unsigned short state);
|
||||
|
||||
private:
|
||||
int mVScrollOffset;
|
||||
|
@ -179,6 +198,8 @@ private:
|
|||
QAction* wCM_FollowInDisassembly;
|
||||
QAction* wCM_FollowInDump;
|
||||
QAction* wCM_FollowInStack;
|
||||
QAction* wCM_Incrementx87Stack;
|
||||
QAction* wCM_Decrementx87Stack;
|
||||
int_t mCip;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue