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 word_switch_(control_lines, *data_): """ select the words(s) from the data that match the enabled control line(s) (generally only 1) """ assert len(control_lines) >= len(data_) word_size = len(data_[0]) assert all(len(d) == word_size for d in data_) output = [] control_lines_ = invert(control_lines) for data_lines_ in zip(*data_): output.append(bit_switch(control_lines_, *data_lines_)) return output
def register(data, clock, negate_in=False, negate_out=False): """ a bank of ms_d_flops that share a clock line """ clock_ = Not(clock) if not negate_in: data_ = invert(data) else: data_ = data res = [] for i_ in data_: d, d_ = ms_d_flop(i_, clock, clock_) if negate_out: res.append(d_) else: res.append(d) return res
def memory(clock, write, address, data_in, size): """ a block of RAM address read write N [N] [N] """ # address_decode can't deal with empty addresses (aka 1 word memories) if not size: control_lines = [Tie(clock.network, True)] else: control_lines = address_decode(address[:size]) # otherwise it's a simple pile of registers switched by the control lines registers = [] data_in_ = invert(data_in) for line in control_lines: registers.append( register(data_in_, And(line, clock, write), negate_in=True, negate_out=True)) return word_switch_(control_lines, *registers)
def word_switch(control_lines, *data): return word_switch_(control_lines, *[invert(word) for word in data])
def bit_mux(address, *data): """ select a single bit from the block of bits based on the address """ assert 2**len(address) >= len(data) control_lines = address_decode(address) return bit_switch(invert(control_lines), *invert(data))
def address_decode(address, limit=None): """ break an address out into individual enable lines """ if limit is None: limit = 2**len(address) address_ = invert(address) return [address_matches(i, address, address_) for i in range(limit)]
def test_jmp2(): """ same deal as above but with automatic signals so more realistic timing """ network = Network() clock = Switch(network) data_in = BinaryIn(network, 8) pc_in = PlaceholderWord(network, 8) write_pc = Placeholder(network) def step(): network.drain() clock.write(True) network.drain() clock.write(False) network.drain() addr, data_out, write = cpu_core(clock, data_in, pc_in, write_pc) write_pc = write_pc.replace( And(write, mux.address_matches(102, addr, invert(addr)))) pc_in = pc_in.replace(data_out) addr = BinaryOut(addr) data_out = BinaryOut(data_out) # fetch addr1 from pc network.drain() assert not write.read() assert addr.read() == 0 data_in.write(100) # fetch data from addr1 step() assert not write.read() assert addr.read() == 100 data_in.write(200) # fetch addr2 from pc step() assert not write.read() assert addr.read() == 1 data_in.write(102) # write data to addr2 AND PC step() assert write.read() assert addr.read() == 102 assert data_out.read() == 200 # fetch addr1 from pc step() assert not write.read() assert addr.read() == 200 data_in.write(99) # fetch data from addr1 step() assert not write.read() assert addr.read() == 99 data_in.write(98) # fetch addr2 from pc step() assert not write.read() assert addr.read() == 201 data_in.write(97) # write data to addr2 step() assert write.read() assert addr.read() == 97 assert data_out.read() == 98