pozitronik: (Default)
[personal profile] pozitronik
13:58 27.03.2013
Пилим восьмибитный процессор. Часть седьмая, баголовная.
Я две недели не публиковал описаний прогресса разработки процессора.
Тем не менее, это не значит, что я им не занимаюсь - занимаюсь, хотя, пожалуй, уже без той остервенелой увлечённости, что в начале, плюс, отвлекаюсь на другие занятия, да ещё сидел без клавиатуры несколько дней. Но даже с учётом всего этого, две недели - срок вполне достаточный для накопления очередной порции интересных доработок.
Я так думал, да. Всего за пару дней я переделал микросхемы, определяющие тип операндов и их количество, переделал командный блок (переупорядочил команды, добавил новые), добавил новые регистры - и очевидных проблем при этом не проявлялось. Вылезали, конечно, кое-какие баги, не найденные раньше, но ничего серьёзного.
Так что я начал было заниматься командами перехода по памяти, которые сплошь однобайтные - и оказалось, что мой управляемый счётчик неправильно работает на операции, описываемой как for ($=0;$i==0;$i++) - то есть команды без операндов им не воспринимались, что вело к неправильному разбору всей дальнейшей памяти.
Окей, проблема локализована, надо только переделать счётчик...
Я потратил на это неделю.

Несложная, казалось бы, задача - а схема не давалась ни в какую. Подход "разбить на подзадачи и решить по отдельности" не работал - решённые подзадачи просто не склеивались в целое. Расписать логику схемы в виде набора логических функций, сократить вывод и реализовать получившееся схемой вовсе нельзя (вернее, можно, но это задача довольно громоздкая, и я бы только запутался).
Тогда я применил другой подход. Если задача не даётся - займись чем-нибудь другим. Пусть подсознание само решает задачу, тебе останется только проверять выдаваемые им варианты. Что, вы так не умеете? Ха-ха, неудачники!
Прошло время, подсознание действительно выдало вариант решения (уже не помню какого, да и не важно). Я открыл схему, прогнал тестовую программу, чтобы освежить в памяти структуру - а схема-то и не работает.
То есть, допустим, какой-то простой код, вроде mov a,1h не работал совсем. При этом вся логическая цепочка работала как надо, на всех контактах были правильные значения, а нужный регистр не устанавливался и всё. Странно, как и то, что раньше-то это работало - более того, при откате не предыдущую версию схемы работало тоже.
Значит что? Значит накосячил где-то при доработках, и проглядел косяк. Попробовал поискать - нету. А различий с последним рабочим образцом накопилось уже достаточно, и разобраться, какие из них являются причиной бага уже довольно трудно.
В общем, я плюнул, откатился на последнюю рабочую версию, и стал переносить доработки понемногу, усиленно тестируя схему после каждого изменения. Снова переделал микросхемы и командный блок, всё выглядело чисто. В недоумении я хотел уже было браться за блок регистров, но тут мне "повезло" (если так можно выразиться) - одна из тестовых программ давала сбой. Программа примерно такая:

MOV REG1,VALUE ;изменяем любой регистр, не обязательно через MOV
SHL REGx,VALUE ;регистр может быть указан любой, не обязательно тот, что в предыдущей команде

Первая команда выполнялась безупречно, а на момент чтения (даже не выполнения!) первого операнда второй команды REG1 обнулялся. Путём перебора, выяснилось, что такой же баг вызывают некоторые другие операнды во второй команде, например SUB и XOR. А, скажем, SUM проходила нормально. Поэкспериментировав, я выяснил, что и не команда даже влияет на появление бага, а полный байт команда+типы параметров; причём последовательности значений "бажных" байт не выглядели хоть как-то осмысленно. Например, значения с 53h до 57h приводили к ошибке, значения в промежутке 58h-63h ошибки не вызывали, а значения выше 63h - опять приводили к багу.
Логики никакой. Да даже и не в том, дело, какая последовательность вызывает ошибку, дело в том, что процессор попросту не мог такую ошибку допустить. У него есть нога EXECUTE, сигнал на которой вызывает выполенение буферизованной команды. Если на ноге нет сигнала - состояние процессора не меняется. Вот эта нога выделена на развёрнутой схеме:


Клик для увеличения

Как видите, n-транзисторы просто отсекают процессор от буфера, так что совершенно не имеет значения, что там "вовне" - если, конечно, на ноге ноль. А на ноге был ноль (сигнал появлялся только тогда, когда счётчик доходил до нужного значения), но процессор всё время вёл себя по разному.
Ошибки не было - и, в то же время, она была. Я потратил уйму времени и нервов, пытаясь разобраться, и был уже близок к тому, чтобы сдаться, признав, что ошибка где-то в Logisim.
Хорошо, что подсознание и тут предложило мне вариант. "Может быть - подумал я - счётчик и вправду выдаёт на выход EXECUTE сигнал, но тут же убирает его?".

Взглянем снова на схему счётчика:


В начальном состоянии на элемент И подаётся единица с компаратора и ноль с тактового входа. При первом такте с тактового входа придёт единица, а с компаратора - ноль. Если значения меняются одновременно, то после И реузльтат всё равно не изменится (0&1==1&0), как и требуется. Но вдруг одновременности не существует?
Забегая вперёд, скажу, что так оно и есть. В справке Logisim, в разделе "Задержки логических элементов" читаем в описании схемы, похожей на нашу:

Но элементы НЕ не реагируют мгновенно на сигналы на входах в реальности, и в Logisim - тоже. В результате, когда значение на входе этой цепи изменяется с 0 на 1, элемент И будет короткое время видеть 1 на обоих входах, и выдаст на выходе 1 на короткое время. Вы не увидите этого на экране.

Так как же проверить такое поведение? Вариант предложен там же, в справке (к собственному удовольствию я дошёл до него самостоятельно): подключить к выходу триггер, и посмотреть, изменится ли его значение, или нет:


Бах! Триггер переключается - а, значит, ошибка вызвана именно тем, что счётчик подаёт сигнал исполнения не тогда, когда требуется. Что же, процитирую справку ещё раз:

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

Почему же этот баг не проявлял себя раньше? Точно не знаю, но думаю, что просто не успел - слишком проста была схема процессора. Впервые проявлять он себя начал, видимо, уже после усложнения, что и заставило меня начать разбираться.
Устранить баг можно, но не нужно. Счётчик всё равно требуется переделывать. А переделка его мне никак не давалась - о чём я уже жаловался выше.
Помучавшись так и эдак, я применил такой подход: описал требуемую логику счётчика на псевдокоде (хотя, какой, к чёрту, псевдокод, это PHP), и попробовал потом описать этот код логической схемой (это всё равно, что строить блок-схему). Код получился такой:

  1. $COMMANDS=array(2,10,12,0,2,11,13,1,15,1,18,0,2,9,7);

  2. $return=array();

  3. $set=TRUE;

  4. $EXEC_FLAG=FALSE;

  5. $i=0;

  6. while (TRUE) {

  7. if ($EXEC_FLAG) {

  8. echo "-->EXEC ";

  9. print_r ($return);

  10. $EXEC_FLAG=FALSE;

  11. $return=array();

  12. }

  13. if ($set) {

  14. $for=$COMMANDS[$i];

  15. echo "!$for ";

  16. $lim=$for;

  17. $set=FALSE;

  18. $cnt=0;

  19. }

  20. echo ":$cnt ";

  21. $return[$cnt]=$COMMANDS[$i];

  22. if ($cnt==$lim) {

  23. $EXEC_FLAG=TRUE;

  24. $set=TRUE;

  25. $i++;

  26. continue;

  27. }

  28. $cnt++;

  29. $i++;

  30. }


$COMMANDS - массив, содержащий количества операндов при интерпретации ячейки памяти, как команды. Остальное, думаю, очевидно.
А вот схема, которая этот код реализует. Названия элементов соответствуют названиям переменных в коде, у регистра lim срабатывание переключено на высокий уровень (т.е. он обновляется не по переключению такта, а всегда, пока на тактовом входе есть сигнал). EXEC_FLAG и set - T-триггеры (в отличии от D-триггера они не устанавливают поданное на вход значение, а переключают собственное, т.о. их удобно использовать в качестве "флагов").


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

read more at Журнал Великого Позитроника

This account has disabled anonymous posting.
If you don't have an account you can create one now.
No Subject Icon Selected
More info about formatting

December 2016

S M T W T F S
    123
45678910
1112131415 1617
18192021222324
25262728293031

Style Credit

Expand Cut Tags

No cut tags
Page generated Jul. 19th, 2025 08:39 pm
Powered by Dreamwidth Studios