moving to nested linked list structure for instructions and arguments. this should allow for better dynamism between instructions and clearer organizational logic.

This commit is contained in:
Josh Ashton
2023-10-12 17:11:55 -06:00
parent 1c2ce3e971
commit 233c1ba1d9
11 changed files with 472 additions and 200 deletions
+1 -1
View File
@@ -3,7 +3,7 @@
#include <string.h>
#include "util/registers.h"
#include "util/functions.h"
#include "util/functions.c"
int help() {
printf(
+1 -1
View File
@@ -3,7 +3,7 @@
#include <stdlib.h>
#include <string.h>
#include "../util/formats.h"
#include "../util/formats.c"
int compareIntArray(int * x, int * y, int size) {
for(int i = 0; i < size; i++)
+1 -1
View File
@@ -2,7 +2,7 @@
#include <stdlib.h>
#include <string.h>
#include "../util/parse.h"
#include "../util/parse.c"
char * filepath;
+175
View File
@@ -0,0 +1,175 @@
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "formats.h"
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.
// 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
int * toBinary(int num, int size) {
// 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;
if(num == 0) return bin;
// Since the binary values are calculated in reverse order, entering the values into the array
// in reverse order will negate this, and leave us with an array in the correct order.
int i = size - 1;
while(num > 0) {
bin[i] = num % 2;
num = num / 2;
i--;
}
return bin;
}
// 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++;
}
}
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;
}
int * iToBinary(i* 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 * immediate = toBinary(format->immediate, 16);
fillArray(bin, immediate, 16, size);
free(immediate);
return bin;
}
char * rToHex(r* format) {
return binaryToHex(rToBinary(format));
}
// Utility function to convert any given I instruction into hexadecimal.
char* iToHex(i* format) {
return binaryToHex(iToBinary(format));
}
-143
View File
@@ -1,8 +1,3 @@
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// Represents the R instruction format.
typedef struct r {
int opcode; // 6 bits
@@ -33,141 +28,3 @@ typedef struct j {
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.
// 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
int* toBinary(int num, int size) {
// 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;
if(num == 0) return bin;
// Since the binary values are calculated in reverse order, entering the values into the array
// in reverse order will negate this, and leave us with an array in the correct order.
int i = size - 1;
while(num > 0) {
bin[i] = num % 2;
num = num / 2;
i--;
}
return bin;
}
// 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++;
}
}
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 "";
}
+14
View File
@@ -1,6 +1,20 @@
#define FOREACH_FUNCTION(FUNCTION) \
FUNCTION(add) \
FUNCTION(jr) \
FUNCTION(syscall) \
FUNCTION(li) \
FUNCTION(addu) \
FUNCTION(and) \
FUNCTION(nor) \
FUNCTION(or) \
FUNCTION(slt) \
FUNCTION(sltu) \
FUNCTION(sll) \
FUNCTION(srl) \
FUNCTION(sub) \
FUNCTION(subu) \
FUNCTION(addi) \
FUNCTION(jal) \
#define GENERATE_ENUM(ENUM) ENUM,
#define GENERATE_STRING(STRING) #STRING,
+197
View File
@@ -0,0 +1,197 @@
#include <stdio.h>
#include <stdlib.h>
#include "formats.c"
r* rFormat;
i* iFormat;
void initFunctions() {
rFormat = (r*)malloc(sizeof(r));
iFormat = (i*)malloc(sizeof(i));
rFormat->opcode = 0;
iFormat->opcode = 0;
}
// -------------------------- R FORMAT INSTRUCTIONS -------------------------- //
char * add(int * args[]) {
rFormat->rd = *args[0];
rFormat->rs = *args[1];
rFormat->rt = *args[2];
rFormat->funct = 32;
// Unused in add instruction.
rFormat->shamt = 0;
return rToHex(rFormat);
}
char * addu(int * args[]) {
rFormat->rd = *args[0];
rFormat->rs = *args[1];
rFormat->rt = *args[2];
rFormat->funct = 33;
// Unused in addu instruction.
rFormat->shamt = 0;
return rToHex(rFormat);
}
char * and(int * args[]) {
rFormat->rd = *args[0];
rFormat->rs = *args[1];
rFormat->rt = *args[2];
rFormat->funct = 36;
// Unused in and instruction.
rFormat->shamt = 0;
return rToHex(rFormat);
}
char * jr(int * args[]) {
rFormat->rs = *args[0];
rFormat->funct = 8;
// Unused in jr instruction.
rFormat->shamt = 0;
rFormat->rd = 0;
rFormat->rt = 0;
return rToHex(rFormat);
}
char * nor(int * args[]) {
rFormat->rd = *args[0];
rFormat->rs = *args[1];
rFormat->rt = *args[2];
rFormat->funct = 39;
// Unused in nor instruction.
rFormat->shamt = 0;
return rToHex(rFormat);
}
char * or(int * args[]) {
rFormat->rd = *args[0];
rFormat->rs = *args[1];
rFormat->rt = *args[2];
rFormat->funct = 37;
// Unused in or instruction.
rFormat->shamt = 0;
return rToHex(rFormat);
}
char * slt(int * args[]) {
rFormat->rd = *args[0];
rFormat->rs = *args[1];
rFormat->rt = *args[2];
rFormat->funct = 42;
// Unused in slt instruction.
rFormat->shamt = 0;
return rToHex(rFormat);
}
char * sltu(int * args[]) {
rFormat->rd = *args[0];
rFormat->rs = *args[1];
rFormat->rt = *args[2];
rFormat->funct = 43;
// Unused in sltu instruction.
rFormat->shamt = 0;
return rToHex(rFormat);
}
char * sll(int * args[]) {
rFormat->rd = *args[0];
rFormat->rt = *args[1];
rFormat->shamt = *args[2];
rFormat->funct = 0;
// Unused in sll instruction.
rFormat->rs = 0;
return rToHex(rFormat);
}
char * srl(int * args[]) {
rFormat->rd = *args[0];
rFormat->rt = *args[1];
rFormat->shamt = *args[2];
rFormat->funct = 2;
// Unused in sll instruction.
rFormat->rs = 0;
return rToHex(rFormat);
}
char * sub(int * args[]) {
rFormat->rd = *args[0];
rFormat->rs = *args[1];
rFormat->rt = *args[2];
rFormat->funct = 34;
// Unused in sll instruction.
rFormat->shamt = 0;
return rToHex(rFormat);
}
char * subu(int * args[]) {
rFormat->rd = *args[0];
rFormat->rs = *args[1];
rFormat->rt = *args[2];
rFormat->funct = 35;
// Unused in sll instruction.
rFormat->shamt = 0;
return rToHex(rFormat);
}
// -------------------------- I FORMAT INSTRUCTIONS -------------------------- //
char * addi(int * args[]) {
iFormat->opcode = 8;
iFormat->rt = *args[0];
iFormat->rs = *args[1];
iFormat->immediate = *args[2];
return iToHex(iFormat);
}
char * addiu(int * args[]) {
iFormat->opcode = 9;
iFormat->rt = *args[0];
iFormat->rs = *args[1];
iFormat->immediate = *args[2];
return iToHex(iFormat);
}
char * andi(int * args[]) {
iFormat->opcode = 12;
iFormat->rt = *args[0];
iFormat->rs = *args[1];
iFormat->immediate = *args[2];
return iToHex(iFormat);
}
char * beq(int * args[]) {
iFormat->opcode = 4;
iFormat->rt = *args[0];
iFormat->rs = *args[1];
iFormat->immediate = *args[2];
return iToHex(iFormat);
}
// -------------------------- J FORMAT INSTRUCTIONS -------------------------- //
-33
View File
@@ -1,33 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include "formats.h"
r* rFormat;
i* iFormat;
void initFunctions() {
rFormat = (r*)malloc(sizeof(r));
iFormat = (i*)malloc(sizeof(i));
}
char * add(int * args[]) {
rFormat->opcode = 0;
rFormat->rd = *args[0];
rFormat->rs = *args[1];
rFormat->rt = *args[2];
rFormat->shamt = *args[3];
rFormat->funct = 20;
return rToHex(rFormat);
}
char * sub(int * args[]) {
rFormat->opcode = 0;
rFormat->rd = *args[0];
rFormat->rs = *args[1];
rFormat->rt = *args[2];
rFormat->shamt = *args[3];
rFormat->funct = 22;
return rToHex(rFormat);
}
+11
View File
@@ -0,0 +1,11 @@
typedef struct args {
int arg;
struct args *nextArg; // Allows dynamically sized lists of arguments. For eg. syscall will just be 1 element, but add has 4 elements.
} args;
typedef struct instruction {
int formatType; // 0 = R, 1 = I, 2 = J
struct instruction* nextInstruction;
struct args* a; // A linked list of each argument of the instruction.
} instruction;
+52
View File
@@ -0,0 +1,52 @@
#include <stdio.h>
#include <stdlib.h>
#include "instruction.h"
int traverse(struct instruction* current) {
while(current->nextInstruction != NULL) {
struct args* currentArgs = current->a;
while(currentArgs != NULL) {
printf("%d ", currentArgs->arg);
currentArgs = currentArgs->nextArg;
}
printf("\n");
current = current->nextInstruction;
}
return 1; // TODO
}
// Test driver for nested linked list functionality.
int main() {
struct instruction* head = (instruction*) malloc(sizeof(instruction));
struct instruction* current = head;
for(int i = 0; i < 20; i++) {
// Get a pseudo random formatType between 0 and 2 inclusive
current->formatType = i % 3;
// Create the head and current pointers for the inner linked list.
struct args* argsHead = (args*) malloc(sizeof(args));
current->a = argsHead;
struct args* argsCurrent = argsHead;
for(int j = 0; j < (i % 4 + 1); j++) {
argsCurrent->arg = j;
argsCurrent->nextArg = (args*) malloc(sizeof(args));
argsCurrent = argsCurrent->nextArg;
}
// Move to the next instruction.
current->nextInstruction = (instruction*) malloc(sizeof(instruction));
current = current->nextInstruction;
}
traverse(head);
}
+17 -18
View File
@@ -4,7 +4,7 @@
#include <stdlib.h>
#include <string.h>
#include "formats.h"
#include "formats.c"
#include "registers.h"
#include "functionAssigner.h"
@@ -12,8 +12,8 @@ FILE * file;
// Determines if the parser should keep a space, based upon if the space is surrounded by two non-space characters.
int determineKeepSpace(char prior, char after) {
if(prior != NULL && !isspace(prior))
if(after != NULL && !isspace(after))
if(&prior != (char *) NULL && !isspace(prior))
if(&after != (char *) NULL && !isspace(after))
return 1;
return 0;
@@ -57,37 +57,38 @@ char * removeCommentsAndWhiteSpace(char * line) {
// Parse a line of assembly into numerical representations for the function (eg. add = 0), registers, offset, etc.
int * parseIntoNotation(char * bareLine) {
int numFunctions = 2; // TODO: Need to obtain dynamically.
int * notation = (int *)calloc(4, sizeof(int));
int numFunctions = 20; // TODO: Need to obtain dynamically.
//char * tokens = strtok(bareLine, " ");
char * token = strtok(bareLine, " ");
int counter = 0;
int cmd;
for(int i = 0; i < numFunctions; i++)
if(strcmp(token, FUNCTION_STRING[i]) == 0) cmd = i;
int * notation = (int *)calloc(4, sizeof(int));
int counter = 1;
while (token != NULL)
{
for(int i = 0; i < numFunctions; i++) {
if(strcmp(token, FUNCTION_STRING[i]) == 0) {
printf("found a match between %s and %s, value is %d\n", token, FUNCTION_STRING[i], i);
notation[counter] = i;
counter++;
continue;
}
// Compare only the first token to all available functions.
if(counter == 0) {
}
if(counter == 0) break;
// Compare subsequent tokens to available registers.
for(int i = 0; i < 32; i++) {
if(strcmp(token, REGISTER_STRING[i]) == 0) {
printf("found a match between %s and %s, value is %d\n", token, REGISTER_STRING[i], i);
notation[counter] = i;
counter++;
continue;
}
}
printf("%s ", token);
token = strtok(NULL, " ");
}
return notation;
}
@@ -96,7 +97,7 @@ int initParse(char * filepath) {
file = fopen(filepath, "r");
// Maximum number of characters in a line is 1024.
char lines[1024];
char lines[256];
// Catch if the file does not exist/cannot be opened.
if(file == NULL) {
@@ -104,13 +105,11 @@ int initParse(char * filepath) {
return 0;
}
// Get each line of the file, remove comments and whitespace, and attempt to parse
while(fgets(lines, sizeof(lines), file)) {
char * line = removeCommentsAndWhiteSpace(lines);
int * notation = parseIntoNotation(line);
printf("notation: %d %d %d %d\n", notation[0], notation[1], notation[2], notation[3]);
free(notation);
}
fclose(file);