\documentclass[11pt, a4paper]{article}
\usepackage[UTF8]{ctex}
\usepackage{geometry}
\usepackage[inline]{enumitem}
\usepackage{amsmath}
\usepackage{float}
\usepackage{listings}
\usepackage{fontspec}
\usepackage{xcolor}

% \newfontfamily\codefont[Ligatures=ResetAll]{Fira Code}[Contextuals={Alternate}]
\newfontfamily\codefont{Cascadia Code}

\lstset{
    basicstyle          =   \small\codefont,
    % ---
    tabsize             =   4,
    showstringspaces    =   false,
    numbers             =   left,
    numberstyle         =   \codefont,
    % ---
    breaklines          =   true,
    captionpos          =   t,      
    % ---
    frame               =   l,
    flexiblecolumns,
    columns = fixed,
}

\lstdefinestyle{asmstyle}{
    % basicstyle = \small\codefont,
    keywordstyle=\bfseries\color{green!40!black},
    commentstyle=\color{purple!40!black},
    identifierstyle=\color{blue!80!white},
}

\title{\textbf{Report for First Assembly Homework}}
\author{2022010639 高艺轩}
\date{}

\begin{document}
\maketitle
\section{Basic Exercises}
\subsection{System Call}
The code is essentially a set of system calls. Set the values in \lstinline{$a0, $a1, $a2} as the arguments to pass to the operation system, and use \lstinline{$v0} to change the exact systemcall.

These systemcalls first open file as read only, then read the contents into the memory; close the file, then open another file in write only mode and write the content just read from the other file.

The last two systemcalls are reading from \lstinline{stdin} and output to \lstinline{stdout}, respectively.

\subsection{Loop and Branch}
The \lstinline{for} loop and \lstinline{if} clause in high level programming language is written in a way that we write the action to do when the expression is satisfied at the top, and then write the other part after that. However, to achieve similar structure in assembly code, we have to compose the logic in the way of ``If the expression is NOT met, then jump further away so the instructions right behind this jump instruction is NOT executed'', and by this way, when the expression is met, \lstinline{pc} won't be altered and the code below will be executed.

The program first read in \lstinline{i} and \lstinline{j} from \lstinline{stdin}, then use a \lstinline{bgez} to decided whether \lstinline{j = -j} needed to be executed. Then, set a register as temp, and count it up to add 1 to \lstinline{i} every time until temp is greater than or equal to (\lstinline{bge}) \lstinline{j}. Lastly, print out the result and set the return value.

\subsection{Array and Pointer}
First, read in the total number \lstinline{n} of the upcoming numbers; Then, request \lstinline{n << 2} bytes of space to store the numbers. Use \lstinline{$t0} as the counter, and \lstinline{$t1} as the pointer, write the number read into memory. Doing the reverse is similar to this. Every iteration adds \lstinline{$t1} by 4 and subtracts \lstinline{$t2} by 4 so that \lstinline{a[i]} and \lstinline{a[n - i - 1]} can be accessed. At last, cycle through the number once more to output the results.

\subsection{Function Call}
Function call is actually very similar to what it is in higher level language. The only difference is that inside a procedure call, first move \lstinline{$sp} by some distance and store all the registers that are required to be preserved but also used by this procedure call, including \lstinline{$ra}. Then write the procedure as if it is a normal program, the arguments of the call is stored in \lstinline{$a0, $a1, $a2} and should be copied to saved registers if needed later. At the end of the procedure, save the return value to \lstinline{$v0}, restore all the saved register value from stack and restore \lstinline{$sp} then call \lstinline{jr $ra} to return.

\section{Practical Application}
\subsection{Direct Insertion Sort}
In \lstinline{insertion_sort}, \lstinline{$s0} is the \lstinline{n}, \lstinline{$s1} is the \lstinline{i} in \lstinline{for} loop. For every element in the list, the procedure uses \lstinline{search} to find its correct position, and use insert to insert it into that position.

In \lstinline{search}, \lstinline{$s0} is \lstinline{&v[0]} and \lstinline{$s2} is \lstinline{v[n]}, \lstinline{$s1} is \lstinline{i} in the \lstinline{search_loop}. The procedure finds the first number that is smaller than the target number, and return the address of one after this smaller number.

In \lstinline{insert}, \lstinline{$s0 = &v[0]}, \lstinline{$s2 = v[n]}, \lstinline{$s1 = i}, string from \lstinline{n - 1}. The procedure moves everything after the target's correct position one slot backward, and then insert the target into its correct position.

In \lstinline{add_compare_count}, the procedure loads the stored compare count, add 1 to it, and then write it back to memory.

\lstinline{print_num_in_buff} is a procedure used for debugging. It prints out all the number in the number buffer, seperated by space and ended by \lstinline{\r\n}.

\subsection{Binary Insertion Sort}
The overall design and structure of the program is same as the `Direct Insertion Sort'. The only difference is that the \lstinline{search} procedure now uses binary search to search for the correct position of the target number.

In the new \lstinline{binary_search} procedure, \lstinline{$s1 = left}, \lstinline{$s2 = right}, \lstinline{$s3 = mid}, and \lstinline{$t0 = &v[0]}, \lstinline{$t1 = v[mid]}, \lstinline{$t2 = v[n] = target_number}. Every time the procedure finds the number in the middle of left and right and compare it with the target number; if the middle number is larger, then further search for left part; if the middle number is smaller, then further search for right part. Do this recursively until the left bound is larger than right bound, which means the left bound is the position to insert this target number.

\subsection{Merge Sort}
The C++ code uses linked list, and thus the \lstinline{main} part of the code have to create the linked list after reading the file into the memory. For every number, allocate a new node on heap, then save the pointer and content. Then it calls \lstinline{merge_sort} and save the sort result into file.

In \lstinline{merge_sort}, \lstinline{$s1} is the stride 1 pointer and \lstinline{$s2} is the stride 2 pointer that goes 2 steps every 1 step the stride 1 pointer tooks. When stride 2 pointer reaches the end of the list, stride 1 pointer is pointing at the middle of the list. Then it breaks the list at the middle, and calls \lstinline{merge_sort} on both parts. Then, use \lstinline{merge_list} to merge back the two parts into a ordered list.

In \lstinline{merge_list}, \lstinline{$s0} is the \lstinline{p_left}, \lstinline{$s1} is the \lstinline{p_right}, and \lstinline{$s7} is the \lstinline{head}. \lstinline{$s2, $s3, $s4, $s5} are used according to the needs, they are typically \lstinline{p_left[1]}, or \lstinline{(p_left[1])[0]}, or \lstinline{p_right_temp}, which are labeled in comments. In essence, the proceture takes two ordered list and reconnect them to combine them into one ordered list.
\end{document}