QuatCore начинает фурычить!

Jan 06, 2020 04:33

Пока что на симуляторе в Quartus'e, но если он там заработал - то высоки шансы, что и на кристалле заработает. Это всё-таки нормальный Timing analysis.

Reset и первые 4 команды - пока всё хорошо :)




Пару слов о программе, которую этот драндулет исполняет. Это первый кусочек аффинного алгоритма, подправленный под наш нынешний набор команд. Сначала приведём сегмент кода:

.code
main proc
SP StackAdr
C [SP]
SP C

CALL AffineAlgorithm

@@endless: JMP @@endless
main endp

AffineAlgorithm proc

Associate4Points proc

;состояние регистров неизвестно (за искл. PC и SP)
FindMDD3 proc
;перво-наперво, находим МДД3
;как точка, сумма квадратов расстояний до которой максимальна (т.е самая отдалённая)
;для каждой точки считаем сумму квадр. расстояний до всех остальных, в т.ч до самой себя (это 0, зато код упрощается)
;внешний цикл (по строкам) - перем. j
;внутр. цикл (по столбцам) - перем. i
;самый-самый внутр. цикл - по индексу перем (X или Y) - перем k
X Points2D
[SP+1] 0 ;максимальная отдалённость, инициализируем нулём
j 3
@@j_loop: i 3 ;также от 0 до 3, чтобы все расстояния просуммировать
[SP] 0 ;здесь будет храниться текущий максимум
@@i_loop: k 1 ;от 0 до 1, т.е значения X и Y
@@k_loop: Acc [X+2i+k] ;загрузили одно значение
SUB [X+2j+k] ;вычитаем второе
SQRD2 Acc ;возводим в квадрат
ADD [SP] ;прибавляем к пред. значению
[SP] Acc
kLOOP @@k_loop ;теперь то же самое для второй координаты
iLOOP @@i_loop
SUB [SP+1]
JL @@skip
C [SP]
[SP+1] C
Y j
@@skip: jLOOP @@j_loop
i Y
k 1
@@swap: C [X+k]
Acc [X+2i+k]
[X+k] Acc
[X+2i+k] C
kLOOP @@swap

;на этом первая часть марлезонского балета закончена.
FindMDD3 endp

SortCCW proc
SortCCW endp

Associate4Points endp

Compute4PointAffine proc
Compute4PointAffine endp

FindRoll proc
FindRoll endp

FindScale proc
FindScale endp

FindVector proc
FindVector endp

JMP [--SP]
AffineAlgorithm endp

Мы начинаем с мучительной инициализации стека. Предположительно, стек мы засунем по такому адресу, к которому не будет "прямого доступа" (это первые 64 и последние 64 слова данных), т.к он и нужен всего один раз, при инициализации. Из-за текущего запрета на операции "из памяти в память", которые распространяются даже на занесение в регистры X/Y/Z/SP значения из памяти (или наоборот), приходится воспользоваться ещё и регистром C из АЛУ. Возможно, в дальнейшем можно будет чуть улучшить модуль QuatCoreMem, но пока попробуем обойтись.

Под спойлером - объявление сегмента данных. Не стал его укорачивать, пущай уж будет "боевым".

[Spoiler (click to open)]

;Бортовая программа ВИПС для QuatCore
;версия от 2.01.2020
;необходимо подрихтовать весь код в соответствии
;с изменившимися командами QuatCore
;и запретом на пересылки "память-память"
;также изменения коснутся представления данных в памяти,
;т.к мы наконец-то созрели до треугольной адресации!

.data

;значения для ZAcc
;возможно, мы решим их переставить местами,
;или раскидать по доступным 128 значениям,
;если это упростит реализацию
ThreeHalf EQU 0
MinusThreeHalf EQU 1
RoundZero EQU 2
Two EQU 3

ORG 0

;целочисленные координаты на фотопр. матрице
;либо сюда заносится во время захвата,
;либо мы сами задаём на стадии сопровождения
RoughPoints:
RoughX0 Int16 0
RoughY0 Int16 0
RoughX1 Int16 0
RoughY1 Int16 0
RoughX2 Int16 0
RoughY2 Int16 0
RoughX3 Int16 0
RoughY3 Int16 0 ;первые 4

RoughX4 Int16 0
RoughY4 Int16 0
RoughX5 Int16 0
RoughY5 Int16 0
RoughX6 Int16 0
RoughY6 Int16 0
RoughX7 Int16 0
RoughY7 Int16 0 ;следующие 4, для них всех Radius0

RoughX8 Int16 0
RoughY8 Int16 0
RoughX9 Int16 0
RoughY9 Int16 0
RoughX10 Int16 0
RoughY10 Int16 0 ;последние 3, для них задаётся Radius1
Radius0 Int16 0 ;сюда наш алгоритм помещает для видеопроцессора: какой должен быть радиус "основных" точек (первых 8) и какой радиус последних 3.
Radius1 Int16 0

;сумма X * Pixel[X,Y], Y * Pixel[X,Y], для нахождения ярк. центра
;их выдаёт "видеопроцессор"
;но сейчас имеем дело с уже обработанными - готовыми коорд. ярк центра,
;нули в середине матрицы, 64 отсчёта на пиксель
Points2d:
;дистанция 300 метров, все углы нулевые
Fx0 Int16 53 ;адр 33
Fy0 Int16 -7

Fx1 Int16 480 ;адр 35
Fy1 Int16 -30

Fx2 Int16 -539 ;адр 37
Fy2 Int16 -302

Fx3 Int16 400 ;адр 39
Fy3 Int16 -997

; Fx0 Int16 49
; Fy0 Int16 -5
; Fx1 Int16 479
; Fy1 Int16 -31
; Fx2 Int16 -543
; Fy2 Int16 -304
; Fx3 Int16 398
; Fy3 Int16 -1000

;дистанция 30 метров, поворот 90 градусов
; Fx0 Int16 2996
; Fy0 Int16 4794
; Fx1 Int16 12794
; Fy1 Int16 3974
; Fx2 Int16 2771
; Fy2 Int16 448
; Fx3 Int16 5756
; Fy3 Int16 -5508

;300 метров, ракурс самый мерзопакостный
; Fx0 Int16 425
; Fy0 Int16 22
; Fx1 Int16 85
; Fy1 Int16 -39
; Fx2 Int16 -541
; Fy2 Int16 -301
; Fx3 Int16 285
; Fy3 Int16 -885

Fx4 Int16 -32768 ;адр 38
Fy4 Int16 ?

Fx5 Int16 -32768 ;адр 40
Fy5 Int16 ?

Fx6 Int16 -32768 ;адр 42
Fy6 Int16 ?

Fx7 Int16 -32768 ;адр 44
Fy7 Int16 ?

;Сумма яркостей пикселей для каждого пятна
W0 dw ?
W1 dw ?
W2 dw ?
W3 dw ?
W4 dw ?
W5 dw ?
W6 dw ?
W7 dw ?

;адр 30h
.rodata
;константы, которые держатся весь сеанс (если только по МКО не поступил массив полётного задания, который их переопределяет!)

PixToRad dw 27710 ;из пикселей (32768=+512 пикс) в рад (32768=1/4 рад) адр. 30h
MetricW:
ManhW dw 11010 ;вес, с которым взять Манхэттенскую метрику ;
ChebW dw 21758 ;вес Чебышевской метрики ;
;с такими весами получаем недурственное приближение к Эвклидовой метрике

;заранее посчитанная матрица для нахождения коэф. аффинного преобразования
;МДД3-МДД1-МБД-МДД2
AffineMat:
AfMat00 Int16 4090 ;адр 33h
AfMat01 Int16 10092
AfMat02 Int16 -14492
AfMat03 Int16 310

AfMat10 Int16 -13992 ;адр 37h
AfMat11 Int16 8627
AfMat12 Int16 -2011
AfMat13 Int16 7376

AfMat20 Int16 1199 ;адр 3Bh
AfMat21 Int16 -5752
AfMat22 Int16 -3495
AfMat23 Int16 -5807 ;адр 3Eh
;решили все-все знаки здесь обратить, чтобы не связываться с X<0, который меня уже порядком достал!
;для этого и коэф. нижней строки аф. матрицы обратили, ибо нефиг.

.data
;32 отсчёта дальности, чтобы посчитать скорость сближения сколько-нибудь точно
DistA[0] dw 0 ;адр. 3Fh
DistA[1] dw 0
DistA[2] dw 0
DistA[3] dw 0
DistA[4] dw 0
DistA[5] dw 0
DistA[6] dw 0
DistA[7] dw 0
DistA[8] dw 0
DistA[9] dw 0
DistA[10] dw 0
DistA[11] dw 0
DistA[12] dw 0
DistA[13] dw 0
DistA[14] dw 0
DistA[15] dw 0
DistA[16] dw 0
DistA[17] dw 0
DistA[18] dw 0
DistA[19] dw 0
DistA[20] dw 0
DistA[21] dw 0
DistA[22] dw 0
DistA[23] dw 0
DistA[24] dw 0
DistA[25] dw 0
DistA[26] dw 0
DistA[27] dw 0
DistA[28] dw 0
DistA[29] dw 0
DistA[30] dw 0
DistA[31] dw 0 ;адр 5Eh

;стек, решили, наконец-то, что он растёт вверх!
;зарезервируем память для него, адр. 5Fh
Stack dw ? ;1 ячейка для адреса возврата в main
st[1] dw ? ;1 ячейка для адреса возврата из RotateVecByQuat ;адр 5Fh
st[2] dw ? ;для хранения X внутри RotateVecByQuat
st[3] dw ? ;1 ячейка для адреса возврата из QuatMultiply
st[4] dw ? ;для хранения ijk внутри QuatMultiply
st[5] dw ? ;промежут. значение кват (0)
st[6] dw ? ;(1)
st[7] dw ? ;(2)
st[8] dw ? ;(3) ;адр 67

.rodata
ORG 163 ;A3h

;координаты отдельных отражателей мишени ближней дистанции, в увеличенном масштабе
;единица измерения - метры,
;диапазон представимых значений - от -0,125 до примерно +0,125 метров
;пользуемся тем фактом, что ракурс не более чем на 30 градусов, поэтому
;"есть где развернуться"

MBD1x Int16 -24904 ;A3h
MBD1y Int16 22282 ;A4h
MBD1z Int16 0 ;здесь же MBD2a ;A5h

MBD2x Int16 -24904 ;A6h
MBD2y Int16 -22282 ;A7h
MBD2z Int16 0 ;здесь же MBD3a ;A8h

MBD3x Int16 0 ;A9h
MBD3y Int16 28836 ;AAh
MBD3z Int16 -11796 ;здесь же MBD4a ;ABh

MBD4x Int16 0 ;ACh
MBD4y Int16 28836 ;ADh
MBD4z Int16 13107 ;здесь же MBD5a ;AEh

MBD5x Int16 0 ;AFh
MBD5y Int16 8651 ;B0h
MBD5z Int16 0 ;здесь же MBD6a ;B1h

MBD6x Int16 0 ;B2h
MBD6y Int16 -9699 ;B3h
MBD6z Int16 0 ;здесь же MBD7a ;B4h

MBD7x Int16 0 ;B5h
MBD7y Int16 -28836 ;B6h
MBD7z Int16 -13107 ;здесь же MBD8a ;B7h

MBD8x Int16 0 ;B8h
MBD8y Int16 -28836 ;B9h
MBD8z Int16 13107 ;BAh

;координаты мишеней дальней дистанции (т.е когда смотрим издалека, и отдельные точки сливаются в одну)
;единица измерения - метры,
;диапазон представимых значений: от -4 до примерно +4 метров
;(хватило бы и -2..+2, но развернуться немножко негде, в прямом смысле)
MDD3x Int16 0 ;BBh
MDD3y Int16 -5554 ;BCh
MDD3z Int16 15794 ;здесь же MDD1a ;BDh

MDD1x Int16 0 ;BEh
MDD1y Int16 -6832 ;BFh
ShortRangeRefPoints: ;и здесь же MDD2a.
MDD1z Int16 410 ;здесь же MBDa ;C0h - первый адресуемый по Imm, он же -64

MDD2x Int16 0 ;C1h
MDD2y Int16 9339 ;C2h
LongRangeRefPoints: ;и здесь же MBDa
MDD2z Int16 4743 ;C3h

MBDx Int16 -2376 ;адр C4h
MBDy Int16 0 ;адр C5h
MBDz Int16 0 ;здесь же MDD2a адр. C6h
StackAdr dw Stack ;адрес стека (он недоступен напрямую!) C7h

.data
;выходные данные
;"в максимальной комплектации" - ковариационная матрица шума измерений Matrix (комп. a11, a12, a22, и т.д., 21 элем.),
;кватернион взаимной ориентации Quat (QuatA, QuatX, QuatY, QuatZ, 4 слова),
;вектор параллельного переноса (TxOut, Ty, Tz, 3 слова),
;значение скорости (Vel, 1 слово)
;сюда же вклинивается вектор K 1х6 (для алгоритма сопровождения),
;и остаются вакантные места на 6 слов и 5 слов.
;плюс дофига "флагов", которые пока что занимают по 16 бит каждый, но можно будет их и покомпактнее
Matrix:
a11 Int16 ? ;адр. C8h

a12 Int16 ?
a22 Int16 ?

a13 Int16 ? ;адр D8h
a23 Int16 ?
a33 Int16 ?

a14 Int16 ? ;адр E0h
a24 Int16 ?
a34 Int16 ?
a44 Int16 ?

a15 Int16 ? ;адр E8h
a25 Int16 ?
a35 Int16 ?
a45 Int16 ?
a55 Int16 ?

a16 Int16 ? ;адр F0h
a26 Int16 ?
a36 Int16 ?
a46 Int16 ?
a56 Int16 ?
a66 Int16 ? ;всё, этого нам хватит! F5h

state dw 1 ;0-поиск (подбор экспозиции, грубое определение дистанции), 1-захват, 2-сопровождение
HasData dw 0 ;0-мы не выдаём данных, 1-выдаём по крайней мере дистанцию и углы с требуемой точностью
QValid dw 0 ;0-только данные дистанции и 2 углов (кватернион выдаётся, но точность не обеспечивается). 1-точность кватерниона обеспечена
VValid dw 0 ;0-показания скорости не обеспечивают точности. 1-точность, указанная в ТЗ, обеспечена
Vel Int16 ? ;скорость сближения (положительная-отдаляемся, отрицательная-сближаемся, т.е производная от дальности)
ErrCode dw 0 ;0: всё хорошо, 1: точка, которая ожидалась на экране, при проецировании вышла за пределы (скорее всего, зацепились за блик)
OneHalf dw 16384 ;для нахождения кватерниона крена.

K1 Int16 0 ;вектор правой части при решении системы линейных уравнений
K2 Int16 0
K3 Int16 0
K4 Int16 0
K5 Int16 0
K6 Int16 0

TxOut dw ? ;Tx вместе с экспонентой
Exp dw ? ;отдельно экспонента
Tx dw ? ;Tx отдельно
Ty Int16 ? ;другие значения
Tz Int16 ?

QuatA Int16 ? ;кватернион взаимной ориентации
QuatX Int16 ?
QuatY Int16 ?
QuatZ Int16 ?

TargetPTR dw LongRangeRefPoints ;когда в дальней зоне, на 3 меньше когда в ближней
TargetCnt dw 3 ;кол-во мишеней, минус 1: 3 в дальней зоне, 10 в ближней
pad85 dw ?

;временные переменные. Не знаю, может и в стек их можно было,
;но мы там вызываем другие проц., нужно сдвигать SP,лениво честно говоря :)
AfTransf:
Tx':
Txx Int16 ? ;F6h
Ty':
Tyx Int16 ? ;F7h
Tz':
Txy Int16 ? ;F8h
B0:
Tyy Int16 ? ;F9h
Bx:
Rx Int16 ? ;FAh
By:
Ry Int16 ? ;FBh
Bz Int16 ?
;коэф. афинного преобр. на этапе захвата
;временная, сдвинутая копия вектора T, если Exp=0..3, на ComputeRoughPoints.
;весь этот бред-чтобы ткнуть носом видеопроцессор "здесь мы ожидаем точку, она нам нахрен не нужна,
;но не пугайся пожалуйста!"

Local0 Int16 ? ;место для локальной переменной (после вычистки системы команд, мы остались без [SP+2], нужно что-то взамен)
Local1 Int16 ? ;для второй!



Также есть листинг, как оно будет распределено по адресам (результат работы транслятора):

[Spoiler (click to open)]

RoughX0: 00 0
RoughY0: 01 0
RoughX1: 02 0
RoughY1: 03 0
RoughX2: 04 0
RoughY2: 05 0
RoughX3: 06 0
RoughY3: 07 0
RoughX4: 08 0
RoughY4: 09 0
RoughX5: 0A 0
RoughY5: 0B 0
RoughX6: 0C 0
RoughY6: 0D 0
RoughX7: 0E 0
RoughY7: 0F 0
RoughX8: 10 0
RoughY8: 11 0
RoughX9: 12 0
RoughY9: 13 0
RoughX10: 14 0
RoughY10: 15 0
Radius0: 16 0
Radius1: 17 0
Fx0: 18 53
Fy0: 19 65529
Fx1: 1A 480
Fy1: 1B 65506
Fx2: 1C 64997
Fy2: 1D 65234
Fx3: 1E 400
Fy3: 1F 64539
Fx4: 20 32768
Fy4: 21 ????
Fx5: 22 32768
Fy5: 23 ????
Fx6: 24 32768
Fy6: 25 ????
Fx7: 26 32768
Fy7: 27 ????
W0: 28 ????
W1: 29 ????
W2: 2A ????
W3: 2B ????
W4: 2C ????
W5: 2D ????
W6: 2E ????
W7: 2F ????
PixToRad: 30 27710
ManhW: 31 11010
ChebW: 32 21758
AfMat00: 33 4090
AfMat01: 34 10092
AfMat02: 35 51044
AfMat03: 36 310
AfMat10: 37 51544
AfMat11: 38 8627
AfMat12: 39 63525
AfMat13: 3A 7376
AfMat20: 3B 1199
AfMat21: 3C 59784
AfMat22: 3D 62041
AfMat23: 3E 59729
DistA[0]: 3F 0
DistA[1]: 40 0
DistA[2]: 41 0
DistA[3]: 42 0
DistA[4]: 43 0
DistA[5]: 44 0
DistA[6]: 45 0
DistA[7]: 46 0
DistA[8]: 47 0
DistA[9]: 48 0
DistA[10]: 49 0
DistA[11]: 4A 0
DistA[12]: 4B 0
DistA[13]: 4C 0
DistA[14]: 4D 0
DistA[15]: 4E 0
DistA[16]: 4F 0
DistA[17]: 50 0
DistA[18]: 51 0
DistA[19]: 52 0
DistA[20]: 53 0
DistA[21]: 54 0
DistA[22]: 55 0
DistA[23]: 56 0
DistA[24]: 57 0
DistA[25]: 58 0
DistA[26]: 59 0
DistA[27]: 5A 0
DistA[28]: 5B 0
DistA[29]: 5C 0
DistA[30]: 5D 0
DistA[31]: 5E 0
Stack: 5F ????
st[1]: 60 ????
st[2]: 61 ????
st[3]: 62 ????
st[4]: 63 ????
st[5]: 64 ????
st[6]: 65 ????
st[7]: 66 ????
st[8]: 67 ????
68 ????
69 ????
6A ????
6B ????
6C ????
6D ????
6E ????
6F ????
70 ????
71 ????
72 ????
73 ????
74 ????
75 ????
76 ????
77 ????
78 ????
79 ????
7A ????
7B ????
7C ????
7D ????
7E ????
7F ????
80 ????
81 ????
82 ????
83 ????
84 ????
85 ????
86 ????
87 ????
88 ????
89 ????
8A ????
8B ????
8C ????
8D ????
8E ????
8F ????
90 ????
91 ????
92 ????
93 ????
94 ????
95 ????
96 ????
97 ????
98 ????
99 ????
9A ????
9B ????
9C ????
9D ????
9E ????
9F ????
A0 ????
A1 ????
A2 ????
MBD1x: A3 40632
MBD1y: A4 22282
MBD1z: A5 0
MBD2x: A6 40632
MBD2y: A7 43254
MBD2z: A8 0
MBD3x: A9 0
MBD3y: AA 28836
MBD3z: AB 53740
MBD4x: AC 0
MBD4y: AD 28836
MBD4z: AE 13107
MBD5x: AF 0
MBD5y: B0 8651
MBD5z: B1 0
MBD6x: B2 0
MBD6y: B3 55837
MBD6z: B4 0
MBD7x: B5 0
MBD7y: B6 36700
MBD7z: B7 52429
MBD8x: B8 0
MBD8y: B9 36700
MBD8z: BA 13107
MDD3x: BB 0
MDD3y: BC 59982
MDD3z: BD 15794
MDD1x: BE 0
MDD1y: BF 58704
MDD1z: C0 410
MDD2x: C1 0
MDD2y: C2 9339
MDD2z: C3 4743
MBDx: C4 63160
MBDy: C5 0
MBDz: C6 0
StackAdr: C7 95
a11: C8 ????
a12: C9 ????
a22: CA ????
a13: CB ????
a23: CC ????
a33: CD ????
a14: CE ????
a24: CF ????
a34: D0 ????
a44: D1 ????
a15: D2 ????
a25: D3 ????
a35: D4 ????
a45: D5 ????
a55: D6 ????
a16: D7 ????
a26: D8 ????
a36: D9 ????
a46: DA ????
a56: DB ????
a66: DC ????
state: DD 1
HasData: DE 0
QValid: DF 0
VValid: E0 0
Vel: E1 ????
ErrCode: E2 0
OneHalf: E3 16384
K1: E4 0
K2: E5 0
K3: E6 0
K4: E7 0
K5: E8 0
K6: E9 0
TxOut: EA ????
Exp: EB ????
Tx: EC ????
Ty: ED ????
Tz: EE ????
QuatA: EF ????
QuatX: F0 ????
QuatY: F1 ????
QuatZ: F2 ????
TargetPTR: F3 195
TargetCnt: F4 3
pad85: F5 ????
Txx: F6 ????
Tyx: F7 ????
Txy: F8 ????
Tyy: F9 ????
Rx: FA ????
Ry: FB ????
Bz: FC ????
Local0: FD ????
Local1: FE ????
FF ????



Также у нас есть листинг инструкций:
[Spoiler (click to open)]

main proc
00 FD47 SP StackAdr
01 8AFC C [SP]
02 FD83 SP C
03 F3B0 CALL AffineAlgorithm
04 B804 @@endless: JMP @@endless
main endp
AffineAlgorithm proc
Associate4Points proc
FindMDD3 proc
05 CD18 X Points2D
06 F000 [SP+1] 0 ;максимальная отдалённость, инициализируем нулём
07 A103 j 3
08 A003 @@j_loop: i 3 ;также от 0 до 3, чтобы все расстояния просуммировать
09 FC00 [SP] 0 ;здесь будет храниться текущий максимум
0A A201 @@i_loop: k 1 ;от 0 до 1, т.е значения X и Y
0B 80C9 @@k_loop: Acc [X+2i+k] ;загрузили одно значение
0C 83CA SUB [X+2j+k] ;вычитаем второе
0D 9C80 SQRD2 Acc ;возводим в квадрат
0E 82FC ADD [SP] ;прибавляем к пред. значению
0F FC80 [SP] Acc
10 AA7B kLOOP @@k_loop ;теперь то же самое для второй координаты
11 A879 iLOOP @@i_loop
12 83F0 SUB [SP+1] ;можно и "пожертвовать" значением в Acc,
13 B004 JL @@skip
14 8AFC C [SP]
15 F083 [SP+1] C
16 DDA1 Y j
17 A971 @@skip: jLOOP @@j_loop
18 A0DD i Y
19 A201 k 1
1A 8AC8 @@swap: C [X+k]
1B 80C9 Acc [X+2i+k]
1C C880 [X+k] Acc
1D C983 [X+2i+k] C
1E AA7C kLOOP @@swap ;а теперь и обе
FindMDD3 endp
SortCCW proc
SortCCW endp
Associate4Points endp
Compute4PointAffine proc
Compute4PointAffine endp
FindRoll proc
FindRoll endp
FindScale proc
FindScale endp
FindVector proc
FindVector endp
1F B8FF JMP [--SP]
AffineAlgorithm endp



Теперь можно отследить, шаг за шагом, что же там происходит.

Первая команда, SP StackAdr (FD 47)
Мы загружаем в указатель стека адрес константы StackAdr. Если глянуть листинг данных, она лежит по адресу C7. Мы же указали в поле SrcAddr число 47. Если мы посмотрим на скриншот, то после сброса (когда сигнал Reset стал низкого уровня), на SrcAddr действительно лежит 47, а на 16-битной шине данных DataBus - значение FFC7. Так происходит из-за расширения знака, который происходит в модуле QuatCoreImm, вот его код:

module QuatCoreIMM (input [7:0] SrcAddr, output [15:0] Q);

assign Q[6:0] = SrcAddr[6:0];
assign Q[15:7] = {9{SrcAddr[6]}}; //sign extension

endmodule

Нам очень хочется уметь представлять маленькие знаковые числа, но на них выделено всего 7 бит в поле команды (первый ноль означает, что мы из 4 модулей мы выбрали QuatCoreIMM, т.е Immediate-значения). Поэтому мы присоединяем к 7-му биту все более старшие, чтобы число -64 осталось таковым и в 16-битной записи.

А дальше происходит ещё одна метаморфоза - модуль памяти сейчас использует 8-битные адреса, поэтому старшие FF начисто игнорируются, и в SP поступает значение C7. Обо всём этом заботится компилятор. Если до значения в памяти можно "достучаться" напрямую, он сформирует правильный адрес, если нет - громко выругается. В этот раз всё пошло как надо.

Теперь смотрим на DestAddr. Как и задумано, там значение FD.
Напомним, что:
адреса 00..7F принадлежат модулю Imm (по Src) / Null (по Dest),
адреса 80..9F принадлежат модулю ALU,
адреса A0..BF принадлежат модулю PC,
адреса C0..FF принадлежат модулю MEM.

И приведём в качестве шпаргалки таблицу адресов MEM:



Адрес FD здесь называется: SP. Всё верно.

Мы видим, что выборка адресов произведена верно, на шине данных лежит то, что надо. Если всё пойдёт правильно, то в SP должно прийти значение C7. На этом такте мы этого узнать не можем, а все-все "потроха" высовывать наружу мне не хотелось. Поехали дальше.

Вторая команда, C [SP] (8A FC)
Видим, что за PC=0 последовало PC=1 (никаких переходов не было). Теперь SrcAddr = FC, DestAddr = 8A - из ПЗУ пришли правильные значения.

На MemAdr по-прежнему сидит значение C7 но теперь оно поступает не с шины данных, а из SP. В ответ на этот адрес, ОЗУ выдаёт значение 005F - адрес, по которому мы хотим разместить стек. Это значение коммутируется на шину данных, и если всё правильно выполнится, должно быть занесено в регистр C а АЛУ. Это операция, выполняющаяся за 1 такт. И действительно, по фронту тактовой частоты PC переключается с 1 на 2. Пока всё хорошо.

Третья команда, SP C (FD 83)
На шине данных по-прежнему значение 005F, но в этот раз поступившее из регистра C. Получателем должен стать регистр SP. Эти 3 команды немного раздражают - будь наши модули чуточку поумнее, можно было бы всё сделать за 1 команду, а может и вовсе научить SP принимать правильное значение по reset'у - и делов с концом! Но пущай будет...

Четвёртая команда, Call AffineAlgorithm, т.е [SP++] Call0 (F3 B0)
А вот это уже куда интереснее!

Модуль PC, при обращении по SrcAddr = B0, должен выдать на шину данных значение PC+1, т.е адрес возврата (по какому адресу надо прыгнуть по выходу из процедуры), и действительно, там мы видим значение 4. В качестве "побочного эффекта" должен произойти прыжок по нулевому адресу из таблицы CallTable. Сейчас компилятор немножечко поумнел и генерит такой код:

//адреса для вызова процедур, "вшитые" в модуль QuatCorePC
module QuatCoreCallTable (input [7:0] SrcAddr, output [4:0] addr);
assign addr =
5'd5; //AffineAlgorithm
endmodule

А именно, в случае, когда в таблице всего одна запись, она выдаётся "безальтернативно" и должна превратить вход "синхронной загрузки" в обычный "вход установки". Но самое главное - прыжок идёт по адресу 5. И как видно по сигналу PC, так оно и будет.

Теперь смотрим, что происходит на стороне Dest. Адрес возврата мы должны занести в стек. И действительно, в MemAdr поступает адрес 5F, который мы указали как начало стека. По MemContent пока идут нули - все "неинициализированные" области мы всё же инициализировали нулями.

Пока всё идёт как надо. Приведём следующий скриншот:



X Points2D (CD 18)
На шину данных поступает "непосредственное значение" и, вероятно, заносится в регистр X. Скоро проверим...

[SP+1] 0 (F0 00)
Мы "разместили" на стеке две локальные переменные. По адресу [SP] будем хранить текущую сумму, а по [SP+1] - максимальную отдалённости точки до всех остальных. Перед началом цикла заносим туда ноль.

Начало стека у нас было: 5F. Там сейчас лежит адрес возврата, а SP прибавил единичку, став 60. Значит, [SP+1] должен обратиться к адресу в памяти 61. Ага, так и есть! И эта область памяти тоже пока нулевая.

j 3 (A1 03)
На шине данных непосредственное значение 3 - всё верно. Из интересного - в память ОЗУ сформировался адрес 19. В этом нет криминала, и можно расшифровать, что это значит. Когда DestAddr не начинается с двух единиц, QuatCoreMemDecoder считает, что обращение к памяти идёт по SrcAddr. Там у нас значение 00 00 00 11. Старшие 2 бита игнорируются, следующие 2 бита выбирают базовый регистр - X. Следующие 2 бита выбирают второй индекс - это 1. И младшие 2 бита выбирают первый индекс - это 4j. Итого, формируется адрес [X+4j+1], и это действительно обращение по адресу 19, т.е запись в регистр X прошла! Другое дело, значение [X+1] не коммутируется на шину данных - так и должно быть.

К следующему такту мы видим, что действительно j=3. Всё работает.

i 3 (A0 03)
На шине данных значение 3. К следующему такту действительно i=3 - присвоение работает. В модуле памяти по-прежнему формируется адрес [X+4j+1], но теперь, поскольку j=3, вместо 19 получается 25 (это всё hex!), всё верно.

[SP] 0 (FC 00)
Сформировался адрес в ОЗУ 60 - так и надо. Пока содержимое по этому адресу нулевое. Всё верно.

k 1 (A2 01)
На шине данных "непосредственное значение" 1. В модуле MEM "на всякий случай" сформировался адрес [X+2i+1], и действительно, значение в скобках равно 1F.

10 команд, полёт нормальный :)
Продолжение следует. Там начинается работа с АЛУ, и что-то странное происходит, нужно что-то подрихтовать. А вот остальные модули - IMM, MEM и PC - меня пока что радуют, всё чётко :)

странные девайсы, математика, ПЛИС, работа

Previous post Next post
Up