Skip to content
This repository has been archived by the owner on May 15, 2021. It is now read-only.

Add support for LOW/HIGH #10

Merged
merged 2 commits into from
Oct 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 21 additions & 7 deletions fengyong/Interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,43 @@

class Interpreter:
Inst = {
"lw": lw_,
"sw": sw_,
"add": add_,
"addi": addi_,
"and": and_,
"andi": andi_,
"beq": beq_,
"bgez": bgez_,
"bgtz": bgtz_,
"blez": blez_,
"bltz": bltz_,
"div": div_,
"j": j_,
"lui": lui_,
"lw": lw_,
"mfhi": mfhi_,
"mflo": mflo_,
"mult": mult_,
"noop": noop_,
"or": or_,
"sub": sub_,
"ori": ori_,
"sll": sll_,
"sllv": sllv_,
"slt": slt_,
"slti": slti_,
"srl": srl_,
"srlv": srlv_,
"sub": sub_,
"sw": sw_,
"xor": xor_,
"xori": xori_,
}
label = {}
hist_inst = []
curr_inst = 0

def __init__(self):
raise SyntaxError(
"Interpreter can not be instantiate. Please use static method."
"Interpreter can not be instantiate. Please use class method."
)

@classmethod
Expand All @@ -41,7 +57,7 @@ def run_line(cls, inst_line, save_hist=True):
code_list, label = Preprocessor.prep_line(inst_line)
if label is not None:
cls.add_label(label)
elif code_list is not None:
if code_list is not None:
if code_list[0] not in cls.Inst:
raise ModuleNotFoundError(
'Unknown instruction "{}".'.format(code_list[0])
Expand All @@ -52,8 +68,6 @@ def run_line(cls, inst_line, save_hist=True):
if save_hist:
cls.hist_inst.append(inst_line)
cls.curr_inst += 1
else:
raise ValueError("God knows what happened")

@classmethod
def add_label(cls, label):
Expand Down
30 changes: 26 additions & 4 deletions fengyong/RegData.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,36 @@ def __repr__(self):
return str(self.value)

@staticmethod
def op(a, b, func, return_regdata=True):
def op(a, b, func, return_regdata=True, res_bin_len=None):
if isinstance(b, int):
return (
RegData(func(a.value, b), a.bin_length)
RegData(
func(a.value, b),
a.bin_length if res_bin_len is None else res_bin_len,
)
if return_regdata
else func(a.value, b)
)
elif isinstance(b, str):
b = RegData(b)
return (
RegData(func(a.value, b.value), max(a.bin_length, b.bin_length))
RegData(
func(a.value, b.value),
max(a.bin_length, b.bin_length)
if res_bin_len is None
else res_bin_len,
)
if return_regdata
else func(a.value, b.value)
)
elif isinstance(b, RegData):
return (
RegData(func(a.value, b.value), max(a.bin_length, b.bin_length))
RegData(
func(a.value, b.value),
max(a.bin_length, b.bin_length)
if res_bin_len is None
else res_bin_len,
)
if return_regdata
else func(a.value, b.value)
)
Expand All @@ -41,6 +54,15 @@ def op(a, b, func, return_regdata=True):
def __add__(self, other_data):
return self.op(self, other_data, int.__add__)

def __mul__(self, other_data):
return self.op(self, other_data, int.__mul__, res_bin_len=64)

def __floordiv__(self, other_data):
return self.op(self, other_data, int.__floordiv__)

def __mod__(self, other_data):
return self.op(self, other_data, int.__mod__)

def __sub__(self, other_data):
return self.op(self, other_data, int.__sub__)

Expand Down
16 changes: 10 additions & 6 deletions fengyong/Registers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ class Registers:
Registers in singleton mode
"""

__data_private = {"$HI": RegData("0", 32), "$LO": RegData("0", 32)}

__data = {
"$0": RegData("0", 32), # 0
"$at": RegData("0", 32), # 由编译器生成的复合指令使用
Expand Down Expand Up @@ -43,8 +45,9 @@ def __init__(self):
raise SyntaxError("Register can not instance, please use class method")

@classmethod
def reg_set(cls, reg_name, value):
if reg_name not in cls.__data.keys():
def reg_set(cls, reg_name, value, is_private=False):
data = cls.__data_private if is_private else cls.__data
if reg_name not in data.keys():
raise ValueError("Unknown register:{}".format(reg_name))
elif not isinstance(value, RegData):
raise TypeError(
Expand All @@ -53,14 +56,15 @@ def reg_set(cls, reg_name, value):
elif value.bin_length > 328:
raise OverflowError("32-bit Register can't hold data:{}".format(value.bin))
else:
cls.__data[reg_name] = value
data[reg_name] = value

@classmethod
def reg_get(cls, reg_name):
if reg_name not in cls.__data.keys():
def reg_get(cls, reg_name, is_private=False):
data = cls.__data_private if is_private else cls.__data
if reg_name not in data.keys():
raise ValueError("Unknown register:{}".format(reg_name))
else:
return cls.__data[reg_name]
return data[reg_name]

@classmethod
def clear(cls):
Expand Down
6 changes: 4 additions & 2 deletions fengyong/Simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ class Simulator(Interpreter):
"%t": lambda: Registers.print("t"),
"%a": lambda: Registers.print("a"),
"%q": exit,
"%about": lambda: print("""
"%about": lambda: print(
"""
______
| ___|
| |_ ___ _ __ __ _ _ _ ___ _ __ __ _
Expand All @@ -30,7 +31,8 @@ class Simulator(Interpreter):
__/ | __/ | __/ |
|___/ |___/ |___/ \n\n
Authored by CQU-AI: Loopyme, Sean, Charles\n
See more information at https://github.com/CQU-AI/pymips/"""),
See more information at https://github.com/CQU-AI/pymips/"""
),
"%exit": exit,
}

Expand Down
48 changes: 31 additions & 17 deletions fengyong/instructions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@

# Currently unsupported instructions
# Unsigned problem: addiu addu sltiu sltu subu multu divu
# LO/HI problem: div divu mfhi mflo mult multu
# Link problem: bgezal bltzal jal
# Jump problem: jr
# Byte problem: lb sb
# Arithmetic shift problem: sra
# Other: syscall
# Oct 19, 2019
# Oct 20, 2019


# Add (with overflow)
Expand All @@ -21,12 +20,12 @@ def add_(rd, rs, rt):

# Add immediate (with overflow)
def addi_(rt, rs, imm):
Registers.reg_set(rt, Registers.reg_get(rs) + int(imm))
Registers.reg_set(rt, Registers.reg_get(rs) + RegData(imm))


# Add immediate unsigned(no overflow)
# def addiu_(rt, rs, imm):
# Registers.reg_set(rt, Registers.reg_get(rs) + int(imm))
# Registers.reg_set(rt, Registers.reg_get(rs) + RegData(imm))

# Add unsigned (no overflow)
# def addu_(rd, rs, rt):
Expand All @@ -39,7 +38,7 @@ def and_(rd, rs, rt):

# Bitwise and immediate
def andi_(rt, rs, imm):
Registers.reg_set(rt, Registers.reg_get(rs) & int(imm))
Registers.reg_set(rt, Registers.reg_get(rs) & RegData(imm))


# Branch on equal
Expand Down Expand Up @@ -74,7 +73,14 @@ def bltz_(rs, LABEL):
# def bltzal_(rs, LABEL):

# Divide
# def div_(rs, rt):
def div_(rs, rt):
Registers.reg_set(
"$LO", Registers.reg_get(rs) // Registers.reg_get(rt), is_private=True
)
Registers.reg_set(
"$HI", Registers.reg_get(rs) % Registers.reg_get(rt), is_private=True
)


# Divide unsigned
# def divu_(rs, rt):
Expand All @@ -95,7 +101,7 @@ def j_(LABEL):

# Load upper immediate
def lui_(rt, imm):
Registers.reg_set(rt, RegData(int(imm < 16)))
Registers.reg_set(rt, RegData(RegData(imm) < 16))


def lw_(rt, add, rs):
Expand All @@ -104,13 +110,21 @@ def lw_(rt, add, rs):


# Move from HI
# def mfhi_(rd):
def mfhi_(rd):
Registers.reg_set(rd, Registers.reg_get("$HI", is_private=True))


# Move from LO
# def mflo_(rd):
def mflo_(rd):
Registers.reg_set(rd, Registers.reg_get("$LO", is_private=True))


# Multiply
# def mult_(rs, rt):
def mult_(rs, rt):
high, low = (Registers.reg_get(rs) * Registers.reg_get(rt)).split([32, 64])
Registers.reg_set("$HI", high, is_private=True)
Registers.reg_set("$LO", low, is_private=True)


# Multiply unsigned
# def multu_(rs, rt):
Expand All @@ -127,15 +141,15 @@ def or_(rd, rs, rt):

# Bitwise or immediate
def ori_(rt, rs, imm):
Registers.reg_set(rt, Registers.reg_get(rs) | int(imm))
Registers.reg_set(rt, Registers.reg_get(rs) | RegData(imm))


# Store byte
# def sb_(rt, offset, rs):

# Shift left logical
def sll_(rt, rs, imm):
Registers.reg_set(rt, Registers.reg_get(rs) << int(imm))
Registers.reg_set(rt, Registers.reg_get(rs) << RegData(imm))


# Shift left logical variable
Expand All @@ -150,24 +164,24 @@ def slt_(rd, rs, rt):

# Set on less than immediate (signed)
def slti_(rt, rs, imm):
Registers.reg_set(rt, RegData(Registers.reg_get(rs) < int(imm)))
Registers.reg_set(rt, RegData(Registers.reg_get(rs) < RegData(imm)))


# Set on less than immediate unsigned
# def sltiu_(rt, rs, imm):
# Registers.reg_set(rt, RegData(Registers.reg_get(rs) < int(imm)))
# Registers.reg_set(rt, RegData(Registers.reg_get(rs) < RegData(imm)))


# Set on less than unsigned
# def sltu_(rt, rs, imm):
# Registers.reg_set(rt, RegData(Registers.reg_get(rs) < int(imm)))
# Registers.reg_set(rt, RegData(Registers.reg_get(rs) < RegData(imm)))

# Shift right arithmetic
# def sra_(rd, rt, shamt)

# Shift right logical
def srl_(rd, rt, shamt):
Registers.reg_set(rd, Registers.reg_get(rt) >> int(shamt))
Registers.reg_set(rd, Registers.reg_get(rt) >> RegData(shamt))


# Shift right logical variable
Expand Down Expand Up @@ -199,4 +213,4 @@ def xor_(rd, rs, rt):

# Bitwise exclusive or immediate
def xori_(rt, rs, imm):
Registers.reg_set(rt, Registers.reg_get(rs) ^ int(imm))
Registers.reg_set(rt, Registers.reg_get(rs) ^ RegData(imm))
8 changes: 8 additions & 0 deletions test/unit_test/muldiv.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
addi $s1, $0, 0xacdb
addi $s2, $0, 0x7f7f7f7f
mult $s1, $s2
mfhi $t1
mflo $t2
div $s2, $s1
mfhi $t3
mflo $t4
8 changes: 8 additions & 0 deletions test/unit_test/run_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ def test_simulate(self):
Simulator.run_file(path)
self.assertEqual(Registers.reg_get("$s0"), 468968)

def test_muldiv(self):
path = "./muldiv.asm"
Simulator.run_file(path)
self.assertEqual(Registers.reg_get("$t1"), (0x7f7f7f7f * 0xacdb) >> 32)
self.assertEqual(Registers.reg_get("$t2"), (0x7f7f7f7f * 0xacdb) & 0xffffffff)
self.assertEqual(Registers.reg_get("$t3"), (0x7f7f7f7f % 0xacdb))
self.assertEqual(Registers.reg_get("$t4"), (0x7f7f7f7f // 0xacdb))


if __name__ == "__main__":
unittest.main()