119 lines
6.9 KiB
TeX
119 lines
6.9 KiB
TeX
\documentclass[a4paper,fontsize=14bp]{article}
|
||
|
||
\input{../common-preamble}
|
||
\input{../fancy-listings-preamble}
|
||
\input{../bmstu-preamble}
|
||
\numerationTop
|
||
|
||
\begin{document}
|
||
\thispagestyle{empty}
|
||
\makeBMSTUHeader
|
||
|
||
Официальное описание из комментария к функции хорошо объясняет, что именно она делает:
|
||
\begin{verbatim}
|
||
Description: minimum Value and Index of the minimum
|
||
element of a vector
|
||
\end{verbatim}
|
||
|
||
Снаружи функция будет вызываться вот так
|
||
\begin{verbatim}
|
||
void minvec (DATA *x, ushort nx, DATA *val, DATA *idx)
|
||
\end{verbatim}
|
||
То есть передадим
|
||
\begin{itemize}
|
||
\item вектор (массив чисел) \code{DATA *x}, важно, что вектор у нас из типа \code{DATA}, который, на самом деле \code{ushort (unsigned short)}, 16-разрядный, то есть при подсчёте сдвига по вектору для получения следующего значения - нужно смещаться на 2 байта.
|
||
\item длину вектора \code{ushort nx},
|
||
\item указатель на полученное значение \code{DATA *val},
|
||
\item указатель на полученный индекс \code{DATA *idx}.
|
||
\end{itemize}
|
||
|
||
Для языка ассемблера, умеющего манипулировать только регистрами, важно понимать, в какие именно регистры будут положены эти параметры
|
||
\begin{itemize}
|
||
\item \code{DATA *x} - указатель AR0
|
||
\item \code{ushort nx} - регистр T0
|
||
\item \code{DATA *val} - указатель AR1
|
||
\item \code{DATA *idx} - указатель AR2
|
||
\end{itemize}
|
||
|
||
дальше последовательно опишем что именно делает функция и как:
|
||
|
||
\begin{verbatim}
|
||
.text
|
||
.global _minvec
|
||
_minvec:
|
||
\end{verbatim}
|
||
|
||
до вызова функции система находилась в каком-то статусе, соответственно, нам нужно этот статус сохранить, чтобы наша функция ничего не сломала
|
||
\begin{verbatim}
|
||
PSH mmap(ST0_55) ; Сохранение регистров статуса на стеке
|
||
PSH mmap(ST1_55)
|
||
PSH mmap(ST2_55)
|
||
PSH mmap(ST3_55)
|
||
\end{verbatim}
|
||
|
||
далее происходит одновременное действие, знак \code{II} показывает, что два этих действия будут выполняться параллельно. Запись очередного значения из вектора во временный регистр \code{AC1} и вычитание 2 из регистра \code{T0}. Запись \code{*AR0+} означает, что мы не только разыменовали указатель (получили значение по указателю, знак *), но и сдвинули указатель вектора на следующий адрес (знак +)
|
||
\begin{verbatim}
|
||
MOV *AR0+,AC1
|
||
|| SUB #2,T0
|
||
\end{verbatim}
|
||
|
||
Сохраним значение из \code{T0} в \code{BRC0} и одновременно запишем 0 в \code{AR3}. Это вспомогательное действие, чтобы высвободить регистры, при помощи которых мы будем делать дальнейшие вычисления.
|
||
\begin{verbatim}
|
||
MOV T0,BRC0
|
||
|| MOV #0,AR3
|
||
\end{verbatim}
|
||
|
||
Далее происходит обнуление регистра \code{T0} и цикл между значением \code{RPTBLOCAL} и \code{end_block:}
|
||
\begin{verbatim}
|
||
MOV #0,T0
|
||
|| RPTBLOCAL end_block-1
|
||
\end{verbatim}
|
||
|
||
В цикле мы кладём следующее значение из вектора в \code{AC0}, помнишь, мы уже клали значение из вектора в \code{AC1}, вот теперь в \code{AC0}. Мнемоника \code{MAR} в явном виде не описана в документации, но есть предположение, что MAR это аббревиатура от Modify Auxiliary Register, то есть по факту это просто увеличение временного указателя на будущий вычисленный индекс на единицу. Напомню, в этот регистр два шага назад, до цикла, мы положили 0, то есть, скорее всего, это будет конечный индекс в векторе, который мы должны вернуть.
|
||
\begin{verbatim}
|
||
MOV *AR0+,AC0
|
||
|| MAR *AR3+
|
||
\end{verbatim}
|
||
|
||
Тут, понятно, мы ищем минимальное из двух значений (мы же положили последовательно два значения из вектора в \code{AC0} и \code{AC1}). Значение, полученное в результате сравнения, будет положено в \code{AC1}\footnote{TMS320C55x-Mnemonic Instruction Set. Reference Guide-2009, p.428}. То, что мы положим минимальное в \code{AC1} даст нам возможность на следующей итерации цикла снова сравнивать с ним прочитанное в \code{AC0} следующее значение из вектора, как мы это делаем на предыдущем шаге.
|
||
\begin{verbatim}
|
||
MIN AC0,AC1
|
||
\end{verbatim}
|
||
|
||
Это проверка условия завершения цикла \footnote{TMS320C55x-Mnemonic Instruction Set. Reference Guide-2009, p.749 (XCCPART), p.20(CARRY)} по биту переноса и одновременно вывод информации из \code{AR3} (в котором, напомню, у нас хранился индекс минимального значения в векторе) по указателю \code{AR2}, который, напомню, нам передали с параметрами функции
|
||
\begin{verbatim}
|
||
XCCPART end_block, !CARRY
|
||
|| MOV AR3,*AR2
|
||
\end{verbatim}
|
||
|
||
По завершении цикла, сохраним полученное значение минимума по указателю \code{AR1}, который мы передали снаружи в параметре \code{val}.
|
||
\begin{verbatim}
|
||
end_block:
|
||
MOV AC1,*AR1
|
||
\end{verbatim}
|
||
|
||
Вернём на место статус системы из сохранённого ранее и выйдем из функции
|
||
\begin{verbatim}
|
||
POP mmap(ST3_55)
|
||
POP mmap(ST2_55)
|
||
POP mmap(ST1_55)
|
||
POP mmap(ST0_55)
|
||
RET
|
||
\end{verbatim}
|
||
|
||
\begin{lstlisting}[language=C,style=CCodeStyle]
|
||
void minvec (DATA *x, ushort nx, DATA *val, DATA *idx) {
|
||
while (nx-- >= 0) {
|
||
if (*val > *(x + nx)) {
|
||
*val = *(x + nx);
|
||
*idx = nx;
|
||
}
|
||
}
|
||
}
|
||
\end{lstlisting}
|
||
|
||
\end{document}
|
||
|
||
|
||
|