def write(self, ptr, instruction=None, **kwargs): data = cvar(dict) old_instruction = cvar(object) if STRICT and not isinstance(ptr, int): raise ValueError('Pointer must be an integer, not %r' % ptr) ptr %= self.size if instruction is not None: if not isinstance(instruction, Instruction): raise TypeError('The instruction parameter must be an ' 'Instruction instance') if STRICT and kwargs != {}: raise ValueError('Cannot supply extra attribute if ' 'instruction is given') with self._lock: old_instruction = self._memory[ptr] self._memory[ptr] = instruction for callback in self._callbacks: callback(ptr, old_instruction, instruction) else: for key in kwargs: if key not in SYNTAX.data_blocks: raise ValueError('%r is not a valid data block.') data = self.read(ptr).as_dict data.update(kwargs) self.write(ptr, Instruction(**data))
def _read(self, memory, ptr): """Return input data of the instruction, based on modifiers. Data with None should _never_ be read.""" m = cvar(str) A = cvar(object) B = cvar(object) m = self.modifier A = memory.read(memory.get_absolute_ptr(ptr, self.A)) B = memory.read(memory.get_absolute_ptr(ptr, self.B)) if m == 'A': return ((None, None, A.A, None), (None, None, B.A, None)) elif m == 'B': return ((None, None, A.B, None), (None, None, B.B, None)) elif m == 'AB': return ((None, None, A.A, None), (None, None, B.B, None)) elif m == 'BA': return ((None, None, A.B, None), (None, None, B.A, None)) elif m == 'F': return ((None, None, A.A, A.B ), (None, None, B.A, B.B )) elif m == 'X': return ((None, None, A.A, A.B ), (None, None, B.B, B.A )) elif m == 'I': return (A.as_tuple, B.as_tuple) else: assert False
def _math(self, A, B, function): "Shortcut for running math operations." res1 = cvar(str) res2 = cvar(str) assert None not in (A[2], B[2]) res1 = B[2][0]+str(function(get_int(A[2]), get_int(B[2]))) res2 = None if A[3] is not None: assert B[3] is not None res2 = B[3][0]+str(function(get_int(A[3]), get_int(B[3]))) return (B[0], B[1], res1, res2)
def _write(self, memory, dest, inst): """Writes data to the memory""" m = cvar(str) m = self.modifier if isinstance(inst, tuple): if m != 'I': # Add an opcode if needed, so it passes sanity checks inst = (inst[0] or 'DAT', inst[1], inst[2], inst[3]) inst = Instruction.from_tuple(inst) elif STRICT and not isinstance(inst, Instruction): raise ValueError('You can only write tuples and instructions, ' 'not %r' % inst) if STRICT and not isinstance(dest, int): raise ValueError('Destination must be an int, not %r.' % dest) if m == 'A': memory.write(dest, A=inst.A) elif m == 'B': memory.write(dest, B=inst.A) elif m == 'AB': memory.write(dest, B=inst.A) elif m == 'BA': memory.write(dest, A=inst.A) elif m == 'F': memory.write(dest, A=inst.A, B=inst.B) elif m == 'X': memory.write(dest, B=inst.B, A=inst.A) elif m == 'I': memory.write(dest, instruction=inst) else: assert False
def _increment(self, memory, ptr, field): "Shortcut for incrementing fields." inst = cvar(object) inst = memory.read(ptr + get_int(field)) if field.startswith('}'): inst.A = inst.A[0] + str(int(inst.A[1:])+1) elif field.startswith('>'): inst.B = inst.B[0] + str(int(inst.B[1:])+1)
def run(self, memory, ptr): oc = cvar(str) dest = cvar(int) A = cvar(object) B = cvar(object) threads = cvar(list) assert memory.read(ptr) == self # Predecrement for field in (self.A, self.B): inst = memory.read(ptr + get_int(field)) if field.startswith('{'): inst.A = inst.A[0] + str(int(inst.A[1:])-1) elif field.startswith('<'): inst.B = inst.B[0] + str(int(inst.B[1:])-1) oc = self.opcode # Postincrement # The order matters: http://www.koth.org/info/icws94.html#5.3.5 self._increment(memory, ptr, self.A) dest = memory.get_absolute_ptr(ptr, self.B) self._increment(memory, ptr, self.B) A, B = self._read(memory, ptr) if oc == 'DAT': threads = [] elif oc == 'NOP': threads = [ptr+1] elif oc == 'MOV': self._write(memory, dest, A) threads = [ptr+1] elif oc == 'ADD': self._write(memory, dest, self._math(A, B, lambda a,b:a+b)) threads = [ptr+1] elif oc == 'SUB': self._write(memory, dest, self._math(A, B, lambda a,b:b-a)) threads = [ptr+1] elif oc == 'MUL': self._write(memory, dest, self._math(A, B, lambda a,b:a*b)) threads = [ptr+1] elif oc == 'DIV': try: self._write(memory, dest, self._math(A, B, lambda a,b:int(b/a))) threads = [ptr+1] except ZeroDivisionError: threads = [] elif oc == 'MOD': try: self._write(memory, dest, self._math(A, B, lambda a,b:b%a)) threads = [ptr+1] except ZeroDivisionError: threads = [] elif oc == 'JMP': # Note that the modifier is ignored threads = [memory.get_absolute_ptr(ptr, self.A)] elif oc == 'JMZ': if get_int(B[2]) == 0 and \ (B[3] is None or get_int(B[3]) == 0): threads = [memory.get_absolute_ptr(ptr, self.A)] else: threads = [ptr+1] elif oc == 'JMN': if get_int(B[2]) == 0 and \ (B[3] is None or get_int(B[3]) == 0): threads = [ptr+1] else: threads = [memory.get_absolute_ptr(ptr, self.A)] elif oc == 'DJN': self.B = self.B[0] + str(get_int(self.B)-1) ptrB = memory.get_absolute_ptr(ptr, self.B) B = self._read(memory, ptrB)[1] # Load the new pointed data # Jump if get_int(B[2]) == 0 and \ (B[3] is None or get_int(B[3]) == 0): threads = [ptr+1] else: threads = [memory.get_absolute_ptr(ptr, self.A)] elif oc == 'CMP' or oc == 'SEQ': if A == B: threads = [ptr+2] else: threads = [ptr+1] elif oc == 'SLT': if get_int(A[2]) < get_int(B[2]) and \ (A[3] is None or A[3] < B[3]): threads = [ptr+2] else: threads = [ptr+1] elif oc == 'SPL': threads = [ptr+1, ptr+get_int(self.A)] else: raise NotImplementedError() return threads