def pc(in_: Bool16 = (False, ) * 16, load: bool = False, inc: bool = False, reset: bool = False) -> Bool16: nonlocal register not_load = not_(load) use_inc = and_(not_load, inc) inc_out = inc_16(register()) mux_inc = mux_16(use_inc, inc_out, in_) mux_reset = mux_16(reset, (False, ) * 16, mux_inc) load_or_inc = or_(load, inc) load_or_inc_or_reset = or_(load_or_inc, reset) return register(mux_reset, load_or_inc_or_reset)
def memory(in_: Bool16, load: bool, address: Bool15) -> Bool16: load_ram_1, load_ram_2, load_screen, load_keyboard = demux_4way( in_=load, selectors=address[13:15]) load_ram = or_(load_ram_1, load_ram_2) ram_out = ram(in_=in_, load=load_ram, address=address[0:14]) screen_out = screen(in_=in_, load=load_screen, address=address[0:12]) keyboard_out = (False, ) * 16 return mux_16_4way(address[13:15], ram_out, ram_out, screen_out, keyboard_out)
def equal_to_zero(in_: Bool16) -> bool: """Returns True if in_ is equal to 0.""" # Reduce to 8 or_01 = or_(in_[0], in_[1]) or_23 = or_(in_[2], in_[3]) or_45 = or_(in_[4], in_[5]) or_67 = or_(in_[6], in_[7]) or_89 = or_(in_[8], in_[9]) or_1011 = or_(in_[10], in_[11]) or_1213 = or_(in_[12], in_[13]) or_1415 = or_(in_[14], in_[15]) # Reduce to 4 or_0123 = or_(or_01, or_23) or_4567 = or_(or_45, or_67) or_891011 = or_(or_89, or_1011) or_12131415 = or_(or_1213, or_1415) # Reduce to 2 or_01234567 = or_(or_0123, or_4567) or_89101112131415 = or_(or_891011, or_12131415) # Reduce to 1 or_result = or_(or_01234567, or_89101112131415) # Return inverse return nand(or_result, or_result)
def test_logic(self): for a, b in self.logic_pairs: self.assertEqual(and_(a, b), a and b) self.assertEqual(or_(a, b), a or b) self.assertEqual(xor_(a, b), (a or b) and not (a and b))
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
def or_16(a: Bool16, b: Bool16) -> Bool16: """Returns 16-bit bitwise or in the form of a tuple of 16 bool values.""" return (or_(a[0], b[0]), or_(a[1], b[1]), or_(a[2], b[2]), or_(a[3], b[3]), or_(a[4], b[4]), or_(a[5], b[5]), or_(a[6], b[6]), or_(a[7], b[7]), or_(a[8], b[8]), or_(a[9], b[9]), or_(a[10], b[10]), or_(a[11], b[11]), or_(a[12], b[12]), or_(a[13], b[13]), or_(a[14], b[14]), or_(a[15], b[15]))