While taking a course in assembly language we were tasked with a project that mimics a text editor. The task was to create a program that allowed users to add text via input or file, view, edit, delete, search, and save the text to a file. This project was done on a raspberry pi with arm64 architecture. I completed this project with a partner where we split the function amongst each other. Notably, this project built upon a previous project in the course that was about creating a string class that allowed a user to manipulate strings with various methods. Utilizing this initial string project we were able to call the functions we previously created while implementing the text editor.
Learning assembly and doing these projects forced me to gain a deeper understanding of how computers work on a lower level. Even outside of the context of assembly, these projects helped me improve upon analyzing and walking through code to understand it as it was easy to lose where you were at when coming back to working on the project. This also revealed to me the value in good coding practices, especially when working with other people. Without a doubt these projects were challenging in how tedious they were, though there was something fun about being so deeply focused on coding your project that you begin to lose track of your surroundings and your mind gets set into assembly mode for a while.
//********************************************************************************
// Programmer : Peijun Zhao/Juliette Raubolt
// RASM : 4
// Purpose : It will be creating a Menu driver program that serves as a text
// editor and save the resulting text to a file
// Author : Peijun Zhao/Juliette Raubolt
// Date : 11/29/2022
//********************************************************************************
// Algorithm
// Create different functions that will perform based on what the user has chosen
// on a menu and creat a menu that will display the following:
// <1> View all strings
// <2> Add string
// <a> from Keyboard
// <b> from File. Static file named input.txt
// <3> Delete string. Given an index #, delete the entire string and
// de-allocate memory (including the node).
// <4> Edit string. Given an index #, replace old string w/ new string.
// Allocate/De-allocate as needed.
// <5> String search. Regardless of case, return all strings that match
// the substring given.
// <6> Save File (output.txt)
// <7> Quit
//********************************************************************************
// Function Alogorithms:
//-------------------------------------------------------------------------------
// edit_node:
// Parameters:
// X0 - head
// X1 - Node index to edit
// X2 - Address of new string
// Returns:
// Nothing, updates linked list
// 1. Call get_node with (index - 1) to get address of node
// 2. LDR X0 with address in first 8 bytes of node and call free
// 3. STR the address of the new string into the first 8 bytes
//-------------------------------------------------------------------------------
// search:
// Parameter:
// X0 - Head of linked list
// X1 - String to search for
// Returns:
// Nothing, outputs search results
// 1. Set a counter = 1 (X21), and found_counter = 0 (X22)
// 2. X20 = traversal pointer = head
// 3. Check if list is empty and output/exit accordingly
// 4. Get address of data in current node (X0 - first 8 bytes of node)
// 5. Call the String_indexof_3
// a - if returns a valid value then add the X21 counter to the found list
// and increment found counter
// b - if not in the string then go to loop logic
// 6. Loop logic - Go to next node and check if reached the end
// 7. End of searching loop
// 8. Print the search summary line
// 9. Traverse the found list and call get_node on the line number given
// 10. Output the line anumber and dat enuber
//-------------------------------------------------------------------------------
// Save
// Traverse and write each to file
//-------------------------------------------------------------------------------
// Exit
// 1. Branch to the end of the program
//-------------------------------------------------------------------------------
// get_node:
// 1. Set X1 = index - 1
// 2. Set X2 = 0
// 3. Set traversal pointer (X0) = head
// 4. Check if list is empty and return if so
// 4. Compare if X2 = X1
// a - if = then exit
// b - if not then get next node and start loop again (X0 = second 8 bytes)
// but check if reached end of list
//-------------------------------------------------------------------------------
// trav_search:
// 1. Set a counter to 1
// 2. X20 = travPtr = head
// 3. Check if list is empty, and if so then exit
// 4. Get address of data in the current node
// 5. Call substring function
// a - If returns a valid value then add counter value to another list
// b - If not then go to loop logic
// 6. Go to next node and check that have not reached end of list
// 7. Once out of the loop traverse, traverse and output list returned
// - Get the count
// - Output the message
// - Get the index in the list and call get_node to get the node
// - Output the contents
//*******************************************************************************
.EQU SIZE, 30720 // Used for getstring when obtaining user input
// File Modes
.equ READONLY, 00
.equ WRITEONLY, 01
.equ READWRITE, 02
.equ CREATEWOT, 01101
.equ CREATEWOA, 02001
.equ CREATERW, 0102
.equ AT_FDCWD, -100
// File Perms
.equ RW_RW__, 0640
.data
// Menu Strings
szTE: .asciz "\n\t\tRASM4 TEXT EDITOR\n"
szMemCon: .asciz "\t Data Structure Heap Memory Consumption: "
szBytes: .asciz " bytes\n"
szNumNodes: .asciz "\t Number of Nodes: 0"
szOpt1: .asciz "\n<1> View all strings\n\n"
szOpt2: .asciz "<2> Add string\n"
szOpt2a: .asciz "\t<a> From Keyboard\n"
szOpt2b: .asciz "\t<b> From File. File name from user\n\n"
szOpt3: .asciz "<3> Delete string. Given am index #, delete the entire string and de-allocate memory (including the node)\n\n"
szOpt4: .asciz "<4> Edit string. Given and index #, replace old string w/ new string. Allocate/De-allocate as needed.\n\n"
szOpt5: .asciz "<5> String search. Regaurdless of case, return all strings that match the substring given.\n\n"
szOpt6: .asciz "<6> Save File. File name from user\n\n"
szOpt7: .asciz "<7> Quit\n\n"
// Input data
szIn1: .asciz "1" // check user input
szIn2a: .asciz "2a" // check user input
szIn2b: .asciz "2b" // check user input
szIn3: .asciz "3" // check user input
szIn4: .asciz "4" // check user input
szIn5: .asciz "5" // check user input
szIn6: .asciz "6" // check user input
szIn7: .asciz "7" // check user input
szLine: .asciz "Line "
szColon: .asciz ": "
headPtr: .quad 0
tailPtr: .quad 0
numOfNodes: .quad 0
dbHeapUsage: .quad 0
szInFilePrompt: .asciz "Enter input file name (name.txt): "
szOutFiPrompt: .asciz "Enter output file name (name.txt): "
szGetOpt: .asciz "Please select an option: "
szValidIn: .asciz "Please select a valid option: "
szSearchPrompt: .asciz "Enter a string to search for: "
szDelPromt: .asciz "Enter the line number to delete: "
szIndexPrompt: .asciz "Enter the line number to edit: "
szEditPrompt: .asciz "Enter the new string: "
szAddPrompt: .asciz "Enter the string to add: "
szEmpty: .asciz ""
szNewline: .asciz "\n"
szNodes: .skip 21
szHeapUsage: .skip 21
szConvert: .skip 104
szLineNum: .skip 21 // Store line num
szKbBuff: .skip 30720 // buffer for keyboard input
fileBuf: .skip 30720 // buffer for file input
chLF: .byte 0xa // Newline \n
chQt: .byte 0x22 // "
// File Locations
szOutFile: .skip 21
szInFile: .skip 21
.global _start
.text
_start:
//************************Called the menu to screen*******************************
Menu:
LDR X0,=szTE // point the address of the szTE to X0
BL putstring // a void external function that print
LDR X0,=szMemCon // poin the address of the szMemCon to X0
BL putstring // a void external function that print the
// c-sting of prompt
LDR X0, =numOfNodes // point address of numOfNodes to X0
LDR X0, [X0]
LDR X1, =szNodes // X1 - store converted value
BL int64asc // a function that will convert
LDR X0, =numOfNodes // X0 - numOfNodes
LDR X0, [X0] // X0 - number of nodes
MOV X1, #16 // X1 - 16 for 16 bytes a node
MUL X0, X0, X1 // X0 - heap usage
LDR X2, =dbHeapUsage // X2 - heap usage int
STR X0, [X2] // Update heap usage
LDR X0, =dbHeapUsage // var with value to convert
LDR X0, [X0]
LDR X1, =szHeapUsage // var to store conversion
BL int64asc // Convert to ascii
LDR X0, =szHeapUsage // Load heap usage to print
BL putstring // Print heap usage
// Output menu info
LDR X0,=szBytes // poin the address of the szBytes to X0
BL putstring // a void external function that print the
// c-sting of prompt
LDR X0,=szNumNodes // poin the address of szNumNodes to X0
BL putstring // a void external function that print the
// c-sting of prompt
// get the number of nodes
LDR X0,=szNodes // point address of numOfNodes to X0
BL putstring // a void external function that print
LDR X0,=szOpt1 // poin the address of the szOpt1 to X0
BL putstring // a void external function that print
LDR X0,=szOpt2 // poin the address of the szOpt2 to X0
BL putstring // a void external function that print
LDR X0,=szOpt2a // poin the address of the szOpt2a to X0
BL putstring // a void external function that print the
// c-sting of prompt
LDR X0,=szOpt2b // poin the address of the szOpt2b to X0
BL putstring // a void external function that print the
// c-sting of prompt
LDR X0,=szOpt3 // poin the address of the szOpt3 to X0
BL putstring // a void external function that print
LDR X0,=szOpt4 // poin the address of the szOpt4 to X0
BL putstring // a void external function that print the
LDR X0,=szOpt5 // poin the address of the szOpt5 to X0
BL putstring // a void external function that print the
LDR X0,=szOpt6 // poin the address of the szOpt6 to X0
BL putstring // a void external function that print the
LDR X0,=szOpt7 // poin the address of the szOpt7 to X0
BL putstring // a void external function that print the
//**********************Get user input and error checking*************************
LDR X0,=szGetOpt // poin the address of the szGetOpt to X0
BL putstring // a void external function that print the
getInput:
LDR X0, =szKbBuff // Load address of the szKbBuff to X0
MOV X1, #SIZE // Load max input size
BL getstring // a external function that get user input
// option 1
LDR X0,=szKbBuff // Load address of the szKbBuff to X0
LDR X1,=szIn1 // Load address of the szIn1 to X1
BL String_equalsIgnoreCase // compare the two strings
CMP X0,#1 // compara if the two string is equal
B.EQ View_String // if equal call View_String
// option 2a
LDR X0,=szKbBuff // Load address of the szKbBuff to X0
LDR X1,=szIn2a // Load address of the szIn2a to X1
BL String_equalsIgnoreCase // compare the two strings
CMP X0,#1 // compara if the two string is equal
B.EQ Add_KbString // if equal call Print_KbString
// option 2b
LDR X0,=szKbBuff // Load address of the szKbBuff to X0
LDR X1,=szIn2b // Load address of the szIn2b to X1
BL String_equalsIgnoreCase // compare the two strings
CMP X0,#1 // compara if the two string is equal
B.EQ Add_File // if equal call Print_File
// option 3
LDR X0,=szKbBuff // Load address of the szKbBuff to X0
LDR X1,=szIn3 // Load address of the szIn3 to X1
BL String_equalsIgnoreCase // compare the two strings
CMP X0,#1 // compara if the two string is equal
B.EQ Delete_String // if equal call Delete_String
// option 4
LDR X0,=szKbBuff // Load address of the szKbBuff to X0
LDR X1,=szIn4 // Load address of the szIn4 to X1
BL String_equalsIgnoreCase // compare the two strings
CMP X0,#1 // compara if the two string is equal
B.EQ edit_node // if equal call edit
// option 5
LDR X0,=szKbBuff // Load address of the szKbBuff to X0
LDR X1,=szIn5 // Load address of the szIn5 to X1
BL String_equalsIgnoreCase // compare the two strings
CMP X0,#1 // compara if the two string is equal
B.EQ search // if equal call search
// option 6
LDR X0,=szKbBuff // Load address of the szKbBuff to X0
LDR X1,=szIn6 // Load address of the szIn6 to X1
BL String_equalsIgnoreCase // compare the two strings
CMP X0,#1 // compara if the two string is equal
B.EQ save // if equal call save
// option 7
LDR X0,=szKbBuff // Load address of the szKbBuff to X0
LDR X1,=szIn7 // Load address of the szIn7 to X1
BL String_equalsIgnoreCase // compare the two strings
CMP X0,#1 // compara if the two string is equal
B.EQ exit // if equal call exit
// if the user has enter a invalid input
LDR X0,=szValidIn // Load address of the szValidIn to X0
BL putstring // a void external function that print the
B getInput // branch to get the user input agin
LDR X0,=chLF // Load address of the chLF to X0
BL putch // output string
//******************************View all the string*******************************
View_String:
LDR X0,=headPtr // poin the address of headPtr to X0
BL traverse_print // Traverse through and print
B Menu // Go to the menu
//******************************adding form keyboard******************************
Add_KbString:
// Prompt for the stirng
LDR X0, =szAddPrompt // Load prompt to print
BL putstring // print prompt
LDR X0, =szKbBuff // Load address of the szKbBuff to X0
MOV X1, #SIZE // Load max input size
BL getstring // a external function that get user input
LDR X0, =szKbBuff // X0 - input
BL String_Length // Get the length of the input
MOV X1, 0xa // X1 - newline
LDR X2, =szKbBuff // X2 - input
STR X1, [X2, X0] // Add newline to input
LDR X0, =szKbBuff // X0 - input for sttr copy
BL String_copy // X0 - allocate string
MOV X20, X0 // Save allocated mem address
LDR X1, =headPtr // X1 - head
LDR X2, =tailPtr // X2 - tail
BL add_node // Add node to linked list
MOV X0, X20 // X0 - allocated mem
BL free // Free the allocated mem
B Menu // Go to the menu
//****************************adding string list form file************************
Add_File:
// Prompt the user for a file name
LDR X0, =szInFilePrompt // Load prompt to print
BL putstring // print prompt
LDR X0, =szKbBuff // Load address of the szKbBuff to X0
MOV X1, #SIZE // Load max input size
BL getstring // Get input
//***************open file*******************
MOV X0, #AT_FDCWD // load directory
MOV X8, #56 // OpenAt
LDR X1, =szKbBuff // file name
MOV X2, #READONLY // flags
MOV X3, #RW_RW__ // file permissions
SVC 0 // service call
// X0 = fd (return value)
MOV X20, X0 // Save for the close file later
STR X20, [SP, #-16]! // Push fd
// Read File
MOV X0, X20 // X0 - fd
MOV X2, #30720 // File input buffer size
LDR X1, =szKbBuff // X1 - input buffer
MOV X8, #63 // READ
SVC 0 // Service call
// Loop initializations
MOV X20, X0 // X20 - length of input
MOV X22, #0 // X22 - loop counter
MOV X23, #0 // X23 - insert index (for str)
read_loop:
LDR X2, =szKbBuff // X2 = file input
LDRB W0, [X2, X22] // Get one byte of the input
CMP W0, 0xa // Check if end of line
B.EQ convert // If end of line then create a node
LDR X1, =szConvert // X1 - hold the string to be made node
STR X0, [X1, X23] // Store the loaded byte
ADD X23, X23, #1 // Increment to updated pos
read_logic:
ADD X22, X22, #1 // Increment loop counter
CMP X22, X20 // Check if processed all of input
B.LT read_loop // If less than then keep looping
B read_end // If processed all then end
convert:
LDR X1, =szConvert // X1 - hold the string to be made node
MOV X0, 0xa
STR X0, [X1, X23] // Store the loaded byte
ADD X23, X23, #1 // Increment to updated pos
LDR X1, =szConvert
MOV X0, 0x00
STR X0, [X1, X23]
MOV X23, #0 // Restore storing index
LDR X0, =szConvert // X0 - one line from file
LDR X1, =headPtr // X1 - head
LDR X2, =tailPtr // X2 - tail
BL add_node // Add node to linked list
MOV X1, 0x00 // Load an empty string
LDR X2, =szConvert // Load the dummy string
STR X1, [X2] // Clear dummy string
STR X1, [X2, #8] // Clear dummy string
STR X1, [X2, #16] // Clear dummy string
STR X1, [X2, #24] // Clear dummy string
STR X1, [X2, #32] // Clear dummy string
STR X1, [X2, #40] // Clear dummy string
STR X1, [X2, #48] // Clear dummy string
STR X1, [X2, #56] // Clear dummy string
STR X1, [X2, #64] // Clear dummy string
STR X1, [X2, #72] // Clear dummy string
STR X1, [X2, #80] // Clear dummy string
STR X1, [X2, #88] // Clear dummy string
STR X1, [X2, #96] // Clear dummy string
B read_logic // Branch to loop logic
read_end:
LDR X0, [SP], #16 // X0 - fd
MOV X8, #57 // CLOSE
SVC 0 // Service call
B Menu
//*********************************Delete a string********************************
Delete_String:
LDR X11, =numOfNodes // X11 - numOfNodes
LDR X12, [X11] // X12 - # of nodes
SUB X12, X12, #1 // Num of nodes + 1
STR X12, [X11] // Update numOfNodes
LDR X0,=szDelPromt // load the promt to print
BL putstring // Print prompt
LDR X0, =szKbBuff // Load address of the szKbBuff to X0
MOV X1, #SIZE // Load max input size
BL getstring // a external function that get user input
LDR X0, =szKbBuff // Load input to convert to int
BL ascint64 // Convert to int
MOV X20, X0 // Save for later
MOV X1, X0 // X1 - index to get
LDR X0, =headPtr // X0 - head
BL get_node // X0 - current node
MOV X21, X0 // Save address for later
LDR X1, =headPtr // X1 - head
LDR X1, [X1] // X1 - addr of 1st node
CMP X0, X1 // Chcek if deleting first node
B.EQ delete_head // Special case delete head
SUB X1, X20, #1 // Previous node is index - 1
LDR X0, =headPtr // X0 - head
BL get_node // Get previous node
MOV X23, X0 // Save for later
LDR X3, [X21, #8] // X3 - Next of current node
STR X3, [X0, #8] // Update prev node's next
LDR X1, =tailPtr // X1 - tail
LDR X1, [X1] // X1 - addr of tail
CMP X21, X1 // Check if deleting tail
B.NE delete_free // Special case delete tail
LDR X24, =tailPtr // X4 - tail
STR X23, [X24] // Tail = prev
delete_free:
LDR X0, [X21] // X0 - address of data
BL free // Free data
MOV X0, X21 // X0 - address of node
BL free // free node
B Menu // Return to menu
delete_head:
// Get the next and set head to that
LDR X3, [X21, #8] // Get next address
LDR X1, =headPtr // X1 - head
STR X3, [X1] // head = next node
B delete_free
//**********************************Edit a string*********************************
edit_node:
LDR X0, =szIndexPrompt // Load index prompt to print
BL putstring // Print prompt
LDR X0, =szKbBuff // Load address of the szKbBuff to X0
MOV X1, #SIZE // Load max input size
BL getstring // a external function that get user input
LDR X0, =szKbBuff // Load input to convert to int
BL ascint64 // Convert to int
MOV X1, X0 // X1 - index to get
LDR X0, =headPtr // X0 - head
BL get_node
STR X0, [SP, #-16]! // Push X0 - address of node
LDR X0, [X0] // X0 - address of current data
BL free // Free that mem
LDR X0, =szEditPrompt // Load edit prompt to print
BL putstring // Print prompt
LDR X0, =szKbBuff // Load address of the szKbBuff to X0
MOV X1, #SIZE // Load max input size
BL getstring // a external function that get user input
LDR X0, =szKbBuff // X0 - input
LDR X1, =szNewline // X1 - newline
BL String_concat // X0 - allocate string
LDR X1, [SP], #16 // Pop X1 - address of node
STR X0, [X1] // Store the new string
B Menu // Go to menu
//********************************Search for a string*****************************
search:
LDR X0, =szSearchPrompt // Load prompt to print
BL putstring // Print search prompt
LDR X0, =szKbBuff // Load address of the szKbBuff to X0
MOV X1, #SIZE // Load max input size
BL getstring // a external function that get user input
LDR X0, =headPtr // X0 - headprt
LDR X1, =szKbBuff // X1 - buffer with input
BL trav_search // Call traverse and search
B Menu // Go to menu
//********************************Save to output file*****************************
save:
// Prompt the user for a file name
LDR X0, =szOutFiPrompt // Load prompt to print
BL putstring // print prompt
LDR X0, =szKbBuff // Load address of the szKbBuff to X0
MOV X1, #SIZE // Load max input size
BL getstring // Get input
// Open file
MOV X0, #AT_FDCWD // dfd for openat
MOV X8, #56 // OPENAT
LDR X1, =szKbBuff // file name
MOV X2, #CREATEWOT // flags
MOV X3, RW_RW__ // mode
SVC 0 // service call
// X0 = fd (return val)
MOV X20, X0 // Save for the close later
// Traverse and write to file
LDR X0, =headPtr // X0 - head
LDR X21, [X0] // X20 = travPtr = head
CMP X20, #0 // Check if list is empty
B.eq end_save // If empty then done
write_loop:
LDR X0, [X21] // address of data in node
MOV X22, X0 // Save address for later
BL String_Length // Get length of string
MOV X2, X0 // X2 - length of message to write
MOV X1, X22 // X1 - message to write
MOV X0, X20 // X0 - fd
MOV X8, #64 // WRITE
SVC 0 // Service call
LDR X21, [X21, #8] // Get address of next node
CMP X21, #0 // Check is equals null (end of list)
B.EQ end_save // If end then finished saving
B write_loop // If not then start loop over
end_save:
// Close file
MOV X0, X20 // X0 = fd
MOV X8, #57 // CLOSE
SVC 0 // Service call
B Menu // Go to menu
//********************************Get a specified node****************************
// X0 - headPtr
// X1 - index to get to
get_node:
SUB X1, X1, #1 // X1 = index - 1 (to account for 0)
MOV X2, #0 // X2 = counter = 0
LDR X0, [X0] // X0 = travPtr = head
CMP X0, #0 // Check for empty list
B.EQ found_node // If empty then done
get_start:
CMP X2, X1 // Check if X2 = X1 (reached node)
B.EQ found_node // Finish if found
ADD X2, X2, #1 // Increment counter
LDR X0, [X0, #8] // Get address of next node
CMP X0, #0 // Check if equals null (end trav)
B.EQ found_node // Reached end of list without finding
B get_start // Start loop again
found_node:
RET // Return to caller
//********************************Traverse and Search*****************************
// X0 - headPtr
// X1 - string to search for
trav_search:
// Preserve link register
STR LR, [SP, #-16]! // Push LR
STR X0, [SP, #-16]! // Push X0 - head ptr
// Copy search stirng and convert to lower
MOV X0, X1 // X0 - string to search for
BL String_copy // Copy string
MOV X22, X0 // Save address for later
BL String_toUpperCase // Convert to lowercase
MOV X21, #1 // Counter = 1 (line/string 1)
LDR X0, [SP], #16 // Pop X0 - head ptr
STR X22, [SP, #-16]! // Push allocated mem address
LDR X20, [X0] // X20 = travPtr = head
CMP X20, #0 // Check if list is empty
B.EQ end_trav // If empty end the traversal
trav_start:
LDR X0, [X20] // X0 - string to search (data of node)
MOV X23, X0 // Save address of string data
BL String_copy // Copy string
MOV X24, X0
BL String_toUpperCase // Convert to lowercase
MOV X1, X22 // X1 - what to search for (passed in)
BL String_lastIndexOf_3 // Check to see if string is found
STR X0, [SP, #-16]! // Push index of results
MOV X0, X24 // Addr of duplicate to lower string
BL free // Free the mem
LDR X0, [SP], #16 // Pop X0 - index of results
CMP X0, #-1 // If = -1 then not found
B.NE found // If != -1 then found so add and cont
loop_logic:
ADD X21, X21, #1 // Increment the current line
LDR X20, [X20, #8] // Get address of next node
CMP X20, #0 // Check if equals null, end trav
B.EQ end_trav // If reached end then end traversal
B trav_start // Start loop again if not at end
found:
LDR X0, =szLine // Load "Line" to print
BL putstring // Print Line
MOV X0, X21 // X0 = line num
LDR X1, =szLineNum // To store ascii line
BL int64asc // Convert to ascii
LDR X0, =szLineNum // Load LineNum to print
BL putstring // Print lineNum
LDR X0, =szColon // Load ": " to print
BL putstring // Print colon
MOV X0, X23 // X0 = data to print
BL putstring // Print found string
B loop_logic // Return to loop
end_trav:
LDR X0, [SP], #16 // Pop mem addr
BL free // Free the mem
LDR LR, [SP], #16 // Pop LR
RET // Return to caller
//*********************************add_node***********************************
add_node:
// Preserve link register
STR LR, [SP, #-16]! // Push LR
// Preserve registers 19-30 for AAPCS
STR X19, [SP, #-16]! // Push
STR X20, [SP, #-16]! // Push
STR X21, [SP, #-16]! // Push
STR X22, [SP, #-16]! // Push
STR X23, [SP, #-16]! // Push
STR X24, [SP, #-16]! // Push
STR X25, [SP, #-16]! // Push
STR X26, [SP, #-16]! // Push
STR X27, [SP, #-16]! // Push
STR X28, [SP, #-16]! // Push
STR X29, [SP, #-16]! // Push
STR X30, [SP, #-16]! // Push
LDR X11, =numOfNodes // X11 - numOfNodes
LDR X12, [X11] // X12 - # of nodes
ADD X12, X12, #1 // Num of nodes + 1
STR X12, [X11] // Update numOfNodes
// Save reg 1, 2 (parameters that will be lost in next function)
STR X1, [SP, #-16]! // Push head
STR X2, [SP, #-16]! // Push tail
// Copy string and get the address of the allocated mem
BL String_copy // X0 = address of allocated space
// Create a node that stores the string and points to null
B create_node // Create a node
end_create:
// Unload the head, tail, and size for the insertion
LDR X2, [SP], #16 // Pop tail
LDR X1, [SP], #16 // Pop head
LDR X3, [X1] // X3 = head
CMP X3, #0 // If head = 0 then list is empty
B.NE insert_node // If not empty then add like normal
// If empty then to insert just set the head and tail equal to new node
STR X0, [X1] // head = new node
STR X0, [X2] // tail = new node
end_insert:
LDR X30, [SP], #16 // Pop
LDR X29, [SP], #16 // Pop
LDR X28, [SP], #16 // Pop
LDR X27, [SP], #16 // Pop
LDR X26, [SP], #16 // Pop
LDR X25, [SP], #16 // Pop
LDR X24, [SP], #16 // Pop
LDR X23, [SP], #16 // Pop
LDR X22, [SP], #16 // Pop
LDR X21, [SP], #16 // Pop
LDR X20, [SP], #16 // Pop
LDR X19, [SP], #16 // Pop
LDR LR, [SP], #16 // Pop LR
RET // Return to caller
create_node:
STR X1, [SP, #-16]! // Push head
STR X2, [SP, #-16]! // Push tail
STR X0, [SP, #-16]! // Push string address
MOV X0, #16 // Allocate 16 bytes
BL malloc // X0 is holding the address of newnode
LDR X1, [SP], #16 // Pop string address
STR X1, [X0] // Set node to have the data address
MOV X1, #0 // Set upper 8 bytes to 0
STR X1, [X0, #8] // Next node address = 0 since new tail
LDR X2, [SP], #16 // Pop head
LDR X1, [SP], #16 // Pop tail
B end_create // Return back to main flow
insert_node:
LDR X3, [X2] // X3 = address of last node of list
STR X0, [X3, #8] // last node pointer = new node
STR X0, [X2] // tail = new node
B end_insert // Return back to main flow
//******************************************************************************
//*****************************traverse_print********************************
traverse_print:
// Preserve link register
STR LR, [SP, #-16]! // Push LR
LDR X20, [X0] // X20 = travPtr = head
CMP X20, #0 // Check if list is empty
B.eq end_traverse // If so exit since nothing to print
MOV X22, #1 // Line counter
loop_start:
LDR X0, =szLine // Load "Line" to print
BL putstring // Print Line
MOV X0, X22 // X0 = line num
LDR X1, =szLineNum // To store ascii line
BL int64asc // Convert to ascii
LDR X0, =szLineNum // Load LineNum to print
BL putstring // Print lineNum
LDR X0, =szColon // Load ": " to print
BL putstring // Print colon
LDR X0, [X20] // X0 = address of data in node
BL putstring // Print the string
// LDR X0, =chLF // Load newline to print
// BL putch // Print newlinw
ADD X22, X22, #1 // Increment line
LDR X21, [X20, #8] // Get address of nex node
CMP X21, #0 // Check if equals null (end of trav)
B.EQ end_traverse // If done then go to end of function
LDR X20, [X20, #8] // X20 = address of next node
B loop_start // Start printing loop again
end_traverse:
LDR LR, [SP], #16 // Pop LR
RET // Return to caller
//****************************************************************************
//*********************************End the program********************************
exit:
LDR X1, =headPtr // X1 - head
LDR X1, [X1] // X1 - addr of 1st node
MOV X21, X1
CMP X1, #0 // If equal then nothing to delete
B.EQ done_delete // Done deleting
// Get the next and set head to that
LDR X3, [X21, #8] // Get next address
LDR X1, =headPtr // X1 - head
STR X3, [X1] // head = next node
LDR X0, [X21] // X0 - address of data
BL free // Free data
MOV X0, X21 // X0 - address of node
BL free // free node
B exit
done_delete:
// Set up parameters to exit and call linux
MOV X0, #0 // Use 0 for return code
MOV X8, #93 // Service command code #93 to terminate program
SVC 0 // Call linux to terminate
.end