|
@@ -0,0 +1,1625 @@
|
|
|
+#ifdef DSP1_CPP
|
|
|
+
|
|
|
+// DSP-1's emulation code
|
|
|
+//
|
|
|
+// Based on research by Overload, The Dumper, Neviksti and Andreas Naive
|
|
|
+// Date: June 2006
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+Dsp1::Dsp1()
|
|
|
+{
|
|
|
+ reset();
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+uint8 Dsp1::getSr()
|
|
|
+{
|
|
|
+ mSrLowByteAccess = ~mSrLowByteAccess;
|
|
|
+ if (mSrLowByteAccess)
|
|
|
+ return 0;
|
|
|
+ else
|
|
|
+ return mSr;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+uint8 Dsp1::getDr()
|
|
|
+{
|
|
|
+ uint8 oDr;
|
|
|
+
|
|
|
+ fsmStep(true, oDr);
|
|
|
+ return oDr;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+void Dsp1::setDr(uint8 iDr)
|
|
|
+{
|
|
|
+ fsmStep(false, iDr);
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+void Dsp1::reset()
|
|
|
+{
|
|
|
+ mSr = DRC|RQM;
|
|
|
+ mSrLowByteAccess = false;
|
|
|
+ mDr = 0x0080; // Only a supposition. Is this correct?
|
|
|
+ mFreeze = false;
|
|
|
+ mFsmMajorState = WAIT_COMMAND;
|
|
|
+ memset(&shared, 0, sizeof(SharedData)); // another supposition
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Though the DSP-1 is unaware of the type of operation (read or write)
|
|
|
+// we need to know what is being done by the program, as the class
|
|
|
+// is responsible for maintaining the binding between the
|
|
|
+// "external" and "internal" representations of the DR (data register).
|
|
|
+
|
|
|
+void Dsp1::fsmStep(bool read, uint8 &data)
|
|
|
+{
|
|
|
+ if (0 == (mSr&RQM)) return;
|
|
|
+ // Now RQM would be cleared; however, as this code is not to be used in
|
|
|
+ // a multithread environment, we will simply fake RQM operation.
|
|
|
+ // (The only exception would be Op1A's freeze.)
|
|
|
+
|
|
|
+ // binding
|
|
|
+ if (read)
|
|
|
+ {
|
|
|
+ if (mSr&DRS)
|
|
|
+ data = static_cast<uint8>(mDr>>8);
|
|
|
+ else
|
|
|
+ data = static_cast<uint8>(mDr);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (mSr&DRS)
|
|
|
+ {
|
|
|
+ mDr &= 0x00ff;
|
|
|
+ mDr |= data<<8;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ mDr &= 0xff00;
|
|
|
+ mDr |= data;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ switch (mFsmMajorState)
|
|
|
+ {
|
|
|
+ case WAIT_COMMAND:
|
|
|
+ mCommand = static_cast<uint8>(mDr);
|
|
|
+ if (!(mCommand & 0xc0)) // valid command?
|
|
|
+ {
|
|
|
+ switch(mCommand)
|
|
|
+ {
|
|
|
+ // freeze cases
|
|
|
+ case 0x1a:
|
|
|
+ case 0x2a:
|
|
|
+ case 0x3a:
|
|
|
+ mFreeze = true;
|
|
|
+ break;
|
|
|
+ // normal cases
|
|
|
+ default:
|
|
|
+ mDataCounter=0;
|
|
|
+ mFsmMajorState = READ_DATA;
|
|
|
+ mSr &= ~DRC;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case READ_DATA:
|
|
|
+ mSr ^= DRS;
|
|
|
+ if (!(mSr&DRS))
|
|
|
+ {
|
|
|
+ mReadBuffer[mDataCounter++] = static_cast<int16>(mDr);
|
|
|
+ if (mDataCounter >= mCommandTable[mCommand].reads)
|
|
|
+ {
|
|
|
+ (this->*mCommandTable[mCommand].callback)(mReadBuffer, mWriteBuffer);
|
|
|
+ if (0 != mCommandTable[mCommand].writes) // any output?
|
|
|
+ {
|
|
|
+ mDataCounter = 0;
|
|
|
+ mDr = static_cast<uint16>(mWriteBuffer[mDataCounter]);
|
|
|
+ mFsmMajorState = WRITE_DATA;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ mDr = 0x0080; // valid command completion
|
|
|
+ mFsmMajorState = WAIT_COMMAND;
|
|
|
+ mSr |= DRC;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case WRITE_DATA:
|
|
|
+ mSr ^= DRS;
|
|
|
+ if (!(mSr&DRS))
|
|
|
+ {
|
|
|
+ ++mDataCounter;
|
|
|
+ if (mDataCounter >= mCommandTable[mCommand].writes)
|
|
|
+ {
|
|
|
+ if ((mCommand == 0x0a)&&(mDr != 0x8000))
|
|
|
+ {
|
|
|
+ // works in continuous mode
|
|
|
+ mReadBuffer[0]++; // next raster line
|
|
|
+ (this->*mCommandTable[mCommand].callback)(mReadBuffer, mWriteBuffer);
|
|
|
+ mDataCounter = 0;
|
|
|
+ mDr = static_cast<uint16>(mWriteBuffer[mDataCounter]);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ mDr = 0x0080; // valid command completion
|
|
|
+ mFsmMajorState = WAIT_COMMAND;
|
|
|
+ mSr |= DRC;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ mDr = static_cast<uint16>(mWriteBuffer[mDataCounter]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ // Now RQM would be set (except when executing Op1A -command equals 0x1a, 0x2a or 0x3a-).
|
|
|
+ if (mFreeze)
|
|
|
+ mSr &= ~RQM;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// The info on this table follows Overload's docs.
|
|
|
+
|
|
|
+const Dsp1::Command Dsp1::mCommandTable[0x40] = {
|
|
|
+ {&Dsp1::multiply, 2, 1}, //0x00
|
|
|
+ {&Dsp1::attitudeA, 4, 0}, //0x01
|
|
|
+ {&Dsp1::parameter, 7, 4}, //0x02
|
|
|
+ {&Dsp1::subjectiveA, 3, 3}, //0x03
|
|
|
+ {&Dsp1::triangle, 2, 2}, //0x04
|
|
|
+ {&Dsp1::attitudeA, 4, 0}, //0x01
|
|
|
+ {&Dsp1::project, 3, 3}, //0x06
|
|
|
+ {&Dsp1::memoryTest, 1, 1}, //0x0f
|
|
|
+ {&Dsp1::radius, 3, 2}, //0x08
|
|
|
+ {&Dsp1::objectiveA, 3, 3}, //0x0d
|
|
|
+ {&Dsp1::raster, 1, 4}, // 0x0a. This will normally work in continuous mode
|
|
|
+ {&Dsp1::scalarA, 3, 1}, //0x0b
|
|
|
+ {&Dsp1::rotate, 3, 2}, //0x0c
|
|
|
+ {&Dsp1::objectiveA, 3, 3}, //0x0d
|
|
|
+ {&Dsp1::target, 2, 2}, //0x0e
|
|
|
+ {&Dsp1::memoryTest, 1, 1}, //0x0f
|
|
|
+
|
|
|
+ {&Dsp1::inverse, 2, 2}, //0x10
|
|
|
+ {&Dsp1::attitudeB, 4, 0}, //0x11
|
|
|
+ {&Dsp1::parameter, 7, 4}, //0x02
|
|
|
+ {&Dsp1::subjectiveB, 3, 3}, //0x13
|
|
|
+ {&Dsp1::gyrate, 6, 3}, //0x14
|
|
|
+ {&Dsp1::attitudeB, 4, 0}, //0x11
|
|
|
+ {&Dsp1::project, 3, 3}, //0x06
|
|
|
+ {&Dsp1::memoryDump, 1, 1024}, //0x1f
|
|
|
+ {&Dsp1::range, 4, 1}, //0x18
|
|
|
+ {&Dsp1::objectiveB, 3, 3}, //0x1d
|
|
|
+ {0, 0, 0}, // 0x1a; the chip freezes
|
|
|
+ {&Dsp1::scalarB, 3, 1}, //0x1b
|
|
|
+ {&Dsp1::polar, 6, 3}, //0x1c
|
|
|
+ {&Dsp1::objectiveB, 3, 3}, //0x1d
|
|
|
+ {&Dsp1::target, 2, 2}, //0x0e
|
|
|
+ {&Dsp1::memoryDump, 1, 1024}, //0x1f
|
|
|
+
|
|
|
+ {&Dsp1::multiply2, 2, 1}, //0x20
|
|
|
+ {&Dsp1::attitudeC, 4, 0}, //0x21
|
|
|
+ {&Dsp1::parameter, 7, 4}, //0x02
|
|
|
+ {&Dsp1::subjectiveC, 3, 3}, //0x23
|
|
|
+ {&Dsp1::triangle, 2, 2}, //0x04
|
|
|
+ {&Dsp1::attitudeC, 4, 0}, //0x21
|
|
|
+ {&Dsp1::project, 3, 3}, //0x06
|
|
|
+ {&Dsp1::memorySize, 1, 1}, //0x2f
|
|
|
+ {&Dsp1::distance, 3, 1}, //0x28
|
|
|
+ {&Dsp1::objectiveC, 3, 3}, //0x2d
|
|
|
+ {0, 0, 0}, // 0x1a; the chip freezes
|
|
|
+ {&Dsp1::scalarC, 3, 1}, //0x2b
|
|
|
+ {&Dsp1::rotate, 3, 2}, //0x0c
|
|
|
+ {&Dsp1::objectiveC, 3, 3}, //0x2d
|
|
|
+ {&Dsp1::target, 2, 2}, //0x0e
|
|
|
+ {&Dsp1::memorySize, 1, 1}, //0x2f
|
|
|
+
|
|
|
+ {&Dsp1::inverse, 2, 2}, //0x10
|
|
|
+ {&Dsp1::attitudeA, 4, 0}, //0x01
|
|
|
+ {&Dsp1::parameter, 7, 4}, //0x02
|
|
|
+ {&Dsp1::subjectiveA, 3, 3}, //0x03
|
|
|
+ {&Dsp1::gyrate, 6, 3}, //0x14
|
|
|
+ {&Dsp1::attitudeA, 4, 0}, //0x01
|
|
|
+ {&Dsp1::project, 3, 3}, //0x06
|
|
|
+ {&Dsp1::memoryDump, 1, 1024}, //0x1f
|
|
|
+ {&Dsp1::range2, 4, 1}, //0x38
|
|
|
+ {&Dsp1::objectiveA, 3, 3}, //0x0d
|
|
|
+ {0, 0, 0}, // 0x1a; the chip freezes
|
|
|
+ {&Dsp1::scalarA, 3, 1}, //0x0b
|
|
|
+ {&Dsp1::polar, 6, 3}, //0x1c
|
|
|
+ {&Dsp1::objectiveA, 3, 3}, //0x0d
|
|
|
+ {&Dsp1::target, 2, 2}, //0x0e
|
|
|
+ {&Dsp1::memoryDump, 1, 1024}, //0x1f
|
|
|
+};
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+void Dsp1::memoryTest(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& Size = input[0];
|
|
|
+ int16& Result = output[0];
|
|
|
+
|
|
|
+ Result = 0x0000;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+void Dsp1::memoryDump(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ memcpy(output, DataRom, 1024);
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+void Dsp1::memorySize(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& Size = output[0];
|
|
|
+
|
|
|
+ Size = 0x0100;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// 16-bit multiplication
|
|
|
+
|
|
|
+void Dsp1::multiply(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& Multiplicand = input[0];
|
|
|
+ int16& Multiplier = input[1];
|
|
|
+ int16& Product = output[0];
|
|
|
+
|
|
|
+ Product = Multiplicand * Multiplier >> 15;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// 16-bit multiplication. 'Alternative' method. Can anyone check this carefully?
|
|
|
+
|
|
|
+void Dsp1::multiply2(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& Multiplicand = input[0];
|
|
|
+ int16& Multiplier = input[1];
|
|
|
+ int16& Product = output[0];
|
|
|
+
|
|
|
+ Product = (Multiplicand * Multiplier >> 15)+1;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// This command determines the inverse of a floating point decimal number.
|
|
|
+
|
|
|
+void Dsp1::inverse(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& Coefficient = input[0];
|
|
|
+ int16& Exponent = input[1];
|
|
|
+ int16& iCoefficient = output[0];
|
|
|
+ int16& iExponent = output[1];
|
|
|
+
|
|
|
+ inverse(Coefficient, Exponent, iCoefficient, iExponent);
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Vector component calculation. Determines the X and Y components for a
|
|
|
+// two-dimensional vector whose size and direction is known.
|
|
|
+// Y = Radius * sin(Angle)
|
|
|
+// X = Radius * cos(Angle)
|
|
|
+
|
|
|
+void Dsp1::triangle(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& Angle = input[0];
|
|
|
+ int16& Radius = input[1];
|
|
|
+ int16& Y = output[0];
|
|
|
+ int16& X = output[1];
|
|
|
+
|
|
|
+ Y = sin(Angle) * Radius >> 15;
|
|
|
+ X = cos(Angle) * Radius >> 15;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Determines the squared norm of a vector (X,Y,Z)
|
|
|
+// The output is Radius = X^2+Y^2+Z^2 (double integer)
|
|
|
+
|
|
|
+void Dsp1::radius(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& X = input[0];
|
|
|
+ int16& Y = input[1];
|
|
|
+ int16& Z = input[2];
|
|
|
+ int16& RadiusLow = output[0];
|
|
|
+ int16& RadiusHigh = output[1];
|
|
|
+
|
|
|
+ int32 Radius;
|
|
|
+
|
|
|
+ Radius = (X * X + Y * Y + Z * Z) << 1;
|
|
|
+ RadiusLow = static_cast<int16>(Radius);
|
|
|
+ RadiusHigh = static_cast<int16>(Radius>>16);
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Vector size comparison. This command compares the size of the vector (X,Y,Z) and the distance (R)
|
|
|
+// from a particular point, and so may be used to determine if a point is within the sphere or radius R.
|
|
|
+// The output is D = X^2+Y^2+Z^2-R^2
|
|
|
+
|
|
|
+void Dsp1::range(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& X = input[0];
|
|
|
+ int16& Y = input[1];
|
|
|
+ int16& Z = input[2];
|
|
|
+ int16& Radius = input[3];
|
|
|
+ int16& Range = output[0];
|
|
|
+
|
|
|
+ Range = (X * X + Y * Y + Z * Z - Radius * Radius) >> 15;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Vector size comparison. 'Alternative' method.
|
|
|
+
|
|
|
+void Dsp1::range2(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& X = input[0];
|
|
|
+ int16& Y = input[1];
|
|
|
+ int16& Z = input[2];
|
|
|
+ int16& Radius = input[3];
|
|
|
+ int16& Range = output[0];
|
|
|
+
|
|
|
+ Range = ((X * X + Y * Y + Z * Z - Radius * Radius) >> 15) + 1;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// This command calculates the norm of a (X,Y,Z) vector, or the distance from
|
|
|
+// the point (X,Y,Z) to (0,0,0), as you prefer to see it.
|
|
|
+// Distance = sqrt(X^2+Y^2+Z^2)
|
|
|
+// The square root of a number 'a' is calculated by doing this: you
|
|
|
+// write 'a' as b*2^2n, with 'b' between 1/4 and 1; then, you calculate
|
|
|
+// c=sqrt(b) by using lineal interpolation between points of a
|
|
|
+// look-up table and, finally, you output the result as c*2^n.
|
|
|
+
|
|
|
+void Dsp1::distance(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& X = input[0];
|
|
|
+ int16& Y = input[1];
|
|
|
+ int16& Z = input[2];
|
|
|
+ int16& Distance = output[0];
|
|
|
+
|
|
|
+ int32 Radius = X * X + Y * Y + Z * Z;
|
|
|
+
|
|
|
+ if (Radius == 0) Distance = 0;
|
|
|
+ else
|
|
|
+ {
|
|
|
+ int16 C, E;
|
|
|
+ normalizeDouble(Radius, C, E);
|
|
|
+ if (E & 1) C = C * 0x4000 >> 15;
|
|
|
+
|
|
|
+ int16 Pos = C * 0x0040 >> 15;
|
|
|
+
|
|
|
+ int16 Node1 = DataRom[0x00d5 + Pos];
|
|
|
+ int16 Node2 = DataRom[0x00d6 + Pos];
|
|
|
+
|
|
|
+ Distance = ((Node2 - Node1) * (C & 0x1ff) >> 9) + Node1;
|
|
|
+
|
|
|
+#if DSP1_VERSION < 0x0102
|
|
|
+ if (Pos & 1) Distance -= (Node2 - Node1);
|
|
|
+#endif
|
|
|
+ Distance >>= (E >> 1);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Determines the (X2, Y2) coordinates obtained by rotating (X1, Y1)
|
|
|
+// clockwise for an angle 'Angle'. The official documentation says
|
|
|
+// 'counterclockwise', but it's obviously wrong (surprise! :P)
|
|
|
+//
|
|
|
+// In matrix notation:
|
|
|
+// |X2| |cos(Angle) sin(Angle)| |X1|
|
|
|
+// | | = | | | |
|
|
|
+// |Y2| |-sin(Angle cos(Angle)| |Y1|
|
|
|
+
|
|
|
+void Dsp1::rotate(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& Angle = input[0];
|
|
|
+ int16& X1 = input[1];
|
|
|
+ int16& Y1 = input[2];
|
|
|
+ int16& X2 = output[0];
|
|
|
+ int16& Y2 = output[1];
|
|
|
+
|
|
|
+ X2 = (Y1 * sin(Angle) >> 15) + (X1 * cos(Angle) >> 15);
|
|
|
+ Y2 = (Y1 * cos(Angle) >> 15) - (X1 * sin(Angle) >> 15);
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Calculate the coordinates (X2, Y2, Z2) obtained when rotating (X1, Y1, Z1)
|
|
|
+// three-dimensionally. Rotation is done in the order of Az around the Z axis,
|
|
|
+// Ay around the Y axis and Ax around the X axis. As occur with the "attitude" commands
|
|
|
+// (see comments in the "gyrate" command), this doesn't match what explained in
|
|
|
+// the official documentation, but it's coherent with what it is done in the "attitude"
|
|
|
+// command (but not with the "gyrate" command).
|
|
|
+//
|
|
|
+// In matrix notation:
|
|
|
+// |X2| |1 0 0 | |cosRy 0 -sinRy| | cosRz sinRz 0| |X1|
|
|
|
+// |Y2| = |0 cosRx sinRx| | 0 1 0 | |-sinRz cosRz 0| |Y1|
|
|
|
+// |Z2| |0 -sinRx cosRx| |sinRy 0 cosRy| | 0 0 1| |Z1|
|
|
|
+
|
|
|
+void Dsp1::polar(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& Az = input[0];
|
|
|
+ int16& Ay = input[1];
|
|
|
+ int16& Ax = input[2];
|
|
|
+ int16& X1 = input[3];
|
|
|
+ int16& Y1 = input[4];
|
|
|
+ int16& Z1 = input[5];
|
|
|
+ int16& X2 = output[0];
|
|
|
+ int16& Y2 = output[1];
|
|
|
+ int16& Z2 = output[2];
|
|
|
+
|
|
|
+ int16 X, Y, Z;
|
|
|
+
|
|
|
+ // Rotate Around Z
|
|
|
+ X = (Y1 * sin(Az) >> 15) + (X1 * cos(Az) >> 15);
|
|
|
+ Y = (Y1 * cos(Az) >> 15) - (X1 * sin(Az) >> 15);
|
|
|
+ X1 = X; Y1 = Y;
|
|
|
+
|
|
|
+ // Rotate Around Y
|
|
|
+ Z = (X1 * sin(Ay) >> 15) + (Z1 * cos(Ay) >> 15);
|
|
|
+ X = (X1 * cos(Ay) >> 15) - (Z1 * sin(Ay) >> 15);
|
|
|
+ X2 = X; Z1 = Z;
|
|
|
+
|
|
|
+ // Rotate Around X
|
|
|
+ Y = (Z1 * sin(Ax) >> 15) + (Y1 * cos(Ax) >> 15);
|
|
|
+ Z = (Z1 * cos(Ax) >> 15) - (Y1 * sin(Ax) >> 15);
|
|
|
+ Y2 = Y; Z2 = Z;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Set up the elements of an "attitude matrix" (there are other ones):
|
|
|
+// S | cosRz sinRz 0| |cosRy 0 -sinRy| |1 0 0 |
|
|
|
+// MatrixA = - |-sinRz cosRz 0| | 0 1 0 | |0 cosRx sinRx|
|
|
|
+// 2 | 0 0 1| |sinRy 0 cosRy| |0 -sinRx cosRx|
|
|
|
+// This matrix is thought to be used within the following framework:
|
|
|
+// let's suppose we define positive rotations around a system of orthogonal axes in this manner:
|
|
|
+// a rotation of +90 degrees around axis3 converts axis2 into axis1
|
|
|
+// a rotation of +90 degrees around axis2 converts axis1 into axis3
|
|
|
+// a rotation of +90 degrees around axis1 converts axis3 into axis2
|
|
|
+// and let's suppose that we have defined a new orthonormal axes system (FLU)
|
|
|
+// by doing the following operations about the standard one (XYZ):
|
|
|
+// first rotating the XYZ system around Z by an angle Rz (obtaining X'Y'Z'),
|
|
|
+// then rotating the resulting system around Y by an angle Ry (obtaining X''Y''Z'')
|
|
|
+// and, finally, rotating the resulting system around X by an angle Rx (obtaining FLU)
|
|
|
+// This FLU (forward/left/up) system represents an "attitude" and, then, the matrix here defined
|
|
|
+// is the change of coordinates matrix that transform coordinates in the FLU
|
|
|
+// system (the "object coordinates") into the standard XYZ system (the "global coordinates"),
|
|
|
+// multiplied by a scale factor S/2, that is:
|
|
|
+// |x| S |f|
|
|
|
+// |y| * - = MatrixA * |l|
|
|
|
+// |z| 2 |u|
|
|
|
+// In a similar way, if we use the transpose of the matrix, we can transform global coordinates
|
|
|
+// into object coordinates:
|
|
|
+// |f| S |x|
|
|
|
+// |l| * - = MatrixA_transposed * |y|
|
|
|
+// |u| 2 |z|
|
|
|
+//
|
|
|
+// input[0]: S
|
|
|
+// input[1]: Rz
|
|
|
+// input[2]: Ry
|
|
|
+// input[3]: Rx
|
|
|
+
|
|
|
+void Dsp1::attitudeA(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& S = input[0];
|
|
|
+ int16& Rz = input[1];
|
|
|
+ int16& Ry = input[2];
|
|
|
+ int16& Rx = input[3];
|
|
|
+
|
|
|
+ int16 SinRz = sin(Rz);
|
|
|
+ int16 CosRz = cos(Rz);
|
|
|
+ int16 SinRy = sin(Ry);
|
|
|
+ int16 CosRy = cos(Ry);
|
|
|
+ int16 SinRx = sin(Rx);
|
|
|
+ int16 CosRx = cos(Rx);
|
|
|
+
|
|
|
+ S >>= 1;
|
|
|
+
|
|
|
+ shared.MatrixA[0][0] = (S * CosRz >> 15) * CosRy >> 15;
|
|
|
+ shared.MatrixA[0][1] = ((S * SinRz >> 15) * CosRx >> 15) + (((S * CosRz >> 15) * SinRx >> 15) * SinRy >> 15);
|
|
|
+ shared.MatrixA[0][2] = ((S * SinRz >> 15) * SinRx >> 15) - (((S * CosRz >> 15) * CosRx >> 15) * SinRy >> 15);
|
|
|
+
|
|
|
+ shared.MatrixA[1][0] = -((S * SinRz >> 15) * CosRy >> 15);
|
|
|
+ shared.MatrixA[1][1] = ((S * CosRz >> 15) * CosRx >> 15) - (((S * SinRz >> 15) * SinRx >> 15) * SinRy >> 15);
|
|
|
+ shared.MatrixA[1][2] = ((S * CosRz >> 15) * SinRx >> 15) + (((S * SinRz >> 15) * CosRx >> 15) * SinRy >> 15);
|
|
|
+
|
|
|
+ shared.MatrixA[2][0] = S * SinRy >> 15;
|
|
|
+ shared.MatrixA[2][1] = -((S * SinRx >> 15) * CosRy >> 15);
|
|
|
+ shared.MatrixA[2][2] = (S * CosRx >> 15) * CosRy >> 15;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Same than 'attitudeA', but with a difference attitude matrix (matrixB)
|
|
|
+
|
|
|
+void Dsp1::attitudeB(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& S = input[0];
|
|
|
+ int16& Rz = input[1];
|
|
|
+ int16& Ry = input[2];
|
|
|
+ int16& Rx = input[3];
|
|
|
+
|
|
|
+ int16 SinRz = sin(Rz);
|
|
|
+ int16 CosRz = cos(Rz);
|
|
|
+ int16 SinRy = sin(Ry);
|
|
|
+ int16 CosRy = cos(Ry);
|
|
|
+ int16 SinRx = sin(Rx);
|
|
|
+ int16 CosRx = cos(Rx);
|
|
|
+
|
|
|
+ S >>= 1;
|
|
|
+
|
|
|
+ shared.MatrixB[0][0] = (S * CosRz >> 15) * CosRy >> 15;
|
|
|
+ shared.MatrixB[0][1] = ((S * SinRz >> 15) * CosRx >> 15) + (((S * CosRz >> 15) * SinRx >> 15) * SinRy >> 15);
|
|
|
+ shared.MatrixB[0][2] = ((S * SinRz >> 15) * SinRx >> 15) - (((S * CosRz >> 15) * CosRx >> 15) * SinRy >> 15);
|
|
|
+
|
|
|
+ shared.MatrixB[1][0] = -((S * SinRz >> 15) * CosRy >> 15);
|
|
|
+ shared.MatrixB[1][1] = ((S * CosRz >> 15) * CosRx >> 15) - (((S * SinRz >> 15) * SinRx >> 15) * SinRy >> 15);
|
|
|
+ shared.MatrixB[1][2] = ((S * CosRz >> 15) * SinRx >> 15) + (((S * SinRz >> 15) * CosRx >> 15) * SinRy >> 15);
|
|
|
+
|
|
|
+ shared.MatrixB[2][0] = S * SinRy >> 15;
|
|
|
+ shared.MatrixB[2][1] = -((S * SinRx >> 15) * CosRy >> 15);
|
|
|
+ shared.MatrixB[2][2] = (S * CosRx >> 15) * CosRy >> 15;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Same than 'attitudeA', but with a difference attitude matrix (matrixC)
|
|
|
+
|
|
|
+void Dsp1::attitudeC(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& S = input[0];
|
|
|
+ int16& Rz = input[1];
|
|
|
+ int16& Ry = input[2];
|
|
|
+ int16& Rx = input[3];
|
|
|
+
|
|
|
+ int16 SinRz = sin(Rz);
|
|
|
+ int16 CosRz = cos(Rz);
|
|
|
+ int16 SinRy = sin(Ry);
|
|
|
+ int16 CosRy = cos(Ry);
|
|
|
+ int16 SinRx = sin(Rx);
|
|
|
+ int16 CosRx = cos(Rx);
|
|
|
+
|
|
|
+ S >>= 1;
|
|
|
+
|
|
|
+ shared.MatrixC[0][0] = (S * CosRz >> 15) * CosRy >> 15;
|
|
|
+ shared.MatrixC[0][1] = ((S * SinRz >> 15) * CosRx >> 15) + (((S * CosRz >> 15) * SinRx >> 15) * SinRy >> 15);
|
|
|
+ shared.MatrixC[0][2] = ((S * SinRz >> 15) * SinRx >> 15) - (((S * CosRz >> 15) * CosRx >> 15) * SinRy >> 15);
|
|
|
+
|
|
|
+ shared.MatrixC[1][0] = -((S * SinRz >> 15) * CosRy >> 15);
|
|
|
+ shared.MatrixC[1][1] = ((S * CosRz >> 15) * CosRx >> 15) - (((S * SinRz >> 15) * SinRx >> 15) * SinRy >> 15);
|
|
|
+ shared.MatrixC[1][2] = ((S * CosRz >> 15) * SinRx >> 15) + (((S * SinRz >> 15) * CosRx >> 15) * SinRy >> 15);
|
|
|
+
|
|
|
+ shared.MatrixC[2][0] = S * SinRy >> 15;
|
|
|
+ shared.MatrixC[2][1] = -((S * SinRx >> 15) * CosRy >> 15);
|
|
|
+ shared.MatrixC[2][2] = (S * CosRx >> 15) * CosRy >> 15;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Convert global coordinates (X,Y,Z) to object coordinates (F,L,U)
|
|
|
+// See the comment in "attitudeA" for a explanation about the calculation.
|
|
|
+//
|
|
|
+// input[0]: X ; input[1]: Y ; input[2]: Z
|
|
|
+// output[0]: F ; output[1]: L ; output[2]: U
|
|
|
+
|
|
|
+void Dsp1::objectiveA(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& X = input[0];
|
|
|
+ int16& Y = input[1];
|
|
|
+ int16& Z = input[2];
|
|
|
+ int16& F = output[0];
|
|
|
+ int16& L = output[1];
|
|
|
+ int16& U = output[2];
|
|
|
+
|
|
|
+ F = (shared.MatrixA[0][0] * X >> 15) + (shared.MatrixA[1][0] * Y >> 15) + (shared.MatrixA[2][0] * Z >> 15);
|
|
|
+ L = (shared.MatrixA[0][1] * X >> 15) + (shared.MatrixA[1][1] * Y >> 15) + (shared.MatrixA[2][1] * Z >> 15);
|
|
|
+ U = (shared.MatrixA[0][2] * X >> 15) + (shared.MatrixA[1][2] * Y >> 15) + (shared.MatrixA[2][2] * Z >> 15);
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Same than 'objectiveA', but for the 'B' attitude
|
|
|
+
|
|
|
+void Dsp1::objectiveB(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& X = input[0];
|
|
|
+ int16& Y = input[1];
|
|
|
+ int16& Z = input[2];
|
|
|
+ int16& F = output[0];
|
|
|
+ int16& L = output[1];
|
|
|
+ int16& U = output[2];
|
|
|
+
|
|
|
+ F = (shared.MatrixB[0][0] * X >> 15) + (shared.MatrixB[1][0] * Y >> 15) + (shared.MatrixB[2][0] * Z >> 15);
|
|
|
+ L = (shared.MatrixB[0][1] * X >> 15) + (shared.MatrixB[1][1] * Y >> 15) + (shared.MatrixB[2][1] * Z >> 15);
|
|
|
+ U = (shared.MatrixB[0][2] * X >> 15) + (shared.MatrixB[1][2] * Y >> 15) + (shared.MatrixB[2][2] * Z >> 15);
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Same than 'objectiveA', but for the 'C' attitude
|
|
|
+
|
|
|
+void Dsp1::objectiveC(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& X = input[0];
|
|
|
+ int16& Y = input[1];
|
|
|
+ int16& Z = input[2];
|
|
|
+ int16& F = output[0];
|
|
|
+ int16& L = output[1];
|
|
|
+ int16& U = output[2];
|
|
|
+
|
|
|
+ F = (shared.MatrixC[0][0] * X >> 15) + (shared.MatrixC[1][0] * Y >> 15) + (shared.MatrixC[2][0] * Z >> 15);
|
|
|
+ L = (shared.MatrixC[0][1] * X >> 15) + (shared.MatrixC[1][1] * Y >> 15) + (shared.MatrixC[2][1] * Z >> 15);
|
|
|
+ U = (shared.MatrixC[0][2] * X >> 15) + (shared.MatrixC[1][2] * Y >> 15) + (shared.MatrixC[2][2] * Z >> 15);
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Convert object coordinates (F,L,U) to object coordinates (X,Y,Z)
|
|
|
+// See the comment in "attitudeA" for a explanation about the calculation.
|
|
|
+//
|
|
|
+// input[0]: F ; input[1]: L ; input[2]: U
|
|
|
+// output[0]: X ; output[1]: Y ; output[2]: Z
|
|
|
+
|
|
|
+void Dsp1::subjectiveA(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& F = input[0];
|
|
|
+ int16& L = input[1];
|
|
|
+ int16& U = input[2];
|
|
|
+ int16& X = output[0];
|
|
|
+ int16& Y = output[1];
|
|
|
+ int16& Z = output[2];
|
|
|
+
|
|
|
+ X = (shared.MatrixA[0][0] * F >> 15) + (shared.MatrixA[0][1] * L >> 15) + (shared.MatrixA[0][2] * U >> 15);
|
|
|
+ Y = (shared.MatrixA[1][0] * F >> 15) + (shared.MatrixA[1][1] * L >> 15) + (shared.MatrixA[1][2] * U >> 15);
|
|
|
+ Z = (shared.MatrixA[2][0] * F >> 15) + (shared.MatrixA[2][1] * L >> 15) + (shared.MatrixA[2][2] * U >> 15);
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Same than 'subjectiveA', but for the 'B' attitude
|
|
|
+
|
|
|
+void Dsp1::subjectiveB(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& F = input[0];
|
|
|
+ int16& L = input[1];
|
|
|
+ int16& U = input[2];
|
|
|
+ int16& X = output[0];
|
|
|
+ int16& Y = output[1];
|
|
|
+ int16& Z = output[2];
|
|
|
+
|
|
|
+ X = (shared.MatrixB[0][0] * F >> 15) + (shared.MatrixB[0][1] * L >> 15) + (shared.MatrixB[0][2] * U >> 15);
|
|
|
+ Y = (shared.MatrixB[1][0] * F >> 15) + (shared.MatrixB[1][1] * L >> 15) + (shared.MatrixB[1][2] * U >> 15);
|
|
|
+ Z = (shared.MatrixB[2][0] * F >> 15) + (shared.MatrixB[2][1] * L >> 15) + (shared.MatrixB[2][2] * U >> 15);
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Same than 'subjectiveA', but for the 'C' attitude
|
|
|
+
|
|
|
+void Dsp1::subjectiveC(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& F = input[0];
|
|
|
+ int16& L = input[1];
|
|
|
+ int16& U = input[2];
|
|
|
+ int16& X = output[0];
|
|
|
+ int16& Y = output[1];
|
|
|
+ int16& Z = output[2];
|
|
|
+
|
|
|
+ X = (shared.MatrixC[0][0] * F >> 15) + (shared.MatrixC[0][1] * L >> 15) + (shared.MatrixC[0][2] * U >> 15);
|
|
|
+ Y = (shared.MatrixC[1][0] * F >> 15) + (shared.MatrixC[1][1] * L >> 15) + (shared.MatrixC[1][2] * U >> 15);
|
|
|
+ Z = (shared.MatrixC[2][0] * F >> 15) + (shared.MatrixC[2][1] * L >> 15) + (shared.MatrixC[2][2] * U >> 15);
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// This command calculates the inner product (S) of a vector (X,Y,Z) and
|
|
|
+// the first column of MatrixA. It should be noted that that first column
|
|
|
+// represent the global coordinates of an unity vector in the forward
|
|
|
+// direction in the object coordinate system (coordinates (1,0,0) in the FLU
|
|
|
+// axes system).
|
|
|
+//
|
|
|
+// input[0]: X ; input[1]: Y ; input[2]: Z
|
|
|
+// output[0]: S
|
|
|
+
|
|
|
+void Dsp1::scalarA(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& X = input[0];
|
|
|
+ int16& Y = input[1];
|
|
|
+ int16& Z = input[2];
|
|
|
+ int16& S = output[0];
|
|
|
+
|
|
|
+ S = (X * shared.MatrixA[0][0] + Y * shared.MatrixA[1][0] + Z * shared.MatrixA[2][0]) >> 15;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Same than 'scalarA', but for the 'B' attitude
|
|
|
+
|
|
|
+void Dsp1::scalarB(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& X = input[0];
|
|
|
+ int16& Y = input[1];
|
|
|
+ int16& Z = input[2];
|
|
|
+ int16& S = output[0];
|
|
|
+
|
|
|
+ S = (X * shared.MatrixB[0][0] + Y * shared.MatrixB[1][0] + Z * shared.MatrixB[2][0]) >> 15;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Same than 'scalarA', but for the 'C' attitude
|
|
|
+
|
|
|
+void Dsp1::scalarC(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& X = input[0];
|
|
|
+ int16& Y = input[1];
|
|
|
+ int16& Z = input[2];
|
|
|
+ int16& S = output[0];
|
|
|
+
|
|
|
+ S = (X * shared.MatrixC[0][0] + Y * shared.MatrixC[1][0] + Z * shared.MatrixC[2][0]) >> 15;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// This command determines the final attitude angles after the body with attitude angles (Ax, Ay, Az) with
|
|
|
+// respect to the global coordinates is rotated by the minor angular displacements (DeltaF, DeltaL, DeltaU).
|
|
|
+// It means that the XYZ axes are rotated by (Ax, Ay, Az) to obtain the FLU axes and, then, these
|
|
|
+// are rotated by (DeltaF, DeltaL, DeltaU). The command calculates and return the new FLU angles respect to the
|
|
|
+// XYZ system (Rx, Ry, Rz)
|
|
|
+// The formulae are:
|
|
|
+// Rx = Ax + (DeltaU*sin(Ay)+DeltaF*cos(Ay))
|
|
|
+// Ry = Ay + DeltaL - tan(Ax)*(DeltaU*cos(Ay)+DeltaF*sin(Ay))
|
|
|
+// Rz = Az + sec(Ax)*(DeltaU*cos(Ay)-DeltaF*sin(Ay))
|
|
|
+//
|
|
|
+// Now the discussion: according to the official documentation, as described in various commands, you pass from
|
|
|
+// XYZ to FLU by doing the rotations in the order Y, X, Z. In this command, the formulae are coherent with the
|
|
|
+// fact that Y is the first axis to do a rotation around it. However, in the "attitude" command, while the official
|
|
|
+// document describe it that way, we have discovered, when reverse engineering the command, that the calculated
|
|
|
+// matrix do the rotation around Y in the second place. This incoherent behaviour of various commands is, in my
|
|
|
+// opinion, a pretty severe implementation error. However, if you only use small "minor displacements", the error term
|
|
|
+// introduced by that incoherence should be almost negligible.
|
|
|
+
|
|
|
+void Dsp1::gyrate(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& Az = input[0];
|
|
|
+ int16& Ax = input[1];
|
|
|
+ int16& Ay = input[2];
|
|
|
+ int16& U = input[3];
|
|
|
+ int16& F = input[4];
|
|
|
+ int16& L = input[5];
|
|
|
+ int16& Rz = output[0];
|
|
|
+ int16& Rx = output[1];
|
|
|
+ int16& Ry = output[2];
|
|
|
+
|
|
|
+ int16 CSec, ESec, CSin, C, E;
|
|
|
+ int16 SinAy = sin(Ay);
|
|
|
+ int16 CosAy = cos(Ay);
|
|
|
+
|
|
|
+ inverse(cos(Ax), 0, CSec, ESec);
|
|
|
+
|
|
|
+ // Rotation Around Z
|
|
|
+ normalizeDouble(U * CosAy - F * SinAy, C, E);
|
|
|
+
|
|
|
+ E = ESec - E;
|
|
|
+
|
|
|
+ normalize(C * CSec >> 15, C, E);
|
|
|
+
|
|
|
+ Rz = Az + denormalizeAndClip(C, E);
|
|
|
+
|
|
|
+ // Rotation Around X
|
|
|
+ Rx = Ax + (U * SinAy >> 15) + (F * CosAy >> 15);
|
|
|
+
|
|
|
+ // Rotation Around Y
|
|
|
+ normalizeDouble(U * CosAy + F * SinAy, C, E);
|
|
|
+
|
|
|
+ E = ESec - E;
|
|
|
+
|
|
|
+ normalize(sin(Ax), CSin, E);
|
|
|
+
|
|
|
+ normalize(-(C * (CSec * CSin >> 15) >> 15), C, E);
|
|
|
+
|
|
|
+ Ry = Ay + denormalizeAndClip(C, E) + L;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+const int16 Dsp1::MaxAZS_Exp[16] = {
|
|
|
+ 0x38b4, 0x38b7, 0x38ba, 0x38be, 0x38c0, 0x38c4, 0x38c7, 0x38ca,
|
|
|
+ 0x38ce, 0x38d0, 0x38d4, 0x38d7, 0x38da, 0x38dd, 0x38e0, 0x38e4
|
|
|
+};
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+
|
|
|
+// Set-up the projection framework. Besides returning some values, it store in RAM some values that
|
|
|
+// will be used by the other three projection commands (raster, target an project)
|
|
|
+// Input:
|
|
|
+// (Fx, Fy, Fz)-> coordinates of base point (global coordinates)
|
|
|
+// Lfe-> distance between the base point and the viewpoint (center of projection)
|
|
|
+// Les-> distance between the base point and the screen
|
|
|
+// Aas-> azimuth angle (0 degrees is east; 90 degrees is north)
|
|
|
+// Azs-> zenith angle (0 degrees is zenith)
|
|
|
+// Output:
|
|
|
+// Vof-> raster line of imaginary center (whatever it means ;) )
|
|
|
+// Vva-> raster line representing the horizon line
|
|
|
+// (Cx, Cy)-> coordinates of the projection of the center of the screen over the ground (ground coordinates)
|
|
|
+
|
|
|
+void Dsp1::parameter(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& Fx = input[0];
|
|
|
+ int16& Fy = input[1];
|
|
|
+ int16& Fz = input[2];
|
|
|
+ int16& Lfe = input[3];
|
|
|
+ int16& Les = input[4];
|
|
|
+ int16& Aas = input[5];
|
|
|
+ int16& Azs = input[6];
|
|
|
+ int16& Vof = output[0];
|
|
|
+ int16& Vva = output[1];
|
|
|
+ int16& Cx = output[2];
|
|
|
+ int16& Cy = output[3];
|
|
|
+
|
|
|
+ int16 CSec, C, E;
|
|
|
+ int16 LfeNx, LfeNy, LfeNz;
|
|
|
+ int16 LesNx, LesNy, LesNz;
|
|
|
+
|
|
|
+ // Copy Zenith angle for clipping
|
|
|
+ int16 AZS = Azs;
|
|
|
+
|
|
|
+ // Store Les and his coefficient and exponent when normalized
|
|
|
+ shared.Les = Les;
|
|
|
+ shared.E_Les=0;
|
|
|
+ normalize(Les, shared.C_Les, shared.E_Les);
|
|
|
+
|
|
|
+ // Store Sine and Cosine of Azimuth and Zenith angle
|
|
|
+ shared.SinAas = sin(Aas);
|
|
|
+ shared.CosAas = cos(Aas);
|
|
|
+ shared.SinAzs = sin(Azs);
|
|
|
+ shared.CosAzs = cos(Azs);
|
|
|
+
|
|
|
+ // normal vector to the screen (norm 1, points toward the center of projection)
|
|
|
+ shared.Nx = shared.SinAzs * -shared.SinAas >> 15;
|
|
|
+ shared.Ny = shared.SinAzs * shared.CosAas >> 15;
|
|
|
+ shared.Nz = shared.CosAzs * 0x7fff >> 15;
|
|
|
+
|
|
|
+ // horizontal vector of the screen (Hz=0, norm 1, points toward the right of the screen)
|
|
|
+ shared.Hx = shared.CosAas*0x7fff>>15;
|
|
|
+ shared.Hy = shared.SinAas*0x7fff>>15;
|
|
|
+
|
|
|
+ // vertical vector of the screen (norm 1, points toward the top of the screen)
|
|
|
+ shared.Vx = shared.CosAzs*-shared.SinAas>>15;
|
|
|
+ shared.Vy = shared.CosAzs*shared.CosAas>>15;
|
|
|
+ shared.Vz = -shared.SinAzs*0x7fff>>15;
|
|
|
+
|
|
|
+ LfeNx = Lfe*shared.Nx>>15;
|
|
|
+ LfeNy = Lfe*shared.Ny>>15;
|
|
|
+ LfeNz = Lfe*shared.Nz>>15;
|
|
|
+
|
|
|
+ // Center of Projection
|
|
|
+ shared.CentreX = Fx+LfeNx;
|
|
|
+ shared.CentreY = Fy+LfeNy;
|
|
|
+ shared.CentreZ = Fz+LfeNz;
|
|
|
+
|
|
|
+ LesNx = Les*shared.Nx>>15;
|
|
|
+ LesNy = Les*shared.Ny>>15;
|
|
|
+ LesNz = Les*shared.Nz>>15;
|
|
|
+
|
|
|
+ // center of the screen (global coordinates)
|
|
|
+ shared.Gx=shared.CentreX-LesNx;
|
|
|
+ shared.Gy=shared.CentreY-LesNy;
|
|
|
+ shared.Gz=shared.CentreZ-LesNz;
|
|
|
+
|
|
|
+
|
|
|
+ E = 0;
|
|
|
+ normalize(shared.CentreZ, C, E);
|
|
|
+
|
|
|
+ shared.CentreZ_C = C;
|
|
|
+ shared.CentreZ_E = E;
|
|
|
+
|
|
|
+ // Determine clip boundary and clip Zenith angle if necessary
|
|
|
+ // (Why to clip? Maybe to avoid the screen can only show sky with no ground? Only a guess...)
|
|
|
+ int16 MaxAZS = MaxAZS_Exp[-E];
|
|
|
+
|
|
|
+ if (AZS < 0) {
|
|
|
+ MaxAZS = -MaxAZS;
|
|
|
+ if (AZS < MaxAZS + 1) AZS = MaxAZS + 1;
|
|
|
+ } else {
|
|
|
+ if (AZS > MaxAZS) AZS = MaxAZS;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Store Sine and Cosine of clipped Zenith angle
|
|
|
+ shared.SinAZS = sin(AZS);
|
|
|
+ shared.CosAZS = cos(AZS);
|
|
|
+
|
|
|
+ // calculate the separation of (cx, cy) from the projection of
|
|
|
+ // the 'centre of projection' over the ground... (CentreZ*tg(AZS))
|
|
|
+ inverse(shared.CosAZS, 0, shared.SecAZS_C1, shared.SecAZS_E1);
|
|
|
+ normalize(C * shared.SecAZS_C1 >> 15, C, E);
|
|
|
+ E += shared.SecAZS_E1;
|
|
|
+ C = denormalizeAndClip(C, E) * shared.SinAZS >> 15;
|
|
|
+
|
|
|
+ // ... and then take into account the position of the centre of
|
|
|
+ // projection and the azimuth angle
|
|
|
+ shared.CentreX += C * shared.SinAas >> 15;
|
|
|
+ shared.CentreY -= C * shared.CosAas >> 15;
|
|
|
+
|
|
|
+ Cx = shared.CentreX;
|
|
|
+ Cy = shared.CentreY;
|
|
|
+
|
|
|
+ // Raster number of imaginary center and horizontal line
|
|
|
+ Vof = 0;
|
|
|
+
|
|
|
+ if ((Azs != AZS) || (Azs == MaxAZS))
|
|
|
+ {
|
|
|
+ // correct vof and vva when Azs is outside the 'non-clipping interval'
|
|
|
+ // we have only some few Taylor coefficients, so we cannot guess which ones
|
|
|
+ // are the approximated functions and, what is worse, we don't know why
|
|
|
+ // the own clipping stuff (and, particularly, this correction) is done
|
|
|
+ if (Azs == -32768) Azs = -32767;
|
|
|
+
|
|
|
+ C = Azs - MaxAZS;
|
|
|
+ if (C >= 0) C--;
|
|
|
+ int16 Aux = ~(C << 2);
|
|
|
+
|
|
|
+ // Vof += x+(1/3)*x^3, where x ranges from 0 to PI/4 when Azs-MaxAZS goes from 0 to 0x2000
|
|
|
+ C = Aux * DataRom[0x0328] >> 15;
|
|
|
+ C = (C * Aux >> 15) + DataRom[0x0327];
|
|
|
+ Vof -= (C * Aux >> 15) * Les >> 15;
|
|
|
+
|
|
|
+ // CosAZS *= 1+(1/2)*x^2+(5/24)*x^24, where x ranges from 0 to PI/4 when Azs-MaxAZS goes from 0 to 0x2000
|
|
|
+ C = Aux * Aux >> 15;
|
|
|
+ Aux = (C * DataRom[0x0324] >> 15) + DataRom[0x0325];
|
|
|
+ shared.CosAZS += (C * Aux >> 15) * shared.CosAZS >> 15;
|
|
|
+ }
|
|
|
+
|
|
|
+ // vertical offset of the screen with regard to the horizontal plane
|
|
|
+ // containing the centre of projection
|
|
|
+ shared.VOffset = Les * shared.CosAZS >> 15;
|
|
|
+
|
|
|
+ // The horizon line (the line in the screen that is crossed by the horizon plane
|
|
|
+ // -the horizontal plane containing the 'centre of projection'-),
|
|
|
+ // will be at distance Les*cotg(AZS) from the centre of the screen. This is difficult
|
|
|
+ // to explain but easily seen in a graph. To better see it, consider it in this way:
|
|
|
+ // Les*tg(AZS-90), draw some lines and apply basic trigonometry. ;)
|
|
|
+ inverse(shared.SinAZS, 0, CSec, E);
|
|
|
+ normalize(shared.VOffset, C, E);
|
|
|
+ normalize(C * CSec >> 15, C, E);
|
|
|
+
|
|
|
+ if (C == -32768) { C >>= 1; E++; }
|
|
|
+
|
|
|
+ Vva = denormalizeAndClip(-C, E);
|
|
|
+
|
|
|
+ // Store Secant of clipped Zenith angle
|
|
|
+ inverse(shared.CosAZS, 0, shared.SecAZS_C2, shared.SecAZS_E2);
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Calculates the matrix which transform an object situated on a raster line (Vs) into
|
|
|
+// his projection over the ground. The modified SecAZS is used here, so
|
|
|
+// i don't understand the fine details, but, basically, it's done
|
|
|
+// this way: The vertical offset between the point of projection and the
|
|
|
+// raster line is calculated (Vs*SinAzs>>15)+VOffset, then the height of
|
|
|
+// the center of projection is measured in that units (*CentreZ_C). If, now
|
|
|
+// you consider the "reference case" (center of projection at an unit of height),
|
|
|
+// the projection of a thin strip containing the raster line will have the same
|
|
|
+// width (as the raster line would be on the ground in this case, but will suffer a
|
|
|
+// change of scale in height (as the ground and the vertical axis would form an angle of 180-Azs degrees).
|
|
|
+// This scale factor, when the angle 'center of screen-center of projection-raster line' is small,
|
|
|
+// can be aproximated by the one of the center of the screen, 1/cos(Azs).(**) (Here is when it's used
|
|
|
+// SecAZS). By last, you have to consider the effect of the azimuth angle Aas, and you are done.
|
|
|
+//
|
|
|
+// Using matrix notation:
|
|
|
+// |A B| Centre_ZS | cos(Aas) -sin(Aas)| |1 0|
|
|
|
+// ProjectionMatrix = | | = ----------- * | | * | |
|
|
|
+// |C D| Vs*sin(Azs) |sin(Aas) cos(Aas)| |0 sec(Azs)|
|
|
|
+//
|
|
|
+// (**)
|
|
|
+// If Les=1, the vertical offset between the center
|
|
|
+// of projection and the center of the screen is Cos(Azs); then, if the vertical
|
|
|
+// offset is 1, the ratio of the projection over the ground respect to the
|
|
|
+// line on the screen is 1/cos(Azs).
|
|
|
+
|
|
|
+void Dsp1::raster(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& Vs = input[0];
|
|
|
+ int16& An = output[0];
|
|
|
+ int16& Bn = output[1];
|
|
|
+ int16& Cn = output[2];
|
|
|
+ int16& Dn = output[3];
|
|
|
+
|
|
|
+ int16 C, E, C1, E1;
|
|
|
+
|
|
|
+ inverse((Vs * shared.SinAzs >> 15) + shared.VOffset, 7, C, E);
|
|
|
+
|
|
|
+ E += shared.CentreZ_E;
|
|
|
+ C1 = C * shared.CentreZ_C >> 15;
|
|
|
+
|
|
|
+ E1 = E + shared.SecAZS_E2;
|
|
|
+
|
|
|
+ normalize(C1, C, E);
|
|
|
+ C = denormalizeAndClip(C, E);
|
|
|
+
|
|
|
+ An = C * shared.CosAas >> 15;
|
|
|
+ Cn = C * shared.SinAas >> 15;
|
|
|
+
|
|
|
+ normalize(C1 * shared.SecAZS_C2 >> 15, C, E1);
|
|
|
+ C = denormalizeAndClip(C, E1);
|
|
|
+
|
|
|
+ Bn = C * -shared.SinAas >> 15;
|
|
|
+ Dn = C * shared.CosAas >> 15;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Calculate the projection over the ground of a selected point of screen
|
|
|
+// It simply apply the projection matrix described in the "Raster" command
|
|
|
+// to the vector (H,V) transposed, and add the result to the position of
|
|
|
+// the centre of projection.
|
|
|
+// The only special point to take into account is the directions on the screen:
|
|
|
+// H is positive rightward, but V is positive downward; this is why
|
|
|
+// the signs take that configuration
|
|
|
+
|
|
|
+void Dsp1::target(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& H = input[0];
|
|
|
+ int16& V = input[1];
|
|
|
+ int16& X = output[0];
|
|
|
+ int16& Y = output[1];
|
|
|
+
|
|
|
+ int16 C, E, C1, E1;
|
|
|
+
|
|
|
+ inverse((V * shared.SinAzs >> 15) + shared.VOffset, 8, C, E);
|
|
|
+
|
|
|
+ E += shared.CentreZ_E;
|
|
|
+ C1 = C * shared.CentreZ_C >> 15;
|
|
|
+
|
|
|
+ E1 = E + shared.SecAZS_E1;
|
|
|
+
|
|
|
+ H <<= 8;
|
|
|
+ normalize(C1, C, E);
|
|
|
+ C = denormalizeAndClip(C, E) * H >> 15;
|
|
|
+
|
|
|
+ X = shared.CentreX + (C * shared.CosAas >> 15);
|
|
|
+ Y = shared.CentreY - (C * shared.SinAas >> 15);
|
|
|
+
|
|
|
+ V <<= 8;
|
|
|
+ normalize(C1 * shared.SecAZS_C1 >> 15, C, E1);
|
|
|
+ C = denormalizeAndClip(C, E1) * V >> 15;
|
|
|
+
|
|
|
+ X += C * -shared.SinAas >> 15;
|
|
|
+ Y += C * shared.CosAas >> 15;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Calculation of the projection over the screen (H,V) of an object (X,Y,Z) and his
|
|
|
+// 'enlargement ratio' (M). The positive directions on the screen are as described
|
|
|
+// in the targe command. M is scaled down by 2^-7, that is, M==0x0100 means ratio 1:1
|
|
|
+
|
|
|
+ void Dsp1::project(int16 *input, int16 *output)
|
|
|
+{
|
|
|
+ int16& X = input[0];
|
|
|
+ int16& Y = input[1];
|
|
|
+ int16& Z = input[2];
|
|
|
+ int16& H = output[0];
|
|
|
+ int16& V = output[1];
|
|
|
+ int16& M = output[2];
|
|
|
+
|
|
|
+ int32 aux, aux4;
|
|
|
+ int16 E, E2, E3, E4, E5, refE, E6, E7;
|
|
|
+ int16 C2, C4, C6, C8, C9, C10, C11, C12, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25, C26;
|
|
|
+ int16 Px, Py, Pz;
|
|
|
+
|
|
|
+ E4=E3=E2=E=E5=0;
|
|
|
+
|
|
|
+ normalizeDouble(int32(X)-shared.Gx, Px, E4);
|
|
|
+ normalizeDouble(int32(Y)-shared.Gy, Py, E);
|
|
|
+ normalizeDouble(int32(Z)-shared.Gz, Pz, E3);
|
|
|
+ Px>>=1; E4--; // to avoid overflows when calculating the scalar products
|
|
|
+ Py>>=1; E--;
|
|
|
+ Pz>>=1; E3--;
|
|
|
+
|
|
|
+ refE = (E<E3)?E:E3;
|
|
|
+ refE = (refE<E4)?refE:E4;
|
|
|
+
|
|
|
+ Px=shiftR(Px,E4-refE); // normalize them to the same exponent
|
|
|
+ Py=shiftR(Py,E-refE);
|
|
|
+ Pz=shiftR(Pz,E3-refE);
|
|
|
+
|
|
|
+ C11=- (Px*shared.Nx>>15);
|
|
|
+ C8=- (Py*shared.Ny>>15);
|
|
|
+ C9=- (Pz*shared.Nz>>15);
|
|
|
+ C12=C11+C8+C9; // this cannot overflow!
|
|
|
+
|
|
|
+ aux4=C12; // de-normalization with 32-bits arithmetic
|
|
|
+ refE = 16-refE; // refE can be up to 3
|
|
|
+ if (refE>=0)
|
|
|
+ aux4 <<=(refE);
|
|
|
+ else
|
|
|
+ aux4 >>=-(refE);
|
|
|
+ if (aux4==-1) aux4 = 0; // why?
|
|
|
+ aux4>>=1;
|
|
|
+
|
|
|
+ aux = static_cast<uint16>(shared.Les) + aux4; // Les - the scalar product of P with the normal vector of the screen
|
|
|
+ normalizeDouble(aux, C10, E2);
|
|
|
+ E2 = 15-E2;
|
|
|
+
|
|
|
+ inverse(C10, 0, C4, E4);
|
|
|
+ C2=C4*shared.C_Les>>15; // scale factor
|
|
|
+
|
|
|
+
|
|
|
+ // H
|
|
|
+ E7=0;
|
|
|
+ C16= (Px*shared.Hx>>15);
|
|
|
+ C20= (Py*shared.Hy>>15);
|
|
|
+ C17=C16+C20; // scalar product of P with the normalized horizontal vector of the screen...
|
|
|
+
|
|
|
+ C18=C17*C2>>15; // ... multiplied by the scale factor
|
|
|
+ normalize(C18, C19, E7);
|
|
|
+ H=denormalizeAndClip(C19, shared.E_Les-E2+refE+E7);
|
|
|
+
|
|
|
+ // V
|
|
|
+ E6=0;
|
|
|
+ C21 = Px*shared.Vx>>15;
|
|
|
+ C22 = Py*shared.Vy>>15;
|
|
|
+ C23 = Pz*shared.Vz>>15;
|
|
|
+ C24=C21+C22+C23; // scalar product of P with the normalized vertical vector of the screen...
|
|
|
+
|
|
|
+ C26=C24*C2>>15; // ... multiplied by the scale factor
|
|
|
+ normalize(C26, C25, E6);
|
|
|
+ V=denormalizeAndClip(C25, shared.E_Les-E2+refE+E6);
|
|
|
+
|
|
|
+ // M
|
|
|
+ normalize(C2, C6, E4);
|
|
|
+ M=denormalizeAndClip(C6, E4+shared.E_Les-E2-7); // M is the scale factor divided by 2^7
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Calculate the sine of the input parameter
|
|
|
+// this is done by linear interpolation between
|
|
|
+// the points of a look-up table
|
|
|
+
|
|
|
+int16 Dsp1::sin(int16 Angle)
|
|
|
+{
|
|
|
+ if (Angle < 0) {
|
|
|
+ if (Angle == -32768) return 0;
|
|
|
+ return -sin(-Angle);
|
|
|
+ }
|
|
|
+ int32 S = SinTable[Angle >> 8] + (MulTable[Angle & 0xff] * SinTable[0x40 + (Angle >> 8)] >> 15);
|
|
|
+ if (S > 32767) S = 32767;
|
|
|
+ return (int16) S;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Calculate the cosine of the input parameter.
|
|
|
+// It's used the same method than in sin(int16)
|
|
|
+
|
|
|
+int16 Dsp1::cos(int16 Angle)
|
|
|
+{
|
|
|
+ if (Angle < 0) {
|
|
|
+ if (Angle == -32768) return -32768;
|
|
|
+ Angle = -Angle;
|
|
|
+ }
|
|
|
+ int32 S = SinTable[0x40 + (Angle >> 8)] - (MulTable[Angle & 0xff] * SinTable[Angle >> 8] >> 15);
|
|
|
+ if (S < -32768) S = -32767;
|
|
|
+ return (int16) S;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Determines the inverse of a floating point decimal number
|
|
|
+// iCoefficient*2^iExponent = 1/(Coefficient*2^Exponent), with the output
|
|
|
+// normalized (iCoefficient represents a number whose absolute value is between 1/2 and 1)
|
|
|
+// To invert 'Coefficient' a first initial guess is taken from a look-up table
|
|
|
+// and, then, two iterations of the Newton method (applied to the function
|
|
|
+// f(x)=1/(2*x)-Coefficient) are done. This results in a close approximation (iCoefficient) to a number 'y'
|
|
|
+// that verify Coefficient*y=1/2. This is why you have to correct the exponent by one
|
|
|
+// unit at the end.
|
|
|
+
|
|
|
+void Dsp1::inverse(int16 Coefficient, int16 Exponent, int16 &iCoefficient, int16 &iExponent)
|
|
|
+{
|
|
|
+ // Step One: Division by Zero
|
|
|
+ if (Coefficient == 0x0000)
|
|
|
+ {
|
|
|
+ iCoefficient = 0x7fff;
|
|
|
+ iExponent = 0x002f;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ int16 Sign = 1;
|
|
|
+
|
|
|
+ // Step Two: Remove Sign
|
|
|
+ if (Coefficient < 0)
|
|
|
+ {
|
|
|
+ if (Coefficient < -32767) Coefficient = -32767;
|
|
|
+ Coefficient = -Coefficient;
|
|
|
+ Sign = -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Step Three: Normalize
|
|
|
+ while (Coefficient < 0x4000)
|
|
|
+ {
|
|
|
+ Coefficient <<= 1;
|
|
|
+ Exponent--;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Step Four: Special Case
|
|
|
+ if (Coefficient == 0x4000)
|
|
|
+ if (Sign == 1) iCoefficient = 0x7fff;
|
|
|
+ else {
|
|
|
+ iCoefficient = -0x4000;
|
|
|
+ Exponent--;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ // Step Five: Initial Guess
|
|
|
+ int16 i = DataRom[((Coefficient - 0x4000) >> 7) + 0x0065];
|
|
|
+
|
|
|
+ // Step Six: Iterate Newton's Method
|
|
|
+ i = (i + (-i * (Coefficient * i >> 15) >> 15)) << 1;
|
|
|
+ i = (i + (-i * (Coefficient * i >> 15) >> 15)) << 1;
|
|
|
+
|
|
|
+ iCoefficient = i * Sign;
|
|
|
+ }
|
|
|
+
|
|
|
+ iExponent = 1 - Exponent;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+int16 Dsp1::denormalizeAndClip(int16 C, int16 E)
|
|
|
+{
|
|
|
+ if (E > 0) {
|
|
|
+ if (C > 0) return 32767; else if (C < 0) return -32767;
|
|
|
+ } else {
|
|
|
+ if (E < 0) return C * DataRom[0x0031 + E] >> 15;
|
|
|
+ }
|
|
|
+ return C;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Normalize the input number (m), understood as ranging from -1 to 1,
|
|
|
+// to the form: Coefficient*2^Exponent,
|
|
|
+// where the absolute value of Coefficient is >= 1/2
|
|
|
+// (Coefficient>=0x4000 or Coefficient <= (int16)0xc001)
|
|
|
+
|
|
|
+void Dsp1::normalize(int16 m, int16 &Coefficient, int16 &Exponent)
|
|
|
+{
|
|
|
+ int16 i = 0x4000;
|
|
|
+ int16 e = 0;
|
|
|
+
|
|
|
+ if (m < 0)
|
|
|
+ while ((m & i) && i)
|
|
|
+ {
|
|
|
+ i >>= 1;
|
|
|
+ e++;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ while (!(m & i) && i)
|
|
|
+ {
|
|
|
+ i >>= 1;
|
|
|
+ e++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (e > 0)
|
|
|
+ Coefficient = m * DataRom[0x21 + e] << 1;
|
|
|
+ else
|
|
|
+ Coefficient = m;
|
|
|
+
|
|
|
+ Exponent -= e;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Same than 'normalize' but with an int32 input
|
|
|
+
|
|
|
+void Dsp1::normalizeDouble(int32 Product, int16 &Coefficient, int16 &Exponent)
|
|
|
+{
|
|
|
+ int16 n = Product & 0x7fff;
|
|
|
+ int16 m = Product >> 15;
|
|
|
+ int16 i = 0x4000;
|
|
|
+ int16 e = 0;
|
|
|
+
|
|
|
+ if (m < 0)
|
|
|
+ while ((m & i) && i)
|
|
|
+ {
|
|
|
+ i >>= 1;
|
|
|
+ e++;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ while (!(m & i) && i)
|
|
|
+ {
|
|
|
+ i >>= 1;
|
|
|
+ e++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (e > 0)
|
|
|
+ {
|
|
|
+ Coefficient = m * DataRom[0x0021 + e] << 1;
|
|
|
+
|
|
|
+ if (e < 15)
|
|
|
+ Coefficient += n * DataRom[0x0040 - e] >> 15;
|
|
|
+ else
|
|
|
+ {
|
|
|
+ i = 0x4000;
|
|
|
+
|
|
|
+ if (m < 0)
|
|
|
+ while ((n & i) && i)
|
|
|
+ {
|
|
|
+ i >>= 1;
|
|
|
+ e++;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ while (!(n & i) && i)
|
|
|
+ {
|
|
|
+ i >>= 1;
|
|
|
+ e++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (e > 15)
|
|
|
+ Coefficient = n * DataRom[0x0012 + e] << 1;
|
|
|
+ else
|
|
|
+ Coefficient += n;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ Coefficient = m;
|
|
|
+
|
|
|
+ Exponent = e;
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Shift to the right
|
|
|
+
|
|
|
+int16 Dsp1::shiftR(int16 C, int16 E)
|
|
|
+{
|
|
|
+ return (C * DataRom[0x0031 + E] >> 15);
|
|
|
+}
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// this is, indeed, only part of the Data ROM
|
|
|
+const int16 Dsp1::SinTable[256] = {
|
|
|
+ 0x0000, 0x0324, 0x0647, 0x096a, 0x0c8b, 0x0fab, 0x12c8, 0x15e2,
|
|
|
+ 0x18f8, 0x1c0b, 0x1f19, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11,
|
|
|
+ 0x30fb, 0x33de, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a,
|
|
|
+ 0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842,
|
|
|
+ 0x5a82, 0x5cb4, 0x5ed7, 0x60ec, 0x62f2, 0x64e8, 0x66cf, 0x68a6,
|
|
|
+ 0x6a6d, 0x6c24, 0x6dca, 0x6f5f, 0x70e2, 0x7255, 0x73b5, 0x7504,
|
|
|
+ 0x7641, 0x776c, 0x7884, 0x798a, 0x7a7d, 0x7b5d, 0x7c29, 0x7ce3,
|
|
|
+ 0x7d8a, 0x7e1d, 0x7e9d, 0x7f09, 0x7f62, 0x7fa7, 0x7fd8, 0x7ff6,
|
|
|
+ 0x7fff, 0x7ff6, 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d,
|
|
|
+ 0x7d8a, 0x7ce3, 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c,
|
|
|
+ 0x7641, 0x7504, 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24,
|
|
|
+ 0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4,
|
|
|
+ 0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4,
|
|
|
+ 0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de,
|
|
|
+ 0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b,
|
|
|
+ 0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324,
|
|
|
+ -0x0000, -0x0324, -0x0647, -0x096a, -0x0c8b, -0x0fab, -0x12c8, -0x15e2,
|
|
|
+ -0x18f8, -0x1c0b, -0x1f19, -0x2223, -0x2528, -0x2826, -0x2b1f, -0x2e11,
|
|
|
+ -0x30fb, -0x33de, -0x36ba, -0x398c, -0x3c56, -0x3f17, -0x41ce, -0x447a,
|
|
|
+ -0x471c, -0x49b4, -0x4c3f, -0x4ebf, -0x5133, -0x539b, -0x55f5, -0x5842,
|
|
|
+ -0x5a82, -0x5cb4, -0x5ed7, -0x60ec, -0x62f2, -0x64e8, -0x66cf, -0x68a6,
|
|
|
+ -0x6a6d, -0x6c24, -0x6dca, -0x6f5f, -0x70e2, -0x7255, -0x73b5, -0x7504,
|
|
|
+ -0x7641, -0x776c, -0x7884, -0x798a, -0x7a7d, -0x7b5d, -0x7c29, -0x7ce3,
|
|
|
+ -0x7d8a, -0x7e1d, -0x7e9d, -0x7f09, -0x7f62, -0x7fa7, -0x7fd8, -0x7ff6,
|
|
|
+ -0x7fff, -0x7ff6, -0x7fd8, -0x7fa7, -0x7f62, -0x7f09, -0x7e9d, -0x7e1d,
|
|
|
+ -0x7d8a, -0x7ce3, -0x7c29, -0x7b5d, -0x7a7d, -0x798a, -0x7884, -0x776c,
|
|
|
+ -0x7641, -0x7504, -0x73b5, -0x7255, -0x70e2, -0x6f5f, -0x6dca, -0x6c24,
|
|
|
+ -0x6a6d, -0x68a6, -0x66cf, -0x64e8, -0x62f2, -0x60ec, -0x5ed7, -0x5cb4,
|
|
|
+ -0x5a82, -0x5842, -0x55f5, -0x539b, -0x5133, -0x4ebf, -0x4c3f, -0x49b4,
|
|
|
+ -0x471c, -0x447a, -0x41ce, -0x3f17, -0x3c56, -0x398c, -0x36ba, -0x33de,
|
|
|
+ -0x30fb, -0x2e11, -0x2b1f, -0x2826, -0x2528, -0x2223, -0x1f19, -0x1c0b,
|
|
|
+ -0x18f8, -0x15e2, -0x12c8, -0x0fab, -0x0c8b, -0x096a, -0x0647, -0x0324};
|
|
|
+
|
|
|
+ //////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Optimised for Performance
|
|
|
+ const int16 Dsp1::MulTable[256] = {
|
|
|
+ 0x0000, 0x0003, 0x0006, 0x0009, 0x000c, 0x000f, 0x0012, 0x0015,
|
|
|
+ 0x0019, 0x001c, 0x001f, 0x0022, 0x0025, 0x0028, 0x002b, 0x002f,
|
|
|
+ 0x0032, 0x0035, 0x0038, 0x003b, 0x003e, 0x0041, 0x0045, 0x0048,
|
|
|
+ 0x004b, 0x004e, 0x0051, 0x0054, 0x0057, 0x005b, 0x005e, 0x0061,
|
|
|
+ 0x0064, 0x0067, 0x006a, 0x006d, 0x0071, 0x0074, 0x0077, 0x007a,
|
|
|
+ 0x007d, 0x0080, 0x0083, 0x0087, 0x008a, 0x008d, 0x0090, 0x0093,
|
|
|
+ 0x0096, 0x0099, 0x009d, 0x00a0, 0x00a3, 0x00a6, 0x00a9, 0x00ac,
|
|
|
+ 0x00af, 0x00b3, 0x00b6, 0x00b9, 0x00bc, 0x00bf, 0x00c2, 0x00c5,
|
|
|
+ 0x00c9, 0x00cc, 0x00cf, 0x00d2, 0x00d5, 0x00d8, 0x00db, 0x00df,
|
|
|
+ 0x00e2, 0x00e5, 0x00e8, 0x00eb, 0x00ee, 0x00f1, 0x00f5, 0x00f8,
|
|
|
+ 0x00fb, 0x00fe, 0x0101, 0x0104, 0x0107, 0x010b, 0x010e, 0x0111,
|
|
|
+ 0x0114, 0x0117, 0x011a, 0x011d, 0x0121, 0x0124, 0x0127, 0x012a,
|
|
|
+ 0x012d, 0x0130, 0x0133, 0x0137, 0x013a, 0x013d, 0x0140, 0x0143,
|
|
|
+ 0x0146, 0x0149, 0x014d, 0x0150, 0x0153, 0x0156, 0x0159, 0x015c,
|
|
|
+ 0x015f, 0x0163, 0x0166, 0x0169, 0x016c, 0x016f, 0x0172, 0x0175,
|
|
|
+ 0x0178, 0x017c, 0x017f, 0x0182, 0x0185, 0x0188, 0x018b, 0x018e,
|
|
|
+ 0x0192, 0x0195, 0x0198, 0x019b, 0x019e, 0x01a1, 0x01a4, 0x01a8,
|
|
|
+ 0x01ab, 0x01ae, 0x01b1, 0x01b4, 0x01b7, 0x01ba, 0x01be, 0x01c1,
|
|
|
+ 0x01c4, 0x01c7, 0x01ca, 0x01cd, 0x01d0, 0x01d4, 0x01d7, 0x01da,
|
|
|
+ 0x01dd, 0x01e0, 0x01e3, 0x01e6, 0x01ea, 0x01ed, 0x01f0, 0x01f3,
|
|
|
+ 0x01f6, 0x01f9, 0x01fc, 0x0200, 0x0203, 0x0206, 0x0209, 0x020c,
|
|
|
+ 0x020f, 0x0212, 0x0216, 0x0219, 0x021c, 0x021f, 0x0222, 0x0225,
|
|
|
+ 0x0228, 0x022c, 0x022f, 0x0232, 0x0235, 0x0238, 0x023b, 0x023e,
|
|
|
+ 0x0242, 0x0245, 0x0248, 0x024b, 0x024e, 0x0251, 0x0254, 0x0258,
|
|
|
+ 0x025b, 0x025e, 0x0261, 0x0264, 0x0267, 0x026a, 0x026e, 0x0271,
|
|
|
+ 0x0274, 0x0277, 0x027a, 0x027d, 0x0280, 0x0284, 0x0287, 0x028a,
|
|
|
+ 0x028d, 0x0290, 0x0293, 0x0296, 0x029a, 0x029d, 0x02a0, 0x02a3,
|
|
|
+ 0x02a6, 0x02a9, 0x02ac, 0x02b0, 0x02b3, 0x02b6, 0x02b9, 0x02bc,
|
|
|
+ 0x02bf, 0x02c2, 0x02c6, 0x02c9, 0x02cc, 0x02cf, 0x02d2, 0x02d5,
|
|
|
+ 0x02d8, 0x02db, 0x02df, 0x02e2, 0x02e5, 0x02e8, 0x02eb, 0x02ee,
|
|
|
+ 0x02f1, 0x02f5, 0x02f8, 0x02fb, 0x02fe, 0x0301, 0x0304, 0x0307,
|
|
|
+ 0x030b, 0x030e, 0x0311, 0x0314, 0x0317, 0x031a, 0x031d, 0x0321};
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+// Data ROM, as logged from a DSP-1B with the 0x1f command;
|
|
|
+// it contains the tables and constants used by the commands.
|
|
|
+// The tables used are: two shift tables (0x022-0x031 and 0x031-0x040 -this last one
|
|
|
+// with an error in 0x03c which has survived to all the DSP-1 revisions-); a inverse
|
|
|
+// table (used as initial guess) at 0x065-0x0e4; a square root table (used also
|
|
|
+// as initial guess) at 0x0e5-0x115; two sin and cos tables (used as nodes to construct
|
|
|
+// a interpolation curve) at, respectively, 0x116-0x197 and 0x196-0x215.
|
|
|
+// As a curiosity, in the positions 0x21c-0x31c it's contained a
|
|
|
+// 257-points arccos table that, apparently, have been not used anywhere
|
|
|
+// (maybe for the MaxAZS_Exp table?).
|
|
|
+ const uint16 Dsp1::DataRom[1024] = {
|
|
|
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
|
|
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
|
|
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
|
|
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
|
|
+ 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020,
|
|
|
+ 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000,
|
|
|
+ 0x4000, 0x7fff, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200,
|
|
|
+ 0x0100, 0x0080, 0x0040, 0x0020, 0x0001, 0x0008, 0x0004, 0x0002,
|
|
|
+ 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
|
|
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
|
|
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
|
|
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
|
|
+ 0x0000, 0x0000, 0x8000, 0xffe5, 0x0100, 0x7fff, 0x7f02, 0x7e08,
|
|
|
+ 0x7d12, 0x7c1f, 0x7b30, 0x7a45, 0x795d, 0x7878, 0x7797, 0x76ba,
|
|
|
+ 0x75df, 0x7507, 0x7433, 0x7361, 0x7293, 0x71c7, 0x70fe, 0x7038,
|
|
|
+ 0x6f75, 0x6eb4, 0x6df6, 0x6d3a, 0x6c81, 0x6bca, 0x6b16, 0x6a64,
|
|
|
+ 0x69b4, 0x6907, 0x685b, 0x67b2, 0x670b, 0x6666, 0x65c4, 0x6523,
|
|
|
+ 0x6484, 0x63e7, 0x634c, 0x62b3, 0x621c, 0x6186, 0x60f2, 0x6060,
|
|
|
+ 0x5fd0, 0x5f41, 0x5eb5, 0x5e29, 0x5d9f, 0x5d17, 0x5c91, 0x5c0c,
|
|
|
+ 0x5b88, 0x5b06, 0x5a85, 0x5a06, 0x5988, 0x590b, 0x5890, 0x5816,
|
|
|
+ 0x579d, 0x5726, 0x56b0, 0x563b, 0x55c8, 0x5555, 0x54e4, 0x5474,
|
|
|
+ 0x5405, 0x5398, 0x532b, 0x52bf, 0x5255, 0x51ec, 0x5183, 0x511c,
|
|
|
+ 0x50b6, 0x5050, 0x4fec, 0x4f89, 0x4f26, 0x4ec5, 0x4e64, 0x4e05,
|
|
|
+ 0x4da6, 0x4d48, 0x4cec, 0x4c90, 0x4c34, 0x4bda, 0x4b81, 0x4b28,
|
|
|
+ 0x4ad0, 0x4a79, 0x4a23, 0x49cd, 0x4979, 0x4925, 0x48d1, 0x487f,
|
|
|
+ 0x482d, 0x47dc, 0x478c, 0x473c, 0x46ed, 0x469f, 0x4651, 0x4604,
|
|
|
+ 0x45b8, 0x456c, 0x4521, 0x44d7, 0x448d, 0x4444, 0x43fc, 0x43b4,
|
|
|
+ 0x436d, 0x4326, 0x42e0, 0x429a, 0x4255, 0x4211, 0x41cd, 0x4189,
|
|
|
+ 0x4146, 0x4104, 0x40c2, 0x4081, 0x4040, 0x3fff, 0x41f7, 0x43e1,
|
|
|
+ 0x45bd, 0x478d, 0x4951, 0x4b0b, 0x4cbb, 0x4e61, 0x4fff, 0x5194,
|
|
|
+ 0x5322, 0x54a9, 0x5628, 0x57a2, 0x5914, 0x5a81, 0x5be9, 0x5d4a,
|
|
|
+ 0x5ea7, 0x5fff, 0x6152, 0x62a0, 0x63ea, 0x6530, 0x6672, 0x67b0,
|
|
|
+ 0x68ea, 0x6a20, 0x6b53, 0x6c83, 0x6daf, 0x6ed9, 0x6fff, 0x7122,
|
|
|
+ 0x7242, 0x735f, 0x747a, 0x7592, 0x76a7, 0x77ba, 0x78cb, 0x79d9,
|
|
|
+ 0x7ae5, 0x7bee, 0x7cf5, 0x7dfa, 0x7efe, 0x7fff, 0x0000, 0x0324,
|
|
|
+ 0x0647, 0x096a, 0x0c8b, 0x0fab, 0x12c8, 0x15e2, 0x18f8, 0x1c0b,
|
|
|
+ 0x1f19, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11, 0x30fb, 0x33de,
|
|
|
+ 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a, 0x471c, 0x49b4,
|
|
|
+ 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842, 0x5a82, 0x5cb4,
|
|
|
+ 0x5ed7, 0x60ec, 0x62f2, 0x64e8, 0x66cf, 0x68a6, 0x6a6d, 0x6c24,
|
|
|
+ 0x6dca, 0x6f5f, 0x70e2, 0x7255, 0x73b5, 0x7504, 0x7641, 0x776c,
|
|
|
+ 0x7884, 0x798a, 0x7a7d, 0x7b5d, 0x7c29, 0x7ce3, 0x7d8a, 0x7e1d,
|
|
|
+ 0x7e9d, 0x7f09, 0x7f62, 0x7fa7, 0x7fd8, 0x7ff6, 0x7fff, 0x7ff6,
|
|
|
+ 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, 0x7d8a, 0x7ce3,
|
|
|
+ 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, 0x7641, 0x7504,
|
|
|
+ 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, 0x6a6d, 0x68a6,
|
|
|
+ 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, 0x5a82, 0x5842,
|
|
|
+ 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, 0x471c, 0x447a,
|
|
|
+ 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, 0x30fb, 0x2e11,
|
|
|
+ 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, 0x18f8, 0x15e2,
|
|
|
+ 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, 0x7fff, 0x7ff6,
|
|
|
+ 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d, 0x7d8a, 0x7ce3,
|
|
|
+ 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c, 0x7641, 0x7504,
|
|
|
+ 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24, 0x6a6d, 0x68a6,
|
|
|
+ 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4, 0x5a82, 0x5842,
|
|
|
+ 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4, 0x471c, 0x447a,
|
|
|
+ 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de, 0x30fb, 0x2e11,
|
|
|
+ 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b, 0x18f8, 0x15e2,
|
|
|
+ 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324, 0x0000, 0xfcdc,
|
|
|
+ 0xf9b9, 0xf696, 0xf375, 0xf055, 0xed38, 0xea1e, 0xe708, 0xe3f5,
|
|
|
+ 0xe0e7, 0xdddd, 0xdad8, 0xd7da, 0xd4e1, 0xd1ef, 0xcf05, 0xcc22,
|
|
|
+ 0xc946, 0xc674, 0xc3aa, 0xc0e9, 0xbe32, 0xbb86, 0xb8e4, 0xb64c,
|
|
|
+ 0xb3c1, 0xb141, 0xaecd, 0xac65, 0xaa0b, 0xa7be, 0xa57e, 0xa34c,
|
|
|
+ 0xa129, 0x9f14, 0x9d0e, 0x9b18, 0x9931, 0x975a, 0x9593, 0x93dc,
|
|
|
+ 0x9236, 0x90a1, 0x8f1e, 0x8dab, 0x8c4b, 0x8afc, 0x89bf, 0x8894,
|
|
|
+ 0x877c, 0x8676, 0x8583, 0x84a3, 0x83d7, 0x831d, 0x8276, 0x81e3,
|
|
|
+ 0x8163, 0x80f7, 0x809e, 0x8059, 0x8028, 0x800a, 0x6488, 0x0080,
|
|
|
+ 0x03ff, 0x0116, 0x0002, 0x0080, 0x4000, 0x3fd7, 0x3faf, 0x3f86,
|
|
|
+ 0x3f5d, 0x3f34, 0x3f0c, 0x3ee3, 0x3eba, 0x3e91, 0x3e68, 0x3e40,
|
|
|
+ 0x3e17, 0x3dee, 0x3dc5, 0x3d9c, 0x3d74, 0x3d4b, 0x3d22, 0x3cf9,
|
|
|
+ 0x3cd0, 0x3ca7, 0x3c7f, 0x3c56, 0x3c2d, 0x3c04, 0x3bdb, 0x3bb2,
|
|
|
+ 0x3b89, 0x3b60, 0x3b37, 0x3b0e, 0x3ae5, 0x3abc, 0x3a93, 0x3a69,
|
|
|
+ 0x3a40, 0x3a17, 0x39ee, 0x39c5, 0x399c, 0x3972, 0x3949, 0x3920,
|
|
|
+ 0x38f6, 0x38cd, 0x38a4, 0x387a, 0x3851, 0x3827, 0x37fe, 0x37d4,
|
|
|
+ 0x37aa, 0x3781, 0x3757, 0x372d, 0x3704, 0x36da, 0x36b0, 0x3686,
|
|
|
+ 0x365c, 0x3632, 0x3609, 0x35df, 0x35b4, 0x358a, 0x3560, 0x3536,
|
|
|
+ 0x350c, 0x34e1, 0x34b7, 0x348d, 0x3462, 0x3438, 0x340d, 0x33e3,
|
|
|
+ 0x33b8, 0x338d, 0x3363, 0x3338, 0x330d, 0x32e2, 0x32b7, 0x328c,
|
|
|
+ 0x3261, 0x3236, 0x320b, 0x31df, 0x31b4, 0x3188, 0x315d, 0x3131,
|
|
|
+ 0x3106, 0x30da, 0x30ae, 0x3083, 0x3057, 0x302b, 0x2fff, 0x2fd2,
|
|
|
+ 0x2fa6, 0x2f7a, 0x2f4d, 0x2f21, 0x2ef4, 0x2ec8, 0x2e9b, 0x2e6e,
|
|
|
+ 0x2e41, 0x2e14, 0x2de7, 0x2dba, 0x2d8d, 0x2d60, 0x2d32, 0x2d05,
|
|
|
+ 0x2cd7, 0x2ca9, 0x2c7b, 0x2c4d, 0x2c1f, 0x2bf1, 0x2bc3, 0x2b94,
|
|
|
+ 0x2b66, 0x2b37, 0x2b09, 0x2ada, 0x2aab, 0x2a7c, 0x2a4c, 0x2a1d,
|
|
|
+ 0x29ed, 0x29be, 0x298e, 0x295e, 0x292e, 0x28fe, 0x28ce, 0x289d,
|
|
|
+ 0x286d, 0x283c, 0x280b, 0x27da, 0x27a9, 0x2777, 0x2746, 0x2714,
|
|
|
+ 0x26e2, 0x26b0, 0x267e, 0x264c, 0x2619, 0x25e7, 0x25b4, 0x2581,
|
|
|
+ 0x254d, 0x251a, 0x24e6, 0x24b2, 0x247e, 0x244a, 0x2415, 0x23e1,
|
|
|
+ 0x23ac, 0x2376, 0x2341, 0x230b, 0x22d6, 0x229f, 0x2269, 0x2232,
|
|
|
+ 0x21fc, 0x21c4, 0x218d, 0x2155, 0x211d, 0x20e5, 0x20ad, 0x2074,
|
|
|
+ 0x203b, 0x2001, 0x1fc7, 0x1f8d, 0x1f53, 0x1f18, 0x1edd, 0x1ea1,
|
|
|
+ 0x1e66, 0x1e29, 0x1ded, 0x1db0, 0x1d72, 0x1d35, 0x1cf6, 0x1cb8,
|
|
|
+ 0x1c79, 0x1c39, 0x1bf9, 0x1bb8, 0x1b77, 0x1b36, 0x1af4, 0x1ab1,
|
|
|
+ 0x1a6e, 0x1a2a, 0x19e6, 0x19a1, 0x195c, 0x1915, 0x18ce, 0x1887,
|
|
|
+ 0x183f, 0x17f5, 0x17ac, 0x1761, 0x1715, 0x16c9, 0x167c, 0x162e,
|
|
|
+ 0x15df, 0x158e, 0x153d, 0x14eb, 0x1497, 0x1442, 0x13ec, 0x1395,
|
|
|
+ 0x133c, 0x12e2, 0x1286, 0x1228, 0x11c9, 0x1167, 0x1104, 0x109e,
|
|
|
+ 0x1036, 0x0fcc, 0x0f5f, 0x0eef, 0x0e7b, 0x0e04, 0x0d89, 0x0d0a,
|
|
|
+ 0x0c86, 0x0bfd, 0x0b6d, 0x0ad6, 0x0a36, 0x098d, 0x08d7, 0x0811,
|
|
|
+ 0x0736, 0x063e, 0x0519, 0x039a, 0x0000, 0x7fff, 0x0100, 0x0080,
|
|
|
+ 0x021d, 0x00c8, 0x00ce, 0x0048, 0x0a26, 0x277a, 0x00ce, 0x6488,
|
|
|
+ 0x14ac, 0x0001, 0x00f9, 0x00fc, 0x00ff, 0x00fc, 0x00f9, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
|
|
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff};
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+#endif
|