def __call__(self, in_: Bool16, load: bool, address: Tuple[bool, ...]) -> Bool16: if load: print('loading new value: ', bool16_to_int(in_)) self.data_dec[bool16_to_int(address)] = bool16_to_int(in_) self.data[address] = in_ print('reading from address ', bool16_to_int(address), ': ', bool16_to_int(self.data[address])) return self.data[address]
def test_unary_alu(self): for num in self.test_numbers: num_bool16 = int_to_bool16(num) num_z = bool16_to_int( unary_alu(zero=True, negation=False, in_=num_bool16)) num_n = bool16_to_int( unary_alu(zero=False, negation=True, in_=num_bool16)) num_zn = bool16_to_int( unary_alu(zero=True, negation=True, in_=num_bool16)) num_plain = bool16_to_int( unary_alu(zero=False, negation=False, in_=num_bool16)) self.assertEqual(0, num_z) self.assertEqual(~num, num_n) self.assertEqual(~0, num_zn) self.assertEqual(num, num_plain)
def test_adder_16(self): # for a, b in self.values: for a, b in ((5, 25), ): a_bools = int_to_bool16(a) b_bools = int_to_bool16(b) c_bools = adder_16(a_bools, b_bools) c = bool16_to_int(c_bools) self.assertEqual(a + b, c)
def read_address(self, address): """Read from the bool16 address location.""" address_index = bool16_to_int(address) try: out = tuple(True if c == '1' else False for c in self.data[address_index]) return out except IndexError: return (False, ) * 16
def py_alu(self, zx: bool, nx: bool, zy: bool, ny: bool, f: bool, no: bool, x: Bool16, y: Bool16) -> Tuple[Bool16, bool, bool]: """Python implementation of an ALU to use as a comparison.""" if zx: x = (False, ) * 16 if zy: y = (False, ) * 16 if nx: x = tuple(not i for i in x) if ny: y = tuple(not i for i in y) if f: f_out = adder_16(x, y) else: f_out = tuple(x_i and y_i for x_i, y_i in zip(x, y)) if no: f_out = tuple(not i for i in f_out) is_zero = bool16_to_int(f_out) == 0 is_negative = bool16_to_int(f_out) < 0 return f_out, is_zero, is_negative
def _read_memory(self, register: Callable) -> int: output = register(clock=True) register(clock=False) return bool16_to_int(output)
def cpu(m_in: Bool16, instructions: Bool16, reset: bool) \ -> Tuple[Bool16, bool, Bool15, Bool15]: """Simulation of the CPU unit. Args: m_in: Value of the M RAM input. instructions: 16 bit instructions for the CPU to follow. reset: If True, program will be restarted. Returns: (a, b, c, d) where a: M output value. b: Write to M instruction. c: Address of M d: address of the next instruction """ nonlocal alu_out # If first instruction digit is 1, then it is a C instruction. a_instruction = not_(instructions[15]) c_instruction = not_(a_instruction) print(f'I = {"".join(["1" if x else "0" for x in instructions])}') if c_instruction: print(f'C instruction') else: print(f'A instruction') print(f'M = {bool16_to_int(m_in)}') print(f'A = {bool16_to_int(a_register((False,)*16, False))}') print(f'D = {bool16_to_int(d_register((False,)*16, False))}') print(f'ALU {bool16_to_int(alu_out)}') # # # # # # # # # # # # # # Register A # instructions[5] represents whether A is the destination alu_to_a = and_(a=c_instruction, b=instructions[5]) if alu_to_a: print('A is destination') # If it's a C instruction and the destination is A then send the ALU output # to the A register. Otherwise send the instruction to Register A. register_a_input = mux_16(alu_to_a, alu_out, instructions) # load_a is True if it is an A instruction or the C instruction has A as # the destination. load_a = or_(a_instruction, alu_to_a) a_to_pc = a_register(register_a_input, load_a) register_a_out = a_to_pc m_address = a_to_pc[0:15] # Returned as output -> # if instructions[12] is True M should be used instead of the A register am_mux_out = mux_16(instructions[12], m_in, register_a_out) # # # # # # # # # # # # # # Register D # If instructions[4] is True the D register is the destination (if it is a # c instruction). load_d = and_(a=c_instruction, b=instructions[4]) register_d_out = d_register(alu_out, load_d) if load_d: print(f'loaded {bool16_to_int(alu_out)} into d') # # # # # # # # # # # # # # ALU # Send the register_d_out into the ALU alu_out, zero_out, neg_out = alu(x=register_d_out, y=am_mux_out, zero_x=instructions[11], negate_x=instructions[10], zero_y=instructions[9], negate_y=instructions[8], add_x_y=instructions[7], negate_output=instructions[6]) print(f'ALU(x={bool16_to_int(register_d_out)}, ' f'y={bool16_to_int(am_mux_out)}, ' f'zero_x={instructions[11]}, ' f'negate_x={instructions[10]}, ' f'zero_y={instructions[9]}, ' f'negate_y={instructions[8]}, ' f'add_x_y={instructions[7]}, ' f'negate_output={instructions[6]})' f' = {bool16_to_int(alu_out)}') m_out = alu_out # Returned as output -> print(f'm_out/alu_out = {"".join(["1" if x else "0" for x in m_out])}') # If it is a C instruction and the destination is M, write to M write_m = and_(c_instruction, instructions[3]) # Returned as output -> if write_m: print('M is the destination') # # # # # # # # # # # # # # PC / JUMP conditionals # Jump if equal to zero jeq = and_(zero_out, instructions[1]) # Jump if less than zero jlt = and_(neg_out, instructions[2]) # Zero or negative zero_or_neg = or_(zero_out, neg_out) # Positive positive = not_(zero_or_neg) # Jump if greater than zero jgt = and_(positive, instructions[0]) # Jump if less than or equal to zero jle = or_(jeq, jlt) # If any conditions are met, ready the jump to A # (less than or equal to and greater than cover all possible conditions # so if either is True, there must be a jump). jump_to_a = or_(jle, jgt) # Only jump if it a C instruction though! load_pc = and_(c_instruction, jump_to_a) # If not loading an address, increase the PC inc_pc = not_(load_pc) # If any conditions were met then the PC will load the address, # otherwise the PC will just increase the address to the program's next line. pc_out = pc(a_to_pc, load_pc, inc_pc, reset)[:15] # returned as output print('## Returns:') print('m_out = ', bool16_to_int(m_out)) print('write_m =', write_m) print('m_address = ', bool16_to_int(m_address)) print('pc_out = ', bool16_to_int(pc_out)) print( '***************************************************************') return m_out, write_m, m_address, pc_out