From 433d40c8d5b2d1cf2059c613f3090d30771eb631 Mon Sep 17 00:00:00 2001 From: omer1977 Date: Thu, 29 Aug 2019 14:19:12 -0400 Subject: [PATCH] . --- assembler/Makefile | 10 + assembler/README.md | 41 ++ assembler/assembler.c | 110 ++++ assembler/file_parser.c | 1193 +++++++++++++++++++++++++++++++++++++ assembler/file_parser.h | 27 + assembler/hash_function.h | 124 ++++ assembler/hash_table.h | 306 ++++++++++ assembler/tokenizer.h | 60 ++ lab0/Makefile | 13 + lab0/README.md | 13 + lab0/mipsInstructionMap.h | 35 ++ lab0/nop.asm | 7 + lab0/simulator.c | 290 +++++++++ lab0/simulator.h | 65 ++ 14 files changed, 2294 insertions(+) create mode 100755 assembler/Makefile create mode 100644 assembler/README.md create mode 100644 assembler/assembler.c create mode 100644 assembler/file_parser.c create mode 100644 assembler/file_parser.h create mode 100644 assembler/hash_function.h create mode 100644 assembler/hash_table.h create mode 100644 assembler/tokenizer.h create mode 100755 lab0/Makefile create mode 100644 lab0/README.md create mode 100644 lab0/mipsInstructionMap.h create mode 100644 lab0/nop.asm create mode 100644 lab0/simulator.c create mode 100644 lab0/simulator.h diff --git a/assembler/Makefile b/assembler/Makefile new file mode 100755 index 0000000..768e37a --- /dev/null +++ b/assembler/Makefile @@ -0,0 +1,10 @@ +HEADERS = file_parser.h + +default: assembler + +assembler: assembler.c file_parser.c + gcc assembler.c file_parser.c -o assembler -std=c99 + +clean: + -rm -f assembler.o + -rm -f assembler diff --git a/assembler/README.md b/assembler/README.md new file mode 100644 index 0000000..c841ef1 --- /dev/null +++ b/assembler/README.md @@ -0,0 +1,41 @@ +Mips Assembler +============== + +An assembler for a subset of the MIPS like instruction set architecture + +# How to use +The assembler will take a file written in assembly language as input on the command line and will produce an output file containing the MIPS machine code. The input file should be in ASCII text. Each line in the input assembly file contains either a mnemonic, a section header (such as .data) or a label (jump or branch target. The maximum length of a line is 4 bytes. Section headers such as .data and .text should be in a line by themselves with no other assembly mnemonic. Similarly, branch targets such as loop: will be on a line by themselves with no other assembly mnemonic. The input assembly file should only contain one data section and one text section. The first section in the file will be the .text section, followed by the .data section. + +The assembler supports the following instruction set: + +R-Type +- add +- sub +- and +- or +- sll +- slt +- srl +- jr + +I-Type +- lw +- sw +- andi +- addi +- slti +- ori +- lui +- beq +- bne + +J-Type +- j +- jal + +# Run + to compile the assembler + $ ./make + + to run the assembler on a nop.asm assembly file to write machine code in nop.out + $ ./assembler nop.asm nop.out diff --git a/assembler/assembler.c b/assembler/assembler.c new file mode 100644 index 0000000..08d3ef6 --- /dev/null +++ b/assembler/assembler.c @@ -0,0 +1,110 @@ +/* + * assembler.c + * + * Created on: Oct 3, 2011 + * Modified by Masab Ahmad + */ +#include +#include +#include +#include "file_parser.h" +#include "hash_table.h" + +int search(char *instruction); + +// Array that holds the supported instructions +char *instructions[] = { + "la", // 0 + "lui", // 1 + "lw", // 2 + "sw", // 3 + "add", // 4 + "sub", // 5 + "addi", // 6 + "or", // 7 + "and", // 8 + "ori", // 9 + "andi", // 10 + "slt", // 11 + "slti", // 12 + "sll", // 13 + "srl", // 14 + "beq", // 15 + "bne", //16 + "j", //17 + "jr", //18 + "jal" //19 + }; + +// Size of array +size_t inst_len = sizeof(instructions)/sizeof(char *); + +int search(char *instruction) { + + int found = 0; + + for (int i = 0; i < inst_len; i++) { + + if (strcmp(instruction, instructions[i]) == 0) { + found = 1; + return i; + } + } + + if (found == 0) + return -1; +} + +// Quick Sort String Comparison Function +int string_comp(const void *a, const void *b) { + return strcmp(*(char **)a, *(char **)b); +} + +int main (int argc, char *argv[]) { + + // Make sure correct number of arguments input + if (argc != 3) { + printf("Incorrect number of arguments"); + } + + else { + + // Open I/O files + // Check that files opened properly + FILE *In; + In = fopen(argv[1], "r"); + if (In == NULL) { + printf("Input file could not be opened."); + exit(1); + } + + FILE *Out; + Out = fopen(argv[2], "w"); + if (Out == NULL) { + printf("Output file could not opened."); + exit(1); + } + + // Sort the array using qsort for faster search + qsort(instructions, inst_len, sizeof(char *), string_comp); + + // Create a hash table of size 127 + hash_table_t *hash_table = create_hash_table(127); + + // Parse in passes + + int passNumber = 1; + parse_file(In, passNumber, instructions, inst_len, hash_table, Out); + + // Rewind input file & start pass 2 + rewind(In); + passNumber = 2; + parse_file(In, passNumber, instructions, inst_len, hash_table, Out); + + // Close files + fclose(In); + fclose(Out); + + return 0; + } +} diff --git a/assembler/file_parser.c b/assembler/file_parser.c new file mode 100644 index 0000000..36faa3e --- /dev/null +++ b/assembler/file_parser.c @@ -0,0 +1,1193 @@ +#include +#include +#include +#include +#include +#include +#include "file_parser.h" +#include "tokenizer.h" + +/* + * The structs below map a character to an integer. + * They are used in order to map a specific instruciton/register to its binary format in ASCII + */ + +int incr = 0; + +// Struct that stores registers and their respective binary reference +struct { + const char *name; + char *address; +} registerMap[] = { + { "zero", "00000" }, + { "at", "00001" }, + { "v0", "00010" }, + { "v1", "00011" }, + { "a0", "00100" }, + { "a1", "00101" }, + { "a2", "00110" }, + { "a3", "00111" }, + { "t0", "01000" }, + { "t1", "01001" }, + { "t2", "01010" }, + { "t3", "01011" }, + { "t4", "01100" }, + { "t5", "01101" }, + { "t6", "01110" }, + { "t7", "01111" }, + { "s0", "10000" }, + { "s1", "10001" }, + { "s2", "10010" }, + { "s3", "10011" }, + { "s4", "10100" }, + { "s5", "10101" }, + { "s6", "10110" }, + { "s7", "10111" }, + { "t8", "11000" }, + { "t9", "11001" }, + { "ra", "11111" }, + { NULL, 0 } }; + +// Struct for R-Type instructions mapping for the 'function' field in the instruction +struct { + const char *name; + char *function; +} rMap[] = { + { "add", "100000" }, + { "sub", "100001" }, + { "and", "100100" }, + { "or", "100101" }, + { "sll", "000000" }, + { "slt", "101010" }, + { "srl", "000010" }, + { "jr", "001000" }, + { NULL, 0 } }; + +// Struct for I-Type instructions +struct { + const char *name; + char *address; +} iMap[] = { + { "lw", "100011" }, + { "sw", "101011" }, + { "andi", "001100" }, + { "ori", "001101" }, + { "lui", "001111" }, + { "beq", "000100" }, + { "bne", "000101" }, + { "slti", "001010" }, + { "addi", "001000" }, + { NULL, 0 } }; + +// Struct for J-Type instructions +struct { + const char *name; + char *address; +} jMap[] = { + { "j", "000010" }, + { "jal", "000011" }, + { NULL, 0 } }; + +int memory_location = 0; + +void parse_file(FILE *fptr, int pass, char *instructions[], size_t inst_len, hash_table_t *hash_table, FILE *Out) { + + char line[MAX_LINE_LENGTH + 1]; + char *tok_ptr, *ret, *token = NULL; + int32_t line_num = 1; + int32_t instruction_count = 0x00000000; + int data_reached = 0; + //FILE *fptr; + + /*fptr = fopen(src_file, "r"); + if (fptr == NULL) { + fprintf(Out, "unable to open file %s. aborting ...\n", src_file); + exit(-1); + }*/ + + while (1) { + if ((ret = fgets(line, MAX_LINE_LENGTH, fptr)) == NULL) + break; + line[MAX_LINE_LENGTH] = 0; + + tok_ptr = line; + if (strlen(line) == MAX_LINE_LENGTH) { + fprintf(Out, + "line %d: line is too long. ignoring line ...\n", line_num); + line_num++; + continue; + } + + /* parse the tokens within a line */ + while (1) { + + token = parse_token(tok_ptr, " \n\t$,", &tok_ptr, NULL); + + /* blank line or comment begins here. go to the next line */ + if (token == NULL || *token == '#') { + line_num++; + free(token); + break; + } + + printf("token: %s\n", token); + + /* + * If token is "la", increment by 8, otherwise if it exists in instructions[], + * increment by 4. + */ + int x = search(token); + //int x = (binarySearch(instructions, 0, inst_len, token)); + if (x >= 0) { + if (strcmp(token, "la") == 0) + instruction_count = instruction_count + 8; + else + instruction_count = instruction_count + 4; + } + + // If token is ".data", reset instruction to .data starting address + else if (strcmp(token, ".data") == 0) { + if(incr==1) + fprintf(Out, "11111111111111111111111111111111\n"); + incr++; + instruction_count = 0x00002000; + data_reached = 1; + } + + printf("PC Count: %d\n", instruction_count); + + // If first pass, then add labels to hash table + if (pass == 1) { + + printf("First pass\n"); + + // if token has ':', then it is a label so add it to hash table + if (strstr(token, ":") && data_reached == 0) { + + printf("Label\n"); + + // Strip out ':' + //printf("Label: %s at %d with address %d: \n", token, line_num, instruction_count); + size_t token_len = strlen(token); + token[token_len - 1] = '\0'; + + // Insert variable to hash table + uint32_t *inst_count; + inst_count = (uint32_t *)malloc(sizeof(uint32_t)); + *inst_count = instruction_count; + int32_t insert = hash_insert(hash_table, token, strlen(token)+1, inst_count); + + if (insert != 1) { + fprintf(Out, "Error inserting into hash table\n"); + exit(1); + } + } + + // If .data has been reached, increment instruction count accordingly + // and store to hash table + else { + + char *var_tok = NULL; + char *var_tok_ptr = tok_ptr; + + // If variable is .word + if (strstr(tok_ptr, ".word")) { + + printf(".word\n"); + + // Variable is array + if (strstr(var_tok_ptr, ":")) { + + printf("array\n"); + + // Store the number in var_tok and the occurance in var_tok_ptr + var_tok = parse_token(var_tok_ptr, ":", &var_tok_ptr, NULL); + + // Convert char* to int + int freq = atoi(var_tok_ptr); + + int num; + sscanf(var_tok, "%*s %d", &num); + + // Increment instruction count by freq + instruction_count = instruction_count + (freq * 4); + + // Strip out ':' from token + size_t token_len = strlen(token); + token[token_len - 1] = '\0'; + + //printf("Key: '%s', len: %zd\n", token, strlen(token)); + + // Insert variable to hash table + uint32_t *inst_count; + inst_count = (uint32_t *)malloc(sizeof(uint32_t)); + *inst_count = instruction_count; + int32_t insert = hash_insert(hash_table, token, strlen(token)+1, inst_count); + + if (insert == 0) { + fprintf(Out, "Error in hash table insertion\n"); + exit(1); + } + + printf("End array\n"); + } + + // Variable is a single variable + else { + + instruction_count = instruction_count + 4; + + // Strip out ':' from token + size_t token_len = strlen(token); + token[token_len - 1] = '\0'; + + // Insert variable to hash table + uint32_t *inst_count; + inst_count = (uint32_t *)malloc(sizeof(uint32_t)); + *inst_count = instruction_count; + int32_t insert = hash_insert(hash_table, token, strlen(token)+1, inst_count); + + if (insert == 0) { + fprintf(Out, "Error in hash table insertion\n"); + exit(1); + } + + printf("end singe var\n"); + } + } + + // Variable is a string + else if (strstr(tok_ptr, ".asciiz")) { + + // Store the ascii in var_tok + var_tok_ptr+= 8; + var_tok = parse_token(var_tok_ptr, "\"", &var_tok_ptr, NULL); + + // Increment instruction count by string length + size_t str_byte_len = strlen(var_tok); + instruction_count = instruction_count + str_byte_len; + + // Strip out ':' from token + size_t token_len = strlen(token); + token[token_len - 1] = '\0'; + + // Insert variable to hash table + uint32_t *inst_count; + inst_count = (uint32_t *)malloc(sizeof(uint32_t)); + *inst_count = instruction_count; + int32_t insert = hash_insert(hash_table, token, strlen(token)+1, inst_count); + + if (insert == 0) { + fprintf(Out, "Error in hash table insertion\n"); + exit(1); + } + } + } + } + + // If second pass, then interpret + else if (pass == 2) { + + printf("############ Pass 2 ##############\n"); + + // start interpreting here + // if j loop --> then instruction is: 000010 then immediate is insturction count in 26 bits?? + + // If in .text section + if (data_reached == 0) { + + // Check instruction type + int instruction_supported = search(token); + char inst_type; + + // If instruction is supported + if (instruction_supported != -1) { + + // token contains the instruction + // tok_ptr points to the rest of the line + + // Determine instruction type + inst_type = instruction_type(token); + + if (inst_type == 'r') { + + // R-Type with $rd, $rs, $rt format + if (strcmp(token, "add") == 0 || strcmp(token, "sub") == 0 + || strcmp(token, "and") == 0 + || strcmp(token, "or") == 0 || strcmp(token, "slt") == 0) { + + // Parse the instructio - get rd, rs, rt registers + char *inst_ptr = tok_ptr; + char *reg = NULL; + + // Create an array of char* that stores rd, rs, rt respectively + char **reg_store; + reg_store = malloc(3 * sizeof(char*)); + if (reg_store == NULL) { + fprintf(Out, "Out of memory\n"); + exit(1); + } + + for (int i = 0; i < 3; i++) { + reg_store[i] = malloc(2 * sizeof(char)); + if (reg_store[i] == NULL) { + fprintf(Out, "Out of memory\n"); + exit(1); + } + } + + // Keeps a reference to which register has been parsed for storage + int count = 0; + while (1) { + + reg = parse_token(inst_ptr, " $,\n\t", &inst_ptr, NULL); + + if (reg == NULL || *reg == '#') { + break; + } + + strcpy(reg_store[count], reg); + count++; + free(reg); + } + + // Send reg_store for output + // rd is in position 0, rs is in position 1 and rt is in position 2 + rtype_instruction(token, reg_store[1], reg_store[2], reg_store[0], 0, Out); + + // Dealloc reg_store + for (int i = 0; i < 3; i++) { + free(reg_store[i]); + } + free(reg_store); + } + + // R-Type with $rd, $rs, shamt format + else if (strcmp(token, "sll") == 0 || strcmp(token, "srl") == 0) { + + // Parse the instructio - get rd, rs, rt registers + char *inst_ptr = tok_ptr; + char *reg = NULL; + + // Create an array of char* that stores rd, rs and shamt + char **reg_store; + reg_store = malloc(3 * sizeof(char*)); + if (reg_store == NULL) { + fprintf(Out, "Out of memory\n"); + exit(1); + } + + for (int i = 0; i < 3; i++) { + reg_store[i] = malloc(2 * sizeof(char)); + if (reg_store[i] == NULL) { + fprintf(Out, "Out of memory\n"); + exit(1); + } + } + + // Keeps a reference to which register has been parsed for storage + int count = 0; + while (1) { + + reg = parse_token(inst_ptr, " $,\n\t", &inst_ptr, NULL); + + if (reg == NULL || *reg == '#') { + break; + } + + strcpy(reg_store[count], reg); + count++; + free(reg); + } + + // Send reg_store for output + // rd is in position 0, rs is in position 1 and shamt is in position 2 + rtype_instruction(token, "00000", reg_store[1], reg_store[0], atoi(reg_store[2]), Out); + + // Dealloc reg_store + for (int i = 0; i < 3; i++) { + free(reg_store[i]); + } + free(reg_store); + } + + else if (strcmp(token, "jr") == 0) { + + // Parse the instruction - rs is in tok_ptr + char *inst_ptr = tok_ptr; + char *reg = NULL; + reg = parse_token(inst_ptr, " $,\n\t", &inst_ptr, NULL); + + rtype_instruction(token, reg, "00000", "00000", 0, Out); + } + } + + // I-Type + else if (inst_type == 'i') { + + // la is pseudo instruction for lui and ori + // Convert to lui and ori and pass those instructions + if (strcmp(token, "la") == 0) { + + // Parse the instruction - get register & immediate + char *inst_ptr = tok_ptr; + char *reg = NULL; + + // Create an array of char* that stores rd, rs and shamt + char **reg_store; + reg_store = malloc(2 * sizeof(char*)); + if (reg_store == NULL) { + fprintf(Out, "Out of memory\n"); + exit(1); + } + + for (int i = 0; i < 2; i++) { + reg_store[i] = malloc(2 * sizeof(char)); + if (reg_store[i] == NULL) { + fprintf(Out, "Out of memory\n"); + exit(1); + } + } + + // Keeps a reference to which register has been parsed for storage + int count = 0; + while (1) { + + reg = parse_token(inst_ptr, " $,\n\t", &inst_ptr, NULL); + + if (reg == NULL || *reg == '#') { + break; + } + + strcpy(reg_store[count], reg); + count++; + free(reg); + } + + // Interpret la instruction. + // The register is at reg_store[0] and the variable is at reg_store[1] + + printf("\n reg_store[0]: %s\n",reg_store[0]); + // Find address of label in hash table + int *address = hash_find(hash_table, reg_store[1], strlen(reg_store[1])+1); + + // Convert address to binary in char* + char addressBinary[33]; + getBin(*address, addressBinary, 32); + + // Get upper and lower bits of address + char upperBits[16]; + char lowerBits[16]; + + for (int i = 0; i < 32; i++) { + if (i < 16) + lowerBits[i] = addressBinary[i]; + else + upperBits[i-16] = addressBinary[i]; + } + + // Call the lui instruction with: lui $reg, upperBits + // Convert upperBits binary to int + int immediate = getDec(upperBits); + //immediate = memory_location; + //memory_location++; + printf("\n LA1: %d \n",immediate); + itype_instruction("lui", "00000", reg_store[0], immediate, Out); + + // Call the ori instruction with: ori $reg, $reg, lowerBits + // Convert lowerBits binary to int + immediate = getDec(lowerBits); + printf("\n LA2: %d",immediate); + itype_instruction("ori", reg_store[0], reg_store[0], immediate, Out); + + // Dealloc reg_store + for (int i = 0; i < 2; i++) { + free(reg_store[i]); + } + free(reg_store); + } + + // I-Type $rt, i($rs) + else if (strcmp(token, "lw") == 0 || strcmp(token, "sw") == 0) { + + // Parse the instructio - rt, immediate and rs + char *inst_ptr = tok_ptr; + char *reg = NULL; + // + // Create an array of char* that stores rd, rs, rt respectively + char **reg_store; + reg_store = malloc(3 * sizeof(char*)); + if (reg_store == NULL) { + fprintf(Out, "Out of memory\n"); + exit(1); + } + + for (int i = 0; i < 3; i++) { + reg_store[i] = malloc(2 * sizeof(char)); + if (reg_store[i] == NULL) { + fprintf(Out, "Out of memory\n"); + exit(1); + } + } + + // Keeps a reference to which register has been parsed for storage + int count = 0; + while (1) { + + reg = parse_token(inst_ptr, " $,\n\t()", &inst_ptr, NULL); + + if (reg == NULL || *reg == '#') { + break; + } + + strcpy(reg_store[count], reg); + count++; + free(reg); + } + + // rt in position 0, immediate in position 1 and rs in position2 + int immediate = atoi(reg_store[1]); + itype_instruction(token, reg_store[2], reg_store[0], immediate, Out); + + // Dealloc reg_store + for (int i = 0; i < 3; i++) { + free(reg_store[i]); + } + free(reg_store); + } + + // I-Type rt, rs, im + else if (strcmp(token, "andi") == 0 || strcmp( token, "ori") == 0 + || strcmp(token, "slti") == 0 || strcmp(token, "addi") == 0) { + + // Parse the instruction - rt, rs, immediate + char *inst_ptr = tok_ptr; + char *reg = NULL; + + // Create an array of char* that stores rt, rs + char **reg_store; + reg_store = malloc(3 * sizeof(char*)); + if (reg_store == NULL) { + fprintf(Out, "Out of memory\n"); + exit(1); + } + + for (int i = 0; i < 3; i++) { + reg_store[i] = malloc(2 * sizeof(char)); + if (reg_store[i] == NULL) { + fprintf(Out, "Out of memory\n"); + exit(1); + } + } + + // Keeps a reference to which register has been parsed for storage + int count = 0; + while (1) { + + reg = parse_token(inst_ptr, " $,\n\t", &inst_ptr, NULL); + + if (reg == NULL || *reg == '#') { + break; + } + + strcpy(reg_store[count], reg); + count++; + free(reg); + } + + // rt in position 0, rs in position 1 and immediate in position 2 + int immediate = atoi(reg_store[2]); + itype_instruction(token, reg_store[1], reg_store[0], immediate, Out); + + // Dealloc reg_store + for (int i = 0; i < 3; i++) { + free(reg_store[i]); + } + free(reg_store); + } + + // I-Type $rt, immediate + else if (strcmp(token, "lui") == 0) { + + // Parse the insturction, rt - immediate + char *inst_ptr = tok_ptr; + char *reg = NULL; + + // Create an array of char* that stores rs, rt + char **reg_store; + reg_store = malloc(2 * sizeof(char*)); + if (reg_store == NULL) { + fprintf(Out, "Out of memory\n"); + exit(1); + } + + for (int i = 0; i < 2; i++) { + reg_store[i] = malloc(2 * sizeof(char)); + if (reg_store[i] == NULL) { + fprintf(Out, "Out of memory\n"); + exit(1); + } + } + + // Keeps a reference to which register has been parsed for storage + int count = 0; + while (1) { + + reg = parse_token(inst_ptr, " $,\n\t", &inst_ptr, NULL); + + if (reg == NULL || *reg == '#') { + break; + } + + strcpy(reg_store[count], reg); + count++; + free(reg); + } + + + // rt in position 0, immediate in position 1 + int immediate = atoi(reg_store[1]); + itype_instruction(token, "00000", reg_store[0], immediate, Out); + + //OK: I changes i < 3 to i < 2 in line 654 below! + // Dealloc reg_store + for (int i = 0; i < 2; i++) { + free(reg_store[i]); + } + free(reg_store); + } + + // I-Type $rs, $rt, label + else if (strcmp(token, "beq") == 0) { + printf("\n In BEQ\n"); + // Parse the instruction - rs, rt + char *inst_ptr = tok_ptr; + char *reg = NULL; + + // Create an array of char* that stores rs, rt + char **reg_store; + reg_store = malloc(2 * sizeof(char*)); + if (reg_store == NULL) { + fprintf(Out, "Out of memory\n"); + exit(1); + } + + for (int i = 0; i < 2; i++) { + reg_store[i] = malloc(2 * sizeof(char)); + if (reg_store[i] == NULL) { + fprintf(Out, "Out of memory\n"); + exit(1); + } + } + + // Keeps a reference to which register has been parsed for storage + int count = 0; + while (1) { + + reg = parse_token(inst_ptr, " $,\n\t", &inst_ptr, NULL); + + if (reg == NULL || *reg == '#') { + break; + } + + strcpy(reg_store[count], reg); + count++; + free(reg); + + if (count == 2) + break; + } + + reg = parse_token(inst_ptr, " $,\n\t", &inst_ptr, NULL); + + // Find hash address for a register and put in an immediate + int *address = hash_find(hash_table, reg, strlen(reg)+1); + + int immediate = *address - instruction_count; //+ + printf("\n OFFSET pre = %d\n ", immediate); + + // OK: this offset modification is wrong! + /* + if(immediate < 0) + immediate = immediate*-1; + printf("\n OFFSET = %d\n ", immediate); + */ + + // Send instruction to itype function + itype_instruction(token, reg_store[0], reg_store[1], immediate, Out); + + // Dealloc reg_store + for (int i = 0; i < 2; i++) { + free(reg_store[i]); + } + free(reg_store); + } + + // I-Type $rs, $rt, label + else if (strcmp(token, "bne") == 0) { + + printf("\n In BNE\n"); + // Parse the instruction - rs, rt + char *inst_ptr = tok_ptr; + char *reg = NULL; + + // Create an array of char* that stores rs, rt + char **reg_store; + reg_store = malloc(2 * sizeof(char*)); + if (reg_store == NULL) { + fprintf(Out, "Out of memory\n"); + exit(1); + } + + for (int i = 0; i < 2; i++) { + reg_store[i] = malloc(2 * sizeof(char)); + if (reg_store[i] == NULL) { + fprintf(Out, "Out of memory\n"); + exit(1); + } + } + // Keeps a reference to which register has been parsed for storage + int count = 0; + while (1) { + + reg = parse_token(inst_ptr, " $,\n\t", &inst_ptr, NULL); + + if (reg == NULL || *reg == '#') { + break; + } + + strcpy(reg_store[count], reg); + count++; + free(reg); + + if (count == 2) + break; + } + + reg = parse_token(inst_ptr, " $,\n\t", &inst_ptr, NULL); + + // Find hash address for a register and put in an immediate + int *address = hash_find(hash_table, reg, strlen(reg)+1); + printf("\n %d %d\n",*address,instruction_count); + //int immediate = *address + instruction_count; + int immediate = *address - instruction_count; //+ + + // OK: this offset modification is wrong! + /* + if(immediate < 0) + immediate = immediate*-1; + printf("\n OFFSET = %d\n ", immediate); + */ + + // Send instruction to itype function + itype_instruction(token, reg_store[0], reg_store[1], immediate, Out); + + // Dealloc reg_store + for (int i = 0; i < 2; i++) { + free(reg_store[i]); + } + free(reg_store); + } + } + + // J-Type + else if (inst_type == 'j') { + + // Parse the instruction - get label + char *inst_ptr = tok_ptr; + + // If comment, extract the label alone + char *comment = strchr(inst_ptr, '#'); + if (comment != NULL) { + + int str_len_count = 0; + for (int i = 0; i < strlen(inst_ptr); i++) { + if (inst_ptr[i] != ' ') + str_len_count++; + else + break; + } + + char new_label[str_len_count+1]; + for (int i = 0; i < str_len_count; i++) + new_label[i] = inst_ptr[i]; + new_label[str_len_count] = '\0'; + + strcpy(inst_ptr, new_label); + } + + else { printf("NO COMMENT\n"); + inst_ptr[strlen(inst_ptr)-1] = '\0'; + } + + // Find hash address for a label and put in an immediate + int *address = hash_find(hash_table, inst_ptr, strlen(inst_ptr)+1); + + // Send to jtype function + jtype_instruction(token, *address, Out); + } + } + + if (strcmp(token, "nop") == 0) { + fprintf(Out, "00000000000000000000000000000000\n"); + } + } + + // If .data part reached + else { + + char *var_tok = NULL; + char *var_tok_ptr = tok_ptr; + + // If variable is .word + if (strstr(tok_ptr, ".word")) { + + int var_value; + + // Variable is array + if (strstr(var_tok_ptr, ":")) { + + // Store the number in var_tok and the occurance in var_tok_ptr + var_tok = parse_token(var_tok_ptr, ":", &var_tok_ptr, NULL); + + // Extract array size, or variable frequency + int freq = atoi(var_tok_ptr); + + // Extract variable value + sscanf(var_tok, "%*s %d", &var_value); + + // Value var_value is repeated freq times. Send to binary rep function + for (int i = 0; i < freq; i++) { + word_rep(var_value, Out); + } + } + + // Variable is a single variable + else { + printf("\n%s\n ", var_tok_ptr); + char * pch; + pch = strtok (var_tok_ptr," "); + pch = strtok (NULL, " "); + var_value = atoi(pch); + printf ("\n INTGER: %d\n",var_value); + // Extract variable value + //sscanf(var_tok_ptr, "%*s %d", &var_value); //.word 10 + + // Variable is in var_value. Send to binary rep function + word_rep(var_value, Out); + //printf("\n VAR: %d\n, var_value"); + } + } + + // Variable is a string + else if (strstr(tok_ptr, ".asciiz")) { + + printf("tok_ptr '%s'\n", tok_ptr); + + if (strncmp(".asciiz ", var_tok_ptr, 8) == 0) { + + // Move var_tok_ptr to beginning of string + var_tok_ptr = var_tok_ptr + 9; + + // Strip out quotation at the end + // Place string in var_tok + var_tok = parse_token(var_tok_ptr, "\"", &var_tok_ptr, NULL); + + ascii_rep(var_tok, Out); + } + } + } + } + + free(token); + } + } +} + +// Binary Search the Array +int binarySearch(char *instructions[], int low, int high, char *string) { + + int mid = low + (high - low) / 2; + int comp = strcmp(instructions[mid], string);\ + + if (comp == 0) + return mid; + + // Not found + if (high <= low) + return -1; + + // If instructions[mid] is less than string + else if (comp > 0) + return binarySearch(instructions, low, mid - 1, string); + + // If instructions[mid] is larger than string + else if (comp < 0) + return binarySearch(instructions, mid + 1, high, string); + + // Return position + else + return mid; + + // Error + return -2; +} + +// Determine Instruction Type +char instruction_type(char *instruction) { + + if (strcmp(instruction, "add") == 0 || strcmp(instruction, "sub") == 0 + || strcmp(instruction, "and") == 0 || strcmp(instruction, "or") + == 0 || strcmp(instruction, "sll") == 0 || strcmp(instruction, + "slt") == 0 || strcmp(instruction, "srl") == 0 || strcmp( + instruction, "jr") == 0) { + + return 'r'; + } + + else if (strcmp(instruction, "lw") == 0 || strcmp(instruction, "sw") == 0 + || strcmp(instruction, "andi") == 0 || strcmp(instruction, "ori") + == 0 || strcmp(instruction, "lui") == 0 || strcmp(instruction, + "beq") == 0 || strcmp(instruction,"bne") == 0 || strcmp(instruction, "slti") == 0 || strcmp( + instruction, "addi") == 0 || strcmp(instruction, "la") == 0) { + + return 'i'; + } + + else if (strcmp(instruction, "j") == 0 || strcmp(instruction, "jal") == 0) { + return 'j'; + } + + // Failsafe return statement + return 0; +} + +// Return the binary representation of the register +char *register_address(char *registerName) { + + size_t i; + for (i = 0; registerMap[i].name != NULL; i++) { + if (strcmp(registerName, registerMap[i].name) == 0) { + return registerMap[i].address; + } + } + + return NULL; +} + +// Write out the R-Type instruction +void rtype_instruction(char *instruction, char *rs, char *rt, char *rd, int shamt, FILE *Out) { + + // Set the instruction bits + char *opcode = "000000"; + + char *rdBin = "00000"; + if (strcmp(rd, "00000") != 0) + rdBin = register_address(rd); + + char *rsBin = "00000"; + if (strcmp(rs, "00000") != 0) + rsBin = register_address(rs); + + char *rtBin = "00000"; + if (strcmp(rt, "00000") != 0) + rtBin = register_address(rt); + + char *func = NULL; + char shamtBin[6]; + + // Convert shamt to binary and put in shamtBin as a char* + getBin(shamt, shamtBin, 5); + + size_t i; + for (i = 0; rMap[i].name != NULL; i++) { + if (strcmp(instruction, rMap[i].name) == 0) { + func = rMap[i].function; + } + } + + // Print out the instruction to the file + fprintf(Out, "%s%s%s%s%s%s\n", opcode, rsBin, rtBin, rdBin, shamtBin, func); +} + +// Write out the I-Type instruction +void itype_instruction(char *instruction, char *rs, char *rt, int immediateNum, FILE *Out) { + + // Set the instruction bits + char *rsBin = "00000"; + if (strcmp(rs, "00000") != 0) + rsBin = register_address(rs); + + char *rtBin = "00000"; + if (strcmp(rt, "00000") != 0) + rtBin = register_address(rt); + + char *opcode = NULL; + char immediate[17]; + + size_t i; + for (i = 0; iMap[i].name != NULL; i++) { + if (strcmp(instruction, iMap[i].name) == 0) { + opcode = iMap[i].address; + } + } + + // Convert immediate to binary + getBin(immediateNum, immediate, 16); + + // Print out the instruction to the file + //printf("\n IMM: %s \n",immediate); + fprintf(Out, "%s%s%s%s\n", opcode, rsBin, rtBin, immediate); +} + +// Write out the J-Type instruction +void jtype_instruction(char *instruction, int immediate, FILE *Out) { + + // Set the instruction bits + char *opcode = NULL; + + // Get opcode bits + size_t i; + for (i = 0; jMap[i].name != NULL; i++) { + if (strcmp(instruction, jMap[i].name) == 0) { + opcode = jMap[i].address; + } + } + + // Convert immediate to binary + char immediateStr[27]; + getBin(immediate, immediateStr, 26); + + // Print out instruction to file + fprintf(Out, "%s%s\n", opcode, immediateStr); +} + +// Write out the variable in binary +void word_rep(int binary_rep, FILE *Out) { + + for (int k = 31; k >= 0; k--) { + fprintf(Out, "%c", (binary_rep & (1 << k)) ? '1' : '0'); + } + + fprintf(Out, "\n"); +} + +// Write out the ascii string +void ascii_rep(char string[], FILE *Out) { + + // Separate the string, and put each four characters in an element of an array of strings + size_t str_length = strlen(string); + str_length++; + int num_strs = str_length / 4; + if ((str_length % 4) > 0) + num_strs++; + + char *ptr; + ptr = &string[0]; + + // Create an array of strings which separates each 4-char string + char **sep_str; + sep_str = malloc(num_strs * sizeof(char*)); + if (sep_str == NULL) { + fprintf(Out, "Out of memory\n"); + exit(1); + } + + for (int i = 0; i < num_strs; i++) { + sep_str[i] = malloc(4 * sizeof(char)); + if (sep_str[i] == NULL) { + fprintf(Out, "Out of memory\n"); + exit(1); + } + } + + int count = 0; + for (int i = 0; i < str_length; i++) { + sep_str[i / 4][i % 4] = *ptr; + ptr++; + count++; + } + + // Reverse each element in the array + char temp; + + for (int i = 0; i < num_strs; i++) { + + for (int j = 0, k = 3; j < k; j++, k--) { + + temp = sep_str[i][j]; + sep_str[i][j] = sep_str[i][k]; + sep_str[i][k] = temp; + } + } + + // Convert into binary + for (int i = 0; i < num_strs; i++) { + + for (int j = 0; j < 4; j++) { + char c = sep_str[i][j]; + for (int k = 7; k >= 0; k--) { + fprintf(Out, "%c", (c & (1 << k)) ? '1' : '0'); + } + } + + fprintf(Out, "\n"); + } + + // Deallocate sep_str + for (int i = 0; i < num_strs; i++) { + free(sep_str[i]); + } + free(sep_str); + sep_str = NULL; +} + +void getBin(int num, char *str, int padding) { + + *(str + padding) = '\0'; + + long pos; + if (padding == 5) + pos = 0x10; + else if (padding == 16) + pos = 0x8000; + else if (padding == 26) + pos = 0x2000000; + else if (padding == 32) + pos = 0x80000000; + + long mask = pos << 1; + while (mask >>= 1) + *str++ = !!(mask & num) + '0'; +} + +// Convert a binary string to a decimal value +int getDec(char *bin) { + + int b, k, m, n; + int len, sum = 0; + + // Length - 1 to accomodate for null terminator + len = strlen(bin) - 1; + + // Iterate the string + for(k = 0; k <= len; k++) { + + // Convert char to numeric value + n = (bin[k] - '0'); + + // Check the character is binary + if ((n > 1) || (n < 0)) { + return 0; + } + + for(b = 1, m = len; m > k; m--) + b *= 2; + + // sum it up + sum = sum + n * b; + } + + return sum; +} + diff --git a/assembler/file_parser.h b/assembler/file_parser.h new file mode 100644 index 0000000..b0ceae3 --- /dev/null +++ b/assembler/file_parser.h @@ -0,0 +1,27 @@ +/* + * file_parser.h + * + * Created on: Oct 3, 2011 + * Modified by Masab Ahmad + */ + +#include "hash_table.h" + +#ifndef FILE_PARSER_H_ +#define FILE_PARSER_H_ + +#define MAX_LINE_LENGTH 256 + +void parse_file(FILE *fptr, int pass, char *instructions[], size_t inst_len, hash_table_t *hash_table, FILE *Out); +int binarySearch(char *instructions[], int low, int high, char *string); +char instruction_type(char *instruction); +char *register_address(char *registerName); +void rtype_instruction(char *instruction, char *rs, char *rt, char *rd, int shamt, FILE *Out); +void itype_instruction(char *instruction, char *rs, char *rt, int immediate, FILE *Out); +void jtype_instruction(char *instruction, int immediate, FILE *Out); +void word_rep(int binary_rep, FILE *Out); +void ascii_rep(char string[], FILE *Out); +void getBin(int num, char *str, int padding); +int getDec(char *bin); + +#endif /* FILE_PARSER_H_ */ diff --git a/assembler/hash_function.h b/assembler/hash_function.h new file mode 100644 index 0000000..a5e115c --- /dev/null +++ b/assembler/hash_function.h @@ -0,0 +1,124 @@ +#ifndef __HASH_FUNCTION_H +#define __HASH_FUNCTION_H + +/* +------------------------------------------------------------------- +lookup.c, by Bob Jenkins, 1996 +hash() and mix() are the only externally useful functions in here. +Routines to test the hash are included if SELF_TEST is defined. +-------------------------------------------------------------------- +*/ + +#include +#include +#include +typedef unsigned long int ub4; /* unsigned 4-byte quantities */ +typedef unsigned char ub1; + +#define hashsize(n) ((ub4)1<<(n)) +#define hashmask(n) (hashsize(n)-1) + +static ub4 hash(register ub1 *k, register ub4 length, register ub4 level); + +/* +-------------------------------------------------------------------- +mix -- mix 4 32-bit values reversibly. +Changing any input bit will usually change at least 32 output bits, + whether the hash is run forward or in reverse. +Changing any input bit will change each of the 32 output bits in d + about half the time when inputs a,b,c,d are uniformly distributed. +mix() takes 32 machine cycles. No 16 or 24 cycle mixer works; this + was confirmed by brute-force search. This hash is the best of + about 500,000 32-cycle hashes examined. +-------------------------------------------------------------------- +*/ + +#define mix(a,b,c,d) \ +{ \ + a += d; d += a; a ^= (a>>7); \ + b += a; a += b; b ^= (b<<13); \ + c += b; b += c; c ^= (c>>17); \ + d += c; c += d; d ^= (d<<9); \ + a += d; d += a; a ^= (a>>3); \ + b += a; a += b; b ^= (b<<7); \ + c += b; b += c; c ^= (c>>15); \ + d += c; c += d; d ^= (d<<11); \ +} + +/* +-------------------------------------------------------------------- +hash() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + len : the length of the key, counting by bytes + level : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. There are no funnels smaller than 32 bits. +About 34+5len instructions. + +There is no need to divide by a prime (division is sooo slow!). If +you need less than 32 bits, use a bitmask. For example, if you need +only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (ub1 **)k, do it like this: + for (i=0, h=0; i= 16) + { + a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24)); + b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24)); + c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24)); + d += (k[12]+((ub4)k[13]<<8)+((ub4)k[14]<<16)+((ub4)k[15]<<24)); + mix(a,b,c,d); + k += 16; len -= 16; + } + + /*------------------------------------- handle the last 15 bytes */ + d += length; + switch(len) /* all the case statements fall through */ + { + case 15: d+=((ub4)k[14]<<24); + case 14: d+=((ub4)k[13]<<16); + case 13: d+=((ub4)k[12]<<8); + /* the first byte of d is reserved for the length */ + case 12: c+=((ub4)k[11]<<24); + case 11: c+=((ub4)k[10]<<16); + case 10: c+=((ub4)k[9]<<8); + case 9 : c+=k[8]; + case 8 : b+=((ub4)k[7]<<24); + case 7 : b+=((ub4)k[6]<<16); + case 6 : b+=((ub4)k[5]<<8); + case 5 : b+=k[4]; + case 4 : a+=((ub4)k[3]<<24); + case 3 : a+=((ub4)k[2]<<16); + case 2 : a+=((ub4)k[1]<<8); + case 1 : a+=k[0]; + /* case 0: nothing left to add */ + } + mix(a,b,c,d); + /*-------------------------------------------- report the result */ + return d; +} +#endif + diff --git a/assembler/hash_table.h b/assembler/hash_table.h new file mode 100644 index 0000000..50f8636 --- /dev/null +++ b/assembler/hash_table.h @@ -0,0 +1,306 @@ +#ifndef __HASH_TABLE__ +#define __HASH_TABLE__ + +#include +#include +#include +#include +#include +#include "hash_function.h" + +#define TRUE 1 +#define FALSE 0 + +typedef struct hash_entry_type +{ + void *key; + void *data; + uint32_t key_len; + struct hash_entry_type *next; + struct hash_entry_type *prev; +} hash_entry_t; + +typedef struct +{ + hash_entry_t **row; + hash_entry_t **tail; +#ifdef __USE_HASH_LOCKS__ + sem_t *row_lock; +#endif + uint32_t size; +} hash_table_t; + +/* + hash table functions + copyright (c) 2005 dr. srinidhi varadarajan +*/ + +/* + + creates a hash table and returns a pointer to it + + parameters: + hash_table_size : size of the hash table to create + + returns: pointer to created hash table or NULL on failure + +*/ + +static inline hash_table_t *create_hash_table(uint32_t hash_table_size) +{ + uint32_t t; + hash_table_t *hash_table; + + hash_table = ( hash_table_t *) malloc(sizeof( hash_table_t)); + if (hash_table == NULL) return(NULL); + + hash_table->row = ( hash_entry_t **) malloc(sizeof( hash_entry_t *) * (hash_table_size)); + if (hash_table->row == NULL) return(NULL); + + hash_table->tail = ( hash_entry_t **) malloc(sizeof( hash_entry_t *) * (hash_table_size)); + if (hash_table->tail == NULL) return(NULL); + +#ifdef __USE_HASH_LOCKS__ + hash_table->row_lock = (sem_t *) malloc(sizeof(sem_t) * (hash_table_size + 2)); + if (hash_table->row_lock == NULL) return(NULL); +#endif + + for (t=0; trow[t] = NULL; + hash_table->tail[t] = NULL; +#ifdef __USE_HASH_LOCKS__ + sem_init(&hash_table->row_lock[t], 0, 1); +#endif + } + + hash_table->size = hash_table_size; + return(hash_table); +} + +/* + inserts a structure into the hash table. + + parameters : + hash_table : Hash table to use + key : key to index the hash table + key_len: length of the hash key in bytes + data : pointer to the data to insert. you should allocate and free the + data pointer within your application + + returns: + TRUE if key was inserted into the table + FALSE if key could not be inserted into the table + + note: a data element can be inserted more than once in this + hash structure. be careful when you use hash_insert to make sure + that if you insert multiple times, you also delete multiple times. +*/ +static inline int32_t hash_insert( hash_table_t *hash_table, void *key, uint32_t key_len, void *data) +{ + uint32_t hash_key, hash_table_size; + hash_entry_t *new_entry, *prev_ptr; + + hash_table_size = hash_table->size; + + hash_key = hash(key, key_len, 7) % hash_table_size; + +#ifdef __USE_HASH_LOCKS__ + sem_wait(&hash_table->row_lock[hash_key]); +#endif + + new_entry = ( hash_entry_t *) malloc(sizeof( hash_entry_t)); + if (new_entry == NULL) + { +#ifdef __USE_HASH_LOCKS__ + sem_post(&hash_table->row_lock[hash_key]); +#endif + return(FALSE); + } + + new_entry->key = (char *) malloc(key_len); + if (new_entry->key == NULL) + { + printf("Warning: Unable to allocate memory for hash key. \n"); + free(new_entry); +#ifdef __USE_HASH_LOCKS__ + sem_post(&hash_table->row_lock[hash_key]); +#endif + return(FALSE); + } + + prev_ptr = hash_table->tail[hash_key]; + new_entry->next = NULL; + new_entry->prev = hash_table->tail[hash_key]; + if (prev_ptr == NULL) + hash_table->row[hash_key] = new_entry; + else + prev_ptr->next = new_entry; + + hash_table->tail[hash_key] = new_entry; + memcpy(new_entry->key, key, key_len); + new_entry->data = data; + new_entry->key_len = key_len; +#ifdef __USE_HASH_LOCKS__ + sem_post(&hash_table->row_lock[hash_key]); +#endif + return(TRUE); +} + +/* + deletes a hash table entry. + + parameters : + hash_table : hash table to use + key : key to index the hash table + key_len: length of the key in bytes + + returns: + TRUE: if key was successfully deleted + FALSE: if key could not be deleted (key was not found) + +*/ +static inline int32_t hash_delete( hash_table_t *hash_table, void *key, uint32_t key_len) +{ + uint32_t hash_key, hash_table_size; + hash_entry_t *ptr, *prev_ptr; + + hash_table_size = hash_table->size; + + hash_key = hash(key, key_len, 7) % hash_table_size; + +#ifdef __USE_HASH_LOCKS__ + sem_wait(&(hash_table->row_lock[hash_key])); +#endif + + ptr = hash_table->row[hash_key]; + prev_ptr = NULL; + + while (ptr != NULL) + { + if (memcmp(ptr->key, key, key_len) == 0) + { + if (prev_ptr == NULL) // First entry + hash_table->row[hash_key] = ptr->next; + else + prev_ptr->next = ptr->next; + + if (ptr->next == NULL) hash_table->tail[hash_key] = prev_ptr; + + free(ptr->key); + free(ptr); +#ifdef __USE_HASH_LOCKS__ + sem_post(&hash_table->row_lock[hash_key]); +#endif + return(TRUE); + } + prev_ptr = ptr; + ptr = ptr->next; + } + +#ifdef __USE_HASH_LOCKS__ + sem_post(&hash_table->row_lock[hash_key]); +#endif + + return(FALSE); +} + + +/* + finds the entry corresponding to key in the hash table + + parameters: + hash_table : pointer to the hash table to use + key : key to index the hash table. + key_len: length of the key in bytes + + returns: + pointer to the data field in the hash table on success + NULL on failure +*/ +static inline void *hash_find( hash_table_t *hash_table, void *key, uint32_t key_len) +{ + uint32_t hash_key, hash_table_size; + hash_entry_t *ptr; + + + hash_table_size = hash_table->size; + + hash_key = hash(key, key_len, 7) % hash_table_size; + +#ifdef __USE_HASH_LOCKS__ + sem_wait(&hash_table->row_lock[hash_key]); +#endif + + ptr = hash_table->row[hash_key]; + while (ptr != NULL) + { + if ((key_len == ptr->key_len) && (memcmp(ptr->key, key, key_len) == 0)) + { +#ifdef __USE_HASH_LOCKS__ + sem_post(&hash_table->row_lock[hash_key]); +#endif + return(ptr->data); + } + ptr = ptr->next; + } +#ifdef __USE_HASH_LOCKS__ + sem_post(&hash_table->row_lock[hash_key]); +#endif + return(NULL); +} + +/* + destroys the hash table and frees all allocated memory + + parameters: + hash_table : pointer to the hash table to use + + returns : nothing +*/ + +static inline void destroy_hash_table( hash_table_t *hash_table) +{ + uint32_t t, count, max_count=0, tot_count=0, hash_table_size; + hash_entry_t *cur_ptr, *tmp_ptr; + + hash_table_size = hash_table->size; + + for (t=0; trow_lock[t]); +#endif + if (hash_table->row[t] != NULL) + { + cur_ptr = hash_table->row[t]; + count = 1; + while (cur_ptr != NULL) + { + free(cur_ptr->key); + tmp_ptr = cur_ptr->next; + free(cur_ptr); + cur_ptr = tmp_ptr; + count++; + } + hash_table->row[t] = NULL; + tot_count += count; + if (count > max_count) max_count = count; + } +#ifdef __USE_HASH_LOCKS__ + sem_post(&hash_table->row_lock[t]); +#endif + } + + printf("Max collision list entries: %u. Total: %u\n", max_count, tot_count); + free(hash_table->row); + free(hash_table->tail); + +#ifdef __USE_HASH_LOCKS__ + free(hash_table->row_lock); +#endif + + free(hash_table); +} + +#endif diff --git a/assembler/tokenizer.h b/assembler/tokenizer.h new file mode 100644 index 0000000..0d81566 --- /dev/null +++ b/assembler/tokenizer.h @@ -0,0 +1,60 @@ +#ifndef __PARSE_UTILS_H_ +#define __PARSE_UTILS_H_ + +/* + author: dr. srinidhi varadarajan + copyright (C) 2005 + + this file contains a thread-safe string tokenization function that can be + used for general purpose parsing. +*/ + +#include +#include +#include +#include + + +/* parses the token in_str delimited by the characters in delim. it returns + an output string out_str, which contains the remaining elements of + the string after the first token. this can be used to parse all tokens in + a line by recursively calling the parse function. + + it also returns the actual delimiting character in delim_char, which can + be used to define numerical ranges. if this is not desired, delim_char may be + set to NULL. + + it returns the first token delimited by characters in delim or NULL, + if no such token is found. + + this is a thread safe implementation +*/ +static inline char *parse_token(char *in_str, char *delim, char **out_str, char *delim_char) +{ + int len; + char *ptr, *tptr, *token; + + /* Bypass leading whitespace delimiters */ + len = strspn(in_str, delim); + ptr = (in_str + len); + + /* Get end of token */ + tptr = strpbrk(ptr, delim); + if (tptr == NULL) return(NULL); + len = tptr - ptr; + + if (delim_char != NULL) *delim_char = *tptr; + + /* Create output string */ + *out_str = tptr + 1; /* go past the delimiter */ + + /* Create token */ + token = (char *) malloc(len + 1); + if (token == NULL) return(NULL); + memcpy(token, ptr, len); + token[len] = (char) 0; + return(token); +} + + +#endif diff --git a/lab0/Makefile b/lab0/Makefile new file mode 100755 index 0000000..c6e2d65 --- /dev/null +++ b/lab0/Makefile @@ -0,0 +1,13 @@ +HEADERS = simulator.h + +default: simulator + +simulator.o: simulator.c $(HEADERS) + gcc -c simulator.c -o simulator.o -std=c99 + +simulator: simulator.o + gcc simulator.o -o simulator -std=c99 + +clean: + -rm -f simulator.o simulator + -rm -f *out *txt diff --git a/lab0/README.md b/lab0/README.md new file mode 100644 index 0000000..bb2de3d --- /dev/null +++ b/lab0/README.md @@ -0,0 +1,13 @@ +MIPS Simulator +============== + +A simulator for the MIPS like Instruction Set, that translates machine code created from the assembler, and then executes the machine instructions. Each instruction goes through a Fetch, Decode, Execute, Memory and Writeback stage of processing. + +# Build + $ make + +# RUN nop.out assembler output file + $ ./simulator nop.out + + + diff --git a/lab0/mipsInstructionMap.h b/lab0/mipsInstructionMap.h new file mode 100644 index 0000000..9994d17 --- /dev/null +++ b/lab0/mipsInstructionMap.h @@ -0,0 +1,35 @@ +/* + * + * mipsInstructionMap.h + * + * Defines instructions as a hex value for comparison + * + * Modified by Masab Ahmad + * + */ + +// R-Type Instructions +#define RTYPEOP 0x0 +#define ADD 0x20 +#define SUB 0x21 +#define AND 0x24 +#define OR 0x25 +#define SLL 0x0 +#define SLT 0x2A +#define SRL 0x2 +#define JR 0x8 + +// I-Type Instructions +#define LW 0x23 +#define SW 0x2B +#define ANDI 0xC +#define ORI 0xD +#define LUI 0xF +#define BEQ 0x4 +#define BNE 0x5 +#define SLTI 0xA +#define ADDI 0x8 + +// J-Type Instructions +#define J 0x2 +#define JAL 0x3 diff --git a/lab0/nop.asm b/lab0/nop.asm new file mode 100644 index 0000000..2e53432 --- /dev/null +++ b/lab0/nop.asm @@ -0,0 +1,7 @@ +.text +sll $zero $zero, 0 # execute NOOP ... done + +.data +2048: .word 10 +2049: .word 32 + diff --git a/lab0/simulator.c b/lab0/simulator.c new file mode 100644 index 0000000..945ced2 --- /dev/null +++ b/lab0/simulator.c @@ -0,0 +1,290 @@ +/* + * riscy-uconn simulator.c + */ + +#include +#include +#include +#include "simulator.h" +#include "mipsInstructionMap.h" + +int debug = 0; + +int main(int argc, char *argv[]) { + + if (argc != 2) { + printf("Incorrect number of arguments\n"); + exit(1); + } + else { + // Open Input file + FILE *fp; + fp = fopen(argv[1], "r"); + + // Call initialize function for registers and instruction/data memory + initialize(fp); + + // Process one instruction at a time + process_instructions(); + + printf("\n Printing Output Registers \n"); + + // Output registers + rdump(); + + // Output Memory + mdump(); + + // Dealloc .data + free(memory); + memory = NULL; + + // Close File + fclose (fp); + return 0; + } +} + +// Function to take in instruciton to parse +void process_instructions() { + + int terminate = 0; + // Cycle PC + int instruction_counter = 0; + + while(terminate != 1) + { + // set terminate flag when SLL $0, $0, 0 (aka NOOP) is executed + if (memory[pc/4] == 0) + terminate = 1; + + //Fetch Instruction + unsigned int instruction_fetch; + instruction_fetch = fetch(); + if(debug==1) + printf("\n IMEM ADDR:%d instruction 0x%08x", pc/4, instruction_fetch); + instruction_counter++; + + // Decode Instruction + struct Registers decode_out; + decode_out = decode(instruction_fetch); + + // Execute Instruction + struct Registers alu_out; + alu_out = execute(decode_out); + + // Memory Stage + struct Registers mem_out; + mem_out = memory_stage(alu_out); + + // Write Back Stage + write_back_stage(mem_out); + }//while pc loop + printf("\n TOTAL INSTRUCTIONS EXECUTED: %d", instruction_counter); +} //process_instruction + +// Advance PC +void advance_pc(int step) { + pc += step; +} + +unsigned int fetch() { + unsigned int inst = 0; + return inst = memory[pc/4]; +} + +struct Registers decode(unsigned int instruction_fetch) { + struct Registers reg_temp; + + // your code for decode phase goes here. + + return reg_temp; +} + + +struct Registers execute(struct Registers decode_out) +{ + return decode_out; +} + + +struct Registers memory_stage(struct Registers alu_out) +{ + return alu_out; +} + +void write_back_stage(struct Registers mem_out) +{ +} // WB Done + + +// Output reigsters +void rdump() +{ + printf("$0 $zero 0x%08x\n", registers[0]); + printf("$1 $at 0x%08x\n", registers[1]); + printf("$2 $v0 0x%08x\n", registers[2]); + printf("$3 $v1 0x%08x\n", registers[3]); + printf("$4 $a0 0x%08x\n", registers[4]); + printf("$5 $a1 0x%08x\n", registers[5]); + printf("$6 $a2 0x%08x\n", registers[6]); + printf("$7 $a3 0x%08x\n", registers[7]); + printf("$8 $t0 0x%08x\n", registers[8]); + printf("$9 $t1 0x%08x\n", registers[9]); + printf("$10 $t2 0x%08x\n", registers[10]); + printf("$11 $t3 0x%08x\n", registers[11]); + printf("$12 $t4 0x%08x\n", registers[12]); + printf("$13 $t5 0x%08x\n", registers[13]); + printf("$14 $t6 0x%08x\n", registers[14]); + printf("$15 $t7 0x%08x\n", registers[15]); + printf("$16 $s0 0x%08x\n", registers[16]); + printf("$17 $s1 0x%08x\n", registers[17]); + printf("$18 $s2 0x%08x\n", registers[18]); + printf("$19 $s3 0x%08x\n", registers[19]); + printf("$20 $s4 0x%08x\n", registers[20]); + printf("$21 $s5 0x%08x\n", registers[21]); + printf("$22 $s6 0x%08x\n", registers[22]); + printf("$23 $s7 0x%08x\n", registers[23]); + printf("$24 $t8 0x%08x\n", registers[24]); + printf("$25 $t9 0x%08x\n", registers[25]); + printf("$26 $k0 0x%08x\n", registers[26]); + printf("$27 $k1 0x%08x\n", registers[27]); + printf("$28 $gp 0x%08x\n", registers[28]); + printf("$29 $sp 0x%08x\n", registers[29]); + printf("$30 $fp 0x%08x\n", registers[30]); + printf("$31 $ra 0x%08x\n", registers[31]); + + printf(" --> pc 0x%08x\n", pc); +} + +// Output Memory +void mdump() +{ + FILE *fptr; + fptr = fopen("mdump.txt","w"); + int i = 0; + for(i=0;i<16384;i++) + { + fprintf(fptr,"\n Memory[%d] = %d",i,memory[i]); + } +} + +void initialize(FILE *fp) +{ + if (fp == NULL) + { + printf("Error opening input file.\n"); + exit(1); + } + + // Initialize registers values' to 0x0 + for (int i = 0; i < 32; i++) + registers[i] = 0x0; + + printf("\n Initialized Registers \n"); + + // Malloc memory + memory = (int *)malloc(16384 * sizeof(int)); + if (memory == NULL) + { + printf("Not enough memory. Aborting..\n"); + exit(1); + } + + // Initialize 'memory' array to -1 + for (int i = 0; i < 16384; i++) + { + memory[i] = -1; + } + + printf("\n Initialized Memory \n"); + + // Initialize variables for parsing + char line[MAX_LENGTH+2]; + char *p; + int i = 0, line_num = 0; + //int line_num = 0, i = 0, data_line = 0; + + // Copy .text section to memory, breaks at nop + while (fgets(line, MAX_LENGTH+2, fp) != NULL) + { + line_num++; + + // Remove '\n' from 'line' + p = strchr(line, '\n'); + if (p != NULL) + *p = '\0'; + + memory[i] = getDec(line); + //printf("\n %d",memory[i]); + + if (strcmp(line, "11111111111111111111111111111111") == 0) + { + memory[i] = 0; + i = 0x800; + break; + } + else + i++; + } + + int j = 2048; //Data Memory Starts at 2048 + for(j=i;j<16384;j++) + { + memory[j] = 2; + //printf("\n %d",memory[i]); + } + + printf("\n Instructions Read, Memory Offset: %d\n", line_num); + + // Seek fp to first instruction in .data + char data[MAX_LENGTH+2]; + int bytes = 33 * line_num; + fseek(fp, bytes, SEEK_SET); + + // Copy .data section to memory + while (fgets(line, MAX_LENGTH+2, fp) != NULL) + { + // Remove '\n' from 'line' + p = strchr(line, '\n'); + if (p != NULL) + *p = '\0'; + + memory[i] = getDec(line); + printf("\n Data: %d %d",i,memory[i]); + i++; + } + + printf("\n Data put in Memory \n"); +} + +// Convert a binary string to a decimal value +int getDec(char *bin) +{ + int b, k, m, n; + int len, sum = 0; + + // Length - 1 to accomodate for null terminator + len = strlen(bin) - 1; + + // Iterate the string + for(k = 0; k <= len; k++) + { + // Convert char to numeric value + n = (bin[k] - '0'); + + // Check the character is binary + if ((n > 1) || (n < 0)) + { + return 0; + } + + for(b = 1, m = len; m > k; m--) + b *= 2; + + // sum it up + sum = sum + n * b; + } + return sum; +} + diff --git a/lab0/simulator.h b/lab0/simulator.h new file mode 100644 index 0000000..1c0a692 --- /dev/null +++ b/lab0/simulator.h @@ -0,0 +1,65 @@ +/* + + * simulator.h + * + * Simulator header file declaring variables and methods + * + * Modified by Masab Ahmad + * 25/07/19 + */ + +#ifndef SIMULATOR_H_ +#define SIMULATOR_H_ + +// Define MAX_LENGTH for number of registers & instruction length +#define MAX_LENGTH 32 + +// Array of size MAX_LENGTH to hold registers +int registers[MAX_LENGTH]; + +// PC Register +unsigned int pc = 0; + +// Memory Allocated +//unsigned int *memory; +int *memory; + +struct Registers +{ + int x; + unsigned int y; + int reg; + int rs; + int rt; + int rd; + int sa; + unsigned short imm; + + int memory_flag; + int addr_mem; + int branch_flag; + int jmp_out_31; + + //ALU Inputs/Outputs + int A; + int B; + int C; + int D; + +}; + +void initialize(FILE *fp); +void process_instructions(); +int getDec(char *bin); +void isZero(int reg); +void advance_pc(int step); +void rdump(); +void mdump(); + +unsigned int fetch(); +struct Registers decode(unsigned int instuction_fetch); +struct Registers execute(struct Registers decode_out); +struct Registers memory_stage(struct Registers alu_out); +void write_back_stage(struct Registers memory_out); + +#endif /* SIMULATOR_H_ */