| /* |
| * ======== TargetDecoder.java ======== |
| */ |
| package xdc.rov; |
| |
| /* |
| * ======== TargetDecoder ======== |
| * This class provides two APIs for decoding values from arrays of target |
| * data. It supports ROV and RTA, but is intended for use in any project. |
| * |
| * 'decodeMAUs' takes an integer array of MAUs and takes the size of the |
| * value to decode in MAUs. |
| * |
| * 'decodeBytes' takes a byte array and takes the size in bytes. |
| * |
| * Both APIs take a 'signed' field to indicate whether the decoded value |
| * should be treated as signed. For example, if the value to decode is a |
| * 'UInt', then 'signed' should be false. If 'signed' is true, the target |
| * data will be decoded using 2's complement. |
| * |
| * Java bytes always treat the data as signed. Integers, however, may be a |
| * signed or unsigned representation of the target data. For example, on a |
| * target with 8-bit MAUs, the value 0xFF may be represented in an integer |
| * as either -1 or 255 depending on the memory read interface. Either |
| * representation may be passed to decodeMAUs, and the result will have the |
| * correct sign based on the 'signed' argument and the MSB of the value. |
| * |
| * decodeBytes does not require that the target have 8-bit MAUs. |
| */ |
| |
| public class TargetDecoder { |
| |
| private TargetType.Endianess endian; |
| private int bitsPerChar; |
| |
| public TargetDecoder(TargetType.Endianess endian, int bitsPerChar) |
| { |
| this.endian = endian; |
| this.bitsPerChar = bitsPerChar; |
| } |
| |
| /* |
| * ======== decodeMAUs ======== |
| * Decodes a target value from an integer array containing target MAUs. |
| * |
| * buffer - Buffer of target MAUs containing the data to decode. |
| * offset - Beginning index in 'buffer' of the data to decode. |
| * size - Size in MAUs (not bytes) of the value to decode. |
| * signed - Whether the value to decode is a signed type. |
| * |
| * The integers in 'buffer' must be MAUs. If the MAU size is 16-bits, then |
| * 'buffer' should contain 16-bit values, not bytes. |
| * |
| * The buffer should be in the endianess of the target. |
| * |
| * The integers in 'buffer' may be the signed or unsigned representation |
| * of the target data. For example, if the MAU size is an 8-bit byte, then |
| * the target value 0xFF may have the integer value -1 or 255. |
| */ |
| public long decodeMAUs(int buffer[], int offset, int size, boolean signed) |
| { |
| return (decode(buffer, offset, size, this.bitsPerChar, signed)); |
| } |
| |
| /* |
| * ======== decodeBytes ======== |
| * Decodes a target value from a bytes array. |
| * |
| * buffer - Buffer of target bytes containing the data to decode. |
| * offset - Beginning index in 'buffer' of the data to decode. |
| * size - Size in bytes (not MAUs) of the value to decode. |
| * signed - Whether the value to decode is a signed type. |
| * |
| * The buffer should be in the endianess of the target. |
| */ |
| public long decodeBytes(byte buffer[], int offset, int size, boolean signed) |
| { |
| int[] intBuf = new int[size]; |
| |
| /* Copy to an integer buffer. */ |
| for (int i = 0; i < size; i++) { |
| intBuf[i] = buffer[offset + i]; |
| } |
| |
| return (decode(intBuf, 0, size, 8, signed)); |
| } |
| |
| /* |
| * ======== decode ======== |
| * This helper function does the common decoding work between decodeMAUs |
| * decodeBytes. |
| * |
| * The added field 'bitsPerInt' is the number of bits represented by each |
| * integer in 'buffer'. This is required because decodeBytes may pass |
| * in an integer buffer which contains 8-bit bytes on a target with 16-bit |
| * MAUs; so bitsPerInt is not always equal to bitsPerChar. |
| * |
| * In other words, the values in buffer cannot be assumed to be bytes or |
| * MAUs. |
| */ |
| private long decode(int buffer[], int offset, int size, int bitsPerInt, |
| boolean signed) |
| { |
| long result = 0; |
| |
| /* |
| * First, add the MAUs or bytes together to get the unsigned |
| * representation of the value. |
| */ |
| |
| /* |
| * Little endian |
| * |
| * Value 0x12345678 |
| * Addr Value |
| * 0x0 0x78 |
| * 0x1 0x56 |
| * 0x2 0x34 |
| * 0x3 0x12 |
| * Read in as [0x78, 0x56, 0x34, 0x12] |
| */ |
| if (endian == TargetType.Endianess.LITTLE) { |
| |
| /* Little endian, so work through the values backwards */ |
| for (int i = size - 1; i >= 0; i--) { |
| long value = buffer[offset + i]; |
| |
| /* If the integer representation is signed, convert to unsigned. */ |
| if (value < 0) { |
| value += 1 << bitsPerInt; |
| } |
| |
| /* Add the value to the result. */ |
| result = result << bitsPerInt; |
| result += value; |
| } |
| } |
| /* |
| * Big endian |
| * |
| * Example value 0x12345678 |
| * Addr Val |
| * 0x0 0x12 |
| * 0x1 0x34 |
| * 0x2 0x56 |
| * 0x3 0x78 |
| * Read in as [0x12, 0x34, 0x56, 0x78] |
| */ |
| else if (endian == TargetType.Endianess.BIG) { |
| |
| /* Big endian, so work through the values in order */ |
| for (int i = 0; i < size; i++) { |
| long value = buffer[offset + i]; |
| |
| /* If the integer representation is signed, convert to unsigned. */ |
| if (value < 0) { |
| value += 1 << bitsPerInt; |
| } |
| |
| /* Add this value to the result. */ |
| result = result << bitsPerInt; |
| result += value; |
| } |
| } |
| |
| /* |
| * Handle signed types. |
| * |
| * Only look at the sign if: |
| * 1. It's a signed type |
| * 2. The size of the type is less than 64-bits |
| * |
| * For a 64-bit signed type, we don't need to do anything to convert |
| * from unsigned to signed, because Java long can't hold a 64-bit |
| * unsigned value. |
| */ |
| if (signed && ((size * bitsPerInt) <= 32)) { |
| int msbInt = 0; |
| /* |
| * Determine the sign of the value (-1 or 1) by looking at the MSB. |
| * |
| * On little endian targets, the sign bit is the last bit. |
| */ |
| if (endian == TargetType.Endianess.LITTLE) { |
| msbInt = buffer[offset + size - 1]; |
| } |
| /* On big endian targets, the sign bit is the first bit. */ |
| else { |
| msbInt = buffer[offset]; |
| } |
| |
| /* If the sign is negative, convert the result to negative. */ |
| if (getSign(msbInt, bitsPerInt) < 0) { |
| result = result - (1l << (size * bitsPerInt)); |
| } |
| } |
| |
| return (result); |
| } |
| |
| /* |
| * ======== getSign ======== |
| * Checks the value containing the MSB to determine the result's sign. |
| * This should only be called on the MSB and if the value being decoded |
| * is a signed type. |
| */ |
| private int getSign(long msbVal, int bitsPerInt) |
| { |
| /* If the MSB MAU is negative then the result is negative. */ |
| if (msbVal < 0) { |
| return (-1); |
| } |
| /* |
| * The integer representation may be signed or unsigned. |
| * If the MSB MAU is greater than the maximum value of the signed |
| * representation (e.g., 127 for an 8-bit MAU), the result is |
| * negative. |
| */ |
| else if ((msbVal & (1 << (bitsPerInt - 1))) != 0) { |
| return (-1); |
| } |
| else { |
| return (1); |
| } |
| } |
| } |