summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--instruction.c240
-rw-r--r--instruction.h42
-rw-r--r--load.c67
-rw-r--r--load.h10
-rwxr-xr-xmakefile5
-rwxr-xr-xqdme.c303
-rwxr-xr-xqdme.h40
7 files changed, 372 insertions, 335 deletions
diff --git a/instruction.c b/instruction.c
new file mode 100644
index 0000000..a5fe208
--- /dev/null
+++ b/instruction.c
@@ -0,0 +1,240 @@
+#include "qdme.h"
+#include "instruction.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* InstFetch: Fetch the next instruction from memory into the given
+ * instruction */
+void InstFetch(inst_t *inst) {
+ uint32_t value = 0;
+ memcpy(&value, memory + pc, WORD_SIZE);
+ switch ((value & 0xFC000000) >> 26) {
+ case 0:
+ inst->type = RTYPE;
+ inst->r.op = (value & 0xFC000000) >> 26;
+ inst->r.rs = (value & 0x03E00000) >> 21;
+ inst->r.rt = (value & 0x001F0000) >> 16;
+ inst->r.rd = (value & 0x0000F800) >> 11;
+ inst->r.shamt = (value & 0x000007C0) >> 6;
+ inst->r.func = value & 0x0000002F;
+ break;
+ case 2:
+ case 3:
+ inst->type = JTYPE;
+ inst->j.op = (value & 0xFC000000) >> 26;
+ inst->j.addr = value & 0X03FFFFFF;
+ break;
+ default:
+ inst->type = ITYPE;
+ inst->i.op = (value & 0xFC000000) >> 26;
+ inst->i.rs = (value & 0x03E00000) >> 21;
+ inst->i.rt = (value & 0x001F0000) >> 16;
+ inst->i.imm = value & 0x0000FFFF;
+ break;
+ }
+ if (inst->value == 0) {
+ inst->type = NOP;
+ }
+ pc += WORD_SIZE;
+}
+
+static void Syscall(void) {
+ char c, *s;
+ switch (regFile[V0]) {
+ case 1: // print integer
+ printf("%d", regFile[A0]);
+ break;
+ case 2: // print float
+ break;
+ case 3: // print double
+ break;
+ case 4: // print string
+ printf("%s", memory + regFile[A0]);
+ break;
+ case 5: // read integer
+ scanf("%d", (int *)regFile + V0);
+ break;
+ case 6: // read float
+ break;
+ case 7: // read double
+ break;
+ case 8: // read string
+ s = (char *)calloc(regFile[A0], sizeof(char));
+ fgets(s, regFile[A0], stdin);
+ memcpy(memory + regFile[A1], s, regFile[A0]);
+ free(s);
+ break;
+ case 9: // sbrk
+ break;
+ case 10: //exit
+ exitStatus = 0;
+ run = false;
+ break;
+ case 11: // print char
+ printf("%c", regFile[A0]);
+ break;
+ case 12: // read char
+ c = 0;
+ scanf("%c", &c);
+ regFile[V0] = c;
+ break;
+ case 13: // open file
+ break;
+ case 14: // read from file
+ break;
+ case 15: // write to file
+ break;
+ case 16: // close file
+ break;
+ case 17: // exit2
+ exitStatus = regFile[A0];
+ run = false;
+ break;
+ }
+}
+
+/* ExecRtype: Execute a given R-Type instruction */
+static void ExecRtype(const inst_t inst) {
+ rtype_t r = inst.r;
+ uint32_t a = regFile[r.rs], b = regFile[r.rt];
+ uint64_t mult = 0;
+ switch (r.func) {
+ case 32: // add
+ regFile[r.rd] = (signed)a + (signed)b;
+ break;
+ case 33: // addu
+ regFile[r.rd] = a + b;
+ break;
+ case 36: // and
+ regFile[r.rd] = a & b;
+ break;
+ case 37: // or
+ regFile[r.rd] = a | b;
+ break;
+ case 42: // slt
+ regFile[r.rd] = (signed)a < (signed)b;
+ break;
+ case 43: // sltu
+ regFile[r.rd] = a < b;
+ break;
+ case 34: // sub
+ regFile[r.rd] = (signed)a - (signed)b;
+ break;
+ case 35: // subu
+ regFile[r.rd] = a - b;
+ break;
+ case 38: // xor
+ regFile[r.rd] = a ^ b;
+ break;
+ case 0: // sll
+ regFile[r.rd] = b << r.shamt;
+ break;
+ case 3: // sra
+ regFile[r.rd] = (signed)b >> r.shamt;
+ break;
+ case 2: // srl
+ regFile[r.rd] = b >> r.shamt;
+ break;
+ case 26: // div
+ hi = (signed)a % (signed)b;
+ lo = (signed)a / (signed)b;
+ break;
+ case 27: // divu
+ hi = a % b;
+ lo = a / b;
+ break;
+ case 24: // mult
+ mult = (signed)a * (signed)b;
+ hi = (0xFFFFFFFF00000000 & mult) >> 32;
+ lo = 0x00000000FFFFFFFF & mult;
+ break;
+ case 25: // multu
+ mult = a * b;
+ hi = (0xFFFFFFFF00000000 & mult) >> 32;
+ lo = 0x00000000FFFFFFFF & mult;
+ break;
+ case 16: // MFHI
+ regFile[r.rd] = hi;
+ break;
+ case 18: // MFLO
+ regFile[r.rd] = lo;
+ break;
+ case 17: // MTHI
+ hi = regFile[r.rs];
+ break;
+ case 19: // MTLO
+ lo = regFile[r.rs];
+ break;
+ case 9: // jalr
+ regFile[r.rd] = pc;
+ /* Intentional Fall Through */
+ case 8: // jr
+ pc = a;
+ break;
+ case 12: // syscall
+ Syscall();
+ break;
+ }
+}
+
+/* InstExec: Execute a given instruction */
+void InstExec(const inst_t inst) {
+ if (inst.type == NOP) {
+ return;
+ }
+ int16_t imm = inst.i.imm;
+ int32_t a = regFile[inst.i.rs];
+ switch (inst.j.op) {
+ case 0: // R-type instruction
+ ExecRtype(inst);
+ break;
+ case 3: // jal
+ regFile[RA] = pc;
+ /* intentional fall through */
+ case 2: // j
+ pc = (0xF0000000 & pc ) | (signed)inst.j.addr;
+ break;
+ case 4: // beq
+ pc = (regFile[inst.i.rs] == regFile[inst.i.rt]) ? pc + 4 +
+ imm : pc;
+ break;
+ case 5: // bne
+ pc = (regFile[inst.i.rs] != regFile[inst.i.rt]) ? pc + 4 +
+ imm : pc;
+ break;
+ case 8: // addi
+ regFile[inst.i.rt] = a + imm;
+ break;
+ case 9: // addiu
+ regFile[inst.i.rt] = (unsigned)a + imm;
+ break;
+ case 12: // andi
+ regFile[inst.i.rt] = a & imm;
+ break;
+ case 13: // ori
+ regFile[inst.i.rt] = a | imm;
+ break;
+ case 14: // xori
+ regFile[inst.i.rt] = a ^ imm;
+ break;
+ case 10: // slti
+ regFile[inst.i.rt] = a < imm;
+ break;
+ case 11: // sltiu
+ regFile[inst.i.rt] = (unsigned)a < (uint16_t)imm;
+ break;
+ case 15: // lui
+ regFile[inst.i.rt] = imm << 16;
+ break;
+ case 35: // lw
+ memcpy(regFile + inst.i.rt, memory + regFile[inst.i.rs] + imm,
+ WORD_SIZE);
+ break;
+ case 43: // sw
+ memcpy(memory + regFile[inst.i.rs] + imm, regFile + inst.i.rt,
+ WORD_SIZE);
+ break;
+ }
+}
+
diff --git a/instruction.h b/instruction.h
new file mode 100644
index 0000000..2e10ed6
--- /dev/null
+++ b/instruction.h
@@ -0,0 +1,42 @@
+#ifndef INSTRUCTION_H
+#define INSTRUCTION_H
+
+#include <stdint.h>
+
+typedef struct {
+ unsigned int op: 6;
+ unsigned int rs: 5;
+ unsigned int rt: 5;
+ unsigned int rd: 5;
+ unsigned int shamt: 5;
+ unsigned int func: 6;
+} rtype_t;
+
+typedef struct {
+ unsigned int op: 6;
+ unsigned int rs: 5;
+ unsigned int rt: 5;
+ unsigned int imm: 16;
+} itype_t;
+
+typedef struct {
+ unsigned int op: 6;
+ unsigned int addr: 26;
+} jtype_t;
+
+typedef enum { NOP, RTYPE, ITYPE, JTYPE } type_t;
+
+typedef struct {
+ type_t type;
+ union {
+ rtype_t r;
+ jtype_t j;
+ itype_t i;
+ uint32_t value;
+ };
+} inst_t;
+
+void InstFetch(inst_t *inst);
+void InstExec(const inst_t inst);
+
+#endif
diff --git a/load.c b/load.c
new file mode 100644
index 0000000..1aa4efd
--- /dev/null
+++ b/load.c
@@ -0,0 +1,67 @@
+#include "load.h"
+#include "qdme.h"
+#include "elf.h"
+#include <stdlib.h>
+
+int LoadBinary(const char * const path) {
+ FILE *fp = fopen(path, "r");
+ if (fp == NULL) {
+ perror("LoadBinary");
+ return -1;
+ }
+
+ ElfHeader_t e = ReadElf(fp);
+ if (!ValidateElf(e)) {
+ return -1;
+ }
+
+ pc = e.e_entry;
+
+ const size_t n = e.e_phnum;
+ ProgramHeader_t *p = (ProgramHeader_t *)calloc(n, e.e_phentsize);
+ if (p == NULL) {
+ perror("calloc");
+ return -1;
+ }
+ ReadProgramHeader(n, p, fp);
+
+ for (size_t i = 0; i < n; i++) {
+ memsize += p[i].memsz;
+ }
+
+ if ((memory = (uint8_t *)calloc(memsize, sizeof(uint8_t))) == NULL) {
+ perror("calloc");
+ free((void *)p);
+ fclose(fp);
+ return -1;
+ }
+
+ for (size_t i = 0; i < n; i++) {
+ if (LoadProgramHeader(p[i], fp) == -1) {
+ free((void *)p);
+ fclose(fp);
+ return -1;
+ }
+ }
+
+ free((void *)p);
+ fclose(fp);
+ return 0;
+}
+
+/* LoadProgramHeader: Load the program segment described by the given program
+ * header from file fp. Returns 0 on success and -1 on failure. */
+int LoadProgramHeader(ProgramHeader_t p, FILE *fp) {
+ uint8_t *memloc = memory + p.vaddr;
+ size_t s = p.filesz;
+ if (fseek(fp, p.offset, SEEK_SET) != 0) {
+ perror("fseek");
+ return -1;
+ }
+ fread(memloc, sizeof(uint8_t), s, fp);
+ if (ferror(fp)) {
+ return -1;
+ }
+ return 0;
+}
+
diff --git a/load.h b/load.h
new file mode 100644
index 0000000..e17e7ec
--- /dev/null
+++ b/load.h
@@ -0,0 +1,10 @@
+#ifndef LOAD_H
+#define LOAD_H
+
+#include "elf.h"
+#include <stdio.h>
+
+int LoadBinary(const char * const path);
+int LoadProgramHeader(ProgramHeader_t p, FILE *fp);
+
+#endif
diff --git a/makefile b/makefile
index 04b267f..9bb2964 100755
--- a/makefile
+++ b/makefile
@@ -1,7 +1,7 @@
CC=gcc
CFLAGS=-Wall -Werror -pedantic --std=c17
-OBJS=qdme.o elf.o
-SRCS=qdme.c elf.c
+OBJS=qdme.o elf.o instruction.o load.o
+SRCS=qdme.c elf.c instruction.c load.c
TARGET=qdme
%.o: %.c %.h
@@ -17,3 +17,4 @@ qdme: $(OBJS)
clean:
rm -rf $(TARGET) $(OBJS)
+
diff --git a/qdme.c b/qdme.c
index 3e03190..a64fb27 100755
--- a/qdme.c
+++ b/qdme.c
@@ -1,10 +1,9 @@
#include <stdio.h>
#include <stdlib.h>
-#include <stdbool.h>
#include <string.h>
-#include <arpa/inet.h>
#include "qdme.h"
-#include "elf.h"
+#include "load.h"
+#include "instruction.h"
uint8_t *memory = NULL;
size_t memsize = MEM_PADD;
@@ -13,242 +12,6 @@ uint32_t regFile[32] = {0};
int exitStatus = 0;
bool run = true;
-int LoadProgramHeader(ProgramHeader_t p, FILE *fp);
-
-/* InstFetch: Fetch the next instruction from memory into the given
- * instruction */
-void InstFetch(inst_t *inst) {
- uint32_t value = 0;
- memcpy(&value, memory + pc, WORD_SIZE);
- switch ((value & 0xFC000000) >> 26) {
- case 0:
- inst->type = RTYPE;
- inst->r.op = (value & 0xFC000000) >> 26;
- inst->r.rs = (value & 0x03E00000) >> 21;
- inst->r.rt = (value & 0x001F0000) >> 16;
- inst->r.rd = (value & 0x0000F800) >> 11;
- inst->r.shamt = (value & 0x000007C0) >> 6;
- inst->r.func = value & 0x0000002F;
- break;
- case 2:
- case 3:
- inst->type = JTYPE;
- inst->j.op = (value & 0xFC000000) >> 26;
- inst->j.addr = value & 0X03FFFFFF;
- break;
- default:
- inst->type = ITYPE;
- inst->i.op = (value & 0xFC000000) >> 26;
- inst->i.rs = (value & 0x03E00000) >> 21;
- inst->i.rt = (value & 0x001F0000) >> 16;
- inst->i.imm = value & 0x0000FFFF;
- break;
- }
- if (inst->value == 0) {
- inst->type = NOP;
- }
- pc += WORD_SIZE;
-}
-
-void Syscall(void) {
- char c, *s;
- switch (regFile[V0]) {
- case 1: // print integer
- printf("%d", regFile[A0]);
- break;
- case 2: // print float
- break;
- case 3: // print double
- break;
- case 4: // print string
- printf("%s", memory + regFile[A0]);
- break;
- case 5: // read integer
- scanf("%d", (int *)regFile + V0);
- break;
- case 6: // read float
- break;
- case 7: // read double
- break;
- case 8: // read string
- s = (char *)calloc(regFile[A0], sizeof(char));
- fgets(s, regFile[A0], stdin);
- memcpy(memory + regFile[A1], s, regFile[A0]);
- free(s);
- break;
- case 9: // sbrk
- break;
- case 10: //exit
- exitStatus = 0;
- run = false;
- break;
- case 11: // print char
- printf("%c", regFile[A0]);
- break;
- case 12: // read char
- c = 0;
- scanf("%c", &c);
- regFile[V0] = c;
- break;
- case 13: // open file
- break;
- case 14: // read from file
- break;
- case 15: // write to file
- break;
- case 16: // close file
- break;
- case 17: // exit2
- exitStatus = regFile[A0];
- run = false;
- break;
- }
-}
-
-/* ExecRtype: Execute a given R-Type instruction */
-void ExecRtype(const inst_t inst) {
- rtype_t r = inst.r;
- uint32_t a = regFile[r.rs], b = regFile[r.rt];
- uint64_t mult = 0;
- switch (r.func) {
- case 32: // add
- regFile[r.rd] = (signed)a + (signed)b;
- break;
- case 33: // addu
- regFile[r.rd] = a + b;
- break;
- case 36: // and
- regFile[r.rd] = a & b;
- break;
- case 37: // or
- regFile[r.rd] = a | b;
- break;
- case 42: // slt
- regFile[r.rd] = (signed)a < (signed)b;
- break;
- case 43: // sltu
- regFile[r.rd] = a < b;
- break;
- case 34: // sub
- regFile[r.rd] = (signed)a - (signed)b;
- break;
- case 35: // subu
- regFile[r.rd] = a - b;
- break;
- case 38: // xor
- regFile[r.rd] = a ^ b;
- break;
- case 0: // sll
- regFile[r.rd] = b << r.shamt;
- break;
- case 3: // sra
- regFile[r.rd] = (signed)b >> r.shamt;
- break;
- case 2: // srl
- regFile[r.rd] = b >> r.shamt;
- break;
- case 26: // div
- hi = (signed)a % (signed)b;
- lo = (signed)a / (signed)b;
- break;
- case 27: // divu
- hi = a % b;
- lo = a / b;
- break;
- case 24: // mult
- mult = (signed)a * (signed)b;
- hi = (0xFFFFFFFF00000000 & mult) >> 32;
- lo = 0x00000000FFFFFFFF & mult;
- break;
- case 25: // multu
- mult = a * b;
- hi = (0xFFFFFFFF00000000 & mult) >> 32;
- lo = 0x00000000FFFFFFFF & mult;
- break;
- case 16: // MFHI
- regFile[r.rd] = hi;
- break;
- case 18: // MFLO
- regFile[r.rd] = lo;
- break;
- case 17: // MTHI
- hi = regFile[r.rs];
- break;
- case 19: // MTLO
- lo = regFile[r.rs];
- break;
- case 9: // jalr
- regFile[r.rd] = pc;
- /* Intentional Fall Through */
- case 8: // jr
- pc = a;
- break;
- case 12: // syscall
- Syscall();
- break;
- }
-}
-
-/* InstExec: Execute a given instruction */
-void InstExec(const inst_t inst) {
- if (inst.type == NOP) {
- return;
- }
- int16_t imm = inst.i.imm;
- int32_t a = regFile[inst.i.rs];
- switch (inst.j.op) {
- case 0: // R-type instruction
- ExecRtype(inst);
- break;
- case 3: // jal
- regFile[RA] = pc;
- /* intentional fall through */
- case 2: // j
- pc = (0xF0000000 & pc ) | (signed)inst.j.addr;
- break;
- case 4: // beq
- pc = (regFile[inst.i.rs] == regFile[inst.i.rt]) ? pc + 4 +
- imm : pc;
- break;
- case 5: // bne
- pc = (regFile[inst.i.rs] != regFile[inst.i.rt]) ? pc + 4 +
- imm : pc;
- break;
- case 8: // addi
- regFile[inst.i.rt] = a + imm;
- break;
- case 9: // addiu
- regFile[inst.i.rt] = (unsigned)a + imm;
- break;
- case 12: // andi
- regFile[inst.i.rt] = a & imm;
- break;
- case 13: // ori
- regFile[inst.i.rt] = a | imm;
- break;
- case 14: // xori
- regFile[inst.i.rt] = a ^ imm;
- break;
- case 10: // slti
- regFile[inst.i.rt] = a < imm;
- break;
- case 11: // sltiu
- regFile[inst.i.rt] = (unsigned)a < (uint16_t)imm;
- break;
- case 15: // lui
- regFile[inst.i.rt] = imm << 16;
- break;
- case 35: // lw
- memcpy(regFile + inst.i.rt, memory + regFile[inst.i.rs] + imm,
- WORD_SIZE);
- break;
- case 43: // sw
- memcpy(memory + regFile[inst.i.rs] + imm, regFile + inst.i.rt,
- WORD_SIZE);
- break;
- }
-}
-
void CycleCpu(void) {
inst_t instFetch, instExec;
memset(&instFetch, 0, sizeof(inst_t));
@@ -260,68 +23,6 @@ void CycleCpu(void) {
}
}
-int LoadBinary(const char * const path) {
- FILE *fp = fopen(path, "r");
- if (fp == NULL) {
- perror("LoadBinary");
- return -1;
- }
-
- ElfHeader_t e = ReadElf(fp);
- if (!ValidateElf(e)) {
- return -1;
- }
-
- pc = e.e_entry;
-
- const size_t n = e.e_phnum;
- ProgramHeader_t *p = (ProgramHeader_t *)calloc(n, e.e_phentsize);
- if (p == NULL) {
- perror("calloc");
- return -1;
- }
- ReadProgramHeader(n, p, fp);
-
- for (size_t i = 0; i < n; i++) {
- memsize += p[i].memsz;
- }
-
- if ((memory = (uint8_t *)calloc(memsize, sizeof(uint8_t))) == NULL) {
- perror("calloc");
- free((void *)p);
- fclose(fp);
- return -1;
- }
-
- for (size_t i = 0; i < n; i++) {
- if (LoadProgramHeader(p[i], fp) == -1) {
- free((void *)p);
- fclose(fp);
- return -1;
- }
- }
-
- free((void *)p);
- fclose(fp);
- return 0;
-}
-
-/* LoadProgramHeader: Load the program segment described by the given program
- * header from file fp. Returns 0 on success and -1 on failure. */
-int LoadProgramHeader(ProgramHeader_t p, FILE *fp) {
- uint8_t *memloc = memory + p.vaddr;
- size_t s = p.filesz;
- if (fseek(fp, p.offset, SEEK_SET) != 0) {
- perror("fseek");
- return -1;
- }
- fread(memloc, sizeof(uint8_t), s, fp);
- if (ferror(fp)) {
- return -1;
- }
- return 0;
-}
-
int main(int argc, char *argv[]) {
if (LoadBinary(*++argv) == -1) {
return -1;
diff --git a/qdme.h b/qdme.h
index 611278f..eb70d25 100755
--- a/qdme.h
+++ b/qdme.h
@@ -1,7 +1,9 @@
#ifndef _QDME_H
#define _QDME_H
+#include <stdbool.h>
#include <stdint.h>
+#include <stddef.h>
#define MEM_PADD 12
#define RA 31
@@ -13,38 +15,12 @@
#define A3 7
#define WORD_SIZE 4
-typedef struct {
- unsigned int op: 6;
- unsigned int rs: 5;
- unsigned int rt: 5;
- unsigned int rd: 5;
- unsigned int shamt: 5;
- unsigned int func: 6;
-} rtype_t;
-
-typedef struct {
- unsigned int op: 6;
- unsigned int rs: 5;
- unsigned int rt: 5;
- unsigned int imm: 16;
-} itype_t;
-
-typedef struct {
- unsigned int op: 6;
- unsigned int addr: 26;
-} jtype_t;
-
-typedef enum { NOP, RTYPE, ITYPE, JTYPE } type_t;
-
-typedef struct {
- type_t type;
- union {
- rtype_t r;
- jtype_t j;
- itype_t i;
- uint32_t value;
- };
-} inst_t;
+extern uint8_t *memory;
+extern size_t memsize;
+extern uint32_t pc, hi, lo;
+extern uint32_t regFile[32];
+extern int exitStatus;
+extern bool run;
#endif