Source code for easier68k.core.models.assembly_parameter

"""
Assembly Parameter

Represents a single parameter in assembly code
this is the new 'EAMode' class
"""

from ..enum.ea_mode import EAMode
from ..enum.register import Register, ALL_ADDRESS_REGISTERS
from ...simulator.m68k import M68K
from ..util.conversions import to_word
from ..models.memory_value import MemoryValue
from ..enum.op_size import OpSize

# should try to make this a constant only defined once
MAX_MEMORY_LOCATION = 16777216  # 2^24


[docs]class AssemblyParameter: def __init__(self, mode: EAMode, data: int): """ Constructor Checks that the mode and the data are considered to be valid, like registers are within the correct bounds and addresses are not out of bounds. """ # ensure that the values are valid # when referencing a register, ensure that the data is within [0, 7] if mode in [EAMode.DataRegisterDirect, EAMode.AddressRegisterIndirectPreDecrement, EAMode.AddressRegisterIndirect, EAMode.AddressRegisterIndirectPostIncrement, EAMode.AddressRegisterDirect]: assert 0 <= data <= 7, 'The register number for this mode must be in the range [0, 7]!' if mode in [EAMode.AbsoluteWordAddress, EAMode.AbsoluteLongAddress]: # ensure that the address isn't outside the bounds of max memory location # and is greater than or eq to 0 assert 0 <= data <= MAX_MEMORY_LOCATION, 'An absolute address must be in the bounds [0, 2^24]!' if mode is EAMode.Immediate: # ensure that the value isn't too large, cannot be larger than a long word # negative values need to be converted into unsigned integers assert -2147483648 <= data <= 2147483647 or 0 <= data <= 0xFFFFFFFF, 'Value must fit inside a long word!' # set values self.mode = mode self.data = data def __str__(self): """ str util method :return: """ return "EA Mode: {}, Data: {}".format(self.mode, self.data)
[docs] def get_value(self, simulator: M68K, length: OpSize = OpSize.WORD) -> MemoryValue: """ Gets the value for this EAMode from the simulator :param simulator: reference to the 68k simulator :param length: the length in bytes associated with this operation, must be 1 2 or 4 :return: the value associated with this assembly parameter """ # this check is probably useless now that the enum is being used assert length in [OpSize.BYTE, OpSize.WORD, OpSize.LONG], 'The length for this operation must be 1 2 or 4 bytes!' # immediates are assumed to be signed values if self.mode is EAMode.IMM: ret = MemoryValue(OpSize(length)) if self.data < 0: ret.set_value_signed_int(self.data) else: ret.set_value_unsigned_int(self.data) return ret if self.mode is EAMode.DRD: # convert the data into the register value assert 0 <= self.data <= 7 data_register = Register(self.data) return simulator.get_register(data_register) if self.mode is EAMode.AddressRegisterDirect: # address register direct gets the value of the register assert Register.A0 <= self.data + Register.A0 <= Register.A7 # offset the value to compensate for the enum offset addr_register = Register(self.data + Register.A0) # get the value of the register, that's it return simulator.get_register(addr_register) if self.mode is EAMode.AddressRegisterIndirect: # address register indirect gets the value that the register points to # check that the register number is valid assert Register.A0.value <= self.data + Register.A0.value <= Register.A7.value # offset the value to compensate for the enum offset addr_register = Register(self.data + Register.A0.value) # this gets the value of the register, which points to a location # in memory where the target value is register_value = simulator.get_register(addr_register) # now get the value in memory of that register val = simulator.memory.get(length, register_value.get_value_unsigned()) return val if self.mode is EAMode.AddressRegisterIndirectPostIncrement: # address register indirect gets the value that the register points to # check that the register number is valid assert Register.A0.value <= self.data + Register.A0.value <= Register.A7.value # offset the value to compensate for the enum offset addr_register = Register(self.data + Register.A0.value) # this gets the value of the register, which points to a location # in memory where the target value is register_value = simulator.get_register(addr_register) # now get the value in memory of that register val = simulator.memory.get(OpSize.LONG, register_value.get_value_unsigned()) total = register_value.get_value_unsigned() + OpSize.LONG.value mv = MemoryValue(OpSize.LONG, unsigned_int=total) # do the post increment simulator.set_register(addr_register, mv) return val if self.mode is EAMode.AddressRegisterIndirectPreDecrement: # address register indirect gets the value that the register points to # check that the register number is valid assert Register.A0 <= self.data + Register.A0 <= Register.A7 # offset the value to compensate for the enum offset addr_register = Register(self.data + Register.A0) # this gets the value of the register, which points to a location # in memory where the target value is register_value = simulator.get_register(addr_register) total = register_value.get_value_unsigned() - OpSize.LONG.value mv = MemoryValue(OpSize.LONG, unsigned_int=total) # do the pre decrement (this does not update the value of register_value) simulator.set_register(addr_register, mv) # now get the value in memory of that register # and return that value return simulator.memory.get(OpSize.LONG, register_value.get_value_unsigned()) if self.mode in [EAMode.AbsoluteLongAddress, EAMode.AbsoluteWordAddress]: # if mode is absolute long or word address # then get the value in memory for that value # ensure that the data is valid assert 0 <= self.data <= MAX_MEMORY_LOCATION, 'The address must be in the range [0, 2^24]!' # get the address being looked for addr = self.data # if word address, mask out extra bits if self.mode is EAMode.AbsoluteWordAddress: addr = to_word(addr) # now get the value of that absolute long address return MemoryValue(OpSize.LONG, unsigned_int=addr) # if nothing was done by now, surely something must be wrong assert False, 'Invalid effective addressing mode!'
[docs] def set_value(self, simulator: M68K, value: MemoryValue): """ Sets the value of a destination mode :param simulator: the reference to the simulator :param value: the value to set for this assembly parameter :param length: the number of bits associated for this instruction, must be 1 2 or 4 :return: """ if not isinstance(value, MemoryValue): raise AssertionError("The value parameter must be of type MemoryValue") if self.mode is EAMode.Immediate: assert False, 'Cannot set the value of an immediate.' if self.mode is EAMode.DRD: # set the value for the data register assert 0 <= self.data <= 7 data_register = Register(self.data) simulator.set_register(data_register, value) if self.mode is EAMode.AddressRegisterDirect: # set the value for the address register # only ensure that it is referring to a valid address register # since this is a direct addressing mode, and not treated as a 'pointer' # to memory, this is not bounded by the number of address lines assert 0 <= self.data <= 7 addr_register = Register(self.data + Register.A0) simulator.set_register(addr_register, value) if self.mode is EAMode.AddressRegisterIndirect: # sets the value in memory that the address register points to assert 0 <= self.data <= 7 assert 0 <= value.get_value_unsigned() <= MAX_MEMORY_LOCATION, 'The value must fit in the memory space [0, 2^24]' addr_register = Register(self.data + Register.A0) location = simulator.get_register(addr_register).get_value_unsigned() simulator.memory.set(value.length, location, value) if self.mode is EAMode.AddressRegisterIndirectPreDecrement: # sets the value in memory that the address register points to assert 0 <= self.data <= 7 assert 0 <= value.get_value_unsigned() <= MAX_MEMORY_LOCATION, 'The value must fit in the memory space [0, 2^24]' addr_register = Register(self.data + Register.A0) location = simulator.get_register(addr_register).get_value_unsigned() location -= value.length.get_number_of_bytes() simulator.set_register(addr_register, MemoryValue(OpSize.LONG, unsigned_int=location)) simulator.memory.set(value.length, location, value) if self.mode is EAMode.AddressRegisterIndirectPostIncrement: # sets the value in memory that the address register points to assert 0 <= self.data <= 7 assert 0 <= value.get_value_unsigned() <= MAX_MEMORY_LOCATION, 'The value must fit in the memory space [0, 2^24]' addr_register = Register(self.data + Register.A0) location = simulator.get_register(addr_register).get_value_unsigned() simulator.memory.set(value.length, location, value) location += value.length.get_number_of_bytes() simulator.set_register(addr_register, MemoryValue(OpSize.LONG, unsigned_int=location)) if self.mode in [EAMode.AbsoluteLongAddress, EAMode.AbsoluteWordAddress]: # assert that the value fits in the bounds of memory assert 0 <= self.data <= MAX_MEMORY_LOCATION assert 0 <= value.get_value_unsigned() <= 0xFFFFFFFF, 'The value must fit inside of a long word!' # if the mode is a word if self.mode is EAMode.AbsoluteWordAddress: # mask it to only be a word value = MemoryValue(value.length, unsigned_int=to_word(value.get_value_unsigned())) # set the value in memory to that simulator.memory.set(value.length, self.data, value)