BMSTU/03-fpga-lab-03-report.tex

263 lines
15 KiB
TeX
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

\documentclass[a4paper,fontsize=14bp]{article}
\input{settings/common-preamble}
\input{settings/fancy-listings-preamble}
\input{settings/bmstu-preamble}
\setcounter{secnumdepth}{4}
\numerationTop
\begin{document}
\thispagestyle{empty}
\makeBMSTUHeader
\makeReportTitle{лабораторной}{№ 3}{Разработка и интеграция пользовательских инструкций в состав ядра Nios II}{Проектирование цифровых устройств на \\ программируемых логических интегральных схемах (ПЛИС)}{}{С.В. Фёдоров}
\newpage
\pagestyle{fancy}
\section{Цель}
Освоить методику использования в составе системы на кристалле пользовательских периферийных модулей и пользовательских инструкций. Реализовать и отладить программное обеспечение системы на кристалле.
\section{Задачи}
\begin{itemize}
\item Изучить методики расширения набора команд процессора пользовательскими инструкциями.
\item Реализовать программное обеспечение, использующее пользовательские инструкции на примере инструкции вычисления количества единиц в двоичном числе.
\item Сравнить быстродействие с программной реализацией на базовом наборе команд.
\item Выполнить индивидуальное задание.
\end{itemize}
\section{Выполнение работы}
По шагам из методического материала был создан проект в САПР Quartus Prime (доступен по \href{https://git.iovchinnikov.ru/ivan-igorevich/fpga-lab-2/commits/branch/lab3}{ссылке}).
Созданная пользовательская инструкция доступна для обращения из программного кода в прикладном проекте.
\section{Индивидуальное задание}
В качестве индивидуального было дано следующее задание: описать пользовательскую инструкцию, принимающую на вход два 32-разрядных значения и возвращающая минимальное, максимальное, верхнее медианное и нижнее медианное значения. Схема получения данных на рис. \hrf{pic:indi-scheme}. Исходные данные представляют собой два 32-разрядных слова, каждое из которых необходимо разделить на четыре 8-разрядных слова, отсортировать все восемь 8-разрядных слов по возрастанию и взять их минимум (1), максимум (4) и медианы (2, 3).
\begin{figure}[H]
\centering
\fontsize{12}{1}\selectfont
\includesvg[scale=1.01]{pics/03-fpga-03-lab-indi-scheme.svg}
\caption{Схема обработки данных}
\label{pic:indi-scheme}
\end{figure}
Поскольку сложность самой быстрой сортировки $O(N*\lg_2(N))$, принято решение опираться на то, что значений в искомом множестве всегда фиксированное число. Сложность задания состоит в том, чтобы получить медианы не отсортированного множества за время меньшее, чем $O(N*\lg_2(N))$. Отсутствие необходимости разработки для множеств не фиксированной длины позволяет воспользоваться несколькими способами получения медианных значений.
\subsection{Описание схемотехнического решения}
Дан исходный числовой ряд (восемь байт, полученных из двух 32-разрядных переменных), например
\[ [31, 44, 216, 0, 132, 68, 18, 100]. \]
Изначально был применён алгоритм комбинационного поиска медианы для 8 значений:
\begin{enumerate}
\item сравнение соседних значений в ряду парами;
\item меньшие значения сравнить с меньшими значениями пар, а большие с большими;
\item взять меньшую из больших полученных пар и б\'{о}льшую из меньших, также сравнить меньшие с меньшими и б\'{о}льшие с б\'{о}льшими;
\end{enumerate}
\begin{equation*}
\begin{gathered}
[31, 44, 216, 0, 132, 68, 18, 100]
\to
\begin{bmatrix}
31, 44 \\ 0, 216 \\ 68, 132 \\ 18, 100
\end{bmatrix}
\\ \to
\begin{bmatrix}
0, 31 \\ 18, 68 \\ 44, 216 \\ 100, 132
\end{bmatrix}
\to
\begin{bmatrix}
44, 100 \\ 31, 68
\end{bmatrix}
\\ \to [31, 44, 68, 100] \to 44, 68;
\end{gathered}
\end{equation*}
Из приведённых вычислений очевидно, что:
\begin{itemize}
\item нижняя медиана = 44
\item верхняя медиана = 68.
\end{itemize}
Однако, дополнительные тесты показали, что алгоритм работает не для всех возможных вариантов начального распределения значений во множестве. Исходные коды модуля \hrf{lst:mediancomb} и вспомогательного \hrf{lst:lessmore} приведены в приложении \hrf{appendix:src}.
\begin{lstlisting}[language=Verilog,style=VerilogStyle,caption={\code{minmedmax.sv}},label={lst:mmm}]
module minmedmax
(
input clk, reset,
input [31:0] in1, in2,
output reg [31:0] result
);
logic [7:0] temp [0:7];
integer status [0:7];
assign temp = '{in1[31:24], in1[23:16], in1[15:8], in1[7:0], in2[31:24], in2[23:16], in2[15:8], in2[7:0]};
integer i, s, mini, maxi;
always_comb begin
for (s = 0; s < 6; s = s + 1) begin
if (s == 0) begin status = '{0,0,0,0,0,0,0,0}; end
mini = 0; maxi = 0;
for (i = 0; i < 8; i = i + 1) begin
if ((temp[i] <= temp[mini] || status[mini] == 1) && status[i] != 1) mini = i;
if ((temp[i] >= temp[maxi] || status[maxi] == 1) && status[i] != 1) maxi = i;
end
status[mini] = 1;
if (s == 0) begin
result[31:24] = temp[maxi];
result[7:0] = temp[mini];
status[maxi] = 1;
end
if (s == 3) begin result[15:8] = temp[mini]; end
if (s == 4) begin result[23:16] = temp[mini]; end
if (s == 5) begin status = '{0,0,0,0,0,0,0,0}; end
end
end // always_comb
endmodule
\end{lstlisting}
Конечный вариант модуля вычисления медиан, минимума и максимума представлен в листинге \hrf{lst:mmm}. Модуль осуществляет проход по сформированной шине из 8-разрядных значений, являющихся результатом конкатенации двух входящих 32-разрядных значений. Создаётся вспомогательный массив для отметок о проверке значения. Основной цикл опирается на сведения о том, что значений всегда восемь, поэтому итераций внешнего цикла нужно шесть (на первой будет найден минимум и максимум, на четвёртом и пятом - медианы, на шестом очищена сервисная шина). Основной цикл проходит по всей 64-разрядной временной шине и выставляет флаги минимума и максимума по следующему условию: \textit{проверяемый} элемент минимальный (максимальный), если он меньше (больше) \textit{найденного} на предыдущем шаге минимального (максимального) элемента или \textit{найденный} уже проверен\footnote{условие добавлено для первой итерации цикла в случаях, когда первой элемент является минимальным или максимальным.} и если проверяемый элемент не был проверен ранее.
\subsection{Описание программного решения}
Два входящих слова записываются во временный указатель и интерпретируются, как указатель на восемь 8-разрядных переменных \code{alt_u8}, далее цикл работает с ними как с массивом данных. На каждом шаге цикла ищется минимальный и максимальный элемент. Найденные элементы меняются местами с теми числами, которые находятся на месте действительно минимального и максимального элемента соответственно. Алгоритм являет собой совмещение \textit{сортировки выбором} и \textit{шейкерной сортировки}. Таким образом за четыре итерации получается сортированное множество, в котором необходимые значения берутся по индексу.
\begin{equation*}
\begin{gathered}
[31, 44, 216, 0, 132, 68, 18, 100] \to \\
[0, 44, 100, 31, 132, 68, 18, 216] \to \\
[0, 18, 100, 31, 44, 68, 132, 216] \to \\
[0, 18, 31, 68, 44, 100, 132, 216] \to \\
[0, 18, 31, 44, 68, 100, 132, 216]
\end{gathered}
\end{equation*}
Программная реализация алгоритма копирует исходные значения функцией \code{memset(dst, src, size)} и обрабатывает ситуацию, в которой найденный максимум равен найденному минимуму.
\begin{lstlisting}[language=C,style=CCodeStyle]
alt_u32 ones_sw (
alt_u32* data_block_a,
alt_u32* data_block_b,
alt_u32 words) {
alt_u32 result;
int word;
for (word = 0; word < words; ++word) {
alt_u8 tmp[8];
memset(tmp, data_block_a[word], 4);
memset((tmp + 4), data_block_b[word], 4);
for (int k = 0; k < 4; ++k) {
int min = tmp[k];
int max = min;
for (int i = k; i < 8 - k; ++i) {
if (min >= tmp[i]) {
min = tmp[i];
tmp[i] = tmp[k];
tmp[k] = min;
}
if ((max <= tmp[i]) && (max != min)) {
max = tmp[i];
tmp[i] = tmp[8 - k - 1];
tmp[8 - k - 1] = max;
}
}
}
result += tmp[0];
result += (tmp[3] << 8);
result += (tmp[4] << 16);
result += (tmp[7] << 24);
}
return result;
}
\end{lstlisting}
\section{Результат и выводы}
После запуска приложения были получены результаты, представленные на рис. %\hrf{:}.
%\begin{figure}[H]
% \centering
% \includegraphics[width=12cm]{.}
% \caption{}
% \label{pic:}
%\end{figure}
Пользовательская инструкция для процессора Nios II -- это эффективный инструмент ускорения работы программы и выноса некоторых алгоритмов поточной обработки данных в аппаратную часть.
\newpage
\appendix
\setcounter{secnumdepth}{4}
\section{Приложения}
\subsection{Исходные коды проекта}
\label{appendix:src}
\begin{lstlisting}[language=Verilog,style=VerilogStyle,caption={\code{lessmore.sv}},label={lst:lessmore}]
module lessmore (
input [7:0] in1,
input [7:0] in2,
output logic [7:0] less,
output logic [7:0] more
);
always_comb begin
if (in1 < in2) begin
less = in1;
more = in2;
end else begin
less = in2;
more = in1;
end
end
endmodule
\end{lstlisting}
\begin{lstlisting}[language=Verilog,style=VerilogStyle,caption={\code{minmedmax.sv}},label={lst:mediancomb}]
module minmelhmax (
input clk,
input reset,
input [31:0] in1,
input [31:0] in2,
output logic [31:0] result
);
logic [7:0] step1less [0:3];
logic [7:0] step1more [0:3];
logic [7:0] step2less [0:3];
logic [7:0] step2more [0:3];
logic [7:0] median [0:3];
logic [7:0] temp [0:3];
// 1: compare pairs
lessmore s01 (in1[7:0], in1[15:8], step1less[0], step1more[0]);
lessmore s02 (in1[23:16], in1[31:24], step1less[1], step1more[1]);
lessmore s03 (in2[7:0], in2[15:8], step1less[2], step1more[2]);
lessmore s04 (in2[23:16], in2[31:24], step1less[3], step1more[3]);
// 2: 1st step mins to mins, maxes to maxes
lessmore s11 (step1less[0], step1less[1], step2less[0], step2more[0]);
lessmore s12 (step1less[2], step1less[3], step2less[1], step2more[1]);
lessmore s13 (step1more[0], step1more[1], step2less[2], step2more[2]);
lessmore s14 (step1more[2], step1more[3], step2less[3], step2more[3]);
// 3: 2nd step less-maxes, more-mins
lessmore s21 (step2less[2], step2less[3], median[0], median[1]);
lessmore s22 (step2more[0], step2more[1], median[2], median[3]);
// 4: median of four
lessmore s31 (median[0], median[1], temp[1], result[1]);
lessmore s32 (median[2], median[3], result[2], temp[2]);
// 5: max and min of input
lessmore s41 (step2less[0], step2less[1], result[0], temp[0]);
lessmore s42 (step2more[2], step2more[3], temp[3], result[3]);
endmodule
\end{lstlisting}
\lstinputlisting[language=C,style=CCodeStyle,caption={\code{sem.c}},label={lst:sem}]{src/sem.c}
\end{document}