aboutsummaryrefslogtreecommitdiff
path: root/comp1521/smips/instr.c
diff options
context:
space:
mode:
authorNicolas James <Eele1Ephe7uZahRie@tutanota.com>2025-02-13 18:00:17 +1100
committerNicolas James <Eele1Ephe7uZahRie@tutanota.com>2025-02-13 18:00:17 +1100
commit98cef5e9a772602d42acfcf233838c760424db9a (patch)
tree5277fa1d7cc0a69a0f166fcbf10fd320f345f049 /comp1521/smips/instr.c
initial commit
Diffstat (limited to 'comp1521/smips/instr.c')
-rw-r--r--comp1521/smips/instr.c160
1 files changed, 160 insertions, 0 deletions
diff --git a/comp1521/smips/instr.c b/comp1521/smips/instr.c
new file mode 100644
index 0000000..645fbae
--- /dev/null
+++ b/comp1521/smips/instr.c
@@ -0,0 +1,160 @@
+#include "instr.h"
+
+// Gets the immediate bits, clearing others and shifting right.
+uint32_t get_i(const uint32_t instr) { return instr & IMMEDIATE_BITS; }
+
+// Gets the pattern bits, clearing others and shifting right.
+uint32_t get_p(const uint32_t instr) { return (instr & PATTERN_BITS) >> 26; }
+
+// Gets the d bits, clearing others and shifting right.
+uint32_t get_d(const uint32_t instr) { return (instr & D_BITS) >> 11; }
+
+// Gets the t bits, clearing others and shifting right.
+uint32_t get_t(const uint32_t instr) { return (instr & T_BITS) >> 16; }
+
+// Gets the s bits, clearing others and shifting right.
+uint32_t get_s(const uint32_t instr) { return (instr & S_BITS) >> 21; }
+
+// $d = $s + $t.
+void mips_add(const uint32_t instr, uint32_t registers[32]) {
+ int d = (int16_t)get_d(instr);
+ int t = (int16_t)get_t(instr);
+ int s = (int16_t)get_s(instr);
+ registers[d] = registers[s] + registers[t];
+}
+
+// $d = $s - $t.
+void mips_sub(const uint32_t instr, uint32_t registers[32]) {
+ int d = (int16_t)get_d(instr);
+ int t = (int16_t)get_t(instr);
+ int s = (int16_t)get_s(instr);
+ registers[d] = registers[s] - registers[t];
+}
+// $d = $s & $t.
+void mips_and(const uint32_t instr, uint32_t registers[32]) {
+ int d = (int16_t)get_d(instr);
+ int t = (int16_t)get_t(instr);
+ int s = (int16_t)get_s(instr);
+ registers[d] = registers[s] & registers[t];
+}
+
+// $d = $s | $t.
+void mips_or(const uint32_t instr, uint32_t registers[32]) {
+ int d = (int16_t)get_d(instr);
+ int t = (int16_t)get_t(instr);
+ int s = (int16_t)get_s(instr);
+ registers[d] = registers[s] | registers[t];
+}
+
+// $d = ($s < $t).
+void mips_slt(const uint32_t instr, uint32_t registers[32]) {
+ int d = (int16_t)get_d(instr);
+ int t = (int16_t)get_t(instr);
+ int s = (int16_t)get_s(instr);
+ registers[d] = registers[s] < registers[t];
+}
+
+// $d = $s * $t.
+void mips_mul(const uint32_t instr, uint32_t registers[32]) {
+ int d = (int16_t)get_d(instr);
+ int t = (int16_t)get_t(instr);
+ int s = (int16_t)get_s(instr);
+ registers[d] = registers[s] * registers[t];
+}
+
+// If ($s == $t) PC += i.
+void mips_beq(FILE *const fptr, const uint32_t instr, uint32_t registers[32]) {
+ int i = (int16_t)get_i(instr);
+ int t = (int16_t)get_t(instr);
+ int s = (int16_t)get_s(instr);
+ if (registers[s] != registers[t]) {
+ return;
+ }
+ if (i >= 0) {
+ for (int j = 0; j <= i; ++j) {
+ get_next_instruction(fptr);
+ }
+ } else {
+ for (int j = 0; j <= -1 * i; ++j) {
+ goto_previous_instruction(fptr);
+ }
+ }
+}
+
+// If ($s != $t) PC += i.
+void mips_bne(FILE *const fptr, const uint32_t instr, uint32_t registers[32]) {
+ int i = (int16_t)get_i(instr);
+ int t = (int16_t)get_t(instr);
+ int s = (int16_t)get_s(instr);
+ if (registers[s] == registers[t]) {
+ return;
+ }
+ if (i >= 0) {
+ for (int j = 0; j <= i; ++j) {
+ get_next_instruction(fptr);
+ }
+ } else {
+ for (int j = 0; j <= -1 * i; ++j) {
+ goto_previous_instruction(fptr);
+ }
+ }
+}
+
+// $t = $s + i.
+void mips_addi(const uint32_t instr, uint32_t registers[32]) {
+ int i = (int16_t)get_i(instr);
+ int t = (int16_t)get_t(instr);
+ int s = (int16_t)get_s(instr);
+ registers[t] = registers[s] + (uint32_t)i;
+}
+
+// $t = $s < i.
+void mips_slti(const uint32_t instr, uint32_t registers[32]) {
+ int i = (int16_t)get_i(instr);
+ int t = (int16_t)get_t(instr);
+ int s = (int16_t)get_s(instr);
+ registers[t] = registers[s] < (uint32_t)i;
+}
+
+// $t = $s & i.
+void mips_andi(const uint32_t instr, uint32_t registers[32]) {
+ int i = (int16_t)get_i(instr);
+ int t = (int16_t)get_t(instr);
+ int s = (int16_t)get_s(instr);
+ registers[t] = registers[s] & (uint32_t)i;
+}
+
+// $t = $s | i.
+void mips_ori(const uint32_t instr, uint32_t registers[32]) {
+ int i = (int16_t)get_i(instr);
+ int t = (int16_t)get_t(instr);
+ int s = (int16_t)get_s(instr);
+ registers[t] = registers[s] | (uint32_t)i;
+}
+
+// $t = i << 16u.
+void mips_lui(const uint32_t instr, uint32_t registers[32]) {
+ int i = (int16_t)get_i(instr);
+ int t = (int16_t)get_t(instr);
+ registers[t] = (uint32_t)i << 16u;
+}
+
+// Syscall function which returns non-zero if execution should stop.
+int mips_syscall(uint32_t registers[32]) {
+ uint32_t v0 = registers[2];
+ uint32_t a0 = registers[4];
+ switch (v0) {
+ case 1:
+ printf("%u", a0);
+ break;
+ case 11:
+ printf("%c", a0 & 0xFFu);
+ break;
+ case 10:
+ return 1;
+ default:
+ printf("Unknown system call: %d\n", v0);
+ return 1;
+ }
+ return 0;
+}