def bus(address, write, modules): """ the bus switches the write line between the modules and muxes the data lines coming back in both cases based on the address lines """ address_ = invert(address) # module prefixes are aligned to their sizes for prefix, size, data_in in modules: assert prefix % 2**size == 0, (prefix, size) # module ranges don't overlap _modules = sorted(modules) for a, b in zip(_modules, _modules[1:]): a_start, a_size, _ = a b_start, b_size, _ = b a_end = a_start + 2**a_size - 1 assert a_end < b_start # the control line for each module is based on the relevant address prefix match control_lines = [] for prefix, size, data_in in modules: prefix //= 2**size control_lines.append(address_matches(prefix, address[size:], address_[size:])) # switch the data and write lines based on the control lines data_out = word_switch(control_lines, *[d for p, s, d in modules]) write_lines = [And(write, ctrl) for ctrl in control_lines] return data_out, write_lines
def jump(clock, write, address, data_in): """ allows manipulation of the PC address read write 0 PC PC 1 PC dest 2 PC if 0: dest -> PC 3 PC if !0: dest -> PC """ assert len(address) >= 2 address = address[:2] control_lines = address_decode(address) # a destination register for conditional jumps write_dest = And(clock, write, control_lines[1]) dest = register(data_in, write_dest) # are we jumping and if so where jump_if_zero = And(control_lines[2], Not(Or(*data_in))) jump_if_not_zero = And(control_lines[3], Or(*data_in)) conditional_jump = Or(jump_if_zero, jump_if_not_zero) unconditional_jump = control_lines[0] write_pc = And(write, Or(conditional_jump, unconditional_jump)) pc_out = word_switch([conditional_jump, unconditional_jump], dest, data_in) return dest, pc_out, write_pc
def rom(clock, write, address, data_in, size, data): address = address[:size] control_lines = address_decode(address, len(data)) assert len(data) <= len(control_lines) network = clock.network data_size = len(data_in) ties = [tie_word(network, data_size, d) for d in data] return word_switch(control_lines, *ties)
def bus(address, write, modules): control_lines = [] for prefix, size, data_in in modules: prefix //= 2**size control_lines.append(equals(prefix, address[size:])) data_out = word_switch(control_lines, *[d for p, s, d in modules]) write_lines = [And(write, ctrl) for ctrl in control_lines] return data_out, write_lines
def cpu_core(clock, data_in, pc_in, write_pc, debug=False): """ the core CPU state machine executes a 4 state loop continuously s0: fetch address from pc s1: fetch value from address and increment pc s2: fetch address from pc s3: store value to address and increment pc """ network = clock.network word_size = len(data_in) # step through the 4 states in order state = PlaceholderWord(network, 2) incr, c = ripple_incr(state) state.replace(register(incr, clock)) s0, s1, s2, s3 = address_decode(state) # pc increments in s1 and s3, incoming pc writes from the jump module are taken in s3 pc = PlaceholderWord(network, word_size) incr, c = ripple_incr(pc) jumping = And(write_pc, s3) new_pc = word_mux([jumping], incr, pc_in) clock_pc = And(clock, Or(s1, s3)) pc.replace(register(new_pc, clock_pc)) # clock in address in s0 and s2 addr = register(data_in, And(clock, Or(s0, s2))) # set address lines to pc in s0 and s2 and to the previously fetched address in s1 and s3 addr_out = word_switch([Or(s0, s2), Or(s1, s3)], pc, addr) # read in data in s1 data = register(data_in, And(clock, s1)) # write out data in s3 write_out = s3 data_out = data if debug: clock.watch('clock') s0.watch('s0') s1.watch('s1') s2.watch('s2') s3.watch('s3') jumping.watch('jumping') clock_pc.watch('clock pc') write_out.watch('write out') return addr_out, data_out, write_out
def rom(clock, write, address, data_in, size, data): """ a block of ROM containing the specified data address read write N data[N] - """ network = clock.network data_size = len(data_in) assert len(data) <= 2**len(address) # just ties muxed by address control_lines = address_decode(address[:size], len(data)) ties = [tie_word(network, data_size, d) for d in data] return word_switch(control_lines, *ties)
def memory(clock, write, address, data_in, size): address = address[:size] write_clock = And(clock, write) if size: control_lines = address_decode(address) else: control_lines = [Tie(clock.network, True)] registers = [] for line in control_lines: registers.append(register(data_in, And(line, write_clock))) return word_switch(control_lines, *registers)
def sub(clock, write, address, data_in): assert len(address) >= 2 address = address[:2] control_lines = address_decode(address) write_a = And(clock, write, control_lines[0]) a = register(data_in, write_a) write_b = And(clock, write, control_lines[1]) b = register(data_in, write_b) res, carry = ripple_subtractor(a, b) carry = pad([carry], len(data_in)) return word_switch(control_lines, a, b, res, carry)