Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
first commit
- Loading branch information
0 parents
commit cfbfc26
Showing
5 changed files
with
466 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# mips_sim_template_python |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,228 @@ | ||
import re | ||
import random | ||
from utilities import print_register, print_register_dump, print_memory_word, int_to_signed_32 | ||
|
||
# Hardware modules | ||
|
||
class Register: | ||
""" | ||
set_data: Set input of the register | ||
set_write: Set the write signal to 1 | ||
read: Read value from the register | ||
clock: Set input of the register to the value of the register | ||
------ | ||
Note that without .set_write(), .clock() will not save the input value | ||
""" | ||
def __init__(self): | ||
self.data_in = 0 | ||
self.write = 0 | ||
self.data = 0 | ||
def set_data(self, d): | ||
self.data_in = d | ||
def set_write(self, w = 1): | ||
self.write = w | ||
def read(self): | ||
return self.data | ||
def clock(self): | ||
if (self.write != 0): | ||
self.data = self.data_in | ||
|
||
class RegisterFile: | ||
def __init__(self): | ||
self.data = [0]*32 | ||
self.read_register_1 = 0 | ||
self.read_register_2 = 0 | ||
self.write_register = 0 | ||
self.write_data = 0 | ||
self.read_data_1 = 0 | ||
self.read_data_2 = 0 | ||
self.regwrite = 0 | ||
self.verbose = 0 | ||
def set_read_registers(self, r1, r2): | ||
self.read_register_1 = r1 & 0x1F | ||
self.read_register_2 = r2 & 0x1F | ||
def set_write_register(self, wr): | ||
self.write_register = wr & 0x1F | ||
def set_write_data(self, d): | ||
self.write_data = d | ||
def set_regwrite(self, d = 1): | ||
self.regwrite = d | ||
def get_read_data_1(self): | ||
if (self.verbose > 0): | ||
print_register ("RF_R1", self.read_register_1, self.data[self.read_register_1]) | ||
return self.data[self.read_register_1] | ||
def get_read_data_2(self): | ||
if (self.verbose > 0): | ||
print_register ("RF_R2", self.read_register_2, self.data[self.read_register_2]) | ||
return self.data[self.read_register_2] | ||
def clock(self): | ||
if (self.regwrite != 0): | ||
if (self.write_register > 0): | ||
self.data[self.write_register] = self.write_data | ||
if (self.verbose > 0): | ||
print_register("RF_W", self.write_register, self.write_data) | ||
def set_verbose(self, v): | ||
self.verbose = v | ||
def dump(self): | ||
for i in range(len(self.data)): | ||
print_register_dump(i, self.data[i]) | ||
if ((i & 3) == 3): | ||
print(""); | ||
|
||
class Memory: | ||
""" | ||
set_address: Set the address of I/O operation | ||
set_data: Set input data | ||
set_memread: Set the memory read signal to 1 | ||
set_memwrite: Set the memory write signal to 1 | ||
get_data: Read value from out | ||
clock: Set input of the register to the value of the register | ||
run: To execute read/write memory | ||
------ | ||
Note that without .set_write(), .clock() will not save the input value | ||
""" | ||
def __init__(self): | ||
self.data = {} | ||
self.address = 0 | ||
self.data_in = 0 | ||
self.data_out = 0 | ||
self.read = 0 | ||
self.write = 0 | ||
self.verbose = 0 | ||
def set_address(self, addr): | ||
self.address = addr | ||
def set_data(self, d): | ||
self.data_in = d | ||
def set_memread(self, v = 1): | ||
self.read = v | ||
def set_memwrite(self, v = 1): | ||
self.write = v | ||
def get_data(self): | ||
return self.data_out | ||
def run(self): | ||
if (self.read == 0 and self.write == 0): | ||
return | ||
if (self.address < 0 or self.address >= 0x80000000): | ||
print("Error: Membery address 0x{0:08X} ({0:d}) is too large.".format(self.address)) | ||
if ((self.address & 3) != 0): | ||
print("Error: Membery address 0x{0:08X} ({0:d}) is not aligned.".format(self.address)) | ||
if (self.read != 0): | ||
if (self.address in self.data): | ||
self.data_out = self.data[self.address] | ||
else: | ||
self.data_out = 0 | ||
if (self.verbose > 0): | ||
print_memory_word ("MEM_R", self.address, self.data_out) | ||
elif (self.write != 0): | ||
self.data[self.address] = self.data_in | ||
if (self.verbose > 0): | ||
print_memory_word ("MEM_W", self.address, self.data_in) | ||
|
||
def get_starting_address(self): | ||
if (len(self.data) == 0): | ||
return 0 | ||
return min(self.data) | ||
# return min(self.data.keys()) | ||
|
||
def get_ending_address(self): | ||
if (len(self.data) == 0): | ||
return 0 | ||
return max(self.data) | ||
# return max(self.data.keys()) | ||
|
||
def set_verbose(self, v): | ||
self.verbose = v | ||
|
||
def dump(self): | ||
for addr in sorted(self.data.keys()): | ||
print_memory_word ("MEM_D", addr, self.data[addr]) | ||
|
||
MAXINT32 = 2147483647 | ||
MININT32 = -2147483648 | ||
|
||
def ALU_32 (n1, n2, alu_control): | ||
""" | ||
Input 0000: And | ||
Input 0001: Or | ||
Input 0010: Addition | ||
Input 0110: Substraction | ||
Input 0111: Set Less Then | ||
Output: | ||
result: Calculated result of the ALU | ||
zero: Zero signal of ALU(1 if result is zero) | ||
""" | ||
result = 0 | ||
if (alu_control == 0): | ||
result = int_to_signed_32(n1 & n2) | ||
elif (alu_control == 1): | ||
result = int_to_signed_32(n1 | n2) | ||
elif (alu_control == 2): | ||
result = (n1 + n2) | ||
if (result > MAXINT32 or result < MININT32): | ||
raise ValueError("Arithmetic overflow from addition %d." % result) | ||
elif (alu_control == 6): | ||
result = (n1 - n2) | ||
if (result > MAXINT32 or result < MININT32): | ||
raise ValueError("Arithmetic overflow from subtraction %d." % result) | ||
elif (alu_control == 7): | ||
result = 1 if (n1 < n2) else 0 | ||
""" | ||
n1 &= 0xFFFFFFFF | ||
n2 &= 0xFFFFFFFF | ||
sign1 = (n1 >> 31) & 1 | ||
sign2 = (n2 >> 31) & 1 | ||
if (sign1 != sign2): | ||
result = 1 if (sign1 > sign2) else 0 | ||
else: | ||
result = 1 if (n1 < n2) else 0 | ||
""" | ||
# can check overflow here | ||
# result >> 31 should be 0 or -1 | ||
zero = 1 if (result == 0) else 0 | ||
return (result, zero) | ||
|
||
def MUX_2_1(o_0, o_1, control): | ||
""" | ||
2-1 MUX | ||
""" | ||
return o_1 if control else o_0 | ||
|
||
def AND_2(d0, d1): | ||
""" | ||
Two-input AND gate. | ||
""" | ||
return (d0 & d1) | ||
|
||
|
||
if __name__ == '__main__': | ||
test = 'MEM' | ||
print ("Test " + test) | ||
if (test == 'RF'): | ||
RF = RegisterFile() | ||
RF.set_verbose(1) | ||
RF.set_regwrite(1) | ||
for i in range(32): | ||
RF.set_write_register(i) | ||
v = (int((random.random() - 0.5) * 0x100000000)) | ||
RF.set_write_data(v) | ||
RF.clock() | ||
RF.dump() | ||
elif (test == 'MEM'): | ||
MEM = Memory() | ||
MEM.set_verbose(1) | ||
MEM.dump() | ||
MEM.set_memwrite(1) | ||
MEM.set_memread(0) | ||
|
||
a = 0x40240; | ||
for i in range(16): | ||
MEM.set_address(a) | ||
v = (int((random.random() - 0.5) * 0x100000000)) | ||
MEM.set_data(v) | ||
MEM.run() | ||
a += 4 | ||
MEM.dump() | ||
from utilities import println_int | ||
println_int ("Staring address", MEM.get_starting_address()) | ||
println_int ("Ending address", MEM.get_ending_address()) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import sys, re | ||
import core_sc, utilities | ||
|
||
def sys_error(s): | ||
print ("Error: " + s) | ||
exit(1) | ||
|
||
argc = len(sys.argv) | ||
if (argc < 2 or argc > 4): | ||
sys_error("Usage: mips_sim input_file [num_cycles] [-v]") | ||
|
||
verbose = 0 | ||
cycles = 0 | ||
mode = 0 | ||
|
||
for a in sys.argv[2:]: | ||
if (a == '-v'): | ||
verbose = 1 | ||
elif (a == '-p1'): | ||
mode = 1 | ||
elif (a == '-q'): | ||
mode = 0xE | ||
else: | ||
cycles = int(a) | ||
|
||
if (cycles < 0): | ||
sys_error("Number of cycles must be nonnegative ({}).".format(cycles)); | ||
|
||
core = core_sc.Core_SC() | ||
utilities.load_file(core.I_Mem, sys.argv[1]) | ||
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) | ||
|
||
actual_cycles = core.run(cycles) | ||
|
||
core.RF.dump() | ||
core.D_Mem.dump() | ||
print("Number of cycles=%d" % actual_cycles) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
|
||
class Signals: | ||
def __init__(self): | ||
self.reset() | ||
|
||
def reset(self): | ||
# already generated | ||
self.PC = self.PC_4 = self.instruction = 0 | ||
|
||
# signals that are extracted from instruction | ||
self.opcode = self.funct = self.rs = self.rt = self.rd = self.immediate = 0 | ||
|
||
# generated by the main control from opcode | ||
self.RegDst = self.Jump = self.Branch = self.MemRead = self.MemtoReg = self.ALUOp = self.MemWrite = self.ALUSrc = self.RegWrite = 0 | ||
|
||
# generated by sign extend | ||
self.Sign_extended_immediate = 0 | ||
|
||
# generated by ALU control | ||
self.ALU_operation = 0 | ||
|
||
# calculated address | ||
self.Branch_address = self.Jump_address = 0 | ||
|
||
# Write_register can be decided early | ||
self.Write_register = self.Write_data = 0 | ||
|
||
# Register file read data | ||
# read_register_1 = rs read_register_2 = rt | ||
self.RF_read_data_1 = self.RF_read_data_2 = 0 | ||
|
||
# ALU | ||
# ALU_input_1 = RF_read_data_1 | ||
self.ALU_input_2 = self.ALU_result = self.Zero = 0 | ||
# for software only. You need to move value to ALU_result and ALU_Zero. | ||
self.ALU_returned_value = [0, 0] | ||
|
||
# D_Mem | ||
# D_Mem address = ALU_result | ||
self.MEM_read_data = 0 | ||
|
||
# PC_branch is the output of the MUX controlled by branch | ||
self.PCSrc = self.PC_branch = 0 | ||
|
||
# PC that will be used to fetch instruction in the next cycle | ||
self.PC_new = 0 | ||
|
||
# Add more signals here |
Oops, something went wrong.