Начало
здесь.
10 команд было исполнены как надо. Дальше начинается активная работа с АЛУ. В чём был глюк - я нашёл, перепутал провода isNeg и busy, соединявшие модули ALU и PC. Поглядим, что здесь творится...
Команда "k 1" выполнилась штатно - уже радость. Дальше пошли более отожранные команды.
ACC [X+2i+k] (80 C9)
В первую очередь, проверяем формирование адреса. i=3, k=1, X=18 (все значения hex). Эффективный адрес: 1F, именно его мы видим на MemAddr. По нему нам выдают значение Fy3 (y-координата третьей точки), FC1B, что соответствует числу -997. Выход памяти коммутируется на шину данных DataBus. Счётчик инструкций на 3 такта застревает на текущей инструкции, потому что в АЛУ всё делается неторопливо: сдал-принял, опись, протокол, отпечатки пальцев!
SUB [X+2j+k] (83 CA)
Адрес сформировался тот же самый, что немудрено, ведь сейчас i=j=3. Поэтому на вход поступило то же самое значение, и опять АЛУ застрял на 3 такта. Что он там натворил - мы пока не знаем.
Следующий скриншот:
SQRD2 Acc (9C 80)
Мы видим, что в аккумуляторе действительно ноль - немудрено, ведь мы число вычитали из себя самого себя! Просто решили, что измеряя сумму квадратов расстояний точки до всех остальных, можем с тем же успехом измерить расстояния и "до самой себя", ради упрощения кода.
Также видим, что мы застряли на этой команде аж на 19 тактов - действительно, эти команды с возведением в квадрат и делением пополам - самые долгие из всех! На втором такте аккумулятор вдруг "ушёл в насыщение", т.е на нём появилось самое большое отрицательное значение 8000 (-32768). Попытаемся понять, что это значит. Управляющий сигнал для аккумулятора выгладит так (см здесь):
assign AccMode = isIdle? ((isOurAddr & (PlusMinusMode == 2'b00))? {1'b1, D[1:0]} : 3'b010) :
(isFirstDiv | isDiv2)? {isLongCommand & (PlusMinusMode == 2'b00), 1'b1, (PlusMinusMode == 2'b00)}:
isAdd? 3'b000:
{1'b0, ~Csenior, 1'b0};
Нас интересует первая строка, поскольку именно она определяет, что будет на аккумуляторе к следующему такту:
((isOurAddr & (PlusMinusMode == 2'b00))? {1'b1, D[1:0]} : 3'b010)
Адрес действительно "наш" (т.е принадлежит диапазону, выделенному для АЛУ), и PlusMinusMode действительно - два нуля. (первый столбец в "периодической системе команд АЛУ"). В этом случае мы заносим константу, определяемую 2 младшими битами из шины данных. Когда там сплошные нули - выходит управляющий сигнал 100, соответствующий константе "-3/2" (16-битные числа у нас имеют диапазон от -1 до +1), так что всё правильно. Данная строка "обслуживает" команду ZAcc, а SQRD2 "попала под раздачу", поскольку известно же, что уже на следующем такте мы обнулим аккумулятор как следует, поэтому нам пофиг, что там было до этого. Зато получили очень экономичный модуль управления АЛУ :)
Следующий слайд, пожалуйста.
ADD [SP] (82 FC)
Проверяем формирование адреса в ОЗУ: 60, всё верно. По этому адресу находится ноль, который мы туда загрузили чуть ранее (да и до этого там был ноль). Операция сложения занимает 3 такта.
[SP] Acc (FC 80)
Результат сложения заносим назад в стек. Результат, как ни странно, нулевой, заносится он по адресу 60, всё хорошо.
kLOOP -5 (AA 7B)
Поскольку k больше нуля, мы должны прыгнуть в начало цикла по k, и при этом из k вычесть единичку. "Литерал" (непосредственное значение) 7B, как обычно, проходит расширение знака до FFFB = -5, и поступает на шину данных.
И мы видим, что к следующему такту действительно k=0, и мы вернулись к инструкции по адресу 0B, ровно туда, куда и хотели.
ACC [X+2i+k] (80 C9)
мы здесь уже были. Но теперь k=0, и мы загружаем число с адреса 1E, т.е Fx3, координата X третьей точки. Там лежит значение 0190, или 400 в десятичной записи.
SUB [X+2j+k] (83 CA)
и здесь уже были. Адрес такой же, как в предыдущей команде, 1E.
SQRD2 Acc (9C 80)
и здесь пока ничего интересного, так как на входе - ноль.
А вот дальше будет веселее - нужно проверить, что мы успешно выходим из цикла по k, успешно прыгаем в начало цикла по i, а после этого наконец-то начнутся реальные (нетривиальные) вычисления!
Ещё 9 команд исполнены абсолютно верно. Продолжение следует...