easier68k.core.util package

Submodules

easier68k.core.util.conversions module

easier68k.core.util.conversions.to_byte(word: int) → int[source]
>>> hex(to_byte(0x12345678))
'0x78'
>>> to_byte(257)
1
>>> hex(to_byte(0x00001101))
'0x1'

Masks the given value to the size of a byte (8 bits) :param word: :return:

easier68k.core.util.conversions.to_word(word: int) → int[source]
>>> hex(to_word(0x1234ABCD))
'0xabcd'
>>> hex(to_word(0))
'0x0'

This size should never happen! >>> hex(to_word(0x12345678ABCD)) ‘0xabcd’

Masks the given value to the size of a word (16 bits) :param word: :return:

easier68k.core.util.find_module module

easier68k.core.util.find_module.find_opcode_cls(opcode: str) → type[source]

Finds the proper module and module class based on the opcode :param opcode: The opcode to search for :return: The module and class found (or (None, None) if it doesn’t find any)

easier68k.core.util.input module

easier68k.core.util.input.get_input()[source]

Wrap input in this method so that it can be wrapped with @patch in tests :return:

easier68k.core.util.opcode_util module

easier68k.core.util.opcode_util.check_valid_command(command: str, template: str, can_take_size=True, valid_sizes=[<OpSize.LONG: 4>, <OpSize.WORD: 2>, <OpSize.BYTE: 1>]) → bool[source]

Checks whether this command is valid

>>> check_valid_command("MOVE.B", "MOVE")
True
>>> check_valid_command("MOVE", "MOVE")
True
>>> check_valid_command("MOV", "MOVE")
False
>>> check_valid_command("LEA", "LEA", can_take_size=False)
True
>>> check_valid_command("LEA.B", "LEA", can_take_size=False)
False
>>> check_valid_command("MOVEA.W", "MOVEA", valid_sizes=[OpSize.WORD, OpSize.LONG])
True
>>> check_valid_command("MOVEA.B", "MOVEA", valid_sizes=[OpSize.WORD, OpSize.LONG])
False
Parameters:
  • command – The command to check
  • template – The type of command we’re checking for (like ‘MOVE’, ‘LEA’, etc.)
  • can_take_size – Whether this command takes a size argument or not
Returns:

Whether this command is valid or not

easier68k.core.util.opcode_util.command_matches(command: str, template: str) → bool[source]
>>> command_matches("MOVE.B", "MOVE")
True
>>> command_matches("MOVE", "MOVE")
True
>>> command_matches("MOV", "MOVE")
False
>>> command_matches("MOV.B", "MOVE")
False

Handles the typical checking of a command string (like ‘MOVE.B’, ‘LEA’, etc.). NOTE: this will match some error conditions, this just does the broadest possible checks. The main one is that this doesn’t check for more than 1 period (MOVE.B.W, for example) or check for valid sizes/lack of sizes. The assumption is that this will be handled in the actual parsing methods for proper error handling. :param command: The command string to parse :param template: The template to check with :return: Whether the command matches

easier68k.core.util.opcode_util.ea_to_binary_post_op(ea: easier68k.core.enum.ea_mode.EAMode, size: easier68k.core.enum.op_size.OpSize) → easier68k.core.models.memory_value.MemoryValue[source]

Gets the binary (if any) of an EA Mode to append after the command itself. For example, if we were to do ‘MOVE.B #$42, D0’, the immediate would need to be appended after the command: this returns the part that needs to be appended.

>>> str(ea_to_binary_post_op(parse_assembly_parameter('#$42'), OpSize.BYTE))
'WORD MemoryValue 0x42'
>>> str(ea_to_binary_post_op(parse_assembly_parameter('D0'), OpSize.WORD))
'None'
>>> str(ea_to_binary_post_op(parse_assembly_parameter('#$42'), OpSize.LONG))
'LONG MemoryValue 0x42'
>>> str(ea_to_binary_post_op(parse_assembly_parameter('($242).W'), OpSize.WORD))
'WORD MemoryValue 0x242'
>>> str(ea_to_binary_post_op(parse_assembly_parameter('($242).L'), OpSize.LONG))
'LONG MemoryValue 0x242'
>>> str(ea_to_binary_post_op(parse_assembly_parameter('#-1'), OpSize.BYTE))
'WORD MemoryValue 0xffff'
>>> str(ea_to_binary_post_op(parse_assembly_parameter('#-113442343'), OpSize.LONG))
'LONG MemoryValue 0xf93d01d9'
Parameters:
  • ea – The effective address that needs to be converted
  • size – The size of the operation
Returns:

The binary that needs to be appended, in string form (or an empty string)

easier68k.core.util.opcode_util.get_size(command: str, default_size=<OpSize.WORD: 2>) → easier68k.core.enum.op_size.OpSize[source]

Gets the size of a command, or supplies the default size

>>> get_size("MOVE.B")
<OpSize.BYTE: 1>
>>> get_size("MOVE")
<OpSize.WORD: 2>
>>> get_size("MOVE", default_size=OpSize.BYTE)
<OpSize.BYTE: 1>
Parameters:
  • command – The command string to parse
  • default_size – The default size if no size is found
Returns:

The size of the command

easier68k.core.util.opcode_util.n_param_from_str(command: str, parameters: str, opcode_cls, n: int = 2, default_size: easier68k.core.enum.op_size.OpSize = <OpSize.WORD: 2>)[source]

Parses a command from text. Note that this assumes that is_valid has already been run and was successful.

Parameters:
  • command – The command itself (e.g. ‘MOVE.B’, ‘LEA’, etc.)
  • parameters – The parameters after the command (such as the source and destination of a move)
  • opcode_cls – The class of opcode we’re parsing to
  • n – The number of parameters to parse
  • default_size – The default size if no size is specified, or None if this is an unsized opcode
Returns:

The parsed command

easier68k.core.util.opcode_util.n_param_is_valid(command: str, parameters: str, opcode: str, n: int = 2, valid_sizes=[<OpSize.LONG: 4>, <OpSize.WORD: 2>, <OpSize.BYTE: 1>], default_size=<OpSize.WORD: 2>, param_invalid_modes=[]) -> (<class 'bool'>, <class 'list'>)[source]

Tests whether the given command is valid

Parameters:
  • command – The command itself (e.g. ‘MOVE.B’, ‘LEA’, etc.)
  • parameters – The parameters after the command (such as the source and destination of a move)
  • opcode – The opcode to check for (‘MOVE’, ‘LEA’, etc.)
  • valid_sizes – valid sizes of the command (empty list or None for no size)
  • default_size – the default size for the command (can be None if it doesn’t take a command)
  • n – the number of parameters to parse
  • param_invalid_modes – list of lists of invalid parameter modes (in order)
Returns:

Whether the given command is valid and a list of issues/warnings encountered

easier68k.core.util.parsing module

easier68k.core.util.parsing.from_str_util(command: str, parameters: str) -> (<enum 'OpSize'>, <class 'list'>, <class 'list'>)[source]

Util method for from_str Splits the command into both parts, gets the normalized size and splits the parameters

>>> from_str_util('MOVE.B', '#123, D0')
(<OpSize.BYTE: 1>, ['#123', 'D0'], ['MOVE', 'B'])
>>> from_str_util('FAKEOP', '$AAAA, #123, $AAAA')
(<OpSize.WORD: 2>, ['$AAAA', '#123', '$AAAA'], ['FAKEOP'])
>>> from_str_util('NOPARAM.L', '')
(<OpSize.LONG: 4>, [''], ['NOPARAM', 'L'])
Parameters:
  • command – the command str
  • parameters – the parameters str
Returns:

size {str}, params {list} of str, parts - both sides of the command after split

easier68k.core.util.parsing.get_label(line: str) → str[source]

Returns the label from a line (if it has one, if not returns None)

>>> get_label('test DC.B $0A')
'test'
>>> get_label(';test DC.B $0A')  # should return nothing
>>> get_label('    BEQ test')  # should return nothing
Parameters:line – The line to get the label from
Returns:The label in the line
easier68k.core.util.parsing.get_opcode(line: str) → str[source]

Gets the opcode out of a line (with or without label)

>>> get_opcode('start EQU $400')
'EQU'
>>> get_opcode('    MOVE.B D0, D1')
'MOVE.B'
>>> get_opcode('; start EQU $400')
''
Parameters:line – The line to get the opcode from
Returns:The opcode found in said line
easier68k.core.util.parsing.has_label(line: str) → bool[source]

Returns whether or not this line has a label in it (basically if it starts with a space or not) :param line: The line to test :return: Whether the test line has a label in it

>>> has_label('data    DC.B $A3')
True
>>> has_label('    BEQ test')
False
>>> has_label('  TRAP #15')
False
>>> has_label(';start EQU $400')
False
easier68k.core.util.parsing.parse_assembly_parameter(addr: str) → easier68k.core.models.assembly_parameter.AssemblyParameter[source]

Parses an effective addressing mode (such as D0, (A1), #$01) and makes a new AssemblyParameter

>>> parse_assembly_parameter('D')
Traceback (most recent call last):
...
AssertionError
>>> str(parse_assembly_parameter('D3'))
'EA Mode: EAMode.DRD, Data: 3'
>>> str(parse_assembly_parameter('A6'))
'EA Mode: EAMode.ARD, Data: 6'
>>> str(parse_assembly_parameter('(A4)'))
'EA Mode: EAMode.ARI, Data: 4'
>>> str(parse_assembly_parameter('(A2)+'))
'EA Mode: EAMode.ARIPI, Data: 2'
>>> str(parse_assembly_parameter('(A2)-'))  # Invalid, can't do "post-decrement"
Traceback (most recent call last):
...
AssertionError
>>> str(parse_assembly_parameter('($45).W'))
'EA Mode: EAMode.AWA, Data: 69'
>>> str(parse_assembly_parameter('(%01010111).L'))
'EA Mode: EAMode.ALA, Data: 87'
>>> str(parse_assembly_parameter('#$FF'))
'EA Mode: EAMode.IMM, Data: 255'
>>> str(parse_assembly_parameter('#$ABCD'))
'EA Mode: EAMode.IMM, Data: 43981'
>>> str(parse_assembly_parameter('#-1'))
'EA Mode: EAMode.IMM, Data: -1'
>>> str(parse_assembly_parameter('#-100'))
'EA Mode: EAMode.IMM, Data: -100'
>>> str(parse_assembly_parameter('-(A2)'))
'EA Mode: EAMode.ARIPD, Data: 2'
easier68k.core.util.parsing.parse_literal(literal: str) → int[source]

Parses a literal (aka “1234” or “$A0F” or “%1001”)

>>> parse_literal('$BA1')
2977
>>> parse_literal('%01010111')
87
>>> parse_literal('57')
57
>>> parse_literal('400')
400
>>> parse_literal('-100')
-100
>>> parse_literal('-1')
-1
Parameters:literal – A string containing the literal to parse
Returns:The parsed literal (a bytearray type)
easier68k.core.util.parsing.strip_comments(line: str) → str[source]

Removes all comments from a line (basically makes this line into the ‘compiler’ version)

>>> strip_comments('label TRAP #15 * This does a thing')
'label TRAP #15 '
>>> strip_comments('    ORG start ;label')
'    ORG start '
>>> strip_comments(';    ADD D0, D1 * asdf')
''
Parameters:line – The line to strip comments from
Returns:The stripped line
easier68k.core.util.parsing.strip_label(line: str) → str[source]

Strips the label from a line, isolating the rest of the line (side effect: also strips comments)

>>> strip_label('ORG start')
'start'
>>> strip_label('RTS ;comm')
''
>>> strip_label(';all commented')
''
>>> strip_label('MOVE D0, D1 * Moves D0 into D1')
'D0, D1 '
Parameters:line – The line to strip the label from
Returns:The stripped line
easier68k.core.util.parsing.strip_opcode(line: str) → str[source]

Strips the opcode from a line

>>> strip_opcode('start EQU $400')
'$400'
>>> strip_opcode('    MOVE.B D0, D1')
'D0, D1'
>>> strip_opcode('    RTS')
''
>>> strip_opcode('start EQU $400 ; comments!')
'$400'
Parameters:line – The line to strip the opcode from
Returns:The line with the opcode stripped (as well as comments and labels)

easier68k.core.util.split_bits module

easier68k.core.util.split_bits.split_bits(word: int, amounts: list)[source]

takes in a word and a list of bit amounts and returns the bits in the word split up. See the doctests for concrete examples

>>> [bin(x) for x in split_bits(0b1001111010000001, [16])]
['0b1001111010000001']
>>> [bin(x) for x in split_bits(0b1001111010000001, [8,8])]
['0b10011110', '0b10000001']

not the whole 16 bits! >>> [bin(x) for x in split_bits(0b1001111010000001, [8])] Traceback (most recent call last): AssertionError: expected to split exactly one word

This is a test splitting MOVE.B (A1),D4 >>> [bin(x) for x in split_bits(0b0001001010000100, [2,2,3,3,3,3])] [‘0b0’, ‘0b1’, ‘0b1’, ‘0b10’, ‘0b0’, ‘0b100’]