diff --git a/fengyong/Interpreter.py b/fengyong/Interpreter.py index 1cf7364..ce3bc5b 100644 --- a/fengyong/Interpreter.py +++ b/fengyong/Interpreter.py @@ -5,19 +5,35 @@ 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 = [] @@ -25,7 +41,7 @@ class Interpreter: def __init__(self): raise SyntaxError( - "Interpreter can not be instantiate. Please use static method." + "Interpreter can not be instantiate. Please use class method." ) @classmethod @@ -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]) @@ -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): diff --git a/fengyong/RegData.py b/fengyong/RegData.py index 417bb56..c8775c9 100644 --- a/fengyong/RegData.py +++ b/fengyong/RegData.py @@ -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) ) @@ -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__) diff --git a/fengyong/Registers.py b/fengyong/Registers.py index 2b58159..7052ea1 100644 --- a/fengyong/Registers.py +++ b/fengyong/Registers.py @@ -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), # 由编译器生成的复合指令使用 @@ -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( @@ -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): diff --git a/fengyong/Simulator.py b/fengyong/Simulator.py index 6d26ea1..dc7d8ed 100644 --- a/fengyong/Simulator.py +++ b/fengyong/Simulator.py @@ -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( + """ ______ | ___| | |_ ___ _ __ __ _ _ _ ___ _ __ __ _ @@ -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, } diff --git a/fengyong/instructions.py b/fengyong/instructions.py index f04ef66..b63830f 100644 --- a/fengyong/instructions.py +++ b/fengyong/instructions.py @@ -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) @@ -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): @@ -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 @@ -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): @@ -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): @@ -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): @@ -127,7 +141,7 @@ 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 @@ -135,7 +149,7 @@ def ori_(rt, rs, imm): # 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 @@ -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 @@ -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)) diff --git a/test/unit_test/muldiv.asm b/test/unit_test/muldiv.asm new file mode 100644 index 0000000..e989fe0 --- /dev/null +++ b/test/unit_test/muldiv.asm @@ -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 \ No newline at end of file diff --git a/test/unit_test/run_test.py b/test/unit_test/run_test.py index ead4e47..03c546c 100644 --- a/test/unit_test/run_test.py +++ b/test/unit_test/run_test.py @@ -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()