Beispiel #1
0
    def _do_resolve_const(self, value, bits=None):
        if isinstance(value, int):
            value = bin(value)[2:]
        if "'" in value:
            lit_width, _, value = value.partition("'")
            assert int(lit_width) == bits
            assert value[0].lower() == 'b'
            value = value[1:]

        if any(x not in '10x' for x in value):
            value = bin(int(value))[2:]

        if value == '1' and bits in [1, None]:
            return ir.ASTPort('__const1_on', 1)
        if value == '0' and bits in [1, None]:
            return ir.ASTPort('__const1_off', 1)
        if value == "x" and bits in [1, None]:
            return ir.ASTPort('__const1_x', 1)

        my_sig = self.circuit.generate_internal_signal(bits)
        port = self.circuit.get_port(my_sig)

        value = '0' * (bits - len(value)) + value

        for i in range(bits):
            self.circuit.children.append(
                ir.ASTAssign(
                    port[i],
                    self.resolve_const(value[len(value) - 1 - i], bits=1)))

        return port
Beispiel #2
0
    def __init__(self, name, inputs=None, outputs=None, internal=None):
        self.name = name
        self.inputs = [ir.ASTPort(name, size) for name, size in (inputs or [])]
        self.outputs = [
            ir.ASTPort(name, size) for name, size in (outputs or [])
        ]

        self.circuit = ir.ASTCircuit(self.inputs, self.outputs)

        for name, size in (internal or []):
            self.circuit.internal_signals[name] = size
Beispiel #3
0
    def _lower_edge(self, info: visit.AlwaysInfo):
        if info.clock_edge is None and info.reset_edge is None:
            return None
        raw_edges = [(str(info.clock_name[1]), info.clock_edge, info.clock_bit)
                     ]
        if info.reset_edge:
            raw_edges.append(
                (str(info.reset_name[1]), info.reset_edge, info.reset_bit))

        edges = []
        for raw in raw_edges:
            name = raw[0]
            port = self.circuit.get_port(name)
            if port.bitsize != 1:
                name += '(' + str(raw[2]) + ')'

            my_port = ir.ASTPort(name, 1)
            if raw[1] != 'posedge':
                my_port = ir.ASTLogicGate('not', children=[my_port])

            edges.append(my_port)

        if len(edges) == 2:
            return ir.ASTLogicGate('or', children=edges)

        return edges[0]
Beispiel #4
0
    def __init__(self, module, terms, binddict, instances, other_modules):
        self.module = module
        self.terms = terms
        self.binddict = binddict
        self.instances = instances
        self.other_modules = other_modules

        terms = {t: terms[t] for t in terms if len(t) == 2}

        inputs = filter_terms(terms, lambda x: 'Input' in x)
        outputs = filter_terms(terms, lambda x: 'Output' in x)
        internal = filter_terms(terms,
                                lambda x: not ('Input' in x or 'Output' in x))

        self.circuit = ir.ASTCircuit([ir.ASTPort(n, s) for n, s in inputs],
                                     [ir.ASTPort(n, s) for n, s in outputs])
        for name, size in internal:
            self.circuit.get_or_create(name, size)

        self.circuit.validate()

        self.resolved_consts = {}

        self.required_intrinsics = set([])

        self.mem_definitions = {}
        self.mem_initial = {}

        for item in self.other_modules[self.module].items:
            if isinstance(item, Decl):
                for arr in item.list:
                    if isinstance(arr, RegArray):
                        self.mem_definitions[arr.name] = arr
            if isinstance(item, Initial):
                item = item.statement.statement
                if item.syscall == 'readmem_sim':
                    with open(item.args[0].value) as f:
                        self.mem_initial[item.args[1].name] = f.read()
                pass
Beispiel #5
0
    def _emit_expr_intrinsic(self, v_name, children, bits=None):
        if v_name == 'Plus':
            assert type(bits) == int
            assert len(children) == 2
            assert all(c.get_bitsize() == bits for c in children)

            result_sig = self.circuit.generate_internal_signal(bits)
            result_port = self.circuit.get_port(result_sig)

            self.required_intrinsics.add(('add', bits))

            self.circuit.children.append(
                ir.ASTSubCircuit(
                    '_add' + str(bits), {
                        'A': children[0],
                        'B': children[1],
                        'Cin': ir.ASTPort('__const1_off', 1),
                    }, {
                        'X': result_port,
                    }))

            return result_port

        raise ValueError
Beispiel #6
0
def generate_intrinsic(info):
    name = '[unknown]'
    circuit = None
    other_intrinsics = set([])

    if info == ('add', 1):
        name = '_add1'
        circuit = ir.ASTCircuit(
            [ir.ASTPort('A', 1),
             ir.ASTPort('B', 1),
             ir.ASTPort('Cin', 1)],
            [ir.ASTPort('X', 1), ir.ASTPort('Cout', 1)])

        circuit.internal_signals['AxorB'] = 1

        circuit.children.append(
            ir.ASTAssign(
                circuit.get_port('AxorB'),
                ir.ASTLogicGate('xor',
                                [circuit.get_port('A'),
                                 circuit.get_port('B')])))

        circuit.children.append(
            ir.ASTAssign(
                circuit.get_port('X'),
                ir.ASTLogicGate(
                    'xor',
                    [circuit.get_port('AxorB'),
                     circuit.get_port('Cin')])))

        circuit.children.append(
            ir.ASTAssign(
                circuit.get_port('Cout'),
                ir.ASTLogicGate('or', [
                    ir.ASTLogicGate(
                        'and', [circuit.get_port('A'),
                                circuit.get_port('B')]),
                    ir.ASTLogicGate(
                        'and',
                        [circuit.get_port('AxorB'),
                         circuit.get_port('Cin')])
                ])))

    elif info[0] == 'add':
        size = info[1]
        other_intrinsics.add(('add', 1))

        name = '_add' + str(size)
        circuit = ir.ASTCircuit([
            ir.ASTPort('A', size),
            ir.ASTPort('B', size),
            ir.ASTPort('Cin', 1)
        ], [ir.ASTPort('X', size),
            ir.ASTPort('Cout', 1)])

        in_cin = 'Cin'

        for i in range(size):
            carry = 'c' + str(i)
            circuit.internal_signals[carry] = 1

            circuit.children.append(
                ir.ASTSubCircuit(
                    '_add1', {
                        'A': circuit.get_port('A')[i],
                        'B': circuit.get_port('B')[i],
                        'Cin': circuit.get_port(in_cin),
                    }, {
                        'X': circuit.get_port('X')[i],
                        'Cout': circuit.get_port(carry),
                    }))
            in_cin = carry

        circuit.children.append(
            ir.ASTAssign(circuit.get_port('Cout'), circuit.get_port(in_cin)))

    # (circuit, new intrinsics that are needed)
    return name, circuit, other_intrinsics
Beispiel #7
0
    def _lower_expr(self, expr, ident=None, bits=None):
        # if isinstance(expr, )
        if isinstance(expr, df.DFPartselect):
            return self.circuit.get_port(expr.var.name[1])[int(expr.lsb.value),
                                                           int(expr.msb.value)]
        elif isinstance(expr, df.DFBranch):

            spec_mux = self._speculative_mux_folding(expr,
                                                     ident=ident,
                                                     bits=bits)
            if spec_mux:
                return spec_mux

            false_node = self._lower_expr(
                expr.falsenode, ident=ident,
                bits=bits) if expr.falsenode else ident
            true_node = self._lower_expr(expr.truenode, ident=ident,
                                         bits=bits) if expr.truenode else ident

            if isinstance(expr.condnode, df.DFIntConst):
                if expr.condnode.eval():
                    return true_node
                else:
                    return false_node

            return ir.ASTMultiplexer(self._lower_expr(expr.condnode, bits=1), {
                0: false_node,
                1: true_node,
            })
        elif isinstance(expr, df.DFTerminal):
            return self.circuit.get_port(str(expr.name[1]))
        elif isinstance(expr, df.DFOperator):

            assert len(expr.nextnodes) == 2 or (len(expr.nextnodes) == 1
                                                and expr.operator in ['Unot'])

            if expr.operator == 'Eq' and isinstance(expr.nextnodes[1],
                                                    df.DFIntConst):
                lhs = self._lower_expr(expr.nextnodes[0])
                bitsize = lhs.get_bitsize()

                lhs_name = self.circuit.generate_internal_signal(bitsize)
                lhs_port = self.circuit.get_port(lhs_name)
                self.circuit.children.append(ir.ASTAssign(lhs_port, lhs))

                const_str = expr.nextnodes[1].value
                if "'" in const_str:
                    _, _, const_str = const_str.partition("'b")

                const_value = int(const_str)

                previous = None

                for i in range(bitsize):
                    my_bit = lhs_port[i]
                    if ((const_value >> i) % 2) == 0:
                        my_bit = ir.ASTLogicGate('not', children=[my_bit])
                    if previous:
                        previous = ir.ASTLogicGate('and',
                                                   children=[previous, my_bit])
                    else:
                        previous = my_bit

                return previous

            lookup = {
                'Lor': 'or',
                'Or': 'or',
                'And': 'and',
                'Xor': 'xor',
                'Unot': 'not'
            }

            if expr.operator in ['Plus']:
                return self._emit_expr_intrinsic(
                    expr.operator,
                    [self._lower_expr(x, bits=bits) for x in expr.nextnodes],
                    bits=bits)

            return ir.ASTLogicGate(
                lookup[expr.operator],
                children=[self._lower_expr(x) for x in expr.nextnodes])
        elif isinstance(expr, df.DFIntConst):
            return self.resolve_const(expr.eval(), bits=bits)
        elif isinstance(expr, df.DFPointer):
            mem_name = str(expr.var.name[1])
            mem_init = ''
            if mem_name in self.mem_initial:
                mem_init = self.mem_initial[mem_name]

            reg_array = self.mem_definitions[mem_name]

            def p(x):
                return df.DFIntConst(x.value).eval()

            assert p(reg_array.width.lsb) == 0
            assert p(reg_array.length.msb) == 0

            address_bits = math.ceil(
                math.log2(
                    p(reg_array.length.lsb) - p(reg_array.length.msb) + 1))
            data_bits = p(reg_array.width.msb) - p(reg_array.width.lsb) + 1

            address = self._lower_expr(expr.ptr, bits=address_bits)

            data_name = self.circuit.generate_internal_signal(data_bits)
            data_port = ir.ASTPort(data_name, data_bits)

            self.circuit.children.append(
                ir.ASTSubCircuit('rom', {'Address': address},
                                 {'Data': data_port},
                                 data={
                                     'address_bits': address_bits,
                                     'data_bits': data_bits,
                                     'contents': mem_init,
                                 }))

            return data_port
        elif isinstance(expr, df.DFConcat):
            pieces = [self._lower_expr(node) for node in expr.nextnodes]
            total_bits = sum(x.get_bitsize() for x in pieces)

            out_name = self.circuit.generate_internal_signal(total_bits)
            out_port = ir.ASTPort(out_name, total_bits)

            high_bit = total_bits - 1
            for piece in pieces:
                low = high_bit - piece.get_bitsize() + 1
                self.circuit.children.append(
                    ir.ASTAssign(ir.ASTSubPort(out_name, low, high_bit),
                                 piece))
                high_bit = low - 1

            return out_port
        else:
            raise ValueError
Beispiel #8
0
def main():
    internal_signals = [('a', 2), ('ALU_func', 2), ('OpTest', 1)]

    # order should match signals starting at index 6 of control ROM
    control_signals = [
        'DrREG', 'DrMEM', 'DrALU', 'DrPC', 'DrOFF', 'LdPC', 'LdIR', 'LdMAR',
        'LdA', 'LdB', 'LdCmp', 'WrREG', 'WrMEM'
    ]

    for sig in control_signals:
        internal_signals.append((sig, 1))

    i_regs = [('iReg' + str(i), 32) for i in range(16)]

    with CircuitBuilder('DataPath', [('clk', 1), ('b', 2)],
                        [('bus', 32), ('PC', 32), ('IR', 32),
                         ('micro_state', 6)] + i_regs + [('IR_imm', 32)],
                        internal_signals):

        # Ld/Dr PC
        port('PC').assign(port('bus'), write_enable=port('LdPC'))
        port('bus').assign(port('PC'), enabled=port('DrPC'))

        # ALU
        port_define('ALU_A', 32).assign(port('bus'), write_enable=port('LdA'))
        port_define('ALU_B', 32).assign(port('bus'), write_enable=port('LdB'))

        sub_circuit('ALU',
                    A=port('ALU_A'),
                    B=port('ALU_B'),
                    Op=port('ALU_func'),
                    Out=port_define('ALU_Out', 32))

        port('bus').assign(port('ALU_Out'), enabled=port('DrALU'))

        # Registers

        sub_circuit('RegFile',
                    clk=port('clk'),
                    Write=port('WrREG'),
                    Index=port_define('RegNo', 4),
                    In=port('bus'),
                    Out=port_define('Reg_Out', 32),
                    **{k: port(k)
                       for k, _ in i_regs})

        port('bus').assign(port('Reg_Out'), enabled=port('DrREG'))

        # Memory
        port_define('MAR', 32).assign(port('bus'), write_enable=port('LdMAR'))

        sub_circuit('Memory',
                    In=port('bus'),
                    Out=port_define('mem_out', 32),
                    Address=port('MAR', 0, 15),
                    Clock=port('clk'),
                    Write=port('WrMEM'))

        port('bus').assign(port('mem_out'), enabled=port('DrMEM'))

        # IR
        port('IR').assign(port('bus'), write_enable=port('LdIR'))

        # poor man's sign extend lmao
        imm = port('IR_imm')
        imm[0, 19] <= port('IR', 0, 19)
        for i in range(20, 32):
            imm[i] <= port('IR', 19)

        port('bus').assign(imm, enabled=port('DrOFF'))

        # Comparison Logic

        sub_circuit('ComparisonLogic',
                    Data=port('bus'),
                    Mode=port('IR', 24, 27),
                    Out=port_define('CmpResult', 1))

        # Misc

        port('RegNo') <= mux(
            port_define('RegSel', 2), {
                0b00: port('IR', 24, 27),
                0b01: port('IR', 20, 23),
                0b10: port('IR', 0, 3),
            })

        sub_circuit('ControlUnit',
                    clk=port('clk'),
                    RegSel=port('RegSel'),
                    ALU_func=port('ALU_func'),
                    Cmp=port('CmpResult'),
                    OpCode=port('IR', 28, 31),
                    OpTest=port('OpTest'),
                    state=port('micro_state'),
                    **{k: port(k)
                       for k in control_signals})

        # my_logic = g_and(port('a')[0], g_or(port('a', 0), port('a', 1)))

        # port('a', 1).assign(my_logic, rising_edge=port('b', 0), enabled=port('b', 0))

        pass

    with CircuitBuilder('ControlUnit', [('clk', 1), ('OpCode', 4), ('Cmp', 1)],
                        [(x, 1) for x in control_signals] + [('RegSel', 2),
                                                             ('ALU_func', 2),
                                                             ('OpTest', 1),
                                                             ('ChkCmp', 1),
                                                             ('state', 6)]):

        with open('circuitsim/rom_main.dat') as f:
            control_rom = f.read()

        with open('circuitsim/rom_seq.dat') as f:
            control_seq_rom = f.read()

        with open('circuitsim/rom_cond.dat') as f:
            control_cond_rom = f.read()

        sub_circuit('rom',
                    Address=port('state'),
                    Data=port_define('control_vector', 25),
                    config={
                        'address_bits': 6,
                        'data_bits': 25,
                        'contents': control_rom,
                    })

        sub_circuit('rom',
                    Address=port('OpCode'),
                    Data=port_define('next_seq_state', 6),
                    config={
                        'address_bits': 4,
                        'data_bits': 6,
                        'contents': control_seq_rom,
                    })

        sub_circuit('rom',
                    Address=port('Cmp'),
                    Data=port_define('next_cmp_state', 6),
                    config={
                        'address_bits': 1,
                        'data_bits': 6,
                        'contents': control_cond_rom,
                    })

        port_define('next_state', 6) <= mux(
            port_define('state_mux', 2), {
                0b00: port('control_vector', 0, 5),
                0b01: port('next_seq_state'),
                0b10: port('next_cmp_state'),
            })

        # every clock we transition state
        port('state').assign(port('next_state'),
                             write_enable=port('__const1_on'))

        for i, v in enumerate(control_signals):
            port(v) <= port('control_vector', 6 + i, 6 + i)

        port('RegSel') <= port('control_vector', 19, 20)
        port('ALU_func') <= port('control_vector', 21, 22)
        port('OpTest') <= port('control_vector', 23)
        port('ChkCmp') <= port('control_vector', 24)

        port('state_mux', 0) <= port('OpTest')
        port('state_mux', 1) <= port('ChkCmp')

        pass

    with CircuitBuilder('RegFile', [('clk', 1), ('Write', 1), ('Index', 4),
                                    ('In', 32), ('__const32_off', 32)],
                        [('Out', 32)] + i_regs):
        write_enables = {}
        outputs = {}

        do_write = g_and(port('clk'), port('Write'))

        for i in range(1, 16):
            write_enables[i] = port_define('WrReg{}'.format(i), 1)
            outputs[i] = port_define('OutReg{}'.format(i), 32)

            outputs[i].assign(port('In'),
                              write_enable=g_and(write_enables[i],
                                                 port('Write')))

        outputs[0] = port('__const32_off')

        for i in range(16):
            port('iReg' + str(i)) <= outputs[i]

        decoder(port('Index'), write_enables)

        port('Out') <= mux(port('Index'), outputs)

    with CircuitBuilder('ALU', [('A', 32), ('B', 32), ('Op', 2),
                                ('__const32_off', 32)], [('Out', 32)]):

        sub_circuit('ADD32',
                    X=port_define('add_result', 32),
                    A=port('A'),
                    B=port('B'),
                    Cin=port('__const1_off'))

        sub_circuit('ADD32',
                    X=port_define('sub_result', 32),
                    A=port('A'),
                    B=g_not(port('B')),
                    Cin=port('__const1_on'))

        port_define('nand_result', 32) <= g_not(g_and(port('A'), port('B')))

        sub_circuit('ADD32',
                    X=port_define('add1_result', 32),
                    A=port('A'),
                    B=port('__const32_off'),
                    Cin=port('__const1_on'))

        port('Out') <= mux(
            port('Op'), {
                0b00: port('add_result'),
                0b01: port('sub_result'),
                0b10: port('nand_result'),
                0b11: port('add1_result'),
            })

    with CircuitBuilder('ComparisonLogic', [('Data', 32), ('Mode', 4)],
                        [('Out', 1)]):

        or_sigs = [port('Data', i, i) for i in range(32)]
        while len(or_sigs) != 1:
            copy = list(or_sigs)
            or_sigs = []
            for i in range(0, len(copy), 2):
                or_sigs.append(g_or(copy[i], copy[i + 1]))

        port('Out') <= mux(port('Mode'), {
            0b00: g_not(or_sigs[0]),
            0b01: port('Data', 31)
        })

    with CircuitBuilder('ADD32', [('A', 32), ('B', 32), ('Cin', 1)],
                        [('X', 32), ('Cout', 1)]):
        in_cin = 'Cin'

        for i in range(32):
            carry = 'c' + str(i)
            sub_circuit('ADD1',
                        A=port('A', i),
                        B=port('B', i),
                        X=port('X', i),
                        Cin=port(in_cin),
                        Cout=port_define(carry, 1))
            in_cin = carry

        port('Cout') <= port(in_cin)

    with CircuitBuilder('ADD1', [('A', 1), ('B', 1), ('Cin', 1)],
                        [('X', 1), ('Cout', 1)]):

        port_define('AxorB', 1) <= g_xor(port('A'), port('B'))

        port('X') <= g_xor(port('AxorB'), port('Cin'))
        port('Cout') <= g_or(g_and(port('A'), port('B')),
                             g_and(port('AxorB'), port('Cin')))

    input = ir.ASTPort('in', 2)
    clock = ir.ASTPort('clock', 1)
    output = ir.ASTPort('out', 2)

    root = ir.ASTCircuit([input, clock], [output])

    meh = ir.ASTPort(root.generate_internal_signal(1), 1)
    root.children.append(ir.ASTAssign(meh, clock))

    # root.children.append(ir.ASTSubCircuit('Bar', {'a': input[0]}, {'out': clock}))

    root.children.append(
        ir.ASTAssign(output,
                     input,
                     enabled=ir.ASTLogicGate('and', children=[clock, meh])))

    # other_root = ir.ASTCircuit([ir.ASTPort('in', 1), ir.ASTPort('in2', 1)], [ir.ASTPort('out', 1)])

    _root_builder.circuits['foo'] = root

    with open('circuitsim/intrinsics.sim', 'r') as f:
        native_circuits = json.load(f)['circuits']

    native_defines = [('Memory', [('Address', 16), ('In', 32), ('Clock', 1),
                                  ('Write', 1)], [('Out', 32)])]

    ir_lowering.compile_circuits(_root_builder.circuits,
                                 filename='circuitsim/gen2.sim',
                                 native_circuits=native_circuits)