Составление инструкций CPU путем слияния четырех коротких шестнадцатеричных строк

Мой код разделяет некоторые значения со своим соседом. Имена «Инструкции, регистры» можно игнорировать в комментариях; просто посмотрите на них как на «имена». Важно то, как они разделяются, что можно увидеть в расчетах.

Я хочу улучшить этот код, потому что он выглядит ужасно, и едва ли можно понять, что происходит.

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;
    }

Я попробую объяснить с помощью примера (хотя я его почти не получаю).

Мы имеем Hexdecimal из 8 символов (это всегда структура).

83340247

Теперь мы можем разбить его, последние 4 - это «Адрес», и его можно удалить. Итак, все, что осталось, это Hexdecimals, которые разделяют ценности.

8334

Теперь, например, код:

lwz r0, 0x0000(r0)

переведет на: 80000000 Итак, lwz == "8" здесь.

lwz r1, 0x0000(r0) == 80200000

Итак, первый «r1» равен «2» справа?

lwz r1, 0x0000(r1) == 80210000

Все выглядит отлично, все разделено, другое «r1» - просто «1».

Теперь вот дилемма, когда они достигают значений выше одного Hexdecimal.

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

Итак, как вы можете видеть, когда они увеличивают размер, они добавят в место «Влево» от начальной точки. Таким образом, r1 (равно 2) станет «3», когда второй «r31» станет достаточно большим, поэтому ему необходимо использовать это пространство.

Я сосать объяснение, но я надеюсь, что эти примеры помогут немного по крайней мере:)

    //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");
        }
c#
8 голосов | спросил Zerowalker 21 12016vEurope/Moscow11bEurope/MoscowMon, 21 Nov 2016 09:35:52 +0300 2016, 09:35:52

2 ответа


5

Вам нужно научиться битполам, или это будет навсегда непрозрачным и болезненным для вас. Причина, по которой люди используют шестнадцатеричный, в первую очередь состоит в том, что каждая цифра аккуратно сопоставляется с четырьмя двоичными цифрами, которые использует реальное оборудование.

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

Давайте отбросим конечные нули для удобства и сосредоточимся на первых четырех цифрах. Преобразуйте в двоичный файл (вы можете сделать это с помощью калькулятора Windows в режиме «программист»):

8021 = 1000000000100001
803F = 1000000000111111
83FF = 1000001111111111

Давайте также преобразуем 31 в двоичный: 11111. Мы знаем, что для обозначения чисел из 0-31 требуется пять двоичных цифр. Давайте отбросим некоторые маркеры '|' чтобы отрезать группы из 5 цифр справа:

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

Теперь ясно, что происходит. Нам просто нужно перевести это в код (ПРЕДУПРЕЖДЕНИЕ: на самом деле не проверено, поскольку я ленив).

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

0x1F = 31 decimal = 11111 двоичный. Он используется как «маска», чтобы выбрать, какие биты мы интересуем: пять самых правых бит. «& Gt;»> оператор перемещает значение вдоль пяти бит, отбрасывая самые правые.

(Я не уверен, что ваш исходный код пытается упаковать или распаковать коды операций?)

ответил pjc50 21 12016vEurope/Moscow11bEurope/MoscowMon, 21 Nov 2016 14:25:02 +0300 2016, 14:25:02
2

Я не могу объяснить вам коды операций или регистры, потому что я понятия не имею, как работать, но я могу рассчитать их так, как вы это делаете. На этот раз я просто покажу альтернативное решение linq-ish:

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");

Так что же я сделал? Я превращаю каждое значение в строку длиной 4, чтобы вы получили это от первого выбора:

 8000 
03E0 
0014 

Затем Sum превращает каждое число в int и добавляет их. Последний шаг - вернуть его в шестнадцатеричный код, чтобы получить 83F4.


Вместо сдвига строки можно сделать то же самое с битовым сдвигом для каждого значения:

var result = hexShared        
    .Select(HexToInt)
    .Select((x, i) => x << (8 - i * 4)
    .Aggregate((x, next)  => x | next)
    .ToString("X");
ответил t3chb0t 21 12016vEurope/Moscow11bEurope/MoscowMon, 21 Nov 2016 12:51:23 +0300 2016, 12:51:23

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132