diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..0cbf9cd
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/.project b/.project
new file mode 100644
index 0000000..accea29
--- /dev/null
+++ b/.project
@@ -0,0 +1,17 @@
+
+
+ mips_sim_java_template
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..191641d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,2 @@
+# mips_sim_template_java
+
diff --git a/src/CombModule.java b/src/CombModule.java
new file mode 100644
index 0000000..0350deb
--- /dev/null
+++ b/src/CombModule.java
@@ -0,0 +1,39 @@
+public final class CombModule {
+ public static int[] ALU_32(int n1, int n2, int alu_control)
+ {
+ int result = 0;
+ int zero;
+ if (alu_control == 0) // and
+ result = (n1 & n2);
+ else if (alu_control == 1) // or
+ result = (n1 | n2);
+ else if (alu_control == 2) // add
+ result = n1 + n2;
+ else if (alu_control == 6) // sub
+ result = n1 - n2;
+ else if (alu_control == 7) // slt
+ {
+ if (n1 < n2)
+ result = 1;
+ else
+ result = 0;
+ }
+ // result &= 0xFFFFFFFF; // no need for Java
+ if (result == 0)
+ zero = 1;
+ else
+ zero = 0;
+ return new int[] {result, zero};
+ }
+
+ public static int MUX_2_1(int d0, int d1, int sel)
+ {
+ return ((sel == 0) ? d0 : d1);
+ }
+
+ public static int AND_2(int d0, int d1)
+ {
+ return (d0 & d1);
+ }
+
+}
\ No newline at end of file
diff --git a/src/Core_SC.java b/src/Core_SC.java
new file mode 100644
index 0000000..7fb5c2c
--- /dev/null
+++ b/src/Core_SC.java
@@ -0,0 +1,192 @@
+
+public class Core_SC {
+
+ private static final int OPCODE_R = 0;
+ private static final int OPCODE_J = 2;
+ private static final int OPCODE_BEQ = 4;
+ private static final int OPCODE_SW = 0x2B;
+ private static final int OPCODE_LW = 0x23;
+ private static final int OPCODE_ADDI = 8;
+
+
+ public Memory I_Mem;
+ public Memory D_Mem;
+ public RegisterFile RF;
+
+ private Register RegPC;
+ private Signals signals;
+
+ private int cycle_num;
+ private int mode;
+
+ // Functions
+ public Core_SC()
+ {
+ RF = new RegisterFile();
+ RegPC = new Register();
+ I_Mem = new Memory();
+ D_Mem = new Memory();
+ signals = new Signals();
+
+ cycle_num = 0;
+ }
+
+ public void set_PC(int pc)
+ {
+ RegPC.set_data(pc);
+ RegPC.set_write(1);
+ }
+
+ public void set_mode(int m)
+ {
+ mode = m;
+ }
+
+ // Your Code
+ public int run(int n_cycles)
+ {
+ int i_cycles = 0;
+ int ending_PC;
+
+ I_Mem.set_memread(1);
+ I_Mem.set_memwrite(0);
+ ending_PC = I_Mem.get_ending_address();
+
+ while (n_cycles == 0 || i_cycles < n_cycles)
+ {
+ if ((mode & 2) == 0) Utilities.print_new_cycle(cycle_num);
+ i_cycles ++;
+ cycle_num ++;
+
+ // clock changes
+ RegPC.clock();
+ RF.clock();
+
+ // read PC
+ signals.PC = RegPC.read();
+ signals.PC_4 = signals.PC_new = signals.PC + 4; // PC + 4
+
+ if ((mode & 2) == 0) Utilities.println_int("PC", signals.PC);
+ if (signals.PC > ending_PC) {
+ if ((mode & 2) == 0) System.out.println("No More Instructions");
+ i_cycles --;
+ break;
+ }
+
+ I_Mem.set_address(signals.PC);
+ I_Mem.run();
+ signals.instruction = I_Mem.get_data();
+ if ((mode & 2) == 0) Utilities.println_int("instruction", signals.instruction);
+
+ // Now you have PC and the instruction
+ // Some signals' value can be extracted from instruction directly
+ signals_from_instruction(signals.instruction, signals);
+
+ // call main_control
+ main_control(signals.opcode, signals);
+
+ // call sign_extend
+ signals.Sign_extended_immediate = sign_extend(signals.immediate);
+
+ // Write_register. Also an example of using MUX
+ signals.Write_register = CombModule.MUX_2_1(signals.rt, signals.rd, signals.RegDst);
+
+ // ALU control
+ signals.ALU_operation = ALU_control(signals.ALUOp, signals.funct);
+
+ // Calculate branch address
+ signals.Branch_address = calculate_branch_address(signals.PC_4, signals.Sign_extended_immediate);
+ signals.Jump_address = calculate_jump_address(signals.PC_4, signals.instruction);
+
+ // Print out signals generated in Phase 1.
+ if ((mode & 4) == 0) Utilities.print_signals_1(signals);
+
+ if ((mode & 1) != 0) {
+ RegPC.set_data(signals.PC_4);
+ RegPC.set_write(1);
+ continue;
+ }
+
+ // You will continue to complete the core in phase 2
+ // Use RF, ALU, D_Mem
+ // Preapre RF write
+ // Compute PC_new
+
+ RegPC.set_data(signals.PC_new);
+ RegPC.set_write(1);
+
+ // Print out signals generated in Phase 2.
+ if ((mode & 8) == 0) Utilities.print_signals_2(signals);
+ }
+ return i_cycles;
+ }
+
+ // Generate signals that can be extracted from instruction
+ private void signals_from_instruction (int instruction, Signals sig)
+ {
+ /* Extract the following signals from instruction.
+ opcode, rs, rt, rd, funct, immediate
+ */
+ sig.opcode = (instruction >> 26) & 0x3F;
+ }
+
+ // Main control unit. Generate control signals from opcode.
+ // The signal values are stored in a Signals object.
+ private void main_control (int opcode, Signals sig)
+ {
+ // Set all signals to 0 first
+ sig.RegDst = 0;
+ sig.Jump = 0;
+ sig.Branch = 0;
+ sig.MemRead = 0;
+ sig.MemtoReg = 0;
+ sig.ALUOp = 0;
+ sig.MemWrite = 0;
+ sig.ALUSrc = 0;
+ sig.RegWrite = 0;
+ if (opcode == OPCODE_R) {
+ sig.RegDst = 1;
+ sig.ALUOp = 2;
+ sig.RegWrite = 1;
+ }
+ // You can throw an exception on unknown opcode.
+ // throw new IllegalArgumentException("Error: Invalid opcode " + opcode);
+ }
+
+ /* Perform sign extension on immd.
+ Sign extend module.
+ Convert 16 bits to an int.
+ Extract the lower 16 bits.
+ If bit 15 of immd is 1, compute the correct negative value (immd - 0x10000).
+ */
+ private int sign_extend (int immd)
+ {
+ immd = immd & 0xFFFF;
+ return immd;
+ }
+
+ // return 4 bits (as an int) ALU_operation from ALUop and funct code.
+ private int ALU_control(int alu_op, int funct)
+ {
+ int alu_control_out = 0;
+ if (alu_op == 0) // lw,sw,addi
+ alu_control_out = 2; // 0010 add
+ // else
+ // throw new IllegalArgumentException("Error: Invalid ALUOp " + alu_op);
+ return alu_control_out;
+ }
+
+ private int calculate_branch_address(int pc_4, int extended)
+ {
+ int addr = 0;
+
+ return addr;
+ }
+
+ private int calculate_jump_address(int pc_4, int instruction)
+ {
+ int addr = 0;
+
+ return addr;
+ }
+}
diff --git a/src/MIPS_Sim.java b/src/MIPS_Sim.java
new file mode 100644
index 0000000..9801489
--- /dev/null
+++ b/src/MIPS_Sim.java
@@ -0,0 +1,59 @@
+
+
+public class MIPS_Sim {
+
+ public static void main(String[] args) {
+ // TODO Auto-generated method stub
+
+ int verbose = 0;
+ int cycles = 0;
+ int mode = 0;
+
+ if (args.length < 1 || args.length > 3) {
+ System.err.println("Error: Please specify an input file.");
+ System.exit(1);
+ }
+
+ for (int i = 1; i < args.length; i ++) {
+ if (args[i].equals("-v")) {
+ verbose = 1;
+ } else if (args[i].equals("-p1")) {
+ mode = 1;
+ } else if (args[i].equals("-q")) {
+ mode = 0xE;
+ } else {
+ try {
+ cycles = Integer.parseInt(args[i]);
+ } catch (NumberFormatException e) {
+ System.err.println("Error: " + args[i] + " is not a valid integer.");
+ System.exit(1);
+ }
+ if (cycles < 0) {
+ System.err.println("Error: Number of cycles must be nonnegative.");
+ System.exit(1);
+ }
+ }
+ }
+ /*
+ {
+ String cwd = System.getProperty("user.dir");
+ System.out.println("Current working directory in Java : " + cwd);
+ System.out.println("Input file name : " + args[0]);
+ }
+ */
+ Core_SC core = new Core_SC();
+ Utilities.load_file(core.I_Mem, args[0]);
+ core.I_Mem.dump();
+ core.set_PC(core.I_Mem.get_starting_address());
+
+ core.I_Mem.set_verbose(verbose);
+ core.RF.set_verbose(verbose);
+ core.set_mode(mode);
+
+ int actual_cycles = core.run(cycles);
+
+ core.RF.dump();
+ core.D_Mem.dump();
+ System.out.println("Number of cycles=" + actual_cycles);
+ }
+}
diff --git a/src/Memory.java b/src/Memory.java
new file mode 100644
index 0000000..61b0748
--- /dev/null
+++ b/src/Memory.java
@@ -0,0 +1,120 @@
+import java.util.TreeMap;
+
+public class Memory {
+
+ private TreeMap data;
+ private int address;
+ private int data_in, data_out;
+ private int read, write;
+
+ // The following members are not hardware signals.
+ private int verbose;
+
+ public Memory()
+ {
+ data = new TreeMap();
+ address = 0;
+ data_in = 0;
+ data_out = 0;
+ read = 0;
+ write = 0;
+
+ verbose = 0;
+ }
+
+ public void set_address(int addr)
+ {
+ address = addr;
+ }
+
+ public void set_data(int d)
+ {
+ data_in = d;
+ }
+
+ public void set_memread(int v)
+ {
+ read = v;
+ }
+
+ public void set_memwrite(int v)
+ {
+ write = v;
+ }
+
+ public int get_data()
+ {
+ return data_out;
+ }
+
+ public void run()
+ {
+ data_out = 0;
+ if (read == 0 && write == 0)
+ return;
+
+ if (address < 0)
+ System.err.format("Error: Membery address 0x%08X (%d) is too large.\n", address, address);
+ if ((address & 3) != 0)
+ System.err.format("Error: Membery address 0x%08X (%d) is not aligned.\n", address, address);
+ if (read == 1)
+ {
+ if (data.containsKey(address))
+ data_out = data.get(address);
+ else
+ data_out = 0;
+ if (verbose > 0)
+ System.out.format("MEM_R 0x%08X 0x%08X %d\n", address, data_out, data_out);
+ }
+ else if (write == 1)
+ {
+ data.put(address, data_in);
+ if (verbose > 0)
+ System.out.format("MEM_W 0x%08X 0x%08X %d\n", address, data_in, data_in);
+ }
+ }
+
+ public int get_starting_address()
+ {
+ if (data.isEmpty())
+ return 0;
+ return data.firstKey();
+ }
+
+ public int get_ending_address()
+ {
+ if (data.isEmpty())
+ return 0;
+ return data.lastKey();
+ }
+
+ public void set_verbose(int v)
+ {
+ verbose = v;
+ }
+
+ public void dump()
+ {
+ if (data.isEmpty())
+ return;
+
+ Integer k = data.firstKey();
+
+ while (k != null) {
+ int v = data.get(k);
+ System.out.format("MEM_D 0x%08X 0x%08X %d\n", k, v, v);
+ k = data.higherKey(k);
+ }
+
+ /* Another implementation. Need to import more modules.
+ Set> data_set = data.entrySet();
+ Iterator> itr_data = data_set.iterator();
+
+ while(itr_data.hasNext()) {
+ Entry w = itr_data.next();
+ System.out.format("D %08X %08X %d\n", w.getKey(), w.getValue(), w.getValue());
+ }
+ */
+ }
+
+}
diff --git a/src/Register.java b/src/Register.java
new file mode 100644
index 0000000..8592e34
--- /dev/null
+++ b/src/Register.java
@@ -0,0 +1,34 @@
+public class Register {
+
+ private int data, data_in;
+ private int write;
+
+
+ public Register()
+ {
+ data_in = 0;
+ write = 0;
+ data = 0;
+ }
+
+ public void set_data(int d)
+ {
+ data_in = d;
+ }
+
+ public void set_write(int w)
+ {
+ write = w;
+ }
+
+ public int read()
+ {
+ return data;
+ }
+
+ public void clock()
+ {
+ if (write != 0)
+ data = data_in;
+ }
+}
diff --git a/src/RegisterFile.java b/src/RegisterFile.java
new file mode 100644
index 0000000..81a3e1c
--- /dev/null
+++ b/src/RegisterFile.java
@@ -0,0 +1,89 @@
+import java.util.Arrays;
+
+public class RegisterFile {
+
+ private int[] data;
+ private int read_register_1, read_register_2, write_register, write_data;
+ private int regwrite;
+
+ private int verbose;
+
+ public RegisterFile()
+ {
+ data = new int[32];
+ Arrays.fill(data, 0);
+ read_register_1 = 0;
+ read_register_2 = 0;
+ write_register = 0;
+ write_data = 0;
+ regwrite = 0;
+ }
+
+ public void set_read_registers(int r1, int r2)
+ {
+ read_register_1 = r1 & 0x1F;
+ read_register_2 = r2 & 0x1F;
+ }
+
+ public void set_write_register(int wr)
+ {
+ write_register = wr & 0x1F;
+ }
+
+ public void set_write_data(int d)
+ {
+ write_data = d;
+ }
+
+ public void set_regwrite(int regw)
+ {
+ regwrite = regw;
+ }
+
+ public int get_read_data_1()
+ {
+ if (verbose > 0)
+ System.out.format("RF_R1 $%02d 0x%08X %d\n", read_register_1, data[read_register_1], data[read_register_1]);
+ return data[read_register_1];
+ }
+
+ public int get_read_data_2()
+ {
+ if (verbose > 0)
+ System.out.format("RF_R2 $%02d 0x%08X %d\n", read_register_2, data[read_register_2], data[read_register_2]);
+ return data[read_register_2];
+ }
+
+ public void clock()
+ {
+ if (regwrite != 0)
+ {
+ if (write_register > 0)
+ {
+ data[write_register] = write_data;
+ if (verbose > 0)
+ System.out.format("RF_W $%02d 0x%08X %d\n", write_register, write_data, write_data);
+ }
+ }
+ }
+
+ public void set_verbose(int v)
+ {
+ verbose = v;
+ }
+
+ public void dump()
+ {
+ int i, nreg;
+
+ nreg = data.length;
+ for (i = 0; i < nreg; i ++)
+ {
+ System.out.format("$%02d=0x%08X(%11d) ", i, data[i], data[i]);
+
+ if ((i & 3) == 3)
+ System.out.println("");
+ }
+ }
+
+}
diff --git a/src/Signals.java b/src/Signals.java
new file mode 100644
index 0000000..0222f59
--- /dev/null
+++ b/src/Signals.java
@@ -0,0 +1,48 @@
+
+public final class Signals {
+
+ // already generated
+ public int PC, PC_4, instruction;
+
+ // signals that are extracted from instruction
+ public int opcode, funct, rs, rt, rd, immediate;
+
+ // generated by the main control from opcode
+ public int RegDst, Jump, Branch, MemRead, MemtoReg, ALUOp, MemWrite, ALUSrc, RegWrite;
+
+ // generated by sign extend
+ public int Sign_extended_immediate; // sign extended immediate
+
+ // generated by ALU control
+ public int ALU_operation;
+
+ // calculated address
+ public int Branch_address, Jump_address;
+
+ // Write_register can be decided early
+ public int Write_register, Write_data;
+
+ // Register file read data
+ // read_register_1 = rs read_register_2 = rt
+ public int RF_read_data_1, RF_read_data_2;
+
+ // ALU
+ // ALU_input_1 = RF_read_data_1
+ public int ALU_input_2, ALU_result, Zero;
+ // for software only. You need to move value to ALU_result and ALU_Zero.
+ public int[] ALU_returned_value;
+
+
+ // D_Mem
+ // D_Mem address = ALU_result
+ public int MEM_read_data;
+
+ // PC_branch is the output of the MUX controlled by branch
+ public int PCSrc, PC_branch;
+
+ // PC that will be used to fetch instruction in the next cycle
+ public int PC_new;
+
+ // Add more signals here
+
+}
diff --git a/src/Utilities.java b/src/Utilities.java
new file mode 100644
index 0000000..1460499
--- /dev/null
+++ b/src/Utilities.java
@@ -0,0 +1,125 @@
+import java.io.*;
+import java.util.*;
+import java.util.regex.*;
+
+public class Utilities {
+
+ public static int hexstr_to_int(String hex_str) {
+ long v = Long.parseLong(hex_str, 16);
+ return (int)v;
+ }
+
+ public static int str_to_int(String str) {
+ long v = Long.decode(str);
+ return (int)v;
+ }
+
+ // nbits must be less than 32
+ public static String int_to_bin_string(int v, int nbits)
+ {
+ v = (v & ((1 << nbits) - 1)) | (1 << nbits);
+ return Integer.toBinaryString(v).substring(1);
+ }
+
+ public static void print_int(String s, int i)
+ {
+ System.out.format("%s=0x%08X %11d", s, i, i);
+ }
+
+ public static void println_int(String s, int i)
+ {
+ System.out.format("%s=0x%08X %11d\n", s, i, i);
+ }
+
+ public static void print_signal(String s, int v, int n)
+ {
+ if (n == 1) {
+ System.out.format("%s=%d\n", s, v & 1);
+ }
+ else if (n < 16) {
+ System.out.format("%s=0b%s %d\n", s, int_to_bin_string(v, n), v);
+ }
+ else if (n == 16) {
+ v = v & 0xFFFF;
+ System.out.format("%s=0x%04X %d\n", s, v, v);
+ }
+ else {
+ System.out.format("%s=0x%08X %d\n", s, v, v);
+ }
+ }
+
+ public static void print_new_cycle(int cycle_num)
+ {
+ System.out.println("==========================================\nCycle " + cycle_num);
+ }
+
+ public static void print_signals_1(Signals sig)
+ {
+ print_signal("opcode", sig.opcode, 6);
+ print_signal("funct", sig.funct, 6);
+ print_signal("rs", sig.rs, 5);
+ print_signal("rt", sig.rt, 5);
+ print_signal("rd", sig.rd, 5);
+ print_signal("immediate", sig.immediate, 16);
+ print_signal("RegDst", sig.RegDst, 1);
+ print_signal("Jump", sig.Jump, 1);
+ print_signal("Branch", sig.Branch, 1);
+ print_signal("MemRead", sig.MemRead, 1);
+ print_signal("MemtoReg", sig.MemtoReg, 1);
+ print_signal("ALUOp", sig.ALUOp, 1);
+ print_signal("MemWrite", sig.MemWrite, 1);
+ print_signal("ALUSrc", sig.ALUSrc, 1);
+ print_signal("RegWrite", sig.RegWrite, 1);
+ print_signal("Sign_extended_immediate", sig.Sign_extended_immediate, 32);
+ print_signal("ALU_operation", sig.ALU_operation, 4);
+ print_signal("Branch_address", sig.Branch_address, 32);
+ print_signal("Jump_address", sig.Jump_address, 32);
+ print_signal("Write_register", sig.Write_register, 5);
+ }
+
+ public static void print_signals_2(Signals sig)
+ {
+ print_signal("RF_read_data_1", sig.RF_read_data_1, 32);
+ print_signal("RF_read_data_2", sig.RF_read_data_2, 32);
+ print_signal("ALU_input_2", sig.ALU_input_2, 32);
+ print_signal("ALU_result", sig.ALU_result, 32);
+ print_signal("Zero", sig.Zero, 1);
+ print_signal("MEM_read_data", sig.MEM_read_data, 32);
+ print_signal("Write_data", sig.Write_data, 32);
+ print_signal("PCSrc", sig.PCSrc, 1);
+ print_signal("PC_branch", sig.PC_branch, 32);
+ print_signal("PC_new", sig.PC_new, 32);
+ }
+
+ public static void load_file(Memory IMem, String filename)
+ {
+ String line;
+ BufferedReader br;
+ String pattern = "^(0x\\p{XDigit}+)\\s+(0x\\p{XDigit}+)";
+ Pattern r = Pattern.compile(pattern);
+ int addr;
+ long data;
+
+ IMem.set_memread(0);
+ IMem.set_memwrite(1);
+ try {
+ br = new BufferedReader(new FileReader(filename));
+
+ while ((line = br.readLine()) != null) { // while loop begins here
+ // System.out.println(line);
+ Matcher m = r.matcher(line);
+ if (m.find()) {
+ // System.out.println(m.group(1) + " " + m.group(2));
+ addr = Integer.decode(m.group(1));
+ data = Long.decode(m.group(2));
+ IMem.set_address(addr);
+ IMem.set_data((int)data); // only the lower 32 bits
+ IMem.run();
+ }
+ } // end while
+ } catch (IOException e){
+ System.err.println("Error: " + e.getMessage());
+ }
+ IMem.set_memwrite(0);
+ }
+}