8
\$\begingroup\$

My code shares some values with its neighbor. The names "Instructions, Registers" can be ignored in the comments; just see them as "names". What's important is how they are shared, which can be seen in the calculations.

What I want is to improve this code, because it looks awful and one can barely understand what's going on.

hexShared = {"80","3E","14"}; //lwz r31, -0x0018(r20)
    //Merge Hex Values that are shared (Basically every other is shared with the next one except the Address)
    private static string mergeHex(string[] hexShared)
    {

        //[ ][ ][ ][ ]
        //[0  1][2  3]
        string s1 = hexShared[0]; //Instruction
        string s2 = hexShared[1]; //Register 1
        string s3 = hexShared[2]; //Register 2

        char c1 = s1[1]; //Instruction Shared with Register 1
        char c2 = s2[0]; //Register 1 Shared with Instruction
        char c3 = s2[1]; //Register 1 Shared with Register 2
        char c4 = s3[0]; //Register 2 Shared with Register 1
        char c5 = s3[1]; //Register 2

        string hex = AddHex(c1, c2);

        string hex2 = AddHex(c3, c4);

        hex = s1[0] + hex + hex2 + c5;

        return hex;
    }

I will try explain with an example (though I barely get it myself).

We have a Hexdecimal of 8 characters (that's the structure always).

83340247

Now we can split it up, the last 4 are the "Address" and it can be taken out. So what remains are Hexdecimals that share values.

8334

Now for example the code:

lwz r0, 0x0000(r0)

will translate to: 80000000 So lwz == "8" here.

lwz r1, 0x0000(r0) == 80200000

So the first "r1" equals "2" right?

lwz r1, 0x0000(r1) == 80210000

It all looks fine, everything is separated, the other "r1" is simply "1".

Now here is the dilemma, when they reach values higher than one Hexdecimal can represent.

lwz r1, 0x0000(r31) == 803F0000
lwz r31, 0x0000(r31) == 83FF0000

So as you can see, when they increase size, they will Add into the place "Left" of their starting point. So r1 (which is 2) will become "3" when the second "r31" becomes large enough so it needs to use that space.

I suck at explaining but i hope this Examples helps a bit at least:)

    //Convert Hex in String to Integer
    public static int HexToInt(string Hex)
    {
        return int.Parse(Hex, NumberStyles.AllowHexSpecifier);
    }


//Sum Two Hex Chars and return it as Hex String (1 character)
        public static string AddHex(char hex1, char hex2)
        {
            int i1 = HexToInt(hex1.ToString());
            int i2 = HexToInt(hex2.ToString());
            int sum = i1 + i2;
            return sum.ToString("X1");
        }
\$\endgroup\$
7
  • 3
    \$\begingroup\$ What does it mean shares values with its neighbor? I cannot figure out what the mergeHex is about. one can barely understand what's going on you're pretty right about that! ;-] \$\endgroup\$ Commented Nov 21, 2016 at 7:18
  • \$\begingroup\$ Haha well it's a complete mess. Basically, if you look at the "strings" you can see that i have to split them up into Chars. Then i have to take a Char from two different strings, Add them and save the result. They they affect each other with the counting, so it's very weird. \$\endgroup\$ Commented Nov 21, 2016 at 7:30
  • \$\begingroup\$ @t3chb0t Added some examples and more explanations:) \$\endgroup\$ Commented Nov 21, 2016 at 7:39
  • \$\begingroup\$ Please add the HexToInt method so one can run it and try it out... will you? And a sample hexShared array. \$\endgroup\$ Commented Nov 21, 2016 at 8:12
  • 1
    \$\begingroup\$ @t3chb0t Done, made some small tweaks, removed Address (as no calculations were made on it anyway as the value gets shared towards the left). Also split the Adding to another function which i inserted as well just to make it cleaner:) \$\endgroup\$ Commented Nov 21, 2016 at 8:54

3 Answers 3

5
\$\begingroup\$

Assembly opcodes are not constructed with string manipulations. They are very carefully designed with bit positioning, so a simple add operation between two integers might not be the best way to describe it.

So your mergeHex method that god-knows-what does with strings should become a method that might do some bit shifting, masks, ...

I sampled the behavior of your mergeHex with two calls (which is not enough to know what it does for all your possible scenarios), but anyway I reached the following conclusion:

  1. The output is a 16bits (word) hex string.
  2. The first 8 bits are given by hexShared[0] | ((hexshared[1] & 0xF0) >> 4)
  3. The last 8 bits are given by ((hexshared[1] & 0x0F) << 4) | values[2]

Turning this into an algorithm becomes now trivial, let me suggest an implementation with some simplifications:

private static string ToWord(string[] hexTokens){
    var values = hexTokens
        .Select(t => HexToInt(t))
        .ToArray();

    var result = values[0] << 8 | values[1] << 4 | values[2];
    return result.ToString("X1");
}
\$\endgroup\$
7
  • \$\begingroup\$ This implementation might not cover all use cases of OP. If possible he would edit his question, or put a comment here describing the non working scenario (if there is any). \$\endgroup\$ Commented Nov 21, 2016 at 9:47
  • \$\begingroup\$ My case is Far from complete, it only works with one type of opcode, which is "Load and Store". Any other instructionset i will have to do manually like i did with this one i guess. But are you saying it's possible to figure out an "universal conversion" for this? I have never understood bitshifting, do you know of any tutorials on it (preferably video), i have tried finding it myself before without much luck. Thanks:) \$\endgroup\$ Commented Nov 21, 2016 at 9:58
  • \$\begingroup\$ @Zerowalker But are you saying it's possible to figure out an "universal conversion" for this? Yes it is. There's nothing like a pen and paper and some couple of simple exercises to understand it. When you shift-left a bit by 1 you are simply multiplying it by two (adding a 0 to the right of it). Convert some hexadecimal to binary do some shifting and ors and see what happens. \$\endgroup\$ Commented Nov 21, 2016 at 10:02
  • \$\begingroup\$ haha well basically have no clue clue what you are saying there, i see the words but they go right past me xD But this is awesome and Very interesting, i had my assumptions that bitshifting or something similar (which modifies it's neighbors) would be the way to go. Really need to read up on this. I tried your method and it seems to work fine. If i may ask, could you provide a quick explanation on what's going on with the bitshifting in your function? Thanks. \$\endgroup\$ Commented Nov 21, 2016 at 10:07
  • \$\begingroup\$ @Zerowalker It's a simplification of the procedure I described in the answer. You take hexShared[0] and "position" it as the first 8bits. So imagine you have Ox0080 to "position" it as Ox8000 you need to shift it 8 times. Then you have 3E and you want to have 0x83E0 so you have to shift it 4 times and make an or with the result. Then you have 14 and you want the result 0x83F4, you just have to make an or with the last result. I hope that makes sense \$\endgroup\$ Commented Nov 21, 2016 at 10:14
5
\$\begingroup\$

You need to learn bitfields or this will be forever opaque and painful for you. The reason people use hexadecimal in the first place is that each digit maps neatly to the four binary digits that the real hardware is using.

lwz r1, 0x0000(r1) == 80210000
lwz r1, 0x0000(r31) == 803F0000
lwz r31, 0x0000(r31) == 83FF0000

Let's drop the trailing zeroes for convenience and focus on the first four digits. Convert to binary (you can do this with the Windows calculator in "programmer" mode):

8021 = 1000000000100001
803F = 1000000000111111
83FF = 1000001111111111

Let's also convert 31 to binary: 11111. We know that referring to numbers from 0-31 requires five binary digits. Let's drop some markers '|' in to cut off groups of 5 digits from the right:

8021 = 100000|00001|00001
803F = 100000|00001|11111
83FF = 100000|11111|11111

Now it's really clear what's going on. We just need to translate that into code (WARNING: not actually tested as I am lazy).

int opcode = 0x80210000;
int registerB = opcode & 0x1F;
int registerA = (opcode>>5) & 0x1F;
int instructionCode = opcode>>10;

0x1F = 31 decimal = 11111 binary. It's being used as a "mask" to select which bits we're interested in: the five rightmost bits. The ">>" operator moves the value along five bits, discarding the rightmost ones.

(I'm not actually sure whether your original code is trying to pack or unpack opcodes?)

\$\endgroup\$
1
  • \$\begingroup\$ Yeah really need to read up on this, so it's called bitfields? I kinda see what's going on:) Though "opcode", why is it 8021? shouldn't it just be "8000"? Though in the scenarios i currently can convert, the values are: 8, 9, 10, 11, 12, 13 (in Decimal, which translates to) "lwz", "stw", "lhz", "sth", "lfs", "stfs" . It's just hardcoded as i saw all these use the same method on the registers / address, and only the first (opcode?) changed. Other instructions does other things, but i assume the main shifting is still in place (or masking or what it's called xd). \$\endgroup\$ Commented Nov 22, 2016 at 0:22
2
\$\begingroup\$

I cannot explain you the opcodes or registers because I have no idea how the work but I can calculate them as you do so this time I'll just show an alternative linq-ish solution:

var hexShared = new[] { "80", "3E", "14" };

const int hexLength = 2;
const int wordLength = 4;

var result = hexShared
    // Adds zeros before or after the string to make a word-long hex of each
    .Select((x, i) => x.PadLeft(i + hexLength, '0').PadRight(wordLength, '0'))
    .Sum(HexToInt)
    .ToString("X");

So what did I do? I turn each value into a string of length 4 so you get this from the first select:

8000 
03E0 
0014 

Then the Sum turns each number into an int and adds them. Last step is to turn it back into a hex to get 83F4.


Instead of string-shifting can do the same with bit-shifting for each value:

var result = hexShared        
    .Select(HexToInt)
    .Select((x, i) => x << (8 - i * 4)
    .Aggregate((x, next)  => x | next)
    .ToString("X");
\$\endgroup\$
1
  • \$\begingroup\$ Quite neat way of using string manipulation in the first segment, need to remember those Linq? methods. \$\endgroup\$ Commented Nov 22, 2016 at 0:23

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.