nabbla (nabbla1) wrote,
nabbla
nabbla1

Category:

Хочешь написать эмулятор процессора -

готовься отлаживать его в окне CPU, даже если пишешь на "языке высокого уровня"!

Я сломал Паскаль...




До недавнего времени у меня эмулятор был "высокоуровневым" - команды умножения он выполнял с помощью целочисленных команд умножения, а именно, умножал два 16-битных цисла, получая 32-битный результат, который и заносился в "аккумулятор". Всё работало безукоризненно - паскаль, может и не очень заточен под всякие вычислительные или системные вещи, но глядел на тип переменных - SmallInt или Word - и всё вычислял правильно - и знаковый на знаковый - и беззнаковый на беззнаковый, и смешанный.

Но затем появился "байпас" (см. монструозное АЛУ), когда ради повышения точности, если одно из значений берётся из 32-битного аккумулятора, то оно переносится в регистр "B" ЦЕЛИКОМ, а не только те 16 бит, что влезают на шину данных. И теперь уже побитово смоделировать поведение такого АЛУ можно только "ручками", в том плане, что у нас теперь умножение 32-битного числа на 16-битное, но умножение не совсем точное, т.к 32-битное число на каждой итерации сдвигается вправо, и младшие биты "пропадают", суммируем мы только старшие 32 бита.

Ну и обломился на одной из самых очевидных строчек, как мне казалось. Мне нужно было сделать циклический сдвиг 16-битного регистра C, и я написал такую строку:

      Regs.C.value := (Regs.C.value SHL 1) OR (Regs.C.value SHR 15);

Делать ассемблерную вставку с командой циклического сдвига не хотелось, вроде даже Intel Atom D510 это дело хавает на приличной скорости, тут нужно просто получить функционально правильный результат и желательно "самоочевидный" код.

C.value - это 16-битное поле, SmallInt, т.е знаковое. Но SHL и SHR - они и в африке операторы ЛОГИЧЕСКОГО сдвига, т.е на место сдвинутых бит должны вставляться нули.

Вот я и пишу: всё сдвинуть влево, и объединить по OR со значением, сдвинутым "до упора" вправо, так что из 16 бит остаётся только самый старший.

Получилось почему-то по-другому.

Начав с числа 994 (0x03E2), пошла такая свистопляска:
994   (0x03E2)
1988  (0x07C4)
3976  (0x1F10)
7952  (0x3E20)
15904 (0x7C40)
-1920 (0xF880)
-1    (0xFFFF)
-1    (0xFFFF)
....


Вот что-то совсем не циклический сдвиг!

И только глянув, как оно превращается в ассемблер, понимаешь, в чём там собака зарыта.

Похоже, что когда компилятор натыкается на SHR или SHL, то всегда использует самые широкие регистры из доступных - 32 бита или даже 64 бита в приложениях x64. Мог бы он этого не делать - видно же, что и результат, и операнды одной ширины, и в x86 можно сдвиги делать любого размера, хоть 8, хоть 16 - но почему-то делает.

А дальше - логика: если переменная объявлена как знаковая, значит, при её расширении до 32 бит надо сделать расширение знака, воспользовавшись movsx вместо самого обычного mov.

Пока у нас числа положительные - никаких проблем. Но когда появилось -1920 (0xF880), оно было расширено до 32 бит (0xFFFF_F880), и уже это 32-битное значение сдвинуто вправо на 15 позиций, давая не просто единичку, а целый злой 0xFFFF (-1), который по OR и весь результат превращает в -1.

Указание рассматривать все переменные как беззнаковые в этом выражении спасает ситуацию:

      Regs.C.value := ((Word(Regs.C.value) shl 1) or (Word(Regs.C.value) shr 15));



Расширение знака теперь заменили на заполнение нулями - это лучше :)

Теперь всё работает ровно так, как было задумано. Но очередные несколько часов ушли куда-то не туда, куда хотелось...
А то я ещё грешным делом подумал - может быть, всё-таки SHR для знаковых чисел заменяется на SAR, но в родном "дизассемблере" всё равно отображается как SHR, честно глянул опкод - нет, всё-таки SHR, логический сдвиг.

Вообще жесть какая-то с отображением самых-самых простых операций. Вон, в verilog арифметический сдвиг вправо вроде как обозначается >>>, но только не работает ни разу, поэтому я ручками его рисую раз за разом:

assign Shifted = {Orig[15], Orig[15:1]}

и всё в этом духе.

Tags: ПЛИС, программки, работа, странные девайсы
Subscribe

  • О вытягивании себя из болота по методу Мюнхгаузена

    Всё готовлюсь к встрече с представителями РКК Энергия, нужно убедить их в моём способе определения положения ВидеоИзмерителя Параметров Сближения на…

  • Ремонт лыжных мостиков

    Вернулся с сегодняшнего субботника. Очень продуктивно: отремонтировали все ТРИ мостика! Правда, для этого надо было разделиться, благо народу…

  • Гетто-байк

    В субботу во время Великой Октябрьской резни бензопилой умудрился петуха сломать в велосипеде. По счастью, уже на следующий день удалось купить…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 11 comments

  • О вытягивании себя из болота по методу Мюнхгаузена

    Всё готовлюсь к встрече с представителями РКК Энергия, нужно убедить их в моём способе определения положения ВидеоИзмерителя Параметров Сближения на…

  • Ремонт лыжных мостиков

    Вернулся с сегодняшнего субботника. Очень продуктивно: отремонтировали все ТРИ мостика! Правда, для этого надо было разделиться, благо народу…

  • Гетто-байк

    В субботу во время Великой Октябрьской резни бензопилой умудрился петуха сломать в велосипеде. По счастью, уже на следующий день удалось купить…