Как процессор парсит машинный код из нулей и единиц

Тема в разделе "WASM.BEGINNERS", создана пользователем Research, 15 янв 2024.

  1. Research

    Research Member

    Публикаций:
    1
    Регистрация:
    6 янв 2024
    Сообщения:
    116
    Каждый процессор имеет свой собственный набор инструкций, интересно как процессор извлекает команды из машинного кода. Как он определяет где начинается одна инструкция, и где начинается другая из сочетания битов?

    Интересно как в процессоре реализован декодер команд, в теории, простыми словами, по какому алкоритму
     
    Последнее редактирование: 15 янв 2024
  2. comrade

    comrade Константин Ёпрст

    Публикаций:
    0
    Регистрация:
    16 сен 2002
    Сообщения:
    232
    Адрес:
    Russian Federation
    Отличный вопрос для ChatGPT. Дам некоторые ключевые слова так как сейчас не могу много писать (времени не хватает и медленно печатаю на кириллице, терпения не хватает).
    • Набор инструкций это ISA (Instruction Set Architecture).
    • Процессор, при архитектуре Вон Ньюманна (Von Neumann), извлекает команда оттуда же откуда и данные. То есть память компьютера содержит как и данные так и инструкции.
    • Процессор, при самой начальной стадии, загружает инструкции по определённому адресу из памяти.
    • Где начинается следующая инструкция: это зависит от ISA. В большинстве ISA инструкции не одного размера. То есть адрес следующей и-ции напрямую зависит от размера текущий. В некоторых ISA (пример VLIW - Very Long Instruction Word) как в Elbrus2000 и Itanium, размер и-ции всегда один. Это по идее упрощает декодер и-ций в процессоре.
    • Как реализован декодер инструкций - это уже сильно зависит от самой реализации процессора. Даже при одной ISA (пример x86) реализации может радикально отличатся как от производителя (Intel vs AMD vs Cyrix) так и от поколения ядра (Intel Pentium vs Pentium II vs Intel Core).
    • В современных процессорах часто одна инструкция разлагается на более мелкие инструкции/шаги (microcode).
    • Процессор в классической литературе делится на control path и data path. Control path это как раз то что считывает инструкции, и зависимости от того что просит делать инструкция, включает или выключает определенные ходы в data path.
    --- Сообщение объединено, 15 янв 2024 ---
    Советую поискать на Github и news.ycombinator.com бесплатный открытый процессор написанный на Verilog или VHDL. Или самому такое сделать (несколько месяцев работы).
    --- Сообщение объединено, 15 янв 2024 ---
    Show HN: First ever FPGA CPU built using open source tools?
    https://news.ycombinator.com/item?id=9955634
    http://www.excamera.com/sphinx/article-j1a-swapforth.html
     
  3. Research

    Research Member

    Публикаций:
    1
    Регистрация:
    6 янв 2024
    Сообщения:
    116
    Я уже спрашивал у ChatGPT. Он воду льет, из за этого решил запостить вопрос на васм.
    Вместе с коммандами есть еще данные. Где данные, а где комманды, если все в виде нулей и единиц?

    Было даже такое предположение что перед данными передается длина,
    и отдельно разбирается набор байтов этой длины, но это вилами на воде.

    Как компьютер из потока нулей и единиц отделяет мух от котлет,
    скорее всего хуманы какой-то стандарт разбора изобрели за все время.

    Вопрос не в плоскости как работает процессор с таким-то набором инструкций,
    а как вообще декодеры разбирают набор нулей и единиц в общем
     
    Последнее редактирование: 15 янв 2024
  4. comrade

    comrade Константин Ёпрст

    Публикаций:
    0
    Регистрация:
    16 сен 2002
    Сообщения:
    232
    Адрес:
    Russian Federation
    Команды это данные для процессора, в специальном формате. Как скажем мультимедиа файл MP4 это данные для декодера MPEG4.

    Именно из нулей и единиц - это уже на уровне транзисторов, NAND/NOR gates и прочее. На базе этих примитивных структур строються более комплексные/сложные (супер-)структуры.

    Посмотри видео Ben Eater на ютубе
    --- Сообщение объединено, 15 янв 2024 ---
    https://www.youtube.com/@BenEater/videos
    --- Сообщение объединено, 15 янв 2024 ---
     
    Research нравится это.
  5. Research

    Research Member

    Публикаций:
    1
    Регистрация:
    6 янв 2024
    Сообщения:
    116
    Вопрос можно переформулировать так:

    1. Есть массив ByteArray из нулей и единиц.
    2. В цикле считываем по 1 байту, и прибавляем к переменной Cmd
    3. ?????
    4. Profit!!!
    --- Сообщение объединено, 15 янв 2024 ---
    [​IMG]
    Что комманды процессора из нулей и единиц с этим полностью согласен, еще есть
    данные, всякие адерса и т.д. они тоже из нулей и единиц, как он отделяет зерна от плевел?
     
    Последнее редактирование: 15 янв 2024
  6. comrade

    comrade Константин Ёпрст

    Публикаций:
    0
    Регистрация:
    16 сен 2002
    Сообщения:
    232
    Адрес:
    Russian Federation
    Вы размышляете в концепте программы где всё делается последовательно. В электронике так не работает. Транзисторы включает или выключает пути, вещи происходят одним мигом
     
  7. Research

    Research Member

    Публикаций:
    1
    Регистрация:
    6 янв 2024
    Сообщения:
    116
    comrade, или считывается по несколько байт сразу, не суть, вопрос в том
    как он узнает из: 011010111011001110101..., что это такая-то инструкция,
    с такими-то данными(они как и команды процессора тоже состоят из 0 и 1).
     
  8. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    457
    Если взять такой сложный в части декодинга процессор как 16-битный Intel 8086, то можно посмотреть на карту опкодов: http://sparksandflames.com/files/x86InstructionChart.html
    Сперва смотрим в первый байт инструкции.
    Если он светло-зеленый, то инструкция закончилась, она однобайтовая, переходим к её выполнению.
    Если цвет тёмно-зеленый, то у инструкции есть еще непосредственное данное - нужно его считать. Там где Ib в табличке это 1 байт, там где Iv - это слово, плюс всякие Jp или Ap - надо смотреть в расшифровку чего и сколько еще надо считать.
    А вот если цвет фиолетовый, то мы имеем дело с инструкцией с байтом ModR/M - надо теперь считать его и пропарсить его и в зависимости от его содержимого следом тоже может лежать байт или слово смещения. Тогда их тоже надо считывать и запихивать в параметры инструкции.
    Как то так.
    --- Сообщение объединено, 15 янв 2024 ---
    P.S.
    И да, более подробный и длинный пересказ вплоть по i86-64 есть тут: https://wasm.in/threads/principy-ko...x86-64-ili-exal-prefiks-cherez-prefiks.34390/
     
    Research нравится это.
  9. f13nd

    f13nd Well-Known Member

    Публикаций:
    0
    Регистрация:
    22 июн 2009
    Сообщения:
    1.993
    Считывается в кэш. Декодируется на жесткой логике, хотя тут наверное все зависит от поколения ядер. Вообще уже давно процессоры умеют в предикцию (предсказание) условных переходов и исполняют инструкции по готовности операндов, а не линейно одну за другой.
     
  10. Intro

    Intro Active Member

    Публикаций:
    0
    Регистрация:
    29 авг 2009
    Сообщения:
    591
    Интересно, декодер в 68к сложней чем 80386?
     
  11. f13nd

    f13nd Well-Known Member

    Публикаций:
    0
    Регистрация:
    22 июн 2009
    Сообщения:
    1.993
    И принципиальная схема есть и в микроскоп можно полюбоваться. IRC/IR (скорей всего представлен A1/A2/A3, A1 я так понял младшие 16 бит текущей инструкции)/IRD - регистры, содержащие инструкции. Учитывая простоту кодирования и общую куцость набора команд скорей всего многократно проще.
    изображение_2024-01-15_135831075.png
     
    Research нравится это.
  12. Intro

    Intro Active Member

    Публикаций:
    0
    Регистрация:
    29 авг 2009
    Сообщения:
    591
    f13nd, надо сравнить 486 и 68040. Первые скалярные процы.
     
  13. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    457
    У моторолы довольно компактно расписали вот тут http://goldencrystal.free.fr/M68kOpcodes-v2.3.pdf кодирование инструкций. В базисе 16-битные слова всё и могут дополняться immediate. В целом компактно и относительно однообразно кодируется.
     
  14. Research

    Research Member

    Публикаций:
    1
    Регистрация:
    6 янв 2024
    Сообщения:
    116
    aa_dav, немного появилась ясность.

    Процессор сначала считывает 1 байт("цвет") из последовательности двоичных данных,
    потом в зависимости от инструкции, считывает данные которые могут быть разной длины,
    http://sparksandflames.com/files/x86InstructionChart.html, сразу за ними считывает следующий 1 байт
    который содержит "цвет/категорию" следующей инструкции, все правильно?

    Код (Text):
    1. proc_data = "011010111011001110101..."; //последовательность двоичных данных
    Код (Text):
    1. color1 = "01101011"; //"первый" кусок данных из proc_data, окном 8 бит.
    2.  
    3. switch(color1)
    4. {
    5.  
    6.     case 'светло-зеленый':
    7.         //1. Считываем следующий байт данных
    8.         //2. Выполняем
    9.       ...
    10.       break;
    11.  
    12.     case 'тёмно-зеленый':
    13.         //1. Парсим параметры инструкции. Много всякой херни.
    14.       ...
    15.       break;
    16.  
    17.     case 'фиолетовый':
    18.         //Мы имеем дело с инструкцией с байтом ModR/M.
    19.       ...
    20.       break;
    21. }
    22.  
    23. //Функции, в них передаем последовательность в виде 0 и 1.
    24.  
    25.    ADD(...);
    26.    INC(...);
    Сначала хочу понять как он линейно парсит на простом примере
     
    Последнее редактирование: 15 янв 2024
    CaptainObvious нравится это.
  15. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    457
    Берем первый байт инструкции. Допустим это $44 - светло-зеленая инструкция INC SP - это вся инструкция в одном байте, просто увеличиваем SP и переходим к следующему байту в памяти как к следующей инструкции.
    Допустим это теперь $B4 - тёмно-зеленая инструкция MOV AH, байт - она тёмно-зеленая, сразу за первым байтом инструкции значит идут так называемые "непосредственные данные". В данном случае тот самый байт который надо записать в AH - считываем этот байт, исполняем теперь инструкцию помещая его в AH и переходим к следующей.
    Допустим на этот раз это $05 - тоже тёмно-зеленая инструкция у которой будет некое данное за ней, но это ADD AX, слово, а значит дальше будет лежать не байт, а два байта этого самого слова которое надо добавить к AX. После него уже будет лежать следующая инструкция.
    И так далее.
    То есть первый байт (опкод) инструкции диктует сколько дополнительных байт будет или нет у неё после. Еще всё еще осложняется фиолетовыми инструкциями которые вторым байтом содержат так называемый байт modR/M который опять таки в свою очередь опять кодирует будут дальше или нет дополнительные данные.
    И еще всё осложняется тем, что существуют еще так называемые префиксы (они в таблице как правило белого цвета) которые можно рассматривать как "модификаторы инструкций" и ставятся непосредственно перед опкодом немного модифицируя поведение опкода.
     
    Research нравится это.
  16. f13nd

    f13nd Well-Known Member

    Публикаций:
    0
    Регистрация:
    22 июн 2009
    Сообщения:
    1.993
    В основе всякого прибора, умеющего считать до 1, такая штука как регистр. Регистр это модуль памяти из n бит, у которого на жесткой схемотехнике реализована простая арифметика (с переносами единиц) и логика (без переноса). Если процессор хочет совершить арифметическо-логическое кунг-фу над некоторыми данными, он помещает эти данные в специально обученный регистр. Раскодирование инструкции тоже происходит в регистре. Основное прием здесь - маска и паттерн. Всякий интерпретатор, например дизассемблер, делает примерно то же самое, что процессор - выделяет маской поле опкода и сравнивает с паттерном (в жесткой логике может быть не совсем очевидно, но по сути это тоже оно). Загляни в исходники абсолютно любого дизассемблера, увидишь как инструкция раскодируется.
     
    Research нравится это.
  17. alex_dz

    alex_dz Active Member

    Публикаций:
    0
    Регистрация:
    26 июл 2006
    Сообщения:
    430
    нашел такой стейтмент ,и как его понимать? :)

    Questions is, what’s the longest possible instruction in the x86 instruction set?
    Answer: you can form a valid x86 instruction with an infinite number of bytes!
    That’s right, you could fill up an entire 64K ROM image with a single valid instruction. To be more specific, there is no limit to the length of 8086 instructions.
     
  18. MaKsIm

    MaKsIm Member

    Публикаций:
    0
    Регистрация:
    11 фев 2008
    Сообщения:
    79
    Лучше представить вот так:

    Это больше относится к процессору Pentium
    У процессора есть регистр анализа инструкции (РАИ) длиной, которая занимает его самая длинная инструкция. В этот регистр загружаются байты по текущему значению из регистров адреса выполнения (РАВ, cs:eip). Далее данные в этом регистре начинают подвергаться анализу. Сначала код инструкции: первые N бит. В зависимости от значения этих бит происходит дальнейший анализ и вычисление длины инструкции, если требуется. После каждой операции данные в РАИ подвергаются битовому сдвигу на величину кратную 8 (до границы байта), а в освободившееся место считываются новые байты из памяти по РАВ и его увеличение на длину инструкции (1 байт). Увеличение сдвига до границы байта нужно т.к. процессор может адресоваться к отдельным байтам памяти, а не к битам.

    Например в x86 некоторые инструкции имеют длину меньше 1 байта, но в остальных битах содержат параметры. Например, инструкция push ds (push cs, push ss или push es) состоит из 6 бит и 2 бит адресации к сегментному регистру. Т.е. процессор выдвинув из РАИ младшие 6 бит уже знает что ему надо делать (сохранить сегментный регистр в стек т.е. ему как минимум нужно значение адреса записанные в ss:esp), но не знает над каким операндом. И выдвинув еще 2 бита узнает о том, что операндом является регистр ds. Таким образом после сдвига 8 бит и освобождения 1 байта в РАИ процессор уже может выполнить инструкцию и переходит к следующим этапам. Передает задачу (РАВ: push ss:esp, ds) в конвейер выполнения инструкций, а сам обращается к дозагрузке освободившегося байта из РАВ + длина РАИ (хотя скорее всего дополнительное значение этой суммы сохранено в теневом РАИ, чтобы можно было загружать байты без дополнительных вычислений суммы) и увеличение РАВ на длину инструкции (1 байт). После заполнения РАИ циклически повторяет анализ.

    На следующем этапе в конвейере задача начинает выполняться по её логике: Проверка доступности адреса для записи, доступности значений в регистрах (нет ли инструкций, которые требуют значений из этих регистров и изменяют их). Когда ничего не мешает выполнению инструкции, тогда выполняется запись двух байт из видимой части сегментного регистра ds в память по адресу ss:esp. На этом инструкция считается выполненной и проверяется флаг трассировки или наличие ошибок. Если есть ошибки выполнения или флаг трассировки, тогда выдаются сигналы INT и РАИ перезагружается в соответствии с таблицами из памяти, а конвейер исполнения сбрасывает все отложенные выполнения.

    Но давайте теперь посмотрим на инструкции других типов. Например, add eax, 5. Точно также выдвигая биты из РАИ процессор пытается определить код операции. Выдвинув 7 бит он уже знает что делать, а еще 1 бит отвечают за дополнительный операнд: длину регистра (AL - bit7=0, AX, EAX или RAX - bit7=1 в зависимости от наличия префиксов) и непосредственного операнда (1 байт - bit7=0, 2, 4 или 8 байт - bit7=1). Далее из РАИ выдвигается N байт непосредственного операнда и добавляется задача (РАВ: add EAX, 0x00000005). Остальное как и в предыдущем случае.

    Это очень кратко и весьма приблизительно. Еще и пропущена куча логики формирования адресов и цикл чтения каталогов страниц для получения физических адресов. Нету проверок наличия страниц памяти в кэше процессора и циклов перезагрузки данных в страницы кэша. И много чего еще.
    Разумеется в современном процессоре это может быть организовано по другому. Но вот технологии анализа инструкций процессоров Pentium очень подробно была описана в Intel SDM. Подробнее можно прочитать про инструкции x86_64 в Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 2A: Instruction Set Reference, A-L CHAPTER 2 INSTRUCTION FORMAT.
     
    Последнее редактирование: 16 янв 2024
    Research нравится это.
  19. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    457
    Могу предположить, что на оригинальном 8086 можно было неограниченно спамить префиксами. Но с точки зрения защищенных режимов это серьёзная уязвимость, т.к. проц не может реагировать на прерывания, поэтому даже если такое и было в 16-битном оригинале возможно, то в i386 по логике вещей должны были против такого сделать illegal instruction.
     
  20. comrade

    comrade Константин Ёпрст

    Публикаций:
    0
    Регистрация:
    16 сен 2002
    Сообщения:
    232
    Адрес:
    Russian Federation
    Это можно и сейчас.

    https://www.gamingdeputy.com/almost...abilities-fixed-with-intels-microcode-update/