nabbla (nabbla1) wrote,
nabbla
nabbla1

Categories:

Баг воспроизведён!

Запустил свой многострадальный алгоритм обнаружения на симуляции, с полноценной картинкой 1024х720 - и ровно в том же месте словил ту самую ошибку, UFLO (исчерпание заданий GPU). Это хорошо, значит, сейчас можно будет её рассмотреть "под микроскопом".



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


Только закончили отправлять задания по этой строке и теперь начали запрашивать результаты. Синхроимпульс прошёл около 30 тактов назад, сейчас идёт "полочка". Поэтому ждём.


И тут же натыкаемся на странность: всё первое пятно мы взяли и пропустили:


Зная о его существовании, мы должны были заказывать отдельные отрезки: перед ним, внутри него и после него, но похоже, что это задание у нас испарилось - либо задание, либо его результаты.

Так что надо вернуться ещё раньше, в начало строки 0x5F = 95:


Тут всё правильно, первый отрезок как раз оканчивается там, где начинается первое пятно. Соответственно, мы на нём получили макс. яркость 0, никакого нового пятна добавлять не стали (или хотя бы расширять имеющиеся) - и вышли в серединку цикла по пятнам, т.е на следующем отрезке мы ожидаем встретить пятно, которое у нас уже записано.


Как видно, этот отрезок вместил в себя всё пятно целиком (шли пиксели 0xFF = 255, и аккурат к окончанию отрезка закончились), мы получили максимальную яркость 255, проверили Y-координату (до окончания пятна ещё ОЧЕНЬ долго), записали себе, что нужно эти же 2 отрезка заказать на следующую строку (сразу заказывать не хотим, вдруг сейчас его расширим, а то и объединим с пятном справа от него?), и начинаем ждать результат по следующему отрезку.


Отрезок этот - огромный интервал между пятнами, но кусок правого пятна в него попал, т.к оно как раз "вширь" пошло. На прошлой строке мы увидели лишь его верхушку.

Получили максимальную яркость 255 и координату 0x2E9 = 745. Начинаем проверять, не находится ли эта точка поблизости от уже найденных пятен. Сначала пятно слева, его координата X = 0x160 = 352, диаметр 0x6B = 107 - похоже на правду. Разумеется, эта точка к тому пятну не относится.

Поэтому начинаем проверять пятно слева, его координата X = 2EC = 748, диаметр 3 (только-только обнаружили). Диаметр расширили с 3 до 5. Следующий слайд:


Координату центра пятна выставили X = 0x2EA = 746.

Далее, вызывается процедура TaskPending, где мы должны выдать задание видеопроцессору на предыдущее пятно, если таковое имеется.

Внимательно смотрим PC=0x35. Здесь SrcAddr = 0x83, т.е взять значение C. И к следующему такту на шину данных поступает это значение, 0x8000 = -32768. Всё верно, это и есть наша "метка", что задание надо выдать!

Тут же идёт команда ABS (взять модуль), а на шину данных тем временем загружается адрес, куда прыгнуть, если переполнения не будет, 0x71 (MidCycle).

Команда JNO (Jump if Not Overflow), как и положено, останавливается на один такт, чтобы дождаться результата АЛУ. Только вот незадача: прыжок выполняется всё равно, хотя по логике должно было случиться переполнение!

Это тем более странно, поскольку мы заканчиваем цикл по "активным пятнам" ровно по тому же критерию: очередной указатель равен 0x8000, что мы проверяем с помощью ABS - и успешно выходим из цикла! Разница в том, что там JO, а здесь JNO. Неужели в этой логике ошиблись?

wire isOurOp = (DestAddr[7:5] == 3'b101)&DestAddr[3]&(~DestStall);

wire isFlags = isOurOp & DestAddr[4];

wire DoJO = (~ALUbusy) & isFlags & DestAddr[1] & (isOFLO ^ DestAddr[2]);


На симуляции видим, что команда JNO - это DestAddr = 0xBE = 1011_11102. Первые 3 бита: "101", и DestAddr[3]=1, и DestStall=0, так что должно получиться isOurOp = 1.

Далее, DestAddr[4]=1, так что и isFlags = 1, т.е у нас сейчас команда условного перехода по одному из флагов: знака либо переполнения, либо по наличию, либо по отсутствию. (всего таких команд 4, но один бит адреса, самый младший, незадействован).

Пока всё верно. В выражение DoJO, ALUbusy ко второму такту приравнивается к нулю, isFlags = 1, DestAddr[1] = 1. Наконец, DestAddr[2]=1, поэтому если isOFLO = 0 (переполнения нет), прыжок будет совершён.

Выходит, что переполнения нет?

Одну возможность я тут вижу: Что, если нам так "помог" Bypass? Он у нас, зараза, неразборчивый:

always @(posedge clk)
	BypassEn <= isOurAddr;


Если на шину данных запрос идёт из АЛУ, то мы внутри АЛУ коммутируем на вход регистра B младшие разряды из аккумулятора, что совершенно необходимо в некоторых вычислениях. Проблема в том, что если запрошен регистр C, то мы всё равно присоединяем разряды из аккумулятора!

А там в младших разрядах вполне могла заваляться "половинка" из-за нашей дурацкой возни с диаметрами и радиусами! А там вообще любого ненулевого значения достаточно, чтобы ПЕРЕПОЛНЕНИЯ НЕ СЛУЧИЛОСЬ! Одно дело, когда значение в точности 0x8000 0000, и совсем другое: 0x8000 8000, оно превратится в 0x7FFF 8000.

Лечится это удивительно легко, мы ужесточаем условие выдачи Bypass:

//0x - Acc (signed with saturation)
//10 - UAC (unsigned)
//11 - C (to store C register into stack)

always @(posedge clk)
	BypassEn <= isOurAddr & (SrcAddr[1:0] != 2'b11);


Теперь он будет включаться только на командах Acc и UAC (Unsigned ACc), но никак не "C". После ооочень долгой повторной симуляции смотрим то же самое место:


Совсем другое дело!

Никаких UFLO (исчерпания заданий GPU) или OFLO (переполнения результатов GPU) теперь не возникает на всём протяжении симуляции (т.е 8 мс), то есть хотя бы строки до 0x78 = 120 проходят нормально. Вот дамп памяти в конце симуляции:


В списке "активных пятен" (ActivePoints) первым идёт (0x160, 0x55), диаметр 0x6B, то есть (352; 85) диаметром 107.
Затем, (0x2DF; 0x70), диаметр 0x3D, или (735; 112) диаметром 61.
И наконец, (0x308; 0x76) диаметром 3, или (776; 118) диаметром 3.

Очень похоже на правду! Левое пятно уже "консолидировалось", правое ещё нет, но лиха беда начало.


Да, не ожидал такой ошибки, всё думал либо на недостаточное время обработки, то ли на глюк в программе, но никак не на ошибку АЛУ, которая там сидела и ждала своего часа СВЫШЕ ГОДА! Ну что ж, теперь первые 8 мс симуляции (а дальше я не делал) проходят правильно.

Сейчас попробую снова "в железе", может сейчас оно возьмёт и сделается от начала до конца?
Tags: ПЛИС, программки, работа, странные девайсы
Subscribe

Recent Posts from This Journal

  • Нахождение двух самых отдалённых точек

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

  • Слишком общительный счётчик

    Вчера я чуть поторопился отсинтезировать проект,параметры не поменял: RomWidth = 8 вместо 7, RamWidth = 9 вместо 8, и ещё EnableByteAccess=1, чтобы…

  • Балансируем конвейер QuatCore

    В пятницу у нас всё замечательно сработало на симуляции, первые 16 миллисекунд полёт нормальный. А вот прошить весь проект на ПЛИС и попробовать "в…

  • Огари разговаривают

    Сегодня по пути на работу встретил огарей прямо в Лосином острове, на берегу Яузы. Эти были на удивление бесстрашны, занимались своими делами, не…

  • Ковыряемся с сантехникой

    Наконец-то закрыл сколько-нибудь пристойно трубы, подводящие к смесителю, в квартире в Москве: А в воскресенье побывал на даче, там очередная…

  • Мартовское велосипедное

    Продолжаю кататься на работу и с работы на велосипеде, а также в РКК Энергию и на дачу. Хотя на две недели случился перерыв, очередная поломка,…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 3 comments