nabbla (nabbla1) wrote,
nabbla
nabbla1

Category:

Тестируем захват ближ. дист. (ч1) на "сбалансированном" QuatCore

Наконец-то закончилась очередная 7-дневная эпопея с бумажками, возвращаюсь к своему макету. Если помните, у меня в очередной раз при увеличении размеров буферов FIFO перестали выполняться тайминги, после чего я сколько-нибудь кардинально "перебрал" свой процессор, часть комбинаторных цепей перенёс на предыдущий этап конвейера, где совсем уж ничего не происходило (раз, два)

Довольно быстро заметил, что полной эквивалентности при этом не вышло: в старом "коде" PreDestAddr защёлкивались в DestAddr только при условии PipeStall = 0, а тут я чего-то совсем позабыл, и защёлкивание PreDestAddr во внутренние регистры QuatCoreMem идёт на каждом такте. Что может пойти не так!?

И как будто этого мало, симуляцию я решил запустить с программой нахождения двух самых отдалённых точек, это первая часть алгоритма захвата (аффинного алгоритма) в ближней дистанции. Этот кусочек я только-только написал на ассемблере и ещё не проверял. К тому же, тут "к нам вернулась" команда ijk, от которой мы на долгое время отказались, но тут уж очень она напрашивалась!

Так что отладка обещает быть очень весёлой!



Сейчас я синтезировал одно только ядро QuatCore, без видеопроцессора и периферии. Получилось 535 ЛЭ, действительно команда ijk внесла свою лепту. Предельная частота аж 32,05 МГц - давненько такого не было, обычно-то я за 25 МГц борюсь!

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

И сразу забил оперативную память всем подряд (что позднее пригодится), чтобы ширина адресной шины стала бы 8 бит, ведь мы в регистре Y (ширина которого равна ширине адресной шины) будем хранить два индекса, и надо хотя бы 8 бит иметь.

Под спойлером листинг памяти.
[Spoiler (click to open)]
Fx0:        00    14528
Fy0:        01    -2944
Fx1:        02    -14016
Fy1:        03    -7872
Fx2:        04    29376
Fy2:        05    -11456
Fx3:        06    22720
Fy3:        07    -13568
Fx4:        08    -18752
Fy4:        09    -20736
Fx5:        0A   -25664
Fy5:        0B   -20800
Fx6:        0C   14848
Fy6:        0D   -23488
Fx7:        0E   -9408
Fy7:        0F   -27648
AfMat00:    10   4090
AfMat01:    11   10092
AfMat02:    12   -14492
AfMat03:    13   310
AfMat10:    14   -13992
AfMat11:    15   8627
AfMat12:    16   -2011
AfMat13:    17   7376
AfMat20:    18   1199
AfMat21:    19   -5752
AfMat22:    1A   -3495
AfMat23:    1B   -5807
SaMat00:    1C   -3249
SaMat01:    1D   16315
SaMat02:    1E   4618
SaMat10:    1F   -3947
SaMat11:    20   -19598
SaMat12:    21   4618
SaMat20:    22   3947
SaMat21:    23   -19598
SaMat22:    24   4618
SaMat30:    25   3249
SaMat31:    26   16315
SaMat32:    27   4618
SaMat40:    28   -7414
SaMat41:    29   3284
SaMat42:    2A   4618
SaMat50:    2B   7414
SaMat51:    2C   3284
SaMat52:    2D   4618
MBD1x:      2E   -24904
MBD1y:      2F   22282
MBD1z:      30   0
MBD2x:      31   -24904
MBD2y:      32   -22282
MBD2z:      33   0
MBD3x:      34   0
MBD3y:      35   28836
MBD3z:      36   -11796
MBD4x:      37   0
MBD4y:      38   28836
MBD4z:      39   13107
MBD5x:      3A   0
MBD5y:      3B   8651
MBD5z:      3C   0
MBD6x:      3D   0
MBD6y:      3E   -9699
MBD6z:      3F   0
MBD7x:      40   0
MBD7y:      41   -28836
MBD7z:      42   -13107
MBD8x:      43   0
MBD8y:      44   -28836
MBD8z:      45   13107
MDD3x:      46   0
MDD3y:      47   -5554
MDD3z:      48   15794
MDD1x:      49   0
MDD1y:      4A   -6832
MDD1z:      4B   410
MDD2x:      4C   0
MDD2y:      4D   9339
MDD2z:      4E   4743
MBDx:       4F   -2376
MBDy:       50   0
MBDz:       51   0
a11:        52   ????
a12:        53   ????
a22:        54   ????
a13:        55   ????
a23:        56   ????
a33:        57   ????
a14:        58   ????
a24:        59   ????
a34:        5A   ????
a44:        5B   ????
a15:        5C   ????
a25:        5D   ????
a35:        5E   ????
a45:        5F   ????
a55:        60   ????
a16:        61   ????
a26:        62   ????
a36:        63   ????
a46:        64  ????
a56:        65  ????
a66:        66  ????
DistA[0]:   67  0x0000
DistA[1]:   68  0x0000
DistA[2]:   69  0x0000
DistA[3]:   6A  0x0000
DistA[4]:   6B  0x0000
DistA[5]:   6C  0x0000
DistA[6]:   6D  0x0000
DistA[7]:   6E  0x0000
DistA[8]:   6F  0x0000
DistA[9]:   70  0x0000
DistA[10]:  71  0x0000
DistA[11]:  72  0x0000
DistA[12]:  73  0x0000
DistA[13]:  74  0x0000
DistA[14]:  75  0x0000
DistA[15]:  76  0x0000
DistA[16]:  77  0x0000
DistA[17]:  78  0x0000
DistA[18]:  79  0x0000
DistA[19]:  7A  0x0000
DistA[20]:  7B  0x0000
DistA[21]:  7C  0x0000
DistA[22]:  7D  0x0000
DistA[23]:  7E  0x0000
DistA[24]:  7F  0x0000
DistA[25]:  80  0x0000
DistA[26]:  81  0x0000
DistA[27]:  82  0x0000
DistA[28]:  83  0x0000
DistA[29]:  84  0x0000
DistA[30]:  85  0x0000
DistA[31]:  86  0x0000
Stack:      87  ????
Stack[1]:   88  ????
            89  ????
            8A  ????
...


Дальше неинициализированная область вплоть до FF.


Самой программой пока используются только адреса 0x00..0x0F, где лежат координаты 8 обнаруженных точек. Остальное всё пока "балласт".

Ну и листинг программы:
Find2Points proc
00  CD00              X       Points2D    ;используется с индексом i, чтобы выбрать точки 0..6
01  ED01              Z       Fx1     ;используется с индексом j, чтобы выбрать точки 1..7
02  A102              j       6       ;в дальнейшем будет выбор между 5 и 6 (если рассматривать 7 найденных точек вместо 8)
03  F000              [SP+1]  0       ;обнуляем. А "Y" (индексы) можно не обнулять, заведомо будут занесены на первой же итерации     
04  A0A1  @@j_loop:   i       j       ;сравниваем точку под индексом j+1 со всеми остальными, чей индекс меньше j+1
05  A203  @@i_loop:   k       1
06  FC00              [SP]    0       ;сравниваем с точкой i. Начинаем считать квадрат расстояния
07  8900              NOP     0 ;AUTOMATICALLY INSERTED BY TRANSLATOR TO PREVENT HAZARD
08  80EA  @@k_loop:   Acc     [Z+2j+k]    ;это Fy[j+1], если k=1, или Fx[j+1], если k=0
09  83C9              SUB     [X+2i+k]    ;это Fy[i], если k=1, или Fx[i], если k=0
0A  9C80              SQRD2   Acc     ;разность возвести в квадрат
0B  82FC              ADD     [SP]
0C  FC80              [SP]    Acc
0D  AA04              kLOOP   @@k_loop
0E  83F0              SUB     [SP+1]  ;сравниваем с самой большим квадратом дистанции на данный момент
0F  B805              JL      @@skip  ;меньше, не интересно
10  F0FC              [SP+1]  [SP]        ;программисты на ассемблерах x86, AVR и ARM должны завидовать, что у нас такое можно!
11  DDA4              Y       ijk     ;и такому
12  A806  @@skip:     iLOOP   @@i_loop
13  A907              jLOOP   @@j_loop
14  A7DD              ijk     Y
15  A008              i       7
16  FCB0              [SP]    Call(SwapPoints)
17  A7DD              ijk     Y
18  A106              j       5
19  FCB0              [SP]    Call(SwapPoints)
Find2Points endp
1A  B009  endless:    JMP     endless
SwapPoints  proc
1B  A203              k       1
1C  8900              NOP     0   ;хотим избежать warning'ов
1D  8AEA  @@swap:     C       [Z+2j+k]
1E  EAC9              [Z+2j+k]    [X+2i+k]
1F  C983              [X+2i+k]    C
20  AA0A              kLOOP   @@swap
21  B0FC              JMP     [SP]
SwapPoints  endp    


И начнём наблюдать.

Очень бодро идёт инициализация: X=0, Z=2, j=6, [SP+1]=0.

Блин, я забыл SP инициализировать! Совсем с дуба рухнул! Срочно исправляем это дело, и пробуем ещё разок!

Листинг подправленной программы:
00  FD00          SP      Stack
Find2Points proc
01  CD01          X       Points2D    ;используется с индексом i, чтобы выбрать точки 0..6
02  ED02          Z       Fx1     ;используется с индексом j, чтобы выбрать точки 1..7
03  A103          j       6       ;в дальнейшем будет выбор между 5 и 6 (если рассматривать 7 найденных точек вместо 8)
04  F001          [SP+1]  0       ;обнуляем. А "Y" (индексы) можно не обнулять, заведомо будут занесены на первой же итерации     
05  A0A1  @@j_loop:   i       j       ;сравниваем точку под индексом j+1 со всеми остальными, чей индекс меньше j+1
06  A204  @@i_loop:   k       1
07  FC01          [SP]        0       ;сравниваем с точкой i. Начинаем считать квадрат расстояния
08  8900      NOP  0 ;AUTOMATICALLY INSERTED BY TRANSLATOR TO PREVENT HAZARD
09  80EA  @@k_loop:   Acc     [Z+2j+k]    ;это Fy[j+1], если k=1, или Fx[j+1], если k=0
0A  83C9          SUB     [X+2i+k]    ;это Fy[i], если k=1, или Fx[i], если k=0
0B  9C80          SQRD2       Acc     ;разность возвести в квадрат
0C  82FC          ADD     [SP]
0D  FC80          [SP]        Acc
0E  AA05          kLOOP       @@k_loop
0F  83F0          SUB     [SP+1]  ;сравниваем с самой большим квадратом дистанции на данный момент
10  B806          JL      @@skip  ;меньше, не интересно
11  F0FC          [SP+1]  [SP]        ;программисты на ассемблерах x86, AVR и ARM должны завидовать, что у нас такое можно!
12  DDA4          Y       ijk     ;и такому
13  A803  @@skip: iLOOP       @@i_loop
14  A907          jLOOP       @@j_loop
15  A7DD          ijk     Y
16  A000          i       7
17  FCB0          [SP]        Call(SwapPoints)
18  A7DD          ijk     Y
19  A107          j       5
1A  FCB0          [SP]        Call(SwapPoints)
Find2Points endp
1B  B008  endless:    JMP endless
SwapPoints  proc
1C  A204              k       1
1D  8900              NOP     0   ;хотим избежать warning'ов
1E  8AEA  @@swap:     C       [Z+2j+k]
1F  EAC9              [Z+2j+k]    [X+2i+k]
20  C983              [X+2i+k]    C
21  AA09              kLOOP       @@swap
22  B0FC              JMP     [SP]
SwapPoints  endp    


И результаты симуляции, самое начало работы:


Ага, первым делом SP = 0x87, затем X=0, Z=2, j=6, [SP+1]=0, i=j=6, k=1, [SP]=0.

Дальше начинается интереснее. В аккумулятор загружается [Z+2j+k], это должен быть адрес 2+2*6+1=15 = 0xF, там лежит -27648 = 0x9400. Да, всё верно.

Затем вычитаем [X+2i+k], адрес 0 + 2*6 + 1 = 13 = 0xD, там лежит -23488 = 0xA440. Результатом становится -4160 = 0xEFC0.

Возводится в квадрат и делится пополам (команда SQRD2), в формате 1.15, после чего добавляется [SP] = 0. Результатом должно стать (-4160)^2/2/32768 = 264,0625, округляется до 264 = 0x108 - всё верно. Этот результат заносится в [SP], и выполняется прыжок в kLOOP. В результате становится k=0.

Теперь в аккумулятор заносится [X+2j+k], адрес 2+2*6+0=14=0xE, там лежит -9408 = 0xDB40, верно. Вычитается [X+2i+k], адрес 0+2*6+0=12=0xC, там лежит 14848 = 3A00. Результатом становится -24256 = 0xA140. Его мы возводим в квадрат и делим пополам, и прибавляем [SP] = 0x108. Что ж, пока память работает как надо.

Следующий слайд:


Результатом должно стать 264 + (-24256)^2/2/32768 = 9241,5625, округляется до 9242 = 0x241A. Это значение заносится назад в [SP]. Далее, прыжок по kLOOP не выполняется, мы идём ниже. Вычитаем из аккумулятора [SP+1] = 0 (наш "текущий максимум"), получаем всё тот же 9242. Прыжок JL не выполняется.

А теперь возникает какая-то хрень! Мы должны были поместить в [SP+1] значение из [SP], равное 0x241A. Но каким-то макаром у нас на шине данных стабильно лежит 0x0013, это значение для прыжка. Похоже, далеко не зря у нас регистры защёлкивались только в отсутствие PipeStall.

Ещё разок этот злополучный фрагмент:


И листинг:

0F  83F0          SUB     [SP+1]  ;сравниваем с самой большим квадратом дистанции на данный момент
10  B806          JL      @@skip  ;меньше, не интересно
11  F0FC          [SP+1]  [SP] 


Смотрим, что происходит. PC=0x11, но выборка SrcAddr была тактом ранее, при PC=0x10, поэтому SrcAddr = 0x06 (адрес, куда прыгать).
PreDestAddr также берётся из PC=0x10, то есть 0xB8 (JL). А DestAddr (сейчас используется для всех модулей, кроме QuatCoreMem) ещё тактом ранее, 0x83 (SUB). АЛУ "озадачивается", и позволяет нам заняться своими делами.

Пошёл следующий такт, переключились в PC=0x12. Сюда защёлкнулся SrcAddr из PC=0x11, то есть 0xFC, это [SP]. В PreDestAddr пришёл 0xF0, это [SP+1]. И в DestAddr: 0xB8 (JL).

И вот тут JL "застревает", поскольку АЛУ ещё не выдал результат. "застревание" проявляется в выдаче SrcStallReq = 1. Тем самым, всем сидящим на шине SrcAddr даётся предупреждение: не делайте никаких "побочных эффектов"! Скажем, команда [SP++] имеет полное право выдавать на шину данных содержимое [SP] хоть 100 тактов кряду. Вот только инкремент надо отключить!

А вот DestStall так и не зажигается, так и было задумано. Ведь из всех устройств на шине, работать должно ровно одно, то самое, которое даёт запрос SrcStallReq. Так зачем ему "самого себя" останавливать?

Поэтому к следующему такту у нас по-прежнему PC=0x11, и по-прежнему SrcAddr = 0xFC, и по-прежнему DestAddr = 0xB8 (JL). А вот внутри QuatCoreMem уже защёлкнулся 0xF0, то есть [SP+1] И поскольку DestStall=0, эта команда ошибочно выполняется "раньше времени", когда на шине данных сидит совсем не то значение, которое было задумано!

На последнем такте работы JL, когда АЛУ наконец освобождается, становится ещё интереснее, у нас ещё и команда [SP+1] по DestAddr "перебивает" команду [SP] по SrcAddr, из-за чего на шину данных вместо [SP] поступает только что записанное значение с [SP+1].


Да, кто бы мог подумать, разрешение работы регистров DestAddr действительно было абсолютно необходимым для корректной работы QuatCore :)

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

Ладно, я доволен уже тем, что вернулся к своему ассемблеру и верилогу. Завтра продолжим.
Tags: ПЛИС, программки, работа, странные девайсы
Subscribe

  • Лестница для самых жадных

    В эти выходные побывал на даче, после 3-недельной "самоизоляции". Забавно, как будто зима началась! Особенно грязные галоши остались на улице, в…

  • Возвращаемся к макету

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

  • Минутка живописи

    В процессе разгребания содержимого квартиры (после нескольких ремонтов) дошёл, наконец, и до картин. В кои-то веки их повесил. Куда их вешать -…

  • Костыль ноутбуку и кабели Франкенштейна (это не я!)

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

  • Атомный файлсервер, убитые петухи и харакири андроида

    Продолжаю совершать хаотические движения по квартире, хвататься то за одну железяку, то за другую, с желанием каждую куда-нибудь "пристроить". "По…

  • Ещё про яркий светильник и ИБП

    Всё-таки применил лежащее дома барахло наиболее простым образом: А ещё наконец-то замерял температуру теплоотвода яркого светильника на кухне,…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 0 comments