|
|
|
@ -51,21 +51,22 @@ class CPU:
|
|
|
|
|
except RiscemuBaseException as ex:
|
|
|
|
|
print(FMT_ERROR + "[CPU] excpetion caught at 0x{:08X}: {}:".format(self.pc-1, ins) + FMT_NONE)
|
|
|
|
|
print(" " + ex.message())
|
|
|
|
|
traceback.print_exception(type(ex), ex, ex.__traceback__)
|
|
|
|
|
#traceback.print_exception(type(ex), ex, ex.__traceback__)
|
|
|
|
|
if self.conf.debug_on_exception:
|
|
|
|
|
launch_debug_session(self, self.mmu, self.regs,
|
|
|
|
|
"Exception encountered, launching debug:".format(self.pc-1))
|
|
|
|
|
|
|
|
|
|
print("Program exited with code {}".format(self.exit_code))
|
|
|
|
|
print(FMT_CPU + "Program exited with code {}".format(self.exit_code) + FMT_NONE)
|
|
|
|
|
|
|
|
|
|
def __run_instruction(self, ins: 'LoadedInstruction'):
|
|
|
|
|
name = 'instruction_' + ins.name
|
|
|
|
|
name = '_CPU__instruction_' + ins.name
|
|
|
|
|
if hasattr(self, name):
|
|
|
|
|
getattr(self, name)(ins)
|
|
|
|
|
else:
|
|
|
|
|
# this should never be reached, as unknown instructions are imparsable
|
|
|
|
|
raise RuntimeError("Unknown instruction: {}".format(ins))
|
|
|
|
|
|
|
|
|
|
def parse_mem_ins(self, ins: 'LoadedInstruction') -> Tuple[str, int]:
|
|
|
|
|
def __parse_mem_ins(self, ins: 'LoadedInstruction') -> Tuple[str, int]:
|
|
|
|
|
"""
|
|
|
|
|
parses both rd, rs1, imm and rd, imm(rs1) arguments and returns (rd, imm+rs1)
|
|
|
|
|
(so a register and address tuple for memory instructions)
|
|
|
|
@ -82,39 +83,39 @@ class CPU:
|
|
|
|
|
rd = ins.get_reg(0)
|
|
|
|
|
return rd, self.regs.get(rs1) + imm
|
|
|
|
|
|
|
|
|
|
def instruction_lb(self, ins: 'LoadedInstruction'):
|
|
|
|
|
rd, addr = self.parse_mem_ins(ins)
|
|
|
|
|
def __instruction_lb(self, ins: 'LoadedInstruction'):
|
|
|
|
|
rd, addr = self.__parse_mem_ins(ins)
|
|
|
|
|
self.regs.set(rd, int_from_bytes(self.mmu.read(addr, 1)))
|
|
|
|
|
|
|
|
|
|
def instruction_lh(self, ins: 'LoadedInstruction'):
|
|
|
|
|
rd, addr = self.parse_mem_ins(ins)
|
|
|
|
|
def __instruction_lh(self, ins: 'LoadedInstruction'):
|
|
|
|
|
rd, addr = self.__parse_mem_ins(ins)
|
|
|
|
|
self.regs.set(rd, int_from_bytes(self.mmu.read(addr, 2)))
|
|
|
|
|
|
|
|
|
|
def instruction_lw(self, ins: 'LoadedInstruction'):
|
|
|
|
|
rd, addr = self.parse_mem_ins(ins)
|
|
|
|
|
def __instruction_lw(self, ins: 'LoadedInstruction'):
|
|
|
|
|
rd, addr = self.__parse_mem_ins(ins)
|
|
|
|
|
self.regs.set(rd, int_from_bytes(self.mmu.read(addr, 4)))
|
|
|
|
|
|
|
|
|
|
def instruction_lbu(self, ins: 'LoadedInstruction'):
|
|
|
|
|
rd, addr = self.parse_mem_ins(ins)
|
|
|
|
|
def __instruction_lbu(self, ins: 'LoadedInstruction'):
|
|
|
|
|
rd, addr = self.__parse_mem_ins(ins)
|
|
|
|
|
self.regs.set(rd, int_from_bytes(self.mmu.read(addr, 1), unsigned=True))
|
|
|
|
|
|
|
|
|
|
def instruction_lhu(self, ins: 'LoadedInstruction'):
|
|
|
|
|
rd, addr = self.parse_mem_ins(ins)
|
|
|
|
|
def __instruction_lhu(self, ins: 'LoadedInstruction'):
|
|
|
|
|
rd, addr = self.__parse_mem_ins(ins)
|
|
|
|
|
self.regs.set(rd, int_from_bytes(self.mmu.read(addr, 2), unsigned=True))
|
|
|
|
|
|
|
|
|
|
def instruction_sb(self, ins: 'LoadedInstruction'):
|
|
|
|
|
rd, addr = self.parse_mem_ins(ins)
|
|
|
|
|
def __instruction_sb(self, ins: 'LoadedInstruction'):
|
|
|
|
|
rd, addr = self.__parse_mem_ins(ins)
|
|
|
|
|
self.mmu.write(addr, 1, int_to_bytes(self.regs.get(rd), 1))
|
|
|
|
|
|
|
|
|
|
def instruction_sh(self, ins: 'LoadedInstruction'):
|
|
|
|
|
rd, addr = self.parse_mem_ins(ins)
|
|
|
|
|
def __instruction_sh(self, ins: 'LoadedInstruction'):
|
|
|
|
|
rd, addr = self.__parse_mem_ins(ins)
|
|
|
|
|
self.mmu.write(addr, 2, int_to_bytes(self.regs.get(rd), 2))
|
|
|
|
|
|
|
|
|
|
def instruction_sw(self, ins: 'LoadedInstruction'):
|
|
|
|
|
rd, addr = self.parse_mem_ins(ins)
|
|
|
|
|
def __instruction_sw(self, ins: 'LoadedInstruction'):
|
|
|
|
|
rd, addr = self.__parse_mem_ins(ins)
|
|
|
|
|
self.mmu.write(addr, 4, int_to_bytes(self.regs.get(rd), 4))
|
|
|
|
|
|
|
|
|
|
def instruction_sll(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_sll(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 3)
|
|
|
|
|
dst = ins.get_reg(0)
|
|
|
|
|
src1 = ins.get_reg(1)
|
|
|
|
@ -124,7 +125,7 @@ class CPU:
|
|
|
|
|
to_signed(to_unsigned(self.regs.get(src1)) << (self.regs.get(src2) & 0b11111))
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def instruction_slli(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_slli(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 3)
|
|
|
|
|
dst = ins.get_reg(0)
|
|
|
|
|
src1 = ins.get_reg(1)
|
|
|
|
@ -134,7 +135,7 @@ class CPU:
|
|
|
|
|
to_signed(to_unsigned(self.regs.get(src1)) << (imm & 0b11111))
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def instruction_srl(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_srl(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 3)
|
|
|
|
|
dst = ins.get_reg(0)
|
|
|
|
|
src1 = ins.get_reg(1)
|
|
|
|
@ -144,7 +145,7 @@ class CPU:
|
|
|
|
|
to_signed(to_unsigned(self.regs.get(src1)) >> (self.regs.get(src2) & 0b11111))
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def instruction_srli(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_srli(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 3)
|
|
|
|
|
dst = ins.get_reg(0)
|
|
|
|
|
src1 = ins.get_reg(1)
|
|
|
|
@ -154,7 +155,7 @@ class CPU:
|
|
|
|
|
to_signed(to_unsigned(self.regs.get(src1)) >> (imm & 0b11111))
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def instruction_sra(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_sra(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 3)
|
|
|
|
|
dst = ins.get_reg(0)
|
|
|
|
|
src1 = ins.get_reg(1)
|
|
|
|
@ -164,7 +165,7 @@ class CPU:
|
|
|
|
|
self.regs.get(src1) >> (self.regs.get(src2) & 0b11111)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def instruction_srai(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_srai(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 3)
|
|
|
|
|
dst = ins.get_reg(0)
|
|
|
|
|
src1 = ins.get_reg(1)
|
|
|
|
@ -174,7 +175,7 @@ class CPU:
|
|
|
|
|
self.regs.get(src1) >> (imm & 0b11111)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def instruction_add(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_add(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 3)
|
|
|
|
|
dst = ins.get_reg(0)
|
|
|
|
|
src1 = ins.get_reg(1)
|
|
|
|
@ -184,7 +185,7 @@ class CPU:
|
|
|
|
|
self.regs.get(src1) + self.regs.get(src2)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def instruction_addi(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_addi(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 3)
|
|
|
|
|
dst = ins.get_reg(0)
|
|
|
|
|
src1 = ins.get_reg(1)
|
|
|
|
@ -194,7 +195,7 @@ class CPU:
|
|
|
|
|
self.regs.get(src1) + imm
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def instruction_sub(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_sub(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 3)
|
|
|
|
|
dst = ins.get_reg(0)
|
|
|
|
|
src1 = ins.get_reg(1)
|
|
|
|
@ -204,13 +205,13 @@ class CPU:
|
|
|
|
|
self.regs.get(src1) - self.regs.get(src2)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def instruction_lui(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_lui(self, ins: 'LoadedInstruction'):
|
|
|
|
|
INS_NOT_IMPLEMENTED(ins)
|
|
|
|
|
|
|
|
|
|
def instruction_auipc(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_auipc(self, ins: 'LoadedInstruction'):
|
|
|
|
|
INS_NOT_IMPLEMENTED(ins)
|
|
|
|
|
|
|
|
|
|
def instruction_xor(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_xor(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 3)
|
|
|
|
|
dst = ins.get_reg(0)
|
|
|
|
|
src1 = ins.get_reg(1)
|
|
|
|
@ -220,10 +221,10 @@ class CPU:
|
|
|
|
|
self.regs.get(src1) ^ self.regs.get(src2)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def instruction_xori(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_xori(self, ins: 'LoadedInstruction'):
|
|
|
|
|
INS_NOT_IMPLEMENTED(ins)
|
|
|
|
|
|
|
|
|
|
def instruction_or(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_or(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 3)
|
|
|
|
|
dst = ins.get_reg(0)
|
|
|
|
|
src1 = ins.get_reg(1)
|
|
|
|
@ -233,10 +234,10 @@ class CPU:
|
|
|
|
|
self.regs.get(src1) | self.regs.get(src2)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def instruction_ori(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_ori(self, ins: 'LoadedInstruction'):
|
|
|
|
|
INS_NOT_IMPLEMENTED(ins)
|
|
|
|
|
|
|
|
|
|
def instruction_and(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_and(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 3)
|
|
|
|
|
dst = ins.get_reg(0)
|
|
|
|
|
src1 = ins.get_reg(1)
|
|
|
|
@ -246,10 +247,10 @@ class CPU:
|
|
|
|
|
self.regs.get(src1) & self.regs.get(src2)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def instruction_andi(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_andi(self, ins: 'LoadedInstruction'):
|
|
|
|
|
INS_NOT_IMPLEMENTED(ins)
|
|
|
|
|
|
|
|
|
|
def instruction_slt(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_slt(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 3)
|
|
|
|
|
dst = ins.get_reg(0)
|
|
|
|
|
src1 = ins.get_reg(1)
|
|
|
|
@ -259,10 +260,10 @@ class CPU:
|
|
|
|
|
int(self.regs.get(src1) < self.regs.get(src2))
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def instruction_slti(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_slti(self, ins: 'LoadedInstruction'):
|
|
|
|
|
INS_NOT_IMPLEMENTED(ins)
|
|
|
|
|
|
|
|
|
|
def instruction_sltu(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_sltu(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 3)
|
|
|
|
|
dst = ins.get_reg(0)
|
|
|
|
|
src1 = ins.get_reg(1)
|
|
|
|
@ -272,10 +273,10 @@ class CPU:
|
|
|
|
|
int(to_unsigned(self.regs.get(src1)) < to_unsigned(self.regs.get(src2)))
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def instruction_sltiu(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_sltiu(self, ins: 'LoadedInstruction'):
|
|
|
|
|
INS_NOT_IMPLEMENTED(ins)
|
|
|
|
|
|
|
|
|
|
def instruction_beq(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_beq(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 3)
|
|
|
|
|
reg1 = ins.get_reg(0)
|
|
|
|
|
reg2 = ins.get_reg(1)
|
|
|
|
@ -283,7 +284,7 @@ class CPU:
|
|
|
|
|
if self.regs.get(reg1) == self.regs.get(reg2):
|
|
|
|
|
self.pc = dest
|
|
|
|
|
|
|
|
|
|
def instruction_bne(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_bne(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 3)
|
|
|
|
|
reg1 = ins.get_reg(0)
|
|
|
|
|
reg2 = ins.get_reg(1)
|
|
|
|
@ -291,7 +292,7 @@ class CPU:
|
|
|
|
|
if self.regs.get(reg1) != self.regs.get(reg2):
|
|
|
|
|
self.pc = dest
|
|
|
|
|
|
|
|
|
|
def instruction_blt(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_blt(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 3)
|
|
|
|
|
reg1 = ins.get_reg(0)
|
|
|
|
|
reg2 = ins.get_reg(1)
|
|
|
|
@ -299,7 +300,7 @@ class CPU:
|
|
|
|
|
if self.regs.get(reg1) < self.regs.get(reg2):
|
|
|
|
|
self.pc = dest
|
|
|
|
|
|
|
|
|
|
def instruction_bge(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_bge(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 3)
|
|
|
|
|
reg1 = ins.get_reg(0)
|
|
|
|
|
reg2 = ins.get_reg(1)
|
|
|
|
@ -307,7 +308,7 @@ class CPU:
|
|
|
|
|
if self.regs.get(reg1) >= self.regs.get(reg2):
|
|
|
|
|
self.pc = dest
|
|
|
|
|
|
|
|
|
|
def instruction_bltu(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_bltu(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 3)
|
|
|
|
|
reg1 = to_unsigned(ins.get_reg(0))
|
|
|
|
|
reg2 = to_unsigned(ins.get_reg(1))
|
|
|
|
@ -315,7 +316,7 @@ class CPU:
|
|
|
|
|
if self.regs.get(reg1) < self.regs.get(reg2):
|
|
|
|
|
self.pc = dest
|
|
|
|
|
|
|
|
|
|
def instruction_bgeu(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_bgeu(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 3)
|
|
|
|
|
reg1 = to_unsigned(ins.get_reg(0))
|
|
|
|
|
reg2 = to_unsigned(ins.get_reg(1))
|
|
|
|
@ -323,12 +324,12 @@ class CPU:
|
|
|
|
|
if self.regs.get(reg1) >= self.regs.get(reg2):
|
|
|
|
|
self.pc = dest
|
|
|
|
|
|
|
|
|
|
def instruction_j(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_j(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 1)
|
|
|
|
|
addr = ins.get_imm(0)
|
|
|
|
|
self.pc = addr
|
|
|
|
|
|
|
|
|
|
def instruction_jal(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_jal(self, ins: 'LoadedInstruction'):
|
|
|
|
|
reg = 'ra' # default register is ra
|
|
|
|
|
if len(ins.args) == 1:
|
|
|
|
|
addr = ins.get_imm(0)
|
|
|
|
@ -339,39 +340,39 @@ class CPU:
|
|
|
|
|
self.regs.set(reg, self.pc)
|
|
|
|
|
self.pc = addr
|
|
|
|
|
|
|
|
|
|
def instruction_jalr(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_jalr(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 2)
|
|
|
|
|
reg = ins.get_reg(0)
|
|
|
|
|
addr = ins.get_imm(1)
|
|
|
|
|
self.regs.set(reg, self.pc)
|
|
|
|
|
self.pc = addr
|
|
|
|
|
|
|
|
|
|
def instruction_ret(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_ret(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 0)
|
|
|
|
|
self.pc = self.regs.get('ra')
|
|
|
|
|
|
|
|
|
|
def instruction_ecall(self, ins: 'LoadedInstruction'):
|
|
|
|
|
self.instruction_scall(ins)
|
|
|
|
|
def __instruction_ecall(self, ins: 'LoadedInstruction'):
|
|
|
|
|
self.__instruction_scall(ins)
|
|
|
|
|
|
|
|
|
|
def instruction_ebreak(self, ins: 'LoadedInstruction'):
|
|
|
|
|
self.instruction_sbreak(ins)
|
|
|
|
|
def __instruction_ebreak(self, ins: 'LoadedInstruction'):
|
|
|
|
|
self.__instruction_sbreak(ins)
|
|
|
|
|
|
|
|
|
|
def instruction_scall(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_scall(self, ins: 'LoadedInstruction'):
|
|
|
|
|
ASSERT_LEN(ins.args, 0)
|
|
|
|
|
syscall = Syscall(self.regs.get('a7'), self.regs, self)
|
|
|
|
|
self.syscall_int.handle_syscall(syscall)
|
|
|
|
|
|
|
|
|
|
def instruction_sbreak(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_sbreak(self, ins: 'LoadedInstruction'):
|
|
|
|
|
launch_debug_session(self, self.mmu, self.regs, "Debug instruction encountered at 0x{:08X}".format(self.pc))
|
|
|
|
|
|
|
|
|
|
def instruction_nop(self, ins: 'LoadedInstruction'):
|
|
|
|
|
def __instruction_nop(self, ins: 'LoadedInstruction'):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def all_instructions():
|
|
|
|
|
for method in vars(CPU):
|
|
|
|
|
if method.startswith('instruction_'):
|
|
|
|
|
yield method[12:]
|
|
|
|
|
if method.startswith('_CPU__instruction_'):
|
|
|
|
|
yield method[18:]
|
|
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
|
return "CPU(pc=0x{:08X}, cycle={})".format(
|
|
|
|
|