| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557 |
- /**--------------------------------------------------------------------------**\
- ============================
- Y Sever Includes - Cell Core
- ============================
- Description:
- Provides a few functions for manipulating the bits in single cells. Note
- that this is distinct from the y_bit library.
- Legal:
- Version: MPL 1.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is the YSI bit include.
-
- The Initial Developer of the Original Code is Alex "Y_Less" Cole.
- Portions created by the Initial Developer are Copyright (C) 2011
- the Initial Developer. All Rights Reserved.
-
- Contributors:
- ZeeX, koolk, JoeBullet/Google63, g_aSlice/Slice
-
- Thanks:
- JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
- ZeeX - Very productive conversations.
- koolk - IsPlayerinAreaEx code.
- TheAlpha - Danish translation.
- breadfish - German translation.
- Fireburn - Dutch translation.
- yom - French translation.
- 50p - Polish translation.
- Zamaroht - Spanish translation.
- Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
- for me to strive to better.
- Pixels^ - Running XScripters where the idea was born.
- Matite - Pestering me to release it and using it.
-
- Very special thanks to:
- Thiadmer - PAWN, whose limits continue to amaze me!
- Kye/Kalcor - SA:MP.
- SA:MP Team past, present and future - SA:MP.
-
- Version:
- 0.2
- Changelog:
- 18/06/11:
- First version.
- Functions:
- Public:
- -
- Core:
- -
- Stock:
- -
- Static:
- -
- Inline:
- -
- API:
- -
- Callbacks:
- -
- Definitions:
- -
- Enums:
- -
- Macros:
- -
- Tags:
- -
- Variables:
- Global:
- -
- Static:
- -
- Commands:
- -
- Compile options:
- -
- \**--------------------------------------------------------------------------**/
- #if defined _INC_y_cell
- #endinput
- #endif
- #define _INC_y_cell
- #include "..\YSI_Internal\y_version"
- #include "..\YSI_Internal\y_globaltags"
- /**--------------------------------------------------------------------------**\
- <summary>
- Cell_ReverseBits(number);
- </summary>
- <param name="number">The number to manipulate.</param>
- <returns>
- All the bits in the input reversed.
- </returns>
- <remarks>
- 1)
- Example: 0b11110000000000000000000000000000
- Becomes: 0b00000000000000000000000000001111
-
- 2)
- Example: 0b10110011100011110000111110000010
- Becomes: 0b01000001111100001111000111001101
-
- 3)
- Example: 0b01010101010101010101010101010101
- Becomes: 0b10101010101010101010101010101010
- </remarks>
- \**--------------------------------------------------------------------------**/
- stock Cell_ReverseBits(GLOBAL_TAG_TYPES:data)
- {
- // Swap adjacent bits.
- // data = ((data & 0b10101010101010101010101010101010) >>> 1) | ((data & 0b01010101010101010101010101010101) << 1);
- #emit LOAD.S.pri data
- #emit PUSH.pri
- #emit CONST.alt 0b10101010101010101010101010101010
- #emit AND
- #emit SHR.C.pri 1
- #emit SWAP.pri
- #emit CONST.alt 0b01010101010101010101010101010101
- #emit AND
- #emit SHL.C.pri 1
- #emit POP.alt
- #emit OR
-
- // Swap adjacent pairs.
- // data = ((data & 0b11001100110011001100110011001100) >>> 2) | ((data & 0b00110011001100110011001100110011) << 2);
- #emit PUSH.pri
- #emit CONST.alt 0b11001100110011001100110011001100
- #emit AND
- #emit SHR.C.pri 2
- #emit SWAP.pri
- #emit CONST.alt 0b00110011001100110011001100110011
- #emit AND
- #emit SHL.C.pri 2
- #emit POP.alt
- #emit OR
-
- // Swap adjacent nibbles.
- // data = ((data & 0b11110000111100001111000011110000) >>> 4) | ((data & 0b00001111000011110000111100001111) << 4);
- #emit PUSH.pri
- #emit CONST.alt 0b11110000111100001111000011110000
- #emit AND
- #emit SHR.C.pri 4
- #emit SWAP.pri
- #emit CONST.alt 0b00001111000011110000111100001111
- #emit AND
- #emit SHL.C.pri 4
- #emit POP.alt
- #emit OR
-
- // Swap all bytes.
- // return (data >>> 24) | ((data & 0x00FF0000) >> 8) | ((data & 0x0000FF00) << 8) | (data << 24);
- #emit PUSH.pri
- #emit MOVE.alt
-
- #emit SHR.C.pri 24
- #emit XCHG
- #emit SHL.C.pri 24
- #emit OR
- #emit SWAP.pri
-
- #emit PUSH.pri
- #emit CONST.alt 0x00FF0000
- #emit AND
- #emit SHR.C.pri 8
- #emit SWAP.pri
-
- #emit CONST.alt 0x0000FF00
- #emit AND
- #emit SHL.C.pri 8
-
- #emit POP.alt
- #emit OR
- #emit POP.alt
- #emit OR
-
- #emit RETN
-
- // Make the compiler happy.
- return 0;
- }
- /**--------------------------------------------------------------------------**\
- <summary>
- Cell_ReverseNibbles(number);
- </summary>
- <param name="number">The number to manipulate.</param>
- <returns>
- All the nibbles (4-bit chunks) in the input reversed.
- </returns>
- <remarks>
- 1)
- Example: 0x12345678
- Becomes: 0x87654321
-
- 2)
- Example: 0x010F0703
- Becomes: 0x3070F010
-
- 3)
- Example: 0xF0F0F0F0
- Becomes: 0x0F0F0F0F
- </remarks>
- \**--------------------------------------------------------------------------**/
- stock Cell_ReverseNibbles(GLOBAL_TAG_TYPES:data)
- {
- // Swap adjacent nibbles.
- // data = ((data & 0b11110000111100001111000011110000) >>> 4) | ((data & 0b00001111000011110000111100001111) << 4);
- #emit LOAD.S.pri data
- #emit PUSH.pri
- #emit CONST.alt 0b11110000111100001111000011110000
- #emit AND
- #emit SHR.C.pri 4
- #emit SWAP.pri
- #emit CONST.alt 0b00001111000011110000111100001111
- #emit AND
- #emit SHL.C.pri 4
- #emit POP.alt
- #emit OR
-
- // Swap all bytes.
- // return (data >>> 24) | ((data & 0x00FF0000) >> 8) | ((data & 0x0000FF00) << 8) | (data << 24);
- #emit PUSH.pri
- #emit MOVE.alt
-
- #emit SHR.C.pri 24
- #emit XCHG
- #emit SHL.C.pri 24
- #emit OR
- #emit SWAP.pri
-
- #emit PUSH.pri
- #emit CONST.alt 0x00FF0000
- #emit AND
- #emit SHR.C.pri 8
- #emit SWAP.pri
-
- #emit CONST.alt 0x0000FF00
- #emit AND
- #emit SHL.C.pri 8
-
- #emit POP.alt
- #emit OR
- #emit POP.alt
- #emit OR
-
- #emit RETN
-
- // Make the compiler happy.
- return 0;
- }
- /**--------------------------------------------------------------------------**\
- <summary>
- Cell_ReverseBytes(number);
- </summary>
- <param name="number">The number to manipulate.</param>
- <returns>
- All the bytes in the input reversed.
- </returns>
- <remarks>
- 1)
- Example: 0x12345678
- Becomes: 0x78563412
-
- 2)
- Example: 0x01020304
- Becomes: 0x04030201
-
- 3)
- Example: 0xFF00FF00
- Becomes: 0x00FF00FF
- </remarks>
- \**--------------------------------------------------------------------------**/
- stock Cell_ReverseBytes(GLOBAL_TAG_TYPES:data)
- {
- // Swap all bytes.
- // return (data >>> 24) | ((data & 0x00FF0000) >> 8) | ((data & 0x0000FF00) << 8) | (data << 24);
- #emit LOAD.S.pri data
- #emit PUSH.pri
- #emit MOVE.alt
-
- #emit SHR.C.pri 24
- #emit XCHG
- #emit SHL.C.pri 24
- #emit OR
- #emit SWAP.pri
-
- #emit PUSH.pri
- #emit CONST.alt 0x00FF0000
- #emit AND
- #emit SHR.C.pri 8
- #emit SWAP.pri
-
- #emit CONST.alt 0x0000FF00
- #emit AND
- #emit SHL.C.pri 8
-
- #emit POP.alt
- #emit OR
- #emit POP.alt
- #emit OR
-
- #emit RETN
-
- // Make the compiler happy.
- return 0;
- }
- /**--------------------------------------------------------------------------**\
- <summary>
- Cell_CountBits(number);
- </summary>
- <param name="number">The number to get the number of 1s in.</param>
- <returns>
- The number of 1s (set bits) in the input.
- </returns>
- <remarks>
- 1)
- Example: 0
- Returns: 0
-
- 2)
- Example: 1
- Returns: 1
-
- 3)
- Example: 0x01010101
- Returns: 4
-
- I rewrote this in assembly just to see if I could pretty much. I also
- rewrote the lookup version in assembly. In theory it should be faster, but
- the marshalling of data was a little awkward.
- </remarks>
- \**--------------------------------------------------------------------------**/
- stock Cell_CountBits(GLOBAL_TAG_TYPES:data)
- {
- // This function is a perfect candidate for re-writing in pure assembly.
- // data = data - ((data >>> 1) & 0x55555555);
- #emit LOAD.S.pri data // From this point on, just use registers!
- #emit PUSH.pri
- #emit SHR.C.pri 1
- #emit CONST.alt 0x55555555
- #emit AND // No "AND.C" annoyingly.
- #emit POP.alt
- #emit SUB.alt
-
- // data = (data & 0x33333333) + ((data >>> 2) & 0x33333333);
- #emit PUSH.pri
- #emit SHR.C.pri 2
- #emit CONST.alt 0x33333333
- #emit AND
- #emit SWAP.pri // Put the second half of the code on the stack.
- #emit AND // "alt" is already the correct value.
- #emit POP.alt
- #emit ADD
-
- // return ((data + (data >>> 4) & 0xF0F0F0F) * 0x1010101) >>> 24;
- #emit MOVE.alt
- #emit SHR.C.pri 4
- #emit ADD
- #emit CONST.alt 0xF0F0F0F
- #emit AND
- #emit SMUL.C 0x1010101
- #emit SHR.C.pri 24
- #emit RETN
-
- // Make the compiler happy.
- return 0;
- }
- /**--------------------------------------------------------------------------**\
- <summary>
- Cell_GetLowestBit(number);
- </summary>
- <param name="number">The number to get the lowest set bit of.</param>
- <returns>
- The integer position of the lowest set bit.
- </returns>
- <remarks>
- 1)
- Example: 0b00000000000000000000000000000001
- Returns: 0
-
- 2)
- Example: 0b00000000000000000000000000001000
- Returns: 3
-
- 3)
- Example: 0b00010001100011000011100010001000
- Returns: 3
-
- NOTE: This function returns "0" for both numbers with the "1" bit set AND
- the number "0", which has NO bits set. Check that the number is valid
- before passing it to this function.
-
- See: http://supertech.csail.mit.edu/papers/debruijn.pdf
- </remarks>
- \**--------------------------------------------------------------------------**/
- stock Cell_GetLowestBit(GLOBAL_TAG_TYPES:data)
- {
- static const
- scDeBruijn[] =
- {
- 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
- 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
- };
-
- // return scDeBruijn[((data & -data) * 0x077CB531) >>> 27];
- #emit LOAD.S.pri data
- #emit MOVE.alt
- #emit NEG
- #emit AND
- #emit SMUL.C 0x077CB531
- #emit SHR.C.pri 27
-
- #emit CONST.alt scDeBruijn
- #emit LIDX
-
- #emit RETN
-
- // Make the compiler happy.
- return 0;
- }
- /**--------------------------------------------------------------------------**\
- <summary>
- Cell_GetLowestBitEx(number);
- </summary>
- <param name="number">The number to get the lowest set bit of PLUS ONE.</param>
- <returns>
- The integer position of the lowest set bit PLUS ONE.
- </returns>
- <remarks>
- This function is identical to "Cell_GetLowestBit", but gives different
- results for 0 and non-zero numbers. The examples below all have a result
- one higher than the "Cell_GetLowestBit" function.
-
- 1)
- Example: 0b00000000000000000000000000000001
- Returns: 1
-
- 2)
- Example: 0b00000000000000000000000000001000
- Returns: 4
-
- 3)
- Example: 0b00010001100011000011100010001000
- Returns: 4
-
- 4)
- Example: 0
- Returns: 0
-
- See: http://supertech.csail.mit.edu/papers/debruijn.pdf
- </remarks>
- \**--------------------------------------------------------------------------**/
- stock Cell_GetLowestBitEx(GLOBAL_TAG_TYPES:data)
- {
- // Sadly these two arrays can't be shared because they have marginally
- // different values. We could write this code to use the other array and
- // do "+ 1", but that adds a WHOLE EXTRA INSTRUCTION! OH NOES!
- static const
- scDeBruijn[] =
- {
- 1, 2, 29, 3, 30, 15, 25, 4, 31, 23, 21, 16, 26, 18, 5, 9,
- 32, 28, 14, 24, 22, 20, 17, 8, 27, 13, 19, 7, 12, 6, 11, 10
- };
- // We load "data" in to "pri" here, so we don't do it within the "if"
- // statement. This, combined with the "RETN" straight after, makes this
- // code as optimal as I can manage! In fact, despite the fact that using
- // code (in this case the "if" statement) is usually less efficient. I have
- // tweaked the main code to account for the generated code such that I
- // couldn't do better even if it was possible to use "JZER" in assembly (it
- // isn't because the offsets don't compile properly). Additionally, because
- // if the check fails then "data" must be 0, then we also know that "pri"
- // must be 0 too, so there's no need to re-load that value as "return 0;"
- // would do.
- if (data)
- {
- // return scDeBruijn[((data & -data) * 0x077CB531) >>> 27];
- #emit MOVE.alt
- #emit NEG
- #emit AND
- #emit SMUL.C 0x077CB531
- #emit SHR.C.pri 27
-
- #emit CONST.alt scDeBruijn
- #emit LIDX
- }
- {} // Zero-cost bug fix.
- #emit RETN
-
- // Make the compiler happy.
- return 0;
- }
- /**--------------------------------------------------------------------------**\
- <summary>
- Cell_GetLowestComponent(number);
- </summary>
- <param name="number">The number to get the number of 1s in.</param>
- <returns>
- The lowest set bit.
- </returns>
- <remarks>
- Similar to Cell_GetLowestBit, but returns the bit, not the position of the
- bit.
-
- 1)
- Example: 0b00000000000000000000000000000001
- Returns: 0b00000000000000000000000000000001
-
- 2)
- Example: 0b00000000000000000000000000001000
- Returns: 0b00000000000000000000000000001000
-
- 3)
- Example: 0b00010001100011000011100010001000
- Returns: 0b00000000000000000000000000001000
- </remarks>
- \**--------------------------------------------------------------------------**/
- stock Cell_GetLowestComponent(GLOBAL_TAG_TYPES:data)
- {
- // return data & -data;
- #emit LOAD.S.pri data
- #emit MOVE.alt
- #emit NEG
- #emit AND
- #emit RETN
-
- // Make the compiler happy.
- return 0;
- }
- #if defined YSI_TESTS
- #include "..\YSI_Core\y_testing"
- #include "y_cell/tests"
- #endif
|