CMPUT 229 — Computer Organization and Architecture I
Lab 2: Linked List to Array Conversion
Creator: Saumya Patel
Introduction
In this lab, you will develop your first RISC‑V assembly subroutine that converts a singly linked list into an array and locates the index of a specified target element.
Background
A linked list is a linear data structure where each element, called a node, is dynamically and independently allocated and stored in memory. The nodes of a linked list may be arbitrarily located in memory and may be in non-contiguous memory locations. Each node contains:
- Data – the integer value held by the node.
- Pointer – the memory address of the subsequent node in the list.
Accessing data stored in linked list instead of arrays has several disadvantages:
- The list needs to be traversed from the head to locate a specific element.
- For each element accessed in this traversal, an extra load operation is needed to obtain the pointer to the next element. This additional access creates a loop carried dependence in the traversal loop which prevents the parallelization of that loop by a compiler.
- If the elements of the linked list are non-contiguous, and potentially scattered in memory, there will be poor spacial locality, leading to many cache misses that negatively affect performance.
- The code to access an element at a sepecific position k in the linked list is more complex than the code to access the element k of an array
Thus, even if a program initially builds a linked list, for instance, because the total number of elements is unknown, if the list will be traversed many times, there is an advantage in converting the list to an array and accessing the elements in the array instead.
In this lab, you will use a singly linked list, a type of linked list in which each node points only to the next node. The pointer field of the last node uses a sentinel value (commonly 0 or –1, in this lab, 0) to signify the end of the list. Unlike arrays, linked lists do not require a fixed size and allow efficient insertion and deletion, although traversal must be done sequentially.
Understanding Linked Lists
1. Definition
A linked list is a sequence of nodes where each node stores data and a reference to the next node. Conceptually, it is similar to a series of connected waypoints, where each point provides the direction to the next.
The linked list is specified by the address of its first node in memory. If the linked list is empty, this address is zero (representing the null value). Each node of the linked list contains one integer value and the address of the next element in the list.
2. Use Case
Linked lists are preferred in scenarios where:
- The number of elements is not known in advance.
- Frequent insertions and deletions are expected, especially in the middle or beginning.
- Memory fragmentation is not a concern (e.g., dynamic heap allocation is available).
While arrays support faster access to elements with a specific index due to direct indexing, they are inefficient when resizing or inserting in between elements.
3. Memory Layout
Linked-list nodes may not be stored in contiguous memory blocks. Each
node is dynamically allocated (e.g., using
malloc) and comprises:
- data: the value stored in the node (e.g., an integer)
- next: the memory address pointing to the next node
The pointer of the tail node holds the value of 0 to indicate the end of the linked list.
4. Visual Representation
C code Example
Below is an example of how a singly linked list can be defined and used in C:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
} Node;
// insert at beginning
Node* insert(Node* head, int value) {
Node* new_node = (Node*)malloc(sizeof(Node)); // allocate memory for new node, common.s already does this. dont worry about it
new_node->data = value;
new_node->next = head;
return new_node;
}
This snippet defines a node structure and a function that inserts a new node at the beginning of a singly linked list.
Task
Your task is to implement a RISC‑V subroutine called
Convert which transforms a singly linked list into an
array. This subroutine should begin at the head of the list,
traversing each node sequentially and storing each node’s data into
consecutive elements of the array. The traversal ends when the address
of the next node of an node in the linked list is the address 0
(0x00000000). encountered in the pointer field, which is then placed
in the following array element.
Additionally, you are required to locate a specified target element
within the list. If the target is found, return the index of its
last occurrence as well as return 1 indicating that the
index is found . For example, if the target value is
5 and it appears at indices 2 and
7, return 7as well as 1 indicating that the
index has been found. If it is not present, return 0 to
indicate its absence as well return -1 for the index of the target
(which has not been found). Upon completion, the array should contain
all node data followed by the sentinel.
The implementation should:
- Traverse the Linked List: Start from the head node and move through each node one by one.
- Store Node Data in the Array: Place each node's data into consecutive array positions.
- Handle Sentinel Pointer: When the pointer field is equal to 0, stop traversal and store the sentinel in the next array element.
- Find the Target Element: During traversal, compare each node's data with the target value. If a match is found, return its index.
- Handle Absence of Target: If no match is found, return -1 to indicate the target is not present.
- Return the Final Array: After traversal, the array should contain all node values and the sentinel.
Input Guarantees
- The linked list should contain between 0 and 50 integers, inclusive.
- All data values in the linked list are integers.
- The target value is an integer.
Specifications
You are
not required to follow the standard register saving and
restoring conventions in your implementation.
The assignment must include the following function:
-
Convert:-
Arguments:
a0: pointer to the output array-
a1: pointer to the head of the linked list -
a2: the value of the target element to locate
-
Return Values:
-
a0: 1 if the target is found, otherwise 0 -
a1: the index of the target element in the linked list, if found. Otherwise -1
-
-
Effect:
- converts a given linked list into an array in a different memory location and indexes the target element
-
Arguments:
-
The output array provided in
a0has sufficient memory allocated to store all elements of the linked list followed including the tail which has the addresss to the next node as 0x00000000 ( 0 ).
Testing
When debugging, it can be very helpful to step through the assembly
code instruction by instruction. You can use
ebreak statements to pause the execution program
execution at a specified instruction and examine the state of the
registers and memory. From that point you can then execute
instructions one by one.
The folder Code/Tests/ contains sample test cases. The
*.txt files contain test inputs. The corresponding
*.out file contains the correct output. The provided test
cases are not extensive. Additional testing is required to ensure that
the solution is correct.
To perfom a test, enter the complete file path of the corresponding
test input into the Program Arguments box in RARS. The file
path cannot have any spaces. Do not put quotations areound the
filename. Provide a full path to the file. For example
/home/user/cmput229/test.txt is a valid path, while
/home/user/cmput 229/this is a test.txt is not.
Once you have entered the path to the test case, you can run the
program. If the program arguments field does not appear in your RARS,
you need to change your settings. Go to Settings ->
Program Arguments Provided To Program
(second option) and make sure that this opiton is checked.
You can test your lab from a terminal with
rars LABFILE pa TESTFILE where LABFILE is
the path to magicSquare.s and TESTFILE
is the path to the file that contains the test case you want to test.
Depending on the version of RARS and your operating system RARS may
print extra copyright lines. Ignore these lines.
Test cases are plain text files ending with .txt and must
follow the format below:
L T
[sequence of integers representing the linked list]
Where:
L: Length of the linked list.T: Target value to find.
Example:
11 5
5 7 2 3 4 5 1 2 3 4 5
Resources
Marking Guide
Assignments too short to be adequately judged for code quality will be given a zero.
- 20% for code cleanliness, readability, and comments.
- 10% for correctly indexing the next node procedure.
- 10% for correctly inserting the element into the array.
- 10% for correctly finding the target element in the linked list.
- 20% for correctly handling the target element in the found/not found case
- 30% for the correct output of the array (each element in the array is worth equal points)
Submission
Ensure that your solution works in the lab machines because it will be graded using the lab machines.
There is a single file to be submitted for this lab:
-
Convert.sshould contain the code for inserting the integers from a linked list into an array. - Do not add a
mainlabel to this file. - Do not modify the line
.include "common.s". - Do not modify the
common.sfile. - Submit only your
Convert.s.