summaryrefslogtreecommitdiff
path: root/mips.c
diff options
context:
space:
mode:
Diffstat (limited to 'mips.c')
-rw-r--r--mips.c315
1 files changed, 315 insertions, 0 deletions
diff --git a/mips.c b/mips.c
new file mode 100644
index 0000000..dcda5f7
--- /dev/null
+++ b/mips.c
@@ -0,0 +1,315 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#define MEM_SIZE 36
+#define RA 31
+#define V0 2
+#define V1 3
+#define A0 4
+#define A1 5
+#define A2 6
+#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 {
+ uint32_t value;
+ rtype_t r;
+ jtype_t j;
+ itype_t i;
+ };
+} inst_t;
+
+uint8_t memory[MEM_SIZE] = {0};
+uint32_t pc = 0, hi = 0, lo = 0;
+uint32_t regFile[32] = {0};
+
+/* 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) >> 24) {
+ 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
+ exit(0);
+ 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
+ exit(regFile[A0]);
+ }
+}
+
+/* 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 8: // jr
+ pc = a;
+ break;
+ case 9: // jalr
+ regFile[r.rd] = pc + 4;
+ pc = a;
+ break;
+ case 12: // syscall
+ Syscall();
+ break;
+ }
+}
+
+/* InstExec: Execute a given instruction */
+void InstExec(const inst_t inst) {
+ if (inst.type == NOP) {
+ return;
+ }
+ switch (inst.j.op) {
+ case 0: // R-type instruction
+ ExecRtype(inst);
+ break;
+ case 3: // jal
+ regFile[RA] = pc + 4;
+ /* intentional fall through */
+ case 2: // j
+ pc = (0xF0000000 & pc ) | inst.j.addr;
+ break;
+ case 4: // beq
+ pc = (regFile[inst.i.rs] == regFile[inst.i.rt]) ? pc + 4 +
+ inst.i.imm : pc;
+ break;
+ case 5: // bne
+ pc = (regFile[inst.i.rs] != regFile[inst.i.rt]) ? pc + 4 +
+ inst.i.imm : pc;
+ break;
+ case 8: // addi
+ regFile[inst.i.rt] = (signed)inst.i.rs + (signed)inst.i.imm;
+ break;
+ case 9: // addiu
+ regFile[inst.i.rt] = inst.i.rs + inst.i.imm;
+ break;
+ case 12: // andi
+ regFile[inst.i.rt] = inst.i.rs & inst.i.imm;
+ break;
+ case 13: // ori
+ regFile[inst.i.rt] = inst.i.rs | inst.i.imm;
+ break;
+ case 14: // xori
+ regFile[inst.i.rt] = inst.i.rs ^ inst.i.imm;
+ break;
+ case 10: // slti
+ regFile[inst.i.rt] = (signed)inst.i.rs < (signed)inst.i.imm;
+ break;
+ case 11: // sltiu
+ regFile[inst.i.rt] = inst.i.rs < inst.i.imm;
+ break;
+ case 15: // lui
+ regFile[inst.i.rt] = inst.i.imm << 16;
+ break;
+ case 35: // lw
+ memcpy(regFile + inst.i.rs, memory + inst.i.rt + inst.i.imm,
+ WORD_SIZE);
+ break;
+ case 43: // sw
+ memcpy(memory + inst.i.rt + inst.i.imm, regFile + inst.i.rs,
+ WORD_SIZE);
+ break;
+ }
+}
+
+void CycleCpu(void) {
+ inst_t instFetch, instExec;
+ memset(&instFetch, 0, sizeof(inst_t));
+ memset(&instExec, 0, sizeof(inst_t));
+ while (pc < MEM_SIZE) {
+ InstFetch(&instFetch);
+ InstExec(instExec);
+ instExec = instFetch;
+ }
+}
+
+int LoadBinary(const char * const path) {
+ FILE *fp = fopen(path, "r");
+ if (fp == NULL) {
+ perror("LoadBinary");
+ return -1;
+ }
+ int8_t byte = 0;
+ size_t i = 0;
+ while ((byte = fgetc(fp)) != EOF && i < MEM_SIZE) {
+ memory[i++] = byte;
+ }
+ fclose(fp);
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ if (LoadBinary(*++argv) == -1) {
+ return -1;
+ }
+ CycleCpu();
+}
+