# Array Search
### Code :
```c=
int arraySearch(int *p_a, int arr_size, int target)
{
int result = -1;
asm volatile(
// Your code
// t0:counter
// t1:a[i]
"mv t0, zero \n\t"
"loop: \n\t"
"beq t0, %[arr_size], end \n\t"
"lw t1, 0(%[p_a]) \n\t"
"beq t1, %[target], find_out \n\t"
"addi %[p_a], %[p_a], 4 \n\t"
"addi t0, t0, 1 \n\t"
"j loop \n\t"
"find_out: \n\t"
"mv %[result], t0 \n\t"
"end: \n\t"
:[p_a] "+r"(p_a), [result] "=r"(result)
:[arr_size] "r"(arr_size), [target] "r"(target)
:"t0", "t1"
);
return result;
}
```
### Explanation
**GOAL : Find the index of specified element**
- `t0` : Counter and index, `t1` : The value of a[i]
- If the element is found, set `target` to `t0`; otherwise, keep it as -1.
# Swap two element
### Code :
```c=
asm volatile(
// Your code
"mv t0, %[j] \n\t"
"slli t0, t0, 2 \n\t"
"add t1, %[array], t0 \n\t"
"lw t2, 0(t1) \n\t"
"lw t3, 4(t1) \n\t"
"blt t2, t3, over \n\t"
"sw t2, 4(t1) \n\t"
"sw t3, 0(t1) \n\t"
"over: \n\t"
:
:[j] "r"(j), [array] "r"(p_a)
:"t0", "t1", "t2", "t3"
);
```
### Exlanation :
**GOAL: Swap two elements if the previous one is bigger**
- Calculate the addresses of `a[j]` and `a[j+1]`
- Swap them by storing values at the opposite locations
# Merge Sort
## splitList
### Code :
```c=
// Split the linked list into two parts
void splitList(Node *head, Node **firstHalf, Node **secondHalf)
{
asm volatile(
/*
Block A (splitList), which splits the linked list into two halves
*/
// t1 : *fast, t2 : *slow
// t3 : pointer to previous node of t2
"mv t1, %[head] \n\t"
"mv t2, %[head] \n\t"
"cut_loop: \n\t"
"mv t3, t2 \n\t"
"ld t2, 8(t2) \n\t"
"ld t1, 8(t1) \n\t"
"beqz t1, cut_over \n\t"
"ld t1, 8(t1) \n\t"
"beqz t1, cut_over \n\t"
"j cut_loop \n\t"
"cut_over: \n\t"
"mv %[firstHalf], %[head] \n\t"
"mv %[secondHalf], t2 \n\t"
"sd zero, 8(t3) \n\t"
:[firstHalf] "+r"(*firstHalf), [secondHalf] "+r"(*secondHalf), [head] "+r"(head)
:
:"t1", "t2", "t3"
);
}
```
### Explanation :
**GOAL : use specified pointer to split one linked list to two linked list**
- Use the [Fast-Slow pointer](https://medium.com/@arifimran5/fast-and-slow-pointer-pattern-in-linked-list-43647869ac99) to find the middle of the linked list `Line 10 to 19`
- `t1` : fast pointer, `t2` : slow pointer, `t3` : a pointer to the node preceding the slow pointer
- Here I use `t3` because I find pointer-to-pointer operations too complex. This pointer helps maintain the tail of the first half by setting its NEXT to 0.
## mergeSortLists
### Code :
```c=
Node *mergeSortedLists(Node *a, Node *b)
{
Node *result = NULL;
Node *tail = NULL;
asm volatile(
/*
Block B (mergeSortedList), which merges two sorted lists into one
*/
// t1:data of node *a
// t2:data of node *b
// use tail to construct the merged list
"lw t1, 0(%[a]) \n\t"
"lw t2, 0(%[b]) \n\t"
"bge t1, t2, result_tob \n\t"
"mv %[result], %[a] \n\t"
"ld %[a], 8(%[a]) \n\t"
"j merge_start \n\t"
"result_tob: \n\t"
"mv %[result], %[b] \n\t"
"ld %[b], 8(%[b]) \n\t"
"merge_start: \n\t"
"mv %[tail], %[result] \n\t"
"merge_loop: \n\t"
"beqz %[a], a_isNULL \n\t"
"beqz %[b], b_isNULL \n\t"
"lw t1, 0(%[a]) \n\t"
"lw t2, 0(%[b]) \n\t"
"bgt t1, t2, b_smaller \n\t"
"a_smaller: \n\t"
"sd %[a], 8(%[tail]) \n\t"
"ld %[tail], 8(%[tail]) \n\t"
"ld %[a], 8(%[a]) \n\t"
"j merge_loop \n\t"
"b_smaller: \n\t"
"sd %[b], 8(%[tail]) \n\t"
"ld %[tail], 8(%[tail]) \n\t"
"ld %[b], 8(%[b]) \n\t"
"j merge_loop \n\t"
"a_isNULL: \n\t"
"sd %[b], 8(%[tail]) \n\t"
"j end \n\t"
"b_isNULL: \n\t"
"sd %[a], 8(%[tail]) \n\t"
"end:"
:[a] "+r"(a), [b] "+r"(b), [tail] "+r"(tail), [result] "+r"(result)
:
:"t0", "t1"
);
return result;
}
```
### Explanation :
**GOAL : merge two sorted list to one sorted list**
Since I want to use recursion to merge two lists, I first compare the heads to determine the initial pointer `result` and then use `tail` to construct the new list.
The recursive steps are as follows:
1. Check that neither pointer `a`, `b` is NULL. If one is, end the recursion `Line 25, 26`
2. Move `tail` to the smaller node and link it `Line 27 to 39`
3. If one list is empty (meaning the other is not), set the NEXT of `tail` to the remaining nodes `Line 40 to 44`
## print list
### Code :
```c=
cur = head;
while (cur) {
printf("%d ", cur->data);
asm volatile(
/*
Block C (Move to the next node), which updates the pointer to
traverse the linked list
*/
"ld %[cur], 8(%[cur]) \n\t"
:[cur] "+r"(cur)
:
:
);
}
```
### Explanation :
Because:
1. The pointer stores the address of the node
2. According to memory alignment, data is allocated 8 bytes (the same as next)
Hence, we access the next node by loading 8 bytes (`ld`) from `*(cur) + 8`
## Verificationlinked_list_sort.c
I use following two instructions to print the result of merge sort
```bash
riscv64-unknown-linux-gnu-gcc -static -march=rv64gcv -o MergeSort linked_list_sort.c
```
```bash
spike --isa=RV64GCV /opt/riscv/riscv64-unknown-linux-gnu/bin/pk MergeSort ../testcases/input/3_1.txt
```