squashing bugs related to Int32 wrapping and sign extension
This commit is contained in:
parent
c2b6385523
commit
4004c5ee6d
@ -24,11 +24,11 @@ class RV32I(InstructionSet):
|
||||
|
||||
def instruction_lb(self, ins: 'Instruction'):
|
||||
rd, addr = self.parse_mem_ins(ins)
|
||||
self.regs.set(rd, Int32(self.mmu.read(addr.unsigned_value, 1)))
|
||||
self.regs.set(rd, Int32.sign_extend(self.mmu.read(addr.unsigned_value, 1), 8))
|
||||
|
||||
def instruction_lh(self, ins: 'Instruction'):
|
||||
rd, addr = self.parse_mem_ins(ins)
|
||||
self.regs.set(rd, Int32(self.mmu.read(addr.unsigned_value, 2)))
|
||||
self.regs.set(rd, Int32.sign_extend(self.mmu.read(addr.unsigned_value, 2), 16))
|
||||
|
||||
def instruction_lw(self, ins: 'Instruction'):
|
||||
rd, addr = self.parse_mem_ins(ins)
|
||||
@ -36,23 +36,23 @@ class RV32I(InstructionSet):
|
||||
|
||||
def instruction_lbu(self, ins: 'Instruction'):
|
||||
rd, addr = self.parse_mem_ins(ins)
|
||||
self.regs.set(rd, UInt32(self.mmu.read(addr.unsigned_value, 1)))
|
||||
self.regs.set(rd, Int32(self.mmu.read(addr.unsigned_value, 1)))
|
||||
|
||||
def instruction_lhu(self, ins: 'Instruction'):
|
||||
rd, addr = self.parse_mem_ins(ins)
|
||||
self.regs.set(rd, UInt32(self.mmu.read(addr.unsigned_value, 2)))
|
||||
self.regs.set(rd, Int32(self.mmu.read(addr.unsigned_value, 2)))
|
||||
|
||||
def instruction_sb(self, ins: 'Instruction'):
|
||||
rd, addr = self.parse_mem_ins(ins)
|
||||
self.mmu.write(addr.value, 1, self.regs.get(rd).to_bytes(1))
|
||||
self.mmu.write(addr.unsigned_value, 1, self.regs.get(rd).to_bytes(1))
|
||||
|
||||
def instruction_sh(self, ins: 'Instruction'):
|
||||
rd, addr = self.parse_mem_ins(ins)
|
||||
self.mmu.write(addr.value, 2, self.regs.get(rd).to_bytes(2))
|
||||
self.mmu.write(addr.unsigned_value, 2, self.regs.get(rd).to_bytes(2))
|
||||
|
||||
def instruction_sw(self, ins: 'Instruction'):
|
||||
rd, addr = self.parse_mem_ins(ins)
|
||||
self.mmu.write(addr.value, 4, self.regs.get(rd).to_bytes(4))
|
||||
self.mmu.write(addr.unsigned_value, 4, self.regs.get(rd).to_bytes(4))
|
||||
|
||||
def instruction_sll(self, ins: 'Instruction'):
|
||||
ASSERT_LEN(ins.args, 3)
|
||||
@ -140,7 +140,7 @@ class RV32I(InstructionSet):
|
||||
def instruction_lui(self, ins: 'Instruction'):
|
||||
ASSERT_LEN(ins.args, 2)
|
||||
reg = ins.get_reg(0)
|
||||
imm = UInt32(ins.get_imm(1)) << 12
|
||||
imm = UInt32(ins.get_imm(1) << 12)
|
||||
self.regs.set(reg, Int32(imm))
|
||||
|
||||
def instruction_auipc(self, ins: 'Instruction'):
|
||||
@ -263,14 +263,14 @@ class RV32I(InstructionSet):
|
||||
ASSERT_LEN(ins.args, 2)
|
||||
reg = ins.get_reg(0)
|
||||
addr = ins.get_imm(1)
|
||||
self.regs.set(reg, self.pc)
|
||||
self.regs.set(reg, Int32(self.pc))
|
||||
self.pc = addr
|
||||
|
||||
def instruction_jalr(self, ins: 'Instruction'):
|
||||
ASSERT_LEN(ins.args, 2)
|
||||
reg = ins.get_reg(0)
|
||||
addr = ins.get_imm(1)
|
||||
self.regs.set(reg, self.pc)
|
||||
self.regs.set(reg, Int32(self.pc))
|
||||
self.pc = addr
|
||||
|
||||
def instruction_ret(self, ins: 'Instruction'):
|
||||
@ -307,13 +307,13 @@ class RV32I(InstructionSet):
|
||||
ASSERT_LEN(ins.args, 2)
|
||||
reg = ins.get_reg(0)
|
||||
immediate = ins.get_imm(1)
|
||||
self.regs.set(reg, immediate)
|
||||
self.regs.set(reg, Int32(immediate))
|
||||
|
||||
def instruction_la(self, ins: 'Instruction'):
|
||||
ASSERT_LEN(ins.args, 2)
|
||||
reg = ins.get_reg(0)
|
||||
immediate = ins.get_imm(1)
|
||||
self.regs.set(reg, immediate)
|
||||
self.regs.set(reg, Int32(immediate))
|
||||
|
||||
def instruction_mv(self, ins: 'Instruction'):
|
||||
ASSERT_LEN(ins.args, 2)
|
||||
|
@ -109,7 +109,7 @@ class Registers:
|
||||
if mark_set:
|
||||
self.last_set = reg
|
||||
# check 32 bit signed bounds
|
||||
self.vals[reg] = val
|
||||
self.vals[reg] = val.unsigned()
|
||||
return True
|
||||
|
||||
def get(self, reg, mark_read=True) -> 'Int32':
|
||||
|
@ -16,7 +16,8 @@ class Int32:
|
||||
|
||||
def __init__(self, val: Union[int, c_int32, c_uint32, 'Int32', bytes, bytearray] = 0):
|
||||
if isinstance(val, (bytes, bytearray)):
|
||||
self._val = self.__class__._type(int.from_bytes(val, 'little', signed=True))
|
||||
signed = len(val) == 4 and self._type == c_int32
|
||||
self._val = self.__class__._type(int.from_bytes(val, 'little', signed=signed))
|
||||
elif isinstance(val, self.__class__._type):
|
||||
self._val = val
|
||||
elif isinstance(val, (c_uint32, c_int32, Int32)):
|
||||
@ -187,7 +188,7 @@ class Int32:
|
||||
:param bytes: The length of the bytearray
|
||||
:return: A little-endian representation of the contained integer
|
||||
"""
|
||||
return bytearray(self.unsigned_value.to_bytes(bytes, 'little'))
|
||||
return bytearray(self.unsigned_value.to_bytes(4, 'little'))[0:bytes]
|
||||
|
||||
def signed(self) -> 'Int32':
|
||||
"""
|
||||
@ -225,6 +226,25 @@ class Int32:
|
||||
def __hex__(self):
|
||||
return hex(self.value)
|
||||
|
||||
@classmethod
|
||||
def sign_extend(cls, data: Union[bytes, bytearray, int], bits: int):
|
||||
"""
|
||||
Create an instance of Int32 by sign extending :param:bits bits from :param:data
|
||||
to 32 bits
|
||||
|
||||
:param data: The source data
|
||||
:param bits: The number of bits in the source data
|
||||
:return: An instance of Int32, holding the sign-extended value
|
||||
"""
|
||||
if isinstance(data, (bytes, bytearray)):
|
||||
data = int.from_bytes(data, 'little')
|
||||
sign = data >> (bits - 1)
|
||||
if sign > 1:
|
||||
print("overflow in Int32.sext!")
|
||||
if sign:
|
||||
data = (data & (2 ** (bits - 1) - 1)) - 2**(bits-1)
|
||||
return cls(data)
|
||||
|
||||
|
||||
class UInt32(Int32):
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user