def test_invalid(self): opcode = ( get_operand_opcode(Token(TokenType.WORD_LITERAL, 0xABCD, 0)) + get_operand_opcode(Token(TokenType.WORD_REGISTER, 'AX', 0))) inst = MOV(self.cpu, opcode) with self.assertRaises(InvalidWriteOperationError): inst.do()
def test_macro_dat_and_datn(self): opcode = self.assembler.assemble_code(''' MOV AX [stuff] NOP SHUTDOWN stuff: .DAT 0x1234 0x56 'ABC' .DATN 0x05 0xFF .DATN 0x03 0x1234 .DATN 0x02 'ABC' ''') expected_opcode = [0x34] expected_opcode += get_operand_opcode( Token(TokenType.WORD_REGISTER, 'AX', None)) expected_opcode += get_operand_opcode( Token( TokenType.REL_REF_WORD, Reference(7, None, 'W'), None, )) expected_opcode += [0x78] expected_opcode += [0x9A] expected_opcode += [0x12, 0x34, 0x56, 0x41, 0x42, 0x43] expected_opcode += [0xFF, 0xFF, 0xFF, 0xFF, 0xFF] expected_opcode += [0x12, 0x34, 0x12, 0x34, 0x12, 0x34] expected_opcode += [0x41, 0x42, 0x43, 0x41, 0x42, 0x43] self.assertListEqual(opcode, expected_opcode)
def test_invalid(self): opcode = ( get_operand_opcode(Token(TokenType.WORD_LITERAL, 0xABCD, 0)) + get_operand_opcode(Token(TokenType.WORD_REGISTER, 'AX', 0)) ) inst = MOV(self.cpu, opcode) with self.assertRaises(InvalidWriteOperationError): inst.do()
def test_word(self): self.cpu.registers.get_register.return_value = 0xFFFF opcode = (get_operand_opcode(Token(TokenType.WORD_REGISTER, 'AX', 0)) + get_operand_opcode(Token(TokenType.WORD_LITERAL, 0xFFFE, 0))) inst = MOV(self.cpu, opcode) self.assertEqual(inst.get_operand(0), 65535) self.assertEqual(inst.get_signed_operand(0), -1) self.assertEqual(inst.get_operand(1), 65534) self.assertEqual(inst.get_signed_operand(1), -2)
def test_byte(self): self.cpu.registers.get_register.return_value = 0xFF opcode = (get_operand_opcode(Token(TokenType.BYTE_REGISTER, 'AL', 0)) + get_operand_opcode(Token(TokenType.BYTE_LITERAL, 0xFE, 0))) inst = MOV(self.cpu, opcode) self.assertEqual(inst.get_operand(0), 255) self.assertEqual(inst.get_signed_operand(0), -1) self.assertEqual(inst.get_operand(1), 254) self.assertEqual(inst.get_signed_operand(1), -2)
def test_byte(self): opcode = (get_operand_opcode(Token(TokenType.BYTE_REGISTER, 'AL', 0)) + get_operand_opcode(Token(TokenType.BYTE_LITERAL, 0xAB, 0))) inst = MOV(self.cpu, opcode) inst.do() self.assertEqual(self.cpu.registers.set_register.call_count, 1) self.assertEqual( self.cpu.registers.set_register.call_args_list[0][0][0], 'AL') self.assertEqual( self.cpu.registers.set_register.call_args_list[0][0][1], 0xAB)
def test_word(self): opcode = (get_operand_opcode(Token(TokenType.WORD_REGISTER, 'AX', 0)) + get_operand_opcode(Token(TokenType.WORD_LITERAL, 0xABCD, 0))) inst = MOV(self.cpu, opcode) inst.do() self.assertEqual(self.cpu.registers.set_register.call_count, 1) self.assertEqual( self.cpu.registers.set_register.call_args_list[0][0][0], 'AX') self.assertEqual( self.cpu.registers.set_register.call_args_list[0][0][1], 0xABCD)
def test_byte(self): opcode = ( get_operand_opcode(Token(TokenType.BYTE_REGISTER, 'AL', 0)) + get_operand_opcode(Token(TokenType.BYTE_LITERAL, 0xAB, 0)) ) inst = MOV(self.cpu, opcode) inst.do() self.assertEqual(self.cpu.registers.set_register.call_count, 1) self.assertEqual(self.cpu.registers.set_register.call_args_list[0][0][0], 'AL') self.assertEqual(self.cpu.registers.set_register.call_args_list[0][0][1], 0xAB)
def test_word(self): opcode = ( get_operand_opcode(Token(TokenType.WORD_REGISTER, 'AX', 0)) + get_operand_opcode(Token(TokenType.WORD_LITERAL, 0xABCD, 0)) ) inst = MOV(self.cpu, opcode) inst.do() self.assertEqual(self.cpu.registers.set_register.call_count, 1) self.assertEqual(self.cpu.registers.set_register.call_args_list[0][0][0], 'AX') self.assertEqual(self.cpu.registers.set_register.call_args_list[0][0][1], 0xABCD)
def test_byte(self): self.cpu.registers.get_register.return_value = 0xFF opcode = ( get_operand_opcode(Token(TokenType.BYTE_REGISTER, 'AL', 0)) + get_operand_opcode(Token(TokenType.BYTE_LITERAL, 0xFE, 0)) ) inst = MOV(self.cpu, opcode) self.assertEqual(inst.get_operand(0), 255) self.assertEqual(inst.get_signed_operand(0), -1) self.assertEqual(inst.get_operand(1), 254) self.assertEqual(inst.get_signed_operand(1), -2)
def test_word(self): self.cpu.registers.get_register.return_value = 0xFFFF opcode = ( get_operand_opcode(Token(TokenType.WORD_REGISTER, 'AX', 0)) + get_operand_opcode(Token(TokenType.WORD_LITERAL, 0xFFFE, 0)) ) inst = MOV(self.cpu, opcode) self.assertEqual(inst.get_operand(0), 65535) self.assertEqual(inst.get_signed_operand(0), -1) self.assertEqual(inst.get_operand(1), 65534) self.assertEqual(inst.get_signed_operand(1), -2)
def test_signed_word(self): opcode = ( get_operand_opcode(Token(TokenType.WORD_REGISTER, 'AX', 0)) + get_operand_opcode(Token(TokenType.WORD_LITERAL, 0xABCD, 0)) ) inst = MOV(self.cpu, opcode) inst.set_signed_operand(0, -1) self.assertEqual(self.cpu.registers.set_register.call_count, 1) self.assertEqual(self.cpu.registers.set_register.call_args_list[0][0][0], 'AX') self.assertEqual(self.cpu.registers.set_register.call_args_list[0][0][1], 0xFFFF) with self.assertRaises(InvalidWriteOperationError): inst.set_signed_operand(1, -1)
def test_register(self): self.assertListEqual(get_operand_opcode(Token(TokenType.WORD_REGISTER, 'AX', 0)), [ _get_opbyte(OpLen.WORD, OpType.REGISTER, 'AX'), ]) self.assertListEqual(get_operand_opcode(Token(TokenType.BYTE_REGISTER, 'AL', 0)), [ _get_opbyte(OpLen.BYTE, OpType.REGISTER, 'AL'), ]) self.assertListEqual(get_operand_opcode(Token(TokenType.BYTE_REGISTER, 'AH', 0)), [ _get_opbyte(OpLen.BYTE, OpType.REGISTER, 'AH'), ]) with self.assertRaises(InvalidRegisterNameError): get_operand_opcode(Token(TokenType.WORD_REGISTER, 'XX', 0))
def test_signed_word(self): opcode = (get_operand_opcode(Token(TokenType.WORD_REGISTER, 'AX', 0)) + get_operand_opcode(Token(TokenType.WORD_LITERAL, 0xABCD, 0))) inst = MOV(self.cpu, opcode) inst.set_signed_operand(0, -1) self.assertEqual(self.cpu.registers.set_register.call_count, 1) self.assertEqual( self.cpu.registers.set_register.call_args_list[0][0][0], 'AX') self.assertEqual( self.cpu.registers.set_register.call_args_list[0][0][1], 0xFFFF) with self.assertRaises(InvalidWriteOperationError): inst.set_signed_operand(1, -1)
def test_signed_byte(self): self.cpu.registers.get_register.return_value = 0xFF opcode = ( get_operand_opcode(Token(TokenType.BYTE_REGISTER, 'AL', 0)) + get_operand_opcode(Token(TokenType.BYTE_LITERAL, 0xAB, 0)) ) inst = MOV(self.cpu, opcode) inst.set_signed_operand(0, -1) self.assertEqual(self.cpu.registers.set_register.call_count, 1) self.assertEqual(self.cpu.registers.set_register.call_args_list[0][0][0], 'AL') self.assertEqual(self.cpu.registers.set_register.call_args_list[0][0][1], 0xFF) with self.assertRaises(InvalidWriteOperationError): inst.set_signed_operand(1, -1)
def test_signed_byte(self): self.cpu.registers.get_register.return_value = 0xFF opcode = (get_operand_opcode(Token(TokenType.BYTE_REGISTER, 'AL', 0)) + get_operand_opcode(Token(TokenType.BYTE_LITERAL, 0xAB, 0))) inst = MOV(self.cpu, opcode) inst.set_signed_operand(0, -1) self.assertEqual(self.cpu.registers.set_register.call_count, 1) self.assertEqual( self.cpu.registers.set_register.call_args_list[0][0][0], 'AL') self.assertEqual( self.cpu.registers.set_register.call_args_list[0][0][1], 0xFF) with self.assertRaises(InvalidWriteOperationError): inst.set_signed_operand(1, -1)
def test_operands(self): opcode = self.assembler.assemble_code(''' MOV AX 0x1234 NOP SHUTDOWN ''') expected_opcode = [0x34] expected_opcode += get_operand_opcode( Token(TokenType.WORD_REGISTER, 'AX', None)) expected_opcode += get_operand_opcode( Token(TokenType.WORD_LITERAL, 0x1234, None)) expected_opcode += [0x78] expected_opcode += [0x9A] self.assertListEqual(opcode, expected_opcode)
def test_macro_const(self): opcode = self.assembler.assemble_code(''' .CONST $stuff 0x1234 .CONST $other_stuff $stuff MOV AX $other_stuff NOP SHUTDOWN ''') expected_opcode = [0x34] expected_opcode += get_operand_opcode( Token(TokenType.WORD_REGISTER, 'AX', None)) expected_opcode += get_operand_opcode( Token(TokenType.WORD_LITERAL, 0x1234, None)) expected_opcode += [0x78] expected_opcode += [0x9A] self.assertListEqual(opcode, expected_opcode)
def _parse_operands(self, args, source_line, line_number, opcode_pos): operands = [] for arg in args: if arg.type == TokenType.STRING_LITERAL: _raise_error( source_line, line_number, arg.pos, 'String literal cannot be instruction operand: {}'.format( arg.value), OperandError) if arg.type == TokenType.VARIABLE: arg = self.substitute_variable(arg, source_line, line_number) if arg.type in LABEL_REFERENCE_TYPES: arg = self._substitute_label(arg, source_line, line_number, opcode_pos) try: operands.append(get_operand_opcode(arg)) except AldebaranError as ex: orig_msg = '{}({})'.format( ex.__class__.__name__, str(ex), ) arg_name = '{}({})'.format( arg.type.name, arg.value, ) _raise_error( source_line, line_number, arg.pos, 'Could not parse operand {} due to {}'.format( arg_name, orig_msg), OperandError, ) return operands
def _parse_operands(self, args, source_line, line_number, opcode_pos): operands = [] for arg in args: if arg.type == TokenType.STRING_LITERAL: _raise_error(source_line, line_number, arg.pos, 'String literal cannot be instruction operand: {}'.format(arg.value), OperandError) if arg.type in LABEL_REFERENCE_TYPES: arg = self._substitute_label(arg, source_line, line_number, opcode_pos) try: operands.append(get_operand_opcode(arg)) except AldebaranError as ex: orig_msg = '{}({})'.format( ex.__class__.__name__, str(ex), ) arg_name = '{}({})'.format( arg.type.name, arg.value, ) _raise_error( source_line, line_number, arg.pos, 'Could not parse operand {} due to {}'.format(arg_name, orig_msg), OperandError, ) return operands
def do(self, params): if self.assembler.current_scope is None: self._raise_macro_error( None, 'Macro {} must be in a scope'.format(self.name)) if len(params) == 1: name_param = params[0] default_value_param = None else: name_param, default_value_param = params if default_value_param.type == TokenType.VARIABLE: default_value_param = self.assembler.substitute_variable( default_value_param, self.source_line, self.line_number) self._validate_parameter(default_value_param, [ TokenType.WORD_LITERAL if self.length == 2 else TokenType.BYTE_LITERAL ], 2) if self.assembler.is_variable_defined(name_param.value): self._raise_error( name_param.pos, 'Variable {} already defined'.format(name_param.value), VariableError) try: self.assembler.current_scope.add_variable(name_param.value, self.length) except ScopeError as ex: self._raise_error(None, str(ex), ScopeError) if default_value_param is not None: # MOV $var default_value inst_opcode, _ = self.assembler.instruction_mapping['MOV'] opcode = [inst_opcode] opcode += get_operand_opcode( self.assembler.current_scope.get_value(name_param.value)) opcode += get_operand_opcode( Token( default_value_param.type, default_value_param.value, None, )) return opcode return []
def test_label_ok(self): opcode = self.assembler.assemble_code(''' loop: NOP JMP loop SHUTDOWN ''') expected_opcode = [0x78] expected_opcode += [0x56] expected_opcode += get_operand_opcode( Token(TokenType.ADDRESS_WORD_LITERAL, -1, None)) expected_opcode += [0x9A] self.assertListEqual(opcode, expected_opcode)
def test_rel_ref(self): self.assertListEqual(get_operand_opcode(Token(TokenType.REL_REF_WORD, Reference(-1, 0, 'B'), 0)), [ _get_opbyte(OpLen.BYTE, OpType.REL_REF_WORD), 0xFF, 0xFF, ]) with self.assertRaises(WordOutOfRangeError): get_operand_opcode(Token(TokenType.REL_REF_WORD, Reference(35000, 0, 'B'), 0)) with self.assertRaises(WordOutOfRangeError): get_operand_opcode(Token(TokenType.REL_REF_WORD, Reference(-35000, 0, 'B'), 0)) self.assertListEqual(get_operand_opcode(Token(TokenType.REL_REF_WORD_BYTE, Reference(-1, 255, 'B'), 0)), [ _get_opbyte(OpLen.BYTE, OpType.REL_REF_WORD_BYTE), 0xFF, 0xFF, 0xFF, ]) self.assertListEqual(get_operand_opcode(Token(TokenType.REL_REF_WORD_REG, Reference(-1, 'BX', 'B'), 0)), [ _get_opbyte(OpLen.BYTE, OpType.REL_REF_WORD_REG, 'BX'), 0xFF, 0xFF, ]) with self.assertRaises(InvalidRegisterNameError): get_operand_opcode(Token(TokenType.REL_REF_WORD_REG, Reference(12000, 'XX', 'B'), 0))
def test_literal(self): self.assertListEqual(get_operand_opcode(Token(TokenType.WORD_LITERAL, 65535, 0)), [ _get_opbyte(OpLen.WORD, OpType.VALUE), 0xFF, 0xFF, ]) with self.assertRaises(WordOutOfRangeError): get_operand_opcode(Token(TokenType.WORD_LITERAL, 65536, 0)) self.assertListEqual(get_operand_opcode(Token(TokenType.BYTE_LITERAL, 255, 0)), [ _get_opbyte(OpLen.BYTE, OpType.VALUE), 0xFF, ]) with self.assertRaises(ByteOutOfRangeError): get_operand_opcode(Token(TokenType.BYTE_LITERAL, -1, 0)) self.assertListEqual(get_operand_opcode(Token(TokenType.ADDRESS_WORD_LITERAL, -1, 0)), [ _get_opbyte(OpLen.WORD, OpType.ADDRESS), 0xFF, 0xFF, ]) with self.assertRaises(WordOutOfRangeError): get_operand_opcode(Token(TokenType.ADDRESS_WORD_LITERAL, 35000, 0))
def test_abs_ref(self): self.assertListEqual(get_operand_opcode(Token(TokenType.ABS_REF_REG, Reference('BX', 0, 'B'), 0)), [ _get_opbyte(OpLen.BYTE, OpType.ABS_REF_REG, 'BX'), 0x00, ]) self.assertListEqual(get_operand_opcode(Token(TokenType.ABS_REF_REG, Reference('BX', 1, 'B'), 0)), [ _get_opbyte(OpLen.BYTE, OpType.ABS_REF_REG, 'BX'), 0x01, ]) self.assertListEqual(get_operand_opcode(Token(TokenType.ABS_REF_REG, Reference('BX', -1, 'W'), 0)), [ _get_opbyte(OpLen.WORD, OpType.ABS_REF_REG, 'BX'), 0xFF, ]) with self.assertRaises(InvalidRegisterNameError): get_operand_opcode(Token(TokenType.ABS_REF_REG, Reference('XX', 0, 'W'), 0)) with self.assertRaises(ByteOutOfRangeError): get_operand_opcode(Token(TokenType.ABS_REF_REG, Reference('BX', 150, 'W'), 0))
def test_other(self): with self.assertRaises(InvalidTokenError): get_operand_opcode(Token(TokenType.STRING_LITERAL, 0, 0)) with self.assertRaises(InvalidTokenError): get_operand_opcode(Token('unknown', 0, 0))
def test_macro_param_and_var(self): opcode = self.assembler.assemble_code(''' ENTER 0x02 0x04 .CONST $default_value 0x1234 .PARAM $p .VAR $v1 .VAR $v2 $default_value MOV AX $p MOV AX $v1 MOV AX $v2 NOP SHUTDOWN ''') expected_opcode = [0xBC] expected_opcode += get_operand_opcode( Token(TokenType.BYTE_LITERAL, 0x02, None)) expected_opcode += get_operand_opcode( Token(TokenType.BYTE_LITERAL, 0x04, None)) expected_opcode += [0x34] expected_opcode += get_operand_opcode( Token( TokenType.ABS_REF_REG, Reference('BP', -3, 'W'), None, )) expected_opcode += get_operand_opcode( Token(TokenType.WORD_LITERAL, 0x1234, None)) expected_opcode += [0x34] expected_opcode += get_operand_opcode( Token(TokenType.WORD_REGISTER, 'AX', None)) expected_opcode += get_operand_opcode( Token( TokenType.ABS_REF_REG, Reference('BP', 7, 'W'), None, )) expected_opcode += [0x34] expected_opcode += get_operand_opcode( Token(TokenType.WORD_REGISTER, 'AX', None)) expected_opcode += get_operand_opcode( Token( TokenType.ABS_REF_REG, Reference('BP', -1, 'W'), None, )) expected_opcode += [0x34] expected_opcode += get_operand_opcode( Token(TokenType.WORD_REGISTER, 'AX', None)) expected_opcode += get_operand_opcode( Token( TokenType.ABS_REF_REG, Reference('BP', -3, 'W'), None, )) expected_opcode += [0x78] expected_opcode += [0x9A] self.assertListEqual(opcode, expected_opcode)