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}
|
|||
|
|
|||
|
|
|||
|
|