def _register_device(self, ioport_number, data): try: data = json.loads(data) except json.decoder.JSONDecodeError: return (HTTPStatus.BAD_REQUEST, { 'error': 'Could not parse data.', }) for field_name in {'type', 'id', 'host', 'port'}: if field_name not in data: return (HTTPStatus.BAD_REQUEST, { 'error': 'Field "{}" missing.'.format(field_name), }) try: device_type = int(data['type'], 16) if device_type < 0x00 or device_type > 0xFF: raise ValueError() except ValueError: return (HTTPStatus.BAD_REQUEST, { 'error': 'Device type must be a 1-byte hex number.', }) try: device_id = int(data['id'], 16) if device_id < 0x00 or device_id > 0xFFFFFF: raise ValueError() device_id = list(device_id.to_bytes(3, 'big')) except ValueError: return (HTTPStatus.BAD_REQUEST, { 'error': 'Device ID must be a 1-byte hex number.', }) device_host, device_port = data['host'], data['port'] if self.ioports[ioport_number].registered: logger.info('A device is already registered to IOPort %s.', ioport_number) return (HTTPStatus.FORBIDDEN, { 'error': 'A device is already registered to this IOPort.', }) if self.ioports[ioport_number].input_queue.qsize() > 0: logger.info('IOPort %s input queue not empty.', ioport_number) return (HTTPStatus.FORBIDDEN, { 'error': 'IOPort input queue not empty.', }) logger.info('Registering device to IOPort %s...', ioport_number) logger.info( 'Device type and ID: %s %s', utils.byte_to_str(device_type), ' '.join(utils.byte_to_str(device_id[i]) for i in range(3)), ) logger.info('Device host and port: %s:%s', device_host, device_port) self._device_registry[4 * ioport_number] = device_type for idx in range(3): self._device_registry[4 * ioport_number + 1 + idx] = device_id[idx] self._set_device_status(ioport_number, 0) self.ioports[ioport_number].register_device(device_host, device_port) self.interrupt_controller.send( self.system_interrupts['device_registered']) logger.info('Device registered to IOPort %s.', ioport_number) return (HTTPStatus.OK, { 'message': 'Device registered.', })
def _check_subtimer(self, subtimer_number, subtimer): if subtimer.mode == SubtimerMode.OFF: return if subtimer.speed > 1: if self._step_count % subtimer.speed != subtimer.phase: return logger.info( 'Subtimer %s called IRQ %s.', utils.byte_to_str(subtimer_number), utils.byte_to_str(subtimer.interrupt_number), ) self._interrupt_controller.send(subtimer.interrupt_number) if subtimer.mode == SubtimerMode.ONESHOT: subtimer.mode = SubtimerMode.OFF
def _check_subtimer(self, subtimer_number, subtimer): if subtimer.mode == SubtimerMode.OFF: return if subtimer.speed > 1: if self._step_count % subtimer.speed != subtimer.phase: return logger.info( 'Subtimer %s called IRQ %s.', utils.byte_to_str(subtimer_number), utils.byte_to_str(subtimer.interrupt_number), ) self._interrupt_controller.send(subtimer.interrupt_number) if subtimer.mode == SubtimerMode.ONESHOT: subtimer.mode = SubtimerMode.OFF
def operand_to_str(operand): ''' Get the string representation of an operand ''' if operand.optype == OpType.EXTENDED: raise InvalidOperandError('Extended optype not supported yet.') if operand.optype == OpType.VALUE: if operand.oplen == OpLen.BYTE: return utils.byte_to_str(operand.opvalue) else: return utils.word_to_str(operand.opvalue) if operand.optype == OpType.ADDRESS: if operand.opvalue < 0: return '^-{}'.format(utils.word_to_str(-operand.opvalue)) return '^{}'.format(utils.word_to_str(operand.opvalue)) if operand.optype == OpType.REGISTER: return operand.opreg if operand.oplen == OpLen.BYTE: oplen_str = 'B' else: oplen_str = '' if operand.optype == OpType.ABS_REF_REG: if operand.opoffset == 0: opoffset_str = '' elif operand.opoffset > 0: opoffset_str = '+{}'.format(utils.byte_to_str(operand.opoffset)) else: opoffset_str = '-{}'.format(utils.byte_to_str(-operand.opoffset)) return '[{}{}]{}'.format( operand.opreg, opoffset_str, oplen_str, ) if operand.opbase < 0: opbase_str = '-{}'.format(utils.word_to_str(-operand.opbase)) else: opbase_str = '{}'.format(utils.word_to_str(operand.opbase)) if operand.optype == OpType.REL_REF_WORD_BYTE: opoffset_str = '+{}'.format(utils.byte_to_str(operand.opoffset)) elif operand.optype == OpType.REL_REF_WORD_REG: opoffset_str = '+{}'.format(operand.opreg) else: opoffset_str = '' return '[{}{}]{}'.format( opbase_str, opoffset_str, oplen_str, )
def operand_to_str(operand): ''' Get the string representation of an operand ''' if operand.optype == OpType.EXTENDED: raise InvalidOperandError('Extended optype not supported yet.') if operand.optype == OpType.VALUE: if operand.oplen == OpLen.BYTE: return utils.byte_to_str(operand.opvalue) else: return utils.word_to_str(operand.opvalue) if operand.optype == OpType.ADDRESS: if operand.opvalue < 0: return '^-{}'.format(utils.word_to_str(-operand.opvalue)) return '^{}'.format(utils.word_to_str(operand.opvalue)) if operand.optype == OpType.REGISTER: return operand.opreg if operand.oplen == OpLen.BYTE: oplen_str = 'B' else: oplen_str = '' if operand.optype == OpType.ABS_REF_REG: if operand.opoffset == 0: opoffset_str = '' elif operand.opoffset > 0: opoffset_str = '+{}'.format(utils.byte_to_str(operand.opoffset)) else: opoffset_str = '-{}'.format(utils.byte_to_str(-operand.opoffset)) return '[{}{}]{}'.format( operand.opreg, opoffset_str, oplen_str, ) if operand.opbase < 0: opbase_str = '-{}'.format(utils.word_to_str(-operand.opbase)) else: opbase_str = '{}'.format(utils.word_to_str(operand.opbase)) if operand.optype == OpType.REL_REF_WORD_BYTE: opoffset_str = '+{}'.format(utils.byte_to_str(operand.opoffset)) elif operand.optype == OpType.REL_REF_WORD_REG: opoffset_str = '+{}'.format(operand.opreg) else: opoffset_str = '' return '[{}{}]{}'.format( opbase_str, opoffset_str, oplen_str, )
def _call_hardware_interrupt(self, interrupt_number): logger.debug('Calling hardware interrupt: %s', utils.byte_to_str(interrupt_number)) self.halt = False self.stack.push_flags() self.disable_interrupts() self.stack.push_word(self.ip) self.ip = self.memory.read_word(self.system_addresses['IVT'] + 2 * interrupt_number)
def _mini_debugger(self): if logger.level != logging.DEBUG: return ram_page_size = 16 stack_page_size = 32 sp = self.registers.get_register('SP', silent=True) bp = self.registers.get_register('BP', silent=True) ram_page = (self.ip // ram_page_size) * ram_page_size rel_sp = self.system_addresses['bottom_of_stack'] - sp stack_page = self.system_addresses['bottom_of_stack'] - ( stack_page_size - 1) - (rel_sp // stack_page_size) * stack_page_size if stack_page < 0: stack_page = 0 logger.debug( 'IP=%s RAM %s-%s: %s', utils.word_to_str(self.ip), utils.word_to_str(ram_page), utils.word_to_str(ram_page + ram_page_size - 1), ''.join([('>' if idx == self.ip else ' ') + utils.byte_to_str(self.memory.read_byte(idx, silent=True)) for idx in range(ram_page, ram_page + ram_page_size)]), ) logger.debug( 'SP=%s BP=%s Stack %s-%s: %s', utils.word_to_str(sp), utils.word_to_str(bp), utils.word_to_str(stack_page), utils.word_to_str(stack_page + stack_page_size - 1), ''.join([ utils.byte_to_str(self.memory.read_byte(idx, silent=True)) + (('{' if idx == bp else '<') if idx == sp else ('[' if idx == bp else ' ')) for idx in range(stack_page, stack_page + stack_page_size) ]), ) logger.debug( 'AX/BX/CX/DX=%s/%s/%s/%s SI/DI=%s/%s', utils.word_to_str(self.registers.get_register('AX', silent=True)), utils.word_to_str(self.registers.get_register('BX', silent=True)), utils.word_to_str(self.registers.get_register('CX', silent=True)), utils.word_to_str(self.registers.get_register('DX', silent=True)), utils.word_to_str(self.registers.get_register('SI', silent=True)), utils.word_to_str(self.registers.get_register('DI', silent=True)), )
def _mini_debugger(self): if logger.level != logging.DEBUG: return ram_page_size = 16 stack_page_size = 32 sp = self.registers.get_register('SP', silent=True) bp = self.registers.get_register('BP', silent=True) ram_page = (self.ip // ram_page_size) * ram_page_size rel_sp = self.system_addresses['bottom_of_stack'] - sp stack_page = self.system_addresses['bottom_of_stack'] - (stack_page_size - 1) - (rel_sp // stack_page_size) * stack_page_size if stack_page < 0: stack_page = 0 logger.debug( 'IP=%s RAM %s-%s: %s', utils.word_to_str(self.ip), utils.word_to_str(ram_page), utils.word_to_str(ram_page + ram_page_size - 1), ''.join([ ('>' if idx == self.ip else ' ') + utils.byte_to_str(self.memory.read_byte(idx, silent=True)) for idx in range(ram_page, ram_page + ram_page_size) ]), ) logger.debug( 'SP=%s BP=%s Stack %s-%s: %s', utils.word_to_str(sp), utils.word_to_str(bp), utils.word_to_str(stack_page), utils.word_to_str(stack_page + stack_page_size - 1), ''.join([utils.byte_to_str(self.memory.read_byte(idx, silent=True)) + ( ( '{' if idx == bp else '<' ) if idx == sp else ( '[' if idx == bp else ' ' ) ) for idx in range(stack_page, stack_page + stack_page_size)]), ) logger.debug( 'AX/BX/CX/DX=%s/%s/%s/%s SI/DI=%s/%s', utils.word_to_str(self.registers.get_register('AX', silent=True)), utils.word_to_str(self.registers.get_register('BX', silent=True)), utils.word_to_str(self.registers.get_register('CX', silent=True)), utils.word_to_str(self.registers.get_register('DX', silent=True)), utils.word_to_str(self.registers.get_register('SI', silent=True)), utils.word_to_str(self.registers.get_register('DI', silent=True)), )
def write_byte(self, pos, value, silent=False): ''' Write byte to RAM at position `pos` ''' if pos < 0 or pos > self.size - 1: raise SegfaultError('Segmentation fault when trying to write byte at {}'.format(utils.word_to_str(pos))) self._content[pos] = value if not silent: logger.debug('Written byte %s to %s.', utils.byte_to_str(value), utils.word_to_str(pos))
def _set_byte_register(self, register_name, value, silent=False): if value < 0x00 or value > 0xFF: raise InvalidRegisterValueError('Invalid register value: {}'.format(value)) if register_name in {'AL', 'BL', 'CL', 'DL'}: self._registers[register_name[0] + 'X'] = utils.set_low(self._registers[register_name[0] + 'X'], value) else: self._registers[register_name[0] + 'X'] = utils.set_high(self._registers[register_name[0] + 'X'], value) if not silent: logger.debug('Set register %s = %s', register_name, utils.byte_to_str(value))
def set_subtimer(self, subtimer_number, raw_mode, speed, phase, interrupt_number): ''' Set subtimer's config ''' try: self._subtimers[subtimer_number].set_config(raw_mode, speed, phase, interrupt_number) except IndexError: raise NoSubtimerError('No subtimer with number: {}'.format(subtimer_number)) logger.info('Subtimer %s set.', utils.byte_to_str(subtimer_number))
def write_byte(self, pos, value, silent=False): ''' Write byte to Virtual RAM at position `pos` ''' if pos < self.addresses['device_controller']['first'] or pos > self.addresses['device_controller']['last']: raise SegfaultError('Segmentation fault when trying to write byte at {}'.format(utils.word_to_str(pos))) self.device_controller.write_byte(pos, value, silent=silent) if not silent: logger.debug('Written byte %s to %s.', utils.byte_to_str(value), utils.word_to_str(pos))
def _call_hardware_interrupt(self, interrupt_number): logger.debug('Calling hardware interrupt: %s', utils.byte_to_str(interrupt_number)) self.halt = False self.stack.push_flags() self.disable_interrupts() self.stack.push_word(self.ip) self.ip = self.memory.read_word(self.system_addresses['IVT'] + 2 * interrupt_number)
def read_byte(self, pos, silent=False): ''' Read byte from Virtual RAM at position `pos` ''' if pos < self.addresses['device_controller']['first'] or pos > self.addresses['device_controller']['last']: raise SegfaultError('Segmentation fault when trying to read byte at {}'.format(utils.word_to_str(pos))) value = self.device_controller.read_byte(pos, silent=silent) if not silent: logger.debug('Read byte %s from %s.', utils.byte_to_str(value), utils.word_to_str(pos)) return value
def do(self): subtimer_number = self.get_operand(0) self.cpu.timer.set_subtimer( subtimer_number, raw_mode=self.get_operand(1), speed=self.get_operand(2), phase=self.get_operand(3), interrupt_number=self.get_operand(4), ) self.cpu.cpu_log('Subtimer %s set.', utils.byte_to_str(subtimer_number))
def read_byte(self, pos, silent=False): ''' Read byte from RAM at position `pos` ''' if pos < 0 or pos > self.size - 1: raise SegfaultError('Segmentation fault when trying to read byte at {}'.format(utils.word_to_str(pos))) value = self._content[pos] if not silent: logger.debug('Read byte %s from %s.', utils.byte_to_str(value), utils.word_to_str(pos)) return value
def check(self): ''' Get interrupt, if there's any ''' try: interrupt_number = self._interrupt_queue.get_nowait() except queue.Empty: return None logger.info('Forwarded IRQ to CPU: %s', utils.byte_to_str(interrupt_number)) logger.debug('Interrupt queue length: %d', self._interrupt_queue.qsize()) return interrupt_number
def push_byte(self, value): ''' Push byte on stack ''' sp = self._registers.get_register('SP', silent=True) if sp < 1: raise StackOverflowError('Stack overflow: {}'.format( utils.word_to_str(sp))) self._ram.write_byte(sp, value, silent=True) logger.debug('Pushed byte %s', utils.byte_to_str(value)) self._registers.set_register('SP', sp - 1, silent=True)
def _parse_instruction(self, inst_opcode, operand_buffer): try: inst_class = self.instruction_opcode_mapping[inst_opcode] except KeyError: raise UnknownOpcodeError('Unknown opcode: {}'.format(utils.byte_to_str(inst_opcode))) instruction = inst_class(self, operand_buffer) logger.info('Instruction: %s %s', inst_class.__name__, ' '.join([ operands.operand_to_str(op) for op in instruction.operands ])) return instruction
def get_register(self, register_name, silent=False): ''' Get register value ''' value = None hex_value = None if register_name in self._registers: value = self._registers[register_name] hex_value = utils.word_to_str(value) elif register_name in {'AL', 'BL', 'CL', 'DL'}: value = utils.get_low(self._registers[register_name[0] + 'X']) hex_value = utils.byte_to_str(value) elif register_name in {'AH', 'BH', 'CH', 'DH'}: value = utils.get_high(self._registers[register_name[0] + 'X']) hex_value = utils.byte_to_str(value) else: raise InvalidRegisterNameError('Invalid register name: {}'.format(register_name)) if not silent: logger.debug('Get register %s = %s', register_name, hex_value) return value
def get_register(self, register_name, silent=False): ''' Get register value ''' value = None hex_value = None if register_name in self._registers: value = self._registers[register_name] hex_value = utils.word_to_str(value) elif register_name in {'AL', 'BL', 'CL', 'DL'}: value = utils.get_low(self._registers[register_name[0] + 'X']) hex_value = utils.byte_to_str(value) elif register_name in {'AH', 'BH', 'CH', 'DH'}: value = utils.get_high(self._registers[register_name[0] + 'X']) hex_value = utils.byte_to_str(value) else: raise InvalidRegisterNameError( 'Invalid register name: {}'.format(register_name)) if not silent: logger.debug('Get register %s = %s', register_name, hex_value) return value
def pop_byte(self): ''' Pop byte from stack ''' sp = self._registers.get_register('SP', silent=True) if sp >= self._bottom_of_stack: raise StackUnderflowError('Stack underflow: {}'.format( utils.word_to_str(sp))) self._registers.set_register('SP', sp + 1, silent=True) value = self._ram.read_byte(sp + 1, silent=True) logger.debug('Popped byte %s', utils.byte_to_str(value)) return value
def set_subtimer(self, subtimer_number, raw_mode, speed, phase, interrupt_number): ''' Set subtimer's config ''' try: self._subtimers[subtimer_number].set_config( raw_mode, speed, phase, interrupt_number) except IndexError: raise NoSubtimerError( 'No subtimer with number: {}'.format(subtimer_number)) logger.info('Subtimer %s set.', utils.byte_to_str(subtimer_number))
def write_byte(self, pos, value, silent=False): ''' Write byte to RAM at position `pos` ''' if pos < 0 or pos > self.size - 1: raise SegfaultError( 'Segmentation fault when trying to write byte at {}'.format( utils.word_to_str(pos))) self._content[pos] = value if not silent: logger.debug('Written byte %s to %s.', utils.byte_to_str(value), utils.word_to_str(pos))
def send(self, interrupt_number): ''' Send interrupt ''' try: interrupt_number = int(interrupt_number) except ValueError: raise InvalidInterruptError('Invalid interrupt: {}'.format(interrupt_number)) if interrupt_number < 0 or interrupt_number > 255: raise InvalidInterruptError('Invalid interrupt: {}'.format(interrupt_number)) self._interrupt_queue.put(interrupt_number) logger.info('Received IRQ: %s', utils.byte_to_str(interrupt_number)) logger.debug('Interrupt queue length: %d', self._interrupt_queue.qsize())
def check(self): ''' Get interrupt, if there's any ''' try: interrupt_number = self._interrupt_queue.get_nowait() except queue.Empty: return None logger.info('Forwarded IRQ to CPU: %s', utils.byte_to_str(interrupt_number)) logger.debug('Interrupt queue length: %d', self._interrupt_queue.qsize()) return interrupt_number
def _set_byte_register(self, register_name, value, silent=False): if value < 0x00 or value > 0xFF: raise InvalidRegisterValueError( 'Invalid register value: {}'.format(value)) if register_name in {'AL', 'BL', 'CL', 'DL'}: self._registers[register_name[0] + 'X'] = utils.set_low( self._registers[register_name[0] + 'X'], value) else: self._registers[register_name[0] + 'X'] = utils.set_high( self._registers[register_name[0] + 'X'], value) if not silent: logger.debug('Set register %s = %s', register_name, utils.byte_to_str(value))
def read_byte(self, pos, silent=False): ''' Read byte from RAM at position `pos` ''' if pos < 0 or pos > self.size - 1: raise SegfaultError( 'Segmentation fault when trying to read byte at {}'.format( utils.word_to_str(pos))) value = self._content[pos] if not silent: logger.debug('Read byte %s from %s.', utils.byte_to_str(value), utils.word_to_str(pos)) return value
def write_byte(self, pos, value, silent=False): ''' Write byte to Virtual RAM at position `pos` ''' if pos < self.addresses['device_controller'][ 'first'] or pos > self.addresses['device_controller']['last']: raise SegfaultError( 'Segmentation fault when trying to write byte at {}'.format( utils.word_to_str(pos))) self.device_controller.write_byte(pos, value, silent=silent) if not silent: logger.debug('Written byte %s to %s.', utils.byte_to_str(value), utils.word_to_str(pos))
def read_byte(self, pos, silent=False): ''' Read byte from device registry or device status table ''' if self.system_addresses['device_registry_address'] <= pos < self.system_addresses['device_registry_address'] + self.system_addresses['device_registry_size']: value = self._device_registry[pos - self.system_addresses['device_registry_address']] elif self.system_addresses['device_status_table_address'] <= pos < self.system_addresses['device_status_table_address'] + self.system_addresses['device_status_table_size']: value = self._device_status_table[pos - self.system_addresses['device_status_table_address']] else: raise SegfaultError('Segmentation fault when trying to read byte at {}'.format(utils.word_to_str(pos))) if not silent: logger.debug('Read byte %s from %s.', utils.byte_to_str(value), utils.word_to_str(pos)) return value
def parse_instruction(self, inst_opcode, operand_buffer): ''' Parse opcode and operand buffer into instruction and operands ''' try: inst_class = self.instruction_opcode_mapping[inst_opcode] except KeyError: raise UnknownOpcodeError('Unknown opcode: {}'.format( utils.byte_to_str(inst_opcode))) instruction = inst_class(self, operand_buffer) logger.info( 'Instruction: %s %s', inst_class.__name__, ' '.join( [operands.operand_to_str(op) for op in instruction.operands])) return instruction
def read_byte(self, pos, silent=False): ''' Read byte from Virtual RAM at position `pos` ''' if pos < self.addresses['device_controller'][ 'first'] or pos > self.addresses['device_controller']['last']: raise SegfaultError( 'Segmentation fault when trying to read byte at {}'.format( utils.word_to_str(pos))) value = self.device_controller.read_byte(pos, silent=silent) if not silent: logger.debug('Read byte %s from %s.', utils.byte_to_str(value), utils.word_to_str(pos)) return value
def _get_stack(self): bottom_of_stack = self.cpu.system_addresses['bottom_of_stack'] first_address = max( self.cpu.registers.get_register('SP', silent=True) - 7, 0) length = bottom_of_stack - first_address + 1 return { 'first_address': utils.word_to_str(first_address), 'last_address': utils.word_to_str(bottom_of_stack), 'content': [ utils.byte_to_str(self.memory.read_byte(first_address + idx)) for idx in range(length) ], }
def send(self, interrupt_number): ''' Send interrupt ''' try: interrupt_number = int(interrupt_number) except ValueError: raise InvalidInterruptError( 'Invalid interrupt: {}'.format(interrupt_number)) if interrupt_number < 0 or interrupt_number > 255: raise InvalidInterruptError( 'Invalid interrupt: {}'.format(interrupt_number)) self._interrupt_queue.put(interrupt_number) logger.info('Received IRQ: %s', utils.byte_to_str(interrupt_number)) logger.debug('Interrupt queue length: %d', self._interrupt_queue.qsize())
def _log_code(self): logger.debug('===CODE===') max_line_opcode_length = max( len(line_opcode) for line_number, opcode_pos, line_opcode, source_line, tokens in self.augmented_opcode) if max_line_opcode_length > MAX_LINE_OPCODE_LENGTH: max_line_opcode_length = MAX_LINE_OPCODE_LENGTH for line_number, opcode_pos, line_opcode, source_line, tokens in self.augmented_opcode: line_label_names = [ token.value for token in tokens if token.type == TokenType.LABEL ] if not line_label_names and not line_opcode: continue logger.debug(' '.join([ '{:4}'.format(line_number), utils.word_to_str(opcode_pos), ' '.join([utils.byte_to_str(op) for op in line_opcode]), ' ' if line_opcode else '', ' ' * (max_line_opcode_length - len(line_opcode)), source_line, ]))
def _log_code(self): logger.debug('===CODE===') max_line_opcode_length = max( len(line_opcode) for line_number, opcode_pos, line_opcode, source_line, tokens in self.augmented_opcode ) if max_line_opcode_length > MAX_LINE_OPCODE_LENGTH: max_line_opcode_length = MAX_LINE_OPCODE_LENGTH for line_number, opcode_pos, line_opcode, source_line, tokens in self.augmented_opcode: line_label_names = [token.value for token in tokens if token.type == TokenType.LABEL] if not line_label_names and not line_opcode: continue logger.debug( ' '.join([ '{:4}'.format(line_number), utils.word_to_str(opcode_pos), ' '.join([utils.byte_to_str(op) for op in line_opcode]), ' ' if line_opcode else '', ' ' * (max_line_opcode_length - len(line_opcode)), source_line, ]) )
def _get_instruction(self, ip): inst_opcode, operand_buffer = self.cpu.read_instruction(ip) try: instruction = self.cpu.parse_instruction(inst_opcode, operand_buffer) except AldebaranError: return None last_idx = 0 operands = [] for op, idx in zip(instruction.operands, instruction.operand_buffer_indices): operands.append({ 'name': operand_to_str(op), 'opcode': utils.binary_to_str(operand_buffer[last_idx:idx]), }) last_idx = idx return { 'name': instruction.__class__.__name__, 'opcode': utils.byte_to_str(inst_opcode), 'operands': operands, }
def _get_memory(self, offset, length): if offset >= config.memory_size or offset < 0: return (HTTPStatus.BAD_REQUEST, { 'error': 'Cannot access memory beyond 0000-{}'.format( utils.word_to_str(config.memory_size - 1)), }) if offset + length > config.memory_size: length = config.memory_size - offset first_address = offset content = [] for idx in range(length): try: content.append( utils.byte_to_str( self.memory.read_byte(first_address + idx))) except SegfaultError: content.append(None) return (HTTPStatus.OK, { 'first_address': utils.word_to_str(first_address), 'last_address': utils.word_to_str(first_address + length - 1), 'content': content, })
def read_byte(self, pos, silent=False): ''' Read byte from device registry or device status table ''' if self.system_addresses[ 'device_registry_address'] <= pos < self.system_addresses[ 'device_registry_address'] + self.system_addresses[ 'device_registry_size']: value = self._device_registry[ pos - self.system_addresses['device_registry_address']] elif self.system_addresses[ 'device_status_table_address'] <= pos < self.system_addresses[ 'device_status_table_address'] + self.system_addresses[ 'device_status_table_size']: value = self._device_status_table[ pos - self.system_addresses['device_status_table_address']] else: raise SegfaultError( 'Segmentation fault when trying to read byte at {}'.format( utils.word_to_str(pos))) if not silent: logger.debug('Read byte %s from %s.', utils.byte_to_str(value), utils.word_to_str(pos)) return value
def crash_dump(self): ''' Print crash dump ''' logger_crash_dump.error('### CRASH DUMP ###') # ip ip = self.cpu.ip logger_crash_dump.error('') logger_crash_dump.error('IP=%s', utils.word_to_str(ip)) logger_crash_dump.error( 'Entry point=%s', utils.word_to_str(self.cpu.system_addresses['entry_point'])) logger_crash_dump.error('Halt=%s', self.cpu.halt) # ram ram_page_size = 16 ram_page = (ip // ram_page_size) * ram_page_size logger_crash_dump.error('') logger_crash_dump.error('RAM:') for page_offset in range(-2, 3): offset = page_offset * ram_page_size if offset + ram_page < 0: continue if offset + ram_page + ram_page_size - 1 > self.ram.size: continue logger_crash_dump.error( '%s: %s', utils.word_to_str(offset + ram_page), ''.join([ ('>' if idx == ip else ' ') + utils.byte_to_str(self.ram.read_byte(idx, silent=True)) for idx in range(offset + ram_page, offset + ram_page + ram_page_size) ]), ) # stack sp = self.cpu.registers.get_register('SP', silent=True) bp = self.cpu.registers.get_register('BP', silent=True) logger_crash_dump.error('') logger_crash_dump.error('SP=%s', utils.word_to_str(sp)) logger_crash_dump.error('BP=%s', utils.word_to_str(bp)) logger_crash_dump.error( 'Bottom of stack=%s', utils.word_to_str(self.cpu.system_addresses['bottom_of_stack'])) logger_crash_dump.error('') logger_crash_dump.error('Stack:') stack_page_size = 16 stack_page = (sp // stack_page_size) * stack_page_size if stack_page < 0: stack_page = 0 for page_offset in range(-1, 4): offset = page_offset * stack_page_size if offset + stack_page < 0: continue if offset + stack_page + stack_page_size - 1 > self.ram.size: continue logger_crash_dump.error( '%s: %s', utils.word_to_str(offset + stack_page), ''.join([ utils.byte_to_str(self.ram.read_byte(idx, silent=True)) + (('{' if idx == bp else '<') if idx == sp else ('[' if idx == bp else ' ')) for idx in range(offset + stack_page, offset + stack_page + stack_page_size) ]), ) # registers logger_crash_dump.error('') logger_crash_dump.error('Registers:') for reg in ['AX', 'BX', 'CX', 'DX', 'SI', 'DI']: logger_crash_dump.error( '%s=%s', reg, utils.word_to_str( self.cpu.registers.get_register(reg, silent=True)))
def _register_device(self, ioport_number, data): try: data = json.loads(data) except json.decoder.JSONDecodeError: return ( HTTPStatus.BAD_REQUEST, { 'error': 'Could not parse data.', } ) for field_name in {'type', 'id', 'host', 'port'}: if field_name not in data: return ( HTTPStatus.BAD_REQUEST, { 'error': 'Field "{}" missing.'.format(field_name), } ) try: device_type = int(data['type'], 16) if device_type < 0x00 or device_type > 0xFF: raise ValueError() except ValueError: return ( HTTPStatus.BAD_REQUEST, { 'error': 'Device type must be a 1-byte hex number.', } ) try: device_id = int(data['id'], 16) if device_id < 0x00 or device_id > 0xFFFFFF: raise ValueError() device_id = list(device_id.to_bytes(3, 'big')) except ValueError: return ( HTTPStatus.BAD_REQUEST, { 'error': 'Device ID must be a 1-byte hex number.', } ) device_host, device_port = data['host'], data['port'] if self.ioports[ioport_number].registered: logger.info('A device is already registered to IOPort %s.', ioport_number) return ( HTTPStatus.FORBIDDEN, { 'error': 'A device is already registered to this IOPort.', } ) if self.ioports[ioport_number].input_queue.qsize() > 0: logger.info('IOPort %s input queue not empty.', ioport_number) return ( HTTPStatus.FORBIDDEN, { 'error': 'IOPort input queue not empty.', } ) logger.info('Registering device to IOPort %s...', ioport_number) logger.info( 'Device type and ID: %s %s', utils.byte_to_str(device_type), ' '.join(utils.byte_to_str(device_id[i]) for i in range(3)), ) logger.info('Device host and port: %s:%s', device_host, device_port) self._device_registry[4 * ioport_number] = device_type for idx in range(3): self._device_registry[4 * ioport_number + 1 + idx] = device_id[idx] self._device_status_table[ioport_number] = 0 self.ioports[ioport_number].register_device(device_host, device_port) self.interrupt_controller.send(self.system_interrupts['device_registered']) logger.info('Device registered to IOPort %s.', ioport_number) return ( HTTPStatus.OK, { 'message': 'Device registered.', } )
def crash_dump(self): ''' Print crash dump ''' logger_crash_dump.error('### CRASH DUMP ###') # ip ip = self.cpu.ip logger_crash_dump.error('') logger_crash_dump.error('IP=%s', utils.word_to_str(ip)) logger_crash_dump.error('Entry point=%s', utils.word_to_str(self.cpu.system_addresses['entry_point'])) logger_crash_dump.error('Halt=%s', self.cpu.halt) # ram ram_page_size = 16 ram_page = (ip // ram_page_size) * ram_page_size logger_crash_dump.error('') logger_crash_dump.error('RAM:') for page_offset in range(-2, 3): offset = page_offset * ram_page_size if offset + ram_page < 0: continue if offset + ram_page + ram_page_size - 1 > self.ram.size: continue logger_crash_dump.error( '%s: %s', utils.word_to_str(offset + ram_page), ''.join([ ('>' if idx == ip else ' ') + utils.byte_to_str(self.ram.read_byte(idx, silent=True)) for idx in range(offset + ram_page, offset + ram_page + ram_page_size) ]), ) # stack sp = self.cpu.registers.get_register('SP', silent=True) bp = self.cpu.registers.get_register('BP', silent=True) logger_crash_dump.error('') logger_crash_dump.error('SP=%s', utils.word_to_str(sp)) logger_crash_dump.error('BP=%s', utils.word_to_str(bp)) logger_crash_dump.error('Bottom of stack=%s', utils.word_to_str(self.cpu.system_addresses['bottom_of_stack'])) logger_crash_dump.error('') logger_crash_dump.error('Stack:') stack_page_size = 16 stack_page = (sp // stack_page_size) * stack_page_size if stack_page < 0: stack_page = 0 for page_offset in range(-1, 4): offset = page_offset * stack_page_size if offset + stack_page < 0: continue if offset + stack_page + stack_page_size - 1 > self.ram.size: continue logger_crash_dump.error( '%s: %s', utils.word_to_str(offset + stack_page), ''.join([utils.byte_to_str(self.ram.read_byte(idx, silent=True)) + ( ( '{' if idx == bp else '<' ) if idx == sp else ( '[' if idx == bp else ' ' ) ) for idx in range(offset + stack_page, offset + stack_page + stack_page_size)]), ) # registers logger_crash_dump.error('') logger_crash_dump.error('Registers:') for reg in ['AX', 'BX', 'CX', 'DX', 'SI', 'DI']: logger_crash_dump.error('%s=%s', reg, utils.word_to_str(self.cpu.registers.get_register(reg, silent=True)))