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