nabbla (nabbla1) wrote,
nabbla
nabbla1

Categories:

QuatCore: измерение масштаба

Медленно, но неумолимо, продвигаемся вперёд. Нахождение самой отдалённой точки, сортировка против часовой стрелки, вычисление матрицы аффинного преобразования и нахождение кватерниона крена с коррекцией матрицы - всё это сделано и работает.

Осталось немного. Сейчас необходимо найти масштаб.

В этот раз задачу разобьём чуть по-другому - не только найдём масштаб, но и его самого отмасштабируем, чтобы был в диапазоне от 16384 до 32767 (от 0,5 до 1), попутно получив "экспоненту". Так мы хоть увидим, чему же равен результат, т.к в противном случае он "застревает" в аккумуляторе, причём часть его - в младших разрядах, которые мы вообще не видим с шины данных.

Так что сейчас мы наконец-то убедимся, что "байпас" (раз, два) работает, а ещё проверим работу флага переполнения и команд условного перехода, на него реагирующих. Ну и глянем, нет ли подводных камней в замене UDIV2 (беззнак. деления на 2, по сути лог. сдвига вправо на 1) на DIV2 (знак. деления на 2) и вычитание 32767.



Код процедуры FindScale:

	;Состояние регистров к этому моменту:
	;X=QuatA,
	;Y=QuatY,
	;Z=AfTransf,
	;i=j=k=Inv=0,
	;C=Acc=Txx
	FindScale	proc
	;1. Вычисляем величины |X-Z| (т.е |Txx - Tyy| ) и |2Y| (например, |Txy+Tyx|, хотя можно 2|Txy| или 2 |Tyx| )
	;важно, что в данный момент Inv=0
				[SP]		0	;манхэттенская метрика, сумма модулей (метрика городских кварталов)
				[SP+1]		0	;чебышевская, максимум от модулей 
				;текущее значение будем хранить в регистре C - дешево и сердито!
				j		3					
				i		1
		@@loop:		Acc		[Z+i^j]	;+Tyx (i=1), -Tyy (i=0)
				PM		[Z+i]	;Txy (i=1), Txx (i=0)   ;поменяли местами чтобы проверить модуль
				ABS		Acc		;|Txy+Tyx| (i=1), |Txx-Tyy| (i=0)
				C		Acc		;сохранили это значение
				ADD		[SP]	
				[SP]		Acc	;обновили манхэттенскую
				Acc		[SP+1]
				;MAX		[SP+1]
				;замена MAX [SP+1]
				SUB		C
				JGE		@@skipCheb 
				[SP+1]		C	;обновили Чебышевскую	
				;конец замены MAX [SP+1]
		@@skipCheb:	Inv		1		;так что на следующей итерации будет "-"
				iLOOP		@@loop
	;теперь в [SP] лежит манхэттенская метрика, а в [SP+1] - чебышевская
	
	;кстати, у нас до сих пор j=3 :)
	;i=k=0
				Acc		[Z+i]	;добавили Txx
				ADD		[Z+i^j]	;и Tyy
	;теперь наши метрики берём с весами
				X		MetricW
				i		1
		@@finExpr:	C		[SP+i]
				FMA		[X+i]
				iLOOP		@@finExpr
	;ага, сделали
	;продемонстрируем результат
				JO		@@endLoop
		@@shl1:		ADD		Acc
				j++		0
				JNO		@@shl1		
	;ага, сделали
		@@endLoop:	[SP+1]		Acc			;финт ушами: заносим значение 32767, ибо нефиг! (другими способами его сложно раздобыть)			
				DIV2		UAC
				SUB		[SP+1]          ;вычитает 32767, что экв. прибавлению 32769
				DIV2S		1		;в итоге, вычитает 1/2
	;ведь мы можем использовать знач. 0..127 в поле Dest как непоср. адрес в памяти, чего добру пропадать!
				X		Exp
				[X+i]		j		;а пока так...
				[SP]		UAC     
	FindScale	endp


С прошлого раза он не очень сильно изменился. Исчез адрес [SP+2] - его мы заменили регистром C, даже лучше.
Исчезла команда MAX (оказалась очень сложной для реализации в том же АЛУ, вместе с десятками других, слишком уж выделялась) - её мы заменили на вычитание и условный переход, потеряли всего 2 байта на этом.

Ну и взят один кусочек из финала и тоже "творчески переработан". Вместо хитрючей команды SHLAcc ... (сдвинуть АККУМУЛЯТОР на 1 влево) мы применили примитивнейшую
ADD Acc

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

Это, увы, потребовало сделать инкремент индексного регистра отдельной командой, причём сейчас он сделан в Dest, а не в Src, как раньше. При этом адрес в Src начисто игнорируется, туда мы сунули ноль, а могли бы что угодно ещё, не имеющее "побочных эффектов".

Сдвиг (умножение на 2) у нас осуществляется до тех пор, пока не наступит переполнения, т.е результат окажется в диапазоне от 32768 до 65535. Далее нужно его сдвинуть назад, чтобы потом при нахождении обратной величины проблем не было, и ещё "округлить" правильно. Когда мы делали матричные операции, об округлении заботились заранее, "обнуляя" аккумулятор не до 0, а до 1/2 младшего разряда. Но здесь мы не имели права вносить эту добавку, поскольку во время сдвигов она бы возросла во много раз, начисто исказив результат. Значит, добавить 1/2 младшего разряда надо уже в самом конце.

За сдвиг вправо на единицу и округление у нас отвечает 3 строки:
	DIV2		UAC
	SUB		[SP+1] ;вычитает 32767, что экв. прибавлению 32769
	DIV2S		1

Сначала осуществляем знаковое деление на 2. Увы, оно так устроено, что игнорирует самый старший бит аккумулятора, поэтому вместо числа в диапазоне 32768..65535 получается диапазон -32768..-1. Как будто бы мы вычли 65536. Далее число делится на два - получается результат в диапазоне -16384..0. Чтобы вернуться к правильному беззнаковому результату, нужно ещё прибавить 32768. Но такое число нам взять сложно - непосредственно в SrcAddr его не положишь в виде Imm (Immediate), нужно куда-то в память, а потом один из адресных регистров на эту область памяти наводить, в общем, муторно это.

А вот значение 32767 мы сами только-только положили на стек - "пригодится!". Вот его-то мы и взяли, да вычли. Если игнорировать самый старший бит аккумулятора, это эквивалентно прибавлению 32769. А нам нужно было прибавить 32768, чтобы получить корректный сдвиг вправо, а потом ещё 1/2, чтобы получить правильное округление.

Так что теперь мы вычитаем эту 1/2, для чего воспользуемся командой, которая у нас всё это время была, "сама собой возникла", но не была задокументирована: DIV2S (divide by 2 and subtract) - вычесть из аккумулятора значение, делённое на 2.

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

Сначала мы долго заставляли эмулятор правильно обработать это дело - и заставили в итоге.

Далее, дело за симулятором в квартусе. Как ни странно, fitter "отпустило" - в этот раз всунул самый обычный, автоматически сгенерённый QuatCoreCallTable.v - и всё нормально синтезировалось в 446 ЛЭ, даже я вернул на место отладочный выход MemAddr[7..0].

Вот полный листинг кода, сейчас его набралось 163 слова.
[Spoiler (click to open)]
main proc
00  FD47              SP          StackAdr
01  8AFC              C           [SP]
02  FD83              SP          C
03  F3B0              CALL        AffineAlgorithm
04  A209              k           9           
05  00E8  @@loop:     NULL        [Z+k]  
06  AA7F              kLOOP       @@loop
07  B807  @@endless:  JMP         @@endless
main endp
AffineAlgorithm     proc
    Associate4Points    proc
        FindMDD3    proc
08  DD18                      Y           Points2D
09  F000                      [SP+1]      0   ;максимальная отдалённость, инициализируем нулём
0A  A103                      j           3
0B  A201          @@j_loop:   k           1   ;также от 0 до 3, чтобы все расстояния просуммировать
0C  FC00                      [SP]        0   ;здесь будет храниться текущий максимум
0D  A003          @@k_loop:   i           3   ;от 0 до 1, т.е значения X и Y
0E  80D9          @@i_loop:   Acc         [Y+2i+k]    ;загрузили одно значение
0F  83DA                      SUB         [Y+2j+k]    ;вычитаем второе
10  9C80                      SQRD2       Acc         ;возводим в квадрат
11  82FC                      ADD         [SP]        ;прибавляем к пред. значению
12  FC80                      [SP]        Acc
13  A87B                      iLOOP       @@i_loop        ;теперь то же самое для второй координаты
14  AA79                      kLOOP       @@k_loop
15  83F0                      SUB         [SP+1]  ;можно и "пожертвовать" значением в Acc,
16  B004                      JL          @@skip
17  8AFC                      C           [SP]
18  F083                      [SP+1]      C
19  CDA1                      X           j
1A  A971          @@skip:     jLOOP       @@j_loop
1B  A0CD                      i           X
1C  CD18                      X           Points2D
1D  ED18                      Z           Points2D
1E  F3B3                      CALL        SwapPoints  ;потёрли текущий максимум (лежал в [SP])-и хрен с ним
        FindMDD3    endp
        SortCCW     proc
1F  CD1A                      X           Fx1 ;чтобы индекс от 2 до 0 соотв. точкам (Fx1,Fy1) ... (Fx3, Fy3)
20  ED1C                      Z           Fx2 ;чтобы иметь сдвинутую на 1 адресацию
21  A301                      Inv         1   ;пока что выкинули команды ijk, без них чуть толще, но даже понятнее
22  F3B2                      CALL        ShiftOrigin
23  A101                      j           1
24  A001                      i           1
25  8AEA          @@loop:     C           [Z+2j+k]
26  90C1                      MUL         [X+2i+1]
27  8AE2                      C           [Z+2j+1]
28  93C9                      FMS         [X+2i+k]    ;нахождение "векторного произведения"
29  B002                      JL          @@skip
2A  F3B3                      CALL        SwapPoints
2B  A87A          @@skip:     iLOOP       @@loop
2C  A979                      jLOOP       @@loop
2D  A300                      Inv         0
2E  F3B2                      CALL        ShiftOrigin     
2F  CD1E                      X           Fx3
30  F3B3                      CALL        SwapPoints
        SortCCW     endp
    Associate4Points endp
    Compute4PointAffine proc
31  CD33                      X           AffineMat
32  ED72                      Z           AfTransf
33  A201                      k           1   ;номер строки результата (и строки AffineMat)
34  A102          @@k_loop:   j           2   ;номер столбца результата (и столбца Points2D)
35  A003          @@j_loop:   i           3   ;номер столбца AffineMat и строки Points2D
36  8803                      ZAcc        RoundZero   ;обнулить до 1/2 мл. разр
37  8AC7          @@i_loop:   C           [X+4j+i]
38  92D9                      FMA         [Y+2i+k]
39  A87E                      iLOOP       @@i_loop
3A  EA80                      [Z+2j+k]    Acc
3B  A97A                      jLOOP       @@j_loop
3C  AA78                      kLOOP       @@k_loop
    Compute4PointAffine endp
    FindRoll    proc
3D  DD7A                      Y           QuatY   ;в этом кватернионе построим,используя Y/Z значения как временные
3E  A001                      i           1
3F  A103                      j           3
40  80E4          @@sico:     Acc         [Z+i]
41  A3A0                      Inv         i
42  81EC                      PM          [Z+i^j]
43  D480                      [Y+i]       Acc
44  A87C                      iLOOP       @@sico
45  F3B1                      CALL NormSiCo
46  CD63                      X       OneHalf
47  84D8                      ABS     [Y+k]
48  8C80                      DIV2    Acc
49  82C8                      ADD     [X+k]
4A  A101                      j       1
4B  B102                      JGE     @@skip
4C  A001                      i       1       ;выходит i=S
4D  CD78          @@skip:     X       QuatA
4E  C480                      [X+i]   Acc
4F  8CD0                      DIV2    [Y+1]
50  CC80                      [X+i^j] Acc         ;по сути, Y+(~S)
51  DD78                      Y       QuatA
52  F3B1                      CALL    NormSiCo    ;подготовили первые 2 компонента кватерниона
53  DD7A                      Y           QuatY
54  A001                      i           1   ;номер строки результата, и строки co/si
55  A201          @@i_loop:   k           1   ;номер столбца результата, и столбца AfTransf
56  A101          @@k_loop:   j           1   ;номер столбца co/si и строки AfTransf
57  8803                      ZAcc        RoundZero   ;обнулить до 1/2 мл. разр
58  8ADC          @@j_loop:   C           [Y+i^j] 
59  91EA                      FMPM        [Z+2j+k]
5A  A97E                      jLOOP       @@j_loop
5B  F980                      [SP+2i+k]   Acc
5C  AA7A                      kLOOP       @@k_loop
5D  A878                      iLOOP       @@i_loop
5E  A003                      i           3
5F  8AF4          @@out_loop: C           [SP+i]  ;эх, грустно без полноценных 2 адресов. Может, сделать-таки?
60  E483                      [Z+i]       C       
61  A87E                      iLOOP       @@out_loop                  
62  A201                      k           1
63  D800          @@clean:    [Y+k]       0
64  AA7F                      kLOOP       @@clean
    FindRoll    endp
    FindScale   proc
65  FC00                      [SP]        0   ;манхэттенская метрика, сумма модулей (метрика городских кварталов)
66  F000                      [SP+1]      0   ;чебышевская, максимум от модулей 
67  A103                      j           3                   
68  A001                      i           1
69  80EC          @@loop:     Acc         [Z+i^j] ;+Tyx (i=1), -Tyy (i=0)
6A  81E4                      PM          [Z+i]   ;Txy (i=1), Txx (i=0)   ;поменяли местами чтобы проверить модуль
6B  8480                      ABS         Acc     ;|Txy+Tyx| (i=1), |Txx-Tyy| (i=0)
6C  8A80                      C           Acc     ;сохранили это значение
6D  82FC                      ADD         [SP]    
6E  FC80                      [SP]        Acc ;обновили манхэттенскую
6F  80F0                      Acc         [SP+1]
70  8383                      SUB         C
71  B102                      JGE         @@skipCheb ;лучше подошел бы JGE и поменять местами [SP+2] и [SP+1]. Разница при нуле-на 1 больше операций.
72  F083                      [SP+1]      C   ;обновили Чебышевскую   
73  A301          @@skipCheb: Inv         1       ;так что на следующей итерации будет "-"
74  A875                      iLOOP       @@loop
75  80E4                      Acc         [Z+i]   ;добавили Txx
76  82EC                      ADD         [Z+i^j] ;и Tyy
77  CD31                      X           MetricW
78  A001                      i           1
79  8AF4          @@finExpr:  C           [SP+i]
7A  92C4                      FMA         [X+i]
7B  A87E                      iLOOP       @@finExpr
7C  B204                      JO          @@endLoop
7D  8280          @@shl1:     ADD         Acc
7E  A500                      j++         0
7F  B37E                      JNO         @@shl1      
80  F080          @@endLoop:  [SP+1]      Acc         ;финт ушами: заносим значение 32767, ибо нефиг! (другими способами его сложно раздобыть)
81  8C82                      DIV2        UAC
82  83F0                      SUB         [SP+1] ;прибавляет 32767. А если вычесть 32767, выйдет по сути прибавление 32769. А нам бы хотелось прибавить 32768,5. 
83  8F01                      DIV2S       1       ;в итоге, вычитает 1/2
84  CD6B                      X           Exp
85  C4A1                      [X+i]       j       ;а пока так...
86  F082                      [SP+1]      UAC
    FindScale   endp
    FindVector  proc
    FindVector  endp
87  B8FF              JMP         [--SP]
AffineAlgorithm     endp
SwapPoints  proc
88  A201              k           1
89  80EA  @@swap:     Acc         [Z+2j+k]
8A  8AC9              C           [X+2i+k]
8B  EA83              [Z+2j+k]    C
8C  C980              [X+2i+k]    Acc
8D  AA7C              kLOOP       @@swap
8E  B8FF              JMP         [--SP]
SwapPoints  endp    
ShiftOrigin proc
8F  A201                  k           1
90  A002  @@k_loop:       i           2   ;как всегда, чтобы Y и X
91  80C9  @@i_loop:       Acc         [X+2i+k]
92  81D8                  PM          [Y+k]
93  C980                  [X+2i+k]    Acc
94  A87D                  iLOOP       @@i_loop
95  AA7B                  kLOOP       @@k_loop
96  B8FF                  JMP         [--SP]
ShiftOrigin endp
NormSiCo    proc
97  A10C                  j           12 ;если "передавать" i как аргумент, то можно регулировать число итераций
98  A001  @@norm:         i           1       ;две компоненты
99  8802                  ZAcc        ThreeHalf       ;выставить 3/2
9A  9FD4  @@innorm:       SQRSD2      [Y+i]   ;вычесть половину от квадрата 
9B  A87F                  iLOOP       @@innorm
9C  8A82                  C           UAC
9D  A001                  i           1
9E  94D4  @@inmult:       MULSU       [Y+i]   ;уможение знакового B на беззнак. C
9F  D480                  [Y+i]       Acc     ;вернули на место!
A0  A87E                  iLOOP       @@inmult                
A1  A977                  jLOOP       @@norm
A2  B8FF                  JMP         [--SP]
NormSiCo    endp



С предыдущей системой команд получалось 145 слов, т.е лишних 18 слов добавилось из-за "аппаратных ограничений", о которых мы раньше не думали.
2 слова потеряли на инициализации стека (мало того, что запихнули его в неудобное место, так ещё команда SP [SP] стала некорректной),
6 - добавленный в main цикл, чтобы посмотреть, что же мы насчитали.
1 слова лишились в SwapPoints из-за пересылок память-память (теперь через регистр),
1 в FindMDD3 по той же причине (либо из-за отсутствия CMP).
1 слово мы потеряли в SortCCW из-за отсутствия команды ijk, которая позволила бы инициализировать два регистра разом.
2 слова у нас добавилось в SortCCW, чтобы поменять местами МБД и МДД2, для алгоритма сопровождения.
3 слова мы потеряли из-за отсутствия укуренной команды ABSP1D2, в процедуре FindRoll
3 слова мы потеряли из-за отсутствия укуренных команд [Y+S] и [Y+~S]
1 слово - опять из-за пересылок память-память.
1 слово теряем из-за отсутствия команды SHLAcc и инкремента на стороне SrcAddr,
1 слово теряем из-за отсутствия команды UDIV2 или UDIV2S,
1 слово добавляем для корректного округления масштаба - раньше мы этого не сделали, а вообще-то зря.

Итого, 23 слова. Но за счёт более ортогональной адресации (X,Y,Z и SP практически равноправны) удалось 5 слов сэкономить :)
В принципе, если припрёт (будет самую малость не укладываться в отведённые блоки памяти, например, займёт 540 слов, а хотелось бы 512), мы будем знать, где можно это дело выцарапать.

Ну ладно, посмотрим - а работает ли оно вообще?


Всё-таки приятно, когда адрес, по которому идёт обращение в ОЗУ, тоже указан. Я уже запомнил, что SP=0x60, значит SP+1=0x61. Мы видим, как оба этих значения на стеке устанавливаются в ноль - одно будет выражать Манхэттенскую метрику, второе - Чебышевскую.

В j заносится в тройку, т.к это адресацией [Z+i] и [Z+i^j] получить элемент верхней строчки матрицы и второй, который расположен ПО ДИАГОНАЛИ от него.

Напомним, на прошлых этапах мы получили матрицу, ПОЧТИ избавленную от крена:


Далее, начинается цикл по i от 1 до нуля. В первой итерации берём элементы вне главной диагонали, единичку и нолик. Складываем их, берём модуль, прибавляем его к Манхэттенской метрике (лежит в [SP]), потом проверяем, нужно ли обновить Чебышевскую метрику (лежит в [SP+1]). Для этого загружаем текущее значение этой метрики (ноль)...


Вычитаем текущий результат (единичку), получаем отрицательное значение. JGE (прыжок, если "больше или равно") не срабатывает, поэтому заносим текущий результат в Чебышевскую метрику, теперь там единица. Выставляем Inv=1, чтобы следующие числа вычитались друг из друга.

Начинаем новую итерацию, в этот раз берём элементы на главной диагонали, причём вычитаем их друг из друга. Получается -2, берём модуль - выходит просто 2, заносим в регистр C (чтобы не пропало), прибавляем старое значение Манхэттенской метрики (единичку), получается 3 - заносим на своё место, в [SP]. Загружаем старое значение Чебышевской метрики. Следующий слайд, пожалуйста!


Сравнив текущее значение (2) со старым значением Чебышевской метрики, решили её обновить - занести значение 2. Успешно выходим из цикла.

Теперь СУММИРУЕМ элементы по главной диагонали, а затем прибавляем к ним Чебышевскую метрику, помноженную на 21758/32768 - это коэффициент, близкий к оптимальному, чтобы из Чебышевской и Манхэттенской метрики получить приближение к Эвклидовой.



Вышли на следующую итерацию, в этот раз прибавляем Манхэттенскую метрику, помноженную на 11010/32768. Действительно, 11010+21758=32768. Впрочем, не проверял, обязательно ли это условие для получения наилучшего приближения, но кажется, что да. Мы срезали "осциллограмму" справа, поскольку там до самого упора продолжается FMA. Поехали дальше.



Вот мы увидели значение масштаба: 874. И начинаем его удваивать, пока не наступит переполнения. Как подсказывает эмулятор, полное значение, хранящееся в аккумуляторе: 874,3359985. И если наш байпас работает, мы должны будем "увидеть" младшие разряды по мере удвоения.

Видим, как работает команда j++, и что прыгать по переполнению мы пока не торопимся, и выходить из цикла - тоже. Тем временем, 874 превращается в 1748 (всё верно), затем в 3496 (что-то маловато), затем в 6993 (по крайней мере, видно, что какая-то добавка есть), затем 13986 (должно было быть 13989 уже), и наконец 27972 (должно было быть 27978). Что-то не то...

ТУПИТ НАШ ХВАЛЁНЫЙ БАЙПАС! Ошибка крылась в модуле QuatCoreALUBreg:
//mode = 00 - shift right
//mode = 01 - shift right and negate
//mode = 10 - load 16 bit (no bypass)
//mode = 11 - load AccWidth bit (bypass enabled)

module QuatCoreALUBreg (input clk, input[AccWidth-18:0] Dsmall, input [15:0] D, input DoSigned, input [1:0] mode,
			output [AccWidth-1:0] Q);

parameter AccWidth = 32;
localparam SmallPartWidth = AccWidth - 16;

reg seniorBit = 1'b0;
reg [14:0] largeQ = 1'b0;
reg [SmallPartWidth-1:0] smallQ = 1'b0;

assign Q = {seniorBit, largeQ, smallQ};

always @(posedge clk) begin
	seniorBit 	<= mode[1]? D[15] : DoSigned? (seniorBit^mode[0]) : 1'b0;
	largeQ 		<= mode[1]? D[14:0] : mode[0]? {~seniorBit, ~largeQ[14:1]} : {seniorBit, largeQ[14:1]};
	smallQ		<= mode[1]? (mode[0]? Dsmall : {SmallPartWidth{1'b0}}) : mode[0]? {~largeQ[0], ~smallQ[SmallPartWidth-1:1]} : {largeQ[0], smallQ[SmallPartWidth-1:1]};
end

endmodule


Всё-таки я не до конца понимаю логику верилога: стоит где-нибудь написать
  State <= 3;

Он поднимет бучу - вы в 3-битный регистр пытаетесь запихнуть 32-битное значение, и нам приходится отсечь все старшие биты, какой ужас!

А здесь я присвоил 16-битному регистру значение с 15-битной шины - и никаких предупреждений, всё хорошо. Строку smallQ надо было подправить:

	smallQ		<= mode[1]? (mode[0]? {Dsmall, 1'b0} : {SmallPartWidth{1'b0}}) : mode[0]? {~largeQ[0], ~smallQ[SmallPartWidth-1:1]} : {largeQ[0], smallQ[SmallPartWidth-1:1]};


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

Проверим исправленный модуль.


Видим последовательность: 874 - 1748 - 3497 - 6994 - 13989, что полностью совпадает с полученным на эмуляторе, и также совпадает с умножением 874,3359985 последовательно на 2, и со взятием целой части. Так что наконец-то оно зафурычило.

Глянем, что происходит дальше.


Следующее число: 27978 - всё верно.
И на следующем числе наступает переполнение, мы выходим из цикла. При этом j=9. Нам нужно было измерять дальность от 0,5 метра до 300 метров, поэтому мы постановили j=0 - это дальность 0,5..1 метр, j=1 - от 1 до 2 метров, и так далее. Иными словами, дальность от 2j-1 до 2j. По такому принципу, j=9 - дальность от 256 до 512 метров. Наша дальность в 300 метров попадает как раз сюда - отлично.

На стек, в [SP+1] отправляется число 32767, как мы и хотели (у нас тут ЗАВЕДОМО переполнение, раз перешли, и оно заведомо положительное, так что ничего другого мы получить не можем).

Далее производим деление на 2. Как видно, на шине данных возникло число -9579, что как раз соответствует 55957 - 65536. Затем вычитаем 32767, и ещё вычитаем 1/2. Затем в переменную "Exp" заносим экспоненту 9, и наконец, на [SP] помещаем результирующую мантиссу, число 27979.

И это правильный ответ, поскольку
874,3359985*25 = 27978,751952
т.е округление у нас правильное. Понятно, чтобы убедиться окончательно, надо будет расммотреть ещё несколько примеров, где будет округление и в другую сторону. Но уже выглядит многообещающе.

Собственно, на этом алгоритм и заканчивается.


Осталось совсем немного - найти обратную величину методом Ньютона и посчитать вектор параллельного переноса. Ну и алгоритм сопровождения целиком, разумеется. И модуль видеообработки на 1,2 ГБит/с.
Tags: ПЛИС, математика, программки, работа, странные девайсы
Subscribe

Recent Posts from This Journal

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

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

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

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

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

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

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 5 comments