Source code for easier68k.core.opcodes.lea

from ...core.enum.ea_mode import EAMode
from ...core.models.assembly_parameter import AssemblyParameter
from ...core.enum import ea_mode_bin
from ...core.enum.ea_mode_bin import parse_ea_from_binary
from ...simulator.m68k import M68K
from ...core.opcodes.opcode import Opcode
from ...core.util import opcode_util
from ...core.enum.op_size import OpSize
from ..util.parsing import parse_assembly_parameter
from ..util.split_bits import split_bits


class Lea(Opcode):
    pass


[docs]class Lea(Opcode): """ LEA: Load Effective Address Operation: < ea > → An Syntax: LEA < ea > ,An Attributes: Size = (Long) Description: Loads the effective address into the specified address register. All 32 bits of the address register are effected by this instruction. Condition Codes: Not affected. """ def __init__(self, params: list): assert len(params) == 2 assert isinstance(params[0], AssemblyParameter) assert isinstance(params[1], AssemblyParameter) # Can't take data register, address register, or ARI with modifications assert params[0].mode not in [EAMode.DRD, EAMode.ARD, EAMode.ARIPD, EAMode.ARIPI, EAMode.IMM] self.src = params[0] # Check that the destination is of a proper type assert params[1].mode == EAMode.ARD # Can only take address register direct self.dest = params[1]
[docs] def assemble(self) -> bytearray: """ Assembles this opcode into hex to be inserted into memory :return: The hex version of this opcode """ # create the opcode ret_opcode = 0b0100 << 12 ret_opcode |= self.dest.data << 9 ret_opcode |= 0b111 << 6 ret_opcode |= ea_mode_bin.parse_from_ea_mode_modefirst(self.src) ret_bytes = bytearray(ret_opcode.to_bytes(2, byteorder='big', signed=False)) ret_bytes.extend( opcode_util.ea_to_binary_post_op(self.src, OpSize.LONG if self.src.mode == EAMode.ALA else OpSize.WORD) .get_value_bytearray()) return ret_bytes
[docs] def execute(self, simulator: M68K): """ Executes this command in a simulator :param simulator: The simulator to execute the command on :return: Nothing """ val_len = OpSize.LONG.get_number_of_bytes() # get the value of the source src_val = self.src.get_value(simulator, val_len) # set the value in the dest self.dest.set_value(simulator, src_val) # increment the program counter by at least 2 bytes (1 word) to_increment = 2 if self.src.mode is EAMode.AddressRegisterIndirect: to_increment += val_len if self.src.mode is EAMode.AbsoluteWordAddress: to_increment += OpSize.LONG.value if self.src.mode is EAMode.AbsoluteLongAddress: to_increment += OpSize.LONG.value simulator.increment_program_counter(to_increment)
def __str__(self): # Makes this a bit easier to read in doctest output return 'LEA command: src {}, dest {}'.format(self.src, self.dest)
[docs] @classmethod def command_matches(cls, command: str) -> bool: """ Checks whether a command string is an instance of this command type :param command: The command string to check (e.g. 'MOVE.B', 'LEA', etc.) :return: Whether the string is an instance of this command type """ return opcode_util.command_matches(command, 'LEA')
[docs] @classmethod def get_word_length(cls, command: str, parameters: str) -> int: """ >>> Lea.get_word_length('LEA', '(A0), A1') 1 >>> Lea.get_word_length('LEA', '#$90, A0') 2 >>> Lea.get_word_length('LEA', '#$ABCDE, A0') 3 >>> Lea.get_word_length('LEA', '($AAAA).L, A6') 3 >>> Lea.get_word_length('LEA', '($AAAA).W, A5') 2 Gets what the end length of this command will be in memory :param command: The text of the command itself (e.g. "LEA", "MOVE.B", etc.) :param parameters: The parameters after the command :return: The length of the bytes in memory in words, as well as a list of warnings or errors encountered """ valid, issues = cls.is_valid(command, parameters) if not valid: return 0 # We can forego asserts in here because we've now confirmed this is valid assembly code # Split the parameters into EA modes params = parameters.split(',') if len(params) != 2: # We need exactly 2 parameters issues.append(('Invalid syntax (missing a parameter/too many parameters)', 'ERROR')) return 0 src = parse_assembly_parameter(params[0].strip()) # Parse the source and make sure it parsed right dest = parse_assembly_parameter(params[1].strip()) length = 1 # Always 1 word not counting additions to end if src.mode == EAMode.IMM: # If we're moving an immediate we have to append the value afterwards if len(hex(src.data)[2:]) > 4: length += 2 else: length += 1 if src.mode == EAMode.AWA: # Appends a word length += 1 if src.mode == EAMode.ALA: # Appends a long, so 2 words length += 2 if dest.mode == EAMode.AWA: # Appends a word length += 1 if dest.mode == EAMode.ALA: # Appends a long, so 2 words length += 2 return length
[docs] @classmethod def is_valid(cls, command: str, parameters: str) -> (bool, list): """ Tests whether the given command is valid >>> Lea.is_valid('LEA', '(A0), A1')[0] True >>> Lea.is_valid('LEA', 'A0')[0] False >>> Lea.is_valid('LEA.B', '(A0), A1')[0] False >>> Lea.is_valid('LEA', 'D0, A2')[0] False >>> Lea.is_valid('LEA', '#$0A, A4')[0] True >>> Lea.is_valid('LEA', '($AAAA).L, A7')[0] True :param command: The command itself (e.g. 'MOVE.B', 'LEA', etc.) :param parameters: The parameters after the command (such as the source and destination of a move) :return: Whether the given command is valid and a list of issues/warnings encountered """ return opcode_util.n_param_is_valid(command, parameters, "LEA", 2, None, None, [[EAMode.DRD, EAMode.ARD, EAMode.ARIPD, EAMode.ARIPI], [mode for mode in EAMode if mode is not EAMode.ARD]]) # Select all but ARD
[docs] @classmethod def disassemble_instruction(cls, data: bytearray) -> (Lea, int): """ Parses some raw data into an instance of the opcode class :param data: The data used to convert into an opcode instance :return: The constructed instance or none if there was an error and the amount of data in words that was used (e.g. extra for immediate data) or 0 for not a match """ assert len(data) >= 2, 'opcode size is at least 1 word' # 'big' endian byte order first_word = int.from_bytes(data[0:2], 'big') [opcode_bin, register_bin, ones_bin, ea_mode, ea_reg] = split_bits(first_word, [4, 3, 3, 3, 3]) # check opcode if opcode_bin != 0b0100 or ones_bin != 0b111: # Second condition to distinguish from TRAP return None wordsUsed = 1 src_EA = parse_ea_from_binary(ea_mode, ea_reg, OpSize.LONG, True, data[wordsUsed * 2:]) wordsUsed += src_EA[1] dest_EA = AssemblyParameter(EAMode.ARD, register_bin) # when making the new Move, need to convert that MoveSize back into an OpSize return cls([src_EA[0], dest_EA])
[docs] @classmethod def from_str(cls, command: str, parameters: str): """ Parses a LEA command from memory. >>> str(Lea.from_str('LEA', '(A0), A1')) 'LEA command: src EA Mode: EAMode.ARI, Data: 0, dest EA Mode: EAMode.ARD, Data: 1' >>> str(Lea.from_str('LEA', '($0A).W, A2')) 'LEA command: src EA Mode: EAMode.AWA, Data: 10, dest EA Mode: EAMode.ARD, Data: 2' :param command: The command itself (e.g. 'MOVE.B', 'LEA', etc.) :param parameters: The parameters after the command (such as the source and destination of a move) """ return opcode_util.n_param_from_str(command, parameters, Lea, 2, None)