From a5136d917bfafaf18d8f8f6b9aee925981a52ef4 Mon Sep 17 00:00:00 2001 From: Josh Ashton Date: Mon, 9 Oct 2023 19:40:47 -0600 Subject: [PATCH] basic reading functionality added, need to complete parsing implementation --- src/test/Fibonacci.asm | 53 +++++++++++++ src/test/testFormats.c | 124 ++++++++++++++++++++++------- src/test/testParse.c | 20 +++++ src/util/formats.h | 172 ++++++++++++++++++++++++++++++++--------- src/util/functions.h | 17 +--- src/util/parse.h | 59 ++++++++++++++ 6 files changed, 369 insertions(+), 76 deletions(-) create mode 100644 src/test/Fibonacci.asm create mode 100644 src/test/testParse.c create mode 100644 src/util/parse.h diff --git a/src/test/Fibonacci.asm b/src/test/Fibonacci.asm new file mode 100644 index 0000000..470e5ee --- /dev/null +++ b/src/test/Fibonacci.asm @@ -0,0 +1,53 @@ +.data + welcomeMessage: .asciiz "Welcome to a MIPS assembly Fibonacci Sequence calculator!\nThis will calculate the nth term of the Fibonacci Sequence.\n" + prompt: .asciiz "Enter a number (n, input n > 2) to find the nth term:" + foundTerm: .asciiz "The nth term is: " + +.text + +main: + li $v0, 4 # syscall 4 is to print a string + la $a0, welcomeMessage # store the ascii string in register a0 + syscall # print + + jal getInput # get the user input + + jal fibonacci # calculate the nth fibonacci term + move $a0, $v0 # move the returned term to register a0 + li $v0, 1 # syscall 1 is to print an int + syscall # print + + ori $v0, $0, 10 # system call code 10 for exit + syscall # exit the program + +getInput: + li $v0, 4 # syscall 4 is to print a string + la $a0, prompt # store the ascii string in register a0 + syscall # print + + li $v0, 5 # syscall 5 is for reading an int + syscall # read an int from the user + move $a0, $v0 # load input into register a0 + + jr $ra # return to caller + +fibonacci: + move $s1, $a0 # Copy the nth term + li $t0, 2 # Counter + li $t1, 0 # Prev value + li $t2, 1 # Current value + li $t3, 0 # Next value + + while: + bge $t0, $s1, done # While the counter is less than n + add $t3, $t1, $t2 # Sum the previous and current values and save in register t3 + move $t1, $t2 # Shift current value to previous value + + move $t2, $t3 # Shift next value to current value + addi $t0, $t0, 1 # Increment counter + + b while # Jump back to start of while loop + + done: + move $v0, $t2 # Move current value to register v0 + jr $ra # Return to caller diff --git a/src/test/testFormats.c b/src/test/testFormats.c index ab97cda..ba272d5 100644 --- a/src/test/testFormats.c +++ b/src/test/testFormats.c @@ -1,9 +1,16 @@ +#include #include #include #include #include "../util/formats.h" +int compareIntArray(int * x, int * y, int size) { + for(int i = 0; i < size; i++) + if(x[i] != y[i]) return 0; + return 1; +} + int test_binaryToHex() { return 1; // TODO } @@ -14,10 +21,7 @@ int test_toBinary_0_size5() { int * binary = toBinary(0, size); int expectedOutput[] = { 0, 0, 0, 0, 0 }; - int cmp = 1; - for(int i = 0; i < size; i++) - if(binary[i] != expectedOutput[i]) cmp = 0; - + int cmp = compareIntArray(binary, expectedOutput, size); free(binary); return cmp; } @@ -28,10 +32,7 @@ int test_toBinary_0_size6() { int * binary = toBinary(0, size); int expectedOutput[] = { 0, 0, 0, 0, 0, 0 }; - int cmp = 1; - for(int i = 0; i < size; i++) - if(binary[i] != expectedOutput[i]) cmp = 0; - + int cmp = compareIntArray(binary, expectedOutput, size); free(binary); return cmp; } @@ -42,10 +43,7 @@ int test_toBinary_10_size6() { int * binary = toBinary(10, size); int expectedOutput[] = { 0, 0, 1, 0, 1, 0 }; - int cmp = 1; - for(int i = 0; i < size; i++) - if(binary[i] != expectedOutput[i]) cmp = 0; - + int cmp = compareIntArray(binary, expectedOutput, size); free(binary); return cmp; } @@ -56,10 +54,7 @@ int test_toBinary_20_size6() { int * binary = toBinary(20, size); int expectedOutput[] = { 0, 1, 0, 1, 0, 0 }; - int cmp = 1; - for(int i = 0; i < size; i++) - if(binary[i] != expectedOutput[i]) cmp = 0; - + int cmp = compareIntArray(binary, expectedOutput, size); free(binary); return cmp; } @@ -70,17 +65,81 @@ int test_toBinary_17_size16() { int * binary = toBinary(17, size); int expectedOutput[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1}; - int cmp = 1; - for(int i = 0; i < size; i++) - if(binary[i] != expectedOutput[i]) cmp = 0; - + int cmp = compareIntArray(binary, expectedOutput, size); free(binary); return cmp; } -int test_rToBinary() { +int test_rToBinary_sll() { r* rFormat = malloc(sizeof(r)); - return 1; // TODO + rFormat->opcode = 0; // Opcode for sll instruction + rFormat->rs = 0; // Register 17. + rFormat->rt = 16; // Register 18. + rFormat->rd = 14; // Register 13. + rFormat->shamt = 2; // Shift amount + rFormat->funct = 0; // Hexadecimal 00, or 0000 0000. + + int * binary = rToBinary(rFormat); + int expectedOutput[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }; + + int cmp = compareIntArray(binary, expectedOutput, 32); + free(binary); + + return cmp; +} + +int test_rToBinary_add() { + r* rFormat = malloc(sizeof(r)); + rFormat->opcode = 0; // Opcode for add instruction + rFormat->rs = 17; // Register 17. + rFormat->rt = 18; // Register 18. + rFormat->rd = 13; // Register 13. + rFormat->shamt = 0; // Shift amount is 0 + rFormat->funct = 32; // Hexadecimal 20, or 0010 0000. + + int * binary = rToBinary(rFormat); + int expectedOutput[] = { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }; + + int cmp = compareIntArray(binary, expectedOutput, 32); + free(binary); + + return cmp; +} + +int test_rToHex_add() { + r* rFormat = malloc(sizeof(r)); + rFormat->opcode = 0; // Opcode for add instruction + rFormat->rs = 17; // Register 17. + rFormat->rt = 18; // Register 18. + rFormat->rd = 13; // Register 13. + rFormat->shamt = 0; // Shift amount is 0 + rFormat->funct = 32; // Hexadecimal 20, or 0010 0000. + + char * hex = rToHex(rFormat); + char * expectedHex = "02326820"; + int cmp = strcmp(hex, expectedHex); + free(hex); + + if(cmp < 0 || cmp > 0) return 0; + else return 1; +} + +int test_rToHex_sll() { + r* rFormat = malloc(sizeof(r)); + rFormat->opcode = 0; // Opcode for sll instruction + rFormat->rs = 0; // Register 17. + rFormat->rt = 16; // Register 18. + rFormat->rd = 14; // Register 13. + rFormat->shamt = 2; // Shift amount + rFormat->funct = 0; // Hexadecimal 00, or 0000 0000. + + char * hex = rToHex(rFormat); + char * expectedHex = "00107080"; + int cmp = strcmp(hex, expectedHex); + free(hex); + + if(cmp < 0 || cmp > 0) return 0; + else return 1; } int test_iToHex() { @@ -89,11 +148,20 @@ int test_iToHex() { } int main() { - printf("\nTesting formats.h functionality.\n"); + printf("\nTesting formats.h functionality. 1 = pass, 0 = fail\n"); - printf("\ntoBinary_0_size5: %d\n", test_toBinary_0_size5()); - printf("\ntoBinary_0_size6: %d\n", test_toBinary_0_size6()); - printf("\ntoBinary_10_size6: %d\n", test_toBinary_10_size6()); - printf("\ntoBinary_20_size6: %d\n", test_toBinary_20_size6()); - printf("\ntoBinary_17_size16: %d\n", test_toBinary_17_size16()); + printf("\nTesting number to binary (with formatted size):\n"); + printf("toBinary_0_size5: %d\n", test_toBinary_0_size5()); + printf("toBinary_0_size6: %d\n", test_toBinary_0_size6()); + printf("toBinary_10_size6: %d\n", test_toBinary_10_size6()); + printf("toBinary_20_size6: %d\n", test_toBinary_20_size6()); + printf("toBinary_17_size16: %d\n", test_toBinary_17_size16()); + + printf("\nTesting R Format to Binary:\n"); + printf("rToBinary_add: %d\n", test_rToBinary_add()); + printf("rToBinary_sll: %d\n", test_rToBinary_sll()); + + printf("\nTesting R Format to Hex:\n"); + printf("rToHex_add: %d\n", test_rToHex_add()); + printf("rToHex_sll: %d\n", test_rToHex_sll()); } diff --git a/src/test/testParse.c b/src/test/testParse.c new file mode 100644 index 0000000..f58f127 --- /dev/null +++ b/src/test/testParse.c @@ -0,0 +1,20 @@ +#include +#include +#include + +#include "../util/parse.h" + +char * filepath; + +int test_readFile() { + initParse(filepath); + return 1; +} + +int main() { + // filepath may be a relative or an absolute filepath + //filepath = "/home/jashton/dev/mipsToHex/src/test/Fibonacci.asm"; + filepath = "Fibonacci.asm"; + + return test_readFile(); +} diff --git a/src/util/formats.h b/src/util/formats.h index e0dfe70..33d04d7 100644 --- a/src/util/formats.h +++ b/src/util/formats.h @@ -1,9 +1,93 @@ +#include #include #include +#include + +// Represents the R instruction format. +typedef struct r { + int opcode; // 6 bits + int opcode_size; + int rs; // 5 bits + int rs_size; + int rt; // 5 bits + int rt_size; + int rd; // 5 bits + int rd_size; + int shamt; // 5 bits + int shamt_size; + int funct; // 6 bits + int functHex_size; +} r; + +// Represents the I instruction format. +typedef struct i { + int opcode; // 6 bits + int rs; // 4 bits + int rt; // 4 bits + int immediate; // 16 bits +} i; + +// Represents the J instruction format. +typedef struct j { + int opcode; // 6 bits + int address; // 26 bits +} j; + +char subBinaryToHex(int * bin) { + int sum = 0; + for(int i = 0; i < 4; i++) { + switch (i) { + case 0: + if(bin[i] == 1) sum += 8; + break; + case 1: + if(bin[i] == 1) sum += 4; + break; + case 2: + if(bin[i] == 1) sum += 2; + break; + case 3: + if(bin[i] == 1) sum += 1; + break; + }; + } + + if(sum < 10) return sum + '0'; + else { + switch (sum) { + case 10: + return 'A'; + case 11: + return 'B'; + case 12: + return 'C'; + case 13: + return 'D'; + case 14: + return 'E'; + case 15: + return 'F'; + default: + return 'G'; + }; + } +} // Utility function to convert any given binary instruction into hexadecimal. -char* binaryToHex(char* bin) { - return "0x00000000"; +// Expected input is an int array containing 32 bits. +char* binaryToHex(int * bin) { + char * hex = (char *)calloc(8, sizeof(char)); + + int j = 0; + for(int i = 0; i < 8; i++) { + int * tmp[4]; + int c = j + 4; + for(; j < c; j++) tmp[j % 4] = &bin[j]; + + hex[i] = subBinaryToHex(* tmp); + } + + return hex; } // Utility function to convert a number to binary @@ -29,43 +113,61 @@ int* toBinary(int num, int size) { return bin; } -// Represents the R instruction format. -typedef struct r { - int opcode; // 6 bits - int opcode_size; - int rs; // 5 bits - int rs_size; - int rt; // 5 bits - int rt_size; - int rd; // 5 bits - int rd_size; - int shamt; // 5 bits - int shamt_size; - char* functHex; // 6 bits - int functHex_size; -} r; - -char* rToBinary(r* format) { - char binary[32]; - - return binary; +// Utility function to copy an existing array into a destination array, starting at a specified index of the existing array. +// This allows for multiple existing arrays to be added in sequence to a destination array. +void fillArray(int * destArray, int * arrayToAdd, int startIndex, int destArraySize) { + int j = 0; + for(int i = startIndex; i < destArraySize; i++) { + destArray[i] = arrayToAdd[j]; + j++; + } } -// Represents the I instruction format. -typedef struct i { - int opcode; // 6 bits - int rs; // 4 bits - int rt; // 4 bits - int immediate; // 16 bits -} i; +int * rToBinary(r* format) { + int size = 32; // R-Format instructions when decoded into their bit strings are 32 bits. + + // Dynamically allows for different sized arrays. Need to manually release from memory. + int * bin = (int*)calloc(size, sizeof(int)); + + // Fill up the array with default values. + for(int i = 0; i < size; i++) + bin[i] = 0; + + // Create the binary form of the field, fill the instruction array with those values, and once complete, free from memory the original array. + + int * opcode = toBinary(format->opcode, 6); + fillArray(bin, opcode, 0, size); + free(opcode); + + int * rs = toBinary(format->rs, 5); + fillArray(bin, rs, 6, size); + free(rs); + + int * rt = toBinary(format->rt, 5); + fillArray(bin, rt, 11, size); + free(rt); + + int * rd = toBinary(format->rd, 5); + fillArray(bin, rd, 16, size); + free(rd); + + int * shamt = toBinary(format->shamt, 5); + fillArray(bin, shamt, 21, size); + free(shamt); + + int * funct = toBinary(format->funct, 6); + fillArray(bin, funct, 26, size); + free(funct); + + return bin; +} + +char * rToHex(r* format) { + int * bin = rToBinary(format); + return binaryToHex(bin); +} // Utility function to convert any given I instruction into hexadecimal. char* iToHex(i* format) { return ""; } - -// Represents the J instruction format. -typedef struct j { - int opcode; // 6 bits - int address; // 26 bits -} j; diff --git a/src/util/functions.h b/src/util/functions.h index 15de0f4..9ea0944 100644 --- a/src/util/functions.h +++ b/src/util/functions.h @@ -10,33 +10,24 @@ void initFunctions() { iFormat = (i*)malloc(sizeof(i)); } -char* add(int * args[]) { +int * add(int * args[]) { rFormat->opcode = 0; rFormat->rd = *args[0]; rFormat->rs = *args[1]; rFormat->rt = *args[2]; rFormat->shamt = *args[4]; - rFormat->functHex = "0x20"; + rFormat->funct = 20; return rToBinary(rFormat); } -char* addi(int * args[]) { - rFormat->opcode = 0; - rFormat->rs = *args[0]; - rFormat->rt = *args[1]; - rFormat->functHex = "0x8"; - - return rToBinary(rFormat); -} - -char* sub(int * args[]) { +int * sub(int * args[]) { rFormat->opcode = 0; rFormat->rd = *args[0]; rFormat->rs = *args[1]; rFormat->rt = *args[2]; rFormat->shamt = *args[4]; - rFormat->functHex = "0x22"; + rFormat->funct = 22; return rToBinary(rFormat); } diff --git a/src/util/parse.h b/src/util/parse.h new file mode 100644 index 0000000..f62932c --- /dev/null +++ b/src/util/parse.h @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include + +FILE * file; + +char * removeCommentsAndWhiteSpace(char * line) { + int j = 0; + char * newLine; + for(int i = 0; i < strlen(line); i++) { + // If we've reached a comment, we can break to return what we have + if(line[i] == '#') break; + + // Remove commas and spaces. + if((line[i] != ',') && (isspace(line[i]) == 0)) { + newLine[j] = line[i]; + j++; + } + } + + // Remove any excess that is stored from a prior line. + for(; j < strlen(line); j++) + newLine[j] = (char)NULL; + + return newLine; +} + +char * parse(char * bareLine) { + char * function; + for(int i = 0; i < strlen(bareLine); i++) { + + } + + return function; +} + +int initParse(char * filepath) { + // Open and read a file. + file = fopen(filepath, "r"); + + // Maximum number of characters in a line is 1024. + char lines[1024]; + + // Catch if the file does not exist/cannot be opened. + if(file == NULL) { + printf("%s cannot be opened.\n", filepath); + return 0; + } + + // Get each line of the file. + while(fgets(lines, sizeof(lines), file)) + printf("%s\n", parse(removeCommentsAndWhiteSpace(lines))); + + fclose(file); + + return 1; +}