Example #1
0
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
Example #2
0
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
Example #3
0
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
Example #4
0
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)
Example #5
0
def word_switch(control_lines, *data):
    return word_switch_(control_lines, *[invert(word) for word in data])
Example #6
0
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))
Example #7
0
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)]
Example #8
0
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